feat(support): continued migration to new field dof support system

mass normaliztion, gravity, displacement, and hydrostatic equilibrium are now migrated
This commit is contained in:
2026-08-24 15:44:24 -04:00
parent 0f3ca8050b
commit 177ae8b38a
48 changed files with 1738 additions and 935 deletions

View File

@@ -25,13 +25,18 @@ namespace {
blocks::get_residual_block<form>(blocks::gravity_field.poisson_term);
blocks::form_layout<form> make_gravity_layout(const fem::FEM &f) {
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
const auto density_map = field::make_field_dof_map<field::Density, DomainSchema>(*f.densityFes);
const auto displacement_map = field::make_field_dof_map<field::Displacement, DomainSchema>(*f.displacementFes);
const auto flux_map = field::make_field_dof_map<field::Gravity, DomainSchema>(*f.gravityFluxFes);
const auto potential_map = field::make_field_dof_map<field::Gravity, DomainSchema>(*f.gravityPotentialFes);
const std::array<int, form::value_block_count> value_sizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize()
density_map.reduced_size(), displacement_map.reduced_size(), flux_map.reduced_size(),
potential_map.reduced_size()
};
const std::array<int, form::residual_block_count> residual_sizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize()
flux_map.reduced_size(), potential_map.reduced_size()
};
return blocks::form_layout<form>(value_sizes, residual_sizes);
@@ -623,16 +628,7 @@ namespace {
using gravity_form = blocks::gravity_field_form;
using gravity_layout = blocks::form_layout<gravity_form>;
gravity_layout make_gravity_jacobian_layout(const fem::FEM &f) {
const std::array<int, gravity_form::value_block_count> value_sizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize()
};
const std::array<int, gravity_form::residual_block_count> residual_sizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize()
};
return gravity_layout(value_sizes, residual_sizes);
return make_gravity_layout(f);
}
template <int index>
@@ -698,7 +694,9 @@ namespace {
fill_value_block(state, layout, gravity_gradient_block, 0.4, 0.23);
fill_value_block(state, layout, gravity_potential_block, 0.3, 0.37);
const mfem::Vector displacement = make_stateless_reference_displacement(f, deformed);
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
const auto displacement_map = field::make_field_dof_map<field::Displacement, DomainSchema>(*f.displacementFes);
const mfem::Vector displacement = displacement_map.gather(make_stateless_reference_displacement(f, deformed));
set_value_block(state, layout, displacement_block, displacement);
return state;
@@ -1026,15 +1024,23 @@ namespace {
const mfem::Vector gravity_gradient = make_read_only_value_view(state, state_offsets, gravity_gradient_block);
CHECK_THAT(
global_relative_vector_error(context.GetDensity(), density, communicator),
global_relative_vector_error(
context.GetDensityTrue(), context.GetDensityMap().scatter(density), communicator
),
Catch::Matchers::WithinAbs(0.0, 0.0)
);
CHECK_THAT(
global_relative_vector_error(context.GetGeometryContext().GetDisplacement(), displacement, communicator),
global_relative_vector_error(
context.GetGeometryContext().GetDisplacementTrue(), context.GetDisplacementMap().scatter(displacement),
communicator
),
Catch::Matchers::WithinAbs(0.0, 0.0)
);
CHECK_THAT(
global_relative_vector_error(context.GetGravityGradient(), gravity_gradient, communicator),
global_relative_vector_error(
context.GetGravityGradientTrue(), context.GetGravityGradientMap().scatter(gravity_gradient),
communicator
),
Catch::Matchers::WithinAbs(0.0, 0.0)
);
}
@@ -1179,7 +1185,7 @@ namespace {
TEST_CASE(
"Gravity Field Operator Mult Preserves Zero State And Static Blocks",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1256,7 +1262,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Operator Mult Applies Stellar Source With Correct Sign",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1283,7 +1289,7 @@ TEST_CASE(
.discretization = {1}, .displacement = {1}, .density = {1}, .gravity_gradient = {1}, .gravity_potential = {1}
};
const mfem::Vector density = make_constant_density(f, 1.0);
const mfem::Vector density = linearization_context.GetDensityMap().gather(make_constant_density(f, 1.0));
set_block(state, layout.value_offsets(), density_block, density);
gravity_operator.Prepare(state, revisions);
@@ -1319,7 +1325,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Operator Mult Ignores Vacuum Density",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1347,8 +1353,9 @@ TEST_CASE(
.discretization = {1}, .displacement = {1}, .density = {1}, .gravity_gradient = {1}, .gravity_potential = {1}
};
const mfem::Vector vacuum_density = make_vacuum_density(f, 1.0);
REQUIRE(vacuum_density.Norml2() > 0.0);
const mfem::Vector vacuum_density_true = make_vacuum_density(f, 1.0);
REQUIRE(vacuum_density_true.Norml2() > 0.0);
const mfem::Vector vacuum_density = linearization_context.GetDensityMap().gather(vacuum_density_true);
set_block(state, layout.value_offsets(), density_block, vacuum_density);
@@ -1362,7 +1369,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Operator Mult Produces A Symmetric Positive Hdiv Mass "
"Action",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1382,7 +1389,7 @@ TEST_CASE(
f, *f.domainMapperStateless, linearization_context, layout.value_offsets(), gravity_jacobian
);
const mfem::Vector displacement = make_displacement(f);
const mfem::Vector displacement = linearization_context.GetDisplacementMap().gather(make_displacement(f));
const mfem::Vector gravity_gradient_a = make_test_vector(layout.size(gravity_gradient_block), 0.27);
const mfem::Vector gravity_gradient_b = make_test_vector(layout.size(gravity_gradient_block), 1.13);
@@ -1433,7 +1440,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Operator Mult Is Additive In Fields At Fixed Displacement",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1453,8 +1460,8 @@ TEST_CASE(
f, *f.domainMapperStateless, linearization_context, layout.value_offsets(), gravity_jacobian
);
const mfem::Vector displacement = make_displacement(f);
const mfem::Vector density = make_constant_density(f, 0.73);
const mfem::Vector displacement = linearization_context.GetDisplacementMap().gather(make_displacement(f));
const mfem::Vector density = linearization_context.GetDensityMap().gather(make_constant_density(f, 0.73));
const mfem::Vector gravity_gradient = make_test_vector(layout.size(gravity_gradient_block), 0.41);
const mfem::Vector gravity_potential = make_test_vector(layout.size(gravity_potential_block), 0.89);
@@ -1514,7 +1521,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Operator Stellar Hdiv Mass Matches Legacy Assembled Mass",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators &tags::legacy_comparison
tags::gravity_legacy
) {
constexpr double parity_tolerance = 1.0e-10;
constexpr double vacuum_tolerance = 1.0e-13;
@@ -1631,7 +1638,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Operator Hdiv Mass Action Matches Stateless Quadrature "
"Reference",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
const utils::Args args = test_utils::setup_args();
@@ -1845,7 +1852,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Jacobian Fixed Geometry Blocks Match Centered Differences",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1865,9 +1872,10 @@ TEST_CASE(
);
mfem::Vector state(layout.value_offsets().Last());
state = 0.0;
state = 0.0;
const mfem::Vector displacement = make_stateless_reference_displacement(f, true);
const mfem::Vector displacement =
linearization_context.GetDisplacementMap().gather(make_stateless_reference_displacement(f, true));
set_value_block(state, layout, displacement_block, displacement);
const operators::context::gravity_field::GravityFieldRevisions revisions{
@@ -1940,7 +1948,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Jacobian Combined Fixed Geometry Direction Matches Centered "
"Differences",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1991,7 +1999,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Jacobian Action Is Linear At Fixed Geometry",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2048,7 +2056,7 @@ TEST_CASE(
}
TEST_CASE(
"Gravity Field Prepare Updates Shared Linearization Context",
tags::unit &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_unit
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2092,9 +2100,9 @@ TEST_CASE(
CHECK(linearization_context.IsPrepared());
const double stored_state_norm =
global_vector_norm(linearization_context.GetDensity(), communicator) +
global_vector_norm(linearization_context.GetGeometryContext().GetDisplacement(), communicator) +
global_vector_norm(linearization_context.GetGravityGradient(), communicator);
global_vector_norm(linearization_context.GetDensityTrue(), communicator) +
global_vector_norm(linearization_context.GetGeometryContext().GetDisplacementTrue(), communicator) +
global_vector_norm(linearization_context.GetGravityGradientTrue(), communicator);
CHECK(stored_state_norm > 0.0);
@@ -2107,7 +2115,7 @@ TEST_CASE(
}
TEST_CASE(
"Mapped Hdiv Mass Variation Is Linear In Displacement Direction",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2176,7 +2184,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Hdiv Mass Variation Matches Centered Geometry Differences",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2220,7 +2228,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Hdiv Mass Geometry Difference Converges To Analytic Variation",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators &tags::convergence
tags::gravity_kernel_convergence
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2266,7 +2274,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Source Variation Is Linear In Displacement Direction",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2339,7 +2347,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Source Variation Matches Centered Geometry Differences",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2385,7 +2393,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Source Geometry Difference Converges To Analytic Variation",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators &tags::convergence
tags::gravity_kernel_convergence
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2431,7 +2439,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Hdiv Mass Variation Is Symmetric",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2479,7 +2487,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Geometry Variations Are Linear In Base Fields",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2571,7 +2579,7 @@ TEST_CASE(
TEST_CASE(
"Mapped Source Variation Ignores Vacuum Density",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_kernel_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2604,7 +2612,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Jacobian Displacement Blocks Match Geometry Kernels",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2618,9 +2626,6 @@ TEST_CASE(
const HdivMassVariationTestFields fields = make_hdiv_mass_variation_test_fields(f);
const mfem::Vector state = make_gravity_jacobian_state(f, layout, true);
const mfem::Vector direction = make_displacement_direction(layout, fields.displacement_direction_1);
const mfem::Vector density = get_value_block(state, layout, density_block);
const mfem::Vector displacement = get_value_block(state, layout, displacement_block);
const mfem::Vector gravity_gradient = get_value_block(state, layout, gravity_gradient_block);
operators::context::gravity_field::GravityFieldLinearizationContext linearization_context(
f, *f.domainMapperStateless
@@ -2645,19 +2650,30 @@ TEST_CASE(
REQUIRE(jacobian_action.Size() == layout.residual_offsets().Last());
const mfem::Vector &density_true = linearization_context.GetDensityTrue();
const mfem::Vector &displacement_true =
linearization_context.GetGeometryContext().GetDisplacementTrue();
const mfem::Vector &gravity_gradient_true = linearization_context.GetGravityGradientTrue();
const mfem::Vector gradient_action = get_residual_block(jacobian_action, layout, gravity_gradient_residual_block);
const mfem::Vector poisson_action = get_residual_block(jacobian_action, layout, gravity_poisson_residual_block);
mfem::Vector expected_gradient_action;
mfem::Vector expected_poisson_action;
mfem::Vector expected_gradient_action_true;
mfem::Vector expected_poisson_action_true;
operators::kernels::apply_mapped_hdiv_mass_variation(
f, *f.domainMapperStateless, gravity_gradient, displacement, fields.displacement_direction_1,
expected_gradient_action
f, *f.domainMapperStateless, gravity_gradient_true, displacement_true, fields.displacement_direction_1,
expected_gradient_action_true
);
operators::kernels::apply_mapped_source_variation(
f, *f.domainMapperStateless, density, displacement, fields.displacement_direction_1, expected_poisson_action
f, *f.domainMapperStateless, density_true, displacement_true, fields.displacement_direction_1,
expected_poisson_action_true
);
expected_poisson_action *= -1.0;
expected_poisson_action_true *= -1.0;
const mfem::Vector expected_gradient_action =
linearization_context.GetGravityGradientMap().gather(expected_gradient_action_true);
const mfem::Vector expected_poisson_action =
linearization_context.GetGravityPotentialMap().gather(expected_poisson_action_true);
MPI_Comm communicator = f.mesh->GetComm();
const double gradient_error = global_relative_error(gradient_action, expected_gradient_action, communicator);
@@ -2677,7 +2693,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Jacobian Displacement Direction Matches Centered "
"Differences",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2732,9 +2748,9 @@ TEST_CASE(
linearization_context, state, layout.value_offsets(), communicator
);
const double base_density_norm = global_vector_norm(linearization_context.GetDensity(), communicator);
const double base_density_norm = global_vector_norm(linearization_context.GetDensityTrue(), communicator);
const double base_gravity_gradient_norm =
global_vector_norm(linearization_context.GetGravityGradient(), communicator);
global_vector_norm(linearization_context.GetGravityGradientTrue(), communicator);
INFO("Base density norm = " << base_density_norm);
INFO("Base gravity-gradient norm = " << base_gravity_gradient_norm);
@@ -2838,7 +2854,7 @@ TEST_CASE(
}
TEST_CASE(
"Gravity Field Jacobian Displacement Difference Converges At Second Order",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators &tags::convergence
tags::gravity_operator_convergence
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -2964,7 +2980,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Jacobian Complete Coupled Direction Matches Centered "
"Differences",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -3108,7 +3124,7 @@ TEST_CASE(
TEST_CASE(
"Reduced Gravity Field Operator Solves Deformed Gravity System With MINRES",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators
tags::gravity_operator_integration
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -3118,11 +3134,11 @@ TEST_CASE(
const gravity_layout layout = make_gravity_jacobian_layout(f);
const HdivMassVariationTestFields fields = make_hdiv_mass_variation_test_fields(f);
const mfem::Vector density = make_source_variation_density(f);
const mfem::Vector displacement = fields.displacement;
const mfem::Vector density_true = make_source_variation_density(f);
const mfem::Vector displacement_true = fields.displacement;
mfem::ParGridFunction legacy_displacement(f.displacementFes.get());
legacy_displacement.SetFromTrueDofs(displacement);
legacy_displacement.SetFromTrueDofs(displacement_true);
f.mapping->SetDisplacement(legacy_displacement);
physics::update_stiffness_matrix(f);
@@ -3133,6 +3149,8 @@ TEST_CASE(
operators::context::gravity_field::GravityFieldLinearizationContext linearization_context(
f, *f.domainMapperStateless
);
const mfem::Vector density = linearization_context.GetDensityMap().gather(density_true);
const mfem::Vector displacement = linearization_context.GetDisplacementMap().gather(displacement_true);
operators::GravityFieldJacobianOperator gravity_jacobian(
f, *f.domainMapperStateless, linearization_context, layout.value_offsets(), layout.residual_offsets()
);
@@ -3291,7 +3309,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Hdiv Operator Difference Is Localized To Vacuum Compactification",
tags::integration &tags::solver &tags::gravity &tags::mfem_operators &tags::legacy_comparison
tags::gravity_legacy
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -3311,16 +3329,7 @@ TEST_CASE(
constexpr auto gravity_gradient_residual_block =
mean_field::utils::blocks::get_residual_block<form>(blocks::gravity_field.gradient_term);
const std::array<int, form::value_block_count> value_sizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize()
};
const std::array<int, form::residual_block_count> residual_sizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize()
};
const blocks::form_layout<form> layout(value_sizes, residual_sizes);
const blocks::form_layout<form> layout = make_gravity_layout(f);
const mfem::Vector gravity_gradient_true = make_full_support_gravity_gradient(f);