Files
FESADev/tests/unit/analysis/hht_time_integration_test.cpp
2026-09-22 21:38:42 +09:00

98 lines
3.6 KiB
C++

#include "fesa/analysis/hht_time_integration.h"
#include <cmath>
#include <gtest/gtest.h>
namespace fesa {
namespace {
TEST(HhtTimeIntegrationTest, KeepsPhysicalAndAlgorithmicAccelerationDistinct) {
const auto parameters = MakeHhtParameters(-0.05);
ASSERT_TRUE(parameters.HasValue());
Vector q(1U);
Vector v(1U);
Vector old_a(1U);
old_a[0U] = 1.0;
const auto predictor = PredictHht(q, v, old_a, 0.1, parameters.Value());
ASSERT_TRUE(predictor.HasValue());
q[0U] = predictor.Value().coordinates[0U] +
parameters.Value().beta * 0.01 * 2.0;
const auto rates = EvaluateHhtRates(q, predictor.Value(), old_a, 0.1,
parameters.Value());
ASSERT_TRUE(rates.HasValue());
EXPECT_NEAR(rates.Value().algorithmic_acceleration[0U], 2.0, 1e-14);
EXPECT_NEAR(rates.Value().acceleration[0U], 1.95 / 0.95, 1e-14);
EXPECT_NEAR(rates.Value().velocity[0U], 0.155, 1e-14);
}
TEST(HhtTimeIntegrationTest, RejectsInvalidParametersAndTime) {
EXPECT_FALSE(MakeHhtParameters(0.01).HasValue());
EXPECT_FALSE(MakeHhtParameters(-0.34).HasValue());
ASSERT_TRUE(MakeHhtParameters(-1.0 / 3.0).HasValue());
const auto parameters = MakeHhtParameters(0.0);
ASSERT_TRUE(parameters.HasValue());
EXPECT_EQ(parameters.Value().beta, 0.25);
EXPECT_EQ(parameters.Value().gamma, 0.5);
const Vector zero(1U);
EXPECT_FALSE(PredictHht(zero, zero, zero, 0.0, parameters.Value()).HasValue());
}
// C02 is a right-continuous STEP load with a nonzero physical a0.
TEST(HhtTimeIntegrationTest, StepOscillatorHasSecondOrderMaximumError) {
const auto parameters = MakeHhtParameters(-0.05);
ASSERT_TRUE(parameters.HasValue());
double previous_q = 0.0;
double previous_v = 0.0;
double previous_a = 0.0;
for (unsigned int power = 4U; power <= 8U; ++power) {
const unsigned int count = 1U << power;
const double h = 1.0 / static_cast<double>(count);
Vector q(1U);
Vector v(1U);
Vector a(1U);
Vector auxiliary(1U);
a[0U] = auxiliary[0U] = 1.0;
double error_q = 0.0;
double error_v = 0.0;
double error_a = 0.0;
for (unsigned int n = 1U; n <= count; ++n) {
const auto predictor = PredictHht(q, v, auxiliary, h, parameters.Value());
ASSERT_TRUE(predictor.HasValue());
const double coefficient =
1.0 / ((1.0 + parameters.Value().alpha) *
parameters.Value().beta * h * h);
q[0U] = (2.0 + 2.0 * coefficient * predictor.Value().coordinates[0U] -
2.0 * parameters.Value().alpha * a[0U] /
(1.0 + parameters.Value().alpha)) /
(8.0 + 2.0 * coefficient);
const auto rates = EvaluateHhtRates(q, predictor.Value(), a, h,
parameters.Value());
ASSERT_TRUE(rates.HasValue());
v = rates.Value().velocity;
a = rates.Value().acceleration;
auxiliary = rates.Value().algorithmic_acceleration;
const double time = static_cast<double>(n) * h;
error_q = (std::max)(error_q, std::abs(q[0U] - 0.25 * (1.0 - std::cos(2.0 * time))) / 0.5);
error_v = (std::max)(error_v, std::abs(v[0U] - 0.5 * std::sin(2.0 * time)) / 0.5);
error_a = (std::max)(error_a, std::abs(a[0U] - std::cos(2.0 * time)));
}
if (power >= 7U) {
EXPECT_GE(std::log2(previous_q / error_q), 1.8);
EXPECT_GE(std::log2(previous_v / error_v), 1.8);
EXPECT_GE(std::log2(previous_a / error_a), 1.8);
}
if (power == 8U) {
EXPECT_LT(error_q, 1e-4);
EXPECT_LT(error_v, 1e-4);
EXPECT_LT(error_a, 1e-4);
}
previous_q = error_q;
previous_v = error_v;
previous_a = error_a;
}
}
} // namespace
} // namespace fesa