Files
FESADev/tests/unit/loads/load_test.cpp
T

108 lines
4.1 KiB
C++

#include <gtest/gtest.h>
#include <array>
#include <cstddef>
#include <filesystem>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "fesa/analysis/analysis_model.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/loads/concentrated_nodal_load.h"
#include "fesa/model/domain.h"
#include "fesa/model/source_target_resolver.h"
namespace {
fesa::Domain MakeDomain() {
const std::filesystem::path source{"models/load-hierarchy.inp"};
fesa::ModelDefinition definition{};
definition.source_path = source;
definition.source_content_identity = "fnv1a64:loadhierarchy";
definition.nodes = {{{"Part-1-1", 10, "10"}, {0.0, 0.0, 0.0}, {source, 2U}},
{{"Part-1-1", 20, "20"}, {1.0, 0.0, 0.0}, {source, 3U}}};
definition.node_sets = {
{"Pair", std::string{"Part-1-1"}, {0U, 1U}, {source, 4U}}};
definition.steps = {{"Step-1", {}, {}, 0.1, 1.0, 0.01, 1.0, {source, 5U}}};
auto domain = fesa::Domain::Create(std::move(definition));
if (!domain.HasValue()) {
throw std::runtime_error{"Load hierarchy Domain construction failed."};
}
return std::move(domain.Value());
}
void ExpectFailureCode(
const fesa::Result<std::vector<fesa::LoadContribution>>& 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()[0U].code, code);
}
} // namespace
// C-LOAD-001
TEST(Load, ConcentratedNodalLoadEmitsStableFullDofContributions) {
static_assert(std::has_virtual_destructor_v<fesa::Load>);
static_assert(!std::is_copy_constructible_v<fesa::StepDefinition>);
static_assert(std::is_move_constructible_v<fesa::StepDefinition>);
fesa::Domain domain = MakeDomain();
auto model = fesa::AnalysisModel::Create(domain);
ASSERT_TRUE(model.HasValue());
auto dofs = fesa::DofManager::Create(model.Value());
ASSERT_TRUE(dofs.HasValue());
const fesa::SourceTargetIndex target_index =
fesa::SourceTargetIndex::FromDomain(domain);
const fesa::SourceTargetResolver resolver{target_index};
const fesa::LoadContext context{domain, dofs.Value(), resolver};
const std::array<double, 6> components{1.0, -2.0, 0.0, 4.0, 0.0, -6.0};
const fesa::ConcentratedNodalLoad load(
{fesa::SourceEntityKind::kNode, "Part-1-1", "pair"}, components, 7U);
const auto result = load.ComputeContributions(context);
ASSERT_TRUE(result.HasValue());
ASSERT_EQ(result.Value().size(), 12U);
for (std::size_t node = 0U; node < 2U; ++node) {
for (std::size_t component = 0U; component < components.size();
++component) {
const auto& contribution =
result.Value()[node * components.size() + component];
EXPECT_EQ(contribution.source_order, 7U);
EXPECT_EQ(contribution.full_dof_index,
node * components.size() + component);
EXPECT_DOUBLE_EQ(contribution.value, components[component]);
}
}
}
TEST(Load, ConcentratedNodalLoadRejectsInvalidInputWithoutContributions) {
fesa::Domain domain = MakeDomain();
auto model = fesa::AnalysisModel::Create(domain);
ASSERT_TRUE(model.HasValue());
auto dofs = fesa::DofManager::Create(model.Value());
ASSERT_TRUE(dofs.HasValue());
const fesa::SourceTargetIndex target_index =
fesa::SourceTargetIndex::FromDomain(domain);
const fesa::SourceTargetResolver resolver{target_index};
const fesa::LoadContext context{domain, dofs.Value(), resolver};
std::array<double, 6> nonfinite{};
nonfinite[2U] = std::numeric_limits<double>::infinity();
const fesa::ConcentratedNodalLoad invalid_value(
{fesa::SourceEntityKind::kNode, "Part-1-1", "10"}, nonfinite, 0U);
ExpectFailureCode(invalid_value.ComputeContributions(context),
"nonfinite-load-value");
const fesa::ConcentratedNodalLoad invalid_target(
{fesa::SourceEntityKind::kNode, "Part-1-1", "Missing"}, {}, 0U);
ExpectFailureCode(invalid_target.ComputeContributions(context),
"invalid-load-target");
}