========================= Wind hydrodynamics ========================= *Module:* ``src/hydrodynamics/`` — :cpp:class:`agb::Hydrodynamics`, with the optional global-Newton :cpp:class:`agb::StructureSolver` (``structure_solver.cpp``, ``henyey_solver.cpp``). The hydrodynamics solves the **stationary, spherically symmetric momentum equation** for the wind velocity, the density, the location of the sonic point, and the mass-loss rate, given the flux-mean extinction from the radiative transfer. The radiative acceleration ========================== The radiation force is parametrised by the ratio of radiative to gravitational acceleration (:cpp:func:`agb::Hydrodynamics::calcAlpha`): .. math:: :label: alpha-hydro \alpha(r) = \frac{\chi_F(r)}{\rho(r)}\, \frac{L_\star}{4\pi c\,G M_\star} , with :math:`\chi_F` the **flux-mean extinction** coefficient supplied by the RT module. When :math:`\alpha>1` the radiation overcomes gravity and a wind is driven. In the cool dust-forming region :math:`\chi_F` is dominated by the grain opacity, so :math:`\alpha` rises sharply across the dust front — this is the engine of the outflow. The Melia :math:`\Phi` transform ================================ The isothermal-sound-speed momentum equation has a **critical (sonic) point** where the wind speed equals the isothermal sound speed :math:`v=c_T`, at which the naïve equation is singular. Following **Melia (1988)**, the code works with the variable .. math:: :label: phi-def \Phi(r) = \tfrac12\!\left(v + \frac{c_T^2}{v}\right) , which is **regular** through the sonic point (its minimum is exactly :math:`\Phi=c_T` at :math:`v=c_T`). The velocity is recovered from :math:`\Phi` by inverting :eq:`phi-def`, .. math:: v = \Phi \mp \sqrt{\Phi^2 - c_T^2} , taking the subsonic (``−``, :math:`v`` (so the same code gives the value and the exact Jacobian). * The radiative acceleration :math:`\alpha` is computed **inside** the residual from the frozen flux-mean extinction, so :math:`\dot{M}` is a true eigenvalue (``s = ln Mdot`` plus the regularity row). * **Per-block residual/variable scaling** is essential: the unknowns span ~20 orders of magnitude (:math:`\Phi\sim10^5` vs. :math:`K_j\sim10^{-13}`), so each block is scaled to :math:`O(1)` before the dense Eigen solve. Without scaling the Newton fails. * A **grey bootstrap** provides the seed; the relaxation-Picard intermediate structure is *not* a valid seed (its transient :math:`\chi_F` is garbage). * Outer **log-space :math:`\chi_F` (α) damping** between solves stabilises the critical-point location. .. important:: The Henyey solver is **not required** for a converged model and is **off by default**. Extensive experiments showed that the exact global Newton with a freely relocating critical point is ill-conditioned for the *marginal* dust-driven wind (:math:`\alpha\approx1` at the sonic point): coupling the dust opacity back into :math:`\alpha` inside the Newton (the "Stage 2" feedback) drives :math:`\alpha` super-Eddington on any moment excursion, losing the critical point. The looser shooting solver with adaptive velocity relaxation "muddles through" and is more robust here. Winters and Dominik reach the same conclusion in prescribing :math:`\dot{M}` and freezing :math:`\alpha` in the Newton, damping it only in the outer loop. Prescribed vs. eigenvalue mass-loss rate ======================================== Two setups are possible: * **Eigenvalue** :math:`\dot{M}` (default) — :math:`\dot{M}` follows from the critical-point regularity :eq:`mdot-eigen`; :math:`R_\star`/:math:`T_\star` float. With carbon depletion this is stable and self-consistent for IRC+10216. * **Prescribed** :math:`\dot{M}` (``[star] mass_loss_rate``) — Winters/Dominik fix :math:`\dot{M}` as a parameter. A consistent prescribed value yields a regular transonic solution; an inconsistent one (e.g. far from the self-consistent eigenvalue) has no transonic solution and the solve is rejected.