feat(cpp-object-oriented-modular-refactoring): step 5 - solver-workflow-google-style

This commit is contained in:
KOKO\Mimi
2026-08-16 06:20:08 +09:00
parent e1c0e357dd
commit 24f006fe4a
52 changed files with 5817 additions and 6369 deletions
+55
View File
@@ -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_
-34
View File
@@ -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
+102
View File
@@ -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_
-66
View File
@@ -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