feat(linear-static-3d-euler-beam): step 24 - linear-static-cli
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#include "fesa/app/fesa_application.hpp"
|
||||
|
||||
#include "fesa/analysis/linear_static_analysis.hpp"
|
||||
#include "fesa/assembly/parallel_for.hpp"
|
||||
#include "fesa/core/diagnostic.hpp"
|
||||
#include "fesa/io/hdf5/hdf5_results_writer.hpp"
|
||||
#include "fesa/solvers/linear/mkl_pardiso_solver.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
namespace {
|
||||
|
||||
constexpr int kSuccessExitCode = 0;
|
||||
constexpr int kUsageExitCode = 2;
|
||||
constexpr int kInputExitCode = 3;
|
||||
constexpr int kModelExitCode = 4;
|
||||
constexpr int kSolverExitCode = 5;
|
||||
constexpr int kOutputExitCode = 6;
|
||||
|
||||
bool startsWithOption(const std::string& argument) {
|
||||
return !argument.empty() && argument.front() == '-';
|
||||
}
|
||||
|
||||
Diagnostic usageDiagnostic() {
|
||||
return {
|
||||
Severity::error,
|
||||
"cli-usage",
|
||||
{{}, 0U},
|
||||
"",
|
||||
"",
|
||||
"Usage: fesa.exe <model.inp> [--output <results.h5>]."};
|
||||
}
|
||||
|
||||
const char* severityName(const Severity severity) {
|
||||
return severity == Severity::warning ? "warning" : "error";
|
||||
}
|
||||
|
||||
void writeDiagnostics(std::vector<Diagnostic> diagnostics) {
|
||||
sortDiagnostics(diagnostics);
|
||||
for (const auto& diagnostic : diagnostics) {
|
||||
// Stable field labels and tab separators keep empty source fields
|
||||
// explicit without depending on locale-specific formatting.
|
||||
std::cerr
|
||||
<< "severity=" << severityName(diagnostic.severity)
|
||||
<< '\t' << "code=" << diagnostic.code
|
||||
<< '\t' << "file="
|
||||
<< diagnostic.location.file.generic_u8string()
|
||||
<< '\t' << "line=" << diagnostic.location.line
|
||||
<< '\t' << "keyword=" << diagnostic.keyword
|
||||
<< '\t' << "entity_identity=" << diagnostic.entityIdentity
|
||||
<< '\t' << "message=" << diagnostic.message
|
||||
<< '\n';
|
||||
}
|
||||
}
|
||||
|
||||
int exitCodeFor(const Status& status) {
|
||||
switch (status.failureCategory().value_or(FailureCategory::input)) {
|
||||
case FailureCategory::input:
|
||||
return kInputExitCode;
|
||||
case FailureCategory::model:
|
||||
return kModelExitCode;
|
||||
case FailureCategory::solver:
|
||||
return kSolverExitCode;
|
||||
case FailureCategory::output:
|
||||
return kOutputExitCode;
|
||||
}
|
||||
return kInputExitCode;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int FesaApplication::run(const std::vector<std::string>& arguments) {
|
||||
const bool defaultOutputForm =
|
||||
arguments.size() == 1U &&
|
||||
!arguments[0U].empty() &&
|
||||
!startsWithOption(arguments[0U]);
|
||||
const bool explicitOutputForm =
|
||||
arguments.size() == 3U &&
|
||||
!arguments[0U].empty() &&
|
||||
!startsWithOption(arguments[0U]) &&
|
||||
arguments[1U] == "--output" &&
|
||||
!arguments[2U].empty();
|
||||
if (!defaultOutputForm && !explicitOutputForm) {
|
||||
writeDiagnostics({usageDiagnostic()});
|
||||
return kUsageExitCode;
|
||||
}
|
||||
|
||||
AnalysisRequest request;
|
||||
request.inputPath = arguments[0U];
|
||||
request.outputPath = explicitOutputForm
|
||||
? std::filesystem::path{arguments[2U]}
|
||||
: std::filesystem::current_path() / "results.h5";
|
||||
|
||||
TbbParallelFor parallelFor;
|
||||
MklPardisoSolver linearSolver;
|
||||
Hdf5ResultsWriter resultsWriter;
|
||||
LinearStaticAnalysis analysis{
|
||||
parallelFor, linearSolver, resultsWriter};
|
||||
const Status status = analysis.run(request);
|
||||
if (status.isOk()) {
|
||||
return kSuccessExitCode;
|
||||
}
|
||||
|
||||
writeDiagnostics(status.diagnostics());
|
||||
return exitCodeFor(status);
|
||||
}
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "fesa/app/fesa_application.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main(const int argc, char* argv[]) {
|
||||
std::vector<std::string> arguments;
|
||||
if (argc > 1) {
|
||||
arguments.reserve(static_cast<std::size_t>(argc - 1));
|
||||
}
|
||||
// The application boundary receives only operands and options, not argv[0].
|
||||
for (int index = 1; index < argc; ++index) {
|
||||
arguments.emplace_back(argv[index]);
|
||||
}
|
||||
return fesa::FesaApplication{}.run(arguments);
|
||||
}
|
||||
Reference in New Issue
Block a user