WaveDM.jl: An Adaptable Simulation Framework for Dynamics of Baryonic and Wave Dark Matter on Galaxy Scales
👋 First time here? Open the Quickstart — it walks you through picking a model and running Crater II in under 10 minutes.
WaveDM.jl is an open-source Julia package for high-performance simulations of wave (fuzzy) dark matter dynamics at galaxy scales. The code solves the time-dependent Schrödinger–Poisson equation (SPE) with a second-order pseudo-spectral split-step Fourier method. Its design philosophy centers on adaptability — making galaxy-scale simulations accessible to a broad range of astrophysicists — and extensibility, so the codebase can grow as a community-oriented project within the Julia ecosystem.
| Built-in preset | model = … keyword |
What you get |
|---|---|---|
| Crater II, Draco, Fornax, … | :dwarf_UFDs |
Ultra-faint dwarf halos (table via list_galaxies()) |
| Generic dwarf, NFW / gNFW / Zhao | :dwarf, :dwarf_NFW, :dwarf_Zhao |
Customisable dwarf halos |
| Milky Way (Zhu 2023 mass model) | :MW |
Realistic host potential, with or without live baryons |
| Early-type galaxy | :Elliptical |
gNFW halo + Jaffe stellar profile |
| Galaxy cluster | :cluster_NFW, :cluster_Burkert |
NFW or Burkert halo + β-model ICM |
| Custom Schrödinger problem | any model + IC_vel, V |
NLO, BEC, optical lattices (see Examples §6 of code paper) |
Beginner-friendly introspectors:
using WaveDM
WaveDM.print_catalog() # full model × baryon_mode × galaxy table
WaveDM.list_supported_models() # programmatic access
WaveDM.list_galaxies() # every UFD with L, b, rho0 (Hayashi 2023)
# Per-catalog accessors and 1-based-id helpers:
WaveDM.list_MW_satellites() # Battaglia 2022 MW satellites
WaveDM.list_SPARC_LTGs() # SPARC late-type galaxies
WaveDM.list_cooke_dwarfs() # Cooke 2022 massive-dwarf names
WaveDM.ufd_index(df, Galaxy_id) # → row index (uniform error message)- Coupled wave + N-body evolution of wave dark matter halos and baryonic components (mesh / static / dynamic particles) on the same grid.
- Time-dependent tidal fields from the Milky Way and external perturbers such as the LMC, with backward-in-time satellite trajectories.
-
Multi-level parallel execution: shared-memory multi-threading, distributed-memory (Julia
Distributed.jl), and GPU acceleration (CUDA.jl) — the same script runs on CPU, multi-threaded, and GPU configurations; distributed workers accelerate IC generation and N-body work, while the full SPE loop runs on one process in this release. - Galaxy-simulation toolbox: gNFW / NFW / Zhao initial-condition generators, Milky-Way mass model (Zhu 2023), MW satellite trajectory lookback (Battaglia 2022), MW/LMC tidal fields, virial and QSS diagnostics, real-time visualization.
-
Cross-disciplinary GNLSE interface — astrophysics, nonlinear optics and cold-atom physics share the same solver through a pluggable potential
$V(\mathbf r, t, \psi)$ .
-
Install Julia ≥ 1.12 from julialang.org.
-
Open Julia, press
]for package mode, then runpkg> add https://github.com/JuliaAstroSim/WaveDM.jl # pkg> add WaveDM # This will be supported soon
-
(Optional) GPU acceleration requires an NVIDIA GPU, the CUDA toolkit, and the
CUDA.jlJulia package.
For development:
git clone https://github.com/JuliaAstroSim/WaveDM.jl.git
cd WaveDM.jl
julia --project -e "using Pkg; Pkg.develop(Pkg.PackageSpec(path='.'))"The shortest useful script: an ultra-faint dwarf (Crater II) under the SPE solver, with the LMC-enabled MW tidal field switched off for a clean virialization:
using WaveDM
using Unitful
simulate_waveDM(;
model = :dwarf_UFDs,
Galaxy_id = 6, # Crater II — try other ids via list_galaxies()
baryon_mode = :ignored, # this preset has no baryonic model
mₐ = 50 * 1e-22 * 1.783e-36u"kg", # m₂₂ = 50
V = (x, y, z, ψ) -> 0.0,
Nx = 128, # 128³ is a smoke test; use 384³ for production runs
Xmax = 20u"kpc",
Tmax = 1.0u"Gyr", # shorten for smoke test; 6 Gyr for production
autoset_timestep = true,
gpu = false, # set true if you have a CUDA GPU
Realtime = false, # set true if you have a monitor
title = "TestRun",
)💡 First time? Run
WaveDM.print_catalog()afterusing WaveDMto see every supported model and ultra-faint dwarf Galaxy_id.
Add the time-dependent MW tidal field, optionally perturbed by the LMC:
simulate_waveDM(;
model = :dwarf_UFDs,
Galaxy_id = 6,
baryon_mode = :ignored,
mₐ = 50 * 1e-22 * 1.783e-36u"kg",
V = (x, y, z, ψ) -> 0.0,
Nx = 384,
Xmax = 20u"kpc",
Tmax = 6.0u"Gyr",
autoset_timestep = true,
MW_tidal_field = true, # time-dependent MW tidal field
df_traj = df_traj, # from the lookback step (see docs Examples §4)
tidal_lookback_time = 6.0u"Gyr",
LMC_tidal_field = true, # include the LMC perturbation
gpu = true,
title = "CraterII_MW_LMC",
)A halo that has reached virialization in the periodic-domain sense (no MW field) ends up in a tide-driven non-equilibrium state once the live MW tidal field is turned on — a useful diagnostic for stripping studies.
Figure: Architecture of WaveDM.jl (taken from the accompanying paper, Meng & Dong 2026).
The plot above summarises 42 observational and theoretical bounds on the wave-CDM particle mass FirstAuthor et al. Year (with a/b suffixes when two different papers share a label); a work that quotes two intervals — Bar et al. 2019, Marsh et al. 2019 — draws two bars on its row. The data — method annotation next to each bar uses standard abbreviations (RC = rotation curve, SH relation = soliton–halo relation, SHMF = subhalo mass function, Lyα P(k) = Lyα flux power spectrum), an arrowhead marks a bound that continues past the plotted mass range, and a hatched cap marks a bound whose quoted value is itself a range. The vector PDF — ma_constraints.pdf — is searchable and copy-able for reuse in papers. The interactive HTML version (hover for citekey/title/DOI) is on the documentation home page. Raw constraint table: docs/constraints/ma_constraints.tex; regeneration recipe: docs/constraints/README.md.
WaveDM.jl integrates four core components on top of the shared JuliaAstroSim infrastructure:
- a pseudo-spectral split-step Fourier method (SSFM) solver for the SPE, evolving
$\psi$ with a second-order kick–drift–kick (KDK) scheme; - an optional baryonic physics module (
AstroNbodySim.jl) with mesh-based and particle-based treatments (baryon_mode = :ignored | :mesh | :particles_static | :particles_dynamic); - a galaxy-simulation toolbox providing trajectory lookback, tidal-field evaluation, virial diagnostics, profile/RC fitting, real-time visualization, and post-processing;
- a multi-level parallel framework combining multi-threading, distributed-memory (
Distributed.jlwith TCP/IP transport), and GPU acceleration (CUDA.jl).
Initial conditions are generated by AstroIC.jl; snapshot I/O is handled by AstroIO.jl. Gas dynamics via SPH is planned for a future release.
The SPE solver evolves the bosonic field AstroNbodySim.jl simultaneously evolves baryonic particles (static or fully dynamic) and computes their gravitational coupling to the wave dark matter. Time-dependent tidal fields from a host halo and external perturbers (e.g. the LMC) are supported. Both DirectSum ($\mathcal{O}(N^2)$) and Tree (
Shared-memory multi-threading, distributed-memory parallelism via Julia's native Distributed.jl, and GPU acceleration via CUDA.jl are all exposed through simple keyword arguments (julia -t N, distributed_memory=true, gpu=true). The same script runs unchanged on CPU, multi-threaded, and GPU configurations. Distributed workers currently accelerate IC generation and N-body work; the distributed FFT Poisson solver is not implemented, so the full SPE loop runs on one process. MPI support is planned for a future release.
using Distributed
addprocs(4)
@everywhere using WaveDM
# Distributed-memory IC generation; the SPE loop itself remains single-process.
simulate_waveDM(; Nx = Ny = Nz = 256, distributed_memory = true, gpu = false,
IC_only = true, ...)Ready-to-use density profiles (gNFW, NFW, Zhao, β-model), the Milky-Way mass model from Zhu et al. (2023), MW-satellite trajectory lookback from Battaglia et al. (2022), MW/LMC tidal fields, on-the-fly virial and energy diagnostics, profile and rotation-curve fitting, and interactive 2D/3D visualization through GLMakie.jl (with terminal-based UnicodePlots.jl for headless runs).
Wave (or "fuzzy") dark matter describes dark matter as an ultralight bosonic field with particle masses
reaches astrophysical scales — comparable to galactic substructure. The macroscopic wavefunction
with
where
An isolated halo with a gNFW initial profile, no baryons, no external tidal field — the cleanest setup for benchmarking the SPE solver:
using WaveDM
using Unitful
simulate_waveDM(;
model = :dwarf_UFDs,
Galaxy_id = 6, # Crater II
baryon_mode = :ignored,
mₐ = 50 * 1e-22 * 1.783e-36u"kg",
V = (x, y, z, ψ) -> 0.0,
Nx = 384,
Xmax = 20u"kpc",
Tmax = 6.0u"Gyr",
autoset_timestep = true,
gpu = true,
Realtime = true,
)Place the Milky Way's baryons on a fixed N-body background by sampling them with AstroIC.ExponentialDisc and switching to baryon_mode = :particles_static:
using WaveDM, AstroIC
using PhysicalParticles, UnitfulAstro, Unitful
particles_stellar_thin = generate(
AstroIC.ExponentialDisc(;
collection = STAR,
NumSamples = 50_000,
TotalMass = 3.5e10u"Msun",
ScaleRadius = 2.42u"kpc",
ScaleHeight = 0.30u"kpc",
)
)
particles_gas_HI = generate(
AstroIC.ExponentialDisc(;
collection = GAS,
NumSamples = 30_000,
TotalMass = 8.0e9u"Msun",
ScaleRadius = 7.0u"kpc",
ScaleHeight = 0.085u"kpc",
HoleRadius = 4.0u"kpc",
)
)
simulate_waveDM(;
model = :MW,
baryon_mode = :particles_static,
baryon_particles = [particles_stellar_thin; particles_gas_HI],
GravitySolver = Tree(),
SofteningLength = 0.1u"kpc", # code default; ε ~ mean particle spacing
Nx = Ny = Nz = 256,
Xmax = 100u"kpc",
Tmax = 3.0u"Gyr",
autoset_timestep = true,
gpu = true,
)For full coupled evolution (wave DM ↔ baryons), use baryon_mode = :particles_dynamic. See the Examples page in the documentation for more.
The full documentation is available at juliaastrosim.github.io/WaveDM.jl.
- Introduction — wave dark matter background, design philosophy, ecosystem
- Installation — installing WaveDM.jl and its dependencies
- Algorithms — SPE, split-step Fourier method, boundary conditions, resolution and timestep criteria, virial / QSS diagnostics
- API Reference — detailed API documentation
- Examples — end-to-end simulation examples
- References — related literature
- Grid size: powers of two (64, 128, 256, …) maximize FFT performance.
-
GPU: most useful for grids
$\gtrsim 256^3$ ; at large$N \gtrsim 512$ , GPU memory can become the bottleneck. -
Multi-threading: launch with
julia -t Nand enableFFTW.set_num_threads(N)for FFT-bound work. -
Distributed:
addprocs(N)thendistributed_memory = true; usesDistributed.jlwith TCP/IP transport (no MPI dependency). The distributed FFT Poisson solver is not implemented yet, so the full SPE loop must run on one process. -
Visualization: increase
StepsBetweenSnapshotsto reduce plotting overhead in long runs.
Detailed benchmarks on a 40-core + NVIDIA Tesla P100 node are reported in the accompanying paper (Meng & Dong 2026).
If you use WaveDM.jl in your research, please cite the accompanying paper:
- Meng, R. & Dong, X. 2026, WaveDM.jl: An Adaptable Simulation Framework for Dynamics of Baryonic and Wave Dark Matter on Galaxy Scales, Research in Astronomy and Astrophysics — journal article · arXiv:2606.25026 · DOI 10.1088/1674-4527/ae9042
@article{meng2026wavedmjladaptablea,
title = {{{WaveDM}}.Jl: {{An Adaptable Simulation Framework}} for {{Dynamics}} of {{Baryonic}} and {{Wave Dark Matter}} on {{Galaxy Scales}}},
shorttitle = {{{WaveDM}}.Jl},
author = {Meng, Runyu and Dong, Xiaobo},
year = 2026,
journal = {Research in Astronomy and Astrophysics},
issn = {1674-4527},
doi = {10.1088/1674-4527/ae9042},
url = {http://iopscience.iop.org/article/10.1088/1674-4527/ae9042},
eprint = {2606.25026},
archiveprefix = {arXiv},
primaryclass = {astro-ph.GA},
urldate = {2026-07-26}
}Publications built on this code base:
- Meng, R. & Dong, X. 2026, Wave Cold Dark Matter Can Reproduce the Radial Acceleration Relation in X-ray Elliptical Galaxies, Research in Astronomy and Astrophysics — journal article · arXiv:2610.18969 · DOI 10.1088/1674-4527/aeac08
@article{meng2026wavecold,
title = {Wave {{Cold Dark Matter Can Reproduce}} the {{Radial Acceleration Relation}} in {{X}}-Ray {{Elliptical Galaxies}}},
author = {Meng, Runyu and Dong, Xiaobo},
year = 2026,
journal = {Research in Astronomy and Astrophysics},
issn = {1674-4527},
doi = {10.1088/1674-4527/aeac08},
url = {http://iopscience.iop.org/article/10.1088/1674-4527/aeac08},
eprint = {2610.18969},
archiveprefix = {arXiv},
primaryclass = {astro-ph.GA},
urldate = {2026-09-24}
}The same entries are also collected in CITATION.bib.
WaveDM.jl is released under the GNU General Public License v3.0 (GPL-3). See the LICENSE file for details.
WaveDM.jl is part of the JuliaAstroSim ecosystem:
- AstroSimBase.jl — basic types and interfaces
- PhysicalParticles.jl — N-body particles and vector algebra
- AstroNbodySim.jl — gravitational N-body simulations, glue layer, and parallel runtime
- AstroIC.jl — initial condition generation
- AstroIO.jl — snapshot I/O
- AstroPlot.jl — analysis and visualization
- PhysicalFFT.jl — FFT primitives for physical problems
- PhysicalFDM.jl — finite-difference operators
- PhysicalTrees.jl — tree gravity solver
- PhysicalMeshes.jl — mesh-based gravity solver
- GalacticDynamics.jl — density profiles and orbit calculations
Planned future developments include:
- MPI support as an alternative distributed-memory backend to
Distributed.jl - SPH solver for gaseous baryonic components
- Adaptive timestep for the SPE solver
- Cosmological initial conditions beyond idealized halos
- Extended cross-disciplinary support for nonlinear optics and cold-atom physics
Contributions are welcome — please open an issue or pull request on GitHub.
For questions, issues, or feature requests, please open an issue on GitHub.
