feat(libmeanfield): centrifugal + pressure
This commit is contained in:
995
tests/operators/prepared_barotropic_closure.cpp
Normal file
995
tests/operators/prepared_barotropic_closure.cpp
Normal file
@@ -0,0 +1,995 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mfem.hpp>
|
||||
|
||||
import mean_field;
|
||||
import test_helpers;
|
||||
|
||||
namespace {
|
||||
mfem::Vector project_scalar(
|
||||
mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
mfem::Coefficient &coefficient
|
||||
) {
|
||||
mfem::ParGridFunction field(&finiteElementSpace);
|
||||
|
||||
field.ProjectCoefficient(coefficient);
|
||||
|
||||
mfem::Vector trueVector;
|
||||
field.GetTrueDofs(trueVector);
|
||||
return trueVector;
|
||||
}
|
||||
|
||||
mfem::Vector make_base_density(const mean_field::fem::FEM &f) {
|
||||
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
||||
return 0.42 + 0.025 * position(0) - 0.012 * position(1) +
|
||||
0.007 * position(2);
|
||||
});
|
||||
|
||||
return project_scalar(*f.densityFes, coefficient);
|
||||
}
|
||||
|
||||
mfem::Vector make_base_enthalpy(const mean_field::fem::FEM &f) {
|
||||
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
||||
return 0.92 + 0.018 * position(0) - 0.011 * position(1) +
|
||||
0.006 * position(2);
|
||||
});
|
||||
|
||||
return project_scalar(*f.enthalpyFes, coefficient);
|
||||
}
|
||||
|
||||
mfem::Vector make_enthalpy_variation(const mean_field::fem::FEM &f) {
|
||||
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
||||
return 0.065 + 0.014 * position(0) + 0.009 * position(2);
|
||||
});
|
||||
|
||||
return project_scalar(*f.enthalpyFes, coefficient);
|
||||
}
|
||||
|
||||
mfem::Vector make_combined_variation(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &enthalpyVariation
|
||||
) {
|
||||
mfem::Vector combinedVariation(
|
||||
densityVariation.Size() + enthalpyVariation.Size()
|
||||
);
|
||||
|
||||
for (int densityDof = 0; densityDof < densityVariation.Size();
|
||||
++densityDof) {
|
||||
combinedVariation(densityDof) = densityVariation(densityDof);
|
||||
}
|
||||
|
||||
for (int enthalpyDof = 0; enthalpyDof < enthalpyVariation.Size();
|
||||
++enthalpyDof) {
|
||||
combinedVariation(densityVariation.Size() + enthalpyDof) =
|
||||
enthalpyVariation(enthalpyDof);
|
||||
}
|
||||
|
||||
return combinedVariation;
|
||||
}
|
||||
struct ClosureCondition {
|
||||
const char *name;
|
||||
|
||||
double polytropicIndex;
|
||||
double polytropicConstant;
|
||||
|
||||
double enthalpyOffset;
|
||||
double enthalpyGradient;
|
||||
|
||||
double densityFactor;
|
||||
double densityOffset;
|
||||
double densityGradient;
|
||||
|
||||
double deformationScale;
|
||||
double directionPhase;
|
||||
};
|
||||
|
||||
inline constexpr std::array<ClosureCondition, 3> conditions{
|
||||
{{.name = "Linear barotrope on identity geometry",
|
||||
.polytropicIndex = 1.0,
|
||||
.polytropicConstant = 0.8,
|
||||
.enthalpyOffset = 0.65,
|
||||
.enthalpyGradient = 0.06,
|
||||
.densityFactor = 0.80,
|
||||
.densityOffset = 0.015,
|
||||
.densityGradient = 0.004,
|
||||
.deformationScale = 0.0,
|
||||
.directionPhase = 0.31},
|
||||
{.name = "Fractional barotrope on moderate deformation",
|
||||
.polytropicIndex = 1.5,
|
||||
.polytropicConstant = 1.2,
|
||||
.enthalpyOffset = 0.90,
|
||||
.enthalpyGradient = 0.09,
|
||||
.densityFactor = 1.15,
|
||||
.densityOffset = -0.003,
|
||||
.densityGradient = 0.003,
|
||||
.deformationScale = 0.45,
|
||||
.directionPhase = 0.53},
|
||||
{.name = "Target n=3 barotrope on strong deformation",
|
||||
.polytropicIndex = 3.0,
|
||||
.polytropicConstant = 1.5,
|
||||
.enthalpyOffset = 1.20,
|
||||
.enthalpyGradient = 0.12,
|
||||
.densityFactor = 1.40,
|
||||
.densityOffset = 0.006,
|
||||
.densityGradient = 0.002,
|
||||
.deformationScale = 1.0,
|
||||
.directionPhase = 0.79}}
|
||||
};
|
||||
|
||||
double evaluate_enthalpy(
|
||||
const mfem::Vector &position,
|
||||
const ClosureCondition &condition
|
||||
) {
|
||||
return condition.enthalpyOffset +
|
||||
condition.enthalpyGradient *
|
||||
(0.50 * position(0) - 0.30 * position(1) +
|
||||
0.20 * position(2));
|
||||
}
|
||||
|
||||
mfem::Vector project_scalar_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_enthalpy(
|
||||
const mean_field::fem::FEM &f,
|
||||
const ClosureCondition &condition
|
||||
) {
|
||||
mfem::FunctionCoefficient coefficient(
|
||||
[condition](const mfem::Vector &position) {
|
||||
return evaluate_enthalpy(position, condition);
|
||||
}
|
||||
);
|
||||
|
||||
return project_scalar_field(*f.enthalpyFes, coefficient);
|
||||
}
|
||||
|
||||
mfem::Vector make_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const ClosureCondition &condition
|
||||
) {
|
||||
mfem::FunctionCoefficient coefficient(
|
||||
[&barotrope, condition](const mfem::Vector &position) {
|
||||
const double enthalpy = evaluate_enthalpy(position, condition);
|
||||
|
||||
return condition.densityFactor *
|
||||
barotrope.density_from_enthalpy(enthalpy) +
|
||||
condition.densityOffset +
|
||||
condition.densityGradient *
|
||||
(0.40 * position(0) + 0.25 * position(1) -
|
||||
0.15 * position(2));
|
||||
}
|
||||
);
|
||||
|
||||
return project_scalar_field(*f.densityFes, coefficient);
|
||||
}
|
||||
|
||||
mfem::Vector make_constant_field(
|
||||
mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const double value
|
||||
) {
|
||||
mfem::ConstantCoefficient coefficient(value);
|
||||
|
||||
return project_scalar_field(finiteElementSpace, coefficient);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Matches Stateless Kernels",
|
||||
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::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
|
||||
REQUIRE_FALSE(preparedOperator.IsPrepared());
|
||||
REQUIRE(preparedOperator.Height() == f.densityFes->GetTrueVSize());
|
||||
REQUIRE(
|
||||
preparedOperator.Width() ==
|
||||
f.densityFes->GetTrueVSize() + f.enthalpyFes->GetTrueVSize()
|
||||
);
|
||||
REQUIRE(preparedOperator.GetDensitySize() == f.densityFes->GetTrueVSize());
|
||||
REQUIRE(
|
||||
preparedOperator.GetEnthalpySize() == f.enthalpyFes->GetTrueVSize()
|
||||
);
|
||||
|
||||
const mfem::Vector baseDensity = make_base_density(f);
|
||||
|
||||
const mfem::Vector baseEnthalpy = make_base_enthalpy(f);
|
||||
|
||||
const mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||
|
||||
const mfem::Vector densityVariation =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), 0.43
|
||||
);
|
||||
|
||||
const mfem::Vector displacementVariation =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.63);
|
||||
|
||||
const mfem::Vector enthalpyVariation = make_enthalpy_variation(f);
|
||||
|
||||
mfem::Vector zeroDensity(f.densityFes->GetTrueVSize());
|
||||
zeroDensity = 0.0;
|
||||
|
||||
mfem::Vector zeroEnthalpy(f.enthalpyFes->GetTrueVSize());
|
||||
zeroEnthalpy = 0.0;
|
||||
|
||||
preparedOperator.Prepare(baseDensity, baseEnthalpy, displacement);
|
||||
|
||||
mfem::Vector preparedResidual;
|
||||
mfem::Vector preparedDensityAction;
|
||||
mfem::Vector preparedEnthalpyAction;
|
||||
mfem::Vector preparedSplitAction;
|
||||
mfem::Vector preparedCombinedAction;
|
||||
|
||||
preparedOperator.BuildResidual(preparedResidual);
|
||||
|
||||
preparedOperator.Mult(
|
||||
densityVariation, zeroEnthalpy, displacementVariation,
|
||||
preparedDensityAction
|
||||
);
|
||||
|
||||
preparedOperator.Mult(
|
||||
zeroDensity, enthalpyVariation, displacementVariation,
|
||||
preparedEnthalpyAction
|
||||
);
|
||||
|
||||
preparedOperator.Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation,
|
||||
preparedSplitAction
|
||||
);
|
||||
|
||||
const mfem::Vector combinedVariation =
|
||||
make_combined_variation(densityVariation, enthalpyVariation);
|
||||
|
||||
preparedOperator.Mult(combinedVariation, preparedCombinedAction);
|
||||
|
||||
mfem::Vector referenceResidual;
|
||||
mfem::Vector referenceDensityAction;
|
||||
mfem::Vector referenceEnthalpyAction;
|
||||
mfem::Vector referenceDisplacementAction;
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, baseDensity, baseEnthalpy,
|
||||
displacement, referenceResidual
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure_density_action(
|
||||
f, *f.domainMapperStateless, barotrope, densityVariation, displacement,
|
||||
referenceDensityAction
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure_enthalpy_action(
|
||||
f, *f.domainMapperStateless, barotrope, baseEnthalpy, enthalpyVariation,
|
||||
displacement, referenceEnthalpyAction
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::
|
||||
apply_barotropic_closure_displacement_action(
|
||||
f, *f.domainMapperStateless, barotrope, baseDensity, baseEnthalpy,
|
||||
displacement, displacementVariation, referenceDisplacementAction
|
||||
);
|
||||
|
||||
mfem::Vector referenceCombinedAction(referenceDensityAction);
|
||||
referenceCombinedAction += referenceEnthalpyAction;
|
||||
referenceCombinedAction += referenceDisplacementAction;
|
||||
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
const double residualError = gravity_prepared_test_utils::relative_error(
|
||||
preparedResidual, referenceResidual, communicator
|
||||
);
|
||||
|
||||
const double densityError = gravity_prepared_test_utils::relative_error(
|
||||
preparedDensityAction, referenceDensityAction, communicator
|
||||
);
|
||||
|
||||
const double enthalpyError = gravity_prepared_test_utils::relative_error(
|
||||
preparedEnthalpyAction, referenceEnthalpyAction, communicator
|
||||
);
|
||||
|
||||
const double splitError = gravity_prepared_test_utils::relative_error(
|
||||
preparedSplitAction, referenceCombinedAction, communicator
|
||||
);
|
||||
|
||||
const double combinedError = gravity_prepared_test_utils::relative_error(
|
||||
preparedCombinedAction, referenceCombinedAction, communicator
|
||||
);
|
||||
|
||||
INFO("Prepared residual error = " << residualError);
|
||||
INFO("Prepared density-action error = " << densityError);
|
||||
INFO("Prepared enthalpy-action error = " << enthalpyError);
|
||||
INFO("Prepared split-action error = " << splitError);
|
||||
INFO("Prepared combined-action error = " << combinedError);
|
||||
|
||||
CHECK(preparedOperator.IsPrepared());
|
||||
CHECK(preparedOperator.GetPreparationCount() == 1);
|
||||
CHECK(residualError < 2.0e-12);
|
||||
CHECK(densityError < 2.0e-12);
|
||||
CHECK(enthalpyError < 2.0e-12);
|
||||
CHECK(splitError < 2.0e-12);
|
||||
CHECK(combinedError < 2.0e-12);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Jacobian Matches Centered Difference",
|
||||
tags::hydro &tags::jacobian &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);
|
||||
|
||||
mfem::Vector baseDensity = make_base_density(f);
|
||||
|
||||
mfem::Vector baseEnthalpy = make_base_enthalpy(f);
|
||||
|
||||
const mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||
|
||||
const mfem::Vector densityVariation =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), 0.71
|
||||
);
|
||||
|
||||
const mfem::Vector displacementVariation =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.63);
|
||||
|
||||
const mfem::Vector enthalpyVariation = make_enthalpy_variation(f);
|
||||
|
||||
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
|
||||
preparedOperator.Prepare(baseDensity, baseEnthalpy, displacement);
|
||||
|
||||
mfem::Vector analyticAction;
|
||||
|
||||
preparedOperator.Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation,
|
||||
analyticAction
|
||||
);
|
||||
|
||||
constexpr double differenceStep = 1.0e-6;
|
||||
|
||||
const mfem::Vector plusDensity =
|
||||
gravity_prepared_test_utils::linear_combination(
|
||||
baseDensity, 1.0, densityVariation, differenceStep
|
||||
);
|
||||
|
||||
const mfem::Vector minusDensity =
|
||||
gravity_prepared_test_utils::linear_combination(
|
||||
baseDensity, 1.0, densityVariation, -differenceStep
|
||||
);
|
||||
|
||||
const mfem::Vector plusEnthalpy =
|
||||
gravity_prepared_test_utils::linear_combination(
|
||||
baseEnthalpy, 1.0, enthalpyVariation, differenceStep
|
||||
);
|
||||
|
||||
const mfem::Vector minusEnthalpy =
|
||||
gravity_prepared_test_utils::linear_combination(
|
||||
baseEnthalpy, 1.0, enthalpyVariation, -differenceStep
|
||||
);
|
||||
|
||||
mfem::Vector plusResidual;
|
||||
mfem::Vector minusResidual;
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, plusDensity, plusEnthalpy,
|
||||
displacement, plusResidual
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, minusDensity, minusEnthalpy,
|
||||
displacement, minusResidual
|
||||
);
|
||||
|
||||
mfem::Vector finiteDifference(plusResidual);
|
||||
finiteDifference -= minusResidual;
|
||||
finiteDifference *= 1.0 / (2.0 * differenceStep);
|
||||
|
||||
const double relativeError = gravity_prepared_test_utils::relative_error(
|
||||
analyticAction, finiteDifference, f.mesh->GetComm()
|
||||
);
|
||||
|
||||
INFO("Prepared EOS centered-difference error = " << relativeError);
|
||||
|
||||
CHECK(relativeError < 2.0e-8);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Reuses Frozen Data",
|
||||
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::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
|
||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||
CHECK(preparedOperator.GetPreparationCount() == 0);
|
||||
|
||||
mfem::Vector baseDensity = make_base_density(f);
|
||||
|
||||
mfem::Vector baseEnthalpy = make_base_enthalpy(f);
|
||||
|
||||
mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||
|
||||
const mfem::Vector displacementVariation =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.63);
|
||||
|
||||
const mfem::Vector densityVariation =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), 0.31
|
||||
);
|
||||
|
||||
const mfem::Vector enthalpyVariation = make_enthalpy_variation(f);
|
||||
|
||||
preparedOperator.Prepare(baseDensity, baseEnthalpy, displacement);
|
||||
|
||||
REQUIRE(preparedOperator.IsPrepared());
|
||||
REQUIRE(preparedOperator.GetPreparationCount() == 1);
|
||||
|
||||
mfem::Vector firstResidual;
|
||||
mfem::Vector firstAction;
|
||||
|
||||
preparedOperator.BuildResidual(firstResidual);
|
||||
|
||||
preparedOperator.Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation, firstAction
|
||||
);
|
||||
|
||||
baseDensity = 7.0;
|
||||
baseEnthalpy = 3.0;
|
||||
displacement *= -4.0;
|
||||
|
||||
const std::uint64_t preparationCount =
|
||||
preparedOperator.GetPreparationCount();
|
||||
|
||||
mfem::Vector repeatedResidual;
|
||||
mfem::Vector repeatedAction;
|
||||
|
||||
preparedOperator.BuildResidual(repeatedResidual);
|
||||
|
||||
preparedOperator.Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation,
|
||||
repeatedAction
|
||||
);
|
||||
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
const double residualReuseError =
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
repeatedResidual, firstResidual, communicator
|
||||
);
|
||||
|
||||
const double actionReuseError = gravity_prepared_test_utils::relative_error(
|
||||
repeatedAction, firstAction, communicator
|
||||
);
|
||||
|
||||
INFO("Frozen residual reuse error = " << residualReuseError);
|
||||
INFO("Frozen action reuse error = " << actionReuseError);
|
||||
|
||||
CHECK(residualReuseError < 2.0e-14);
|
||||
CHECK(actionReuseError < 2.0e-14);
|
||||
CHECK(preparedOperator.GetPreparationCount() == preparationCount);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Reprepares For New Geometry",
|
||||
tags::hydro &tags::mapping &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);
|
||||
|
||||
const mfem::Vector baseDensity = make_base_density(f);
|
||||
|
||||
const mfem::Vector baseEnthalpy = make_base_enthalpy(f);
|
||||
|
||||
const mfem::Vector densityVariation =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), 0.59
|
||||
);
|
||||
|
||||
mfem::Vector zeroEnthalpy(f.enthalpyFes->GetTrueVSize());
|
||||
zeroEnthalpy = 0.0;
|
||||
|
||||
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
|
||||
mfem::Vector identityAction;
|
||||
mfem::Vector deformedAction;
|
||||
|
||||
for (const double deformationScale : {0.0, 1.0}) {
|
||||
const mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(f, deformationScale);
|
||||
|
||||
const mfem::Vector displacementVariation =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.63);
|
||||
|
||||
preparedOperator.Prepare(baseDensity, baseEnthalpy, displacement);
|
||||
|
||||
mfem::Vector preparedResidual;
|
||||
mfem::Vector preparedAction;
|
||||
mfem::Vector referenceResidual;
|
||||
mfem::Vector referenceAction;
|
||||
|
||||
preparedOperator.BuildResidual(preparedResidual);
|
||||
|
||||
preparedOperator.Mult(
|
||||
densityVariation, zeroEnthalpy, displacementVariation,
|
||||
preparedAction
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, baseDensity, baseEnthalpy,
|
||||
displacement, referenceResidual
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure_density_action(
|
||||
f, *f.domainMapperStateless, barotrope, densityVariation,
|
||||
displacement, referenceAction
|
||||
);
|
||||
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
const double residualError =
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
preparedResidual, referenceResidual, communicator
|
||||
);
|
||||
|
||||
const double actionError = gravity_prepared_test_utils::relative_error(
|
||||
preparedAction, referenceAction, communicator
|
||||
);
|
||||
|
||||
INFO("Deformation scale = " << deformationScale);
|
||||
INFO("Reprepared residual error = " << residualError);
|
||||
INFO("Reprepared action error = " << actionError);
|
||||
|
||||
CHECK(residualError < 2.0e-12);
|
||||
CHECK(actionError < 2.0e-12);
|
||||
|
||||
if (deformationScale == 0.0) {
|
||||
identityAction = preparedAction;
|
||||
} else {
|
||||
deformedAction = preparedAction;
|
||||
}
|
||||
}
|
||||
|
||||
const double geometryChange = gravity_prepared_test_utils::relative_error(
|
||||
deformedAction, identityAction, f.mesh->GetComm()
|
||||
);
|
||||
|
||||
INFO("Prepared closure geometry change = " << geometryChange);
|
||||
|
||||
CHECK(preparedOperator.GetPreparationCount() == 2);
|
||||
CHECK(geometryChange > 1.0e-5);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Complete Barotropic Closure Matches Blocks And Centered Differences "
|
||||
"Across Conditions",
|
||||
tags::barotrope &tags::closure &tags::hydro &tags::integration
|
||||
&tags::jacobian &tags::mapping &tags::physics &tags::prepared
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f =
|
||||
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
REQUIRE(f.domainMapperStateless != nullptr);
|
||||
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
constexpr double differenceStep = 1.0e-5;
|
||||
|
||||
for (std::size_t conditionIndex = 0; conditionIndex <
|
||||
|
||||
conditions.size();
|
||||
++conditionIndex) {
|
||||
const auto &condition =
|
||||
|
||||
conditions[conditionIndex];
|
||||
|
||||
DYNAMIC_SECTION(condition.name) {
|
||||
const mean_field::physics::PolytropicBarotrope barotrope(
|
||||
condition.polytropicIndex, condition.polytropicConstant
|
||||
);
|
||||
|
||||
const mfem::Vector baseDensity =
|
||||
|
||||
make_density(f, barotrope, condition);
|
||||
|
||||
const mfem::Vector baseEnthalpy =
|
||||
|
||||
make_enthalpy(f, condition);
|
||||
|
||||
const mfem::Vector baseDisplacement =
|
||||
gravity_prepared_test_utils::make_displacement(
|
||||
f, condition.deformationScale
|
||||
);
|
||||
|
||||
mfem::Vector densityVariation =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.densityFes->GetTrueVSize(), condition.directionPhase
|
||||
);
|
||||
|
||||
mfem::Vector enthalpyVariation =
|
||||
gravity_prepared_test_utils::make_deterministic_vector(
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
condition.directionPhase + 0.27
|
||||
);
|
||||
|
||||
mfem::Vector displacementVariation =
|
||||
gravity_prepared_test_utils::make_displacement(
|
||||
f, condition.directionPhase
|
||||
);
|
||||
|
||||
mfem::Vector densityAction;
|
||||
mfem::Vector enthalpyAction;
|
||||
mfem::Vector displacementAction;
|
||||
|
||||
mean_field::operators::kernels::
|
||||
apply_barotropic_closure_density_action(
|
||||
f, *f.domainMapperStateless, barotrope, densityVariation,
|
||||
baseDisplacement, densityAction
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::
|
||||
apply_barotropic_closure_enthalpy_action(
|
||||
f, *f.domainMapperStateless, barotrope, baseEnthalpy,
|
||||
enthalpyVariation, baseDisplacement, enthalpyAction
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::
|
||||
apply_barotropic_closure_displacement_action(
|
||||
f, *f.domainMapperStateless, barotrope, baseDensity,
|
||||
baseEnthalpy, baseDisplacement, displacementVariation,
|
||||
displacementAction
|
||||
);
|
||||
|
||||
double densityActionNorm = gravity_prepared_test_utils::global_norm(
|
||||
densityAction, communicator
|
||||
);
|
||||
|
||||
double enthalpyActionNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
enthalpyAction, communicator
|
||||
);
|
||||
|
||||
double displacementActionNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
displacementAction, communicator
|
||||
);
|
||||
|
||||
REQUIRE(densityActionNorm > 1.0e-12);
|
||||
REQUIRE(enthalpyActionNorm > 1.0e-12);
|
||||
REQUIRE(displacementActionNorm > 1.0e-12);
|
||||
|
||||
const double targetActionNorm = std::min(
|
||||
{densityActionNorm, enthalpyActionNorm, displacementActionNorm}
|
||||
);
|
||||
|
||||
const double densityScale = targetActionNorm / densityActionNorm;
|
||||
|
||||
const double enthalpyScale = targetActionNorm / enthalpyActionNorm;
|
||||
|
||||
const double displacementScale =
|
||||
targetActionNorm / displacementActionNorm;
|
||||
|
||||
densityVariation *= densityScale;
|
||||
densityAction *= densityScale;
|
||||
|
||||
enthalpyVariation *= enthalpyScale;
|
||||
enthalpyAction *= enthalpyScale;
|
||||
|
||||
displacementVariation *= displacementScale;
|
||||
displacementAction *= displacementScale;
|
||||
|
||||
densityActionNorm = gravity_prepared_test_utils::global_norm(
|
||||
densityAction, communicator
|
||||
);
|
||||
|
||||
enthalpyActionNorm = gravity_prepared_test_utils::global_norm(
|
||||
enthalpyAction, communicator
|
||||
);
|
||||
|
||||
displacementActionNorm = gravity_prepared_test_utils::global_norm(
|
||||
displacementAction, communicator
|
||||
);
|
||||
|
||||
mean_field::operators::context::barotropic::
|
||||
BarotropicClosureLinearizationContext context(
|
||||
f, *f.domainMapperStateless, barotrope
|
||||
);
|
||||
|
||||
const std::uint64_t revisionBase =
|
||||
100 + static_cast<std::uint64_t>(10 * conditionIndex);
|
||||
|
||||
const mean_field::operators::context::barotropic::
|
||||
BarotropicClosureRevisions revisions{
|
||||
.density = revisionBase + 1,
|
||||
.enthalpy = revisionBase + 2,
|
||||
.displacement = revisionBase + 3
|
||||
};
|
||||
|
||||
context.Prepare(
|
||||
baseDensity, baseEnthalpy, baseDisplacement, revisions
|
||||
);
|
||||
|
||||
mfem::Vector preparedResidual;
|
||||
mfem::Vector referenceResidual;
|
||||
|
||||
context.BuildResidual(preparedResidual);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, baseDensity,
|
||||
baseEnthalpy, baseDisplacement, referenceResidual
|
||||
);
|
||||
|
||||
const double residualEvaluationError =
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
preparedResidual, referenceResidual, communicator
|
||||
);
|
||||
|
||||
mfem::Vector preparedAction;
|
||||
|
||||
context.GetOperator().Mult(
|
||||
densityVariation, enthalpyVariation, displacementVariation,
|
||||
preparedAction
|
||||
);
|
||||
|
||||
mfem::Vector blockSum(densityAction);
|
||||
|
||||
blockSum += enthalpyAction;
|
||||
blockSum += displacementAction;
|
||||
|
||||
const double blockAssemblyError =
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
preparedAction, blockSum, communicator
|
||||
);
|
||||
|
||||
mfem::Vector plusDensity(baseDensity);
|
||||
|
||||
mfem::Vector minusDensity(baseDensity);
|
||||
|
||||
mfem::Vector plusEnthalpy(baseEnthalpy);
|
||||
|
||||
mfem::Vector minusEnthalpy(baseEnthalpy);
|
||||
|
||||
mfem::Vector plusDisplacement(baseDisplacement);
|
||||
|
||||
mfem::Vector minusDisplacement(baseDisplacement);
|
||||
|
||||
plusDensity.Add(differenceStep, densityVariation);
|
||||
|
||||
minusDensity.Add(-differenceStep, densityVariation);
|
||||
|
||||
plusEnthalpy.Add(differenceStep, enthalpyVariation);
|
||||
|
||||
minusEnthalpy.Add(-differenceStep, enthalpyVariation);
|
||||
|
||||
plusDisplacement.Add(differenceStep, displacementVariation);
|
||||
|
||||
minusDisplacement.Add(-differenceStep, displacementVariation);
|
||||
|
||||
mfem::Vector plusResidual;
|
||||
mfem::Vector minusResidual;
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, plusDensity,
|
||||
plusEnthalpy, plusDisplacement, plusResidual
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, minusDensity,
|
||||
minusEnthalpy, minusDisplacement, minusResidual
|
||||
);
|
||||
|
||||
mfem::Vector finiteDifference(plusResidual);
|
||||
|
||||
finiteDifference -= minusResidual;
|
||||
|
||||
finiteDifference *= 1.0 / (2.0 * differenceStep);
|
||||
|
||||
mfem::Vector finiteDifferenceError(preparedAction);
|
||||
|
||||
finiteDifferenceError -= finiteDifference;
|
||||
|
||||
const double finiteDifferenceErrorNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
finiteDifferenceError, communicator
|
||||
);
|
||||
|
||||
const double blockNormSum =
|
||||
densityActionNorm + enthalpyActionNorm + displacementActionNorm;
|
||||
|
||||
const double blockScaledDifferenceError =
|
||||
finiteDifferenceErrorNorm / blockNormSum;
|
||||
|
||||
const double completeRelativeError =
|
||||
gravity_prepared_test_utils::relative_error(
|
||||
preparedAction, finiteDifference, communicator
|
||||
);
|
||||
|
||||
INFO("Condition = " << condition.name);
|
||||
|
||||
INFO("Polytropic index = " << condition.polytropicIndex);
|
||||
|
||||
INFO("Deformation scale = " << condition.deformationScale);
|
||||
|
||||
INFO("Prepared residual error = " << residualEvaluationError);
|
||||
|
||||
INFO("Complete block-assembly error = " << blockAssemblyError);
|
||||
|
||||
INFO("Density-action norm = " << densityActionNorm);
|
||||
|
||||
INFO("Enthalpy-action norm = " << enthalpyActionNorm);
|
||||
|
||||
INFO("Displacement-action norm = " << displacementActionNorm);
|
||||
|
||||
INFO(
|
||||
"Complete centered-difference relative error = "
|
||||
<< completeRelativeError
|
||||
);
|
||||
|
||||
INFO(
|
||||
"Block-scaled centered-difference error = "
|
||||
<< blockScaledDifferenceError
|
||||
);
|
||||
|
||||
CHECK(context.GetPreparationCount() == 1);
|
||||
CHECK(residualEvaluationError < 5.0e-12);
|
||||
CHECK(blockAssemblyError < 5.0e-12);
|
||||
CHECK(blockScaledDifferenceError < 2.0e-7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Exact Constant Barotropic Closure Remains Zero Under Deformation",
|
||||
tags::barotrope &tags::closure &tags::hydro &tags::integration
|
||||
&tags::jacobian &tags::mapping &tags::physics
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
|
||||
mean_field::fem::FEM f =
|
||||
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
|
||||
REQUIRE(f.domainMapperStateless != nullptr);
|
||||
|
||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.5);
|
||||
|
||||
constexpr double enthalpyValue = 1.20;
|
||||
|
||||
const double equilibriumDensityValue =
|
||||
barotrope.density_from_enthalpy(enthalpyValue);
|
||||
|
||||
const mfem::Vector enthalpy =
|
||||
make_constant_field(*f.enthalpyFes, enthalpyValue);
|
||||
|
||||
const mfem::Vector equilibriumDensity =
|
||||
make_constant_field(*f.densityFes, equilibriumDensityValue);
|
||||
|
||||
const mfem::Vector referenceDensity =
|
||||
make_constant_field(*f.densityFes, equilibriumDensityValue + 1.0);
|
||||
|
||||
const mfem::Vector displacementVariation =
|
||||
gravity_prepared_test_utils::make_displacement(f, 0.67);
|
||||
|
||||
const MPI_Comm communicator = f.mesh->GetComm();
|
||||
|
||||
for (const double deformationScale : {0.0, 0.5, 1.0}) {
|
||||
DYNAMIC_SECTION("Deformation scale = " << deformationScale) {
|
||||
const mfem::Vector displacement =
|
||||
gravity_prepared_test_utils::make_displacement(
|
||||
f, deformationScale
|
||||
);
|
||||
|
||||
mfem::Vector exactResidual;
|
||||
mfem::Vector referenceResidual;
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, equilibriumDensity,
|
||||
enthalpy, displacement, exactResidual
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::apply_barotropic_closure(
|
||||
f, *f.domainMapperStateless, barotrope, referenceDensity,
|
||||
enthalpy, displacement, referenceResidual
|
||||
);
|
||||
|
||||
mfem::Vector exactGeometryAction;
|
||||
mfem::Vector referenceGeometryAction;
|
||||
|
||||
mean_field::operators::kernels::
|
||||
apply_barotropic_closure_displacement_action(
|
||||
f, *f.domainMapperStateless, barotrope, equilibriumDensity,
|
||||
enthalpy, displacement, displacementVariation,
|
||||
exactGeometryAction
|
||||
);
|
||||
|
||||
mean_field::operators::kernels::
|
||||
apply_barotropic_closure_displacement_action(
|
||||
f, *f.domainMapperStateless, barotrope, referenceDensity,
|
||||
enthalpy, displacement, displacementVariation,
|
||||
referenceGeometryAction
|
||||
);
|
||||
|
||||
const double exactResidualNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
exactResidual, communicator
|
||||
);
|
||||
|
||||
const double referenceResidualNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
referenceResidual, communicator
|
||||
);
|
||||
|
||||
const double exactGeometryNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
exactGeometryAction, communicator
|
||||
);
|
||||
|
||||
const double referenceGeometryNorm =
|
||||
gravity_prepared_test_utils::global_norm(
|
||||
referenceGeometryAction, communicator
|
||||
);
|
||||
|
||||
INFO("Deformation scale = " << deformationScale);
|
||||
|
||||
INFO("Exact-closure residual norm = " << exactResidualNorm);
|
||||
|
||||
INFO("Reference residual norm = " << referenceResidualNorm);
|
||||
|
||||
INFO("Exact-closure geometry-action norm = " << exactGeometryNorm);
|
||||
|
||||
INFO("Reference geometry-action norm = " << referenceGeometryNorm);
|
||||
|
||||
REQUIRE(referenceResidualNorm > 1.0e-12);
|
||||
REQUIRE(referenceGeometryNorm > 1.0e-14);
|
||||
|
||||
CHECK(exactResidualNorm <= 5.0e-12 * referenceResidualNorm);
|
||||
|
||||
CHECK(exactGeometryNorm <= 5.0e-12 * referenceGeometryNorm);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user