feat(field-support): added field support system, mid migration
currently the barotope and the pressure force operator are migrated to the new support system
This commit is contained in:
@@ -1,297 +1,416 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <mfem.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
import mean_field;
|
||||
import test_helpers;
|
||||
|
||||
namespace barotropic_closure_context_test_utils {
|
||||
mfem::Vector project_field(
|
||||
mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
mfem::Coefficient &coefficient
|
||||
namespace field = mean_field::field;
|
||||
namespace domain = mean_field::utils::domain;
|
||||
namespace context = mean_field::operators::context::barotropic;
|
||||
|
||||
using Schema = domain::CoreEnvelopeVacuumDomainSchema;
|
||||
|
||||
struct Maps final {
|
||||
field::FieldDofMap density;
|
||||
field::FieldDofMap enthalpy;
|
||||
field::FieldDofMap displacement;
|
||||
|
||||
explicit Maps(const mean_field::fem::FEM &f)
|
||||
: density(
|
||||
field::make_field_dof_map<
|
||||
field::Density,
|
||||
Schema>(*f.densityFes)
|
||||
),
|
||||
enthalpy(
|
||||
field::make_field_dof_map<
|
||||
field::Enthalpy,
|
||||
Schema>(*f.enthalpyFes)
|
||||
),
|
||||
displacement(
|
||||
field::make_field_dof_map<
|
||||
field::Displacement,
|
||||
Schema>(*f.displacementFes)
|
||||
) {
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] context::BarotropicClosureDependencies make_dependencies() {
|
||||
return {
|
||||
.discretization = {.identity = 101, .revision = 2},
|
||||
.density = {.identity = 103, .revision = 3},
|
||||
.enthalpy = {.identity = 107, .revision = 5},
|
||||
.displacement = {.identity = 109, .revision = 7}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] context::BarotropicClosureStateView make_state(
|
||||
const mfem::Vector &density,
|
||||
const mfem::Vector &enthalpy,
|
||||
const mfem::Vector &displacement
|
||||
) {
|
||||
mfem::ParGridFunction field(&finiteElementSpace);
|
||||
|
||||
field.ProjectCoefficient(coefficient);
|
||||
|
||||
mfem::Vector trueVector;
|
||||
field.GetTrueDofs(trueVector);
|
||||
|
||||
return trueVector;
|
||||
return {.density = density, .enthalpy = enthalpy, .displacement = displacement};
|
||||
}
|
||||
|
||||
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);
|
||||
[[nodiscard]] mfem::Vector reduce(
|
||||
const field::FieldDofMap &map,
|
||||
const mfem::Vector &full
|
||||
) {
|
||||
return map.gather(full);
|
||||
}
|
||||
|
||||
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);
|
||||
[[nodiscard]] mfem::Vector make_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const double phase
|
||||
) {
|
||||
mfem::ParGridFunction value(f.densityFes.get());
|
||||
mfem::FunctionCoefficient coefficient([phase](const mfem::Vector &position) {
|
||||
return 0.71 + 0.05 * std::sin(0.63 * position(0) + phase) + 0.02 * position(1);
|
||||
});
|
||||
value.ProjectCoefficient(coefficient);
|
||||
mfem::Vector result;
|
||||
value.GetTrueDofs(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return project_field(*f.enthalpyFes, coefficient);
|
||||
[[nodiscard]] mfem::Vector make_enthalpy(
|
||||
const mean_field::fem::FEM &f,
|
||||
const double phase
|
||||
) {
|
||||
mfem::ParGridFunction value(f.enthalpyFes.get());
|
||||
mfem::FunctionCoefficient coefficient([phase](const mfem::Vector &position) {
|
||||
return 0.93 + 0.04 * std::cos(0.57 * position(1) - phase) + 0.015 * position(2);
|
||||
});
|
||||
value.ProjectCoefficient(coefficient);
|
||||
mfem::Vector result;
|
||||
value.GetTrueDofs(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] double relative_error(
|
||||
const mfem::Vector &left,
|
||||
const mfem::Vector &right,
|
||||
const MPI_Comm communicator
|
||||
) {
|
||||
return gravity_prepared_test_utils::relative_error(left, right, communicator);
|
||||
}
|
||||
} // namespace barotropic_closure_context_test_utils
|
||||
|
||||
TEST_CASE(
|
||||
"Barotropic Closure Context Tracks Independent Revisions",
|
||||
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::unit
|
||||
"Prepared Barotropic Closure Owns Its Linearization Context",
|
||||
tags::barotrope &tags::closure &tags::contexts &tags::prepared &tags::field &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
using Operator = mean_field::operators::PreparedBarotropicClosureOperator;
|
||||
using Context = mean_field::operators::context::barotropic::BarotropicClosureLinearizationContext;
|
||||
|
||||
mean_field::fem::FEM f =
|
||||
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
STATIC_REQUIRE_FALSE(std::is_copy_constructible_v<Context>);
|
||||
STATIC_REQUIRE_FALSE(std::is_copy_assignable_v<Context>);
|
||||
STATIC_REQUIRE_FALSE(std::is_move_constructible_v<Context>);
|
||||
STATIC_REQUIRE_FALSE(std::is_move_assignable_v<Context>);
|
||||
|
||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.5);
|
||||
auto args = test_utils::setup_args();
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
mean_field::operators::context::barotropic::
|
||||
BarotropicClosureLinearizationContext context(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
const mean_field::eos::Polytrope equationOfState(3.0, 1.5);
|
||||
Operator preparedOperator(f, *f.domainMapperStateless, equationOfState);
|
||||
|
||||
mfem::Vector density =
|
||||
barotropic_closure_context_test_utils::make_density(f);
|
||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||
CHECK_FALSE(preparedOperator.GetContext().IsPrepared());
|
||||
CHECK(&preparedOperator.GetContext() == &preparedOperator.GetContext());
|
||||
|
||||
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);
|
||||
const auto statistics = preparedOperator.GetContextPreparationStatistics();
|
||||
CHECK(statistics.staticPreparations == 0);
|
||||
CHECK(statistics.geometryPreparations == 0);
|
||||
CHECK(statistics.baseStatePreparations == 0);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Barotropic Closure Context Reprepares A Consistent Frozen State",
|
||||
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::unit
|
||||
"Barotropic Closure Context Applies Selective Invalidation In Reduced Field Coordinates",
|
||||
tags::barotrope &tags::closure &tags::contexts &tags::prepared &tags::field &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
using namespace barotropic_closure_context_test_utils;
|
||||
|
||||
mean_field::fem::FEM f =
|
||||
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
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);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
mean_field::operators::context::barotropic::
|
||||
BarotropicClosureLinearizationContext context(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
const Maps maps(f);
|
||||
|
||||
const mfem::Vector density =
|
||||
barotropic_closure_context_test_utils::make_density(f);
|
||||
const mean_field::eos::Polytrope equationOfState(3.0, 1.5);
|
||||
|
||||
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
|
||||
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, equationOfState
|
||||
);
|
||||
|
||||
mfem::Vector changedDensity(density);
|
||||
changedDensity.Add(0.025, densityVariation);
|
||||
mfem::Vector density = reduce(maps.density, make_density(f, 0.17));
|
||||
|
||||
mfem::Vector changedEnthalpy(enthalpy);
|
||||
changedEnthalpy.Add(0.015, enthalpyVariation);
|
||||
mfem::Vector enthalpy = reduce(maps.enthalpy, make_enthalpy(f, 0.29));
|
||||
|
||||
const mfem::Vector deformedDisplacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||
const mfem::Vector initialDisplacement =
|
||||
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.35));
|
||||
|
||||
context.Prepare(
|
||||
changedDensity, changedEnthalpy, deformedDisplacement, revisions
|
||||
);
|
||||
/*
|
||||
* A second smooth, orientation-preserving geometry.
|
||||
*
|
||||
* Do not manufacture a new geometry by perturbing an arbitrary H1
|
||||
* coefficient. A modest change in one high-order displacement DOF can
|
||||
* correspond to a very large local displacement gradient and can invert
|
||||
* an element.
|
||||
*/
|
||||
const mfem::Vector changedDisplacement =
|
||||
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.85));
|
||||
|
||||
mfem::Vector unchangedResidual;
|
||||
mfem::Vector unchangedAction;
|
||||
mfem::Vector displacement(initialDisplacement);
|
||||
|
||||
context.BuildResidual(unchangedResidual);
|
||||
auto dependencies = make_dependencies();
|
||||
|
||||
context.GetOperator().Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation,
|
||||
unchangedAction
|
||||
);
|
||||
const auto initialReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
const auto &context = preparedOperator.GetContext();
|
||||
|
||||
REQUIRE(preparedOperator.IsPrepared());
|
||||
|
||||
REQUIRE(context.IsPrepared());
|
||||
|
||||
CHECK(context.MatchesDependencies(dependencies));
|
||||
|
||||
CHECK(context.GetDependencies() == dependencies);
|
||||
|
||||
CHECK(initialReport.contextReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(initialReport.contextReport.preparedGeometryState);
|
||||
|
||||
CHECK(initialReport.contextReport.preparedBaseState);
|
||||
|
||||
CHECK(initialReport.contextReport.updatedDensity);
|
||||
|
||||
CHECK(initialReport.contextReport.updatedEnthalpy);
|
||||
|
||||
CHECK(initialReport.contextReport.updatedDisplacement);
|
||||
|
||||
CHECK(initialReport.preparedElementData);
|
||||
|
||||
CHECK(initialReport.DidAnyWork());
|
||||
|
||||
CHECK(preparedOperator.GetPreparationCount() == 1);
|
||||
|
||||
const mfem::Vector frozenDensity = context.GetBaseDensity();
|
||||
|
||||
const mfem::Vector frozenEnthalpy = context.GetBaseEnthalpy();
|
||||
|
||||
const mfem::Vector frozenDisplacement = context.GetDisplacement();
|
||||
|
||||
/*
|
||||
* Modify all three candidate states without updating their dependency
|
||||
* stamps.
|
||||
*
|
||||
* The context must continue exposing the previously frozen state.
|
||||
*/
|
||||
density(0) += 0.25;
|
||||
enthalpy(0) -= 0.18;
|
||||
displacement = changedDisplacement;
|
||||
|
||||
const auto repeatedReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
CHECK_FALSE(repeatedReport.DidAnyWork());
|
||||
|
||||
CHECK_FALSE(repeatedReport.contextReport.updatedDensity);
|
||||
|
||||
CHECK_FALSE(repeatedReport.contextReport.updatedEnthalpy);
|
||||
|
||||
CHECK_FALSE(repeatedReport.contextReport.updatedDisplacement);
|
||||
|
||||
CHECK_FALSE(repeatedReport.preparedElementData);
|
||||
|
||||
CHECK(preparedOperator.GetPreparationCount() == 1);
|
||||
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
CHECK(context.GetPreparationCount() == 1);
|
||||
CHECK(relative_error(context.GetBaseDensity(), frozenDensity, communicator) == 0.0);
|
||||
|
||||
CHECK(
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
unchangedResidual, initialResidual, communicator
|
||||
) < 5.0e-15
|
||||
CHECK(relative_error(context.GetBaseEnthalpy(), frozenEnthalpy, communicator) == 0.0);
|
||||
|
||||
CHECK(relative_error(context.GetDisplacement(), frozenDisplacement, communicator) == 0.0);
|
||||
|
||||
/*
|
||||
* Density invalidation.
|
||||
*
|
||||
* Geometry remains frozen because the displacement dependency did not
|
||||
* change.
|
||||
*/
|
||||
++dependencies.density.revision;
|
||||
|
||||
const auto densityReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
CHECK_FALSE(densityReport.contextReport.preparedStaticDependencies);
|
||||
|
||||
CHECK_FALSE(densityReport.contextReport.preparedGeometryState);
|
||||
|
||||
CHECK(densityReport.contextReport.preparedBaseState);
|
||||
|
||||
CHECK(densityReport.contextReport.updatedDensity);
|
||||
|
||||
CHECK_FALSE(densityReport.contextReport.updatedEnthalpy);
|
||||
|
||||
CHECK_FALSE(densityReport.contextReport.updatedDisplacement);
|
||||
|
||||
CHECK(densityReport.preparedElementData);
|
||||
|
||||
CHECK(context.GetBaseDensity()(0) == density(0));
|
||||
|
||||
/*
|
||||
* The candidate displacement has changed, but because its revision has
|
||||
* not changed the context must still retain the original geometry.
|
||||
*/
|
||||
CHECK(relative_error(context.GetDisplacement(), frozenDisplacement, communicator) == 0.0);
|
||||
|
||||
/*
|
||||
* Enthalpy invalidation.
|
||||
*/
|
||||
++dependencies.enthalpy.revision;
|
||||
|
||||
const auto enthalpyReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
CHECK_FALSE(enthalpyReport.contextReport.preparedStaticDependencies);
|
||||
|
||||
CHECK_FALSE(enthalpyReport.contextReport.preparedGeometryState);
|
||||
|
||||
CHECK(enthalpyReport.contextReport.preparedBaseState);
|
||||
|
||||
CHECK_FALSE(enthalpyReport.contextReport.updatedDensity);
|
||||
|
||||
CHECK(enthalpyReport.contextReport.updatedEnthalpy);
|
||||
|
||||
CHECK_FALSE(enthalpyReport.contextReport.updatedDisplacement);
|
||||
|
||||
CHECK(enthalpyReport.preparedElementData);
|
||||
|
||||
CHECK(context.GetBaseEnthalpy()(0) == enthalpy(0));
|
||||
|
||||
CHECK(relative_error(context.GetDisplacement(), frozenDisplacement, communicator) == 0.0);
|
||||
|
||||
/*
|
||||
* Displacement invalidation.
|
||||
*
|
||||
* The changed geometry is now intentionally accepted. Because it came
|
||||
* from the smooth test displacement projection rather than an arbitrary
|
||||
* single H1 coefficient mutation, it remains a valid mapping.
|
||||
*/
|
||||
++dependencies.displacement.revision;
|
||||
|
||||
const auto displacementReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
CHECK_FALSE(displacementReport.contextReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(displacementReport.contextReport.preparedGeometryState);
|
||||
|
||||
CHECK(displacementReport.contextReport.preparedBaseState);
|
||||
|
||||
CHECK_FALSE(displacementReport.contextReport.updatedDensity);
|
||||
|
||||
CHECK_FALSE(displacementReport.contextReport.updatedEnthalpy);
|
||||
|
||||
CHECK(displacementReport.contextReport.updatedDisplacement);
|
||||
|
||||
CHECK(displacementReport.preparedElementData);
|
||||
|
||||
CHECK(relative_error(context.GetDisplacement(), changedDisplacement, communicator) == 0.0);
|
||||
|
||||
/*
|
||||
* Discretization invalidates everything.
|
||||
*/
|
||||
++dependencies.discretization.revision;
|
||||
|
||||
const auto discretizationReport =
|
||||
preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
CHECK(discretizationReport.contextReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(discretizationReport.contextReport.preparedGeometryState);
|
||||
|
||||
CHECK(discretizationReport.contextReport.preparedBaseState);
|
||||
|
||||
CHECK(discretizationReport.contextReport.updatedDensity);
|
||||
|
||||
CHECK(discretizationReport.contextReport.updatedEnthalpy);
|
||||
|
||||
CHECK(discretizationReport.contextReport.updatedDisplacement);
|
||||
|
||||
CHECK(discretizationReport.preparedElementData);
|
||||
|
||||
const auto finalStatistics = preparedOperator.GetContextPreparationStatistics();
|
||||
|
||||
CHECK(finalStatistics.staticPreparations == 2);
|
||||
|
||||
CHECK(finalStatistics.geometryPreparations == 3);
|
||||
|
||||
CHECK(finalStatistics.baseStatePreparations == 5);
|
||||
|
||||
CHECK(preparedOperator.GetPreparationCount() == 5);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Barotropic Closure Context Uses Identity And Revision For Every Dependency",
|
||||
tags::barotrope &tags::closure &tags::contexts &tags::prepared &tags::field &tags::unit
|
||||
) {
|
||||
using namespace barotropic_closure_context_test_utils;
|
||||
|
||||
auto args = test_utils::setup_args();
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
const Maps maps(f);
|
||||
const mean_field::eos::Polytrope equationOfState(3.0, 1.5);
|
||||
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, equationOfState
|
||||
);
|
||||
|
||||
CHECK(
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
unchangedAction, initialAction, communicator
|
||||
) < 5.0e-15
|
||||
);
|
||||
mfem::Vector density = reduce(maps.density, make_density(f, 0.41));
|
||||
mfem::Vector enthalpy = reduce(maps.enthalpy, make_enthalpy(f, 0.53));
|
||||
mfem::Vector displacement = reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.60));
|
||||
|
||||
++revisions.density;
|
||||
++revisions.enthalpy;
|
||||
++revisions.displacement;
|
||||
auto dependencies = make_dependencies();
|
||||
preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
|
||||
context.Prepare(
|
||||
changedDensity, changedEnthalpy, deformedDisplacement, revisions
|
||||
);
|
||||
const mfem::Vector frozenDensity = preparedOperator.GetContext().GetBaseDensity();
|
||||
density(0) += 0.19;
|
||||
|
||||
mfem::Vector preparedResidual;
|
||||
mfem::Vector preparedAction;
|
||||
const auto sameStampReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
CHECK_FALSE(sameStampReport.DidAnyWork());
|
||||
CHECK(preparedOperator.GetContext().GetBaseDensity()(0) == frozenDensity(0));
|
||||
|
||||
context.BuildResidual(preparedResidual);
|
||||
++dependencies.density.identity;
|
||||
++dependencies.density.revision;
|
||||
|
||||
context.GetOperator().Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation,
|
||||
preparedAction
|
||||
);
|
||||
const auto newIdentityReport = preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
CHECK_FALSE(newIdentityReport.contextReport.preparedStaticDependencies);
|
||||
CHECK_FALSE(newIdentityReport.contextReport.preparedGeometryState);
|
||||
CHECK(newIdentityReport.contextReport.preparedBaseState);
|
||||
CHECK(newIdentityReport.contextReport.updatedDensity);
|
||||
CHECK(preparedOperator.GetContext().GetBaseDensity()(0) == density(0));
|
||||
CHECK(preparedOperator.GetContext().MatchesDependencies(dependencies));
|
||||
|
||||
mfem::Vector referenceResidual;
|
||||
mfem::Vector referenceDensityAction;
|
||||
mfem::Vector referenceEnthalpyAction;
|
||||
mfem::Vector referenceDisplacementAction;
|
||||
++dependencies.displacement.identity;
|
||||
++dependencies.displacement.revision;
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, changedDensity, changedEnthalpy,
|
||||
deformedDisplacement, referenceResidual
|
||||
);
|
||||
const auto displacementIdentityReport =
|
||||
preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
CHECK_FALSE(displacementIdentityReport.contextReport.preparedStaticDependencies);
|
||||
CHECK(displacementIdentityReport.contextReport.preparedGeometryState);
|
||||
CHECK(displacementIdentityReport.contextReport.preparedBaseState);
|
||||
CHECK(displacementIdentityReport.contextReport.updatedDisplacement);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure_density_action(
|
||||
f, *f.domainMapperStateless, barotrope, densityVariation,
|
||||
deformedDisplacement, referenceDensityAction
|
||||
);
|
||||
++dependencies.discretization.identity;
|
||||
++dependencies.discretization.revision;
|
||||
|
||||
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);
|
||||
}
|
||||
const auto discretizationIdentityReport =
|
||||
preparedOperator.Prepare(make_state(density, enthalpy, displacement), dependencies);
|
||||
CHECK(discretizationIdentityReport.contextReport.preparedStaticDependencies);
|
||||
CHECK(discretizationIdentityReport.contextReport.preparedGeometryState);
|
||||
CHECK(discretizationIdentityReport.contextReport.preparedBaseState);
|
||||
}
|
||||
|
||||
@@ -15,20 +15,13 @@ TEST_CASE(
|
||||
auto args = test_utils::setup_args();
|
||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
gravity_context::GravityFieldLinearizationContext context(
|
||||
f, *f.domainMapperStateless
|
||||
);
|
||||
gravity_context::GravityFieldLinearizationContext context(f, *f.domainMapperStateless);
|
||||
|
||||
mfem::Vector density = prepared_test::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), 0.11
|
||||
);
|
||||
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 gravity_potential = prepared_test::make_deterministic_vector(
|
||||
f.gravityPotentialFes->GetTrueVSize(), 0.63
|
||||
);
|
||||
mfem::Vector gravity_gradient = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.37);
|
||||
mfem::Vector gravity_potential =
|
||||
prepared_test::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.63);
|
||||
|
||||
gravity_context::GravityFieldRevisions revisions;
|
||||
|
||||
@@ -43,8 +36,7 @@ TEST_CASE(
|
||||
|
||||
REQUIRE_FALSE(context.IsPrepared());
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport initial_report =
|
||||
context.Prepare(make_state(), revisions);
|
||||
const gravity_context::GravityFieldPreparationReport initial_report = context.Prepare(make_state(), revisions);
|
||||
|
||||
REQUIRE(context.IsPrepared());
|
||||
CHECK(initial_report.geometry.reconstructed_operators);
|
||||
@@ -55,41 +47,27 @@ TEST_CASE(
|
||||
CHECK(initial_report.updated_gravity_gradient);
|
||||
CHECK(initial_report.DidAnyWork());
|
||||
|
||||
const auto initial_mass_preparations =
|
||||
context.GetGeometryContext().GetMassOperator().GetPreparationCount();
|
||||
const auto initial_source_preparations =
|
||||
context.GetGeometryContext().GetSourceOperator().GetPreparationCount();
|
||||
const auto initial_mass_preparations = context.GetGeometryContext().GetMassOperator().GetPreparationCount();
|
||||
const auto initial_source_preparations = context.GetGeometryContext().GetSourceOperator().GetPreparationCount();
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport repeated_report =
|
||||
context.Prepare(make_state(), revisions);
|
||||
const gravity_context::GravityFieldPreparationReport repeated_report = context.Prepare(make_state(), revisions);
|
||||
|
||||
CHECK_FALSE(repeated_report.DidAnyWork());
|
||||
CHECK(
|
||||
context.GetGeometryContext().GetMassOperator().GetPreparationCount() ==
|
||||
initial_mass_preparations
|
||||
);
|
||||
CHECK(
|
||||
context.GetGeometryContext()
|
||||
.GetSourceOperator()
|
||||
.GetPreparationCount() == initial_source_preparations
|
||||
);
|
||||
CHECK(context.GetGeometryContext().GetMassOperator().GetPreparationCount() == initial_mass_preparations);
|
||||
CHECK(context.GetGeometryContext().GetSourceOperator().GetPreparationCount() == initial_source_preparations);
|
||||
|
||||
gravity_potential(0) += 0.25;
|
||||
++revisions.gravity_potential.value;
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport potential_report =
|
||||
context.Prepare(make_state(), revisions);
|
||||
const gravity_context::GravityFieldPreparationReport potential_report = context.Prepare(make_state(), revisions);
|
||||
|
||||
CHECK_FALSE(potential_report.DidAnyWork());
|
||||
CHECK(
|
||||
context.GetRevisions().gravity_potential == revisions.gravity_potential
|
||||
);
|
||||
CHECK(context.GetRevisions().gravity_potential == revisions.gravity_potential);
|
||||
|
||||
density(0) += 0.5;
|
||||
++revisions.density.value;
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport density_report =
|
||||
context.Prepare(make_state(), revisions);
|
||||
const gravity_context::GravityFieldPreparationReport density_report = context.Prepare(make_state(), revisions);
|
||||
|
||||
CHECK(density_report.updated_density);
|
||||
CHECK_FALSE(density_report.updated_gravity_gradient);
|
||||
@@ -99,8 +77,7 @@ TEST_CASE(
|
||||
gravity_gradient(0) -= 0.4;
|
||||
++revisions.gravity_gradient.value;
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport gradient_report =
|
||||
context.Prepare(make_state(), revisions);
|
||||
const gravity_context::GravityFieldPreparationReport gradient_report = context.Prepare(make_state(), revisions);
|
||||
|
||||
CHECK_FALSE(gradient_report.updated_density);
|
||||
CHECK(gradient_report.updated_gravity_gradient);
|
||||
@@ -110,8 +87,7 @@ TEST_CASE(
|
||||
displacement = prepared_test::make_displacement(f, 1.0);
|
||||
++revisions.displacement.value;
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport displacement_report =
|
||||
context.Prepare(make_state(), revisions);
|
||||
const gravity_context::GravityFieldPreparationReport displacement_report = context.Prepare(make_state(), revisions);
|
||||
|
||||
CHECK_FALSE(displacement_report.geometry.reconstructed_operators);
|
||||
CHECK(displacement_report.geometry.rebuilt_mass_operator);
|
||||
@@ -119,15 +95,8 @@ TEST_CASE(
|
||||
CHECK(displacement_report.geometry.refreshed_variation_state);
|
||||
CHECK_FALSE(displacement_report.updated_density);
|
||||
CHECK_FALSE(displacement_report.updated_gravity_gradient);
|
||||
CHECK(
|
||||
context.GetGeometryContext().GetMassOperator().GetPreparationCount() ==
|
||||
initial_mass_preparations + 1
|
||||
);
|
||||
CHECK(
|
||||
context.GetGeometryContext()
|
||||
.GetSourceOperator()
|
||||
.GetPreparationCount() == initial_source_preparations + 1
|
||||
);
|
||||
CHECK(context.GetGeometryContext().GetMassOperator().GetPreparationCount() == initial_mass_preparations + 1);
|
||||
CHECK(context.GetGeometryContext().GetSourceOperator().GetPreparationCount() == initial_source_preparations + 1);
|
||||
|
||||
++revisions.discretization.value;
|
||||
|
||||
@@ -139,15 +108,8 @@ TEST_CASE(
|
||||
CHECK(discretization_report.geometry.rebuilt_source_operator);
|
||||
CHECK(discretization_report.updated_density);
|
||||
CHECK(discretization_report.updated_gravity_gradient);
|
||||
CHECK(
|
||||
context.GetGeometryContext().GetMassOperator().GetPreparationCount() ==
|
||||
1
|
||||
);
|
||||
CHECK(
|
||||
context.GetGeometryContext()
|
||||
.GetSourceOperator()
|
||||
.GetPreparationCount() == 1
|
||||
);
|
||||
CHECK(context.GetGeometryContext().GetMassOperator().GetPreparationCount() == 1);
|
||||
CHECK(context.GetGeometryContext().GetSourceOperator().GetPreparationCount() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
@@ -157,20 +119,13 @@ TEST_CASE(
|
||||
auto args = test_utils::setup_args();
|
||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
gravity_context::GravityFieldLinearizationContext context(
|
||||
f, *f.domainMapperStateless
|
||||
);
|
||||
gravity_context::GravityFieldLinearizationContext context(f, *f.domainMapperStateless);
|
||||
|
||||
mfem::Vector density = prepared_test::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), 0.13
|
||||
);
|
||||
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 gravity_potential = prepared_test::make_deterministic_vector(
|
||||
f.gravityPotentialFes->GetTrueVSize(), 0.71
|
||||
);
|
||||
mfem::Vector gravity_gradient = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.47);
|
||||
mfem::Vector gravity_potential =
|
||||
prepared_test::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.71);
|
||||
|
||||
gravity_context::GravityFieldRevisions revisions;
|
||||
|
||||
@@ -182,9 +137,8 @@ TEST_CASE(
|
||||
revisions
|
||||
);
|
||||
|
||||
const mfem::Vector frozen_density = context.GetDensity();
|
||||
const mfem::Vector frozen_displacement =
|
||||
context.GetGeometryContext().GetDisplacement();
|
||||
const mfem::Vector frozen_density = context.GetDensity();
|
||||
const mfem::Vector frozen_displacement = context.GetGeometryContext().GetDisplacement();
|
||||
const mfem::Vector frozen_gravity_gradient = context.GetGravityGradient();
|
||||
|
||||
density = 0.0;
|
||||
@@ -192,49 +146,36 @@ TEST_CASE(
|
||||
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.GetDensity(), frozen_density, f.mesh->GetComm()
|
||||
context.GetGeometryContext().GetDisplacement(), frozen_displacement, f.displacementFes->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
CHECK(
|
||||
prepared_test::relative_error(
|
||||
context.GetGeometryContext().GetDisplacement(), frozen_displacement,
|
||||
f.displacementFes->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
CHECK(
|
||||
prepared_test::relative_error(
|
||||
context.GetGravityGradient(), frozen_gravity_gradient,
|
||||
f.gravityFluxFes->GetComm()
|
||||
context.GetGravityGradient(), frozen_gravity_gradient, f.gravityFluxFes->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
|
||||
const gravity_context::GravityFieldPreparationReport
|
||||
unchanged_revision_report = context.Prepare(
|
||||
{.density = density,
|
||||
.displacement = displacement,
|
||||
.gravity_gradient = gravity_gradient,
|
||||
.gravity_potential = gravity_potential},
|
||||
revisions
|
||||
);
|
||||
const gravity_context::GravityFieldPreparationReport unchanged_revision_report = context.Prepare(
|
||||
{.density = density,
|
||||
.displacement = displacement,
|
||||
.gravity_gradient = gravity_gradient,
|
||||
.gravity_potential = gravity_potential},
|
||||
revisions
|
||||
);
|
||||
|
||||
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.GetDensity(), frozen_density, f.mesh->GetComm()
|
||||
context.GetGeometryContext().GetDisplacement(), frozen_displacement, f.displacementFes->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
CHECK(
|
||||
prepared_test::relative_error(
|
||||
context.GetGeometryContext().GetDisplacement(), frozen_displacement,
|
||||
f.displacementFes->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
CHECK(
|
||||
prepared_test::relative_error(
|
||||
context.GetGravityGradient(), frozen_gravity_gradient,
|
||||
f.gravityFluxFes->GetComm()
|
||||
context.GetGravityGradient(), frozen_gravity_gradient, f.gravityFluxFes->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
}
|
||||
@@ -246,21 +187,13 @@ TEST_CASE(
|
||||
auto args = test_utils::setup_args();
|
||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
gravity_context::GravityFieldGeometryContext first_context(
|
||||
f, *f.domainMapperStateless
|
||||
);
|
||||
gravity_context::GravityFieldGeometryContext second_context(
|
||||
f, *f.domainMapperStateless
|
||||
);
|
||||
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 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
|
||||
);
|
||||
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});
|
||||
@@ -270,36 +203,21 @@ TEST_CASE(
|
||||
mfem::Vector second_action_after;
|
||||
|
||||
first_context.GetMassOperator().Mult(gravity_gradient, first_action);
|
||||
second_context.GetMassOperator().Mult(
|
||||
gravity_gradient, second_action_before
|
||||
);
|
||||
second_context.GetMassOperator().Mult(gravity_gradient, second_action_before);
|
||||
|
||||
const mfem::Vector updated_first_displacement =
|
||||
prepared_test::make_displacement(f, 0.6);
|
||||
first_context.Prepare(
|
||||
updated_first_displacement, {.value = 0}, {.value = 1}
|
||||
);
|
||||
const mfem::Vector updated_first_displacement = 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
|
||||
);
|
||||
second_context.GetMassOperator().Mult(gravity_gradient, second_action_after);
|
||||
|
||||
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
|
||||
const double independent_context_error = prepared_test::relative_error(
|
||||
second_action_after, second_action_before, communicator
|
||||
);
|
||||
const double distinct_geometry_difference = prepared_test::relative_error(
|
||||
first_action, second_action_before, communicator
|
||||
);
|
||||
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
|
||||
const double independent_context_error =
|
||||
prepared_test::relative_error(second_action_after, second_action_before, communicator);
|
||||
const double distinct_geometry_difference =
|
||||
prepared_test::relative_error(first_action, second_action_before, communicator);
|
||||
|
||||
INFO(
|
||||
"Second-context change after preparing first context = "
|
||||
<< independent_context_error
|
||||
);
|
||||
INFO(
|
||||
"Difference between independently prepared geometries = "
|
||||
<< distinct_geometry_difference
|
||||
);
|
||||
INFO("Second-context change after preparing first context = " << independent_context_error);
|
||||
INFO("Difference between independently prepared geometries = " << distinct_geometry_difference);
|
||||
|
||||
CHECK(independent_context_error < 2.0e-14);
|
||||
CHECK(distinct_geometry_difference > 1.0e-5);
|
||||
|
||||
@@ -5,9 +5,7 @@ import mean_field;
|
||||
import test_helpers;
|
||||
|
||||
namespace hydrostatic_context_test_utils {
|
||||
mean_field::operators::context::hydrostatic::
|
||||
HydrostaticEquilibriumDependencies
|
||||
make_dependencies() {
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies make_dependencies() {
|
||||
return {
|
||||
.discretization = {.identity = 101, .revision = 2},
|
||||
.enthalpy = {.identity = 103, .revision = 3},
|
||||
@@ -18,8 +16,7 @@ namespace hydrostatic_context_test_utils {
|
||||
};
|
||||
}
|
||||
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumStateView
|
||||
make_state(
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumStateView make_state(
|
||||
const mfem::Vector &enthalpy,
|
||||
const mfem::Vector &gravityPotential,
|
||||
const mfem::Vector &displacement,
|
||||
@@ -33,10 +30,7 @@ namespace hydrostatic_context_test_utils {
|
||||
};
|
||||
}
|
||||
|
||||
void check_base_only(
|
||||
const mean_field::operators::context::hydrostatic::
|
||||
HydrostaticPreparationReport &report
|
||||
) {
|
||||
void check_base_only(const mean_field::operators::context::hydrostatic::HydrostaticPreparationReport &report) {
|
||||
CHECK_FALSE(report.preparedStaticDependencies);
|
||||
CHECK_FALSE(report.preparedGeometryState);
|
||||
CHECK_FALSE(report.preparedRotationDependencies);
|
||||
@@ -48,32 +42,23 @@ TEST_CASE(
|
||||
"Hydrostatic Context Applies Selective Invalidation",
|
||||
tags::barotrope &tags::contexts &tags::hydro &tags::prepared &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
auto args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f =
|
||||
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumContext
|
||||
context(f, *f.domainMapperStateless);
|
||||
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 = gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.17);
|
||||
|
||||
mfem::Vector gravityPotential =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.gravityPotentialFes->GetTrueVSize(), 0.31
|
||||
);
|
||||
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.31);
|
||||
|
||||
mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.35);
|
||||
mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.35);
|
||||
|
||||
double bernoulliConstant = 0.73;
|
||||
double bernoulliConstant = 0.73;
|
||||
|
||||
mean_field::operators::context::hydrostatic::
|
||||
HydrostaticEquilibriumDependencies dependencies =
|
||||
hydrostatic_context_test_utils::make_dependencies();
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies dependencies =
|
||||
hydrostatic_context_test_utils::make_dependencies();
|
||||
|
||||
CHECK_FALSE(context.IsPrepared());
|
||||
CHECK_FALSE(context.MatchesDependencies(dependencies));
|
||||
@@ -86,9 +71,7 @@ TEST_CASE(
|
||||
CHECK(initialStatistics.baseStatePreparations == 0);
|
||||
|
||||
const auto initialReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -106,14 +89,13 @@ TEST_CASE(
|
||||
CHECK(initialReport.updatedBernoulliConstant);
|
||||
CHECK(initialReport.DidAnyWork());
|
||||
|
||||
const mfem::Vector frozenEnthalpy = context.GetBaseEnthalpyTrue();
|
||||
const mfem::Vector frozenEnthalpy = context.GetBaseEnthalpyTrue();
|
||||
|
||||
const mfem::Vector frozenGravityPotential =
|
||||
context.GetBaseGravityPotentialTrue();
|
||||
const mfem::Vector frozenGravityPotential = context.GetBaseGravityPotentialTrue();
|
||||
|
||||
const mfem::Vector frozenDisplacement = context.GetDisplacementTrue();
|
||||
const mfem::Vector frozenDisplacement = context.GetDisplacementTrue();
|
||||
|
||||
const double frozenBernoulliConstant = context.GetBernoulliConstant();
|
||||
const double frozenBernoulliConstant = context.GetBernoulliConstant();
|
||||
|
||||
enthalpy(0) += 0.125;
|
||||
gravityPotential(0) -= 0.075;
|
||||
@@ -121,9 +103,7 @@ TEST_CASE(
|
||||
bernoulliConstant += 0.20;
|
||||
|
||||
const auto repeatedReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -136,22 +116,18 @@ TEST_CASE(
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
CHECK(
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
context.GetBaseEnthalpyTrue(), frozenEnthalpy, communicator
|
||||
) == 0.0
|
||||
gravity_prepared_test_utils::relative_error(context.GetBaseEnthalpyTrue(), frozenEnthalpy, communicator) == 0.0
|
||||
);
|
||||
|
||||
CHECK(
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
context.GetBaseGravityPotentialTrue(), frozenGravityPotential,
|
||||
communicator
|
||||
context.GetBaseGravityPotentialTrue(), frozenGravityPotential, communicator
|
||||
) == 0.0
|
||||
);
|
||||
|
||||
CHECK(
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
context.GetDisplacementTrue(), frozenDisplacement, communicator
|
||||
) == 0.0
|
||||
gravity_prepared_test_utils::relative_error(context.GetDisplacementTrue(), frozenDisplacement, communicator) ==
|
||||
0.0
|
||||
);
|
||||
|
||||
CHECK(context.GetBernoulliConstant() == frozenBernoulliConstant);
|
||||
@@ -159,9 +135,7 @@ TEST_CASE(
|
||||
++dependencies.enthalpy.revision;
|
||||
|
||||
const auto enthalpyReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -176,9 +150,7 @@ TEST_CASE(
|
||||
++dependencies.gravityPotential.revision;
|
||||
|
||||
const auto gravityPotentialReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -194,9 +166,7 @@ TEST_CASE(
|
||||
++dependencies.bernoulliConstant.revision;
|
||||
|
||||
const auto bernoulliReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -212,9 +182,7 @@ TEST_CASE(
|
||||
++dependencies.rotation.revision;
|
||||
|
||||
const auto rotationReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -230,9 +198,7 @@ TEST_CASE(
|
||||
++dependencies.displacement.revision;
|
||||
|
||||
const auto displacementReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -251,9 +217,7 @@ TEST_CASE(
|
||||
++dependencies.discretization.revision;
|
||||
|
||||
const auto discretizationReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -278,32 +242,23 @@ TEST_CASE(
|
||||
"Hydrostatic Context Uses Identity In Every Dependency",
|
||||
tags::barotrope &tags::contexts &tags::hydro &tags::prepared &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
auto args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f =
|
||||
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumContext
|
||||
context(f, *f.domainMapperStateless);
|
||||
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 = gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.23);
|
||||
|
||||
const mfem::Vector gravityPotential =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.gravityPotentialFes->GetTrueVSize(), 0.41
|
||||
);
|
||||
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.41);
|
||||
|
||||
const mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.60);
|
||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.60);
|
||||
|
||||
constexpr double bernoulliConstant = 0.81;
|
||||
|
||||
mean_field::operators::context::hydrostatic::
|
||||
HydrostaticEquilibriumDependencies dependencies =
|
||||
hydrostatic_context_test_utils::make_dependencies();
|
||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies dependencies =
|
||||
hydrostatic_context_test_utils::make_dependencies();
|
||||
|
||||
const auto preparedEnthalpyDependency = dependencies.enthalpy;
|
||||
|
||||
@@ -319,9 +274,7 @@ TEST_CASE(
|
||||
CHECK(resetNewIdentity.CanFollow(preparedEnthalpyDependency));
|
||||
|
||||
context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -330,9 +283,7 @@ TEST_CASE(
|
||||
enthalpy(0) += 0.33;
|
||||
|
||||
const auto sameStampReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -343,9 +294,7 @@ TEST_CASE(
|
||||
dependencies.enthalpy.revision = 0;
|
||||
|
||||
const auto newIdentityReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
@@ -359,9 +308,7 @@ TEST_CASE(
|
||||
dependencies.rotation.revision = 0;
|
||||
|
||||
const auto newRotationIdentityReport = context.Prepare(
|
||||
hydrostatic_context_test_utils::make_state(
|
||||
enthalpy, gravityPotential, displacement, bernoulliConstant
|
||||
),
|
||||
hydrostatic_context_test_utils::make_state(enthalpy, gravityPotential, displacement, bernoulliConstant),
|
||||
dependencies
|
||||
);
|
||||
|
||||
|
||||
325
tests/operators/contexts/pressure_force_context.cpp
Normal file
325
tests/operators/contexts/pressure_force_context.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <mfem.hpp>
|
||||
|
||||
import mean_field;
|
||||
import test_helpers;
|
||||
|
||||
namespace pressure_force_context_test_utils {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
|
||||
struct Maps final {
|
||||
mean_field::field::FieldDofMap enthalpy;
|
||||
mean_field::field::FieldDofMap displacement;
|
||||
|
||||
explicit Maps(const mean_field::fem::FEM &f)
|
||||
: enthalpy(
|
||||
mean_field::field::make_field_dof_map<
|
||||
mean_field::field::Enthalpy,
|
||||
DomainSchema>(*f.enthalpyFes)
|
||||
),
|
||||
displacement(
|
||||
mean_field::field::make_field_dof_map<
|
||||
mean_field::field::Displacement,
|
||||
DomainSchema>(*f.displacementFes)
|
||||
) {
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
mfem::Vector make_enthalpy_true(
|
||||
const mean_field::fem::FEM &f,
|
||||
const double phase
|
||||
) {
|
||||
mfem::Vector enthalpy(f.enthalpyFes->GetTrueVSize());
|
||||
|
||||
for (int index = 0; index < enthalpy.Size(); ++index) {
|
||||
const double position = static_cast<double>(index + 1);
|
||||
|
||||
enthalpy(index) =
|
||||
0.95 + 0.08 * std::sin(0.17 * position + phase) + 0.03 * std::cos(0.11 * position - 0.5 * phase);
|
||||
}
|
||||
|
||||
return enthalpy;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
double relative_difference(
|
||||
const mfem::Vector &left,
|
||||
const mfem::Vector &right,
|
||||
const MPI_Comm communicator
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
left.Size() == right.Size(), "Cannot compare pressure-force context vectors with "
|
||||
"different sizes."
|
||||
);
|
||||
|
||||
mfem::Vector difference(left);
|
||||
|
||||
difference -= right;
|
||||
|
||||
const double scale = std::max(
|
||||
{gravity_prepared_test_utils::global_norm(left, communicator),
|
||||
gravity_prepared_test_utils::global_norm(right, communicator),
|
||||
100.0 * std::numeric_limits<double>::epsilon()}
|
||||
);
|
||||
|
||||
return gravity_prepared_test_utils::global_norm(difference, communicator) / scale;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
mean_field::operators::context::pressure_force::PressureForceDependencies make_dependencies() {
|
||||
return {
|
||||
.discretization = {.identity = 101, .revision = 7},
|
||||
.enthalpy = {.identity = 103, .revision = 11},
|
||||
.displacement = {.identity = 107, .revision = 13}
|
||||
};
|
||||
}
|
||||
} // namespace pressure_force_context_test_utils
|
||||
|
||||
TEST_CASE(
|
||||
"Pressure Force Context Applies Selective Invalidation In FieldDof Coordinates",
|
||||
tags::barotrope &tags::pressure &tags::prepared &tags::field &tags::unit
|
||||
) {
|
||||
mean_field::utils::Args args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
REQUIRE(f.okay());
|
||||
|
||||
const pressure_force_context_test_utils::Maps maps(f);
|
||||
|
||||
mean_field::operators::context::pressure_force::PressureForceLinearizationContext context(
|
||||
f, *f.domainMapperStateless, maps.enthalpy, maps.displacement
|
||||
);
|
||||
|
||||
mfem::Vector enthalpy = maps.enthalpy.gather(pressure_force_context_test_utils::make_enthalpy_true(f, 0.23));
|
||||
|
||||
const mfem::Vector initialDisplacement =
|
||||
maps.displacement.gather(gravity_prepared_test_utils::make_displacement(f, 0.41));
|
||||
|
||||
const mfem::Vector changedDisplacement =
|
||||
maps.displacement.gather(gravity_prepared_test_utils::make_displacement(f, 0.79));
|
||||
|
||||
mfem::Vector displacement(initialDisplacement);
|
||||
|
||||
auto dependencies = pressure_force_context_test_utils::make_dependencies();
|
||||
|
||||
const mean_field::operators::context::pressure_force::PressureForceStateView state{
|
||||
.enthalpy = enthalpy, .displacement = displacement
|
||||
};
|
||||
|
||||
CHECK_FALSE(context.IsPrepared());
|
||||
|
||||
const auto initialReport = context.Prepare(state, dependencies);
|
||||
|
||||
REQUIRE(context.IsPrepared());
|
||||
|
||||
CHECK(context.MatchesDependencies(dependencies));
|
||||
|
||||
CHECK(initialReport.DidAnyWork());
|
||||
|
||||
CHECK(initialReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(initialReport.preparedGeometryState);
|
||||
|
||||
CHECK(initialReport.preparedMaterialState);
|
||||
|
||||
CHECK(initialReport.updatedEnthalpy);
|
||||
|
||||
CHECK(initialReport.updatedDisplacement);
|
||||
|
||||
REQUIRE(maps.enthalpy.reduced_size() < maps.enthalpy.full_size());
|
||||
|
||||
CHECK(maps.displacement.is_identity());
|
||||
|
||||
CHECK(context.GetBaseEnthalpy().Size() == maps.enthalpy.reduced_size());
|
||||
|
||||
CHECK(context.GetDisplacement().Size() == maps.displacement.reduced_size());
|
||||
|
||||
const auto unchangedReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK_FALSE(unchangedReport.DidAnyWork());
|
||||
|
||||
const mfem::Vector frozenEnthalpy(context.GetBaseEnthalpy());
|
||||
|
||||
const mfem::Vector frozenDisplacement(context.GetDisplacement());
|
||||
|
||||
enthalpy(0) += 0.125;
|
||||
|
||||
displacement = changedDisplacement;
|
||||
|
||||
const auto unstampedReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK_FALSE(unstampedReport.DidAnyWork());
|
||||
|
||||
CHECK(
|
||||
pressure_force_context_test_utils::relative_difference(
|
||||
context.GetBaseEnthalpy(), frozenEnthalpy, f.mesh->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
|
||||
CHECK(
|
||||
pressure_force_context_test_utils::relative_difference(
|
||||
context.GetDisplacement(), frozenDisplacement, f.mesh->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
|
||||
++dependencies.enthalpy.revision;
|
||||
|
||||
const auto enthalpyReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK(enthalpyReport.DidAnyWork());
|
||||
|
||||
CHECK_FALSE(enthalpyReport.preparedStaticDependencies);
|
||||
|
||||
CHECK_FALSE(enthalpyReport.preparedGeometryState);
|
||||
|
||||
CHECK(enthalpyReport.preparedMaterialState);
|
||||
|
||||
CHECK(enthalpyReport.updatedEnthalpy);
|
||||
|
||||
CHECK_FALSE(enthalpyReport.updatedDisplacement);
|
||||
|
||||
CHECK(context.GetBaseEnthalpy()(0) == enthalpy(0));
|
||||
|
||||
CHECK(
|
||||
pressure_force_context_test_utils::relative_difference(
|
||||
context.GetDisplacement(), frozenDisplacement, f.mesh->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
|
||||
++dependencies.displacement.revision;
|
||||
|
||||
const auto displacementReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK(displacementReport.DidAnyWork());
|
||||
|
||||
CHECK_FALSE(displacementReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(displacementReport.preparedGeometryState);
|
||||
|
||||
CHECK(displacementReport.preparedMaterialState);
|
||||
|
||||
CHECK_FALSE(displacementReport.updatedEnthalpy);
|
||||
|
||||
CHECK(displacementReport.updatedDisplacement);
|
||||
|
||||
CHECK(
|
||||
pressure_force_context_test_utils::relative_difference(
|
||||
context.GetDisplacement(), changedDisplacement, f.mesh->GetComm()
|
||||
) == 0.0
|
||||
);
|
||||
|
||||
++dependencies.discretization.revision;
|
||||
|
||||
const auto discretizationReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK(discretizationReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(discretizationReport.preparedGeometryState);
|
||||
|
||||
CHECK(discretizationReport.preparedMaterialState);
|
||||
|
||||
CHECK(discretizationReport.updatedEnthalpy);
|
||||
|
||||
CHECK(discretizationReport.updatedDisplacement);
|
||||
|
||||
const auto &statistics = context.GetPreparationStatistics();
|
||||
|
||||
CHECK(statistics.staticPreparations == 2);
|
||||
|
||||
CHECK(statistics.geometryPreparations == 3);
|
||||
|
||||
CHECK(statistics.materialPreparations == 4);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Pressure Force Context Uses Identity And Revision In Every Dependency",
|
||||
tags::barotrope &tags::pressure &tags::prepared &tags::field &tags::unit
|
||||
) {
|
||||
mean_field::utils::Args args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
REQUIRE(f.okay());
|
||||
|
||||
const pressure_force_context_test_utils::Maps maps(f);
|
||||
|
||||
mean_field::operators::context::pressure_force::PressureForceLinearizationContext context(
|
||||
f, *f.domainMapperStateless, maps.enthalpy, maps.displacement
|
||||
);
|
||||
|
||||
const mfem::Vector enthalpy = maps.enthalpy.gather(pressure_force_context_test_utils::make_enthalpy_true(f, 0.61));
|
||||
|
||||
const mfem::Vector displacement = maps.displacement.gather(gravity_prepared_test_utils::make_displacement(f, 0.73));
|
||||
|
||||
const mean_field::operators::context::pressure_force::PressureForceStateView state{
|
||||
.enthalpy = enthalpy, .displacement = displacement
|
||||
};
|
||||
|
||||
auto dependencies = pressure_force_context_test_utils::make_dependencies();
|
||||
|
||||
context.Prepare(state, dependencies);
|
||||
|
||||
++dependencies.enthalpy.identity;
|
||||
|
||||
dependencies.enthalpy.revision = 0;
|
||||
|
||||
const auto enthalpyIdentityReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK_FALSE(enthalpyIdentityReport.preparedStaticDependencies);
|
||||
|
||||
CHECK_FALSE(enthalpyIdentityReport.preparedGeometryState);
|
||||
|
||||
CHECK(enthalpyIdentityReport.preparedMaterialState);
|
||||
|
||||
CHECK(enthalpyIdentityReport.updatedEnthalpy);
|
||||
|
||||
CHECK_FALSE(enthalpyIdentityReport.updatedDisplacement);
|
||||
|
||||
++dependencies.displacement.identity;
|
||||
|
||||
dependencies.displacement.revision = 0;
|
||||
|
||||
const auto displacementIdentityReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK_FALSE(displacementIdentityReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(displacementIdentityReport.preparedGeometryState);
|
||||
|
||||
CHECK(displacementIdentityReport.preparedMaterialState);
|
||||
|
||||
CHECK_FALSE(displacementIdentityReport.updatedEnthalpy);
|
||||
|
||||
CHECK(displacementIdentityReport.updatedDisplacement);
|
||||
|
||||
++dependencies.discretization.identity;
|
||||
|
||||
dependencies.discretization.revision = 0;
|
||||
|
||||
const auto discretizationIdentityReport = context.Prepare(state, dependencies);
|
||||
|
||||
CHECK(discretizationIdentityReport.preparedStaticDependencies);
|
||||
|
||||
CHECK(discretizationIdentityReport.preparedGeometryState);
|
||||
|
||||
CHECK(discretizationIdentityReport.preparedMaterialState);
|
||||
|
||||
CHECK(discretizationIdentityReport.updatedEnthalpy);
|
||||
|
||||
CHECK(discretizationIdentityReport.updatedDisplacement);
|
||||
|
||||
CHECK(context.MatchesDependencies(dependencies));
|
||||
|
||||
const auto &statistics = context.GetPreparationStatistics();
|
||||
|
||||
CHECK(statistics.staticPreparations == 2);
|
||||
|
||||
CHECK(statistics.geometryPreparations == 3);
|
||||
|
||||
CHECK(statistics.materialPreparations == 4);
|
||||
}
|
||||
181
tests/operators/contexts/rotation_displacement_force_context.cpp
Normal file
181
tests/operators/contexts/rotation_displacement_force_context.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
import mean_field;
|
||||
import test_helpers;
|
||||
|
||||
namespace rotational_displacement_force_context_test_utils {
|
||||
using Context =
|
||||
mean_field::operators::context::rotational_displacement_force::RotationalDisplacementForceLinearizationContext;
|
||||
|
||||
using Dependencies =
|
||||
mean_field::operators::context::rotational_displacement_force::RotationalDisplacementForceDependencies;
|
||||
|
||||
[[nodiscard]] Dependencies make_dependencies() {
|
||||
return {
|
||||
.discretization = {.identity = 101, .revision = 3},
|
||||
.density = {.identity = 103, .revision = 5},
|
||||
.displacement = {.identity = 107, .revision = 7},
|
||||
.rotation = {.identity = 109, .revision = 11}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Vector make_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const double offset
|
||||
) {
|
||||
mfem::ParGridFunction density(f.densityFes.get());
|
||||
|
||||
mfem::FunctionCoefficient coefficient([offset](const mfem::Vector &position) {
|
||||
return offset + 0.04 * position(0) - 0.03 * position(1) + 0.02 * position(2);
|
||||
});
|
||||
|
||||
density.ProjectCoefficient(coefficient);
|
||||
|
||||
mfem::Vector densityTrue;
|
||||
density.GetTrueDofs(densityTrue);
|
||||
return densityTrue;
|
||||
}
|
||||
|
||||
[[nodiscard]] double relative_difference(
|
||||
const mfem::Vector &left,
|
||||
const mfem::Vector &right
|
||||
) {
|
||||
mfem::Vector difference(left);
|
||||
difference -= right;
|
||||
|
||||
return difference.Norml2() / std::max(right.Norml2(), 1.0e-30);
|
||||
}
|
||||
} // namespace rotational_displacement_force_context_test_utils
|
||||
|
||||
TEST_CASE(
|
||||
"Rotational Displacement Force Context Applies Selective Invalidation",
|
||||
tags::centrifugal &tags::contexts &tags::unit
|
||||
) {
|
||||
mean_field::utils::Args args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
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();
|
||||
|
||||
rotational_displacement_force_context_test_utils::Context context(f, *f.domainMapperStateless);
|
||||
|
||||
const auto initialReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
REQUIRE(context.IsPrepared());
|
||||
CHECK(context.MatchesDependencies(dependencies));
|
||||
CHECK(initialReport.preparedStaticDependencies);
|
||||
CHECK(initialReport.preparedGeometryState);
|
||||
CHECK(initialReport.preparedRotationDependencies);
|
||||
CHECK(initialReport.preparedBaseState);
|
||||
CHECK(initialReport.updatedDensity);
|
||||
CHECK(initialReport.updatedDisplacement);
|
||||
|
||||
CHECK(
|
||||
rotational_displacement_force_context_test_utils::relative_difference(context.GetBaseDensityTrue(), density) <
|
||||
1.0e-14
|
||||
);
|
||||
|
||||
CHECK(
|
||||
rotational_displacement_force_context_test_utils::relative_difference(
|
||||
context.GetDisplacementTrue(), displacement
|
||||
) < 1.0e-14
|
||||
);
|
||||
|
||||
const auto unchangedReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
CHECK_FALSE(unchangedReport.DidAnyWork());
|
||||
|
||||
density = rotational_displacement_force_context_test_utils::make_density(f, 1.17);
|
||||
|
||||
++dependencies.density.revision;
|
||||
|
||||
const auto densityReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
CHECK_FALSE(densityReport.preparedStaticDependencies);
|
||||
CHECK_FALSE(densityReport.preparedGeometryState);
|
||||
CHECK_FALSE(densityReport.preparedRotationDependencies);
|
||||
CHECK(densityReport.preparedBaseState);
|
||||
CHECK(densityReport.updatedDensity);
|
||||
CHECK_FALSE(densityReport.updatedDisplacement);
|
||||
|
||||
const mfem::Vector densityAfterDensityRevision(context.GetBaseDensityTrue());
|
||||
|
||||
displacement = gravity_prepared_test_utils::make_displacement(f, 0.81);
|
||||
|
||||
++dependencies.displacement.revision;
|
||||
|
||||
const auto displacementReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
CHECK_FALSE(displacementReport.preparedStaticDependencies);
|
||||
CHECK(displacementReport.preparedGeometryState);
|
||||
CHECK_FALSE(displacementReport.preparedRotationDependencies);
|
||||
CHECK(displacementReport.preparedBaseState);
|
||||
CHECK_FALSE(displacementReport.updatedDensity);
|
||||
CHECK(displacementReport.updatedDisplacement);
|
||||
|
||||
CHECK(
|
||||
rotational_displacement_force_context_test_utils::relative_difference(
|
||||
context.GetBaseDensityTrue(), densityAfterDensityRevision
|
||||
) < 1.0e-14
|
||||
);
|
||||
|
||||
++dependencies.rotation.revision;
|
||||
|
||||
const auto rotationReport = context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
CHECK_FALSE(rotationReport.preparedStaticDependencies);
|
||||
CHECK_FALSE(rotationReport.preparedGeometryState);
|
||||
CHECK(rotationReport.preparedRotationDependencies);
|
||||
CHECK(rotationReport.preparedBaseState);
|
||||
CHECK_FALSE(rotationReport.updatedDensity);
|
||||
CHECK_FALSE(rotationReport.updatedDisplacement);
|
||||
|
||||
const auto statistics = context.GetPreparationStatistics();
|
||||
|
||||
CHECK(statistics.staticPreparations == 1);
|
||||
CHECK(statistics.geometryPreparations == 2);
|
||||
CHECK(statistics.rotationPreparations == 2);
|
||||
CHECK(statistics.baseStatePreparations == 4);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Rotational Displacement Force Context Treats New Identities As New "
|
||||
"Dependency Streams",
|
||||
tags::centrifugal &tags::contexts &tags::unit
|
||||
) {
|
||||
mean_field::utils::Args args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
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();
|
||||
|
||||
rotational_displacement_force_context_test_utils::Context context(f, *f.domainMapperStateless);
|
||||
|
||||
context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
dependencies.density.identity += 1000;
|
||||
dependencies.density.revision = 0;
|
||||
|
||||
const auto report = context.Prepare({.density = density, .displacement = displacement}, dependencies);
|
||||
|
||||
CHECK(report.preparedBaseState);
|
||||
CHECK(report.updatedDensity);
|
||||
CHECK_FALSE(report.preparedGeometryState);
|
||||
CHECK_FALSE(report.preparedRotationDependencies);
|
||||
}
|
||||
Reference in New Issue
Block a user