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

@@ -10,18 +10,19 @@ namespace gravity_context = operators::context::gravity_field;
TEST_CASE(
"Gravity Field Linearization Context Applies Selective Invalidation",
tags::integration &tags::gravity &tags::contexts
tags::gravity_context
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
gravity_context::GravityFieldLinearizationContext context(f, *f.domainMapperStateless);
mfem::Vector density = prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.11);
mfem::Vector displacement = prepared_test::make_displacement(f, 0.0);
mfem::Vector gravity_gradient = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.37);
mfem::Vector density = prepared_test::make_deterministic_vector(context.GetDensityMap().reduced_size(), 0.11);
mfem::Vector displacement = context.GetDisplacementMap().gather(prepared_test::make_displacement(f, 0.0));
mfem::Vector gravity_gradient =
prepared_test::make_deterministic_vector(context.GetGravityGradientMap().reduced_size(), 0.37);
mfem::Vector gravity_potential =
prepared_test::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.63);
prepared_test::make_deterministic_vector(context.GetGravityPotentialMap().reduced_size(), 0.63);
gravity_context::GravityFieldRevisions revisions;
@@ -72,7 +73,7 @@ TEST_CASE(
CHECK(density_report.updated_density);
CHECK_FALSE(density_report.updated_gravity_gradient);
CHECK_FALSE(density_report.geometry.DidAnyWork());
CHECK(context.GetDensity()(0) == density(0));
CHECK(context.GetDensityTrue()(context.GetDensityMap().true_dof(0)) == density(0));
gravity_gradient(0) -= 0.4;
++revisions.gravity_gradient.value;
@@ -82,9 +83,9 @@ TEST_CASE(
CHECK_FALSE(gradient_report.updated_density);
CHECK(gradient_report.updated_gravity_gradient);
CHECK_FALSE(gradient_report.geometry.DidAnyWork());
CHECK(context.GetGravityGradient()(0) == gravity_gradient(0));
CHECK(context.GetGravityGradientTrue()(context.GetGravityGradientMap().true_dof(0)) == gravity_gradient(0));
displacement = prepared_test::make_displacement(f, 1.0);
displacement = context.GetDisplacementMap().gather(prepared_test::make_displacement(f, 1.0));
++revisions.displacement.value;
const gravity_context::GravityFieldPreparationReport displacement_report = context.Prepare(make_state(), revisions);
@@ -114,18 +115,19 @@ TEST_CASE(
TEST_CASE(
"Gravity Field Linearization Context Owns Frozen Base Fields",
tags::integration &tags::gravity &tags::contexts
tags::gravity_context
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
gravity_context::GravityFieldLinearizationContext context(f, *f.domainMapperStateless);
mfem::Vector density = prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.13);
mfem::Vector displacement = prepared_test::make_displacement(f, 0.4);
mfem::Vector gravity_gradient = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.47);
mfem::Vector density = prepared_test::make_deterministic_vector(context.GetDensityMap().reduced_size(), 0.13);
mfem::Vector displacement = context.GetDisplacementMap().gather(prepared_test::make_displacement(f, 0.4));
mfem::Vector gravity_gradient =
prepared_test::make_deterministic_vector(context.GetGravityGradientMap().reduced_size(), 0.47);
mfem::Vector gravity_potential =
prepared_test::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.71);
prepared_test::make_deterministic_vector(context.GetGravityPotentialMap().reduced_size(), 0.71);
gravity_context::GravityFieldRevisions revisions;
@@ -137,24 +139,24 @@ TEST_CASE(
revisions
);
const mfem::Vector frozen_density = context.GetDensity();
const mfem::Vector frozen_displacement = context.GetGeometryContext().GetDisplacement();
const mfem::Vector frozen_gravity_gradient = context.GetGravityGradient();
const mfem::Vector frozen_density = context.GetDensityTrue();
const mfem::Vector frozen_displacement = context.GetGeometryContext().GetDisplacementTrue();
const mfem::Vector frozen_gravity_gradient = context.GetGravityGradientTrue();
density = 0.0;
displacement = 0.0;
gravity_gradient = 0.0;
gravity_potential = 0.0;
CHECK(prepared_test::relative_error(context.GetDensity(), frozen_density, f.mesh->GetComm()) == 0.0);
CHECK(prepared_test::relative_error(context.GetDensityTrue(), frozen_density, f.mesh->GetComm()) == 0.0);
CHECK(
prepared_test::relative_error(
context.GetGeometryContext().GetDisplacement(), frozen_displacement, f.displacementFes->GetComm()
context.GetGeometryContext().GetDisplacementTrue(), frozen_displacement, f.displacementFes->GetComm()
) == 0.0
);
CHECK(
prepared_test::relative_error(
context.GetGravityGradient(), frozen_gravity_gradient, f.gravityFluxFes->GetComm()
context.GetGravityGradientTrue(), frozen_gravity_gradient, f.gravityFluxFes->GetComm()
) == 0.0
);
@@ -167,22 +169,22 @@ TEST_CASE(
);
CHECK_FALSE(unchanged_revision_report.DidAnyWork());
CHECK(prepared_test::relative_error(context.GetDensity(), frozen_density, f.mesh->GetComm()) == 0.0);
CHECK(prepared_test::relative_error(context.GetDensityTrue(), frozen_density, f.mesh->GetComm()) == 0.0);
CHECK(
prepared_test::relative_error(
context.GetGeometryContext().GetDisplacement(), frozen_displacement, f.displacementFes->GetComm()
context.GetGeometryContext().GetDisplacementTrue(), frozen_displacement, f.displacementFes->GetComm()
) == 0.0
);
CHECK(
prepared_test::relative_error(
context.GetGravityGradient(), frozen_gravity_gradient, f.gravityFluxFes->GetComm()
context.GetGravityGradientTrue(), frozen_gravity_gradient, f.gravityFluxFes->GetComm()
) == 0.0
);
}
TEST_CASE(
"Gravity Field Geometry Contexts Have Independent Prepared State",
tags::integration &tags::gravity &tags::contexts
tags::gravity_context
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -190,10 +192,13 @@ TEST_CASE(
gravity_context::GravityFieldGeometryContext first_context(f, *f.domainMapperStateless);
gravity_context::GravityFieldGeometryContext second_context(f, *f.domainMapperStateless);
const mfem::Vector first_displacement = prepared_test::make_displacement(f, 0.0);
const mfem::Vector second_displacement = prepared_test::make_displacement(f, 1.0);
const mfem::Vector gravity_gradient =
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.35);
const mfem::Vector first_displacement =
first_context.GetDisplacementMap().gather(prepared_test::make_displacement(f, 0.0));
const mfem::Vector second_displacement =
second_context.GetDisplacementMap().gather(prepared_test::make_displacement(f, 1.0));
const mfem::Vector gravity_gradient = prepared_test::make_field_map<field::Gravity>(f).gather(
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.35)
);
first_context.Prepare(first_displacement, {.value = 0}, {.value = 0});
second_context.Prepare(second_displacement, {.value = 0}, {.value = 0});
@@ -205,7 +210,8 @@ TEST_CASE(
first_context.GetMassOperator().Mult(gravity_gradient, first_action);
second_context.GetMassOperator().Mult(gravity_gradient, second_action_before);
const mfem::Vector updated_first_displacement = prepared_test::make_displacement(f, 0.6);
const mfem::Vector updated_first_displacement =
first_context.GetDisplacementMap().gather(prepared_test::make_displacement(f, 0.6));
first_context.Prepare(updated_first_displacement, {.value = 0}, {.value = 1});
second_context.GetMassOperator().Mult(gravity_gradient, second_action_after);

View File

@@ -40,7 +40,7 @@ namespace hydrostatic_context_test_utils {
TEST_CASE(
"Hydrostatic Context Applies Selective Invalidation",
tags::barotrope &tags::contexts &tags::hydro &tags::prepared &tags::unit
tags::barotrope_hydrostatic_context &tags::unit
) {
auto args = test_utils::setup_args();
@@ -48,12 +48,15 @@ TEST_CASE(
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumContext context(f, *f.domainMapperStateless);
mfem::Vector enthalpy = gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.17);
mfem::Vector enthalpy =
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(*f.enthalpyFes, 0.17);
mfem::Vector gravityPotential =
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.31);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, 0.31
);
mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.35);
mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.35);
double bernoulliConstant = 0.73;
@@ -145,7 +148,7 @@ TEST_CASE(
CHECK_FALSE(enthalpyReport.updatedGravityPotential);
CHECK_FALSE(enthalpyReport.updatedDisplacement);
CHECK_FALSE(enthalpyReport.updatedBernoulliConstant);
CHECK(context.GetBaseEnthalpyTrue()(0) == enthalpy(0));
CHECK(context.GetBaseEnthalpyTrue()(context.GetEnthalpyMap().true_dof(0)) == enthalpy(0));
++dependencies.gravityPotential.revision;
@@ -161,7 +164,9 @@ TEST_CASE(
CHECK_FALSE(gravityPotentialReport.updatedDisplacement);
CHECK_FALSE(gravityPotentialReport.updatedBernoulliConstant);
CHECK(context.GetBaseGravityPotentialTrue()(0) == gravityPotential(0));
CHECK(
context.GetBaseGravityPotentialTrue()(context.GetGravityPotentialMap().true_dof(0)) == gravityPotential(0)
);
++dependencies.bernoulliConstant.revision;
@@ -212,7 +217,7 @@ TEST_CASE(
CHECK(displacementReport.updatedDisplacement);
CHECK_FALSE(displacementReport.updatedBernoulliConstant);
CHECK(context.GetDisplacementTrue()(0) == displacement(0));
CHECK(context.GetDisplacementTrue()(context.GetDisplacementMap().true_dof(0)) == displacement(0));
++dependencies.discretization.revision;
@@ -240,7 +245,7 @@ TEST_CASE(
TEST_CASE(
"Hydrostatic Context Uses Identity In Every Dependency",
tags::barotrope &tags::contexts &tags::hydro &tags::prepared &tags::unit
tags::barotrope_hydrostatic_context &tags::unit
) {
auto args = test_utils::setup_args();
@@ -248,12 +253,15 @@ TEST_CASE(
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumContext context(f, *f.domainMapperStateless);
mfem::Vector enthalpy = gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.23);
mfem::Vector enthalpy =
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(*f.enthalpyFes, 0.23);
const mfem::Vector gravityPotential =
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.41);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, 0.41
);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.60);
const mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.60);
constexpr double bernoulliConstant = 0.81;
@@ -288,7 +296,10 @@ TEST_CASE(
);
CHECK_FALSE(sameStampReport.DidAnyWork());
CHECK(context.GetBaseEnthalpyTrue()(0) == firstFrozenEnthalpy(0));
CHECK(
context.GetBaseEnthalpyTrue()(context.GetEnthalpyMap().true_dof(0)) ==
firstFrozenEnthalpy(context.GetEnthalpyMap().true_dof(0))
);
++dependencies.enthalpy.identity;
dependencies.enthalpy.revision = 0;
@@ -301,7 +312,7 @@ TEST_CASE(
hydrostatic_context_test_utils::check_base_only(newIdentityReport);
CHECK(newIdentityReport.updatedEnthalpy);
CHECK(context.GetBaseEnthalpyTrue()(0) == enthalpy(0));
CHECK(context.GetBaseEnthalpyTrue()(context.GetEnthalpyMap().true_dof(0)) == enthalpy(0));
CHECK(context.MatchesDependencies(dependencies));
++dependencies.rotation.identity;

View File

@@ -53,7 +53,7 @@ namespace rotational_displacement_force_context_test_utils {
TEST_CASE(
"Rotational Displacement Force Context Applies Selective Invalidation",
tags::centrifugal &tags::contexts &tags::unit
tags::rotation_context_unit
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -61,15 +61,16 @@ TEST_CASE(
REQUIRE(f.okay());
mfem::Vector density = rotational_displacement_force_context_test_utils::make_density(f, 0.83);
mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.47);
auto dependencies = rotational_displacement_force_context_test_utils::make_dependencies();
auto dependencies = rotational_displacement_force_context_test_utils::make_dependencies();
rotational_displacement_force_context_test_utils::Context context(f, *f.domainMapperStateless);
const auto initialReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
mfem::Vector densityTrue = rotational_displacement_force_context_test_utils::make_density(f, 0.83);
mfem::Vector density = context.GetDensityMap().gather(densityTrue);
mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.47);
mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
const auto initialReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
REQUIRE(context.IsPrepared());
CHECK(context.MatchesDependencies(dependencies));
@@ -80,14 +81,18 @@ TEST_CASE(
CHECK(initialReport.updatedDensity);
CHECK(initialReport.updatedDisplacement);
const mfem::Vector expectedDensityTrue = context.GetDensityMap().scatter(density);
const mfem::Vector expectedDisplacementTrue = context.GetDisplacementMap().scatter(displacement);
CHECK(
rotational_displacement_force_context_test_utils::relative_difference(context.GetBaseDensityTrue(), density) <
1.0e-14
rotational_displacement_force_context_test_utils::relative_difference(
context.GetBaseDensityTrue(), expectedDensityTrue
) < 1.0e-14
);
CHECK(
rotational_displacement_force_context_test_utils::relative_difference(
context.GetDisplacementTrue(), displacement
context.GetDisplacementTrue(), expectedDisplacementTrue
) < 1.0e-14
);
@@ -95,7 +100,8 @@ TEST_CASE(
CHECK_FALSE(unchangedReport.DidAnyWork());
density = rotational_displacement_force_context_test_utils::make_density(f, 1.17);
densityTrue = rotational_displacement_force_context_test_utils::make_density(f, 1.17);
density = context.GetDensityMap().gather(densityTrue);
++dependencies.density.revision;
@@ -110,7 +116,8 @@ TEST_CASE(
const mfem::Vector densityAfterDensityRevision(context.GetBaseDensityTrue());
displacement = gravity_prepared_test_utils::make_displacement(f, 0.81);
displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.81);
displacement = context.GetDisplacementMap().gather(displacementTrue);
++dependencies.displacement.revision;
@@ -151,7 +158,7 @@ TEST_CASE(
TEST_CASE(
"Rotational Displacement Force Context Treats New Identities As New "
"Dependency Streams",
tags::centrifugal &tags::contexts &tags::unit
tags::rotation_context_unit
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -159,14 +166,15 @@ TEST_CASE(
REQUIRE(f.okay());
const mfem::Vector density = rotational_displacement_force_context_test_utils::make_density(f, 0.91);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.39);
auto dependencies = rotational_displacement_force_context_test_utils::make_dependencies();
auto dependencies = rotational_displacement_force_context_test_utils::make_dependencies();
rotational_displacement_force_context_test_utils::Context context(f, *f.domainMapperStateless);
const mfem::Vector density =
context.GetDensityMap().gather(rotational_displacement_force_context_test_utils::make_density(f, 0.91));
const mfem::Vector displacement =
context.GetDisplacementMap().gather(gravity_prepared_test_utils::make_displacement(f, 0.39));
context.Prepare({.density = density, .displacement = displacement}, dependencies);
dependencies.density.identity += 1000;

View File

@@ -58,14 +58,25 @@ namespace gravity_displacement_force_test_utils {
);
[[nodiscard]] mean_field::operators::GravityDisplacementForceLayout make_layout(const mean_field::fem::FEM &f) {
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
const auto densityMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(f);
const auto displacementMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Displacement>(f);
const auto gravityFluxMap =
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityFluxFes);
const auto gravityPotentialMap =
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
const auto enthalpyMap =
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy, DomainSchema>(*f.enthalpyFes);
const std::array<int, CoupledForm::value_block_count> valueSizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
const std::array<int, CoupledForm::residual_block_count> residualSizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize(), f.densityFes->GetTrueVSize(),
f.displacementFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
return {valueSizes, residualSizes};
@@ -221,10 +232,10 @@ namespace gravity_displacement_force_test_utils {
const mean_field::operators::context::gravity_field::GravityFieldRevisions &revisions
) {
context.Prepare(
{.density = density,
.displacement = displacement,
.gravity_gradient = gravityGradient,
.gravity_potential = gravityPotential},
{.density = context.GetDensityMap().gather(density),
.displacement = context.GetDisplacementMap().gather(displacement),
.gravity_gradient = context.GetGravityGradientMap().gather(gravityGradient),
.gravity_potential = context.GetGravityPotentialMap().gather(gravityPotential)},
revisions
);
}
@@ -314,7 +325,7 @@ namespace gravity_displacement_force_test_utils {
TEST_CASE(
"Gravity Displacement Force Query Includes Every Registered Operand",
tags::gravity &tags::quadrature &tags::unit
tags::gravity_unit
) {
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
@@ -350,7 +361,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Displacement Force Uses Positive Grad-Phi Sign And Excludes "
"Vacuum",
tags::gravity &tags::integration &tags::accuracy
tags::gravity_kernel_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -413,7 +424,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Gravity Displacement Force Reuses Shared Gravity Revisions",
tags::gravity &tags::prepared &tags::integration
tags::gravity_prepared
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -457,9 +468,11 @@ TEST_CASE(
f, *f.domainMapperStateless, density, gravityGradient, displacement, kernelResidual
);
const mfem::Vector kernelResidualReduced = gravityContext.GetDisplacementMap().gather(kernelResidual);
CHECK(
gravity_displacement_force_test_utils::relative_difference(
preparedResidual, kernelResidual, f.mesh->GetComm()
preparedResidual, kernelResidualReduced, f.mesh->GetComm()
) < 2.0e-12
);
@@ -493,7 +506,7 @@ TEST_CASE(
TEST_CASE(
"Gravity Displacement Force Jacobian Matches All Columns And Centered "
"Differences",
tags::gravity &tags::prepared &tags::jacobian &tags::accuracy
tags::gravity_prepared_jacobian_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -532,19 +545,24 @@ TEST_CASE(
preparedOperator.Prepare();
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
const mfem::Vector gravityGradientDirectionReduced =
gravityContext.GetGravityGradientMap().gather(gravityGradientDirection);
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
mfem::Vector densityAction;
mfem::Vector gravityAction;
mfem::Vector displacementAction;
mfem::Vector completeAction;
preparedOperator.ApplyDensityJacobianAction(densityDirection, densityAction);
preparedOperator.ApplyDensityJacobianAction(densityDirectionReduced, densityAction);
preparedOperator.ApplyGravityGradientJacobianAction(gravityGradientDirection, gravityAction);
preparedOperator.ApplyGravityGradientJacobianAction(gravityGradientDirectionReduced, gravityAction);
preparedOperator.ApplyDisplacementJacobianAction(displacementDirection, displacementAction);
preparedOperator.ApplyDisplacementJacobianAction(displacementDirectionReduced, displacementAction);
preparedOperator.ApplyCompleteJacobianAction(
densityDirection, displacementDirection, gravityGradientDirection, completeAction
densityDirectionReduced, displacementDirectionReduced, gravityGradientDirectionReduced, completeAction
);
mfem::Vector summedColumns(densityAction);
@@ -559,29 +577,34 @@ TEST_CASE(
mfem::Vector zeroDensity(densityDirection.Size());
mfem::Vector zeroGravity(gravityGradientDirection.Size());
mfem::Vector zeroDisplacement(displacementDirection.Size());
zeroDensity = 0.0;
zeroGravity = 0.0;
zeroDisplacement = 0.0;
zeroDensity = 0.0;
zeroGravity = 0.0;
zeroDisplacement = 0.0;
constexpr double step = 1.0e-5;
constexpr double step = 1.0e-5;
const mfem::Vector densityDifference = gravity_displacement_force_test_utils::centered_difference(
const mfem::Vector densityDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
f, density, densityDirection, gravityGradient, zeroGravity, displacement, zeroDisplacement, step
);
const mfem::Vector gravityDifference = gravity_displacement_force_test_utils::centered_difference(
const mfem::Vector gravityDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
f, density, zeroDensity, gravityGradient, gravityGradientDirection, displacement, zeroDisplacement, step
);
const mfem::Vector displacementDifference = gravity_displacement_force_test_utils::centered_difference(
const mfem::Vector displacementDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
f, density, zeroDensity, gravityGradient, zeroGravity, displacement, displacementDirection, step
);
const mfem::Vector completeDifference = gravity_displacement_force_test_utils::centered_difference(
const mfem::Vector completeDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
f, density, densityDirection, gravityGradient, gravityGradientDirection, displacement, displacementDirection,
step
);
const mfem::Vector densityDifference = gravityContext.GetDisplacementMap().gather(densityDifferenceTrue);
const mfem::Vector gravityDifference = gravityContext.GetDisplacementMap().gather(gravityDifferenceTrue);
const mfem::Vector displacementDifference = gravityContext.GetDisplacementMap().gather(displacementDifferenceTrue);
const mfem::Vector completeDifference = gravityContext.GetDisplacementMap().gather(completeDifferenceTrue);
const double densityError =
gravity_displacement_force_test_utils::relative_difference(densityAction, densityDifference, f.mesh->GetComm());
@@ -609,7 +632,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Gravity Displacement Force MFEM Adapter Routes Only R-d",
tags::gravity &tags::prepared &tags::mfem_operators &tags::unit
tags::gravity_prepared_unit
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -648,22 +671,27 @@ TEST_CASE(
preparedOperator.Prepare();
const auto layout = gravity_displacement_force_test_utils::make_layout(f);
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
const mfem::Vector gravityGradientDirectionReduced =
gravityContext.GetGravityGradientMap().gather(gravityGradientDirection);
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
const auto layout = gravity_displacement_force_test_utils::make_layout(f);
mean_field::operators::PreparedGravityDisplacementForceJacobianOperator adapter(layout, preparedOperator);
mfem::BlockVector direction(layout.value_offsets());
direction = 0.0;
direction = 0.0;
direction.GetBlock(gravity_displacement_force_test_utils::densityValue) = densityDirection;
direction.GetBlock(gravity_displacement_force_test_utils::densityValue) = densityDirectionReduced;
direction.GetBlock(gravity_displacement_force_test_utils::displacementValue) = displacementDirection;
direction.GetBlock(gravity_displacement_force_test_utils::displacementValue) = displacementDirectionReduced;
direction.GetBlock(gravity_displacement_force_test_utils::gravityGradientValue) = gravityGradientDirection;
direction.GetBlock(gravity_displacement_force_test_utils::gravityGradientValue) = gravityGradientDirectionReduced;
direction.GetBlock(gravity_displacement_force_test_utils::gravityPotentialValue) = 0.29;
direction.GetBlock(gravity_displacement_force_test_utils::gravityPotentialValue) = 0.29;
direction.GetBlock(gravity_displacement_force_test_utils::enthalpyValue) = -0.37;
direction.GetBlock(gravity_displacement_force_test_utils::enthalpyValue) = -0.37;
direction.GetBlock(gravity_displacement_force_test_utils::barotropicConstantValue) = 0.43;
@@ -673,7 +701,8 @@ TEST_CASE(
mfem::Vector expectedDisplacementAction;
preparedOperator.ApplyCompleteJacobianAction(
densityDirection, displacementDirection, gravityGradientDirection, expectedDisplacementAction
densityDirectionReduced, displacementDirectionReduced, gravityGradientDirectionReduced,
expectedDisplacementAction
);
const mfem::Vector actualDisplacementAction = gravity_displacement_force_test_utils::copy_residual_block(
@@ -707,4 +736,4 @@ TEST_CASE(
for (const mfem::Vector &row : zeroRows) {
CHECK(gravity_prepared_test_utils::global_norm(row, f.mesh->GetComm()) == 0.0);
}
}
}

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);

View File

@@ -66,26 +66,24 @@ namespace prepared_displacement_residual_test_utils {
}
[[nodiscard]] mean_field::operators::DisplacementResidualLayout make_layout(const mean_field::fem::FEM &f) {
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
const auto densityMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(f);
const auto displacementMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Displacement>(f);
const auto gravityFluxMap =
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityFluxFes);
const auto gravityPotentialMap =
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
const auto enthalpyMap = make_enthalpy_map(f);
/*
* Transitional displacement-composer layout.
*
* Pressure has now migrated its h column to supported FieldDof
* coordinates, while the density-consuming mechanical children are
* intentionally still full-space until the next migration slice.
*
* The adapter only writes R_d. The unrelated residual-row sizes remain
* at their current full-space values in this standalone adapter test.
*/
const std::array<int, CoupledForm::value_block_count> valueSizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize(), enthalpyMap.reduced_size(), 1
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
const std::array<int, CoupledForm::residual_block_count> residualSizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize(), f.densityFes->GetTrueVSize(),
f.displacementFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
return {valueSizes, residualSizes};
@@ -273,10 +271,10 @@ namespace prepared_displacement_residual_test_utils {
const std::uint64_t potentialRevision
) {
context.Prepare(
{.density = density,
.displacement = displacement,
.gravity_gradient = gravityGradient,
.gravity_potential = gravityPotential},
{.density = context.GetDensityMap().gather(density),
.displacement = context.GetDisplacementMap().gather(displacement),
.gravity_gradient = context.GetGravityGradientMap().gather(gravityGradient),
.gravity_potential = context.GetGravityPotentialMap().gather(gravityPotential)},
make_gravity_revisions(dependencies, potentialRevision)
);
}
@@ -334,7 +332,7 @@ namespace prepared_displacement_residual_test_utils {
TEST_CASE(
"Prepared Displacement Residual Equals The Three Prepared Contributors",
tags::barotrope &tags::prepared &tags::integration &tags::residuals
tags::barotrope_prepared
) {
using Operator = mean_field::operators::PreparedDisplacementResidualOperator;
@@ -419,7 +417,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Displacement Residual Selectively Orchestrates Its Children",
tags::barotrope &tags::prepared &tags::contexts &tags::integration
tags::barotrope_context_integration
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -537,7 +535,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Displacement Residual Jacobian Equals The Contributor Sums",
tags::barotrope &tags::prepared &tags::jacobian &tags::accuracy
tags::barotrope_prepared_jacobian_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -585,30 +583,37 @@ TEST_CASE(
preparedOperator.Prepare({.enthalpy = enthalpy}, dependencies, rotation);
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
const mfem::Vector gravityDirectionReduced = gravityContext.GetGravityGradientMap().gather(gravityDirection);
mfem::Vector densityAction;
mfem::Vector displacementAction;
mfem::Vector gravityAction;
mfem::Vector enthalpyAction;
mfem::Vector completeAction;
preparedOperator.ApplyDensityJacobianAction(densityDirection, densityAction);
preparedOperator.ApplyDensityJacobianAction(densityDirectionReduced, densityAction);
preparedOperator.ApplyDisplacementJacobianAction(displacementDirection, displacementAction);
preparedOperator.ApplyDisplacementJacobianAction(displacementDirectionReduced, displacementAction);
preparedOperator.ApplyGravityGradientJacobianAction(gravityDirection, gravityAction);
preparedOperator.ApplyGravityGradientJacobianAction(gravityDirectionReduced, gravityAction);
preparedOperator.ApplyEnthalpyJacobianAction(enthalpyDirection, enthalpyAction);
preparedOperator.ApplyCompleteJacobianAction(
densityDirection, displacementDirection, gravityDirection, enthalpyDirection, completeAction
densityDirectionReduced, displacementDirectionReduced, gravityDirectionReduced, enthalpyDirection,
completeAction
);
mfem::Vector expectedDensity;
mfem::Vector expectedRotationDensity;
preparedOperator.GetGravityOperator().ApplyDensityJacobianAction(densityDirection, expectedDensity);
preparedOperator.GetGravityOperator().ApplyDensityJacobianAction(densityDirectionReduced, expectedDensity);
preparedOperator.GetRotationalOperator().ApplyDensityJacobianAction(densityDirection, expectedRotationDensity);
preparedOperator.GetRotationalOperator().ApplyDensityJacobianAction(
densityDirectionReduced, expectedRotationDensity
);
expectedDensity += expectedRotationDensity;
@@ -616,21 +621,23 @@ TEST_CASE(
mfem::Vector expectedGravityDisplacement;
mfem::Vector expectedRotationDisplacement;
preparedOperator.GetPressureOperator().ApplyDisplacementJacobianAction(displacementDirection, expectedDisplacement);
preparedOperator.GetPressureOperator().ApplyDisplacementJacobianAction(
displacementDirectionReduced, expectedDisplacement
);
preparedOperator.GetGravityOperator().ApplyDisplacementJacobianAction(
displacementDirection, expectedGravityDisplacement
displacementDirectionReduced, expectedGravityDisplacement
);
preparedOperator.GetRotationalOperator().ApplyDisplacementJacobianAction(
displacementDirection, expectedRotationDisplacement
displacementDirectionReduced, expectedRotationDisplacement
);
expectedDisplacement += expectedGravityDisplacement;
expectedDisplacement += expectedRotationDisplacement;
mfem::Vector expectedGravity;
preparedOperator.GetGravityOperator().ApplyGravityGradientJacobianAction(gravityDirection, expectedGravity);
preparedOperator.GetGravityOperator().ApplyGravityGradientJacobianAction(gravityDirectionReduced, expectedGravity);
mfem::Vector expectedEnthalpy;
preparedOperator.GetPressureOperator().ApplyEnthalpyJacobianAction(enthalpyDirection, expectedEnthalpy);
@@ -672,7 +679,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Displacement Residual Jacobian Matches A Simultaneous "
"Centered Difference On Deformed Geometry",
tags::barotrope &tags::prepared &tags::jacobian &tags::accuracy &tags::geometry
tags::barotrope_prepared_jacobian_accuracy &tags::geometry
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -720,10 +727,15 @@ TEST_CASE(
preparedOperator.Prepare({.enthalpy = baseEnthalpy}, dependencies, rotation);
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
const mfem::Vector gravityDirectionReduced = gravityContext.GetGravityGradientMap().gather(gravityDirection);
mfem::Vector jacobianAction;
preparedOperator.ApplyCompleteJacobianAction(
densityDirection, displacementDirection, gravityDirection, enthalpyDirection, jacobianAction
densityDirectionReduced, displacementDirectionReduced, gravityDirectionReduced, enthalpyDirection,
jacobianAction
);
constexpr double step = 1.0e-5;
@@ -793,7 +805,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Displacement Residual MFEM Adapter Routes Only R-d",
tags::barotrope &tags::prepared &tags::jacobian &tags::mfem_operators &tags::unit
tags::barotrope_prepared_jacobian_unit
) {
using JacobianForm = mean_field::utils::blocks::barotropic_equilibrium_jacobian_form;
@@ -876,6 +888,10 @@ TEST_CASE(
preparedOperator.Prepare({.enthalpy = enthalpy}, dependencies, rotation);
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
const mfem::Vector gravityDirectionReduced = gravityContext.GetGravityGradientMap().gather(gravityDirection);
const mean_field::operators::DisplacementResidualLayout layout =
prepared_displacement_residual_test_utils::make_layout(f);
@@ -889,24 +905,25 @@ TEST_CASE(
);
mfem::BlockVector direction(layout.value_offsets());
direction = 0.0;
direction = 0.0;
direction.GetBlock(prepared_displacement_residual_test_utils::densityValue) = densityDirection;
direction.GetBlock(prepared_displacement_residual_test_utils::densityValue) = densityDirectionReduced;
direction.GetBlock(prepared_displacement_residual_test_utils::displacementValue) = displacementDirection;
direction.GetBlock(prepared_displacement_residual_test_utils::displacementValue) = displacementDirectionReduced;
direction.GetBlock(prepared_displacement_residual_test_utils::gravityGradientValue) = gravityDirection;
direction.GetBlock(prepared_displacement_residual_test_utils::gravityGradientValue) = gravityDirectionReduced;
direction.GetBlock(prepared_displacement_residual_test_utils::enthalpyValue) = enthalpyDirection;
direction.GetBlock(prepared_displacement_residual_test_utils::enthalpyValue) = enthalpyDirection;
direction.GetBlock(prepared_displacement_residual_test_utils::gravityPotentialValue) = 0.59;
direction.GetBlock(prepared_displacement_residual_test_utils::gravityPotentialValue) = 0.59;
direction.GetBlock(prepared_displacement_residual_test_utils::barotropicConstantValue) = -0.73;
mfem::Vector expectedDisplacementAction;
preparedOperator.ApplyCompleteJacobianAction(
densityDirection, displacementDirection, gravityDirection, enthalpyDirection, expectedDisplacementAction
densityDirectionReduced, displacementDirectionReduced, gravityDirectionReduced, enthalpyDirection,
expectedDisplacementAction
);
mfem::Vector action;

View File

@@ -11,31 +11,36 @@ namespace prepared_test = gravity_prepared_test_utils;
TEST_CASE(
"Prepared Mapped Gravity Source Matches Stateless Kernel",
tags::integration &tags::mfem_operators &tags::prepared
tags::gravity_prepared
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
operators::PreparedMappedGravitySourceOperator prepared_operator(f, *f.domainMapperStateless);
REQUIRE(prepared_operator.Width() == f.densityFes->GetTrueVSize());
REQUIRE(prepared_operator.Height() == f.gravityPotentialFes->GetTrueVSize());
REQUIRE(prepared_operator.Width() == prepared_operator.GetDensityMap().reduced_size());
REQUIRE(prepared_operator.Height() == prepared_operator.GetPotentialMap().reduced_size());
const mfem::Vector density = prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.41);
const MPI_Comm communicator = f.mesh->GetComm();
const mfem::Vector density_true = prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.41);
const mfem::Vector density = prepared_operator.GetDensityMap().gather(density_true);
const MPI_Comm communicator = f.mesh->GetComm();
mfem::Vector identity_action;
mfem::Vector deformed_action;
for (const double deformation_scale : {0.0, 1.0}) {
const mfem::Vector displacement = prepared_test::make_displacement(f, deformation_scale);
const mfem::Vector displacement_true = prepared_test::make_displacement(f, deformation_scale);
const mfem::Vector displacement = prepared_operator.GetDisplacementMap().gather(displacement_true);
prepared_operator.Prepare(displacement);
mfem::Vector prepared_action;
mfem::Vector reference_action;
prepared_operator.Mult(density, prepared_action);
operators::kernels::apply_mapped_source(f, *f.domainMapperStateless, density, displacement, reference_action);
mfem::Vector reference_action_true;
operators::kernels::apply_mapped_source(
f, *f.domainMapperStateless, density_true, displacement_true, reference_action_true
);
const mfem::Vector reference_action = prepared_operator.GetPotentialMap().gather(reference_action_true);
const double relative_error = prepared_test::relative_error(prepared_action, reference_action, communicator);
@@ -64,28 +69,36 @@ TEST_CASE(
TEST_CASE(
"Prepared Mapped Gravity Source Preserves Linearity And Excludes Vacuum",
tags::integration &tags::gravity &tags::prepared
tags::gravity_prepared
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
operators::PreparedMappedGravitySourceOperator prepared_operator(f, *f.domainMapperStateless);
REQUIRE(prepared_operator.Width() == f.densityFes->GetTrueVSize());
REQUIRE(prepared_operator.Height() == f.gravityPotentialFes->GetTrueVSize());
const mfem::Vector displacement = prepared_test::make_displacement(f, 1.0);
REQUIRE(prepared_operator.Width() == prepared_operator.GetDensityMap().reduced_size());
REQUIRE(prepared_operator.Height() == prepared_operator.GetPotentialMap().reduced_size());
const mfem::Vector displacement =
prepared_operator.GetDisplacementMap().gather(prepared_test::make_displacement(f, 1.0));
prepared_operator.Prepare(displacement);
const mfem::Vector first = prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.27);
const mfem::Vector second = prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.79);
const mfem::Vector combination = prepared_test::linear_combination(first, 1.3, second, -0.6);
const mfem::Vector stellar_density = prepared_test::make_domain_supported_density(f, true);
const mfem::Vector vacuum_density = prepared_test::make_domain_supported_density(f, false);
const mfem::Vector first = prepared_operator.GetDensityMap().gather(
prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.27)
);
const mfem::Vector second = prepared_operator.GetDensityMap().gather(
prepared_test::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.79)
);
const mfem::Vector combination = prepared_test::linear_combination(first, 1.3, second, -0.6);
const mfem::Vector stellar_density =
prepared_operator.GetDensityMap().gather(prepared_test::make_domain_supported_density(f, true));
const mfem::Vector vacuum_density =
prepared_operator.GetDensityMap().gather(prepared_test::make_domain_supported_density(f, false));
mfem::Vector first_action;
mfem::Vector second_action;
mfem::Vector combination_action;
mfem::Vector stellar_action;
mfem::Vector vacuum_action;
mfem::Vector transpose_action;
prepared_operator.Mult(first, first_action);
prepared_operator.Mult(second, second_action);
@@ -93,6 +106,10 @@ TEST_CASE(
prepared_operator.Mult(stellar_density, stellar_action);
prepared_operator.Mult(vacuum_density, vacuum_action);
const mfem::Vector potential =
prepared_test::make_deterministic_vector(prepared_operator.GetPotentialMap().reduced_size(), 1.17);
prepared_operator.MultTranspose(potential, transpose_action);
const mfem::Vector expected_combination = prepared_test::linear_combination(first_action, 1.3, second_action, -0.6);
const MPI_Comm communicator = f.mesh->GetComm();
@@ -100,6 +117,9 @@ TEST_CASE(
prepared_test::relative_error(combination_action, expected_combination, communicator);
const double stellar_norm = prepared_test::global_norm(stellar_action, communicator);
const double vacuum_norm = prepared_test::global_norm(vacuum_action, communicator);
const double forward_pairing = prepared_test::global_dot(first_action, potential, communicator);
const double transpose_pairing = prepared_test::global_dot(first, transpose_action, communicator);
const double transpose_error = prepared_test::relative_scalar_error(forward_pairing, transpose_pairing);
const std::uint64_t preparation_count = prepared_operator.GetPreparationCount();
mfem::Vector repeated_action;
@@ -108,10 +128,12 @@ TEST_CASE(
INFO("Relative source linearity error = " << linearity_error);
INFO("Stellar source norm = " << stellar_norm);
INFO("Vacuum-only source norm = " << vacuum_norm);
INFO("Relative source-transpose pairing error = " << transpose_error);
CHECK_THAT(linearity_error, WithinAbs(0.0, 2.0e-12));
CHECK(stellar_norm > 0.0);
CHECK(vacuum_norm <= 1.0e-13 * stellar_norm);
CHECK_THAT(transpose_error, WithinAbs(0.0, 2.0e-12));
CHECK(prepared_test::relative_error(repeated_action, first_action, communicator) < 2.0e-14);
CHECK(prepared_operator.GetPreparationCount() == preparation_count);
}

View File

@@ -11,32 +11,37 @@ namespace prepared_test = gravity_prepared_test_utils;
TEST_CASE(
"Prepared Mapped Hdiv Mass Matches Stateless Kernel",
tags::integration &tags::mfem_operators &tags::prepared
tags::gravity_prepared
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
operators::PreparedMappedHDivMassOperator prepared_operator(f, *f.domainMapperStateless);
REQUIRE(prepared_operator.Width() == prepared_operator.GetFluxMap().reduced_size());
REQUIRE(prepared_operator.Height() == prepared_operator.GetFluxMap().reduced_size());
const mfem::Vector gravity_gradient =
const mfem::Vector gravity_gradient_true =
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.21);
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
const mfem::Vector gravity_gradient = prepared_operator.GetFluxMap().gather(gravity_gradient_true);
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
mfem::Vector identity_action;
mfem::Vector deformed_action;
for (const double deformation_scale : {0.0, 1.0}) {
const mfem::Vector displacement = prepared_test::make_displacement(f, deformation_scale);
const mfem::Vector displacement_true = prepared_test::make_displacement(f, deformation_scale);
const mfem::Vector displacement = prepared_operator.GetDisplacementMap().gather(displacement_true);
prepared_operator.Prepare(displacement);
mfem::Vector prepared_action;
mfem::Vector reference_action;
prepared_operator.Mult(gravity_gradient, prepared_action);
mfem::Vector reference_action_true;
operators::kernels::apply_mapped_hdiv_mass(
f, *f.domainMapperStateless, gravity_gradient, displacement, reference_action
f, *f.domainMapperStateless, gravity_gradient_true, displacement_true, reference_action_true
);
const mfem::Vector reference_action = prepared_operator.GetFluxMap().gather(reference_action_true);
const double relative_error = prepared_test::relative_error(prepared_action, reference_action, communicator);
@@ -65,17 +70,24 @@ TEST_CASE(
TEST_CASE(
"Prepared Mapped Hdiv Mass Preserves Operator Identities",
tags::integration &tags::gravity &tags::prepared
tags::gravity_prepared
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
operators::PreparedMappedHDivMassOperator prepared_operator(f, *f.domainMapperStateless);
const mfem::Vector displacement = prepared_test::make_displacement(f, 1.0);
REQUIRE(prepared_operator.Width() == prepared_operator.GetFluxMap().reduced_size());
REQUIRE(prepared_operator.Height() == prepared_operator.GetFluxMap().reduced_size());
const mfem::Vector displacement =
prepared_operator.GetDisplacementMap().gather(prepared_test::make_displacement(f, 1.0));
prepared_operator.Prepare(displacement);
const mfem::Vector first = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.17);
const mfem::Vector second = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.83);
const mfem::Vector first = prepared_operator.GetFluxMap().gather(
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.17)
);
const mfem::Vector second = prepared_operator.GetFluxMap().gather(
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.83)
);
const mfem::Vector combination = prepared_test::linear_combination(first, 1.7, second, -0.4);
mfem::Vector first_action;
@@ -121,4 +133,4 @@ TEST_CASE(
CHECK(second_energy > 0.0);
CHECK(prepared_test::relative_error(repeated_action, first_action, communicator) < 2.0e-14);
CHECK(prepared_operator.GetPreparationCount() == preparation_count);
}
}

View File

@@ -34,14 +34,18 @@ namespace prepared_hydrostatic_test_utils {
const mean_field::fem::FEM &f,
const double phase = 0.19
) {
return gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), phase);
return field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, phase
);
}
mfem::Vector make_gravity_potential(
const mean_field::fem::FEM &f,
const double phase = 0.37
) {
return gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), phase);
return field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, phase
);
}
mean_field::physics::RigidRotation make_rotation(const double scale = 1.0) {
@@ -63,7 +67,7 @@ namespace prepared_hydrostatic_test_utils {
TEST_CASE(
"Prepared Hydrostatic Residual Matches Stateless Kernel",
tags::barotrope &tags::hydro &tags::prepared &tags::residuals &tags::unit
tags::barotrope_hydrostatic_prepared_residual &tags::unit
) {
auto args = test_utils::setup_args();
@@ -75,7 +79,7 @@ TEST_CASE(
const mfem::Vector gravityPotential = prepared_hydrostatic_test_utils::make_gravity_potential(f);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.73);
const mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.73);
constexpr double bernoulliConstant = 0.41;
@@ -97,9 +101,8 @@ TEST_CASE(
preparedOperator.BuildResidual(preparedResidual);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpy, gravityPotential, displacement, bernoulliConstant,
referenceResidual
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpy, gravityPotential, displacement, bernoulliConstant, referenceResidual
);
const double relativeError =
@@ -131,7 +134,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Hydrostatic Residual Reuses And Selectively Rebuilds Data",
tags::barotrope &tags::hydro &tags::prepared &tags::residuals &tags::unit
tags::barotrope_hydrostatic_prepared_residual &tags::unit
) {
auto args = test_utils::setup_args();
@@ -143,7 +146,7 @@ TEST_CASE(
mfem::Vector gravityPotential = prepared_hydrostatic_test_utils::make_gravity_potential(f);
mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.42);
mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.42);
double bernoulliConstant = 0.36;
@@ -168,7 +171,7 @@ TEST_CASE(
enthalpy(0) += 0.29;
gravityPotential(0) -= 0.17;
displacement = gravity_prepared_test_utils::make_displacement(f, 0.73);
displacement = field_dof_test_utils::make_supported_displacement(f, 0.73);
bernoulliConstant += 0.23;
const auto unchangedReport = preparedOperator.Prepare(
@@ -199,9 +202,9 @@ TEST_CASE(
preparedOperator.BuildResidual(enthalpyResidual);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, initialRotation, enthalpy, initialGravityPotential, initialDisplacement,
initialBernoulliConstant, enthalpyReference
field_dof_test_utils::apply_hydrostatic_reference(
f, initialRotation, enthalpy, initialGravityPotential, initialDisplacement, initialBernoulliConstant,
enthalpyReference
);
CHECK_FALSE(enthalpyReport.contextReport.preparedStaticDependencies);
@@ -226,9 +229,9 @@ TEST_CASE(
preparedOperator.BuildResidual(rotationResidual);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, changedRotation, enthalpy, initialGravityPotential, initialDisplacement,
initialBernoulliConstant, rotationReference
field_dof_test_utils::apply_hydrostatic_reference(
f, changedRotation, enthalpy, initialGravityPotential, initialDisplacement, initialBernoulliConstant,
rotationReference
);
CHECK_FALSE(rotationReport.contextReport.preparedStaticDependencies);
@@ -253,9 +256,9 @@ TEST_CASE(
preparedOperator.BuildResidual(displacementResidual);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, changedRotation, enthalpy, initialGravityPotential, displacement,
initialBernoulliConstant, displacementReference
field_dof_test_utils::apply_hydrostatic_reference(
f, changedRotation, enthalpy, initialGravityPotential, displacement, initialBernoulliConstant,
displacementReference
);
CHECK_FALSE(displacementReport.contextReport.preparedStaticDependencies);

View File

@@ -144,8 +144,7 @@ namespace prepared_hydrostatic_analytic_solve_test_utils {
TEST_CASE(
"Prepared Hydrostatic Operator Solves Analytic Bernoulli Equilibria",
tags::barotrope &tags::hydro &tags::prepared &tags::integration &tags::solver &tags::convergence &tags::accuracy
&tags::analytic_comparison
tags::barotrope_hydrostatic_prepared_analytic &tags::convergence &tags::accuracy
) {
using prepared_hydrostatic_analytic_solve_test_utils::AnalyticCase;
@@ -181,6 +180,15 @@ TEST_CASE(
const MPI_Comm communicator = f.mesh->GetComm();
const mean_field::field::FieldDofMap enthalpyMap =
field_dof_test_utils::make_map<mean_field::field::Enthalpy>(*f.enthalpyFes);
const mean_field::field::FieldDofMap gravityPotentialMap =
field_dof_test_utils::make_map<mean_field::field::Gravity>(*f.gravityPotentialFes);
const mean_field::field::FieldDofMap displacementMap =
field_dof_test_utils::make_map<mean_field::field::Displacement>(*f.displacementFes);
const mfem::Array<int> stellarElementMarker =
prepared_hydrostatic_analytic_solve_test_utils::make_stellar_element_marker(f);
@@ -234,11 +242,14 @@ TEST_CASE(
potentialField.ProjectCoefficient(potentialCoefficient);
mfem::Vector displacement;
mfem::Vector gravityPotential;
mfem::Vector displacementTrue;
mfem::Vector gravityPotentialTrue;
displacementField.GetTrueDofs(displacement);
potentialField.GetTrueDofs(gravityPotential);
displacementField.GetTrueDofs(displacementTrue);
potentialField.GetTrueDofs(gravityPotentialTrue);
const mfem::Vector displacement = displacementMap.gather(displacementTrue);
const mfem::Vector gravityPotential = gravityPotentialMap.gather(gravityPotentialTrue);
/*
* This projection is not used as the solution. It gives
@@ -266,7 +277,7 @@ TEST_CASE(
/*
* Begin deliberately far from equilibrium.
*/
mfem::Vector enthalpy(f.enthalpyFes->GetTrueVSize());
mfem::Vector enthalpy(enthalpyMap.reduced_size());
enthalpy = 0.0;
@@ -301,21 +312,20 @@ TEST_CASE(
* enthalpy solve.
*/
prepared_hydrostatic_analytic_solve_test_utils::EnthalpyJacobianOperator enthalpyJacobian(
f.enthalpyFes->GetTrueVSize(), preparedOperator
enthalpyMap.reduced_size(), preparedOperator
);
mfem::Vector rightHandSide(initialResidual);
rightHandSide *= -1.0;
mfem::Vector enthalpyCorrection(f.enthalpyFes->GetTrueVSize());
mfem::Vector enthalpyCorrection(enthalpyMap.reduced_size());
enthalpyCorrection = 0.0;
/*
* The operator is positive definite on stellar-supported
* enthalpy DOFs and semidefinite on exterior-only DOFs.
* The RHS is in its range, so MINRES is appropriate for
* the compatible system.
* The reduced operator contains only stellar-supported
* enthalpy DOFs and is positive definite. MINRES remains
* appropriate for this symmetric system.
*/
mfem::MINRESSolver linearSolver(communicator);
@@ -375,7 +385,9 @@ TEST_CASE(
*/
mfem::ParGridFunction solvedEnthalpyField(f.enthalpyFes.get());
solvedEnthalpyField.SetFromTrueDofs(enthalpy);
mfem::Vector enthalpyTrue(enthalpyMap.full_size());
enthalpyMap.scatter(enthalpy, enthalpyTrue);
solvedEnthalpyField.SetFromTrueDofs(enthalpyTrue);
const double solvedAnalyticError =
solvedEnthalpyField.ComputeL2Error(exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
@@ -416,4 +428,4 @@ TEST_CASE(
CHECK(relativeSolvedAnalyticError / relativeProjectionError < 5.0);
}
}
}
}

View File

@@ -51,9 +51,9 @@ namespace prepared_hydrostatic_complete_test_utils {
const double firstPhase,
const double secondPhase
) {
mfem::Vector direction = gravity_prepared_test_utils::make_displacement(f, firstPhase);
mfem::Vector direction = field_dof_test_utils::make_supported_displacement(f, firstPhase);
const mfem::Vector secondField = gravity_prepared_test_utils::make_displacement(f, secondPhase);
const mfem::Vector secondField = field_dof_test_utils::make_supported_displacement(f, secondPhase);
direction -= secondField;
return direction;
@@ -97,14 +97,12 @@ namespace prepared_hydrostatic_complete_test_utils {
mfem::Vector residualPlus;
mfem::Vector residualMinus;
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpyPlus, gravityPotentialPlus, displacementPlus,
bernoulliConstantPlus, residualPlus
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpyPlus, gravityPotentialPlus, displacementPlus, bernoulliConstantPlus, residualPlus
);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpyMinus, gravityPotentialMinus, displacementMinus,
bernoulliConstantMinus, residualMinus
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpyMinus, gravityPotentialMinus, displacementMinus, bernoulliConstantMinus, residualMinus
);
difference = residualPlus;
@@ -131,7 +129,7 @@ namespace prepared_hydrostatic_complete_test_utils {
TEST_CASE(
"Prepared Hydrostatic Complete Jacobian Matches Sum And Centered "
"Differences",
tags::barotrope &tags::hydro &tags::integration &tags::jacobian &tags::prepared &tags::self_consistency
tags::barotrope_hydrostatic_prepared_jacobian &tags::self_consistency
) {
auto args = test_utils::setup_args();
@@ -140,12 +138,16 @@ TEST_CASE(
mean_field::operators::PreparedHydrostaticEquilibriumOperator preparedOperator(f, *f.domainMapperStateless);
const mfem::Vector enthalpy =
gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.34);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, 0.34
);
const mfem::Vector gravityPotential =
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.57);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, 0.57
);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.68);
const mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.68);
constexpr double bernoulliConstant = 0.43;
@@ -159,10 +161,14 @@ TEST_CASE(
);
const mfem::Vector enthalpyVariation =
gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 1.07);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, 1.07
);
const mfem::Vector gravityPotentialVariation =
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 1.31);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, 1.31
);
const mfem::Vector displacementVariation =
prepared_hydrostatic_complete_test_utils::make_displacement_direction(f, 1.19, 0.38);
@@ -221,7 +227,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Hydrostatic MFEM Adapter Uses Four Block Layout And Reuses "
"Preparation",
tags::barotrope &tags::hydro &tags::integration &tags::jacobian &tags::mfem_operators &tags::prepared &tags::unit
tags::barotrope_hydrostatic_prepared_jacobian &tags::mfem_operators &tags::unit
) {
auto args = test_utils::setup_args();
@@ -230,12 +236,16 @@ TEST_CASE(
mean_field::operators::PreparedHydrostaticEquilibriumOperator preparedOperator(f, *f.domainMapperStateless);
const mfem::Vector enthalpy =
gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.41);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, 0.41
);
const mfem::Vector gravityPotential =
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.63);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, 0.63
);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.74);
const mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.74);
constexpr double bernoulliConstant = 0.38;
@@ -255,20 +265,26 @@ TEST_CASE(
CHECK(
layout.Offset(mean_field::operators::HydrostaticJacobianInputBlock::gravityPotential) ==
f.enthalpyFes->GetTrueVSize()
preparedOperator.GetEnthalpyMap().reduced_size()
);
CHECK(layout.Size(mean_field::operators::HydrostaticJacobianInputBlock::bernoulliConstant) == 1);
CHECK(adapter.Width() == layout.GetTotalSize());
CHECK(adapter.Height() == layout.GetResidualSize());
CHECK(adapter.Height() == f.enthalpyFes->GetTrueVSize());
CHECK(adapter.Height() == preparedOperator.GetEnthalpyMap().reduced_size());
CHECK(preparedOperator.GetEnthalpyMap().inactive_size() > 0);
const mfem::Vector enthalpyVariation =
gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 1.12);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, 1.12
);
const mfem::Vector gravityPotentialVariation =
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 1.39);
field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, 1.39
);
const mfem::Vector displacementVariation =
prepared_hydrostatic_complete_test_utils::make_displacement_direction(f, 1.28, 0.49);

View File

@@ -34,14 +34,18 @@ namespace prepared_hydrostatic_displacement_test_utils {
const mean_field::fem::FEM &f,
const double phase = 0.29
) {
return gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), phase);
return field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, phase
);
}
mfem::Vector make_gravity_potential(
const mean_field::fem::FEM &f,
const double phase = 0.47
) {
return gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), phase);
return field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, phase
);
}
mfem::Vector make_displacement_direction(
@@ -49,9 +53,9 @@ namespace prepared_hydrostatic_displacement_test_utils {
const double firstPhase,
const double secondPhase
) {
mfem::Vector direction = gravity_prepared_test_utils::make_displacement(f, firstPhase);
mfem::Vector direction = field_dof_test_utils::make_supported_displacement(f, firstPhase);
const mfem::Vector secondField = gravity_prepared_test_utils::make_displacement(f, secondPhase);
const mfem::Vector secondField = field_dof_test_utils::make_supported_displacement(f, secondPhase);
direction -= secondField;
return direction;
@@ -93,14 +97,12 @@ namespace prepared_hydrostatic_displacement_test_utils {
mfem::Vector residualPlus;
mfem::Vector residualMinus;
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpy, gravityPotential, displacementPlus, bernoulliConstant,
residualPlus
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpy, gravityPotential, displacementPlus, bernoulliConstant, residualPlus
);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpy, gravityPotential, displacementMinus, bernoulliConstant,
residualMinus
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpy, gravityPotential, displacementMinus, bernoulliConstant, residualMinus
);
difference = residualPlus;
@@ -119,7 +121,7 @@ namespace prepared_hydrostatic_displacement_test_utils {
TEST_CASE(
"Prepared Hydrostatic Displacement Jacobian Matches Centered Differences",
tags::barotrope &tags::hydro &tags::jacobian &tags::prepared &tags::unit
tags::barotrope_hydrostatic_prepared_jacobian &tags::unit
) {
auto args = test_utils::setup_args();
@@ -131,7 +133,7 @@ TEST_CASE(
const mfem::Vector gravityPotential = prepared_hydrostatic_displacement_test_utils::make_gravity_potential(f);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.73);
const mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.73);
constexpr double bernoulliConstant = 0.39;
@@ -201,7 +203,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Hydrostatic Displacement Jacobian Reuses And Refreshes Frozen "
"Data",
tags::barotrope &tags::hydro &tags::jacobian &tags::prepared &tags::unit
tags::barotrope_hydrostatic_prepared_jacobian &tags::unit
) {
auto args = test_utils::setup_args();
@@ -213,7 +215,7 @@ TEST_CASE(
const mfem::Vector gravityPotential = prepared_hydrostatic_displacement_test_utils::make_gravity_potential(f, 0.53);
mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.42);
mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.42);
constexpr double bernoulliConstant = 0.36;
@@ -284,7 +286,7 @@ TEST_CASE(
CHECK(rotationReferenceError < 2.0e-7);
CHECK(rotationEffect > 1.0e-8);
displacement = gravity_prepared_test_utils::make_displacement(f, 0.91);
displacement = field_dof_test_utils::make_supported_displacement(f, 0.91);
++dependencies.displacement.revision;

View File

@@ -34,14 +34,18 @@ namespace prepared_hydrostatic_jacobian_test_utils {
const mean_field::fem::FEM &f,
const double phase = 0.23
) {
return gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), phase);
return field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Enthalpy>(
*f.enthalpyFes, phase
);
}
mfem::Vector make_gravity_potential(
const mean_field::fem::FEM &f,
const double phase = 0.41
) {
return gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), phase);
return field_dof_test_utils::make_deterministic_supported_vector<mean_field::field::Gravity>(
*f.gravityPotentialFes, phase
);
}
mean_field::physics::RigidRotation make_rotation(const double scale = 1.0) {
@@ -75,14 +79,12 @@ namespace prepared_hydrostatic_jacobian_test_utils {
mfem::Vector residualPlus;
mfem::Vector residualMinus;
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpyPlus, gravityPotentialPlus, displacement,
bernoulliConstantPlus, residualPlus
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpyPlus, gravityPotentialPlus, displacement, bernoulliConstantPlus, residualPlus
);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpyMinus, gravityPotentialMinus, displacement,
bernoulliConstantMinus, residualMinus
field_dof_test_utils::apply_hydrostatic_reference(
f, rotation, enthalpyMinus, gravityPotentialMinus, displacement, bernoulliConstantMinus, residualMinus
);
// The two states are separated by one complete variation:
@@ -103,7 +105,7 @@ namespace prepared_hydrostatic_jacobian_test_utils {
TEST_CASE(
"Prepared Hydrostatic Algebraic Jacobian Matches Centered Residual "
"Differences",
tags::barotrope &tags::hydro &tags::jacobian &tags::prepared &tags::unit
tags::barotrope_hydrostatic_prepared_jacobian &tags::unit
) {
auto args = test_utils::setup_args();
@@ -115,7 +117,7 @@ TEST_CASE(
const mfem::Vector gravityPotential = prepared_hydrostatic_jacobian_test_utils::make_gravity_potential(f);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.73);
const mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.73);
constexpr double bernoulliConstant = 0.39;
@@ -251,7 +253,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Hydrostatic Algebraic Jacobian Reuses And Rebuilds Only With "
"Geometry",
tags::barotrope &tags::hydro &tags::jacobian &tags::prepared &tags::unit
tags::barotrope_hydrostatic_prepared_jacobian &tags::unit
) {
auto args = test_utils::setup_args();
@@ -263,7 +265,7 @@ TEST_CASE(
mfem::Vector gravityPotential = prepared_hydrostatic_jacobian_test_utils::make_gravity_potential(f);
mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.42);
mfem::Vector displacement = field_dof_test_utils::make_supported_displacement(f, 0.42);
double bernoulliConstant = 0.37;
@@ -340,7 +342,7 @@ TEST_CASE(
CHECK(preparedOperator.GetAlgebraicJacobianStatistics().preparations == 1);
displacement = gravity_prepared_test_utils::make_displacement(f, 0.73);
displacement = field_dof_test_utils::make_supported_displacement(f, 0.73);
++dependencies.displacement.revision;

View File

@@ -26,14 +26,25 @@ namespace mass_normalization_test_utils {
);
[[nodiscard]] mean_field::operators::MassNormalizationLayout make_layout(const mean_field::fem::FEM &f) {
const auto densityMap =
field_dof_test_utils::make_map<mean_field::field::Density>(*f.densityFes);
const auto displacementMap =
field_dof_test_utils::make_map<mean_field::field::Displacement>(*f.displacementFes);
const auto gravityFluxMap =
field_dof_test_utils::make_map<mean_field::field::Gravity>(*f.gravityFluxFes);
const auto gravityPotentialMap =
field_dof_test_utils::make_map<mean_field::field::Gravity>(*f.gravityPotentialFes);
const auto enthalpyMap =
field_dof_test_utils::make_map<mean_field::field::Enthalpy>(*f.enthalpyFes);
const std::array<int, CoupledForm::value_block_count> valueSizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
const std::array<int, CoupledForm::residual_block_count> residualSizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize(), f.densityFes->GetTrueVSize(),
f.displacementFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
return {valueSizes, residualSizes};
@@ -163,10 +174,10 @@ namespace mass_normalization_test_utils {
gravityPotential = 0.0;
context.Prepare(
{.density = density,
.displacement = displacement,
.gravity_gradient = gravityGradient,
.gravity_potential = gravityPotential},
{.density = context.GetDensityMap().gather(density),
.displacement = context.GetDisplacementMap().gather(displacement),
.gravity_gradient = context.GetGravityGradientMap().gather(gravityGradient),
.gravity_potential = context.GetGravityPotentialMap().gather(gravityPotential)},
make_gravity_revisions(dependencies, gravityGradientRevision, gravityPotentialRevision)
);
}
@@ -189,7 +200,7 @@ namespace mass_normalization_test_utils {
TEST_CASE(
"Prepared Mass Normalization Has The Analytic Affine Volume Scaling",
tags::barotrope &tags::prepared &tags::analytic_comparison
tags::barotrope_mass_normalization_analytic
) {
using Operator = mean_field::operators::PreparedMassNormalizationOperator;
@@ -265,7 +276,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Mass Normalization Density Jacobian Matches Centered Difference",
tags::barotrope &tags::prepared &tags::jacobian &tags::accuracy
tags::barotrope_mass_normalization_jacobian &tags::accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
@@ -285,8 +296,10 @@ TEST_CASE(
mean_field::operators::PreparedMassNormalizationOperator massOperator(f, *f.domainMapperStateless, gravityContext);
massOperator.Prepare({.targetMass = 1.23}, dependencies);
const mfem::Vector reducedDensityDirection = gravityContext.GetDensityMap().gather(densityDirection);
mfem::Vector analyticAction;
massOperator.ApplyDensityJacobianAction(densityDirection, analyticAction);
massOperator.ApplyDensityJacobianAction(reducedDensityDirection, analyticAction);
constexpr double epsilon = 1.0e-3;
mfem::Vector densityPlus(density);
@@ -312,7 +325,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Mass Normalization Geometry Jacobian Matches Centered Difference",
tags::barotrope &tags::prepared &tags::jacobian &tags::geometry
tags::barotrope_mass_normalization_jacobian &tags::geometry
) {
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
@@ -332,8 +345,11 @@ TEST_CASE(
mean_field::operators::PreparedMassNormalizationOperator massOperator(f, *f.domainMapperStateless, gravityContext);
massOperator.Prepare({.targetMass = 1.11}, dependencies);
const mfem::Vector reducedDisplacementDirection =
gravityContext.GetDisplacementMap().gather(displacementDirection);
mfem::Vector analyticAction;
massOperator.ApplyDisplacementJacobianAction(displacementDirection, analyticAction);
massOperator.ApplyDisplacementJacobianAction(reducedDisplacementDirection, analyticAction);
constexpr double epsilon = 1.0e-6;
mfem::Vector displacementPlus(displacement);
@@ -359,7 +375,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Mass Normalization Selectively Refreshes Its Cached State",
tags::barotrope &tags::prepared &tags::contexts &tags::integration
tags::barotrope_mass_normalization_context &tags::integration
) {
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
@@ -439,7 +455,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Mass Normalization Complete Action And Coupled Routing Are Exact",
tags::barotrope &tags::prepared &tags::jacobian &tags::mfem_operators
tags::barotrope_mass_normalization_jacobian
) {
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
@@ -460,13 +476,19 @@ TEST_CASE(
mean_field::operators::PreparedMassNormalizationOperator massOperator(f, *f.domainMapperStateless, gravityContext);
massOperator.Prepare({.targetMass = 1.19}, dependencies);
const mfem::Vector reducedDensityDirection = gravityContext.GetDensityMap().gather(densityDirection);
const mfem::Vector reducedDisplacementDirection =
gravityContext.GetDisplacementMap().gather(displacementDirection);
mfem::Vector densityAction;
mfem::Vector displacementAction;
mfem::Vector completeAction;
massOperator.ApplyDensityJacobianAction(densityDirection, densityAction);
massOperator.ApplyDisplacementJacobianAction(displacementDirection, displacementAction);
massOperator.ApplyCompleteJacobianAction(densityDirection, displacementDirection, completeAction);
massOperator.ApplyDensityJacobianAction(reducedDensityDirection, densityAction);
massOperator.ApplyDisplacementJacobianAction(reducedDisplacementDirection, displacementAction);
massOperator.ApplyCompleteJacobianAction(
reducedDensityDirection, reducedDisplacementDirection, completeAction
);
CHECK(
mass_normalization_test_utils::relative_error(completeAction(0), densityAction(0) + displacementAction(0)) <
@@ -476,16 +498,26 @@ TEST_CASE(
const auto layout = mass_normalization_test_utils::make_layout(f);
mean_field::operators::PreparedMassNormalizationJacobianOperator adapter(layout, massOperator);
CHECK(
layout.size(mass_normalization_test_utils::densityValue) ==
gravityContext.GetDensityMap().reduced_size()
);
CHECK(
layout.size(mass_normalization_test_utils::displacementValue) ==
gravityContext.GetDisplacementMap().reduced_size()
);
CHECK(gravityContext.GetDensityMap().inactive_size() > 0);
mfem::Vector direction(layout.value_offsets().Last());
direction = 0.0;
for (int entry = 0; entry < densityDirection.Size(); ++entry) {
direction(layout.offset(mass_normalization_test_utils::densityValue) + entry) = densityDirection(entry);
for (int entry = 0; entry < reducedDensityDirection.Size(); ++entry) {
direction(layout.offset(mass_normalization_test_utils::densityValue) + entry) = reducedDensityDirection(entry);
}
for (int entry = 0; entry < displacementDirection.Size(); ++entry) {
for (int entry = 0; entry < reducedDisplacementDirection.Size(); ++entry) {
direction(layout.offset(mass_normalization_test_utils::displacementValue) + entry) =
displacementDirection(entry);
reducedDisplacementDirection(entry);
}
mfem::Vector coupledAction;
@@ -505,4 +537,4 @@ TEST_CASE(
CHECK(&massOperator.GetFEM() == &f);
CHECK(&massOperator.GetGravityContext() == &gravityContext);
CHECK(adapter.GetLayout().residual_offsets().Last() == layout.residual_offsets().Last());
}
}

View File

@@ -58,14 +58,25 @@ namespace rotational_displacement_force_test_utils {
);
[[nodiscard]] mean_field::operators::RotationalDisplacementForceLayout make_layout(const mean_field::fem::FEM &f) {
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
const auto densityMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(f);
const auto displacementMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Displacement>(f);
const auto gravityFluxMap =
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityFluxFes);
const auto gravityPotentialMap =
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
const auto enthalpyMap =
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy, DomainSchema>(*f.enthalpyFes);
const std::array<int, CoupledForm::value_block_count> valueSizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
const std::array<int, CoupledForm::residual_block_count> residualSizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize(), f.densityFes->GetTrueVSize(),
f.displacementFes->GetTrueVSize(), f.enthalpyFes->GetTrueVSize(), 1
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
};
return {valueSizes, residualSizes};
@@ -275,7 +286,7 @@ namespace rotational_displacement_force_test_utils {
TEST_CASE(
"Rotational Displacement Force Query Includes Density Test And Linear "
"Position",
tags::centrifugal &tags::quadrature &tags::unit
tags::rotation_prepared_unit
) {
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
@@ -300,7 +311,7 @@ TEST_CASE(
TEST_CASE(
"Rotational Displacement Force Uses Negative Rotation-Potential "
"Gradient And Excludes Vacuum",
tags::centrifugal &tags::kernels &tags::integration &tags::accuracy
tags::rotation_kernel_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -368,7 +379,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Rotational Displacement Force Reprepares Selectively",
tags::centrifugal &tags::prepared &tags::integration
tags::rotation_prepared
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -376,9 +387,9 @@ TEST_CASE(
REQUIRE(f.okay());
mfem::Vector density = rotational_displacement_force_test_utils::make_density(f, 0.37);
mfem::Vector densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.37);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.53);
const mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.53);
mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation(0.81);
@@ -386,6 +397,10 @@ TEST_CASE(
mean_field::operators::PreparedRotationalDisplacementForceOperator preparedOperator(f, *f.domainMapperStateless);
const auto &context = preparedOperator.GetContext();
mfem::Vector density = context.GetDensityMap().gather(densityTrue);
const mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
const auto initialReport =
preparedOperator.Prepare({.density = density, .displacement = displacement}, dependencies, rotation);
@@ -400,19 +415,22 @@ TEST_CASE(
preparedOperator.BuildResidual(preparedResidual);
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
f, *f.domainMapperStateless, rotation, density, displacement, kernelResidual
f, *f.domainMapperStateless, rotation, densityTrue, displacementTrue, kernelResidual
);
const mfem::Vector kernelResidualReduced = context.GetDisplacementMap().gather(kernelResidual);
CHECK(
rotational_displacement_force_test_utils::relative_difference(
preparedResidual, kernelResidual, f.mesh->GetComm()
preparedResidual, kernelResidualReduced, f.mesh->GetComm()
) < 2.0e-12
);
CHECK_FALSE(preparedOperator.Prepare({.density = density, .displacement = displacement}, dependencies, rotation)
.DidAnyWork());
density = rotational_displacement_force_test_utils::make_density(f, 0.79);
densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.79);
density = context.GetDensityMap().gather(densityTrue);
++dependencies.density.revision;
@@ -438,7 +456,7 @@ TEST_CASE(
TEST_CASE(
"Rotational Displacement Force Jacobian Matches Both Columns And "
"Centered Differences",
tags::centrifugal &tags::prepared &tags::jacobian &tags::accuracy
tags::rotation_prepared_jacobian_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -446,18 +464,25 @@ TEST_CASE(
REQUIRE(f.okay());
const mfem::Vector density = rotational_displacement_force_test_utils::make_density(f, 0.43);
const mfem::Vector densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.43);
const mfem::Vector densityDirection = rotational_displacement_force_test_utils::make_density_direction(f, 0.59);
const mfem::Vector densityDirectionTrue = rotational_displacement_force_test_utils::make_density_direction(f, 0.59);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.61);
const mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.61);
const mfem::Vector displacementDirection = rotational_displacement_force_test_utils::make_displacement_direction(f);
const mfem::Vector displacementDirectionTrue =
rotational_displacement_force_test_utils::make_displacement_direction(f);
const mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation(0.93);
mean_field::operators::PreparedRotationalDisplacementForceOperator preparedOperator(f, *f.domainMapperStateless);
const auto &context = preparedOperator.GetContext();
const mfem::Vector density = context.GetDensityMap().gather(densityTrue);
const mfem::Vector densityDirection = context.GetDensityMap().gather(densityDirectionTrue);
const mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
const mfem::Vector displacementDirection = context.GetDisplacementMap().gather(displacementDirectionTrue);
preparedOperator.Prepare(
{.density = density, .displacement = displacement},
rotational_displacement_force_test_utils::make_dependencies(), rotation
@@ -482,26 +507,30 @@ TEST_CASE(
) < 2.0e-12
);
mfem::Vector zeroDensity(densityDirection.Size());
mfem::Vector zeroDisplacement(displacementDirection.Size());
zeroDensity = 0.0;
zeroDisplacement = 0.0;
mfem::Vector zeroDensityTrue(densityDirectionTrue.Size());
mfem::Vector zeroDisplacementTrue(displacementDirectionTrue.Size());
zeroDensityTrue = 0.0;
zeroDisplacementTrue = 0.0;
constexpr double step = 1.0e-5;
constexpr double step = 1.0e-5;
const mfem::Vector densityDifference = rotational_displacement_force_test_utils::centered_difference(
f, rotation, density, densityDirection, displacement, zeroDisplacement, step
const mfem::Vector densityDifferenceTrue = rotational_displacement_force_test_utils::centered_difference(
f, rotation, densityTrue, densityDirectionTrue, displacementTrue, zeroDisplacementTrue, step
);
const mfem::Vector displacementDifference = rotational_displacement_force_test_utils::centered_difference(
f, rotation, density, zeroDensity, displacement, displacementDirection, step
const mfem::Vector displacementDifferenceTrue = rotational_displacement_force_test_utils::centered_difference(
f, rotation, densityTrue, zeroDensityTrue, displacementTrue, displacementDirectionTrue, step
);
const mfem::Vector completeDifference = rotational_displacement_force_test_utils::centered_difference(
f, rotation, density, densityDirection, displacement, displacementDirection, step
const mfem::Vector completeDifferenceTrue = rotational_displacement_force_test_utils::centered_difference(
f, rotation, densityTrue, densityDirectionTrue, displacementTrue, displacementDirectionTrue, step
);
const double densityError = rotational_displacement_force_test_utils::relative_difference(
const mfem::Vector densityDifference = context.GetDisplacementMap().gather(densityDifferenceTrue);
const mfem::Vector displacementDifference = context.GetDisplacementMap().gather(displacementDifferenceTrue);
const mfem::Vector completeDifference = context.GetDisplacementMap().gather(completeDifferenceTrue);
const double densityError = rotational_displacement_force_test_utils::relative_difference(
densityAction, densityDifference, f.mesh->GetComm()
);
@@ -524,7 +553,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Rotational Displacement Force MFEM Adapter Routes Only R-d",
tags::centrifugal &tags::prepared &tags::mfem_operators &tags::unit
tags::rotation_prepared_unit
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -532,18 +561,25 @@ TEST_CASE(
REQUIRE(f.okay());
const mfem::Vector density = rotational_displacement_force_test_utils::make_density(f, 0.47);
const mfem::Vector densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.47);
const mfem::Vector densityDirection = rotational_displacement_force_test_utils::make_density_direction(f, 0.63);
const mfem::Vector densityDirectionTrue = rotational_displacement_force_test_utils::make_density_direction(f, 0.63);
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.57);
const mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.57);
const mfem::Vector displacementDirection = rotational_displacement_force_test_utils::make_displacement_direction(f);
const mfem::Vector displacementDirectionTrue =
rotational_displacement_force_test_utils::make_displacement_direction(f);
const mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation(0.87);
mean_field::operators::PreparedRotationalDisplacementForceOperator preparedOperator(f, *f.domainMapperStateless);
const auto &context = preparedOperator.GetContext();
const mfem::Vector density = context.GetDensityMap().gather(densityTrue);
const mfem::Vector densityDirection = context.GetDensityMap().gather(densityDirectionTrue);
const mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
const mfem::Vector displacementDirection = context.GetDisplacementMap().gather(displacementDirectionTrue);
preparedOperator.Prepare(
{.density = density, .displacement = displacement},
rotational_displacement_force_test_utils::make_dependencies(), rotation

View File

@@ -152,7 +152,7 @@ namespace rotational_displacement_force_affine_deformation_test_utils {
TEST_CASE(
"Rotational Displacement Force Matches A Nontrivially Deformed "
"Homogeneous Ellipsoid",
tags::centrifugal &tags::analytic_comparison &tags::accuracy &tags::geometry
tags::rotation_analytic_accuracy_geometry
) {
mean_field::utils::Args args = test_utils::setup_args();

View File

@@ -67,7 +67,7 @@ namespace rotational_displacement_force_analytic_test_utils {
TEST_CASE(
"Rigid Rotation Gradient And Hessian Action Match The Analytic "
"Potential",
tags::centrifugal &tags::unit &tags::accuracy
tags::rotation_analytic_unit
) {
mfem::Vector angularVelocity(3);
angularVelocity(0) = 0.23;
@@ -130,7 +130,7 @@ TEST_CASE(
TEST_CASE(
"Rotational Displacement Force Reproduces The Homogeneous Sphere "
"Rotational Virial",
tags::centrifugal &tags::analytic_comparison &tags::accuracy
tags::rotation_analytic_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();
@@ -187,7 +187,7 @@ TEST_CASE(
TEST_CASE(
"Rotational Displacement Force Matches The Analytic Off-Axis "
"Resultant",
tags::centrifugal &tags::analytic_comparison &tags::accuracy
tags::rotation_analytic_accuracy
) {
mean_field::utils::Args args = test_utils::setup_args();

View File

@@ -153,23 +153,16 @@ namespace stellar_equilibrium_test_utils {
return map.gather(fullEnthalpy);
}
[[nodiscard]] mfem::Vector pack_full_gravity_state(
const mean_field::fem::FEM &f,
const mfem::Vector &fullDensity,
[[nodiscard]] mfem::Vector pack_gravity_state(
const mfem::Vector &density,
const mfem::Vector &displacement,
const mfem::Vector &gravityGradient,
const mfem::Vector &gravityPotential
) {
const std::array<int, 4> blockSizes{
f.densityFes->GetTrueVSize(), f.displacementFes->GetTrueVSize(), f.gravityFluxFes->GetTrueVSize(),
f.gravityPotentialFes->GetTrueVSize()
density.Size(), displacement.Size(), gravityGradient.Size(), gravityPotential.Size()
};
MFEM_VERIFY(fullDensity.Size() == blockSizes[0], "Full density has the wrong gravity-state size.");
MFEM_VERIFY(displacement.Size() == blockSizes[1], "Displacement has the wrong gravity-state size.");
MFEM_VERIFY(gravityGradient.Size() == blockSizes[2], "Gravity gradient has the wrong gravity-state size.");
MFEM_VERIFY(gravityPotential.Size() == blockSizes[3], "Gravity potential has the wrong gravity-state size.");
const std::array<int, 5> offsets{
0, blockSizes[0], blockSizes[0] + blockSizes[1], blockSizes[0] + blockSizes[1] + blockSizes[2],
blockSizes[0] + blockSizes[1] + blockSizes[2] + blockSizes[3]
@@ -178,7 +171,7 @@ namespace stellar_equilibrium_test_utils {
mfem::Vector packed(offsets[4]);
const std::array<const mfem::Vector *, 4> blocks{
&fullDensity, &displacement, &gravityGradient, &gravityPotential
&density, &displacement, &gravityGradient, &gravityPotential
};
for (int block = 0; block < 4; ++block) {
@@ -494,27 +487,24 @@ namespace stellar_equilibrium_test_utils {
const mfem::Vector &state
) {
const mean_field::operators::StellarEquilibriumLayout &layout = stellarOperator.GetLayout();
const FieldMaps maps(f);
const mfem::Vector reducedDensity = const_value_view(state, layout, densityValue);
const mfem::Vector displacement = const_value_view(state, layout, displacementValue);
const mfem::Vector gravityGradient = const_value_view(state, layout, gravityGradientValue);
const mfem::Vector gravityPotential = const_value_view(state, layout, gravityPotentialValue);
const mfem::Vector fullDensity = maps.density.scatter(reducedDensity);
const mfem::Vector gravityState =
pack_full_gravity_state(f, fullDensity, displacement, gravityGradient, gravityPotential);
pack_gravity_state(reducedDensity, displacement, gravityGradient, gravityPotential);
mfem::Vector gravity;
mfem::Vector closure;
mfem::Vector displacementResidualValue;
mfem::Vector fullHydrostatic;
mfem::Vector hydrostatic;
mfem::Vector mass;
stellarOperator.GetGravityOperator().Mult(gravityState, gravity);
stellarOperator.GetBarotropicClosureOperator().BuildResidual(closure);
stellarOperator.GetDisplacementOperator().BuildResidual(displacementResidualValue);
stellarOperator.GetHydrostaticOperator().BuildResidual(fullHydrostatic);
stellarOperator.GetHydrostaticOperator().BuildResidual(hydrostatic);
stellarOperator.GetMassNormalizationOperator().BuildResidual(mass);
mfem::Vector result(layout.residual_offsets().Last());
@@ -537,10 +527,7 @@ namespace stellar_equilibrium_test_utils {
residual_view(result, layout, displacementResidual) = displacementResidualValue;
{
mfem::Vector reducedHydrostatic = residual_view(result, layout, enthalpyResidual);
maps.enthalpy.gather(fullHydrostatic, reducedHydrostatic);
}
residual_view(result, layout, enthalpyResidual) = hydrostatic;
residual_view(result, layout, massResidual) = mass;
@@ -549,11 +536,9 @@ namespace stellar_equilibrium_test_utils {
[[nodiscard]] mfem::Vector explicit_jacobian_action(
const mean_field::operators::PreparedStellarEquilibriumOperator &stellarOperator,
const mean_field::fem::FEM &f,
const mfem::Vector &direction
) {
const mean_field::operators::StellarEquilibriumLayout &layout = stellarOperator.GetLayout();
const FieldMaps maps(f);
const mfem::Vector reducedDensityDirection = const_value_view(direction, layout, densityValue);
const mfem::Vector displacementDirection = const_value_view(direction, layout, displacementValue);
@@ -562,17 +547,14 @@ namespace stellar_equilibrium_test_utils {
const mfem::Vector reducedEnthalpyDirection = const_value_view(direction, layout, enthalpyValue);
const mfem::Vector bernoulliDirection = const_value_view(direction, layout, bernoulliValue);
const mfem::Vector fullDensityDirection = maps.density.scatter(reducedDensityDirection);
const mfem::Vector fullEnthalpyDirection = maps.enthalpy.scatter(reducedEnthalpyDirection);
const mfem::Vector gravityDirection = pack_full_gravity_state(
f, fullDensityDirection, displacementDirection, gravityGradientDirection, gravityPotentialDirection
const mfem::Vector gravityDirection = pack_gravity_state(
reducedDensityDirection, displacementDirection, gravityGradientDirection, gravityPotentialDirection
);
mfem::Vector gravityAction;
mfem::Vector closureAction;
mfem::Vector displacementAction;
mfem::Vector fullHydrostaticAction;
mfem::Vector hydrostaticAction;
mfem::Vector massAction;
stellarOperator.GetGravityJacobianOperator().Mult(gravityDirection, gravityAction);
@@ -582,17 +564,17 @@ namespace stellar_equilibrium_test_utils {
);
stellarOperator.GetDisplacementOperator().ApplyCompleteJacobianAction(
fullDensityDirection, displacementDirection, gravityGradientDirection, fullEnthalpyDirection,
reducedDensityDirection, displacementDirection, gravityGradientDirection, reducedEnthalpyDirection,
displacementAction
);
stellarOperator.GetHydrostaticOperator().ApplyCompleteJacobianAction(
fullEnthalpyDirection, gravityPotentialDirection, bernoulliDirection(0), displacementDirection,
fullHydrostaticAction
reducedEnthalpyDirection, gravityPotentialDirection, bernoulliDirection(0), displacementDirection,
hydrostaticAction
);
stellarOperator.GetMassNormalizationOperator().ApplyCompleteJacobianAction(
fullDensityDirection, displacementDirection, massAction
reducedDensityDirection, displacementDirection, massAction
);
mfem::Vector result(layout.residual_offsets().Last());
@@ -615,10 +597,7 @@ namespace stellar_equilibrium_test_utils {
residual_view(result, layout, displacementResidual) = displacementAction;
{
mfem::Vector reducedHydrostaticAction = residual_view(result, layout, enthalpyResidual);
maps.enthalpy.gather(fullHydrostaticAction, reducedHydrostaticAction);
}
residual_view(result, layout, enthalpyResidual) = hydrostaticAction;
residual_view(result, layout, massResidual) = massAction;
@@ -719,7 +698,7 @@ TEST_CASE(
TEST_CASE(
"Prepared Stellar Equilibrium Jacobian Is The Exact Restricted Full Child Jacobian",
tags::barotrope &tags::prepared &tags::field &tags::jacobian &tags::integration &tags::accuracy
tags::barotrope_prepared_jacobian_accuracy &tags::field
) {
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
@@ -742,7 +721,7 @@ TEST_CASE(
stellarOperator.Mult(direction, rootAction);
const mfem::Vector explicitAction =
stellar_equilibrium_test_utils::explicit_jacobian_action(stellarOperator, f, direction);
stellar_equilibrium_test_utils::explicit_jacobian_action(stellarOperator, direction);
const double difference =
stellar_equilibrium_test_utils::relative_difference(rootAction, explicitAction, f.mesh->GetComm());

View File

@@ -1077,7 +1077,7 @@ namespace {
TEST_CASE(
"Uniform Potential Matches Analytic",
tags::gravity &tags::analytic_comparison &tags::initialization
tags::gravity_analytic_initialization
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1161,7 +1161,7 @@ TEST_CASE(
TEST_CASE(
"Parabolic Density Virial Self-Consistency",
tags::gravity &tags::analytic_comparison &tags::initialization
tags::gravity_analytic_initialization
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1218,7 +1218,7 @@ TEST_CASE(
TEST_CASE(
"Rational Density Virial Self-Consistency",
tags::gravity &tags::self_consistency &tags::initialization
tags::gravity_consistency_initialization
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1278,7 +1278,7 @@ TEST_CASE(
TEST_CASE(
"Homogeneous Ellipsoid Analytic Gravity",
tags::gravity &tags::analytic_comparison &tags::initialization
tags::gravity_analytic_initialization
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1482,7 +1482,7 @@ TEST_CASE(
TEST_CASE(
"Deformed Rational Density Virial Self-Consistency",
tags::gravity &tags::self_consistency &tags::initialization
tags::gravity_consistency_initialization
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
@@ -1565,7 +1565,7 @@ TEST_CASE(
TEST_CASE(
"New Gravity Potential Matches Uniform Sphere Analytic",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration
tags::gravity_analytic
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -1675,7 +1675,7 @@ TEST_CASE(
TEST_CASE(
"New Gravity Potential Matches Legacy Solver On Homogeneous Ellipsoid",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration &tags::legacy_comparison
tags::gravity_legacy
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -1739,13 +1739,22 @@ TEST_CASE(
constexpr auto gravity_poisson_residual_block =
utils::blocks::get_residual_block<gravity_form>(utils::blocks::gravity_field.poisson_term);
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
const field::FieldDofMap density_map = field::make_field_dof_map<field::Density, DomainSchema>(*f.densityFes);
const field::FieldDofMap displacement_map =
field::make_field_dof_map<field::Displacement, DomainSchema>(*f.displacementFes);
const field::FieldDofMap gravity_flux_map =
field::make_field_dof_map<field::Gravity, DomainSchema>(*f.gravityFluxFes);
const field::FieldDofMap gravity_potential_map =
field::make_field_dof_map<field::Gravity, DomainSchema>(*f.gravityPotentialFes);
const std::array<int, gravity_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(), gravity_flux_map.reduced_size(),
gravity_potential_map.reduced_size()
};
const std::array<int, gravity_form::residual_block_count> residual_sizes{
f.gravityFluxFes->GetTrueVSize(), f.gravityPotentialFes->GetTrueVSize()
gravity_flux_map.reduced_size(), gravity_potential_map.reduced_size()
};
const utils::blocks::form_layout<gravity_form> gravity_layout(value_sizes, residual_sizes);
@@ -1760,6 +1769,8 @@ TEST_CASE(
REQUIRE(density_true.Size() == f.densityFes->GetTrueVSize());
REQUIRE(displacement_true.Size() == f.displacementFes->GetTrueVSize());
const mfem::Vector reduced_density = density_map.gather(density_true);
const mfem::Vector reduced_displacement = displacement_map.gather(displacement_true);
operators::context::gravity_field::GravityFieldLinearizationContext residual_linearization_context(
f, *f.domainMapperStateless
@@ -1779,24 +1790,24 @@ TEST_CASE(
);
operators::ReducedGravityFieldOperator new_reduced_operator(
residual_gravity_operator, residual_geometry_context, displacement_true
residual_gravity_operator, residual_geometry_context, reduced_displacement
);
REQUIRE(new_reduced_operator.Width() == gravity_system_size);
REQUIRE(new_reduced_operator.Height() == gravity_system_size);
mfem::Vector new_right_hand_side;
new_reduced_operator.BuildRightHandSide(density_true, new_right_hand_side);
new_reduced_operator.BuildRightHandSide(reduced_density, new_right_hand_side);
REQUIRE(new_right_hand_side.Size() == gravity_system_size);
REQUIRE(f.gravityContext.source_form->Width() == density_true.Size());
REQUIRE(f.gravityContext.source_form->Width() == reduced_density.Size());
REQUIRE(f.gravityContext.source_form->Height() == gravity_poisson_size);
mfem::Vector legacy_source_action(f.gravityContext.source_form->Height());
legacy_source_action = 0.0;
f.gravityContext.source_form->Mult(density_true, legacy_source_action);
f.gravityContext.source_form->Mult(reduced_density, legacy_source_action);
REQUIRE(legacy_source_action.Size() == gravity_poisson_size);
@@ -2057,7 +2068,7 @@ TEST_CASE(
TEST_CASE(
"New Gravity Potential Deformed Rational Density Virial Self-Consistency",
tags::gravity &tags::self_consistency &tags::initialization &tags::integration
tags::gravity_consistency
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -2183,7 +2194,7 @@ TEST_CASE(
TEST_CASE(
"New Gravity Potential Resolves Exterior Monopole By Compactification "
"Shell",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration
tags::gravity_analytic
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -2305,7 +2316,7 @@ TEST_CASE(
TEST_CASE(
"New Exterior Monopole Error Is Separated From Finite Element Projection "
"Floor",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration &tags::accuracy
tags::gravity_analytic_accuracy
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -2466,7 +2477,7 @@ TEST_CASE(
TEST_CASE(
"New Gravity Potential Matches Analytic Interior Potential For A Deformed "
"Homogeneous Star",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration &tags::accuracy
tags::gravity_analytic_accuracy
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -2807,7 +2818,7 @@ static void evaluate_ferrers_n1_gradient(
TEST_CASE(
"New Gravity Potential Matches Analytic Ferrers Ellipsoid",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration &tags::accuracy
tags::gravity_analytic_accuracy
) {
auto args = test_utils::setup_args();

View File

@@ -458,9 +458,10 @@ namespace {
const mfem::Vector projection_rhs = assemble_monopole_projection_rhs(f, displacement, mass, stellar_radius);
mean_field::operators::PreparedMappedHDivMassOperator mass_operator(f, *f.domainMapperStateless);
mass_operator.Prepare(displacement_true);
mass_operator.Prepare(mass_operator.GetDisplacementMap().gather(displacement_true));
const mfem::Vector reduced_projection_rhs = mass_operator.GetFluxMap().gather(projection_rhs);
mfem::Vector projected_gradient(f.gravityFluxFes->GetTrueVSize());
mfem::Vector projected_gradient(mass_operator.Width());
projected_gradient = 0.0;
mfem::CGSolver solver(f.gravityFluxFes->GetComm());
@@ -469,13 +470,13 @@ namespace {
solver.SetAbsTol(1.0e-12);
solver.SetMaxIter(2000);
solver.SetPrintLevel(0);
solver.Mult(projection_rhs, projected_gradient);
solver.Mult(reduced_projection_rhs, projected_gradient);
mfem::Vector projection_residual;
mass_operator.Mult(projected_gradient, projection_residual);
projection_residual -= projection_rhs;
projection_residual -= reduced_projection_rhs;
const double source_norm = global_norm(projection_rhs, f.gravityFluxFes->GetComm());
const double source_norm = global_norm(reduced_projection_rhs, f.gravityFluxFes->GetComm());
const double residual_norm = global_norm(projection_residual, f.gravityFluxFes->GetComm());
const double relative_residual = residual_norm / std::max(source_norm, std::numeric_limits<double>::epsilon());
@@ -487,7 +488,7 @@ namespace {
REQUIRE(std::isfinite(relative_residual));
REQUIRE(relative_residual < 1.0e-8);
return projected_gradient;
return mass_operator.GetFluxMap().scatter(projected_gradient);
}
double mapped_hdiv_relative_error(
@@ -502,7 +503,7 @@ namespace {
displacement.GetTrueDofs(displacement_true);
mean_field::operators::PreparedMappedHDivMassOperator mass_operator(f, *f.domainMapperStateless);
mass_operator.Prepare(displacement_true);
mass_operator.Prepare(mass_operator.GetDisplacementMap().gather(displacement_true));
mfem::Vector difference(computed);
difference -= reference;
@@ -510,13 +511,15 @@ namespace {
mfem::Vector difference_action;
mfem::Vector reference_action;
mass_operator.Mult(difference, difference_action);
mass_operator.Mult(reference, reference_action);
const mfem::Vector reduced_difference = mass_operator.GetFluxMap().gather(difference);
const mfem::Vector reduced_reference = mass_operator.GetFluxMap().gather(reference);
mass_operator.Mult(reduced_difference, difference_action);
mass_operator.Mult(reduced_reference, reference_action);
MPI_Comm communicator = f.gravityFluxFes->GetComm();
const double difference_energy = global_dot(difference, difference_action, communicator);
const double reference_energy = global_dot(reference, reference_action, communicator);
const double difference_energy = global_dot(reduced_difference, difference_action, communicator);
const double reference_energy = global_dot(reduced_reference, reference_action, communicator);
REQUIRE(difference_energy >= -1.0e-12 * std::abs(reference_energy));
REQUIRE(reference_energy > 0.0);
@@ -853,7 +856,7 @@ namespace {
TEST_CASE(
"New Gravity Monopole Accuracy And Projection Floor",
tags::gravity &tags::analytic_comparison &tags::initialization &tags::integration &tags::accuracy
tags::gravity_analytic_accuracy
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;
@@ -1022,7 +1025,7 @@ TEST_CASE(
TEST_CASE(
"New Gravity Virial Consistency Across Volume Preserving Deformation",
tags::gravity &tags::self_consistency &tags::initialization &tags::integration &tags::accuracy
tags::gravity_consistency &tags::accuracy
) {
auto args = test_utils::setup_args();
args.p.rtol = 1.0e-13;

View File

@@ -2,6 +2,7 @@ module;
#include <algorithm>
#include <array>
#include <catch2/internal/catch_stringref.hpp>
#include <concepts>
#include <string>
#include <mfem.hpp>
@@ -86,6 +87,27 @@ export namespace test_utils {
} // namespace test_utils
export namespace gravity_prepared_test_utils {
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
template <typename FieldT> inline mean_field::field::FieldDofMap make_field_map(const mean_field::fem::FEM &f) {
if constexpr (std::same_as<FieldT, mean_field::field::Density>) {
return mean_field::field::make_field_dof_map<FieldT, DomainSchema>(*f.densityFes);
} else if constexpr (std::same_as<FieldT, mean_field::field::Displacement>) {
return mean_field::field::make_field_dof_map<FieldT, DomainSchema>(*f.displacementFes);
} else {
static_assert(std::same_as<FieldT, mean_field::field::Gravity>);
return mean_field::field::make_field_dof_map<FieldT, DomainSchema>(*f.gravityFluxFes);
}
}
template <typename FieldT>
inline mfem::Vector gather_field(
const mean_field::fem::FEM &f,
const mfem::Vector &true_vector
) {
return make_field_map<FieldT>(f).gather(true_vector);
}
inline mfem::Vector make_deterministic_vector(
const int size,
const double phase = 0.0
@@ -207,59 +229,193 @@ export namespace gravity_prepared_test_utils {
}
} // namespace gravity_prepared_test_utils
export namespace field_dof_test_utils {
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
template <typename FieldT>
inline mean_field::field::FieldDofMap make_map(const mfem::ParFiniteElementSpace &finiteElementSpace) {
return mean_field::field::make_field_dof_map<FieldT, DomainSchema>(finiteElementSpace);
}
template <typename FieldT>
inline mfem::Vector make_deterministic_supported_vector(
const mfem::ParFiniteElementSpace &finiteElementSpace,
const double phase
) {
const mean_field::field::FieldDofMap map = make_map<FieldT>(finiteElementSpace);
const mfem::Vector full =
gravity_prepared_test_utils::make_deterministic_vector(map.full_size(), phase);
return map.gather(full);
}
inline mfem::Vector make_supported_displacement(
const mean_field::fem::FEM &f,
const double phase
) {
const mean_field::field::FieldDofMap map =
make_map<mean_field::field::Displacement>(*f.displacementFes);
return map.gather(gravity_prepared_test_utils::make_displacement(f, phase));
}
inline void apply_hydrostatic_reference(
const mean_field::fem::FEM &f,
const mean_field::physics::RigidRotation &rotation,
const mfem::Vector &enthalpy,
const mfem::Vector &gravityPotential,
const mfem::Vector &displacement,
const double bernoulliConstant,
mfem::Vector &residual
) {
const mean_field::field::FieldDofMap enthalpyMap =
make_map<mean_field::field::Enthalpy>(*f.enthalpyFes);
const mean_field::field::FieldDofMap gravityPotentialMap =
make_map<mean_field::field::Gravity>(*f.gravityPotentialFes);
const mean_field::field::FieldDofMap displacementMap =
make_map<mean_field::field::Displacement>(*f.displacementFes);
mfem::Vector enthalpyTrue(enthalpyMap.full_size());
mfem::Vector gravityPotentialTrue(gravityPotentialMap.full_size());
mfem::Vector displacementTrue(displacementMap.full_size());
mfem::Vector residualTrue;
enthalpyMap.scatter(enthalpy, enthalpyTrue);
gravityPotentialMap.scatter(gravityPotential, gravityPotentialTrue);
displacementMap.scatter(displacement, displacementTrue);
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
f, *f.domainMapperStateless, rotation, enthalpyTrue, gravityPotentialTrue, displacementTrue,
bernoulliConstant, residualTrue
);
residual.SetSize(enthalpyMap.reduced_size());
enthalpyMap.gather(residualTrue, residual);
}
} // namespace field_dof_test_utils
export namespace tags {
inline constexpr auto geometry = make_tag("geometry");
inline constexpr auto physics = make_tag("physics");
inline constexpr auto unit = make_tag("unit");
inline constexpr auto mesh = make_tag("mesh");
inline constexpr auto integration = make_tag("integration");
inline constexpr auto solver = make_tag("solver");
inline constexpr auto integrator = make_tag("integrator");
inline constexpr auto mapping = make_tag("mapping");
inline constexpr auto utils = make_tag("utils");
inline constexpr auto mfem_operators = make_tag("operators");
inline constexpr auto initialization = make_tag("initialization");
inline constexpr auto accuracy = make_tag("accuracy");
inline constexpr auto closure = make_tag("closure");
inline constexpr auto kernels = make_tag("kernels");
inline constexpr auto surface = make_tag("surface");
inline constexpr auto model = make_tag("model");
inline constexpr auto geometry = make_tag("geometry");
inline constexpr auto physics = make_tag("physics");
inline constexpr auto unit = make_tag("unit");
inline constexpr auto mesh = make_tag("mesh");
inline constexpr auto integration = make_tag("integration");
inline constexpr auto solver = make_tag("solver");
inline constexpr auto integrator = make_tag("integrator");
inline constexpr auto mapping = make_tag("mapping");
inline constexpr auto utils = make_tag("utils");
inline constexpr auto mfem_operators = make_tag("operators");
inline constexpr auto initialization = make_tag("initialization");
inline constexpr auto accuracy = make_tag("accuracy");
inline constexpr auto closure = make_tag("closure");
inline constexpr auto kernels = make_tag("kernels");
inline constexpr auto surface = make_tag("surface");
inline constexpr auto model = make_tag("model");
inline constexpr auto field = sub_tag(mesh & physics, "field");
inline constexpr auto field = sub_tag(mesh & physics, "field");
inline constexpr auto legacy_comparison = make_tag("legacy_comparison");
inline constexpr auto pressure = sub_tag(physics, "pressure");
inline constexpr auto legacy_comparison = make_tag("legacy_comparison");
inline constexpr auto pressure = sub_tag(physics, "pressure");
inline constexpr auto hydro = sub_tag(physics, "hydro");
inline constexpr auto jacobian = sub_tag(integration & physics, "jacobian");
inline constexpr auto residuals = sub_tag(integration & physics, "residuals");
inline constexpr auto volume = sub_tag(mesh & geometry, "volume");
inline constexpr auto quadrature = sub_tag(mesh & geometry & solver, "quadrature");
inline constexpr auto convergence = sub_tag(solver, "convergence");
inline constexpr auto transformations = sub_tag(mesh & geometry, "transformations");
inline constexpr auto hydro = sub_tag(physics, "hydro");
inline constexpr auto jacobian = sub_tag(integration & physics, "jacobian");
inline constexpr auto residuals = sub_tag(integration & physics, "residuals");
inline constexpr auto volume = sub_tag(mesh & geometry, "volume");
inline constexpr auto quadrature = sub_tag(mesh & geometry & solver, "quadrature");
inline constexpr auto convergence = sub_tag(solver, "convergence");
inline constexpr auto transformations = sub_tag(mesh & geometry, "transformations");
inline constexpr auto h_refinement = sub_tag(mesh & convergence, "h_refinement");
inline constexpr auto p_refinement = sub_tag(mesh & convergence, "p_refinement");
inline constexpr auto h_refinement = sub_tag(mesh & convergence, "h_refinement");
inline constexpr auto p_refinement = sub_tag(mesh & convergence, "p_refinement");
inline constexpr auto analytic_comparison = sub_tag(solver & physics & residuals, "analytic_comparison");
inline constexpr auto self_consistency = sub_tag(solver & physics, "self_consistency");
inline constexpr auto analytic_comparison = sub_tag(solver & physics & residuals, "analytic_comparison");
inline constexpr auto self_consistency = sub_tag(solver & physics, "self_consistency");
inline constexpr auto centrifugal = sub_tag(solver & physics, "centrifugal");
inline constexpr auto advection = sub_tag(solver & physics, "advection");
inline constexpr auto coriolis = sub_tag(solver & physics, "coriolis");
inline constexpr auto gravity = sub_tag(solver & physics, "gravity");
inline constexpr auto enthalpy = sub_tag(solver & physics, "enthalpy");
inline constexpr auto barotrope = sub_tag(physics, "barotrope");
inline constexpr auto mass_continuity = sub_tag(solver & physics, "mass_continuity");
inline constexpr auto pressure_gradient = sub_tag(solver & physics, "pressure_gradient");
inline constexpr auto viscosity = sub_tag(solver & physics, "viscosity");
inline constexpr auto centrifugal = sub_tag(solver & physics, "centrifugal");
inline constexpr auto advection = sub_tag(solver & physics, "advection");
inline constexpr auto coriolis = sub_tag(solver & physics, "coriolis");
inline constexpr auto gravity = sub_tag(solver & physics, "gravity");
inline constexpr auto enthalpy = sub_tag(solver & physics, "enthalpy");
inline constexpr auto barotrope = sub_tag(physics, "barotrope");
inline constexpr auto mass_continuity = sub_tag(solver & physics, "mass_continuity");
inline constexpr auto pressure_gradient = sub_tag(solver & physics, "pressure_gradient");
inline constexpr auto viscosity = sub_tag(solver & physics, "viscosity");
inline constexpr auto compactification = sub_tag(mesh & mapping, "compactification");
inline constexpr auto kelvin = sub_tag(compactification, "kelvin");
inline constexpr auto compactification = sub_tag(mesh & mapping, "compactification");
inline constexpr auto kelvin = sub_tag(compactification, "kelvin");
inline constexpr auto prepared = sub_tag(solver & physics, "prepared");
inline constexpr auto contexts = sub_tag(solver, "contexts");
inline constexpr auto prepared = sub_tag(solver & physics, "prepared");
inline constexpr auto contexts = sub_tag(solver, "contexts");
inline constexpr auto domain = sub_tag(mesh, "domain");
inline constexpr auto domain = sub_tag(mesh, "domain");
// Canonical gravity-suite tags. These intentionally compose leaf tags
// exactly once so Catch2 output remains useful and free of repeated
// [solver]/[physics] entries inherited from older composite tags.
inline constexpr auto gravity_unit = gravity & unit;
inline constexpr auto gravity_integration = gravity & integration;
inline constexpr auto gravity_operator = gravity & mfem_operators;
inline constexpr auto gravity_prepared = gravity & make_tag("prepared");
inline constexpr auto gravity_context = gravity & make_tag("context");
inline constexpr auto gravity_kernel = gravity & kernels;
inline constexpr auto gravity_accuracy = gravity & accuracy;
inline constexpr auto gravity_legacy = gravity & legacy_comparison;
inline constexpr auto gravity_operator_unit = gravity_operator & unit;
inline constexpr auto gravity_operator_integration = gravity_operator & integration;
inline constexpr auto gravity_operator_convergence = gravity_operator & integration & make_tag("convergence");
inline constexpr auto gravity_analytic = gravity & integration & make_tag("analytic_comparison");
inline constexpr auto gravity_consistency = gravity & integration & make_tag("self_consistency");
inline constexpr auto gravity_prepared_jacobian = gravity_prepared & integration & make_tag("jacobian");
inline constexpr auto gravity_prepared_unit = gravity_prepared & unit;
inline constexpr auto gravity_prepared_jacobian_accuracy = gravity_prepared_jacobian & accuracy;
inline constexpr auto gravity_kernel_accuracy = gravity_kernel & accuracy;
inline constexpr auto gravity_kernel_integration = gravity_kernel & integration;
inline constexpr auto gravity_kernel_convergence = gravity_kernel & integration & make_tag("convergence");
inline constexpr auto gravity_analytic_accuracy = gravity_analytic & accuracy;
inline constexpr auto gravity_analytic_initialization = gravity_analytic & initialization;
inline constexpr auto gravity_consistency_initialization = gravity_consistency & initialization;
inline constexpr auto barotrope_prepared = barotrope & solver & make_tag("prepared");
inline constexpr auto barotrope_prepared_jacobian = barotrope_prepared & integration & make_tag("jacobian");
inline constexpr auto barotrope_context = barotrope & solver & make_tag("context");
inline constexpr auto barotrope_context_integration = barotrope_context & integration;
inline constexpr auto barotrope_prepared_analytic =
barotrope_prepared & integration & make_tag("analytic_comparison");
inline constexpr auto barotrope_prepared_jacobian_accuracy = barotrope_prepared_jacobian & accuracy;
inline constexpr auto barotrope_prepared_jacobian_geometry = barotrope_prepared_jacobian & geometry;
inline constexpr auto barotrope_prepared_jacobian_unit = barotrope_prepared_jacobian & unit;
// Canonical hydrostatic-suite tags. The leaf tags are composed directly
// so inherited [physics]/[solver] tags appear only once.
inline constexpr auto barotrope_hydrostatic = barotrope & solver & make_tag("hydro");
inline constexpr auto barotrope_hydrostatic_context = barotrope_hydrostatic & make_tag("context");
inline constexpr auto barotrope_hydrostatic_prepared = barotrope_hydrostatic & make_tag("prepared");
inline constexpr auto barotrope_hydrostatic_prepared_residual =
barotrope_hydrostatic_prepared & integration & make_tag("residual");
inline constexpr auto barotrope_hydrostatic_prepared_jacobian =
barotrope_hydrostatic_prepared & integration & make_tag("jacobian");
inline constexpr auto barotrope_hydrostatic_prepared_analytic =
barotrope_hydrostatic_prepared & integration & make_tag("analytic_comparison");
inline constexpr auto barotrope_mass_normalization =
barotrope & solver & make_tag("mass_normalization");
inline constexpr auto barotrope_mass_normalization_context =
barotrope_mass_normalization & make_tag("context");
inline constexpr auto barotrope_mass_normalization_prepared =
barotrope_mass_normalization & make_tag("prepared");
inline constexpr auto barotrope_mass_normalization_jacobian =
barotrope_mass_normalization_prepared & integration & make_tag("jacobian");
inline constexpr auto barotrope_mass_normalization_analytic =
barotrope_mass_normalization_prepared & integration & make_tag("analytic_comparison");
inline constexpr auto rotation_prepared = centrifugal & make_tag("prepared");
inline constexpr auto rotation_context = centrifugal & make_tag("context");
inline constexpr auto rotation_analytic = centrifugal & integration & make_tag("analytic_comparison");
inline constexpr auto rotation_context_unit = rotation_context & unit;
inline constexpr auto rotation_prepared_unit = rotation_prepared & unit;
inline constexpr auto rotation_prepared_jacobian = rotation_prepared & integration & make_tag("jacobian");
inline constexpr auto rotation_prepared_jacobian_accuracy = rotation_prepared_jacobian & accuracy;
inline constexpr auto rotation_kernel_accuracy = centrifugal & kernels & accuracy;
inline constexpr auto rotation_analytic_unit = rotation_analytic & unit;
inline constexpr auto rotation_analytic_accuracy = rotation_analytic & accuracy;
inline constexpr auto rotation_analytic_accuracy_geometry = rotation_analytic_accuracy & geometry;
} // namespace tags