Process reference: wall_modes

Generated from the docstrings of vaft.process.wall_modes: 22 public functions. Each entry is what vaft.process.describe("wall_modes.<name>") prints. All process categories

Overview

The reduced vessel-wall contract (VEST-Tokamak/vfit#8) in one line: local eigenbasis, global electromagnetic dynamics. The wall’s current vector is partitioned by physical segment, each segment gets its own L/R eigenbasis, the bases are block-assembled into V_seg, and every reduced operator is then a projection of the full matrices – so the mutual inductance between segments survives in the off-diagonal blocks of the reduced inductance.

Naming trap, stated once. Throughout vaft.process.electromagnetics the passive-passive inductance is called M_mat and the passive-to-source coupling L_mat; this module keeps those argument names for compatibility and says which is which at every signature. In the formulas below L is the physics inductance (code M_mat), R the diagonal resistance (code R_mat) and M the source coupling (code L_mat).

Per segment g with diagonal R_gg and symmetric-definite L_gg::

S_g = R_gg^{-1/2} L_gg R_gg^{-1/2}          (symmetric)
S_g q = tau q                                (eigh; tau ARE the L/R times)
v     = R_gg^{-1/2} q                        (R-orthonormal)

so that v^T R_gg v = 1, v^T L_gg v = tau and R_gg v = L_gg v / tau. The eigenvalues are the local decay times; modes are ordered by descending tau within each segment and the largest-|component| entry of every mode is positive. Assembled over segments (scattered by element index, so an interleaved loop order needs no permutation)::

V_seg = blockdiag(V_1, ..., V_G)             (N, M_tot)
R_r   = V_seg^T R V_seg = I                  (computed and checked)
L_r   = V_seg^T L V_seg                      diag blocks diag(tau_g), off-diagonal coupling
M_r   = V_seg^T M                            (M_tot, n_src)
G_red = G_full V_seg                         for any (n_obs, N) response

The projection is exact in the R inner product: a = V_seg^T R I_w, which for a truncated basis is the R-orthogonal (least-dissipation) projection. Amplitudes carry units of sqrt(W): a^T a is the ohmic dissipation of the wall current. Conversions – Euclidean-normalized modes have a_E = a ||v||_2, inductance-normalized ones a_L = a sqrt(tau).

This module chooses no reduced order. It returns every mode of every segment and offers selection helpers; which modes to keep is the validation study’s question (vfit #10, vaft #494), and the tools for that question live here too: the reduced circuit solve (solve_reduced_eddy), rankings of the modes by response rather than by decay time (mode_scores), a greedy segment-wise allocation to a tolerance (allocate_per_segment), and the drive-independent moment patterns (moment_patterns) that the study compares the eigenbasis against.

Nothing here reads an ODS; vaft.omas.process_wrapper.compute_wall_mode_basis_ods does the mapping.

Functions

allocate_per_segmentGreedy segment-wise allocation M_repr to a response tolerance. Convention
build_wall_mode_basisBuild the segment-wise eigenbasis of a wall. Convention
canonical_signFlip each column so its largest-magnitude entry is positive. Convention
check_wall_mode_basisMetrics of a basis against the matrices it claims to diagonalize; no verdict.
combined_operatorsReduced operators for an arbitrary R-orthonormal basis. Convention
global_time_constantsThe whole wall’s decay times, from the full-rank reduced inductance. Convention
mode_scoresRankings of the retained modes, one value per retained coefficient.
moment_patternsDrive-independent wall patterns from the source coupling. Convention
orthonormalize_rAn R-orthonormal basis of span(X), canonical in sign. Convention
projectModal amplitudes a = V^T R I_w. Convention
reconstructWall currents I_w = V a from modal amplitudes.
reconstruction_errorHow far a reconstruction is from the full current, in the norms that matter. Convention
reduce_responseReduce any linear response with the wall elements as its columns.
reduced_operatorsProject the full wall matrices onto the retained modes. Convention
segment_eigenmodesSolve one segment’s pencil R_gg v = L_gg v / tau. Convention
select_allKeep every mode of every segment: the full-rank selection.
select_by_scoreKeep the highest-scoring modes across segments. Convention
select_slowestKeep the slowest modes, globally or per segment.
select_tau_rangeKeep the modes whose decay time lies in a range, per segment.
solve_reduced_eddyIntegrate the reduced circuit L_r da/dt + R_r a = -M_r dI_src/dt.
subspace_angles_rPrincipal angles between two mode subspaces in the R inner product. Convention
symmetrize_inductanceFold a mutual-inductance matrix onto its symmetric part, with a refusal.

allocate_per_segment

Machine-independentConvention-sensitive source
allocate_per_segment(basis, R_mat, M_mat, L_mat, drive, time, *, tolerance, metric='dissipation', G=None, score=None, step=1, max_modes=None, dt_sub=5e-05)

Greedy segment-wise allocation M_repr to a response tolerance.

A global allocation for a given total is simply select_by_score; this routine answers the other question – the smallest total that meets a response tolerance, and how it should be split between segments.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming, (N, N).

L_matnumpy.ndarrayH

Passive-to-source coupling in code naming, (N, n_src).

drivenumpy.ndarrayA

Source currents, (n_times, n_src).

timenumpy.ndarrays

Time grid of the drive.

tolerancefloat-

Relative error the allocation stops at.

metric{'dissipation', 'output'}, optional-

Which error to measure.

Gnumpy.ndarray or None, optionalany/A

Observation response, required by metric="output".

scorenumpy.ndarray or None, optional-

Ranking within each segment; output_weight when None.

stepint, optional-

Modes added per round.

max_modesint or None, optional-

Cap on the total.

dt_subfloat, optionals

Sub-step of the solves.

Returns
keeptuple of numpy.ndarray-

The allocation, one index array per segment.

historylist of dict-

One row per round: the running M_repr, its total M_total, the metric under its own name, and by_segment.

Convention

The per-segment error is the segment’s share of the global squared error in the same norm, so a segment the drive barely reaches never attracts modes. metric="output" measures the relative error of G I_w instead, which ranks a mode by what a diagnostic would see rather than by what it dissipates.

Processing steps · Defaults · Applicability · Limitations · Provenance

Processing steps

  1. Solve the full wall once under drive and rank the candidates within each segment (the output_weight ranking of mode_scores by default, which needs no more than that solve).
  2. Start from no modes at all.
  3. Each round, re-solve the reduced wall, measure the global metric and each segment’s share of it, and add step modes to the segment carrying the largest remaining error, in that segment’s ranked order.
  4. Stop when the metric drops to tolerance, when max_modes is reached, or when every candidate is used.

Defaults

metric="dissipation" is the relative R-energy error of the wall current, the norm this basis is built in; it is a conventional choice, not a tuned one. dt_sub is a validated-workflow default, as in solve_reduced_eddy.

Applicability

Machine-independent.

Limitations

Greedy, so the allocation is not proven minimal; it is the smallest total this order of additions reaches. Each round costs a reduced solve, and the result is only as general as the drive it was allocated under.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.
  3. The reduced-order validation study (VEST-Tokamak/vfit#10, vaft #494), which asks which modes to keep; this module answers no part of that question by itself.

build_wall_mode_basis

Machine-independentConvention-sensitive source
build_wall_mode_basis(R_mat, M_mat, segments, *, symmetry_rtol=1e-08, symmetry_reject=1e-06, cluster_rtol=1e-06, on_cluster='raise', residual_atol=1e-10, cond_max=1000000000000.0, provenance=None)

Build the segment-wise eigenbasis of a wall.

Partitions the wall’s current vector by physical segment, gives each segment its own eigenbasis (segment_eigenmodes), and records how it was done. No coupling is discarded here: the inter-segment mutual inductance survives because every reduced operator is later a projection of the full matrices.

NameTypeUnitDescription
R_matnumpy.ndarrayOhm

Diagonal loop resistance of the wall, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming; the physics L, (N, N)

segmentssequence-

Objects with .id and .index (WallSegment) or (id, index) pairs, together covering every element exactly once.

symmetry_rtol, symmetry_rejectfloat, optional-

Passed to symmetrize_inductance.

cluster_rtolfloat, optional-

Relative decay-time gap below which a within-segment pair counts as near-degenerate.

on_cluster{'raise', 'warn'}, optional-

What to do about such a pair.

residual_atol, cond_maxfloat, optional-

Passed to segment_eigenmodes.

provenancemapping of str to str or None, optional-

Extra entries – the asset the matrices came from, a shot, a build – merged into the recorded provenance.

Returns
—WallModeBasis-

Every segment’s complete eigenbasis, the element count, and the provenance.

Convention

Argument naming follows vaft.process.electromagnetics, not the physics: M_mat is the passive-passive inductance (physics L) and L_mat the passive-to-source coupling (physics M). R_mat is the diagonal loop resistance either way.

Raises

  • WallModeError When the segment map does not cover the elements exactly once, when a segment’s pencil is refused, or, with on_cluster="raise", when a near-degenerate pair is found.
Processing steps · Defaults · Applicability · Limitations · Provenance

Processing steps

  1. Fold the inductance onto its symmetric part (symmetrize_inductance) and record the asymmetry.
  2. Read the segment map; the segments must cover every element exactly once.
  3. Solve each segment’s pencil.
  4. Check the within-segment decay-time gaps and act on on_cluster.
  5. Record normalization, sign rule, mode order, projection formula, input asymmetry and the segment ids in the basis provenance.

Defaults

cluster_rtol = 1e-6 is a numerical convenience: inside a closer pair the individual modes are arbitrary up to rotation, so the default refuses rather than let the provenance claim a determinism it does not have. The remaining tolerances are those of the routines they are passed to.

Applicability

Machine-independent. The VEST wall’s segment map comes from vaft.machine_mapping; nothing here knows a VEST number.

Limitations

A near-degenerate eigenspace is refused, not resolved: the honest comparison between two such bases is subspace_angles_r, not a column-by-column one.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

canonical_sign

Machine-independentConvention-sensitive source
canonical_sign(V)
Show source vaft/process/wall_modes.py, lines 209–256
def canonical_sign(V: np.ndarray) -> np.ndarray:
    """Flip each column so its largest-magnitude entry is positive.

    An eigenvector is defined up to sign; without a rule two runs of the same
    build can disagree, and a stored basis cannot be compared with a fresh one.

    Parameters
    ----------
    V : numpy.ndarray
        Modes as columns, ``(n, m)`` [any].

    Returns
    -------
    numpy.ndarray
        The same modes with each column's sign fixed [any].

    Convention
    ----------
    The sign rule of this module (``SIGN_RULE = "max_abs_positive"``): the
    largest-magnitude entry of every column is made positive, ties going to the
    lowest index (``argmax`` on ``|v|``).  A pure function of the column, so
    repeated runs agree bitwise.

    Applicability
    -------------
    Machine-independent.

    Limitations
    -----------
    Two entries of exactly equal magnitude and opposite sign make the rule
    index-dependent rather than ill-defined; a near-degenerate *eigenspace* is
    the real ambiguity, and :func:`build_wall_mode_basis` refuses that case
    instead of signing it.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    V = np.array(V, dtype=float, copy=True)
    if V.ndim != 2:
        raise WallModeError("modes must be a 2-D array of columns")
    pivots = np.argmax(np.abs(V), axis=0)
    signs = np.sign(V[pivots, np.arange(V.shape[1])])
    signs[signs == 0.0] = 1.0
    return V * signs[None, :]

Flip each column so its largest-magnitude entry is positive.

An eigenvector is defined up to sign; without a rule two runs of the same build can disagree, and a stored basis cannot be compared with a fresh one.

NameTypeUnitDescription
Vnumpy.ndarrayany

Modes as columns, (n, m).

Returns
—numpy.ndarrayany

The same modes with each column’s sign fixed.

Convention

The sign rule of this module (SIGN_RULE = "max_abs_positive"): the largest-magnitude entry of every column is made positive, ties going to the lowest index (argmax on |v|). A pure function of the column, so repeated runs agree bitwise.

Applicability · Limitations · Provenance

Applicability

Machine-independent.

Limitations

Two entries of exactly equal magnitude and opposite sign make the rule index-dependent rather than ill-defined; a near-degenerate eigenspace is the real ambiguity, and build_wall_mode_basis refuses that case instead of signing it.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

check_wall_mode_basis

Machine-independent source
check_wall_mode_basis(basis, R_mat, M_mat)
Show source vaft/process/wall_modes.py, lines 1139–1200
def check_wall_mode_basis(basis: WallModeBasis, R_mat: np.ndarray, M_mat: np.ndarray) -> dict[str, Any]:
    """Metrics of a basis against the matrices it claims to diagonalize; no verdict.

    Numbers a caller or a report can threshold as it sees fit; nothing here
    decides whether a basis is good enough.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    M_mat : numpy.ndarray
        Passive-passive inductance in code naming, ``(N, N)`` [H].

    Returns
    -------
    dict
        ``n_elements``, ``n_modes``, ``r_r_identity_error``
        (``max|V^T R V - I|``), ``l_r_symmetry_error``,
        ``max_segment_residual``, ``min_relative_gap`` and ``coupling`` [-].

        ``coupling`` holds, per segment pair, the Frobenius norm of that
        off-diagonal block of ``L_r`` relative to the geometric mean of the two
        diagonal blocks, so a reader can see which segments actually talk to
        each other [-].

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    ops = reduced_operators(basis, R_mat, M_mat)
    M_tot = ops.L_r.shape[0]
    identity_error = float(np.max(np.abs(ops.R_r - np.eye(M_tot))))
    offsets = np.cumsum([0] + [seg.size for seg in basis.segments])
    coupling: dict[str, float] = {}
    for i, a in enumerate(basis.segments):
        for j, b in enumerate(basis.segments):
            if j <= i:
                continue
            block = ops.L_r[offsets[i]:offsets[i + 1], offsets[j]:offsets[j + 1]]
            scale = np.sqrt(
                np.linalg.norm(ops.L_r[offsets[i]:offsets[i + 1], offsets[i]:offsets[i + 1]])
                * np.linalg.norm(ops.L_r[offsets[j]:offsets[j + 1], offsets[j]:offsets[j + 1]])
            )
            coupling[f"{a.id}-{b.id}"] = float(np.linalg.norm(block) / scale) if scale > 0 else float("nan")
    return {
        "n_elements": basis.n_elements,
        "n_modes": basis.n_modes(),
        "r_r_identity_error": identity_error,
        "l_r_symmetry_error": float(np.max(np.abs(ops.L_r - ops.L_r.T)) / np.max(np.abs(ops.L_r))),
        "max_segment_residual": max(seg.residual for seg in basis.segments),
        "min_relative_gap": min(seg.min_relative_gap for seg in basis.segments),
        "coupling": coupling,
    }

Metrics of a basis against the matrices it claims to diagonalize; no verdict.

Numbers a caller or a report can threshold as it sees fit; nothing here decides whether a basis is good enough.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming, (N, N).

Returns
—dict-

n_elements, n_modes, r_r_identity_error (max|V^T R V - I|), l_r_symmetry_error, max_segment_residual, min_relative_gap and coupling. coupling holds, per segment pair, the Frobenius norm of that off-diagonal block of L_r relative to the geometric mean of the two diagonal blocks, so a reader can see which segments actually talk to each other [-].

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

combined_operators

Machine-independentConvention-sensitive source
combined_operators(V, R_mat, M_mat, L_mat=None, *, label='pattern')
Show source vaft/process/wall_modes.py, lines 1812–1883
def combined_operators(
    V: np.ndarray,
    R_mat: np.ndarray,
    M_mat: np.ndarray,
    L_mat: np.ndarray | None = None,
    *,
    label: str = "pattern",
) -> ReducedWall:
    """Reduced operators for an arbitrary R-orthonormal basis.

    The same projections as :func:`reduced_operators`, for a basis that is not
    (only) segment eigenmodes -- an enrichment by :func:`moment_patterns`, say,
    or a POD basis.

    Input semantics
    ---------------
    Element space: the assembled wall matrices and a basis whose columns are wall
    patterns.

    Output semantics
    ----------------
    Mode space: operators of the basis's own coordinates, labelled ``(label, k)``
    rather than by segment.

    Parameters
    ----------
    V : numpy.ndarray
        R-orthonormal basis as columns, ``(N, m)`` [Ohm**-0.5].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    M_mat : numpy.ndarray
        Passive-passive inductance in code naming, ``(N, N)`` [H].
    L_mat : numpy.ndarray or None, optional
        Passive-to-source coupling in code naming, ``(N, n_src)`` [H].
    label : str, optional
        Label component of every coefficient's ``(label, k)`` name [-].

    Returns
    -------
    ReducedWall
        ``L_r`` [H], ``R_r`` [Ohm], ``M_r`` [H] when a source coupling was given,
        and the labels [-].

    Convention
    ----------
    ``R_r`` is computed, not assumed: a basis that is not R-orthonormal in the
    matrices passed here shows up as a non-identity rather than silently changing
    the dynamics.  Use :func:`orthonormalize_r` to make one that is.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    V = np.asarray(V, dtype=float)
    r = _diagonal_resistance(R_mat, where="R_mat")
    if V.ndim != 2 or V.shape[0] != r.size:
        raise WallModeError(f"basis has shape {V.shape}; expected ({r.size}, m)")
    L = np.asarray(M_mat, dtype=float)
    return ReducedWall(
        L_r=V.T @ L @ V,
        R_r=V.T @ (r[:, None] * V),
        M_r=None if L_mat is None else V.T @ np.asarray(L_mat, dtype=float),
        labels=tuple((str(label), k) for k in range(V.shape[1])),
        keep=(np.arange(V.shape[1], dtype=np.int64),),
    )

Reduced operators for an arbitrary R-orthonormal basis.

The same projections as reduced_operators, for a basis that is not (only) segment eigenmodes – an enrichment by moment_patterns, say, or a POD basis.

NameTypeUnitDescription
Vnumpy.ndarrayOhm**-0.5

R-orthonormal basis as columns, (N, m).

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming, (N, N).

L_matnumpy.ndarray or None, optionalH

Passive-to-source coupling in code naming, (N, n_src).

labelstr, optional-

Label component of every coefficient’s (label, k) name.

Returns
—ReducedWall-

L_r [H], R_r [Ohm], M_r [H] when a source coupling was given, and the labels.

Convention

R_r is computed, not assumed: a basis that is not R-orthonormal in the matrices passed here shows up as a non-identity rather than silently changing the dynamics. Use orthonormalize_r to make one that is.

Input semantics · Output semantics · Applicability · Provenance

Input semantics

Element space: the assembled wall matrices and a basis whose columns are wall patterns.

Output semantics

Mode space: operators of the basis’s own coordinates, labelled (label, k) rather than by segment.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

global_time_constants

Machine-independentConvention-sensitive source
global_time_constants(basis, M_mat)
Show source vaft/process/wall_modes.py, lines 1097–1136
def global_time_constants(basis: WallModeBasis, M_mat: np.ndarray) -> np.ndarray:
    """The whole wall's decay times, from the full-rank reduced inductance.

    With ``R_r = I`` the reduced pencil is an ordinary symmetric eigenproblem, so
    ``eigvalsh(L_r)`` are the global L/R times.  They are not the segments' local
    times: the difference between the two is exactly the inter-segment coupling
    the basis keeps.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    M_mat : numpy.ndarray
        Passive-passive inductance in code naming, ``(N, N)`` [H].

    Returns
    -------
    numpy.ndarray
        Global decay times, descending, ``(N,)`` [s].

    Convention
    ----------
    Full rank by construction: every mode of every segment takes part, because a
    truncated basis would report the decay times of a different wall.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    V = basis.V(None)
    L_r = V.T @ np.asarray(M_mat, dtype=float) @ V
    L_r = 0.5 * (L_r + L_r.T)
    return np.sort(np.linalg.eigvalsh(L_r))[::-1]

The whole wall’s decay times, from the full-rank reduced inductance.

With R_r = I the reduced pencil is an ordinary symmetric eigenproblem, so eigvalsh(L_r) are the global L/R times. They are not the segments’ local times: the difference between the two is exactly the inter-segment coupling the basis keeps.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming, (N, N).

Returns
—numpy.ndarrays

Global decay times, descending, (N,).

Convention

Full rank by construction: every mode of every segment takes part, because a truncated basis would report the decay times of a different wall.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

mode_scores

Machine-independent source
mode_scores(basis, R_mat, M_mat, L_mat, *, G=None, drive=None, time=None, keep=None, dt_sub=5e-05)

Rankings of the retained modes, one value per retained coefficient.

Rankings, not verdicts: each is a different answer to which modes carry the wall’s response, and the order study compares them.

tau the decay time – what the spectrum alone would rank by; drive_gain tau_k ||M_r[k, :]|| ||G_red[:, k]|| – the quasi-static amplitude a unit source ramp excites in mode k, times how visible the mode is at the observation points (all ones without G); needs no drive; response_energy the rms of the projected full response a = V^T R I_w(t) under drive – how much dissipation each mode actually carried; output_weight response_energy times the observability, the ranking that minimizes the diagnostic-space error fastest on the packaged wall.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming, (N, N).

L_matnumpy.ndarrayH

Passive-to-source coupling in code naming, (N, n_src).

Gnumpy.ndarray or None, optionalany/A

Observation response with wall elements as columns, (n_obs, N); without it every mode is equally observable.

drivenumpy.ndarray or None, optionalA

Source currents, (n_times, n_src); needed by the last two rankings

timenumpy.ndarray or None, optionals

Time grid of the drive.

keepsequence of numpy.ndarray or None, optional-

Candidate modes per segment; every mode when None.

dt_subfloat, optionals

Sub-step of the full-wall solve the last two rankings need.

Returns
—dict of str to numpy.ndarray-

tau, drive_gain and, when a drive was given, response_energy and output_weight; each array is aligned with basis.labels(keep). tau is in seconds; the three rankings are relative numbers whose scale carries no meaning, only their order does.

Defaults · Applicability · Limitations · Provenance

Defaults

dt_sub = 50 us is a validated-workflow default, as in solve_reduced_eddy.

Applicability

Machine-independent. The claim that output_weight falls fastest is an observation on the packaged VEST wall, not a theorem.

Limitations

The last two rankings cost one full wall solve. Every ranking is relative to the drive and observation set it was computed with; a mode invisible to one diagnostic set is not an unimportant mode.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.
  3. The reduced-order validation study (VEST-Tokamak/vfit#10, vaft #494), which asks which modes to keep; this module answers no part of that question by itself.

moment_patterns

Machine-independentConvention-sensitive source
moment_patterns(R_mat, M_mat, L_mat, order=1)
Show source vaft/process/wall_modes.py, lines 1731–1809
def moment_patterns(R_mat: np.ndarray, M_mat: np.ndarray, L_mat: np.ndarray, order: int = 1) -> np.ndarray:
    """Drive-independent wall patterns from the source coupling.

    An R-orthonormal basis of the block Krylov space
    ``span{R^{-1} M, (R^{-1} L) R^{-1} M, ...}`` up to ``order`` blocks.  The
    first block is the resistive limit -- the wall current a constant source ramp
    settles into, ``I_w = -R^{-1} M dI_src/dt`` -- and each further block is the
    next inductive correction of the slowly driven response: the Laplace-domain
    moments of the wall's transfer function, matched at zero frequency.

    Built as a block Arnoldi iteration in the R inner product, so the blocks stay
    independent where the raw powers would collapse onto the slowest mode; a
    block that adds no new direction ends the iteration early and the basis is
    narrower than ``order * n_src``.

    Parameters
    ----------
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    M_mat : numpy.ndarray
        Passive-passive inductance in code naming; the physics ``L``, ``(N, N)``
        [H].
    L_mat : numpy.ndarray
        Passive-to-source coupling in code naming; the physics ``M``,
        ``(N, n_src)`` [H].
    order : int, optional
        How many Krylov blocks to build [-].

    Returns
    -------
    numpy.ndarray
        R-orthonormal patterns as columns, ``(N, m)`` with
        ``m <= order * n_src`` [Ohm**-0.5].

    Convention
    ----------
    Argument naming follows :mod:`vaft.process.electromagnetics`, not the
    physics: ``M_mat`` is the passive-passive inductance (physics ``L``) and
    ``L_mat`` the passive-to-source coupling (physics ``M``).  ``R_mat`` is the
    diagonal loop resistance either way.

    Applicability
    -------------
    Machine-independent.  The comparison quoted below is a VEST observation, not
    a property of the method.

    Limitations
    -----------
    A zero-frequency expansion: on the packaged VEST wall ten resistive patterns
    reproduce the probe response of a real PF drive to about 1 %, where 150
    eigenmodes are needed for the same, but fast transients remain the
    eigenmodes' territory.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    .. [vfit10] The reduced-order validation study (VEST-Tokamak/vfit#10, vaft
       #494), which asks which modes to keep; this module answers no part of that
       question by itself.
    """
    if int(order) < 1:
        raise WallModeError("order must be at least 1")
    r = _diagonal_resistance(R_mat, where="R_mat")
    L = np.asarray(M_mat, dtype=float)
    Q = orthonormalize_r(np.asarray(L_mat, dtype=float) / r[:, None], R_mat)
    blocks = [Q]
    for _ in range(int(order) - 1):
        X = (L @ blocks[-1]) / r[:, None]
        V = np.hstack(blocks)
        X = X - V @ (V.T @ (r[:, None] * X))          # R-orthogonal to everything so far
        X = X - V @ (V.T @ (r[:, None] * X))          # twice, for the usual reason
        Q = orthonormalize_r(X, R_mat, rtol=1e-8)
        if Q.shape[1] == 0:
            break
        blocks.append(Q)
    return canonical_sign(np.hstack(blocks))

Drive-independent wall patterns from the source coupling.

An R-orthonormal basis of the block Krylov space span{R^{-1} M, (R^{-1} L) R^{-1} M, ...} up to order blocks. The first block is the resistive limit – the wall current a constant source ramp settles into, I_w = -R^{-1} M dI_src/dt – and each further block is the next inductive correction of the slowly driven response: the Laplace-domain moments of the wall’s transfer function, matched at zero frequency.

Built as a block Arnoldi iteration in the R inner product, so the blocks stay independent where the raw powers would collapse onto the slowest mode; a block that adds no new direction ends the iteration early and the basis is narrower than order * n_src.

NameTypeUnitDescription
R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming; the physics L, (N, N)

L_matnumpy.ndarrayH

Passive-to-source coupling in code naming; the physics M, (N, n_src).

orderint, optional-

How many Krylov blocks to build.

Returns
—numpy.ndarrayOhm**-0.5

R-orthonormal patterns as columns, (N, m) with m <= order * n_src.

Convention

Argument naming follows vaft.process.electromagnetics, not the physics: M_mat is the passive-passive inductance (physics L) and L_mat the passive-to-source coupling (physics M). R_mat is the diagonal loop resistance either way.

Applicability · Limitations · Provenance

Applicability

Machine-independent. The comparison quoted below is a VEST observation, not a property of the method.

Limitations

A zero-frequency expansion: on the packaged VEST wall ten resistive patterns reproduce the probe response of a real PF drive to about 1 %, where 150 eigenmodes are needed for the same, but fast transients remain the eigenmodes’ territory.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.
  3. The reduced-order validation study (VEST-Tokamak/vfit#10, vaft #494), which asks which modes to keep; this module answers no part of that question by itself.

orthonormalize_r

Machine-independentConvention-sensitive source
orthonormalize_r(X, R_mat, *, rtol=1e-10)
Show source vaft/process/wall_modes.py, lines 1674–1728
def orthonormalize_r(X: np.ndarray, R_mat: np.ndarray, *, rtol: float = 1e-10) -> np.ndarray:
    """An R-orthonormal basis of ``span(X)``, canonical in sign.

    QR of ``R^{1/2} X`` with the dependent columns dropped, so a set of patterns
    that repeats a direction does not return a singular basis.

    Parameters
    ----------
    X : numpy.ndarray
        Patterns as columns, ``(N, m)`` [any].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    rtol : float, optional
        A column whose triangular-factor diagonal falls below this times the
        largest is dependent and is dropped [-].

    Returns
    -------
    numpy.ndarray
        R-orthonormal, sign-canonical basis, ``(N, m')`` with ``m' <= m``
        [Ohm**-0.5].

    Defaults
    --------
    ``rtol = 1e-10`` is a numerical convenience: the rank cut of the QR in double
    precision.

    Convention
    ----------
    Modes are R-orthonormal (``v^T R v = 1``) and sign-canonical
    (:func:`canonical_sign`), so amplitudes carry units of sqrt(W) and ``a^T a``
    is the wall current's ohmic dissipation.  This is the same normalization the eigenbasis carries, which
    is what lets a pattern basis and an eigenbasis be combined in one reduction
    (:func:`combined_operators`).

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    r = _diagonal_resistance(R_mat, where="R_mat")
    X = np.asarray(X, dtype=float)
    if X.ndim != 2 or X.shape[0] != r.size:
        raise WallModeError(f"patterns have shape {X.shape}; expected ({r.size}, m)")
    w = np.sqrt(r)[:, None]
    Q, T = np.linalg.qr(w * X)
    diag = np.abs(np.diag(T))
    independent = diag > rtol * max(diag.max() if diag.size else 0.0, 1e-300)
    return canonical_sign(Q[:, independent] / w)

An R-orthonormal basis of span(X), canonical in sign.

QR of R^{1/2} X with the dependent columns dropped, so a set of patterns that repeats a direction does not return a singular basis.

NameTypeUnitDescription
Xnumpy.ndarrayany

Patterns as columns, (N, m).

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

rtolfloat, optional-

A column whose triangular-factor diagonal falls below this times the largest is dependent and is dropped.

Returns
—numpy.ndarrayOhm**-0.5

R-orthonormal, sign-canonical basis, (N, m') with m' <= m

Convention

Modes are R-orthonormal (v^T R v = 1) and sign-canonical (canonical_sign), so amplitudes carry units of sqrt(W) and a^T a is the wall current’s ohmic dissipation. This is the same normalization the eigenbasis carries, which is what lets a pattern basis and an eigenbasis be combined in one reduction (combined_operators).

Defaults · Applicability · Provenance

Defaults

rtol = 1e-10 is a numerical convenience: the rank cut of the QR in double precision.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

project

Machine-independentConvention-sensitive source
project(basis, I_w, R_mat, keep=None)
Show source vaft/process/wall_modes.py, lines 769–826
def project(
    basis: WallModeBasis, I_w: np.ndarray, R_mat: np.ndarray, keep: Sequence[np.ndarray] | None = None
) -> np.ndarray:
    """Modal amplitudes ``a = V^T R I_w``.

    Exact for a current that lies inside the retained subspace; for a truncated
    basis it is the R-orthogonal projection, which is the least-dissipation one.

    Input semantics
    ---------------
    Element space: a wall current, one entry per element, measured or solved.

    Output semantics
    ----------------
    Mode space: amplitudes in the R inner product, so ``a^T a`` is the current's
    ohmic dissipation.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    I_w : numpy.ndarray
        Wall current, ``(N,)`` or ``(n_times, N)`` [A].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    keep : sequence of numpy.ndarray or None, optional
        Retained mode indices per segment; every mode when ``None`` [-].

    Returns
    -------
    numpy.ndarray
        Amplitudes, ``(M_tot,)`` or ``(n_times, M_tot)`` [W**0.5].

    Convention
    ----------
    Modes are R-orthonormal (``v^T R v = 1``) and sign-canonical
    (:func:`canonical_sign`), so amplitudes carry units of sqrt(W) and ``a^T a``
    is the wall current's ohmic dissipation.  Two other normalizations are in use elsewhere and
    convert from this one: Euclidean-normalized modes have ``a_E = a ||v||_2``,
    inductance-normalized ones ``a_L = a sqrt(tau)``.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    V = basis.V(keep)
    r = _diagonal_resistance(R_mat, where="R_mat")
    I_w = np.asarray(I_w, dtype=float)
    if I_w.ndim == 1:
        return V.T @ (r * I_w)
    return (I_w * r[None, :]) @ V

Modal amplitudes a = V^T R I_w.

Exact for a current that lies inside the retained subspace; for a truncated basis it is the R-orthogonal projection, which is the least-dissipation one.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

I_wnumpy.ndarrayA

Wall current, (N,) or (n_times, N).

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

keepsequence of numpy.ndarray or None, optional-

Retained mode indices per segment; every mode when None.

Returns
—numpy.ndarrayW**0.5

Amplitudes, (M_tot,) or (n_times, M_tot).

Convention

Modes are R-orthonormal (v^T R v = 1) and sign-canonical (canonical_sign), so amplitudes carry units of sqrt(W) and a^T a is the wall current’s ohmic dissipation. Two other normalizations are in use elsewhere and convert from this one: Euclidean-normalized modes have a_E = a ||v||_2, inductance-normalized ones a_L = a sqrt(tau).

Input semantics · Output semantics · Applicability · Provenance

Input semantics

Element space: a wall current, one entry per element, measured or solved.

Output semantics

Mode space: amplitudes in the R inner product, so a^T a is the current’s ohmic dissipation.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

reconstruct

Machine-independent source
reconstruct(basis, a, keep=None)
Show source vaft/process/wall_modes.py, lines 829–870
def reconstruct(basis: WallModeBasis, a: np.ndarray, keep: Sequence[np.ndarray] | None = None) -> np.ndarray:
    """Wall currents ``I_w = V a`` from modal amplitudes.

    The inverse direction of :func:`project`; exact only for the retained
    subspace, which is what :func:`reconstruction_error` measures.

    Input semantics
    ---------------
    Mode space: amplitudes of the retained modes.

    Output semantics
    ----------------
    Element space: a wall current on every element, whatever the retained order.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    a : numpy.ndarray
        Amplitudes, ``(M_tot,)`` or ``(n_times, M_tot)`` [W**0.5].
    keep : sequence of numpy.ndarray or None, optional
        Retained mode indices per segment; every mode when ``None`` [-].

    Returns
    -------
    numpy.ndarray
        Wall current, ``(N,)`` or ``(n_times, N)`` [A].

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    V = basis.V(keep)
    a = np.asarray(a, dtype=float)
    return V @ a if a.ndim == 1 else a @ V.T

Wall currents I_w = V a from modal amplitudes.

The inverse direction of project; exact only for the retained subspace, which is what reconstruction_error measures.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

anumpy.ndarrayW**0.5

Amplitudes, (M_tot,) or (n_times, M_tot).

keepsequence of numpy.ndarray or None, optional-

Retained mode indices per segment; every mode when None.

Returns
—numpy.ndarrayA

Wall current, (N,) or (n_times, N).

Input semantics · Output semantics · Applicability · Provenance

Input semantics

Mode space: amplitudes of the retained modes.

Output semantics

Element space: a wall current on every element, whatever the retained order.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

reconstruction_error

Machine-independentConvention-sensitive source
reconstruction_error(I_w, I_rec, R_mat, basis=None)
Show source vaft/process/wall_modes.py, lines 873–933
def reconstruction_error(
    I_w: np.ndarray, I_rec: np.ndarray, R_mat: np.ndarray, basis: WallModeBasis | None = None
) -> dict[str, Any]:
    """How far a reconstruction is from the full current, in the norms that matter.

    Parameters
    ----------
    I_w : numpy.ndarray
        The full wall current, ``(N,)`` or ``(n_times, N)`` [A].
    I_rec : numpy.ndarray
        The reconstruction, same shape [A].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    basis : WallModeBasis or None, optional
        When given, the same measures are reported per segment [-].

    Returns
    -------
    dict
        ``relative_l2``, ``relative_dissipation`` and ``max_abs``, plus one
        such entry per segment id when a basis was given [-].

        ``max_abs`` is the largest absolute element error, in amperes; the
        other two are relative.

    Convention
    ----------
    ``relative_dissipation`` weighs each element by its resistance -- the natural
    norm of this basis, where the error's ohmic power is compared with the
    current's -- and ``relative_l2`` is the plain Euclidean measure.  They differ
    by however unevenly the wall's resistance is distributed, so a reported
    error means nothing without saying which of the two it is.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    r = _diagonal_resistance(R_mat, where="R_mat")
    I_w = np.asarray(I_w, dtype=float).reshape(-1, r.size)
    I_rec = np.asarray(I_rec, dtype=float).reshape(-1, r.size)
    err = I_rec - I_w

    def _measures(e: np.ndarray, ref: np.ndarray, w: np.ndarray) -> dict[str, float]:
        l2 = float(np.linalg.norm(e) / max(np.linalg.norm(ref), 1e-300))
        diss = float(np.sqrt(np.sum(e**2 * w) / max(np.sum(ref**2 * w), 1e-300)))
        return {"relative_l2": l2, "relative_dissipation": diss, "max_abs": float(np.max(np.abs(e)))}

    out: dict[str, Any] = _measures(err, I_w, r[None, :])
    if basis is not None:
        out["segments"] = {
            seg.id: _measures(err[:, seg.index], I_w[:, seg.index], r[None, seg.index])
            for seg in basis.segments
        }
    return out

How far a reconstruction is from the full current, in the norms that matter.

NameTypeUnitDescription
I_wnumpy.ndarrayA

The full wall current, (N,) or (n_times, N).

I_recnumpy.ndarrayA

The reconstruction, same shape.

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

basisWallModeBasis or None, optional-

When given, the same measures are reported per segment.

Returns
—dict-

relative_l2, relative_dissipation and max_abs, plus one such entry per segment id when a basis was given. max_abs is the largest absolute element error, in amperes; the other two are relative.

Convention

relative_dissipation weighs each element by its resistance – the natural norm of this basis, where the error’s ohmic power is compared with the current’s – and relative_l2 is the plain Euclidean measure. They differ by however unevenly the wall’s resistance is distributed, so a reported error means nothing without saying which of the two it is.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

reduce_response

Machine-independent source
reduce_response(G_full, basis, keep=None)
Show source vaft/process/wall_modes.py, lines 936–982
def reduce_response(
    G_full: np.ndarray, basis: WallModeBasis, keep: Sequence[np.ndarray] | None = None
) -> np.ndarray:
    """Reduce any linear response with the wall elements as its columns.

    Probe field, flux-loop flux, grid psi or B, an EFIT table -- one matmul, no
    per-class logic, so every response class is reduced by the same basis.

    Input semantics
    ---------------
    Element space: a response matrix mapping every wall element to observations.

    Output semantics
    ----------------
    Mode space: the same map from the retained modal amplitudes.

    Parameters
    ----------
    G_full : numpy.ndarray
        Response with wall elements as columns, ``(n_obs, N)`` [any/A].
    basis : WallModeBasis
        The eigenbasis [-].
    keep : sequence of numpy.ndarray or None, optional
        Retained mode indices per segment; every mode when ``None`` [-].

    Returns
    -------
    numpy.ndarray
        ``G_red = G_full V_seg``, ``(n_obs, M_tot)`` [any/W**0.5].

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    G_full = np.asarray(G_full, dtype=float)
    if G_full.shape[-1] != basis.n_elements:
        raise WallModeError(
            f"response has {G_full.shape[-1]} wall columns, basis has {basis.n_elements} elements"
        )
    return G_full @ basis.V(keep)

Reduce any linear response with the wall elements as its columns.

Probe field, flux-loop flux, grid psi or B, an EFIT table – one matmul, no per-class logic, so every response class is reduced by the same basis.

NameTypeUnitDescription
G_fullnumpy.ndarrayany/A

Response with wall elements as columns, (n_obs, N).

basisWallModeBasis-

The eigenbasis.

keepsequence of numpy.ndarray or None, optional-

Retained mode indices per segment; every mode when None.

Returns
—numpy.ndarrayany/W**0.5

G_red = G_full V_seg, (n_obs, M_tot).

Input semantics · Output semantics · Applicability · Provenance

Input semantics

Element space: a response matrix mapping every wall element to observations.

Output semantics

Mode space: the same map from the retained modal amplitudes.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

reduced_operators

Machine-independentConvention-sensitive source
reduced_operators(basis, R_mat, M_mat, L_mat=None, keep=None)
Show source vaft/process/wall_modes.py, lines 693–766
def reduced_operators(
    basis: WallModeBasis,
    R_mat: np.ndarray,
    M_mat: np.ndarray,
    L_mat: np.ndarray | None = None,
    keep: Sequence[np.ndarray] | None = None,
) -> ReducedWall:
    """Project the full wall matrices onto the retained modes.

    The global half of the contract.  Because the *full* matrices are projected,
    the mutual inductance between segments survives in the off-diagonal blocks of
    ``L_r``; only the diagonal blocks are the local ``diag(tau_g)``.

    Input semantics
    ---------------
    Element space: the assembled wall matrices, one row and column per wall
    element, as :mod:`vaft.process.electromagnetics` builds them.

    Output semantics
    ----------------
    Mode space: operators of the retained modal coordinates, whose amplitudes
    carry units of sqrt(W).  A solve on them is the reduced circuit
    (:func:`solve_reduced_eddy`); to come back to element space, use
    :func:`reconstruct`.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].
    M_mat : numpy.ndarray
        Passive-passive inductance in code naming, ``(N, N)`` [H].
    L_mat : numpy.ndarray or None, optional
        Passive-to-source coupling in code naming, ``(N, n_src)`` [H].
    keep : sequence of numpy.ndarray or None, optional
        Retained mode indices per segment; every mode when ``None`` [-].

    Returns
    -------
    ReducedWall
        ``L_r`` ``(M_tot, M_tot)`` [H], ``R_r`` ``(M_tot, M_tot)`` [Ohm],
        ``M_r`` ``(M_tot, n_src)`` [H] when a source coupling was given, and the
        ``(segment_id, k)`` label of every coefficient [-].

    Convention
    ----------
    Argument naming follows :mod:`vaft.process.electromagnetics`, not the
    physics: ``M_mat`` is the passive-passive inductance (physics ``L``) and
    ``L_mat`` the passive-to-source coupling (physics ``M``).  ``R_mat`` is the
    diagonal loop resistance either way.

    ``R_r`` is computed rather than assumed to be the identity, so a basis built
    on other matrices than the ones passed here shows up as a non-identity
    instead of silently changing the dynamics.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    V = basis.V(keep)
    r = _diagonal_resistance(R_mat, where="R_mat")
    L = np.asarray(M_mat, dtype=float)
    L_r = V.T @ L @ V
    R_r = V.T @ (r[:, None] * V)
    M_r = None if L_mat is None else V.T @ np.asarray(L_mat, dtype=float)
    return ReducedWall(L_r=L_r, R_r=R_r, M_r=M_r, labels=basis.labels(keep), keep=basis._keep(keep))

Project the full wall matrices onto the retained modes.

The global half of the contract. Because the full matrices are projected, the mutual inductance between segments survives in the off-diagonal blocks of L_r; only the diagonal blocks are the local diag(tau_g).

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

M_matnumpy.ndarrayH

Passive-passive inductance in code naming, (N, N).

L_matnumpy.ndarray or None, optionalH

Passive-to-source coupling in code naming, (N, n_src).

keepsequence of numpy.ndarray or None, optional-

Retained mode indices per segment; every mode when None.

Returns
—ReducedWall-

L_r (M_tot, M_tot) [H], R_r (M_tot, M_tot) [Ohm], M_r (M_tot, n_src) [H] when a source coupling was given, and the (segment_id, k) label of every coefficient.

Convention

Argument naming follows vaft.process.electromagnetics, not the physics: M_mat is the passive-passive inductance (physics L) and L_mat the passive-to-source coupling (physics M). R_mat is the diagonal loop resistance either way.

R_r is computed rather than assumed to be the identity, so a basis built on other matrices than the ones passed here shows up as a non-identity instead of silently changing the dynamics.

Input semantics · Output semantics · Applicability · Provenance

Input semantics

Element space: the assembled wall matrices, one row and column per wall element, as vaft.process.electromagnetics builds them.

Output semantics

Mode space: operators of the retained modal coordinates, whose amplitudes carry units of sqrt(W). A solve on them is the reduced circuit (solve_reduced_eddy); to come back to element space, use reconstruct.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

segment_eigenmodes

Machine-independentConvention-sensitive source
segment_eigenmodes(R_gg, L_gg, *, residual_atol=1e-10, cond_max=1000000000000.0, tau_floor_rel=1e-12)

Solve one segment’s pencil R_gg v = L_gg v / tau.

The local half of the contract: each segment’s own L/R eigenbasis, from which the global dynamics are then built by projecting the full matrices.

NameTypeUnitDescription
R_ggnumpy.ndarrayOhm

The segment’s diagonal resistance, as a matrix or as its diagonal

L_ggnumpy.ndarrayH

The segment’s symmetric inductance block.

residual_atolfloat, optional-

Largest relative pencil residual accepted.

cond_maxfloat, optional-

Largest accepted spread of decay times within the segment.

tau_floor_relfloat, optional-

Smallest accepted decay time, relative to the largest.

Returns
taunumpy.ndarrays

Local decay times, descending, (n_g,).

Vnumpy.ndarrayOhm**-0.5

R-orthonormal, sign-canonical modes as columns, (n_g, n_g)

residualfloat-

max|R V - L V / tau| / max|R V|.

Convention

Modes are R-orthonormal (v^T R v = 1) and sign-canonical (canonical_sign), so amplitudes carry units of sqrt(W) and a^T a is the wall current’s ohmic dissipation. Ordering is by descending tau within the segment, which is the mode index every keep and every label refers to.

Raises

  • WallModeError When the block is not a usable inductance (a non-positive eigenvalue is a current pattern with no stored energy), when the spread exceeds cond_max so the fastest mode is numerically indistinguishable from zero, or when the residual exceeds residual_atol.
Processing steps · Defaults · Applicability · Provenance

Processing steps

  1. Whiten by the resistance: S = R^{-1/2} L R^{-1/2}, symmetric.
  2. eigh(S); the eigenvalues are the local L/R decay times.
  3. Map back, v = R^{-1/2} q, so v^T R v = 1 and v^T L v = tau.
  4. Order by descending tau and fix the signs (canonical_sign).

Defaults

All three are numerical convenience, set where double precision stops supporting the answer rather than where physics changes.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

select_all

Machine-independent source
select_all(basis)
Show source vaft/process/wall_modes.py, lines 989–1013
def select_all(basis: WallModeBasis) -> tuple[np.ndarray, ...]:
    """Keep every mode of every segment: the full-rank selection.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].

    Returns
    -------
    tuple of numpy.ndarray
        One index array per segment, holding every mode index [-].

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    return basis._keep(None)

Keep every mode of every segment: the full-rank selection.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

Returns
—tuple of numpy.ndarray-

One index array per segment, holding every mode index.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

select_by_score

Machine-independentConvention-sensitive source
select_by_score(basis, score, M, keep=None)
Show source vaft/process/wall_modes.py, lines 1454–1506
def select_by_score(
    basis: WallModeBasis, score: np.ndarray, M: int, keep: Sequence[np.ndarray] | None = None
) -> tuple[np.ndarray, ...]:
    """Keep the highest-scoring modes across segments.

    The global counterpart of :func:`select_slowest`, for any ranking -- usually
    one of :func:`mode_scores`.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    score : numpy.ndarray
        One value per coefficient of ``basis.labels(keep)`` [-].
    M : int
        How many modes to keep in total [-].
    keep : sequence of numpy.ndarray or None, optional
        Candidate modes per segment; every mode when ``None`` [-].

    Returns
    -------
    tuple of numpy.ndarray
        One index array per segment [-].

    Convention
    ----------
    Ties resolve toward the earlier label, so the selection is deterministic for
    a given score vector.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    .. [vfit10] The reduced-order validation study (VEST-Tokamak/vfit#10, vaft
       #494), which asks which modes to keep; this module answers no part of that
       question by itself.
    """
    labels = basis.labels(keep)
    score = np.asarray(score, dtype=float).reshape(-1)
    if score.size != len(labels):
        raise WallModeError(f"score has {score.size} entries for {len(labels)} candidate modes")
    order = np.argsort(-score, kind="stable")[: max(int(M), 0)]
    chosen = set(labels[i] for i in order)
    return tuple(
        np.array(sorted(k for (seg_id, k) in chosen if seg_id == seg.id), dtype=np.int64)
        for seg in basis.segments
    )

Keep the highest-scoring modes across segments.

The global counterpart of select_slowest, for any ranking – usually one of mode_scores.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

scorenumpy.ndarray-

One value per coefficient of basis.labels(keep).

Mint-

How many modes to keep in total.

keepsequence of numpy.ndarray or None, optional-

Candidate modes per segment; every mode when None.

Returns
—tuple of numpy.ndarray-

One index array per segment.

Convention

Ties resolve toward the earlier label, so the selection is deterministic for a given score vector.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.
  3. The reduced-order validation study (VEST-Tokamak/vfit#10, vaft #494), which asks which modes to keep; this module answers no part of that question by itself.

select_slowest

Machine-independent source
select_slowest(basis, M)
Show source vaft/process/wall_modes.py, lines 1016–1060
def select_slowest(basis: WallModeBasis, M: int | Sequence[int]) -> tuple[np.ndarray, ...]:
    """Keep the slowest modes, globally or per segment.

    The selection the spectrum alone suggests; whether it is the right one for a
    given drive is what :func:`mode_scores` exists to question.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    M : int or sequence of int
        A count taken globally across segments by descending decay time, or one
        count per segment [-].

    Returns
    -------
    tuple of numpy.ndarray
        One index array per segment [-].

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    .. [vfit10] The reduced-order validation study (VEST-Tokamak/vfit#10, vaft
       #494), which asks which modes to keep; this module answers no part of that
       question by itself.
    """
    if isinstance(M, (int, np.integer)):
        tau = basis.tau()
        labels = basis.labels()
        chosen = set(labels[i] for i in np.argsort(-tau, kind="stable")[: int(M)])
        return tuple(
            np.array([k for k in range(seg.size) if (seg.id, k) in chosen], dtype=np.int64)
            for seg in basis.segments
        )
    counts = list(M)
    if len(counts) != len(basis.segments):
        raise WallModeError(f"per-segment M has {len(counts)} entries for {len(basis.segments)} segments")
    return tuple(np.arange(min(int(m), seg.size), dtype=np.int64) for seg, m in zip(basis.segments, counts))

Keep the slowest modes, globally or per segment.

The selection the spectrum alone suggests; whether it is the right one for a given drive is what mode_scores exists to question.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

Mint or sequence of int-

A count taken globally across segments by descending decay time, or one count per segment.

Returns
—tuple of numpy.ndarray-

One index array per segment.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.
  3. The reduced-order validation study (VEST-Tokamak/vfit#10, vaft #494), which asks which modes to keep; this module answers no part of that question by itself.

select_tau_range

Machine-independent source
select_tau_range(basis, tau_min, tau_max=inf)
Show source vaft/process/wall_modes.py, lines 1063–1094
def select_tau_range(basis: WallModeBasis, tau_min: float, tau_max: float = np.inf) -> tuple[np.ndarray, ...]:
    """Keep the modes whose decay time lies in a range, per segment.

    Parameters
    ----------
    basis : WallModeBasis
        The eigenbasis [-].
    tau_min : float
        Lower bound, inclusive [s].
    tau_max : float, optional
        Upper bound, inclusive [s].

    Returns
    -------
    tuple of numpy.ndarray
        One index array per segment [-].

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    return tuple(
        np.flatnonzero((seg.tau >= tau_min) & (seg.tau <= tau_max)).astype(np.int64)
        for seg in basis.segments
    )

Keep the modes whose decay time lies in a range, per segment.

NameTypeUnitDescription
basisWallModeBasis-

The eigenbasis.

tau_minfloats

Lower bound, inclusive.

tau_maxfloat, optionals

Upper bound, inclusive.

Returns
—tuple of numpy.ndarray-

One index array per segment.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

solve_reduced_eddy

Machine-independent source
solve_reduced_eddy(reduced, drive, time, *, V=None, dt_sub=5e-05, method='auto')
Show source vaft/process/wall_modes.py, lines 1253–1332
def solve_reduced_eddy(
    reduced: ReducedWall,
    drive: np.ndarray,
    time: np.ndarray,
    *,
    V: np.ndarray | None = None,
    dt_sub: float = 5.0e-5,
    method: str = "auto",
) -> tuple[np.ndarray, np.ndarray | None]:
    """Integrate the reduced circuit ``L_r da/dt + R_r a = -M_r dI_src/dt``.

    The same integrator as the full wall
    (:func:`vaft.process.electromagnetics.solve_eddy_currents`), fed the projected
    operators, so the only difference between the two solutions is the retained
    subspace: with every mode kept they agree to rounding.

    Input semantics
    ---------------
    Mode space: reduced operators and a source drive in element-independent
    coordinates.

    Output semantics
    ----------------
    Mode space amplitudes, and -- when the retained ``V`` is given -- the
    reconstructed element-space wall current alongside them.

    Parameters
    ----------
    reduced : ReducedWall
        The projected operators; ``M_r`` must be present [-].
    drive : numpy.ndarray
        Source currents, ``(n_times, n_src)`` on ``time`` [A].
    time : numpy.ndarray
        Time grid of the drive [s].
    V : numpy.ndarray or None, optional
        The retained modes, ``(N, M_tot)``; when given, the wall current is
        reconstructed too [Ohm**-0.5].
    dt_sub : float, optional
        Sub-step of the integrator [s].
    method : str, optional
        Integration method, forwarded to the full-wall solver [-].

    Returns
    -------
    a : numpy.ndarray
        Modal amplitudes, ``(n_times, M_tot)`` [W**0.5].
    I_w : numpy.ndarray or None
        ``V a``, ``(n_times, N)``, or ``None`` when no ``V`` was given [A].

    Defaults
    --------
    ``dt_sub = 50 us`` is a validated-workflow default: the sub-step the full-wall
    solver is used with in the VEST eddy-current workflow.  ``method="auto"``
    leaves the choice to that solver.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    .. [vfit10] The reduced-order validation study (VEST-Tokamak/vfit#10, vaft
       #494), which asks which modes to keep; this module answers no part of that
       question by itself.
    """
    from vaft.process.electromagnetics import solve_eddy_currents

    if reduced.M_r is None:
        raise WallModeError("solve_reduced_eddy needs the projected source coupling M_r")
    a = solve_eddy_currents(
        reduced.R_r, reduced.M_r, reduced.L_r,
        np.asarray(drive, dtype=float), np.asarray(time, dtype=float),
        dt_sub=dt_sub, method=method,
    )
    I_w = None if V is None else a @ np.asarray(V, dtype=float).T
    return a, I_w

Integrate the reduced circuit L_r da/dt + R_r a = -M_r dI_src/dt.

The same integrator as the full wall (vaft.process.electromagnetics.solve_eddy_currents), fed the projected operators, so the only difference between the two solutions is the retained subspace: with every mode kept they agree to rounding.

NameTypeUnitDescription
reducedReducedWall-

The projected operators; M_r must be present.

drivenumpy.ndarrayA

Source currents, (n_times, n_src) on time.

timenumpy.ndarrays

Time grid of the drive.

Vnumpy.ndarray or None, optionalOhm**-0.5

The retained modes, (N, M_tot); when given, the wall current is reconstructed too.

dt_subfloat, optionals

Sub-step of the integrator.

methodstr, optional-

Integration method, forwarded to the full-wall solver.

Returns
anumpy.ndarrayW**0.5

Modal amplitudes, (n_times, M_tot).

I_wnumpy.ndarray or NoneA

V a, (n_times, N), or None when no V was given.

Input semantics · Output semantics · Defaults · Applicability · Provenance

Input semantics

Mode space: reduced operators and a source drive in element-independent coordinates.

Output semantics

Mode space amplitudes, and – when the retained V is given – the reconstructed element-space wall current alongside them.

Defaults

dt_sub = 50 us is a validated-workflow default: the sub-step the full-wall solver is used with in the VEST eddy-current workflow. method="auto" leaves the choice to that solver.

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.
  3. The reduced-order validation study (VEST-Tokamak/vfit#10, vaft #494), which asks which modes to keep; this module answers no part of that question by itself.

subspace_angles_r

Machine-independentConvention-sensitive source
subspace_angles_r(V_a, V_b, R_mat)
Show source vaft/process/wall_modes.py, lines 1203–1246
def subspace_angles_r(V_a: np.ndarray, V_b: np.ndarray, R_mat: np.ndarray) -> np.ndarray:
    """Principal angles between two mode subspaces in the R inner product.

    Two bases of a near-degenerate eigenspace differ by a rotation, so the right
    question is whether they span the same space, not whether their columns
    match.

    Parameters
    ----------
    V_a : numpy.ndarray
        First set of modes as columns, ``(N, m_a)`` [Ohm**-0.5].
    V_b : numpy.ndarray
        Second set, ``(N, m_b)`` [Ohm**-0.5].
    R_mat : numpy.ndarray
        Diagonal loop resistance, ``(N, N)`` or its diagonal [Ohm].

    Returns
    -------
    numpy.ndarray
        Principal angles, ascending, ``(min(m_a, m_b),)`` [rad].

    Convention
    ----------
    The angles are taken in the R metric, not the Euclidean one: both sets are
    mapped by ``R^{1/2}`` first, so the ordinary angles of the mapped columns are
    the R-metric angles of the originals.  A zero angle means a shared direction;
    ``pi/2`` means an R-orthogonal one.

    Applicability
    -------------
    Machine-independent.

    Provenance
    ----------
    .. [473] Issue #473, which built the segment-wise eigenbasis, and #500, which
       added the selection, scoring and moment tools.
    .. [vfit8] The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local
       eigenbasis, global electromagnetic dynamics.
    """
    from scipy.linalg import subspace_angles

    r = _diagonal_resistance(R_mat, where="R_mat")
    w = np.sqrt(r)[:, None]
    return subspace_angles(w * np.asarray(V_a, dtype=float), w * np.asarray(V_b, dtype=float))

Principal angles between two mode subspaces in the R inner product.

Two bases of a near-degenerate eigenspace differ by a rotation, so the right question is whether they span the same space, not whether their columns match.

NameTypeUnitDescription
V_anumpy.ndarrayOhm**-0.5

First set of modes as columns, (N, m_a).

V_bnumpy.ndarrayOhm**-0.5

Second set, (N, m_b).

R_matnumpy.ndarrayOhm

Diagonal loop resistance, (N, N) or its diagonal.

Returns
—numpy.ndarrayrad

Principal angles, ascending, (min(m_a, m_b),).

Convention

The angles are taken in the R metric, not the Euclidean one: both sets are mapped by R^{1/2} first, so the ordinary angles of the mapped columns are the R-metric angles of the originals. A zero angle means a shared direction; pi/2 means an R-orthogonal one.

Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

symmetrize_inductance

Machine-independent source
symmetrize_inductance(L, *, rtol=1e-08, reject=1e-06)

Fold a mutual-inductance matrix onto its symmetric part, with a refusal.

Reciprocity makes a mutual-inductance matrix symmetric, so a departure is a defect in the asset, not noise. The sanctioned place to repair reciprocity is the coupling mapper (vaft.machine_mapping.em_coupling.em_coupling, issue #373), which is why this one refuses rather than repairs beyond a rounding-sized asymmetry.

NameTypeUnitDescription
Lnumpy.ndarrayH

The inductance matrix, (N, N).

rtolfloat, optional-

Below this relative asymmetry the fold is silent.

rejectfloat, optional-

Above this relative asymmetry the matrix is refused.

Returns
L_symnumpy.ndarrayH

(L + L^T) / 2.

asymmetryfloat-

max|L - L^T| / max|L|, recorded in the basis provenance.

Raises

  • WallModeError When the asymmetry exceeds reject, and before that when the matrix is not square, carries a non-finite entry, or is identically zero.
Defaults · Applicability · Warnings · Provenance

Defaults

rtol = 1e-8 is a numerical convenience, the size of double-precision round-off accumulated over an assembly of this scale. reject = 1e-6 is empirical: the asymmetry of the packaged VEST coupling asset once its one-sided material factor was repaired (issue #373).

Applicability

Machine-independent.

Warnings

An asymmetry between rtol and reject is folded with a UserWarning, so the repair reaches the provenance rather than happening silently.

Provenance

  1. Issue #473, which built the segment-wise eigenbasis, and #500, which added the selection, scoring and moment tools.
  2. The reduced vessel-wall contract, VEST-Tokamak/vfit#8: local eigenbasis, global electromagnetic dynamics.

results matching ""

    No results matching ""