Files
FESADev/src/fesa/analysis/prepared_analysis.cpp
T

301 lines
11 KiB
C++

#include "fesa/analysis/prepared_analysis.h"
#include <memory>
#include <utility>
#include "analysis_procedures.h"
#include "fesa/analysis/analysis_model.h"
#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/solid_frequency_procedure.h"
#include "fesa/analysis/solid_hht_dynamic_procedure.h"
#include "fesa/analysis/solid_static_procedure.h"
#include "fesa/analysis/transient_heat_procedure.h"
#include "fesa/app/output_paths.h"
#include "fesa/io/abaqus/domain_mapper.h"
#include "fesa/io/abaqus/input_reader.h"
#include "fesa/results/prepared_results_writer.h"
namespace fesa {
Result<PreparedAnalysisInput> PrepareAnalysisInput(
const std::filesystem::path& input_path) {
const Result<ParsedInput> syntax = AbaqusInputReader{}.Read(input_path);
if (!syntax.HasValue()) {
return Result<PreparedAnalysisInput>::Failure(syntax.GetStatus());
}
Result<Domain> mapped = AbaqusDomainMapper{}.Map(syntax.Value());
if (!mapped.HasValue()) {
return Result<PreparedAnalysisInput>::Failure(mapped.GetStatus());
}
PreparedAnalysisInput prepared{std::move(mapped.Value()), {}};
prepared.diagnostics = prepared.domain.Warnings();
SortDiagnostics(prepared.diagnostics);
return Result<PreparedAnalysisInput>::Success(std::move(prepared));
}
namespace {
enum class ProcedureKind {
kLinearStatic,
kNonlinearStatic,
kLinearFrequency,
kHhtDynamic,
kSolidStatic,
kSolidFrequency,
kSolidHhtDynamic,
kTransientHeat
};
// Keep procedure precedence and step-count diagnostics common to both APIs.
Result<ProcedureKind> SelectProcedure(const Domain& domain) {
if (domain.ThermalStep() != nullptr)
return Result<ProcedureKind>::Success(ProcedureKind::kTransientHeat);
if (domain.Steps().Size() != 1U) {
return Result<ProcedureKind>::Failure(Status::Failure(
FailureCategory::kInput,
{{Severity::kError,
"invalid-analysis-step-count",
{},
"*STEP",
{},
"Prepared analysis requires exactly one analysis step."}}));
}
if (domain.IsSolid()) {
if (domain.Dynamic() != nullptr)
return Result<ProcedureKind>::Success(ProcedureKind::kSolidHhtDynamic);
if (domain.Steps()[0U].IsFrequency())
return Result<ProcedureKind>::Success(ProcedureKind::kSolidFrequency);
return Result<ProcedureKind>::Success(ProcedureKind::kSolidStatic);
}
if (domain.Dynamic() != nullptr)
return Result<ProcedureKind>::Success(ProcedureKind::kHhtDynamic);
if (domain.Steps()[0U].IsFrequency())
return Result<ProcedureKind>::Success(ProcedureKind::kLinearFrequency);
if (domain.Steps()[0U].IsNonlinearStatic())
return Result<ProcedureKind>::Success(ProcedureKind::kNonlinearStatic);
return Result<ProcedureKind>::Success(ProcedureKind::kLinearStatic);
}
template <typename Payload>
Result<PreparedAnalysisOutcome> Completed(Result<Payload> result) {
if (!result.HasValue())
return Result<PreparedAnalysisOutcome>::Failure(result.GetStatus());
return Result<PreparedAnalysisOutcome>::Success(
PreparedAnalysisOutcome{std::move(result.Value())});
}
Result<PreparedAnalysisOutcome>
MissingExecutor(const char* code, const char* keyword, const char* message) {
return Result<PreparedAnalysisOutcome>::Failure(
Status::Failure(FailureCategory::kSolver,
{{Severity::kError, code, {}, keyword, {}, message}}));
}
} // namespace
Result<PreparedAnalysisOutcome>
LinearStaticProcedure::Execute(const Domain& domain) {
return Completed(executor_.Execute(domain));
}
Result<PreparedAnalysisOutcome>
NonlinearStaticProcedure::Execute(const Domain& domain) {
return Completed(executor_.Execute(domain, log_));
}
Result<PreparedAnalysisOutcome>
LinearFrequencyProcedure::Execute(const Domain& domain) {
return Completed(executor_.Execute(domain));
}
Result<PreparedAnalysisOutcome>
HhtDynamicProcedure::Execute(const Domain& domain) {
return Completed(executor_.Execute(domain, log_));
}
Result<PreparedAnalysisOutcome>
SolidStaticProcedure::Execute(const Domain& domain) {
SolidStaticState state;
const Status execution = executor_.ExecuteInto(domain, state);
for (const auto& record : state.IterationRecords()) {
const Status written = log_.Write(record, domain.Steps()[0U].Name());
if (!written.IsOk())
return Result<PreparedAnalysisOutcome>::Failure(written);
}
if (!execution.IsOk())
return Result<PreparedAnalysisOutcome>::Failure(execution);
return Result<PreparedAnalysisOutcome>::Success(PreparedAnalysisOutcome{
SolidStaticExecutionResult{std::move(state), domain.Warnings()}});
}
Result<PreparedAnalysisOutcome>
SolidFrequencyProcedure::Execute(const Domain& domain) {
return Completed(executor_.Execute(domain));
}
Result<PreparedAnalysisOutcome>
SolidHhtDynamicProcedure::Execute(const Domain& domain) {
auto model = AnalysisModel::Create(domain);
if (!model.HasValue())
return Result<PreparedAnalysisOutcome>::Failure(model.GetStatus());
auto dofs = DofManager::Create(model.Value());
if (!dofs.HasValue())
return Result<PreparedAnalysisOutcome>::Failure(dofs.GetStatus());
auto state = SolidDynamicAnalysisState::Create(domain, dofs.Value());
if (!state.HasValue())
return Result<PreparedAnalysisOutcome>::Failure(state.GetStatus());
const Status execution = executor_.ExecuteInto(domain, state.Value());
for (const auto& record : state.Value().IterationRecords()) {
const Status written = log_.Write(record);
if (!written.IsOk())
return Result<PreparedAnalysisOutcome>::Failure(written);
}
if (!execution.IsOk())
return Result<PreparedAnalysisOutcome>::Failure(execution);
return Result<PreparedAnalysisOutcome>::Success(
PreparedAnalysisOutcome{SolidDynamicExecutionResult{
std::move(dofs.Value()), std::move(state.Value())}});
}
Result<PreparedAnalysisOutcome>
TransientHeatProcedure::Execute(const Domain& domain) {
return Completed(executor_.Execute(domain));
}
Result<std::unique_ptr<AnalysisProcedure>> CreateAnalysisProcedure(
const Domain& domain, const ParallelFor& parallel_for,
LinearSolver& linear_solver, TangentSolver& tangent_solver,
const EigenSolver& eigen_solver, NewtonIterationLogWriter& log) {
const auto kind = SelectProcedure(domain);
if (!kind.HasValue())
return Result<std::unique_ptr<AnalysisProcedure>>::Failure(
kind.GetStatus());
std::unique_ptr<AnalysisProcedure> procedure;
switch (kind.Value()) {
case ProcedureKind::kLinearStatic:
procedure =
std::make_unique<LinearStaticProcedure>(parallel_for, linear_solver);
break;
case ProcedureKind::kNonlinearStatic:
procedure = std::make_unique<NonlinearStaticProcedure>(parallel_for,
tangent_solver, log);
break;
case ProcedureKind::kLinearFrequency:
procedure = std::make_unique<LinearFrequencyProcedure>(eigen_solver);
break;
case ProcedureKind::kHhtDynamic:
procedure = std::make_unique<HhtDynamicProcedure>(
parallel_for, linear_solver, tangent_solver, log);
break;
case ProcedureKind::kSolidStatic:
procedure = std::make_unique<SolidStaticProcedure>(
parallel_for, linear_solver, tangent_solver, log);
break;
case ProcedureKind::kSolidFrequency:
procedure = std::make_unique<SolidFrequencyProcedure>(eigen_solver);
break;
case ProcedureKind::kSolidHhtDynamic:
procedure = std::make_unique<SolidHhtDynamicProcedure>(
parallel_for, linear_solver, tangent_solver, log);
break;
case ProcedureKind::kTransientHeat:
procedure =
std::make_unique<TransientHeatProcedure>(parallel_for, linear_solver);
break;
}
return Result<std::unique_ptr<AnalysisProcedure>>::Success(
std::move(procedure));
}
Result<PreparedAnalysisOutcome>
ExecutePreparedAnalysis(const Domain& domain, AnalysisProcedure& procedure) {
return procedure.Execute(domain);
}
Result<PreparedAnalysisOutcome> ExecutePreparedAnalysis(
const Domain& domain, LinearStaticProcedureExecutor& linear_executor,
NonlinearStaticProcedureExecutor& nonlinear_executor,
const LinearFrequencyProcedureExecutor& frequency_executor,
NewtonIterationLogWriter& log,
const HhtDynamicProcedureExecutor* dynamic_executor,
const TransientHeatProcedureExecutor* thermal_executor,
const SolidStaticProcedureExecutor* solid_static_executor,
const SolidFrequencyProcedureExecutor* solid_frequency_executor,
const SolidHhtDynamicProcedureExecutor* solid_dynamic_executor) {
const auto kind = SelectProcedure(domain);
if (!kind.HasValue())
return Result<PreparedAnalysisOutcome>::Failure(kind.GetStatus());
std::unique_ptr<AnalysisProcedure> procedure;
switch (kind.Value()) {
case ProcedureKind::kLinearStatic:
procedure = std::make_unique<LinearStaticProcedure>(linear_executor);
break;
case ProcedureKind::kNonlinearStatic:
procedure =
std::make_unique<NonlinearStaticProcedure>(nonlinear_executor, log);
break;
case ProcedureKind::kLinearFrequency:
procedure = std::make_unique<LinearFrequencyProcedure>(frequency_executor);
break;
case ProcedureKind::kHhtDynamic:
if (dynamic_executor == nullptr)
return MissingExecutor("missing-dynamic-executor", "DYNAMIC",
"Dynamic execution adapter is required.");
procedure = std::make_unique<HhtDynamicProcedure>(*dynamic_executor, log);
break;
case ProcedureKind::kSolidStatic:
if (solid_static_executor == nullptr)
return MissingExecutor(
"missing-solid-executor", "",
"The selected Solid execution adapter is required.");
procedure =
std::make_unique<SolidStaticProcedure>(*solid_static_executor, log);
break;
case ProcedureKind::kSolidFrequency:
if (solid_frequency_executor == nullptr)
return MissingExecutor(
"missing-solid-executor", "",
"The selected Solid execution adapter is required.");
procedure =
std::make_unique<SolidFrequencyProcedure>(*solid_frequency_executor);
break;
case ProcedureKind::kSolidHhtDynamic:
if (solid_dynamic_executor == nullptr)
return MissingExecutor(
"missing-solid-executor", "",
"The selected Solid execution adapter is required.");
procedure = std::make_unique<SolidHhtDynamicProcedure>(
*solid_dynamic_executor, log);
break;
case ProcedureKind::kTransientHeat:
if (thermal_executor == nullptr)
return MissingExecutor("missing-thermal-executor", "HEAT TRANSFER",
"Thermal execution adapter is required.");
procedure = std::make_unique<TransientHeatProcedure>(*thermal_executor);
break;
}
return ExecutePreparedAnalysis(domain, *procedure);
}
Status FinalizePreparedAnalysisResult(
const DerivedOutputPaths& paths, const Domain& domain,
const PreparedAnalysisOutcome& outcome,
const std::vector<Diagnostic>& diagnostics, ResultsWriter& linear_writer,
NonlinearResultsWriter& nonlinear_writer, EigenResultsWriter& eigen_writer,
DynamicResultsWriter* dynamic_writer, ThermalResultsWriter* thermal_writer,
SolidResultsWriter* solid_writer) {
return WritePreparedAnalysisResult(
paths.results_path, domain, outcome, diagnostics, linear_writer,
nonlinear_writer, eigen_writer, dynamic_writer, thermal_writer,
solid_writer);
}
} // namespace fesa