feat(fem-and-beam-kernel): step 0 — quadrature-and-shape-functions
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
#include <fesa/fem/gauss_rule.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(Quadrature, OnePointRuleIntegratesDegreeZeroAndOneExactly) {
|
||||
const auto rule = fesa::gauss_rule_1d(1);
|
||||
|
||||
ASSERT_EQ(rule.size(), 1);
|
||||
EXPECT_DOUBLE_EQ(rule[0].weight, 2.0);
|
||||
EXPECT_DOUBLE_EQ(rule[0].weight * rule[0].xi, 0.0);
|
||||
}
|
||||
|
||||
TEST(Quadrature, TwoPointRuleIntegratesThroughDegreeThreeWithinRoundoff) {
|
||||
const auto rule = fesa::gauss_rule_1d(2);
|
||||
|
||||
ASSERT_EQ(rule.size(), 2);
|
||||
|
||||
double degree_zero = 0.0;
|
||||
double degree_one = 0.0;
|
||||
double degree_two = 0.0;
|
||||
double degree_three = 0.0;
|
||||
for (const auto& point : rule) {
|
||||
const double xi_squared = point.xi * point.xi;
|
||||
degree_zero += point.weight;
|
||||
degree_one += point.weight * point.xi;
|
||||
degree_two += point.weight * xi_squared;
|
||||
degree_three += point.weight * xi_squared * point.xi;
|
||||
}
|
||||
|
||||
// Sixteen ulps at unit scale cover only the rounding in these short sums.
|
||||
constexpr double tolerance =
|
||||
16.0 * std::numeric_limits<double>::epsilon();
|
||||
EXPECT_NEAR(degree_zero, 2.0, tolerance);
|
||||
EXPECT_NEAR(degree_one, 0.0, tolerance);
|
||||
EXPECT_NEAR(degree_two, 2.0 / 3.0, tolerance);
|
||||
EXPECT_NEAR(degree_three, 0.0, tolerance);
|
||||
}
|
||||
|
||||
TEST(Quadrature, RejectsUnsupportedOrders) {
|
||||
for (const int order : std::array{0, 3, -1}) {
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(fesa::gauss_rule_1d(order)),
|
||||
std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <fesa/fem/line2_shape.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(ShapeFunction, InterpolatesBothEndpoints) {
|
||||
const auto first_endpoint = fesa::line2_shape(-1.0);
|
||||
const auto second_endpoint = fesa::line2_shape(1.0);
|
||||
|
||||
EXPECT_DOUBLE_EQ(first_endpoint[0], 1.0);
|
||||
EXPECT_DOUBLE_EQ(first_endpoint[1], 0.0);
|
||||
EXPECT_DOUBLE_EQ(second_endpoint[0], 0.0);
|
||||
EXPECT_DOUBLE_EQ(second_endpoint[1], 1.0);
|
||||
}
|
||||
|
||||
TEST(ShapeFunction, FormsPartitionOfUnityWithinRoundoff) {
|
||||
for (const double xi : std::array{-1.0, -0.25, 0.0, 0.4, 1.0}) {
|
||||
const auto shape = fesa::line2_shape(xi);
|
||||
|
||||
// Four ulps at unit scale cover the two affine evaluations and sum.
|
||||
constexpr double tolerance =
|
||||
4.0 * std::numeric_limits<double>::epsilon();
|
||||
EXPECT_NEAR(shape[0] + shape[1], 1.0, tolerance) << "xi=" << xi;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ShapeFunction, DerivativesSumToZeroAtEveryNaturalCoordinate) {
|
||||
for (const double xi : std::array{-1.0, -0.25, 0.0, 0.4, 1.0}) {
|
||||
const auto derivative = fesa::line2_shape_derivative(xi);
|
||||
|
||||
EXPECT_DOUBLE_EQ(derivative[0], -0.5);
|
||||
EXPECT_DOUBLE_EQ(derivative[1], 0.5);
|
||||
EXPECT_DOUBLE_EQ(derivative[0] + derivative[1], 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Jacobian, ReturnsHalfThePhysicalLength) {
|
||||
EXPECT_DOUBLE_EQ(fesa::line2_jacobian(4.0), 2.0);
|
||||
EXPECT_DOUBLE_EQ(fesa::line2_jacobian(0.25), 0.125);
|
||||
}
|
||||
|
||||
TEST(Jacobian, DoesNotAdjustSmallPositiveFiniteLengths) {
|
||||
constexpr double length = 1.0e-300;
|
||||
|
||||
EXPECT_DOUBLE_EQ(fesa::line2_jacobian(length), length / 2.0);
|
||||
}
|
||||
|
||||
TEST(Jacobian, RejectsNonpositiveAndNonfiniteLengths) {
|
||||
const double infinity = std::numeric_limits<double>::infinity();
|
||||
const double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
for (const double length : std::array{0.0, -1.0, infinity, nan}) {
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(fesa::line2_jacobian(length)),
|
||||
std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Jacobian, RejectsLengthWhoseHalfUnderflowsToZero) {
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(fesa::line2_jacobian(
|
||||
std::numeric_limits<double>::denorm_min())),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user