### PICMI Input Script Example Source: https://picmi.readthedocs.io/en/latest/how_to_use/using.html A comprehensive example of a PICMI input script, showing parameter definition, conditional code-specific logic, and component initialization. ```python #!/usr/bin/env python3 # This should be the only line that needs to be changed for different codes # e.g. `from pywarpx import picmi` # `from fbpic import picmi` # `from warp import picmi` from plasmacode import picmi # Create alias fror constants cst = picmi.constants # Run parameters - can be in separate file # ======================================== # Physics parameters # ------------------ # --- laser import math laser_polarization = math.pi/2 # Polarization angle (in rad) laser_a0 = 4. # Normalized potential vector laser_wavelength = 8e-07 # Wavelength of the laser (in meters) laser_waist = 5e-06 # Waist of the laser (in meters) laser_duration = 15e-15 # Duration of the laser (in seconds) laser_injection_loc = 9.e-6 # Position of injection (in meters, along z) laser_focal_distance = 100.e-6 # Focal distance from the injection (in meters) laser_t_peak = 30.e-15 # The time at which the laser reaches its peak # at the antenna injection location (in seconds) # --- plasma plasma_density_expression = "1.e23*(1+tanh((z - 20.e-6)/10.e-6))/2." plasma_min = [-20.e-6, -20.e-6, 0.0e-6] plasma_max = [ 20.e-6, 20.e-6, 1.e-3] # --- electron bunch bunch_physical_particles = 1.e8 bunch_rms_size = [1.e-6, 1.e-6, 1.e-6] bunch_rms_velocity = [0.,0.,10.*cst.c] bunch_centroid_position = [0.,0.,-22.e-6] bunch_centroid_velocity = [0.,0.,1000.*cst.c] # Numerics parameters # ------------------- # --- Nb time steps max_steps = 1000 # --- grid nx = 64 ny = 64 nz = 480 xmin = 1.5*plasma_min[0] xmax = 1.5*plasma_max[0] ymin = 1.5*plasma_min[1] ymax = 1.5*plasma_max[1] zmin = -38.e-6 zmax = 10.e-6 moving_window_velocity = [0., 0., cst.c] n_macroparticle_per_cell = [2, 2, 2] # --- geometry and solver em_solver_method = 'CKC' # Cole-Karkkainen-Cowan stencil geometry = '3D' # Note that code-specific changes can be introduced with `picmi.codename` if picmi.codename == 'fbpic': em_solver_method = 'PSATD' # Pseudo-Spectral Analytical Time Domain solver geometry = 'RZ' n_macroparticle_per_cell = [2, 4, 2] # number of particle per cell in the r, theta, z direction respectively # Physics part - can be in separate file # ====================================== # Physics components # ------------------ # --- laser laser = picmi.GaussianLaser( wavelength = laser_wavelength, waist = laser_waist, duration = laser_duration, focal_position = [0., 0., laser_focal_distance + laser_injection_loc], centroid_position = [0., 0., laser_injection_loc - cst.c*laser_t_peak], polarization_direction = [math.cos(laser_polarization), math.sin(laser_polarization), 0.], propagation_direction = [0,0,1], a0 = laser_a0) # --- plasma plasma_dist = picmi.AnalyticDistribution( density_expression = plasma_density_expression, lower_bound = plasma_min, upper_bound = plasma_max, fill_in = True) plasma = picmi.MultiSpecies( particle_types = ['He', 'Ar', 'electron'], names = ['He+', 'Argon', 'e-'], charge_states = [1, 5, None], proportions = [0.2, 0.8, 0.2 + 5*0.8], initial_distribution=plasma_dist) # Individual species in a `MultiSpecies` can be addressed either # with their index (using Python indexing conventions) or with their name # (if the user provided a name) # Set the ionization for the species number 1 (Argon) # and place the created electrons into the species number 2 (electron) if picmi.codename != 'warpx': argon_ionization = picmi.FieldIonization( model = "ADK", # Ammosov-Delone-Krainov model ionized_species = plasma['Argon'], product_species = plasma['e-']) # --- electron bunch beam_dist = picmi.GaussianBunchDistribution( n_physical_particles = bunch_physical_particles, rms_bunch_size = bunch_rms_size, rms_velocity = bunch_rms_velocity, centroid_position = bunch_centroid_position, centroid_velocity = bunch_centroid_velocity ) beam = picmi.Species( particle_type = 'electron', name = 'beam', initial_distribution = beam_dist) # Numerics components # ------------------- ``` -------------------------------- ### Initialize AnalyticDistribution Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/particles.html Example of creating an analytic distribution with a density expression defined by spatial coordinates and parameters. ```python dist = AnalyticDistribution(density_expression='((x**2+y**2)v0.34.0. """ self._check_deprecated_argument( "n_macroparticle_per_cell", message="n_macroparticle_per_cell was renamed. It is deprecated in favor of n_macroparticles_per_cell and will be removed in a future version.", raise_error=False, ) if n_macroparticle_per_cell is not None: if self.n_macroparticles_per_cell is None: self.n_macroparticles_per_cell = n_macroparticle_per_cell else: raise ValueError( f"PICMI_GriddedLayout: You have specified {self.n_macroparticles_per_cell=} as well as the deprecated {n_macroparticle_per_cell=}." ) if self.n_macroparticles_per_cell is None: raise ValueError( "PICMI_GriddedLayout: You have not specified n_macroparticles_per_cell." ) @property def n_macroparticle_per_cell(self): return self.n_macroparticles_per_cell @n_macroparticle_per_cell.setter def _(self, value): self.n_macroparticles_per_cell = value ``` -------------------------------- ### Initialize PICMI_GaussianBunchDistribution Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/particles.html Defines a Gaussian particle distribution with specified physical particle count, size, and velocity parameters. ```python def __init__(self,n_physical_particles, rms_bunch_size, rms_velocity = [0.,0.,0.], centroid_position = [0.,0.,0.], centroid_velocity = [0.,0.,0.], velocity_divergence = [0.,0.,0.], **kw): self.n_physical_particles = n_physical_particles self.rms_bunch_size = rms_bunch_size self.rms_velocity = rms_velocity self.centroid_position = centroid_position self.centroid_velocity = centroid_velocity self.velocity_divergence = velocity_divergence self.handle_init(kw) ``` -------------------------------- ### Initialize PICMI_LoadAppliedField Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/applied_fields.html Initializes a class to apply E and B fields from an OpenPMD file directly to particles. ```python class PICMI_LoadAppliedField(_ClassWithInit): """ The E and B fields read from file are applied to the particles directly. (They are not affected by the field solver.) The expected format is the file is OpenPMD with axes (x,y,z) in Cartesian, or (r,z) in Cylindrical geometry. Parameters ---------- read_fields_from_path: string Path to file with field data load_B: bool, default=True If False, do not load magnetic field load_E: bool, default=True If False, do not load electric field """ def __init__(self, read_fields_from_path, load_B=True, load_E=True, **kw): self.load_B = load_B self.load_E = load_E self.read_fields_from_path = read_fields_from_path self.handle_init(kw) ``` -------------------------------- ### Define a PICMI Simulation Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/simulation.html Initialize a simulation object with solver, time step, and physical constraints. ```python class PICMI_Simulation(_ClassWithInit): """ Creates a Simulation object Parameters ---------- solver: field solver instance This is the field solver to be used in the simulation. It should be an instance of field solver classes. time_step_size: float Absolute time step size of the simulation [s]. Needed if the CFL is not specified elsewhere. max_steps: integer Maximum number of time steps. Specify either this, or `max_time`, or use the `step` function directly. max_time: float Maximum physical time to run the simulation [s]. Specify either this, or `max_steps`, or use the `step` function directly. verbose: integer, optional Verbosity flag. A larger integer results in more verbose output particle_shape: {'NGP', 'linear', 'quadratic', 'cubic'} Default particle shape for species added to this simulation gamma_boost: float, optional Lorentz factor of the boosted simulation frame. Note that all input values should be in the lab frame. """ def __init__(self, solver=None, time_step_size=None, max_steps=None, max_time=None, verbose=None, particle_shape='linear', gamma_boost=None, load_balancing=None, **kw): self.solver = solver self.time_step_size = time_step_size self.verbose = verbose self.max_steps = max_steps self.max_time = max_time self.particle_shape = particle_shape self.gamma_boost = gamma_boost self.species = [] self.layouts = [] self.initialize_self_fields = [] self.injection_plane_positions = [] self.injection_plane_normal_vectors = [] self.lasers = [] self.laser_injection_methods = [] self.applied_fields = [] self.diagnostics = [] self.interactions = [] self.load_balancing = load_balancing self.handle_init(kw) ``` -------------------------------- ### Configure Simulation Grid Source: https://picmi.readthedocs.io/en/latest/how_to_use/using.html Define Cartesian or Cylindrical grids using PICMI classes, specifying boundaries and boundary conditions. ```python if geometry == '3D': grid = picmi.Cartesian3DGrid( number_of_cells = [nx, ny, nz], lower_bound = [xmin, ymin, zmin], upper_bound = [xmax, ymax, zmax], lower_boundary_conditions = ['periodic', 'periodic', 'open'], upper_boundary_conditions = ['periodic', 'periodic', 'open'], moving_window_velocity = moving_window_velocity) # Note that code-specific arguments use the code name as a prefix. elif geometry == 'RZ': # In the following lists: # - the first element corresponds to the radial direction # - the second element corresponds to the longitudinal direction grid = picmi.CylindricalGrid( number_of_cells = [nx//2, nz], lower_bound = [0., zmin], upper_bound = [xmax, zmax], lower_boundary_conditions = [ None, 'open'], upper_boundary_conditions = ['reflective', 'open'], n_azimuthal_modes = 2, moving_window_velocity = [0., cst.c], warpx_max_grid_size = 32) ``` -------------------------------- ### Initialize PICMI_LabFrameParticleDiagnostic Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/diagnostics.html Constructor for the particle diagnostic class, defining species, snapshot intervals, and output directory settings. ```python class PICMI_LabFrameParticleDiagnostic(_ClassWithInit): """ Defines the particle diagnostics in the lab frame Parameters ---------- grid: grid instance Grid object for the diagnostic num_snapshots: integer Number of lab frame snapshots to make dt_snapshots: float Time between each snapshot in lab frame species: species instance or list of species instances, optional Species to write out. If not specified, all species are written. Note that the name attribute must be defined for the species. data_list: list of strings, optional The data to be written out. Possible values 'position', 'momentum', 'weighting'. Defaults to the output list of the implementing code. time_start: float, default=0 Time for the first snapshot in lab frame write_dir: string, optional Directory where data is to be written parallelio: bool, optional If set to True, particle diagnostics are dumped in parallel name: string, optional Sets the base name for the diagnostic output files """ def __init__(self, grid, num_snapshots, dt_snapshots, data_list=None, time_start = 0., species = None, write_dir = None, parallelio = None, name = None, **kw): if data_list is not None: assert isinstance(data_list, list), 'LabFrameParticleDiagnostic: data_list must be a list' self.grid = grid self.num_snapshots = num_snapshots self.dt_snapshots = dt_snapshots self.time_start = time_start self.species = species self.data_list = data_list self.write_dir = write_dir self.parallelio = parallelio self.name = name self.handle_init(kw) ``` -------------------------------- ### Initialize Laser Antenna Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/lasers.html Constructor for the laser antenna injection method, allowing specification of position and normal vector. ```python def __init__(self, position, normal_vector=None, **kw): self.position = position self.normal_vector = normal_vector self.handle_init(kw) ``` -------------------------------- ### Initialize PICMI_ParticleDiagnostic Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/diagnostics.html Defines particle diagnostics in the simulation frame with configurable species, data lists, and output directories. ```python class PICMI_ParticleDiagnostic(_ClassWithInit) : def __init__(self, period, species=None, data_list=None, write_dir = None, step_min = None, step_max = None, parallelio = None, name = None, **kw): if data_list is not None: assert isinstance(data_list, list), 'ParticleDiagnostic: data_list must be a list' self.period = period self.species = species self.data_list = data_list self.write_dir = write_dir self.step_min = step_min self.step_max = step_max self.parallelio = parallelio self.name = name self.handle_init(kw) ``` -------------------------------- ### Initialize PICMI_BinomialSmoother Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/fields.html Defines a binomial smoother operator for grids with configurable passes, compensation, stride, and alpha coefficients. ```python class PICMI_BinomialSmoother(_ClassWithInit): """ Describes a binomial smoother operator (applied to grids) Parameters ---------- n_pass: vector of integers Number of passes along each axis compensation: vector of booleans, optional Flags whether to apply comensation along each axis stride: vector of integers, optional Stride along each axis alpha: vector of floats, optional Smoothing coefficients along each axis """ def __init__(self, n_pass=None, compensation=None, stride=None, alpha=None, **kw): self.n_pass = n_pass self.compensation = compensation self.stride = stride self.alpha = alpha self.handle_init(kw) ``` -------------------------------- ### PICMI_CylindricalGrid Constructor Source: https://picmi.readthedocs.io/en/latest/standard/grid.html Initializes a new instance of the PICMI_CylindricalGrid class with specified grid dimensions, boundaries, and boundary conditions. ```APIDOC ## class picmistandard.PICMI_CylindricalGrid ### Description Initializes an axisymmetric, cylindrical grid. Parameters can be provided as vectors or as individual axis-specific values. ### Parameters - **number_of_cells** (vector of integers) - Optional - Number of cells along each axis. - **lower_bound** (vector of floats) - Optional - Position of the node at the lower bound [m]. - **upper_bound** (vector of floats) - Optional - Position of the node at the upper bound [m]. - **lower_boundary_conditions** (vector of strings) - Optional - Conditions at lower boundaries (periodic, open, dirichlet, absorbing_silver_mueller, neumann). - **upper_boundary_conditions** (vector of strings) - Optional - Conditions at upper boundaries (periodic, open, dirichlet, absorbing_silver_mueller, neumann). - **nr** (integer) - Optional - Number of cells along R. - **nz** (integer) - Optional - Number of cells along Z. - **n_azimuthal_modes** (integer) - Optional - Number of azimuthal modes. - **rmin** (float) - Optional - Position of first node along R [m]. - **rmax** (float) - Optional - Position of last node along R [m]. - **zmin** (float) - Optional - Position of first node along Z [m]. - **zmax** (float) - Optional - Position of last node along Z [m]. - **bc_rmin** (vector of strings) - Optional - Boundary condition at min R. - **bc_rmax** (vector of strings) - Optional - Boundary condition at max R. - **bc_zmin** (vector of strings) - Optional - Boundary condition at min Z. - **bc_zmax** (vector of strings) - Optional - Boundary condition at max Z. - **moving_window_velocity** (vector of floats) - Optional - Moving frame velocity [m/s]. - **refined_regions** (list of lists) - Optional - List of refined regions [level, lo, hi, refinement_factor]. - **lower_bound_particles** (vector of floats) - Optional - Position of particle lower bound [m]. - **upper_bound_particles** (vector of floats) - Optional - Position of particle upper bound [m]. - **rmin_particles** (float) - Optional - Position of min particle boundary along R [m]. - **rmax_particles** (float) - Optional - Position of max particle boundary along R [m]. - **zmin_particles** (float) - Optional - Position of min particle boundary along Z [m]. - **zmax_particles** (float) - Optional - Position of max particle boundary along Z [m]. - **lower_boundary_conditions_particles** (vector of strings) - Optional - Particle conditions at lower boundaries (periodic, absorbing, reflect, thermal). - **upper_boundary_conditions_particles** (vector of strings) - Optional - Particle conditions at upper boundaries (periodic, absorbing, reflect, thermal). - **bc_rmin_particles** (string) - Optional - Particle boundary condition at min R. - **bc_rmax_particles** (string) - Optional - Particle boundary condition at max R. - **bc_zmin_particles** (string) - Optional - Particle boundary condition at min Z. - **bc_zmax_particles** (string) - Optional - Particle boundary condition at max Z. - **guard_cells** (vector of integers) - Optional - Number of guard cells. - **pml_cells** (vector of integers) - Optional - Number of PML cells. ``` -------------------------------- ### Initialize Field and Particle Parameters Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/fields.html Initializes grid and particle boundary parameters, performing sanity checks to ensure either individual attributes or vector values are provided. ```python number_of_dimensions = 1 def __init__(self, number_of_cells=None, lower_bound=None, upper_bound=None, lower_boundary_conditions=None, upper_boundary_conditions=None, nx=None, xmin=None, xmax=None, bc_xmin=None, bc_xmax=None, moving_window_velocity=None, refined_regions=[],lower_bound_particles=None, upper_bound_particles=None, xmin_particles=None, xmax_particles=None, lower_boundary_conditions_particles=None, upper_boundary_conditions_particles=None, bc_xmin_particles=None, bc_xmax_particles=None, guard_cells=None, pml_cells=None, **kw): # Sanity check and init of input arguments related to grid parameters assert (number_of_cells is None) and (nx is not None) or \ (number_of_cells is not None) and (nx is None), \ Exception('Either number_of_cells or nx must be specified') assert (lower_bound is None) and (xmin is not None) or \ (lower_bound is not None) and (xmin is None), \ Exception('Either lower_bound or xmin must be specified') assert (upper_bound is None) and (xmax is not None) or \ (upper_bound is not None) and (xmax is None), \ Exception('Either upper_bound or xmax must be specified') assert (lower_boundary_conditions is None) and (bc_xmin is not None) or \ (lower_boundary_conditions is not None) and (bc_xmin is None), \ Exception('Either lower_boundary_conditions or bc_xmin') assert (upper_boundary_conditions is None) and (bc_xmax is not None) or \ (upper_boundary_conditions is not None) and (bc_xmax is None), \ Exception('Either upper_boundary_conditions or bc_xmax must be specified') if number_of_cells is None: number_of_cells = [nx] if lower_bound is None: lower_bound = [xmin] if upper_bound is None: upper_bound = [xmax] if lower_boundary_conditions is None: lower_boundary_conditions = [bc_xmin] if upper_boundary_conditions is None: upper_boundary_conditions = [bc_xmax,] # Sanity check and init of input arguments related to particle boundary parameters # By default, if not specified, particle boundary values are the same as field boundary values # By default, if not specified, particle boundary conditions are the same as field boundary conditions if lower_bound_particles is None: if (xmin_particles is None): lower_bound_particles = lower_bound else: lower_bound_particles = [xmin_particles] if upper_bound_particles is None: if (xmax_particles is None): upper_bound_particles = upper_bound else: upper_bound_particles=[xmax_particles] if lower_boundary_conditions_particles is None: if (bc_xmin_particles is None): lower_boundary_conditions_particles = lower_boundary_conditions else: lower_boundary_conditions_particles = [bc_xmin_particles] if upper_boundary_conditions_particles is None: if (bc_xmax_particles is None): upper_boundary_conditions_particles = upper_boundary_conditions else: upper_boundary_conditions_particles = [bc_xmax_particles] ``` -------------------------------- ### step(nsteps=1) Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/simulation.html Runs the simulation for a specified number of timesteps. ```APIDOC ## step(nsteps=1) ### Description Run the simulation for `nsteps` timesteps. ### Parameters - **nsteps** (integer) - Optional - The number of timesteps (default=1). ``` -------------------------------- ### PICMI_ElectrostaticSolver Source: https://picmi.readthedocs.io/en/latest/standard/field.html Constructor for the electrostatic field solver class. ```APIDOC ## class picmistandard.PICMI_ElectrostaticSolver ### Description Electrostatic field solver class. ### Parameters - **grid** (grid instance) - Required - Grid object for the diagnostic - **method** (string) - Required - One of 'FFT', or 'Multigrid' - **required_precision** (float) - Optional - Level of precision required for iterative solvers - **maximum_iterations** (integer) - Optional - Maximum number of iterations for iterative solvers ``` -------------------------------- ### PICMI_ParticleListDistribution Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/particles.html Initializes a particle distribution by providing explicit lists of positions, velocities, and weights. ```APIDOC ## PICMI_ParticleListDistribution ### Description Load particles at the specified positions and velocities. ### Parameters - **x** (float) - Optional - List of x positions of the particles [m] - **y** (float) - Optional - List of y positions of the particles [m] - **z** (float) - Optional - List of z positions of the particles [m] - **ux** (float) - Optional - List of ux positions of the particles (ux = gamma*vx) [m/s] - **uy** (float) - Optional - List of uy positions of the particles (uy = gamma*vy) [m/s] - **uz** (float) - Optional - List of uz positions of the particles (uz = gamma*vz) [m/s] - **weight** (float) - Required - Particle weight or list of weights, number of real particles per simulation particle ``` -------------------------------- ### Defining a PICMI class Source: https://picmi.readthedocs.io/en/latest/_sources/how_to_use/implementing.rst.txt Implement PICMI classes by subclassing the corresponding class from picmistandard and defining an init method. ```python import picmistandard class Simulation( picmistandard.PICMI_Simulation ): def init(self, kw): # Code-specific initialization self.initialized_space_charge_sources = False ``` -------------------------------- ### Execute Simulation Steps Source: https://picmi.readthedocs.io/en/latest/_modules/picmistandard/simulation.html Advances the simulation by a specified number of timesteps. Must be implemented by the simulation backend. ```python def step(self, nsteps=1): """ Run the simulation for `nsteps` timesteps Parameters ---------- nsteps: integer, default=1 The number of timesteps """ raise NotImplementedError ``` -------------------------------- ### PICMI_Simulation Class Methods Source: https://picmi.readthedocs.io/en/latest/_sources/standard/simulation.rst.txt Methods available on the PICMI_Simulation object for configuring and running simulations. ```APIDOC ## PICMI_Simulation ### Description The central object in a PICMI script used to define simulation time, field solvers, registered species, and other simulation parameters. ### Methods - **step()**: Advances the simulation by one step. - **add_species(species)**: Registers a species to the simulation. - **add_laser(laser)**: Adds a laser to the simulation. - **add_applied_field(field)**: Adds an applied field to the simulation. - **write_input_file(filename)**: Generates the simulation input file. - **extension()**: Returns the simulation extension. ```