oxiflow 0.3.0

Generic PDE solving engine for transport, reaction and diffusion phenomena (∂u/∂t + ∇·F = S)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# oxiflow — Development Program

This document is the architectural reference for oxiflow. It covers the design principles,
milestone specifications, design invariants, ecosystem strategy, and decision log that guide
all implementation work from v0.1 to v3.0.

> **Current version:** v0.0.1 (crates.io name reservation)
> **Active development:** v0.1 placeholder in preparation
> **Document version:** 2.0 — March 2026

---

## Table of Contents

1. [Vision & Principles]#1-vision--principles
2. [Milestone Overview]#2-milestone-overview
3. [J1 — Core Architecture (v0.2)]#3-j1--core-architecture-v02
4. [J2 — Complete Context (v0.3)]#4-j2--complete-context-v03
5. [J3 — Multi-Component (v0.4)]#5-j3--multi-component-v04
6. [J4 — Solvers & Discretisation (v0.4–0.5)]#6-j4--solvers--discretisation-v04-05
7. [J5 — Performance (v0.7)]#7-j5--performance-v07
8. [J6 — Ecosystem v1.0]#8-j6--ecosystem-v10
9. [FEM Compatibility — v2.0 Trajectory]#9-fem-compatibility--v20-trajectory
10. [J8 — Niche Frameworks — v3.0]#10-j8--niche-frameworks--v30
11. [Known Ecosystem Frameworks]#11-known-ecosystem-frameworks
12. [Architectural Decision Log]#12-architectural-decision-log
13. [Risk Register]#13-risk-register
14. [Timeline]#14-timeline

---

## 1. Vision & Principles

oxiflow is a generic Rust engine for numerical modelling of fields and fluxes — any problem
governed by conservation laws or field equations of the canonical form:

```
∂u/∂t + ∇·F(u, ∇u) = S(u, x, t)
```

where `u` is a field (concentration, velocity, temperature, pressure, magnetic field...),
`F` is a flux (advective + diffusive + dispersive), and `S` is a source or reaction term.

The engine serves as the foundation for a family of domain-specific **niche frameworks**
that add physical vocabulary, pre-implemented models, and declarative configuration for
specific scientific communities — chromatography, surface geophysics, heat transfer,
diffusive electromagnetism, and any domain a third party wishes to address.

### Non-negotiable design principles

- **Declarative before implicit** — model requirements are expressed in types, not runtime
  conventions
- **Generic ContextValue** — context variables cover scalars, vectors, matrices and fields,
  not just `f64`
- **Compile-time type safety** — configuration errors cause compile errors or immediate
  pre-solve failures, never silent panics
- **Zero overhead for simple cases** — a scalar model pays no cost from generics
- **Open extensibility** — adding a context type, solver, or domain requires no modification
  of the engine core
- **Strict separation of concerns** — model declares, calculator executes, solver
  orchestrates, Scenario validates
- **Anticipated FEM compatibility** — v1.0 abstractions are designed to not presuppose
  structured grids (INV-1/2/3)
- **Plugin-safe API** — all public traits are object-safe so third-party framework crates
  can implement them without accessing engine internals (INV-4, from v2.0)

### Positioning

oxiflow is not a full CFD framework (like OpenFOAM) and not a Python wrapper around LAPACK.
It is a numerical composition engine providing building blocks for rigorous, maintainable,
performant PDE solvers in any domain of continuous physics — and the foundation for a family
of niche frameworks that bring that power to specific scientific communities with minimal
boilerplate.

---

## 2. Milestone Overview

| Milestone              | Version | Target   | Theme                                           |
|------------------------|---------|----------|-------------------------------------------------|
| J0 — Foundations       | v0.0.5  | Acquired | crates.io placeholder · CI · project structure  |
| J1 — Core Architecture | v0.1    | Acquired | ContextValue · OxiflowError · Mesh (INV-1)      |
| J2 — Complete Context  | v0.2    | M+4      | Requiring BCs · topological ordering            |
| J3 — Multi-Component   | v0.3    | M+6      | PhysicalQuantity · CouplingOperator (INV-3)     |
| J4a — Integrators      | v0.4    | M+8      | Temporal integrators                            |
| J4b — Discretisation   | v0.5    | M+10     | DiscreteOperator (INV-2) · FD/FV/WENO           |
| J5 — Performance       | v0.6    | M+13     | Rayon · cache · benchmarks                      |
| J6 — Ecosystem v1.0    | v1.0    | M+16     | 7 examples · FEM audit · stable API             |
| J7 — FEM               | v2.0    | M+24     | Unstructured meshes · ALE · INV-4 plugin-safe   |
| J8 — Frameworks        | v3.0    | M+32     | oxiflow-chrom · oxiflow-geo · CLI · third-party |

Each milestone is independently deliverable. J1 alone (v0.2) is a usable library for
chromatography modelling. Third-party framework development can begin as soon as v2.0
is published and INV-4 is in place.

---

## 3. J1 — Core Architecture (v0.2)

### 3.1 ContextValue

```rust
pub enum ContextValue {
    Scalar(f64),
    Vector(DVector<f64>),
    Matrix(DMatrix<f64>),
    Field2D(DMatrix<f64>),
    Boolean(bool),
}
```

### 3.2 OxiflowError

```rust
#[derive(Debug, thiserror::Error)]
pub enum OxiflowError {
    #[error("Missing calculator for variable: {0:?}")]
    MissingCalculator(ContextVariable),
    #[error("Computation failed for {variable:?}: {source}")]
    ComputationFailed { variable: ContextVariable, source: Box<dyn std::error::Error> },
    #[error("Circular dependency detected involving: {0:?}")]
    CircularDependency(ContextVariable),
    #[error("Type mismatch: expected {expected:?}, got {actual:?}")]
    TypeMismatch { expected: &'static str, actual: &'static str },
    #[error("Invalid domain configuration: {0}")]
    InvalidDomain(String),
    #[error("External data error: {0}")]
    ExternalData(String),
    #[error("Solver diverged at t={time:.4e}: {reason}")]
    SolverDivergence { time: f64, reason: String },
}
```

### 3.3 RequiresContext

```rust
pub trait RequiresContext {
    fn required_variables(&self) -> Vec<ContextVariable>;
    fn optional_variables(&self) -> Vec<ContextVariable> { vec![] }
    fn depends_on(&self) -> Vec<ContextVariable> { vec![] }
    fn priority(&self) -> u32 { 100 }
}
```

### 3.4 Mesh trait — INV-1

```rust
pub trait Mesh: Send + Sync {
    fn n_dof(&self) -> usize;
    fn coordinates(&self, i: usize) -> Vec<f64>;
    fn spatial_dimension(&self) -> usize;
    fn characteristic_length(&self) -> f64;
}
```

**Exit criterion:** a simple chromatography model works end-to-end with `ComputeContext`.
`UniformGrid1D` implements `Mesh`.

---

## 4. J2 — Complete Context (v0.3)

Requiring `BoundaryCondition` — closes the gap from the original architecture.
Topological ordering via Kahn's algorithm. Enriched built-in calculators (gradient, Laplacian,
quadrature, external tabulated data, HDF5 file reader).

Chromatography BC mappings:

| Chromatography BC | Mathematical type | Context needed                  |
|-------------------|-------------------|---------------------------------|
| Simplified BC     | Dirichlet         | injection concentration profile |
| Danckwerts inlet  | Robin             | time + gradient                 |
| Danckwerts outlet | Neumann           | gradient only                   |

---

## 5. J3 — Multi-Component (v0.4)

Indexed `PhysicalQuantity`. `MultiDomainState`. `CouplingOperator` inter-domain (INV-3).
Proto lahar–lake example on regular grids — the regression base for v2.0 FEM.

---

## 6. J4 — Solvers & Discretisation (v0.4–0.5)

Temporal integrators: Forward Euler, RK4, DoPri45, Backward Euler, Crank–Nicolson, BDF2/3,
IMEX (Strang splitting).

Abstract `DiscreteOperator` (INV-2) — integrators are generic over the scheme:

```rust
pub trait DiscreteOperator: Send + Sync {
    type MeshType: Mesh;
    fn apply(&self, field: &ContextValue, mesh: &Self::MeshType)
        -> Result<ContextValue, OxiflowError>;
}
```

Spatial schemes: FD (upwind/centred, 1st/2nd order), WENO3/5, conservative FV,
Lax–Wendroff, flux limiters (MinMod, Van Leer, Superbee), adaptive Péclet-based selection.

Linear algebra delegated to `nalgebra` (dense) and `faer` (sparse).

---

## 7. J5 — Performance (v0.7)

Rayon parallelism (opt-in `parallel` feature). Dirty-flag cache. Criterion benchmarks.
Feature flags: `parallel`, `serde`, `hdf5`.

**Exit criterion:** reference benchmark (1D diffusion, 1000 points, 10k steps) < 100 ms.

---

## 8. J6 — Ecosystem v1.0

Seven multi-domain examples: competitive chromatography, transient heat transfer,
Gray–Scott Turing patterns, Burgers boundary layer, Terzaghi consolidation,
magnetic diffusion (proto), lahar–lake coupled grids.

FEM invariant audit before publication (INV-1/2/3 verified across the full codebase).

API stability: SemVer strict, `cargo-semver-checks` in release pipeline, MSRV documented.

---

## 9. FEM Compatibility — v2.0 Trajectory

### 9.1 Motivating case

A rapid gravitational movement (lahar, landslide) entering a body of water and generating
a submersion wave. Requires unstructured meshing for irregular geometry and adaptive
refinement for the wave front — both impossible with finite differences.

| Component        | Model                           | Challenge                       |
|------------------|---------------------------------|---------------------------------|
| Granular domain  | Bingham + extended Saint-Venant | moving boundary · adaptive mesh |
| Fluid domain     | Shallow Water equations         | irregular bathymetry            |
| Moving interface | ALE formulation                 | mass/momentum transfer          |

### 9.2 INV-4 — Plugin-safe API

**Introduced at v2.0.** All public traits must be object-safe and fully accessible from
an external crate without depending on engine internals.

Verification: a dedicated integration test crate `oxiflow-test-plugin` (external, not
part of the workspace) implements all four public traits and is compiled in CI.

```rust
// This must compile from an external crate — never from pub(crate) types
use oxiflow::{PhysicalModel, BoundaryCondition, CouplingOperator, DiscreteOperator, Mesh};

struct ExternalModel;
impl PhysicalModel for ExternalModel { /* ... */ }
impl RequiresContext for ExternalModel { /* ... */ }
```

INV-4 is the prerequisite for v3.0. No niche framework can be developed before it is in
place and verified.

### 9.3 v2.0 scope

Unstructured mesh (Gmsh/Triangle readers, triangles 2D, tetrahedra 3D, h-adaptive
refinement). Function spaces (P1, P2 Lagrange, Raviart–Thomas, DG0). FEM assembler
(stiffness and mass matrices, Gauss quadrature, face integration). Sparse linear solvers
(`faer-sparse`, ILU/AMG preconditioners). ALE formulation for the lahar–lake example.

---

## 10. J8 — Niche Frameworks — v3.0

### 10.1 Architecture

The engine exposes a `PluginRegistry` that frameworks use to register their components:

```rust
// Engine (oxiflow)
pub struct PluginRegistry {
    models:      HashMap<&'static str, Box<dyn ModelFactory>>,
    calculators: HashMap<&'static str, Box<dyn CalculatorFactory>>,
    boundaries:  HashMap<&'static str, Box<dyn BCFactory>>,
}

// Framework (e.g. oxiflow-chrom)
pub fn register(registry: &mut PluginRegistry) {
    registry.register_model("langmuir",      LangmuirFactory);
    registry.register_model("thomas",         ThomasFactory);
    registry.register_model("sma",            SMAFactory);
    registry.register_bc("danckwerts",        DanckwertsFactory);
    registry.register_bc("simplified",        SimplifiedBCFactory);
    registry.register_calculator("dispersion",AxialDispersionFactory);
}
```

The engine has no knowledge of any framework. Frameworks depend on the engine.
This is a strict one-direction dependency.

### 10.2 Declarative configuration

The engine provides the generic TOML infrastructure. Each framework extends it with
domain-specific sections:

```toml
# Resolved by the engine
[solver]
integrator = "crank_nicolson"
dt = 0.01
t_end = 600.0

[mesh.column]
type = "uniform_1d"
length = 0.25
n_points = 500

# Resolved by oxiflow-chrom
[chromatography.column]
mode = "gradient_elution"

[[chromatography.solute]]
name = "protein_A"
isotherm = "langmuir"
H = 2.5
b = 0.08

[chromatography.boundary]
inlet  = "danckwerts"
outlet = "danckwerts"
```

### 10.3 CLI

```bash
oxiflow run problem.toml          # solve
oxiflow check problem.toml        # validate before solving
oxiflow list frameworks           # oxiflow-chrom, oxiflow-geo, ...
oxiflow list models --framework chrom
```

### 10.4 Planned first-party frameworks

| Crate            | Domain                     | Key models                                             |
|------------------|----------------------------|--------------------------------------------------------|
| `oxiflow-chrom`  | Chromatography             | Langmuir, SMA, Thomas, gradient elution, Danckwerts BC |
| `oxiflow-geo`    | Surface geophysics         | Bingham Saint-Venant, Shallow Water, ALE interface     |
| `oxiflow-thermo` | Heat transfer              | Fourier flux, Robin BC, phase change                   |
| `oxiflow-em`     | Diffusive electromagnetism | magnetic diffusion, eddy currents                      |

### 10.5 Third-party frameworks

Third parties are explicitly encouraged to publish `oxiflow-*` crates on crates.io.
Requirements for a third-party framework:

- Depends on `oxiflow = "2"` (or higher).
- Preserves the `NOTICE` file from the engine in any redistribution (Apache 2.0 requirement).
- Uses a compatible license (Apache 2.0 recommended; any OSI-approved license accepted).
- Uses the `oxiflow-` prefix on crates.io for discoverability.
- Opens a PR against the engine repository to be added to the
  [Known Ecosystem Frameworks]#11-known-ecosystem-frameworks list below.

---

## 11. Known Ecosystem Frameworks

| Crate            | Domain             | Maintainer        | Status       |
|------------------|--------------------|-------------------|--------------|
| `oxiflow-chrom`  | Chromatography     | oxiflow core team | Planned v3.0 |
| `oxiflow-geo`    | Surface geophysics | oxiflow core team | Planned v3.0 |
| `oxiflow-thermo` | Heat transfer      | oxiflow core team | Planned v3.0 |
| `oxiflow-em`     | Diffusive EM       | oxiflow core team | Planned v3.0 |

*To add a framework to this list, open a PR modifying this table.*

---

## 12. Architectural Decision Log

| Decision               | Choice                                              | Rejected alternative            | Milestone | Invariant |
|------------------------|-----------------------------------------------------|---------------------------------|-----------|-----------|
| Calculator return type | `ContextValue` enum                                 | `f64` scalar only               | J1        |           |
| Error type             | `OxiflowError` enum                                 | `String`                        | J1        |           |
| Context access API     | `ComputeContext` type-safe from v0.2                | Progressive migration           | J1        |           |
| Needs declaration      | Separate `RequiresContext` trait                    | Method on `PhysicalModel`       | J1        |           |
| Spatial support        | Abstract `Mesh` trait                               | `dx`/`nx` in `PhysicalState`    | J1        | INV-1     |
| BC requirements        | `RequiresContext` on `BoundaryCondition`            | Manual aggregation              | J2        |           |
| Ordering               | Hybrid topology + priority                          | Pure DAG or priority only       | J2        |           |
| Multi-component        | Indexed `PhysicalQuantity`                          | Flat enum with breaking changes | J3        |           |
| Multi-domain coupling  | `CouplingOperator` with `DomainId` + `Interface`    | Ad-hoc method                   | J3        | INV-3     |
| Spatial operators      | Abstract `DiscreteOperator` parameterised by `Mesh` | FD hardcoded                    | J4        | INV-2     |
| Linear solvers         | `faer`/`nalgebra` delegation                        | Custom implementation           | J4        |           |
| Parallelism            | Rayon, opt-in feature flag                          | Mandatory or absent             | J5        |           |
| Caching                | Dirty flag + temporal invalidation                  | Systematic recomputation        | J5        |           |
| API stability          | SemVer + `cargo-semver-checks` + FEM audit          | Informal convention             | J6        |           |
| Plugin architecture    | Object-safe traits + `PluginRegistry`               | Monolithic crate                | J7        | INV-4     |
| Framework config       | TOML + runtime registry                             | proc-macro DSL                  | J8        |           |
| License                | Apache 2.0 only                                     | MIT or dual MIT/Apache          | J0        |           |

---

## 13. Risk Register

| ID      | Risk                                                               | Probability | Mitigation                                                                                                               |
|---------|--------------------------------------------------------------------|-------------|--------------------------------------------------------------------------------------------------------------------------|
| R1      | `ContextValue` generics too complex for users                      | Medium      | Ergonomic helpers (`.as_scalar()?`); user testing at v0.2                                                                |
| R2      | Silent dependency ordering bugs                                    | Low         | Exhaustive cycle detection tests; debug logging                                                                          |
| R3      | `PhysicalQuantity` indexing too verbose                            | Medium      | Idiomatic constructors (`::solute(k)`); UX feedback before v1.0                                                          |
| R4      | Implicit solvers require heavy linear algebra                      | High        | Delegate to `faer`/`nalgebra`; document limits                                                                           |
| R5      | Rayon + potential `unsafe`                                         | Low         | Opt-in flag; ThreadSanitizer in CI; explicit `unsafe` review                                                             |
| R6      | Scope too ambitious — no milestone delivered                       | Medium      | Each milestone independently deliverable                                                                                 |
| R7      | Breaking change forced before v1.0                                 | Low         | Accepted pre-1.0 but documented                                                                                          |
| R8      | INV-1/2/3 silently violated during J1–J6                           | Medium      | Formal audit at J6; dedicated integration tests                                                                          |
| R9      | ALE incompatible with CouplingOperator design                      | Low         | Proto lahar–lake at J3 is the test bench                                                                                 |
| **R10** | **INV-4 violated — third-party frameworks break on engine update** | **Medium**  | **`oxiflow-test-plugin` external crate in CI from v2.0; `cargo-semver-checks` in release pipeline**                      |
| **R11** | **Fragmentation — incompatible third-party frameworks**            | **Low**     | **INV-4 + stable public API is the only compatibility contract; framework authors are responsible for their own SemVer** |

---

## 14. Timeline

| Month   | Milestone            | Key objectives                                                 |
|---------|----------------------|----------------------------------------------------------------|
| M0      | v0.0.5 — Foundations | crates.io placeholder · CI · README · NOTICE                   |
| M+1–2   | v0.1 — J1            | ContextValue · OxiflowError · Mesh (INV-1)                     |
| M+3–4   | v0.2 — J2            | Requiring BCs · topology · built-in calculators                |
| M+5–6   | v0.3 — J3            | PhysicalQuantity · CouplingOperator (INV-3) · proto lahar–lake |
| M+7–8   | v0.4 — J4a           | Temporal integrators                                           |
| M+9–10  | v0.5 — J4b           | DiscreteOperator (INV-2) · FD/FV · WENO                        |
| M+11–13 | v0.6 — J5            | Rayon · cache · benchmarks                                     |
| M+14–15 | v0.9 — RC            | 7 examples · API freeze · FEM audit                            |
| M+16    | v1.0                 | Stable release · official publication                          |
| M+17–24 | v2.0 — J7            | Unstructured mesh · FEM assembler · ALE · INV-4                |
| M+25–32 | v3.0 — J8            | oxiflow-chrom · oxiflow-geo · oxiflow-thermo · CLI             |
| M+32+   | Third-party          | Community frameworks on crates.io                              |

---

*oxiflow Development Program v2.0 · March 2026 · Living document — updated at each milestone*