# AcaysiaRT

> For the complete documentation index, see [llms.txt](https://acaysia.com/llms.txt); a single-file corpus of every page is at [llms-full.txt](https://acaysia.com/llms-full.txt). Every page in that index is served as Markdown: append `.md` to its URL or send `Accept: text/markdown`.

Canonical: https://acaysia.com/engines/acaysia-rt

**Simulation Runtime**

A high-throughput GPU simulation runtime built for **ensemble prediction** — the control, optimization, and learning workflows that single-trajectory solvers cannot support. One templated CUDA core serves **127 registered process models**, from a pH-CSTR to a 168-state chromatography column, each one bit-exact parity-tested against a PyTorch reference. Proven first on chemical reactors.

It is the runtime underneath the Acaysia MPPI control system, the engine [AcaysiaDRT](https://acaysia.com/engines/acaysia-drt.md) composes for spatial detail, and — through its [Rete](https://acaysia.com/engines/acaysia-rt.md) layer — the engine that runs whole plants with recycle.

*Schematic of an MPPI ensemble rollout: thousands of sampled control trajectories fanning out from one process state, cost-weighted toward a setpoint band. Schematic — MPPI samples N rollouts over horizon H, then softmax-weights them by cost.*

## Headline Stats

- **127** — Registered process models
- **6.1B** — Reactor-steps/sec on one RTX 5080
- **182×** — Faster than the PyTorch reference

## Measured, With Conditions Attached

Every number below is a reproducible benchmark from the repository, not a projection. A throughput figure without its batch size, horizon, and GPU is not a claim.

| Backend | 10,000 rollouts × H=100 | Throughput |
| --- | --- | --- |
| PyTorch (CPU) — reference / debug only | 29.85 ms | ~33 M reactor-steps/sec |
| **CUDA (RTX 5080, Blackwell sm_120)** | **0.164 ms** | **~6.1 B reactor-steps/sec** |

### Multi-GPU: Data-parallel batch sharding

Reactors are independent, so a batch splits across GPUs and results stay **bit-exact** against the single-GPU path. Measured on 2× RTX 5080 at N=200,000 × H=100 — a 646 MB trajectory.

| Mode | Time | Throughput |
| --- | --- | --- |
| 1 GPU (all N) | 5.6 ms | 3.6 B steps/sec |
| 2 GPU, shards resident | 2.0 ms | 10 B steps/sec (~2.8×) |
| 2 GPU, gathered to one device | 23 ms | 0.9 B steps/sec |

The trajectory tensor is large, so gathering it back to one device dominates the kernel. Multi-GPU pays off when the batch exceeds one card's VRAM, or when each GPU keeps its shard resident across many ticks — per-GPU MPPI or training — rather than gathering every call.

## One Core, 127 Process Models

The engine and MPPI kernels are `template<class Model>` and instantiated per model, so the same high-performance core serves every reactor archetype. A new model is a registry drop-in architecturally — it inherits the engine *and* model-generic MPPI without touching dispatch.

### Reactors & separations: The classical core

pH-CSTR, reactive CSTR, PFR, batch and semi-batch. Binary and multi-feed distillation, dividing-wall columns, absorbers, strippers, extractors, decanters, flash drums, evaporators, crystallizers.

### Minerals & pyrometallurgy: Heavy industry

Leach tanks, autoclave pressure-oxidation, thickeners, grinding mills, flotation cells, hydrocyclones, screens, filter presses, EAF and BOF steelmaking on JANAF thermodynamics.

### Energy transition: Electrochemical & capture

SOEC electrolyzers, vanadium redox-flow batteries, solid-sorbent direct-air capture on a temperature/vacuum swing, fired heaters, boilers, compressors, expanders, FCC regenerators.

### Bio, water & food: Living and regulated processes

Immobilized-enzyme packed beds, penicillin fed-batch fermentation, photobioreactors, ASM2d biological nutrient removal, UV advanced-oxidation, UHT pasteurization.

| Representative model | What it is | Controlled output |
| --- | --- | --- |
| **pH-CSTR** | Neutralization with carbonate and weak acid/base equilibria — the reference model | pH |
| Distillation column | Binary constant-molar-overflow, tray-by-tray (Skogestad "Column A") | Distillate purity |
| Reaction-network CSTR | Data-defined mass-action reactor, fixed-dim, any network — hosts 45 curated processes | Product concentration |
| Crystallizer | Cooling MSMPR via the method of moments | Temperature → crystal size |
| Autoclave POx leach | Pressure-oxidation hydrometallurgical leach | Metal extraction |
| Dividing-wall column | 82-state thermally-coupled distillation | Side-draw purity |
| Penicillin fermenter | Bajpai–Reuss fed-batch antibiotic fermentation | Product titer |
| SOEC electrolyzer | Solid-oxide electrolysis cell | Hydrogen rate |

A representative selection. Alongside the 127 registered models sit **45 curated reaction-network processes** running on the shared reaction-network engine. **126 of 127** are MPPI-controllable — the exception is `pipe`, a transfer-line connector. The largest state dimension in the registry is 168; 43 models carry the stream contract that makes them wireable into a [Rete](https://acaysia.com/engines/acaysia-rt.md) plant.

## Technical Specifications

### Backend policy: CUDA is production

The CUDA engine is the only production backend. PyTorch exists for distribution/ABI, the Python API surface, and reference correctness checking — it is not a second execution engine, and selecting it emits an explicit warning.

### Kernels: One core, instantiated per model

Adding a process model does not mean writing a new engine. Each model plugs into the same templated CUDA core and the same controller, so performance work done once benefits every model in the registry — and a new one arrives without a bespoke code path to maintain.

### API: Tensors in, tensors out

`step` / `rollout` / `observe` dispatch through the registry; `step_soa` and `rollout_soa` are the structure-of-arrays fast path for MPPI hot loops. TORCH_LIBRARY bindings keep tensors zero-copy on device.

### State design: Conserved totals, projected equilibrium

Speciation is never carried in state. The step marches conserved totals and clamps to physical bounds; `observe()` solves equilibrium on demand — a log-domain Newton iteration for pH — and applies sensor bias at the output.

## Model-Generic MPPI

One sampling-based CUDA controller works with every registered model. Its cost is data-driven over a model's observable vector — per-output target, weight, and bounds — so a model picks what it tracks by setting weights. There is no per-model controller code to write.

### Sampling: Thousands of futures per tick

MPPI needs thousands of parallel rollouts over a 100–200 step horizon with consistent, deterministic stepping. That requirement is the reason this runtime exists, and it is what makes path-integral control practical for process plants.

### Closed loop: Convergence-tested per model

Every MPPI-controllable model ships a closed-loop convergence test, not just a smoke test — the controller has to actually drive that model's tracked output to target in CI.

### Biasing: Surrogate corrections, cleanly bounded

The biasing layer is the entry-side transform that shapes a learned surrogate's predicted corrections into a model's declared correction slots — 117 of the 127 models have them. It is deliberately standalone: torch and the ontology only, enforced by test.

### Plants: Whole-flowsheet control

Single units compose into plants through the Rete layer below, where one MPPI sample becomes one whole-plant rollout — recycle loops included.

## Rete: Whole Plants, Not Just Units

A plant is not a pile of unit operations — it is a **loop**. Product streams get fed back into the units that made them, and every recycle changes the duty of everything upstream. Rete is the layer that wires AcaysiaRT models into a full flowsheet and marches the whole thing forward at once, recycle included.

*Flowsheet schematic: fresh feed enters a reactor, flows to a decanter, which splits into a product draw (30%) and a recycle stream (70%) returning to the reactor inlet.*

### Recycle changes the answer

Run that loop at 70% recycle and the two conversion numbers move in *opposite* directions. Per-pass conversion falls from 0.4623 to 0.3068 — each trip through the reactor does less work. Overall conversion on fresh feed rises from 0.4623 to **0.5961**.

That divergence is the textbook recycle result, and it is exactly what a unit-by-unit model cannot tell you. It is also why plant decisions made from single-unit simulations go wrong: the number that matters is the one a loop produces. The balances are cross-checked against **DWSIM**.

### Control: Tune the plant, not the loop

Plant-wide MPPI treats one control sample as one whole-plant rollout, so the controller optimizes across units instead of fighting itself — the classic failure when each loop is tuned in isolation and the recycle carries the disagreement around.

### Scale: Dozens of units, thousands of futures

Plants of 50-plus mixed unit types march on the GPU, batched over thousands of samples at once. Fusing a plant into a single kernel is worth roughly **22×** over the same work run unit-by-unit on the same card.

### Portable: A plant is a document

Topology, feeds, connections, and targets live in a declarative definition you can save, diff, and hand to someone else. Configuration is an artifact, not a state buried in a session.

### Settling: Answers about dynamics

It marches in time rather than solving for a steady state, so it reports *when* a recycle loop settles and how it got there — startup, disturbance rejection, and the transients a steady-state flowsheet package never shows you.

## Validation Provenance

Validation runs on a T0–T5 ladder where **tier, numerical outcome, and health are orthogonal**. A strong oracle does not lose its tier when it exposes a model gap — which is exactly what keeps the incentives honest.

| Tier | What it means |
| --- | --- |
| **T0** | Running-deployment validation, tied to a real deployment and its committed operating envelope |
| **T1** | Full-model oracle — an independent reference covering primary behavior, regimes, and outputs |
| **T2** | Partial independent oracle — measurements, standards, or an authoritative external tool on a named subset |
| **T3** | Local scientific reference — a good validator-authored analytical model, not externally grounded |
| **T4** | Cross-implementation parity — catches numerical and indexing defects; *cannot* establish that the physics is right |
| **T5** | Supporting assurance — calibration replay, invariants, regression |

### Census: 92 of 127 models at T0–T2

72% of the roster carries independent evidence at the top three tiers, across **264 logical validators** over 200 cached runs. Current health: 261 fresh, 0 stale, 0 failed.

### Oracles: Best-in-class, per domain

A deliberate collage rather than one tool: Cantera for gas and combustion, PHREEQC for aqueous and hydrometallurgy, JANAF for pyrometallurgy, CoolProp for thermophysical properties, and published benchmarks — ASM2d/BSM, Bajpai–Reuss, HCH-1 — for biological units.

### Calibration: Blind, fit, or held-out

Every validator declares how it was calibrated. That is the structural defense against the classic failure mode of fitting a model to its own oracle and then citing the agreement as evidence.

### Test suite: 2,650 tests

Per-model CUDA↔PyTorch parity, physics invariants, and MPPI closed-loop convergence for all 127 models; plus MPPI cost-layout contracts, biasing slot writes, and multi-GPU sharding. CUDA tests are hardware-gated.

Distances are reported as multiples of the declared tolerance: 0.58× means 42% headroom remains, 1.83× means 83% over. A gap never demotes a tier — it is the result the validator was built to find, and several validators have surfaced and documented real fidelity gaps.

## Simple, Powerful API

Tensors in, tensors out. Pick a model by name; the registry handles dispatch.

**Installation (source):**

```bash
# AcaysiaRT ships from source with the CUDA extension
pip install -e .
python setup.py build_ext --inplace

# Requires torch, numpy, and the shared
# acaysia-ontology-schemas contracts package
```

**Quick Start (Python):**

```python
import torch
import acaysia_rt as art

# pH-CSTR state [N, 8]: T, V, DIC, ALK,
# WAC_TOT, WBASE_TOT, BIAS_PH, UA_SCALE
states = torch.tensor([[
    298.0, 100.0, 0.002, 0.002,
    0.0, 0.0, 0.0, 1.0
]], device="cuda")

# Roll out a horizon of 100 steps
traj = art.rollout(states, controls_seq, dt=0.1)

# Derived quantities: pH, speciation, ...
pH = art.observe(states)[:, art.OutputIndex.PH]
```

## Ready to Accelerate Your Control Systems

Contact us to discuss how AcaysiaRT can power your MPPI control and simulation workloads.

[Request Early Access](https://acaysia.com/contact.md)
