conatus.model.Simulation

class conatus.model.Simulation(comp, *, scheme, dt, backend='cpu', **solver_kw)[source]

Bases: object

Time integration of a compiled IVP (Model.simulate): scheme and dt are explicit.

Parameters:
  • comp (Compiled)

  • scheme (str)

  • dt (float)

  • backend (str)

  • solver_kw (Any)

property t: float

Current simulation time.

property dt: float

Time step (fixed at simulate; the run never changes it on its own: only an explicit Studio set on a step declared settable by watch(settable=...), recorded).

property iteration: int

Number of steps taken.

initial(*, layout=None, check=True, t=None, **values)[source]

Initial state by unknown name: callables of coordinate names (T=lambda x, z: -z, preferred: unambiguous), numbers, or arrays of grid values with exactly the shape of sim.grid(name) (e.g. the state of another simulation at the same N; the layout is the grid of grid(), components first, then the coordinates in order, i.e. np.meshgrid(x, z, indexing="ij")); unknowns not given start at zero (declared by explain()).

On a grid with two axes of the same size the shape cannot tell indexing="ij" from NumPy’s default "xy" (transposed): such an array is refused unless it is one returned by sim.grid(...) or layout="ij" declares it.

Callable data are checked (conatus.model.initial_check): non-finite values are refused, and so are clearly wrong data (relative spectral tail beyond the resolution above INITIAL_TAIL_REFUSE on some axis, or a jump at the ends of a periodic axis: an aliased mode, a function not periodic on the box), naming the axis; data that are only not fully resolved (tail between INITIAL_TAIL_TOL and INITIAL_TAIL_REFUSE, e.g. the coarse N of a resolution study) give one InitialDataWarning, recorded by explain(). check=False silences both (declared by explain()).

t: the time at which this state is given (default 0). Time-dependent forcing and boundary data are evaluated from it, every output row and checkpoint carries times t + k dt, run(until=...) is read on that clock, checkpoints record it (a chain continued by resume_or_start() with another t is refused) and explain() states it. In a model with an unknown named t (which then has no time), t= is that unknown’s data.

Parameters:
  • layout (str | None)

  • check (bool)

  • t (Any)

  • values (Any)

Return type:

Simulation

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

Advance to time until (must be a whole number of steps: dt is never changed) or by steps steps. callback(sim) runs every every steps (both or neither), with this Simulation as argument, like the functions of watch() (the expert IVPSolver.run passes the solver). A watched simulation (watch()) also calls the watch every poll steps; a stop from the Studio raises StopRun out of here (the run ends where it is).

record / cache: the run registry, as IVPSolver.run (conatus.runs): with record given, the recorded run is returned; otherwise this Simulation (chaining).

on_stop: what a Studio stop does: "raise" (default, v0.1) raises cn.StopRun out of here; "return" ends the run where it is and returns normally, so that the post-processing after run() still runs (sim.stopped then holds the reason).

Parameters:
  • until (float | None)

  • steps (int | None)

  • callback (Callable | None)

  • every (int | None)

  • record (Any)

  • cache (bool)

  • on_stop (str)

watch(run_id, *, film=None, stats=None, every_s=0.5, scalars_every_s=0.25, poll=10, film_mb=256.0, max_px=384, max_px3d=48, spool=None, checkpoint_dir=None, meta=None, controls_every_s=1.0, settable=None)[source]

Make the run visible live in the Studio, with its film.

film: the views, a list of field names (["T", "u.x"]) or {name: source} with a source = a field name, a function f(sim) or cn.view(...) (scale, slice, 3D mode); the first is the default view. stats: {name: f(sim) | cn.series(...) | cn.spectrum(...) | cn.profile(...)}. every_s: wall seconds between two frames of a view; scalars_every_s: between two evaluations of the numbers; poll: steps between two calls of the watch; controls_every_s: wall seconds between two reads of the Studio commands. settable={"dt": (lo, hi)}: the time step may be changed from the Studio or an agent (command set, bounds checked, Runge-Kutta schemes only: a multistep scheme, SBDF* or CNAB*, is refused with settable because its history was built with one dt; recorded as an event). Note the units: every_s, scalars_every_s and controls_every_s are wall-clock seconds, poll is in steps (output(every=) and checkpoints(every=) count steps). The Studio shows nothing else (no hidden physics); the numbers of the run are unchanged (tests/studio/test_watch.py). Defaults are declared by explain(). Returns the Watch.

Parameters:
  • run_id (str)

  • film (Any)

  • stats (Mapping[str, Any] | None)

  • every_s (float)

  • scalars_every_s (float)

  • poll (int)

  • film_mb (float)

  • max_px (int)

  • max_px3d (int)

  • spool (str | Path | None)

  • checkpoint_dir (str | Path | None)

  • meta (Mapping[str, Any] | None)

  • controls_every_s (float)

  • settable (Mapping[str, Any] | None)

output(path, tasks, *, every, mode=None, initial=True)[source]

Write tasks to the HDF5 analysis file path every every steps during run() (cn.io.AnalysisFile): ["T", "u.x"] (grid values of unknowns or components) or {name: name | f(sim)}. initial (default True): the state at the start of the next run() is written too (the row of t = 0 on a fresh start; never twice: a resumed chain already holds it), declared by explain(); initial=False: the first row is at iteration every. mode is required if the file exists ("w" replaces, "a" appends, "resume" appends after a restart from an older checkpoint, dropping the rows after the current iteration: declared by explain()). Rows hold sim_time, iteration and the provenance of the run; read back with cn.io.read(path).

Parameters:
  • path (str | Path)

  • tasks (Any)

  • every (int)

  • mode (str | None)

  • initial (bool)

particles(positions, *, path=None, every=None, velocity='u', at_walls='refuse', mode=None, initial=True)[source]

Passive tracer particles advected during run() (conatus.model.particles). positions: (P, d) in coordinate order or {coord: array}. The velocity at a particle is the exact spectral series of velocity at its position; each flow step advances the particles by one RK4 step, the midpoint velocity interpolated in time (cubic, last four flow states): order 4 in a steady flow, 3 in an unsteady one. Periodic axes: unwrapped positions (also written wrapped). at_walls: "refuse" (a step ending outside the walls raises) or "clip" (put back on the wall, counted). path + every: an HDF5 file of the cn.io layout (position, position_unwrapped, velocity, wall_clips; dims t, particle, component; mode and initial as output()). Cartesian boxes, CPU and GPU. Returns the Tracers (positions(), velocities(), explain()).

Parameters:
  • positions (Any)

  • path (str | Path | None)

  • every (int | None)

  • velocity (str)

  • at_walls (str)

  • mode (str | None)

  • initial (bool)

dye(name, path, *, every, mode=None, initial=True, field=True)[source]

Write the dye name (declared by m.dye, or any scalar unknown) and its conservation diagnostics every every steps during run() (conatus.model.dye.DyeFile): grid values (field=True), mass = integ(c), variance, minimum, maximum and the spectral tail; mode and initial as output(). Read back with cn.io.read(path).

Parameters:
  • name (str)

  • path (str | Path)

  • every (int)

  • mode (str | None)

  • initial (bool)

  • field (bool)

checkpoints(directory, *, every, keep=2, grids=False)[source]

Exact restart files directory/checkpoint_<iteration>.h5 every every steps during run(), the keep most recent kept (cn.io.CheckpointSeries; default conatus.io.checkpoint.CHECKPOINT_KEEP = 2: the latest and the one before it). The next job resumes with sim.restart(cn.io.latest(directory)).

Parameters:
  • directory (str | Path)

  • every (int)

  • keep (int)

  • grids (bool)

properties(*, every, **props)[source]

Global flow properties evaluated every every steps during run() (the role of Dedalus’ GlobalFlowProperty): props.max("Re"), min, grid_average, volume_average, integral. A property is an unknown or component name or a function f(sim) of grid values (conatus.diagnostics.properties).

Parameters:
  • every (int)

  • props (Any)

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

Checkpoint now: state, multistep history and clock (.h5: HDF5 with provenance, readable by cn.io.read; .npz: NumPy). A restart continues bit-for-bit. A suffix naming another format (.hdf, .nc, …) is refused: it used to be written as a NumPy file with .npz appended (review of the inputs audit).

Parameters:
  • path (str | Path)

  • grids (bool)

Return type:

Path

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

Continue from a checkpoint (save / checkpoints); the scheme, dt, resolution and options must be those of the file (checked, never adapted), and so must the model, its equations, its parameters and its box: a difference is refused with the list of what differs. allow names what may differ deliberately, e.g. allow=("kappa",) to continue this state at a new kappa (also "parameters", "model", "equations", "geometry"); it is printed by explain() and carried by every later checkpoint. None (what cn.io.latest returns for an empty directory) is refused with an explanation.

Parameters:
  • path (str | Path | None)

  • allow (Any)

Return type:

Simulation

resume_or_start(directory, *, allow=(), check=True, t=None, **initial)[source]

One script for every job of a chain: continue from the latest checkpoint of directory (cn.io.latest) if it holds one, else start from initial (as initial(); the directory is created). Afterwards an output() without mode creates its file on a fresh start ("w"; an existing file is refused, never replaced silently: mode="w" replaces it explicitly) and continues it after a restart ("resume": rows written after the checkpoint are dropped, the exact restart writes them again). Which branch was taken, and each output’s mode, are declared by explain(). Call it before output() and checkpoints(). The checkpoint must be a state of this run (model, equations, parameters, resolution, box: restart(); allow= names what may differ); check is passed to initial() on a fresh start. Both checkpoint formats are found (checkpoint_*.h5 and checkpoint_*.npz). t: the start time of a fresh start (initial()); on a resume it must be the start time recorded by the chain’s checkpoints (refused otherwise: the script would describe another run).

Parameters:
  • directory (str | Path)

  • allow (Any)

  • check (bool)

  • t (Any)

  • initial (Any)

Return type:

Simulation

unwatch()[source]

Stop watching: the final status is sent and the telemetry writer stops.

Return type:

None

flowmap(T, *, t0=None, checkpoints=None)[source]

Exact discrete tangent and adjoint of this simulation over the horizon T (conatus.adjoint.FlowMap: jvp, vjp, Revolve with checkpoints slots; t0 required when the equations depend on time). The state vectors are those of sim.solver (sim.solver.X); the tau unknowns are carried, never shown. Calling the map, Φ(X0), leaves this simulation where it was (state, time, iteration, multistep history): the map runs the solver and puts them back (review of the state audit, F6: sim.flowmap(T)(X0) used to move the simulation to X_N at time t0 + T).

Parameters:
  • T (float)

  • t0 (float | None)

  • checkpoints (int | None)

nlop(*, T, E0, fields=None, t0=None, checkpoints=None, **kw)[source]

Nonlinear optimal perturbation of this simulation (NLOP.from_solver): maximise the energy ½∫|u|² dV at time T over seeds of energy E0. fields: the velocity unknowns by default (declared with m.velocity); pressure and taus never enter the energy.

Parameters:
  • T (float)

  • E0 (float)

  • fields (tuple[str, ...] | None)

  • t0 (float | None)

  • checkpoints (int | None)

  • kw (Any)

lyapunov(n_vectors, *, transient, align, T, reortho_every, inner, n_blocks, seed, starts=None, zero_mean=(), project=None, covariant=False, clv_window=None, clv_backward=None, clv_every=1, clv_checkpoints=None, progress=None)[source]

Lyapunov exponents (and covariant Lyapunov vectors) of this simulation’s discrete map (conatus.chaos.lyapunov_spectrum): the n_vectors leading exponents with their standard errors, from the exact tangent of the step (same scheme, same dt), on one or several trajectories integrated as one batch (CPU or GPU, the backend of the simulation). Durations are times, each a whole number of steps (transient, align) or of intervals reortho_every * dt (T, clv_window, clv_backward), never rounded:

  • transient: trajectory only; align: trajectory and tangent vectors (alignment, no averaging); T: averaging time per trajectory, in n_blocks blocks;

  • inner: "euclidean" (on the state vector of coefficients) or a positive diagonal weight; seed: the random initial tangent vectors;

  • starts: None (the current state), an array (B, n) of states, or a list of sim.initial keyword dicts (B trajectories); the simulation’s state is not advanced;

  • zero_mean=("u",): tangent vectors restricted to zero mean for these unknowns (all axes periodic: the invariant subspace of conserved means, e.g. Kuramoto–Sivashinsky), or project=f (V -> P V) for another invariant subspace;

  • covariant=True: the CLVs of Ginelli et al. (2007) over a window of length clv_window ending clv_backward before the end (backward transient), kept every clv_every interval; clv_checkpoints=s bounds the memory (s checkpoints and one recomputation, see lyapunov_spectrum).

The result (LyapunovResult) has explain() (exponents ± errors, Kaplan–Yorke dimension, CLV memory, covariance residual, principal angles), angles(j), pair_angle(i, j), domination(tau) (domination of the Oseledets splitting, entangled clusters, physical-mode count) and clv_grid(name, i) (a CLV as grid values).

Parameters:
  • n_vectors (int)

  • transient (float)

  • align (float)

  • T (float)

  • reortho_every (int)

  • inner (Any)

  • n_blocks (int)

  • seed (int)

  • starts (Any)

  • zero_mean (Any)

  • project (Callable | None)

  • covariant (bool)

  • clv_window (float | None)

  • clv_backward (float | None)

  • clv_every (int)

  • clv_checkpoints (int | None)

  • progress (Callable | None)

grid(name)[source]

Values of an unknown on the grid (coordinate(c) gives the points). On a sine/cosine axis only the physical interval [a, b] is returned (N + 1 points, both walls included), not the doubled period.

Parameters:

name (str)

Return type:

ndarray

evaluate(expr)[source]

Grid values of an expression of the current state written as in the equations ("dz(T)", "0.5*u@u", "Ra*T - p"): unknowns, given fields, parameters and the time t; on the grid of grid() (constant directions broadcast). An expression constant in space (a full integral "integ(u@u)/2", a parameter) is returned as a number (Python float or complex; a vector: its components), not as a grid array. The pseudospectral products are those of the right-hand side (dealiased grid, then the first N modes kept). Cartesian geometries (the curvilinear evaluators keep their own layouts: refused there).

Parameters:

expr (str)

Return type:

Any

coordinate(name)[source]

Grid points of coordinate name matching grid() (a sine/cosine axis: the N + 1 points of [a, b]; disk, annulus, pipe, sphere, ball, shell: the solver’s own grids).

Parameters:

name (str)

Return type:

ndarray

coeffs(name)[source]

Spectral coefficients (expert layout; a sine/cosine axis: the RealFourier(2N) coefficients of the doubled period, cos/-sin pairs, half of them zero by parity).

Parameters:

name (str)

Return type:

ndarray

cfl(velocity='u', safety=REQUIRED)[source]

CFL time step of the current state (a stability indicator, not an error control). safety has no default (REQUIRED in help()): it scales the returned step (0.5 before v0.1).

Parameters:
  • velocity (str)

  • safety (float)

Return type:

float

methods()[source]

The Methods paragraph (conatus.methods) with the native-layer decisions.

explain(*, full=False)[source]

The run in a few lines: resolution, scheme, time step, backend, the summary of the model’s decisions, the initial state, the checks, outputs and warnings. full=True: every automatic decision of the compiled model (term-by-term split, taus and their modes, gauge, bases) and the whole solver layout.

Parameters:

full (bool)

Return type:

str