Nemesis is a flexible, multi-physics, multi-scale algorithm for integrating hierarchical systems (e.g., planetary systems in star clusters, circumstellar disks, or binaries in galactic environments) embedded within the AMUSE library.
Nemesis works by decoupling tight subsystems from the global environment, integrating them in isolation, and then synchronising the micro- and macroscales at regular intervals. This scheme allows:
- High parallelisability
- Accurate energy conservation compared to direct N-body only runs
- Seamless inclusion of the galactic tidal field and stellar evolution
A full description is given in Hochart & Portegies Zwart (in prep.).
A demonstration video is available here.
For AMUSE installation instructions, see this guide.
At runtime, Nemesis automatically creates output directories for a given run. These are hosted under data/:
simulation_snapshot/– HDF5 snapshots of particle phase-space and massescollision_snapshot/– plain-text files describing detected collisionssim_stats/– text files with run statistics
Runs can be resumed automatically, provided diagnostic parameters (dtbridge, dt_diag) are unchanged.
- Install dependencies:
conda install --file requirements.txt
or
pip install -r requirements.txt - Compile C++ files. These are used to calculate the correction kicks between subsystems and the global environment, synchronising the micro- and macrostate:
cd src/cpp
make - Generate initial condiitons. For instance:
cd examples/python basic_cluster/particle_initialiser.pyThis will create a particle set with several planetary systems. The particle set are always saved in a folderICs/. - Run simulation. From the project root:
python main.pyIf, instead, you wish to simulate your system for 1 Myr with a bridge time step of 100 yr:python main.py --tend=1Myr --dtbridge=100yrCommand-line arguments are documented in main.py docstrings.
main.py: Run code to simulate your system.examples/: Folders with several examples initialising particles set to be run.src/environment_functions.py: Script containing various functions to define different environment properties.src/globals.py: All global constants and magic numbers used in the simulation.src/grav_correctors.py: Force correction routines to synchronise the micro- and macrostates (synchronise parent with children).src/hierarchical_particles.py: Script to categorise particles into parents and children.src/nemesis.py: Script hosting the evolution procedure.tests/: Folders with several test examples.
In addition to the input functions needed to execute interface.py, the following may vary depending on your simulation:
main.py:
galactic_frame(): The phase-space coordinates of the particles embedded within an analytical galactic potential. Default is centered about a Milky Way-like galaxy.RUN_IDX: The system realisation within yourinitial_particles/directory wished to simulate.
src/globals.py:
ASTEROID_RADIUS: Collision radius for asteroid (test) particles.CONNECTED_COEFF: Threshold for detecting particles within a subsystem that are ejected.EPS: Tolerance with which models have successfully integrated to required time step.GRAV_THRESHOLD: Threshold for modifying the parent particle radius in case it is relatively isolated. This not currently being used.MIN_EVOL_MASS: The minimum mass for a particle to be flagged for stellar evolution.PARENT_NWORKER: Number of workers for parent integrator.PARENT_RADIUS_COEFF: Pre-factor influencing the parent particle radius.PARENT_RADIUS_MAX: Maximum allowed parent particle radius.
src/nemesis.py:
_sub_worker(): Number of child workers. CurrentAMUSEfunctionalities forces this variable to remain fixed tonumber_of_workers = 1. Dedicated gravitational solver for subsystems._parent_worker: Dedicated gravitational solver for parent code.
To run example script, execute python basic_cluster/particle_initialiser.py to create an AMUSE particle set. Afterwards, execute python main.py.
Two example Nemesis test is provided. Running these not only provide a way to gauge if any modifcations alter the physics in ways not wished for, but also allow one to familiarise themselves with the algorithm. Both compare its performance relative to N-body integrators, with one focusing on the von Zeipel-Lidov-Kozai (ZLK) effect and the other a typical cluster simulation.
To run this test follow:
- Set-up initial conditions:
python /tests/ZKL_test/initialise_LZK.py - To run Nemesis:
python /tests/ZKL_test/run_ZKL.py - To plot results:
python/tests/ZKL_test/plot_ZKL.py
Some vital notes regarding the test:
- These are some suggested parameters:
- In
nemesis._parent_worker, useHuaynoas parent integrator with modeSHARED10_COLLISIONS. - In
nemesis._sub_worker, useHuaynoas children integrator with modeSHARED10_COLLISIONS. - In
nemesis._sub_workerset child converter withscale_radius / 10. - End time: 10 Myr.
- Bridge time: 500 yr.
- Diagnostic time: 5000 yr.
- Code internal time-step: 0.1.
- Turn off galactic field + stellar evolution.
- Change
PARENT_RADIUS_COEFFinsrc/globalsto 1e-5 au, 100 au and 1000 au. - Turn off children collisions. Make sure that the parent and child code is the same integrator. This allows testing the performance of the child split algorithm vs. non-splitting scenarios.
- In
To run this test follow:
- Set-up initial conditions:
python /tests/cluster_test/initialise_cluster.py - To run Nemesis:
python /tests/cluster_test/run_cluster.pywith the flagRUN_NEMESIS = 1 - To run direct N-body code:
python /tests/cluster_test/run_cluster.pywith the flagRUN_NEMESIS = 0 - To plot results:
python /tests/cluster_test/plot_cluster.py
Some vital notes regarding the test:
- Ensure that both parent and child integrator within
Nemesisare the same. This should also be an identical integrator to that selected during the direct N-body runs. Additionally, make sure all code parameters (i.e converter, internal time-step...) are identical to ease comparison. A good code to use for this test isPh4since the cluster initialised contains test particles by default andPh4is able to handle such a demographic efficiently. Some advice forNemesisparameters:- In
nemesis._parent_worker, usePh4as parent integrator. - In
nemesis._sub_worker, usePh4as children integrator. - End time: 0.1 Myr -- Deviation will occur due to chaos. This is a short enough time to allow any systematic errors to emerge but not too short for chaos to greatly affect integration.
- Bridge time: 500 yr
- Diagnostic time: 10000 yr
- Code internal time-step: 0.1
- Turn off galactic field + stellar evolution -- This will allow a better comparison in performance on the gravitational side of
Nemesis. - Turn off children collisions
- In
- To setup children at the initial time step, it is required that the particle set contains a
syst_idattribute whose value is an integer. The set of particles with the samesyst_idvalue will be flagged as a subsystem as long assyst_id> 0. - Since Nemesis relies heavily on frequent stop/start (hibernate/resume) cycles for its child integrators, sockets are used instead of MPI. The persistent stop/start cycles conflict with MPI worker behaviour since MPI workers cannot safely handle repeated suspend/resume signals, especially in large-N simulations where hundreds of worker processes are active. Repeated stop/start operations can lead to workers being incorrectly terminated, crashing the simulation altogether. Socket-based channels, however, can tolerate stop/start cyles because they do not use the tightly coupled, state-sensitive collective semantics of MPI. The problem, however, is that children code are restricted to one core per.