refactor: move solver skeleton implementations to cpp
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
#include <fesa/analysis/analysis.hpp>
|
||||
|
||||
namespace fesa::analysis {
|
||||
|
||||
Analysis::~Analysis() = default;
|
||||
|
||||
void Analysis::run()
|
||||
{
|
||||
initialize();
|
||||
build_analysis_model();
|
||||
build_dof_map();
|
||||
build_sparse_pattern();
|
||||
assemble();
|
||||
apply_boundary_conditions();
|
||||
solve();
|
||||
update_state();
|
||||
write_results();
|
||||
}
|
||||
|
||||
void Analysis::initialize() {}
|
||||
void Analysis::build_analysis_model() {}
|
||||
void Analysis::build_dof_map() {}
|
||||
void Analysis::build_sparse_pattern() {}
|
||||
void Analysis::assemble() {}
|
||||
void Analysis::apply_boundary_conditions() {}
|
||||
void Analysis::solve() {}
|
||||
void Analysis::update_state() {}
|
||||
void Analysis::write_results() {}
|
||||
|
||||
} // namespace fesa::analysis
|
||||
@@ -4,31 +4,20 @@ namespace fesa::analysis {
|
||||
|
||||
class Analysis {
|
||||
public:
|
||||
virtual ~Analysis() = default;
|
||||
virtual ~Analysis();
|
||||
|
||||
void run()
|
||||
{
|
||||
initialize();
|
||||
build_analysis_model();
|
||||
build_dof_map();
|
||||
build_sparse_pattern();
|
||||
assemble();
|
||||
apply_boundary_conditions();
|
||||
solve();
|
||||
update_state();
|
||||
write_results();
|
||||
}
|
||||
void run();
|
||||
|
||||
protected:
|
||||
virtual void initialize() {}
|
||||
virtual void build_analysis_model() {}
|
||||
virtual void build_dof_map() {}
|
||||
virtual void build_sparse_pattern() {}
|
||||
virtual void assemble() {}
|
||||
virtual void apply_boundary_conditions() {}
|
||||
virtual void solve() {}
|
||||
virtual void update_state() {}
|
||||
virtual void write_results() {}
|
||||
virtual void initialize();
|
||||
virtual void build_analysis_model();
|
||||
virtual void build_dof_map();
|
||||
virtual void build_sparse_pattern();
|
||||
virtual void assemble();
|
||||
virtual void apply_boundary_conditions();
|
||||
virtual void solve();
|
||||
virtual void update_state();
|
||||
virtual void write_results();
|
||||
};
|
||||
|
||||
} // namespace fesa::analysis
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <fesa/analysis/analysis_model.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fesa::analysis {
|
||||
|
||||
AnalysisModel::AnalysisModel(const model::Domain& domain, core::StepId step_id)
|
||||
: domain_(domain), step_(domain.find_step(step_id))
|
||||
{
|
||||
if (step_ == nullptr) {
|
||||
throw std::invalid_argument("analysis step not found");
|
||||
}
|
||||
|
||||
for (const auto& element : domain_.elements()) {
|
||||
active_elements_.push_back(&element);
|
||||
}
|
||||
for (const auto& boundary_condition : step_->boundary_conditions()) {
|
||||
active_boundary_conditions_.push_back(&boundary_condition);
|
||||
}
|
||||
for (const auto& load : step_->loads()) {
|
||||
active_loads_.push_back(&load);
|
||||
}
|
||||
}
|
||||
|
||||
const model::Domain& AnalysisModel::domain() const
|
||||
{
|
||||
return domain_;
|
||||
}
|
||||
|
||||
const model::AnalysisStep& AnalysisModel::step() const
|
||||
{
|
||||
return *step_;
|
||||
}
|
||||
|
||||
const std::vector<const model::Element*>& AnalysisModel::active_elements() const
|
||||
{
|
||||
return active_elements_;
|
||||
}
|
||||
|
||||
const std::vector<const model::BoundaryCondition*>& AnalysisModel::active_boundary_conditions() const
|
||||
{
|
||||
return active_boundary_conditions_;
|
||||
}
|
||||
|
||||
const std::vector<const model::Load*>& AnalysisModel::active_loads() const
|
||||
{
|
||||
return active_loads_;
|
||||
}
|
||||
|
||||
const model::Property* AnalysisModel::property_for(const model::Element& element) const
|
||||
{
|
||||
return domain_.find_property(element.property_id());
|
||||
}
|
||||
|
||||
const model::Material* AnalysisModel::material_for(const model::Property& property) const
|
||||
{
|
||||
return domain_.find_material(property.material_id());
|
||||
}
|
||||
|
||||
} // namespace fesa::analysis
|
||||
@@ -2,65 +2,21 @@
|
||||
|
||||
#include <fesa/model/domain.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa::analysis {
|
||||
|
||||
class AnalysisModel {
|
||||
public:
|
||||
AnalysisModel(const model::Domain& domain, core::StepId step_id)
|
||||
: domain_(domain), step_(domain.find_step(step_id))
|
||||
{
|
||||
if (step_ == nullptr) {
|
||||
throw std::invalid_argument("analysis step not found");
|
||||
}
|
||||
AnalysisModel(const model::Domain& domain, core::StepId step_id);
|
||||
|
||||
for (const auto& element : domain_.elements()) {
|
||||
active_elements_.push_back(&element);
|
||||
}
|
||||
for (const auto& boundary_condition : step_->boundary_conditions()) {
|
||||
active_boundary_conditions_.push_back(&boundary_condition);
|
||||
}
|
||||
for (const auto& load : step_->loads()) {
|
||||
active_loads_.push_back(&load);
|
||||
}
|
||||
}
|
||||
|
||||
const model::Domain& domain() const
|
||||
{
|
||||
return domain_;
|
||||
}
|
||||
|
||||
const model::AnalysisStep& step() const
|
||||
{
|
||||
return *step_;
|
||||
}
|
||||
|
||||
const std::vector<const model::Element*>& active_elements() const
|
||||
{
|
||||
return active_elements_;
|
||||
}
|
||||
|
||||
const std::vector<const model::BoundaryCondition*>& active_boundary_conditions() const
|
||||
{
|
||||
return active_boundary_conditions_;
|
||||
}
|
||||
|
||||
const std::vector<const model::Load*>& active_loads() const
|
||||
{
|
||||
return active_loads_;
|
||||
}
|
||||
|
||||
const model::Property* property_for(const model::Element& element) const
|
||||
{
|
||||
return domain_.find_property(element.property_id());
|
||||
}
|
||||
|
||||
const model::Material* material_for(const model::Property& property) const
|
||||
{
|
||||
return domain_.find_material(property.material_id());
|
||||
}
|
||||
const model::Domain& domain() const;
|
||||
const model::AnalysisStep& step() const;
|
||||
const std::vector<const model::Element*>& active_elements() const;
|
||||
const std::vector<const model::BoundaryCondition*>& active_boundary_conditions() const;
|
||||
const std::vector<const model::Load*>& active_loads() const;
|
||||
const model::Property* property_for(const model::Element& element) const;
|
||||
const model::Material* material_for(const model::Property& property) const;
|
||||
|
||||
private:
|
||||
const model::Domain& domain_;
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
#include <fesa/analysis/analysis_state.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace fesa::analysis {
|
||||
|
||||
AnalysisState::AnalysisState(int total_dof_count)
|
||||
: displacement_(vector_of(total_dof_count)),
|
||||
velocity_(vector_of(total_dof_count)),
|
||||
acceleration_(vector_of(total_dof_count)),
|
||||
temperature_(vector_of(total_dof_count)),
|
||||
external_force_(vector_of(total_dof_count)),
|
||||
internal_force_(vector_of(total_dof_count)),
|
||||
residual_(vector_of(total_dof_count))
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::displacement() const
|
||||
{
|
||||
return displacement_;
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::velocity() const
|
||||
{
|
||||
return velocity_;
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::acceleration() const
|
||||
{
|
||||
return acceleration_;
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::temperature() const
|
||||
{
|
||||
return temperature_;
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::external_force() const
|
||||
{
|
||||
return external_force_;
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::internal_force() const
|
||||
{
|
||||
return internal_force_;
|
||||
}
|
||||
|
||||
const std::vector<double>& AnalysisState::residual() const
|
||||
{
|
||||
return residual_;
|
||||
}
|
||||
|
||||
void AnalysisState::set_displacement(std::vector<double> values)
|
||||
{
|
||||
assign_same_size(displacement_, std::move(values));
|
||||
}
|
||||
|
||||
void AnalysisState::set_external_force(std::vector<double> values)
|
||||
{
|
||||
assign_same_size(external_force_, std::move(values));
|
||||
}
|
||||
|
||||
void AnalysisState::set_internal_force(std::vector<double> values)
|
||||
{
|
||||
assign_same_size(internal_force_, std::move(values));
|
||||
}
|
||||
|
||||
void AnalysisState::update_residual()
|
||||
{
|
||||
for (std::size_t index = 0; index < residual_.size(); ++index) {
|
||||
residual_[index] = external_force_[index] - internal_force_[index];
|
||||
}
|
||||
}
|
||||
|
||||
IterationState& AnalysisState::iteration_state()
|
||||
{
|
||||
return iteration_state_;
|
||||
}
|
||||
|
||||
const IterationState& AnalysisState::iteration_state() const
|
||||
{
|
||||
return iteration_state_;
|
||||
}
|
||||
|
||||
void AnalysisState::set_element_state(core::ElementId element_id, std::vector<double> state)
|
||||
{
|
||||
for (auto& entry : element_states_) {
|
||||
if (entry.first.value == element_id.value) {
|
||||
entry.second = std::move(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
element_states_.push_back({element_id, std::move(state)});
|
||||
}
|
||||
|
||||
const std::vector<double>* AnalysisState::element_state(core::ElementId element_id) const
|
||||
{
|
||||
for (const auto& entry : element_states_) {
|
||||
if (entry.first.value == element_id.value) {
|
||||
return &entry.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<double> AnalysisState::vector_of(int size)
|
||||
{
|
||||
if (size < 0) {
|
||||
throw std::invalid_argument("negative dof count");
|
||||
}
|
||||
return std::vector<double>(static_cast<std::size_t>(size), 0.0);
|
||||
}
|
||||
|
||||
void AnalysisState::assign_same_size(std::vector<double>& target, std::vector<double> values)
|
||||
{
|
||||
if (target.size() != values.size()) {
|
||||
throw std::invalid_argument("vector size mismatch");
|
||||
}
|
||||
target = std::move(values);
|
||||
}
|
||||
|
||||
} // namespace fesa::analysis
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <fesa/core/ids.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fesa::analysis {
|
||||
@@ -16,121 +14,30 @@ struct IterationState {
|
||||
|
||||
class AnalysisState {
|
||||
public:
|
||||
explicit AnalysisState(int total_dof_count)
|
||||
: displacement_(vector_of(total_dof_count)),
|
||||
velocity_(vector_of(total_dof_count)),
|
||||
acceleration_(vector_of(total_dof_count)),
|
||||
temperature_(vector_of(total_dof_count)),
|
||||
external_force_(vector_of(total_dof_count)),
|
||||
internal_force_(vector_of(total_dof_count)),
|
||||
residual_(vector_of(total_dof_count))
|
||||
{
|
||||
}
|
||||
explicit AnalysisState(int total_dof_count);
|
||||
|
||||
const std::vector<double>& displacement() const
|
||||
{
|
||||
return displacement_;
|
||||
}
|
||||
const std::vector<double>& displacement() const;
|
||||
const std::vector<double>& velocity() const;
|
||||
const std::vector<double>& acceleration() const;
|
||||
const std::vector<double>& temperature() const;
|
||||
const std::vector<double>& external_force() const;
|
||||
const std::vector<double>& internal_force() const;
|
||||
const std::vector<double>& residual() const;
|
||||
|
||||
const std::vector<double>& velocity() const
|
||||
{
|
||||
return velocity_;
|
||||
}
|
||||
void set_displacement(std::vector<double> values);
|
||||
void set_external_force(std::vector<double> values);
|
||||
void set_internal_force(std::vector<double> values);
|
||||
void update_residual();
|
||||
|
||||
const std::vector<double>& acceleration() const
|
||||
{
|
||||
return acceleration_;
|
||||
}
|
||||
IterationState& iteration_state();
|
||||
const IterationState& iteration_state() const;
|
||||
|
||||
const std::vector<double>& temperature() const
|
||||
{
|
||||
return temperature_;
|
||||
}
|
||||
|
||||
const std::vector<double>& external_force() const
|
||||
{
|
||||
return external_force_;
|
||||
}
|
||||
|
||||
const std::vector<double>& internal_force() const
|
||||
{
|
||||
return internal_force_;
|
||||
}
|
||||
|
||||
const std::vector<double>& residual() const
|
||||
{
|
||||
return residual_;
|
||||
}
|
||||
|
||||
void set_displacement(std::vector<double> values)
|
||||
{
|
||||
assign_same_size(displacement_, std::move(values));
|
||||
}
|
||||
|
||||
void set_external_force(std::vector<double> values)
|
||||
{
|
||||
assign_same_size(external_force_, std::move(values));
|
||||
}
|
||||
|
||||
void set_internal_force(std::vector<double> values)
|
||||
{
|
||||
assign_same_size(internal_force_, std::move(values));
|
||||
}
|
||||
|
||||
void update_residual()
|
||||
{
|
||||
for (std::size_t index = 0; index < residual_.size(); ++index) {
|
||||
residual_[index] = external_force_[index] - internal_force_[index];
|
||||
}
|
||||
}
|
||||
|
||||
IterationState& iteration_state()
|
||||
{
|
||||
return iteration_state_;
|
||||
}
|
||||
|
||||
const IterationState& iteration_state() const
|
||||
{
|
||||
return iteration_state_;
|
||||
}
|
||||
|
||||
void set_element_state(core::ElementId element_id, std::vector<double> state)
|
||||
{
|
||||
for (auto& entry : element_states_) {
|
||||
if (entry.first.value == element_id.value) {
|
||||
entry.second = std::move(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
element_states_.push_back({element_id, std::move(state)});
|
||||
}
|
||||
|
||||
const std::vector<double>* element_state(core::ElementId element_id) const
|
||||
{
|
||||
for (const auto& entry : element_states_) {
|
||||
if (entry.first.value == element_id.value) {
|
||||
return &entry.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void set_element_state(core::ElementId element_id, std::vector<double> state);
|
||||
const std::vector<double>* element_state(core::ElementId element_id) const;
|
||||
|
||||
private:
|
||||
static std::vector<double> vector_of(int size)
|
||||
{
|
||||
if (size < 0) {
|
||||
throw std::invalid_argument("negative dof count");
|
||||
}
|
||||
return std::vector<double>(static_cast<std::size_t>(size), 0.0);
|
||||
}
|
||||
|
||||
static void assign_same_size(std::vector<double>& target, std::vector<double> values)
|
||||
{
|
||||
if (target.size() != values.size()) {
|
||||
throw std::invalid_argument("vector size mismatch");
|
||||
}
|
||||
target = std::move(values);
|
||||
}
|
||||
static std::vector<double> vector_of(int size);
|
||||
static void assign_same_size(std::vector<double>& target, std::vector<double> values);
|
||||
|
||||
std::vector<double> displacement_;
|
||||
std::vector<double> velocity_;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <fesa/analysis/linear_static_analysis.hpp>
|
||||
|
||||
namespace fesa::analysis {
|
||||
|
||||
LinearStaticAnalysis::LinearStaticAnalysis(const model::Domain& domain, core::StepId step_id)
|
||||
: domain_(domain), step_id_(step_id)
|
||||
{
|
||||
}
|
||||
|
||||
const AnalysisModel* LinearStaticAnalysis::analysis_model() const
|
||||
{
|
||||
return analysis_model_.get();
|
||||
}
|
||||
|
||||
const AnalysisState* LinearStaticAnalysis::state() const
|
||||
{
|
||||
return state_.get();
|
||||
}
|
||||
|
||||
void LinearStaticAnalysis::build_analysis_model()
|
||||
{
|
||||
analysis_model_ = std::make_unique<AnalysisModel>(domain_, step_id_);
|
||||
}
|
||||
|
||||
void LinearStaticAnalysis::build_dof_map()
|
||||
{
|
||||
dof_manager_ = std::make_unique<fem::DofManager>();
|
||||
for (const auto* element : analysis_model_->active_elements()) {
|
||||
for (const auto node_id : element->node_ids()) {
|
||||
dof_manager_->define_node_dofs(node_id, {
|
||||
model::DofComponent::ux,
|
||||
model::DofComponent::uy,
|
||||
model::DofComponent::uz
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const auto* boundary_condition : analysis_model_->active_boundary_conditions()) {
|
||||
dof_manager_->apply_boundary_condition(*boundary_condition);
|
||||
}
|
||||
dof_manager_->number_equations();
|
||||
}
|
||||
|
||||
void LinearStaticAnalysis::update_state()
|
||||
{
|
||||
state_ = std::make_unique<AnalysisState>(dof_manager_->total_dof_count());
|
||||
}
|
||||
|
||||
} // namespace fesa::analysis
|
||||
@@ -11,49 +11,15 @@ namespace fesa::analysis {
|
||||
|
||||
class LinearStaticAnalysis : public Analysis {
|
||||
public:
|
||||
LinearStaticAnalysis(const model::Domain& domain, core::StepId step_id)
|
||||
: domain_(domain), step_id_(step_id)
|
||||
{
|
||||
}
|
||||
LinearStaticAnalysis(const model::Domain& domain, core::StepId step_id);
|
||||
|
||||
const AnalysisModel* analysis_model() const
|
||||
{
|
||||
return analysis_model_.get();
|
||||
}
|
||||
|
||||
const AnalysisState* state() const
|
||||
{
|
||||
return state_.get();
|
||||
}
|
||||
const AnalysisModel* analysis_model() const;
|
||||
const AnalysisState* state() const;
|
||||
|
||||
protected:
|
||||
void build_analysis_model() override
|
||||
{
|
||||
analysis_model_ = std::make_unique<AnalysisModel>(domain_, step_id_);
|
||||
}
|
||||
|
||||
void build_dof_map() override
|
||||
{
|
||||
dof_manager_ = std::make_unique<fem::DofManager>();
|
||||
for (const auto* element : analysis_model_->active_elements()) {
|
||||
for (const auto node_id : element->node_ids()) {
|
||||
dof_manager_->define_node_dofs(node_id, {
|
||||
model::DofComponent::ux,
|
||||
model::DofComponent::uy,
|
||||
model::DofComponent::uz
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const auto* boundary_condition : analysis_model_->active_boundary_conditions()) {
|
||||
dof_manager_->apply_boundary_condition(*boundary_condition);
|
||||
}
|
||||
dof_manager_->number_equations();
|
||||
}
|
||||
|
||||
void update_state() override
|
||||
{
|
||||
state_ = std::make_unique<AnalysisState>(dof_manager_->total_dof_count());
|
||||
}
|
||||
void build_analysis_model() override;
|
||||
void build_dof_map() override;
|
||||
void update_state() override;
|
||||
|
||||
private:
|
||||
const model::Domain& domain_;
|
||||
|
||||
Reference in New Issue
Block a user