Process reference: ntv_coil_response

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

Overview

A non-axisymmetric coil set with K independently driven groups is described by one complex phasor per group, c_k = A_k exp(+i phi_k). On a fixed plasma and kinetic background, the signed toroidal torque PENTRC computes from the GPEC displacement that excitation drives may – or may not – be a Hermitian quadratic form of the phasors (issue #1887):

T(c) = c^H Q c,        Q = Q^H.

This module holds the algebra for testing that hypothesis and, only where it holds, for using it. It runs no solver: each torque it takes is a number some GPEC -> PENTRC evaluation produced (vaft.code.gpec.torque_profile), and each phasor is the excitation that evaluation was run with.

quadratic_probe_design ──▶ K^2 probes  (e_i, e_i+e_j, e_i+i e_j)
hermitian_torque_matrix ─▶ Q from the probes' torques
quadratic_invariance_checks ─▶ T(a c) = a^2 T(c), T(-c) = T(c), T(e^{i chi} c) = T(c)
qualify_torque_matrix ───▶ held-out error -> "qualified" / "rejected" / "insufficient"
fit_inhomogeneous_torque ─▶ T0 + 2 Re(b^H c) + c^H Q c, to see whether T0 and b vanish
two_group_phase_extrema, budgeted_torque_extrema, fixed_amplitude_phase_extrema

A rejected hypothesis is a result, not a failure of this module: the direct scan it was tested on is then the operating-space study, and no optimizer here should be fed that Q.

SymbolMeaningUnit
Knumber of independently driven coil groups-
ccomplex excitation phasor per group, c_k = A_k exp(+i phi_k)phasor
A_kdeclared amplitude normalization of group k (not a sector-peak
phi_kphase of group krad
Tsigned scalar torque of one evaluation (e.g. the enclosed edge
QHermitian torque matrix, T = c^H Q cN m / phasor^2
DHermitian positive-definite excitation metric of a budget c^H D c [-]

Phasor sign. c_k = A_k exp(+i phi_k) and T = c^H Q c. The cross-term recovery below depends on it: with the opposite phasor sign the imaginary part of every Q_ij changes sign.

Signed torque. T keeps PENTRC’s sign; nothing here takes |T|. A failed or uncomputed evaluation is NaN, never zero.

Common phase. For a single toroidal mode, T(e^{i chi} c) = T(c), so a K-group phase optimum has K - 1 free phases; group 0’s phase is held at zero.

Functions

budgeted_torque_extremaLargest and smallest signed torque over free complex excitations with c^H D c = budget. Convention
coil_phasorsComplex excitation phasors A_k exp(+i phi_k) of the coil groups. Convention
fit_inhomogeneous_torqueLeast-squares T = T0 + 2 Re(b^H c) + c^H Q c, to test whether T0 and b vanish. Convention
fixed_amplitude_phase_extremaPhases of the largest and smallest signed torque with every group amplitude fixed. Convention
hermitian_torque_matrixThe Hermitian Q of T = c^H Q c from the probe torques. Convention
ntv_operating_spaceDirect NTV torques (and a qualified model) as a #1178 coil operating-space result. Convention
quadratic_invariance_checksTests of a pure quadratic response that need no Q: scaling, sign, common phase. Convention
quadratic_probe_designThe K^2 unit excitations that determine a Hermitian Q. Convention
quadratic_torqueSigned torque c^H Q c of one excitation or a stack of them. Convention
qualify_torque_matrixQualify or reject a Q against direct evaluations it was not built from. Convention
two_group_phase_extremaRelative phases of the largest and smallest signed torque of two groups. Convention

budgeted_torque_extrema

Machine-independentConvention-sensitive source
budgeted_torque_extrema(Q, D, budget)
Show source vaft/process/ntv_coil_response.py, lines 647–716
def budgeted_torque_extrema(Q: np.ndarray, D: np.ndarray, budget: float) -> dict[str, object]:
    """Largest and smallest signed torque over free complex excitations with ``c^H D c = budget``.

    Parameters
    ----------
    Q : numpy.ndarray
        Hermitian torque matrix of a qualified model, possibly indefinite [N m / phasor^2].
    D : numpy.ndarray
        Hermitian positive-definite excitation metric [-].
    budget : float
        The excitation budget ``P_0 > 0`` [phasor^2].

    Returns
    -------
    extrema : dict
        ``T_max``/``T_min`` [N m], ``c_max``/``c_min`` meeting the budget
        [phasor], and the generalized ``eigenvalues`` ascending [N m / phasor^2].

    Raises
    ------
    ValueError
        ``D`` is not positive definite, shapes disagree, or the budget is not
        positive.

    Processing steps
    ----------------
    1. Solve ``Q v = lambda D v`` (generalized Hermitian eigenproblem).
    2. Scale the extreme eigenvectors to ``v^H D v = P_0``; ``T = lambda P_0``.

    Convention
    ----------
    Signed: with an indefinite ``Q`` the minimum is a negative torque, not a
    small magnitude.  The returned phasors are defined up to a common phase.

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

    Limitations
    -----------
    A mathematical optimum of the phasor space: actual sector or circuit
    current limits, winding signs and fixed group amplitudes are not imposed
    and must be checked separately.

    Provenance
    ----------
    .. [1887] Issue #1887, Sec. 8 (free complex excitation with a budget).
    """
    from scipy.linalg import eigh

    q = _hermitian(Q)
    d = _hermitian(D)
    if d.shape != q.shape:
        raise ValueError("Q and D differ in shape")
    if not budget > 0:
        raise ValueError("the budget must be positive")
    if np.linalg.eigvalsh(d).min() <= 0:
        raise ValueError("D must be positive definite")
    values, vectors = eigh(q, d)

    def scaled(v):
        return v * np.sqrt(budget / float(np.real(v.conj() @ d @ v)))

    return {
        "T_max": float(values[-1] * budget),
        "T_min": float(values[0] * budget),
        "c_max": scaled(vectors[:, -1]),
        "c_min": scaled(vectors[:, 0]),
        "eigenvalues": values,
    }

Largest and smallest signed torque over free complex excitations with c^H D c = budget.

NameTypeUnitDescription
Qnumpy.ndarrayN m / phasor^2

Hermitian torque matrix of a qualified model, possibly indefinite.

Dnumpy.ndarray-

Hermitian positive-definite excitation metric.

budgetfloatphasor^2

The excitation budget P_0 > 0.

Returns
extremadictN m / phasor^2

T_max/T_min [N m], c_max/c_min meeting the budget [phasor], and the generalized eigenvalues ascending.

Convention

Signed: with an indefinite Q the minimum is a negative torque, not a small magnitude. The returned phasors are defined up to a common phase.

Raises

  • ValueError D is not positive definite, shapes disagree, or the budget is not positive.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Solve Q v = lambda D v (generalized Hermitian eigenproblem).
  2. Scale the extreme eigenvectors to v^H D v = P_0; T = lambda P_0.

Applicability

Machine-independent.

Limitations

A mathematical optimum of the phasor space: actual sector or circuit current limits, winding signs and fixed group amplitudes are not imposed and must be checked separately.

Provenance

  1. Issue #1887, Sec. 8 (free complex excitation with a budget).

coil_phasors

Machine-independentConvention-sensitive source
coil_phasors(amplitudes, phases)
Show source vaft/process/ntv_coil_response.py, lines 116–156
def coil_phasors(amplitudes: Sequence[float], phases: Sequence[float]) -> np.ndarray:
    """Complex excitation phasors ``A_k exp(+i phi_k)`` of the coil groups.

    Parameters
    ----------
    amplitudes : sequence of float
        Declared amplitude normalization of each group, not negative [phasor].
    phases : sequence of float
        Phase of each group [rad].

    Returns
    -------
    c : numpy.ndarray
        Complex phasor per group [phasor].

    Raises
    ------
    ValueError
        The two sequences differ in length or an amplitude is negative or not
        finite.

    Convention
    ----------
    ``c_k = A_k exp(+i phi_k)``; the sign of the exponent is the one
    :func:`hermitian_torque_matrix` recovers cross terms in.

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

    Provenance
    ----------
    .. [1887] Issue #1887, phasor convention.
    """
    a = np.asarray(amplitudes, dtype=float).ravel()
    phi = np.asarray(phases, dtype=float).ravel()
    if a.shape != phi.shape:
        raise ValueError(f"{a.size} amplitudes for {phi.size} phases")
    if not np.all(np.isfinite(a)) or np.any(a < 0):
        raise ValueError("amplitudes must be finite and not negative")
    return a * np.exp(1j * phi)

Complex excitation phasors A_k exp(+i phi_k) of the coil groups.

NameTypeUnitDescription
amplitudessequence of floatphasor

Declared amplitude normalization of each group, not negative.

phasessequence of floatrad

Phase of each group.

Returns
cnumpy.ndarrayphasor

Complex phasor per group.

Convention

c_k = A_k exp(+i phi_k); the sign of the exponent is the one hermitian_torque_matrix recovers cross terms in.

Raises

  • ValueError The two sequences differ in length or an amplitude is negative or not finite.
Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. Issue #1887, phasor convention.

fit_inhomogeneous_torque

Machine-independentConvention-sensitive source
fit_inhomogeneous_torque(phasors, torques)

Least-squares T = T0 + 2 Re(b^H c) + c^H Q c, to test whether T0 and b vanish.

NameTypeUnitDescription
phasorsnumpy.ndarrayphasor

(N, K) excitations with finite direct torques.

torquessequence of floatN m

Their signed torques.

Returns
fitdict-

T0 [N m], b (length K) [N m / phasor], Q (Hermitian) [N m / phasor^2], residual_rms [N m], rank and unknowns.

Convention

2 Re(b^H c) = 2 (Re b . Re c + Im b . Im c) and c^H Q c = sum_i Q_ii |c_i|^2 + 2 sum_{i<j} Re(conj(c_i) Q_ij c_j).

Raises

  • ValueError Fewer finite samples than the 1 + 2K + K^2 real unknowns, shapes disagree, or the samples do not determine every unknown (rank deficient) – e.g. a scan at fixed amplitudes |c_k|, where T0 and the Q_ii are collinear.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Real unknowns: T0, Re b, Im b, Q_ii and, for i < j, Re Q_ij and Im Q_ij.
  2. Each sample contributes one real equation; solve by least squares.
  3. Refuse a rank-deficient design rather than split collinear terms.

Applicability

Machine-independent.

Limitations

A nonzero T0 or b means a background (an error field, another coil) is present; the pure form c^H Q c then does not apply as is.

Provenance

  1. Issue #1887, Sec. 5 (the inhomogeneous form tested first).

fixed_amplitude_phase_extrema

Machine-independentConvention-sensitive source
fixed_amplitude_phase_extrema(Q, amplitudes, *, grid_points, refine)

Phases of the largest and smallest signed torque with every group amplitude fixed.

NameTypeUnitDescription
Qnumpy.ndarrayN m / phasor^2

K x K Hermitian torque matrix of a qualified model.

amplitudessequence of floatphasor

Fixed amplitude of each group, not negative.

grid_pointsint-

Phase samples per free phase of the deterministic grid, at least 4.

refineint-

How many of the best grid points per extremum to polish with a local optimizer; 0 keeps the grid answer.

Returns
extremadict-

phases_max/phases_min (group 0 held at 0) [rad], T_max/ T_min [N m] and evaluations, the model evaluations used.

Convention

c_k = A_k exp(+i phi_k); extrema of the signed torque.

Raises

  • ValueError Shapes disagree, an amplitude is negative, grid_points < 4, or the grid would exceed two million points.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Hold group 0’s phase at 0 (common phase is irrelevant for one n).
  2. Evaluate c^H Q c on a grid_points^(K-1) phase grid.
  3. Polish the refine best points of each extremum with L-BFGS-B on the free phases and keep the best.

Applicability

Machine-independent.

Limitations

Nonconvex for K >= 3: the grid plus local polish is a deterministic reference, not a proof of the global optimum at coarse grids. The grid grows as grid_points^(K-1).

Provenance

  1. Issue #1887, Sec. 8 (multi-group fixed-amplitude optimization).

hermitian_torque_matrix

Machine-independentConvention-sensitive source
hermitian_torque_matrix(torques, groups)
Show source vaft/process/ntv_coil_response.py, lines 207–270
def hermitian_torque_matrix(torques: Mapping[str, float], groups: int) -> np.ndarray:
    """The Hermitian ``Q`` of ``T = c^H Q c`` from the probe torques.

    Parameters
    ----------
    torques : mapping of str to float
        Signed torque of each probe of :func:`quadratic_probe_design`, keyed
        by its label [N m].
    groups : int
        Number of coil groups ``K`` [-].

    Returns
    -------
    Q : numpy.ndarray
        ``K x K`` Hermitian matrix [N m / phasor^2].

    Raises
    ------
    KeyError
        A probe label is missing.
    ValueError
        A probe torque is not finite (a failed evaluation cannot identify ``Q``).

    Processing steps
    ----------------
    1. ``Q_ii = T(e_i)``.
    2. ``Re Q_ij = [T(e_i + e_j) - T(e_i) - T(e_j)] / 2``.
    3. ``Im Q_ij = [T(e_i) + T(e_j) - T(e_i + i e_j)] / 2``.
    4. ``Q_ji = conj(Q_ij)``.

    Convention
    ----------
    With ``c = e_i + i e_j``, ``c^H Q c = Q_ii + Q_jj - 2 Im Q_ij``, which is
    step 3; it holds for the ``exp(+i phi)`` phasor of :func:`coil_phasors`.

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

    Limitations
    -----------
    A ``Q`` that reproduces its own probes exactly is not thereby validated:
    the probes determine it.  Only :func:`qualify_torque_matrix` on held-out
    evaluations can qualify it.

    Provenance
    ----------
    .. [1887] Issue #1887, Sec. 6.
    """
    k = int(groups)
    labels = [label for label, _ in quadratic_probe_design(k)]
    values = {label: float(torques[label]) for label in labels}
    bad = sorted(label for label, value in values.items() if not np.isfinite(value))
    if bad:
        raise ValueError(f"probe torques are not finite: {bad}")
    q = np.zeros((k, k), dtype=complex)
    for i in range(k):
        q[i, i] = values[f"e{i}"]
    for i, j in combinations(range(k), 2):
        real = 0.5 * (values[f"e{i}+e{j}"] - values[f"e{i}"] - values[f"e{j}"])
        imag = 0.5 * (values[f"e{i}"] + values[f"e{j}"] - values[f"e{i}+ie{j}"])
        q[i, j] = real + 1j * imag
        q[j, i] = real - 1j * imag
    return q

The Hermitian Q of T = c^H Q c from the probe torques.

NameTypeUnitDescription
torquesmapping of str to floatN m

Signed torque of each probe of quadratic_probe_design, keyed by its label.

groupsint-

Number of coil groups K.

Returns
Qnumpy.ndarrayN m / phasor^2

K x K Hermitian matrix.

Convention

With c = e_i + i e_j, c^H Q c = Q_ii + Q_jj - 2 Im Q_ij, which is step 3; it holds for the exp(+i phi) phasor of coil_phasors.

Raises

  • KeyError A probe label is missing.
  • ValueError A probe torque is not finite (a failed evaluation cannot identify Q).
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Q_ii = T(e_i).
  2. Re Q_ij = [T(e_i + e_j) - T(e_i) - T(e_j)] / 2.
  3. Im Q_ij = [T(e_i) + T(e_j) - T(e_i + i e_j)] / 2.
  4. Q_ji = conj(Q_ij).

Applicability

Machine-independent.

Limitations

A Q that reproduces its own probes exactly is not thereby validated: the probes determine it. Only qualify_torque_matrix on held-out evaluations can qualify it.

Provenance

  1. Issue #1887, Sec. 6.

ntv_operating_space

Machine-independentConvention-sensitive source
ntv_operating_space(groups, n, phasors, torques, *, sample_ids, roles, amplitude_unit, frame, provenance, qualification=None)

Direct NTV torques (and a qualified model) as a #1178 coil operating-space result.

NameTypeUnitDescription
groupssequence of str-

Coil-group names in phasor order.

nint-

Toroidal mode number.

phasorsnumpy.ndarrayphasor

(N, K) excitations in phasor units.

torquessequence of floatN m

Direct signed torque per sample; NaN for a failed evaluation.

sample_idssequence of str-

Stable id per sample.

rolessequence of str-

Role per sample, from vaft.process.coil_operating_space.OPERATING_SPACE_ROLES.

amplitude_unitfloatA per turn

Cosine amplitude of one phasor unit.

framestr-

The toroidal frame the sector angles were taken in.

provenancemapping-

What produced the direct torques: method, scalar radius, kinetic identity, solver tolerances.

qualificationTorqueMatrixQualification, optional-

A qualified result of qualify_torque_matrix; its Q adds ntv_torque_model rows for every sample.

Returns
resultvaft.process.coil_operating_space.CoilOperatingSpace-

ntv_torque rows (valid or failed) and, with a qualified model, ntv_torque_model rows.

Convention

The excitation convention is vaft.process.coil_operating_space.COIL_EXCITATION_CONVENTION (c = A exp(+i delta)); measured and modelled torques never share a metric.

Raises

  • ValueError Lengths disagree, amplitude_unit is not positive, the qualification given is not qualified, or its Q is for another number of groups.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Amplitudes |c| * amplitude_unit and phases arg c mod 2 pi.
  2. One ntv_torque row per sample: valid with its value, or failed with NaN.
  3. With a qualified model, one ntv_torque_model row per sample, c^H Q c; its provenance records the qualification.

Applicability

Machine-independent.

Limitations

A model row is a prediction valid only within the qualified domain the qualification’s provenance describes. Nothing checks that Q was built from the same PENTRC method and tolerances as torques; the caller’s provenance is recorded as that claim.

Provenance

  1. Issue #1887, NTV torque on the #1178 operating space.
  2. Issue #1886, the result schema.

quadratic_invariance_checks

Machine-independentConvention-sensitive source
quadratic_invariance_checks(base_torque, *, scaled=(), reversed_torque=None, rotated=(), atol, rtol)
Show source vaft/process/ntv_coil_response.py, lines 309–388
def quadratic_invariance_checks(
    base_torque: float,
    *,
    scaled: Sequence[tuple[float, float]] = (),
    reversed_torque: float | None = None,
    rotated: Sequence[tuple[float, float]] = (),
    atol: float,
    rtol: float,
) -> tuple[QuadraticTorqueCheck, ...]:
    """Tests of a pure quadratic response that need no ``Q``: scaling, sign, common phase.

    Parameters
    ----------
    base_torque : float
        Signed torque of the reference excitation ``c`` [N m].
    scaled : sequence of (float, float)
        ``(a, T(a c))`` for positive real factors ``a`` [-, N m].
    reversed_torque : float, optional
        ``T(-c)`` [N m].
    rotated : sequence of (float, float)
        ``(chi, T(exp(i chi) c))`` for common phase rotations [rad, N m].
    atol : float
        Absolute tolerance, the scale below which a torque is near zero [N m].
    rtol : float
        Relative tolerance away from zero [-].

    Returns
    -------
    checks : tuple of QuadraticTorqueCheck
        ``amplitude_scaling`` (expects ``a^2 T(c)``), ``sign_reversal``
        (expects ``T(c)``) and ``common_phase`` (expects ``T(c)``), each only
        when its samples were given [-].

    Raises
    ------
    ValueError
        A tolerance is negative, a factor ``a`` is not positive, or a torque
        is not finite.

    Processing steps
    ----------------
    1. Expected torque per sample from the homogeneous-quadratic hypothesis.
    2. A sample passes when ``|T - T_expected| <= atol + rtol |T_expected|``.
    3. One check per kind, passed only if every sample of that kind passes.

    Convention
    ----------
    The common-phase test assumes a single toroidal mode ``n``; a mixed-``n``
    excitation is not phase-invariant and should not be given here.

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

    Limitations
    -----------
    A failed check rejects the *pure* quadratic form; a constant or linear
    term (a background field) is examined by :func:`fit_inhomogeneous_torque`.
    The tolerances are the caller's: no universal NTV tolerance exists.

    Provenance
    ----------
    .. [1887] Issue #1887, Sec. 5.
    """
    _tolerances(atol, rtol)
    base = _finite(base_torque, "base_torque")
    checks: list[QuadraticTorqueCheck] = []
    if scaled:
        factors = np.array([float(a) for a, _ in scaled])
        if np.any(factors <= 0):
            raise ValueError("scaling factors must be positive")
        values = np.array([_finite(t, "scaled torque") for _, t in scaled])
        checks.append(_check("amplitude_scaling", values, factors**2 * base, atol, rtol))
    if reversed_torque is not None:
        checks.append(_check("sign_reversal", np.array([_finite(reversed_torque, "reversed_torque")]),
                             np.array([base]), atol, rtol))
    if rotated:
        values = np.array([_finite(t, "rotated torque") for _, t in rotated])
        checks.append(_check("common_phase", values, np.full(values.shape, base), atol, rtol))
    return tuple(checks)

Tests of a pure quadratic response that need no Q: scaling, sign, common phase.

NameTypeUnitDescription
base_torquefloatN m

Signed torque of the reference excitation c.

scaledsequence of (float, float)-, N m

(a, T(a c)) for positive real factors a.

reversed_torquefloat, optionalN m

T(-c).

rotatedsequence of (float, float)rad, N m

(chi, T(exp(i chi) c)) for common phase rotations.

atolfloatN m

Absolute tolerance, the scale below which a torque is near zero.

rtolfloat-

Relative tolerance away from zero.

Returns
checkstuple of QuadraticTorqueCheck-

amplitude_scaling (expects a^2 T(c)), sign_reversal (expects T(c)) and common_phase (expects T(c)), each only when its samples were given.

Convention

The common-phase test assumes a single toroidal mode n; a mixed-n excitation is not phase-invariant and should not be given here.

Raises

  • ValueError A tolerance is negative, a factor a is not positive, or a torque is not finite.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Expected torque per sample from the homogeneous-quadratic hypothesis.
  2. A sample passes when |T - T_expected| <= atol + rtol |T_expected|.
  3. One check per kind, passed only if every sample of that kind passes.

Applicability

Machine-independent.

Limitations

A failed check rejects the pure quadratic form; a constant or linear term (a background field) is examined by fit_inhomogeneous_torque. The tolerances are the caller’s: no universal NTV tolerance exists.

Provenance

  1. Issue #1887, Sec. 5.

quadratic_probe_design

Machine-independentConvention-sensitive source
quadratic_probe_design(groups)
Show source vaft/process/ntv_coil_response.py, lines 159–204
def quadratic_probe_design(groups: int) -> tuple[tuple[str, np.ndarray], ...]:
    """The ``K^2`` unit excitations that determine a Hermitian ``Q``.

    Parameters
    ----------
    groups : int
        Number of independently driven coil groups ``K``, at least 1 [-].

    Returns
    -------
    probes : tuple of (str, numpy.ndarray)
        ``("e0", e_0)``, ..., then for every ``i < j`` ``("e{i}+e{j}", e_i + e_j)``
        and ``("e{i}+ie{j}", e_i + i e_j)``: ``K + 2 C(K, 2) = K^2`` phasors [phasor].

    Raises
    ------
    ValueError
        ``groups`` is below 1.

    Convention
    ----------
    The mixed probes put ``+i`` on the higher-index group, matching the
    ``exp(+i phi)`` phasor of :func:`coil_phasors`.

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

    Limitations
    -----------
    ``K^2`` evaluations identify ``Q`` only; validating it needs further
    held-out evaluations (:func:`qualify_torque_matrix`).

    Provenance
    ----------
    .. [1887] Issue #1887, Sec. 6 (probe identities and their count).
    """
    k = int(groups)
    if k < 1:
        raise ValueError("at least one coil group is needed")
    unit = np.eye(k, dtype=complex)
    probes = [(f"e{i}", unit[i]) for i in range(k)]
    for i, j in combinations(range(k), 2):
        probes.append((f"e{i}+e{j}", unit[i] + unit[j]))
        probes.append((f"e{i}+ie{j}", unit[i] + 1j * unit[j]))
    return tuple(probes)

The K^2 unit excitations that determine a Hermitian Q.

NameTypeUnitDescription
groupsint-

Number of independently driven coil groups K, at least 1.

Returns
probestuple of (str, numpy.ndarray)phasor

("e0", e_0), …, then for every i < j ("e{i}+e{j}", e_i + e_j) and ("e{i}+ie{j}", e_i + i e_j): K + 2 C(K, 2) = K^2 phasors.

Convention

The mixed probes put +i on the higher-index group, matching the exp(+i phi) phasor of coil_phasors.

Raises

  • ValueError groups is below 1.
Applicability · Limitations · Provenance

Applicability

Machine-independent.

Limitations

K^2 evaluations identify Q only; validating it needs further held-out evaluations (qualify_torque_matrix).

Provenance

  1. Issue #1887, Sec. 6 (probe identities and their count).

quadratic_torque

Machine-independentConvention-sensitive source
quadratic_torque(Q, phasors)
Show source vaft/process/ntv_coil_response.py, lines 273–306
def quadratic_torque(Q: np.ndarray, phasors: np.ndarray) -> np.ndarray:
    """Signed torque ``c^H Q c`` of one excitation or a stack of them.

    Parameters
    ----------
    Q : numpy.ndarray
        ``K x K`` Hermitian torque matrix [N m / phasor^2].
    phasors : numpy.ndarray
        One phasor vector of length ``K``, or an ``(N, K)`` stack [phasor].

    Returns
    -------
    torque : numpy.ndarray
        Real signed torque, scalar or length ``N`` [N m].

    Raises
    ------
    ValueError
        ``Q`` is not square and Hermitian, or the phasors do not match it.

    Convention
    ----------
    ``T = c^H Q c`` with ``c_k = A_k exp(+i phi_k)``; the imaginary part,
    zero for a Hermitian ``Q``, is dropped after the check.

    Applicability
    -------------
    Machine-independent.
    """
    q = _hermitian(Q)
    c = np.asarray(phasors, dtype=complex)
    if c.shape[-1] != q.shape[0]:
        raise ValueError(f"phasors of length {c.shape[-1]} for a {q.shape[0]}-group Q")
    return np.real(np.einsum("...i,ij,...j->...", c.conj(), q, c))

Signed torque c^H Q c of one excitation or a stack of them.

NameTypeUnitDescription
Qnumpy.ndarrayN m / phasor^2

K x K Hermitian torque matrix.

phasorsnumpy.ndarrayphasor

One phasor vector of length K, or an (N, K) stack.

Returns
torquenumpy.ndarrayN m

Real signed torque, scalar or length N.

Convention

T = c^H Q c with c_k = A_k exp(+i phi_k); the imaginary part, zero for a Hermitian Q, is dropped after the check.

Raises

  • ValueError Q is not square and Hermitian, or the phasors do not match it.
Applicability

Applicability

Machine-independent.

qualify_torque_matrix

Machine-independentConvention-sensitive source
qualify_torque_matrix(Q, held_out_phasors, held_out_torques, *, atol, rtol, invariance_checks=())

Qualify or reject a Q against direct evaluations it was not built from.

NameTypeUnitDescription
Qnumpy.ndarrayN m / phasor^2

Hermitian torque matrix, e.g. from hermitian_torque_matrix.

held_out_phasorsnumpy.ndarrayphasor

(N, K) excitations not among the probes that built Q.

held_out_torquessequence of floatN m

Their direct signed torques; NaN marks a failed evaluation.

atolfloatN m

Absolute tolerance, the near-zero torque scale.

rtolfloat-

Relative tolerance away from zero.

invariance_checkssequence of QuadraticTorqueCheck, optional-

From quadratic_invariance_checks; any failure rejects.

Returns
qualificationTorqueMatrixQualification-

rejected when any compared sample or invariance check fails; otherwise insufficient when any held-out evaluation failed (NaN) or none was given, since a failed run is not evidence; otherwise qualified.

Convention

The comparison is on the signed torque; a model that matches |T| but not its sign fails.

Raises

  • ValueError Shapes disagree, Q is not Hermitian, or a tolerance is negative.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Set aside held-out samples whose direct torque is NaN, and count them.
  2. Compare c^H Q c with the direct torque per sample, passing when |dT| <= atol + rtol |T_direct|.
  3. Combine with the invariance checks into one status.

Applicability

Machine-independent.

Limitations

Qualification holds for the background, n, PENTRC method, grid and amplitude range the evaluations covered, and nowhere else.

Provenance

  1. Issue #1887, Sec. 6 (held-out validation).

two_group_phase_extrema

Machine-independentConvention-sensitive source
two_group_phase_extrema(Q, amplitudes)
Show source vaft/process/ntv_coil_response.py, lines 580–644
def two_group_phase_extrema(Q: np.ndarray, amplitudes: Sequence[float]) -> dict[str, object]:
    """Relative phases of the largest and smallest signed torque of two groups.

    Parameters
    ----------
    Q : numpy.ndarray
        ``2 x 2`` Hermitian torque matrix of a qualified model [N m / phasor^2].
    amplitudes : sequence of float
        Fixed amplitudes ``(A_1, A_2)``, not negative [phasor].

    Returns
    -------
    extrema : dict
        ``delta_phi_max`` and ``delta_phi_min`` in ``[0, 2 pi)`` [rad], or
        ``None`` when the torque does not depend on the phase; ``T_max`` and
        ``T_min`` [N m]; ``phase_independent`` [-].

    Raises
    ------
    ValueError
        ``Q`` is not ``2 x 2`` Hermitian or an amplitude is negative.

    Processing steps
    ----------------
    1. ``T(dphi) = Q_11 A_1^2 + Q_22 A_2^2 + 2 A_1 A_2 |Q_12| cos(dphi + arg Q_12)``.
    2. Maximum at ``dphi = -arg Q_12``, minimum at ``pi - arg Q_12``.
    3. With ``Q_12 = 0`` or a zero amplitude no phase is preferred.

    Convention
    ----------
    ``c = (A_1, A_2 exp(+i dphi))``; the extrema are of the *signed* torque,
    not of ``|T|`` or of a braking criterion.

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

    Limitations
    -----------
    Valid only where :func:`qualify_torque_matrix` qualified ``Q``.

    Provenance
    ----------
    .. [1887] Issue #1887, Sec. 8.
    """
    q = _hermitian(Q)
    if q.shape != (2, 2):
        raise ValueError("two_group_phase_extrema needs a 2 x 2 Q")
    a1, a2 = (float(a) for a in amplitudes)
    if a1 < 0 or a2 < 0:
        raise ValueError("amplitudes must not be negative")
    base = float(np.real(q[0, 0])) * a1**2 + float(np.real(q[1, 1])) * a2**2
    swing = 2 * a1 * a2 * abs(q[0, 1])
    scale = max(abs(base), abs(q[0, 0]) * a1**2, abs(q[1, 1]) * a2**2, np.finfo(float).tiny)
    if swing <= 64 * np.finfo(float).eps * scale:  # below the roundoff of the diagonal terms
        return {"delta_phi_max": None, "delta_phi_min": None, "T_max": base, "T_min": base,
                "phase_independent": True}
    arg = float(np.angle(q[0, 1]))
    return {
        "delta_phi_max": float(np.mod(-arg, 2 * np.pi)),
        "delta_phi_min": float(np.mod(np.pi - arg, 2 * np.pi)),
        "T_max": base + swing,
        "T_min": base - swing,
        "phase_independent": False,
    }

Relative phases of the largest and smallest signed torque of two groups.

NameTypeUnitDescription
Qnumpy.ndarrayN m / phasor^2

2 x 2 Hermitian torque matrix of a qualified model.

amplitudessequence of floatphasor

Fixed amplitudes (A_1, A_2), not negative.

Returns
extremadict-

delta_phi_max and delta_phi_min in [0, 2 pi) [rad], or None when the torque does not depend on the phase; T_max and T_min [N m]; phase_independent.

Convention

c = (A_1, A_2 exp(+i dphi)); the extrema are of the signed torque, not of |T| or of a braking criterion.

Raises

  • ValueError Q is not 2 x 2 Hermitian or an amplitude is negative.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. T(dphi) = Q_11 A_1^2 + Q_22 A_2^2 + 2 A_1 A_2 |Q_12| cos(dphi + arg Q_12).
  2. Maximum at dphi = -arg Q_12, minimum at pi - arg Q_12.
  3. With Q_12 = 0 or a zero amplitude no phase is preferred.

Applicability

Machine-independent.

Limitations

Valid only where qualify_torque_matrix qualified Q.

Provenance

  1. Issue #1887, Sec. 8.

results matching ""

    No results matching ""