Skip to content

Native scientific process calls

V0.3.0 connects the native Aerosol aggregate to explicit CPU scientific strategies. The aggregate owns ParticleData, full-order GasData, and EnvironmentData references; strategies own physical configuration and RNG. The integration regression is particula/integration_tests/native_scientific_processes_test.py. It builds through the v0.3.0 public initializers/builders and forbids facade construction.

Representation and inventory

Representation Population storage Species inventory in kg Volume
discrete Bin number density, m^-3 Sum of per-particle mass times bin density, times V Exactly 1 m^3
continuous_pdf Radius PDF dn/dr, m^-4 Radius trapezoidal integral of mass times PDF, times V Exactly 1 m^3
particle_resolved Raw representative counts Sum of per-particle mass times count Positive physical V

Per-particle species mass is kg. Resolved number density is count/V. Gas concentration is kg/m^3 in complete gas order, including inert lanes. CPU strategies currently require one box. Container support for more boxes does not imply multi-box strategy execution.

Explicit calls and configuration

Pass aerosol.particles, aerosol.gas, and scalar values from aerosol.environment to the configured strategy:

import particula as par
from docs.Examples.native_state_access import build_aerosol, build_condensation

# Run from the v0.3.0 development checkout; the fixture includes ordered inert gas.
aerosol = build_aerosol()
condensation = build_condensation(aerosol.gas).condensation_strategy
coagulation = par.dynamics.BrownianCoagulationStrategy("particle_resolved")
wall_loss = par.dynamics.SphericalWallLossStrategy(
    wall_eddy_diffusivity=1e-3, chamber_radius=0.5,
    distribution_type="particle_resolved",
)
time_step = 1.0
initial_particle_mass = aerosol.particles.species_mass_inventory.copy()
initial_gas = aerosol.gas.concentration.copy()
temperature = float(aerosol.environment.temperature[0])
pressure = float(aerosol.environment.pressure[0])

condensation.step(
    aerosol.particles, aerosol.gas, temperature, pressure, time_step
)
coagulation.step(aerosol.particles, temperature, pressure, time_step)
wall_loss.step(aerosol.particles, temperature, pressure, time_step)

These names denote configured process objects, not aggregate methods or a new orchestration API. Each call preserves its supplied container and primary array identities. Preflight validates current mutable state before publication; CPU stochastic draws are not rolled back after consumption. Three successive calls are three separate transactions, not a whole-sequence rollback guarantee.

Condensation requires an explicit immutable process-owned map, for example CondensationSpeciesMap(("inert", "B", "A"), ((2, 0), (1, 1))). The map binds gas A to particle lane 0 and gas B to lane 1. Transport, vapor-pressure and latent-heat parameters follow full gas order; activity/surface composition follows full particle order. Skip indices refer to gas lanes. Partitioning remains dynamic; unmapped, disabled and skipped lanes do not transfer. See condensation contracts.

Native condensation supports PMF/PDF and arbitrary nonnegative resolved weights. Its finite-stage limiter accounts for actual representable mass changes, evaporation, available gas and PDF quadrature. Staggered modes retain their existing sequential current-gas coupling. Disabling gas updates models a fixed reservoir and does not establish closed-system conservation.

Complete evaporation retires a resolved particle by clearing its count and charge after gas/energy accounting. A remaining nonvolatile or unmapped core keeps the particle active. The resulting free slots are valid for subsequent coagulation and wall loss; gas-phase charge transport is not modeled.

Native coagulation supports the existing CPU mechanisms, including turbulent DNS and the charged strategy variants. Resolved merging requires equal positive active counts within a box; unequal weights reject before selection. Density steps preserve the existing number-density update while keeping per-bin species masses and charge fixed. Their intended use is uniform composition across radius or a single effective material with prescribed effective density, rather than tracking radius-dependent composition. Effective density alone does not provide per-species transport. When composition varies with size, individual species and weighted charge need not be conserved, even if total-mass error converges under grid refinement. This accepted limitation is characterized by independent tests; conservative species transport is deferred. See coagulation contracts.

Choose particle_resolved to track species composition that varies with radius or more complex interactions involving individual particles' composition, size, and charge. Resolved particles retain their own species masses as they evolve and merge. Use the supported process models and their constraints described here; resolved coagulation requires equal positive active counts.

Native CPU wall loss retains forward Euler for PMF/PDF and Bernoulli whole- representative removal for resolved counts, including unequal weights. Account for removed inventory as an explicit sink. V0.3.0 native CPU resolved removal clears charge together with mass/count, so removed slots satisfy the activation free-slot contract. Surviving and untouched inactive storage is preserved. This amends v0.3.0 charge retention without changing the CPU removal law. GPU removal also clears charge. See wall-loss contracts.

Direct/prepared Warp boundary

Transfers are explicit and preserve raw values and supported representation tags. Direct condensation supports discrete density and resolved counts with an explicit species binding; direct coagulation and wall loss support resolved counts. Tagged PDF execution rejects. Coagulation retains its eleven supported mechanism masks and equal-count restriction; no GPU DNS or unsupported mask support follows from metadata.

Configuration and ownership checks happen during preparation. Frozen prepared calls retain references and scalar semantics; callers must keep their payloads valid and re-prepare after layout, mapping or semantic changes. Enqueue does not revalidate, upload, allocate, read back, synchronize or rebind. Wall-loss prepared calls also retain the explicit kernel reset flag: persistent replay requires initialized caller-owned RNG and initialize_rng=False.

Integration and migration boundary

The native integration suite verifies condensation deltas separately in particles and mapped gas, actual resolved coagulation conservation at V=.25/¼, the retained fixed-composition density update and its characterized limitation, and wall-loss sinks. It keeps gas and environment protected across particle-only processes. The owning unit suites provide the wider mechanism, control, rejection and stochastic matrices.

Native runnable composition, execution adapters, dilution/nucleation and resident/checkpoint integration are available under their bounded contracts. See the source, communication and resident sections below, the migration guide, and the complete direct sequence. Temporary facades and untagged compatibility dispatch remain until v0.3.0; these examples do not authorize deletion, a release, or GPU performance claims.

Native source integration (v0.3.0)

Nucleation(source_config, commit_config) reads the currently held native Aerosol.gas and Aerosol.environment on each equal substep. Its source config requires an explicit NucleationSpeciesMap from particula.dynamics.nucleation.species_mapping: full expected gas names and unique (gas_index, particle_index) pairs. Gas and particle species widths may be different. Positive injection composition entries must map to a particle lane and have partitioning enabled; unmapped gas and particle-only species are preserved. Native CPU source commits require one resolved box.

Potential rates and immutable finalization records retain number-density units. At commit, admitted event density is multiplied by current physical volume. maximum_slot_weight limits represented counts per newly activated slot. Native final diagnostics expose event_count_units="count"; gas transfer and mapped conservation residuals remain mass densities. Representative-volume scaling reduces existing counts and provisional source counts with volume; it preserves pre-existing particle density and gas concentration. Physical volume evolution is a separate operation. Resampling retains count-weighted species mass and charge under its existing bounded moment checks.

Each source attempt stages before writing, retains array identities, and restores attempted particle/gas writes if a CPU writer fails. Earlier committed substeps remain applied when a later attempt fails. The small docs/Examples/Nucleation/cpu_nucleation.py example exercises this native API at non-unit volume with inert gas in the unified container. The former LegacyNucleation compatibility runnable has been removed. Construct Nucleation(source_config, commit_config) and keep environmental state on the native aerosol; no constructor-time environment copy or facade cache synchronization is required.

The direct GPU nucleation_step_gpu requires a separately prepared NucleationSpeciesBinding for tagged resolved storage. Create it with prepare_nucleation_species_map from particula.gpu.nucleation_species_mapping, supplying retained full gas names and the explicit source map. Preparation uploads only lane configuration and pins exact carrier arrays; replacing storage or metadata requires preparation again. Full-gas numerical validation outputs use gas width; resampling scratch uses particle width.

GPU source rates/final demand are densities. The existing direct algorithm requires admitted density times volume to be an integral int32 event count and activates one unit-count slot per event. It does not adopt the CPU weighted-slot packing algorithm. Native representative scaling acts on count demand and volume once, preserves gas concentration, and restores density units before final gas removal. Prepared repeated enqueue performs no allocation, transfer, readback or synchronization; device validation gates invalid live state before primary writers, with explicit observation afterward. Standalone GPU resampling and representative scaling likewise admit only resolved native storage, retaining count-weighted moments or count/volume density respectively.

Native direct communication and physical volume

The concrete GPU communication primitives accept tagged resolved counts. Particle transport moves the same represented count out of the source and into its destination, including unequal-volume boxes. Fixed-capacity planning retains its exact population matching, ascending free-slot allocation and gated commit. Count-weighted species mass and signed charge are conserved. PMF/PDF particle transport is unsupported.

volume_evolution_step_gpu prescribes physical volume: native particle counts, per-particle masses and charge remain unchanged, while every gas density scales by the old/new volume ratio. This differs from representative-volume exhaustion, which scales native counts and volume together while preserving gas density. Invalid volumes or unrepresentable count densities gate primary writes. Callers retain device placement, transfers and synchronization; prepared enqueue uses pinned storage without allocation or host readback.

Resident native metadata and diagnostics

Resident setup accepts tagged PMF and resolved populations and preserves their raw storage. It pins the population type, complete gas names, and separate particle-material and gas widths. Registry validation and capture signatures reject changed semantics or bindings; dispatch does not infer or rebind maps. Condensation and nucleation requests require their explicit uploaded mappings. Gas updates, thermodynamics and gas-shaped scratch use the full gas width.

Native number diagnostics report number density (resolved counts divided by physical volume). Total-species-mass diagnostics require an explicit CondensationSpeciesMap in ResidentDiagnosticRegistration.species_map with the session's gas order and every particle material mapped. Outputs are extensive kg in gas order: gas concentration times volume plus mapped particle inventory. Unmapped particle-only material is supported by process calls, but this bounded gas-order total-mass diagnostic rejects it rather than dropping its inventory. Two-snapshot diagnostics do not require a mass map.