Files
FESADev/tests/test_element_module_includes.cpp
T

174 lines
9.0 KiB
C++

#include "fesa/Element/Element.hpp"
#include <array>
#include <cmath>
#include <stdexcept>
namespace {
void check(bool value, const char* message) {
if (!value) {
throw std::runtime_error(message);
}
}
void checkNear(fesa::Real actual, fesa::Real expected, fesa::Real tolerance, const char* message) {
if (std::fabs(actual - expected) > tolerance) {
throw std::runtime_error(message);
}
}
void checkVecNear(const fesa::Vec3& actual, const fesa::Vec3& expected, fesa::Real tolerance, const char* message) {
checkNear(actual.x, expected.x, tolerance, message);
checkNear(actual.y, expected.y, tolerance, message);
checkNear(actual.z, expected.z, tolerance, message);
}
void checkRightHandedOrthonormal(const fesa::Vec3& e1, const fesa::Vec3& e2, const fesa::Vec3& e3) {
checkNear(fesa::norm(e1), 1.0, 1.0e-14, "e1 norm changed");
checkNear(fesa::norm(e2), 1.0, 1.0e-14, "e2 norm changed");
checkNear(fesa::norm(e3), 1.0, 1.0e-14, "e3 norm changed");
checkNear(fesa::dot(e1, e2), 0.0, 1.0e-14, "e1/e2 orthogonality changed");
checkNear(fesa::dot(e1, e3), 0.0, 1.0e-14, "e1/e3 orthogonality changed");
checkNear(fesa::dot(e2, e3), 0.0, 1.0e-14, "e2/e3 orthogonality changed");
checkNear(fesa::dot(fesa::cross(e1, e2), e3), 1.0, 1.0e-14, "basis handedness changed");
}
fesa::MITC4ElementDofVector zeroElementDofs() {
fesa::MITC4ElementDofVector values{};
values.fill(0.0);
return values;
}
} // namespace
int main() {
const auto center = fesa::shapeFunctions(0.0, 0.0);
checkNear(center.n[0] + center.n[1] + center.n[2] + center.n[3], 1.0, 1.0e-15, "shape sum changed");
checkNear(center.dr[0], -0.25, 1.0e-15, "center dN1/dxi changed");
checkNear(center.ds[2], 0.25, 1.0e-15, "center dN3/deta changed");
const auto nodes = fesa::mitc4NodeNaturalCoordinates();
checkNear(nodes[0].xi, -1.0, 1.0e-15, "node 1 xi changed");
checkNear(nodes[0].eta, -1.0, 1.0e-15, "node 1 eta changed");
checkNear(nodes[2].xi, 1.0, 1.0e-15, "node 3 xi changed");
checkNear(nodes[2].eta, 1.0, 1.0e-15, "node 3 eta changed");
for (std::size_t i = 0; i < 4; ++i) {
const auto corner = fesa::shapeFunctions(nodes[i].xi, nodes[i].eta);
checkNear(corner.n[i], 1.0, 1.0e-15, "corner interpolation changed");
}
const auto tying = fesa::mitc4TyingPoints();
check(tying[0].label == "A" && tying[0].natural.xi == 0.0 && tying[0].natural.eta == -1.0,
"tying point A changed");
check((tying[0].edge_node_indices == std::array<fesa::LocalIndex, 2>{0, 1}), "tying edge A changed");
check(tying[1].label == "B" && tying[1].natural.xi == -1.0 && tying[1].natural.eta == 0.0,
"tying point B changed");
check((tying[1].edge_node_indices == std::array<fesa::LocalIndex, 2>{0, 3}), "tying edge B changed");
check(tying[2].label == "C" && tying[2].natural.xi == 0.0 && tying[2].natural.eta == 1.0,
"tying point C changed");
check((tying[2].edge_node_indices == std::array<fesa::LocalIndex, 2>{3, 2}), "tying edge C changed");
check(tying[3].label == "D" && tying[3].natural.xi == 1.0 && tying[3].natural.eta == 0.0,
"tying point D changed");
check((tying[3].edge_node_indices == std::array<fesa::LocalIndex, 2>{1, 2}), "tying edge D changed");
const std::array<fesa::Vec3, 4> coords = {{{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}}};
const auto geometry = fesa::buildMITC4Geometry(coords, 0.2);
check(geometry.ok(), "flat geometry should remain valid");
checkVecNear(geometry.center_normal, {0, 0, 1}, 1.0e-14, "center normal changed");
for (const auto& frame : geometry.nodal_frames) {
checkVecNear(frame.v1, {1, 0, 0}, 1.0e-14, "director v1 changed");
checkVecNear(frame.v2, {0, 1, 0}, 1.0e-14, "director v2 changed");
checkVecNear(frame.vn, {0, 0, 1}, 1.0e-14, "director normal changed");
checkRightHandedOrthonormal(frame.v1, frame.v2, frame.vn);
}
const auto basis = fesa::computeMITC4IntegrationBasis(geometry, 0.0, 0.0, 0.0);
check(basis.ok(), "flat integration basis should remain valid");
checkVecNear(basis.g1, {0.5, 0, 0}, 1.0e-14, "g1 changed");
checkVecNear(basis.g2, {0, 0.5, 0}, 1.0e-14, "g2 changed");
checkVecNear(basis.g3, {0, 0, 0.1}, 1.0e-14, "g3 changed");
checkRightHandedOrthonormal(basis.local.e1, basis.local.e2, basis.local.e3);
checkNear(basis.jacobian, 0.025, 1.0e-14, "Jacobian changed");
const auto invalid_thickness = fesa::buildMITC4Geometry(coords, 0.0);
check(!invalid_thickness.ok(), "invalid thickness should remain diagnosed");
check(fesa::containsDiagnostic(invalid_thickness.diagnostics, "FESA-MITC4-THICKNESS"), "thickness diagnostic changed");
const std::array<fesa::Vec3, 4> collinear = {{{0, 0, 0}, {1, 0, 0}, {2, 0, 0}, {3, 0, 0}}};
const auto singular = fesa::buildMITC4Geometry(collinear, 0.1);
check(!singular.ok(), "singular normal should remain diagnosed");
check(fesa::containsDiagnostic(singular.diagnostics, "FESA-MITC4-SINGULAR-NORMAL"), "normal diagnostic changed");
const auto rotations = fesa::mitc4LocalRotations(geometry.nodal_frames[0], {1.0, 2.0, 3.0});
checkNear(rotations.alpha, 1.0, 1.0e-14, "alpha rotation changed");
checkNear(rotations.beta, 2.0, 1.0e-14, "beta rotation changed");
checkNear(rotations.gamma, 3.0, 1.0e-14, "gamma rotation changed");
checkVecNear(fesa::mitc4DirectorIncrement(geometry.nodal_frames[0], {0.0, 2.0, 5.0}), {2, 0, 0}, 1.0e-14,
"director increment changed");
auto dofs = zeroElementDofs();
for (std::size_t node = 0; node < 4; ++node) {
dofs[6 * node + 0] = 1.0;
dofs[6 * node + 1] = 0.5;
dofs[6 * node + 4] = 2.0;
dofs[6 * node + 5] = 99.0;
}
const auto mid = fesa::mitc4DisplacementDerivatives(geometry, dofs, 0.0, 0.0, 0.0);
check(mid.ok(), "midsurface displacement interpolation changed");
checkVecNear(mid.displacement, {1.0, 0.5, 0.0}, 1.0e-14, "midsurface displacement value changed");
const auto top = fesa::mitc4DisplacementDerivatives(geometry, dofs, 0.0, 0.0, 1.0);
check(top.ok(), "top displacement interpolation changed");
checkVecNear(top.displacement, {1.2, 0.5, 0.0}, 1.0e-14, "top displacement value changed");
constexpr fesa::Real xi = 0.2;
constexpr fesa::Real eta = -0.3;
constexpr fesa::Real zeta = 0.4;
const auto rows = fesa::mitc4DirectCovariantStrainRows(geometry, xi, eta, zeta);
check(rows.ok(), "direct covariant strain rows should remain valid");
check(fesa::mitc4StrainComponentLabels()[0] == "eps11", "strain label eps11 changed");
check(fesa::strainComponentIndex(fesa::MITC4StrainComponent::Gamma23) == 3, "gamma23 index changed");
check(fesa::strainComponentIndex(fesa::MITC4StrainComponent::Gamma13) == 4, "gamma13 index changed");
const fesa::Real h = 1.0e-6;
const std::array<std::size_t, 4> checked_dofs = {0, 7, 10, 11};
for (std::size_t dof : checked_dofs) {
auto plus = zeroElementDofs();
auto minus = zeroElementDofs();
plus[dof] = h;
minus[dof] = -h;
const auto plus_strain = fesa::mitc4DirectCovariantStrain(geometry, plus, xi, eta, zeta);
const auto minus_strain = fesa::mitc4DirectCovariantStrain(geometry, minus, xi, eta, zeta);
check(plus_strain.ok() && minus_strain.ok(), "direct strain perturbation changed");
for (std::size_t component = 0; component < 6; ++component) {
const fesa::Real finite_difference = (plus_strain.values[component] - minus_strain.values[component]) / (2.0 * h);
checkNear(rows.rows[component][dof], finite_difference, 1.0e-8, "direct strain row finite difference changed");
}
}
const auto gamma23 = fesa::strainComponentIndex(fesa::MITC4StrainComponent::Gamma23);
const auto gamma13 = fesa::strainComponentIndex(fesa::MITC4StrainComponent::Gamma13);
const auto direct_at_point = fesa::mitc4DirectCovariantStrainRows(geometry, 0.5, 0.25, 0.0);
const auto direct_a = fesa::mitc4DirectCovariantStrainRows(geometry, 0.0, -1.0, 0.0);
const auto direct_b = fesa::mitc4DirectCovariantStrainRows(geometry, -1.0, 0.0, 0.0);
const auto direct_c = fesa::mitc4DirectCovariantStrainRows(geometry, 0.0, 1.0, 0.0);
const auto direct_d = fesa::mitc4DirectCovariantStrainRows(geometry, 1.0, 0.0, 0.0);
const auto tied = fesa::mitc4TiedCovariantStrainRows(geometry, 0.5, 0.25, 0.0);
check(direct_at_point.ok() && tied.ok(), "MITC tied rows should remain valid");
const std::size_t node2_ry = 6 + 4;
const fesa::Real expected_gamma13 =
0.5 * (1.0 - 0.25) * direct_a.rows[gamma13][node2_ry] + 0.5 * (1.0 + 0.25) * direct_c.rows[gamma13][node2_ry];
checkNear(tied.rows[gamma13][node2_ry], expected_gamma13, 1.0e-14, "MITC gamma13 tying interpolation changed");
check(std::fabs(tied.rows[gamma13][node2_ry] - direct_at_point.rows[gamma13][node2_ry]) > 1.0e-4,
"MITC gamma13 should not be direct Gauss shear");
const std::size_t node4_rx = 3 * 6 + 3;
const fesa::Real expected_gamma23 =
0.5 * (1.0 - 0.5) * direct_b.rows[gamma23][node4_rx] + 0.5 * (1.0 + 0.5) * direct_d.rows[gamma23][node4_rx];
checkNear(tied.rows[gamma23][node4_rx], expected_gamma23, 1.0e-14, "MITC gamma23 tying interpolation changed");
check(std::fabs(tied.rows[gamma23][node4_rx] - direct_at_point.rows[gamma23][node4_rx]) > 1.0e-4,
"MITC gamma23 should not be direct Gauss shear");
return 0;
}