114 lines
3.4 KiB
C++
114 lines
3.4 KiB
C++
#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() &&
|
|
!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
|