refactor: move solver skeleton implementations to cpp
This commit is contained in:
+5
-3
@@ -2,9 +2,11 @@ cmake_minimum_required(VERSION 3.20)
|
|||||||
|
|
||||||
project(FESA LANGUAGES CXX)
|
project(FESA LANGUAGES CXX)
|
||||||
|
|
||||||
add_library(fesa_core INTERFACE)
|
file(GLOB_RECURSE FESA_CORE_SOURCES CONFIGURE_DEPENDS src/fesa/*.cpp)
|
||||||
target_compile_features(fesa_core INTERFACE cxx_std_17)
|
|
||||||
target_include_directories(fesa_core INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
add_library(fesa_core STATIC ${FESA_CORE_SOURCES})
|
||||||
|
target_compile_features(fesa_core PUBLIC cxx_std_17)
|
||||||
|
target_include_directories(fesa_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|||||||
@@ -7,12 +7,19 @@
|
|||||||
|
|
||||||
## Commands Run
|
## Commands Run
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m unittest scripts.test_header_declaration_only
|
||||||
|
```
|
||||||
|
|
||||||
|
- exit_code: 0
|
||||||
|
- summary: Solver headers contain declarations only; function bodies are implemented in `.cpp` files.
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
python -m unittest discover -s scripts -p "test_*.py"
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
- exit_code: 0
|
- exit_code: 0
|
||||||
- summary: 98 Python Harness tests passed.
|
- summary: 99 Python Harness tests passed.
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
python scripts/validate_workspace.py
|
python scripts/validate_workspace.py
|
||||||
@@ -52,6 +59,15 @@ ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R solver_core_sk
|
|||||||
- `results_containers_test`
|
- `results_containers_test`
|
||||||
- `solver_core_skeleton_integration_test`
|
- `solver_core_skeleton_integration_test`
|
||||||
|
|
||||||
|
## Structural Tests Added
|
||||||
|
|
||||||
|
- `scripts.test_header_declaration_only`
|
||||||
|
|
||||||
|
## Build Structure
|
||||||
|
|
||||||
|
- `fesa_core` now builds as a static library from `src/fesa/**/*.cpp`.
|
||||||
|
- Solver headers under `src/fesa/**/*.hpp` declare functions only; method bodies live in matching `.cpp` translation units.
|
||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
|
|
||||||
- No element stiffness, residual, tangent, or stress recovery calculation is implemented.
|
- No element stiffness, residual, tangent, or stress recovery calculation is implemented.
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
HEADER_ROOT = ROOT / "src" / "fesa"
|
||||||
|
|
||||||
|
|
||||||
|
def _looks_like_function_definition(prefix):
|
||||||
|
if "(" not in prefix or ")" not in prefix:
|
||||||
|
return False
|
||||||
|
|
||||||
|
stripped = prefix.strip()
|
||||||
|
control_prefixes = ("if ", "for ", "while ", "switch ", "catch ")
|
||||||
|
declaration_prefixes = ("namespace ", "class ", "struct ", "enum ")
|
||||||
|
return not stripped.startswith(control_prefixes + declaration_prefixes)
|
||||||
|
|
||||||
|
|
||||||
|
class HeaderDeclarationOnlyTests(unittest.TestCase):
|
||||||
|
def test_solver_headers_do_not_contain_function_bodies(self):
|
||||||
|
violations = []
|
||||||
|
|
||||||
|
for header in sorted(HEADER_ROOT.rglob("*.hpp")):
|
||||||
|
candidate = ""
|
||||||
|
for line_number, line in enumerate(header.read_text(encoding="utf-8").splitlines(), start=1):
|
||||||
|
stripped = line.strip()
|
||||||
|
if not stripped:
|
||||||
|
continue
|
||||||
|
|
||||||
|
candidate = f"{candidate} {stripped}".strip()
|
||||||
|
if "{" in stripped and _looks_like_function_definition(candidate.split("{", 1)[0]):
|
||||||
|
violations.append(f"{header.relative_to(ROOT)}:{line_number}: function body in header")
|
||||||
|
|
||||||
|
if re.search(r"\([^;{}]*\)\s*=\s*(default|delete)\s*;", stripped):
|
||||||
|
violations.append(f"{header.relative_to(ROOT)}:{line_number}: function definition in header")
|
||||||
|
|
||||||
|
if stripped.endswith(";") or stripped.endswith("}") or stripped.endswith(":"):
|
||||||
|
candidate = ""
|
||||||
|
|
||||||
|
self.assertEqual([], violations)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -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 {
|
class Analysis {
|
||||||
public:
|
public:
|
||||||
virtual ~Analysis() = default;
|
virtual ~Analysis();
|
||||||
|
|
||||||
void run()
|
void run();
|
||||||
{
|
|
||||||
initialize();
|
|
||||||
build_analysis_model();
|
|
||||||
build_dof_map();
|
|
||||||
build_sparse_pattern();
|
|
||||||
assemble();
|
|
||||||
apply_boundary_conditions();
|
|
||||||
solve();
|
|
||||||
update_state();
|
|
||||||
write_results();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void initialize() {}
|
virtual void initialize();
|
||||||
virtual void build_analysis_model() {}
|
virtual void build_analysis_model();
|
||||||
virtual void build_dof_map() {}
|
virtual void build_dof_map();
|
||||||
virtual void build_sparse_pattern() {}
|
virtual void build_sparse_pattern();
|
||||||
virtual void assemble() {}
|
virtual void assemble();
|
||||||
virtual void apply_boundary_conditions() {}
|
virtual void apply_boundary_conditions();
|
||||||
virtual void solve() {}
|
virtual void solve();
|
||||||
virtual void update_state() {}
|
virtual void update_state();
|
||||||
virtual void write_results() {}
|
virtual void write_results();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fesa::analysis
|
} // 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 <fesa/model/domain.hpp>
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::analysis {
|
namespace fesa::analysis {
|
||||||
|
|
||||||
class AnalysisModel {
|
class AnalysisModel {
|
||||||
public:
|
public:
|
||||||
AnalysisModel(const model::Domain& domain, core::StepId step_id)
|
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()) {
|
const model::Domain& domain() const;
|
||||||
active_elements_.push_back(&element);
|
const model::AnalysisStep& step() const;
|
||||||
}
|
const std::vector<const model::Element*>& active_elements() const;
|
||||||
for (const auto& boundary_condition : step_->boundary_conditions()) {
|
const std::vector<const model::BoundaryCondition*>& active_boundary_conditions() const;
|
||||||
active_boundary_conditions_.push_back(&boundary_condition);
|
const std::vector<const model::Load*>& active_loads() const;
|
||||||
}
|
const model::Property* property_for(const model::Element& element) const;
|
||||||
for (const auto& load : step_->loads()) {
|
const model::Material* material_for(const model::Property& property) const;
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const model::Domain& domain_;
|
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 <fesa/core/ids.hpp>
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::analysis {
|
namespace fesa::analysis {
|
||||||
@@ -16,121 +14,30 @@ struct IterationState {
|
|||||||
|
|
||||||
class AnalysisState {
|
class AnalysisState {
|
||||||
public:
|
public:
|
||||||
explicit AnalysisState(int total_dof_count)
|
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))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<double>& displacement() const
|
const std::vector<double>& displacement() const;
|
||||||
{
|
const std::vector<double>& velocity() const;
|
||||||
return displacement_;
|
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
|
void set_displacement(std::vector<double> values);
|
||||||
{
|
void set_external_force(std::vector<double> values);
|
||||||
return velocity_;
|
void set_internal_force(std::vector<double> values);
|
||||||
}
|
void update_residual();
|
||||||
|
|
||||||
const std::vector<double>& acceleration() const
|
IterationState& iteration_state();
|
||||||
{
|
const IterationState& iteration_state() const;
|
||||||
return acceleration_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<double>& temperature() const
|
void set_element_state(core::ElementId element_id, std::vector<double> state);
|
||||||
{
|
const std::vector<double>* element_state(core::ElementId element_id) 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<double> vector_of(int size)
|
static std::vector<double> vector_of(int size);
|
||||||
{
|
static void assign_same_size(std::vector<double>& target, std::vector<double> values);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> displacement_;
|
std::vector<double> displacement_;
|
||||||
std::vector<double> velocity_;
|
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 {
|
class LinearStaticAnalysis : public Analysis {
|
||||||
public:
|
public:
|
||||||
LinearStaticAnalysis(const model::Domain& domain, core::StepId step_id)
|
LinearStaticAnalysis(const model::Domain& domain, core::StepId step_id);
|
||||||
: domain_(domain), step_id_(step_id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnalysisModel* analysis_model() const
|
const AnalysisModel* analysis_model() const;
|
||||||
{
|
const AnalysisState* state() const;
|
||||||
return analysis_model_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnalysisState* state() const
|
|
||||||
{
|
|
||||||
return state_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void build_analysis_model() override
|
void build_analysis_model() override;
|
||||||
{
|
void build_dof_map() override;
|
||||||
analysis_model_ = std::make_unique<AnalysisModel>(domain_, step_id_);
|
void update_state() override;
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const model::Domain& domain_;
|
const model::Domain& domain_;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include <fesa/core/status.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::core {
|
||||||
|
|
||||||
|
Status Status::ok()
|
||||||
|
{
|
||||||
|
return Status{};
|
||||||
|
}
|
||||||
|
|
||||||
|
Status Status::failure(Diagnostic diagnostic)
|
||||||
|
{
|
||||||
|
Status status;
|
||||||
|
status.add(std::move(diagnostic));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Status::is_ok() const
|
||||||
|
{
|
||||||
|
return diagnostics_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Diagnostic>& Status::diagnostics() const
|
||||||
|
{
|
||||||
|
return diagnostics_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Status::add(Diagnostic diagnostic)
|
||||||
|
{
|
||||||
|
diagnostics_.push_back(std::move(diagnostic));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::core
|
||||||
@@ -2,39 +2,18 @@
|
|||||||
|
|
||||||
#include <fesa/core/diagnostic.hpp>
|
#include <fesa/core/diagnostic.hpp>
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::core {
|
namespace fesa::core {
|
||||||
|
|
||||||
class Status {
|
class Status {
|
||||||
public:
|
public:
|
||||||
static Status ok()
|
static Status ok();
|
||||||
{
|
static Status failure(Diagnostic diagnostic);
|
||||||
return Status{};
|
|
||||||
}
|
|
||||||
|
|
||||||
static Status failure(Diagnostic diagnostic)
|
bool is_ok() const;
|
||||||
{
|
const std::vector<Diagnostic>& diagnostics() const;
|
||||||
Status status;
|
void add(Diagnostic diagnostic);
|
||||||
status.add(std::move(diagnostic));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_ok() const
|
|
||||||
{
|
|
||||||
return diagnostics_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Diagnostic>& diagnostics() const
|
|
||||||
{
|
|
||||||
return diagnostics_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(Diagnostic diagnostic)
|
|
||||||
{
|
|
||||||
diagnostics_.push_back(std::move(diagnostic));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Diagnostic> diagnostics_;
|
std::vector<Diagnostic> diagnostics_;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include <fesa/fem/dof_key.hpp>
|
||||||
|
|
||||||
|
namespace fesa::fem {
|
||||||
|
|
||||||
|
bool operator==(const DofKey& lhs, const DofKey& rhs)
|
||||||
|
{
|
||||||
|
return lhs.node_id.value == rhs.node_id.value && lhs.component == rhs.component;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::fem
|
||||||
@@ -10,9 +10,6 @@ struct DofKey {
|
|||||||
model::DofComponent component;
|
model::DofComponent component;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const DofKey& lhs, const DofKey& rhs)
|
bool operator==(const DofKey& lhs, const DofKey& rhs);
|
||||||
{
|
|
||||||
return lhs.node_id.value == rhs.node_id.value && lhs.component == rhs.component;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fesa::fem
|
} // namespace fesa::fem
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#include <fesa/fem/dof_manager.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace fesa::fem {
|
||||||
|
|
||||||
|
void DofManager::define_node_dofs(core::NodeId node_id, std::vector<model::DofComponent> components)
|
||||||
|
{
|
||||||
|
for (const auto component : components) {
|
||||||
|
DofKey key{node_id, component};
|
||||||
|
if (find_record(key) == records_.end()) {
|
||||||
|
records_.push_back({key});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DofManager::apply_boundary_condition(const model::BoundaryCondition& bc)
|
||||||
|
{
|
||||||
|
auto record = find_record({bc.node_id(), bc.component()});
|
||||||
|
if (record == records_.end()) {
|
||||||
|
throw std::invalid_argument("boundary condition references undefined dof");
|
||||||
|
}
|
||||||
|
record->constrained = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DofManager::number_equations()
|
||||||
|
{
|
||||||
|
std::sort(records_.begin(), records_.end(), [](const Record& lhs, const Record& rhs) {
|
||||||
|
if (lhs.key.node_id.value != rhs.key.node_id.value) {
|
||||||
|
return lhs.key.node_id.value < rhs.key.node_id.value;
|
||||||
|
}
|
||||||
|
return static_cast<int>(lhs.key.component) < static_cast<int>(rhs.key.component);
|
||||||
|
});
|
||||||
|
|
||||||
|
int free_id = 0;
|
||||||
|
for (int equation_id = 0; equation_id < static_cast<int>(records_.size()); ++equation_id) {
|
||||||
|
records_[equation_id].equation_id = equation_id;
|
||||||
|
if (records_[equation_id].constrained) {
|
||||||
|
records_[equation_id].free_equation_id = std::nullopt;
|
||||||
|
} else {
|
||||||
|
records_[equation_id].free_equation_id = free_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sparse_pattern_.clear();
|
||||||
|
for (int row = 0; row < free_id; ++row) {
|
||||||
|
for (int column = 0; column < free_id; ++column) {
|
||||||
|
sparse_pattern_.push_back({row, column});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DofManager::total_dof_count() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(records_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int DofManager::free_dof_count() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(
|
||||||
|
std::count_if(records_.begin(), records_.end(), [](const Record& record) {
|
||||||
|
return !record.constrained;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DofManager::constrained_dof_count() const
|
||||||
|
{
|
||||||
|
return total_dof_count() - free_dof_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DofManager::is_constrained(DofKey key) const
|
||||||
|
{
|
||||||
|
return require_record(key).constrained;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DofManager::equation_id(DofKey key) const
|
||||||
|
{
|
||||||
|
return require_record(key).equation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> DofManager::free_equation_id(DofKey key) const
|
||||||
|
{
|
||||||
|
return require_record(key).free_equation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> DofManager::expand_free_vector(const std::vector<double>& free_values) const
|
||||||
|
{
|
||||||
|
if (free_values.size() != static_cast<std::size_t>(free_dof_count())) {
|
||||||
|
throw std::invalid_argument("free vector size does not match dof manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> full(records_.size(), 0.0);
|
||||||
|
for (const auto& record : records_) {
|
||||||
|
if (record.free_equation_id.has_value()) {
|
||||||
|
full[static_cast<std::size_t>(record.equation_id)] =
|
||||||
|
free_values[static_cast<std::size_t>(*record.free_equation_id)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return full;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::pair<int, int>>& DofManager::sparse_pattern() const
|
||||||
|
{
|
||||||
|
return sparse_pattern_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DofManager::Record>::iterator DofManager::find_record(DofKey key)
|
||||||
|
{
|
||||||
|
return std::find_if(records_.begin(), records_.end(), [key](const Record& record) {
|
||||||
|
return record.key == key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DofManager::Record>::const_iterator DofManager::find_record(DofKey key) const
|
||||||
|
{
|
||||||
|
return std::find_if(records_.begin(), records_.end(), [key](const Record& record) {
|
||||||
|
return record.key == key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const DofManager::Record& DofManager::require_record(DofKey key) const
|
||||||
|
{
|
||||||
|
const auto record = find_record(key);
|
||||||
|
if (record == records_.end()) {
|
||||||
|
throw std::invalid_argument("dof is not defined");
|
||||||
|
}
|
||||||
|
return *record;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::fem
|
||||||
+14
-123
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
#include <fesa/fem/dof_key.hpp>
|
#include <fesa/fem/dof_key.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -12,106 +10,18 @@ namespace fesa::fem {
|
|||||||
|
|
||||||
class DofManager {
|
class DofManager {
|
||||||
public:
|
public:
|
||||||
void define_node_dofs(core::NodeId node_id, std::vector<model::DofComponent> components)
|
void define_node_dofs(core::NodeId node_id, std::vector<model::DofComponent> components);
|
||||||
{
|
void apply_boundary_condition(const model::BoundaryCondition& bc);
|
||||||
for (const auto component : components) {
|
void number_equations();
|
||||||
DofKey key{node_id, component};
|
|
||||||
if (find_record(key) == records_.end()) {
|
|
||||||
records_.push_back({key});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply_boundary_condition(const model::BoundaryCondition& bc)
|
int total_dof_count() const;
|
||||||
{
|
int free_dof_count() const;
|
||||||
auto record = find_record({bc.node_id(), bc.component()});
|
int constrained_dof_count() const;
|
||||||
if (record == records_.end()) {
|
bool is_constrained(DofKey key) const;
|
||||||
throw std::invalid_argument("boundary condition references undefined dof");
|
int equation_id(DofKey key) const;
|
||||||
}
|
std::optional<int> free_equation_id(DofKey key) const;
|
||||||
record->constrained = true;
|
std::vector<double> expand_free_vector(const std::vector<double>& free_values) const;
|
||||||
}
|
const std::vector<std::pair<int, int>>& sparse_pattern() const;
|
||||||
|
|
||||||
void number_equations()
|
|
||||||
{
|
|
||||||
std::sort(records_.begin(), records_.end(), [](const Record& lhs, const Record& rhs) {
|
|
||||||
if (lhs.key.node_id.value != rhs.key.node_id.value) {
|
|
||||||
return lhs.key.node_id.value < rhs.key.node_id.value;
|
|
||||||
}
|
|
||||||
return static_cast<int>(lhs.key.component) < static_cast<int>(rhs.key.component);
|
|
||||||
});
|
|
||||||
|
|
||||||
int free_id = 0;
|
|
||||||
for (int equation_id = 0; equation_id < static_cast<int>(records_.size()); ++equation_id) {
|
|
||||||
records_[equation_id].equation_id = equation_id;
|
|
||||||
if (records_[equation_id].constrained) {
|
|
||||||
records_[equation_id].free_equation_id = std::nullopt;
|
|
||||||
} else {
|
|
||||||
records_[equation_id].free_equation_id = free_id++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sparse_pattern_.clear();
|
|
||||||
for (int row = 0; row < free_id; ++row) {
|
|
||||||
for (int column = 0; column < free_id; ++column) {
|
|
||||||
sparse_pattern_.push_back({row, column});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int total_dof_count() const
|
|
||||||
{
|
|
||||||
return static_cast<int>(records_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
int free_dof_count() const
|
|
||||||
{
|
|
||||||
return static_cast<int>(
|
|
||||||
std::count_if(records_.begin(), records_.end(), [](const Record& record) {
|
|
||||||
return !record.constrained;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
int constrained_dof_count() const
|
|
||||||
{
|
|
||||||
return total_dof_count() - free_dof_count();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_constrained(DofKey key) const
|
|
||||||
{
|
|
||||||
return require_record(key).constrained;
|
|
||||||
}
|
|
||||||
|
|
||||||
int equation_id(DofKey key) const
|
|
||||||
{
|
|
||||||
return require_record(key).equation_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<int> free_equation_id(DofKey key) const
|
|
||||||
{
|
|
||||||
return require_record(key).free_equation_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> expand_free_vector(const std::vector<double>& free_values) const
|
|
||||||
{
|
|
||||||
if (free_values.size() != static_cast<std::size_t>(free_dof_count())) {
|
|
||||||
throw std::invalid_argument("free vector size does not match dof manager");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> full(records_.size(), 0.0);
|
|
||||||
for (const auto& record : records_) {
|
|
||||||
if (record.free_equation_id.has_value()) {
|
|
||||||
full[static_cast<std::size_t>(record.equation_id)] =
|
|
||||||
free_values[static_cast<std::size_t>(*record.free_equation_id)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return full;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::pair<int, int>>& sparse_pattern() const
|
|
||||||
{
|
|
||||||
return sparse_pattern_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Record {
|
struct Record {
|
||||||
@@ -121,28 +31,9 @@ private:
|
|||||||
std::optional<int> free_equation_id;
|
std::optional<int> free_equation_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Record>::iterator find_record(DofKey key)
|
std::vector<Record>::iterator find_record(DofKey key);
|
||||||
{
|
std::vector<Record>::const_iterator find_record(DofKey key) const;
|
||||||
return std::find_if(records_.begin(), records_.end(), [key](const Record& record) {
|
const Record& require_record(DofKey key) const;
|
||||||
return record.key == key;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Record>::const_iterator find_record(DofKey key) const
|
|
||||||
{
|
|
||||||
return std::find_if(records_.begin(), records_.end(), [key](const Record& record) {
|
|
||||||
return record.key == key;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const Record& require_record(DofKey key) const
|
|
||||||
{
|
|
||||||
const auto record = find_record(key);
|
|
||||||
if (record == records_.end()) {
|
|
||||||
throw std::invalid_argument("dof is not defined");
|
|
||||||
}
|
|
||||||
return *record;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Record> records_;
|
std::vector<Record> records_;
|
||||||
std::vector<std::pair<int, int>> sparse_pattern_;
|
std::vector<std::pair<int, int>> sparse_pattern_;
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#include <fesa/model/analysis_step.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
AnalysisStep::AnalysisStep(core::StepId id, std::string name)
|
||||||
|
: id_(id), name_(std::move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::StepId AnalysisStep::id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& AnalysisStep::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalysisStep::add_boundary_condition(BoundaryCondition bc)
|
||||||
|
{
|
||||||
|
boundary_conditions_.push_back(std::move(bc));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalysisStep::add_load(Load load)
|
||||||
|
{
|
||||||
|
loads_.push_back(std::move(load));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<BoundaryCondition>& AnalysisStep::boundary_conditions() const
|
||||||
|
{
|
||||||
|
return boundary_conditions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Load>& AnalysisStep::loads() const
|
||||||
|
{
|
||||||
|
return loads_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
@@ -4,47 +4,20 @@
|
|||||||
#include <fesa/model/load.hpp>
|
#include <fesa/model/load.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::model {
|
namespace fesa::model {
|
||||||
|
|
||||||
class AnalysisStep {
|
class AnalysisStep {
|
||||||
public:
|
public:
|
||||||
AnalysisStep(core::StepId id, std::string name)
|
AnalysisStep(core::StepId id, std::string name);
|
||||||
: id_(id), name_(std::move(name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::StepId id() const
|
core::StepId id() const;
|
||||||
{
|
const std::string& name() const;
|
||||||
return id_;
|
void add_boundary_condition(BoundaryCondition bc);
|
||||||
}
|
void add_load(Load load);
|
||||||
|
const std::vector<BoundaryCondition>& boundary_conditions() const;
|
||||||
const std::string& name() const
|
const std::vector<Load>& loads() const;
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_boundary_condition(BoundaryCondition bc)
|
|
||||||
{
|
|
||||||
boundary_conditions_.push_back(std::move(bc));
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_load(Load load)
|
|
||||||
{
|
|
||||||
loads_.push_back(std::move(load));
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<BoundaryCondition>& boundary_conditions() const
|
|
||||||
{
|
|
||||||
return boundary_conditions_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Load>& loads() const
|
|
||||||
{
|
|
||||||
return loads_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::StepId id_;
|
core::StepId id_;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <fesa/model/boundary_condition.hpp>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
BoundaryCondition::BoundaryCondition(core::NodeId node_id, DofComponent component, double value)
|
||||||
|
: node_id_(node_id), component_(component), value_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::NodeId BoundaryCondition::node_id() const
|
||||||
|
{
|
||||||
|
return node_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DofComponent BoundaryCondition::component() const
|
||||||
|
{
|
||||||
|
return component_;
|
||||||
|
}
|
||||||
|
|
||||||
|
double BoundaryCondition::value() const
|
||||||
|
{
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
@@ -16,25 +16,11 @@ enum class DofComponent {
|
|||||||
|
|
||||||
class BoundaryCondition {
|
class BoundaryCondition {
|
||||||
public:
|
public:
|
||||||
BoundaryCondition(core::NodeId node_id, DofComponent component, double value)
|
BoundaryCondition(core::NodeId node_id, DofComponent component, double value);
|
||||||
: node_id_(node_id), component_(component), value_(value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::NodeId node_id() const
|
core::NodeId node_id() const;
|
||||||
{
|
DofComponent component() const;
|
||||||
return node_id_;
|
double value() const;
|
||||||
}
|
|
||||||
|
|
||||||
DofComponent component() const
|
|
||||||
{
|
|
||||||
return component_;
|
|
||||||
}
|
|
||||||
|
|
||||||
double value() const
|
|
||||||
{
|
|
||||||
return value_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::NodeId node_id_;
|
core::NodeId node_id_;
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#include <fesa/model/domain.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
void Domain::add_node(Node node)
|
||||||
|
{
|
||||||
|
nodes_.push_back(std::move(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Domain::add_element(Element element)
|
||||||
|
{
|
||||||
|
elements_.push_back(std::move(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Domain::add_material(Material material)
|
||||||
|
{
|
||||||
|
materials_.push_back(std::move(material));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Domain::add_property(Property property)
|
||||||
|
{
|
||||||
|
properties_.push_back(std::move(property));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Domain::add_step(AnalysisStep step)
|
||||||
|
{
|
||||||
|
steps_.push_back(std::move(step));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Node>& Domain::nodes() const
|
||||||
|
{
|
||||||
|
return nodes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Element>& Domain::elements() const
|
||||||
|
{
|
||||||
|
return elements_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Material>& Domain::materials() const
|
||||||
|
{
|
||||||
|
return materials_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Property>& Domain::properties() const
|
||||||
|
{
|
||||||
|
return properties_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<AnalysisStep>& Domain::steps() const
|
||||||
|
{
|
||||||
|
return steps_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node* Domain::find_node(core::NodeId id) const
|
||||||
|
{
|
||||||
|
for (const auto& node : nodes_) {
|
||||||
|
if (node.id().value == id.value) {
|
||||||
|
return &node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Element* Domain::find_element(core::ElementId id) const
|
||||||
|
{
|
||||||
|
for (const auto& element : elements_) {
|
||||||
|
if (element.id().value == id.value) {
|
||||||
|
return &element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Material* Domain::find_material(core::MaterialId id) const
|
||||||
|
{
|
||||||
|
for (const auto& material : materials_) {
|
||||||
|
if (material.id().value == id.value) {
|
||||||
|
return &material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Property* Domain::find_property(core::PropertyId id) const
|
||||||
|
{
|
||||||
|
for (const auto& property : properties_) {
|
||||||
|
if (property.id().value == id.value) {
|
||||||
|
return &property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnalysisStep* Domain::find_step(core::StepId id) const
|
||||||
|
{
|
||||||
|
for (const auto& step : steps_) {
|
||||||
|
if (step.id().value == id.value) {
|
||||||
|
return &step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
+15
-98
@@ -6,112 +6,29 @@
|
|||||||
#include <fesa/model/node.hpp>
|
#include <fesa/model/node.hpp>
|
||||||
#include <fesa/model/property.hpp>
|
#include <fesa/model/property.hpp>
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::model {
|
namespace fesa::model {
|
||||||
|
|
||||||
class Domain {
|
class Domain {
|
||||||
public:
|
public:
|
||||||
void add_node(Node node)
|
void add_node(Node node);
|
||||||
{
|
void add_element(Element element);
|
||||||
nodes_.push_back(std::move(node));
|
void add_material(Material material);
|
||||||
}
|
void add_property(Property property);
|
||||||
|
void add_step(AnalysisStep step);
|
||||||
|
|
||||||
void add_element(Element element)
|
const std::vector<Node>& nodes() const;
|
||||||
{
|
const std::vector<Element>& elements() const;
|
||||||
elements_.push_back(std::move(element));
|
const std::vector<Material>& materials() const;
|
||||||
}
|
const std::vector<Property>& properties() const;
|
||||||
|
const std::vector<AnalysisStep>& steps() const;
|
||||||
|
|
||||||
void add_material(Material material)
|
const Node* find_node(core::NodeId id) const;
|
||||||
{
|
const Element* find_element(core::ElementId id) const;
|
||||||
materials_.push_back(std::move(material));
|
const Material* find_material(core::MaterialId id) const;
|
||||||
}
|
const Property* find_property(core::PropertyId id) const;
|
||||||
|
const AnalysisStep* find_step(core::StepId id) const;
|
||||||
void add_property(Property property)
|
|
||||||
{
|
|
||||||
properties_.push_back(std::move(property));
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_step(AnalysisStep step)
|
|
||||||
{
|
|
||||||
steps_.push_back(std::move(step));
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Node>& nodes() const
|
|
||||||
{
|
|
||||||
return nodes_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Element>& elements() const
|
|
||||||
{
|
|
||||||
return elements_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Material>& materials() const
|
|
||||||
{
|
|
||||||
return materials_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Property>& properties() const
|
|
||||||
{
|
|
||||||
return properties_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<AnalysisStep>& steps() const
|
|
||||||
{
|
|
||||||
return steps_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Node* find_node(core::NodeId id) const
|
|
||||||
{
|
|
||||||
for (const auto& node : nodes_) {
|
|
||||||
if (node.id().value == id.value) {
|
|
||||||
return &node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Element* find_element(core::ElementId id) const
|
|
||||||
{
|
|
||||||
for (const auto& element : elements_) {
|
|
||||||
if (element.id().value == id.value) {
|
|
||||||
return &element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Material* find_material(core::MaterialId id) const
|
|
||||||
{
|
|
||||||
for (const auto& material : materials_) {
|
|
||||||
if (material.id().value == id.value) {
|
|
||||||
return &material;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Property* find_property(core::PropertyId id) const
|
|
||||||
{
|
|
||||||
for (const auto& property : properties_) {
|
|
||||||
if (property.id().value == id.value) {
|
|
||||||
return &property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnalysisStep* find_step(core::StepId id) const
|
|
||||||
{
|
|
||||||
for (const auto& step : steps_) {
|
|
||||||
if (step.id().value == id.value) {
|
|
||||||
return &step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Node> nodes_;
|
std::vector<Node> nodes_;
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include <fesa/model/element.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
Element::Element(core::ElementId id,
|
||||||
|
ElementTopology topology,
|
||||||
|
std::vector<core::NodeId> node_ids,
|
||||||
|
core::PropertyId property_id)
|
||||||
|
: id_(id),
|
||||||
|
topology_(topology),
|
||||||
|
node_ids_(std::move(node_ids)),
|
||||||
|
property_id_(property_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::ElementId Element::id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementTopology Element::topology() const
|
||||||
|
{
|
||||||
|
return topology_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<core::NodeId>& Element::node_ids() const
|
||||||
|
{
|
||||||
|
return node_ids_;
|
||||||
|
}
|
||||||
|
|
||||||
|
core::PropertyId Element::property_id() const
|
||||||
|
{
|
||||||
|
return property_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <fesa/core/ids.hpp>
|
#include <fesa/core/ids.hpp>
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::model {
|
namespace fesa::model {
|
||||||
@@ -18,33 +17,12 @@ public:
|
|||||||
Element(core::ElementId id,
|
Element(core::ElementId id,
|
||||||
ElementTopology topology,
|
ElementTopology topology,
|
||||||
std::vector<core::NodeId> node_ids,
|
std::vector<core::NodeId> node_ids,
|
||||||
core::PropertyId property_id)
|
core::PropertyId property_id);
|
||||||
: id_(id),
|
|
||||||
topology_(topology),
|
|
||||||
node_ids_(std::move(node_ids)),
|
|
||||||
property_id_(property_id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::ElementId id() const
|
core::ElementId id() const;
|
||||||
{
|
ElementTopology topology() const;
|
||||||
return id_;
|
const std::vector<core::NodeId>& node_ids() const;
|
||||||
}
|
core::PropertyId property_id() const;
|
||||||
|
|
||||||
ElementTopology topology() const
|
|
||||||
{
|
|
||||||
return topology_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<core::NodeId>& node_ids() const
|
|
||||||
{
|
|
||||||
return node_ids_;
|
|
||||||
}
|
|
||||||
|
|
||||||
core::PropertyId property_id() const
|
|
||||||
{
|
|
||||||
return property_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::ElementId id_;
|
core::ElementId id_;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <fesa/model/load.hpp>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
Load::Load(core::NodeId node_id, DofComponent component, double value)
|
||||||
|
: node_id_(node_id), component_(component), value_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::NodeId Load::node_id() const
|
||||||
|
{
|
||||||
|
return node_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DofComponent Load::component() const
|
||||||
|
{
|
||||||
|
return component_;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Load::value() const
|
||||||
|
{
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
+4
-18
@@ -6,25 +6,11 @@ namespace fesa::model {
|
|||||||
|
|
||||||
class Load {
|
class Load {
|
||||||
public:
|
public:
|
||||||
Load(core::NodeId node_id, DofComponent component, double value)
|
Load(core::NodeId node_id, DofComponent component, double value);
|
||||||
: node_id_(node_id), component_(component), value_(value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::NodeId node_id() const
|
core::NodeId node_id() const;
|
||||||
{
|
DofComponent component() const;
|
||||||
return node_id_;
|
double value() const;
|
||||||
}
|
|
||||||
|
|
||||||
DofComponent component() const
|
|
||||||
{
|
|
||||||
return component_;
|
|
||||||
}
|
|
||||||
|
|
||||||
double value() const
|
|
||||||
{
|
|
||||||
return value_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::NodeId node_id_;
|
core::NodeId node_id_;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include <fesa/model/material.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
Material::Material(core::MaterialId id, std::string name)
|
||||||
|
: id_(id), name_(std::move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::MaterialId Material::id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Material::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
@@ -3,26 +3,15 @@
|
|||||||
#include <fesa/core/ids.hpp>
|
#include <fesa/core/ids.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fesa::model {
|
namespace fesa::model {
|
||||||
|
|
||||||
class Material {
|
class Material {
|
||||||
public:
|
public:
|
||||||
Material(core::MaterialId id, std::string name)
|
Material(core::MaterialId id, std::string name);
|
||||||
: id_(id), name_(std::move(name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::MaterialId id() const
|
core::MaterialId id() const;
|
||||||
{
|
const std::string& name() const;
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& name() const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::MaterialId id_;
|
core::MaterialId id_;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include <fesa/model/node.hpp>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
Node::Node(core::NodeId id, std::array<double, 3> coordinates)
|
||||||
|
: id_(id), coordinates_(coordinates)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::NodeId Node::id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array<double, 3>& Node::coordinates() const
|
||||||
|
{
|
||||||
|
return coordinates_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
+3
-13
@@ -8,20 +8,10 @@ namespace fesa::model {
|
|||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
public:
|
public:
|
||||||
Node(core::NodeId id, std::array<double, 3> coordinates)
|
Node(core::NodeId id, std::array<double, 3> coordinates);
|
||||||
: id_(id), coordinates_(coordinates)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::NodeId id() const
|
core::NodeId id() const;
|
||||||
{
|
const std::array<double, 3>& coordinates() const;
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<double, 3>& coordinates() const
|
|
||||||
{
|
|
||||||
return coordinates_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::NodeId id_;
|
core::NodeId id_;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include <fesa/model/property.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::model {
|
||||||
|
|
||||||
|
Property::Property(core::PropertyId id, std::string name, core::MaterialId material_id)
|
||||||
|
: id_(id), name_(std::move(name)), material_id_(material_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
core::PropertyId Property::id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Property::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
core::MaterialId Property::material_id() const
|
||||||
|
{
|
||||||
|
return material_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::model
|
||||||
@@ -3,31 +3,16 @@
|
|||||||
#include <fesa/core/ids.hpp>
|
#include <fesa/core/ids.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fesa::model {
|
namespace fesa::model {
|
||||||
|
|
||||||
class Property {
|
class Property {
|
||||||
public:
|
public:
|
||||||
Property(core::PropertyId id, std::string name, core::MaterialId material_id)
|
Property(core::PropertyId id, std::string name, core::MaterialId material_id);
|
||||||
: id_(id), name_(std::move(name)), material_id_(material_id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
core::PropertyId id() const
|
core::PropertyId id() const;
|
||||||
{
|
const std::string& name() const;
|
||||||
return id_;
|
core::MaterialId material_id() const;
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& name() const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
core::MaterialId material_id() const
|
|
||||||
{
|
|
||||||
return material_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::PropertyId id_;
|
core::PropertyId id_;
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include <fesa/results/results.hpp>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fesa::results {
|
||||||
|
|
||||||
|
ResultFrame::ResultFrame(int frame_id, double time)
|
||||||
|
: frame_id_(frame_id), time_(time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ResultFrame::frame_id() const
|
||||||
|
{
|
||||||
|
return frame_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ResultFrame::time() const
|
||||||
|
{
|
||||||
|
return time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResultFrame::add_field_output(FieldOutput output)
|
||||||
|
{
|
||||||
|
if (output.components.empty()) {
|
||||||
|
throw std::invalid_argument("field output must have components");
|
||||||
|
}
|
||||||
|
if (output.entity_ids.size() * output.components.size() != output.values.size()) {
|
||||||
|
throw std::invalid_argument("field output values do not match row shape");
|
||||||
|
}
|
||||||
|
field_outputs_.push_back(std::move(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResultFrame::add_history_output(HistoryOutput output)
|
||||||
|
{
|
||||||
|
history_outputs_.push_back(std::move(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<FieldOutput>& ResultFrame::field_outputs() const
|
||||||
|
{
|
||||||
|
return field_outputs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<HistoryOutput>& ResultFrame::history_outputs() const
|
||||||
|
{
|
||||||
|
return history_outputs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStep::ResultStep(std::string name)
|
||||||
|
: name_(std::move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& ResultStep::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultFrame& ResultStep::add_frame(int frame_id, double time)
|
||||||
|
{
|
||||||
|
frames_.push_back(ResultFrame{frame_id, time});
|
||||||
|
return frames_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<ResultFrame>& ResultStep::frames() const
|
||||||
|
{
|
||||||
|
return frames_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fesa::results
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fesa::results {
|
namespace fesa::results {
|
||||||
@@ -29,46 +27,14 @@ struct HistoryOutput {
|
|||||||
|
|
||||||
class ResultFrame {
|
class ResultFrame {
|
||||||
public:
|
public:
|
||||||
ResultFrame(int frame_id, double time)
|
ResultFrame(int frame_id, double time);
|
||||||
: frame_id_(frame_id), time_(time)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int frame_id() const
|
int frame_id() const;
|
||||||
{
|
double time() const;
|
||||||
return frame_id_;
|
void add_field_output(FieldOutput output);
|
||||||
}
|
void add_history_output(HistoryOutput output);
|
||||||
|
const std::vector<FieldOutput>& field_outputs() const;
|
||||||
double time() const
|
const std::vector<HistoryOutput>& history_outputs() const;
|
||||||
{
|
|
||||||
return time_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_field_output(FieldOutput output)
|
|
||||||
{
|
|
||||||
if (output.components.empty()) {
|
|
||||||
throw std::invalid_argument("field output must have components");
|
|
||||||
}
|
|
||||||
if (output.entity_ids.size() * output.components.size() != output.values.size()) {
|
|
||||||
throw std::invalid_argument("field output values do not match row shape");
|
|
||||||
}
|
|
||||||
field_outputs_.push_back(std::move(output));
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_history_output(HistoryOutput output)
|
|
||||||
{
|
|
||||||
history_outputs_.push_back(std::move(output));
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<FieldOutput>& field_outputs() const
|
|
||||||
{
|
|
||||||
return field_outputs_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<HistoryOutput>& history_outputs() const
|
|
||||||
{
|
|
||||||
return history_outputs_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int frame_id_;
|
int frame_id_;
|
||||||
@@ -79,26 +45,11 @@ private:
|
|||||||
|
|
||||||
class ResultStep {
|
class ResultStep {
|
||||||
public:
|
public:
|
||||||
explicit ResultStep(std::string name)
|
explicit ResultStep(std::string name);
|
||||||
: name_(std::move(name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& name() const
|
const std::string& name() const;
|
||||||
{
|
ResultFrame& add_frame(int frame_id, double time);
|
||||||
return name_;
|
const std::vector<ResultFrame>& frames() const;
|
||||||
}
|
|
||||||
|
|
||||||
ResultFrame& add_frame(int frame_id, double time)
|
|
||||||
{
|
|
||||||
frames_.push_back(ResultFrame{frame_id, time});
|
|
||||||
return frames_.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<ResultFrame>& frames() const
|
|
||||||
{
|
|
||||||
return frames_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|||||||
Reference in New Issue
Block a user