.. _usage-howto-python-extend:
Extend a Simulation with Python
===============================
Overview
--------
ImpactX's Python interface lets you weave custom Python code into a running simulation.
Through this interface, you can **access and modify simulation data**, e.g., particle phase-space coordinates, the reference particle, and space-charge fields, as the simulation is tracking the beam.
This facilitates a wide range of workflows, including:
- **In-situ diagnostics** that compute quantities of interest at each turn or element without writing files to disk.
- **Dynamic lattice manipulation**, e.g., changing element strengths between turns, ramping voltages, or feedback systems.
- **Custom beam optics elements**, e.g., a non-linear kick or a tabulated map, plugged in via the :py:class:`impactx.elements.Programmable` element.
- **AI/ML surrogate models** built with PyTorch or TensorFlow to emulate detailed transport in a single element.
Because ImpactX exposes particles and fields *without copies* through `pyAMReX `__,
per-step Python callbacks have very low overhead and stay GPU-resident when ImpactX runs on GPUs
(``cupy``, PyTorch, etc. can operate directly on the device data).
.. _usage-howto-python-extend-run:
How to run a simulation with Python extensions
----------------------------------------------
- **Install ImpactX with the Python interface**: when compiling from source, this means ``-DImpactX_PYTHON=ON``
(see :ref:`building `). Pre-built :ref:`ImpactX packages ` also include this interface.
- **Write a Python script that drives the simulation**, registering callbacks or programmable elements before calling :py:meth:`~impactx.ImpactX.track_particles`.
A minimal template looks like:
.. code-block:: python
from impactx import ImpactX, distribution, elements
sim = ImpactX()
sim.space_charge = False
sim.init_grids()
# ... set up reference particle, distribution, and lattice ...
# register tracking hooks or programmable elements here:
def after_each_period(sim):
turn = sim.tracking_period
# e.g. compute a custom diagnostic from sim.beam
sim.hook["after_period"] = after_each_period
# advance the simulation
sim.track_particles()
sim.finalize()
- **Run the script** like any Python script, optionally under MPI:
.. code-block:: bash
mpirun -np python