zephyrus.thermostat
thermostat
thermostat.py
Wind-temperature thermostat: local heating against radiative cooling.
Author: Mara Attia
three_level_populations(species, n_tot, n_e, T)
Steady-state level populations (n1, n2, n3) of a three-level system.
Electron-impact excitation and deexcitation plus radiative decay, with
no radiative excitation (every emitted photon escapes: cool-to-space).
Rate coefficients follow the effective-collision-strength form
k_lu = gamma (8.629e-6 / (g_l sqrt(T))) exp(-E_lu / kB T) with
deexcitation by detailed balance (Nakayama et al. 2022, Eqs. 13-14).
Densities in cm^-3.
Source code in src/zephyrus/thermostat.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | |
three_level_cooling(species, n_tot, n_e, T)
Line cooling of one species, erg s^-1 cm^-3, cool-to-space.
Source code in src/zephyrus/thermostat.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
ionization_fraction(n_cgs, T, F_cgs, hnu_erg, sigma_cm2, alpha_cm3s)
Local photoionization-recombination balance ionization fraction.
Solves f^2 / (1 - f) = R with R = sigma F / (h nu alpha n), the
quadratic root in [0, 1], written as f = 2 / (1 + sqrt(1 + 4/R)):
the textbook form (-R + sqrt(R^2 + 4R)) / 2 cancels catastrophically
at large R and can return fractions above 1. Zero flux or zero density
gives zero.
Source code in src/zephyrus/thermostat.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
front_constants(element_fractions)
Monochromatic-front constants (h nu [erg], E_ion [erg], sigma [cm^2]).
Hydrogen front for winds with an atomized hydrogen fraction of one half or more, the nitrogen-like front otherwise. Treating the base gas as atomized in front of the ionizing continuum is an approximation the front constants inherit.
Source code in src/zephyrus/thermostat.py
134 135 136 137 138 139 140 141 142 143 144 | |
recombination_alpha(element_fractions, T)
Composition recombination coefficient, cm^3 s^-1.
Nitrogen-dominated winds use the Badnell fit for N; other compositions take the mole-fraction-weighted case B coefficients.
Source code in src/zephyrus/thermostat.py
147 148 149 150 151 152 153 154 155 | |
balance_at(T, base, element_fractions, F_xuv, cool_atomic=True, cool_co2_band=True, cool_o_finestructure=True, cool_recombination=True, col_co2=0.0)
Heating minus cooling [erg s^-1 cm^-3] at temperature T.
Evaluated on the wind-base level base (a level dict with n
[m^-3] and vmr; densities converted to cgs internally), for the
atomized composition element_fractions under the XUV flux F_xuv
[W m^-2] that heats the level (the dispatcher passes the surface
average F_xuv / 4 for the wind). col_co2 is the CO2 column above the level [cm^-2], which
sets the escape probability of the 15 micron band (zero evaluates the
band at its zero-column ceiling). Returns (residual, detail) with the
detail carrying the ionization fraction, both totals, and the per-channel
parts.
Source code in src/zephyrus/thermostat.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
solve_wind_temperature(T_eq, base, element_fractions, F_xuv, cool_atomic=True, cool_co2_band=True, cool_o_finestructure=True, cool_recombination=True, n_scan=120, col_co2=0.0)
Thermostat root-find on the bracket [T_eq, 5e4 K].
Scans the balance upward in temperature and bisects the first downward
crossing of heating through cooling, which selects the lowest stable
root when several exist. When no root lies inside the bracket the
temperature clamps to the nearer edge with the clamped field set
('low' when cooling already wins at T_eq, 'high' when heating still
wins at the upper edge). A high clamp is expected at dense wind bases,
where electron densities above the forbidden-line critical densities
quench the three-level coolants collisionally and the wind runs hot.
A clamped temperature is the edge of the bracket and not a solution:
the balance usually has a root near 1e5 K, outside the model since its
coolants are neutral and the gas there is fully ionized, and every
quantity built on the clamped value (the sound speed, the sonic radius,
the recombination-limited rate, the sonic-point Knudsen number)
inherits that. F_xuv and col_co2 are passed to balance_at,
so the flux is the one heating the wind (the dispatcher passes the
surface average F_xuv / 4), and overlying_co2_column gives the
hydrostatic column. Returns (T_wind, detail).
Raises:
| Type | Description |
|---|---|
ValueError
|
If every cooling channel is disabled: a pure-heating balance has no root by construction and would silently clamp high. |
Source code in src/zephyrus/thermostat.py
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | |
overlying_co2_column(level, M_p)
CO2 column above a level [cm^-2], in hydrostatic balance.
x_CO2 p / (mu g) with g = G M_p / r^2 at the level, for a level
dict with p [Pa], r [m], mmw [kg], and vmr: the column
Johnstone et al. (2018) Eq. (38) reads the escape probability from,
with the mixing ratio held at its value at the level.
Source code in src/zephyrus/thermostat.py
307 308 309 310 311 312 313 314 315 316 317 | |