conatus.expert.IVPSolver

class conatus.expert.IVPSolver(plan, scheme, dt, *, reduced=None, ordering='interleaved', startup='lower_order', startup_substeps=2, time_parameter=None, backend='cpu', f_backend='evaluator', complexify=False, decouple=False, bc_time='auto', check_finite=True)[source]

Bases: object

Constant-step IMEX solver of a discretized IVP (see module docstring).

Parameters:
  • plan (Plan)

  • scheme (str)

  • dt (float)

  • reduced (bool | None)

  • ordering (str)

  • startup (str)

  • startup_substeps (int)

  • time_parameter (str | None)

  • backend (str)

  • f_backend (str)

  • complexify (bool)

  • decouple (bool)

  • bc_time (str)

  • check_finite (bool | int)

set_state(data, t=0.0)[source]

Initial condition: FieldData (explicit layout) or callables of the coordinate grids. Variables not given start at zero. Resets the multistep history.

Parameters:
  • data (Mapping[Field, Any])

  • t (float)

Return type:

None

coeffs(name)[source]

Coefficient array of variable name (host array, the plan’s layout).

Parameters:

name (str)

Return type:

ndarray

grid(name)[source]

Values of variable name on its (non-dealiased) grid.

Parameters:

name (str)

Return type:

ndarray

F(X, t)[source]

Stacked explicit right-hand side F(X, t) (pseudospectral, dealiased products).

Parameters:
  • X (ndarray)

  • t (float)

Return type:

ndarray

property bc_time: str

Convention actually used for time-dependent boundary data: ‘rk’, ‘stage’ or ‘step’ (bc_time='auto' resolved; the reason of a fallback is in explain()).

bc_rows()[source]

Device rows of the time-dependent boundary data imposed at stage times, or None (no such data, or bc_time=’step’). FlowMap zeroes the same rows in the tangent and the adjoint (their right-hand side does not depend on the state).

impose_bc(rhs, t, beta, G=None)[source]

The rows of the time-dependent boundary data of a solve (a M + beta L) X = rhs replaced by beta g(t), so that L_row X = g(t) at the time t of the state computed (G: the boundary values to impose instead, a global vector – bc_time=’rk’). No-op (same array, same bits) without such data or with bc_time=’step’.

Parameters:
  • t (float)

  • beta (float)

rk_stages(x0, t, dt, tableau=None, F=None)[source]

Stage states [X_0, X_1, …, X_s] of one IMEX Runge–Kutta step (X_s = next state). The single implementation of the RK arithmetic: step() and the adjoint (conatus.adjoint.FlowMap) both use it, so tangent/adjoint replay exactly the forward stages. F: optional replacement of F() with the same signature (X, t).

Parameters:
  • x0 (ndarray)

  • t (float)

  • dt (float)

Return type:

list

step()[source]

One step of the declared scheme (start-up steps of a multistep scheme included).

Return type:

None

set_dt(dt)[source]

Change the step (Runge–Kutta only: multistep coefficients are constant-step here).

Parameters:

dt (float)

Return type:

None

run(steps, callback=None, every=None, *, record=None, cache=False)[source]

Advance steps steps; callback(self) after every step whose iteration is a multiple of every.

record (run registry, conatus.runs): True, a run name, a dict of options or an open run (with cn.runs.track(...) as run) records this call (numerics, problem hash, code, start/end state) and returns the run; None (default) records nothing and returns None. cache=True (off by default, needs record) reuses the end state of an identical recorded computation instead of stepping, with a warning saying what was reused.

callback and every go together and are both explicit: a callback without every used to be silently never called (every defaulted to 0). The call frequency costs time and changes what a monitor sees, so it is not chosen for the user; the refusal happens before any step is taken.

Parameters:
  • steps (int)

  • callback (Callable[[IVPSolver], None] | None)

  • every (int | None)

  • cache (bool)

run_graph(steps)[source]

Advance steps steps by replaying one captured CUDA graph per step (backend=’cuda’ only). Same arithmetic as run(): one step is captured once, then replayed; this removes the per-kernel launch/Python latency. Explicit opt-in. A time-dependent F is refused (a captured step would freeze t) unless the solver refreshes its time factors in device slots before each replay (spherical f_backend=’fused’ with a Runge–Kutta scheme: sphere_fused.GraphScalars; same factors as step(), rows built per block of _GRAPH_TABLE_ROWS steps).

SBDF: the multistep history lives in fixed device buffers during the replay (rotated by copies inside the graph, same values as the Python deque) and is written back to the deque afterwards, so run(), checkpoints and restarts continue identically. Steps before the history is full (start-up) are taken with step() first.

Parameters:

steps (int)

Return type:

None

save_checkpoint(path, *, grids=False)[source]

State + multistep history + clock: a restart continues bit-for-bit.

Format chosen by the suffix: .h5 / .hdf5 writes an HDF5 file readable without Conatus (conatus.io: state, history, per-unknown coefficients, provenance; with grids=True also the grid values of each unknown); any other path is a NumPy .npz (suffix added if missing, the historical format). Both are written to a temporary file then renamed, so a job killed while writing never leaves a truncated checkpoint.

Parameters:
  • path (str | Path)

  • grids (bool)

Return type:

Path

load_checkpoint(path, *, allow=())[source]

Restart from save_checkpoint() (.npz or .h5): every numerical option must match the solver’s (a restart never changes the numerics silently), and so must what the state is a state of: model, equations, parameters, resolution and geometry, and the data of every given field and the user functions (0.1.1; conatus.io._identity). allow names what may differ deliberately: parameter, given-field or function names (allow=("kappa",)) or "parameters", "data", "functions", "model", "equations", "geometry"; an allowed difference is printed by explain() and carried by every later checkpoint.

Parameters:
  • path (str | Path)

  • allow (Any)

Return type:

None

property effective_order: int

Global order of the run with its startup (review finding 17): the nominal order of the scheme, except that startup='lower_order' starts a multistep scheme with a first-order step (SBDF1, CNAB1), whose O(dt^2) local error caps the global order at 2 (SBDF3/SBDF4 converge at order 2, not 3/4); startup='rk443' keeps the nominal order.

explain(*, full=False)[source]

Scheme, step, backend and the finite-state check, in a few lines; full=True: also the system layout (groups, buckets, bands), the evaluator of F, boundary data and what runs where. Subclasses write their full text in _explain_full.

Parameters:

full (bool)

Return type:

str

memory_report(steps=None, cufft_query=None)

Declared device memory of this solver (liveness planner): conatus.runtime.memory.

Parameters:
  • steps (int | None)

  • cufft_query (bool | None)

profile(steps=10, *, warmup=2, peaks=None, restore=True)

Per-phase timing with GPU synchronisation and a simple roofline: conatus.runtime.profile.

Parameters:
  • steps (int)

  • warmup (int)

  • restore (bool)