conatus.model.Linearization

class conatus.model.Linearization(model, about, eigenvalue='s', period=None, base_residual='check')[source]

Bases: object

Normal modes of a model about a base state (Model.linearize(about=...)).

Base values: 0 (the zero field), a number, or a callable of coordinate names; a callable is a non-constant coefficient on the coordinates it depends on (a Fourier coordinate along which it is exactly constant on the grid is dropped, declared).

Time-periodic base (period=P): a callable may also take t; the base is then U = Σ_m U_m e^{2πimt/P}, its harmonics computed by a discrete Fourier transform over _TIME_SAMPLES instants per period (the harmonics kept and the size of the dropped ones are reported by explain(); an under-sampled base is refused). Such a base has no normal modes: use floquet() (Floquet exponents) and optimal_gain() (transient growth).

Parameters:
  • about (Mapping[Any, Any])

  • eigenvalue (str)

  • period (float | None)

  • base_residual (str)

compile(N, dealias=None)[source]

(EVP, ncc, compiled IVP) at resolution N; the harmonics of a time-periodic base are in self.harmonics ({base field: {m: data}}, empty for a steady base).

Parameters:
  • N (Any)

  • dealias (Any)

property harmonics: dict

{base field: {m: data}} of the last compiled time-periodic base (empty if steady).

discretize(N, dealias=None, k=None, **kw)[source]

The Plan of the EVP (expert: its groups and matrices).

Parameters:
  • N (Any)

  • dealias (Any)

  • k (Any)

  • kw (Any)

group(plan, k=None, **which)[source]

The group of wavenumber k (Cartesian) or m=/kz=/ell= (curvilinear).

Parameters:
  • k (Any)

  • which (Any)

eigenvalues(N, *, k=None, dealias=None, drift=None, n=None, **kw)[source]

Eigenvalues s of the normal modes exp(s t) of wavenumber k (conatus.eigenvalues). On a sine/cosine axis every vertical wavenumber n pi / L (n < N) is its own group: the result gathers all of them (or only n=).

Parameters:
  • N (Any)

  • k (Any)

  • dealias (Any)

  • drift (Any)

  • n (int | None)

  • kw (Any)

wavenumber_names()[source]

{name usable in parametric(over=...): Fourier coordinate}: "k" with one periodic axis, "k<coord>" ("kx", "ky") with several.

Return type:

dict[str, str]

parametric(N, over, *, k=None, dealias=None, drift=None, drift_tol=None, **kw)[source]

ParametricEVP of the normal modes in over (same contract as Model.parametric): declared parameters of the model ("Ra") and the wavenumber ("k"; "kx", "ky" with several periodic axes, see wavenumber_names()), which becomes a continuous pencil parameter, so that X.critical(lin.parametric(N, over=("Ra", "k"), drift=N2, drift_tol=1e-6), "Ra", bracket=(a, b), over={"k": (k1, k2)}, xtol=1e-9) gives the critical point of a ready linearization. Values left out of a call take the declared ones (logged): the model’s parameters, and for a wavenumber k= or, if not given, the fundamental 2 pi / L of the box. A periodic axis not in over is fixed at k= (the group of that wavenumber, as eigenvalues(N, k=)). drift=N2 with its required drift_tol rejects spurious tau modes, as Model.parametric.

Parameters:
  • N (Any)

  • over (Any)

  • k (Any)

  • dealias (Any)

  • drift (Any)

  • drift_tol (Any)

  • kw (Any)

periodic_operator(N, *, k=None, dealias=None, fields=None, rank_tol=1e-10, ncc_cutoff=None, ncc_tail_tol=1e-08, **which)[source]

The conatus.growth.PeriodicOperator of wavenumber k: the linearized equations M X’ + L0 X = -Σ_m e^{2πimt/P} B_m X with the base flow’s harmonics (a steady base is in L0, implicit, and B = 0), the exact energy of fields (default: the velocity unknowns) and the admissible states (continuity and boundary conditions).

Parameters:
  • N (Any)

  • k (Any)

  • dealias (Any)

  • fields (Any)

  • rank_tol (float)

  • ncc_cutoff (float | None)

  • ncc_tail_tol (float)

  • which (Any)

optimal_gain(N, *, k=None, t0, T, steps, scheme, backend='cpu', dealias=None, fields=None, **which)[source]

Optimal energy gain max E(t0 + T)/E(t0) over admissible perturbations of wavenumber k (conatus.growth.OptimalGain: .G, .seed, .explain()). The time stepper (IMEX Runge-Kutta: RK111, RK222, RK443) and dt = T/steps are yours, as in simulate().

Parameters:
  • N (Any)

  • k (Any)

  • t0 (float)

  • T (float)

  • steps (int)

  • scheme (str)

  • backend (str)

  • dealias (Any)

  • fields (Any)

  • which (Any)

floquet(N, *, k=None, method, dealias=None, fields=None, steps=None, **kw)[source]

Floquet exponents of the perturbations of wavenumber k about the time-periodic base (conatus.growth.FloquetExponents): method="hill" with Nh and targets, or method="monodromy" with steps (time steps per period) and scheme.

Parameters:
  • N (Any)

  • k (Any)

  • method (str)

  • dealias (Any)

  • fields (Any)

  • steps (int | None)

  • kw (Any)

explain(N=None, *, k=None, full=False)[source]

Base state and eigenvalue convention (a few lines); with N, how the base enters. full=True with N: also every decision of the compiled eigenproblem (operator terms, taus and their modes, gauge, bases). N as in eigenvalues(): one int is the wall-normal size, the Fourier sizes then hold k (default: the fundamental wavenumber 2 pi / L of each periodic axis; the decisions do not depend on it: lin.explain(24) was refused while lin.eigenvalues(24, k=...) took the same N).

Parameters:
  • N (Any)

  • k (Any)

  • full (bool)

Return type:

str