#pragma once #include "fesa/Assembly/Assembly.hpp" #include "fesa/Core/Core.hpp" #include "fesa/IO/IO.hpp" #include "fesa/Math/Math.hpp" #include "fesa/Results/Results.hpp" #include "fesa/Util/Diagnostics.hpp" #include #include namespace fesa { struct AnalysisResult { AnalysisModel model; AnalysisState state; ResultFile result_file; std::vector diagnostics; bool ok() const { return !hasError(diagnostics); } }; class Analysis { public: virtual ~Analysis() = default; AnalysisResult run(const Domain& domain) const { AnalysisResult result; initialize(domain, result); if (hasError(result.diagnostics)) { return result; } solve(domain, result); return result; } protected: virtual void initialize(const Domain& domain, AnalysisResult& result) const { auto diagnostics = validateDomain(domain); result.diagnostics.insert(result.diagnostics.end(), diagnostics.begin(), diagnostics.end()); } virtual void solve(const Domain& domain, AnalysisResult& result) const = 0; }; class LinearStaticAnalysis final : public Analysis { public: explicit LinearStaticAnalysis(const LinearSolver* solver = nullptr) : solver_(solver) {} protected: void solve(const Domain& domain, AnalysisResult& result) const override { result.model = buildLinearStaticAnalysisModel(domain); result.diagnostics.insert(result.diagnostics.end(), result.model.diagnostics.begin(), result.model.diagnostics.end()); if (hasError(result.diagnostics)) { return; } DofManager dofs(domain); if (dofs.freeDofCount() == 0) { result.diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-SINGULAR-NO-FREE-DOFS", "No free DOFs exist after applying constraints", "dof")); return; } AssemblyResult assembly = assembleSystem(domain, dofs); result.diagnostics.insert(result.diagnostics.end(), assembly.diagnostics.begin(), assembly.diagnostics.end()); if (hasError(result.diagnostics)) { return; } const auto reduced = projectToReducedSystem(assembly, dofs); result.diagnostics.insert(result.diagnostics.end(), reduced.diagnostics.begin(), reduced.diagnostics.end()); if (hasError(result.diagnostics)) { return; } const LinearSolver& active_solver = solver_ == nullptr ? defaultSolver() : *solver_; SolveResult solved = active_solver.solve(reduced.k, reduced.f); result.diagnostics.insert(result.diagnostics.end(), solved.diagnostics.begin(), solved.diagnostics.end()); if (!solved.ok()) { return; } if (static_cast(solved.x.size()) != dofs.freeDofCount()) { result.diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-SOLVER-SIZE", "Linear solver returned a vector with the wrong size", "solver")); return; } result.state.u_full = dofs.reconstructFullVector(solved.x); result.state.f_external_full = assembly.f_full; result.state.f_internal_full = assembly.k_full.multiply(result.state.u_full); result.state.reaction_full = recoverFullReaction(assembly.k_full, result.state.u_full, result.state.f_external_full); result.state.converged = true; InMemoryResultsWriter writer; writer.writeLinearStatic(domain, result.model, dofs, result.state.u_full, result.state.reaction_full); result.result_file = writer.result(); } private: static const LinearSolver& defaultSolver() { static const GaussianEliminationSolver solver; return solver; } const LinearSolver* solver_ = nullptr; }; inline AnalysisResult runLinearStaticInputString(const std::string& text, const std::string& source_name = "", const LinearSolver* solver = nullptr) { AbaqusInputParser parser; const auto parsed = parser.parseString(text, source_name); if (!parsed.ok()) { AnalysisResult result; result.diagnostics = parsed.diagnostics; return result; } LinearStaticAnalysis analysis(solver); return analysis.run(parsed.domain); } } // namespace fesa