feat(cpp-object-oriented-modular-refactoring): step 5 - solver-workflow-google-style
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#ifndef FESA_ANALYSIS_ANALYSIS_MODEL_H_
|
||||
#define FESA_ANALYSIS_ANALYSIS_MODEL_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Provides the active-step view into a non-owned Domain.
|
||||
/// @note The referenced Domain must outlive this object and retains all
|
||||
/// semantic ownership.
|
||||
class AnalysisModel {
|
||||
public:
|
||||
/// @brief Creates the sole active-step view for a valid Domain.
|
||||
/// @param domain Domain that remains alive for the returned view's lifetime.
|
||||
/// @return A stable view or an input-cardinality failure.
|
||||
static Result<AnalysisModel> Create(const Domain& domain);
|
||||
|
||||
/// @brief Returns the non-owned Domain backing this view.
|
||||
const Domain& GetDomain() const noexcept;
|
||||
|
||||
/// @brief Returns the sole active static step.
|
||||
const StaticStepDefinition& Step() const noexcept;
|
||||
|
||||
/// @brief Returns active beam element indices in stable internal order.
|
||||
const std::vector<EntityIndex>& ActiveElements() const noexcept;
|
||||
|
||||
/// @brief Returns reachable material indices in stable internal order.
|
||||
const std::vector<EntityIndex>& ActiveMaterials() const noexcept;
|
||||
|
||||
/// @brief Returns reachable beam-section indices in stable internal order.
|
||||
const std::vector<EntityIndex>& ActiveSections() const noexcept;
|
||||
|
||||
/// @brief Returns boundary-condition indices in source order.
|
||||
const std::vector<EntityIndex>& ActiveBoundaryConditions() const noexcept;
|
||||
|
||||
/// @brief Returns concentrated-load indices in source order.
|
||||
const std::vector<EntityIndex>& ActiveLoads() const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Builds stable indices without copying the referenced Domain.
|
||||
explicit AnalysisModel(const Domain& domain);
|
||||
|
||||
const Domain* domain_;
|
||||
std::vector<EntityIndex> active_elements_;
|
||||
std::vector<EntityIndex> active_materials_;
|
||||
std::vector<EntityIndex> active_sections_;
|
||||
std::vector<EntityIndex> active_boundary_conditions_;
|
||||
std::vector<EntityIndex> active_loads_;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_ANALYSIS_ANALYSIS_MODEL_H_
|
||||
@@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
// Provides the sole active-step view while the referenced Domain retains all
|
||||
// semantic ownership and must outlive this object.
|
||||
class AnalysisModel {
|
||||
public:
|
||||
static Result<AnalysisModel> create(const Domain& domain);
|
||||
|
||||
const Domain& domain() const noexcept;
|
||||
const StaticStepDefinition& step() const noexcept;
|
||||
const std::vector<EntityIndex>& activeElements() const noexcept;
|
||||
const std::vector<EntityIndex>& activeMaterials() const noexcept;
|
||||
const std::vector<EntityIndex>& activeSections() const noexcept;
|
||||
const std::vector<EntityIndex>& activeBoundaryConditions() const noexcept;
|
||||
const std::vector<EntityIndex>& activeLoads() const noexcept;
|
||||
|
||||
private:
|
||||
explicit AnalysisModel(const Domain& domain);
|
||||
|
||||
const Domain* domain_;
|
||||
std::vector<EntityIndex> activeElements_;
|
||||
std::vector<EntityIndex> activeMaterials_;
|
||||
std::vector<EntityIndex> activeSections_;
|
||||
std::vector<EntityIndex> activeBoundaryConditions_;
|
||||
std::vector<EntityIndex> activeLoads_;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef FESA_ANALYSIS_ANALYSIS_STATE_H_
|
||||
#define FESA_ANALYSIS_ANALYSIS_STATE_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/math/vector.h"
|
||||
#include "fesa/results/result_records.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Owns mutable quantities required by the V0 linear-static frame.
|
||||
class AnalysisState {
|
||||
public:
|
||||
/// @brief Allocates zeroed full-DOF vectors for a DOF manager.
|
||||
/// @param dofs Owner of the full-DOF dimension used by every state vector.
|
||||
/// @param identity Stable step and frame identity for this state.
|
||||
static AnalysisState Create(const DofManager& dofs,
|
||||
StepFrameIdentity identity);
|
||||
|
||||
/// @brief Returns mutable full-space displacement.
|
||||
Vector& Displacement() noexcept;
|
||||
/// @brief Returns full-space displacement.
|
||||
const Vector& Displacement() const noexcept;
|
||||
/// @brief Returns mutable full-space external force.
|
||||
Vector& ExternalForce() noexcept;
|
||||
/// @brief Returns full-space external force.
|
||||
const Vector& ExternalForce() const noexcept;
|
||||
/// @brief Returns mutable full-space internal force.
|
||||
Vector& InternalForce() noexcept;
|
||||
/// @brief Returns full-space internal force.
|
||||
const Vector& InternalForce() const noexcept;
|
||||
/// @brief Returns mutable full residual K*d-F.
|
||||
Vector& Residual() noexcept;
|
||||
/// @brief Returns full residual K*d-F.
|
||||
const Vector& Residual() const noexcept;
|
||||
/// @brief Returns mutable full-index reaction and free residual evidence.
|
||||
Vector& Reaction() noexcept;
|
||||
/// @brief Returns full-index reaction and free residual evidence.
|
||||
const Vector& Reaction() const noexcept;
|
||||
/// @brief Returns the stable step and frame identity.
|
||||
const StepFrameIdentity& Identity() const noexcept;
|
||||
/// @brief Returns mutable beam endpoint result rows.
|
||||
std::vector<EndpointResultRow>& EndpointResults() noexcept;
|
||||
/// @brief Returns beam endpoint result rows.
|
||||
const std::vector<EndpointResultRow>& EndpointResults() const noexcept;
|
||||
/// @brief Returns mutable beam Gauss result rows.
|
||||
std::vector<GaussResultRow>& GaussResults() noexcept;
|
||||
/// @brief Returns beam Gauss result rows.
|
||||
const std::vector<GaussResultRow>& GaussResults() const noexcept;
|
||||
/// @brief Returns mutable beam axial-stress rows.
|
||||
std::vector<StressS11Row>& StressResults() noexcept;
|
||||
/// @brief Returns beam axial-stress rows.
|
||||
const std::vector<StressS11Row>& StressResults() const noexcept;
|
||||
|
||||
/// @brief Validates and atomically replaces all shell recovery evidence.
|
||||
/// @param expected_element_order Unique shell indices in stable order.
|
||||
/// @param candidate Complete shell rows, energy, and equilibrium evidence.
|
||||
/// @return Success only after the complete candidate is validated and
|
||||
/// committed; failure preserves the prior shell state.
|
||||
Status CommitShellResults(
|
||||
const std::vector<EntityIndex>& expected_element_order,
|
||||
ShellStateCandidate candidate);
|
||||
|
||||
/// @brief Returns shell rows in stable element and location order.
|
||||
const std::vector<ShellResultRow>& ShellResults() const noexcept;
|
||||
/// @brief Returns physical shell strain energy without drilling energy.
|
||||
double PhysicalStrainEnergy() const noexcept;
|
||||
/// @brief Returns global force and moment equilibrium components.
|
||||
const std::array<double, 6>& Equilibrium() const noexcept;
|
||||
/// @brief Returns normalized shell verification metrics.
|
||||
const std::array<double, 3>& VerificationMetrics() const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Allocates state storage for one stable full-DOF dimension.
|
||||
AnalysisState(std::size_t full_dof_count, StepFrameIdentity identity);
|
||||
|
||||
StepFrameIdentity identity_;
|
||||
Vector displacement_;
|
||||
Vector external_force_;
|
||||
Vector internal_force_;
|
||||
Vector residual_;
|
||||
// Reactions retain full-index space so free residual components remain
|
||||
// visible.
|
||||
Vector reaction_;
|
||||
// Recovery appends rows in stable element/location order.
|
||||
std::vector<EndpointResultRow> endpoint_results_;
|
||||
std::vector<GaussResultRow> gauss_results_;
|
||||
std::vector<StressS11Row> stress_results_;
|
||||
// Shell recovery is replaced only through validated candidate commit.
|
||||
std::vector<ShellResultRow> shell_results_;
|
||||
double physical_strain_energy_{0.0};
|
||||
std::array<double, 6> equilibrium_{};
|
||||
std::array<double, 3> verification_metrics_{};
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_ANALYSIS_ANALYSIS_STATE_H_
|
||||
@@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/fem/dof_manager.hpp"
|
||||
#include "fesa/math/vector.h"
|
||||
#include "fesa/results/result_records.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
// Owns only the mutable quantities required by the V0 linear-static frame.
|
||||
class AnalysisState {
|
||||
public:
|
||||
static AnalysisState create(
|
||||
const DofManager& dofs, StepFrameIdentity identity);
|
||||
|
||||
Vector& displacement() noexcept;
|
||||
const Vector& displacement() const noexcept;
|
||||
Vector& externalForce() noexcept;
|
||||
const Vector& externalForce() const noexcept;
|
||||
Vector& internalForce() noexcept;
|
||||
const Vector& internalForce() const noexcept;
|
||||
Vector& residual() noexcept;
|
||||
const Vector& residual() const noexcept;
|
||||
Vector& reaction() noexcept;
|
||||
const Vector& reaction() const noexcept;
|
||||
const StepFrameIdentity& identity() const noexcept;
|
||||
std::vector<EndpointResultRow>& endpointResults() noexcept;
|
||||
const std::vector<EndpointResultRow>& endpointResults() const noexcept;
|
||||
std::vector<GaussResultRow>& gaussResults() noexcept;
|
||||
const std::vector<GaussResultRow>& gaussResults() const noexcept;
|
||||
std::vector<StressS11Row>& stressResults() noexcept;
|
||||
const std::vector<StressS11Row>& stressResults() const noexcept;
|
||||
Status commitShellResults(
|
||||
const std::vector<EntityIndex>& expectedElementOrder,
|
||||
ShellStateCandidate candidate);
|
||||
const std::vector<ShellResultRow>& shellResults() const noexcept;
|
||||
double physicalStrainEnergy() const noexcept;
|
||||
const std::array<double, 6>& equilibrium() const noexcept;
|
||||
const std::array<double, 3>& verificationMetrics() const noexcept;
|
||||
|
||||
private:
|
||||
AnalysisState(std::size_t fullDofCount, StepFrameIdentity identity);
|
||||
|
||||
StepFrameIdentity identity_;
|
||||
Vector displacement_;
|
||||
Vector externalForce_;
|
||||
Vector internalForce_;
|
||||
Vector residual_;
|
||||
// Reactions retain full-index space so free residual components remain visible.
|
||||
Vector reaction_;
|
||||
// Recovery appends rows in stable element/location order.
|
||||
std::vector<EndpointResultRow> endpointResults_;
|
||||
std::vector<GaussResultRow> gaussResults_;
|
||||
std::vector<StressS11Row> stressResults_;
|
||||
// Shell recovery is replaced only through validated candidate commit.
|
||||
std::vector<ShellResultRow> shellResults_;
|
||||
double physicalStrainEnergy_{0.0};
|
||||
std::array<double, 6> equilibrium_{};
|
||||
std::array<double, 3> verificationMetrics_{};
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef FESA_ANALYSIS_LINEAR_STATIC_ANALYSIS_H_
|
||||
#define FESA_ANALYSIS_LINEAR_STATIC_ANALYSIS_H_
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/analysis/analysis_model.h"
|
||||
#include "fesa/analysis/analysis_state.h"
|
||||
#include "fesa/constraints/essential_constraints.h"
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
class LinearSolver;
|
||||
class ParallelFor;
|
||||
class ResultsWriter;
|
||||
|
||||
/// @brief Carries input and authoritative output paths for one analysis run.
|
||||
struct AnalysisRequest {
|
||||
std::filesystem::path input_path;
|
||||
std::filesystem::path output_path;
|
||||
};
|
||||
|
||||
/// @brief Executes the current approved V0 analysis lifecycle.
|
||||
class Analysis {
|
||||
public:
|
||||
virtual ~Analysis() = default;
|
||||
|
||||
/// @brief Runs the eight current lifecycle stages in their approved order.
|
||||
/// @param request Input and output paths for this run.
|
||||
/// @return The first stage failure or successful result finalization.
|
||||
Status Run(const AnalysisRequest& request);
|
||||
|
||||
protected:
|
||||
/// @brief Initializes owned input and Domain state for a run.
|
||||
virtual Status Initialize(const AnalysisRequest& request) = 0;
|
||||
/// @brief Builds the non-owning active-model view.
|
||||
virtual Status BuildAnalysisModel() = 0;
|
||||
/// @brief Builds stable DOF numbering and the sparse structural pattern.
|
||||
virtual Status BuildDofMapAndSparsePattern() = 0;
|
||||
/// @brief Assembles full stiffness and stable constraint partitions.
|
||||
virtual Status AssembleAndPartitionStiffness() = 0;
|
||||
/// @brief Factorizes Kff before any load assembly.
|
||||
virtual Status Factorize() = 0;
|
||||
/// @brief Assembles loads and forms Ff-Kfc*dc without solving.
|
||||
virtual Status AssembleLoadsAndEffectiveRhs() = 0;
|
||||
/// @brief Substitutes the retained factorization and reconstructs full d.
|
||||
virtual Status SubstituteAndReconstruct() = 0;
|
||||
/// @brief Recovers a complete candidate and writes authoritative results.
|
||||
virtual Status RecoverAndWriteResults() = 0;
|
||||
};
|
||||
|
||||
/// @brief Orchestrates the single-step linear-static procedure.
|
||||
/// @note Factorization, substitution, recovery, and writing remain separately
|
||||
/// observable through injected backend boundaries.
|
||||
class LinearStaticAnalysis final : public Analysis {
|
||||
public:
|
||||
/// @brief Creates a procedure using non-owned backend adapters.
|
||||
/// @note All three adapters must outlive this analysis object.
|
||||
LinearStaticAnalysis(const ParallelFor& parallel_for,
|
||||
LinearSolver& linear_solver,
|
||||
ResultsWriter& results_writer);
|
||||
|
||||
protected:
|
||||
/// @copydoc Analysis::Initialize
|
||||
Status Initialize(const AnalysisRequest& request) override;
|
||||
/// @copydoc Analysis::BuildAnalysisModel
|
||||
Status BuildAnalysisModel() override;
|
||||
/// @copydoc Analysis::BuildDofMapAndSparsePattern
|
||||
Status BuildDofMapAndSparsePattern() override;
|
||||
/// @copydoc Analysis::AssembleAndPartitionStiffness
|
||||
Status AssembleAndPartitionStiffness() override;
|
||||
/// @copydoc Analysis::Factorize
|
||||
Status Factorize() override;
|
||||
/// @copydoc Analysis::AssembleLoadsAndEffectiveRhs
|
||||
Status AssembleLoadsAndEffectiveRhs() override;
|
||||
/// @copydoc Analysis::SubstituteAndReconstruct
|
||||
Status SubstituteAndReconstruct() override;
|
||||
/// @copydoc Analysis::RecoverAndWriteResults
|
||||
Status RecoverAndWriteResults() override;
|
||||
|
||||
private:
|
||||
const ParallelFor& parallel_for_;
|
||||
LinearSolver& linear_solver_;
|
||||
ResultsWriter& results_writer_;
|
||||
AnalysisRequest request_;
|
||||
std::unique_ptr<Domain> domain_;
|
||||
std::unique_ptr<AnalysisModel> model_;
|
||||
std::unique_ptr<DofManager> dofs_;
|
||||
std::unique_ptr<AnalysisState> state_;
|
||||
std::unique_ptr<SparseMatrix> full_stiffness_;
|
||||
std::unique_ptr<PartitionedStiffness> partitioned_stiffness_;
|
||||
std::unique_ptr<Vector> effective_rhs_;
|
||||
std::vector<Diagnostic> diagnostics_;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_ANALYSIS_LINEAR_STATIC_ANALYSIS_H_
|
||||
@@ -1,78 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/analysis/analysis_model.hpp"
|
||||
#include "fesa/analysis/analysis_state.hpp"
|
||||
#include "fesa/constraints/essential_constraints.hpp"
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/fem/dof_manager.hpp"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
class LinearSolver;
|
||||
class ParallelFor;
|
||||
class ResultsWriter;
|
||||
|
||||
struct AnalysisRequest {
|
||||
std::filesystem::path inputPath;
|
||||
std::filesystem::path outputPath;
|
||||
};
|
||||
|
||||
// Fixes the public V0 lifecycle while leaving each analysis procedure to
|
||||
// implement its approved stages.
|
||||
class Analysis {
|
||||
public:
|
||||
virtual ~Analysis() = default;
|
||||
Status run(const AnalysisRequest& request);
|
||||
|
||||
protected:
|
||||
virtual Status initialize(const AnalysisRequest& request) = 0;
|
||||
virtual Status buildAnalysisModel() = 0;
|
||||
virtual Status buildDofMapAndSparsePattern() = 0;
|
||||
virtual Status assembleAndPartitionStiffness() = 0;
|
||||
virtual Status factorize() = 0;
|
||||
virtual Status assembleLoadsAndEffectiveRhs() = 0;
|
||||
virtual Status substituteAndReconstruct() = 0;
|
||||
virtual Status recoverAndWriteResults() = 0;
|
||||
};
|
||||
|
||||
// Orchestrates the single-step B33 procedure through injected backend
|
||||
// boundaries so factorization and substitution remain independently visible.
|
||||
class LinearStaticAnalysis final : public Analysis {
|
||||
public:
|
||||
LinearStaticAnalysis(const ParallelFor& parallelFor,
|
||||
LinearSolver& linearSolver,
|
||||
ResultsWriter& resultsWriter);
|
||||
|
||||
protected:
|
||||
Status initialize(const AnalysisRequest& request) override;
|
||||
Status buildAnalysisModel() override;
|
||||
Status buildDofMapAndSparsePattern() override;
|
||||
Status assembleAndPartitionStiffness() override;
|
||||
Status factorize() override;
|
||||
Status assembleLoadsAndEffectiveRhs() override;
|
||||
Status substituteAndReconstruct() override;
|
||||
Status recoverAndWriteResults() override;
|
||||
|
||||
private:
|
||||
const ParallelFor& parallelFor_;
|
||||
LinearSolver& linearSolver_;
|
||||
ResultsWriter& resultsWriter_;
|
||||
AnalysisRequest request_;
|
||||
std::unique_ptr<Domain> domain_;
|
||||
std::unique_ptr<AnalysisModel> model_;
|
||||
std::unique_ptr<DofManager> dofs_;
|
||||
std::unique_ptr<AnalysisState> state_;
|
||||
std::unique_ptr<SparseMatrix> fullStiffness_;
|
||||
std::unique_ptr<PartitionedStiffness> partitionedStiffness_;
|
||||
std::unique_ptr<Vector> effectiveRhs_;
|
||||
std::vector<Diagnostic> diagnostics_;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef FESA_ASSEMBLY_LOAD_ASSEMBLER_H_
|
||||
#define FESA_ASSEMBLY_LOAD_ASSEMBLER_H_
|
||||
|
||||
#include "fesa/analysis/analysis_model.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Assembles semantic nodal loads in stable source order.
|
||||
class LoadAssembler {
|
||||
public:
|
||||
/// @brief Accumulates all active CLOAD rows in full-DOF space.
|
||||
/// @return A finite full load vector or a structured model failure.
|
||||
static Result<Vector> AssembleFullNodalLoad(const AnalysisModel& model,
|
||||
const DofManager& dofs);
|
||||
|
||||
/// @brief Forms Ff-Kfc*dc in stable free/constrained order.
|
||||
/// @note This operation neither factorizes nor invokes a solver.
|
||||
static Result<Vector> EffectiveFreeRhs(const Vector& full_load,
|
||||
const SparseMatrix& kfc,
|
||||
const Vector& prescribed_values,
|
||||
const DofManager& dofs);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_ASSEMBLY_LOAD_ASSEMBLER_H_
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/analysis/analysis_model.hpp"
|
||||
#include "fesa/fem/dof_manager.hpp"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
// Assembles only semantic nodal CLOAD records and forms the eliminated free
|
||||
// right-hand side; stiffness factorization remains an analysis responsibility.
|
||||
class LoadAssembler {
|
||||
public:
|
||||
static Result<Vector> assembleFullNodalLoad(
|
||||
const AnalysisModel& model,
|
||||
const DofManager& dofs);
|
||||
static Result<Vector> effectiveFreeRhs(
|
||||
const Vector& fullLoad,
|
||||
const SparseMatrix& kfc,
|
||||
const Vector& prescribedValues,
|
||||
const DofManager& dofs);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef FESA_ASSEMBLY_PARALLEL_FOR_H_
|
||||
#define FESA_ASSEMBLY_PARALLEL_FOR_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Executes independent index-addressed work behind a backend boundary.
|
||||
/// @note Callers own output storage and each invocation may write only its
|
||||
/// index-owned slot.
|
||||
class ParallelFor {
|
||||
public:
|
||||
virtual ~ParallelFor() = default;
|
||||
|
||||
/// @brief Invokes body once for every index in [0, count).
|
||||
virtual void Execute(std::size_t count,
|
||||
const std::function<void(std::size_t)>& body) const = 0;
|
||||
};
|
||||
|
||||
/// @brief Executes index-addressed work serially.
|
||||
class SerialParallelFor final : public ParallelFor {
|
||||
public:
|
||||
/// @copydoc ParallelFor::Execute
|
||||
void Execute(std::size_t count,
|
||||
const std::function<void(std::size_t)>& body) const override;
|
||||
};
|
||||
|
||||
/// @brief Executes index-addressed work through oneTBB.
|
||||
class TbbParallelFor final : public ParallelFor {
|
||||
public:
|
||||
/// @copydoc ParallelFor::Execute
|
||||
void Execute(std::size_t count,
|
||||
const std::function<void(std::size_t)>& body) const override;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_ASSEMBLY_PARALLEL_FOR_H_
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
// Executes independent index-addressed work without exposing the backend.
|
||||
// Callers own output storage and must confine each invocation to its index.
|
||||
class ParallelFor {
|
||||
public:
|
||||
virtual ~ParallelFor() = default;
|
||||
virtual void execute(
|
||||
std::size_t count,
|
||||
const std::function<void(std::size_t)>& body) const = 0;
|
||||
};
|
||||
|
||||
class SerialParallelFor final : public ParallelFor {
|
||||
public:
|
||||
void execute(
|
||||
std::size_t count,
|
||||
const std::function<void(std::size_t)>& body) const override;
|
||||
};
|
||||
|
||||
class TbbParallelFor final : public ParallelFor {
|
||||
public:
|
||||
void execute(
|
||||
std::size_t count,
|
||||
const std::function<void(std::size_t)>& body) const override;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef FESA_ASSEMBLY_SPARSE_ASSEMBLER_H_
|
||||
#define FESA_ASSEMBLY_SPARSE_ASSEMBLER_H_
|
||||
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
class AnalysisModel;
|
||||
class DofManager;
|
||||
class ParallelFor;
|
||||
|
||||
/// @brief Owns deterministic element-contribution reduction into global CSR.
|
||||
class SparseAssembler {
|
||||
public:
|
||||
/// @brief Assembles stiffness in stable source-element and local-entry order.
|
||||
/// @return A validated full-DOF CSR matrix or structured model failure.
|
||||
/// @note Parallel workers produce index-owned local buffers; serial reduction
|
||||
/// remains the sole global CSR writer.
|
||||
static Result<SparseMatrix> AssembleStiffness(
|
||||
const AnalysisModel& model, const DofManager& dofs,
|
||||
const ParallelFor& parallel_for);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_ASSEMBLY_SPARSE_ASSEMBLER_H_
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
class AnalysisModel;
|
||||
class DofManager;
|
||||
class ParallelFor;
|
||||
|
||||
class SparseAssembler {
|
||||
public:
|
||||
static Result<SparseMatrix> assembleStiffness(
|
||||
const AnalysisModel& model,
|
||||
const DofManager& dofs,
|
||||
const ParallelFor& parallelFor);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef FESA_CONSTRAINTS_ESSENTIAL_CONSTRAINTS_H_
|
||||
#define FESA_CONSTRAINTS_ESSENTIAL_CONSTRAINTS_H_
|
||||
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
class DofManager;
|
||||
|
||||
/// @brief Stores full-stiffness blocks in stable free/constrained order.
|
||||
struct PartitionedStiffness {
|
||||
SparseMatrix kff;
|
||||
SparseMatrix kfc;
|
||||
SparseMatrix kcf;
|
||||
SparseMatrix kcc;
|
||||
};
|
||||
|
||||
/// @brief Applies stable prescribed-displacement elimination.
|
||||
class EssentialConstraints {
|
||||
public:
|
||||
/// @brief Partitions full stiffness into Kff, Kfc, Kcf, and Kcc.
|
||||
static Result<PartitionedStiffness> Partition(const SparseMatrix& full,
|
||||
const DofManager& dofs);
|
||||
|
||||
/// @brief Gathers a full vector in stable free-equation order.
|
||||
static Vector GatherFree(const Vector& full, const DofManager& dofs);
|
||||
|
||||
/// @brief Gathers a full vector in stable constrained-DOF order.
|
||||
static Vector GatherConstrained(const Vector& full, const DofManager& dofs);
|
||||
|
||||
/// @brief Reconstructs full d from stable df and exact prescribed dc.
|
||||
static Vector ReconstructFull(const Vector& free_values,
|
||||
const Vector& constrained_values,
|
||||
const DofManager& dofs);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_CONSTRAINTS_ESSENTIAL_CONSTRAINTS_H_
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
class DofManager;
|
||||
|
||||
struct PartitionedStiffness {
|
||||
SparseMatrix kff;
|
||||
SparseMatrix kfc;
|
||||
SparseMatrix kcf;
|
||||
SparseMatrix kcc;
|
||||
};
|
||||
|
||||
// Applies the DofManager's stable elimination order without owning equation
|
||||
// numbering, load assembly, or a solver policy.
|
||||
class EssentialConstraints {
|
||||
public:
|
||||
static Result<PartitionedStiffness> partition(
|
||||
const SparseMatrix& full,
|
||||
const DofManager& dofs);
|
||||
static Vector gatherFree(const Vector& full, const DofManager& dofs);
|
||||
static Vector gatherConstrained(
|
||||
const Vector& full,
|
||||
const DofManager& dofs);
|
||||
static Vector reconstructFull(
|
||||
const Vector& freeValues,
|
||||
const Vector& constrainedValues,
|
||||
const DofManager& dofs);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifndef FESA_FEM_DOF_MANAGER_H_
|
||||
#define FESA_FEM_DOF_MANAGER_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/analysis/analysis_model.h"
|
||||
#include "fesa/math/vector.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Identifies one component in the stable six-DOF node layout.
|
||||
enum class DofComponent : std::uint8_t {
|
||||
kUx,
|
||||
kUy,
|
||||
kUz,
|
||||
kUrx,
|
||||
kUry,
|
||||
kUrz,
|
||||
};
|
||||
|
||||
/// @brief Stores the stable structural CSR pattern.
|
||||
struct SparsePattern {
|
||||
std::vector<std::size_t> row_offsets;
|
||||
std::vector<std::size_t> column_indices;
|
||||
};
|
||||
|
||||
/// @brief Owns full/free/constrained numbering, scatter maps, and CSR pattern.
|
||||
class DofManager {
|
||||
public:
|
||||
/// @brief Creates every equation-space mapping for an active model.
|
||||
static Result<DofManager> Create(const AnalysisModel& model);
|
||||
|
||||
/// @brief Returns the full node-by-component DOF count.
|
||||
std::size_t FullDofCount() const noexcept;
|
||||
/// @brief Returns the free-equation count.
|
||||
std::size_t FreeDofCount() const noexcept;
|
||||
/// @brief Returns the prescribed-DOF count.
|
||||
std::size_t ConstrainedDofCount() const noexcept;
|
||||
/// @brief Maps a stable node index and component to a full DOF.
|
||||
std::size_t FullDof(EntityIndex node, DofComponent component) const;
|
||||
/// @brief Returns the free equation for a full DOF when unconstrained.
|
||||
std::optional<std::size_t> FreeEquation(std::size_t full_dof) const;
|
||||
/// @brief Returns a beam scatter in endpoint/component order.
|
||||
const std::array<std::size_t, 12>& ElementScatter(EntityIndex element) const;
|
||||
/// @brief Returns a shell scatter in node/component order.
|
||||
const std::array<std::size_t, 24>& ShellElementScatter(
|
||||
EntityIndex element) const;
|
||||
/// @brief Returns free full DOFs in stable increasing order.
|
||||
const std::vector<std::size_t>& FreeDofs() const noexcept;
|
||||
/// @brief Returns constrained full DOFs in stable increasing order.
|
||||
const std::vector<std::size_t>& ConstrainedDofs() const noexcept;
|
||||
/// @brief Returns dc in constrained-DOF order.
|
||||
const Vector& PrescribedValues() const noexcept;
|
||||
/// @brief Returns the full-space structural CSR pattern.
|
||||
const SparsePattern& GetSparsePattern() const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Takes ownership of fully validated stable equation mappings.
|
||||
DofManager(std::size_t full_dof_count,
|
||||
std::vector<std::optional<std::size_t>> free_equations,
|
||||
std::vector<std::array<std::size_t, 12>> element_scatters,
|
||||
std::vector<std::array<std::size_t, 24>> shell_element_scatters,
|
||||
std::vector<std::size_t> free_dofs,
|
||||
std::vector<std::size_t> constrained_dofs,
|
||||
Vector prescribed_values, SparsePattern sparse_pattern);
|
||||
|
||||
std::size_t full_dof_count_;
|
||||
std::vector<std::optional<std::size_t>> free_equations_;
|
||||
std::vector<std::array<std::size_t, 12>> element_scatters_;
|
||||
std::vector<std::array<std::size_t, 24>> shell_element_scatters_;
|
||||
std::vector<std::size_t> free_dofs_;
|
||||
std::vector<std::size_t> constrained_dofs_;
|
||||
Vector prescribed_values_;
|
||||
SparsePattern sparse_pattern_;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_FEM_DOF_MANAGER_H_
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/analysis/analysis_model.hpp"
|
||||
#include "fesa/math/vector.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
enum class DofComponent : std::uint8_t {
|
||||
ux,
|
||||
uy,
|
||||
uz,
|
||||
urx,
|
||||
ury,
|
||||
urz
|
||||
};
|
||||
|
||||
struct SparsePattern {
|
||||
std::vector<std::size_t> rowOffsets;
|
||||
std::vector<std::size_t> columnIndices;
|
||||
};
|
||||
|
||||
// Owns every equation-space mapping so semantic model objects remain free of
|
||||
// analysis-specific equation IDs.
|
||||
class DofManager {
|
||||
public:
|
||||
static Result<DofManager> create(const AnalysisModel& model);
|
||||
|
||||
std::size_t fullDofCount() const noexcept;
|
||||
std::size_t freeDofCount() const noexcept;
|
||||
std::size_t constrainedDofCount() const noexcept;
|
||||
std::size_t fullDof(EntityIndex node, DofComponent component) const;
|
||||
std::optional<std::size_t> freeEquation(std::size_t fullDof) const;
|
||||
const std::array<std::size_t, 12>& elementScatter(
|
||||
EntityIndex element) const;
|
||||
const std::array<std::size_t, 24>& shellElementScatter(
|
||||
EntityIndex element) const;
|
||||
const std::vector<std::size_t>& freeDofs() const noexcept;
|
||||
const std::vector<std::size_t>& constrainedDofs() const noexcept;
|
||||
const Vector& prescribedValues() const noexcept;
|
||||
const SparsePattern& sparsePattern() const noexcept;
|
||||
|
||||
private:
|
||||
DofManager(
|
||||
std::size_t fullDofCount,
|
||||
std::vector<std::optional<std::size_t>> freeEquations,
|
||||
std::vector<std::array<std::size_t, 12>> elementScatters,
|
||||
std::vector<std::array<std::size_t, 24>> shellElementScatters,
|
||||
std::vector<std::size_t> freeDofs,
|
||||
std::vector<std::size_t> constrainedDofs,
|
||||
Vector prescribedValues,
|
||||
SparsePattern sparsePattern);
|
||||
|
||||
std::size_t fullDofCount_;
|
||||
std::vector<std::optional<std::size_t>> freeEquations_;
|
||||
std::vector<std::array<std::size_t, 12>> elementScatters_;
|
||||
std::vector<std::array<std::size_t, 24>> shellElementScatters_;
|
||||
std::vector<std::size_t> freeDofs_;
|
||||
std::vector<std::size_t> constrainedDofs_;
|
||||
Vector prescribedValues_;
|
||||
SparsePattern sparsePattern_;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/results/results_writer.hpp"
|
||||
#include "fesa/results/results_writer.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
// Writes schema-v0 output while keeping backend and platform types private.
|
||||
class Hdf5ResultsWriter final : public ResultsWriter {
|
||||
public:
|
||||
Status write(
|
||||
Status Write(
|
||||
const std::filesystem::path& outputPath,
|
||||
const Domain& domain,
|
||||
const AnalysisState& state,
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef FESA_RESULTS_RESULT_RECORDS_H_
|
||||
#define FESA_RESULTS_RESULT_RECORDS_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/model/model_types.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Identifies one deterministic result frame.
|
||||
struct StepFrameIdentity {
|
||||
std::string step_name;
|
||||
std::size_t frame_index;
|
||||
};
|
||||
|
||||
/// @brief Stores one beam endpoint action and section-resultant row.
|
||||
struct EndpointResultRow {
|
||||
EntityIndex element;
|
||||
int endpoint;
|
||||
SourceEntityId node;
|
||||
std::array<double, 6> end_action;
|
||||
std::array<double, 4> section_resultant;
|
||||
};
|
||||
|
||||
/// @brief Stores one beam Gauss generalized result row.
|
||||
struct GaussResultRow {
|
||||
EntityIndex element;
|
||||
int gauss_point;
|
||||
std::array<double, 4> generalized_strain;
|
||||
std::array<double, 4> generalized_resultant;
|
||||
};
|
||||
|
||||
/// @brief Stores one beam axial-stress section-point row.
|
||||
struct StressS11Row {
|
||||
EntityIndex element;
|
||||
int gauss_point;
|
||||
std::size_t section_point;
|
||||
double x1;
|
||||
double x2;
|
||||
double s11;
|
||||
std::string source;
|
||||
};
|
||||
|
||||
/// @brief Identifies one MITC4 midsurface integration location.
|
||||
enum class ShellMidsurfaceLocation { kGp1, kGp2, kGp3, kGp4 };
|
||||
|
||||
/// @brief Identifies one through-thickness shell recovery position.
|
||||
enum class ShellSectionPosition { kBottom, kMiddle, kTop };
|
||||
|
||||
/// @brief Stores one through-thickness shell stress row.
|
||||
struct ShellSectionStressRow {
|
||||
ShellSectionPosition position;
|
||||
double zeta;
|
||||
std::array<double, 3> components;
|
||||
};
|
||||
|
||||
/// @brief Stores one MITC4 physical recovery row.
|
||||
struct ShellResultRow {
|
||||
EntityIndex element;
|
||||
ShellMidsurfaceLocation location;
|
||||
std::array<double, 2> natural_coordinates;
|
||||
// Axis rows [e1,e2,e3], global-component columns.
|
||||
std::array<std::array<double, 3>, 3> local_frame;
|
||||
std::array<double, 8> generalized_strain;
|
||||
std::array<double, 8> section_resultant;
|
||||
// Fixed BOTTOM, MIDDLE, TOP order; components are [S11,S22,S12].
|
||||
std::array<ShellSectionStressRow, 3> stress;
|
||||
};
|
||||
|
||||
/// @brief Carries a complete shell result candidate for atomic validation.
|
||||
struct ShellStateCandidate {
|
||||
std::vector<ShellResultRow> rows;
|
||||
double physical_strain_energy{0.0};
|
||||
// [FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3].
|
||||
std::array<double, 6> equilibrium{};
|
||||
// [FREE_RESIDUAL_NORMALIZED,FORCE_BALANCE_NORMALIZED,
|
||||
// MOMENT_BALANCE_NORMALIZED].
|
||||
std::array<double, 3> verification_metrics{};
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_RESULTS_RESULT_RECORDS_H_
|
||||
@@ -1,83 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/model/model_types.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
struct StepFrameIdentity {
|
||||
std::string stepName;
|
||||
std::size_t frameIndex;
|
||||
};
|
||||
|
||||
struct EndpointResultRow {
|
||||
EntityIndex element;
|
||||
int endpoint;
|
||||
SourceEntityId node;
|
||||
std::array<double, 6> endAction;
|
||||
std::array<double, 4> sectionResultant;
|
||||
};
|
||||
|
||||
struct GaussResultRow {
|
||||
EntityIndex element;
|
||||
int gaussPoint;
|
||||
std::array<double, 4> generalizedStrain;
|
||||
std::array<double, 4> generalizedResultant;
|
||||
};
|
||||
|
||||
struct StressS11Row {
|
||||
EntityIndex element;
|
||||
int gaussPoint;
|
||||
std::size_t sectionPoint;
|
||||
double x1;
|
||||
double x2;
|
||||
double s11;
|
||||
std::string source;
|
||||
};
|
||||
|
||||
enum class ShellMidsurfaceLocation {
|
||||
gp1,
|
||||
gp2,
|
||||
gp3,
|
||||
gp4
|
||||
};
|
||||
|
||||
enum class ShellSectionPosition {
|
||||
bottom,
|
||||
middle,
|
||||
top
|
||||
};
|
||||
|
||||
struct ShellSectionStressRow {
|
||||
ShellSectionPosition position;
|
||||
double zeta;
|
||||
std::array<double, 3> components;
|
||||
};
|
||||
|
||||
struct ShellResultRow {
|
||||
EntityIndex element;
|
||||
ShellMidsurfaceLocation location;
|
||||
std::array<double, 2> naturalCoordinates;
|
||||
// Axis rows [e1,e2,e3], global-component columns.
|
||||
std::array<std::array<double, 3>, 3> localFrame;
|
||||
std::array<double, 8> generalizedStrain;
|
||||
std::array<double, 8> sectionResultant;
|
||||
// Fixed BOTTOM, MIDDLE, TOP order; components are [S11,S22,S12].
|
||||
std::array<ShellSectionStressRow, 3> stress;
|
||||
};
|
||||
|
||||
struct ShellStateCandidate {
|
||||
std::vector<ShellResultRow> rows;
|
||||
double physicalStrainEnergy{0.0};
|
||||
// [FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3].
|
||||
std::array<double, 6> equilibrium{};
|
||||
// [FREE_RESIDUAL_NORMALIZED,FORCE_BALANCE_NORMALIZED,
|
||||
// MOMENT_BALANCE_NORMALIZED].
|
||||
std::array<double, 3> verificationMetrics{};
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef FESA_RESULTS_RESULT_RECOVERY_H_
|
||||
#define FESA_RESULTS_RESULT_RECOVERY_H_
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/analysis/analysis_model.h"
|
||||
#include "fesa/analysis/analysis_state.h"
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Stores one normalized positive-local-x node-station row.
|
||||
struct NodeStationResultRow {
|
||||
SourceEntityId node;
|
||||
EntityIndex representative_element;
|
||||
std::array<double, 4> section_resultant;
|
||||
};
|
||||
|
||||
/// @brief Recovers full equilibrium and active concrete element rows.
|
||||
class ResultRecovery {
|
||||
public:
|
||||
/// @brief Builds and atomically commits a complete recovery candidate.
|
||||
/// @return Success after full residual K*d-F and all result rows validate.
|
||||
static Status Recover(const AnalysisModel& model, const DofManager& dofs,
|
||||
const SparseMatrix& full_stiffness,
|
||||
AnalysisState& state);
|
||||
|
||||
/// @brief Normalizes eligible endpoint rows to source node stations.
|
||||
/// @param component_tolerances Per-component interior-station tolerances.
|
||||
/// @return Stable source-node rows or a structured identity/value failure.
|
||||
static Result<std::vector<NodeStationResultRow>>
|
||||
NormalizeSectionResultantsToNodeStations(
|
||||
const AnalysisModel& model,
|
||||
const std::vector<EndpointResultRow>& endpoint_rows,
|
||||
const std::array<double, 4>& component_tolerances);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_RESULTS_RESULT_RECOVERY_H_
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/analysis/analysis_model.hpp"
|
||||
#include "fesa/analysis/analysis_state.hpp"
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/fem/dof_manager.hpp"
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
struct NodeStationResultRow {
|
||||
SourceEntityId node;
|
||||
EntityIndex representativeElement;
|
||||
std::array<double, 4> sectionResultant;
|
||||
};
|
||||
|
||||
// Recovers full-space equilibrium and the active concrete element rows without
|
||||
// exposing element or sparse-backend details to result consumers.
|
||||
class ResultRecovery {
|
||||
public:
|
||||
static Status recover(const AnalysisModel& model,
|
||||
const DofManager& dofs,
|
||||
const SparseMatrix& fullStiffness,
|
||||
AnalysisState& state);
|
||||
|
||||
static Result<std::vector<NodeStationResultRow>>
|
||||
normalizeSectionResultantsToNodeStations(
|
||||
const AnalysisModel& model,
|
||||
const std::vector<EndpointResultRow>& endpointRows,
|
||||
const std::array<double, 4>& componentTolerances);
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef FESA_RESULTS_RESULTS_WRITER_H_
|
||||
#define FESA_RESULTS_RESULTS_WRITER_H_
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/analysis/analysis_state.h"
|
||||
#include "fesa/core/diagnostic.h"
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
/// @brief Isolates authoritative result storage from the solver core.
|
||||
class ResultsWriter {
|
||||
public:
|
||||
virtual ~ResultsWriter() = default;
|
||||
|
||||
/// @brief Writes one complete validated analysis state.
|
||||
/// @return Success only after backend-specific finalization completes.
|
||||
virtual Status Write(const std::filesystem::path& output_path,
|
||||
const Domain& domain, const AnalysisState& state,
|
||||
const std::vector<Diagnostic>& diagnostics) = 0;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
#endif // FESA_RESULTS_RESULTS_WRITER_H_
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fesa/analysis/analysis_state.hpp"
|
||||
#include "fesa/core/diagnostic.h"
|
||||
#include "fesa/core/status.h"
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa {
|
||||
|
||||
// Keeps the solver core independent of the authoritative result-storage backend.
|
||||
class ResultsWriter {
|
||||
public:
|
||||
virtual ~ResultsWriter() = default;
|
||||
|
||||
virtual Status write(
|
||||
const std::filesystem::path& outputPath,
|
||||
const Domain& domain,
|
||||
const AnalysisState& state,
|
||||
const std::vector<Diagnostic>& diagnostics) = 0;
|
||||
};
|
||||
|
||||
} // namespace fesa
|
||||
Reference in New Issue
Block a user