feat: add analysis model objects

This commit is contained in:
김경종
2026-06-09 09:04:21 +09:00
parent fdeac602f4
commit 8f24213ab7
44 changed files with 1893 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
#include "fesa/boundary/SinglePointConstraint.hpp"
namespace fesa::boundary {
SinglePointConstraint::SinglePointConstraint(NodeId node_id, Dof dof, double value)
: node_id_(node_id), dof_(dof), value_(value) {}
BoundaryConditionKind SinglePointConstraint::kind() const noexcept {
return BoundaryConditionKind::SinglePointConstraint;
}
NodeId SinglePointConstraint::nodeId() const noexcept {
return node_id_;
}
Dof SinglePointConstraint::dof() const noexcept {
return dof_;
}
double SinglePointConstraint::value() const noexcept {
return value_;
}
} // namespace fesa::boundary
+135
View File
@@ -1,5 +1,8 @@
#include "fesa/core/Domain.hpp"
#include "fesa/boundary/SinglePointConstraint.hpp"
#include "fesa/load/NodalLoad.hpp"
#include <stdexcept>
#include <utility>
@@ -243,6 +246,72 @@ void Domain::addStep(LinearStaticStepDefinition step) {
steps_.emplace(id, std::move(step));
}
void Domain::addElementObject(std::unique_ptr<fesa::element::Element> element) {
if (!element) {
throw std::invalid_argument("element object is null");
}
const ElementId id = element->id();
if (element_objects_.find(id) != element_objects_.end()) {
throw std::invalid_argument("duplicate element object id");
}
for (const NodeId node_id : element->connectivity()) {
if (findNode(node_id) == nullptr) {
throw std::invalid_argument("element object references missing node id");
}
}
element_objects_.emplace(id, std::move(element));
}
void Domain::addMaterialObject(std::unique_ptr<fesa::material::Material> material) {
if (!material) {
throw std::invalid_argument("material object is null");
}
const MaterialId id = material->id();
const auto inserted = material_objects_.emplace(id, std::move(material));
if (!inserted.second) {
throw std::invalid_argument("duplicate material object id");
}
}
std::size_t Domain::addLoadObject(std::unique_ptr<fesa::load::Load> load) {
if (!load) {
throw std::invalid_argument("load object is null");
}
if (const auto* nodal = dynamic_cast<const fesa::load::NodalLoad*>(load.get())) {
for (const auto& existing : load_objects_) {
const auto* existing_nodal = dynamic_cast<const fesa::load::NodalLoad*>(existing.get());
if (existing_nodal != nullptr &&
existing_nodal->nodeId() == nodal->nodeId() &&
existing_nodal->dof() == nodal->dof()) {
throw std::invalid_argument("duplicate nodal load key");
}
}
}
const std::size_t index = load_objects_.size();
load_objects_.push_back(std::move(load));
return index;
}
std::size_t Domain::addBoundaryObject(std::unique_ptr<fesa::boundary::BoundaryCondition> boundary) {
if (!boundary) {
throw std::invalid_argument("boundary object is null");
}
if (const auto* spc = dynamic_cast<const fesa::boundary::SinglePointConstraint*>(boundary.get())) {
for (const auto& existing : boundary_objects_) {
const auto* existing_spc =
dynamic_cast<const fesa::boundary::SinglePointConstraint*>(existing.get());
if (existing_spc != nullptr &&
existing_spc->nodeId() == spc->nodeId() &&
existing_spc->dof() == spc->dof()) {
throw std::invalid_argument("duplicate boundary object key");
}
}
}
const std::size_t index = boundary_objects_.size();
boundary_objects_.push_back(std::move(boundary));
return index;
}
const Node* Domain::findNode(NodeId id) const noexcept {
const auto it = nodes_.find(id);
return it == nodes_.end() ? nullptr : &it->second;
@@ -378,4 +447,70 @@ std::size_t Domain::stepCount() const noexcept {
return steps_.size();
}
const fesa::element::Element* Domain::findElementObject(ElementId id) const noexcept {
const auto it = element_objects_.find(id);
return it == element_objects_.end() ? nullptr : it->second.get();
}
const fesa::element::Element& Domain::elementObject(ElementId id) const {
const fesa::element::Element* found = findElementObject(id);
if (found == nullptr) {
throw std::out_of_range("element object id not found");
}
return *found;
}
std::size_t Domain::elementObjectCount() const noexcept {
return element_objects_.size();
}
const fesa::material::Material* Domain::findMaterialObject(MaterialId id) const noexcept {
const auto it = material_objects_.find(id);
return it == material_objects_.end() ? nullptr : it->second.get();
}
const fesa::material::Material& Domain::materialObject(MaterialId id) const {
const fesa::material::Material* found = findMaterialObject(id);
if (found == nullptr) {
throw std::out_of_range("material object id not found");
}
return *found;
}
std::size_t Domain::materialObjectCount() const noexcept {
return material_objects_.size();
}
const fesa::load::Load* Domain::findLoadObject(std::size_t index) const noexcept {
return index < load_objects_.size() ? load_objects_[index].get() : nullptr;
}
const fesa::load::Load& Domain::loadObject(std::size_t index) const {
const fesa::load::Load* found = findLoadObject(index);
if (found == nullptr) {
throw std::out_of_range("load object index not found");
}
return *found;
}
std::size_t Domain::loadObjectCount() const noexcept {
return load_objects_.size();
}
const fesa::boundary::BoundaryCondition* Domain::findBoundaryObject(std::size_t index) const noexcept {
return index < boundary_objects_.size() ? boundary_objects_[index].get() : nullptr;
}
const fesa::boundary::BoundaryCondition& Domain::boundaryObject(std::size_t index) const {
const fesa::boundary::BoundaryCondition* found = findBoundaryObject(index);
if (found == nullptr) {
throw std::out_of_range("boundary object index not found");
}
return *found;
}
std::size_t Domain::boundaryObjectCount() const noexcept {
return boundary_objects_.size();
}
} // namespace fesa::core
+37
View File
@@ -0,0 +1,37 @@
#include "fesa/element/Mitc4Element.hpp"
#include "fesa/core/Node.hpp"
namespace fesa::element {
Mitc4Element::Mitc4Element(
ElementId id,
std::array<NodeId, 4> connectivity,
PropertyId property_id)
: id_(id), connectivity_(connectivity), property_id_(property_id) {}
ElementId Mitc4Element::id() const noexcept {
return id_;
}
ElementType Mitc4Element::type() const noexcept {
return ElementType::Mitc4;
}
std::size_t Mitc4Element::nodeCount() const noexcept {
return connectivity_.size();
}
std::size_t Mitc4Element::dofCount() const noexcept {
return connectivity_.size() * fesa::core::Node::dofCount();
}
const std::array<NodeId, 4>& Mitc4Element::connectivity() const noexcept {
return connectivity_;
}
PropertyId Mitc4Element::propertyId() const noexcept {
return property_id_;
}
} // namespace fesa::element
+24
View File
@@ -0,0 +1,24 @@
#include "fesa/load/NodalLoad.hpp"
namespace fesa::load {
NodalLoad::NodalLoad(NodeId node_id, Dof dof, double value)
: node_id_(node_id), dof_(dof), value_(value) {}
LoadKind NodalLoad::kind() const noexcept {
return LoadKind::Nodal;
}
NodeId NodalLoad::nodeId() const noexcept {
return node_id_;
}
Dof NodalLoad::dof() const noexcept {
return dof_;
}
double NodalLoad::value() const noexcept {
return value_;
}
} // namespace fesa::load
+23
View File
@@ -0,0 +1,23 @@
#include "fesa/material/LinearElasticMaterial.hpp"
namespace fesa::material {
LinearElasticMaterial::LinearElasticMaterial(
MaterialId id,
double young_modulus,
double poisson_ratio)
: id_(id), young_modulus_(young_modulus), poisson_ratio_(poisson_ratio) {}
MaterialId LinearElasticMaterial::id() const noexcept {
return id_;
}
double LinearElasticMaterial::youngModulus() const noexcept {
return young_modulus_;
}
double LinearElasticMaterial::poissonRatio() const noexcept {
return poisson_ratio_;
}
} // namespace fesa::material
+26
View File
@@ -0,0 +1,26 @@
#include "fesa/property/ShellProperty.hpp"
#include <stdexcept>
namespace fesa::property {
ShellProperty::ShellProperty(PropertyId id, MaterialId material_id, double thickness)
: id_(id), material_id_(material_id), thickness_(thickness) {
if (thickness <= 0.0) {
throw std::invalid_argument("shell property thickness must be positive");
}
}
PropertyId ShellProperty::id() const noexcept {
return id_;
}
MaterialId ShellProperty::materialId() const noexcept {
return material_id_;
}
double ShellProperty::thickness() const noexcept {
return thickness_;
}
} // namespace fesa::property