.. _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