Python Interface

This document lists all Python-exposed functions from the pipic module with their arguments and descriptions. (See src/pipic.h for C++ implementation.)

Initialization

pipic.init(solver, nx, xmin, xmax, ny=1, ymin=-0.5, ymax=0.5, nz=1, zmin=-0.5, zmax=0.5)

Initialize a PIC simulation container.

Parameters:

  • solver (str): Solver name. Available options: "fourier_boris", "ec", "ec2", "electrostatic_1d", "emc2".

  • nx (int): Number of grid cells in x-direction (must be power of 2 for FFT-based solvers).

  • xmin, xmax (float): Spatial domain boundaries in x-direction (cm).

  • ny (int, optional): Number of grid cells in y-direction. Default: 1 (for 2D/1D).

  • ymin, ymax (float, optional): Spatial domain boundaries in y-direction (cm). Default: -0.5, 0.5.

  • nz (int, optional): Number of grid cells in z-direction. Default: 1 (for 1D).

  • zmin, zmax (float, optional): Spatial domain boundaries in z-direction (cm). Default: -0.5, 0.5.

Returns: Simulation object.

Example:

import pipic
sim = pipic.init(solver='fourier_boris', nx=256, xmin=0, xmax=1e-3)

Read-Only Attributes:

After initialization, the simulation object exposes grid parameters:

  • sim.nx, sim.ny, sim.nz: Grid cell counts.

  • sim.xmin, sim.xmax, sim.ymin, sim.ymax, sim.zmin, sim.zmax: Domain boundaries.

Advance

sim.advance(time_step, number_of_iterations=1, use_omp=True)

Advance the simulation by one or more time steps.

Parameters:

  • time_step (float): Duration of each time step in seconds.

  • number_of_iterations (int, optional): Number of time steps to advance. Default: 1.

  • use_omp (bool, optional): Enable OpenMP parallelization. Default: True.

Example:

dt = 1e-16  # seconds
sim.advance(time_step=dt, number_of_iterations=100)

Field Callbacks

sim.field_loop(handler, data_double=0, data_int=0, use_omp=False)

Iterate over grid nodes to initialize or read field values.

Parameters:

  • handler (int): Address of field loop callback.

  • data_double (int, optional): Address of double-precision data array.

  • data_int (int, optional): Address of integer data array.

  • use_omp (bool, optional): Enable OpenMP parallelization. Default: False.

Handler signature:

from numba import cfunc
from pipic import types

@cfunc(types.field_loop_callback)
def field_handler(ind, r, E, B, data_double, data_int):
    # ind: grid indices [ix, iy, iz, component_code]
    # r: position [x, y, z]
    # E: electric field [Ex, Ey, Ez] - can be modified
    # B: magnetic field [Bx, By, Bz] - can be modified

Example (initialize electric field):

@cfunc(types.field_loop_callback)
def set_field(ind, r, E, B, data_double, data_int):
    E[0] = 1e4 * np.sin(2*np.pi*r[0]/L)

sim.field_loop(handler=set_field.address)

Particle Callbacks

sim.add_particles(name, number, charge, mass, temperature, density, data_double=0, data_int=0)

Add particles to the simulation.

Parameters:

  • name (str): Particle species identifier (e.g., "electron", "positron", "photon").

  • number (int): Total number of macroparticles to add.

  • charge (float): Particle charge in esu (use pipic.consts.electron_charge for electrons).

  • mass (float): Particle mass in grams (use pipic.consts.electron_mass for electrons).

  • temperature (float): Initial thermal energy in erg, defined as \(\\frac{2}{3}\\langle E_k \\rangle\).

  • density (int): Address of density callback function (see below).

  • data_double (int, optional): Address of double-precision data array. Default: 0.

  • data_int (int, optional): Address of integer data array. Default: 0.

Example:

from numba import cfunc
from pipic import types

@cfunc(types.add_particles_callback)
def uniform_density(r, data_double, data_int):
    return 1e18  # cm⁻³

sim.add_particles(name='electron',
                 number=10000,
                 charge=pipic.consts.electron_charge,
                 mass=pipic.consts.electron_mass,
                 temperature=1e-6 * pipic.consts.electron_mass * pipic.consts.light_velocity**2,
                 density=uniform_density.address)

Density Callback (for add_particles)

from numba import cfunc
from pipic import types

@cfunc(types.add_particles_callback)
def density_profile(r, data_double, data_int):
    # r[0] = x, r[1] = y, r[2] = z
    return density_value  # particles per cm³

sim.particle_loop(name, handler, data_double=0, data_int=0)

Iterate over particles of a specific type (single-threaded).

Parameters:

  • name (str): Particle species to loop over.

  • handler (int): Address of particle loop callback.

  • data_double (int, optional): Address of double-precision data array.

  • data_int (int, optional): Address of integer data array.

Handler signature:

from numba import cfunc, carray
from pipic import types

@cfunc(types.particle_loop_callback)
def particle_handler(r, p, w, id, data_double, data_int):
    # r: position array [x, y, z]
    # p: momentum array [px, py, pz]
    # w: weight array [weight]
    # id: particle ID array [id]
    # Read but DO NOT modify r, p, w, id directly
    # Use data arrays for output

Add Handler

sim.add_handler(name, subject="", handler=0, field_handler=0, data_double=0, data_int=0)

Register a custom extension handler.

Parameters:

  • name (str): Handler identifier.

  • subject (str, optional): Target particle types (e.g., "electron, positron"), "all_types", or "cells". Default: empty.

  • handler (int, optional): Address of particle/cell handler callback. Default: 0.

  • field_handler (int, optional): Address of field handler callback. Default: 0.

  • data_double (int, optional): Address of double-precision shared data.

  • data_int (int, optional): Address of integer shared data.

Example:

import pipic.extensions.qed_gonoskov2015 as qed

handler_ptr = qed.handler()
sim.add_handler(name='qed_gonoskov2015',
               subject='electron, positron',
               handler=handler_ptr)

Constants and Utilities

Constants Module

Access physical constants via pipic.consts:

from pipic import consts

consts.light_velocity      # c = 2.998×10¹⁰ cm/s
consts.electron_charge     # e = -4.803×10⁻¹⁰ esu
consts.electron_mass       # mₑ = 9.109×10⁻²⁸ g
consts.proton_mass         # mₚ = 1.673×10⁻²⁴ g
consts.pi                  # π = 3.14159...
consts.hbar                # ℏ = 1.055×10⁻²⁷ erg·s

Callback Types

Callback type signatures via pipic.types:

  • types.add_particles_callback: For density profiles

  • types.particle_loop_callback: For particle iteration

  • types.field_loop_callback: For field iteration

Utilities

pipic.addressof(array)

Get memory address of NumPy array for passing to callbacks.

Parameters:

  • array: NumPy array

Returns: int (memory address)

Example:

import numpy as np
data = np.zeros(100, dtype=np.double)
sim.field_loop(handler=callback.address,
              data_double=pipic.addressof(data))

Advanced Usage

Particle Queries

sim.get_number_of_particles()

Return total number of macroparticles across all species.

Returns: int

sim.get_type_index(type_name)

Get internal index for a particle type.

Parameters:

  • type_name (str): Particle species name.

Returns: int (type index)

Custom Field Sampling

sim.custom_field_loop(number_of_iterations, it2r, field2data, data_double=0, data_int=0)

Sample fields at arbitrary coordinates.

Parameters:

  • number_of_iterations (int): Number of sample points.

  • it2r (int): Address of coordinate callback.

  • field2data (int): Address of field-to-data callback.

  • data_double (int, optional): Address of double-precision data array.

  • data_int (int, optional): Address of integer data array.

Solver-Specific Settings

sim.fourier_solver_settings(divergence_cleaning=-1, sin2_kfilter=-1)

Configure Fourier-based solver options (only for fourier_boris and related solvers).

Parameters:

  • divergence_cleaning (int, optional): Enable (1) or disable (0) divergence cleaning. Default: -1 (no change).

  • sin2_kfilter (int, optional): Enable (1) or disable (0) high-frequency filter. Default: -1 (no change).

Example:

sim.fourier_solver_settings(divergence_cleaning=1, sin2_kfilter=0)

sim.en_corr_type(correction_type=2)

Set energy correction type for EC/EC2 solvers.

Parameters:

  • correction_type (int, optional): Correction algorithm variant. Default: 2.

Note: Only applicable to ec and ec2 solvers.

Logging and Diagnostics

sim.log_policy(log_to_file=True, log_to_screen=False)

Control logging output destinations.

Parameters:

  • log_to_file (bool, optional): Write log messages to pipic_log.txt. Default: True.

  • log_to_screen (bool, optional): Print log messages to console. Default: False.

sim.set_rng_seed(seed)

Set random number generator seed for reproducibility.

Parameters:

  • seed (int): RNG seed value.

Example:

sim.set_rng_seed(42)  # Deterministic runs

Advanced C++ Integration

sim.ensemble_data()

Return pointer to internal ensemble data structure (for advanced C++ integration).

Returns: int (memory address)

sim.simulation_box()

Return pointer to simulation box structure (for advanced C++ integration).

Returns: int (memory address)