Files
FESADev/tests/unit/analysis/analysis_state_test.cpp
T

171 lines
6.2 KiB
C++

#include "fesa/analysis/analysis_state.h"
#include <gtest/gtest.h>
#include <filesystem>
#include <iterator>
#include <type_traits>
#include <utility>
namespace {
template <class T, class = void>
struct HasVelocity : std::false_type {};
template <class T>
struct HasVelocity<T, std::void_t<decltype(std::declval<T&>().Velocity())>>
: std::true_type {};
template <class T, class = void>
struct HasAcceleration : std::false_type {};
template <class T>
struct HasAcceleration<T,
std::void_t<decltype(std::declval<T&>().Acceleration())>>
: std::true_type {};
template <class T, class = void>
struct HasTemperature : std::false_type {};
template <class T>
struct HasTemperature<T,
std::void_t<decltype(std::declval<T&>().Temperature())>>
: std::true_type {};
template <class T, class = void>
struct HasIterationHistory : std::false_type {};
template <class T>
struct HasIterationHistory<
T, std::void_t<decltype(std::declval<T&>().IterationHistory())>>
: std::true_type {};
template <class T, class = void>
struct HasNonlinearState : std::false_type {};
template <class T>
struct HasNonlinearState<
T, std::void_t<decltype(std::declval<T&>().NonlinearState())>>
: std::true_type {};
fesa::DofManager MakeDofs() {
fesa::ModelDefinition definition{};
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.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.source_path, 20U}}},
{},
0.1,
1.0,
0.01,
1.0,
{definition.source_path, 19U}}};
auto domain = fesa::Domain::Create(std::move(definition));
EXPECT_TRUE(domain.HasValue());
auto model = fesa::AnalysisModel::Create(domain.Value());
EXPECT_TRUE(model.HasValue());
auto dofs = fesa::DofManager::Create(model.Value());
EXPECT_TRUE(dofs.HasValue());
return std::move(dofs.Value());
}
void ExpectAllZero(const fesa::Vector& vector) {
for (std::size_t index = 0U; index < vector.Size(); ++index) {
EXPECT_DOUBLE_EQ(vector[index], 0.0);
}
}
} // namespace
TEST(AnalysisState, AllocatesOnlyV0FullVectors) {
const auto dofs = MakeDofs();
ASSERT_EQ(dofs.FullDofCount(), 12U);
ASSERT_EQ(dofs.ConstrainedDofCount(), 6U);
auto state = fesa::AnalysisState::Create(dofs, {"Step-1", 0U});
const fesa::AnalysisState& const_state = state;
const fesa::Vector* const vectors[] = {
&const_state.Displacement(), &const_state.ExternalForce(),
&const_state.InternalForce(), &const_state.Residual(),
&const_state.Reaction()};
for (const auto* vector : vectors) {
EXPECT_EQ(vector->Size(), dofs.FullDofCount());
ExpectAllZero(*vector);
}
for (std::size_t left = 0U; left < std::size(vectors); ++left) {
for (std::size_t right = left + 1U; right < std::size(vectors); ++right) {
EXPECT_NE(vectors[left]->Data(), vectors[right]->Data());
}
}
state.Displacement()[0] = 4.0;
state.Reaction()[11] = -9.0;
EXPECT_DOUBLE_EQ(state.Displacement()[0], 4.0);
EXPECT_DOUBLE_EQ(state.Reaction()[11], -9.0);
EXPECT_DOUBLE_EQ(state.ExternalForce()[0], 0.0);
EXPECT_DOUBLE_EQ(state.InternalForce()[0], 0.0);
EXPECT_DOUBLE_EQ(state.Residual()[0], 0.0);
EXPECT_FALSE(HasVelocity<fesa::AnalysisState>::value);
EXPECT_FALSE(HasAcceleration<fesa::AnalysisState>::value);
EXPECT_FALSE(HasTemperature<fesa::AnalysisState>::value);
EXPECT_FALSE(HasIterationHistory<fesa::AnalysisState>::value);
EXPECT_FALSE(HasNonlinearState<fesa::AnalysisState>::value);
}
TEST(AnalysisState, CopiesOrMovesWithoutAliasing) {
static_assert(std::is_copy_constructible_v<fesa::AnalysisState>);
static_assert(std::is_copy_assignable_v<fesa::AnalysisState>);
static_assert(std::is_move_constructible_v<fesa::AnalysisState>);
static_assert(std::is_move_assignable_v<fesa::AnalysisState>);
const auto dofs = MakeDofs();
auto original = fesa::AnalysisState::Create(dofs, {"Step-1", 0U});
original.Displacement()[0] = 3.0;
original.Reaction()[11] = -2.0;
original.EndpointResults().push_back({0U,
-1,
{"Beam-1", 1, "1"},
{1.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{2.0, 0.0, 0.0, 0.0}});
original.GaussResults().push_back(
{0U, 1, {0.1, 0.0, 0.0, 0.0}, {10.0, 0.0, 0.0, 0.0}});
original.StressResults().push_back(
{0U, 1, 0U, 0.0, 0.0, 10.0, "fesa-default"});
auto copied = original;
EXPECT_NE(copied.Displacement().Data(), original.Displacement().Data());
EXPECT_NE(copied.Reaction().Data(), original.Reaction().Data());
EXPECT_NE(copied.EndpointResults().data(), original.EndpointResults().data());
EXPECT_NE(copied.GaussResults().data(), original.GaussResults().data());
EXPECT_NE(copied.StressResults().data(), original.StressResults().data());
copied.Displacement()[0] = 30.0;
copied.EndpointResults()[0].end_action[0] = 20.0;
EXPECT_DOUBLE_EQ(original.Displacement()[0], 3.0);
EXPECT_DOUBLE_EQ(original.EndpointResults()[0].end_action[0], 1.0);
auto moved = std::move(copied);
EXPECT_EQ(moved.Identity().step_name, "Step-1");
EXPECT_DOUBLE_EQ(moved.Displacement()[0], 30.0);
EXPECT_DOUBLE_EQ(moved.EndpointResults()[0].end_action[0], 20.0);
EXPECT_NE(moved.Displacement().Data(), original.Displacement().Data());
EXPECT_NE(moved.EndpointResults().data(), original.EndpointResults().data());
auto copy_assigned = fesa::AnalysisState::Create(dofs, {"Other", 3U});
copy_assigned = original;
copy_assigned.Reaction()[11] = -20.0;
EXPECT_DOUBLE_EQ(original.Reaction()[11], -2.0);
EXPECT_EQ(copy_assigned.Identity().step_name, "Step-1");
auto move_assigned = fesa::AnalysisState::Create(dofs, {"Other", 4U});
move_assigned = std::move(copy_assigned);
EXPECT_EQ(move_assigned.Identity().step_name, "Step-1");
EXPECT_DOUBLE_EQ(move_assigned.Reaction()[11], -20.0);
EXPECT_NE(move_assigned.Reaction().Data(), original.Reaction().Data());
}