feat: add thermal semantic domain model
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
#include "fesa/model/domain.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "fesa/analysis/analysis_model.h"
|
||||
#include "fesa/elements/ds4_thermal.h"
|
||||
#include "fesa/materials/isotropic_thermal_material.h"
|
||||
|
||||
namespace {
|
||||
|
||||
fesa::SourceLocation Location() { return {"models/thermal.inp", 10U}; }
|
||||
|
||||
fesa::ModelDefinition ValidDefinition() {
|
||||
fesa::ModelDefinition definition{};
|
||||
definition.source_path = "models/thermal.inp";
|
||||
definition.nodes = {
|
||||
{{"Plate", 1, "1"}, {0.0, 0.0, 0.0}, Location()},
|
||||
{{"Plate", 2, "2"}, {1.0, 0.0, 0.0}, Location()},
|
||||
{{"Plate", 3, "3"}, {1.0, 1.0, 0.0}, Location()},
|
||||
{{"Plate", 4, "4"}, {0.0, 1.0, 0.0}, Location()},
|
||||
{{"Plate", 5, "5"}, {2.0, 2.0, 0.0}, Location()}};
|
||||
definition.thermal_materials = {
|
||||
{{"", 1, "Thermal-Steel"}, "Thermal-Steel", 45.0, 7800.0, 500.0,
|
||||
Location()}};
|
||||
definition.thermal_sections = {
|
||||
{{"", 1, "Section"}, "Section", 0.01, 0U, Location()}};
|
||||
definition.thermal_elements = {{{"Plate", 8, "8"}, {0U, 1U, 2U, 3U},
|
||||
0U, Location()}};
|
||||
definition.thermal_initial_conditions = {{0U, 12.5, Location()}};
|
||||
definition.thermal_model_boundaries = {{0U, 11, 10.0, Location()}};
|
||||
definition.thermal_step = {"Heat", 0.2, 1.0, 100U, false,
|
||||
{{0U, 11, 20.0, Location()}},
|
||||
{{0U, 15, -5.0, Location()}}, Location()};
|
||||
return definition;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(IsotropicThermalMaterial, RequiresFinitePositivePropertiesAndIdentity) {
|
||||
const auto valid = fesa::IsotropicThermalMaterial::Create(
|
||||
{"", 7, "Thermal-Steel"}, "Thermal-Steel", 45.0, 7800.0, 500.0,
|
||||
Location());
|
||||
ASSERT_TRUE(valid.HasValue());
|
||||
EXPECT_EQ(valid.Value().Kind(), fesa::MaterialKind::kIsotropicThermal);
|
||||
EXPECT_DOUBLE_EQ(valid.Value().Conductivity(), 45.0);
|
||||
EXPECT_DOUBLE_EQ(valid.Value().Density(), 7800.0);
|
||||
EXPECT_DOUBLE_EQ(valid.Value().SpecificHeat(), 500.0);
|
||||
|
||||
const auto invalid = fesa::IsotropicThermalMaterial::Create(
|
||||
{"", 7, "Thermal-Steel"}, "Thermal-Steel",
|
||||
std::numeric_limits<double>::infinity(), 7800.0, 500.0, Location());
|
||||
ASSERT_FALSE(invalid.HasValue());
|
||||
EXPECT_EQ(invalid.GetStatus().Category(), fesa::FailureCategory::kModel);
|
||||
}
|
||||
|
||||
TEST(ThermalDomain, OwnsFiveStationDefinitionsWithoutEquationState) {
|
||||
static_assert(!std::is_copy_constructible_v<fesa::Domain>);
|
||||
static_assert(std::is_move_constructible_v<fesa::Domain>);
|
||||
static_assert(std::has_virtual_destructor_v<fesa::ElementDefinition>);
|
||||
|
||||
const auto result = fesa::Domain::Create(ValidDefinition());
|
||||
ASSERT_TRUE(result.HasValue());
|
||||
const fesa::Domain& domain = result.Value();
|
||||
ASSERT_NE(domain.ThermalStep(), nullptr);
|
||||
EXPECT_EQ(domain.ThermalElements().Size(), 1U);
|
||||
EXPECT_EQ(domain.ThermalElements()[0U].Kind(),
|
||||
fesa::ElementDefinitionKind::kDs4Thermal);
|
||||
EXPECT_EQ(domain.ThermalElements()[0U].NodeIndices(),
|
||||
(std::vector<fesa::EntityIndex>{0U, 1U, 2U, 3U}));
|
||||
EXPECT_EQ(domain.ThermalInitialConditions()[0U].station_values,
|
||||
(std::array<double, 5>{12.5, 12.5, 12.5, 12.5, 12.5}));
|
||||
EXPECT_EQ(domain.ThermalStep()->Boundaries()[0U].value, 20.0);
|
||||
EXPECT_EQ(domain.ThermalStep()->Loads()[0U].source_order, 0U);
|
||||
}
|
||||
|
||||
TEST(ThermalDomain, RejectsInactiveTargetsConflictsAndMixedElements) {
|
||||
auto invalid = ValidDefinition();
|
||||
invalid.thermal_initial_conditions.push_back({4U, 12.5, Location()});
|
||||
const auto inactive = fesa::Domain::Create(std::move(invalid));
|
||||
ASSERT_FALSE(inactive.HasValue());
|
||||
EXPECT_EQ(inactive.GetStatus().Category(), fesa::FailureCategory::kModel);
|
||||
|
||||
invalid = ValidDefinition();
|
||||
invalid.thermal_step->boundaries.push_back({0U, 11, 21.0, Location()});
|
||||
const auto conflicting = fesa::Domain::Create(std::move(invalid));
|
||||
ASSERT_FALSE(conflicting.HasValue());
|
||||
EXPECT_EQ(conflicting.GetStatus().Category(), fesa::FailureCategory::kModel);
|
||||
|
||||
invalid = ValidDefinition();
|
||||
invalid.elements.push_back(
|
||||
{{"Plate", 9, "9"}, {0U, 1U}, 0U, 0U, Location()});
|
||||
const auto mixed = fesa::Domain::Create(std::move(invalid));
|
||||
ASSERT_FALSE(mixed.HasValue());
|
||||
EXPECT_EQ(mixed.GetStatus().Category(), fesa::FailureCategory::kModel);
|
||||
}
|
||||
|
||||
TEST(ThermalDomain, AllowsEqualInitialTargetsAndStepBoundaryOverride) {
|
||||
auto definition = ValidDefinition();
|
||||
definition.thermal_initial_conditions.push_back({0U, 12.5, Location()});
|
||||
const auto equal_initial = fesa::Domain::Create(std::move(definition));
|
||||
EXPECT_TRUE(equal_initial.HasValue());
|
||||
|
||||
definition = ValidDefinition();
|
||||
definition.thermal_initial_conditions.push_back({0U, 13.0, Location()});
|
||||
const auto conflicting_initial = fesa::Domain::Create(std::move(definition));
|
||||
ASSERT_FALSE(conflicting_initial.HasValue());
|
||||
EXPECT_EQ(conflicting_initial.GetStatus().Category(),
|
||||
fesa::FailureCategory::kModel);
|
||||
|
||||
definition = ValidDefinition();
|
||||
definition.thermal_step->boundaries.push_back({0U, 11, 20.0, Location()});
|
||||
const auto overriding_step = fesa::Domain::Create(std::move(definition));
|
||||
EXPECT_TRUE(overriding_step.HasValue());
|
||||
}
|
||||
|
||||
TEST(ThermalAnalysisModel, ViewsConnectedDs4EntitiesWithoutOwningDomain) {
|
||||
auto domain_result = fesa::Domain::Create(ValidDefinition());
|
||||
ASSERT_TRUE(domain_result.HasValue());
|
||||
const fesa::Domain& domain = domain_result.Value();
|
||||
|
||||
const auto model_result = fesa::AnalysisModel::Create(domain);
|
||||
ASSERT_TRUE(model_result.HasValue());
|
||||
const fesa::AnalysisModel& model = model_result.Value();
|
||||
EXPECT_TRUE(model.IsThermal());
|
||||
EXPECT_EQ(model.ThermalStep(), domain.ThermalStep());
|
||||
EXPECT_EQ(model.ActiveThermalElements(),
|
||||
(std::vector<fesa::EntityIndex>{0U}));
|
||||
EXPECT_EQ(model.ActiveThermalNodes(),
|
||||
(std::vector<fesa::EntityIndex>{0U, 1U, 2U, 3U}));
|
||||
EXPECT_EQ(&model.GetDomain(), &domain);
|
||||
}
|
||||
Reference in New Issue
Block a user