feat(cpp-object-oriented-modular-refactoring): step 4 - model-element-google-style

This commit is contained in:
KOKO\Mimi
2026-08-16 05:37:40 +09:00
parent 34ab8b5bf1
commit 8bc0ea2f8e
46 changed files with 5184 additions and 5323 deletions
+23 -23
View File
@@ -12,8 +12,8 @@ namespace {
fesa::ModelDefinition makeDefinition() {
const std::filesystem::path source{"models/analysis-model.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.nodes = {
{{"Beam-1", 1, "1"}, {0.0, 0.0, 0.0}, {source, 10U}},
{{"Beam-1", 2, "2"}, {1.0, 0.0, 0.0}, {source, 11U}},
@@ -57,7 +57,7 @@ fesa::ModelDefinition makeDefinition() {
} // namespace
TEST(AnalysisModel, ClassifiesActiveEntitiesInStableOrder) {
auto domainResult = fesa::Domain::create(makeDefinition());
auto domainResult = fesa::Domain::Create(makeDefinition());
ASSERT_TRUE(domainResult.HasValue());
auto modelResult = fesa::AnalysisModel::create(domainResult.Value());
@@ -82,41 +82,41 @@ TEST(AnalysisModel, ClassifiesActiveEntitiesInStableOrder) {
}
TEST(AnalysisModel, ReferencesWithoutCopyingOrMutatingDomain) {
auto domainResult = fesa::Domain::create(makeDefinition());
auto domainResult = fesa::Domain::Create(makeDefinition());
ASSERT_TRUE(domainResult.HasValue());
const fesa::Domain& domain = domainResult.Value();
const auto* const elementAddress = domain.elements().data();
const auto* const materialAddress = domain.materials().data();
const auto* const sectionAddress = domain.sections().data();
const std::string stepName = domain.steps()[0].name;
const double firstLoadMagnitude = domain.steps()[0].loads[0].magnitude;
const auto* const elementAddress = domain.Elements().data();
const auto* const materialAddress = domain.Materials().data();
const auto* const sectionAddress = domain.Sections().data();
const std::string stepName = domain.Steps()[0].name;
const double firstLoadMagnitude = domain.Steps()[0].loads[0].magnitude;
auto modelResult = fesa::AnalysisModel::create(domain);
ASSERT_TRUE(modelResult.HasValue());
const auto& model = modelResult.Value();
EXPECT_EQ(&model.domain(), &domain);
EXPECT_EQ(&model.step(), &domain.steps()[0]);
EXPECT_EQ(model.domain().elements().data(), elementAddress);
EXPECT_EQ(model.domain().materials().data(), materialAddress);
EXPECT_EQ(model.domain().sections().data(), sectionAddress);
EXPECT_EQ(&model.step(), &domain.Steps()[0]);
EXPECT_EQ(model.domain().Elements().data(), elementAddress);
EXPECT_EQ(model.domain().Materials().data(), materialAddress);
EXPECT_EQ(model.domain().Sections().data(), sectionAddress);
EXPECT_EQ(
&model.domain().elements()[model.activeElements()[1]],
&domain.elements()[1]);
&model.domain().Elements()[model.activeElements()[1]],
&domain.Elements()[1]);
EXPECT_EQ(
&model.domain().materials()[model.activeMaterials()[2]],
&domain.materials()[2]);
&model.domain().Materials()[model.activeMaterials()[2]],
&domain.Materials()[2]);
EXPECT_EQ(
&model.domain().sections()[model.activeSections()[1]],
&domain.sections()[1]);
EXPECT_EQ(domain.steps()[0].name, stepName);
EXPECT_DOUBLE_EQ(domain.steps()[0].loads[0].magnitude, firstLoadMagnitude);
&model.domain().Sections()[model.activeSections()[1]],
&domain.Sections()[1]);
EXPECT_EQ(domain.Steps()[0].name, stepName);
EXPECT_DOUBLE_EQ(domain.Steps()[0].loads[0].magnitude, firstLoadMagnitude);
}
TEST(AnalysisModel, RejectsMissingOrMultipleStep) {
auto missingDefinition = makeDefinition();
missingDefinition.steps.clear();
auto missingDomain = fesa::Domain::create(std::move(missingDefinition));
auto missingDomain = fesa::Domain::Create(std::move(missingDefinition));
ASSERT_TRUE(missingDomain.HasValue());
auto missing = fesa::AnalysisModel::create(missingDomain.Value());
@@ -136,7 +136,7 @@ TEST(AnalysisModel, RejectsMissingOrMultipleStep) {
secondStep.name = "Step-2";
secondStep.location.line = 60U;
multipleDefinition.steps.push_back(std::move(secondStep));
auto multipleDomain = fesa::Domain::create(std::move(multipleDefinition));
auto multipleDomain = fesa::Domain::Create(std::move(multipleDefinition));
ASSERT_TRUE(multipleDomain.HasValue());
auto multiple = fesa::AnalysisModel::create(multipleDomain.Value());
+7 -7
View File
@@ -49,22 +49,22 @@ struct HasNonlinearState<
fesa::DofManager makeDofs() {
fesa::ModelDefinition definition{};
definition.sourcePath = "models/analysis-state.inp";
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = "models/analysis-state.inp";
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.nodes = {
{{"Beam-1", 1, "1"}, {0.0, 0.0, 0.0}, {definition.sourcePath, 10U}},
{{"Beam-1", 2, "2"}, {1.0, 0.0, 0.0}, {definition.sourcePath, 11U}}};
{{"Beam-1", 1, "1"}, {0.0, 0.0, 0.0}, {definition.source_path, 10U}},
{{"Beam-1", 2, "2"}, {1.0, 0.0, 0.0}, {definition.source_path, 11U}}};
definition.steps = {{
"Step-1",
{{"1", 1, 6, 0.0, {definition.sourcePath, 20U}}},
{{"1", 1, 6, 0.0, {definition.source_path, 20U}}},
{},
0.1,
1.0,
0.01,
1.0,
{definition.sourcePath, 19U}}};
{definition.source_path, 19U}}};
auto domain = fesa::Domain::create(std::move(definition));
auto domain = fesa::Domain::Create(std::move(definition));
EXPECT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
EXPECT_TRUE(model.HasValue());
+12 -12
View File
@@ -2,7 +2,7 @@
#include "fesa/analysis/analysis_model.hpp"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <gtest/gtest.h>
@@ -33,8 +33,8 @@ LoadFixture makeFixture(
std::vector<fesa::NodalLoad> loads) {
const std::filesystem::path source{"models/load-assembly.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:abcdef0123456789";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:abcdef0123456789";
for (std::size_t index = 0U; index < nodeCount; ++index) {
const auto label = static_cast<std::int64_t>((index + 1U) * 10U);
definition.nodes.push_back({
@@ -42,7 +42,7 @@ LoadFixture makeFixture(
{static_cast<double>(index), 0.0, 0.0},
{source, index + 2U}});
}
definition.nodeSets = std::move(nodeSets);
definition.node_sets = std::move(nodeSets);
definition.steps = {{
"Step-1",
std::move(boundaries),
@@ -53,7 +53,7 @@ LoadFixture makeFixture(
1.0,
{source, 20U}}};
auto domainResult = fesa::Domain::create(std::move(definition));
auto domainResult = fesa::Domain::Create(std::move(definition));
if (!domainResult.HasValue()) {
throw std::runtime_error{"Load fixture Domain construction failed."};
}
@@ -81,8 +81,8 @@ LoadFixture makeShellFixture(
std::vector<fesa::NodalLoad> loads) {
const std::filesystem::path source{"models/shell-load-assembly.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:1122334455667788";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:1122334455667788";
definition.nodes = {
{{"Shell-1", 10, "10"}, {0.0, 0.0, 0.0}, {source, 2U}},
{{"Shell-1", 20, "20"}, {1.0, 0.0, 0.0}, {source, 3U}},
@@ -90,17 +90,17 @@ LoadFixture makeShellFixture(
{{"Shell-1", 40, "40"}, {0.0, 1.0, 0.0}, {source, 5U}}};
definition.materials = {
{"Material", 1000.0, 0.25, {source, 6U}}};
definition.shellSections = {
definition.shell_sections = {
{"ShellSection", 0.1, 0U, {source, 7U}}};
definition.shellElements = {{
definition.shell_elements = {{
{"Shell-1", 1, "1"},
fesa::ShellSourceElementType::s4,
fesa::ShellSourceElementType::kS4,
{0U, 1U, 2U, 3U},
0U,
0U,
{source, 8U}}};
for (std::size_t node = 0U; node < definition.nodes.size(); ++node) {
definition.shellNodeInitialFrames.push_back({
definition.shell_node_initial_frames.push_back({
static_cast<fesa::EntityIndex>(node),
{0.0, 0.0, 1.0},
{1.0, 0.0, 0.0},
@@ -116,7 +116,7 @@ LoadFixture makeShellFixture(
1.0,
{source, 20U}}};
auto domainResult = fesa::Domain::create(std::move(definition));
auto domainResult = fesa::Domain::Create(std::move(definition));
if (!domainResult.HasValue()) {
throw std::runtime_error{"Shell load fixture Domain construction failed."};
}
+31 -31
View File
@@ -1,9 +1,9 @@
#include "fesa/analysis/analysis_model.hpp"
#include "fesa/assembly/parallel_for.hpp"
#include "fesa/assembly/sparse_assembler.hpp"
#include "fesa/elements/mitc4_shell.hpp"
#include "fesa/elements/mitc4_shell.h"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <gtest/gtest.h>
@@ -19,8 +19,8 @@ namespace {
fesa::ModelDefinition makeDefinition() {
const std::filesystem::path source{"models/sparse-assembly.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.nodes = {
{{"Beam-1", 1, "1"}, {0.0, 0.0, 0.0}, {source, 10U}},
{{"Beam-1", 2, "2"}, {2.0, 0.0, 0.0}, {source, 11U}},
@@ -50,8 +50,8 @@ fesa::ModelDefinition makeShellDefinition(
const bool twoElements = false) {
const std::filesystem::path source{"models/shell-sparse-assembly.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:fedcba9876543210";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:fedcba9876543210";
if (twoElements) {
definition.nodes = {
{{"Shell-1", 1, "1"}, {0.0, 0.0, 0.0}, {source, 10U}},
@@ -61,13 +61,13 @@ fesa::ModelDefinition makeShellDefinition(
{{"Shell-1", 5, "5"}, {1.0, 1.0, 0.0}, {source, 14U}},
{{"Shell-1", 6, "6"}, {2.0, 1.0, 0.0}, {source, 15U}}};
for (std::size_t node = 0U; node < definition.nodes.size(); ++node) {
definition.shellNodeInitialFrames.push_back({
definition.shell_node_initial_frames.push_back({
static_cast<fesa::EntityIndex>(node),
{0.0, 0.0, 1.0},
{1.0, 0.0, 0.0},
{0.0, 1.0, 0.0}});
}
definition.shellElements = {
definition.shell_elements = {
{{"Shell-1", 10, "10"}, sourceType, {0U, 1U, 4U, 3U},
0U, 0U, {source, 40U}},
{{"Shell-1", 20, "20"}, sourceType, {1U, 2U, 5U, 4U},
@@ -80,19 +80,19 @@ fesa::ModelDefinition makeShellDefinition(
{{"Shell-1", 3, "3"}, {0.0, 1.0, 1.0}, {source, 12U}},
{{"Shell-1", 4, "4"}, {0.0, 0.0, 1.0}, {source, 13U}}};
for (std::size_t node = 0U; node < definition.nodes.size(); ++node) {
definition.shellNodeInitialFrames.push_back({
definition.shell_node_initial_frames.push_back({
static_cast<fesa::EntityIndex>(node),
{1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}});
}
definition.shellElements = {{
definition.shell_elements = {{
{"Shell-1", 10, "10"}, sourceType, {0U, 1U, 2U, 3U},
0U, 0U, {source, 40U}}};
}
definition.materials = {
{"Material", 120.0, 0.25, {source, 20U}}};
definition.shellSections = {
definition.shell_sections = {
{"ShellSection", 0.2, 0U, {source, 30U}}};
definition.steps = {{
"Step-1", {}, {}, 0.1, 1.0, 0.01, 1.0, {source, 50U}}};
@@ -102,30 +102,30 @@ fesa::ModelDefinition makeShellDefinition(
fesa::Result<fesa::Mitc4Stiffness> directShellStiffness(
const fesa::Domain& domain,
const fesa::EntityIndex elementIndex) {
const auto& definition = domain.shellElements().at(elementIndex);
const auto& definition = domain.ShellElements().at(elementIndex);
std::array<const fesa::Node*, 4> nodes{};
std::array<std::array<double, 3>, 4> directors{};
for (std::size_t node = 0U; node < definition.nodeIndices.size(); ++node) {
const fesa::EntityIndex nodeIndex = definition.nodeIndices[node];
nodes[node] = &domain.nodes().at(nodeIndex);
directors[node] = domain.shellNodeInitialFrames().at(nodeIndex).director;
for (std::size_t node = 0U; node < definition.node_indices.size(); ++node) {
const fesa::EntityIndex nodeIndex = definition.node_indices[node];
nodes[node] = &domain.Nodes().at(nodeIndex);
directors[node] = domain.ShellNodeInitialFrames().at(nodeIndex).director;
}
auto shell = fesa::Mitc4Shell::create(
auto shell = fesa::Mitc4Shell::Create(
nodes,
directors,
domain.shellSections().at(definition.sectionIndex),
domain.materials().at(definition.materialIndex));
domain.ShellSections().at(definition.section_index),
domain.Materials().at(definition.material_index));
if (!shell.HasValue()) {
return fesa::Result<fesa::Mitc4Stiffness>::Failure(shell.GetStatus());
}
return shell.Value().stiffness();
return shell.Value().Stiffness();
}
fesa::Result<fesa::SparseMatrix> assembleShell(
const fesa::ShellSourceElementType sourceType,
const fesa::ParallelFor& parallelFor,
const bool twoElements = false) {
auto domain = fesa::Domain::create(
auto domain = fesa::Domain::Create(
makeShellDefinition(sourceType, twoElements));
if (!domain.HasValue()) {
return fesa::Result<fesa::SparseMatrix>::Failure(domain.GetStatus());
@@ -198,7 +198,7 @@ void expectByteIdentical(
}
TEST(SparseAssembly, SerialTbbAndRepeatedRunsAreByteIdentical) {
auto domainResult = fesa::Domain::create(makeDefinition());
auto domainResult = fesa::Domain::Create(makeDefinition());
ASSERT_TRUE(domainResult.HasValue());
auto modelResult = fesa::AnalysisModel::create(domainResult.Value());
ASSERT_TRUE(modelResult.HasValue());
@@ -257,8 +257,8 @@ TEST(SparseAssembly, SerialTbbAndRepeatedRunsAreByteIdentical) {
TEST(
SparseAssembly,
AssemblesFourNodeTwentyFourDofKernelAndPreservesDiagonalSlots) {
auto domain = fesa::Domain::create(
makeShellDefinition(fesa::ShellSourceElementType::s4));
auto domain = fesa::Domain::Create(
makeShellDefinition(fesa::ShellSourceElementType::kS4));
ASSERT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
ASSERT_TRUE(model.HasValue());
@@ -290,7 +290,7 @@ TEST(
for (std::size_t column = 0U; column < 24U; ++column) {
EXPECT_DOUBLE_EQ(
entry(assembled.Value(), row, column),
expected.Value().stabilizedGlobal24(row, column));
expected.Value().stabilized_global24(row, column));
}
}
}
@@ -300,11 +300,11 @@ TEST(SparseAssembly, ShellSerialTbbReverseAndRepeatedRunsAreByteIdentical) {
fesa::TbbParallelFor tbbExecutor;
ReverseParallelFor reverseExecutor;
auto serial = assembleShell(
fesa::ShellSourceElementType::s4, serialExecutor, true);
fesa::ShellSourceElementType::kS4, serialExecutor, true);
auto tbb = assembleShell(
fesa::ShellSourceElementType::s4, tbbExecutor, true);
fesa::ShellSourceElementType::kS4, tbbExecutor, true);
auto reversed = assembleShell(
fesa::ShellSourceElementType::s4, reverseExecutor, true);
fesa::ShellSourceElementType::kS4, reverseExecutor, true);
ASSERT_TRUE(serial.HasValue());
ASSERT_TRUE(tbb.HasValue());
ASSERT_TRUE(reversed.HasValue());
@@ -315,7 +315,7 @@ TEST(SparseAssembly, ShellSerialTbbReverseAndRepeatedRunsAreByteIdentical) {
expectByteIdentical(reversed.Value(), serial.Value());
for (std::size_t repetition = 0U; repetition < 8U; ++repetition) {
auto repeated = assembleShell(
fesa::ShellSourceElementType::s4, tbbExecutor, true);
fesa::ShellSourceElementType::kS4, tbbExecutor, true);
ASSERT_TRUE(repeated.HasValue());
expectByteIdentical(repeated.Value(), serial.Value());
}
@@ -324,9 +324,9 @@ TEST(SparseAssembly, ShellSerialTbbReverseAndRepeatedRunsAreByteIdentical) {
TEST(SparseAssembly, S4AndS4rSemanticFixturesAssembleIdenticalStiffness) {
fesa::SerialParallelFor serialExecutor;
auto s4 = assembleShell(
fesa::ShellSourceElementType::s4, serialExecutor);
fesa::ShellSourceElementType::kS4, serialExecutor);
auto s4r = assembleShell(
fesa::ShellSourceElementType::s4r, serialExecutor);
fesa::ShellSourceElementType::kS4r, serialExecutor);
ASSERT_TRUE(s4.HasValue());
ASSERT_TRUE(s4r.HasValue());
EXPECT_TRUE(std::any_of(
@@ -2,7 +2,7 @@
#include "fesa/analysis/analysis_model.hpp"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <gtest/gtest.h>
@@ -19,8 +19,8 @@ fesa::DofManager makeDofs(
std::vector<fesa::BoundaryCondition> boundaries) {
const std::filesystem::path source{"models/essential-constraints.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:1234567890abcdef";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:1234567890abcdef";
definition.nodes = {
{{"Beam-1", 1, "1"}, {0.0, 0.0, 0.0}, {source, 2U}}};
definition.steps = {{
@@ -33,7 +33,7 @@ fesa::DofManager makeDofs(
1.0,
{source, 10U}}};
auto domain = fesa::Domain::create(std::move(definition));
auto domain = fesa::Domain::Create(std::move(definition));
EXPECT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
EXPECT_TRUE(model.HasValue());
@@ -46,8 +46,8 @@ fesa::DofManager makeShellSizedDofs(
std::vector<fesa::BoundaryCondition> boundaries) {
const std::filesystem::path source{"models/shell-essential-constraints.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:8877665544332211";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:8877665544332211";
definition.nodes = {
{{"Shell-1", 1, "1"}, {0.0, 0.0, 0.0}, {source, 2U}},
{{"Shell-1", 2, "2"}, {1.0, 0.0, 0.0}, {source, 3U}},
@@ -55,11 +55,11 @@ fesa::DofManager makeShellSizedDofs(
{{"Shell-1", 4, "4"}, {0.0, 1.0, 0.0}, {source, 5U}}};
definition.materials = {
{"Material", 1000.0, 0.25, {source, 6U}}};
definition.shellSections = {
definition.shell_sections = {
{"ShellSection", 0.1, 0U, {source, 7U}}};
definition.shellElements = {{
definition.shell_elements = {{
{"Shell-1", 1, "1"},
fesa::ShellSourceElementType::s4,
fesa::ShellSourceElementType::kS4,
{0U, 1U, 2U, 3U},
0U,
0U,
@@ -74,7 +74,7 @@ fesa::DofManager makeShellSizedDofs(
1.0,
{source, 10U}}};
auto domain = fesa::Domain::create(std::move(definition));
auto domain = fesa::Domain::Create(std::move(definition));
EXPECT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
EXPECT_TRUE(model.HasValue());
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -14,8 +14,8 @@ namespace {
fesa::ModelDefinition makeDefinition() {
const std::filesystem::path source{"models/dof-manager.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.nodes = {
{{"Beam-1", 10, "10"}, {0.0, 0.0, 0.0}, {source, 10U}},
{{"Beam-1", 20, "20"}, {1.0, 0.0, 0.0}, {source, 11U}},
@@ -28,7 +28,7 @@ fesa::ModelDefinition makeDefinition() {
definition.elements = {
{{"Beam-1", 100, "100"}, {0U, 1U}, 0U, 0U, {source, 40U}},
{{"Beam-1", 200, "200"}, {1U, 2U}, 0U, 0U, {source, 41U}}};
definition.nodeSets = {
definition.node_sets = {
{"Root", std::optional<std::string>{"Beam-1"}, {0U}, {source, 50U}},
{"Ends", std::optional<std::string>{"Beam-1"}, {0U, 2U}, {source, 51U}}};
definition.steps = {{
@@ -49,8 +49,8 @@ fesa::ModelDefinition makeDefinition() {
fesa::ModelDefinition makeShellDefinition() {
const std::filesystem::path source{"models/shell-dof-manager.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:1122334455667788";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:1122334455667788";
definition.nodes = {
{{"Shell-1", 10, "10"}, {0.0, 0.0, 0.0}, {source, 10U}},
{{"Shell-1", 20, "20"}, {1.0, 0.0, 0.0}, {source, 11U}},
@@ -58,11 +58,11 @@ fesa::ModelDefinition makeShellDefinition() {
{{"Shell-1", 40, "40"}, {0.0, 1.0, 0.0}, {source, 13U}}};
definition.materials = {
{"Material", 1000.0, 0.25, {source, 20U}}};
definition.shellSections = {
definition.shell_sections = {
{"ShellSection", 0.1, 0U, {source, 30U}}};
definition.shellElements = {{
definition.shell_elements = {{
{"Shell-1", 100, "100"},
fesa::ShellSourceElementType::s4,
fesa::ShellSourceElementType::kS4,
{2U, 0U, 3U, 1U},
0U,
0U,
@@ -77,7 +77,7 @@ struct DofFixture {
};
DofFixture makeDofFixture(fesa::ModelDefinition definition = makeDefinition()) {
auto domain = fesa::Domain::create(std::move(definition));
auto domain = fesa::Domain::Create(std::move(definition));
EXPECT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
EXPECT_TRUE(model.HasValue());
@@ -131,8 +131,8 @@ TEST(DofManager, ExpandsAndValidatesPrescribedValues) {
auto conflictingDefinition = makeDefinition();
conflictingDefinition.steps[0].boundaries.push_back(
{"root", 1, 1, 1.0, {conflictingDefinition.sourcePath, 77U}});
auto domain = fesa::Domain::create(std::move(conflictingDefinition));
{"root", 1, 1, 1.0, {conflictingDefinition.source_path, 77U}});
auto domain = fesa::Domain::Create(std::move(conflictingDefinition));
ASSERT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
ASSERT_TRUE(model.HasValue());
+139 -139
View File
@@ -249,55 +249,55 @@ TEST(InpDomainMapping, MapsEverySupportedKeywordAndLegacyDeck) {
ASSERT_TRUE(result.HasValue());
const fesa::Domain& domain = result.Value();
ASSERT_EQ(domain.nodes().size(), 2U);
EXPECT_EQ(domain.nodes()[0].sourceId.instance_name, "Beam-1");
EXPECT_EQ(domain.nodes()[0].sourceId.source_label, 1);
EXPECT_EQ(domain.nodes()[0].sourceId.source_label_text, "0001");
EXPECT_EQ(domain.nodes()[1].sourceId.source_label_text, "0002");
EXPECT_DOUBLE_EQ(domain.nodes()[1].coordinates[0], 2.0);
ASSERT_EQ(domain.Nodes().size(), 2U);
EXPECT_EQ(domain.Nodes()[0].source_id.instance_name, "Beam-1");
EXPECT_EQ(domain.Nodes()[0].source_id.source_label, 1);
EXPECT_EQ(domain.Nodes()[0].source_id.source_label_text, "0001");
EXPECT_EQ(domain.Nodes()[1].source_id.source_label_text, "0002");
EXPECT_DOUBLE_EQ(domain.Nodes()[1].coordinates[0], 2.0);
ASSERT_EQ(domain.elements().size(), 1U);
EXPECT_EQ(domain.elements()[0].sourceId.source_label_text, "0007");
EXPECT_EQ(domain.elements()[0].nodeIndices[0], 0U);
EXPECT_EQ(domain.elements()[0].nodeIndices[1], 1U);
ASSERT_EQ(domain.Elements().size(), 1U);
EXPECT_EQ(domain.Elements()[0].source_id.source_label_text, "0007");
EXPECT_EQ(domain.Elements()[0].node_indices[0], 0U);
EXPECT_EQ(domain.Elements()[0].node_indices[1], 1U);
ASSERT_EQ(domain.materials().size(), 1U);
EXPECT_EQ(domain.materials()[0].name, "Steel");
EXPECT_DOUBLE_EQ(domain.materials()[0].youngsModulus, 210000.0);
EXPECT_DOUBLE_EQ(domain.materials()[0].poissonRatio, 0.75);
ASSERT_EQ(domain.Materials().size(), 1U);
EXPECT_EQ(domain.Materials()[0].name, "Steel");
EXPECT_DOUBLE_EQ(domain.Materials()[0].youngs_modulus, 210000.0);
EXPECT_DOUBLE_EQ(domain.Materials()[0].poisson_ratio, 0.75);
ASSERT_EQ(domain.sections().size(), 1U);
const auto& section = domain.sections()[0];
ASSERT_EQ(domain.Sections().size(), 1U);
const auto& section = domain.Sections()[0];
EXPECT_DOUBLE_EQ(section.area, 2.0);
EXPECT_DOUBLE_EQ(section.i11, 3.0);
EXPECT_DOUBLE_EQ(section.i12, 0.0);
EXPECT_DOUBLE_EQ(section.i22, 4.0);
EXPECT_DOUBLE_EQ(section.torsionalConstant, 5.0);
EXPECT_EQ(section.firstAxis, (std::array<double, 3>{0.0, 1.0, 0.0}));
EXPECT_DOUBLE_EQ(section.torsional_constant, 5.0);
EXPECT_EQ(section.first_axis, (std::array<double, 3>{0.0, 1.0, 0.0}));
EXPECT_EQ(
section.sectionPoints,
section.section_points,
(std::vector<std::array<double, 2>>{{-0.5, 0.25}, {0.5, -0.25}}));
EXPECT_EQ(domain.elements()[0].materialIndex, 0U);
EXPECT_EQ(domain.elements()[0].sectionIndex, 0U);
EXPECT_EQ(domain.Elements()[0].material_index, 0U);
EXPECT_EQ(domain.Elements()[0].section_index, 0U);
ASSERT_EQ(domain.steps().size(), 1U);
const auto& step = domain.steps()[0];
ASSERT_EQ(domain.Steps().size(), 1U);
const auto& step = domain.Steps()[0];
EXPECT_EQ(step.name, "Step-1");
EXPECT_DOUBLE_EQ(step.initialIncrement, 0.25);
EXPECT_DOUBLE_EQ(step.timePeriod, 1.5);
EXPECT_DOUBLE_EQ(step.minimumIncrement, 0.01);
EXPECT_DOUBLE_EQ(step.maximumIncrement, 1.5);
EXPECT_DOUBLE_EQ(step.initial_increment, 0.25);
EXPECT_DOUBLE_EQ(step.time_period, 1.5);
EXPECT_DOUBLE_EQ(step.minimum_increment, 0.01);
EXPECT_DOUBLE_EQ(step.maximum_increment, 1.5);
ASSERT_EQ(step.boundaries.size(), 2U);
EXPECT_EQ(step.boundaries[0].target, "rootassembly");
EXPECT_EQ(step.boundaries[0].firstDof, 1);
EXPECT_EQ(step.boundaries[0].first_dof, 1);
EXPECT_DOUBLE_EQ(step.boundaries[0].value, 0.125);
EXPECT_EQ(step.boundaries[1].lastDof, 2);
EXPECT_EQ(step.boundaries[1].last_dof, 2);
EXPECT_DOUBLE_EQ(step.boundaries[1].value, 0.0);
ASSERT_EQ(step.loads.size(), 1U);
EXPECT_EQ(step.loads[0].target, "RootAssembly");
EXPECT_EQ(step.loads[0].dof, 6);
EXPECT_DOUBLE_EQ(step.loads[0].magnitude, -12.5);
EXPECT_EQ(domain.warnings().size(), 8U);
EXPECT_EQ(domain.Warnings().size(), 8U);
const auto legacyPath = repositoryRoot() / "reference" /
"cantilever beam" / "cantilever beam.inp";
@@ -307,12 +307,12 @@ TEST(InpDomainMapping, MapsEverySupportedKeywordAndLegacyDeck) {
ASSERT_TRUE(parsedLegacy.HasValue());
auto legacy = fesa::AbaqusDomainMapper{}.map(parsedLegacy.Value());
ASSERT_TRUE(legacy.HasValue());
EXPECT_EQ(legacy.Value().nodes().size(), 11U);
EXPECT_EQ(legacy.Value().elements().size(), 10U);
EXPECT_EQ(legacy.Value().materials().size(), 1U);
EXPECT_EQ(legacy.Value().sections().size(), 1U);
EXPECT_EQ(legacy.Value().steps().size(), 1U);
EXPECT_EQ(legacy.Value().warnings().size(), 7U);
EXPECT_EQ(legacy.Value().Nodes().size(), 11U);
EXPECT_EQ(legacy.Value().Elements().size(), 10U);
EXPECT_EQ(legacy.Value().Materials().size(), 1U);
EXPECT_EQ(legacy.Value().Sections().size(), 1U);
EXPECT_EQ(legacy.Value().Steps().size(), 1U);
EXPECT_EQ(legacy.Value().Warnings().size(), 7U);
EXPECT_EQ(readExactBytes(legacyPath), bytesBefore);
EXPECT_EQ(std::filesystem::last_write_time(legacyPath), timestampBefore);
}
@@ -359,52 +359,52 @@ OnlySecond, 2, 5.
ASSERT_TRUE(result.HasValue());
const fesa::Domain& domain = result.Value();
ASSERT_EQ(domain.nodes().size(), 4U);
EXPECT_EQ(domain.nodes()[0].sourceId.instance_name, "First");
EXPECT_EQ(domain.nodes()[0].sourceId.source_label, 10);
EXPECT_EQ(domain.nodes()[1].sourceId.instance_name, "First");
EXPECT_EQ(domain.nodes()[1].sourceId.source_label, 20);
EXPECT_EQ(domain.nodes()[2].sourceId.instance_name, "Second");
EXPECT_EQ(domain.nodes()[2].sourceId.source_label, 10);
EXPECT_EQ(domain.nodes()[3].sourceId.instance_name, "Second");
EXPECT_EQ(domain.nodes()[3].sourceId.source_label, 20);
ASSERT_EQ(domain.Nodes().size(), 4U);
EXPECT_EQ(domain.Nodes()[0].source_id.instance_name, "First");
EXPECT_EQ(domain.Nodes()[0].source_id.source_label, 10);
EXPECT_EQ(domain.Nodes()[1].source_id.instance_name, "First");
EXPECT_EQ(domain.Nodes()[1].source_id.source_label, 20);
EXPECT_EQ(domain.Nodes()[2].source_id.instance_name, "Second");
EXPECT_EQ(domain.Nodes()[2].source_id.source_label, 10);
EXPECT_EQ(domain.Nodes()[3].source_id.instance_name, "Second");
EXPECT_EQ(domain.Nodes()[3].source_id.source_label, 20);
ASSERT_EQ(domain.elements().size(), 2U);
EXPECT_EQ(domain.elements()[0].sourceId.instance_name, "First");
EXPECT_EQ(domain.elements()[0].nodeIndices,
ASSERT_EQ(domain.Elements().size(), 2U);
EXPECT_EQ(domain.Elements()[0].source_id.instance_name, "First");
EXPECT_EQ(domain.Elements()[0].node_indices,
(std::array<fesa::EntityIndex, 2>{0U, 1U}));
EXPECT_EQ(domain.elements()[1].sourceId.instance_name, "Second");
EXPECT_EQ(domain.elements()[1].nodeIndices,
EXPECT_EQ(domain.Elements()[1].source_id.instance_name, "Second");
EXPECT_EQ(domain.Elements()[1].node_indices,
(std::array<fesa::EntityIndex, 2>{2U, 3U}));
ASSERT_EQ(domain.nodeSets().size(), 3U);
EXPECT_EQ(domain.nodeSets()[0].name, "Ends");
EXPECT_EQ(domain.nodeSets()[0].instanceName, std::optional<std::string>{"First"});
EXPECT_EQ(domain.nodeSets()[0].nodeIndices,
ASSERT_EQ(domain.NodeSets().size(), 3U);
EXPECT_EQ(domain.NodeSets()[0].name, "Ends");
EXPECT_EQ(domain.NodeSets()[0].instance_name, std::optional<std::string>{"First"});
EXPECT_EQ(domain.NodeSets()[0].node_indices,
(std::vector<fesa::EntityIndex>{0U, 1U}));
EXPECT_EQ(domain.nodeSets()[1].instanceName, std::optional<std::string>{"Second"});
EXPECT_EQ(domain.nodeSets()[1].nodeIndices,
EXPECT_EQ(domain.NodeSets()[1].instance_name, std::optional<std::string>{"Second"});
EXPECT_EQ(domain.NodeSets()[1].node_indices,
(std::vector<fesa::EntityIndex>{2U, 3U}));
EXPECT_EQ(domain.nodeSets()[2].name, "OnlySecond");
EXPECT_EQ(domain.nodeSets()[2].nodeIndices,
EXPECT_EQ(domain.NodeSets()[2].name, "OnlySecond");
EXPECT_EQ(domain.NodeSets()[2].node_indices,
(std::vector<fesa::EntityIndex>{3U}));
ASSERT_EQ(domain.elementSets().size(), 3U);
EXPECT_EQ(domain.elementSets()[0].instanceName,
ASSERT_EQ(domain.ElementSets().size(), 3U);
EXPECT_EQ(domain.ElementSets()[0].instance_name,
std::optional<std::string>{"First"});
EXPECT_EQ(domain.elementSets()[0].elementIndices,
EXPECT_EQ(domain.ElementSets()[0].element_indices,
(std::vector<fesa::EntityIndex>{0U}));
EXPECT_EQ(domain.elementSets()[1].instanceName,
EXPECT_EQ(domain.ElementSets()[1].instance_name,
std::optional<std::string>{"Second"});
EXPECT_EQ(domain.elementSets()[1].elementIndices,
EXPECT_EQ(domain.ElementSets()[1].element_indices,
(std::vector<fesa::EntityIndex>{1U}));
EXPECT_EQ(domain.elementSets()[2].name, "OnlySecondBeam");
EXPECT_EQ(domain.elementSets()[2].elementIndices,
EXPECT_EQ(domain.ElementSets()[2].name, "OnlySecondBeam");
EXPECT_EQ(domain.ElementSets()[2].element_indices,
(std::vector<fesa::EntityIndex>{1U}));
ASSERT_EQ(domain.steps().size(), 1U);
EXPECT_EQ(domain.steps()[0].boundaries[0].target, "OnlySecond");
EXPECT_EQ(domain.steps()[0].loads[0].target, "OnlySecond");
ASSERT_EQ(domain.Steps().size(), 1U);
EXPECT_EQ(domain.Steps()[0].boundaries[0].target, "OnlySecond");
EXPECT_EQ(domain.Steps()[0].loads[0].target, "OnlySecond");
auto direct = mapText(
"direct-node-labels",
@@ -413,8 +413,8 @@ OnlySecond, 2, 5.
"Tip, 2, -1.",
"2, 2, -1."));
ASSERT_TRUE(direct.HasValue());
EXPECT_EQ(direct.Value().steps()[0].boundaries[0].target, "1");
EXPECT_EQ(direct.Value().steps()[0].loads[0].target, "2");
EXPECT_EQ(direct.Value().Steps()[0].boundaries[0].target, "1");
EXPECT_EQ(direct.Value().Steps()[0].loads[0].target, "2");
auto aboveThresholds = mapText(
"above-geometry-thresholds",
@@ -447,10 +447,10 @@ TEST(InpDomainMapping, KeepsNodeAndElementSetNamesInSeparateNamespaces) {
ASSERT_TRUE(sharedName.HasValue());
const auto& domain = sharedName.Value();
EXPECT_TRUE(std::any_of(
domain.nodeSets().begin(), domain.nodeSets().end(),
domain.NodeSets().begin(), domain.NodeSets().end(),
[](const fesa::NodeSet& set) { return set.name == "ShellS4"; }));
EXPECT_TRUE(std::any_of(
domain.elementSets().begin(), domain.elementSets().end(),
domain.ElementSets().begin(), domain.ElementSets().end(),
[](const fesa::ElementSet& set) { return set.name == "ShellS4"; }));
auto duplicateNodeSet = mapText(
@@ -486,16 +486,16 @@ TEST(InpDomainMapping, KeepsNodeAndElementSetNamesInSeparateNamespaces) {
ASSERT_TRUE(assemblySharedName.HasValue());
const auto& assemblyDomain = assemblySharedName.Value();
const auto rootNodeSetCount = std::count_if(
assemblyDomain.nodeSets().begin(), assemblyDomain.nodeSets().end(),
assemblyDomain.NodeSets().begin(), assemblyDomain.NodeSets().end(),
[](const fesa::NodeSet& set) { return set.name == "Root"; });
EXPECT_EQ(rootNodeSetCount, 1);
const auto rootNodeSet = std::find_if(
assemblyDomain.nodeSets().begin(), assemblyDomain.nodeSets().end(),
assemblyDomain.NodeSets().begin(), assemblyDomain.NodeSets().end(),
[](const fesa::NodeSet& set) { return set.name == "Root"; });
ASSERT_NE(rootNodeSet, assemblyDomain.nodeSets().end());
EXPECT_EQ(rootNodeSet->nodeIndices, (std::vector<fesa::EntityIndex>{0U}));
ASSERT_NE(rootNodeSet, assemblyDomain.NodeSets().end());
EXPECT_EQ(rootNodeSet->node_indices, (std::vector<fesa::EntityIndex>{0U}));
EXPECT_EQ(std::count_if(
assemblyDomain.elementSets().begin(), assemblyDomain.elementSets().end(),
assemblyDomain.ElementSets().begin(), assemblyDomain.ElementSets().end(),
[](const fesa::ElementSet& set) { return set.name == "Root"; }), 1);
}
@@ -505,33 +505,33 @@ TEST(InpDomainMapping, NoOpAllowlistWarnsWithoutSemanticEffect) {
ASSERT_TRUE(plain.HasValue());
ASSERT_TRUE(withNoOps.HasValue());
EXPECT_TRUE(plain.Value().warnings().empty());
ASSERT_EQ(withNoOps.Value().warnings().size(), 8U);
EXPECT_EQ(withNoOps.Value().warnings()[0].code, "ignored-input-keyword");
EXPECT_EQ(withNoOps.Value().warnings()[0].keyword, "PREPRINT");
EXPECT_EQ(withNoOps.Value().warnings()[1].keyword,
EXPECT_TRUE(plain.Value().Warnings().empty());
ASSERT_EQ(withNoOps.Value().Warnings().size(), 8U);
EXPECT_EQ(withNoOps.Value().Warnings()[0].code, "ignored-input-keyword");
EXPECT_EQ(withNoOps.Value().Warnings()[0].keyword, "PREPRINT");
EXPECT_EQ(withNoOps.Value().Warnings()[1].keyword,
"TRANSVERSE SHEAR STIFFNESS");
EXPECT_EQ(withNoOps.Value().warnings()[2].keyword, "RESTART");
EXPECT_EQ(withNoOps.Value().warnings()[3].keyword, "OUTPUT");
EXPECT_EQ(withNoOps.Value().warnings()[4].keyword, "NODE OUTPUT");
EXPECT_EQ(withNoOps.Value().warnings()[5].keyword, "ELEMENT OUTPUT");
EXPECT_EQ(withNoOps.Value().warnings()[6].keyword, "CONTACT OUTPUT");
EXPECT_EQ(withNoOps.Value().warnings()[7].keyword, "OUTPUT");
for (const auto& warning : withNoOps.Value().warnings()) {
EXPECT_EQ(withNoOps.Value().Warnings()[2].keyword, "RESTART");
EXPECT_EQ(withNoOps.Value().Warnings()[3].keyword, "OUTPUT");
EXPECT_EQ(withNoOps.Value().Warnings()[4].keyword, "NODE OUTPUT");
EXPECT_EQ(withNoOps.Value().Warnings()[5].keyword, "ELEMENT OUTPUT");
EXPECT_EQ(withNoOps.Value().Warnings()[6].keyword, "CONTACT OUTPUT");
EXPECT_EQ(withNoOps.Value().Warnings()[7].keyword, "OUTPUT");
for (const auto& warning : withNoOps.Value().Warnings()) {
EXPECT_EQ(warning.severity, fesa::Severity::kWarning);
}
EXPECT_EQ(withNoOps.Value().nodes().size(), plain.Value().nodes().size());
EXPECT_EQ(withNoOps.Value().elements().size(), plain.Value().elements().size());
EXPECT_EQ(withNoOps.Value().materials().size(), plain.Value().materials().size());
EXPECT_EQ(withNoOps.Value().sections().size(), plain.Value().sections().size());
EXPECT_EQ(withNoOps.Value().nodeSets().size(), plain.Value().nodeSets().size());
EXPECT_EQ(withNoOps.Value().elementSets().size(), plain.Value().elementSets().size());
EXPECT_EQ(withNoOps.Value().steps().size(), plain.Value().steps().size());
EXPECT_EQ(withNoOps.Value().steps()[0].boundaries.size(),
plain.Value().steps()[0].boundaries.size());
EXPECT_EQ(withNoOps.Value().steps()[0].loads.size(),
plain.Value().steps()[0].loads.size());
EXPECT_EQ(withNoOps.Value().Nodes().size(), plain.Value().Nodes().size());
EXPECT_EQ(withNoOps.Value().Elements().size(), plain.Value().Elements().size());
EXPECT_EQ(withNoOps.Value().Materials().size(), plain.Value().Materials().size());
EXPECT_EQ(withNoOps.Value().Sections().size(), plain.Value().Sections().size());
EXPECT_EQ(withNoOps.Value().NodeSets().size(), plain.Value().NodeSets().size());
EXPECT_EQ(withNoOps.Value().ElementSets().size(), plain.Value().ElementSets().size());
EXPECT_EQ(withNoOps.Value().Steps().size(), plain.Value().Steps().size());
EXPECT_EQ(withNoOps.Value().Steps()[0].boundaries.size(),
plain.Value().Steps()[0].boundaries.size());
EXPECT_EQ(withNoOps.Value().Steps()[0].loads.size(),
plain.Value().Steps()[0].loads.size());
}
// MITC4-MAP-001
@@ -540,63 +540,63 @@ TEST(InpDomainMapping, MapsS4AndS4rThroughOneMitc4Identity) {
ASSERT_TRUE(result.HasValue());
const fesa::Domain& domain = result.Value();
EXPECT_TRUE(domain.elements().empty());
ASSERT_EQ(domain.shellElements().size(), 4U);
EXPECT_EQ(domain.shellElements()[0].sourceId.instance_name, "First");
EXPECT_EQ(domain.shellElements()[0].sourceId.source_label_text, "0010");
EXPECT_TRUE(domain.Elements().empty());
ASSERT_EQ(domain.ShellElements().size(), 4U);
EXPECT_EQ(domain.ShellElements()[0].source_id.instance_name, "First");
EXPECT_EQ(domain.ShellElements()[0].source_id.source_label_text, "0010");
EXPECT_EQ(
domain.shellElements()[0].sourceType,
fesa::ShellSourceElementType::s4);
domain.ShellElements()[0].source_type,
fesa::ShellSourceElementType::kS4);
EXPECT_EQ(
domain.shellElements()[0].nodeIndices,
domain.ShellElements()[0].node_indices,
(std::array<fesa::EntityIndex, 4>{0U, 1U, 2U, 3U}));
EXPECT_EQ(domain.shellElements()[0].sectionIndex, 0U);
EXPECT_EQ(domain.shellElements()[0].materialIndex, 0U);
EXPECT_EQ(domain.ShellElements()[0].section_index, 0U);
EXPECT_EQ(domain.ShellElements()[0].material_index, 0U);
EXPECT_EQ(domain.shellElements()[1].sourceId.instance_name, "First");
EXPECT_EQ(domain.ShellElements()[1].source_id.instance_name, "First");
EXPECT_EQ(
domain.shellElements()[1].sourceType,
fesa::ShellSourceElementType::s4r);
domain.ShellElements()[1].source_type,
fesa::ShellSourceElementType::kS4r);
EXPECT_EQ(
domain.shellElements()[1].nodeIndices,
domain.ShellElements()[1].node_indices,
(std::array<fesa::EntityIndex, 4>{1U, 4U, 5U, 2U}));
EXPECT_EQ(domain.shellElements()[1].sectionIndex, 1U);
EXPECT_EQ(domain.shellElements()[1].materialIndex, 1U);
EXPECT_EQ(domain.ShellElements()[1].section_index, 1U);
EXPECT_EQ(domain.ShellElements()[1].material_index, 1U);
EXPECT_EQ(domain.shellElements()[2].sourceId.instance_name, "Second");
EXPECT_EQ(domain.ShellElements()[2].source_id.instance_name, "Second");
EXPECT_EQ(
domain.shellElements()[2].nodeIndices,
domain.ShellElements()[2].node_indices,
(std::array<fesa::EntityIndex, 4>{6U, 7U, 8U, 9U}));
EXPECT_EQ(domain.shellElements()[3].sourceId.instance_name, "Second");
EXPECT_EQ(domain.ShellElements()[3].source_id.instance_name, "Second");
EXPECT_EQ(
fesa::kMitc4InternalFormulation,
std::string_view{"FESA-MITC4"});
ASSERT_EQ(domain.shellSections().size(), 2U);
EXPECT_EQ(domain.shellSections()[0].name, "ShellS4");
EXPECT_DOUBLE_EQ(domain.shellSections()[0].thickness, 0.1);
EXPECT_EQ(domain.shellSections()[0].materialIndex, 0U);
EXPECT_EQ(domain.shellSections()[1].name, "ShellS4R");
EXPECT_DOUBLE_EQ(domain.shellSections()[1].thickness, 0.2);
EXPECT_EQ(domain.shellSections()[1].materialIndex, 1U);
ASSERT_EQ(domain.ShellSections().size(), 2U);
EXPECT_EQ(domain.ShellSections()[0].name, "ShellS4");
EXPECT_DOUBLE_EQ(domain.ShellSections()[0].thickness, 0.1);
EXPECT_EQ(domain.ShellSections()[0].material_index, 0U);
EXPECT_EQ(domain.ShellSections()[1].name, "ShellS4R");
EXPECT_DOUBLE_EQ(domain.ShellSections()[1].thickness, 0.2);
EXPECT_EQ(domain.ShellSections()[1].material_index, 1U);
ASSERT_EQ(domain.shellNodeInitialFrames().size(), domain.nodes().size());
EXPECT_EQ(domain.shellNodeInitialFrames()[0].nodeIndex, 0U);
ASSERT_EQ(domain.ShellNodeInitialFrames().size(), domain.Nodes().size());
EXPECT_EQ(domain.ShellNodeInitialFrames()[0].node_index, 0U);
EXPECT_EQ(
domain.shellNodeInitialFrames()[0].director,
domain.ShellNodeInitialFrames()[0].director,
(std::array<double, 3>{0.0, 0.0, 1.0}));
EXPECT_EQ(
domain.shellNodeInitialFrames()[0].tangentA,
domain.ShellNodeInitialFrames()[0].tangent_a,
(std::array<double, 3>{1.0, 0.0, 0.0}));
EXPECT_EQ(
domain.shellNodeInitialFrames()[0].tangentB,
domain.ShellNodeInitialFrames()[0].tangent_b,
(std::array<double, 3>{0.0, 1.0, 0.0}));
ASSERT_EQ(domain.steps().size(), 1U);
ASSERT_EQ(domain.steps()[0].boundaries.size(), 1U);
EXPECT_EQ(domain.steps()[0].boundaries[0].lastDof, 6);
ASSERT_EQ(domain.steps()[0].loads.size(), 1U);
EXPECT_EQ(domain.steps()[0].loads[0].dof, 6);
ASSERT_EQ(domain.Steps().size(), 1U);
ASSERT_EQ(domain.Steps()[0].boundaries.size(), 1U);
EXPECT_EQ(domain.Steps()[0].boundaries[0].last_dof, 6);
ASSERT_EQ(domain.Steps()[0].loads.size(), 1U);
EXPECT_EQ(domain.Steps()[0].loads[0].dof, 6);
}
// MITC4-MAP-002
@@ -690,10 +690,10 @@ TEST(InpDomainMapping, PreservesProcedureLoadAndOutputRequestBoundariesForShells
"*Output, field\n*Node Output\nU, RF\n*Element Output\nS\n*End Step\n");
auto valid = mapText("mitc4-map-004-no-ops", withNoOps);
ASSERT_TRUE(valid.HasValue());
ASSERT_EQ(valid.Value().warnings().size(), 3U);
EXPECT_EQ(valid.Value().warnings()[0].keyword, "OUTPUT");
EXPECT_EQ(valid.Value().warnings()[1].keyword, "NODE OUTPUT");
EXPECT_EQ(valid.Value().warnings()[2].keyword, "ELEMENT OUTPUT");
ASSERT_EQ(valid.Value().Warnings().size(), 3U);
EXPECT_EQ(valid.Value().Warnings()[0].keyword, "OUTPUT");
EXPECT_EQ(valid.Value().Warnings()[1].keyword, "NODE OUTPUT");
EXPECT_EQ(valid.Value().Warnings()[2].keyword, "ELEMENT OUTPUT");
struct InvalidCase {
std::string name;
+20 -20
View File
@@ -7,7 +7,7 @@
#include "fesa/analysis/analysis_state.hpp"
#include "fesa/build_info.h"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <hdf5.h>
@@ -123,8 +123,8 @@ fesa::ModelDefinition makeDefinition(
const std::filesystem::path& source,
const bool useDefaultCentroid) {
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.nodes = {
{{u8"Beam-\u03b1", 101, "101"}, {0.0, 0.0, 0.0}, {source, 10U}},
{{u8"Beam-\u03b1", 202, "202"}, {3.0, 4.0, 0.0}, {source, 11U}}};
@@ -156,7 +156,7 @@ fesa::ModelDefinition makeDefinition(
WriterFixture makeFixture(
const std::filesystem::path& source,
const bool useDefaultCentroid = false) {
auto domainResult = fesa::Domain::create(
auto domainResult = fesa::Domain::Create(
makeDefinition(source, useDefaultCentroid));
if (!domainResult.HasValue()) {
throw std::runtime_error{"Writer fixture Domain construction failed."};
@@ -186,16 +186,16 @@ WriterFixture makeFixture(
state->reaction()[index] = 100.0 + static_cast<double>(index);
}
const auto& nodes = domain->nodes();
const auto& nodes = domain->Nodes();
state->endpointResults() = {
{0U,
0,
nodes[0U].sourceId,
nodes[0U].source_id,
{1.0, 2.0, 3.0, 4.0, 5.0, 6.0},
{11.0, 12.0, 13.0, 14.0}},
{0U,
1,
nodes[1U].sourceId,
nodes[1U].source_id,
{7.0, 8.0, 9.0, 10.0, 11.0, 12.0},
{15.0, 16.0, 17.0, 18.0}}};
state->gaussResults() = {
@@ -217,8 +217,8 @@ WriterFixture makeFixture(
fesa::ModelDefinition makeShellDefinition(const std::filesystem::path& source) {
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:fedcba9876543210";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:fedcba9876543210";
definition.nodes = {
{{"Shell-1", 11, "11"}, {-1.0, -1.0, 0.0}, {source, 10U}},
{{"Shell-1", 12, "12"}, {1.0, -1.0, 0.0}, {source, 11U}},
@@ -226,23 +226,23 @@ fesa::ModelDefinition makeShellDefinition(const std::filesystem::path& source) {
{{"Shell-1", 14, "14"}, {-1.0, 1.0, 0.0}, {source, 13U}}};
definition.materials = {
{"ShellSteel", 210.0e9, 0.3, {source, 20U}}};
definition.shellSections = {
definition.shell_sections = {
{"PlateSet", 0.02, 0U, {source, 30U}}};
definition.shellElements = {{
definition.shell_elements = {{
{"Shell-1", 401, "401"},
fesa::ShellSourceElementType::s4r,
fesa::ShellSourceElementType::kS4r,
{0U, 1U, 2U, 3U},
0U,
0U,
{source, 40U}}};
for (std::size_t node = 0U; node < definition.nodes.size(); ++node) {
definition.shellNodeInitialFrames.push_back({
definition.shell_node_initial_frames.push_back({
static_cast<fesa::EntityIndex>(node),
{0.0, 0.0, 1.0},
{1.0, 0.0, 0.0},
{0.0, 1.0, 0.0}});
}
definition.nodeSets = {
definition.node_sets = {
{"Fixed", {}, {0U}, {source, 50U}}};
definition.steps = {{
"Step-1",
@@ -258,7 +258,7 @@ fesa::ModelDefinition makeShellDefinition(const std::filesystem::path& source) {
}
WriterFixture makeShellFixture(const std::filesystem::path& source) {
auto domainResult = fesa::Domain::create(makeShellDefinition(source));
auto domainResult = fesa::Domain::Create(makeShellDefinition(source));
if (!domainResult.HasValue()) {
throw std::runtime_error{"Shell writer fixture Domain construction failed."};
}
@@ -1033,7 +1033,7 @@ TEST(Hdf5ResultsWriter, WritesMandatoryOutputsDespiteOutputRequests) {
const fesa::Diagnostic ignoredRequest{
fesa::Severity::kWarning,
"ignored-output-request",
{fixture.domain->sourcePath(), 70U},
{fixture.domain->SourcePath(), 70U},
"*OUTPUT",
"FIELD",
"Abaqus output requests do not filter FESA mandatory results."};
@@ -1065,13 +1065,13 @@ TEST(Hdf5ResultsWriter, WritesWarningsAndDefaultCentroid) {
std::vector<fesa::Diagnostic> diagnostics = {
{fesa::Severity::kWarning,
"ignored-output-request",
{fixture.domain->sourcePath(), 80U},
{fixture.domain->SourcePath(), 80U},
"*OUTPUT",
"FIELD",
"Ignored output request."},
{fesa::Severity::kWarning,
"ignored-keyword",
{fixture.domain->sourcePath(), 20U},
{fixture.domain->SourcePath(), 20U},
"*PREPRINT",
"",
"Ignored generator control."}};
@@ -1098,7 +1098,7 @@ TEST(Hdf5ResultsWriter, WritesWarningsAndDefaultCentroid) {
EXPECT_STREQ(rows[0U].code, "ignored-keyword");
EXPECT_STREQ(
rows[0U].file,
std::filesystem::absolute(fixture.domain->sourcePath())
std::filesystem::absolute(fixture.domain->SourcePath())
.lexically_normal()
.generic_u8string()
.c_str());
@@ -1321,7 +1321,7 @@ TEST(Hdf5ResultsWriter, WritesShellInventoryDespiteRequestsAndOmitsForbiddenPath
const fesa::Diagnostic ignoredRequest{
fesa::Severity::kWarning,
"ignored-output-request",
{fixture.domain->sourcePath(), 80U},
{fixture.domain->SourcePath(), 80U},
"*ELEMENT OUTPUT",
"S",
"Output requests cannot filter mandatory shell results."};
+238 -224
View File
@@ -1,4 +1,4 @@
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <gtest/gtest.h>
@@ -10,254 +10,268 @@
namespace {
fesa::ModelDefinition makeOwnedDefinition() {
fesa::ModelDefinition definition{};
definition.sourcePath = "models/owned.inp";
definition.sourceContentIdentity = "fnv1a64:fedcba9876543210";
definition.heading = "Stable declaration order";
definition.nodes = {
{{"Instance-A", 20, "0020"}, {2.0, 0.0, 0.0}, {"models/owned.inp", 12U}},
{{"Instance-A", 10, "0010"}, {1.0, 0.0, 0.0}, {"models/owned.inp", 11U}}};
definition.elements = {{
{"Instance-A", 5, "0005"},
{fesa::EntityIndex{1}, fesa::EntityIndex{0}},
fesa::EntityIndex{0},
fesa::EntityIndex{0},
{"models/owned.inp", 20U}}};
definition.materials = {{
"Steel", 210.0e9, 0.3, {"models/owned.inp", 30U}}};
definition.sections = {{
"Section-1",
0.02,
1.0e-5,
0.0,
2.0e-5,
5.0e-6,
{0.0, 1.0, 0.0},
{{-0.1, 0.0}, {0.1, 0.0}},
{"models/owned.inp", 40U}}};
definition.nodeSets = {{
"Tip", std::string{"Instance-A"}, {0U}, {"models/owned.inp", 45U}}};
definition.elementSets = {{
"Beam", std::string{"Instance-A"}, {0U}, {"models/owned.inp", 46U}}};
definition.parts = {{
"BeamPart", {20, 10}, {5}, {"Tip"}, {"Beam"},
{"models/owned.inp", 2U}}};
definition.instances = {{
"Instance-A",
"BeamPart",
{{20, 0U}, {10, 1U}},
{{5, 0U}},
{"models/owned.inp", 50U}}};
definition.steps = {{
"Step-1",
{{"Root", 1, 6, 0.0, {"models/owned.inp", 60U}}},
{{"Tip", 3, -1000.0, {"models/owned.inp", 61U}}},
0.1,
1.0,
1.0e-5,
1.0,
{"models/owned.inp", 55U}}};
definition.warnings = {{
fesa::Severity::kWarning,
"ignored-output-request",
{"models/owned.inp", 70U},
"*OUTPUT",
"",
"Ignored output request."}};
return definition;
fesa::ModelDefinition MakeOwnedDefinition() {
fesa::ModelDefinition definition{};
definition.source_path = "models/owned.inp";
definition.source_content_identity = "fnv1a64:fedcba9876543210";
definition.heading = "Stable declaration order";
definition.nodes = {
{{"Instance-A", 20, "0020"}, {2.0, 0.0, 0.0}, {"models/owned.inp", 12U}},
{{"Instance-A", 10, "0010"}, {1.0, 0.0, 0.0}, {"models/owned.inp", 11U}}};
definition.elements = {{{"Instance-A", 5, "0005"},
{fesa::EntityIndex{1}, fesa::EntityIndex{0}},
fesa::EntityIndex{0},
fesa::EntityIndex{0},
{"models/owned.inp", 20U}}};
definition.materials = {{"Steel", 210.0e9, 0.3, {"models/owned.inp", 30U}}};
definition.sections = {{"Section-1",
0.02,
1.0e-5,
0.0,
2.0e-5,
5.0e-6,
{0.0, 1.0, 0.0},
{{-0.1, 0.0}, {0.1, 0.0}},
{"models/owned.inp", 40U}}};
definition.node_sets = {
{"Tip", std::string{"Instance-A"}, {0U}, {"models/owned.inp", 45U}}};
definition.element_sets = {
{"Beam", std::string{"Instance-A"}, {0U}, {"models/owned.inp", 46U}}};
definition.parts = {
{"BeamPart", {20, 10}, {5}, {"Tip"}, {"Beam"}, {"models/owned.inp", 2U}}};
definition.instances = {{"Instance-A",
"BeamPart",
{{20, 0U}, {10, 1U}},
{{5, 0U}},
{"models/owned.inp", 50U}}};
definition.steps = {{"Step-1",
{{"Root", 1, 6, 0.0, {"models/owned.inp", 60U}}},
{{"Tip", 3, -1000.0, {"models/owned.inp", 61U}}},
0.1,
1.0,
1.0e-5,
1.0,
{"models/owned.inp", 55U}}};
definition.warnings = {{fesa::Severity::kWarning,
"ignored-output-request",
{"models/owned.inp", 70U},
"*OUTPUT",
"",
"Ignored output request."}};
return definition;
}
} // namespace
} // namespace
TEST(DomainModel, ImmutableOwnershipPreservesStableOrder) {
auto definition = makeOwnedDefinition();
auto result = fesa::Domain::create(definition);
ASSERT_TRUE(result.HasValue());
auto definition = MakeOwnedDefinition();
auto result = fesa::Domain::Create(definition);
ASSERT_TRUE(result.HasValue());
definition.sourcePath = "mutated.inp";
definition.sourceContentIdentity = "mutated";
definition.nodes[0].sourceId.source_label_text = "mutated";
definition.nodes[0].coordinates[0] = -99.0;
definition.sections[0].sectionPoints[0][0] = -99.0;
definition.steps[0].loads[0].magnitude = 99.0;
definition.warnings[0].code = "mutated";
definition.source_path = "mutated.inp";
definition.source_content_identity = "mutated";
definition.nodes[0].source_id.source_label_text = "mutated";
definition.nodes[0].coordinates[0] = -99.0;
definition.sections[0].section_points[0][0] = -99.0;
definition.steps[0].loads[0].magnitude = 99.0;
definition.warnings[0].code = "mutated";
const fesa::Domain& domain = result.Value();
const fesa::Node* const firstNodeAddress = domain.nodes().data();
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().nodes()),
const std::vector<fesa::Node>&>);
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().elements()),
const std::vector<fesa::EulerBeam3DDefinition>&>);
const fesa::Domain& domain = result.Value();
const fesa::Node* const first_node_address = domain.Nodes().data();
static_assert(
std::is_same_v<decltype(std::declval<const fesa::Domain&>().Nodes()),
const std::vector<fesa::Node>&>);
static_assert(
std::is_same_v<decltype(std::declval<const fesa::Domain&>().Elements()),
const std::vector<fesa::EulerBeam3DDefinition>&>);
EXPECT_EQ(domain.sourcePath(), std::filesystem::path{"models/owned.inp"});
EXPECT_EQ(domain.sourceContentIdentity(), "fnv1a64:fedcba9876543210");
ASSERT_EQ(domain.nodes().size(), 2U);
EXPECT_EQ(domain.nodes()[0].sourceId.source_label, 20);
EXPECT_EQ(domain.nodes()[0].sourceId.source_label_text, "0020");
EXPECT_DOUBLE_EQ(domain.nodes()[0].coordinates[0], 2.0);
EXPECT_EQ(domain.nodes()[1].sourceId.source_label, 10);
EXPECT_EQ(domain.nodes().data(), firstNodeAddress);
EXPECT_EQ(domain.SourcePath(), std::filesystem::path{"models/owned.inp"});
EXPECT_EQ(domain.SourceContentIdentity(), "fnv1a64:fedcba9876543210");
ASSERT_EQ(domain.Nodes().size(), 2U);
EXPECT_EQ(domain.Nodes()[0].source_id.source_label, 20);
EXPECT_EQ(domain.Nodes()[0].source_id.source_label_text, "0020");
EXPECT_DOUBLE_EQ(domain.Nodes()[0].coordinates[0], 2.0);
EXPECT_EQ(domain.Nodes()[1].source_id.source_label, 10);
EXPECT_EQ(domain.Nodes().data(), first_node_address);
ASSERT_EQ(domain.elements().size(), 1U);
EXPECT_EQ(domain.elements()[0].nodeIndices[0], 1U);
EXPECT_EQ(domain.elements()[0].nodeIndices[1], 0U);
ASSERT_EQ(domain.materials().size(), 1U);
ASSERT_EQ(domain.sections().size(), 1U);
EXPECT_DOUBLE_EQ(domain.sections()[0].sectionPoints[0][0], -0.1);
ASSERT_EQ(domain.nodeSets().size(), 1U);
EXPECT_EQ(domain.nodeSets()[0].nodeIndices[0], 0U);
ASSERT_EQ(domain.elementSets().size(), 1U);
EXPECT_EQ(domain.elementSets()[0].elementIndices[0], 0U);
ASSERT_EQ(domain.Elements().size(), 1U);
EXPECT_EQ(domain.Elements()[0].node_indices[0], 1U);
EXPECT_EQ(domain.Elements()[0].node_indices[1], 0U);
ASSERT_EQ(domain.Materials().size(), 1U);
ASSERT_EQ(domain.Sections().size(), 1U);
EXPECT_DOUBLE_EQ(domain.Sections()[0].section_points[0][0], -0.1);
ASSERT_EQ(domain.NodeSets().size(), 1U);
EXPECT_EQ(domain.NodeSets()[0].node_indices[0], 0U);
ASSERT_EQ(domain.ElementSets().size(), 1U);
EXPECT_EQ(domain.ElementSets()[0].element_indices[0], 0U);
ASSERT_EQ(domain.steps().size(), 1U);
EXPECT_EQ(domain.steps()[0].name, "Step-1");
EXPECT_DOUBLE_EQ(domain.steps()[0].initialIncrement, 0.1);
EXPECT_DOUBLE_EQ(domain.steps()[0].timePeriod, 1.0);
EXPECT_DOUBLE_EQ(domain.steps()[0].minimumIncrement, 1.0e-5);
EXPECT_DOUBLE_EQ(domain.steps()[0].maximumIncrement, 1.0);
ASSERT_EQ(domain.steps()[0].boundaries.size(), 1U);
ASSERT_EQ(domain.steps()[0].loads.size(), 1U);
EXPECT_DOUBLE_EQ(domain.steps()[0].loads[0].magnitude, -1000.0);
ASSERT_EQ(domain.Steps().size(), 1U);
EXPECT_EQ(domain.Steps()[0].name, "Step-1");
EXPECT_DOUBLE_EQ(domain.Steps()[0].initial_increment, 0.1);
EXPECT_DOUBLE_EQ(domain.Steps()[0].time_period, 1.0);
EXPECT_DOUBLE_EQ(domain.Steps()[0].minimum_increment, 1.0e-5);
EXPECT_DOUBLE_EQ(domain.Steps()[0].maximum_increment, 1.0);
ASSERT_EQ(domain.Steps()[0].boundaries.size(), 1U);
ASSERT_EQ(domain.Steps()[0].loads.size(), 1U);
EXPECT_DOUBLE_EQ(domain.Steps()[0].loads[0].magnitude, -1000.0);
ASSERT_EQ(domain.warnings().size(), 1U);
EXPECT_EQ(domain.warnings()[0].code, "ignored-output-request");
ASSERT_EQ(domain.Warnings().size(), 1U);
EXPECT_EQ(domain.Warnings()[0].code, "ignored-output-request");
}
TEST(DomainModel, MultipleIdentityInstancesDoNotMerge) {
fesa::ModelDefinition definition{};
definition.sourcePath = "models/two-instances.inp";
definition.sourceContentIdentity = "fnv1a64:0011223344556677";
definition.nodes = {
{{"Instance-A", 1, "1"}, {0.0, 0.0, 0.0}, {"models/two-instances.inp", 10U}},
{{"Instance-A", 2, "2"}, {1.0, 0.0, 0.0}, {"models/two-instances.inp", 11U}},
{{"Instance-B", 1, "1"}, {0.0, 0.0, 0.0}, {"models/two-instances.inp", 10U}},
{{"Instance-B", 2, "2"}, {1.0, 0.0, 0.0}, {"models/two-instances.inp", 11U}}};
definition.elements = {
{{"Instance-A", 1, "1"}, {0U, 1U}, 0U, 0U, {"models/two-instances.inp", 20U}},
{{"Instance-B", 1, "1"}, {2U, 3U}, 0U, 0U, {"models/two-instances.inp", 20U}}};
definition.materials = {{
"Steel", 210.0e9, 0.3, {"models/two-instances.inp", 30U}}};
definition.sections = {{
"Section-1",
0.02,
1.0e-5,
0.0,
2.0e-5,
5.0e-6,
{0.0, 1.0, 0.0},
{},
{"models/two-instances.inp", 40U}}};
definition.parts = {{
"BeamPart", {1, 2}, {1}, {}, {}, {"models/two-instances.inp", 2U}}};
definition.instances = {
{"Instance-A", "BeamPart", {{1, 0U}, {2, 1U}}, {{1, 0U}},
{"models/two-instances.inp", 50U}},
{"Instance-B", "BeamPart", {{1, 2U}, {2, 3U}}, {{1, 1U}},
{"models/two-instances.inp", 51U}}};
definition.steps = {{
"Step-1", {}, {}, 0.1, 1.0, 1.0e-5, 1.0,
{"models/two-instances.inp", 60U}}};
fesa::ModelDefinition definition{};
definition.source_path = "models/two-instances.inp";
definition.source_content_identity = "fnv1a64:0011223344556677";
definition.nodes = {{{"Instance-A", 1, "1"},
{0.0, 0.0, 0.0},
{"models/two-instances.inp", 10U}},
{{"Instance-A", 2, "2"},
{1.0, 0.0, 0.0},
{"models/two-instances.inp", 11U}},
{{"Instance-B", 1, "1"},
{0.0, 0.0, 0.0},
{"models/two-instances.inp", 10U}},
{{"Instance-B", 2, "2"},
{1.0, 0.0, 0.0},
{"models/two-instances.inp", 11U}}};
definition.elements = {{{"Instance-A", 1, "1"},
{0U, 1U},
0U,
0U,
{"models/two-instances.inp", 20U}},
{{"Instance-B", 1, "1"},
{2U, 3U},
0U,
0U,
{"models/two-instances.inp", 20U}}};
definition.materials = {
{"Steel", 210.0e9, 0.3, {"models/two-instances.inp", 30U}}};
definition.sections = {{"Section-1",
0.02,
1.0e-5,
0.0,
2.0e-5,
5.0e-6,
{0.0, 1.0, 0.0},
{},
{"models/two-instances.inp", 40U}}};
definition.parts = {
{"BeamPart", {1, 2}, {1}, {}, {}, {"models/two-instances.inp", 2U}}};
definition.instances = {{"Instance-A",
"BeamPart",
{{1, 0U}, {2, 1U}},
{{1, 0U}},
{"models/two-instances.inp", 50U}},
{"Instance-B",
"BeamPart",
{{1, 2U}, {2, 3U}},
{{1, 1U}},
{"models/two-instances.inp", 51U}}};
definition.steps = {{"Step-1",
{},
{},
0.1,
1.0,
1.0e-5,
1.0,
{"models/two-instances.inp", 60U}}};
auto result = fesa::Domain::create(std::move(definition));
ASSERT_TRUE(result.HasValue());
const fesa::Domain& domain = result.Value();
auto result = fesa::Domain::Create(std::move(definition));
ASSERT_TRUE(result.HasValue());
const fesa::Domain& domain = result.Value();
ASSERT_EQ(domain.nodes().size(), 4U);
EXPECT_EQ(domain.nodes()[0].sourceId.source_label, 1);
EXPECT_EQ(domain.nodes()[2].sourceId.source_label, 1);
EXPECT_EQ(domain.nodes()[0].sourceId.source_label_text, "1");
EXPECT_EQ(domain.nodes()[2].sourceId.source_label_text, "1");
EXPECT_NE(
domain.nodes()[0].sourceId.instance_name,
domain.nodes()[2].sourceId.instance_name);
ASSERT_EQ(domain.Nodes().size(), 4U);
EXPECT_EQ(domain.Nodes()[0].source_id.source_label, 1);
EXPECT_EQ(domain.Nodes()[2].source_id.source_label, 1);
EXPECT_EQ(domain.Nodes()[0].source_id.source_label_text, "1");
EXPECT_EQ(domain.Nodes()[2].source_id.source_label_text, "1");
EXPECT_NE(domain.Nodes()[0].source_id.instance_name,
domain.Nodes()[2].source_id.instance_name);
ASSERT_EQ(domain.elements().size(), 2U);
EXPECT_EQ(domain.elements()[0].sourceId.source_label, 1);
EXPECT_EQ(domain.elements()[1].sourceId.source_label, 1);
EXPECT_EQ(domain.elements()[0].sourceId.instance_name, "Instance-A");
EXPECT_EQ(domain.elements()[1].sourceId.instance_name, "Instance-B");
EXPECT_EQ(domain.elements()[0].nodeIndices[0], 0U);
EXPECT_EQ(domain.elements()[1].nodeIndices[0], 2U);
ASSERT_EQ(domain.Elements().size(), 2U);
EXPECT_EQ(domain.Elements()[0].source_id.source_label, 1);
EXPECT_EQ(domain.Elements()[1].source_id.source_label, 1);
EXPECT_EQ(domain.Elements()[0].source_id.instance_name, "Instance-A");
EXPECT_EQ(domain.Elements()[1].source_id.instance_name, "Instance-B");
EXPECT_EQ(domain.Elements()[0].node_indices[0], 0U);
EXPECT_EQ(domain.Elements()[1].node_indices[0], 2U);
}
// MITC4-MODEL-002
TEST(DomainModel, ShellOwnershipPreservesResolvedAssignmentsAndOptionalFrames) {
fesa::ModelDefinition definition{};
definition.sourcePath = "models/shell-owned.inp";
definition.sourceContentIdentity = "fnv1a64:1234567890abcdef";
definition.materials = {
{"Material-B", 70.0e9, 0.33, {"models/shell-owned.inp", 31U}},
{"Material-A", 210.0e9, 0.3, {"models/shell-owned.inp", 30U}}};
definition.shellSections = {
{"Section-B", 0.02, 0U, {"models/shell-owned.inp", 41U}},
{"Section-A", 0.01, 1U, {"models/shell-owned.inp", 40U}}};
definition.shellElements = {
{{"Shell-Instance", 20, "0020"},
fesa::ShellSourceElementType::s4r,
{4U, 5U, 6U, 7U},
0U,
0U,
{"models/shell-owned.inp", 21U}},
{{"Shell-Instance", 10, "0010"},
fesa::ShellSourceElementType::s4,
{0U, 1U, 2U, 3U},
1U,
1U,
{"models/shell-owned.inp", 20U}}};
definition.shellNodeInitialFrames = {
{4U, {0.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}},
{0U, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}}};
fesa::ModelDefinition definition{};
definition.source_path = "models/shell-owned.inp";
definition.source_content_identity = "fnv1a64:1234567890abcdef";
definition.materials = {
{"Material-B", 70.0e9, 0.33, {"models/shell-owned.inp", 31U}},
{"Material-A", 210.0e9, 0.3, {"models/shell-owned.inp", 30U}}};
definition.shell_sections = {
{"Section-B", 0.02, 0U, {"models/shell-owned.inp", 41U}},
{"Section-A", 0.01, 1U, {"models/shell-owned.inp", 40U}}};
definition.shell_elements = {{{"Shell-Instance", 20, "0020"},
fesa::ShellSourceElementType::kS4r,
{4U, 5U, 6U, 7U},
0U,
0U,
{"models/shell-owned.inp", 21U}},
{{"Shell-Instance", 10, "0010"},
fesa::ShellSourceElementType::kS4,
{0U, 1U, 2U, 3U},
1U,
1U,
{"models/shell-owned.inp", 20U}}};
definition.shell_node_initial_frames = {
{4U, {0.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}},
{0U, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}}};
auto result = fesa::Domain::create(definition);
ASSERT_TRUE(result.HasValue());
auto result = fesa::Domain::Create(definition);
ASSERT_TRUE(result.HasValue());
definition.shellSections[0].thickness = -1.0;
definition.shellElements[0].sourceId.source_label_text = "mutated";
definition.shellNodeInitialFrames[0].director[2] = -1.0;
definition.shell_sections[0].thickness = -1.0;
definition.shell_elements[0].source_id.source_label_text = "mutated";
definition.shell_node_initial_frames[0].director[2] = -1.0;
const fesa::Domain& domain = result.Value();
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().shellElements()),
const std::vector<fesa::Mitc4ShellDefinition>&>);
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().shellSections()),
const std::vector<fesa::ShellSection>&>);
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().shellNodeInitialFrames()),
const std::vector<fesa::ShellNodeInitialFrame>&>);
const fesa::Domain& domain = result.Value();
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().ShellElements()),
const std::vector<fesa::Mitc4ShellDefinition>&>);
static_assert(std::is_same_v<
decltype(std::declval<const fesa::Domain&>().ShellSections()),
const std::vector<fesa::ShellSection>&>);
static_assert(
std::is_same_v<decltype(std::declval<const fesa::Domain&>()
.ShellNodeInitialFrames()),
const std::vector<fesa::ShellNodeInitialFrame>&>);
ASSERT_EQ(domain.shellElements().size(), 2U);
EXPECT_EQ(domain.shellElements()[0].sourceId.source_label, 20);
EXPECT_EQ(domain.shellElements()[0].sourceId.source_label_text, "0020");
EXPECT_EQ(domain.shellElements()[1].sourceId.source_label, 10);
EXPECT_EQ(domain.shellElements()[0].sourceType, fesa::ShellSourceElementType::s4r);
EXPECT_EQ(domain.shellElements()[1].sourceType, fesa::ShellSourceElementType::s4);
EXPECT_EQ(domain.shellElements()[0].nodeIndices[3], 7U);
EXPECT_EQ(domain.shellElements()[0].materialIndex, 0U);
EXPECT_EQ(domain.shellElements()[0].sectionIndex, 0U);
ASSERT_EQ(domain.ShellElements().size(), 2U);
EXPECT_EQ(domain.ShellElements()[0].source_id.source_label, 20);
EXPECT_EQ(domain.ShellElements()[0].source_id.source_label_text, "0020");
EXPECT_EQ(domain.ShellElements()[1].source_id.source_label, 10);
EXPECT_EQ(domain.ShellElements()[0].source_type,
fesa::ShellSourceElementType::kS4r);
EXPECT_EQ(domain.ShellElements()[1].source_type,
fesa::ShellSourceElementType::kS4);
EXPECT_EQ(domain.ShellElements()[0].node_indices[3], 7U);
EXPECT_EQ(domain.ShellElements()[0].material_index, 0U);
EXPECT_EQ(domain.ShellElements()[0].section_index, 0U);
ASSERT_EQ(domain.shellSections().size(), 2U);
EXPECT_EQ(domain.shellSections()[0].name, "Section-B");
EXPECT_DOUBLE_EQ(domain.shellSections()[0].thickness, 0.02);
EXPECT_EQ(domain.shellSections()[0].materialIndex, 0U);
EXPECT_EQ(domain.shellSections()[1].name, "Section-A");
ASSERT_EQ(domain.ShellSections().size(), 2U);
EXPECT_EQ(domain.ShellSections()[0].name, "Section-B");
EXPECT_DOUBLE_EQ(domain.ShellSections()[0].thickness, 0.02);
EXPECT_EQ(domain.ShellSections()[0].material_index, 0U);
EXPECT_EQ(domain.ShellSections()[1].name, "Section-A");
ASSERT_EQ(domain.shellNodeInitialFrames().size(), 2U);
EXPECT_EQ(domain.shellNodeInitialFrames()[0].nodeIndex, 4U);
EXPECT_EQ(
domain.shellNodeInitialFrames()[0].director,
(std::array<double, 3>{0.0, 0.0, 1.0}));
EXPECT_EQ(
domain.shellNodeInitialFrames()[0].tangentA,
(std::array<double, 3>{1.0, 0.0, 0.0}));
EXPECT_EQ(
domain.shellNodeInitialFrames()[0].tangentB,
(std::array<double, 3>{0.0, 1.0, 0.0}));
ASSERT_EQ(domain.ShellNodeInitialFrames().size(), 2U);
EXPECT_EQ(domain.ShellNodeInitialFrames()[0].node_index, 4U);
EXPECT_EQ(domain.ShellNodeInitialFrames()[0].director,
(std::array<double, 3>{0.0, 0.0, 1.0}));
EXPECT_EQ(domain.ShellNodeInitialFrames()[0].tangent_a,
(std::array<double, 3>{1.0, 0.0, 0.0}));
EXPECT_EQ(domain.ShellNodeInitialFrames()[0].tangent_b,
(std::array<double, 3>{0.0, 1.0, 0.0}));
auto noFramesResult = fesa::Domain::create(fesa::ModelDefinition{});
ASSERT_TRUE(noFramesResult.HasValue());
EXPECT_TRUE(noFramesResult.Value().shellNodeInitialFrames().empty());
auto no_frames_result = fesa::Domain::Create(fesa::ModelDefinition{});
ASSERT_TRUE(no_frames_result.HasValue());
EXPECT_TRUE(no_frames_result.Value().ShellNodeInitialFrames().empty());
}
+124 -148
View File
@@ -1,4 +1,4 @@
#include "fesa/model/model_types.hpp"
#include "fesa/model/model_types.h"
#include <gtest/gtest.h>
@@ -14,174 +14,150 @@
namespace {
template<class T, class = void>
template <class T, class = void>
struct HasEquationId : std::false_type {};
template<class T>
template <class T>
struct HasEquationId<T, std::void_t<decltype(std::declval<T&>().equationId)>>
: std::true_type {};
template<class T, class = void>
template <class T, class = void>
struct HasEquationIds : std::false_type {};
template<class T>
template <class T>
struct HasEquationIds<T, std::void_t<decltype(std::declval<T&>().equationIds)>>
: std::true_type {};
} // namespace
} // namespace
TEST(DomainModel, SourceAndInternalIdentityRemainDistinct) {
const fesa::SourceLocation nodeLocation{
std::filesystem::path{"models/beam.inp"}, 11U};
const fesa::SourceEntityId firstIdentity{"Instance-A", 7, "0007"};
const fesa::SourceEntityId equalIdentity{"Instance-A", 7, "0007"};
const fesa::SourceEntityId laterIdentity{"Instance-B", 7, "0007"};
const fesa::SourceLocation node_location{
std::filesystem::path{"models/beam.inp"}, 11U};
const fesa::SourceEntityId first_identity{"Instance-A", 7, "0007"};
const fesa::SourceEntityId equal_identity{"Instance-A", 7, "0007"};
const fesa::SourceEntityId later_identity{"Instance-B", 7, "0007"};
EXPECT_EQ(
std::make_tuple(
firstIdentity.instance_name,
firstIdentity.source_label,
firstIdentity.source_label_text),
std::make_tuple(
equalIdentity.instance_name,
equalIdentity.source_label,
equalIdentity.source_label_text));
EXPECT_LT(
std::make_tuple(
firstIdentity.instance_name,
firstIdentity.source_label,
firstIdentity.source_label_text),
std::make_tuple(
laterIdentity.instance_name,
laterIdentity.source_label,
laterIdentity.source_label_text));
EXPECT_EQ(
std::make_tuple(first_identity.instance_name, first_identity.source_label,
first_identity.source_label_text),
std::make_tuple(equal_identity.instance_name, equal_identity.source_label,
equal_identity.source_label_text));
EXPECT_LT(
std::make_tuple(first_identity.instance_name, first_identity.source_label,
first_identity.source_label_text),
std::make_tuple(later_identity.instance_name, later_identity.source_label,
later_identity.source_label_text));
const fesa::Node node{firstIdentity, {1.0, 2.0, 3.0}, nodeLocation};
const fesa::LinearElasticMaterial material{
"Steel", 210.0e9, 0.3, {"models/beam.inp", 30U}};
const fesa::GeneralBeamSection section{
"Section-1",
0.02,
1.0e-5,
0.0,
2.0e-5,
5.0e-6,
{0.0, 1.0, 0.0},
{{-0.1, 0.0}, {0.1, 0.0}},
{"models/beam.inp", 40U}};
const fesa::EulerBeam3DDefinition element{
{"Instance-A", 3, "0003"},
{fesa::EntityIndex{5}, fesa::EntityIndex{9}},
fesa::EntityIndex{2},
fesa::EntityIndex{4},
{"models/beam.inp", 20U}};
const fesa::BoundaryCondition boundary{
"Root", 1, 6, 0.0, {"models/beam.inp", 60U}};
const fesa::NodalLoad load{
"Tip", 3, -1000.0, {"models/beam.inp", 70U}};
const fesa::StaticStepDefinition step{
"Step-1",
{boundary},
{load},
0.1,
1.0,
1.0e-5,
1.0,
{"models/beam.inp", 50U}};
const fesa::NodeSet nodeSet{
"Root", std::string{"Instance-A"}, {5U}, {"models/beam.inp", 25U}};
const fesa::ElementSet elementSet{
"Beam", std::string{"Instance-A"}, {4U}, {"models/beam.inp", 26U}};
const fesa::PartDefinition part{
"BeamPart", {7, 8}, {3}, {"Root", "Tip"}, {"Beam"},
{"models/beam.inp", 2U}};
const fesa::InstanceDefinition instance{
"Instance-A",
"BeamPart",
{{7, 5U}, {8, 9U}},
{{3, 4U}},
{"models/beam.inp", 80U}};
const fesa::Node node{first_identity, {1.0, 2.0, 3.0}, node_location};
const fesa::LinearElasticMaterial material{
"Steel", 210.0e9, 0.3, {"models/beam.inp", 30U}};
const fesa::GeneralBeamSection section{"Section-1",
0.02,
1.0e-5,
0.0,
2.0e-5,
5.0e-6,
{0.0, 1.0, 0.0},
{{-0.1, 0.0}, {0.1, 0.0}},
{"models/beam.inp", 40U}};
const fesa::EulerBeam3DDefinition element{
{"Instance-A", 3, "0003"},
{fesa::EntityIndex{5}, fesa::EntityIndex{9}},
fesa::EntityIndex{2},
fesa::EntityIndex{4},
{"models/beam.inp", 20U}};
const fesa::BoundaryCondition boundary{
"Root", 1, 6, 0.0, {"models/beam.inp", 60U}};
const fesa::NodalLoad load{"Tip", 3, -1000.0, {"models/beam.inp", 70U}};
const fesa::StaticStepDefinition step{
"Step-1", {boundary}, {load}, 0.1,
1.0, 1.0e-5, 1.0, {"models/beam.inp", 50U}};
const fesa::NodeSet node_set{
"Root", std::string{"Instance-A"}, {5U}, {"models/beam.inp", 25U}};
const fesa::ElementSet element_set{
"Beam", std::string{"Instance-A"}, {4U}, {"models/beam.inp", 26U}};
const fesa::PartDefinition part{"BeamPart", {7, 8},
{3}, {"Root", "Tip"},
{"Beam"}, {"models/beam.inp", 2U}};
const fesa::InstanceDefinition instance{"Instance-A",
"BeamPart",
{{7, 5U}, {8, 9U}},
{{3, 4U}},
{"models/beam.inp", 80U}};
fesa::ModelDefinition definition{};
definition.sourcePath = "models/beam.inp";
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.heading = "Identity mapping fixture";
definition.nodes = {node};
definition.elements = {element};
definition.materials = {material};
definition.sections = {section};
definition.nodeSets = {nodeSet};
definition.elementSets = {elementSet};
definition.parts = {part};
definition.instances = {instance};
definition.steps = {step};
definition.warnings = {{
fesa::Severity::kWarning,
"ignored-output-request",
{"models/beam.inp", 75U},
"*OUTPUT",
"",
"Output request does not alter mandatory FESA results."}};
fesa::ModelDefinition definition{};
definition.source_path = "models/beam.inp";
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.heading = "Identity mapping fixture";
definition.nodes = {node};
definition.elements = {element};
definition.materials = {material};
definition.sections = {section};
definition.node_sets = {node_set};
definition.element_sets = {element_set};
definition.parts = {part};
definition.instances = {instance};
definition.steps = {step};
definition.warnings = {
{fesa::Severity::kWarning,
"ignored-output-request",
{"models/beam.inp", 75U},
"*OUTPUT",
"",
"Output request does not alter mandatory FESA results."}};
ASSERT_EQ(definition.nodes.size(), 1U);
EXPECT_EQ(definition.nodes[0].sourceId.source_label_text, "0007");
EXPECT_EQ(definition.nodes[0].location.line, 11U);
ASSERT_EQ(definition.instances.size(), 1U);
EXPECT_EQ(definition.instances[0].partName, "BeamPart");
EXPECT_EQ(definition.instances[0].nodeMappings[0].sourceLabel, 7);
EXPECT_EQ(definition.instances[0].nodeMappings[0].internalIndex, 5U);
EXPECT_EQ(definition.instances[0].elementMappings[0].internalIndex, 4U);
EXPECT_EQ(definition.steps[0].initialIncrement, 0.1);
EXPECT_EQ(definition.steps[0].timePeriod, 1.0);
EXPECT_EQ(definition.steps[0].minimumIncrement, 1.0e-5);
EXPECT_EQ(definition.steps[0].maximumIncrement, 1.0);
ASSERT_EQ(definition.warnings.size(), 1U);
EXPECT_EQ(definition.warnings[0].location.line, 75U);
ASSERT_EQ(definition.nodes.size(), 1U);
EXPECT_EQ(definition.nodes[0].source_id.source_label_text, "0007");
EXPECT_EQ(definition.nodes[0].location.line, 11U);
ASSERT_EQ(definition.instances.size(), 1U);
EXPECT_EQ(definition.instances[0].part_name, "BeamPart");
EXPECT_EQ(definition.instances[0].node_mappings[0].source_label, 7);
EXPECT_EQ(definition.instances[0].node_mappings[0].internal_index, 5U);
EXPECT_EQ(definition.instances[0].element_mappings[0].internal_index, 4U);
EXPECT_EQ(definition.steps[0].initial_increment, 0.1);
EXPECT_EQ(definition.steps[0].time_period, 1.0);
EXPECT_EQ(definition.steps[0].minimum_increment, 1.0e-5);
EXPECT_EQ(definition.steps[0].maximum_increment, 1.0);
ASSERT_EQ(definition.warnings.size(), 1U);
EXPECT_EQ(definition.warnings[0].location.line, 75U);
static_assert(!HasEquationId<fesa::Node>::value);
static_assert(!HasEquationIds<fesa::Node>::value);
static_assert(!HasEquationId<fesa::EulerBeam3DDefinition>::value);
static_assert(!HasEquationIds<fesa::EulerBeam3DDefinition>::value);
static_assert(!HasEquationId<fesa::Node>::value);
static_assert(!HasEquationIds<fesa::Node>::value);
static_assert(!HasEquationId<fesa::EulerBeam3DDefinition>::value);
static_assert(!HasEquationIds<fesa::EulerBeam3DDefinition>::value);
}
// MITC4-MODEL-001
TEST(DomainModel, Mitc4ShellRecordsPreserveSourceAndInternalIdentity) {
const fesa::Mitc4ShellDefinition s4Element{
{"Shell-Instance", 41, "0041"},
fesa::ShellSourceElementType::s4,
{fesa::EntityIndex{3},
fesa::EntityIndex{5},
fesa::EntityIndex{8},
fesa::EntityIndex{13}},
fesa::EntityIndex{2},
fesa::EntityIndex{7},
{"models/shell.inp", 20U}};
const fesa::Mitc4ShellDefinition s4rElement{
{"Shell-Instance", 42, "0042"},
fesa::ShellSourceElementType::s4r,
{fesa::EntityIndex{13},
fesa::EntityIndex{8},
fesa::EntityIndex{5},
fesa::EntityIndex{3}},
fesa::EntityIndex{2},
fesa::EntityIndex{7},
{"models/shell.inp", 21U}};
const fesa::Mitc4ShellDefinition s4_element{
{"Shell-Instance", 41, "0041"},
fesa::ShellSourceElementType::kS4,
{fesa::EntityIndex{3}, fesa::EntityIndex{5}, fesa::EntityIndex{8},
fesa::EntityIndex{13}},
fesa::EntityIndex{2},
fesa::EntityIndex{7},
{"models/shell.inp", 20U}};
const fesa::Mitc4ShellDefinition s4r_element{
{"Shell-Instance", 42, "0042"},
fesa::ShellSourceElementType::kS4r,
{fesa::EntityIndex{13}, fesa::EntityIndex{8}, fesa::EntityIndex{5},
fesa::EntityIndex{3}},
fesa::EntityIndex{2},
fesa::EntityIndex{7},
{"models/shell.inp", 21U}};
EXPECT_EQ(s4Element.sourceId.instance_name, "Shell-Instance");
EXPECT_EQ(s4Element.sourceId.source_label, 41);
EXPECT_EQ(s4Element.sourceId.source_label_text, "0041");
EXPECT_EQ(s4Element.sourceType, fesa::ShellSourceElementType::s4);
EXPECT_EQ(s4rElement.sourceType, fesa::ShellSourceElementType::s4r);
EXPECT_NE(s4Element.sourceType, s4rElement.sourceType);
EXPECT_EQ(
fesa::kMitc4InternalFormulation,
std::string_view{"FESA-MITC4"});
EXPECT_EQ(
s4Element.nodeIndices,
(std::array<fesa::EntityIndex, 4>{3U, 5U, 8U, 13U}));
EXPECT_EQ(s4Element.materialIndex, 2U);
EXPECT_EQ(s4Element.sectionIndex, 7U);
EXPECT_EQ(s4_element.source_id.instance_name, "Shell-Instance");
EXPECT_EQ(s4_element.source_id.source_label, 41);
EXPECT_EQ(s4_element.source_id.source_label_text, "0041");
EXPECT_EQ(s4_element.source_type, fesa::ShellSourceElementType::kS4);
EXPECT_EQ(s4r_element.source_type, fesa::ShellSourceElementType::kS4r);
EXPECT_NE(s4_element.source_type, s4r_element.source_type);
EXPECT_EQ(fesa::kMitc4InternalFormulation, std::string_view{"FESA-MITC4"});
EXPECT_EQ(s4_element.node_indices,
(std::array<fesa::EntityIndex, 4>{3U, 5U, 8U, 13U}));
EXPECT_EQ(s4_element.material_index, 2U);
EXPECT_EQ(s4_element.section_index, 7U);
static_assert(!HasEquationId<fesa::Mitc4ShellDefinition>::value);
static_assert(!HasEquationIds<fesa::Mitc4ShellDefinition>::value);
static_assert(!HasEquationId<fesa::Mitc4ShellDefinition>::value);
static_assert(!HasEquationIds<fesa::Mitc4ShellDefinition>::value);
}
+192 -213
View File
@@ -1,4 +1,4 @@
#include "fesa/model/shell_geometry.hpp"
#include "fesa/model/shell_geometry.h"
#include <gtest/gtest.h>
@@ -14,263 +14,242 @@ namespace {
using Vector3 = std::array<double, 3>;
fesa::Node node(fesa::EntityIndex label, Vector3 coordinates) {
return {
{"Shell-Instance", static_cast<std::int64_t>(label),
std::to_string(label)},
coordinates,
{"shell-geometry.inp", static_cast<std::size_t>(label + 1U)}};
fesa::Node Node(fesa::EntityIndex label, Vector3 coordinates) {
return {{"Shell-Instance", static_cast<std::int64_t>(label),
std::to_string(label)},
coordinates,
{"shell-geometry.inp", static_cast<std::size_t>(label + 1U)}};
}
fesa::Mitc4ShellDefinition element(
fesa::EntityIndex label,
std::array<fesa::EntityIndex, 4> nodeIndices) {
return {
{"Shell-Instance", static_cast<std::int64_t>(label),
std::to_string(label)},
fesa::ShellSourceElementType::s4,
nodeIndices,
0U,
0U,
{"shell-geometry.inp", static_cast<std::size_t>(100U + label)}};
fesa::Mitc4ShellDefinition Element(
fesa::EntityIndex label, std::array<fesa::EntityIndex, 4> node_indices) {
return {{"Shell-Instance", static_cast<std::int64_t>(label),
std::to_string(label)},
fesa::ShellSourceElementType::kS4,
node_indices,
0U,
0U,
{"shell-geometry.inp", static_cast<std::size_t>(100U + label)}};
}
std::vector<fesa::ShellSection> sections(double thickness = 0.2) {
return {{"Section", thickness, 0U, {"shell-geometry.inp", 90U}}};
std::vector<fesa::ShellSection> Sections(double thickness = 0.2) {
return {{"Section", thickness, 0U, {"shell-geometry.inp", 90U}}};
}
double dot(const Vector3& left, const Vector3& right) {
return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
double Dot(const Vector3& left, const Vector3& right) {
return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
}
Vector3 cross(const Vector3& left, const Vector3& right) {
return {
left[1] * right[2] - left[2] * right[1],
left[2] * right[0] - left[0] * right[2],
left[0] * right[1] - left[1] * right[0]};
Vector3 Cross(const Vector3& left, const Vector3& right) {
return {left[1] * right[2] - left[2] * right[1],
left[2] * right[0] - left[0] * right[2],
left[0] * right[1] - left[1] * right[0]};
}
double norm(const Vector3& value) {
return std::sqrt(dot(value, value));
double Norm(const Vector3& value) { return std::sqrt(Dot(value, value)); }
void ExpectVectorNear(const Vector3& actual, const Vector3& expected,
double tolerance = 1.0e-12) {
for (std::size_t component = 0U; component < actual.size(); ++component) {
EXPECT_NEAR(actual[component], expected[component], tolerance);
}
}
void expectVectorNear(
const Vector3& actual,
const Vector3& expected,
double tolerance = 1.0e-12) {
for (std::size_t component = 0U; component < actual.size(); ++component) {
EXPECT_NEAR(actual[component], expected[component], tolerance);
}
void ExpectRightHandedFrame(const fesa::ShellNodeInitialFrame& frame) {
EXPECT_NEAR(Norm(frame.director), 1.0, 1.0e-12);
EXPECT_NEAR(Norm(frame.tangent_a), 1.0, 1.0e-12);
EXPECT_NEAR(Norm(frame.tangent_b), 1.0, 1.0e-12);
EXPECT_NEAR(Dot(frame.director, frame.tangent_a), 0.0, 1.0e-12);
EXPECT_NEAR(Dot(frame.director, frame.tangent_b), 0.0, 1.0e-12);
EXPECT_NEAR(Dot(frame.tangent_a, frame.tangent_b), 0.0, 1.0e-12);
ExpectVectorNear(Cross(frame.tangent_a, frame.tangent_b), frame.director);
}
void expectRightHandedFrame(const fesa::ShellNodeInitialFrame& frame) {
EXPECT_NEAR(norm(frame.director), 1.0, 1.0e-12);
EXPECT_NEAR(norm(frame.tangentA), 1.0, 1.0e-12);
EXPECT_NEAR(norm(frame.tangentB), 1.0, 1.0e-12);
EXPECT_NEAR(dot(frame.director, frame.tangentA), 0.0, 1.0e-12);
EXPECT_NEAR(dot(frame.director, frame.tangentB), 0.0, 1.0e-12);
EXPECT_NEAR(dot(frame.tangentA, frame.tangentB), 0.0, 1.0e-12);
expectVectorNear(cross(frame.tangentA, frame.tangentB), frame.director);
const fesa::ShellNodeInitialFrame& FrameFor(const fesa::ShellGeometry& geometry,
fesa::EntityIndex node_index) {
const auto found =
std::find_if(geometry.nodal_frames.begin(), geometry.nodal_frames.end(),
[node_index](const fesa::ShellNodeInitialFrame& frame) {
return frame.node_index == node_index;
});
EXPECT_NE(found, geometry.nodal_frames.end());
return *found;
}
const fesa::ShellNodeInitialFrame& frameFor(
const fesa::ShellGeometry& geometry,
fesa::EntityIndex nodeIndex) {
const auto found = std::find_if(
geometry.nodalFrames.begin(),
geometry.nodalFrames.end(),
[nodeIndex](const fesa::ShellNodeInitialFrame& frame) {
return frame.nodeIndex == nodeIndex;
});
EXPECT_NE(found, geometry.nodalFrames.end());
return *found;
void ExpectFailureCode(const fesa::Result<fesa::ShellGeometry>& result,
const std::string& code) {
ASSERT_FALSE(result.HasValue());
EXPECT_EQ(result.GetStatus().Category(), fesa::FailureCategory::kModel);
ASSERT_EQ(result.GetStatus().Diagnostics().size(), 1U);
EXPECT_EQ(result.GetStatus().Diagnostics()[0].code, code);
}
void expectFailureCode(
const fesa::Result<fesa::ShellGeometry>& result,
const std::string& code) {
ASSERT_FALSE(result.HasValue());
EXPECT_EQ(result.GetStatus().Category(), fesa::FailureCategory::kModel);
ASSERT_EQ(result.GetStatus().Diagnostics().size(), 1U);
EXPECT_EQ(result.GetStatus().Diagnostics()[0].code, code);
}
} // namespace
} // namespace
// MITC4-GEO-001
TEST(Mitc4Geometry, BuildsDeterministicFramesForPlanarRotatedAndWarpedElements) {
const std::vector<fesa::Node> planarNodes{
node(0U, {0.0, 0.0, 0.0}),
node(1U, {1.0, 0.0, 0.0}),
node(2U, {1.0, 1.0, 0.0}),
node(3U, {0.0, 1.0, 0.0})};
auto planar = fesa::preprocessShellGeometry(
planarNodes, {element(10U, {0U, 1U, 2U, 3U})}, sections());
TEST(Mitc4Geometry,
BuildsDeterministicFramesForPlanarRotatedAndWarpedElements) {
const std::vector<fesa::Node> planar_nodes{
Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {1.0, 1.0, 0.0}), Node(3U, {0.0, 1.0, 0.0})};
auto planar = fesa::PreprocessShellGeometry(
planar_nodes, {Element(10U, {0U, 1U, 2U, 3U})}, Sections());
ASSERT_TRUE(planar.HasValue());
ASSERT_EQ(planar.Value().elementData.size(), 1U);
expectVectorNear(planar.Value().elementData[0].normalCandidate, {0.0, 0.0, 1.0});
EXPECT_NEAR(planar.Value().elementData[0].surfaceAreaWeight, 1.0, 1.0e-12);
ASSERT_EQ(planar.Value().nodalFrames.size(), 4U);
for (const auto& frame : planar.Value().nodalFrames) {
expectVectorNear(frame.director, {0.0, 0.0, 1.0});
expectVectorNear(frame.tangentA, {1.0, 0.0, 0.0});
expectVectorNear(frame.tangentB, {0.0, 1.0, 0.0});
expectRightHandedFrame(frame);
}
ASSERT_TRUE(planar.HasValue());
ASSERT_EQ(planar.Value().element_data.size(), 1U);
ExpectVectorNear(planar.Value().element_data[0].normal_candidate,
{0.0, 0.0, 1.0});
EXPECT_NEAR(planar.Value().element_data[0].surface_area_weight, 1.0, 1.0e-12);
ASSERT_EQ(planar.Value().nodal_frames.size(), 4U);
for (const auto& frame : planar.Value().nodal_frames) {
ExpectVectorNear(frame.director, {0.0, 0.0, 1.0});
ExpectVectorNear(frame.tangent_a, {1.0, 0.0, 0.0});
ExpectVectorNear(frame.tangent_b, {0.0, 1.0, 0.0});
ExpectRightHandedFrame(frame);
}
const std::vector<fesa::Node> rotatedNodes{
node(0U, {0.0, 0.0, 0.0}),
node(1U, {0.0, 1.0, 0.0}),
node(2U, {0.0, 1.0, 1.0}),
node(3U, {0.0, 0.0, 1.0})};
auto rotated = fesa::preprocessShellGeometry(
rotatedNodes, {element(11U, {0U, 1U, 2U, 3U})}, sections());
const std::vector<fesa::Node> rotated_nodes{
Node(0U, {0.0, 0.0, 0.0}), Node(1U, {0.0, 1.0, 0.0}),
Node(2U, {0.0, 1.0, 1.0}), Node(3U, {0.0, 0.0, 1.0})};
auto rotated = fesa::PreprocessShellGeometry(
rotated_nodes, {Element(11U, {0U, 1U, 2U, 3U})}, Sections());
ASSERT_TRUE(rotated.HasValue());
const auto& rotatedFrame = frameFor(rotated.Value(), 0U);
expectVectorNear(rotatedFrame.director, {1.0, 0.0, 0.0});
expectVectorNear(rotatedFrame.tangentA, {0.0, 1.0, 0.0});
expectVectorNear(rotatedFrame.tangentB, {0.0, 0.0, 1.0});
expectRightHandedFrame(rotatedFrame);
ASSERT_TRUE(rotated.HasValue());
const auto& rotated_frame = FrameFor(rotated.Value(), 0U);
ExpectVectorNear(rotated_frame.director, {1.0, 0.0, 0.0});
ExpectVectorNear(rotated_frame.tangent_a, {0.0, 1.0, 0.0});
ExpectVectorNear(rotated_frame.tangent_b, {0.0, 0.0, 1.0});
ExpectRightHandedFrame(rotated_frame);
const std::vector<fesa::Node> warpedNodes{
node(0U, {0.0, 0.0, 0.0}),
node(1U, {2.0, 0.0, 0.0}),
node(2U, {2.0, 1.0, 0.2}),
node(3U, {0.0, 1.0, 0.0})};
auto warped = fesa::preprocessShellGeometry(
warpedNodes, {element(12U, {0U, 1U, 2U, 3U})}, sections());
const std::vector<fesa::Node> warped_nodes{
Node(0U, {0.0, 0.0, 0.0}), Node(1U, {2.0, 0.0, 0.0}),
Node(2U, {2.0, 1.0, 0.2}), Node(3U, {0.0, 1.0, 0.0})};
auto warped = fesa::PreprocessShellGeometry(
warped_nodes, {Element(12U, {0U, 1U, 2U, 3U})}, Sections());
ASSERT_TRUE(warped.HasValue());
EXPECT_GT(warped.Value().elementData[0].surfaceAreaWeight, 2.0);
for (const auto& frame : warped.Value().nodalFrames) {
expectRightHandedFrame(frame);
}
ASSERT_TRUE(warped.HasValue());
EXPECT_GT(warped.Value().element_data[0].surface_area_weight, 2.0);
for (const auto& frame : warped.Value().nodal_frames) {
ExpectRightHandedFrame(frame);
}
}
// MITC4-GEO-002
TEST(Mitc4Geometry, AreaWeightsSharedDirectorsInStableSourceIdentityOrder) {
const std::vector<fesa::Node> nodes{
node(0U, {0.0, 0.0, 0.0}),
node(1U, {1.0, 0.0, 0.0}),
node(2U, {1.0, 1.0, 0.0}),
node(3U, {0.0, 1.0, 0.0}),
node(4U, {2.0, 0.0, 1.0}),
node(5U, {2.0, 1.0, 1.0})};
const auto flat = element(10U, {0U, 1U, 2U, 3U});
const auto tilted = element(20U, {1U, 4U, 5U, 2U});
const std::vector<fesa::Node> nodes{
Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {1.0, 1.0, 0.0}), Node(3U, {0.0, 1.0, 0.0}),
Node(4U, {2.0, 0.0, 1.0}), Node(5U, {2.0, 1.0, 1.0})};
const auto flat = Element(10U, {0U, 1U, 2U, 3U});
const auto tilted = Element(20U, {1U, 4U, 5U, 2U});
auto first = fesa::preprocessShellGeometry(
nodes, {tilted, flat}, sections());
auto second = fesa::preprocessShellGeometry(
nodes, {flat, tilted}, sections());
auto first = fesa::PreprocessShellGeometry(nodes, {tilted, flat}, Sections());
auto second =
fesa::PreprocessShellGeometry(nodes, {flat, tilted}, Sections());
ASSERT_TRUE(first.HasValue());
ASSERT_TRUE(second.HasValue());
const Vector3 expectedSharedDirector{
-1.0 / std::sqrt(5.0), 0.0, 2.0 / std::sqrt(5.0)};
for (const auto sharedNode : {1U, 2U}) {
const auto& firstFrame = frameFor(first.Value(), sharedNode);
const auto& secondFrame = frameFor(second.Value(), sharedNode);
expectVectorNear(firstFrame.director, expectedSharedDirector);
expectVectorNear(firstFrame.director, secondFrame.director, 0.0);
expectVectorNear(firstFrame.tangentA, {0.0, 1.0, 0.0});
expectRightHandedFrame(firstFrame);
}
ASSERT_TRUE(first.HasValue());
ASSERT_TRUE(second.HasValue());
const Vector3 expected_shared_director{-1.0 / std::sqrt(5.0), 0.0,
2.0 / std::sqrt(5.0)};
for (const auto sharedNode : {1U, 2U}) {
const auto& firstFrame = FrameFor(first.Value(), sharedNode);
const auto& secondFrame = FrameFor(second.Value(), sharedNode);
ExpectVectorNear(firstFrame.director, expected_shared_director);
ExpectVectorNear(firstFrame.director, secondFrame.director, 0.0);
ExpectVectorNear(firstFrame.tangent_a, {0.0, 1.0, 0.0});
ExpectRightHandedFrame(firstFrame);
}
}
// MITC4-GEO-003
TEST(Mitc4Geometry, RejectsInvalidSurfaceJacobianAndIncidentOrientationCases) {
const auto validElement = element(10U, {0U, 1U, 2U, 3U});
const auto valid_element = Element(10U, {0U, 1U, 2U, 3U});
expectFailureCode(
fesa::preprocessShellGeometry(
{node(0U, {0.0, 0.0, 0.0}), node(1U, {0.0, 0.0, 0.0}),
node(2U, {1.0, 1.0, 0.0}), node(3U, {0.0, 1.0, 0.0})},
{validElement}, sections()),
"invalid-shell-geometry");
ExpectFailureCode(fesa::PreprocessShellGeometry(
{Node(0U, {0.0, 0.0, 0.0}), Node(1U, {0.0, 0.0, 0.0}),
Node(2U, {1.0, 1.0, 0.0}), Node(3U, {0.0, 1.0, 0.0})},
{valid_element}, Sections()),
"invalid-shell-geometry");
expectFailureCode(
fesa::preprocessShellGeometry(
{node(0U, {0.0, 0.0, 0.0}), node(1U, {1.0, 1.0, 0.0}),
node(2U, {0.0, 1.0, 0.0}), node(3U, {1.0, 0.0, 0.0})},
{validElement}, sections()),
"invalid-shell-geometry");
ExpectFailureCode(fesa::PreprocessShellGeometry(
{Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 1.0, 0.0}),
Node(2U, {0.0, 1.0, 0.0}), Node(3U, {1.0, 0.0, 0.0})},
{valid_element}, Sections()),
"invalid-shell-geometry");
expectFailureCode(
fesa::preprocessShellGeometry(
{node(0U, {0.0, 0.0, 0.0}), node(1U, {1.0, 0.0, 0.0}),
node(2U, {2.0, 0.0, 0.0}), node(3U, {3.0, 0.0, 0.0})},
{validElement}, sections()),
"invalid-shell-geometry");
ExpectFailureCode(fesa::PreprocessShellGeometry(
{Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {2.0, 0.0, 0.0}), Node(3U, {3.0, 0.0, 0.0})},
{valid_element}, Sections()),
"invalid-shell-geometry");
expectFailureCode(
fesa::preprocessShellGeometry(
{node(0U, {0.0, 0.0, 0.0}), node(1U, {1.0, 0.0, 0.0}),
node(2U, {0.05, 0.05, 0.0}), node(3U, {0.0, 1.0, 0.0})},
{validElement}, sections()),
"invalid-shell-geometry");
ExpectFailureCode(
fesa::PreprocessShellGeometry(
{Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {0.05, 0.05, 0.0}), Node(3U, {0.0, 1.0, 0.0})},
{valid_element}, Sections()),
"invalid-shell-geometry");
expectFailureCode(
fesa::preprocessShellGeometry(
{node(0U, {0.0, 0.0, 0.0}),
node(1U, {1.0, 0.0, 0.0}),
node(2U, {1.0, std::numeric_limits<double>::quiet_NaN(), 0.0}),
node(3U, {0.0, 1.0, 0.0})},
{validElement}, sections()),
"invalid-shell-geometry");
ExpectFailureCode(
fesa::PreprocessShellGeometry(
{Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {1.0, std::numeric_limits<double>::quiet_NaN(), 0.0}),
Node(3U, {0.0, 1.0, 0.0})},
{valid_element}, Sections()),
"invalid-shell-geometry");
expectFailureCode(
fesa::preprocessShellGeometry(
{node(0U, {0.0, 0.0, 0.0}), node(1U, {1.0, 0.0, 0.0}),
node(2U, {1.0, 1.0, 0.0}), node(3U, {0.0, 1.0, 0.0})},
{validElement}, sections(0.0)),
"invalid-shell-jacobian");
ExpectFailureCode(fesa::PreprocessShellGeometry(
{Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {1.0, 1.0, 0.0}), Node(3U, {0.0, 1.0, 0.0})},
{valid_element}, Sections(0.0)),
"invalid-shell-jacobian");
const std::vector<fesa::Node> opposedNodes{
node(0U, {0.0, 0.0, 0.0}), node(1U, {1.0, 0.0, 0.0}),
node(2U, {1.0, 1.0, 0.0}), node(3U, {0.0, 1.0, 0.0})};
expectFailureCode(
fesa::preprocessShellGeometry(
opposedNodes,
{element(10U, {0U, 1U, 2U, 3U}),
element(20U, {0U, 3U, 2U, 1U})},
sections()),
"opposed-incident-normal");
const std::vector<fesa::Node> opposed_nodes{
Node(0U, {0.0, 0.0, 0.0}), Node(1U, {1.0, 0.0, 0.0}),
Node(2U, {1.0, 1.0, 0.0}), Node(3U, {0.0, 1.0, 0.0})};
ExpectFailureCode(
fesa::PreprocessShellGeometry(
opposed_nodes,
{Element(10U, {0U, 1U, 2U, 3U}), Element(20U, {0U, 3U, 2U, 1U})},
Sections()),
"opposed-incident-normal");
}
// MITC4-GEO-004
TEST(Mitc4Geometry, ExposesTheCompleteRequiredValidationPointInventory) {
const auto& points = fesa::shellGeometryValidationPoints();
ASSERT_EQ(points.size(), 17U);
EXPECT_EQ(
std::count_if(points.begin(), points.end(), [](const auto& point) {
return point.kind == fesa::ShellGeometryPointKind::center;
}),
1);
EXPECT_EQ(
std::count_if(points.begin(), points.end(), [](const auto& point) {
return point.kind == fesa::ShellGeometryPointKind::stiffness;
}),
8);
EXPECT_EQ(
std::count_if(points.begin(), points.end(), [](const auto& point) {
return point.kind == fesa::ShellGeometryPointKind::tying;
}),
4);
EXPECT_EQ(
std::count_if(points.begin(), points.end(), [](const auto& point) {
return point.kind == fesa::ShellGeometryPointKind::recovery;
}),
4);
const auto& points = fesa::ShellGeometryValidationPoints();
ASSERT_EQ(points.size(), 17U);
EXPECT_EQ(std::count_if(points.begin(), points.end(),
[](const auto& point) {
return point.kind ==
fesa::ShellGeometryPointKind::kCenter;
}),
1);
EXPECT_EQ(std::count_if(points.begin(), points.end(),
[](const auto& point) {
return point.kind ==
fesa::ShellGeometryPointKind::kStiffness;
}),
8);
EXPECT_EQ(std::count_if(points.begin(), points.end(),
[](const auto& point) {
return point.kind ==
fesa::ShellGeometryPointKind::kTying;
}),
4);
EXPECT_EQ(std::count_if(points.begin(), points.end(),
[](const auto& point) {
return point.kind ==
fesa::ShellGeometryPointKind::kRecovery;
}),
4);
EXPECT_EQ(points.front().naturalCoordinates, (Vector3{0.0, 0.0, 0.0}));
const double gauss = 1.0 / std::sqrt(3.0);
EXPECT_EQ(points[1].naturalCoordinates, (Vector3{-gauss, -gauss, -gauss}));
EXPECT_EQ(points[8].naturalCoordinates, (Vector3{-gauss, gauss, gauss}));
EXPECT_EQ(points[9].naturalCoordinates, (Vector3{0.0, -1.0, 0.0}));
EXPECT_EQ(points[12].naturalCoordinates, (Vector3{1.0, 0.0, 0.0}));
EXPECT_EQ(points[13].naturalCoordinates, (Vector3{-gauss, -gauss, 0.0}));
EXPECT_EQ(points[16].naturalCoordinates, (Vector3{-gauss, gauss, 0.0}));
EXPECT_EQ(points.front().natural_coordinates, (Vector3{0.0, 0.0, 0.0}));
const double gauss = 1.0 / std::sqrt(3.0);
EXPECT_EQ(points[1].natural_coordinates, (Vector3{-gauss, -gauss, -gauss}));
EXPECT_EQ(points[8].natural_coordinates, (Vector3{-gauss, gauss, gauss}));
EXPECT_EQ(points[9].natural_coordinates, (Vector3{0.0, -1.0, 0.0}));
EXPECT_EQ(points[12].natural_coordinates, (Vector3{1.0, 0.0, 0.0}));
EXPECT_EQ(points[13].natural_coordinates, (Vector3{-gauss, -gauss, 0.0}));
EXPECT_EQ(points[16].natural_coordinates, (Vector3{-gauss, gauss, 0.0}));
}
+4 -4
View File
@@ -13,13 +13,13 @@ namespace {
fesa::DofManager makeEmptyDofs() {
fesa::ModelDefinition definition{};
definition.sourcePath = "models/result-records.inp";
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = "models/result-records.inp";
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.steps = {{
"Step-1", {}, {}, 0.1, 1.0, 0.01, 1.0,
{definition.sourcePath, 10U}}};
{definition.source_path, 10U}}};
auto domain = fesa::Domain::create(std::move(definition));
auto domain = fesa::Domain::Create(std::move(definition));
EXPECT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::create(domain.Value());
EXPECT_TRUE(model.HasValue());
+26 -26
View File
@@ -6,7 +6,7 @@
#include "fesa/assembly/parallel_for.hpp"
#include "fesa/assembly/sparse_assembler.hpp"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <gtest/gtest.h>
@@ -51,8 +51,8 @@ fesa::ModelDefinition makeDefinition(
const bool nonzeroPrescription = true) {
const std::filesystem::path source{"models/result-recovery.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:0123456789abcdef";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:0123456789abcdef";
definition.nodes = {
{{"Beam-1", 1, "1"}, {0.0, 0.0, 0.0}, {source, 10U}},
{{"Beam-1", 2, "2"}, {kLength, 0.0, 0.0}, {source, 11U}}};
@@ -110,7 +110,7 @@ RecoveryFixture makeFixture(
const bool reverseSecond = false,
const bool sectionJump = false,
const bool nonzeroPrescription = true) {
auto domainResult = fesa::Domain::create(makeDefinition(
auto domainResult = fesa::Domain::Create(makeDefinition(
twoElements,
std::move(sectionPoints),
std::move(loads),
@@ -158,8 +158,8 @@ fesa::ModelDefinition makeShellDefinition(
std::vector<fesa::NodalLoad> loads = {}) {
const std::filesystem::path source{"models/shell-result-recovery.inp"};
fesa::ModelDefinition definition{};
definition.sourcePath = source;
definition.sourceContentIdentity = "fnv1a64:fedcba9876543210";
definition.source_path = source;
definition.source_content_identity = "fnv1a64:fedcba9876543210";
definition.nodes = {
{{"Shell-1", 1, "1"}, {-1.0, -1.0, 0.0}, {source, 10U}},
{{"Shell-1", 2, "2"}, {1.0, -1.0, 0.0}, {source, 11U}},
@@ -175,26 +175,26 @@ fesa::ModelDefinition makeShellDefinition(
}
definition.materials = {
{"Material", 120.0, 0.25, {source, 20U}}};
definition.shellSections = {
definition.shell_sections = {
{"ShellSection", 2.0, 0U, {source, 30U}}};
definition.shellElements = {{
definition.shell_elements = {{
{"Shell-1", 10, "10"},
fesa::ShellSourceElementType::s4,
fesa::ShellSourceElementType::kS4,
{0U, 1U, twoElements ? 4U : 3U, twoElements ? 3U : 2U},
0U,
0U,
{source, 40U}}};
if (twoElements) {
definition.shellElements.push_back({
definition.shell_elements.push_back({
{"Shell-1", 20, "20"},
fesa::ShellSourceElementType::s4r,
fesa::ShellSourceElementType::kS4r,
{1U, 2U, 5U, 4U},
0U,
0U,
{source, 41U}});
}
for (std::size_t node = 0U; node < definition.nodes.size(); ++node) {
definition.shellNodeInitialFrames.push_back({
definition.shell_node_initial_frames.push_back({
static_cast<fesa::EntityIndex>(node),
{0.0, 0.0, 1.0},
{1.0, 0.0, 0.0},
@@ -206,7 +206,7 @@ fesa::ModelDefinition makeShellDefinition(
for (std::size_t node = 0U; node < definition.nodes.size(); ++node) {
allNodes.push_back(static_cast<fesa::EntityIndex>(node));
}
definition.nodeSets.push_back(
definition.node_sets.push_back(
{"All", {}, std::move(allNodes), {source, 50U}});
}
definition.steps = {{
@@ -225,7 +225,7 @@ fesa::ModelDefinition makeShellDefinition(
}
ShellRecoveryFixture makeShellFixture(fesa::ModelDefinition definition) {
auto domainResult = fesa::Domain::create(std::move(definition));
auto domainResult = fesa::Domain::Create(std::move(definition));
if (!domainResult.HasValue()) {
throw std::runtime_error{
"Shell recovery fixture Domain construction failed."};
@@ -272,10 +272,10 @@ fesa::AnalysisState makeShellPhysicalState(
auto state = fesa::AnalysisState::create(
*fixture.dofs, {"Step-1", 0U});
for (std::size_t node = 0U;
node < fixture.domain->nodes().size();
node < fixture.domain->Nodes().size();
++node) {
const double x = fixture.domain->nodes()[node].coordinates[0U];
const double y = fixture.domain->nodes()[node].coordinates[1U];
const double x = fixture.domain->Nodes()[node].coordinates[0U];
const double y = fixture.domain->Nodes()[node].coordinates[1U];
const std::size_t offset = 6U * node;
state.displacement()[offset] =
generalized[0U] * x + 0.5 * generalized[2U] * y;
@@ -345,19 +345,19 @@ void expectScaledNear(
std::vector<fesa::EndpointResultRow> makeStationRows(
const RecoveryFixture& fixture) {
const auto& nodes = fixture.domain->nodes();
const auto& elements = fixture.domain->elements();
const auto& nodes = fixture.domain->Nodes();
const auto& elements = fixture.domain->Elements();
return {
{0U, 0, nodes[elements[0U].nodeIndices[0U]].sourceId,
{0U, 0, nodes[elements[0U].node_indices[0U]].source_id,
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1.0, 2.0, 3.0, 4.0}},
{0U, 1, nodes[elements[0U].nodeIndices[1U]].sourceId,
{0U, 1, nodes[elements[0U].node_indices[1U]].source_id,
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{5.0, 6.0, 7.0, 8.0}},
{1U, 0, nodes[elements[1U].nodeIndices[0U]].sourceId,
{1U, 0, nodes[elements[1U].node_indices[0U]].source_id,
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{5.0, 6.0, 7.0, 8.0}},
{1U, 1, nodes[elements[1U].nodeIndices[1U]].sourceId,
{1U, 1, nodes[elements[1U].node_indices[1U]].source_id,
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{9.0, 10.0, 11.0, 12.0}}};
}
@@ -639,10 +639,10 @@ TEST(ResultRecovery, RecoversShellRowsInStableElementAndGpOrder) {
auto state = fesa::AnalysisState::create(
*fixture.dofs, {"Step-1", 0U});
for (std::size_t node = 0U;
node < fixture.domain->nodes().size();
node < fixture.domain->Nodes().size();
++node) {
const double x = fixture.domain->nodes()[node].coordinates[0U];
const double y = fixture.domain->nodes()[node].coordinates[1U];
const double x = fixture.domain->Nodes()[node].coordinates[0U];
const double y = fixture.domain->Nodes()[node].coordinates[1U];
state.displacement()[node * 6U] = 0.1 * x + 0.1 * y;
state.displacement()[node * 6U + 1U] = -0.05 * y + 0.1 * x;
}
+1 -1
View File
@@ -3,7 +3,7 @@
#include "fesa/analysis/analysis_state.hpp"
#include "fesa/core/diagnostic.h"
#include "fesa/core/status.h"
#include "fesa/model/domain.hpp"
#include "fesa/model/domain.h"
#include <filesystem>
#include <type_traits>