987 lines
46 KiB
C++
987 lines
46 KiB
C++
#include <algorithm>
|
|
#include <array>
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <mfem.hpp>
|
|
#include <stdexcept>
|
|
#include <type_traits>
|
|
|
|
import mean_field;
|
|
import test_helpers;
|
|
|
|
namespace prepared_barotropic_closure_test_utils {
|
|
namespace field = mean_field::field;
|
|
namespace domain = mean_field::utils::domain;
|
|
|
|
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)
|
|
) {
|
|
}
|
|
};
|
|
|
|
using ClosureDependencies = mean_field::operators::context::barotropic::BarotropicClosureDependencies;
|
|
|
|
[[nodiscard]] ClosureDependencies make_dependencies(const std::uint64_t revisionOffset = 0) {
|
|
return {
|
|
.discretization = {.identity = 201, .revision = 3 + revisionOffset},
|
|
.density = {.identity = 211, .revision = 5 + revisionOffset},
|
|
.enthalpy = {.identity = 223, .revision = 7 + revisionOffset},
|
|
.displacement = {.identity = 227, .revision = 11 + revisionOffset}
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] mean_field::operators::context::barotropic::BarotropicClosureStateView make_state_view(
|
|
const mfem::Vector &density,
|
|
const mfem::Vector &enthalpy,
|
|
const mfem::Vector &displacement
|
|
) {
|
|
return {.density = density, .enthalpy = enthalpy, .displacement = displacement};
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector project_scalar(
|
|
mfem::ParFiniteElementSpace &finiteElementSpace,
|
|
mfem::Coefficient &coefficient
|
|
) {
|
|
mfem::ParGridFunction fieldValue(&finiteElementSpace);
|
|
fieldValue.ProjectCoefficient(coefficient);
|
|
|
|
mfem::Vector trueVector;
|
|
fieldValue.GetTrueDofs(trueVector);
|
|
return trueVector;
|
|
}
|
|
|
|
[[nodiscard]] 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);
|
|
}
|
|
|
|
[[nodiscard]] 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);
|
|
}
|
|
|
|
[[nodiscard]] 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);
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector make_constant_field(
|
|
mfem::ParFiniteElementSpace &finiteElementSpace,
|
|
const double value
|
|
) {
|
|
mfem::ConstantCoefficient coefficient(value);
|
|
return project_scalar(finiteElementSpace, coefficient);
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector make_folding_displacement(const mean_field::fem::FEM &f) {
|
|
mfem::ParGridFunction fieldValue(f.displacementFes.get());
|
|
mfem::VectorFunctionCoefficient coefficient(
|
|
f.mesh->Dimension(), [](const mfem::Vector &position, mfem::Vector &value) {
|
|
value.SetSize(position.Size());
|
|
value = 0.0;
|
|
value(0) = -2.0 * position(0);
|
|
}
|
|
);
|
|
fieldValue.ProjectCoefficient(coefficient);
|
|
|
|
mfem::Vector result;
|
|
fieldValue.GetTrueDofs(result);
|
|
return result;
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector reduce(
|
|
const field::FieldDofMap &map,
|
|
const mfem::Vector &full
|
|
) {
|
|
return map.gather(full);
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector expand(
|
|
const field::FieldDofMap &map,
|
|
const mfem::Vector &reduced
|
|
) {
|
|
return map.scatter(reduced);
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector make_combined_variation(
|
|
const mfem::Vector &densityVariation,
|
|
const mfem::Vector &enthalpyVariation,
|
|
const mfem::Vector &displacementVariation
|
|
) {
|
|
mfem::Vector combined(densityVariation.Size() + enthalpyVariation.Size() + displacementVariation.Size());
|
|
|
|
int offset = 0;
|
|
for (int index = 0; index < densityVariation.Size(); ++index) {
|
|
combined(offset + index) = densityVariation(index);
|
|
}
|
|
offset += densityVariation.Size();
|
|
|
|
for (int index = 0; index < enthalpyVariation.Size(); ++index) {
|
|
combined(offset + index) = enthalpyVariation(index);
|
|
}
|
|
offset += enthalpyVariation.Size();
|
|
|
|
for (int index = 0; index < displacementVariation.Size(); ++index) {
|
|
combined(offset + index) = displacementVariation(index);
|
|
}
|
|
|
|
return combined;
|
|
}
|
|
|
|
[[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);
|
|
}
|
|
|
|
[[nodiscard]] double global_norm(
|
|
const mfem::Vector &vector,
|
|
const MPI_Comm communicator
|
|
) {
|
|
return gravity_prepared_test_utils::global_norm(vector, communicator);
|
|
}
|
|
|
|
[[nodiscard]] long long global_sum(
|
|
const int localValue,
|
|
const MPI_Comm communicator
|
|
) {
|
|
const long long local = static_cast<long long>(localValue);
|
|
long long global = 0;
|
|
MPI_Allreduce(&local, &global, 1, MPI_LONG_LONG, MPI_SUM, communicator);
|
|
return global;
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector gather_reference(
|
|
const field::FieldDofMap &densityMap,
|
|
const mfem::Vector &fullReference
|
|
) {
|
|
return densityMap.gather(fullReference);
|
|
}
|
|
|
|
struct ClosureCondition final {
|
|
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 polytrope 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 polytrope 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 polytrope 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}}
|
|
};
|
|
|
|
[[nodiscard]] 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));
|
|
}
|
|
|
|
[[nodiscard]] 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(*f.enthalpyFes, coefficient);
|
|
}
|
|
|
|
[[nodiscard]] mfem::Vector make_density(
|
|
const mean_field::fem::FEM &f,
|
|
const mean_field::eos::Polytrope &equationOfState,
|
|
const ClosureCondition &condition
|
|
) {
|
|
mfem::FunctionCoefficient coefficient([&equationOfState, condition](const mfem::Vector &position) {
|
|
const double enthalpy = evaluate_enthalpy(position, condition);
|
|
const double equationOfStateDensity = mean_field::eos::evaluate<mean_field::eos::quantity::Density>(
|
|
equationOfState, mean_field::eos::SpecificEnthalpyValue{enthalpy}
|
|
)
|
|
.value();
|
|
return condition.densityFactor * equationOfStateDensity + condition.densityOffset +
|
|
condition.densityGradient * (0.40 * position(0) + 0.25 * position(1) - 0.15 * position(2));
|
|
});
|
|
return project_scalar(*f.densityFes, coefficient);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Uses FieldDof Supported Dimensions",
|
|
tags::barotrope &tags::closure &tags::prepared &tags::field &tags::unit
|
|
) {
|
|
using Operator = mean_field::operators::PreparedBarotropicClosureOperator;
|
|
|
|
STATIC_REQUIRE_FALSE(std::is_copy_constructible_v<Operator>);
|
|
STATIC_REQUIRE_FALSE(std::is_copy_assignable_v<Operator>);
|
|
STATIC_REQUIRE_FALSE(std::is_move_constructible_v<Operator>);
|
|
STATIC_REQUIRE_FALSE(std::is_move_assignable_v<Operator>);
|
|
STATIC_REQUIRE(std::is_trivially_copyable_v<mean_field::operators::BarotropicClosurePreparationRejection>);
|
|
|
|
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 prepared_barotropic_closure_test_utils::Maps maps(f);
|
|
const mean_field::eos::Polytrope equationOfState(3.0, 1.5);
|
|
Operator preparedOperator(f, *f.domainMapperStateless, equationOfState);
|
|
|
|
CHECK_FALSE(preparedOperator.IsPrepared());
|
|
CHECK(preparedOperator.GetPreparationCount() == 0);
|
|
|
|
CHECK(preparedOperator.GetDensitySize() == maps.density.reduced_size());
|
|
CHECK(preparedOperator.GetEnthalpySize() == maps.enthalpy.reduced_size());
|
|
CHECK(preparedOperator.GetDisplacementSize() == maps.displacement.reduced_size());
|
|
|
|
CHECK(preparedOperator.Height() == maps.density.reduced_size());
|
|
CHECK(
|
|
preparedOperator.Width() ==
|
|
maps.density.reduced_size() + maps.enthalpy.reduced_size() + maps.displacement.reduced_size()
|
|
);
|
|
|
|
CHECK(maps.displacement.is_identity());
|
|
|
|
const MPI_Comm communicator = f.mesh->GetComm();
|
|
const long long globalDensityFull =
|
|
prepared_barotropic_closure_test_utils::global_sum(maps.density.full_size(), communicator);
|
|
const long long globalDensityReduced =
|
|
prepared_barotropic_closure_test_utils::global_sum(maps.density.reduced_size(), communicator);
|
|
const long long globalEnthalpyFull =
|
|
prepared_barotropic_closure_test_utils::global_sum(maps.enthalpy.full_size(), communicator);
|
|
const long long globalEnthalpyReduced =
|
|
prepared_barotropic_closure_test_utils::global_sum(maps.enthalpy.reduced_size(), communicator);
|
|
|
|
REQUIRE(globalDensityReduced > 0);
|
|
REQUIRE(globalEnthalpyReduced > 0);
|
|
CHECK(globalDensityReduced < globalDensityFull);
|
|
CHECK(globalEnthalpyReduced < globalEnthalpyFull);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Reports Expected EOS Rejections Without Unwinding",
|
|
tags::barotrope &tags::closure &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);
|
|
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
|
|
);
|
|
|
|
mfem::Vector density(maps.density.reduced_size());
|
|
mfem::Vector enthalpy(maps.enthalpy.reduced_size());
|
|
mfem::Vector displacement(maps.displacement.reduced_size());
|
|
density = 0.0;
|
|
enthalpy = -1.0;
|
|
displacement = 0.0;
|
|
auto dependencies = make_dependencies();
|
|
|
|
const auto outsideDomain =
|
|
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
REQUIRE_FALSE(outsideDomain.has_value());
|
|
CHECK(
|
|
outsideDomain.error().reason ==
|
|
mean_field::operators::BarotropicClosurePreparationRejectionReason::equation_of_state
|
|
);
|
|
CHECK(outsideDomain.error().equationOfStateError == mean_field::eos::EvaluationErrorCode::outside_domain);
|
|
CHECK_FALSE(preparedOperator.IsPrepared());
|
|
try {
|
|
(void)preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
FAIL("The compatibility Prepare overload accepted an out-of-domain EOS input.");
|
|
} catch (const mean_field::eos::EvaluationError &error) {
|
|
CHECK(error.code() == mean_field::eos::EvaluationErrorCode::outside_domain);
|
|
}
|
|
|
|
// Keep the interpolated input finite while forcing the n = 3
|
|
// polytropic density evaluation to overflow.
|
|
enthalpy = 1.0e150;
|
|
++dependencies.enthalpy.revision;
|
|
|
|
const auto rejected =
|
|
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
REQUIRE_FALSE(rejected.has_value());
|
|
CHECK(
|
|
rejected.error().reason ==
|
|
mean_field::operators::BarotropicClosurePreparationRejectionReason::equation_of_state
|
|
);
|
|
CHECK(rejected.error().equationOfStateError == mean_field::eos::EvaluationErrorCode::nonfinite_result);
|
|
CHECK_FALSE(preparedOperator.IsPrepared());
|
|
try {
|
|
(void)preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
FAIL("The compatibility Prepare overload accepted a non-finite EOS result.");
|
|
} catch (const mean_field::eos::EvaluationError &error) {
|
|
CHECK(error.code() == mean_field::eos::EvaluationErrorCode::nonfinite_result);
|
|
}
|
|
|
|
enthalpy = 1.0;
|
|
++dependencies.enthalpy.revision;
|
|
const auto accepted =
|
|
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
REQUIRE(accepted.has_value());
|
|
CHECK(preparedOperator.IsPrepared());
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Reports Invalid Candidate Geometry Without Unwinding",
|
|
tags::barotrope &tags::closure &tags::prepared &tags::geometry &tags::unit
|
|
) {
|
|
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
|
|
);
|
|
|
|
mfem::Vector density(maps.density.reduced_size());
|
|
mfem::Vector enthalpy(maps.enthalpy.reduced_size());
|
|
density = 1.0;
|
|
enthalpy = 1.0;
|
|
mfem::Vector displacement = reduce(maps.displacement, make_folding_displacement(f));
|
|
auto dependencies = make_dependencies();
|
|
|
|
const auto rejected =
|
|
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
REQUIRE_FALSE(rejected.has_value());
|
|
CHECK(
|
|
rejected.error().reason ==
|
|
mean_field::operators::BarotropicClosurePreparationRejectionReason::mapping_failure
|
|
);
|
|
CHECK(rejected.error().mappingStatus == mean_field::mapping::MappingStatus::non_positive_determinant);
|
|
CHECK_FALSE(preparedOperator.IsPrepared());
|
|
CHECK_THROWS_AS(
|
|
preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies), std::domain_error
|
|
);
|
|
|
|
displacement = 0.0;
|
|
++dependencies.displacement.revision;
|
|
const auto accepted =
|
|
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
REQUIRE(accepted.has_value());
|
|
CHECK(preparedOperator.IsPrepared());
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Matches Full Stateless Kernels Through FieldDof Restriction",
|
|
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::field &tags::integration
|
|
) {
|
|
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
|
|
);
|
|
|
|
const mfem::Vector fullBaseDensity = make_base_density(f);
|
|
const mfem::Vector fullBaseEnthalpy = make_base_enthalpy(f);
|
|
const mfem::Vector fullDisplacement = gravity_prepared_test_utils::make_displacement(f, 1.0);
|
|
|
|
const mfem::Vector density = reduce(maps.density, fullBaseDensity);
|
|
const mfem::Vector enthalpy = reduce(maps.enthalpy, fullBaseEnthalpy);
|
|
const mfem::Vector displacement = reduce(maps.displacement, fullDisplacement);
|
|
|
|
const mfem::Vector rawDensityVariation =
|
|
gravity_prepared_test_utils::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.43);
|
|
const mfem::Vector rawEnthalpyVariation = make_enthalpy_variation(f);
|
|
const mfem::Vector rawDisplacementVariation = gravity_prepared_test_utils::make_displacement(f, 0.63);
|
|
|
|
const mfem::Vector densityVariation = reduce(maps.density, rawDensityVariation);
|
|
const mfem::Vector enthalpyVariation = reduce(maps.enthalpy, rawEnthalpyVariation);
|
|
const mfem::Vector displacementVariation = reduce(maps.displacement, rawDisplacementVariation);
|
|
|
|
const mfem::Vector fullDensityVariation = expand(maps.density, densityVariation);
|
|
const mfem::Vector fullEnthalpyVariation = expand(maps.enthalpy, enthalpyVariation);
|
|
const mfem::Vector fullDisplacementVariation = expand(maps.displacement, displacementVariation);
|
|
|
|
mfem::Vector zeroDensity(maps.density.reduced_size());
|
|
mfem::Vector zeroEnthalpy(maps.enthalpy.reduced_size());
|
|
mfem::Vector zeroDisplacement(maps.displacement.reduced_size());
|
|
zeroDensity = 0.0;
|
|
zeroEnthalpy = 0.0;
|
|
zeroDisplacement = 0.0;
|
|
|
|
preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), make_dependencies());
|
|
|
|
mfem::Vector preparedResidual;
|
|
mfem::Vector preparedDensityAction;
|
|
mfem::Vector preparedEnthalpyAction;
|
|
mfem::Vector preparedDisplacementAction;
|
|
mfem::Vector preparedCompleteAction;
|
|
mfem::Vector preparedPackedAction;
|
|
|
|
preparedOperator.BuildResidual(preparedResidual);
|
|
preparedOperator.Mult(densityVariation, zeroEnthalpy, zeroDisplacement, preparedDensityAction);
|
|
preparedOperator.Mult(zeroDensity, enthalpyVariation, zeroDisplacement, preparedEnthalpyAction);
|
|
preparedOperator.Mult(zeroDensity, zeroEnthalpy, displacementVariation, preparedDisplacementAction);
|
|
preparedOperator.Mult(densityVariation, enthalpyVariation, displacementVariation, preparedCompleteAction);
|
|
|
|
const mfem::Vector packedDirection =
|
|
make_combined_variation(densityVariation, enthalpyVariation, displacementVariation);
|
|
preparedOperator.Mult(packedDirection, preparedPackedAction);
|
|
|
|
mfem::Vector fullReferenceResidual;
|
|
mfem::Vector fullReferenceDensityAction;
|
|
mfem::Vector fullReferenceEnthalpyAction;
|
|
mfem::Vector fullReferenceDisplacementAction;
|
|
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, density),
|
|
expand(maps.enthalpy, enthalpy), expand(maps.displacement, displacement), fullReferenceResidual
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure_density_action(
|
|
f, *f.domainMapperStateless, equationOfState, fullDensityVariation, expand(maps.displacement, displacement),
|
|
fullReferenceDensityAction
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure_enthalpy_action(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.enthalpy, enthalpy), fullEnthalpyVariation,
|
|
expand(maps.displacement, displacement), fullReferenceEnthalpyAction
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure_displacement_action(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, density),
|
|
expand(maps.enthalpy, enthalpy), expand(maps.displacement, displacement), fullDisplacementVariation,
|
|
fullReferenceDisplacementAction
|
|
);
|
|
|
|
const mfem::Vector referenceResidual = gather_reference(maps.density, fullReferenceResidual);
|
|
const mfem::Vector referenceDensityAction = gather_reference(maps.density, fullReferenceDensityAction);
|
|
const mfem::Vector referenceEnthalpyAction = gather_reference(maps.density, fullReferenceEnthalpyAction);
|
|
const mfem::Vector referenceDisplacementAction =
|
|
gather_reference(maps.density, fullReferenceDisplacementAction);
|
|
|
|
mfem::Vector referenceCompleteAction(referenceDensityAction);
|
|
referenceCompleteAction += referenceEnthalpyAction;
|
|
referenceCompleteAction += referenceDisplacementAction;
|
|
|
|
const MPI_Comm communicator = f.mesh->GetComm();
|
|
|
|
CHECK(relative_error(preparedResidual, referenceResidual, communicator) < 2.0e-12);
|
|
CHECK(relative_error(preparedDensityAction, referenceDensityAction, communicator) < 2.0e-12);
|
|
CHECK(relative_error(preparedEnthalpyAction, referenceEnthalpyAction, communicator) < 2.0e-12);
|
|
CHECK(relative_error(preparedDisplacementAction, referenceDisplacementAction, communicator) < 2.0e-12);
|
|
CHECK(relative_error(preparedCompleteAction, referenceCompleteAction, communicator) < 2.0e-12);
|
|
CHECK(relative_error(preparedPackedAction, referenceCompleteAction, communicator) < 2.0e-12);
|
|
|
|
CHECK(preparedOperator.GetPreparationCount() == 1);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Jacobian Matches A Reduced Coordinate Centered Difference",
|
|
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::field &tags::jacobian &tags::accuracy
|
|
) {
|
|
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);
|
|
|
|
const mfem::Vector density = reduce(maps.density, make_base_density(f));
|
|
const mfem::Vector enthalpy = reduce(maps.enthalpy, make_base_enthalpy(f));
|
|
const mfem::Vector displacement =
|
|
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.8));
|
|
|
|
const mfem::Vector densityVariation = reduce(
|
|
maps.density, gravity_prepared_test_utils::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.71)
|
|
);
|
|
const mfem::Vector enthalpyVariation = reduce(maps.enthalpy, make_enthalpy_variation(f));
|
|
const mfem::Vector displacementVariation =
|
|
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.63));
|
|
|
|
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
|
f, *f.domainMapperStateless, equationOfState
|
|
);
|
|
preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), make_dependencies());
|
|
|
|
mfem::Vector analyticAction;
|
|
preparedOperator.Mult(densityVariation, enthalpyVariation, displacementVariation, analyticAction);
|
|
|
|
constexpr double differenceStep = 1.0e-5;
|
|
|
|
mfem::Vector plusDensity(density);
|
|
mfem::Vector minusDensity(density);
|
|
mfem::Vector plusEnthalpy(enthalpy);
|
|
mfem::Vector minusEnthalpy(enthalpy);
|
|
mfem::Vector plusDisplacement(displacement);
|
|
mfem::Vector minusDisplacement(displacement);
|
|
|
|
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 plusFullResidual;
|
|
mfem::Vector minusFullResidual;
|
|
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, plusDensity),
|
|
expand(maps.enthalpy, plusEnthalpy), expand(maps.displacement, plusDisplacement), plusFullResidual
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, minusDensity),
|
|
expand(maps.enthalpy, minusEnthalpy), expand(maps.displacement, minusDisplacement), minusFullResidual
|
|
);
|
|
|
|
mfem::Vector finiteDifference = maps.density.gather(plusFullResidual);
|
|
mfem::Vector minusReduced = maps.density.gather(minusFullResidual);
|
|
finiteDifference -= minusReduced;
|
|
finiteDifference /= 2.0 * differenceStep;
|
|
|
|
const double error = relative_error(analyticAction, finiteDifference, f.mesh->GetComm());
|
|
INFO("Reduced closure centered-difference error = " << error);
|
|
CHECK(error < 2.0e-7);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Reuses Its Frozen Expanded State",
|
|
tags::barotrope &tags::closure &tags::prepared &tags::field &tags::unit
|
|
) {
|
|
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
|
|
);
|
|
|
|
mfem::Vector density = reduce(maps.density, make_base_density(f));
|
|
mfem::Vector enthalpy = reduce(maps.enthalpy, make_base_enthalpy(f));
|
|
mfem::Vector displacement = reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 1.0));
|
|
|
|
const mfem::Vector densityVariation = reduce(
|
|
maps.density, gravity_prepared_test_utils::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.31)
|
|
);
|
|
const mfem::Vector enthalpyVariation = reduce(maps.enthalpy, make_enthalpy_variation(f));
|
|
const mfem::Vector displacementVariation =
|
|
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.63));
|
|
|
|
preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), make_dependencies());
|
|
REQUIRE(preparedOperator.GetPreparationCount() == 1);
|
|
|
|
mfem::Vector firstResidual;
|
|
mfem::Vector firstAction;
|
|
preparedOperator.BuildResidual(firstResidual);
|
|
preparedOperator.Mult(densityVariation, enthalpyVariation, displacementVariation, firstAction);
|
|
|
|
density = 7.0;
|
|
enthalpy = 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();
|
|
CHECK(relative_error(repeatedResidual, firstResidual, communicator) < 2.0e-14);
|
|
CHECK(relative_error(repeatedAction, firstAction, communicator) < 2.0e-14);
|
|
CHECK(preparedOperator.GetPreparationCount() == preparationCount);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Reprepares Correctly For New Geometry",
|
|
tags::barotrope &tags::closure &tags::hydro &tags::mapping &tags::prepared &tags::field &tags::integration
|
|
) {
|
|
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);
|
|
|
|
const mfem::Vector density = reduce(maps.density, make_base_density(f));
|
|
const mfem::Vector enthalpy = reduce(maps.enthalpy, make_base_enthalpy(f));
|
|
const mfem::Vector densityVariation = reduce(
|
|
maps.density, gravity_prepared_test_utils::make_deterministic_vector(f.densityFes->GetTrueVSize(), 0.59)
|
|
);
|
|
|
|
mfem::Vector zeroEnthalpy(maps.enthalpy.reduced_size());
|
|
mfem::Vector zeroDisplacementVariation(maps.displacement.reduced_size());
|
|
zeroEnthalpy = 0.0;
|
|
zeroDisplacementVariation = 0.0;
|
|
|
|
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
|
f, *f.domainMapperStateless, equationOfState
|
|
);
|
|
|
|
mfem::Vector identityAction;
|
|
mfem::Vector deformedAction;
|
|
ClosureDependencies dependencies = make_dependencies();
|
|
|
|
for (const double deformationScale : {0.0, 1.0}) {
|
|
CAPTURE(deformationScale);
|
|
|
|
const mfem::Vector displacement =
|
|
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, deformationScale));
|
|
|
|
preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies);
|
|
|
|
mfem::Vector preparedResidual;
|
|
mfem::Vector preparedAction;
|
|
preparedOperator.BuildResidual(preparedResidual);
|
|
preparedOperator.Mult(densityVariation, zeroEnthalpy, zeroDisplacementVariation, preparedAction);
|
|
|
|
mfem::Vector fullReferenceResidual;
|
|
mfem::Vector fullReferenceAction;
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, density),
|
|
expand(maps.enthalpy, enthalpy), expand(maps.displacement, displacement), fullReferenceResidual
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure_density_action(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, densityVariation),
|
|
expand(maps.displacement, displacement), fullReferenceAction
|
|
);
|
|
|
|
const mfem::Vector referenceResidual = maps.density.gather(fullReferenceResidual);
|
|
const mfem::Vector referenceAction = maps.density.gather(fullReferenceAction);
|
|
|
|
const MPI_Comm communicator = f.mesh->GetComm();
|
|
CHECK(relative_error(preparedResidual, referenceResidual, communicator) < 2.0e-12);
|
|
CHECK(relative_error(preparedAction, referenceAction, communicator) < 2.0e-12);
|
|
|
|
if (deformationScale == 0.0) {
|
|
identityAction = preparedAction;
|
|
} else {
|
|
deformedAction = preparedAction;
|
|
}
|
|
|
|
++dependencies.displacement.revision;
|
|
}
|
|
|
|
const double geometryChange = relative_error(deformedAction, identityAction, f.mesh->GetComm());
|
|
INFO("Prepared closure geometry change = " << geometryChange);
|
|
CHECK(preparedOperator.GetPreparationCount() == 2);
|
|
CHECK(geometryChange > 1.0e-5);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Prepared Barotropic Closure Covers Multiple EOS And Geometry Conditions In Reduced Coordinates",
|
|
tags::barotrope &tags::closure &tags::hydro &tags::integration &tags::jacobian &tags::mapping &tags::physics
|
|
&tags::prepared &tags::field
|
|
) {
|
|
auto args = test_utils::setup_args();
|
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
|
REQUIRE(f.okay());
|
|
REQUIRE(f.domainMapperStateless != nullptr);
|
|
|
|
const Maps maps(f);
|
|
const MPI_Comm communicator = f.mesh->GetComm();
|
|
constexpr double differenceStep = 1.0e-5;
|
|
|
|
for (std::size_t conditionIndex = 0; conditionIndex < conditions.size(); ++conditionIndex) {
|
|
const ClosureCondition &condition = conditions[conditionIndex];
|
|
|
|
DYNAMIC_SECTION(condition.name) {
|
|
const mean_field::eos::Polytrope equationOfState(
|
|
condition.polytropicIndex, condition.polytropicConstant
|
|
);
|
|
|
|
const mfem::Vector fullBaseDensityRaw = make_density(f, equationOfState, condition);
|
|
const mfem::Vector fullBaseEnthalpyRaw = make_enthalpy(f, condition);
|
|
const mfem::Vector fullBaseDisplacementRaw =
|
|
gravity_prepared_test_utils::make_displacement(f, condition.deformationScale);
|
|
|
|
const mfem::Vector baseDensity = reduce(maps.density, fullBaseDensityRaw);
|
|
const mfem::Vector baseEnthalpy = reduce(maps.enthalpy, fullBaseEnthalpyRaw);
|
|
const mfem::Vector baseDisplacement = reduce(maps.displacement, fullBaseDisplacementRaw);
|
|
|
|
mfem::Vector densityVariation = reduce(
|
|
maps.density, gravity_prepared_test_utils::make_deterministic_vector(
|
|
f.densityFes->GetTrueVSize(), condition.directionPhase
|
|
)
|
|
);
|
|
mfem::Vector enthalpyVariation = reduce(maps.enthalpy, make_enthalpy_variation(f));
|
|
mfem::Vector displacementVariation = reduce(
|
|
maps.displacement,
|
|
gravity_prepared_test_utils::make_displacement(f, 0.55 + 0.1 * condition.directionPhase)
|
|
);
|
|
|
|
mfem::Vector fullDensityAction;
|
|
mfem::Vector fullEnthalpyAction;
|
|
mfem::Vector fullDisplacementAction;
|
|
|
|
mean_field::operators::kernels::apply_barotropic_closure_density_action(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, densityVariation),
|
|
expand(maps.displacement, baseDisplacement), fullDensityAction
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure_enthalpy_action(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.enthalpy, baseEnthalpy),
|
|
expand(maps.enthalpy, enthalpyVariation), expand(maps.displacement, baseDisplacement),
|
|
fullEnthalpyAction
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure_displacement_action(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, baseDensity),
|
|
expand(maps.enthalpy, baseEnthalpy), expand(maps.displacement, baseDisplacement),
|
|
expand(maps.displacement, displacementVariation), fullDisplacementAction
|
|
);
|
|
|
|
mfem::Vector densityAction = maps.density.gather(fullDensityAction);
|
|
mfem::Vector enthalpyAction = maps.density.gather(fullEnthalpyAction);
|
|
mfem::Vector displacementAction = maps.density.gather(fullDisplacementAction);
|
|
|
|
double densityNorm = global_norm(densityAction, communicator);
|
|
double enthalpyNorm = global_norm(enthalpyAction, communicator);
|
|
double displacementNorm = global_norm(displacementAction, communicator);
|
|
|
|
REQUIRE(densityNorm > 1.0e-12);
|
|
REQUIRE(enthalpyNorm > 1.0e-12);
|
|
REQUIRE(displacementNorm > 1.0e-12);
|
|
|
|
const double targetNorm = std::min({densityNorm, enthalpyNorm, displacementNorm});
|
|
const double densityScale = targetNorm / densityNorm;
|
|
const double enthalpyScale = targetNorm / enthalpyNorm;
|
|
const double displacementScale = targetNorm / displacementNorm;
|
|
|
|
densityVariation *= densityScale;
|
|
enthalpyVariation *= enthalpyScale;
|
|
displacementVariation *= displacementScale;
|
|
densityAction *= densityScale;
|
|
enthalpyAction *= enthalpyScale;
|
|
displacementAction *= displacementScale;
|
|
|
|
densityNorm = global_norm(densityAction, communicator);
|
|
enthalpyNorm = global_norm(enthalpyAction, communicator);
|
|
displacementNorm = global_norm(displacementAction, communicator);
|
|
|
|
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
|
f, *f.domainMapperStateless, equationOfState
|
|
);
|
|
preparedOperator.Prepare(
|
|
make_state_view(baseDensity, baseEnthalpy, baseDisplacement), make_dependencies()
|
|
);
|
|
|
|
mfem::Vector preparedResidual;
|
|
mfem::Vector preparedAction;
|
|
preparedOperator.BuildResidual(preparedResidual);
|
|
preparedOperator.Mult(densityVariation, enthalpyVariation, displacementVariation, preparedAction);
|
|
|
|
mfem::Vector fullReferenceResidual;
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, baseDensity),
|
|
expand(maps.enthalpy, baseEnthalpy), expand(maps.displacement, baseDisplacement),
|
|
fullReferenceResidual
|
|
);
|
|
const mfem::Vector referenceResidual = maps.density.gather(fullReferenceResidual);
|
|
|
|
mfem::Vector blockSum(densityAction);
|
|
blockSum += enthalpyAction;
|
|
blockSum += displacementAction;
|
|
|
|
const double residualEvaluationError =
|
|
relative_error(preparedResidual, referenceResidual, communicator);
|
|
const double blockAssemblyError = 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 fullPlusResidual;
|
|
mfem::Vector fullMinusResidual;
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, plusDensity),
|
|
expand(maps.enthalpy, plusEnthalpy), expand(maps.displacement, plusDisplacement), fullPlusResidual
|
|
);
|
|
mean_field::operators::kernels::apply_barotropic_closure(
|
|
f, *f.domainMapperStateless, equationOfState, expand(maps.density, minusDensity),
|
|
expand(maps.enthalpy, minusEnthalpy), expand(maps.displacement, minusDisplacement),
|
|
fullMinusResidual
|
|
);
|
|
|
|
mfem::Vector finiteDifference = maps.density.gather(fullPlusResidual);
|
|
const mfem::Vector minusReduced = maps.density.gather(fullMinusResidual);
|
|
finiteDifference -= minusReduced;
|
|
finiteDifference /= 2.0 * differenceStep;
|
|
|
|
mfem::Vector finiteDifferenceError(preparedAction);
|
|
finiteDifferenceError -= finiteDifference;
|
|
|
|
const double finiteDifferenceErrorNorm = global_norm(finiteDifferenceError, communicator);
|
|
const double blockNormSum = densityNorm + enthalpyNorm + displacementNorm;
|
|
const double blockScaledDifferenceError = finiteDifferenceErrorNorm / blockNormSum;
|
|
const double completeRelativeError = 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("Complete centered-difference relative error = " << completeRelativeError);
|
|
INFO("Block-scaled centered-difference error = " << blockScaledDifferenceError);
|
|
|
|
CHECK(preparedOperator.GetPreparationCount() == 1);
|
|
CHECK(residualEvaluationError < 5.0e-12);
|
|
CHECK(blockAssemblyError < 5.0e-12);
|
|
CHECK(blockScaledDifferenceError < 2.0e-7);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Exact Constant Prepared Barotropic Closure Remains Zero Under Deformation",
|
|
tags::barotrope &tags::closure &tags::hydro &tags::integration &tags::jacobian &tags::mapping &tags::physics
|
|
&tags::prepared &tags::field
|
|
) {
|
|
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);
|
|
|
|
constexpr double enthalpyValue = 1.20;
|
|
const double equilibriumDensityValue =
|
|
mean_field::eos::evaluate<mean_field::eos::quantity::Density>(
|
|
equationOfState, mean_field::eos::SpecificEnthalpyValue{enthalpyValue}
|
|
)
|
|
.value();
|
|
|
|
const mfem::Vector enthalpy = reduce(maps.enthalpy, make_constant_field(*f.enthalpyFes, enthalpyValue));
|
|
const mfem::Vector equilibriumDensity =
|
|
reduce(maps.density, make_constant_field(*f.densityFes, equilibriumDensityValue));
|
|
const mfem::Vector referenceDensity =
|
|
reduce(maps.density, make_constant_field(*f.densityFes, equilibriumDensityValue + 1.0));
|
|
const mfem::Vector displacementVariation =
|
|
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, 0.67));
|
|
|
|
mfem::Vector zeroDensity(maps.density.reduced_size());
|
|
mfem::Vector zeroEnthalpy(maps.enthalpy.reduced_size());
|
|
zeroDensity = 0.0;
|
|
zeroEnthalpy = 0.0;
|
|
|
|
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 =
|
|
reduce(maps.displacement, gravity_prepared_test_utils::make_displacement(f, deformationScale));
|
|
|
|
mean_field::operators::PreparedBarotropicClosureOperator exactOperator(
|
|
f, *f.domainMapperStateless, equationOfState
|
|
);
|
|
mean_field::operators::PreparedBarotropicClosureOperator referenceOperator(
|
|
f, *f.domainMapperStateless, equationOfState
|
|
);
|
|
|
|
exactOperator.Prepare(make_state_view(equilibriumDensity, enthalpy, displacement), make_dependencies());
|
|
referenceOperator.Prepare(
|
|
make_state_view(referenceDensity, enthalpy, displacement), make_dependencies()
|
|
);
|
|
|
|
mfem::Vector exactResidual;
|
|
mfem::Vector referenceResidual;
|
|
mfem::Vector exactGeometryAction;
|
|
mfem::Vector referenceGeometryAction;
|
|
|
|
exactOperator.BuildResidual(exactResidual);
|
|
referenceOperator.BuildResidual(referenceResidual);
|
|
exactOperator.Mult(zeroDensity, zeroEnthalpy, displacementVariation, exactGeometryAction);
|
|
referenceOperator.Mult(zeroDensity, zeroEnthalpy, displacementVariation, referenceGeometryAction);
|
|
|
|
const double exactResidualNorm = global_norm(exactResidual, communicator);
|
|
const double referenceResidualNorm = global_norm(referenceResidual, communicator);
|
|
const double exactGeometryNorm = global_norm(exactGeometryAction, communicator);
|
|
const double referenceGeometryNorm = global_norm(referenceGeometryAction, communicator);
|
|
|
|
INFO("Deformation scale = " << deformationScale);
|
|
INFO("Exact reduced closure residual norm = " << exactResidualNorm);
|
|
INFO("Reference reduced residual norm = " << referenceResidualNorm);
|
|
INFO("Exact reduced geometry-action norm = " << exactGeometryNorm);
|
|
INFO("Reference reduced 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace prepared_barotropic_closure_test_utils
|