H₂ Formation
This test has a single reaction with a constant rate, which means there is an exact solution to compare against at every point in time, not only at the end. Because the chemistry is so simple, what it really exercises is the integrator rather than the network.
The network
File: networks/h2form/react_h2form.jet (PRIZMO format)
There are two species: H and H2. The generated indices are idx_h and idx_h2.
What it checks
The rate coefficient is a constant, so nothing here depends on temperature, on an equation of state, or on any other species. What remains is the ODE on its own:
which integrates exactly:
Because the answer is known at every instant, you can measure the error directly rather than only spotting outright failure, and watch how that error responds as you tighten tolerances.
The factor of two
Both reactants are the same species, so each reaction event removes two H atoms. JAFF's generated right-hand side already accounts for this: the flux is k n_H², and it enters dn_H/dt twice. So if the measured τ comes out a factor of two off while the shape of the curve looks right, the most likely explanation is that the host code is applying its own duplicate-reactant convention on top of the one already in the generated code.
Setup
| Quantity | Value | Note |
|---|---|---|
| Temperature | anything, e.g. 100 K |
The rate does not use it; set something valid for your EOS. |
Initial n_H |
6.0e7 cm⁻³ |
Gives τ = 8.3333e8 s. |
Initial n_H2 |
0 |
Start fully atomic. |
| End time | 1e3 τ (8.33e11 s) |
Long enough that n_H has dropped three decades. |
| Output | log-spaced from 1e-4 τ |
The interesting error behaviour is early. |
Density only rescales time
As with cie_h, the reaction is second order, so the solution depends on t and n_H0 only through the ratio t/τ. Any starting density works, as long as you rescale the end time to keep t/τ covering the same range.
What to plot
Left: n_H/n_H0 and 2 n_H2/n_H0 against t/τ, log-log, with the analytic curve overlaid. Right: the relative error of n_H against the analytic solution, same x-axis.

Two features of the left panel are worth reading off directly. The curves cross at t/τ = 1 by construction, and n_H becomes a straight line of slope −1 once t ≫ τ. A late-time slope that is not −1 points to the wrong reaction order — something a single end-state comparison would miss entirely.
The right panel shows what a reference-quality run looks like: error near round-off early on, growing to about 1e-11 as the steps accumulate. A production run will sit higher than this, and that is entirely expected.
What to expect
With n_H0 = 6.0e7 cm⁻³ and k = 1e-17 cm³ s⁻¹:
t/τ |
n_H/n_H0 |
2 n_H2/n_H0 |
|---|---|---|
| 0.1 | 0.909091 | 0.090909 |
| 1 | 0.500000 | 0.500000 |
| 10 | 0.090909 | 0.909091 |
| 100 | 0.009901 | 0.990099 |
| 1000 | 0.000999 | 0.999001 |
Suggested acceptance:
| Quantity | Threshold |
|---|---|
largest relative error of n_H against the analytic |
< 10 × your solver's rtol |
largest departure of (n_H + 2 n_H2) / n_H0 from 1 |
< 1e-10 |
fitted τ from the late-time slope |
within 1% of 1 / (2 k n_H0) |
The first threshold is written in terms of your own tolerance on purpose: the point is whether the integrator delivers the accuracy it claims, not whether it hits some fixed number. A useful check is to halve rtol and see whether the error drops with it. If it does not, something other than truncation is setting the error floor — usually a species floor, a clip, or a wrong Jacobian.
Reference data
benchmarks/h2form/h2form_n6e7.txt — integrated at rtol = 1e-12, agreeing with the analytic solution to 4.2e-12 worst-case.
| Column | Meaning |
|---|---|
t |
time (s), for n_H0 = 6e7 |
t_tau |
t / τ |
n_H |
atomic hydrogen (cm⁻³) |
n_H2 |
molecular hydrogen (cm⁻³) |
n_H_over_n0 |
n_H / n_H0 |
Since the closed form is exact, you can skip the table entirely and compare against 1/(1 + t/τ) directly. The table is provided mainly to give a concrete sense of how close a well-converged run should get.
When it fails
| Symptom | Cause |
|---|---|
Curve has the right shape, τ off by exactly 2 |
Duplicate-reactant convention applied twice, or k interpreted as the per-atom rate. |
| Late-time slope is not −1 | Reaction order wrong — the flux is not quadratic in n_H. |
Error flat and large regardless of rtol |
Jacobian wrong (the solver falls back to very small steps and its error estimate stops being meaningful), or a floor clamping n_H2 early. |
Error grows without bound after t ≈ τ |
Explicit integrator, or step-size control disabled. |
n_H + 2 n_H2 drifts |
Renormalization or clipping enabled; neither is appropriate here. |
| Early curve looks like straight segments | Output cadence too coarse. Sample logarithmically; the integrator is likely fine. |