#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace fesa { namespace { AnalysisRunResult failure(std::vector diagnostics) { return {false, std::nullopt, std::move(diagnostics)}; } AnalysisRunResult equation_failure( std::string code, std::string message) { return failure({{ DiagnosticStage::equation, Severity::error, std::move(code), std::move(message), std::nullopt, }}); } NodalFrame build_nodal_frame( const Domain& domain, const DofManager& dofs, const std::vector& displacement, const std::vector& reaction) { std::vector node_ids; node_ids.reserve(domain.nodes().size()); for (const Node& node : domain.nodes()) { node_ids.push_back(node.id); } std::ranges::sort(node_ids); NodalFrame nodal; nodal.node_ids = std::move(node_ids); nodal.displacement.reserve(nodal.node_ids.size()); nodal.reaction.reserve(nodal.node_ids.size()); for (const NodeId node_id : nodal.node_ids) { std::array node_displacement{}; std::array node_reaction{}; for (std::size_t component = 0; component < 6; ++component) { const std::size_t full_dof = dofs.full_dof({ node_id, static_cast(component), }); node_displacement[component] = displacement[full_dof]; node_reaction[component] = reaction[full_dof]; } nodal.displacement.push_back(node_displacement); nodal.reaction.push_back(node_reaction); } return nodal; } } // namespace AnalysisRunResult LinearStaticAnalysis::run(const Domain& domain) const { const DofManager dofs = DofManager::build(domain); std::optional original; try { original = assemble_serial(domain, dofs); } catch (const std::exception& error) { return equation_failure( "equation.assembly_failed", error.what()); } ConstraintResult constrained = eliminate_essential_bcs(*original, dofs); if (!constrained.reduced_system.has_value()) { return failure(std::move(constrained.diagnostics)); } std::vector reduced_solution; if (dofs.free_equation_count() != 0) { PardisoLinearSolver solver; LinearSolveResult solved = solver.solve( constrained.reduced_system->stiffness, constrained.reduced_system->force); if (!solved.diagnostics.empty()) { return failure(std::move(solved.diagnostics)); } reduced_solution = std::move(solved.solution); } std::vector displacement; try { displacement = dofs.reconstruct_full(reduced_solution); } catch (const std::exception& error) { return equation_failure( "equation.solution_reconstruction_failed", error.what()); } std::vector reaction; try { reaction = recover_reaction(*original, displacement); } catch (const std::exception& error) { return equation_failure( "equation.reaction_recovery_failed", error.what()); } ResultDatabase database{ "1.0.0", {{ domain.step().name, {{ 1.0, build_nodal_frame( domain, dofs, displacement, reaction), {}, }}, }}, }; Status status = validate_result_database(database); if (!status.succeeded) { return failure(std::move(status.diagnostics)); } return {true, std::move(database), {}}; } } // namespace fesa