Skip to content

phantom interface - #197

Merged
cpinte merged 8 commits into
mainfrom
phantom_interface
Nov 3, 2026
Merged

cpinte merged 8 commits into
mainfrom
phantom_interface

Conversation

@cpinte

@cpinte cpinte commented Nov 2, 2026

Copy link
Copy Markdown
Owner
  • mcfost2phantom: packets carry energy again, arrays allocated once for phantom's maxima
  • mcfost2phantom: stellar parameters from the sinks at each call, ghost particle temperatures
  • Voronoi star neighbours and star fields initialised (wrong temperatures with phantom sinks)
  • Phantom readers: several dumps with sinks, HDF5 sink properties, random gap, dust mass
  • Remove the unused C++ interface and CMakeLists.txt
  • Hydro readers: Gadget-2 stars and gas masses, new stars in FARGO3D/Athena++, secondary fixes
  • phantom interface: review fixes, shared star reallocation
  • Remove internal review references from comments

Type of PR:
Bug fix / / modification to existing code

Description:
Fixes to the Phantom interface (live coupling through the library and dump reading) and consistency fixes across the hydro readers.

Live coupling (mcfost2phantom)

  • Packets carry energy again in library mode (E_paquet was 0, so no heating).
  • Arrays allocated once: init_mcfost_phantom takes an optional max_particles (phantom's maxp); the stellar arrays are sized from xyzmh_ptmass. Without max_particles, ×8 headroom with APR as before. A call exceeding the allocation now stops with a clear error instead of writing out of bounds.
  • Stellar parameters from phantom's sinks (Teff, Reff, luminosity) updated at each call; sinks with a luminosity only use the isochrones.
  • Correct temperatures returned for ghost (coincident) particles; packet counters reset and random streams freed at each call.

Voronoi and stars

  • Voronoi star-neighbour flags initialised (in Voronoi.f90 and voro++_wrapper.cpp): uninitialised cells sent packets into stars, giving wrong temperatures with sinks.
  • Default values for every field of star_type: undefined fUV/slope_UV gave infinite stellar energies.
  • Star reallocation shared by all hydro readers (resize_stars).

Hydro readers

  • Several phantom dumps with sinks (-phantom-avg, -add, -multi), binary and HDF5; sink Teff, Reff and luminosity read from HDF5 dumps.
  • -random_gap and -random_outside_gap were swapped.
  • Variable dust: the total dust mass given by the caller is applied.
  • Gadget-2 binary: stars, gas masses from the MASS block, parameter-file stars kept when the file has none.
  • FARGO3D, Athena++: new stars indexed from n_stars_old + 1.
  • PLUTO, FARGO3D: record length from inquire(iolength) (wrong with ifort, overflow above about 2.7e8 cells).
  • SPH grain-size interpolation: bracketing and several dust populations; -vphi_kep central mass and per-particle gas temperature; spherical-grid reads checked.

Housekeeping and tests

  • Removed the unused C++ interface (mcfost2hydro.cpp, interface_template.cpp) and CMakeLists.txt.
  • Unit tests test_mcfost2phantom (variable particle number, sinks, overflow, dust mass) and test_randomize_gap; integration tests test_phantom_avg and test_gadget2_binary.

Behaviour changes

  • -random_gap / -random_outside_gap now act as documented.
  • With variable dust, the dust mass follows the caller rather than the parameter file.
  • Phantom should pass max_particles = maxp to init_mcfost_phantom (companion change in phantom).

… phantom's maxima

- run_thermal_mc: E_paquet = 1 at the start of each temperature calculation.
  The library path never set it since run_thermal_mc replaced its own photon
  loop (58c531c, v4.1.14): every packet carried no energy and
  run_mcfost_phantom returned the 1 K floor for every particle

- Arrays sized by the cells and stars allocated once, on the first call, for
  the maximum number of particles (new optional argument max_particles of
  init_mcfost_phantom, phantom's maxp) and of sinks (size of xyzmh_ptmass,
  phantom's maxptmass): later calls with more particles or new sinks wrote
  out of bounds. Stellar arrays allocated for the maximum number of sinks
  (alloc_dynamique and allocate_stellar_spectra: optional n_stars_max).
  Without max_particles, the first call's number is used and a call exceeding
  it stops with an error

- Number of packets per cell (n_packets) reset at each call, instead of
  accumulating over the calls

- Random number streams freed at the end of each call

- Unit test test_mcfost2phantom: library initialised once, then three calls
  with 5000, 8000 and 3000 particles and a new sink; overflow case without
  max_particles. Unit tests run from test_suite/; .para files allowed in
  test_suite/unit
… particle temperatures

- Stellar parameters given by phantom's sinks (Teff, luminosity): per-read
  flag lstar_from_phantom instead of setting the user option lfix_star, which
  stayed on for the next calls (new sinks dropped, Teff no longer updated)

- Ghost particles (on top of another one): temperature and number of packets
  written at the phantom index of the ghost, not at its mcfost index (other
  particles were overwritten, ghosts kept -1)

- test_duplicate_particles: a ghost is not the main particle of other ghosts
  (chains of 3+ coincident particles lost mass and temperatures)

- n_packets = 0 for the particles not kept by mcfost

- test_mcfost2phantom: Teff from phantom then isochrones, new sink, accreted
  particles, pair and triplet of coincident particles
…es with phantom sinks)

- Star neighbour flags of the Voronoi cells initialised to false (per-thread
  array in Voronoi.f90, each cell in voro++_wrapper.cpp): uninitialised cells
  were flagged at random (1000-2900 per star instead of 26-41) and packets
  crossing them were sent into a star

- Default values for all the fields of star_type: the hydro readers
  reallocate star at each dump and set only some of them; with Teff and
  radius from phantom's sinks, fUV and slope_UV were undefined (stellar
  energy up to 3e32 or Inf, all particles at 1 K in some runs)

- test_mcfost2phantom: planet sink with its 0.1 au accretion radius as
  stellar radius
…om gap, dust mass

- Several dumps (-phantom-avg, -add, -multi), binary and HDF5 readers: sinks
  counted in the header pass and allocated once (stopped with an allocation
  error), accumulated over the files, first file only with -phantom-avg;
  particle types not shifted for the next files (particles of file 2+ were
  dropped); dustfrac (real8) and apr_level for the particles of the file;
  npartoftype per file; modify_dump with the total number of particles

- HDF5 reader: sink arrays zeroed, lum, Teff and Reff read when present
  (stellar parameters from phantom were ignored), through a contiguous array

- -random_gap and -random_outside_gap were swapped

- Variable dust: total dust mass given by the caller applied (dust mass of
  phantom dumps with dust species followed the parameter file)

- Dust moments: no dust mass added for the star cells

- Tests: test_randomize_gap, test_mcfost2phantom dust mode, test_phantom_avg
- mcfost2hydro.cpp, interface_template.cpp: never built or used, and could
  not link: they declared the library routines as init_mcfost_phantom_ etc.,
  while they are Fortran module procedures with compiler-dependent names and
  optional and assumed-shape arguments (a C interface would need bind(C)
  wrappers)

- CMakeLists.txt: truncated and never used, the Makefile is the build system
…hena++, secondary fixes

- Gadget-2 binary: global n_stars updated (shadowed by a local), stars are
  the non-gas particles with individual masses (the gas was counted as
  stars), gas masses from the MASS block when not in the header (gas mass
  was 0), star positions and masses at the right offsets

- FARGO3D, Athena++: defaults for new stars from n_stars_old+1 (reset the
  last existing star, or wrote star(0)); Athena++ planet vz = 0 (was 1)

- -vphi_kep: central mass from the existing sinks (read a 2nd sink with one),
  in Msun with the phantom mass unit; atomic gas temperature for each particle
  (was computed once with stale indices)

- Grain size interpolation: bracketing loop, factor clamped to [0,1]
  (could extrapolate to negative densities)

- Spherical grid reader: status of each read checked

- PLUTO, FARGO3D: record length from inquire(iolength), 8-byte integer
  (assumed bytes, wrong with ifort; overflow above ~2.7e8 cells)

- Test test_gadget2_binary (synthetic Gadget-2 file)
- library: without max_particles, keep phantom's x8 headroom with APR;
  error if more sinks than allocated; allocation kept across calls to
  init_mcfost_phantom

- SPH2mcfost: reset the grain-size bin index between dust populations

- Gadget binary reader: keep the parameter-file stars without stars in the
  file, preserve T, radius and spectrum (as the HDF5 reader)

- resize_stars (parameters) replaces the star reallocation of the phantom,
  athena++, fargo3d, Gadget and density readers

- clarify the message for sinks with luminosity only (isochrones are used)
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Code Review by Gemini

Code Review Summary

This PR provides a thorough, well-engineered set of fixes for the live coupling interface (mcfost2phantom), the hydro readers (Phantom, Gadget-2, FARGO3D, PLUTO, Athena++), and Voronoi tessellation logic.


Key Improvements & Physical/Numerical Validity

  1. Packet Energy Allocation in Library Mode (src/dust_transfer.f90):
    Setting E_paquet = 1.0_dp in run_thermal_mc fixes a critical bug where photon packets carried 0 energy when MCFOST was invoked as a library, resulting in zero radiative heating.

  2. Memory Bounds & Single Allocation (src/mcfost2phantom.f90, src/mem.f90):
    Pre-allocating cell and sink arrays for max_particles and max_sinks prevents repetitive allocation/deallocation on live hydro steps and stops with a clear error if limits are exceeded, preventing buffer overflows.

  3. Voronoi Star-Neighbour Initialization (src/Voronoi.f90, src/voro++_wrapper.cpp):
    Explicitly initializing star_neighb_tmp = .false. inside the OpenMP thread loop fixes an uninitialized memory issue where non-boundary cells were randomly flagged as star neighbours, producing incorrect gas/dust temperatures near sink particles.

  4. Swap Fix for Gap Randomization (src/mess_up_SPH.f90):
    Corrected the boolean inversion logic in randomize_gap, ensuring -random_gap rotates particles inside the gap while -random_outside_gap rotates particles outside, matching intended behavior.

  5. Multi-File Phantom Dust & Sink Handling (src/read_phantom.f90):

    • dustfrac reading in binary dumps was corrected to offset by np0, fixing corrupted multi-file particle reads.
    • Sink particle count logic properly handles -phantom-avg vs multi-file additions without duplicating stellar sources.
  6. I/O Record Length Overflow (src/read_fargo3d.f90, src/read_pluto.f90):
    Using inquire(iolength=...) and 64-bit integer calculations for unformatted direct I/O record lengths prevents integer overflow for large hydro grids ($> 2.7 \times 10^8$ cells) and ensures cross-compiler compatibility between gfortran (bytes) and ifort (4-byte words).


Minor Technical Notes & Recommendations

  1. Loop Bounding in Grain Size Interpolation (src/SPH2mcfost.f90):

    if (r_grain(k) < a_sph(l)) l = 1
    do while ((r_grain(k) > a_sph(l+1)) .and. (l < ndusttypes))
       l = l+1
    enddo

    Note: Bounding l < ndusttypes ensures a_sph(l+1) accesses indices up to ndusttypes + 1, which is within the bounds of a_sph(1:ndusttypes+1). The interpolation factor f is explicitly clamped to [0, 1], preventing extrapolated/negative dust densities.

  2. Ghost Particle Mapping (src/mcfost2phantom.f90):
    set_ghost_particle_temperature correctly uses particle_id(i) and is_ghost(i) to map temperature and packet counters back to the original Phantom particle array indices, preserving physical consistency for merged SPH sites.


Conclusion

The PR is high quality, addresses key edge cases in numerical stability and parallel execution, and is backed by unit tests (test_mcfost2phantom, test_randomize_gap).

Status: Ready to merge.

@cpinte
cpinte merged commit c4daec4 into main Nov 3, 2026
22 checks passed
@cpinte
cpinte deleted the phantom_interface branch November 3, 2026 01:02
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