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
+31
View File
@@ -0,0 +1,31 @@
#include "fesa/boundary/BoundaryCondition.hpp"
#include "fesa/boundary/SinglePointConstraint.hpp"
#include <memory>
namespace {
int require(bool condition) {
return condition ? 0 : 1;
}
} // namespace
int run_boundary_base_tests() {
std::unique_ptr<fesa::boundary::BoundaryCondition> owned =
std::make_unique<fesa::boundary::SinglePointConstraint>(1, fesa::core::Dof::UR3, 0.25);
const fesa::boundary::BoundaryCondition& boundary = *owned;
const auto& spc = static_cast<const fesa::boundary::SinglePointConstraint&>(boundary);
if (const int result = require(boundary.kind() == fesa::boundary::BoundaryConditionKind::SinglePointConstraint);
result != 0) {
return result;
}
if (const int result = require(spc.nodeId() == 1); result != 0) {
return result;
}
if (const int result = require(spc.dof() == fesa::core::Dof::UR3); result != 0) {
return result;
}
return require(spc.value() == 0.25);
}
+4
View File
@@ -1,4 +1,5 @@
int run_boundary_condition_tests();
int run_domain_model_object_tests();
int run_domain_storage_tests();
int run_element_definition_tests();
int run_load_definition_tests();
@@ -27,6 +28,9 @@ int main() {
if (const int result = run_boundary_condition_tests(); result != 0) {
return result;
}
if (const int result = run_domain_model_object_tests(); result != 0) {
return result;
}
if (const int result = run_load_definition_tests(); result != 0) {
return result;
}
+169
View File
@@ -0,0 +1,169 @@
#include "fesa/boundary/SinglePointConstraint.hpp"
#include "fesa/core/Domain.hpp"
#include "fesa/element/Mitc4Element.hpp"
#include "fesa/load/NodalLoad.hpp"
#include "fesa/material/LinearElasticMaterial.hpp"
#include <memory>
#include <stdexcept>
namespace {
int require(bool condition) {
return condition ? 0 : 1;
}
template <typename Exception, typename Function>
int require_throws(Function&& function) {
try {
function();
} catch (const Exception&) {
return 0;
} catch (...) {
return 1;
}
return 1;
}
fesa::core::Domain populated_domain() {
fesa::core::Domain domain;
domain.addNode(fesa::core::Node{1, 0.0, 0.0, 0.0});
domain.addNode(fesa::core::Node{2, 1.0, 0.0, 0.0});
domain.addNode(fesa::core::Node{3, 1.0, 1.0, 0.0});
domain.addNode(fesa::core::Node{4, 0.0, 1.0, 0.0});
return domain;
}
int domain_owns_element_and_material_objects() {
fesa::core::Domain domain = populated_domain();
domain.addElementObject(std::make_unique<fesa::element::Mitc4Element>(
100,
std::array<fesa::core::NodeId, 4>{1, 2, 3, 4},
500));
domain.addMaterialObject(std::make_unique<fesa::material::LinearElasticMaterial>(700, 210.0, 0.3));
const fesa::element::Element* element = domain.findElementObject(100);
if (const int result = require(element != nullptr); result != 0) {
return result;
}
if (const int result = require(element->type() == fesa::core::ElementType::Mitc4); result != 0) {
return result;
}
if (const int result = require(domain.elementObject(100).propertyId() == 500); result != 0) {
return result;
}
const fesa::material::Material* material = domain.findMaterialObject(700);
if (const int result = require(material != nullptr); result != 0) {
return result;
}
return require(domain.materialObject(700).id() == 700);
}
int duplicate_element_and_material_object_ids_throw() {
fesa::core::Domain domain = populated_domain();
domain.addElementObject(std::make_unique<fesa::element::Mitc4Element>(
100,
std::array<fesa::core::NodeId, 4>{1, 2, 3, 4},
500));
domain.addMaterialObject(std::make_unique<fesa::material::LinearElasticMaterial>(700, 210.0, 0.3));
if (const int result = require_throws<std::invalid_argument>([&domain]() {
domain.addElementObject(std::make_unique<fesa::element::Mitc4Element>(
100,
std::array<fesa::core::NodeId, 4>{1, 2, 3, 4},
500));
});
result != 0) {
return result;
}
return require_throws<std::invalid_argument>([&domain]() {
domain.addMaterialObject(std::make_unique<fesa::material::LinearElasticMaterial>(700, 100.0, 0.25));
});
}
int missing_model_object_direct_lookup_throws() {
const fesa::core::Domain domain;
if (const int result = require(domain.findElementObject(404) == nullptr); result != 0) {
return result;
}
if (const int result = require(domain.findMaterialObject(404) == nullptr); result != 0) {
return result;
}
if (const int result = require_throws<std::out_of_range>([&domain]() {
(void)domain.elementObject(404);
});
result != 0) {
return result;
}
return require_throws<std::out_of_range>([&domain]() {
(void)domain.materialObject(404);
});
}
int domain_owns_load_and_boundary_objects_by_index() {
fesa::core::Domain domain = populated_domain();
const std::size_t load_index = domain.addLoadObject(
std::make_unique<fesa::load::NodalLoad>(1, fesa::core::Dof::U3, -100.0));
const std::size_t boundary_index = domain.addBoundaryObject(
std::make_unique<fesa::boundary::SinglePointConstraint>(1, fesa::core::Dof::U1, 0.0));
if (const int result = require(load_index == 0); result != 0) {
return result;
}
if (const int result = require(boundary_index == 0); result != 0) {
return result;
}
if (const int result = require(domain.findLoadObject(load_index) != nullptr); result != 0) {
return result;
}
if (const int result = require(domain.findBoundaryObject(boundary_index) != nullptr); result != 0) {
return result;
}
if (const int result = require(domain.loadObject(load_index).kind() == fesa::load::LoadKind::Nodal); result != 0) {
return result;
}
return require(
domain.boundaryObject(boundary_index).kind() ==
fesa::boundary::BoundaryConditionKind::SinglePointConstraint);
}
int duplicate_load_and_boundary_keys_throw() {
fesa::core::Domain domain = populated_domain();
domain.addLoadObject(std::make_unique<fesa::load::NodalLoad>(1, fesa::core::Dof::U3, -100.0));
domain.addBoundaryObject(std::make_unique<fesa::boundary::SinglePointConstraint>(1, fesa::core::Dof::U1, 0.0));
if (const int result = require_throws<std::invalid_argument>([&domain]() {
domain.addLoadObject(std::make_unique<fesa::load::NodalLoad>(1, fesa::core::Dof::U3, -200.0));
});
result != 0) {
return result;
}
return require_throws<std::invalid_argument>([&domain]() {
domain.addBoundaryObject(std::make_unique<fesa::boundary::SinglePointConstraint>(1, fesa::core::Dof::U1, 1.0));
});
}
} // namespace
int run_domain_model_object_tests() {
if (const int result = domain_owns_element_and_material_objects(); result != 0) {
return result;
}
if (const int result = duplicate_element_and_material_object_ids_throw(); result != 0) {
return result;
}
if (const int result = missing_model_object_direct_lookup_throws(); result != 0) {
return result;
}
if (const int result = domain_owns_load_and_boundary_objects_by_index(); result != 0) {
return result;
}
if (const int result = duplicate_load_and_boundary_keys_throw(); result != 0) {
return result;
}
return 0;
}
+10
View File
@@ -1,5 +1,8 @@
#include "fesa/core/Node.hpp"
#include <array>
#include <type_traits>
namespace {
int require(bool condition) {
@@ -11,6 +14,9 @@ int require(bool condition) {
int run_node_tests() {
const fesa::core::Node node{42, 1.0, 2.0, 3.0};
if (const int result = require(fesa::core::Node::dofCount() == 6); result != 0) {
return result;
}
if (const int result = require(node.id() == 42); result != 0) {
return result;
}
@@ -32,6 +38,10 @@ int run_node_tests() {
if (const int result = require(node.coordinates()[2] == 3.0); result != 0) {
return result;
}
if (const int result = require((std::is_same<decltype(node.coordinates()), const std::array<double, 3>&>::value));
result != 0) {
return result;
}
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
#include "fesa/element/Element.hpp"
#include <array>
#include <memory>
namespace {
using fesa::element::ElementId;
using fesa::element::ElementType;
using fesa::element::NodeId;
using fesa::element::PropertyId;
int require(bool condition) {
return condition ? 0 : 1;
}
class TestElement final : public fesa::element::Element {
public:
ElementId id() const noexcept override { return 100; }
ElementType type() const noexcept override { return ElementType::Mitc4; }
std::size_t nodeCount() const noexcept override { return connectivity_.size(); }
const std::array<NodeId, 4>& connectivity() const noexcept override { return connectivity_; }
PropertyId propertyId() const noexcept override { return 500; }
private:
std::array<NodeId, 4> connectivity_{1, 2, 3, 4};
};
} // namespace
int run_element_base_tests() {
std::unique_ptr<fesa::element::Element> owned = std::make_unique<TestElement>();
const fesa::element::Element& element = *owned;
if (const int result = require(element.id() == 100); result != 0) {
return result;
}
if (const int result = require(element.type() == fesa::core::ElementType::Mitc4); result != 0) {
return result;
}
if (const int result = require(element.nodeCount() == 4); result != 0) {
return result;
}
if (const int result = require(element.connectivity()[0] == 1); result != 0) {
return result;
}
if (const int result = require(element.connectivity()[3] == 4); result != 0) {
return result;
}
return require(element.propertyId() == 500);
}
@@ -0,0 +1,40 @@
#include "fesa/element/Mitc4Element.hpp"
namespace {
int require(bool condition) {
return condition ? 0 : 1;
}
} // namespace
int run_mitc4_element_model_tests() {
const fesa::element::Mitc4Element mitc4{100, {1, 2, 3, 4}, 500};
const fesa::element::Element& element = mitc4;
if (const int result = require(element.id() == 100); result != 0) {
return result;
}
if (const int result = require(element.type() == fesa::core::ElementType::Mitc4); result != 0) {
return result;
}
if (const int result = require(element.nodeCount() == 4); result != 0) {
return result;
}
if (const int result = require(mitc4.dofCount() == 24); result != 0) {
return result;
}
if (const int result = require(element.connectivity()[0] == 1); result != 0) {
return result;
}
if (const int result = require(element.connectivity()[1] == 2); result != 0) {
return result;
}
if (const int result = require(element.connectivity()[2] == 3); result != 0) {
return result;
}
if (const int result = require(element.connectivity()[3] == 4); result != 0) {
return result;
}
return require(element.propertyId() == 500);
}
+30
View File
@@ -0,0 +1,30 @@
#include "fesa/load/Load.hpp"
#include "fesa/load/NodalLoad.hpp"
#include <memory>
namespace {
int require(bool condition) {
return condition ? 0 : 1;
}
} // namespace
int run_load_base_tests() {
std::unique_ptr<fesa::load::Load> owned =
std::make_unique<fesa::load::NodalLoad>(1, fesa::core::Dof::U3, -100.0);
const fesa::load::Load& load = *owned;
const auto& nodal = static_cast<const fesa::load::NodalLoad&>(load);
if (const int result = require(load.kind() == fesa::load::LoadKind::Nodal); result != 0) {
return result;
}
if (const int result = require(nodal.nodeId() == 1); result != 0) {
return result;
}
if (const int result = require(nodal.dof() == fesa::core::Dof::U3); result != 0) {
return result;
}
return require(nodal.value() == -100.0);
}
+27
View File
@@ -0,0 +1,27 @@
#include "fesa/material/LinearElasticMaterial.hpp"
#include "fesa/material/Material.hpp"
#include <memory>
namespace {
int require(bool condition) {
return condition ? 0 : 1;
}
} // namespace
int run_material_base_tests() {
std::unique_ptr<fesa::material::Material> owned =
std::make_unique<fesa::material::LinearElasticMaterial>(700, 210.0, 0.3);
const fesa::material::Material& material = *owned;
const auto& elastic = static_cast<const fesa::material::LinearElasticMaterial&>(material);
if (const int result = require(material.id() == 700); result != 0) {
return result;
}
if (const int result = require(elastic.youngModulus() == 210.0); result != 0) {
return result;
}
return require(elastic.poissonRatio() == 0.3);
}
+28
View File
@@ -0,0 +1,28 @@
int run_boundary_base_tests();
int run_element_base_tests();
int run_load_base_tests();
int run_material_base_tests();
int run_mitc4_element_model_tests();
int run_shell_property_tests();
int main() {
if (const int result = run_boundary_base_tests(); result != 0) {
return result;
}
if (const int result = run_element_base_tests(); result != 0) {
return result;
}
if (const int result = run_mitc4_element_model_tests(); result != 0) {
return result;
}
if (const int result = run_material_base_tests(); result != 0) {
return result;
}
if (const int result = run_shell_property_tests(); result != 0) {
return result;
}
if (const int result = run_load_base_tests(); result != 0) {
return result;
}
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
#include "fesa/property/ShellProperty.hpp"
#include <stdexcept>
namespace {
int require(bool condition) {
return condition ? 0 : 1;
}
template <typename Exception, typename Function>
int require_throws(Function&& function) {
try {
function();
} catch (const Exception&) {
return 0;
} catch (...) {
return 1;
}
return 1;
}
} // namespace
int run_shell_property_tests() {
const fesa::property::ShellProperty property{500, 700, 0.01};
if (const int result = require(property.id() == 500); result != 0) {
return result;
}
if (const int result = require(property.materialId() == 700); result != 0) {
return result;
}
if (const int result = require(property.thickness() == 0.01); result != 0) {
return result;
}
if (const int result = require_throws<std::invalid_argument>([]() {
(void)fesa::property::ShellProperty{501, 700, 0.0};
});
result != 0) {
return result;
}
return require_throws<std::invalid_argument>([]() {
(void)fesa::property::ShellProperty{502, 700, -0.01};
});
}