\documentclass[11pt]{article} \usepackage[T1]{fontenc} \usepackage{lmodern} \usepackage[margin=0.82in]{geometry} \usepackage{amsmath} \usepackage{amssymb} \usepackage{booktabs} \usepackage{enumitem} \usepackage{xcolor} \usepackage{listings} \usepackage{tabularx} \usepackage{longtable} \usepackage{fancyhdr} \usepackage{microtype} \usepackage{hyperref} \definecolor{MeanFieldBlue}{HTML}{174A67} \definecolor{MeanFieldLightBlue}{HTML}{EAF3F8} \definecolor{MeanFieldGold}{HTML}{A66500} \definecolor{CodeBackground}{HTML}{F5F7F8} \definecolor{CodeComment}{HTML}{476B45} \definecolor{CodeKeyword}{HTML}{6B327A} \hypersetup{ colorlinks=true, linkcolor=MeanFieldBlue, urlcolor=MeanFieldBlue, pdftitle={MeanField Physics Developer Manual}, pdfauthor={MeanField extension example} } \pagestyle{fancy} \fancyhf{} \lhead{MeanField Physics Developer Manual} \rhead{Extension Example} \cfoot{\thepage} \setlength{\headheight}{14pt} \setlist[itemize]{leftmargin=1.35em,itemsep=0.25em,topsep=0.35em} \setlist[enumerate]{leftmargin=1.5em,itemsep=0.35em,topsep=0.35em} \lstdefinestyle{meanfieldcpp}{ language=C++, basicstyle=\ttfamily\small, keywordstyle=\color{CodeKeyword}\bfseries, commentstyle=\color{CodeComment}, stringstyle=\color{MeanFieldGold}, backgroundcolor=\color{CodeBackground}, frame=single, rulecolor=\color{MeanFieldBlue!35}, numbers=left, numberstyle=\tiny\color{black!55}, numbersep=7pt, breaklines=true, breakatwhitespace=true, columns=fullflexible, keepspaces=true, showstringspaces=false, tabsize=4 } \lstdefinestyle{meanfieldshell}{ basicstyle=\ttfamily\small, backgroundcolor=\color{CodeBackground}, frame=single, rulecolor=\color{MeanFieldBlue!35}, breaklines=true, columns=fullflexible, keepspaces=true, showstringspaces=false } \newcommand{\MeanField}{\textnormal{\textsc{MeanField}}} \newcommand{\code}[1]{\texttt{#1}} \newcommand{\dd}{\mathrm{d}} \newcommand{\pd}[2]{\frac{\partial #1}{\partial #2}} \newenvironment{developerbox} {\begin{center}\begin{minipage}{0.94\textwidth}\color{MeanFieldBlue}\hrule\vspace{0.55em}\color{black}} {\vspace{0.55em}\color{MeanFieldBlue}\hrule\end{minipage}\end{center}} \title{\vspace{-1.5em}\color{MeanFieldBlue}\Huge\bfseries Developing Physics Extensions for \MeanField\\[0.4em] \Large A worked ideal-gas plus radiation equation of state} \author{Physics developer example module} \date{Code checkpoint \code{71423d543f1775d3b943d9c0361f49edd56b59c1}\\ Manual built 2026-09-06} \begin{document} \maketitle \begin{developerbox} \textbf{What this manual promises.} You will implement a real two-variable equation of state, make its physical relations and Jacobian derivatives compile-time contracts, and compose it with the existing isobaric surface, fixed-total-mass invariant, and fixed-angular-momentum invariant. You do not need to write block indices or repeat the model assembly logic. \medskip \textbf{What this manual does not claim.} The current numerical stellar-equilibrium core is barotropic. The worked EOS depends independently on density and temperature. It therefore forms a valid typed stellar-model specification, but it cannot yet be passed to the current \code{discretize} operation. A temperature or entropy field and a governing thermal equation must be added to the equilibrium formulation first. The example encodes this boundary as a compile-time assertion. \end{developerbox} \tableofcontents \clearpage \section{Audience and objective} This manual is for an astronomer or physicist who knows the equations they want to add but may not be interested in the template machinery used to assemble a nonlinear root system. The central design rule is: \begin{quote} State the physics once, in physics vocabulary. Let the library infer the structural type of the model, residual, Jacobian, normalization plan, and preconditioner wherever a runtime implementation exists. If a required piece does not exist, reject the operation at compile time. \end{quote} The worked extension lives entirely under \code{extension\_example/}. It does not modify a source file in \code{libmeanfield/}. This separation matters. It demonstrates the public extension surface rather than relying on privileged access to the implementation. At the end, you should be able to answer four questions for a proposed physics extension: \begin{enumerate} \item What quantities and relations does the new physics provide? \item Which analytic derivatives does a Newton Jacobian require? \item Which existing specifications can be composed with it immediately? \item Is the complete numerical runtime available, or is only the symbolic model declaration available? \end{enumerate} \section{The mental model: five layers} It helps to separate five ideas that are often blended together in scientific software. \begin{longtable}{p{0.16\textwidth} p{0.31\textwidth} p{0.43\textwidth}} \toprule \textbf{Layer} & \textbf{Physics question} & \textbf{MeanField representation} \\ \midrule \endhead Quantity & What does this scalar mean? & A type such as \code{Density}, \code{Temperature}, or \code{Pressure}, wrapped in a \code{QuantityValue}. \\ \addlinespace Relation & Which variables determine which result? & A compile-time sentence such as $P=P(\rho,T)$, represented by \code{eos::Relation}. \\ \addlinespace Specification & What physical choice did the model make? & A concrete EOS, surface condition, invariant, phase condition, gauge, or rotation law with a small \code{ModelDefinition}. \\ \addlinespace Compiled system & Which unknowns, residuals, and Jacobian couplings follow from the selected specifications? & A type inferred from the complete, variadic specification pack. \\ \addlinespace Runtime provider & How are those residuals and derivatives evaluated on a mesh? & Numerical assembly, normalization, and preconditioning code that must exist for the compiled type. \\ \bottomrule \end{longtable} A model may be valid at one layer and intentionally unavailable at a later layer. In this example, $P(\rho,T)$ is a valid EOS relation and the four chosen specifications form a valid stellar-model type. The present runtime provider has a barotropic material core, so it rejects the thermal model before a discretization object can be formed. This distinction prevents two dangerous outcomes: \begin{itemize} \item silently dropping a supplied physical constraint; and \item pretending a multidimensional EOS is barotropic by choosing an undocumented path through thermodynamic state space. \end{itemize} \section{Map of the example module} \begin{tabularx}{\textwidth}{p{0.37\textwidth} X} \toprule \textbf{File} & \textbf{Purpose} \\ \midrule \code{ideal\_gas\_radiation.cppm} & Declares relations, implements the EOS, analytic derivatives, input validation, and compile-time protocol checks. \\ \code{rotating\_stellar\_model.cppm} & Provides the small physics-facing composition wrapper and documents the current runtime boundary. \\ \code{demo.cpp} & Evaluates one CGS thermodynamic state and constructs the typed stellar-model specification. \\ \code{tests/ideal\_gas\_radiation.cpp} & Tests dimensions, thermodynamic identities, scaling laws, derivative accuracy, and domain handling. \\ \code{tests/rotating\_stellar\_}\newline\code{model.cpp} & Tests inferred roles, exact specification types, values, and capability rejection. \\ \code{manual/physics\_developer\_}\newline\code{manual.tex} & The source of this manual. \\ \bottomrule \end{tabularx} The module has its own library, demonstration executable, and test executable. It links to \MeanField, but its files are not added to the \code{mean\_field} library target and its tests are not added to the main regression executable. \section{Worked physics: ideal gas plus radiation} \subsection{Assumptions} The example describes a deliberately simple local thermodynamic model: \begin{itemize} \item matter is a classical, nondegenerate, monatomic ideal gas; \item the mean molecular weight $\mu$ is fixed; \item gas and radiation share a single temperature $T$; \item radiation is in local thermodynamic equilibrium; \item ionization, composition evolution, pairs, degeneracy, Coulomb corrections, and opacity do not enter the EOS. \end{itemize} These assumptions are appropriate for demonstrating the extension protocol. They are not a universal stellar EOS. Let $k_{\mathrm B}$ be Boltzmann's constant, $m_{\mathrm u}$ the atomic mass unit, $a$ the radiation energy-density constant, and \begin{equation} \mathcal{R} = \frac{k_{\mathrm B}}{\mu m_{\mathrm u}} \end{equation} the gas constant per unit mass. The pressure contributions are \begin{align} P_{\mathrm{gas}} &= \rho \mathcal{R} T, \\ P_{\mathrm{rad}} &= \frac{aT^4}{3}, \\ P(\rho,T) &= P_{\mathrm{gas}} + P_{\mathrm{rad}}. \end{align} For a monatomic gas, the specific internal energies are \begin{align} u_{\mathrm{gas}} &= \frac{3}{2}\mathcal{R}T, \\ u_{\mathrm{rad}} &= \frac{aT^4}{\rho}, \\ u(\rho,T) &= u_{\mathrm{gas}} + u_{\mathrm{rad}}. \end{align} Using $h=u+P/\rho$, the specific enthalpy is \begin{equation} h(\rho,T) = \frac{5}{2}\mathcal{R}T + \frac{4aT^4}{3\rho}. \end{equation} \subsection{Analytic derivatives} A Newton method needs derivatives of the residual with respect to its state. For this EOS, the useful local derivatives are \begin{align} \left.\pd{P}{\rho}\right|_T &= \mathcal{R}T, & \left.\pd{P}{T}\right|_\rho &= \rho\mathcal{R}+\frac{4aT^3}{3}, \\ \left.\pd{u}{\rho}\right|_T &= -\frac{aT^4}{\rho^2}, & \left.\pd{u}{T}\right|_\rho &= \frac{3}{2}\mathcal{R}+\frac{4aT^3}{\rho}, \\ \left.\pd{h}{\rho}\right|_T &= -\frac{4aT^4}{3\rho^2}, & \left.\pd{h}{T}\right|_\rho &= \frac{5}{2}\mathcal{R}+\frac{16aT^3}{3\rho}. \end{align} The subscript is not optional notation. It tells the developer what is held fixed and corresponds directly to the \code{WithRespectTo<...>} tag in the code. A derivative with the right numerical return type but the wrong held variable is a physics bug. \subsection{Domain and units} The implemented material domain is \begin{equation} \rho > 0, \qquad T \geq 0. \end{equation} Positive density is required because the specific radiation energy and enthalpy contain $1/\rho$. The radiation constant may be set to zero for a pure-gas verification problem. Other constants and $\mu$ must be finite and positive. \MeanField's \code{QuantityValue} gives semantic type safety. It does not perform dimensional algebra or unit conversion. The defaults in this example are CGS: \begin{center} \begin{tabular}{lll} \toprule Constant & Default & CGS unit \\ \midrule $k_{\mathrm B}$ & $1.380649\times10^{-16}$ & erg K$^{-1}$ \\ $m_{\mathrm u}$ & $1.66053906660\times10^{-24}$ & g \\ $a$ & $7.5657\times10^{-15}$ & erg cm$^{-3}$ K$^{-4}$ \\ \bottomrule \end{tabular} \end{center} If the rest of a model uses nondimensional or code units, all three constants, density, temperature, and returned thermodynamic values must be transformed coherently. A typed value prevents passing temperature where density belongs; it cannot detect a CGS value mixed with a nondimensional one. \section{Implementing the EOS} \subsection{Step 1: name the relations} The first code says what the EOS knows, without saying how it computes it. \begin{lstlisting}[style=meanfieldcpp] namespace q = mean_field::dimensions::quantity; using PressureFromDensityAndTemperature = mean_field::eos::Relation< q::Pressure, q::Density, q::Temperature>; using SpecificEnthalpyFromDensityAndTemperature = mean_field::eos::Relation< q::SpecificEnthalpy, q::Density, q::Temperature>; \end{lstlisting} The first template argument is the output. Remaining arguments are inputs in call order. Consequently, \begin{lstlisting}[style=meanfieldcpp] eos::evaluate(eosModel, density, temperature); \end{lstlisting} is valid, while the same call with \code{temperature, density} is rejected at compile time. Use an existing quantity type when it has the intended physical meaning. Temperature and specific internal energy already exist in \code{mean\_field::dimensions::quantity}. If a genuinely new quantity is needed, it can derive from \code{ThermodynamicQuantity} and provide a stable identifier, but adding a quantity to numerical normalization also requires an appropriate scale law and runtime support. \subsection{Step 2: identify the specification role} Inside the EOS class, one alias connects the physics type to the stellar-model front end: \begin{lstlisting}[style=meanfieldcpp] using ModelDefinition = mean_field::eos::ConstitutiveLaw< IdealGasRadiation, "IdealGasRadiation">; \end{lstlisting} The stable name is used in compile-time keys and runtime descriptions. Choose a specific, durable name. Do not encode parameter values in it, and do not reuse the same role-name pair for unrelated physics. This alias is the wrapper intended for physics developers. It projects to the more general model-definition machinery, but the EOS author does not need to name generated blocks, residual rows, or a normalization topology because a constitutive law owns no scalar solver border by itself. \subsection{Step 3: publish the complete relation catalog} \begin{lstlisting}[style=meanfieldcpp] using Relations = mean_field::eos::RelationCatalog< PressureFromDensityAndTemperature, SpecificInternalEnergyFromDensityAndTemperature, SpecificEnthalpyFromDensityAndTemperature>; \end{lstlisting} Treat this catalog as an API promise. Every listed relation must have an exact \code{evaluate} overload. A relation that exists as a helper function but is missing from the catalog is not visible to generic consumers. A relation in the catalog without a matching evaluator makes \code{EquationOfStateModel} false. \subsection{Step 4: implement evaluations in physics notation} The pressure overload is small because named component functions expose useful diagnostics: \begin{lstlisting}[style=meanfieldcpp] [[nodiscard]] dimensions::PressureValue evaluate( PressureFromDensityAndTemperature, dimensions::DensityValue density, dimensions::TemperatureValue temperature ) const { return pressureContributions(density, temperature).total(); } \end{lstlisting} The relation tag is an empty compile-time object. It selects the overload but does not cost storage. Return the exact typed value requested by the relation. Returning a raw \code{double}, even with the correct number, fails the EOS concept. The generic user-facing call is \begin{lstlisting}[style=meanfieldcpp] const auto pressure = mean_field::eos::evaluate< mean_field::dimensions::quantity::Pressure>( equationOfState, density, temperature ); \end{lstlisting} This call infers the relation from output type and typed input sequence. Client code does not construct relation tags directly. \subsection{Step 5: implement Jacobian derivatives} Each derivative overload repeats the relation and states the differentiation variable explicitly: \begin{lstlisting}[style=meanfieldcpp] [[nodiscard]] eos::PartialDerivative partialDerivative( PressureFromDensityAndTemperature, eos::WithRespectTo, dimensions::DensityValue density, dimensions::TemperatureValue temperature ) const { const double T = temperature.value(); return eos::PartialDerivative{ density.value() * specificGasConstant() + 4.0 * parameters().radiationConstant * T * T * T / 3.0 }; } \end{lstlisting} The important contracts are: \begin{itemize} \item relation inputs occur in the same order as in \code{evaluate}; \item \code{WithRespectTo} identifies the independent variable; \item the return type is exactly \code{PartialDerivative}; and \item the formula is a partial derivative at fixed density. \end{itemize} \subsection{Step 6: make the compiler check the public claim} The source finishes with assertions such as \begin{lstlisting}[style=meanfieldcpp] static_assert(eos::EquationOfStateModel); static_assert(eos::SupportsPartialDerivative< IdealGasRadiation, PressureFromDensityAndTemperature, q::Temperature>); \end{lstlisting} These assertions are not substitutes for numerical tests. They prove shape: the relation is declared, the argument order matches, and the exact output type exists. Numerical tests must still prove that the derivative computes the right mathematics. \section{Composing a rotating stellar model} The model itself is the direct expression of the physical choices: \begin{lstlisting}[style=meanfieldcpp] auto model = mean_field::model::StellarModel( IdealGasRadiation(eosParameters), mean_field::surface::Isobaric({.Psurf = surfacePressure}), mean_field::integral::FixedTotalMass({.Mtotal = totalMass}), mean_field::integral::FixedAngularMomentum({ .Jtotal = totalAngularMomentum, .axis = rotationAxis, .center = rotationCenter }) ); \end{lstlisting} The example wraps this expression in \code{makeRotatingStellarModel}. The wrapper groups frequently used inputs; it does not duplicate model assembly. An advanced caller can always use \code{StellarModel(...)} directly. The compiler infers four distinct specification types and their roles: \begin{center} \begin{tabularx}{0.94\textwidth}{p{0.28\textwidth} p{0.21\textwidth} X} \toprule Specification & Role & Structural contribution \\ \midrule \code{IdealGasRadiation} & constitutive law & EOS relations; no generated scalar coordinate \\ \code{Isobaric} & boundary condition & fixed surface pressure; no generated scalar coordinate \\ \code{FixedTotalMass} & invariant & mass constraint residual and its scalar multiplier \\ \code{FixedAngularMomentum} & invariant & angular-momentum constraint residual and angular velocity as a physical coordinate \\ \bottomrule \end{tabularx} \end{center} The two invariants each contribute one scalar unknown and one scalar residual. The complete symbolic operator remains square. Reordering the constructor arguments does not define a new physical combination: the library canonicalizes the specification set by stable compile-time keys while storing exactly one object of each inferred type. \begin{samepage} The model exposes physics-facing accessors: \begin{lstlisting}[style=meanfieldcpp] model.equationOfState(); model.surfaceCondition(); model.specification(); model.specification(); \end{lstlisting} These preserve exact types. There is no base-class downcast and no string lookup in the inner numerical path. \end{samepage} \section{What compiles today, and why} \subsection{The three useful questions} For a new model, ask these separately: \begin{enumerate} \item \textbf{Is each object a valid specification?} The type has a valid role definition, parameters, and contribution metadata. \item \textbf{Can the objects form a stellar-model type?} Their stable keys are unique, exactly one constitutive law is present, and generated scalar arities make a square symbolic system. \item \textbf{Can the current numerical backend discretize that exact type?} Every core equation, surface conversion, residual assembly, Jacobian coupling, normalization action, and runtime provider exists. \end{enumerate} For this example, the answers are yes, yes, and no. \subsection{Why the current core rejects this EOS} The current stellar material core is barotropic. Its state can close density through a relation of the form \begin{equation} \rho = \rho(h), \end{equation} with the corresponding derivative $\dd\rho/\dd h$. This is sufficient for a polytropic barotrope. The example instead supplies \begin{equation} P=P(\rho,T), \qquad u=u(\rho,T), \qquad h=h(\rho,T). \end{equation} Hydrostatic balance plus an isobaric surface does not determine both $\rho$ and $T$ throughout the star. A second physical equation is required. Depending on the intended model, it might be an entropy prescription, radiative energy transport, convective closure, or a full energy equation with sources and sinks. The example therefore includes \begin{lstlisting}[style=meanfieldcpp] static_assert(model::StellarModelType); static_assert(!equilibrium::StellarEquilibriumModel); \end{lstlisting} The second assertion is a capability tripwire. When a thermal equilibrium core is eventually implemented, the assertion and this manual must be revised together. \subsection{What must be added for a coupled thermal solve} A physically complete extension will need all of the following, designed as a single compile-time path rather than a special case for this EOS: \begin{enumerate} \item A selected thermal state coordinate, such as temperature or specific entropy, with a finite-element field family. \item A thermal residual equation whose physical closure is explicit. \item EOS relations and partial derivatives required by both hydrostatic and thermal residuals. \item Surface data appropriate to the thermal equation, such as a fixed temperature, luminosity, or atmosphere matching condition. \item Generated block and Jacobian couplings inferred from the selected thermodynamic equation set. \item Normalization metadata for the new field and residual, including a physically meaningful Riesz map and scale. \item A preconditioner component that approximates the new thermal block and its important coupling to structure. \item Runtime providers for assembly and linearization of every inferred contribution. \end{enumerate} The EOS in this module is already expressed in the multi-input relation vocabulary needed by such a future core. It should not be rewritten as a bespoke EOS-backend combination. \section{Testing a physics extension} A robust extension test suite has four layers. Passing only the first layer is not enough. \subsection{Compile-time protocol tests} These answer structural questions: \begin{itemize} \item Is the class a self-describing constitutive-law specification? \item Does every catalog relation have an exact evaluator? \item Are required partial derivatives available? \item Are input order and output quantity types enforced? \item Does composition preserve the exact EOS, surface, and invariant types? \item Is the inferred scalar root system square? \end{itemize} The reversed pressure call $(T,\rho)$ is tested as a non-callable expression. This is a useful negative contract: it proves that strong quantity types catch an error that two raw \code{double} arguments would not catch. \subsection{Exact worked state} The tests choose artificial constants that make hand calculation easy: \begin{equation} \mu=2, \quad k_{\mathrm B}=12, \quad m_{\mathrm u}=3, \quad a=9, \end{equation} so $\mathcal{R}=2$. At $\rho=4$ and $T=2$, \begin{align} P_{\mathrm{gas}} &= 16, & P_{\mathrm{rad}} &= 48, & P &= 64,\\ u_{\mathrm{gas}} &= 6, & u_{\mathrm{rad}} &= 36, & u &= 42,\\ h &= u + P/\rho = 42 + 16 = 58. \end{align} This single state catches wrong factors of $1/3$, $3/2$, $4/3$, and $5/2$. It also tests the independent thermodynamic identity $h=u+P/\rho$. \subsection{Scaling and limiting behavior} The tests verify transformations more diagnostic than a list of isolated numbers: \begin{itemize} \item doubling $\rho$ doubles $P_{\mathrm{gas}}$; \item changing $\rho$ leaves $P_{\mathrm{rad}}$ unchanged; \item doubling $T$ doubles $P_{\mathrm{gas}}$; \item doubling $T$ multiplies $P_{\mathrm{rad}}$ by 16; and \item at $T_{\mathrm{cross}}=(3\rho\mathcal{R}/a)^{1/3}$, gas and radiation pressures agree. \end{itemize} These claims exercise the physical exponents and parameter dependencies. They would fail even if a few reference values happened to be fitted correctly. \subsection{Analytic versus numerical derivatives} Every one of the six analytic partial derivatives is compared with a centered difference at three materially different states. For a scalar function $f$, \begin{equation} f'(x) \approx \frac{f(x+\epsilon)-f(x-\epsilon)}{2\epsilon}. \end{equation} The test uses \begin{equation} \epsilon = \epsilon_{\mathrm{machine}}^{1/3} \max(1,|x|). \end{equation} For a centered difference, this scale balances truncation and roundoff for smooth double-precision functions. The comparison tolerance is selected from the observed error order and is much tighter than a solver tolerance. It tests the local Jacobian implementation, not convergence of a nonlinear solve. When extending a tabulated or iterative EOS, use tolerances justified by that algorithm's interpolation and inner-solve error. Do not copy the analytic-EOS tolerance mechanically. \subsection{Domain tests} Tests require rejection of invalid constants, nonfinite values, zero density, and negative temperature. Domain tests should check error categories where a caller can recover differently from a nonfinite input and an out-of-domain state. \section{Adding other kinds of physics} The same pattern extends beyond an EOS: declare a physics-facing wrapper, state dependencies and effects once, and let the compiler generate structure. The details below are a map, not a replacement for tests of the actual equations. \subsection{Surface conditions} A surface condition uses \begin{lstlisting}[style=meanfieldcpp] using ModelDefinition = mean_field::surface::BoundaryCondition< MySurfaceCondition, "MySurfaceCondition">; \end{lstlisting} It should name its physical target quantity and typed target value. A new surface condition can enter a \code{StellarModel} as a distinct type before a runtime surface compiler exists. Full discretization is available only if the chosen EOS can convert the boundary statement into the thermodynamic variable used by the selected material formulation. For example, an isothermal surface is physically meaningful for a thermal model. It does not become meaningful for a barotropic formulation merely because both types compile as specifications. \subsection{Integral invariants} An invariant such as fixed mass or fixed angular momentum owns a global scalar equation and usually a conjugate scalar coordinate. Physics-facing aliases include \code{FixedScalarWithMultiplier} and \code{FixedScalarWithPhysicalCoordinate}. Their declarations identify: \begin{itemize} \item the target physical quantity; \item the generated coordinate quantity; \item the constraint residual quantity; \item which state quantities the integral reads; \item which equations the generated coordinate changes; \item stable symbols and identifiers; and \item normalization metadata. \end{itemize} That information is enough to generate the border shape and required Jacobian incidence. A runtime provider must still implement the integral, its derivative, and its action on affected equations. If that provider is absent, compilation must stop at the operation boundary rather than ignore the invariant. \subsection{Phase conditions} A phase condition removes a neutral direction or selects one representative of a family. It is not necessarily a conserved physical quantity. Fixed central density, for example, can serve as a phase constraint while fixed total mass is the physically informed invariant. Use \code{ScalarPhaseCondition} for the physics-facing declaration. Keep the distinction explicit in naming, documentation, and tests: an invariant changes the physical problem, while a phase condition selects a solution within a degenerate representation. \section{Normalization and preconditioning} Normalization and preconditioning solve different problems. The normalization operator gives each field and residual a physically meaningful inner product and scale. Conceptually, it maps the raw root system to coordinates where comparisons such as residual norms and line-search acceptance are not dominated merely by units. A pressure-like row near $10^{16}$ and a dimensionless row near unity should not be compared as raw numbers. The preconditioner approximates the inverse action of the scaled Jacobian. It is concerned with coupling and spectral difficulty, not just magnitude. A good normalization can improve the numerical setting in which the preconditioner operates, but it cannot replace an approximation to elliptic, material, surface, or global-border couplings. For a new generated scalar, the specification must provide normalization metadata that is dimensionally coherent with its target, coordinate, and residual quantities. For a new distributed thermal field, the discretization must select a compatible topology and physical scale. If no scale law exists, the correct outcome is a compile-time rejection of normalized discretization, not an identity scale inserted without documentation. Physics tests for a new normalization should include: \begin{itemize} \item invariance under the intended change of physical units; \item expected mesh-refinement behavior of the discrete norm; \item exact results for constant or low-order fields when available; \item consistent scaling of a residual and its Jacobian action; and \item quantified interaction with the chosen preconditioner. \end{itemize} \section{A practical development workflow} \begin{enumerate} \item \textbf{Write the equations first.} List state variables, parameters, outputs, domains, held-fixed variables, and expected limits. \item \textbf{Reuse or define quantity types.} Avoid raw scalars at public physics boundaries. \item \textbf{Declare the smallest honest relation catalog.} Do not promise an inverse relation that is multivalued or requires an undocumented closure. \item \textbf{Implement evaluations and analytic derivatives together.} Keeping them adjacent makes sign and factor audits easier. \item \textbf{Add compile-time assertions.} Check the EOS concept, each required derivative, the exact composed model type, and negative capability cases. \item \textbf{Add hand-calculated physics tests.} Use states that expose every coefficient and term. \item \textbf{Add property tests.} Check scaling laws, limits, monotonicity, conservation identities, symmetry, or convexity as appropriate. \item \textbf{Compare derivatives numerically.} Cover the relevant state domain, not just one comfortable point. \item \textbf{Compose with several existing specifications.} Confirm that the model infers roles and preserves exact types without a bespoke combination. \item \textbf{Ask the runtime capability question explicitly.} If false, document which physical equation or provider is absent. \item \textbf{Build only the extension target while iterating.} Run the wider regression suite only when shared library code changes. \end{enumerate} \section{Build and run} From the repository root, use the configured build directory and request only the extension targets: \begin{lstlisting}[style=meanfieldshell] cmake --build cmake-build-profile-homebrew-llvm \ --target extension_example_demo extension_example_tests \end{lstlisting} Run only the extension tests: \begin{lstlisting}[style=meanfieldshell] ./cmake-build-profile-homebrew-llvm/extension_example/extension_example_tests \end{lstlisting} Run the demonstration: \begin{lstlisting}[style=meanfieldshell] ./cmake-build-profile-homebrew-llvm/extension_example/extension_example_demo \end{lstlisting} Compile this manual into the build directory: \begin{lstlisting}[style=meanfieldshell] cmake --build cmake-build-profile-homebrew-llvm \ --target extension_example_manual \end{lstlisting} The extension tests use a separate Catch2 executable. Running it does not run the main \MeanField{} test suite. \section{Gotchas} \begin{enumerate} \item \textbf{A typed scalar is not a unit library.} A \code{TemperatureValue} says ``temperature,'' not ``kelvin.'' Keep the whole parameter set in one coherent unit system. \item \textbf{Relation input order is part of the type.} $P(\rho,T)$ and $P(T,\rho)$ are different relation types even if a human could reorder the arguments. \item \textbf{The catalog is authoritative.} An overload omitted from \code{Relations} is invisible to generic dispatch. A catalog entry without an exact overload invalidates the EOS concept. \item \textbf{State what is held fixed.} A total derivative along an isentrope is not the same as a partial derivative at fixed temperature. \item \textbf{Do not invent an inverse closure.} A two-variable EOS does not generally supply $\rho(h)$ without another thermodynamic condition. \item \textbf{Specification success is not runtime success.} A valid \code{StellarModel} type can be rejected by \code{discretize} when a required numerical provider is absent. \item \textbf{A surface statement must match the formulation.} Fixed pressure alone does not set both density and temperature at a thermal surface. \item \textbf{Stable names are identities.} Keep them unique within a role and stable across harmless refactors. \item \textbf{An invariant is not a phase condition.} Fixed total mass is physically informative; fixed central density may be used to select a phase. Their generated coordinates have different meanings. \item \textbf{Analytic formulas still need numerical audits.} Templates can prove that $\partial P/\partial T$ exists, not that a factor of four is correct. \item \textbf{Avoid EOS-specific solver branches.} Extend generic relation, equation, normalization, and provider mechanisms so future EOS types follow the same path. \item \textbf{Validate before powers or division.} Nonfinite inputs and invalid density should fail with an EOS-domain error rather than propagate a NaN through a global residual. \end{enumerate} \section{Review checklists} \subsection{EOS author checklist} \begin{itemize} \item[$\square$] Assumptions and validity domain are written down. \item[$\square$] Parameters have physical names and coherent units. \item[$\square$] Public inputs and outputs use quantity types. \item[$\square$] The relation catalog is minimal and complete. \item[$\square$] Every catalog relation has an exact evaluator. \item[$\square$] Every required Jacobian partial has the correct held-fixed variable and return type. \item[$\square$] Nonfinite and out-of-domain states are rejected. \item[$\square$] Hand-worked values test all coefficients. \item[$\square$] Physical scaling laws and limiting regimes are tested. \item[$\square$] Analytic derivatives agree with numerical derivatives. \end{itemize} \subsection{Coupled-model checklist} \begin{itemize} \item[$\square$] Exactly one constitutive law is present. \item[$\square$] Surface and EOS relations are thermodynamically compatible. \item[$\square$] Every supplied invariant and phase condition appears in the inferred model type. \item[$\square$] Generated unknown and residual arities are square. \item[$\square$] All Jacobian incidences required by declared dependencies and effects are present. \item[$\square$] Every new coordinate and residual has normalization metadata and a runtime action. \item[$\square$] The preconditioner includes the important new couplings. \item[$\square$] Runtime capability is asserted before discretization. \item[$\square$] Failure of an unsupported combination occurs at compile time with a useful boundary and message. \end{itemize} \clearpage \section{Glossary} \begin{longtable}{p{0.24\textwidth} p{0.69\textwidth}} \toprule \textbf{Term} & \textbf{Meaning in this code base} \\ \midrule \endhead Barotropic EOS & An EOS whose thermodynamic closure can be expressed with one independent material coordinate for the current problem, such as $\rho=\rho(h)$. \\ \addlinespace Boundary condition & A physical statement applied at a domain boundary, such as fixed surface pressure. It is a model specification role. \\ \addlinespace Canonical specification set & The order-independent compile-time collection of the exact specification types supplied to \code{StellarModel}. \\ \addlinespace Compile-time contract & A property checked by C++ type formation or a concept, before a numerical run begins. \\ \addlinespace Constitutive law & A specification that relates material state quantities. An EOS is the principal example. \\ \addlinespace Discretization & The mesh, finite-element spaces, ordering, normalization prescription, and runtime data needed to turn a compiled physical system into a finite-dimensional root problem. \\ \addlinespace Equation of state (EOS) & A set of thermodynamic relations with a declared validity domain and parameters. \\ \addlinespace Generated coordinate & A scalar unknown introduced by a specification, such as the mass-constraint multiplier or angular velocity associated with fixed angular momentum. \\ \addlinespace Invariant & A physically prescribed global quantity enforced by a residual, such as total mass or total angular momentum. \\ \addlinespace Jacobian & The derivative of the full residual vector with respect to the full state vector. Its block structure is inferred from compiled equations and specification contributions. \\ \addlinespace Model specification & One exact physical choice carrying a role, stable key, parameters, and structural contribution metadata. \\ \addlinespace Normalization & A physically informed mapping that supplies comparable coordinates and residual norms across fields with different units, topologies, and magnitudes. \\ \addlinespace Partial derivative & A derivative with respect to one declared relation input while its other inputs are held fixed. \\ \addlinespace Phase condition & A condition that removes a neutral direction or chooses one representative from a family of equivalent solutions. It is distinct from a physical invariant. \\ \addlinespace Physical Riesz map & The discrete map induced by a selected physical inner product and scale. It connects a field or residual with its dual coordinate in a topology-aware way. \\ \addlinespace Preconditioner & An efficient approximation to the inverse scaled Jacobian, used to make the linearized solve tractable. \\ \addlinespace Quantity type & A zero-storage type that names physical meaning, such as \code{Temperature}. A \code{QuantityValue} stores the scalar. \\ \addlinespace Relation catalog & The complete compile-time list of input-output relations an EOS claims to implement. \\ \addlinespace Residual & One equation written as a quantity that should be zero at a solution. The full nonlinear problem is a vector of residual blocks. \\ \addlinespace Runtime provider & Numerical code that evaluates or assembles an inferred physics contribution for a particular formulation. \\ \addlinespace Solver border & The small set of generated global scalar rows and columns coupled to the distributed physical core. \\ \addlinespace Specification role & The category of a physical choice: constitutive law, boundary condition, invariant, phase condition, gauge choice, or rotation law. \\ \addlinespace Stable name & A compile-time string used with a role to identify one specification mechanism consistently across inferred structures and runtime descriptions. \\ \addlinespace Stellar model & The strongly typed, canonical composition of the exact physical specification objects selected by a user. \\ \addlinespace Symbolically square & The compiled state and residual descriptions have equal total scalar arity before mesh-dependent sizes are known. \\ \addlinespace Thermal closure & The additional equation or prescription needed to determine an independent thermal variable such as temperature or entropy. \\ \addlinespace Typed value & A scalar wrapper whose C++ type carries its physical meaning and prevents accidental interchange of unrelated quantities. \\ \bottomrule \end{longtable} \section{Final perspective} The extension mechanism is successful when a physics developer can read the new source primarily as equations, parameters, domains, and derivatives. The compiler should then answer structural questions: whether the relations are complete, whether the selected model is square, which exact constraints are present, and whether the current numerical backend implements every inferred piece. The ideal-gas plus radiation example intentionally reaches that boundary. It demonstrates a valid nonbarotropic EOS and a valid rotating stellar-model specification without claiming a nonexistent thermal equilibrium solve. That is the behavior future extensions should preserve: composable when supported, precisely rejected when incomplete, and always honest about the physics. \end{document}