feat(cpp-object-oriented-modular-refactoring): step 19 - boundary-condition-policy

This commit is contained in:
KOKO\Mimi
2026-08-16 11:23:20 +09:00
parent f26e0a61a8
commit 64a43948ef
27 changed files with 919 additions and 365 deletions
@@ -7,7 +7,7 @@
#include "fesa/analysis/analysis_model.h"
#include "fesa/analysis/analysis_state.h"
#include "fesa/constraints/essential_constraints.h"
#include "fesa/constraints/essential_constraint_policy.h"
#include "fesa/core/status.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/math/sparse_matrix.h"
@@ -0,0 +1,71 @@
#ifndef FESA_CONSTRAINTS_BOUNDARY_CONDITION_H_
#define FESA_CONSTRAINTS_BOUNDARY_CONDITION_H_
#include <cstddef>
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "fesa/core/diagnostic.h"
#include "fesa/core/status.h"
namespace fesa {
class DofManager;
class Domain;
class SourceTargetResolver;
/// @brief Describes one prescribed value in stable full-DOF order.
struct ConstraintDefinition {
std::size_t source_order;
std::size_t full_dof_index;
double prescribed_value;
};
/// @brief Provides immutable semantic and equation context to a boundary.
/// @note Every referenced object must outlive a constraint request.
struct BoundaryConditionContext {
const Domain& domain;
const DofManager& dof_manager;
const SourceTargetResolver& target_resolver;
};
/// @brief Produces ordered constraint definitions without equation mutation.
class BoundaryCondition {
public:
virtual ~BoundaryCondition() = default;
/// @brief Resolves finite full-DOF definitions in stable target order.
/// @param context Non-owning semantic and equation context for this call.
/// @return Ordered definitions or a structured model failure.
virtual Result<std::vector<ConstraintDefinition>> ResolveConstraints(
const BoundaryConditionContext& context) const = 0;
/// @brief Returns the source location used by policy diagnostics.
const SourceLocation& Location() const noexcept { return location_; }
/// @brief Returns the source target identity used by policy diagnostics.
const std::string& TargetIdentity() const noexcept {
return target_identity_;
}
protected:
/// @brief Creates a boundary with optional shared diagnostic provenance.
BoundaryCondition(std::string target_identity = {},
SourceLocation location = {})
: target_identity_{std::move(target_identity)},
location_{std::move(location)} {}
private:
std::string target_identity_;
SourceLocation location_;
};
/// @brief Holds non-owning boundaries in an explicitly supplied source order.
using BoundaryConditionView =
std::vector<std::reference_wrapper<const BoundaryCondition>>;
} // namespace fesa
#endif // FESA_CONSTRAINTS_BOUNDARY_CONDITION_H_
@@ -0,0 +1,43 @@
#ifndef FESA_CONSTRAINTS_ESSENTIAL_CONSTRAINT_POLICY_H_
#define FESA_CONSTRAINTS_ESSENTIAL_CONSTRAINT_POLICY_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 k_ff;
SparseMatrix k_fc;
SparseMatrix k_cf;
SparseMatrix k_cc;
};
/// @brief Applies stable prescribed-displacement elimination.
class EssentialConstraintPolicy {
public:
/// @brief Partitions full stiffness into Kff, Kfc, Kcf, and Kcc.
Result<PartitionedStiffness> Partition(const SparseMatrix& full_stiffness,
const DofManager& dof_manager) const;
/// @brief Gathers a full vector in stable free-equation order.
Vector GatherFree(const Vector& full_values,
const DofManager& dof_manager) const;
/// @brief Gathers a full vector in stable constrained-DOF order.
Vector GatherConstrained(const Vector& full_values,
const DofManager& dof_manager) const;
/// @brief Reconstructs full d from stable df and exact prescribed dc.
Vector ReconstructFull(const Vector& free_values,
const Vector& constrained_values,
const DofManager& dof_manager) const;
};
} // namespace fesa
#endif // FESA_CONSTRAINTS_ESSENTIAL_CONSTRAINT_POLICY_H_
@@ -1,41 +0,0 @@
#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_
@@ -0,0 +1,48 @@
#ifndef FESA_CONSTRAINTS_PRESCRIBED_DISPLACEMENT_H_
#define FESA_CONSTRAINTS_PRESCRIBED_DISPLACEMENT_H_
#include <cstddef>
#include "fesa/constraints/boundary_condition.h"
#include "fesa/core/diagnostic.h"
#include "fesa/elements/element.h"
#include "fesa/model/source_target_resolver.h"
namespace fesa {
/// @brief Emits one prescribed nodal displacement component for a target.
class PrescribedDisplacementBoundaryCondition final : public BoundaryCondition {
public:
/// @brief Creates one prescribed component in stable source order.
PrescribedDisplacementBoundaryCondition(SourceTargetQuery target,
DofComponent component,
double prescribed_value,
std::size_t source_order,
SourceLocation location = {});
/// @brief Resolves target-major full-DOF constraint definitions.
Result<std::vector<ConstraintDefinition>> ResolveConstraints(
const BoundaryConditionContext& context) const override;
/// @brief Returns the immutable source target query.
const SourceTargetQuery& Target() const noexcept;
/// @brief Returns the prescribed global DOF component.
DofComponent Component() const noexcept;
/// @brief Returns the exact prescribed displacement value.
double PrescribedValue() const noexcept;
/// @brief Returns the stable boundary-definition order.
std::size_t SourceOrder() const noexcept;
private:
SourceTargetQuery target_;
DofComponent component_;
double prescribed_value_;
std::size_t source_order_;
};
} // namespace fesa
#endif // FESA_CONSTRAINTS_PRESCRIBED_DISPLACEMENT_H_
+9 -1
View File
@@ -7,6 +7,7 @@
#include <vector>
#include "fesa/analysis/analysis_model.h"
#include "fesa/constraints/boundary_condition.h"
#include "fesa/elements/element.h"
#include "fesa/math/vector.h"
@@ -39,6 +40,12 @@ class DofManager {
Status Build(const AnalysisModel& analysis_model,
const ElementView& elements);
/// @brief Builds mappings from explicit runtime elements and boundaries.
/// @param boundaries Non-owning definitions in stable source order.
/// @return Success after atomic replacement or a structured failure.
Status Build(const AnalysisModel& analysis_model, const ElementView& elements,
const BoundaryConditionView& boundaries);
/// @brief Returns the full node-by-component DOF count.
std::size_t FullDofCount() const noexcept;
/// @brief Returns the free-equation count.
@@ -75,7 +82,8 @@ class DofManager {
/// @brief Builds from copied layouts after the caller fixes their order.
Status BuildLayouts(const AnalysisModel& analysis_model,
const std::vector<ElementDofLayout>& layouts);
const std::vector<ElementDofLayout>& layouts,
const BoundaryConditionView& boundaries);
/// @brief Takes ownership of fully validated stable equation mappings.
DofManager(std::size_t full_dof_count,
+12 -3
View File
@@ -7,6 +7,8 @@
#include <string>
#include <vector>
#include "fesa/constraints/boundary_condition.h"
#include "fesa/constraints/prescribed_displacement.h"
#include "fesa/core/status.h"
#include "fesa/loads/concentrated_nodal_load.h"
#include "fesa/loads/load.h"
@@ -58,8 +60,12 @@ class StepDefinition {
/// @brief Returns the source step name.
const std::string& Name() const noexcept;
/// @brief Returns current boundary records in declaration order.
const std::vector<BoundaryCondition>& Boundaries() const noexcept;
/// @brief Returns polymorphic boundaries in stable source/component order.
const BoundaryConditionView& BoundaryConditions() const noexcept;
/// @brief Returns prescribed displacements in stable source/component order.
const DomainCollectionView<PrescribedDisplacementBoundaryCondition>&
PrescribedDisplacements() const noexcept;
/// @brief Returns polymorphic loads in stable source order.
const LoadView& Loads() const noexcept;
@@ -90,7 +96,10 @@ class StepDefinition {
explicit StepDefinition(StaticStepDefinition definition);
std::string name_;
std::vector<BoundaryCondition> boundaries_;
std::vector<std::unique_ptr<BoundaryCondition>> boundary_conditions_;
BoundaryConditionView boundary_conditions_view_;
DomainCollectionView<PrescribedDisplacementBoundaryCondition>
prescribed_displacements_view_;
std::vector<std::unique_ptr<Load>> loads_;
LoadView loads_view_;
DomainCollectionView<ConcentratedNodalLoad> concentrated_loads_view_;
+2 -2
View File
@@ -36,7 +36,7 @@ struct ShellNodeInitialFrame {
};
/// @brief Stores one prescribed nodal degree-of-freedom range.
struct BoundaryCondition {
struct PrescribedDisplacementDefinition {
std::string target;
int first_dof;
int last_dof;
@@ -55,7 +55,7 @@ struct NodalLoad {
/// @brief Stores the approved single linear-static step definition.
struct StaticStepDefinition {
std::string name;
std::vector<BoundaryCondition> boundaries;
std::vector<PrescribedDisplacementDefinition> boundaries;
std::vector<NodalLoad> loads;
double initial_increment;
double time_period;