Skip to content

Modifications related to the mass swapping fixes and other minor changes#25

Open
angel-chandro wants to merge 15 commits intoICRAR:develfrom
angel-chandro:devel
Open

Modifications related to the mass swapping fixes and other minor changes#25
angel-chandro wants to merge 15 commits intoICRAR:develfrom
angel-chandro:devel

Conversation

@angel-chandro
Copy link
Contributor

@angel-chandro angel-chandro commented Feb 24, 2026

  • Minor changes to the mass swapping fixes when calculating galaxy properties

  • Mass swapping modifications applied to properties of type 2 galaxies

  • Corrections when assigning the spin parameter (with mass swapping fixes or without them)

  • Redefine host halo when we select the central subhalos, since the subhalo_type is being changed, but the host halo ID is not. This is leading to type 0 galaxies associated with satellite subhalos and type 1 galaxies associated with central subhalos when looking at the output variables id_halo_tree and id_subhalo_tree.

  • Additional minor changes: including cases where the final snapshot is different to z=0, removing unused parts and other bits

  • Include a conditional if statement when m_in<0 due to precision errors

  • Remove the Python script that generated the SFR-Mstars plane.

Summary by Sourcery

Adjust dark matter mass-swapping handling and related galaxy/subhalo property propagation across tree building, halo evolution, and physical modules.

Bug Fixes:

  • Correct host halo identification and property propagation when redefining central subhalos, ensuring consistency between halo and subhalo IDs and concentrations.
  • Fix spin parameter (lambda) assignment for centrals and satellites, including infall properties and interpolation cases, to avoid inconsistent or recomputed values.
  • Ensure type 2 galaxy structural properties (mass, concentration, virial velocity, spin) are derived from appropriate infall or current subhalo properties depending on mass-swapping configuration.
  • Use the correct maximum-snapshot redshift instead of assuming z=0 when computing merger timescales near the final snapshot.
  • Avoid negative ionised gas mass due to precision errors when computing the ionised gas fraction in star formation.
  • Fix central/satellite cooling and dynamical time calculations so virial quantities come from the correct (host or infall) halo under mass-swapping corrections.

Enhancements:

  • Simplify central and satellite property computation by removing unused mass-swapping helper functions and relying on central-subhalo definition logic.
  • Clarify and slightly adjust option parsing for transient definition modes and tidy comments and logging messages.
  • Propagate dark matter halo parameters into galaxy transfer routines to make behavior conditional on mass-swapping settings.

Documentation:

  • Improve in-code comments and field descriptions for subhalo metadata to better document snapshot semantics and interpolation flags.

Chores:

  • Remove an obsolete Python script for generating the SFR–M* plane from the repository.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 24, 2026

Reviewer's Guide

This PR refines how halo and subhalo properties are defined under the mass-swapping fix, propagates those properties consistently to galaxies (especially type 2), corrects spin/virial-velocity usage in several physics modules, tightens transient/edge-case handling, and removes obsolete code and a Python helper script.

Sequence diagram for transferring galaxies between snapshots with mass-swapping fix

sequenceDiagram
    participant SharkRunner_impl as SharkRunner_impl
    participant Evolve as transfer_galaxies_to_next_snapshot
    participant Subhalo as Subhalo
    participant Galaxy as Galaxy

    SharkRunner_impl->>Evolve: transfer_galaxies_to_next_snapshot(all_halos_this_snapshot, snapshot, all_baryons, dark_matter_params)

    loop for each halo and subhalo
        Evolve->>Subhalo: check_subhalo_galaxy_composition()
        Evolve->>Evolve: adjust_main_galaxy(parent_subhalo, descendant_subhalo, dark_matter_params)
        activate Evolve
        alt main_galaxy is type2
            alt dark_matter_params.apply_fix_to_mass_swapping_events == true
                Evolve->>Galaxy: set type2 props from parent_subhalo.concentration_infall, Mvir_infall, lambda_infall, Vvir_infall
            else dark_matter_params.apply_fix_to_mass_swapping_events == false
                Evolve->>Galaxy: set type2 props from parent_subhalo.concentration, Mvir, lambda, Vvir
            end
        end
        Evolve-->>Subhalo: transfer_galaxies_to(descendant_subhalo)
        deactivate Evolve
    end

    Evolve-->>SharkRunner_impl: done for snapshot
Loading

Updated class diagram for halo, subhalo, and galaxy mass-swapping properties

classDiagram
    class DarkMatterHaloParameters {
        bool apply_fix_to_mass_swapping_events
        bool use_converged_lambda_catalog
        double min_part_convergence
    }

    class DarkMatterHalos {
        halo_virial_velocity(m, z)
        halo_virial_radius(m, z)
        nfw_concentration(m, z)
        halo_lambda(subhalo, m, z, npart)
    }

    class Halo {
        int id
        double Mvir
        double Vvir
        double concentration
        double lambda
        int snapshot
        Subhalo* central_subhalo
        vector~SubhaloPtr~ satellite_subhalos
    }

    class Subhalo {
        int id
        int snapshot
        int descendant_snapshot
        int last_snapshot_identified
        bool has_descendant
        bool has_mainprogenitor
        bool main_progenitor
        bool IsInterpolated
        bool transient_candidate
        subhalo_type_t subhalo_type
        double Mvir
        double Mvir_infall
        double Vvir
        double Vvir_infall
        double rvir_infall
        double concentration
        double concentration_infall
        double lambda
        double lambda_infall
        Vector3 L
        Vector3 L_infall
        Halo* host_halo
    }

    class Galaxy {
        galaxy_type_t galaxy_type
        double concentration_type2
        double msubhalo_type2
        double lambda_type2
        double vvir_type2
        double r_rps
        struct bulge_gas
    }

    class TreeBuilder {
        define_central_subhalos(trees, sim_params, dark_matter_params, darkmatterhalos)
        define_central_subhalo(halo, subhalo, sim_params, dark_matter_params, darkmatterhalos, final_snap)
        define_ages_halos(trees, sim_params, darkmatterhalos)
        spin_interpolated_halos(trees, sim_params)
        remove_satellite(halo, subhalo)
    }

    DarkMatterHaloParameters <-- TreeBuilder : uses
    DarkMatterHalos <-- TreeBuilder : uses

    Halo "1" o-- "many" Subhalo : all_subhalos
    Halo "1" o-- "1" Subhalo : central_subhalo
    Subhalo --> Halo : host_halo

    Subhalo "1" --> "many" Galaxy : hosts_galaxies

    DarkMatterHaloParameters <-- DarkMatterHalos : params

    class GalaxyMergers {
        merging_timescale(galaxy, primary, secondary, simparams, cosmology, dark_matter_params)
    }

    DarkMatterHaloParameters <-- GalaxyMergers : uses

    class EvolveHalos {
        transfer_galaxies_to_next_snapshot(halos, snapshot, AllBaryons, dark_matter_params)
        adjust_main_galaxy(parent, descendant, dark_matter_params)
    }

    DarkMatterHaloParameters <-- EvolveHalos : uses

    class GasCooling {
        cooling_rate(subhalo, galaxy, z, delta_t, dark_matter_params)
    }

    DarkMatterHaloParameters <-- GasCooling : uses

    class DarkMatterHalos_subhalo_time {
        subhalo_dynamical_time(subhalo, z)
    }

    DarkMatterHaloParameters <-- DarkMatterHalos_subhalo_time : uses
    Subhalo <-- DarkMatterHalos_subhalo_time : input

    Subhalo <-- DarkMatterHalos : halo_lambda_input
    Subhalo <-- TreeBuilder : define_central_subhalo
    Halo <-- TreeBuilder : define_central_subhalo
    Subhalo <-- TreeBuilder : define_ages_halos
    Galaxy <-- GalaxyMergers : merging_timescale_updates
    Galaxy <-- EvolveHalos : adjust_main_galaxy_updates
    Subhalo <-- GasCooling : cooling_rate_uses
    Galaxy <-- GasCooling : cooling_rate_uses
Loading

Flow diagram for GasCooling::cooling_rate virial velocity and hot gas fraction selection

flowchart TD
    A[Start cooling_rate] --> B[Compute base vvir = subhalo.Vvir]
    B --> C[Compute base fhot = mhot / subhalo.Mvir]

    C --> D{subhalo.subhalo_type == CENTRAL && apply_fix_to_mass_swapping_events?}
    D -- Yes --> E[Set vvir = subhalo.host_halo.Vvir]
    E --> F[Set fhot = mhot / subhalo.host_halo.Mvir]
    D -- No --> G[Keep base vvir and fhot]

    E --> H
    G --> H{subhalo.subhalo_type == SATELLITE && subhalo.Vvir_infall != 0 && apply_fix_to_mass_swapping_events?}

    H -- Yes --> I[Set vvir = subhalo.Vvir_infall]
    I --> J[Set fhot = mhot / subhalo.Mvir_infall]

    H -- No --> K[Use current vvir and fhot]

    J --> L[Continue with cooling radius and rate calculations]
    K --> L[Continue with cooling radius and rate calculations]
    L --> M[End cooling_rate]
Loading

File-Level Changes

Change Details Files
Refine definition of central subhalos and host halos so halo properties and IDs stay consistent with their central subhalos and with the mass-swapping fix.
  • Extend define_central_subhalo to take a final_snap flag and only recompute the spin parameter lambda at the final snapshot or when using converged lambda catalogues for sufficiently resolved subhalos
  • When applying the mass-swapping fix, recompute central-subhalo concentration and virial velocity from the host halo mass, and propagate spin and Vvir back to the host halo
  • Ensure halo->id is updated to match the central subhalo id and that halo->lambda, Vvir, and concentration are consistent with the central subhalo
  • Adjust logging text when defining central subhalos and host halo properties
  • Remove now-redundant functions that recomputed central and satellite subhalo properties after tree building
src/tree_builder.cpp
include/tree_builder.h
Use the correct host-halo or infall properties when propagating subhalo information to galaxies, especially for type 2 galaxies and under mass-swapping corrections.
  • Change adjust_main_galaxy so that type 2 satellite properties come from infall quantities (concentration_infall, Mvir_infall, lambda_infall, Vvir_infall) when the mass-swapping fix is active, otherwise keep using instantaneous subhalo values
  • Thread DarkMatterHaloParameters into transfer_galaxies_to_next_snapshot and pass it down to adjust_main_galaxy
  • In galaxy mergers, set the type 2 structural properties for merger remnants from secondary infall quantities when the mass-swapping fix is active, otherwise from current subhalo properties
src/evolve_halos.cpp
include/evolve_halos.h
src/shark_runner.cpp
src/galaxy_mergers.cpp
Align use of spin, concentration, virial velocity and angular-momentum-related quantities with the corrected host/infall definitions across cooling, dynamics, and infall-property assignment.
  • In GasCooling::cooling_rate, compute the specific angular momentum from the current subhalo L for central subhalos and the host halo mass when mass-swapping is enabled
  • In GasCooling::cooling_rate, for centrals under mass swapping use host-halo Vvir and mass when computing vvir and fhot, and keep using infall Vvir and mass for satellites when available
  • In DarkMatterHalos::subhalo_dynamical_time, for centrals under mass swapping, base the dynamical time on the host halo virial radius and Vvir instead of subhalo Vvir
  • Clarify halo_lambda semantics: spin is always defined from the subhalo; for satellites under mass swapping, use L_infall instead of L
  • When defining infall properties in define_ages_halos, reuse host_halo concentration, lambda, and Vvir rather than recomputing them; also ensure concentration propagation for interpolated subhalos uses main_progenitor->host_halo->concentration
src/gas_cooling.cpp
src/dark_matter_halos.cpp
src/tree_builder.cpp
Fix redshift handling and commentary around snapshots and merging/starburst timescales, including non–z=0 final snapshots.
  • When computing the next-step redshift in merging_timescale and merging_galaxies, use simparams.redshifts[simparams.max_snapshot] instead of hard-coding z2 = 0 when the next snapshot exceeds max_snapshot
  • Clarify comments in several places about how Vvir is interpreted (subhalo vs host halo under mass-swapping corrections)
  • Tighten transient-definition option parsing by making the "const_10minpart" branch explicitly an else-if
src/galaxy_mergers.cpp
src/disk_instability.cpp
src/execution.cpp
Improve robustness and documentation of subhalo and star-formation internals, and remove dead/obsolete code and scripts.
  • Guard against small negative m_in values in StarFormation::ionised_gas_fraction by clamping m_in to zero, preventing negative ionised fractions due to precision errors
  • Minor comment and formatting fixes in Subhalo class documentation (e.g. descendant_snapshot, last_snapshot_identified, IsInterpolated)
  • Remove commented-out halo Vvir/concentration precomputation in SURFSReader::read_halos
  • Delete the unused Python script that generated the SFR–Mstars plane
src/star_formation.cpp
include/subhalo.h
src/merger_tree_reader.cpp
(Python SFR–Mstars script file removed)

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

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

  • In DarkMatterHalos::subhalo_dynamical_time, r and v are no longer initialised for the default (no mass-swapping) case, so if neither of the apply_fix_to_mass_swapping_events branches trigger, r and v stay at 0 and will lead to invalid dynamics; consider restoring a default assignment (e.g. using subhalo.Mvir and subhalo.Vvir) before the conditional branches.
  • adjust_main_galaxy and transfer_galaxies_to_next_snapshot now take DarkMatterHaloParameters by value, which causes an unnecessary copy each call; consider passing it as a const reference instead unless mutation is required.
  • In TreeBuilder::define_central_subhalo, when apply_fix_to_mass_swapping_events is true you use the host halo mass (mvir = halo->Mvir) to recompute lambda but still compute npart from the subhalo mass; if npart is meant to represent the particle count of the mass used for lambda, it might be more consistent to derive it from mvir rather than subhalo->Mvir.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In DarkMatterHalos::subhalo_dynamical_time, r and v are no longer initialised for the default (no mass-swapping) case, so if neither of the apply_fix_to_mass_swapping_events branches trigger, r and v stay at 0 and will lead to invalid dynamics; consider restoring a default assignment (e.g. using subhalo.Mvir and subhalo.Vvir) before the conditional branches.
- adjust_main_galaxy and transfer_galaxies_to_next_snapshot now take DarkMatterHaloParameters by value, which causes an unnecessary copy each call; consider passing it as a const reference instead unless mutation is required.
- In TreeBuilder::define_central_subhalo, when apply_fix_to_mass_swapping_events is true you use the host halo mass (mvir = halo->Mvir) to recompute lambda but still compute npart from the subhalo mass; if npart is meant to represent the particle count of the mass used for lambda, it might be more consistent to derive it from mvir rather than subhalo->Mvir.

## Individual Comments

### Comment 1
<location path="src/dark_matter_halos.cpp" line_range="147-152" />
<code_context>
 	double r = 0;
 	double v = 0;

-	r = halo_virial_radius(subhalo.Mvir, z);;
-	v = subhalo.Vvir;
-
 	if(subhalo.subhalo_type == Subhalo::CENTRAL &&
 	               params.apply_fix_to_mass_swapping_events){
 	        r = halo_virial_radius(subhalo.host_halo->Mvir, z);
-		v = subhalo.Vvir;
+		v = subhalo.host_halo->Vvir;
 	}
 	else if(subhalo.subhalo_type == Subhalo::SATELLITE && subhalo.rvir_infall != 0 &&
 	               params.apply_fix_to_mass_swapping_events){
</code_context>
<issue_to_address>
**issue (bug_risk):** r and v can remain unset when mass-swapping fix is disabled, leading to invalid dynamical times

With the generic `r`/`v` initialisation removed, when `params.apply_fix_to_mass_swapping_events` is false neither branch runs and both remain `0`. This changes behaviour from the previous version and can produce `tdyn = 0/0` or `0`, which is likely a bug. Please reintroduce the default initialisation (e.g. `r = halo_virial_radius(subhalo.Mvir, z); v = subhalo.Vvir;`) before the conditional and override it only when the fix is applied.
</issue_to_address>

### Comment 2
<location path="src/evolve_halos.cpp" line_range="36-37" />
<code_context>
 namespace shark {

-void adjust_main_galaxy(const SubhaloPtr &parent, const SubhaloPtr &descendant)
+void adjust_main_galaxy(const SubhaloPtr &parent, const SubhaloPtr &descendant,
+		DarkMatterHaloParameters dark_matter_params)
 {
 	// A subhalo that is not main progenitor of its descendant cannot
</code_context>
<issue_to_address>
**suggestion (performance):** Pass DarkMatterHaloParameters by const reference instead of by value

Here and in `transfer_galaxies_to_next_snapshot`, `DarkMatterHaloParameters` is copied on each call. Since it’s configuration and not modified, please pass it as `const DarkMatterHaloParameters&` to avoid unnecessary copies and match the usual calling convention in this codebase.
</issue_to_address>

### Comment 3
<location path="include/evolve_halos.h" line_range="50" />
<code_context>
  * @param AllBaryons The TotalBaryon accummulation object
  */
-void transfer_galaxies_to_next_snapshot(const std::vector<HaloPtr> &halos, int snapshot, TotalBaryon &AllBaryons);
+void transfer_galaxies_to_next_snapshot(const std::vector<HaloPtr> &halos, int snapshot, TotalBaryon &AllBaryons, DarkMatterHaloParameters dark_matter_params);

 void track_total_baryons(Cosmology &cosmology, ExecutionParameters execparams, SimulationParameters simulation_params, const std::vector<HaloPtr> &halos,
</code_context>
<issue_to_address>
**suggestion:** Align declaration with recommended const-reference signature for DarkMatterHaloParameters

To stay consistent with the implementation, this parameter should be `const DarkMatterHaloParameters &dark_matter_params` instead of pass-by-value, avoiding an extra copy per snapshot and making the non-mutating intent explicit.

```suggestion
void transfer_galaxies_to_next_snapshot(const std::vector<HaloPtr> &halos, int snapshot, TotalBaryon &AllBaryons, const DarkMatterHaloParameters &dark_matter_params);
```
</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.

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