Source code for struphy.particles.parameters

from dataclasses import dataclass

import cunumpy as xp

from struphy.io.options import LiteralOptions
from struphy.utils.utils import __dataclass_repr_all_stacked__, __dataclass_repr_no_defaults__, check_option


[docs] @dataclass class LoadingParameters: """Configuration for particle (marker) loading strategies and data sources. This class encapsulates all parameters needed to initialize particles in simulations, including population size, spatial and velocity distributions, loading algorithms, and restart/external data sources. Supports multiple loading strategies: Monte-Carlo based distributions with customizable moments, regular grid tesselation, specific manually-defined markers, and loading from restart or external HDF5 files. Parameters ---------- Np : int, default=5000 Total number of particles to load into the simulation. ppc : int, optional Particles per cell to load if a grid is defined. Cell divisions follow ``domain_array``. ppb : int, optional Particles per sorting box. Sorting boxes are defined by ``boxes_per_dim``. loading : LiteralOptions.OptsLoading, default="pseudo_random" Loading algorithm strategy. Options include various Monte-Carlo methods or 'tesselation' for regular grid positioning. seed : int, optional Seed for the random number generator for reproducible results. If None, no seed is applied. moments : tuple, optional Mean velocities and temperatures defining the Gaussian velocity distribution. If None, automatically computed from the background distribution. spatial : LiteralOptions.OptsSpatialLoading, default="uniform" Spatial sampling method: 'uniform' samples uniformly in (eta1, eta2) coordinates, while 'disc' samples uniformly on the disc image of the coordinate space. specific_markers : tuple[tuple], optional Manually-defined markers as tuples of phase space coordinates (floats). Each tuple represents a single particle's initial state. n_quad : int, default=1 Number of quadrature points used for tesselation-based particle loading. set_zero_velocity: tuple Initialize velocity of Maxwellain along selected axis to be zero. dir_external : str, optional Absolute path to HDF5 file from which to load external marker data. dir_particles_abs : str, optional Absolute path to HDF5 file from which to load restart marker data. dir_particles : str, optional Relative path (relative to output folder) to HDF5 restart file for loading markers. restart_key : str, optional HDF5 dataset key within the 'restart/' folder containing marker array data. """ Np: int = 5000 ppc: int = None ppb: int = None loading: LiteralOptions.OptsLoading = "pseudo_random" seed: int = None moments: tuple = None spatial: LiteralOptions.OptsSpatialLoading = "uniform" specific_markers: tuple[tuple] = None set_zero_velocity: tuple[bool] = (False, False, False) n_quad: int = 1 dir_exrernal: str = None dir_particles: str = None dir_particles_abs: str = None restart_key: str = None def __post_init__(self): check_option(self.loading, LiteralOptions.OptsLoading) check_option(self.spatial, LiteralOptions.OptsSpatialLoading) def __repr_no_defaults__(self): return __dataclass_repr_all_stacked__(self)
[docs] @dataclass class WeightsParameters: """Configuration for particle weight handling and variance reduction. Manages particle weighting strategies used in Monte-Carlo type simulations, including control variate techniques for variance reduction and weight thresholding to eliminate negligibly-weighted particles. Parameters ---------- control_variate : bool, default=False Whether to apply control variate variance reduction technique to particle weights. reject_weights : bool, default=False Whether to filter out particles with weights below the specified threshold. threshold : float, default=0.0 Minimum weight threshold. Particles with weights below this value are rejected when ``reject_weights`` is True. """ control_variate: bool = False reject_weights: bool = False threshold: float = 0.0 def __repr_no_defaults__(self): return __dataclass_repr_all_stacked__(self)
[docs] @dataclass class BoundaryParameters: """Configuration for boundary conditions applied to particles and kernel reconstructions. Defines how particles behave at domain boundaries (particle boundary conditions) and how smoothed particle hydrodynamics (SPH) kernel reconstructions are handled at domain edges. Supports independent boundary conditions per spatial dimension. Parameters ---------- bc : tuple[LiteralOptions.OptsMarkerBC], default=("periodic", "periodic", "periodic") Particle boundary conditions for each spatial direction (3D). Options per direction: 'remove' (delete particles), 'reflect' (specular reflection), 'periodic' (wrap around), or 'refill' (reload particles). bc_refill : list, optional Refill strategy when 'refill' boundary condition is active. Either 'inner' or 'outer'. bc_sph : tuple[LiteralOptions.OptsRecontructBC], default=("periodic", "periodic", "periodic") Boundary conditions for SPH kernel reconstruction in each spatial direction. Typically matches or differs from ``bc`` depending on reconstruction needs. mean_velocity_index : int, optional If any boundary condition is 'noslip', this index specifies the position in the marker array where the mean velocity for the noslip condition is stored. """ bc: tuple[LiteralOptions.OptsMarkerBC] = ("periodic", "periodic", "periodic") bc_refill = None bc_sph: tuple[LiteralOptions.OptsRecontructBC] = ("periodic", "periodic", "periodic") mean_velocity_index: int | None = None def __post_init__(self): check_option(self.bc, LiteralOptions.OptsMarkerBC) check_option(self.bc_sph, LiteralOptions.OptsRecontructBC) def __repr_no_defaults__(self): return __dataclass_repr_all_stacked__(self)
[docs] @dataclass class SortingParameters: """Configuration for particle sorting strategies and parameters. Manages the organization of particles into spatial bins (sorting boxes) to optimize neighbor searches and interactions. Supports independent control over the number of boxes per dimension and whether to apply MPI domain decomposition along each dimension. Parameters ---------- do_sort: bool Whether to sort particles in memory. sorting_frequency: int The number of time steps between two sortings (=0 means no sorting is performed). boxes_per_dim: tuple[int] | None Number of sorting boxes in each direction of logical space, (n_eta1, n_eta2, n_eta3). If None, no sorting boxes are specified. box_bufsize : float Relative buffer size for box array (default = 0.25). A number of 1.0 means that the box array is double the size needed to hold N/n_boxes particles, where N is the total number of particles. dims_mask: tuple[bool] True if the dimension is to be used in the domain decomposition (=default for each dimension). If dims_mask[i]=False, the i-th dimension will not be decomposed. """ do_sort: bool = False sorting_frequency: int = 0 boxes_per_dim: tuple[int] | None = None box_bufsize: float = 2.0 dims_mask: tuple = (True, True, True) def __repr_no_defaults__(self): return __dataclass_repr_all_stacked__(self)
[docs] @dataclass class BinningPlot: """Configuration for particle phase-space binning and histogram generation. Produces binned distributions from particle data across specified phase-space coordinates. Supports arbitrary combinations of spatial (eta) and velocity (v) coordinates with flexible binning resolution and coordinate ranges. Automatically computes bin edges and allocates storage for full and delta-f distributions. Parameters ---------- slice : str, default="e1" Phase-space coordinates to bin, specified as underscore-separated coordinate names (e.g., 'e1', 'e1_e2', 'e1_v1'). Valid coordinates: 'e1', 'e2', 'e3' (spatial), 'v1', 'v2', 'v3' (velocity). Example: 'e1' produces 1D binning over eta1; 'e1_v1' produces 2D binning over eta1 and v1. n_bins : int | tuple[int], default=128 Number of bins per coordinate. If int, applies to all coordinates; if tuple, specifies bins for each coordinate separately. ranges : tuple[float] | tuple[tuple[float]], default=(0.0, 1.0) Binning ranges as intervals [min, max] for each coordinate. If a single tuple, applies to all coordinates; if nested tuples, specifies range for each coordinate. divide_by_jac : bool, default=True Whether to normalize distributions by the Jacobian determinant (volume-to-0-form conversion). Set False to use unnormalized bin counts. output_quantity : LiteralOptions.BinningQuantity, default="density" Quantity to compute in binning: determines weighting scheme and output format. """ slice: str = "e1" n_bins: int | tuple[int] = 128 ranges: tuple[float] | tuple[tuple[float]] = (0.0, 1.0) divide_by_jac: bool = True output_quantity: LiteralOptions.BinningQuantity = "density" def __post_init__(self): if isinstance(self.n_bins, int): self.n_bins = (self.n_bins,) if not isinstance(self.ranges[0], tuple): self.ranges = (self.ranges,) assert ((len(self.slice) - 2) / 3).is_integer(), ( f"Binning coordinates must be separated by '_', but reads {self.slice}." ) assert len(self.slice.split("_")) == len(self.ranges) == len(self.n_bins), ( f"Number of slices names ({len(self.slice.split('_'))}), number of bins ({len(self.n_bins)}), and number of ranges ({len(self.ranges)}) are inconsistent with each other!\n\n" ) check_option(self.output_quantity, LiteralOptions.BinningQuantity) # computations and allocations self._bin_edges = [] for nb, rng in zip(self.n_bins, self.ranges): self._bin_edges += [xp.linspace(rng[0], rng[1], nb + 1)] self._bin_edges = tuple(self.bin_edges) self._f = xp.zeros(self.n_bins, dtype=float) self._df = xp.zeros(self.n_bins, dtype=float) @property def bin_edges(self) -> tuple: return self._bin_edges @property def f(self) -> xp.ndarray: """The binned distribution function (full-f).""" return self._f @property def df(self) -> xp.ndarray: """The binned distribution function minus the background (delta-f).""" return self._df def __repr__(self): return __dataclass_repr_no_defaults__(self)
[docs] @dataclass class KernelDensityPlot: """Configuration for smoothed particle hydrodynamics (SPH) density reconstructions. Evaluates particle density fields at structured grid points using SPH kernel interpolation. Supports 1D, 2D, and 3D evaluations with independent resolution control per dimension. Parameters ---------- pts_e1 : int, default=16 Number of evaluation grid points in the first spatial direction (eta1). pts_e2 : int, default=16 Number of evaluation grid points in the second spatial direction (eta2). pts_e3 : int, default=1 Number of evaluation grid points in the third spatial direction (eta3). Set to 1 for 2D density plots. """ pts_e1: int = 16 pts_e2: int = 16 pts_e3: int = 1 def __post_init__(self): e1 = xp.linspace(0.0, 1.0, self.pts_e1) e2 = xp.linspace(0.0, 1.0, self.pts_e2) e3 = xp.linspace(0.0, 1.0, self.pts_e3) ee1, ee2, ee3 = xp.meshgrid(e1, e2, e3, indexing="ij") self._plot_pts = (ee1, ee2, ee3) self._n_sph = xp.zeros(ee1.shape, dtype=float) @property def plot_pts(self) -> tuple: return self._plot_pts @property def n_sph(self) -> xp.ndarray: """The evaluated density.""" return self._n_sph
[docs] @dataclass class SavingParameters: """Configuration for particle data saving strategies and parameters. Manages how particle data is saved during simulations, including the frequency of saves, the types of data to save (single markers, full distribution vs. delta-f or kernel evaluations), and the output formats. Supports flexible control over what particle information is stored and when. Parameters ---------- n_markers: int | float Number of particles/markers for which to save trajectories. If float and <1.0, then understood as the fraction of the total number of markers. binned_data: tuple[BinningPlot] A tuple of BinningPlot objects. kernel_density_plots: tuple[KernelDensityPlot] A tuple of KernelDensityPlot objects. """ n_markers: int | float = 3 binning_plots: tuple[BinningPlot] = () kernel_density_plots: tuple[KernelDensityPlot] = () def __repr_no_defaults__(self): return __dataclass_repr_all_stacked__(self)