Skip to content

Dev#23

Merged
MBradley1985 merged 80 commits into
mainfrom
dev
Jul 6, 2026
Merged

Dev#23
MBradley1985 merged 80 commits into
mainfrom
dev

Conversation

@MBradley1985

Copy link
Copy Markdown
Owner

No description provided.

… knob

  Satellite stripping (strip_from_satellite) removed 1/N of the recomputed
  baryon excess per substep, so the fraction stripped over a snapshot is
  1-(1-1/N)^N -- set by the substep count N rather than elapsed time or any
  physical timescale. Under adaptive/dynamical-time stepping N varies, so this
  becomes a redshift-dependent artifact in principle.

  Add an opt-in physical alternative behind PhysicalStrippingOn (default 0):
    0 = legacy geometric (excess/effective_steps), reproduced bit-for-bit so
        the calibrated baseline is unchanged
    1 = physical timescale: strip excess*(dt/t_strip) per substep, telescoping
        to 1-exp(-dT/t_dyn) over a snapshot -- N-invariant in the limit and
        tied to the host dynamical time (Rvir/Vvir), passed in from the
        substep loop. Per-substep fraction capped at 1 for the dt>=t_strip
        (high-z) limit.

  Add SubstepResolution (double, default 1.0): a runtime multiplier on the
  adaptive substep count (scales both the STEPS floor and MAX_STEPS cap)
  without resizing the compile-time SFR arrays, enabling convergence /
  N-invariance sweeps from the parameter file instead of recompiling.

  Add plotting/compare_stripping.py: overlays N runs on the four
  stripping-sensitive diagnostics (satellite quenched fraction, gas fraction,
  HI mass function by type, baryon fraction vs Mvir) for A/B testing.

  Tests: existing 16 stripping calls keep asserting legacy behaviour on the
  default path; add 3 physical-path tests (exponential law, N-invariance,
  high-z cap). All 18 suites pass.

  Verified in production runs: at matched N legacy and physical are
  indistinguishable (<0.2% in every satellite statistic); the only residual
  is a small global resolution effect shared by both schemes.
…n knob

  Legacy satellite stripping removed 1/N of the recomputed baryon excess per
  substep, so the fraction stripped over a snapshot is 1-(1-1/N)^N -- set by the
  substep count N rather than elapsed time. Under dynamical-time stepping N
  varies, making this an in-principle redshift/cadence artifact.

  Add two opt-in physical alternatives behind PhysicalStrippingOn (default 0):
    0 = legacy geometric (excess/effective_steps), reproduced bit-for-bit so
        the calibrated baseline is unchanged.
    1 = physical timescale, per substep: strip excess*(dt/t_dyn) each substep,
        telescoping to 1-exp(-dT/t_dyn); N-invariant in the limit (~1% residual).
    2 = physical timescale, analytic: strip exactly 1-exp(-dT/t_dyn) once per
        snapshot, OUTSIDE the substep loop -- zero substep-count dependence and
        cadence-invariant (the Option-1 "evaluate once" + Option-2 "exponential"
        hybrid). t_dyn is the central's Rvir/Vvir.

  Add SubstepResolution (double, default 1.0): runtime multiplier on the adaptive
  substep count (scales STEPS floor and MAX_STEPS cap) for convergence /
  N-invariance sweeps without recompiling or resizing the SFR arrays.

  Add plotting/compare_stripping.py to overlay N runs on the stripping-sensitive
  diagnostics (satellite quenched fraction, gas fraction, HI mass function by
  type, baryon fraction vs Mvir).

  Tests: 16 existing stripping calls keep asserting legacy behaviour on the
  default path; add 5 physical-path tests (exponential law, N-invariance, high-z
  cap, analytic exactness, substep-count independence). All 18 suites pass.

  Verified in Millennium runs: modes 0/1/2 agree to <0.2% in every satellite
  statistic at production resolution (stripping saturates); the analytic mode is
  the substep-independent, cadence-invariant formulation to prefer going forward.
… with dynamical time to strip outside of the substep loop. Removing stripping being dependant on time-steps.
…d really just be kept as 1.0, just the dynamical time.
# Conflicts:
#	.gitignore
#	src/core_build_model.c
Baselines now reflect the merged physics (physical stripping schemes +
HII ionization). 5444 datasets per config, determinism re-verified
(two consecutive runs bit-identical).
- Remove committed Sphinx build output (docs/_build) and Doxygen XML
  (_doxygen/) from version control; they are build artifacts.
- Ignore docs/_build/ and _doxygen/ going forward.
- Drop editor/tool-local ignore entries that are better kept in
  .git/info/exclude.
- Fix root 'make tests' target (was pointing at a nonexistent launcher
  script); add 'make regression' for the byte-for-byte baseline sweep.
- Write the missing docs/developer/REGRESSION_BASELINE.md referenced by
  the regression scripts; document the two verification systems and the
  bit-identical policy.
- Move root-level developer notes into docs/developer/.
- Reconcile dataset-count claims (5380 -> 5444) in README, docs, and
  CONTRIBUTING.
- Point run_sage_batch.sh at the shipped .par files.
- Ignore generated docs (docs/_build/, _doxygen/).
The committed reference.sha256 predated the physical-stripping rework
and the HII-ionization merge; physics on this branch legitimately
differs. Regenerated with mpirun -n 1; verify now passes.
The PROCESS_LHVT_STYLE conditional was never defined, guarded by an
#error, and called functions that do not exist anywhere in the tree.
Remove the dead blocks in sage.c, the orig_index field they used, and
core_tree_utils.c/.h whose three public functions were only referenced
from those blocks.

Verified: all 5444 baseline datasets bit-identical.
USE_SAGE_IN_MCMC_MODE was not defined by any build configuration and
diverged from the fiducial output (2 of 82 HDF5 fields, altered merger
bookkeeping). Keep only the standard paths.

Verified: all 5444 baseline datasets bit-identical.
- Delete #if 0 blocks (disabled short-Type struct variants, ctrees
  column self-test, stale #undef).
- Delete commented-out debug fprintf lines across the tree readers,
  HDF5 writer, and allocator.
- Replace an embedded code-generation prompt transcript in
  buffered_io.c with the module's standing header description.
- Gate the per-task forest-assignment [LOG] stderr prints behind
  VERBOSE like every other info message.

Verified: all 5444 baseline datasets bit-identical.
- GALAXY::CentralMvir was never read or written; the output writers
  compute their own CentralMvir from the FOF host halo.
- GALAXY::TotalSatelliteBaryons was accumulated every snapshot but
  never read by physics or either output format; drop the field, the
  accumulation loop, and its self-contained unit test.
- params::CGMrecipeSAGEOn was declared but never parsed or referenced.

Verified: all 5444 baseline datasets bit-identical; all 18 unit test
suites pass.
- Make file-local functions static (do_AGN_heating_cgm, the two BR06
  disk-structure helpers) and drop their public declarations.
- Replace magic 60.0/30.0 literals in starformation_ffb with the
  existing FIRE_V_CRIT_KMS / KD11_METAL_HALO_MASS constants (same
  double values, bit-identical).
- Use MAX_STRING_LEN-1 instead of a stale literal 511 in the parameter
  parser bounds.
- Drop the inert -DGNU_SOURCE flag (nothing tests GNU_SOURCE; glibc
  keys on _GNU_SOURCE and gnu99 already enables GNU extensions).
- Fix inaccurate comments: NDEBUG claims in macros.h, evolve_galaxies
  docstring, ConcentrationOn mode list, stale GD14 cross-references.
- Normalize the remaining tab-indented lines in the physics files.

Verified: all 5444 baseline datasets bit-identical; all 18 unit test
suites pass.
starformation_ffb computed the identical (1+z)^alpha * (V/Vcrit)^beta
scaling twice (reheating and ejection). Hoist it into a single
precomputed value, mirroring the main star-formation path. Same
expression, operands, and evaluation order.

Verified: all 5444 baseline datasets bit-identical.
generate_galaxy_indices repeated the same multi-line hint five times,
differing only in reader filename and long-stale hardcoded line
numbers. Replace with one generic message (plus the consistent-trees
ascii variant). Error-path stderr text only.

Verified: all 5444 baseline datasets bit-identical.
The 'CGM when CGMrecipeOn and Regime==0, else HotGas' if/else ladder
was repeated at eight deposit sites across star formation, mergers,
and reincorporation. Replace with two static inline helpers
(add_metals_to_hot_reservoir / add_gas_to_hot_reservoir) in
model_misc.h. The += operations are unchanged.

Verified: all 5444 baseline datasets bit-identical; all 18 unit test
suites pass.
The 'tracks molecular gas' test appeared as a six-term OR chain in
some places and as (sf != 0 && sf != 2) in others; the BR06 family
test appeared as (== 1 || == 3). Replace all with
sf_prescription_tracks_h2() / sf_prescription_is_br06() inline
predicates. SFprescription is now validated to [0, 7] at parameter
read (previously an out-of-range value silently formed zero stars),
which makes the two historical forms provably equivalent.

Verified: all 5444 baseline datasets bit-identical; all 18 unit test
suites pass.
- New GitHub Actions workflow: serial build + unit tests, MPI compile
  check, and a non-blocking mini-Millennium smoke run (trees cached;
  external download must not gate merges). Dependencies come from a
  single conda prefix via micromamba because the Makefile's CI path
  derives HDF5_DIR from gsl-config --prefix.
- Fix the two gcc -Wformat-truncation/-Wstringop-truncation warnings
  that would trip -Werror on CI (memcpy of the fixed-size tag buffer;
  precision-capped %s). Warning-clean under both clang and gcc-16.

Verified: all 5444 baseline datasets bit-identical.
Profiling (macOS sample) shows the run dominated by libm
transcendentals, with calculate_molecular_fraction_radial_integration
the hottest SAGE function (25 bins per galaxy per substep):

- BR06 (default): the stellar scale height (pow/log10) depends only on
  the disk scale length; compute once per galaxy instead of per bin
  via a _from_hstar variant. The per-bin arithmetic is unchanged.
- KMT09/K13: the metallicity, chi, and the log numerator depend only
  on disk metallicity; hoisted before the loop (identical values).
- KD12: reuse the hoisted disk metallicity.

Also update tests/README.md counts to the actual 559 tests across 18
suites and refresh the per-suite table.

Verified: all 5444 baseline datasets bit-identical; all 18 unit test
suites pass. Median runtime 11.53s -> 11.10s (~4%) on mini-Millennium.
The sage_binary writer writes GALAXY_OUTPUT structs to disk verbatim.
The struct has 8 bytes of alignment padding per record (before g_max
and after r_heat) which was never initialised, so uninitialised heap
bytes leaked into the output files. Every field value was unaffected,
but the files were non-reproducible at the byte level: the benchmark
checksum test failed intermittently (~1 in 4 runs), on this branch and
on the pre-cleanup base commit alike.

memset the output block before filling it and regenerate the benchmark
reference (only padding bytes changed; verified 0 science-byte diffs
against the previous output and 10/10 clean verify runs). HDF5 output
is written per-field and was never affected.

Verified: all 5444 HDF5 baseline datasets bit-identical; all 18 unit
test suites pass.
Add the three satellite-stripping parameters (PhysicalStrippingOn,
SubstepResolution, StrippingTimescaleFactor) at their compiled
defaults so the reference config lists every registered parameter,
and normalise LastSnapshotNr spelling to match the code (parsing is
case-insensitive, so no behaviour change either way).

Verified: all 5444 baseline datasets bit-identical.
A syntactically valid but fake ORCID is worse than none; the CFF
schema does not require it. Re-add when a real iD is available.
MBradley1985 and others added 29 commits July 4, 2026 15:35
The smoke lanes never passed: the mini-Millennium tarball holds trees/...
relative paths and was being unpacked at the workspace root instead of
inside input/millennium (where first_run.sh unpacks it), so sage found no
tree files. The MPI build check failed because conda-forge packages the
MPI compiler wrappers separately -- installing openmpi alone provides no
mpicc; add openmpi-mpicc and the compilers toolchain.

Also add workflow_dispatch so the workflow can be exercised from a branch,
bump the tree cache key past any treeless cache entries, and verify the
unpack produced trees_063.0 before caching.
The tarball holds flat files (trees_063.*, millennium.a_list) with no
directory prefix -- first_run.sh untars it from inside
input/millennium/trees/, not one level up. The unpack-verification guard
added in the previous commit caught this.
Caught by AddressSanitizer on the (short-lived) sanitized CI lane:
the SaveFullSFH Description/Units attributes passed string literals to
CREATE_STRING_ATTRIBUTE with a declared size of MAX_STRING_LEN, so
H5Awrite read ~1 KiB from a ~100-byte literal -- an out-of-bounds read
whose trailing bytes (whatever rodata followed the literal) were written
into the output file. The per-field Description/Units buffers were
correctly sized but uninitialized past the snprintf'd text, leaking
stack bytes into the file the same way the struct-padding bug did for
binary output.

Literals are now staged through a zeroed MAX_STRING_LEN buffer and the
field-metadata arrays are zeroed before filling. Attribute datatypes and
file layout are unchanged; every byte written is now defined. All 5444
datasets verified bit-identical.
The mini-Millennium smoke run and its sanitized variant depended on
downloading simulation trees from an external mirror inside CI, which is
fragile and pulls data through GitHub runners on every push. Both lanes
served their purpose (the sanitized run caught the HDF5 string-attribute
overflow fixed in the previous commit); model runs are a local gate, and
sanitized runs remain available locally via 'make MEM-CHECK=yes'. CI
keeps the hermetic jobs: serial build + unit tests and the MPI compile
check.
…unit tests

Round 3 of the pre-release cleanup: units audit and code-unit macros,
per-paper SF prescription functions, model_misc split by physics domain,
startup option validation, clamp counters, the approved HI ionisation
bookkeeping fix (baselines re-captured), H2 chemistry unit tests, the
HDF5 string-attribute overflow fix, and CI repairs (MPI wrapper package,
tree unpack path) with the download-dependent smoke lanes removed.
New model_ram_pressure.c implements the Gunn & Gott (1972) criterion for
stripping satellite ColdGas: gas at disk radius r is removed where
P_ram = eps * rho_host(R_orb) * v_sat^2 exceeds the restoring force
2*pi*G*Sigma_disk(r)*Sigma_gas(r). With exponential gas and stellar disks
sharing DiskScaleRadius the stripping radius is analytic and the stripped
fraction is (1 + r_strip/rs)*exp(-r_strip/rs).

The driver runs once per snapshot from evolve_galaxies(), outside the
substep loop, with the same 1-exp(-dT/t_strip) cadence and t_strip as the
PhysicalStrippingOn == 2 hot-gas scheme; the two channels are otherwise
independent (halo starvation vs ISM removal). Ambient density comes from
the same profiles the cooling recipes assume: cgm_density_at_radius()
(now external) for CGM-regime hosts, isothermal M_hot/(4 pi Rvir r^2)
for hot-regime hosts. Stripped gas and metals route to the central via
the regime-aware add_gas_to_hot_reservoir().

New optional parameters (registered and range-checked at startup):
RamPressureStrippingOn (0/1, default 0) and RamPressureEpsilon
(default 1.0, order-unity infall-geometry prefactor).

With the default RamPressureStrippingOn = 0 the millennium and
microuchuu baselines verify bit-identical.
Covers ram_pressure_stripped_fraction (bounds over 12 decades of P_ram,
guard values, monotonicity, f_strip = 1 at/above the central restoring
force, ~0 in the deep-potential limit, exact (1+x)exp(-x) at x = 2) and
ram_pressure_strip_satellite (mass and metal conservation between the
satellite and the host reservoir, metallicity of the stripped gas,
regime-aware routing to CGMgas, the 1-exp(-dt/t_strip) cadence factor,
no-ambient-medium / gas-free / zero-disk-radius guards, the Vvir
fallback for degenerate velocities, and weaker stripping at larger
orbital radius in the isothermal host profile).
Adds a ram_pressure_strip_satellite() section to docs/physics/infall.md
(criterion, ambient profiles, analytic stripped fraction, once-per-
snapshot cadence, the fixed-rs surface-density caveat, and the
calibration-check warning for toggled-on runs) and registers
RamPressureStrippingOn / RamPressureEpsilon in the parameter tables.
RamPressureStrippingOn = 0 and RamPressureEpsilon = 1.0, the built-in
defaults, so the millennium_all baseline stays bit-identical (verified:
5444 datasets).
plotting/rps_validation.py compares matched microUchuu runs (toggle
off / epsilon sweep) against the validation-plan observables:
quenched Type-1 satellite fraction vs host mass (Wetzel+12 SDSS band),
median satellite HI-to-stellar ratio vs host mass (Brown+17 trend),
the global HI mass function against the ALFALFA Schechter fit
(Jones+18) as the calibration-safety check, and median HI retention
vs time since infall split by host mass -- the cumulative-exposure
signature of the mechanism. Missing sweep runs are skipped so the
script works on any subset.
Orphans dominate cluster cores but were skipped, capping the HI
deficiency the channel can produce exactly where observations show the
strongest signal. Include them with a frozen-orbit approximation: the
position stays frozen at the snapshot the subhalo was lost (the true
orbit only decays further in, so rho_host and hence the stripping are
underestimated -- the conservative side), while the stale stored
velocity is replaced by the host Vvir, since its offset from the
CURRENT central velocity is not a meaningful orbital speed.

Adds a unit test pinning the orphan path to the equivalent Type 1
satellite at v = Vvir. Default-off output unchanged (millennium verify
bit-identical).
Type 2 orphans merge or disrupt within a snapshot of subhalo loss in
the default configuration (zero survive to any output), so the
frozen-orbit path only matters for configurations with long-lived
orphans.
do_AGN_heating_cgm clamps coolingGas against the pre-accretion CGMgas,
then subtracts the Bondi AGNaccreted from the reservoir -- so the
returned coolingGas can exceed the remaining CGM by up to AGNaccreted
and the caller overdraws it. Latent with the default uniform profile
(the overlap of a reservoir-limited cooling clamp and nonzero accretion
stays below the 1e-12 assert tolerance); CGMDensityProfile = 1 (NFW)
trips the XASSERT abort immediately at startup.

Millennium regression remains bit-identical; full unit suite passes.
The precipitation branch drains the CGM at dM/dt = f_precip * M_CGM /
t_ff once tcool/tff < PRECIP_THRESHOLD, so the only stable end state is
an empty reservoir: 99% of CGM-regime centrals at logMvir 11.3-12 sit
below the threshold (median tcool/tff ~ 0.2) and dump their whole CGM
into the disk, where H2-thermostated SF cannot consume it. This is the
dominant source of the factor 2-90 HIMF excess over ALFALFA and the
+0.2-0.45 dex offset from the xGASS gas fractions (the excess is 80%
centrals). The CGM density profile does not matter: NFW and beta runs
move the census by ~1% because the sigmoid saturates regardless.

PrecipRegulationOn = 1 condenses only the gas above the Voit
equilibrium: t_cool scales as 1/M_CGM at fixed profile and temperature,
so M_eq = M_CGM * (tcool/tff)/threshold and

    dM/dt = f_precip * (M_CGM - M_eq) / t_ff

relaxes toward tcool/tff = threshold and shuts off, converting the
free-fall dump of the stored reservoir into a pass-through limited by
the rate at which infall and reheated gas push the CGM back over M_eq.

Default 0 is byte-identical (millennium verify passes). Unit tests
cover the exact throttle factor and the self-quenching relaxation.
BHs currently bootstrap only through mergers and disk instabilities, so
merger-poor field halos arrive at the Mshock crossing with undermassive
BHs (median logM_BH 6.7 vs 7.4 for normal 1e12 centrals) and no
radio-mode maintenance -- they keep cooling at 14-38 Msun/yr and build
the logMHI > 10.5 tail of the HI mass function (x50-90 over ALFALFA,
unmoved by every wind/cooling/reincorporation lever tested).

BlackHoleSeedOn = 1 gives every new galaxy a BlackHoleSeedMass seed
(default 1e-5 = 10^5 Msun/h) so the Bondi radio-mode loop can engage in
quiet halos. EXPERIMENTAL placeholder for the dedicated BH-seeding work;
default 0 leaves output bit-identical (millennium verify passes).
…efault

Flip RamPressureStrippingOn and PrecipRegulationOn to on by default after
the microUchuu validation this branch built:
- RamPressureStrippingOn = 1: Gunn & Gott (1972) ISM stripping of
  satellites reproduces the satellite HI-deficiency-vs-host-mass trend
  and lifts the cluster-scale quenched fraction toward Wetzel+12.
- PrecipRegulationOn = 1: precipitation relaxes toward the tcool/tff
  equilibrium instead of draining the CGM at the free-fall rate; the
  physically correct Voit behaviour (macroscopically small at z=0 since
  little CGM sits in the marginal window, but correct).

millennium_all.par updated to pin both on explicitly; the gitignored
vanilla configs are pinned off locally to preserve classic-SAGE runs.
This intentionally changes the default output -- baselines regenerated
in the following commit.
Intentional baseline update to bless the on-by-default ram-pressure
stripping + precipitation regulation as the canonical output. Recaptured
with the serial build (make USE-MPI=):
- tests/baseline/millennium (5444 datasets), verify passes
- tests/baseline/millennium_all (5444 datasets), verify passes
- tests/benchmark/reference.sha256 (64 binary files), verify passes
The local microuchuu baseline (gitignored) was recaptured too.

These replace the pre-toggle byte-identical references; classic-SAGE
output remains reproducible via the vanilla configs.
Ram-pressure ISM stripping + precipitation regulation (now default-on)
The default flip (c33be43) updated the RamPressureStrippingOn struct
comment and the read-parameter default comments but left several places
still describing the old off-by-default state:
- core_allvars.h PrecipRegulationOn struct comment (said 0=DEFAULT)
- model_ram_pressure.c header (said default 0)
- docs/parameters.md RamPressureStrippingOn default column (0 -> 1) and
  a missing PrecipRegulationOn row (now added)
- docs/physics/infall.md two RamPressureStrippingOn default mentions

Comment/doc only -- no output change.
docs: fix stale default-off comments for RPS / precipitation regulation
Bring README, CHANGELOG, and the RTD physics docs up to date with the
now-default-on channels merged in #20/#21:

- CHANGELOG.md: new top entry covering ram-pressure ISM stripping, the
  self-regulating precipitation law, the AGN/CGM overdraw bugfix, and the
  intentional default flip with regenerated baselines.
- README.md: RamPressureStrippingOn + PrecipRegulationOn added to the
  'what is new' table, a satellite ram-pressure stripping subsection, and
  the precipitation-regulation row in the CGM table.
- docs/physics/cooling_and_heating.md: precipitation self-regulation
  (M_eq / free-fall shut-off), the PrecipRegulationOn switch, and the
  post-accretion coolingGas re-cap.

parameters.md and infall.md were already updated in #20/#21. RTD build
verified locally (doxygen + sphinx, all pages render clean).
…bsteps, disruption split

Backfill feature-level changelog coverage that was missing:
- Physical satellite stripping (PhysicalStrippingOn schemes 0/1/2 +
  StrippingTimescaleFactor): the substep-count-dependent stock scheme vs
  the physical 1-exp(-dT/t_strip) schemes, with the analytic
  once-per-snapshot scheme 2 as default (the timescale/cadence RPS reuses).
- Adaptive substeps (SubstepResolution): substep count scales with
  deltaT/t_dyn so high-z snapshots are resolved; runtime multiplier for
  convergence testing.
- Satellite-disruption mass split (DynamicDisruptionSplit + alpha/cref):
  fixed / mass-ratio / concentration-weighted ICS-vs-central partition.

RTD build verified. HI ionisation was already covered by the HI
bookkeeping section.
…bsteps

Backfill the physics-options coverage that was missing from the README,
matching the changelog:
- Satellite hot-gas stripping (PhysicalStrippingOn schemes 0/1/2 +
  StrippingTimescaleFactor): the starvation channel complementary to the
  ISM ram-pressure stripping, default scheme 2 (analytic, substep-invariant).
- Adaptive time integration (SubstepResolution): substep count scales with
  deltaT/t_dyn; runtime multiplier for convergence testing.

DynamicDisruptionSplit was already in the Mergers/ICS table; the two new
default-on channels (RPS, precip regulation) were added earlier.
…knob

The substep sweep showed SubstepResolution is the single largest lever on
the massive-end SMF (coarse steps over-cool), and its runtime cost makes it
a real decision rather than a hidden default. Expose it explicitly in
millennium.par under a dedicated 'Numerical time resolution' section with a
prominent calibration-locked / runtime-vs-convergence comment, and document
it (plus the previously-undocumented PhysicalStrippingOn row and
StrippingTimescaleFactor) in docs/parameters.md with a convergence note:
~0.1 dex SMF shift from 1.0 to converged (within observational scatter),
runtime ~linear in substep count, effect inherited from classic SAGE cooling
(not the new physics). Adds the default value only -> output byte-identical
(millennium verify passes).
Hardcode the calibrated behaviour and drop the parameters (each fixed at
its former default, so output is byte-identical):

- PhysicalStrippingOn -> always the analytic once-per-snapshot scheme
  (former default 2); scheme 0/1 branches and the in-loop strip call
  removed. strip_from_satellite loses its effective_steps argument.
- StrippingTimescaleFactor -> t_strip = t_dyn(host) (former 1.0).
- PrecipRegulationOn -> precipitation is always self-regulating (former
  default 1); the free-fall-drain branch removed.
- HIIonizationOn -> the HI ionisation cut is always applied (former 1).
- SigmaHIcrit -> fixed SIGMA_HI_CRIT constant = 0.5 Msun/pc^2.
- CGMAGNOn -> CGM-regime AGN heating fires whenever AGNrecipeOn > 0
  (former 1); the condition drops the CGMAGNOn term.

Struct fields, REG() entries, defaults, and range-checks removed;
millennium_all.par tags dropped. Unit tests updated to the single
behaviour (stripping scheme tests collapsed to the analytic case; HI
partition and precipitation tests rewritten toggle-free).

Byte-identical verified: millennium, millennium_all, microuchuu (all
datasets), and the MPI benchmark (64 files). 20/20 unit suites pass.
Update the parameter reference, physics docs, README, and changelog for
the now-fixed behaviour: drop the PhysicalStrippingOn / StrippingTimescale
Factor / PrecipRegulationOn / CGMAGNOn parameter rows; rewrite the
satellite hot-gas stripping section for the single analytic scheme; state
precipitation self-regulation and the HI ionisation cut (Sigma_HI_crit =
0.5) as always-on; add a CHANGELOG entry. RTD build verified.
@MBradley1985 MBradley1985 merged commit cbb2c48 into main Jul 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant