#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 #include #include #include 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 [--output ]."}; } const char* severityName(const Severity severity) { return severity == Severity::warning ? "warning" : "error"; } void writeDiagnostics(std::vector 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& 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() && !startsWithOption(arguments[2U]); 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