Skip to content

Modular stellar-evolution framework for Star particles#1962

Merged
markkrumholz merged 34 commits into
developmentfrom
chong/claude/stellar-evolution-framework
Jun 24, 2026
Merged

Modular stellar-evolution framework for Star particles#1962
markkrumholz merged 34 commits into
developmentfrom
chong/claude/stellar-evolution-framework

Conversation

@chongchonghe

Copy link
Copy Markdown
Contributor

Description

Add a modular, compile-time-selectable stellar-evolution framework for Star particles, with a stateless analytic toy model as the default, plus a validation test that checks radius and luminosity against closed-form solutions and asserts the numerical Bondi accretion rate.

Motivation

Currently Quokka has no Star particle type with stellar-evolution physics. This PR adds the framework, a toy model, and a validating test problem so that more sophisticated stateful models (e.g., ORION model or tabulated stellar tracks) can be plugged in later without changing the dispatch machinery.

What changed

Framework (src/particles/stellar_models.hpp, src/particles/starparticle_radiation.hpp)

  • ToyStellarModel — stateless analytic laws: R ∝ M^0.4, L_star ∝ M^3.5, L_acc = GMṁ/R. Pure GPU device functions.
  • Model::evolve(Real *rdata, int n_groups, Real dt) — takes the full particle real-data array so the model can read and modify any component (mass, radius, luminosity groups, velocity, etc.). The dispatcher simply passes &p.rdata(0) — the model owns all field access.

Shared index header (src/particles/star_particle_indices.H — new)

  • Extracted StarParticleDataIdx enum and all index constants (StarParticleMassIdx, StarParticleMdotIdx, StarParticleRadiusIdx, StarParticleLumIdx, etc.) into a standalone header that both stellar_models.hpp and particle_types.hpp include. Avoids circular dependencies while letting models use named indices.

Star particle type (src/particles/particle_types.hpp, src/particles/PhysicsParticles.hpp)

  • New ParticleSwitch::Star and ParticleType::Star.
  • Star real-component layout: mass, vx, vy, vz, birth_time, mdot, radius, lum with lum expandable to nGroups slots. Component count is auto-composed from nGroups + the model's nExtraReal/nExtraInt.
  • Star descriptor registered with allows_accretion=true and mdotIndex_=StarParticleMdotIdx.

DefaultParticleTraits refactoring (particle_types.hpp + 15 test problems)

  • Introduced DefaultParticleTraits as a base struct holding particle_switch = None and using stellar_model = quokka::ToyStellarModel. Particle_Traits<problem_t> now inherits from it. This avoids having to touch every test problem when new particle-trait parameters are added.
  • All 15 existing Particle_Traits specializations updated to : DefaultParticleTraits.
  • Removed the standalone StellarModel_Traits — model selection now goes through Particle_Traits::stellar_model.

Simulation wiring (src/simulation.hpp, src/QuokkaSimulation.hpp, src/linear_advection/AdvectionSimulation.hpp)

  • StarParticles container member, createInitialStarParticles() pure virtual + default empty definition, Star block in InitPhyParticles.
  • Star particles are correctly loaded from checkpoint on restart (via initializeParticleContainerFromCheckpoint) matching the pattern used by all other particle types.

Validation test (src/problems/ParticleStarEvolution/)

  • Places one Star particle at the domain centre in a uniform, isothermal medium and lets it accrete via the grid Bondi module.
  • r_B is set ~10× smaller than dx so the accretion is in the sub-grid Bondi regime.
  • Validates each coarse step: R(M) and L(M,ṁ) match the toy model closed forms within 2%, accounting for the one-step lag between accretion and the stellar update.
  • Validates the mean numerical dM/dt matches the analytic Bondi rate within 10%.
  • B₀ is set to 1×10⁻¹¹ so that β ≫ 1 and the magnetised Bondi rate converges to the unmagnetised formula.

Documentation (docs/markdown/particles.md)

  • New "Star Particle Type" section covering attributes, model selection, the toy model, and the validation test.

Related issues

N/A

Checklist

Before this pull request can be reviewed, all of these tasks should be completed. Denote completed tasks with an x inside the square brackets [ ] in the Markdown source below:

  • I have added a description (see above).
  • I have added a link to any related issues (if applicable; see above).
  • I have read the Contributing Guide.
  • I have added tests for any new physics that this PR adds to the code.
  • (For quokka-astro org members) I have manually triggered the GPU tests with the magic comment /azp run.

chongchonghe and others added 22 commits June 15, 2026 16:56
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…model

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…etadata

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… descriptor

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…pdate path

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…dation problem

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lidation test

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ce DefaultParticleTraits

Replace standalone StellarModel_Traits with a stellar_model alias in
DefaultParticleTraits, inherited by all Particle_Traits specializations.
This avoids updating every problem when new particle-trait parameters
are added. All 15 existing test problems now inherit from
DefaultParticleTraits.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Shrink r_B to ~0.1*dx (M0=0.1 Msun, half_size=1.2e19) so accretion
  is in the sub-grid Bondi regime.
- Add compile-time assertion that r_B < 0.1*dx.
- Reduce B0 to 1e-11 so that beta >> 1 and cf ~ cs, making the
  numerical Bondi rate match the unmagnetized analytic formula.
- Fix the one-step lag in the luminosity check: the stellar update
  runs before accretion, so pair each recorded L[i] with the prior
  step's mdot.
- Assert that the mean numerical dM/dt matches the analytic Bondi
  rate within 10%.
- Add createInitialStarParticles to AdvectionSimulation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
StellarUpdate is only declared in starparticle_radiation.hpp (guarded by
AMREX_SPACEDIM==3). The Star ParticlePropertyUpdateTraits specialization
must be similarly guarded, otherwise 1D/2D builds fail with "StellarUpdate
has not been declared".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add mass <= 0.0 guards in radius() and luminosityStar() to prevent
  std::pow domain errors with fractional exponents.
- Update docs to reference Particle_Traits<problem_t>::stellar_model
  instead of the removed StellarModel_Traits.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the manual particle-tile creation with InitFromAsciiFile,
which is MPI-safe (only rank 0 reads the file) and avoids duplicate
particles on multi-rank runs. The position is then adjusted to the
cell centre in a post-processing pass, matching the ParticleAccretion
pattern.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
M0_in_Msun is captured in a GPU ParallelFor lambda and must be
accessible from device code.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Guard StarParticleLumIdx write with if constexpr (Nout > 0) to prevent
  out-of-bounds access when radiation is disabled.
- Zero-fill remaining luminosity groups when Nout > 1 so that uninitialised
  values aren't deposited into multigroup radiation.
- Pass -1 for lum_idx to the Star descriptor when nGroups == 0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When restarting from a checkpoint, Star particles were always
freshly created via createInitialStarParticles(), discarding the
checkpointed mass/mdot/radius/luminosity state. Match the pattern
used by all other particle types and call
initializeParticleContainerFromCheckpoint when is_restart is true.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Broaden Model::evolve() from evolve(mass, mdot, dt, radius_out, lum_out)
to evolve(mass&, mdot, radius_val&, lum*, n_groups, dt). This lets each
model decide what to read and modify:
- mass and radius are in/out (model may read current values, e.g. for
  stateful integration, or modify them, e.g. wind mass loss)
- lum is a pointer to all n_groups luminosity slots (model writes all
  groups, supporting multi-group radiation)
The dispatcher in StellarUpdate reads current mass/mdot/radius from the
particle, passes them to evolve(), and writes back any changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract StarParticleDataIdx into a standalone star_particle_indices.H
so stellar models can include the index constants without pulling in the
full particle type machinery (avoiding circular includes).

Model::evolve() now takes (Real *rdata, int n_groups, Real dt) — the
complete particle real-data array — letting each model read and modify
any component (mass, mdot, radius, lum, velocity, etc.) using the named
indices. The dispatcher in StellarUpdate simplifies to a single call:
Model::evolve(&p.rdata(0), Nout, dt).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new Star particle type to support modular, pluggable stellar-evolution models selected at compile time, along with a stateless ToyStellarModel and a validation test problem (ParticleStarEvolution). The reviewer identified a critical issue in the validation test's computeAfterTimestep function, where particle data is recorded only on the IO processor (rank 0). In a parallel MPI simulation, if the single star particle resides on a different rank, the IO processor will have empty data, causing the validation checks to fail. The reviewer provided a code suggestion to resolve this by extracting the particle properties on the owning rank and performing a global sum reduction across all ranks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/problems/ParticleStarEvolution/testParticleStarEvolution.cpp
chongchonghe and others added 2 commits June 17, 2026 15:34
Replace `const auto &real_data = ...getParticleDataAtLevel(...).first`
with structured binding `const auto [real_data, int_data] = ...` to avoid
binding a reference to a member of a temporary pair. This matches the
pattern used in BinaryOrbitCIC and is MPI-safe across all ranks.

Also iterate with range-for instead of accessing real_data[0] directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chongchonghe chongchonghe marked this pull request as ready for review June 18, 2026 06:01
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. documentation Improvements or additions to documentation labels Jun 18, 2026
chongchonghe and others added 2 commits June 19, 2026 05:25
Two fixes:

1. Add static_assert preventing both ParticleSwitch::Sink and
   ParticleSwitch::Star from being enabled simultaneously. Both
   accrete via the same accretion-rate buffer, and the current
   computeSinkAccretion / applySinkAccretion dispatch would double-
   apply gas removal. Includes a comment describing the refactoring
   needed to support multiple accreting types in the future.

2. Pass integer particle data (p.idata()) to Model::evolve() so that
   stellar models with nExtraInt > 0 (e.g. ORION) can read and update
   integer state. The toy model ignores it; the dispatcher passes
   nullptr when NInt == 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chongchonghe

chongchonghe commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

@markkrumholz Ready for review again.

Comment thread src/particles/particle_types.hpp
Comment thread src/particles/particle_update.hpp Outdated
Comment thread src/particles/particle_update.hpp Outdated

@markkrumholz markkrumholz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There's a merge conflict that needs to be resolved, but on top of that, I'm confused by the design of passing an array of gpu_constants data to the evolve routine. Why do that? Why not just have the evolve routine implemented by each star particle class have access to the internal class members, some of which can be data tables that live on GPU? Since these tables are presumably read once during startup and then stored and not altered, I don't see the reason to pass them around rather than just have them be class members that are set on initialization.

@markkrumholz

Copy link
Copy Markdown
Collaborator

@chongchonghe, comments added.

chongchonghe and others added 8 commits June 23, 2026 02:29
…ultPhysicsTraits

Address Mark's review comments:

1. Add StarParticleIntIdx enum (stage) and StarParticleIntegerComps alias,
   wire expandEnumNames into getParticleIntCompNames for Star particles.
   When nExtraInt > 0 (ORION model), names expand as stage_0, stage_1, ...

2. Remove gpu_tables from the Star stellar-evolution update path.
   Stellar models own their internal tables. The updateParticleProperties
   specialization now inlines its own loop instead of calling applyUpdate
   with a dummy LuminosityGpuConstTables.

3. Inherit Physics_Traits<StarEvolutionProblem> from DefaultPhysicsTraits
   to pick up the resistity_model default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove gpu_tables parameter from the entire update chain:
- applyUpdate() no longer takes gpu_tables
- updateProperties() no longer takes gpu_tables
- updateLuminosity() no longer takes gpu_tables — it reads
  g_device_luminosity_tables<Nout> directly (AMREX_GPU_MANAGED)

StochasticStellarPop::updateParticleProperties loads tables into the
global before calling applyUpdate. Star::updateProperties inherits
updateParticleProperties from the base class (no custom loop needed).

All particle types now share the same applyUpdate signature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, Particle_Traits<SubcycleProblem> has no stellar_model
typedef, causing StarParticleRealComps<SubcycleProblem> to fail on CUDA
when std::unique_ptr<StarParticleContainer<SubcycleProblem>> requires
the complete type (AMRSimulation member for all problem types).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chongchonghe

Copy link
Copy Markdown
Contributor Author

/azp run quick
/azp run rocm-quick

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@chongchonghe

Copy link
Copy Markdown
Contributor Author

/azp run quick

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@chongchonghe

Copy link
Copy Markdown
Contributor Author

@markkrumholz All comments addressed. Ready for review.

@chongchonghe

Copy link
Copy Markdown
Contributor Author

/azp run rocm-quick

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jun 24, 2026
@markkrumholz markkrumholz added this pull request to the merge queue Jun 24, 2026
Merged via the queue into development with commit f4323d0 Jun 24, 2026
61 of 62 checks passed
@chongchonghe chongchonghe deleted the chong/claude/stellar-evolution-framework branch June 27, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request lgtm This PR has been approved by a maintainer particles size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants