feat(newton): first newton solver implementation

This commit is contained in:
2026-09-08 06:36:39 -04:00
parent 76818f2f82
commit b3c04d507a
98 changed files with 20397 additions and 11040 deletions

View File

@@ -1,6 +1,7 @@
#include <algorithm>
#include <cmath>
#include <concepts>
#include <limits>
#include <numbers>
#include <type_traits>
#include <utility>
@@ -12,8 +13,7 @@ import mean_field;
import test_helpers;
namespace outer_manifest_report_test {
template <mean_field::model::StellarModelType Model>
class PreparedEarlierMultiplier;
template <mean_field::model::StellarModelType Model> class PreparedEarlierMultiplier;
class EarlierMultiplier final {
public:
@@ -36,12 +36,9 @@ namespace outer_manifest_report_test {
"R_a",
"specific_energy",
"specific_energy">>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<
PreparedEarlierMultiplier>;
using EquilibriumPhysics = mean_field::operators::SpecificationEquilibriumPhysics<PreparedEarlierMultiplier>;
explicit EarlierMultiplier(const Parameters parameters) noexcept
: m_target(parameters.target) {
explicit EarlierMultiplier(const Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] mean_field::dimensions::SpecificEnergyValue target() const noexcept {
@@ -52,20 +49,20 @@ namespace outer_manifest_report_test {
mean_field::dimensions::SpecificEnergyValue m_target;
};
template <mean_field::model::StellarModelType Model>
class PreparedEarlierMultiplier final {
template <mean_field::model::StellarModelType Model> class PreparedEarlierMultiplier final {
public:
using Report = mean_field::operators::EmptySpecificationPreparationReport;
explicit PreparedEarlierMultiplier(const EarlierMultiplier &) noexcept {
}
template <typename StateView>
[[nodiscard]] Report PrepareAfterPhysical(const StateView &) noexcept {
template <typename StateView> [[nodiscard]] Report PrepareAfterPhysical(const StateView &) noexcept {
return {};
}
template <typename Equation, typename Row>
template <
typename Equation,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddResidual(
Equation,
Row &
@@ -73,9 +70,15 @@ namespace outer_manifest_report_test {
return mean_field::stellar::structuralZero;
}
template <typename Equation, typename State, typename Direction, typename Row>
template <
typename Equation,
typename State,
typename Direction,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<Equation, State>,
mean_field::stellar::Derivative<
Equation,
State>,
const Direction &,
Row &
) const noexcept {
@@ -89,40 +92,38 @@ namespace outer_manifest_report_test {
} // namespace outer_manifest_report_test
namespace {
using BaseModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
using BaseModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::integral::FixedTotalMass>>;
using CentralDensityModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
using CentralDensityModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::integral::FixedTotalMass,
mean_field::constraint::FixedCentralDensity>>;
using AngularMomentumModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
using AngularMomentumModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::integral::FixedTotalMass,
mean_field::integral::FixedAngularMomentum>>;
using AngularMomentumCentralDensityModel =
mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::integral::FixedTotalMass,
mean_field::integral::FixedAngularMomentum,
mean_field::constraint::FixedCentralDensity>>;
using AngularMomentumCentralDensityModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::integral::FixedTotalMass,
mean_field::integral::FixedAngularMomentum,
mean_field::constraint::FixedCentralDensity>>;
using IncompleteModel =
mean_field::model::StellarModel<mean_field::models::SpecificationSet<mean_field::eos::Polytrope>>;
using EarlierMultiplierModel =
mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
outer_manifest_report_test::EarlierMultiplier,
mean_field::integral::FixedTotalMass>>;
using EarlierMultiplierModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
outer_manifest_report_test::EarlierMultiplier,
mean_field::integral::FixedTotalMass>>;
template <typename Candidate>
concept HasLegacyNumericalModelAdapter = requires { typename Candidate::NumericalModelAdapter; };
@@ -166,8 +167,8 @@ TEST_CASE(
) {
using namespace mean_field;
using BaseProblem = equilibrium::StellarEquilibriumProblem<BaseModel>;
using CentralDensityProblem = equilibrium::StellarEquilibriumProblem<CentralDensityModel>;
using BaseProblem = equilibrium::StellarEquilibriumProblem<BaseModel>;
using CentralDensityProblem = equilibrium::StellarEquilibriumProblem<CentralDensityModel>;
using AngularMomentumProblem = equilibrium::StellarEquilibriumProblem<AngularMomentumModel>;
using AngularMomentumCentralDensityProblem =
equilibrium::StellarEquilibriumProblem<AngularMomentumCentralDensityModel>;
@@ -178,14 +179,17 @@ TEST_CASE(
STATIC_CHECK(equilibrium::StellarEquilibriumModel<AngularMomentumCentralDensityModel>);
STATIC_CHECK(equilibrium::StellarEquilibriumModel<EarlierMultiplierModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<IncompleteModel>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumRuntimeContribution<
outer_manifest_report_test::EarlierMultiplier>::registered);
STATIC_CHECK_FALSE(operators::stellarEquilibriumBackendRuntimeAuthorized<
outer_manifest_report_test::EarlierMultiplier,
EarlierMultiplierModel>);
STATIC_CHECK(operators::StellarEquilibriumPhysicsAvailableFor<
outer_manifest_report_test::EarlierMultiplier,
EarlierMultiplierModel>);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumRuntimeContribution<outer_manifest_report_test::EarlierMultiplier>::registered
);
STATIC_CHECK_FALSE(
operators::stellarEquilibriumBackendRuntimeAuthorized<
outer_manifest_report_test::EarlierMultiplier, EarlierMultiplierModel>
);
STATIC_CHECK(
operators::StellarEquilibriumPhysicsAvailableFor<
outer_manifest_report_test::EarlierMultiplier, EarlierMultiplierModel>
);
STATIC_CHECK_FALSE(std::same_as<BaseProblem, CentralDensityProblem>);
STATIC_CHECK(BaseProblem::symbolicallySquare);
STATIC_CHECK(CentralDensityProblem::symbolicallySquare);
@@ -213,20 +217,23 @@ TEST_CASE(
typename AngularMomentumProblem::PreparedOperatorType,
operators::PreparedVariadicStellarEquilibriumOperator<AngularMomentumModel>>
);
STATIC_CHECK_FALSE(std::same_as<
typename BaseProblem::PreparedOperatorType,
typename CentralDensityProblem::PreparedOperatorType>);
STATIC_CHECK_FALSE(std::same_as<
typename AngularMomentumProblem::PreparedOperatorType,
typename AngularMomentumCentralDensityProblem::PreparedOperatorType>);
STATIC_CHECK_FALSE(
std::same_as<typename BaseProblem::PreparedOperatorType, typename CentralDensityProblem::PreparedOperatorType>
);
STATIC_CHECK_FALSE(
std::same_as<
typename AngularMomentumProblem::PreparedOperatorType,
typename AngularMomentumCentralDensityProblem::PreparedOperatorType>
);
STATIC_CHECK(AngularMomentumProblem::FormType::value_block_count == 7);
STATIC_CHECK(AngularMomentumCentralDensityProblem::FormType::value_block_count == 8);
STATIC_CHECK(std::same_as<
typename BaseProblem::FormType,
utils::blocks::surface_deformed_stellar_equilibrium_form>);
STATIC_CHECK(std::same_as<
typename CentralDensityProblem::FormType,
utils::blocks::central_density_bordered_stellar_equilibrium_form>);
STATIC_CHECK(
std::same_as<typename BaseProblem::FormType, utils::blocks::surface_deformed_stellar_equilibrium_form>
);
STATIC_CHECK(
std::same_as<
typename CentralDensityProblem::FormType, utils::blocks::central_density_bordered_stellar_equilibrium_form>
);
STATIC_CHECK(
std::same_as<
typename BaseProblem::CompiledSurfaceConstraintType,
@@ -242,34 +249,29 @@ TEST_CASE(
) {
using namespace mean_field;
utils::Args arguments = test_utils::setup_args();
utils::Args arguments = test_utils::setup_args();
fem::FEM finiteElements = fem::setup_fem(arguments.mesh_file, arguments, 0);
REQUIRE(finiteElements.okay());
constexpr double radius = utils::RADIUS;
constexpr double mass = utils::MASS;
constexpr double radius = utils::RADIUS;
constexpr double mass = utils::MASS;
constexpr double targetAngularMomentum = 0.1;
const double polytropicConstant = 2.0 * utils::G * radius * radius / std::numbers::pi_v<double>;
const double seedCentralDensity =
std::numbers::pi_v<double> * mass / (4.0 * radius * radius * radius);
auto model = model::StellarModel(
const double polytropicConstant = 2.0 * utils::G * radius * radius / std::numbers::pi_v<double>;
const double seedCentralDensity = std::numbers::pi_v<double> * mass / (4.0 * radius * radius * radius);
auto model = model::StellarModel(
eos::Polytrope({.n = 1.0, .K = polytropicConstant}),
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}),
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{mass}}),
integral::FixedAngularMomentum({
.Jtotal = dimensions::AngularMomentumValue{targetAngularMomentum},
.axis = {0.0, 0.0, 3.0}
})
integral::FixedAngularMomentum(
{.Jtotal = dimensions::AngularMomentumValue{targetAngularMomentum}, .axis = {0.0, 0.0, 3.0}}
)
);
auto problem = equilibrium::discretize(model, finiteElements);
auto problem = equilibrium::discretize(model, std::move(finiteElements));
auto projected = seed::makeProjectedEquilibriumState(
problem,
seed::LaneEmden({
.centralDensity = dimensions::DensityValue{seedCentralDensity},
.radialSampleCount = 1024
})
seed::LaneEmden({.centralDensity = dimensions::DensityValue{seedCentralDensity}, .radialSampleCount = 1024})
);
auto dependencies = make_dependencies();
auto dependencies = make_dependencies();
const auto preparation = problem.Prepare(projected.values, dependencies);
CHECK(preparation.generatedPhysicalControl);
@@ -284,7 +286,7 @@ TEST_CASE(
CHECK(std::abs(angularReport.scaledResidual) < 7.0e-4);
mfem::Vector direction(problem.StateSize());
direction = 0.0;
direction = 0.0;
mfem::Vector angularVelocityDirection = problem.GetManifest().stateView(direction).block(
utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term
);
@@ -309,15 +311,15 @@ TEST_CASE(
plusResidual -= minusResidual;
plusResidual /= 2.0 * step;
auto analyticView = problem.GetManifest().residualView(analyticAction);
auto differenceView = problem.GetManifest().residualView(plusResidual);
auto analyticView = problem.GetManifest().residualView(analyticAction);
auto differenceView = problem.GetManifest().residualView(plusResidual);
const auto blockError = [&](const auto &term) {
const mfem::Vector analytic = analyticView.block(term);
const mfem::Vector analytic = analyticView.block(term);
const mfem::Vector difference = differenceView.block(term);
return relative_difference(analytic, difference);
};
const double surfaceError = blockError(utils::blocks::surface_deformation_field.shape_equilibrium_term);
const double surfaceError = blockError(utils::blocks::surface_deformation_field.shape_equilibrium_term);
const double enthalpyError = blockError(utils::blocks::enthalpy_field.specific_term);
const double angularMomentumError =
blockError(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term);
@@ -335,13 +337,48 @@ TEST_CASE(
CHECK(analyticView.block(utils::blocks::density_field.mass_term).Norml2() == 0.0);
CHECK(analyticView.block(utils::blocks::fixed_total_mass_constraint.mass_normalization_term).Norml2() == 0.0);
mfem::Vector nonFiniteAngularVelocityState(projected.values);
auto nonFiniteAngularVelocity = problem.GetManifest()
.stateView(nonFiniteAngularVelocityState)
.block(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term);
REQUIRE(nonFiniteAngularVelocity.Size() == 1);
nonFiniteAngularVelocity(0) = std::numeric_limits<double>::quiet_NaN();
nonFiniteAngularVelocity.SyncAliasMemory(nonFiniteAngularVelocityState);
const auto nonFiniteControl = problem.TryPrepare(nonFiniteAngularVelocityState, dependencies);
REQUIRE_FALSE(nonFiniteControl.has_value());
CHECK(
nonFiniteControl.error().reason == operators::StellarEquilibriumPreparationRejectionReason::non_finite_physics
);
CHECK_FALSE(problem.IsPrepared());
REQUIRE(problem.TryPrepare(projected.values, dependencies).has_value());
mfem::Vector negativeDensityState(projected.values);
auto negativeDensity =
problem.GetManifest().stateView(negativeDensityState).block(utils::blocks::density_field.mass_term);
negativeDensity *= -1.0;
negativeDensity.SyncAliasMemory(negativeDensityState);
auto negativeDensityDependencies = dependencies;
++negativeDensityDependencies.density.revision;
const auto inadmissibleMoment = problem.TryPrepare(negativeDensityState, negativeDensityDependencies);
REQUIRE_FALSE(inadmissibleMoment.has_value());
CHECK(
inadmissibleMoment.error().reason ==
operators::StellarEquilibriumPreparationRejectionReason::inadmissible_physics
);
CHECK_FALSE(problem.IsPrepared());
++negativeDensityDependencies.density.revision;
REQUIRE(problem.TryPrepare(projected.values, negativeDensityDependencies).has_value());
CHECK(problem.IsPrepared());
auto zeroModel = model::StellarModel(
eos::Polytrope({.n = 1.0, .K = polytropicConstant}),
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}),
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{mass}}),
integral::FixedAngularMomentum({.Jtotal = dimensions::AngularMomentumValue{0.0}})
);
auto zeroProblem = equilibrium::discretize(zeroModel, finiteElements);
fem::FEM zeroFiniteElements = fem::setup_fem(arguments.mesh_file, arguments, 0);
REQUIRE(zeroFiniteElements.okay());
auto zeroProblem = equilibrium::discretize(zeroModel, std::move(zeroFiniteElements));
mfem::Vector zeroState(projected.values);
zeroProblem.GetManifest().stateView(zeroState).block(
utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term
@@ -361,47 +398,37 @@ TEST_CASE(
) {
using namespace mean_field;
using Form = operators::CompiledStellarEquilibriumForm<EarlierMultiplierModel>;
using EarlierValue = utils::blocks::generated_value_block<
models::MultiplierFor<outer_manifest_report_test::EarlierMultiplier>>;
using EarlierValue =
utils::blocks::generated_value_block<models::MultiplierFor<outer_manifest_report_test::EarlierMultiplier>>;
using MassValue = utils::blocks::fixed_total_mass::mass_normalization::value;
STATIC_CHECK(utils::blocks::type_index_v<
EarlierValue,
typename Form::value_blocks> == 5);
STATIC_CHECK(utils::blocks::type_index_v<
MassValue,
typename Form::value_blocks> == 6);
STATIC_CHECK(utils::blocks::type_index_v<EarlierValue, typename Form::value_blocks> == 5);
STATIC_CHECK(utils::blocks::type_index_v<MassValue, typename Form::value_blocks> == 6);
utils::Args arguments = test_utils::setup_args();
utils::Args arguments = test_utils::setup_args();
fem::FEM finiteElements = fem::setup_fem(arguments.mesh_file, arguments, 0);
REQUIRE(finiteElements.okay());
auto model = model::StellarModel(
eos::Polytrope({.n = 1.0, .K = 0.25}),
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}),
outer_manifest_report_test::EarlierMultiplier({
.target = dimensions::SpecificEnergyValue{0.75}}),
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}),
outer_manifest_report_test::EarlierMultiplier({.target = dimensions::SpecificEnergyValue{0.75}}),
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{1.25}})
);
auto problem = equilibrium::discretize(model, finiteElements);
auto problem = equilibrium::discretize(model, std::move(finiteElements));
mfem::Vector state(problem.StateSize());
state = 0.0;
const auto stateView = problem.GetManifest().stateView(state);
stateView.block(utils::blocks::density_field.mass_term) = 1.0;
state = 0.0;
const auto stateView = problem.GetManifest().stateView(state);
stateView.block(utils::blocks::density_field.mass_term) = 1.0;
stateView.block(utils::blocks::enthalpy_field.specific_term) = 1.0;
stateView.block(utils::blocks::fixed_total_mass_constraint.mass_normalization_term) = 0.25;
const auto preparation = problem.Prepare(
state,
make_dependencies(),
make_zero_rotation()
);
REQUIRE(preparation.physical.DidAnyWork());
const auto preparation = problem.TryPrepare(state, make_dependencies(), make_zero_rotation());
REQUIRE(preparation.has_value());
REQUIRE(preparation->physical.DidAnyWork());
const auto report = problem.GetPreparedOperator().GetFixedMassReport();
const auto &outerDescriptor =
problem.GetManifest().template specification<models::FixedTotalMass>();
const auto report = problem.GetPreparedOperator().GetFixedMassReport();
const auto &outerDescriptor = problem.GetManifest().template specification<models::FixedTotalMass>();
CHECK(report.descriptor.stableId == outerDescriptor.stableId);
CHECK(report.descriptor.valueBlock == outerDescriptor.valueBlock);
CHECK(report.descriptor.residualBlock == outerDescriptor.residualBlock);
@@ -409,8 +436,7 @@ TEST_CASE(
CHECK(report.descriptor.residualBlock == 6);
CHECK(report.descriptor.target == 1.25);
CHECK(report.dimensionalResidual == report.achieved - report.descriptor.target);
CHECK(report.scaledResidual ==
report.dimensionalResidual / report.descriptor.residualScale);
CHECK(report.scaledResidual == report.dimensionalResidual / report.descriptor.residualScale);
}
TEST_CASE(
@@ -419,32 +445,38 @@ TEST_CASE(
) {
using namespace mean_field;
utils::Args args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(f.okay());
utils::Args args = test_utils::setup_args();
fem::FEM legacyFiniteElements = fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(legacyFiniteElements.okay());
fem::FEM modelDrivenFiniteElements = fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(modelDrivenFiniteElements.okay());
const MPI_Comm modelDrivenCommunicator = modelDrivenFiniteElements.mesh->GetComm();
const mapping::DomainMapper *modelDrivenMapper = modelDrivenFiniteElements.domainMapperStateless.get();
models::StellarModel legacyModel{
models::structure::PolytropicStructure{eos::Polytrope{3.0, 0.25}, 1.25},
surface::ConstantPressureSurface{eos::PressureValue{0.0}}
};
operators::PreparedStellarEquilibriumOperator legacyOperator(f, *f.domainMapperStateless, legacyModel);
operators::PreparedStellarEquilibriumOperator legacyOperator(
legacyFiniteElements, *legacyFiniteElements.domainMapperStateless, legacyModel
);
const equilibrium::StellarDiscretization discretization{f, *f.domainMapperStateless};
auto equilibriumProblem = equilibrium::discretize(
model::StellarModel(
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{1.25}}),
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}), eos::Polytrope({.n = 3.0, .K = 0.25})
),
discretization
std::move(modelDrivenFiniteElements)
);
auto &modelDrivenOperator = equilibriumProblem.GetPreparedOperator();
auto &modelDrivenOperator = equilibriumProblem.GetPreparedOperator();
const auto &physicalOperator = equilibriumProblem.GetPhysicalOperator();
CHECK(equilibriumProblem.StateSize() == legacyOperator.Width());
CHECK(equilibriumProblem.EquationSize() == legacyOperator.Height());
CHECK(equilibriumProblem.StateSize() == equilibriumProblem.EquationSize());
CHECK(&equilibriumProblem.GetDiscretization().finiteElementModel() == &f);
CHECK(&equilibriumProblem.GetDiscretization().domainMapper() == f.domainMapperStateless.get());
CHECK(equilibriumProblem.GetCommunicator() == modelDrivenCommunicator);
CHECK(&equilibriumProblem.GetDiscretization().domainMapper() == modelDrivenMapper);
CHECK(equilibriumProblem.GetDiscretization().isCurrent());
CHECK(physicalOperator.GetTargetMass() == 1.25);
CHECK(physicalOperator.GetSurfaceConstraintOperator().GetPhysicalCondition().targetPressure == 0.0);
@@ -455,7 +487,7 @@ TEST_CASE(
mfem::Vector state(legacyOperator.Width());
state = 0.0;
const auto stateView = legacyOperator.GetRootManifest().stateView(state);
const auto stateView = legacyOperator.GetRootManifest().stateView(state);
stateView.block(utils::blocks::density_field.mass_term) = 1.0;
stateView.block(utils::blocks::enthalpy_field.specific_term) = 1.0;
@@ -487,29 +519,28 @@ TEST_CASE(
) {
using namespace mean_field;
utils::Args arguments = test_utils::setup_args();
utils::Args arguments = test_utils::setup_args();
fem::FEM finiteElements = fem::setup_fem(arguments.mesh_file, arguments, 0);
REQUIRE(finiteElements.okay());
auto model = model::StellarModel(
eos::Polytrope({.n = 1.0, .K = 0.25}),
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}),
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}),
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{1.0}}),
integral::FixedAngularMomentum({.Jtotal = dimensions::AngularMomentumValue{0.2}}),
constraint::FixedCentralDensity({.RhoC = dimensions::DensityValue{1.0}})
);
auto problem = equilibrium::discretize(model, finiteElements);
auto problem = equilibrium::discretize(model, std::move(finiteElements));
using Problem = std::remove_cvref_t<decltype(problem)>;
STATIC_CHECK(Problem::FormType::value_block_count == 8);
STATIC_CHECK(Problem::FormType::residual_block_count == 8);
mfem::Vector state(problem.StateSize());
state = 0.0;
const auto stateView = problem.GetManifest().stateView(state);
stateView.block(utils::blocks::density_field.mass_term) = 1.0;
state = 0.0;
const auto stateView = problem.GetManifest().stateView(state);
stateView.block(utils::blocks::density_field.mass_term) = 1.0;
stateView.block(utils::blocks::enthalpy_field.specific_term) = 1.0;
stateView.block(utils::blocks::fixed_total_mass_constraint.mass_normalization_term) = 0.25;
stateView.block(utils::blocks::fixed_total_mass_constraint.mass_normalization_term) = 0.25;
stateView.block(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term) = 0.4;
stateView.block(utils::blocks::fixed_central_density_phase.central_value_term) = 0.03;
stateView.block(utils::blocks::fixed_central_density_phase.central_value_term) = 0.03;
const auto report = problem.Prepare(state, make_dependencies());
CHECK(report.template specification<models::FixedCentralDensity>().constraint.DidAnyWork());
@@ -517,18 +548,18 @@ TEST_CASE(
CHECK(problem.IsPrepared());
CHECK(problem.StateSize() == problem.GetPhysicalOperator().Width() + 2);
REQUIRE(problem.GetManifest().constraints().size() == 4);
CHECK(problem.GetManifest().template specification<models::FixedAngularMomentum>().stableId ==
"FixedAngularMomentum");
CHECK(problem.GetManifest().template specification<models::FixedCentralDensity>().stableId ==
"FixedCentralDensity");
CHECK(
problem.GetManifest().template specification<models::FixedAngularMomentum>().stableId == "FixedAngularMomentum"
);
CHECK(
problem.GetManifest().template specification<models::FixedCentralDensity>().stableId == "FixedCentralDensity"
);
mfem::Vector residual;
problem.BuildResidual(residual);
REQUIRE(residual.Size() == problem.EquationSize());
const auto residualView = problem.GetManifest().residualView(residual);
CHECK(std::isfinite(
residualView.block(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term)(0)
));
CHECK(std::isfinite(residualView.block(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term)(0)));
CHECK(std::isfinite(residualView.block(utils::blocks::fixed_central_density_phase.central_value_term)(0)));
mfem::Vector direction(problem.StateSize());