Simulation classes¶
- class lambdapic.simulation.Simulation(nx: int, ny: int, dx: float, dy: float, npatch_x: int = 0, npatch_y: int = 0, nsteps: int | None = None, sim_time: float | None = None, dt_cfl: float = 0.95, n_guard: int = 3, boundary_conditions: ~typing.Dict[~typing.Literal['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax'], ~typing.Literal['pml', 'periodic']] = <factory>, cpml_thickness: int = 6, log_file: str | None = None, truncate_log: bool = True, random_seed: int | None = None, comm: ~mpi4py.MPI.Comm | None = None)[source]¶
Main simulation class for 2D Particle-In-Cell (PIC) simulations.
- Parameters:
nx (int) – Number of grid cells in x direction. Must be divisible by npatch_x.
ny (int) – Number of grid cells in y direction. Must be divisible by npatch_y.
dx (float) – Grid cell size in x direction (meters).
dy (float) – Grid cell size in y direction (meters).
npatch_x (int) – Number of patches to divide the domain into along x direction. Default 0 for auto patch number.
npatch_y (int) – Number of patches to divide the domain into along y direction. Default 0 for auto patch number.
nsteps (int, optional) – Number of simulation steps. Mutually exclusive with sim_time.
sim_time (float, optional) – Total simulation time in seconds. Mutually exclusive with nsteps.
dt_cfl (float, optional) – CFL (Courant-Friedrichs-Lewy) stability factor. Must be ≤ 1.0. The actual time step is calculated as dt = dt_cfl / (c * sqrt(1/dx² + 1/dy²)). Defaults to 0.95.
n_guard (int, optional) – Number of guard cells used for field synchronization between patches. Defaults to 3.
boundary_conditions (Dict[Literal['xmin', 'xmax', 'ymin', 'ymax'], Literal['pml', 'periodic']], optional) – Dictionary mapping boundary names to their conditions. Supported boundaries: ‘xmin’, ‘xmax’, ‘ymin’, ‘ymax’. Supported conditions: ‘pml’ (Perfectly Matched Layer) or ‘periodic’. Defaults to all boundaries set to ‘pml’.
cpml_thickness (int, optional) – Thickness of CPML (Convolutional PML) absorbing boundary layers in grid cells. Defaults to 6.
log_file (str, optional) – Path to log file. If None, generates timestamp-based filename. Defaults to None.
truncate_log (bool, optional) – Whether to truncate existing log file or append to it. Defaults to True.
random_seed (int, optional) – Random seed for reproducible particle initialization (default: None)
comm (mpi4py.MPI.Comm, optional) – MPI communicator. If None, uses MPI.COMM_WORLD. Defaults to None.
- add_collision(collision_groups: Sequence[Sequence[Species]])[source]¶
Register particle collision groups for the simulation.
- Parameters:
collision_groups – A sequence of groups, where each group is a sequence of Species. All unique pairs within a group (including intra-species) are considered for collisions.
Example
[[e1, e1, e2, e3], [ion, ion]] will perform e1<->e1, e1<->e2, e1<->e3, e2<->e3 collisions, and ion<->ion collisions.
[[e1, e1], [e1, ion], [e2, ion], [ion, ion]]. This is manually specifying all collision pairs.
Notes
Species in the groups must already be added to the simulation via add_species().
If called after the simulation has already been initialized, this will immediately construct the Collision object.
- add_species(species: Sequence[Species])[source]¶
Add particle species to the simulation.
- Parameters:
species – One or more species to add to the simulation
Note
Automatically ensures unique species names by renaming: electron -> electron.1
Assigns ispec indices to each species
Species must be added before initialization
- create_patches() Patches[source]¶
Create and initialize all patches for the simulation domain.
- Returns:
Collection of all patches with initialized neighbor relationships
Note
Creates a 2D grid of patches based on npatch_x and npatch_y
Initializes neighbor indices for patch communication
Only called on rank 0 during initialization
- generate_lists()[source]¶
Generate particle lists for all modules.
Creates particle lists needed by: - Pushers - Radiation modules - Field interpolator - Current depositor
- initialize()[source]¶
Initialize the simulation components.
This method: 1. Creates and distributes patches across MPI ranks 2. Initializes fields, boundaries, and MPI communication 3. Adds species and particles 4. Sets up solvers, interpolators, and pushers 5. Configures QED modules if needed
Note
Must be called before running the simulation. Performs collective MPI operations and should be called on all ranks.
- maxwell_stage()[source]¶
Perform a single Maxwell solver stage (half time step).
Updates electromagnetic fields using the FDTD method: 1. Updates E field by 0.5*dt 2. Synchronizes E field across patches 3. Updates B field by 0.5*dt 4. Synchronizes B field across patches
- run(nsteps: int | None = None, sim_time: float | None = None, callbacks: ~typing.Sequence[~typing.Callable[[~lambdapic.simulation.Simulation], None]] | None = None, stop_callback: ~typing.Callable[[...], bool] = <function Simulation.<lambda>>)[source]¶
Run the simulation for a specified number of steps or time duration.
- Parameters:
nsteps – Number of time steps to run (mutually exclusive with sim_time)
sim_time – Total simulation time in seconds (mutually exclusive with nsteps)
callbacks – Callbacks to execute at different simulation stages
Note
The main simulation loop performs: 1. Field updates (Maxwell solver) 2. Particle pushing (position and momentum) 3. Current deposition 4. QED processes (radiation and pair production) 5. Particle synchronization between patches 6. Callback execution at defined stages
- property time: float¶
Get the current simulation time in seconds.
- Returns:
Current simulation time (itime * dt)
- class lambdapic.simulation.Simulation3D(nx: int, ny: int, nz: int, dx: float, dy: float, dz: float, npatch_x: int = 0, npatch_y: int = 0, npatch_z: int = 0, nsteps: int | None = None, sim_time: float | None = None, dt_cfl: float = 0.95, n_guard: int = 3, boundary_conditions: ~typing.Dict[~typing.Literal['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax'], ~typing.Literal['pml', 'periodic']] = <factory>, cpml_thickness: int = 6, log_file: str | None = None, truncate_log: bool = True, random_seed: int | None = None, comm: ~mpi4py.MPI.Comm | None = None)[source]¶
Bases:
SimulationMain class for 3D PIC simulation.
- Parameters:
nx (int) – Number of grid cells in x direction. Must be divisible by npatch_x.
ny (int) – Number of grid cells in y direction. Must be divisible by npatch_y.
nz (int) – Number of grid cells in z direction. Must be divisible by npatch_z.
dx (float) – Grid cell size in x direction (meters).
dy (float) – Grid cell size in y direction (meters).
dz (float) – Grid cell size in z direction (meters).
npatch_x (int) – Number of patches to divide the domain into along x direction. Default 0 for auto patch number.
npatch_y (int) – Number of patches to divide the domain into along y direction. Default 0 for auto patch number.
npatch_z (int) – Number of patches to divide the domain into along z direction. Default 0 for auto patch number.
nsteps (int, optional) – Number of simulation steps. Mutually exclusive with sim_time.
sim_time (float, optional) – Total simulation time in seconds. Mutually exclusive with nsteps.
dt_cfl (float, optional) – CFL (Courant-Friedrichs-Lewy) stability factor. Must be ≤ 1.0. The actual time step is calculated as dt = dt_cfl / (c * sqrt(1/dx² + 1/dy² + 1/dz²)). Defaults to 0.95.
n_guard (int, optional) – Number of guard cells used for field synchronization between patches. Defaults to 3.
boundary_conditions (Dict[Literal['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax'], Literal['pml', 'periodic']], optional) – Dictionary mapping boundary names to their conditions. Supported boundaries: ‘xmin’, ‘xmax’, ‘ymin’, ‘ymax’, ‘zmin’, ‘zmax’. Supported conditions: ‘pml’ (Perfectly Matched Layer) or ‘periodic’. Defaults to all boundaries set to ‘pml’.
cpml_thickness (int, optional) – Thickness of CPML (Convolutional PML) absorbing boundary layers in grid cells. Defaults to 6.
log_file (Optional[str], optional) – Path to log file. If None, generates timestamp-based filename. Defaults to None.
truncate_log (bool, optional) – Whether to truncate existing log file or append to it. Defaults to True.
random_seed (int, optional) – Random seed for reproducible particle initialization (default: None)
comm (Optional[mpi4py.MPI.Comm], optional) – MPI communicator. If None, uses MPI.COMM_WORLD. Defaults to None.
- create_patches()[source]¶
Create and initialize all 3D patches for the simulation domain.
- Returns:
Collection of all 3D patches with initialized neighbor relationships
Note
Creates a 3D grid of patches based on npatch_x, npatch_y, and npatch_z
Initializes neighbor indices for patch communication
Only called on rank 0 during initialization
- class lambdapic.simulation.SimulationCallbacks(callbacks: Sequence[Callable[[Simulation], None]], simulation: Simulation)[source]¶
Manages the execution of callbacks at different simulation stages.
Initialize the callback manager.
- Parameters:
callbacks – List of callback objects
simulation – The simulation instance to pass to callbacks
Integrated Features¶
The Simulation class includes several features that
are activated automatically during run():
Progress Bar¶
When calling run(), a ProgressBar is
created automatically. The progress bar detects whether the output is a terminal or
a log file and adapts its display accordingly: in terminals it uses tqdm for an
interactive progress bar, and in non-terminal environments it emits structured log
messages at regular intervals.
Dynamic Load Balancing¶
During run(), a LoadBalancer monitors
the computational load across MPI ranks. When the load imbalance exceeds a configurable
threshold, the load balancer triggers automatic patch rebalancing to redistribute work
evenly. After rebalancing, update_patches() is
called automatically to regenerate field and particle lists for all simulation modules.
The load of each patch is calculated as:
load = npart + (nx * ny [* nz]) / 2
where npart is the number of alive particles and the grid term accounts for field
computation cost. This calculation is performed internally by
_calculate_patch_loads().