feat: adopt lumped mass and reduced-coordinate shell HHT
Integrate Hex8 mass verification and fixed-null-basis shell dynamics with numerical and physics handoff evidence. Preserve interrupted reference and full-validation status; full integration validation is deferred until after performance optimization.
This commit is contained in:
@@ -79,8 +79,8 @@ fesa::ModelDefinition TwoBricks(double h, unsigned count, bool nonlinear) {
|
||||
fesa::SourceLocation{});
|
||||
return d;
|
||||
}
|
||||
// Closed polynomial brick integrals: integral Na*X and integral grad Na.
|
||||
// These do not call the production stiffness, mass, quadrature or response.
|
||||
// Closed polynomial brick integrals and pre-restriction row-sum masses. These
|
||||
// do not call the production stiffness, mass, quadrature or response.
|
||||
std::vector<double> ExactForce(const fesa::ModelDefinition& d, double t,
|
||||
bool nonlinear) {
|
||||
const auto m = Motion(t, nonlinear);
|
||||
@@ -89,14 +89,14 @@ std::vector<double> ExactForce(const fesa::ModelDefinition& d, double t,
|
||||
const auto& nodes = d.solid_elements[e].node_indices;
|
||||
for (unsigned a = 0; a < 8; ++a) {
|
||||
const auto& x = d.nodes[nodes[a]].coordinates;
|
||||
std::array<double, 3> integral_x{}, gradient{};
|
||||
std::array<double, 3> gradient{};
|
||||
for (unsigned c = 0; c < 3; ++c) {
|
||||
const double origin = c == 0 ? static_cast<double>(e) : 0;
|
||||
const double local = x[c] - origin;
|
||||
integral_x[c] = 2 * (origin / 8 + (1 + local) / 24);
|
||||
gradient[c] = (2 * local - 1) / 4;
|
||||
}
|
||||
const auto inertia = Apply(m.acceleration, integral_x);
|
||||
const auto inertia = Apply(
|
||||
m.acceleration, {.25 * x[0], .25 * x[1], .25 * x[2]});
|
||||
const auto internal = Apply(m.piola, gradient);
|
||||
for (unsigned c = 0; c < 3; ++c)
|
||||
f[3 * nodes[a] + c] += inertia[c] + internal[c];
|
||||
@@ -110,16 +110,8 @@ std::vector<double> ExactMassProduct(const fesa::Domain& d,
|
||||
for (unsigned e = 0; e < 2; ++e) {
|
||||
const auto& nodes = d.SolidElements()[e].node_indices;
|
||||
for (unsigned a = 0; a < 8; ++a)
|
||||
for (unsigned b = 0; b < 8; ++b) {
|
||||
double coefficient = 2.0 / 216;
|
||||
for (unsigned c = 0; c < 3; ++c)
|
||||
coefficient *= d.Nodes()[nodes[a]].coordinates[c] ==
|
||||
d.Nodes()[nodes[b]].coordinates[c]
|
||||
? 2
|
||||
: 1;
|
||||
for (unsigned c = 0; c < 3; ++c)
|
||||
result[3 * nodes[a] + c] += coefficient * v[3 * nodes[b] + c];
|
||||
}
|
||||
for (unsigned c = 0; c < 3; ++c)
|
||||
result[3 * nodes[a] + c] += .25 * v[3 * nodes[a] + c];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -505,8 +497,8 @@ TEST(SolidHhtTemporal,
|
||||
}
|
||||
|
||||
TEST(SolidHhtTemporal, IndependentThreeDofBrickOscillatorHasSecondOrderUVA) {
|
||||
// Node0's three translations are free. Exact polynomial integrals yield
|
||||
// M=(rho/27)I, Kii=41/18, Kij=19/30 for mu=4.8 and direct kappa=8.
|
||||
// Node0's three translations are free. Pre-restriction row-sum lumping
|
||||
// yields M=(rho/8)I, Kii=41/18, Kij=19/30 for mu=4.8 and kappa=8.
|
||||
std::array<std::array<double, 3>, 3> errors{};
|
||||
for (unsigned level = 0; level < 3; ++level) {
|
||||
const double h = .02 / static_cast<double>(1U << level);
|
||||
@@ -528,7 +520,7 @@ TEST(SolidHhtTemporal, IndependentThreeDofBrickOscillatorHasSecondOrderUVA) {
|
||||
ASSERT_TRUE(result.HasValue())
|
||||
<< solid_hht_test::Message(result.GetStatus());
|
||||
const auto& f = result.Value().state.CommittedState();
|
||||
const double m = 2.0 / 27;
|
||||
const double m = .25;
|
||||
const double diagonal = 41.0 / 18;
|
||||
const double off = 19.0 / 30;
|
||||
const std::array<double, 2> k{diagonal + 2 * off, diagonal - off};
|
||||
@@ -562,7 +554,7 @@ TEST(SolidHhtTemporal, IndependentThreeDofBrickOscillatorHasSecondOrderUVA) {
|
||||
|
||||
TEST(SolidHhtTemporal, IndependentScalarBrickOscillatorHasSecondOrderUVA) {
|
||||
std::array<std::array<double, 3>, 3> errors{};
|
||||
const double m = 2.0 / 27;
|
||||
const double m = .25;
|
||||
const double k = 41.0 / 18;
|
||||
const double w = std::sqrt(k / m);
|
||||
for (unsigned level = 0; level < 3; ++level) {
|
||||
|
||||
Reference in New Issue
Block a user