A simple, fast, and powerful particle simulator for aerosol science.
Requires: Python 3.12+
Documentation | Examples | PyPI
pip install particulaor via conda:
conda install -c conda-forge particulaimport particula as par
# Build an aerosol system
aerosol = (
par.AerosolBuilder()
.set_atmosphere(atmosphere)
.set_particles(particles)
.build()
)
# Run dynamics (chainable with | operator)
process = par.dynamics.Condensation(strategy) | par.dynamics.Coagulation(strategy)
aerosol = process.execute(aerosol, time_step=10, sub_steps=1000)For the Canonical low-level direct-condensation contract,
see the container, shape, and CPU↔GPU transfer boundaries.
For a runnable low-level walkthrough, run python docs/Examples/gpu_direct_kernels_quick_start.py to see explicit
to_warp_* / from_warp_* boundaries, lazy kernel imports from
particula.gpu.kernels, two direct condensation calls with reused scratch
buffers, latent-heat, and energy sidecars on Warp's CPU backend by default.
For the bounded Brownian particle-resolved coagulation path, run
python docs/Examples/gpu_coagulation_direct.py. It explicitly transfers
ParticleData to Warp's CPU backend by default, performs two direct calls
with caller-owned collision and persistent RNG sidecars, and restores a CPU
checkpoint. When Warp is unavailable or disabled, it reports that no kernel
ran; it provides no CPU fallback, Runnable API, CUDA requirement, or
performance claim.
For migration details and updated API mappings, see the
ParticleData and GasData Migration Guide.
Legacy facades remain available, with deprecation planned for v0.3.0.
EnvironmentData now also participates in the public Warp CPU↔GPU helpers via
particula.gpu.{to_warp_environment_data, from_warp_environment_data} for
single-box and multi-box round trips.
Import GPU kernel entry points condensation_step_gpu and
coagulation_step_gpu from particula.gpu.kernels. Top-level
particula.gpu remains the transfer/context-helper surface and does not
re-export those direct kernel step functions. The kernel entry points accept
scalar temperature / pressure inputs, per-box Warp arrays with shape
(n_boxes,), hybrid scalar-plus-Warp-array direct inputs when environment
is omitted, or a WarpEnvironmentData via the keyword-only environment=
parameter.
Mixed scalar-plus-environment calls still fail early by design. Explicit
environment inputs must match the particle/gas device and use (n_boxes,)
temperature and pressure arrays. All accepted temperature, pressure, and
coagulation volume inputs are validated as positive finite physical values
before launch.
coagulation_step_gpu accepts an optional keyword-only mechanism_config
from particula.gpu.kernels.coagulation; this configuration API is not
re-exported from particula.gpu.kernels. Omitting it preserves the Brownian,
particle-resolved path. The direct-kernel entry point executes all four
singleton masks (1, 2, 4, 8), six unordered two-way masks (3, 5,
6, 9, 10, 12), and the four-way mask (15) for Brownian,
charged-hard-sphere, SP2016 sedimentation, and ST1956 turbulent shear.
Requested tuples normalize to that order. Non-turbulent three-way mask 7
raises the stable deferred-execution error at capability preflight, before
particle metadata or enabled-term validation. Turbulent three-way masks (11,
13, 14) proceed through particle metadata and enabled-term validation, then
raise that error before downstream normalization, allocation, RNG setup, kernel
launch, or mutation.
Approved combinations use sanitized fp64 component rates and one shared
candidate, acceptance, RNG, collision-output, and apply path. A sum of
component majorants is safe but may be conservative when component maxima occur
on different pairs. Particle state and supplied collision/RNG buffers remain
caller-owned same-device Warp resources; persistent RNG state is reused unless
initialize_rng=True requests a reset. Sedimentation-enabled modes validate
finite, nonnegative particle mass and concentration plus finite, positive
density before mutable state work.
Every turbulent-shear-enabled approved mask requires keyword-only
turbulent_dissipation (m²/s³) and fluid_density (kg/m³), each as a positive
finite Python or NumPy floating scalar or an active-device wp.float64 Warp
array shaped (n_boxes,); non-turbulent masks ignore them. This remains a
bounded direct-kernel path: it adds no high-level Runnable, CPU fallback,
hidden state transfer, graph-capture guarantee, performance claim, or broad
accuracy claim.
condensation_step_gpu additionally requires a keyword-only
ThermodynamicsConfig through thermodynamics=. After all inputs and optional
buffers validate, each successful call refreshes the caller-owned,
device-resident WarpGasData.vapor_pressure from the current normalized
per-box temperature before condensation mass transfer. This overwrite makes a
previous vapor-pressure buffer stale by design. Scalar temperatures, direct
Warp temperature arrays, and WarpEnvironmentData are supported; non-float64
temperature arrays are cast on-device for the refresh without a host
vapor-pressure transfer.
Caller-owned thermodynamics configurations and optional mass-transfer buffers may be reused across calls. A failed preflight, including missing or device-incompatible thermodynamics, leaves caller-owned simulation and output buffers unchanged.
Before a direct condensation call can mutate state, gas.partitioning must be
an active-device, binary wp.int32 mask shaped (n_boxes, n_species).
Disabled species and zero-concentration particle slots receive no transfer.
Invalid masks, and invalid optional P2-only reduction/scale/accumulator scratch
sidecars, raise ValueError without changing caller-owned state. The P2-only
sidecars finalize inventory-limited transfers during each substep. The direct
kernel updates particle masses and applies the matching particle-concentration-
weighted delta to gas.concentration after each finalized transfer.
Each successful direct condensation call executes exactly four equal
time_step / 4.0 substeps. A supplied scratch work buffer retains the final
raw P1 proposal, while the returned total (and optional energy diagnostic) use
the P2-finalized transfers accumulated over the whole call. Vapor-pressure
refresh depends on temperature, not gas concentration; subsequent
mass-transfer proposals read the gas concentration coupled by prior substeps.
The direct condensation kernel also accepts optional keyword-only,
active-device wp.float64 sidecars: latent_heat, shaped (n_species,), and
the caller-owned write-only energy_transfer, shaped (n_boxes, n_species).
Nonzero latent heat applies the per-species rate correction during each of the
four fixed substeps; omitting it, or setting a species entry to zero, preserves
that species' isothermal rate path. energy_transfer requires latent_heat
and is overwritten after successful preflight with signed, whole-call
P2-finalized transfer times latent heat. It remains caller-owned rather than
becoming a third return item; the canonical contract defines its ownership,
units, and direct-step limits.
For focused troubleshooting and reproduction commands, see the GPU condensation command matrix.
particula/
├── gas/ # Gas phase: species, vapor pressure, atmosphere
├── particles/ # Particle representations & distributions
├── dynamics/ # Time-dependent processes
│ ├── coagulation/
│ ├── condensation/
│ └── wall_loss/
├── activity/ # Activity coefficients, phase separation
├── equilibria/ # Gas-particle partitioning
└── util/ # Constants, validation, unit conversion
| Looking for... | Go to |
|---|---|
| Tutorials & walkthroughs | Examples/ |
| Scientific background | Theory/ |
| API reference | Full Docs |
| Contributing | contribute/ |
- Aerosol — Building and inspecting aerosol objects
- Dynamics — Coagulation, condensation, wall loss simulations
- Equilibria — Gas-particle partitioning calculations
- Gas Phase — Vapor pressure, species properties
- Particle Phase — Size distributions, optical properties
- Simulations — Full end-to-end scientific scenarios
-
Aerosol Tutorial — Learn how to build gas species, atmospheres, particle distributions, and combine them into an
Aerosolobject. -
CPU Latent-Heat Condensation Bookkeeping — CPU-only walkthrough showing diagnostic latent-heat bookkeeping from real condensation mass transfer with no temperature feedback.
-
Organic Partitioning & Coagulation — Full simulation of secondary organic aerosol (SOA) formation from 10 organic vapors, followed by Brownian coagulation over 10 minutes.
-
Cloud Chamber Cycles — Multi-cycle cloud droplet activation demonstrating κ-Köhler theory across 3 seed compositions (Ammonium Sulfate, Sucrose, Mixed), showing how hygroscopicity affects activation at different supersaturations.
- Gas & Particle Phases — Full thermodynamic modeling with swappable strategies
- Dynamics — Coagulation, condensation, wall loss, dilution
- Flexible Representations — Discrete bins, continuous PDF, particle-resolved
- Builder Pattern — Clean, validated object construction with unit conversion
- Composable Processes — Chain runnables with
|operator - Condensation Utilities — Non-isothermal helpers via
particula.dynamics.get_thermal_resistance_factor,particula.dynamics.get_mass_transfer_rate_latent_heat, andparticula.dynamics.get_latent_heat_energy_released - Condensation Strategies —
CondensationIsothermalplusCondensationLatentHeatwith latent-heat-correctedmass_transfer_rate()/rate()andstep()energy tracking vialast_latent_heat_energy, with optionaldynamic_viscosityoverride - Latent Heat Factories — Build constant, linear, and power-law latent heat
strategies via
particula.gas.LatentHeatFactorywith unit-aware builders and gas-phase exports for upcoming non-isothermal workflows
If you use Particula in your research, please cite:
Particula [Computer software]. DOI: 10.5281/zenodo.6634653
MIT