feat: add analysis model objects
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user