perf(jacobian-action): major updates to jacobian action application by removing redudant quadrature work. ~5x increase in speed
This commit is contained in:
193
tests/operators/prepared_central_density_stellar_equilibrium.cpp
Normal file
193
tests/operators/prepared_central_density_stellar_equilibrium.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <mfem.hpp>
|
||||
|
||||
import mean_field;
|
||||
import test_helpers;
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] mean_field::operators::StellarEquilibriumDependencies make_dependencies() {
|
||||
return {
|
||||
.discretization = {.identity = 3109, .revision = 1},
|
||||
.density = {.identity = 3119, .revision = 1},
|
||||
.surfaceDeformation = {.identity = 3121, .revision = 1},
|
||||
.gravityGradient = {.identity = 3137, .revision = 1},
|
||||
.gravityPotential = {.identity = 3163, .revision = 1},
|
||||
.enthalpy = {.identity = 3167, .revision = 1},
|
||||
.bernoulliConstant = {.identity = 3169, .revision = 1},
|
||||
.rotation = {.identity = 3181, .revision = 1},
|
||||
.targetMass = {.identity = 3187, .revision = 1}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::physics::RigidRotation make_zero_rotation() {
|
||||
mfem::Vector angularVelocity(3);
|
||||
mfem::Vector center(3);
|
||||
angularVelocity = 0.0;
|
||||
center = 0.0;
|
||||
return {angularVelocity, center};
|
||||
}
|
||||
|
||||
[[nodiscard]] double relative_difference(
|
||||
const mfem::Vector &left,
|
||||
const mfem::Vector &right
|
||||
) {
|
||||
mfem::Vector difference(left);
|
||||
difference -= right;
|
||||
return difference.Norml2() / std::max({1.0, left.Norml2(), right.Norml2()});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE(
|
||||
"Central Density Bordered Root Preserves The Physical Operator Prefix",
|
||||
tags::central_density_phase_integration
|
||||
) {
|
||||
using namespace mean_field;
|
||||
|
||||
STATIC_CHECK_FALSE(
|
||||
std::same_as<
|
||||
operators::PreparedStellarEquilibriumOperator, operators::PreparedCentralDensityStellarEquilibriumOperator>
|
||||
);
|
||||
STATIC_CHECK(
|
||||
operators::CentralDensityStellarEquilibriumSpecificationModel::compilationClass ==
|
||||
models::ModelCompilationClass::isolated_root
|
||||
);
|
||||
|
||||
utils::Args args = test_utils::setup_args();
|
||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
models::StellarModel stellarModel{
|
||||
models::structure::PolytropicStructure{eos::Polytrope{3.0, 0.25}, 1.0},
|
||||
surface::ConstantPressureSurface{dimensions::PressureValue{0.0}}
|
||||
};
|
||||
operators::PreparedStellarEquilibriumOperator physicalOperator(f, *f.domainMapperStateless, stellarModel);
|
||||
auto equilibriumProblem = equilibrium::discretize(
|
||||
model::StellarModel(
|
||||
constraint::FixedCentralDensity({.RhoC = dimensions::DensityValue{1.0}}),
|
||||
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{1.0}}),
|
||||
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}), eos::Polytrope({.n = 3.0, .K = 0.25})
|
||||
),
|
||||
equilibrium::StellarDiscretization{f, *f.domainMapperStateless}
|
||||
);
|
||||
auto &borderedOperator = equilibriumProblem.GetPreparedOperator();
|
||||
|
||||
STATIC_CHECK(
|
||||
std::same_as<
|
||||
typename std::remove_cvref_t<decltype(equilibriumProblem)>::PreparedOperatorType,
|
||||
operators::PreparedCentralDensityStellarEquilibriumOperator>
|
||||
);
|
||||
CHECK(
|
||||
equilibriumProblem.GetStellarModel().specification<constraint::FixedCentralDensity>().targetDensity() ==
|
||||
dimensions::DensityValue{1.0}
|
||||
);
|
||||
CHECK(equilibriumProblem.StateSize() == equilibriumProblem.EquationSize());
|
||||
|
||||
CHECK(borderedOperator.Width() == physicalOperator.Width() + 1);
|
||||
CHECK(borderedOperator.Height() == physicalOperator.Height() + 1);
|
||||
CHECK(borderedOperator.GetRootManifest().valueBlocks().size() == 7);
|
||||
CHECK(borderedOperator.GetRootManifest().residualBlocks().size() == 7);
|
||||
CHECK(borderedOperator.GetRootManifest().constraints().size() == 3);
|
||||
CHECK(borderedOperator.GetRootManifest().specificationDescriptors().size() == 4);
|
||||
|
||||
const auto constraints = borderedOperator.GetRootManifest().constraints();
|
||||
CHECK(constraints[2].stableId == "FixedCentralDensity");
|
||||
CHECK(constraints[2].role == models::SpecificationRole::phase_condition);
|
||||
CHECK(constraints[2].columnPolicy == operators::RootColumnPolicy::solver_border);
|
||||
CHECK(constraints[2].target == 1.0);
|
||||
REQUIRE(constraints[2].carrierTarget.has_value());
|
||||
CHECK(*constraints[2].carrierTarget == 1.0);
|
||||
CHECK(constraints[2].targetUnits == "density");
|
||||
CHECK(constraints[2].residualUnits == "specific_enthalpy");
|
||||
|
||||
mfem::Vector physicalState(physicalOperator.Width());
|
||||
physicalState = 0.0;
|
||||
const auto physicalStateView = physicalOperator.GetRootStateView(physicalState);
|
||||
physicalStateView.block(utils::blocks::density_field.mass_term) = 1.0;
|
||||
physicalStateView.block(utils::blocks::enthalpy_field.specific_term) = 1.0;
|
||||
|
||||
mfem::Vector borderedState(borderedOperator.Width());
|
||||
borderedState = 0.0;
|
||||
mfem::Vector(borderedState.GetData(), physicalState.Size()) = physicalState;
|
||||
|
||||
const operators::StellarEquilibriumDependencies dependencies = make_dependencies();
|
||||
const physics::RigidRotation rotation = make_zero_rotation();
|
||||
physicalOperator.Prepare(physicalState, dependencies, rotation);
|
||||
const operators::PreparedCentralDensityStellarEquilibriumReport initialReport =
|
||||
equilibriumProblem.Prepare(borderedState, dependencies, rotation);
|
||||
CHECK(initialReport.physical.assembledResidual);
|
||||
CHECK(initialReport.phase.assembledResidual);
|
||||
CHECK(initialReport.assembledResidual);
|
||||
|
||||
mfem::Vector physicalResidual;
|
||||
mfem::Vector borderedResidual;
|
||||
physicalOperator.BuildResidual(physicalResidual);
|
||||
equilibriumProblem.BuildResidual(borderedResidual);
|
||||
const mfem::Vector borderedPhysicalResidual(borderedResidual.GetData(), physicalResidual.Size());
|
||||
CHECK(relative_difference(borderedPhysicalResidual, physicalResidual) < 2.0e-15);
|
||||
CHECK(borderedResidual(borderedResidual.Size() - 1) == 0.0);
|
||||
|
||||
const operators::CentralDensityConstraintReport centralReport = borderedOperator.GetCentralDensityReport();
|
||||
CHECK(centralReport.targetDensity == 1.0);
|
||||
CHECK(centralReport.achievedDensity == 1.0);
|
||||
CHECK(centralReport.enthalpyResidual == 0.0);
|
||||
|
||||
mfem::Vector physicalDirection(physicalOperator.Width());
|
||||
for (int index = 0; index < physicalDirection.Size(); ++index) {
|
||||
physicalDirection(index) = 0.01 * std::sin(0.37 * static_cast<double>(index + 1));
|
||||
}
|
||||
mfem::Vector borderedDirection(borderedOperator.Width());
|
||||
borderedDirection = 0.0;
|
||||
mfem::Vector(borderedDirection.GetData(), physicalDirection.Size()) = physicalDirection;
|
||||
|
||||
mfem::Vector physicalAction;
|
||||
mfem::Vector borderedAction;
|
||||
physicalOperator.Mult(physicalDirection, physicalAction);
|
||||
equilibriumProblem.ApplyLinearization(borderedDirection, borderedAction);
|
||||
const mfem::Vector borderedPhysicalAction(borderedAction.GetData(), physicalAction.Size());
|
||||
CHECK(relative_difference(borderedPhysicalAction, physicalAction) < 2.0e-15);
|
||||
|
||||
const auto borderedDirectionView = borderedOperator.GetRootManifest().directionView(borderedDirection);
|
||||
const mfem::Vector enthalpyDirection = borderedDirectionView.block(utils::blocks::enthalpy_field.specific_term);
|
||||
double localCenterDirection = 0.0;
|
||||
for (const int centerDof : borderedOperator.GetCentralDensityConstraint().GetCenterDof().reduced_dofs()) {
|
||||
localCenterDirection += enthalpyDirection(centerDof);
|
||||
}
|
||||
double globalCenterDirection = 0.0;
|
||||
MPI_Allreduce(&localCenterDirection, &globalCenterDirection, 1, MPI_DOUBLE, MPI_SUM, f.mesh->GetComm());
|
||||
CHECK(borderedAction(borderedAction.Size() - 1) == globalCenterDirection);
|
||||
|
||||
const auto repeatedReport = borderedOperator.Prepare(borderedState, dependencies, rotation);
|
||||
CHECK_FALSE(repeatedReport.physical.DidAnyWork());
|
||||
CHECK_FALSE(repeatedReport.phase.DidAnyWork());
|
||||
CHECK_FALSE(repeatedReport.assembledResidual);
|
||||
|
||||
borderedState(borderedState.Size() - 1) = 0.375;
|
||||
const auto borderReport = borderedOperator.Prepare(borderedState, dependencies, rotation);
|
||||
CHECK_FALSE(borderReport.physical.DidAnyWork());
|
||||
CHECK(borderReport.phase.refreshedBorder);
|
||||
CHECK(borderReport.assembledResidual);
|
||||
|
||||
mfem::Vector borderOnlyDirection(borderedOperator.Width());
|
||||
borderOnlyDirection = 0.0;
|
||||
borderOnlyDirection(borderOnlyDirection.Size() - 1) = -0.625;
|
||||
const std::uint64_t preparationsBeforeMult = borderedOperator.GetCentralDensityConstraint().GetPreparationCount();
|
||||
borderedOperator.Mult(borderOnlyDirection, borderedAction);
|
||||
CHECK(borderedOperator.GetCentralDensityConstraint().GetPreparationCount() == preparationsBeforeMult);
|
||||
CHECK(borderedAction(borderedAction.Size() - 1) == 0.0);
|
||||
|
||||
const auto actionView = borderedOperator.GetRootManifest().residualView(borderedAction);
|
||||
const mfem::Vector enthalpyAction = actionView.block(utils::blocks::enthalpy_field.specific_term);
|
||||
double localBorderEntry = 0.0;
|
||||
for (const int centerDof : borderedOperator.GetCentralDensityConstraint().GetCenterDof().reduced_dofs()) {
|
||||
localBorderEntry += enthalpyAction(centerDof);
|
||||
}
|
||||
double globalBorderEntry = 0.0;
|
||||
MPI_Allreduce(&localBorderEntry, &globalBorderEntry, 1, MPI_DOUBLE, MPI_SUM, f.mesh->GetComm());
|
||||
CHECK(globalBorderEntry == -0.625);
|
||||
}
|
||||
Reference in New Issue
Block a user