feat: implement consistent-mass HHT shell dynamics

This commit is contained in:
KOKO\Mimi
2026-09-22 21:38:42 +09:00
parent fec8cf09c2
commit f0dc42a280
41 changed files with 9294 additions and 125 deletions
@@ -0,0 +1,113 @@
#ifndef FESA_ANALYSIS_DYNAMIC_ANALYSIS_STATE_H_
#define FESA_ANALYSIS_DYNAMIC_ANALYSIS_STATE_H_
#include <array>
#include <cstdint>
#include <vector>
#include "fesa/core/source_identity.h"
#include "fesa/core/status.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/math/vector.h"
#include "fesa/model/domain.h"
#include "fesa/results/result_records.h"
namespace fesa {
/// @brief Stores one accepted endpoint of an HHT dynamic step.
struct DynamicAcceptedFrameState {
std::uint32_t frame_index = 0U;
std::uint32_t increment_index = 0U;
std::uint32_t iteration_count = 0U;
double time = 0.0;
bool is_initial = false;
std::vector<EntityIndex> nodal_internal_order;
std::vector<SourceEntityId> nodal_source_ids;
Vector generalized_coordinates{0U};
Vector velocity{0U};
Vector acceleration{0U};
Vector algorithmic_acceleration{0U};
std::vector<std::array<std::array<double, 3>, 3>> nodal_triad;
std::vector<std::array<double, 3>> nodal_director;
Vector angular_velocity{0U};
Vector angular_acceleration{0U};
Vector inertia_force{0U};
Vector internal_force{0U};
Vector external_force{0U};
Vector residual{0U};
Vector reaction{0U};
Vector residual_scale{0U};
std::vector<ShellResultRow> shell_results;
double kinetic_energy = 0.0;
double physical_strain_energy = 0.0;
double drilling_energy = 0.0;
double external_work = 0.0;
double energy_defect = 0.0;
std::array<double, 6> global_equilibrium{};
std::array<double, 3> linear_momentum{};
std::array<double, 3> angular_momentum{};
std::array<double, 3> linear_momentum_rate{};
std::array<double, 3> angular_momentum_rate{};
std::array<double, 2> free_residual_metrics{};
Vector hidden_constraint{0U};
Vector hidden_velocity_defect{0U};
Vector hidden_acceleration_defect{0U};
Vector hidden_constraint_scale{0U};
Vector hidden_velocity_defect_scale{0U};
Vector hidden_acceleration_defect_scale{0U};
};
/// @brief Owns accepted HHT frame history and the current committed endpoint.
class DynamicAnalysisState {
public:
/// @brief Creates an uninitialized state that cannot be written or committed.
DynamicAnalysisState() = default;
/// @brief Validates the immutable dynamic inventory and schedule.
/// @return A state ready to accept the required frame zero.
static Result<DynamicAnalysisState> Create(const Domain& domain,
const DofManager& dofs);
/// @brief Returns an independent copy of the committed frame.
/// @pre At least one frame has been committed.
Result<DynamicAcceptedFrameState> BeginTrialFromCommitted() const;
/// @brief Atomically accepts one complete finite dynamic frame.
Status CommitAcceptedFrame(const DynamicAcceptedFrameState& frame);
/// @brief Discards caller-owned trial data without mutating this state.
void DiscardTrial() noexcept;
/// @brief Returns accepted frames in frame-index order.
const std::vector<DynamicAcceptedFrameState>& AcceptedFrames() const noexcept;
/// @brief Returns the current committed frame.
/// @pre At least one frame has been committed.
const DynamicAcceptedFrameState& CommittedState() const;
/// @brief Reports whether Create has validated this state inventory.
bool IsInitialized() const noexcept;
private:
DynamicAnalysisState(std::size_t full_dof_count,
std::uint32_t increment_count, double initial_increment,
std::vector<EntityIndex> shell_element_order,
std::vector<std::size_t> constrained_dofs,
std::vector<SourceEntityId> nodal_source_ids,
std::vector<ShellNodeInitialFrame> initial_frames);
std::size_t full_dof_count_ = 0U;
std::uint32_t increment_count_ = 0U;
double initial_increment_ = 0.0;
std::vector<EntityIndex> shell_element_order_;
std::vector<std::size_t> constrained_dofs_;
std::vector<SourceEntityId> nodal_source_ids_;
std::vector<ShellNodeInitialFrame> initial_frames_;
std::vector<DynamicAcceptedFrameState> accepted_frames_;
std::size_t hidden_constraint_count_ = 0U;
bool initialized_ = false;
};
} // namespace fesa
#endif // FESA_ANALYSIS_DYNAMIC_ANALYSIS_STATE_H_
@@ -0,0 +1,29 @@
#ifndef FESA_ANALYSIS_HHT_DYNAMIC_PROCEDURE_H_
#define FESA_ANALYSIS_HHT_DYNAMIC_PROCEDURE_H_
#include "fesa/analysis/prepared_analysis.h"
namespace fesa {
class LinearSolver;
class ParallelFor;
class TangentSolver;
/// @brief Executes endpoint-equilibrium HHT with consistent shell inertia.
class HhtDynamicProcedureExecutor {
public:
/// @brief Retains caller-owned deterministic execution and solve adapters.
HhtDynamicProcedureExecutor(const ParallelFor& parallel_for,
LinearSolver& positive_solver,
TangentSolver& tangent_solver);
/// @brief Returns complete accepted history without opening result output.
Result<DynamicExecutionResult> Execute(const Domain& domain,
NewtonIterationLogWriter& log) const;
private:
const ParallelFor& parallel_for_;
LinearSolver& positive_solver_;
TangentSolver& tangent_solver_;
};
} // namespace fesa
#endif // FESA_ANALYSIS_HHT_DYNAMIC_PROCEDURE_H_
@@ -0,0 +1,50 @@
#ifndef FESA_ANALYSIS_HHT_TIME_INTEGRATION_H_
#define FESA_ANALYSIS_HHT_TIME_INTEGRATION_H_
#include "fesa/core/status.h"
#include "fesa/math/vector.h"
namespace fesa {
/// @brief Stores the coupled original negative-alpha HHT coefficients.
struct HhtParameters {
double alpha;
double beta;
double gamma;
};
/// @brief Stores the displacement and velocity Newmark predictors.
struct HhtPredictor {
Vector coordinates;
Vector velocity;
};
/// @brief Separates physical chart rates from the auxiliary acceleration.
struct HhtRates {
Vector velocity;
Vector acceleration;
Vector algorithmic_acceleration;
};
/// @brief Builds coupled coefficients for alpha in [-1/3, 0].
/// @note The public INP subset uses only alpha=-0.05.
Result<HhtParameters> MakeHhtParameters(double alpha);
/// @brief Predicts q and v using the old auxiliary acceleration.
/// @param time_increment Finite positive duration in input time units.
Result<HhtPredictor> PredictHht(const Vector& coordinates,
const Vector& velocity,
const Vector& algorithmic_acceleration,
double time_increment,
const HhtParameters& parameters);
/// @brief Recovers physical and auxiliary rates from one trial coordinate.
/// @param old_acceleration Physical endpoint acceleration at the old time.
Result<HhtRates> EvaluateHhtRates(const Vector& coordinates,
const HhtPredictor& predictor,
const Vector& old_acceleration,
double time_increment,
const HhtParameters& parameters);
} // namespace fesa
#endif // FESA_ANALYSIS_HHT_TIME_INTEGRATION_H_
@@ -1,6 +1,7 @@
#ifndef FESA_ANALYSIS_NEWTON_ITERATION_LOG_H_
#define FESA_ANALYSIS_NEWTON_ITERATION_LOG_H_
#include <array>
#include <cstdint>
#include <filesystem>
#include <fstream>
@@ -49,6 +50,27 @@ struct NewtonIterationLogRecord {
bool combined_passed;
};
/// @brief Carries two-channel HHT endpoint convergence evidence.
/// @note Array entries are translation and rotation channels, respectively.
/// Corrections are dimensionless N2 metrics; rate corrections already include
/// h or h squared. Residual numerator and scale retain force/moment units.
struct DynamicNewtonIterationLogRecord {
std::uint32_t increment_index = 0U;
std::uint32_t iteration_index = 0U;
double time = 0.0;
std::string stage;
std::string outcome;
std::string failure_code;
std::array<double, 2U> residual_numerator{};
std::array<double, 2U> residual_scale{};
std::array<double, 2U> coordinate_correction{};
std::array<double, 2U> velocity_correction{};
std::array<double, 2U> acceleration_correction{};
std::array<double, 2U> algorithmic_correction{};
bool residual_pass = false;
bool correction_pass = false;
};
/// @brief Writes deterministic, line-oriented Newton iteration diagnostics.
/// @note A write, flush, or close failure permanently prevents a successful
/// log lifecycle for this writer instance.
@@ -66,6 +88,11 @@ class NewtonIterationLogWriter {
/// failure with code `log-output-failure`.
Status Write(const NewtonIterationLogRecord& record);
/// @brief Writes one complete HHT record using schema `hht-log-v1`.
/// @return Success after the complete line is written; invalid numeric
/// evidence or stream failure permanently fails this writer instance.
Status Write(const DynamicNewtonIterationLogRecord& record);
/// @brief Flushes every complete record written so far to the log.
/// @return Success after the stream flush, otherwise an output failure with
/// code `log-output-failure`.
+14 -3
View File
@@ -6,6 +6,7 @@
#include <vector>
#include "fesa/analysis/analysis_state.h"
#include "fesa/analysis/dynamic_analysis_state.h"
#include "fesa/analysis/eigen_analysis_state.h"
#include "fesa/analysis/nonlinear_analysis_state.h"
#include "fesa/core/diagnostic.h"
@@ -21,6 +22,8 @@ class NewtonIterationLogWriter;
class NonlinearResultsWriter;
class NonlinearStaticProcedureExecutor;
class ResultsWriter;
class HhtDynamicProcedureExecutor;
class DynamicResultsWriter;
struct DerivedOutputPaths;
/// @brief Owns one parsed and semantically mapped analysis input.
@@ -49,9 +52,15 @@ struct NonlinearStaticExecutionResult {
std::vector<Diagnostic> diagnostics;
};
/// @brief Stores a complete HHT history before atomic result finalization.
struct DynamicExecutionResult {
DynamicAnalysisState state;
std::vector<Diagnostic> diagnostics;
};
using PreparedAnalysisOutcome =
std::variant<LinearStaticExecutionResult, NonlinearStaticExecutionResult,
EigenAnalysisState>;
EigenAnalysisState, DynamicExecutionResult>;
/// @brief Selects the approved procedure from a prepared Domain.
/// @pre The executors and log outlive this call.
@@ -60,7 +69,8 @@ Result<PreparedAnalysisOutcome> ExecutePreparedAnalysis(
const Domain& domain, LinearStaticProcedureExecutor& linear_executor,
NonlinearStaticProcedureExecutor& nonlinear_executor,
const LinearFrequencyProcedureExecutor& frequency_executor,
NewtonIterationLogWriter& log);
NewtonIterationLogWriter& log,
const HhtDynamicProcedureExecutor* dynamic_executor = nullptr);
/// @brief Writes an already computed outcome to its authoritative result file.
/// @pre The Newton log has closed successfully before this function is called.
@@ -69,7 +79,8 @@ Status FinalizePreparedAnalysisResult(
const DerivedOutputPaths& paths, const Domain& domain,
const PreparedAnalysisOutcome& outcome,
const std::vector<Diagnostic>& diagnostics, ResultsWriter& linear_writer,
NonlinearResultsWriter& nonlinear_writer, EigenResultsWriter& eigen_writer);
NonlinearResultsWriter& nonlinear_writer, EigenResultsWriter& eigen_writer,
DynamicResultsWriter* dynamic_writer = nullptr);
} // namespace fesa