Reject unsupported pressure traces before polynomial state certification
This commit is contained in:
@@ -18,6 +18,44 @@ export import :solver.enthalpy_admissibility;
|
||||
export import :normalization.stellar_equilibrium;
|
||||
export import :utils.domain;
|
||||
|
||||
export namespace mean_field::solver::detail {
|
||||
template <class SurfaceConstraint>
|
||||
concept PolynomialEnthalpySurfaceConstraint = requires {
|
||||
typename SurfaceConstraint::CarrierQuantity;
|
||||
typename SurfaceConstraint::Relation;
|
||||
requires std::same_as<typename SurfaceConstraint::CarrierQuantity,dimensions::quantity::SpecificEnthalpy>;
|
||||
requires std::same_as<typename SurfaceConstraint::Relation,eos::SpecificEnthalpyFromPressure>;
|
||||
};
|
||||
|
||||
// The polynomial engine fixes homogeneous trace rows. Check the physical
|
||||
// prescription before inspecting coefficients, so an unsupported surface
|
||||
// condition is never reported as an invalid numerical starting state.
|
||||
template <PolynomialEnthalpySurfaceConstraint SurfaceConstraint, class EquationOfState>
|
||||
void RequirePolynomialEnthalpySurface(const SurfaceConstraint &surface,
|
||||
const EquationOfState &equationOfState, MPI_Comm communicator) {
|
||||
int localUnsupported = surface.targetPressure().value() == 0.0 ? 0 : 1;
|
||||
int globalUnsupported = 0;
|
||||
if (MPI_Allreduce(&localUnsupported,&globalUnsupported,1,MPI_INT,MPI_MAX,communicator) != MPI_SUCCESS)
|
||||
throw std::runtime_error("Could not validate the polynomial enthalpy surface prescription.");
|
||||
if (globalUnsupported)
|
||||
throw std::invalid_argument("PolynomialEnthalpy supports only zero prescribed surface pressure (Psurf=0).");
|
||||
bool homogeneous = false;
|
||||
try {
|
||||
const double trace = eos::evaluate<dimensions::quantity::SpecificEnthalpy>(
|
||||
equationOfState,surface.targetPressure()).value();
|
||||
homogeneous = std::isfinite(trace) && trace == 0.0;
|
||||
} catch (...) {
|
||||
// A rank-local EOS exception must not strand other ranks in the
|
||||
// collective compatibility check that follows.
|
||||
}
|
||||
localUnsupported = homogeneous ? 0 : 1;
|
||||
if (MPI_Allreduce(&localUnsupported,&globalUnsupported,1,MPI_INT,MPI_MAX,communicator) != MPI_SUCCESS)
|
||||
throw std::runtime_error("Could not validate the zero-pressure enthalpy reference.");
|
||||
if (globalUnsupported)
|
||||
throw std::invalid_argument("PolynomialEnthalpy requires the EOS to prescribe h(Psurf=0)=0.");
|
||||
}
|
||||
}
|
||||
|
||||
export namespace mean_field::solver {
|
||||
/*
|
||||
* The solver owns this workspace only when a positivity policy is selected.
|
||||
@@ -28,6 +66,8 @@ export namespace mean_field::solver {
|
||||
class PreparedStellarEnthalpyStrategy final {
|
||||
using Problem = std::remove_cvref_t<decltype(std::declval<State &>().Problem())>;
|
||||
using Form = typename Problem::FormType;
|
||||
static_assert(detail::PolynomialEnthalpySurfaceConstraint<typename Problem::CompiledSurfaceConstraintType>,
|
||||
"PolynomialEnthalpy requires a state-independent specific-enthalpy pressure surface relation.");
|
||||
using Schema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
using Domain = field::FieldDomainT<field::Enthalpy>;
|
||||
static constexpr int enthalpyIndex = utils::blocks::type_index_v<
|
||||
@@ -39,6 +79,8 @@ export namespace mean_field::solver {
|
||||
: m_state(&state),
|
||||
m_offset(state.Problem().GetManifest().layout().offset(enthalpyBlock)),
|
||||
m_size(state.Problem().GetManifest().layout().size(enthalpyBlock)) {
|
||||
detail::RequirePolynomialEnthalpySurface(state.Problem().GetCompiledSurfaceConstraint(),
|
||||
state.Problem().GetStellarModel().equationOfState(),state.Problem().GetCommunicator());
|
||||
const auto &fem = equilibrium::detail::StellarEquilibriumProblemFactory::FiniteElementModel(state.Problem());
|
||||
if (!fem.mesh || !fem.enthalpyFes)
|
||||
throw std::invalid_argument("Stellar enthalpy certification requires a complete enthalpy FE space.");
|
||||
|
||||
Reference in New Issue
Block a user