#include #include #include #include #include #include import mean_field; import test_helpers; namespace { using CanonicalModel = mean_field::models:: Model; using PermutedModel = mean_field::models:: Model; using CentralDensityModel = mean_field::models::Model< mean_field::models::FixedCentralDensity, mean_field::surface::Isobaric, mean_field::eos::Polytrope, mean_field::models::FixedTotalMass>; using Form = mean_field::utils::blocks::surface_deformed_stellar_equilibrium_form; using JacobianForm = mean_field::utils::blocks::surface_deformed_stellar_equilibrium_jacobian_form; using Manifest = mean_field::operators::CompiledRootManifest; using CentralForm = mean_field::utils::blocks::central_density_bordered_stellar_equilibrium_form; using CentralJacobianForm = mean_field::utils::blocks::central_density_bordered_stellar_equilibrium_jacobian_form; using CentralManifest = mean_field::operators::CompiledRootManifest; [[nodiscard]] Manifest make_manifest() { const std::array valueSizes{2, 3, 4, 5, 6, 1}; const std::array residualSizes{4, 5, 2, 3, 6, 1}; return {valueSizes, residualSizes, 2.5, 0.125, 3}; } } // namespace TEST_CASE( "Model Values Are Stored In Canonical Specification Order", tags::model_specification_type_contract ) { STATIC_CHECK(std::same_as); STATIC_CHECK(CanonicalModel::symbolicallySquare); STATIC_CHECK(CanonicalModel::hasCompleteRootCompiler); STATIC_CHECK(CanonicalModel::compilationClass == mean_field::models::ModelCompilationClass::isolated_root); STATIC_CHECK(CentralDensityModel::symbolicallySquare); STATIC_CHECK(CentralDensityModel::hasCompleteRootCompiler); STATIC_CHECK(CentralDensityModel::compilationClass == mean_field::models::ModelCompilationClass::isolated_root); const mean_field::eos::Polytrope equationOfState{2.0, 0.75}; const mean_field::surface::Isobaric surface{mean_field::dimensions::PressureValue{0.125}}; const mean_field::models::FixedTotalMass mass{mean_field::dimensions::MassValue{1.75}}; const CanonicalModel model{mass, surface, equationOfState}; CHECK(model.specification().polytropic_index() == 2.0); CHECK(model.specification().targetPressure().value() == 0.125); CHECK( model.specification().targetMass() == mean_field::dimensions::MassValue{1.75} ); const auto descriptors = model.runtimeSpecificationDescriptors(); REQUIRE(descriptors.size() == 3); CHECK(descriptors[0].specification.name == "Polytrope"); CHECK(descriptors[1].specification.name == "IsobaricSurface"); CHECK(descriptors[2].specification.name == "FixedTotalMass"); CHECK(descriptors[0].canonicalIndex == 0); CHECK(descriptors[1].canonicalIndex == 1); CHECK(descriptors[2].canonicalIndex == 2); CHECK(descriptors[0].hasRootCompiler); CHECK(descriptors[1].hasRootCompiler); CHECK(descriptors[2].hasRootCompiler); } TEST_CASE( "Central Density Root Manifest Appends A Carrier Phase Row And Solver Border", tags::root_manifest_type_contract ) { const std::array valueSizes{2, 3, 4, 5, 6, 1, 1}; const std::array residualSizes{4, 5, 2, 3, 6, 1, 1}; const CentralManifest manifest( valueSizes, residualSizes, 2.5, 0.125, 3, mean_field::operators::CentralDensityManifestInput{ .targetDensity = 8.0, .targetEnthalpy = 2.0, .centerDofCount = 1 } ); CHECK(manifest.layout().value_offsets().Last() == 22); CHECK(manifest.layout().residual_offsets().Last() == 22); REQUIRE(manifest.valueBlocks().size() == 7); REQUIRE(manifest.residualBlocks().size() == 7); CHECK(manifest.valueBlocks()[6].stableId == "fixed_central_density.border"); CHECK(manifest.valueBlocks()[6].symbol == "lambda_rho_c"); CHECK(manifest.valueBlocks()[6].columnPolicy == mean_field::operators::RootColumnPolicy::solver_border); CHECK(manifest.residualBlocks()[6].stableId == "fixed_central_density.residual"); CHECK(manifest.residualBlocks()[6].symbol == "R_rho_c"); CHECK(manifest.residualBlocks()[6].scale == 2.0); const auto constraints = manifest.constraints(); REQUIRE(constraints.size() == 3); CHECK(constraints[2].stableId == "FixedCentralDensity"); CHECK(constraints[2].role == mean_field::models::SpecificationRole::phase_condition); CHECK(constraints[2].valueBlock == 6); CHECK(constraints[2].residualBlock == 6); CHECK(constraints[2].target == 8.0); REQUIRE(constraints[2].carrierTarget.has_value()); CHECK(*constraints[2].carrierTarget == 2.0); CHECK(constraints[2].residualScale == 2.0); } TEST_CASE( "Compiled Root Manifest Centralizes Canonical Blocks Provenance And Scaling", tags::root_manifest_type_contract ) { const Manifest manifest = make_manifest(); STATIC_CHECK(Manifest::symbolicallySquare); STATIC_CHECK(Manifest::compilationClass == mean_field::models::ModelCompilationClass::isolated_root); CHECK(manifest.layout().value_offsets().Last() == 21); CHECK(manifest.layout().residual_offsets().Last() == 21); const auto values = manifest.valueBlocks(); const auto residuals = manifest.residualBlocks(); REQUIRE(values.size() == 6); REQUIRE(residuals.size() == 6); CHECK(values[0].stableId == "density"); CHECK(values[0].symbol == "rho"); CHECK(values[1].stableId == "surface_deformation"); CHECK(values[5].stableId == "fixed_total_mass.multiplier"); CHECK(values[5].symbol == "C"); CHECK(values[5].provenance == mean_field::operators::RootBlockProvenance::model_specification); CHECK(values[5].source == "FixedTotalMass"); CHECK(values[5].columnPolicy == mean_field::operators::RootColumnPolicy::existing_physical_multiplier); CHECK(residuals[5].stableId == "fixed_total_mass.residual"); CHECK(residuals[5].symbol == "R_M"); CHECK(residuals[5].rowInjection == mean_field::operators::RootRowInjection::append_global); CHECK(residuals[5].scalePolicy == mean_field::operators::RootScalePolicy::target_relative); CHECK(residuals[5].scale == 2.5); const auto replacements = manifest.rowReplacements(); REQUIRE(replacements.size() == 1); CHECK(replacements[0].sourceSpecification == "IsobaricSurface"); CHECK(replacements[0].replacedRowCount == 3); CHECK(replacements[0].carrierResidualBlock == 4); const auto constraints = manifest.constraints(); REQUIRE(constraints.size() == 2); CHECK(constraints[0].stableId == "FixedTotalMass"); CHECK(constraints[0].valueBlock == 5); CHECK(constraints[0].residualBlock == 5); CHECK(constraints[0].target == 2.5); CHECK(constraints[0].residualScale == 2.5); CHECK(constraints[1].stableId == "IsobaricSurface"); CHECK(constraints[1].rowInjection == mean_field::operators::RootRowInjection::replace_carrier_rows); CHECK(constraints[1].target == 0.125); CHECK_FALSE(constraints[1].carrierTarget.has_value()); const auto report = manifest.fixedMassReport(2.75); CHECK(report.achieved == 2.75); CHECK(report.dimensionalResidual == 0.25); CHECK(report.scaledResidual == 0.1); } TEST_CASE( "Typed Root Views Resolve Blocks Through The Compiled Manifest", tags::root_manifest_type_contract ) { const Manifest manifest = make_manifest(); mfem::Vector state(manifest.layout().value_offsets().Last()); for (int index = 0; index < state.Size(); ++index) { state(index) = static_cast(index + 1); } const auto stateView = manifest.stateView(state); const mfem::Vector density = stateView.block(mean_field::utils::blocks::density_field.mass_term); const mfem::Vector surface = stateView.block(mean_field::utils::blocks::surface_deformation_field.parameters_term); const mfem::Vector multiplier = stateView.block(mean_field::utils::blocks::fixed_total_mass_constraint.mass_normalization_term); REQUIRE(density.Size() == 2); REQUIRE(surface.Size() == 3); REQUIRE(multiplier.Size() == 1); CHECK(density(0) == 1.0); CHECK(surface(0) == 3.0); CHECK(multiplier(0) == 21.0); mfem::Vector residual(manifest.layout().residual_offsets().Last()); residual = 0.0; const auto residualView = manifest.residualView(residual); mfem::Vector massResidual(1); massResidual(0) = -0.375; residualView.assign(mean_field::utils::blocks::fixed_total_mass_constraint.mass_normalization_term, massResidual); CHECK(residual(20) == -0.375); mfem::Vector wrongState(state.Size() - 1); CHECK_THROWS_AS(manifest.stateView(wrongState), std::invalid_argument); }