/** * One point of a convergence study: a choice of the three knobs that decide * *how well* the same problem is being solved, rather than what the problem is. * * niter iterations of the implicit solve (structural — it unrolls into the * compiled step, so each value is its own compiled session) * lmax the spectral band, and with it the grid (also structural) * dtDiv the timestep, as an integer divisor of the model's own dt * * dt is a *divisor* rather than a free value on purpose, and it is the whole * reason the comparison can be trusted: variants have to be compared at the * same model time, and with dt = dtBase/K every variant lands exactly on the * same t after K times as many steps — no rounding, no drift, no interpolation * in time. A free dt would put each variant on its own timeline and every * difference reported would be part real and part "these are 0.003 apart". */ export interface Variant { /** Iterations of the implicit solve. */ niter: number; /** Spectral band limit. */ lmax: number; /** Timestep divisor: this variant runs at dtBase / dtDiv. */ dtDiv: number; } /** Stable identity of a variant, for keying maps and the reference