Skip to content

Collision between a star (sink particle) and a local section of an accretion disc#801

Merged
danieljprice merged 8 commits intodanieljprice:masterfrom
tajjankovic:inject-disk-localdisk
Feb 25, 2026
Merged

Collision between a star (sink particle) and a local section of an accretion disc#801
danieljprice merged 8 commits intodanieljprice:masterfrom
tajjankovic:inject-disk-localdisk

Conversation

@tajjankovic
Copy link
Contributor

Description:
Adds new setup targets for constructing a local section of an accretion disc and simulating star-disc collisions (as a model for QPEs). Introduces a local-disk setup generator, a star-disc collision setup wrapper (hydro and radiation-hydro variants), a first-pass injection/collision module for disc–sink interactions, and a moddump utility for adding/initialising a sink particle.

Components modified:

  • Setup (src/setup)
  • Main code (src/main)
  • Moddump utilities (src/utils/moddump)
  • Analysis utilities (src/utils/analysis)
  • Test suite (src/tests)
  • Documentation (docs/)
  • Build/CI (build/ or github actions) (setup registration in Makefile_setups)

Type of change:

  • Bug fix

  • Physics improvements

  • Better initial conditions

  • Performance improvements

  • Documentation update

  • Better testing

  • Code cleanup / refactor

  • Other (please describe)

    • Adds new setups and supporting utilities for local-disk + QPE experiment workflows

Summary of changes:

  • build/Makefile_setups:

    • Adds three new SETUP targets:

      • localdisk: constructs a local cuboid section of an accretion disc.
      • qpe_hyd: hydro QPE experiment (local disk + sink/star impact).
      • qpe_rh: radiation-hydro QPE experiment (as above with RADIATION=yes).
    • qpe_* uses SRCINJECT=inject_disk.f90, MODFILE=moddump_addsink.f90 and defines -DLIGHTCURVE.

  • src/setup/set_localdisk.f90:

    • New setup file to generate a local section of an accretion disc (cuboid of gas).
    • Supports uniform or Gaussian density profiles (with configurable sigma values).
  • src/main/inject_disk.f90:

    • New injection/collision module for disc–sink/star interaction experiments.
    • Current implementation does not inject new particles yet (injection will be implemented in a follow-up).
    • Gas–sink interactions are currently treated as elastic collisions.
  • src/utils/moddump_addsink.f90:

    • New moddump utility to add/initialise a sink particle.
    • Allows user control over sink position and velocity.

Testing:

  • Built Phantom with SETUP=localdisk, SETUP=qpe_hyd and SETUP=qpe_rh on Linux (gfortran + OpenMP).
  • Ran local test simulations for each setup to confirm setup generation and runtime without errors.
  • Verified moddump_addsink produces expected sink initialisation (position/velocity changes applied).

Did you run the bots? no (CI will run on PR)
Did you update relevant documentation in the docs directory? no
Did you add comments such that the purpose of the code is understandable? yes
Is there a unit test that could be added for this feature/bug? no

Related issues: (none)

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @tajjankovic, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly expands the simulation capabilities by introducing new setups and supporting utilities for modeling star-disc collisions, particularly relevant for Quasi-Periodic Eruptions (QPEs). It enables the generation of local accretion disk sections and the simulation of their interaction with a central star (represented as a sink particle), offering both hydrodynamic and radiation-hydrodynamic variants.

Highlights

  • New Simulation Setups: Introduced three new simulation setups: 'localdisk' for a local accretion disk section, 'qpe_hyd' for hydrodynamic star-disc collisions, and 'qpe_rh' for radiation-hydrodynamic star-disc collisions.
  • Gas-Sink Interaction Module: Added a new module ('inject_disk.f90') to manage gas-sink interactions, specifically implementing elastic collisions between gas particles and a sink particle.
  • Local Accretion Disk Generator: Developed a new setup generator ('set_localdisk.f90') for creating local accretion disk sections with configurable uniform or Gaussian density profiles.
  • Sink Particle Initialization Utility: Provided a new moddump utility ('moddump_addsink.f90') to facilitate the addition and initialization of sink particles with specified properties.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • build/Makefile_setups
    • Added 'localdisk' setup target, configuring it for a local accretion disk with periodic boundaries and no gravity.
    • Added 'qpe_hyd' setup target for hydrodynamic QPE simulations, utilizing 'inject_disk.f90' and 'moddump_addsink.f90'.
    • Added 'qpe_rh' setup target for radiation-hydrodynamic QPE simulations, similar to 'qpe_hyd' but with radiation enabled.
  • src/main/inject_disk.f90
    • Implemented the 'inject' module to handle elastic collisions between gas particles and a sink particle.
    • Included logic to calculate collision points and reflect particle velocities.
  • src/setup/set_localdisk.f90
    • Created a new setup routine to initialize a local cuboid section of an accretion disk.
    • Allowed configuration of disk dimensions, particle count, intercepted mass, and vertical density profile (uniform or Gaussian).
    • Set up simulation units based on solar radius and a fraction of the speed of light.
  • src/utils/moddump_addsink.f90
    • Introduced a moddump utility to add and initialize a sink particle into a simulation.
    • Enabled setting the sink particle's mass, radius, initial position, and velocity.
Activity
  • The author built Phantom with the new 'localdisk', 'qpe_hyd', and 'qpe_rh' setups on Linux (gfortran + OpenMP).
  • Local test simulations were run for each new setup to confirm correct generation and error-free runtime.
  • The 'moddump_addsink' utility was verified to correctly initialize sink particle positions and velocities.
  • CI will run on the pull request as bots were not run locally.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

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

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 new setups for simulating star-disc collisions, a valuable addition for modeling QPEs, with new modules for setup generation, particle injection, and dump file modification. However, a critical security concern has been identified: two potential buffer overflow vulnerabilities exist where user-supplied or state-dependent counts (number of particles and number of sink particles) are used to index arrays without verifying them against maxp and maxptmass. This could lead to memory corruption or application crashes. Additionally, the review highlights areas for improving maintainability and robustness, such as addressing code duplication in the Makefile, removing unused code, and replacing hardcoded values (especially for sink particle properties) with constants or configurable parameters.

Comment on lines 40 to 45
msink = solarm/umass ! mass of the perturber - 1Msun
!msink = 0.925 ! for Sun-like polytrope with Rsink = 0.8Rstar
z0 = 5. ! initial distance of the perturber
incl = 90./180*3.14192 ! inclination
vz0 = 1 ! 0 for core
rsink = 1 !0.8 for core
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The properties of the sink particle (msink, z0, incl, vz0, rsink) are hardcoded. This makes the utility inflexible. The PR description mentions "Allows user control over sink position and velocity", which suggests these should be configurable. Consider reading these values from a setup file, similar to how set_localdisk.f90 handles its parameters. This would greatly improve the usability of this utility.

print *,'-----Sink particle distance alog z-direction is:', z0
print *,'-----Sink particle velocity is:', vz0

nptmass = nptmass + 1
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The modify_dump subroutine increments nptmass and uses it to index the xyzmh_ptmass and vxyz_ptmass arrays without verifying if it exceeds the maximum allowed number of sink particles (maxptmass). If the limit is already reached, this will lead to an out-of-bounds memory access and potential memory corruption. It is recommended to import maxptmass from the part module and add a check before incrementing nptmass.

hfact = 1.2

!get the number of particles
npart = Nparts
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The setpart subroutine reads the number of particles (Nparts) from the setup file and assigns it to npart without checking if it exceeds the maximum allowed particles (maxp). The subsequent loop from 1 to npart indexes the xyzh and vxyzu arrays, which can lead to a buffer overflow if Nparts is greater than maxp. It is recommended to import maxp from the part module and verify that Nparts <= maxp before proceeding.

Comment on lines 215 to 236
ifeq ($(SETUP), qpe_hyd)
# hydrodynamic QPE simulation
SETUPFILE= setup_empty.f90
KNOWN_SETUP=yes
ISOTHERMAL=no
GRAVITY=no
SRCINJECT=inject_disk.f90
FPPFLAGS= -DLIGHTCURVE
MODFILE= moddump_addsink.f90
endif

ifeq ($(SETUP), qpe_rh)
# rad.-hydrodnymic QPE simulation
RADIATION=yes
SETUPFILE= setup_empty.f90
KNOWN_SETUP=yes
ISOTHERMAL=no
GRAVITY=no
SRCINJECT=inject_disk.f90
FPPFLAGS= -DLIGHTCURVE
MODFILE= moddump_addsink.f90
endif
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The qpe_hyd and qpe_rh targets are nearly identical, with the only difference being the RADIATION=yes flag in qpe_rh. This duplication can be reduced to improve maintainability. Consider using a common variable to share settings between them. For example:

ifeq ($(SETUP), qpe_hyd)
    QPE_BASE_SETTINGS = yes
endif

ifeq ($(SETUP), qpe_rh)
    QPE_BASE_SETTINGS = yes
    RADIATION         = yes
endif

ifeq ($(QPE_BASE_SETTINGS),yes)
#   (rad.-)hydrodynamic QPE simulation
    SETUPFILE= setup_empty.f90
    KNOWN_SETUP=yes
    ISOTHERMAL=no
    GRAVITY=no
    SRCINJECT=inject_disk.f90
    FPPFLAGS= -DLIGHTCURVE
    MODFILE= moddump_addsink.f90
endif

Comment on lines 82 to 88
use part, only:igas,kill_particle,shuffle_part,ihsoft
use partinject,only:add_or_update_particle
use io, only:master
use sortutils, only:indexx
use vectorutils, only:rotatevec
use physcon, only:pi,solarm,years,c
use random, only:ran2
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

There are several unused modules and variables imported in the inject_particles subroutine. For example, igas, kill_particle, shuffle_part from part, and modules like partinject, io, sortutils, vectorutils, physcon, and random are not used within the subroutine. Removing unused imports improves code clarity and reduces dependencies. The only import that seems to be used is ihsoft from the part module.

 use part,      only:ihsoft

! drift remaining time - new method
rel_r = rel_r + rel_v*(dt - thit) ! r_new
rmag = norm2(rel_r)
if (rmag < star_r) rel_r = rel_r * (star_r/rmag) * 1.00001 ! if still inside (or numerically on surface), push slightly outside
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The magic number 1.00001 is used to push particles slightly outside the star's surface. It's better to define this as a named constant to improve readability and make it easier to modify if needed.

       if (rmag < star_r) rel_r = rel_r * (star_r/rmag) * 1.00001_8 ! if still inside (or numerically on surface), push slightly outside

endif

enddo
print *,'Did bounce (properly):',nbounce,'min_d=',min_d, 'dt=',dtlast
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This print statement appears to be for debugging purposes. It should be removed from the final code to avoid cluttering the output during production runs.


! units
r_unit = solarr
v_unit = 0.1*3e10 ! 0.1*c - typical velocity in QPEs
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The speed of light c is hardcoded as 3e10. It's better to use the constant c from the physcon module for better maintainability and accuracy. You'll need to add c to the use physcon statement on line 42, like so: use physcon, only:au,solarm,pi,solarr,c.

v_unit = 0.1*c ! 0.1*c - typical velocity in QPEs

msink = solarm/umass ! mass of the perturber - 1Msun
!msink = 0.925 ! for Sun-like polytrope with Rsink = 0.8Rstar
z0 = 5. ! initial distance of the perturber
incl = 90./180*3.14192 ! inclination
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The value of pi is hardcoded as 3.14192. The physcon module, which is already in use, provides a more precise pi constant. Using the constant from physcon will improve accuracy and maintainability.

incl = 90./180*pi ! inclination

Copy link
Owner

Choose a reason for hiding this comment

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

can use the deg_to_rad constant from physcon here

@danieljprice
Copy link
Owner

thanks for the p-r @tajjankovic, most of the failures here are compiler warnings that need fixing before merge. Can check/eliminate these by compiling with NOWARN=yes

see also gemini comments, most are straightforward I think. Let me know if you need help!

@tajjankovic
Copy link
Contributor Author

@danieljprice Thanks! I think I’ve addressed all the comments (bounds checks, configurable addsink.moddump, physcon constants, removal of debug/unused code, and Makefile_setups cleanup).

Separate design question (before I go too far): I’m trying to make the star–disc collision more accurate by modelling the stellar envelope as gas while replacing the interior (e.g. r < 0.8 R*) with a single softened core/sink. Current workflow: relax a Sun-like polytrope (~1e7 particles), delete r < 0.78 R*, insert a single particle with M = M_deleted and hsoft ≈ 0.78 R*, and keep a ~1h shell near R_env with frozen properties to prevent inward migration. However, I’m not confident that the approach I’m taking in particle freezing is the best within Phantom.

Would you prefer I open a separate draft PR with the work-in-progress for discussion, or discuss the design here first and then implement?

@danieljprice
Copy link
Owner

@tajjankovic remaining test failure is a warning when compiling phantomsetup with SETUP=qpe:

../src/main/inject_disk.f90(52): error #6843: A dummy argument with an explicit INTENT(OUT) declaration is not given an explicit value.   [DTINJECT]
                              npart,npart_old,npartoftype,dtinject)
  --------------------------------------------------------^
  compilation aborted for ../src/main/inject_disk.f90 (code 1)
  make[1]: *** [Makefile:426: inject_disk.o] Error 1
  make: *** [Makefile:16: setup] Error 2
  Checking qpe (setup)... FAILED
  compiling phantom with SETUP=qpe
  ../src/main/inject_disk.f90(52): error #6843: A dummy argument with an explicit INTENT(OUT) declaration is not gi

For the putting-a-core-in-a-star question, we normally handle this automatically inside the set_star procedure -- there's an option to add a sink particle core, currently it only works with setup of MESA or Kepler stars but with a couple of lines of code could easily be made to work for a polytrope as well. The procedure there is to remap the stellar profile to a flattened profile that accounts for the softened potential from the sink particle. This profile is then written to a file and read back to construct the "new" star which will then be close to being in hydrostatic equilibrium.

Trying to freeze particles is something we've also tried but it's a tricky to maintain conservation properties. Good project for next phantom workshop in Sydney!

@danieljprice
Copy link
Owner

danieljprice commented Feb 23, 2026

also worth a look is that (for similar reasons to you, to simulate a star crashing through a disc) I added the ability to add a star made of gas to the "grdisc" setup. This uses the set_star procedure so is quite general, suggest to have a look in setup_grdisc.f90 for the relevant code...

@tajjankovic
Copy link
Contributor Author

@danieljprice I’ve pushed a small fix for the remaining CI failure: dtinject is now assigned a default value at entry to inject_particles. I can’t reproduce the warning locally with gfortran, but hopefully this should address the ifort/ifx check.

Thanks for the suggestions. Also, thanks for the Sydney workshop note! I’d completely overlooked that.

@danieljprice
Copy link
Owner

remaining CI failure is in the build of phantomtest

  F90-S-0084-Illegal use of symbol set_default_options_inject - not public entity of module (../src/tests/test_wind.f90: 149)
    0 inform,   0 warnings,   1 severes, 0 fatal for init_testwind
  make[1]: *** [Makefile:426: test_wind.o] Error 1
  make: *** [Makefile:16: phantomtest] Error 2

can be reproduced with

make SETUP=qpe phantomtest

(I think you just need a blank set_default_options_inject in your inject module).

Thanks again for the contributions!

@danieljprice danieljprice merged commit 52a0bff into danieljprice:master Feb 25, 2026
269 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants