Files
MeanField/tests/operators/contexts/barotropic_closure_linearization_context.cpp

297 lines
9.2 KiB
C++

#include <cstdint>
#include <catch2/catch_test_macros.hpp>
#include <mfem.hpp>
import mean_field;
import test_helpers;
namespace barotropic_closure_context_test_utils {
mfem::Vector project_field(
mfem::ParFiniteElementSpace &finiteElementSpace,
mfem::Coefficient &coefficient
) {
mfem::ParGridFunction field(&finiteElementSpace);
field.ProjectCoefficient(coefficient);
mfem::Vector trueVector;
field.GetTrueDofs(trueVector);
return trueVector;
}
mfem::Vector make_density(const mean_field::fem::FEM &f) {
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
return 0.55 + 0.025 * position(0) - 0.010 * position(1);
});
return project_field(*f.densityFes, coefficient);
}
mfem::Vector make_enthalpy(const mean_field::fem::FEM &f) {
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
return 0.90 + 0.020 * position(0) - 0.010 * position(1) +
0.005 * position(2);
});
return project_field(*f.enthalpyFes, coefficient);
}
} // namespace barotropic_closure_context_test_utils
TEST_CASE(
"Barotropic Closure Context Tracks Independent Revisions",
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::unit
) {
auto args = test_utils::setup_args();
mean_field::fem::FEM f =
mean_field::fem::setup_fem(args.mesh_file, args, 0);
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.5);
mean_field::operators::context::barotropic::
BarotropicClosureLinearizationContext context(
f, *f.domainMapperStateless, barotrope
);
mfem::Vector density =
barotropic_closure_context_test_utils::make_density(f);
mfem::Vector enthalpy =
barotropic_closure_context_test_utils::make_enthalpy(f);
mfem::Vector displacement =
gravity_prepared_test_utils::make_displacement(f, 0.0);
mean_field::operators::context::barotropic::BarotropicClosureRevisions
revisions{.density = 3, .enthalpy = 5, .displacement = 7};
CHECK_FALSE(context.IsPrepared());
CHECK(context.GetPreparationCount() == 0);
context.Prepare(density, enthalpy, displacement, revisions);
REQUIRE(context.IsPrepared());
CHECK(context.MatchesRevisions(revisions));
CHECK(context.GetRevisions() == revisions);
CHECK(context.GetPreparationCount() == 1);
CHECK(context.GetOperator().GetPreparationCount() == 1);
context.Prepare(density, enthalpy, displacement, revisions);
CHECK(context.GetPreparationCount() == 1);
const double frozenDensityValue = context.GetBaseDensityTrue()(0);
density(0) += 0.125;
CHECK(context.GetBaseDensityTrue()(0) == frozenDensityValue);
context.Prepare(density, enthalpy, displacement, revisions);
CHECK(context.GetPreparationCount() == 1);
CHECK(context.GetBaseDensityTrue()(0) == frozenDensityValue);
++revisions.density;
context.Prepare(density, enthalpy, displacement, revisions);
CHECK(context.GetPreparationCount() == 2);
CHECK(context.GetBaseDensityTrue()(0) == density(0));
enthalpy(0) += 0.050;
++revisions.enthalpy;
context.Prepare(density, enthalpy, displacement, revisions);
CHECK(context.GetPreparationCount() == 3);
CHECK(context.GetBaseEnthalpyTrue()(0) == enthalpy(0));
displacement = gravity_prepared_test_utils::make_displacement(f, 1.0);
++revisions.displacement;
context.Prepare(density, enthalpy, displacement, revisions);
CHECK(context.GetPreparationCount() == 4);
CHECK(context.GetRevisions() == revisions);
CHECK(context.MatchesRevisions(revisions));
CHECK(context.GetOperator().GetPreparationCount() == 4);
}
TEST_CASE(
"Barotropic Closure Context Reprepares A Consistent Frozen State",
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::unit
) {
auto args = test_utils::setup_args();
mean_field::fem::FEM f =
mean_field::fem::setup_fem(args.mesh_file, args, 0);
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.5);
mean_field::operators::context::barotropic::
BarotropicClosureLinearizationContext context(
f, *f.domainMapperStateless, barotrope
);
const mfem::Vector density =
barotropic_closure_context_test_utils::make_density(f);
const mfem::Vector enthalpy =
barotropic_closure_context_test_utils::make_enthalpy(f);
const mfem::Vector identityDisplacement =
gravity_prepared_test_utils::make_displacement(f, 0.0);
const mfem::Vector densityVariation =
gravity_prepared_test_utils::make_deterministic_vector(
f.densityFes->GetTrueVSize(), 0.37
);
const mfem::Vector enthalpyVariation =
gravity_prepared_test_utils::make_deterministic_vector(
f.enthalpyFes->GetTrueVSize(), 0.71
);
const mfem::Vector displacementVariation =
gravity_prepared_test_utils::make_deterministic_vector(
f.displacementFes->GetTrueVSize(), 0.37
);
mean_field::operators::context::barotropic::BarotropicClosureRevisions
revisions{.density = 11, .enthalpy = 13, .displacement = 17};
context.Prepare(density, enthalpy, identityDisplacement, revisions);
mfem::Vector initialResidual;
mfem::Vector initialAction;
context.BuildResidual(initialResidual);
context.GetOperator().Mult(
densityVariation, enthalpyVariation, displacementVariation,
initialAction
);
mfem::Vector changedDensity(density);
changedDensity.Add(0.025, densityVariation);
mfem::Vector changedEnthalpy(enthalpy);
changedEnthalpy.Add(0.015, enthalpyVariation);
const mfem::Vector deformedDisplacement =
gravity_prepared_test_utils::make_displacement(f, 1.0);
context.Prepare(
changedDensity, changedEnthalpy, deformedDisplacement, revisions
);
mfem::Vector unchangedResidual;
mfem::Vector unchangedAction;
context.BuildResidual(unchangedResidual);
context.GetOperator().Mult(
densityVariation, enthalpyVariation, displacementVariation,
unchangedAction
);
const MPI_Comm communicator = f.mesh->GetComm();
CHECK(context.GetPreparationCount() == 1);
CHECK(
gravity_prepared_test_utils::relative_error(
unchangedResidual, initialResidual, communicator
) < 5.0e-15
);
CHECK(
gravity_prepared_test_utils::relative_error(
unchangedAction, initialAction, communicator
) < 5.0e-15
);
++revisions.density;
++revisions.enthalpy;
++revisions.displacement;
context.Prepare(
changedDensity, changedEnthalpy, deformedDisplacement, revisions
);
mfem::Vector preparedResidual;
mfem::Vector preparedAction;
context.BuildResidual(preparedResidual);
context.GetOperator().Mult(
densityVariation, enthalpyVariation, displacementVariation,
preparedAction
);
mfem::Vector referenceResidual;
mfem::Vector referenceDensityAction;
mfem::Vector referenceEnthalpyAction;
mfem::Vector referenceDisplacementAction;
mean_field::operators::kernels::apply_barotropic_closure(
f, *f.domainMapperStateless, barotrope, changedDensity, changedEnthalpy,
deformedDisplacement, referenceResidual
);
mean_field::operators::kernels::apply_barotropic_closure_density_action(
f, *f.domainMapperStateless, barotrope, densityVariation,
deformedDisplacement, referenceDensityAction
);
mean_field::operators::kernels::apply_barotropic_closure_enthalpy_action(
f, *f.domainMapperStateless, barotrope, changedEnthalpy,
enthalpyVariation, deformedDisplacement, referenceEnthalpyAction
);
mean_field::operators::kernels::
apply_barotropic_closure_displacement_action(
f, *f.domainMapperStateless, barotrope, changedDensity,
changedEnthalpy, deformedDisplacement, displacementVariation,
referenceDisplacementAction
);
mfem::Vector referenceAction(referenceDensityAction);
referenceAction += referenceEnthalpyAction;
referenceAction += referenceDisplacementAction;
const double residualError = gravity_prepared_test_utils::relative_error(
preparedResidual, referenceResidual, communicator
);
const double actionError = gravity_prepared_test_utils::relative_error(
preparedAction, referenceAction, communicator
);
const double residualChange = gravity_prepared_test_utils::relative_error(
preparedResidual, initialResidual, communicator
);
const double actionChange = gravity_prepared_test_utils::relative_error(
preparedAction, initialAction, communicator
);
INFO("Prepared-context residual error = " << residualError);
INFO("Prepared-context Jacobian error = " << actionError);
INFO("Residual change after valid revision = " << residualChange);
INFO("Jacobian change after valid revision = " << actionChange);
CHECK(context.GetPreparationCount() == 2);
CHECK(residualError < 5.0e-12);
CHECK(actionError < 5.0e-12);
CHECK(residualChange > 1.0e-6);
CHECK(actionChange > 1.0e-6);
}