150 lines
5.2 KiB
C++
150 lines
5.2 KiB
C++
#include "fesa/app/fesa_application.h"
|
|
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "fesa/analysis/hht_dynamic_procedure.h"
|
|
#include "fesa/analysis/linear_frequency_procedure.h"
|
|
#include "fesa/analysis/linear_static_procedure.h"
|
|
#include "fesa/analysis/newton_iteration_log.h"
|
|
#include "fesa/analysis/nonlinear_static_procedure.h"
|
|
#include "fesa/analysis/prepared_analysis.h"
|
|
#include "fesa/app/output_paths.h"
|
|
#include "fesa/assembly/parallel_for.h"
|
|
#include "fesa/core/diagnostic.h"
|
|
#include "fesa/io/hdf5/dynamic_hdf5_results_writer.h"
|
|
#include "fesa/io/hdf5/eigen_hdf5_results_writer.h"
|
|
#include "fesa/io/hdf5/hdf5_results_writer.h"
|
|
#include "fesa/io/hdf5/nonlinear_hdf5_results_writer.h"
|
|
#include "fesa/io/hdf5/thermal_hdf5_results_writer.h"
|
|
#include "fesa/solvers/linear/mkl_pardiso_solver.h"
|
|
#include "fesa/solvers/linear/mkl_pardiso_tangent_solver.h"
|
|
|
|
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;
|
|
|
|
const char* SeverityName(const Severity severity) {
|
|
return severity == Severity::kWarning ? "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.entity_identity << '\t'
|
|
<< "message=" << diagnostic.message << '\n';
|
|
}
|
|
}
|
|
|
|
int ExitCodeFor(const Status& status) {
|
|
switch (status.Category().value_or(FailureCategory::kInput)) {
|
|
case FailureCategory::kInput:
|
|
return kInputExitCode;
|
|
case FailureCategory::kModel:
|
|
return kModelExitCode;
|
|
case FailureCategory::kSolver:
|
|
return kSolverExitCode;
|
|
case FailureCategory::kOutput:
|
|
return kOutputExitCode;
|
|
}
|
|
return kInputExitCode;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int FesaApplication::Run(const std::vector<std::string>& arguments) {
|
|
const auto paths =
|
|
DeriveSingleInputOutputPaths(arguments, std::filesystem::current_path());
|
|
if (!paths.HasValue()) {
|
|
WriteDiagnostics(paths.GetStatus().Diagnostics());
|
|
return kUsageExitCode;
|
|
}
|
|
|
|
auto lease = AcquireOutputWriteLease(paths.Value());
|
|
if (!lease.HasValue()) {
|
|
WriteDiagnostics(lease.GetStatus().Diagnostics());
|
|
return kOutputExitCode;
|
|
}
|
|
|
|
TbbParallelFor parallel_for;
|
|
MklPardisoSolver linear_solver;
|
|
MklPardisoTangentSolver tangent_solver;
|
|
Hdf5ResultsWriter linear_writer;
|
|
NonlinearHdf5ResultsWriter nonlinear_writer;
|
|
EigenHdf5ResultsWriter eigen_writer;
|
|
DynamicHdf5ResultsWriter dynamic_writer;
|
|
ThermalHdf5ResultsWriter thermal_writer;
|
|
NewtonIterationLogWriter log;
|
|
|
|
Status status = log.Open(paths.Value().log_path);
|
|
if (!status.IsOk()) {
|
|
WriteDiagnostics(status.Diagnostics());
|
|
return ExitCodeFor(status);
|
|
}
|
|
|
|
Result<PreparedAnalysisInput> prepared =
|
|
PrepareAnalysisInput(paths.Value().input_path);
|
|
if (!prepared.HasValue()) {
|
|
status = prepared.GetStatus();
|
|
} else {
|
|
LinearStaticProcedureExecutor linear_executor(parallel_for, linear_solver);
|
|
NonlinearStaticProcedureExecutor nonlinear_executor(parallel_for,
|
|
tangent_solver);
|
|
const LinearFrequencyProcedureExecutor frequency_executor;
|
|
const HhtDynamicProcedureExecutor dynamic_executor(
|
|
parallel_for, linear_solver, tangent_solver);
|
|
const TransientHeatProcedureExecutor thermal_executor(parallel_for,
|
|
linear_solver);
|
|
Result<PreparedAnalysisOutcome> outcome = ExecutePreparedAnalysis(
|
|
prepared.Value().domain, linear_executor, nonlinear_executor,
|
|
frequency_executor, log, &dynamic_executor, &thermal_executor);
|
|
if (!outcome.HasValue()) {
|
|
status = outcome.GetStatus();
|
|
} else {
|
|
const Status close_status = log.Close();
|
|
if (!close_status.IsOk()) {
|
|
WriteDiagnostics(close_status.Diagnostics());
|
|
return ExitCodeFor(close_status);
|
|
}
|
|
status = FinalizePreparedAnalysisResult(
|
|
paths.Value(), prepared.Value().domain, outcome.Value(),
|
|
prepared.Value().diagnostics, linear_writer, nonlinear_writer,
|
|
eigen_writer, &dynamic_writer, &thermal_writer);
|
|
if (status.IsOk()) {
|
|
return kSuccessExitCode;
|
|
}
|
|
WriteDiagnostics(status.Diagnostics());
|
|
return ExitCodeFor(status);
|
|
}
|
|
}
|
|
|
|
const Status close_status = log.Close();
|
|
if (!close_status.IsOk()) {
|
|
WriteDiagnostics(close_status.Diagnostics());
|
|
return ExitCodeFor(close_status);
|
|
}
|
|
if (status.IsOk()) {
|
|
return kSuccessExitCode;
|
|
}
|
|
|
|
WriteDiagnostics(status.Diagnostics());
|
|
return ExitCodeFor(status);
|
|
}
|
|
|
|
} // namespace fesa
|