Skip to content

Always filter emissivity fields - #755

Open
jordanflitter wants to merge 16 commits into
release-v4.3from
filter_emissivity
Open

Always filter emissivity fields#755
jordanflitter wants to merge 16 commits into
release-v4.3from
filter_emissivity

Conversation

@jordanflitter

@jordanflitter jordanflitter commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Fix #668.

Before this PR, the Eulerian source models did not compute the emissivity fields (in HaloBox) and filter them to get the radiation fields (in RadiationFields). Instead, the density field was filtered in order to compute the "effective emissivity field" for each shell, while the radiation fields were computed on the fly in the evaluation of the spin temperature. This PR changes that and unifies the prescription for computing the emissivity and radiation fields, regardless if the considered source models are Eulerian or Lagrangian. This change allowed to clean many redundant lines in RadiationFields.c that were used for the "old" Eulerian source models, making the code much cleaner and more modular (but there's still some work to do...).

In evaluating the spin temperature, the only difference between the two types of source models is that in the Eulerian source models we use the Eulerian density field to compute the emissivity fields on the Eulerian grid, while for the Lagrangian source models we use the Lagrangian field to compute the emissivity fields on the Lagrangian grid, and then we advect them to the Eulerian grid (there's also a multiplication by 1+delta of the emissivity fields in the Eulerian source models, I am still not sure if it's really required...). There are however still differences in how the code computes the reionization field for the two types of source models, but I left this work for a future PR.

Because this PR changes the output (i.e. realizations of the spin/brightness temperature field) for the Eulerian source models, I have made several tests to confirm that I did not introduce a new bug, see my next comment below.

Other more minor changes that were made:

  • There was a bug in CONST-ION-EFF. In this source model, it is assumed that the SFRD/emissivity fields follow the time derivative of the collapsed fraction. However, the mean fixing ratio avg_fix_term was computed for the plain collapsed fraction, but was applied on the derivative of the collapsed fraction. Compared to what we do in the other source models, it is more consistent to compute avg_fix_term for the derivative of the collapsed fraction (which is proportional to the SFRD). That was fixed in this PR.
  • A new page, called Radiation_Fields.rst was added to the docs. This file describes the history of how emissivity fields and radiation fields were computed in 21cmFAST, including the changes that were made in v4.3 and were part of this PR.
  • Previously, MINIMIZE_MEMORY affected how the radiation fields were computed in the Eulerian source models. After this PR, its effect on the code has been reduced significantly, which allowed to delete/optimize some tests.

Summary by Sourcery

Unify emissivity generation and radiation-field filtering across Eulerian and Lagrangian source models.

New Features:

  • Compute emissivity fields for Eulerian source models in HaloBox and process them through the same RadiationFields pipeline used by Lagrangian source models.
  • Require explicit radiation-field inputs for spin-temperature calculations and expose HaloBox and RadiationFields consistently across simulation outputs and caching.

Bug Fixes:

  • Correct CONST-ION-EFF normalization by deriving the mean-fix factor from the collapsed-fraction derivative used for emissivity.
  • Fix Eulerian emissivity and X-ray scaling, density weighting, and source-grid handling.

Enhancements:

  • Remove the legacy Eulerian radiation-field computation and substantially simplify radiation-field setup, memory management, and source-model branching.
  • Reduce MINIMIZE_MEMORY-specific behavior and compute HaloBox fields only when required by enabled outputs or physics.
  • Allow Lyman-alpha multiple scattering with Eulerian source models and refine halo-mass range validation.

Documentation:

  • Add documentation describing the evolution and unified computation of emissivity and radiation fields.

Tests:

  • Update spin-temperature, output-structure, caching, input-validation, and integration coverage for unified Eulerian and Lagrangian radiation-field workflows.
  • Remove obsolete MINIMIZE_MEMORY tests and adapt expected outputs to the revised field lifecycle.

Prepared HaloBox to work also with Eulerian source models. If we work with Eulerian source models, then we use the Eulerian perturbed density field rather than the Lagrangian density field from the initial conditions, and we do not advect it into its final Eulerian positions as we do for the Lagrangian source models. For E-INTEGRAL, the SFRD and X-ray emissivity are computed very similarly to what is already found in RadiationFields.c. Note that the X-ray emissivity is computed differently between Lagrangian and Eulerian source models, so special care was given to differentiate between these two types of source models. Also, we don’t compute the SFRD directly for CONST-ION-EFF, but rather evaluate it via rho_b * F_STAR10 * df_coll/dt, so another attention is given there. For the Eulerian source models, we multiply the emissivity fields by (1+delta), except for N_ion, and we also do mean fixing, just like it was used to be done until now. In addition, I optimized the allocation of the fields of HaloBox: halo_sfr and halo_sfr_mini are required only if USE_TS_FLUCT=True, while whalo_sfr is used only for the Lagrangian source models (for now). n_ion is allocated for all source models, even though it is used only for the Lagrangian source models, as this might change in the future.
Two bugs were fixed in RadiationFields.c for CONST-ION-EFF. The first one, and the more major one, is that mean_sfr_zpp was always computed via EvaluateSFRD. This is wrong because EvaluateSFRD contains a mass-dependent term for star formation efficiency and also exponential damping, unlike the collapsed fraction which has a sharp cutoff. On top of that, the local collapsed fraction is computed under the assumption of the PS mass function, but EvaluateSFRD assumes the input HMF, which is usually Sheth-Tormen. The second bug was that the mean fixing did something like [df_coll/dz](x) *= f_coll_global / <f_coll(x)>, instead of [df_coll/dz](x) *= df_coll_dz_global / <[df_coll/dz](x)>. The latter of course is more correct as it fixes the mean of the fluctuating quantity, which is the derivative of the collapsed fraction.
Changed our integration tests that work with CONST-ION-EFF to work also with HMF=PS. The reason for that is that in CONST-ION-EFF the fluctuating collpased fraction is taken from extended PS theory, so it is the more appropriate halo mass function to consider when working with CONST-ION-EFF. It also silences a warning that we have about working with CONST-ION-EFF and HMF which is different than PS.
Introduced a temporary USE_NEW_CODE boolean flag. This flag was helpful in testing and comparing the old E-INTEGRAL source model vs the new E-INTEGRAL source model. After fixing two bugs in HaloBox.c, the global spin temperature from run_global_evolution agree very well, with and without mini-halos. As for the global spin temperature from run_lightcone, divergence at low redshifts can be seen. I confirmed that this divergence is real and not a consequence of an uknown bug by comparing between L-INTEGRAL and the new E-INTEGRAL, but forced to still use the lagrangian density field: in that configuration, both source models had the same input density field, as well as the same algorithm for computing the radiation fields, and indeed the same output (global spin temperature from run_lightcone) was obtained. This means that the divergence at low redshifts in the global spin temperature between the old and new E-INTEGRAL source models (from run_lightcone) is a genuine real effect, and not a bug. The reason for that divergence is because filtering and computing the emissivity fields given the density field are two non-linear operations, and as such, they do not commute. In addition to confirming the correctness of the new E-INTEGRAL source model, all the tests in the test suite pass.
A few commits ago I thought I fixed a bug in CONST-ION-EFF in RadiationFields.c since I thought that mean_sfr_zpp is determined by the mass-dependent version of EvaluateSFRD, namely an integral over the user's mass function (which is not necessarily PS), with mass-dependent star formation efficiency term, and an exponential cutoff, all seem not to match the call per cell in calculate_sfrd_from_grid. However, I didn't notice that EvaluateSFRD has a branch for the mass-independent source model, where Fcoll_General is calculated (or an interpolation of a table that was initialized with this function is performed). This is actually okay, since Fcoll_General executes the correct integral, but with the user's halo mass function, so the mean fixing corrects the mean by using the correct user's halo mass function (rather than PS). I therefore restored the code, the test, and the data files for CONST-ION-EFF from a few commits ago. Having said that, there is still a subtle bug of computing avg_fix_term for the plain collpased fraction, while that avg_fix_term is used in correcting the derivative of the collapsed fraction. This still needs to be fixed and will be done in the next commit.
As I said in my last commit, there was still a bug of computing the mean ratio for the collapsed fraction for SOURCE_MODE=CONST-ION-EFF, while this ratio was applied to fix the derivative of the collapsed fraction. I fixed that in this commit. Since I use in get_uhmf_averages the numerical derivative of Fcoll_General, and the latter function doesn't need sigma_min, I could remove the integral_cond input and its associated lines that I added a few commits ago. As this fix changes the spin temperature output, I had to also update the datafile for the ts_nomdz configuration. I can tell that before updating the datafile, I got an AssertionError due to a mismatch in the global signal which was as high as 28%, though I think it could have been higher because we stop the test only at z=18. This shows anyway the impact that this bug had on the output of the simulation for CONST-ION-EFF.
Removed the temporary USE_NEW_CODE flag, by assuming it is True all the time. This allowed to clear many lines from the old code in RadiationFields.c, as well as in SpinTemperatureBox.c. As a consequence of this change, we now always compute HaloBox, and we also always compute RadiationFields.c (if USE_TS_FLUCT=True). In addition, we can now use LYA_MULTIPLE_SCATTERING also for the Eulerian source models. Due to adopting USE_NEW_CODE=True, the spin temperature for the Eulerian source models have changed, it is now higher (mostly at low redshifts when the density field becomes highly non-linear) due to the Jensen inequality, as we now compute first the emissivity fields (convex functions of the density field) and then filter, unlike the opposite ordering in the old code of the Eulerian source models. I therefore reproduced the relevant data files (that work with Eulerian source models and USE_TS_FLUCT=True), in order to pass the integration tests. Also minor adjustments had to be done in some test modules that test the python code. After all these changes, all the tests now pass.
After the last commit many code lines became redundant and unused. I removed many of them in this commit. All tests pass.
Included a new rst file in the docs named Radiation_Fields.rst. That file describes the history of the radiation fields in 21cmFAST, including the changes in this PR
Until this PR, MINIMIZE_MEMORY also affected how the computation of the spin temperature and the radiation fields is performed. After this PR, it's no longer the case. I therefore removed test_minimize_memory.py, as this test module was originally included to test the code of MINIMIZE_MEMORY in SpinTemperatureBox.c. I also removed USE_TS_FLUCT from the minimize_mem configuration and updated the corresponding datafile from the same reason. Finally, I noticed that mean_free_path is evaluated only if we do recombination calculations, so I optimized its allocation in outputs.py
@jordanflitter jordanflitter self-assigned this Aug 10, 2026
@sourcery-ai

sourcery-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Unifies emissivity and radiation field computation for Eulerian and Lagrangian source models, reworking HaloBox/RadiationFields/TsBox pipelines, fixing CONST-ION-EFF SFRD consistency, and simplifying MINIMIZE_MEMORY behavior and Python wrappers/docs/tests accordingly.

Sequence diagram for unified emissivity/radiation pipeline in spin temperature computation

sequenceDiagram
    actor User
    participant drivers_single_field as compute_spin_temperature
    participant HaloBox as ComputeHaloBox
    participant RadiationFields as UpdateRadiationFields
    participant TsBox as ComputeTsBox
    participant PerturbedField
    participant InitialConditions

    User->>drivers_single_field: compute_spin_temperature(inputs, redshift, ...)
    drivers_single_field->>PerturbedField: load_all()
    drivers_single_field->>InitialConditions: load_all()
    drivers_single_field->>HaloBox: ComputeHaloBox(redshift, InitialConditions, PerturbedField, HaloCatalog, previous_spin_temp, previous_ionize_box, HaloBox)
    note over HaloBox,PerturbedField: Emissivity fields (halo_sfr, halo_xray, n_ion, ...) computed
    drivers_single_field->>RadiationFields: compute_radiation_fields(redshift, hboxes, PerturbedField, InitialConditions, ...)
    RadiationFields->>RadiationFields: UpdateRadiationFields(redshift, HaloBox, R_inner, R_outer, R_ct, R_star, mode, cleanup, RadiationFields)
    note over RadiationFields: Radiation fields (xray_ionization_rate, lya_flux_*, lyw_flux, ...) updated from emissivities
    drivers_single_field->>TsBox: ComputeTsBox(redshift, prev_redshift, perturbed_field_redshift, TsBox, PerturbedField, IonizedBox, RadiationFields, cleanup)
    TsBox->>TsBox: use RadiationFields.Q_HI and radiation grids for spin temperature
    TsBox-->>User: TsBox result
Loading

Flow diagram for unified emissivity/radiation computation across Eulerian and Lagrangian source models

flowchart LR
    subgraph SourceModelSelection
        A[source_model]
        A -->|source_model_uses_eulerian_grids| B[Eulerian branch]
        A -->|source_model_uses_lagrangian_grids| C[Lagrangian branch]
    end

    subgraph EmissivityComputation
        B --> B1[ComputeHaloBox redshift InitialConditions PerturbedField HaloCatalog etc]
        C --> C1[ComputeHaloBox redshift InitialConditions PerturbedField HaloCatalog etc]
        B1 --> D[HaloBox emissivity fields halo_sfr halo_xray n_ion etc]
        C1 --> D
    end

    subgraph RadiationFieldsComputation
        D --> E[UpdateRadiationFields redshift HaloBox R_inner R_outer R_ct R_star etc]
        E --> F[RadiationFields grids xray_ionization_rate xray_lya_flux lyw_flux lya_flux_*]
    end

    subgraph SpinTemperatureEvaluation
        F --> G[ComputeTsBox redshift prev_redshift perturbed_field_redshift TsBox PerturbedField IonizedBox RadiationFields etc]
        G --> H[TsBox spin temperature Q_HI etc]
    end
Loading

File-Level Changes

Change Details Files
Remove Eulerian-only filtering and interpolation machinery from RadiationFields, making radiation shells depend solely on precomputed emissivity fields from HaloBox and simplifying global tables.
  • Deleted FFTW-based density/Mcrit filtering helpers and associated global arrays for Eulerian grids
  • Simplified z-edge setup and removed unused growth/mass sigma tables
  • Made frequency-integral tables always computed over all shells, independent of MINIMIZE_MEMORY or source grid type
  • Removed Eulerian-specific SFRD mean-fixing and MINIMIZE_MEMORY path from radiation shell accumulation, now consuming filtered_sfr/filtered_xray from RadiationFields
  • Unified volume unit conversion in radiation field normalisation to use pure comoving volume
src/py21cmfast/src/RadiationFields.c
src/py21cmfast/src/RadiationFields.h
src/py21cmfast/src/SpinTemperatureBox.c
Refactor HaloBox to explicitly compute emissivity/sfr/xray integrals for both mass-dependent and CONST-ION-EFF source models, encode Eulerian vs Lagrangian differences, and provide consistent mean-fixing and averaging.
  • Extended IntegralCondition/HaloProperties to track sigma_min and removed unused turnover-mass outputs
  • Reworked get_uhmf_averages to derive prefactors for n_ion, SFRD, X-ray emissivity, and weighted SFRD depending on source_model type and USE_TS_FLUCT/USE_MINI_HALOS/EXTRA_HALOBOX_FIELDS
  • Fixed CONST-ION-EFF bug by computing avg_fix_term off dfcoll/dz-equivalent SFRD integral rather than Fcoll itself
  • Made get_halobox_averages depend on perturbed Eulerian density (1+delta factor) and split behaviour for Eulerian vs Lagrangian and recombination models
  • Updated mean_fix_grids to scale only fields actually used (n_ion, SFRD, X-ray, whalo_sfr) and to require perturbed_field for Eulerian models
  • Changed get_cell_integrals to compute SFRD/X-ray differently for mass-dependent vs CONST-ION-EFF models and to multiply emissivities by (1+delta) on Eulerian grids
  • Adjusted set_fixed_grids to use appropriate density (Eulerian vs Lagrangian, low-res vs high-res), build conditional tables only when needed, and pass perturbed_field into mean-fix
  • Updated halobox debug printing to log separate expectations for n_ion, SFRD, X-ray, and optional extra fields
src/py21cmfast/src/HaloBox.c
src/py21cmfast/src/HaloBox.h
src/py21cmfast/src/scaling_relations.c
Revise grid advection and emissivity mapping in map_mass so that Lagrangian source models advect halo properties while Eulerian models stay fixed, with unified prefactors for emissivity fields and recombination inputs.
  • Added defensive check that emissivity output volume matches density input for Eulerian models
  • Derived mass/SFRD/n_ion/X-ray prefactors based on source_model, USE_TS_FLUCT, USE_MINI_HALOS, EXTRA_HALOBOX_FIELDS, and dtdz for CONST-ION-EFF
  • Restricted velocity-based displacement and CIC interpolation to Lagrangian source grids; Eulerian grids use direct density index without advection
  • Ensured halo_xray is proportional to SFRD for Eulerian models via combined prefactors and stellar_mass_mini contribution
  • Limited whalo_sfr construction to Lagrangian recombination models via n_ion scaling
src/py21cmfast/src/map_mass.c
Update Python HaloBox/TsBox/RadiationFields wrappers, single-field drivers, cache management, and global_evolution/lightcone utilities to reflect new emissivity pipeline, required inputs, and optional fields.
  • Made halo_sfr optional in wrapper HaloBox outputs, only allocating when USE_TS_FLUCT, and gated whalo_sfr on Lagrangian grids
  • Adjusted HaloBox.new to allocate extra fields under EXTRA_HALOBOX_FIELDS, TS fluctuations, mini-halos, and recombination models; extended tests to assert new optional behaviour
  • Changed HaloBox.get_required_input_arrays to request PerturbedField density for Eulerian models and IC velocities only for Lagrangian grids (with 2LPT variants)
  • Extended HaloBox.compute signature to require perturbed_field; added validation in compute_halo_grid for required initial_conditions/perturbed_field depending on source model and V_CB_MODEL, with new tests
  • Removed legacy path that created dummy RadiationFields inside compute_spin_temperature for Eulerian source models; TsBox now always expects RadiationFields
  • Simplified TsBox/HaloBox get_required_input_arrays for RadiationFields/HaloBox inputs based on new design (always use radiation fields; only use n_ion/whalo_sfr for Lagrangian grids)
  • Modified TsBox.new to only allocate mean_free_path when recombination enabled, independent of MINIMIZE_MEMORY
  • Updated management.get_expected_outputs and caching.RunCache to always include HaloBox and RadiationFields when TS fluctuations enabled, aligning cache expectations
  • Extended caching tests to expect HaloBox/RadiationFields/TsBox presence and added option to include InitialConditions in get_all_boxes_at_z
src/py21cmfast/wrapper/outputs.py
src/py21cmfast/wrapper/inputs.py
src/py21cmfast/drivers/single_field.py
src/py21cmfast/drivers/coeval.py
src/py21cmfast/drivers/global_evolution.py
src/py21cmfast/drivers/lightcone.py
src/py21cmfast/management.py
src/py21cmfast/io/caching.py
tests/test_output_structs.py
tests/test_singlefield.py
tests/io/test_caching.py
tests/test_input_structs.py
Tighten constraints and behaviour around MINIMIZE_MEMORY and halomass-range checks, and adjust integration test configuration to match new pipeline.
  • Reduced impact of MINIMIZE_MEMORY on radiation field computation by no longer using per-R FFTW filtering, removing fftwf cleanup calls
  • Updated halomass range checker to early-return for non-lagrangian source grids and documented why warnings currently only trigger for L-INTEGRAL
  • Adjusted integration-test configuration for CONST-ION-EFF and MINIMIZE_MEMORY templates to reflect new defaults (e.g., USE_TS_FLUCT not required with MINIMIZE_MEMORY)
src/py21cmfast/src/RadiationFields.c
src/py21cmfast/wrapper/inputs.py
tests/produce_integration_test_data.py
tests/test_minimize_memory.py
Add documentation page describing radiation/emissivity field history and current implementation.
  • Introduced Radiation_Fields.rst to docs, outlining how emissivity and radiation fields are computed across source models and versions, including v4.3 changes
  • Linked new page from the documentation index for discoverability
docs/Radiation_Fields.rst
docs/index.rst

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@jordanflitter jordanflitter added context: python wrapper Changes predominantly concerning the python wrapper context: C backend Changes occur predominantly in the C code type: maint: refactoring Refactoring type: maint: removal Removals and Deprecations type: accuracy Enhancement that improves accuracy labels Aug 10, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 13 issues, and left some high level feedback:

  • The prefactor setup for SFRD/Nion/X-ray (e.g., in get_uhmf_averages, get_cell_integrals, and move_grid_galprops) is now duplicated and quite intricate; consider centralising this logic in a shared helper to reduce the risk of the Eulerian/Lagrangian and mass‑dependent/mass‑independent branches drifting out of sync.
  • In move_grid_galprops, the strict vol_ratio_out != 1.0 check for Eulerian source models may trip on floating-point round-off; using a small tolerance or checking integer volumes directly would make this safety check more robust.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The prefactor setup for SFRD/Nion/X-ray (e.g., in `get_uhmf_averages`, `get_cell_integrals`, and `move_grid_galprops`) is now duplicated and quite intricate; consider centralising this logic in a shared helper to reduce the risk of the Eulerian/Lagrangian and mass‑dependent/mass‑independent branches drifting out of sync.
- In `move_grid_galprops`, the strict `vol_ratio_out != 1.0` check for Eulerian source models may trip on floating-point round-off; using a small tolerance or checking integer volumes directly would make this safety check more robust.

## Individual Comments

### Comment 1
<location path="docs/Radiation_Fields.rst" line_range="29" />
<code_context>
+ionized electron of energy :math:`E_e = h_{\rm P}\nu - E^i_{\rm th}` that is deposited as heat in the IGM (a function of :math:`E_e` and
+the local ionization fraction), :math:`f_i` is the number fraction of species :math:`i` in the IGM, and :math:`\sigma_i(\nu)` is the
+cross-section for photo-ionization of a particle from species :math:`i` due to the interaction with an X-ray photon of frequency :math:`\nu`.
+To understand the above experssion, let us consider the following components:
+
+* :math:`f_i \sigma_i(\nu) J_X(\nu)` is the production rate of electrons (with energy :math:`E_e`) per gas particle per
</code_context>
<issue_to_address>
**issue (typo):** Correct typo in 'experssion'.

Spelling: use 'expression' instead of 'experssion'.

```suggestion
To understand the above expression, let us consider the following components:
```
</issue_to_address>

### Comment 2
<location path="docs/Radiation_Fields.rst" line_range="47-48" />
<code_context>
+
+where :math:`k_B` is Boltzmann's constant and :math:`x_e` is the local ionization fraction. The X-ray heating rate is thus a physical
+quantity that can be represented as a 3D box at a given redshift, and is thus considered a "radiation field" in ``21cmFAST``.
+Similarly, the photionization rate due to X-ray radiation, as well as the contribution to the Lyman-alpha flux from X-ray excitation of HI
+atoms, are also considered "radiation fields".
+
</code_context>
<issue_to_address>
**issue (typo):** Fix spelling of 'photionization'.

Use 'photoionization' instead of 'photionization' in this sentence.

```suggestion
Similarly, the photoionization rate due to X-ray radiation, as well as the contribution to the Lyman-alpha flux from X-ray excitation of HI
atoms, are also considered "radiation fields".
```
</issue_to_address>

### Comment 3
<location path="docs/Radiation_Fields.rst" line_range="82" />
<code_context>
+traditional radiative transfer codes.
+
+The Lyman alpha flux from continuum photons (photons that were emitted with frequency below Lyman beta and redshifted into Lyman alpha) and
+injected photons (photons that were emitted with frequency above Lyman beta and went atomic cascades once they had redshifted into a Lyman
+resonance) is computed in a similar manner,
+
</code_context>
<issue_to_address>
**suggestion (typo):** Improve grammar in 'went atomic cascades'.

Please rephrase 'went atomic cascades' to 'went through atomic cascades' or 'underwent atomic cascades' to correct the grammar.

Suggested implementation:

```
injected photons (photons that were emitted with frequency above Lyman beta and underwent atomic cascades once they had redshifted into a Lyman
resonance) is computed in a similar manner,

```

If this sentence is wrapped differently in your actual file (e.g., different line breaks), adjust the SEARCH block to match the exact existing text so the replacement applies correctly.
</issue_to_address>

### Comment 4
<location path="docs/Radiation_Fields.rst" line_range="128" />
<code_context>
+
+    \epsilon_\alpha(z, \delta) = \bar\n_b(z=0) (1+\delta) N_{\gamma /{\rm b}} f_* \frac{d}{dt}f_{\rm coll}(z, M_{\rm turn} ; \delta, M_{\rm cond}),
+
+where :math:`\bar\n_b` is the mean baryon number density and :math:`N_{\gamma /{\rm b}}` is the number of stellar photons per baryon
+(the latter is a free parameter).
+
</code_context>
<issue_to_address>
**issue (typo):** Fix LaTeX command `\bar\n_b`.

`\n` is not a valid LaTeX command, so this won’t render correctly. Use `\bar n_b` within the math environment instead.

```suggestion
    \epsilon_\alpha(z, \delta) = \bar n_b(z=0) (1+\delta) N_{\gamma /{\rm b}} f_* \frac{d}{dt}f_{\rm coll}(z, M_{\rm turn} ; \delta, M_{\rm cond}),
```
</issue_to_address>

### Comment 5
<location path="docs/Radiation_Fields.rst" line_range="144" />
<code_context>
+
+where :math:`\bar\rho_m` is the mean matter density and :math:`dn/dM_h(z, M_h ; \delta_{\rm cond}, M_{\rm cond})` is the conditional halo
+mass function in a region of size :math:`R(M_{\rm cond}) = [3M_{\rm cond}/(4\pi \bar\rho_m)]^{1/3}` and overdensity :math:`\delta_{\rm cond}`.
+For the calculation of the conditionl collapsed fraction, ``21cmFAST`` v1.0.0 assumed that the conditional halo mass function was given
+by the Sheth-Tormen conditional mass function. Under this assumption, the conditional collapsed fraction has an analytical form,
+
</code_context>
<issue_to_address>
**issue (typo):** Correct spelling of 'conditionl'.

Replace 'conditionl' with 'conditional' in this sentence.

```suggestion
For the calculation of the conditional collapsed fraction, ``21cmFAST`` v1.0.0 assumed that the conditional halo mass function was given
```
</issue_to_address>

### Comment 6
<location path="docs/Radiation_Fields.rst" line_range="157" />
<code_context>
+radius :math:`R(M) = [3M/(4\pi \bar\rho_m)]^{1/3}`.
+
+While ``21cmFAST`` v1.0.0 used the analytical result for the conditional collapsed fraction from the extended Press-Schechter formalism
+in order to assess the fluctuations in the emissivity fields, the code also normalized the mean collapsed fraction in the box to match
+the global collapsed fraction, as given by solving the above intergral numerically with the user's selected halo mass function
+(which by default was the Sheth-Tormen mass function).
+
</code_context>
<issue_to_address>
**issue (typo):** Correct spelling of 'intergral'.

'intergral' should be corrected to 'integral' in that sentence.

```suggestion
the global collapsed fraction, as given by solving the above integral numerically with the user's selected halo mass function
```
</issue_to_address>

### Comment 7
<location path="docs/Radiation_Fields.rst" line_range="165" />
<code_context>
+
+Given the above definitions for the emissivity fields, the effective emissivity fields are achieved by interpolating in time/redshift and
+filtering in space. Since ``21cmFAST`` v1.0.0 did not have the emissivity fields on a grid, the interpolation and filtering was done in
+the following way. Firstly, given they Eulerian density field :math:`\delta_{\rm E}(z, \mathbf{x})` at redshift :math:`z` (the current
+snapshot's redshift), the code evaluated the density field at the integrated redshift :math:`z'` by scaling with the linear growth factor,
+namely :math:`\delta_{\rm E}(z', \mathbf{x}) \approx \delta_{\rm E}(z, \mathbf{x}) D(z')/D(z)`. Then, instead of filtering the emissivity
</code_context>
<issue_to_address>
**issue (typo):** Fix grammar in 'given they Eulerian density field'.

Replace 'they' with 'the' so the sentence reads 'given the Eulerian density field'.

```suggestion
the following way. Firstly, given the Eulerian density field :math:`\delta_{\rm E}(z, \mathbf{x})` at redshift :math:`z` (the current
```
</issue_to_address>

### Comment 8
<location path="docs/Radiation_Fields.rst" line_range="254" />
<code_context>
+where :math:`\nu_\alpha` is the Lyman-alpha frequency. Several notes:
+
+* Note that unlike previous radiation fields, the LW flux contains units of energy, owned by the factor of :math:`h_{\rm P}\nu_\alpha`.
+* The contribution to the LW flux came from both atomic cooling galaxies (ACGs) and MCGs, as the SFRD in both populations is modedled a bit
+differently, mostly in the modeling of the star formation efficiency, the turnover mass and the duty fraction (see more details on the
+latter two in :doc:`M_TURN`). Likewise, the contribution to the X-ray and Lyman-alpha fluxes also came from both ACGs and MCGs.
</code_context>
<issue_to_address>
**issue (typo):** Correct spelling of 'modedled'.

Replace "modedled" with "modeled" in this sentence.

```suggestion
* The contribution to the LW flux came from both atomic cooling galaxies (ACGs) and MCGs, as the SFRD in both populations is modeled a bit
```
</issue_to_address>

### Comment 9
<location path="docs/Radiation_Fields.rst" line_range="258" />
<code_context>
+differently, mostly in the modeling of the star formation efficiency, the turnover mass and the duty fraction (see more details on the
+latter two in :doc:`M_TURN`). Likewise, the contribution to the X-ray and Lyman-alpha fluxes also came from both ACGs and MCGs.
+* It was assumed that ACGs contained only popII stars, while MCGs contained only popIII stars. Therefore,
+the shape of the SEDs in ACGs and MCGs were also different in the evaluation of Lyman-alpha and LW fluxes, as well their amplitudes
+(controlled by the free parameter :math:`N_{\gamma /{\rm b}}`, which was now split into two free parameters). However, for the evaluation
+of the X-ray flux, the SEDs in both ACGs and MCGs were assumed to be the same, and were modeled as in previous versions, namely
</code_context>
<issue_to_address>
**suggestion (typo):** Improve phrasing 'as well their amplitudes'.

Change the phrase to "as well as their amplitudes" for correct grammar.

```suggestion
the shape of the SEDs in ACGs and MCGs were also different in the evaluation of Lyman-alpha and LW fluxes, as well as their amplitudes
```
</issue_to_address>

### Comment 10
<location path="docs/Radiation_Fields.rst" line_range="283-286" />
<code_context>
+* ``"E-INTEGRAL"``:
+  This option was equivalent to setting ``USE_MASS_DEPNDENT_ZETA`` to True in previous versions.
+
+* ``"L-INTEGRAL"``:
+  This is a new source model that was introduced in v4.0.0. It was similar to ``"E-INTEGRAL"``, but the emissivity
+  fields were computed on the Lagrangian density grid, and then mapped to the Eulerian grid (see details below).
+
+* ``"DEXM-ESF"``:
+  This is a new source model that was introduced in v4.0.0, similar to ``"L-INTEGRAL"``, but the emissivity fields recieved
+  contributions from resolved discrete halos that were found via the excursion-set formalism (ESF), as was implemented by
+  the ``DEXM`` algorithm (see Mesinger & Furlanetto 2007, https://arxiv.org/pdf/0704.0946).
</code_context>
<issue_to_address>
**issue (typo):** Correct spelling of 'recieved'.

In this description, change 'recieved' to 'received'.

```suggestion
* ``"DEXM-ESF"``:
  This is a new source model that was introduced in v4.0.0, similar to ``"L-INTEGRAL"``, but the emissivity fields received
  contributions from resolved discrete halos that were found via the excursion-set formalism (ESF), as was implemented by
  the ``DEXM`` algorithm (see Mesinger & Furlanetto 2007, https://arxiv.org/pdf/0704.0946).
```
</issue_to_address>

### Comment 11
<location path="docs/Radiation_Fields.rst" line_range="308-309" />
<code_context>
+
+    \epsilon(z, \mathbf{x}) \to \epsilon^{\rm eff}(z', \mathbf{x})=\epsilon[z', \delta_{\rm E}^R(z,\mathbf{x}) D(z')/D(z)].
+
+In contrast, for the three "Lagrangian" source models, the emissivity fields were computed on the Lagrangian density grid, and were
+then advected to the Eulerian grid by an algorithm similar to 2LPT. Moroever, the emissivity fields in the "Lagrangian" source models
+were computed as an interemediate output of the code (stored in the ``HaloBox`` class). This enabled to interpolate the emissivity fields
+at redshift :math:`z'`. Then, for each spherical integrated shell with innter radius :math:`R_{\rm i}` and outer radius :math:`R_{\rm o}`,
</code_context>
<issue_to_address>
**issue (typo):** Correct spelling of 'Moroever'.

Please correct the spelling to 'Moreover'.

Suggested implementation:

```
then advected to the Eulerian grid by an algorithm similar to 2LPT. Moreover, the emissivity fields in the "Lagrangian" source models

```

While not part of your specific request, you may also want to correct other typos in the same paragraph (e.g., "interemediate" → "intermediate", "innter" → "inner") for clarity and professionalism.
</issue_to_address>

### Comment 12
<location path="docs/Radiation_Fields.rst" line_range="273-277" />
<code_context>
+emissivity fields and the radiation fields was changed for several new configurations that were introduced in that version. This was
+controlled by the new enum parameter ``SOURCE_MODEL``, which had five options:
+
+* ``"CONST-ION-EFF"``:
+  This option was equivalent to setting ``USE_MASS_DEPNDENT_ZETA`` to False in previous versions.
+
+* ``"E-INTEGRAL"``:
</code_context>
<issue_to_address>
**issue (typo):** Fix typo in flag name `USE_MASS_DEPNDENT_ZETA`.

Earlier the flag is spelled `USE_MASS_DEPENDENT_ZETA`, but here it appears as `USE_MASS_DEPNDENT_ZETA` (missing `E`). Please correct this for consistency and to avoid confusion when users reference the flag name.

```suggestion
* ``"CONST-ION-EFF"``:
  This option was equivalent to setting ``USE_MASS_DEPENDENT_ZETA`` to False in previous versions.

* ``"E-INTEGRAL"``:
  This option was equivalent to setting ``USE_MASS_DEPENDENT_ZETA`` to True in previous versions.
```
</issue_to_address>

### Comment 13
<location path="docs/Radiation_Fields.rst" line_range="341" />
<code_context>
+that in the former, the emissivity fields were computed on the Eulerian density grid, while in the latter, the emissivity fields were
+computed on the Lagrangian density grid and then advected to the Eulerian grid.
+
+Furthermore, in v4.3.0, the effect of Lyman-alpha multiple scattering could have been applied via a new flag called ``LYA_MULTIPLE_SCATTERING``,
+regardless if the simulated source model was "Eulerian" or "Lagrangian". When this flag was set to True, the effective emissivity for
+Lyman-alpha photons was achieved by filtering the interpolated emissivity field with a generalization of the sphericall shell filter
+(see more details in Flitter, Munoz and Mesinger 2026, https://arxiv.org/pdf/2601.14360).
+
</code_context>
<issue_to_address>
**issue (typo):** Correct spelling of 'sphericall'.

```suggestion
Lyman-alpha photons was achieved by filtering the interpolated emissivity field with a generalization of the spherical shell filter
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst Outdated
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.75000% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.42%. Comparing base (f3c11a1) to head (f792659).
⚠️ Report is 1 commits behind head on release-v4.3.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/py21cmfast/drivers/single_field.py 80.00% 1 Missing and 1 partial ⚠️
src/py21cmfast/wrapper/outputs.py 94.73% 0 Missing and 2 partials ⚠️
src/py21cmfast/wrapper/inputs.py 95.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@               Coverage Diff                @@
##           release-v4.3     #755      +/-   ##
================================================
- Coverage         91.45%   91.42%   -0.04%     
================================================
  Files                33       33              
  Lines              5245     5224      -21     
  Branches            921      914       -7     
================================================
- Hits               4797     4776      -21     
  Misses              286      286              
  Partials            162      162              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Corrected some typos/rendering issues on the docs. In addition, I fixed a test that somehow managed to pass in certain OS (weird...)
@jordanflitter

Copy link
Copy Markdown
Contributor Author

Validation tests

In order to validate the new code, I introduced a temporary USE_NEW_CODE flag. I used that flag to run simulations with the old/new Eulerian source models. Since the old Eulerian source models did not have HaloBox and RadiationFields outputs, I could only study the fields from TsBox, and spin_temperature is the most relevant one because it depends on both X-ray heating (controlled by the halo_xray field in HaloBox) and WF coupling (controlled by the halo_sfr field in HaloBox).

I started first by running two quick run_global_evolutions simulations, and measuring the residuals in the global spin temperature for each Eulerian source model.

Old vs New code (global evolution, E-INTEGRAL, with mini-halos) Old vs New code (global evolution, E-INTEGRAL, without mini-halos) Old vs New code (global evolution, CONST-ION-EFF)

As can be seen, the residuals of the global spin temperature are almost sub-percent at all redshifts and Eulerian source models, and because all the integration tests for the Lagrangian source models have passed without modifying the datafiles, this means that there is no bug in the prefactors that multiply the integrals, or in the mean fixing.

Interestingly, if I repeat the same comparison, but for the global spin temperature from run_lightcone, there is a divergence between the old and new Eulerian source models at low redshifts. However, this divergence is expected! (as I explain in the comment below)
To convince myself that indeed there is no bug in the new Eulerian source models, I did the following test. In HaloBox.c, I used the temporary USE_NEW_CODE flag to force the new E-INTEGRAL source model to use the Lagrangian density field for the emissivity fields (instead of the Eulerian density field). Under this configuration, E-INTEGRAL and L-INTEGRAL shared the same input density field for HaloBox, so if there was a bug in the new code for the evaluation of the emissivity fields (given the input density field), then a mismatch between the global spin temperatures of the two source models would have been observed. Yet, there wasn't such a mismatch, the two global spin temperatures agreed up to sub-percent differences, which means that there is no bug in the new code for the evaluation of the emissivity fields (given the input density field). Therefore, the divergence that is seen in the global spin temperature (from run_lightcone) between the old and new E-INTEGRAL codes is a real one! I explain its origin in the comment below.

Old vs New code (lightcone, CONST-ION-EFF) Old vs New code (lightcone, E-INTEGRAL, with mini-halos) Old vs New code (lightcone, E-INTEGRAL, without mini-halos)

@jordanflitter jordanflitter linked an issue Aug 10, 2026 that may be closed by this pull request
@jordanflitter

Copy link
Copy Markdown
Contributor Author

Origin of the discrepancy at low redshifts (Jensen's inequality!)

The main difference between the old and new codes for the Eulerian source models is flipping the order of operations:

  • In the old code, the Eulerian density field was filtered, and then the emissivity function was applied on the filtered density field.
  • In the new code, the emissivity function is applied on the Eulerian density field, and then the emissivity field is filtered.

Because the emissivity function is a convex function of the density field, and filtering can be viewed as a weighted average, we can apply the Jensen's inequality: for a convex function f(delta), <f(delta)> > f(<delta>). Thus, from the Jensen's inequality, we can predict that the new code should yield a larger effective emissivity, and stronger radiation fields! (i.e. stronger X-ray and Lya fluxes)

At sufficiently low redshifts, the WF coupling saturates, and the spin temperature follows the gas kinetic temperature. Because of the increased X-ray flux in the new code, X-ray heating is more efficient, which means that the gas heats up faster and the spin temperature is higher. We see exactly that when we compare the coeval boxes of the spin temperature between the old and new codes! Interestingly, it also seems that the spin temperature field is smoother in the new code.

Old vs New code (coeval, CONST-ION-EFF, spin temperature) Old vs New code (coeval, E-INTEGRAL, without mini-halos, spin temperature)

Because the spin temperature is higher (but not much higher compared to CMB temperature), the brightness temperature is also higher. Because the spin temperature in the new code is smoother, also the brightness temperature becomes smoother, so power in small scales (high k) is expected to be suppressed in the new code compared to the old one!

Old vs New code (coeval, CONST-ION-EFF, brightness temperature) Old vs New code (coeval, E-INTEGRAL, without mini-halos, brightness temperature)

@steven-murray steven-murray left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jordanflitter for the code and for the tests and plots. This is looking good to me, with the caveat of some comments.

Comment thread src/py21cmfast/drivers/single_field.py Outdated
Comment thread src/py21cmfast/io/caching.py
Comment thread src/py21cmfast/src/HaloBox.c
Comment thread src/py21cmfast/wrapper/inputs.py Outdated
Comment on lines +2546 to +2551
# TODO: the last warning below (that we also test), is only reachable if max_integral_mass is larger than
# the upper mass_limits, but if we have halos then the latter is max_dexm which is exactly the same as max_integral_mass.
# Thus the conclusion is that this warning is reachable only when we use L-INTEGRAL. Therefore, I am keeping the quick return
# if we don't use lagrangian_source_grid (instead of a quick return if we don't use has_discrete_halos), but I suggest to
# modify the code below to include also Eulerian source models, (and the comment above that says that "there are no problems
# if we are not using halos")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to follow this... should we not implement that in this PR then?

@jordanflitter jordanflitter Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure. I am bit confused about this function. We test that the last warning in this function is triggered in test_input_structs.py::test_halomass_ranges with SOURCE_MODEL="L-INTEGRAL", but I think it doesn't make sense because we are supposed to integrate over the entire mass-range in this source model, with no gaps. So I think this function/test should be revised, and I am not sure if it should be in this PR (because this check doesn't do anything with Eulerian source models, I just wonder if it's really relevant to L-INTEGRAL).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed check_halomass_range and test_halomass_ranges in the last commit.

Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst
Comment thread docs/Radiation_Fields.rst
Comment thread docs/Radiation_Fields.rst

.. math::

\epsilon_X(z, \delta) = \bar\rho_b(z=0) (1+\delta) \zeta_X f_* \frac{d}{dt}f_{\rm coll}(z, M_{\rm turn} ; \delta, M_{\rm cond}),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my own enrichment: this is saying that I generate X-ray photons at a rate proportional to the rate at which I form stars. I suppose this is empirically reasonable but it seems a bit strange: in my imagination if I had a galaxy that had stopped forming stars, it could still produce X-ray photons. Is there some empirical work that this assumption is based on?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely agree with everything you said ("you hit the nail on the head!", as LLMs like to say).

Up to this day, we still assume that the emissivity fields are proportional to the SFRD. This is very clear from the modeling of the X-ray emissivity, which is proportional to L_X/SFR *SFRD, where L_X/SFR is our astro parameter (bad naming!), L_X/SFR ~ 10^40 erg/sec *yr/M_sun (it actually accounts for photons up to energy 2 keV). Anyway, the v2 paper where this modeling is first introduced is https://arxiv.org/pdf/1809.08995, where it seems like they took the empiric relation from https://arxiv.org/pdf/1702.00409. But I totally agree with you, I always thought that it's weird to assume that the star-formation timescale is the relevant timescale for the calculation of the emissivity (but maybe I'm missing something...). Anyway, this is the justification for the X-ray emissivity. As for the emissivity that is used for the Lya flux, I don't know what is the justification to assume that it is proportional to the SFRD.

And note that while you reached the correct conclusion, that part you were commenting about was regarding the modeling in v1. In that paper/version, there was no reference to the SFRD in the model, but if we compare the equations with v2 (which was the first 21cmFAST paper to use the term "SFRD" in the context of modeling the emissivity), then we can see that the SFRD in v1 was proportional the derivative of the collapsed fraction.

Comment thread docs/Radiation_Fields.rst
where :math:`\bar\rho_m` is the mean matter density and :math:`dn/dM_h(z, M_h ; \delta_{\rm cond}, M_{\rm cond})` is the conditional halo
mass function in a region of size :math:`R(M_{\rm cond}) = [3M_{\rm cond}/(4\pi \bar\rho_m)]^{1/3}` and overdensity :math:`\delta_{\rm cond}`.
For the calculation of the conditional collapsed fraction, ``21cmFAST`` v1.0.0 assumed that the conditional halo mass function was given
by the Sheth-Tormen conditional mass function. Under this assumption, the conditional collapsed fraction has an analytical form,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the ST CHMF or the PS CHMF?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in theory, the conditional mass function that should have been used there is ST, but since the collapsed fraction only has analytic from with PS, then the PS mass function was used in computing the local conditional collapsed fraction. Then, as the text below explains, the ST mass function was used to normalize the collapsed fraction, such that the mean collapsed fraction in the box would match the theoretical global collapsed fraction (while assuming the ST mass function).

Comment thread docs/Radiation_Fields.rst
Comment on lines +155 to +158
While ``21cmFAST`` v1.0.0 used the analytical result for the conditional collapsed fraction from the extended Press-Schechter formalism
in order to assess the fluctuations in the emissivity fields, the code also normalized the mean collapsed fraction in the box to match
the global collapsed fraction, as given by solving the above integral numerically with the user's selected halo mass function
(which by default was the Sheth-Tormen mass function).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I think what you are saying here is that the CHMF equation here, if integrated over the PDF of delta, by construction gives the global Press-Schechter HMF. However, since the user is able to select a non-press-shechter global HMF, we still use this PS formula for the CHMF, but we apply a renormalization such that \int d delta p(delta) CHMF == Custom_HMF(sigma). Is that right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's exactly correct ("you hit the nail on the head again!")

Today btw, we don't do mean fixing if we use ST mass function and Lagrangian source models. This is clear from the following line (in scaling_relations.c):

consts->fix_mean =
        source_model_uses_eulerian_grids(matter_options_global->SOURCE_MODEL) ||
        matter_options_global->HMF == HMF_WATSON || matter_options_global->HMF == HMF_WATSON_Z ||
        matter_options_global->HMF == HMF_REED07 || matter_options_global->HMF == HMF_YUNG24;

I don't like this logic and indeed we have an open issue about it, #669.

Comment thread docs/Radiation_Fields.rst Outdated
Comment thread docs/Radiation_Fields.rst
Base automatically changed from 4D_removal to release-v4.3 August 19, 2026 12:51
This merger includes cautious resolution of conflicts. All tests passed.
Overhaul of check_halomass_range. It now matches better with the C code. It works only if we have discrete halos in the simulation, otherwise everything is fine. The warning about minimum mass was removed as it wasn't reachable. We raise a warning if the largest halo in the simulation (derived from the box size) is not very big. Also, test_halomass_ranges was modified.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

context: C backend Changes occur predominantly in the C code context: python wrapper Changes predominantly concerning the python wrapper type: accuracy Enhancement that improves accuracy type: maint: refactoring Refactoring type: maint: removal Removals and Deprecations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Filter emissivity fields in all SOURCE_MODEL options

2 participants