Add controlled density-order projection and coupled-solve observations

This commit is contained in:
2026-09-19 10:48:14 -04:00
parent dd955abca5
commit 2ca6890a18
5 changed files with 970 additions and 1 deletions

View File

@@ -35,6 +35,7 @@ import mean_field;
#include "spherical_harmonic_surface_diagnostics.hpp"
#include "negative_density_diagnostics.hpp"
#include "negative_density_regions.hpp"
#include "density_order_projection.hpp"
using namespace mean_field;
namespace {
@@ -49,6 +50,7 @@ struct Options {
bool reducedSurfaceProbe = false, reducedSurfaceAlgebraCheck = false;
bool densityDiagnostic = false;
bool densityRegions = false;
bool densityOrderProjection = false, densityOrderFinal = false;
int surfaceDegree = 4, surfaceMaximumOrder = -1;
std::string surfacePrescription = "nodal";
bool coupledTrialProbe = false, coupledSeedControl = false;
@@ -135,6 +137,12 @@ Options Parse(int argc, char **argv) {
o.densityDiagnostic = true;
o.densityRegions = true;
}
else if (a == "--density-order-projection") {
o.densityDiagnostic = true;
o.densityOrderProjection = true;
}
else if (a == "--density-order-final")
o.densityOrderFinal = true;
else if (a == "--density-snapshot")
o.densitySnapshot = v();
else if (a == "--surface-prescription")
@@ -209,6 +217,8 @@ Options Parse(int argc, char **argv) {
throw std::invalid_argument("Surface prescriptions are nodal or harmonics");
if (!o.densitySnapshot.empty() && !o.densityDiagnostic)
throw std::invalid_argument("--density-snapshot requires --density-diagnostic");
if ((o.densityOrderProjection && o.densityRegions) || (o.densityDiagnostic && o.densityOrderFinal))
throw std::invalid_argument("Choose one frozen density observation or the coupled final observation");
if (o.densityDiagnostic && (o.maxNewton != 0 || o.strategy != "baseline" || o.probes ||
o.pressureProbe || o.shapeCurvature || o.surfaceTrace || o.strategyProbe || o.positivityProbe ||
o.positivityCertificate || o.preconditionerProbe || o.nonlinearStepProbe || o.reducedSurfaceProbe ||
@@ -687,6 +697,13 @@ int RunContext(Context &context, const Options &o, const Scales &scales) {
<< "\ncontext_gravity_schur_relaxation=" << (contextUsesGravitySchur ? o.schurRelaxation : 0.0)
<< "\nschur_correction_sweeps=" << o.schurCorrectionSweeps << "\nschur_relaxation=" << o.schurRelaxation
<< "\ncompiler=" << __VERSION__ << "\ncompiled=" << __DATE__ << ' ' << __TIME__ << '\n';
metadata << "density_order=" << field::Density::scalarOrder
<< "\nenthalpy_order=" << field::Enthalpy::scalarOrder
<< "\ngravity_potential_order=" << field::Gravity::potentialOrder
<< "\ngravity_flux_order=" << field::Gravity::fluxOrder
<< "\ndisplacement_order=" << field::Displacement::Vector::familyOrder
<< "\ndensity_order_projection=" << o.densityOrderProjection
<< "\ndensity_order_final=" << o.densityOrderFinal << '\n';
if (o.densityDiagnostic) {
metadata << "density_diagnostic=1\ndensity_region_integral=" << o.densityRegions << "\ndensity_source="
<< (o.densitySnapshot.empty() ? "lane_emden_seed" : o.densitySnapshot.string()) << '\n';
@@ -727,7 +744,9 @@ int RunContext(Context &context, const Options &o, const Scales &scales) {
adapter.scatter(closureResidual, closureFull);
SaveVector(o.output / "production_closure_residual_full.txt", closureFull);
SaveVector(o.output / "observed_density_coefficients.txt", physical.density);
if (o.densityRegions)
if (o.densityOrderProjection)
experiment::plateau_diagnostics::RecordDensityOrderProjection(physical, o.n, scales.K, o.output);
else if (o.densityRegions)
experiment::plateau_diagnostics::RecordDensityNegativeRegions(physical, o.n, scales.K, o.output);
else
experiment::plateau_diagnostics::RecordNegativeDensity(physical, o.n, scales.K, o.output);
@@ -1215,6 +1234,16 @@ int RunContext(Context &context, const Options &o, const Scales &scales) {
solver::detail::StellarEquilibriumContextDiagnostics::WithState(context, [&](auto &s, const fem::FEM &f) {
SaveVector(o.output / "accepted_state.txt", s.AcceptedPhysicalState());
physicalMetrics(s, f, "final");
if (o.densityOrderFinal) {
experiment::polytrope_validation::PhysicalState physical(s, f);
experiment::plateau_diagnostics::RecordDensityOrderState(physical, o.n, scales.K, o.output);
auto rules = File(o.output / "final_closure_rules.csv");
rules << "element,quadrature_order,quadrature_points\n";
s.Problem().GetPhysicalOperator().GetBarotropicClosureOperator().VisitMappedGeometryRules(
[&](int element, const mfem::IntegrationRule &rule) {
rules << element << ',' << rule.GetOrder() << ',' << rule.GetNPoints() << '\n';
});
}
const auto &schur = s.physicalInverse->GetGroupedPreconditioner().GetFactorization().GetSchurComplement();
auto sh = File(o.output / "border_schur.csv");
for (int i = 0; i < schur.Height(); ++i) {