Process reference: cocos

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

Overview

vaft.data.cocos declares what each convention and each external code is. This module answers whether a given equilibrium is actually consistent with the convention it claims, which is the check that catches a mislabelled file before its signs propagate into derived quantities.

Sauter & Medvedev 2013 Eq. 23 gives six relations that any equilibrium in a given COCOS must satisfy, in terms of the signs of the plasma current and the vacuum toroidal field:

=============== ===================================== quantity required sign =============== ===================================== F sigma_B0 Phi_tor sigma_B0 psi_edge - sigma_Ip * sigma_Bp psi_axis dp/dpsi -sigma_Ip * sigma_Bp j_phi sigma_Ip q sigma_Ip * sigma_B0 * sigma_rhotheta =============== =====================================

The q relation is reported as a warning rather than an error: Sauter Sect. IV notes that codes frequently emit abs(q), so a mismatch there is common and is not on its own evidence of a wrong index.

Only four of the six are checkable against vaft.data.equilibrium.EquilibriumData as it stands: it carries no toroidal current density and no toroidal flux, so j_phi and Phi_tor are always reported as unverifiable. They are listed here because they are part of Eq. 23 and become checkable if those fields are ever added, not because they are being tested today.

Functions

cocos_consistency_signsObserved sign of each Sauter Eq. 23 quantity, or None where not determinable. Convention
cocos_field_scalesThe two sign multipliers that carry an equilibrium from one COCOS to another. Convention
identify_conventionCandidate COCOS indices for an equilibrium, from its observable signs. Convention
identify_flux_exponentDecide whether psi is stored in weber or weber per radian, from Ampere’s law. Convention
identify_flux_exponent_from_qDecide weber versus weber per radian by rebuilding q on closed contours. Convention
validate_cocosCheck an equilibrium against the Sauter Eq. 23 relations for one COCOS index. Convention

cocos_consistency_signs

Machine-independentConvention-sensitive source
cocos_consistency_signs(equilibrium)

Observed sign of each Sauter Eq. 23 quantity, or None where not determinable.

Reads signs off the equilibrium as it stands. Nothing is compared against a convention here and nothing is converted; validate_cocos does the comparison and vaft.process.equilibrium.convert_cocos is the only transform in the package.

NameTypeUnitDescription
equilibriumEquilibriumData-

The equilibrium to inspect. Missing fields yield None for the relations that need them rather than an error.

Returns
—dict of str to int or None-

Keys f, q, j_phi, phi_tor, dpsi, pprime; each +1, -1, or None when the field is absent or all-zero.

Convention

Signs only, in whatever convention the equilibrium is already in; this function neither assumes nor imposes a COCOS. j_phi and phi_tor are always None today because vaft.data.equilibrium.EquilibriumData carries neither a toroidal current density nor a toroidal flux; they are reported so that Eq. 23 is represented in full, not because they are tested.

Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. f, q, j_phi and phi_tor: the sign of the profile’s median, with a deadband so a numerically-zero profile reports None.
  2. dpsi: the sign of psi_boundary - psi_axis.
  3. pprime: the stored pprime profile’s sign when the equilibrium carries one, which for a GEQDSK or an ODS it essentially always does. Only when it does not is the bulk slope (p_edge - p_axis)/(psi_edge - psi_axis) used instead, taken on a profile reordered axis-to-edge so the direction is known.

Applicability

Machine-independent.

Limitations

A bulk slope is the sign of the overall trend, not of every point: a non-monotonic pressure profile still reports one sign. Because the stored pprime takes precedence, the fallback rarely runs in practice; that the two paths can disagree for a hand-built equilibrium is tracked in #605.

Provenance

  1. Sauter and Medvedev, Tokamak Coordinate Conventions: COCOS, Comput. Phys. Commun. 184, 293 (2013), Eq. 23, which defines the six sign relations this function measures. The preference for a bulk pressure slope over a pointwise derivative is that paper’s own recommendation.

cocos_field_scales

Machine-independentConvention-sensitive source
cocos_field_scales(source, target)
Show source vaft/process/cocos.py, lines 840–909
def cocos_field_scales(source: int, target: int) -> tuple[int, int]:
    """The two sign multipliers that carry an equilibrium from one COCOS to another.

    Parameters
    ----------
    source : int
        The index the equilibrium is in [-].
    target : int
        The index it is wanted in [-].

    Returns
    -------
    tuple of int
        ``(psi_scale, field_scale)``, each ``+1`` or ``-1``. ``psi_scale``
        multiplies the poloidal flux -- ``psi`` on the grid and the axis and
        boundary values with it -- and ``field_scale`` multiplies the toroidal
        field and the poloidal current function ``F`` [-].

    Raises
    ------
    ValueError
        Either index is not one of the eighteen COCOS indices.

    Convention
    ----------
    From Sauter Eq. 12, ``B_pol = sigma_Bp sigma_RphiZ grad(psi) x grad(phi) /
    (2 pi)**e_Bp``: the sign ``psi`` carries relative to the physical poloidal
    field is the **product** ``sigma_Bp * sigma_RphiZ``, so the flux flips when
    that product differs between the two conventions. The toroidal field's
    direction follows ``sigma_RphiZ`` alone, so ``F`` and ``B_t`` flip when the
    handedness of ``(R, phi, Z)`` differs.

    **This is a sign conversion, not a unit conversion.** ``e_Bp`` differs
    between the 1-8 and 11-18 families by a factor of ``2 pi`` on ``psi``, and
    nothing here applies it: a caller crossing the families has to scale the
    flux itself, and :func:`identify_flux_exponent` is what tells it which
    family a file is in.

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

    Processing steps
    ----------------
    1. Look up both conventions' ``sigma_Bp`` and ``sigma_RphiZ``.
    2. The flux multiplier is the product of the two ``sigma_Bp sigma_RphiZ``
       products; the field multiplier is the product of the two
       ``sigma_RphiZ``.

    Limitations
    -----------
    Says nothing about ``sigma_rhothetaphi``, which sets the poloidal angle's
    direction. Two conventions differing only in that give ``(+1, +1)`` here
    and still disagree about the sign of ``theta`` -- a caller relabelling a
    poloidal angle needs the third sigma, not these two.

    Provenance
    ----------
    .. [sauter] O. Sauter and S. Yu. Medvedev, Comput. Phys. Commun. 184
       (2013) 293, Eq. 12 and Table I.
    .. [measured] Two conversions measured on real runs, both reproduced by
       this rule: a COCOS 5 g-file into FLARE's COCOS 3 needs ``(-1, +1)``,
       and a COCOS 2 CHEASE equilibrium needs ``(+1, -1)``.
    """
    from vaft.data.cocos import cocos_spec

    first, second = cocos_spec(int(source)), cocos_spec(int(target))
    psi_scale = (first.sigma_bp * first.sigma_rpz) * (second.sigma_bp * second.sigma_rpz)
    field_scale = first.sigma_rpz * second.sigma_rpz
    return int(psi_scale), int(field_scale)

The two sign multipliers that carry an equilibrium from one COCOS to another.

NameTypeUnitDescription
sourceint-

The index the equilibrium is in.

targetint-

The index it is wanted in.

Returns
—tuple of int-

(psi_scale, field_scale), each +1 or -1. psi_scale multiplies the poloidal flux – psi on the grid and the axis and boundary values with it – and field_scale multiplies the toroidal field and the poloidal current function F.

Convention

From Sauter Eq. 12, B_pol = sigma_Bp sigma_RphiZ grad(psi) x grad(phi) / (2 pi)**e_Bp: the sign psi carries relative to the physical poloidal field is the product sigma_Bp * sigma_RphiZ, so the flux flips when that product differs between the two conventions. The toroidal field’s direction follows sigma_RphiZ alone, so F and B_t flip when the handedness of (R, phi, Z) differs.

This is a sign conversion, not a unit conversion. e_Bp differs between the 1-8 and 11-18 families by a factor of 2 pi on psi, and nothing here applies it: a caller crossing the families has to scale the flux itself, and identify_flux_exponent is what tells it which family a file is in.

Raises

  • ValueError Either index is not one of the eighteen COCOS indices.
Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Look up both conventions’ sigma_Bp and sigma_RphiZ.
  2. The flux multiplier is the product of the two sigma_Bp sigma_RphiZ products; the field multiplier is the product of the two sigma_RphiZ.

Applicability

Machine-independent.

Limitations

Says nothing about sigma_rhothetaphi, which sets the poloidal angle’s direction. Two conventions differing only in that give (+1, +1) here and still disagree about the sign of theta – a caller relabelling a poloidal angle needs the third sigma, not these two.

Provenance

  1. O. Sauter and S. Yu. Medvedev, Comput. Phys. Commun. 184 (2013) 293, Eq. 12 and Table I.
  2. Two conversions measured on real runs, both reproduced by this rule: a COCOS 5 g-file into FLARE’s COCOS 3 needs (-1, +1), and a COCOS 2 CHEASE equilibrium needs (+1, -1).

identify_convention

Machine-independentConvention-sensitive source
identify_convention(equilibrium, *, clockwise_phi=None)

Candidate COCOS indices for an equilibrium, from its observable signs.

Narrows rather than decides: the return is every index consistent with what the data shows, which is often more than one. A caller that needs a single index supplies the missing fact instead of guessing.

NameTypeUnitDescription
equilibriumEquilibriumData-

Must carry bt0, ip, q and psi_1d; without them the candidate set is empty.

clockwise_phibool, optional-

Whether the machine’s toroidal angle runs clockwise seen from above. A fact about the machine, not about the data; without it both the odd and the even index of each pair are returned.

Returns
—tuple of int-

The candidate COCOS indices in increasing order, empty when the required fields are missing or the sign identification fails.

Convention

Returns indices in the standard 1 to 18 numbering; 9 and 10 do not exist. The sign family and the storage family are identified by different evidence, signs for the first and an Ampere loop integral for the second, and either can be inconclusive on its own. What each index means is declared in vaft.data.cocos, not here.

Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Reorder psi_1d and q axis-to-edge when the stored profile runs the other way.
  2. Get the sign family from omas.identify_cocos, which reads it off the signs of ip, bt0, q and the psi gradient.
  3. Narrow to 1-8 or 11-18 using identify_flux_exponent, falling back to identify_flux_exponent_from_q when that one had no inputs to measure, and keeping the full set when neither answers.

Applicability

Machine-independent. clockwise_phi is where a machine’s own geometry enters.

Limitations

The axis-to-edge reorder exists because identify_cocos reads the psi gradient at the first node, so a boundary-first profile would invert the poloidal-flux sign silently. When both flux-exponent rungs abstain the result spans both storage families, and a caller that then converts must not assume the candidates share one. The contour-q rung is deliberately not consulted when the Ampere rung ran and rejected both families: that is a file whose ip and psi map disagree, and reporting a confident index for it would hide the disagreement rather than resolve it. Any exception from the underlying identification is reported as no candidates rather than raised.

Provenance

  1. Sauter and Medvedev (2013) for the index numbering and the sign relations the identification rests on.
  2. omas.identify_cocos supplies the sign family; its flux-exponent argument is deliberately not used, see identify_flux_exponent.
  3. The contour-q fallback is the legacy implementation’s geqdsk_cocos.py::flux_normalization_diagnostic, ported in identify_flux_exponent_from_q.

identify_flux_exponent

Machine-independentConvention-sensitive source
identify_flux_exponent(equilibrium)

Decide whether psi is stored in weber or weber per radian, from Ampere’s law.

The loop integral of the poloidal field around the last closed flux surface equals mu0*|Ip|. Computing that field from psi as if it were weber per radian gives a ratio of 1 when the assumption holds and 2*pi when psi is really in weber, so the two answers are a factor 2*pi apart and the test is decisive rather than a threshold on a continuum.

NameTypeUnitDescription
equilibriumEquilibriumData-

Must carry ip, a closed lcfs, and a psi map on its r and z grid; anything missing yields (None, None).

Returns
—tuple of (int or None, float or None)-

(e_Bp, ratio). e_Bp is 0 for a weber-per-radian psi (COCOS 1-8) and 1 for a weber psi (COCOS 11-18), or None when the inputs are unavailable or the ratio lands near neither answer. ratio is the measured loop integral over mu0*|Ip|.

Convention

Decides which storage family psi is in; it does not rescale psi and does not say which of the eight sign orientations applies. e_Bp is Sauter’s flux exponent: 0 means the 2*pi is not carried in psi, 1 means it is.

Processing steps · Defaults · Applicability · Limitations · Provenance

Processing steps

  1. Close the LCFS contour and compute the poloidal field on it with vaft.process.equilibrium.poloidal_field_at_boundary in the weber-per-radian form; only the magnitude matters.
  2. Integrate it along the contour by the trapezoidal rule.
  3. Divide by mu0*|Ip|.
  4. Accept 0 or 1 if the ratio is within FLUX_EXPONENT_TOLERANCE of 1 or 2*pi; otherwise abstain.

Defaults

FLUX_EXPONENT_TOLERANCE is 0.15, a numerical convenience rather than a physical threshold: a correct equilibrium lands within about half a percent, the residual being LCFS discretization, so the band is roughly thirty times the observed error while leaving the two acceptance windows far apart, at 0.85 to 1.15 against 5.34 to 7.23.

Applicability

Machine-independent.

Limitations

Abstains rather than picking the nearer of two wrong answers. A ratio near neither value is evidence the input is broken, a truncated LCFS or an ip that disagrees with the psi map, not evidence of a convention. Needs a 2-D psi map and an LCFS, so a profiles-only equilibrium cannot be classified.

Provenance

  1. Sauter and Medvedev (2013) for e_Bp and the storage families.
  2. Replaces the a argument of omas.identify_cocos, which is not usable here: it evaluates pi*B0*(a[i]-a[0])**2/(psi[i]-psi[0]) at the node adjacent to the axis, where the minor radius goes as sqrt(psi), so a linear reconstruction underestimates it and the estimate depends on its square. On the packaged VEST sample that picks the wrong family on a margin of 0.22 against 1.67, where this loop integral separates 1.004 from 6.31.

identify_flux_exponent_from_q

Machine-independentConvention-sensitive source
identify_flux_exponent_from_q(equilibrium, *, levels=None)

Decide weber versus weber per radian by rebuilding q on closed contours.

The second, independent answer to the question identify_flux_exponent asks. The safety factor of a closed surface is q = |F|/(2*pi) * contour_integral(dl / (R |grad psi|)) when psi is in weber per radian, and 2*pi times that when psi is in weber, so comparing both reconstructions against the q profile the file already carries separates the two families.

It needs q and F; it needs neither ip nor a boundary outline, which is exactly what identify_flux_exponent cannot do without. On the three real equilibria this was measured on the two agree; where they differ is that this one still answers when the current record is zero or the boundary outline is missing.

NameTypeUnitDescription
equilibriumEquilibriumData-

Must carry r, z, psi, psi_axis, psi_boundary, psi_1d, q and f; anything missing is an abstention, not an error.

levelsarray_like, optional-

Normalized flux levels to trace, defaulting to CONTOUR_Q_LEVELS

Returns
—ContourQNormalization-

exponent 0 for weber per radian and 1 for weber, or None with a reason when the measurement does not support either.

Convention

Decides Sauter’s flux exponent e_Bp – whether the 2*pi is carried inside psi – and nothing else. It does not rescale psi, does not identify a sign orientation, and does not distinguish the eight indices within a family. q and F are compared by magnitude, because codes routinely emit abs(q) and the sign question belongs to validate_cocos.

Processing steps · Defaults · Applicability · Limitations · Provenance

Processing steps

  1. Trace each requested level with vaft.process.equilibrium.extract_flux_surface_contours and keep the longest closed contour that encloses the magnetic axis; a level whose contours are all open or all off-axis contributes nothing.
  2. On each kept contour evaluate |grad psi| = R * B_p with vaft.process.equilibrium.poloidal_field_at_boundary in its weber-per-radian form and integrate dl / (R |grad psi|) by the midpoint rule.
  3. Form the two candidate safety factors, |F|/(2*pi) times that integral and 2*pi times the first, and take each one’s |ln(q_model / q_stored)| against the stored |q| interpolated to the level.
  4. Take the median of each across the surfaces and accept the smaller one, but only when it is itself within CONTOUR_Q_LOG_TOLERANCE.

Defaults

CONTOUR_Q_LEVELS and CONTOUR_Q_MIN_SURFACES are legacy compatibility values, carried over from geqdsk_cocos.flux_normalization_diagnostic so the two agree surface for surface. CONTOUR_Q_LOG_TOLERANCE is a numerical convenience: the Ampere rung’s 15% band made symmetric in the ratio, so a model q 1.16 times too large and one 1.16 times too small are equally far out. A plain relative error is not symmetric and accepted the second while rejecting the first.

Applicability

Machine-independent. Needs a 2-D psi map with closed interior surfaces, so a profiles-only equilibrium cannot be classified.

Limitations

Abstains rather than picking the nearer of two wrong answers. A q profile that disagrees with its own psi map – a rescaled psi, a q taken from a different solve – makes both hypotheses wrong, and this reports that rather than a family. Marching squares resolves a contour only to the grid cell, so the log-ratio has a floor set by the grid: it was 1e-5 to 4e-4 on 129-by-129 and 513-by-513 reconstructions, against a losing log-ratio of ln(2*pi) = 1.8379.

Provenance

  1. The legacy implementation’s geqdsk_cocos.py::flux_normalization_diagnostic, which is the method and the levels. Its acceptance rule was relative only – the winner had to beat the loser threefold, with no bar on the winner’s own agreement – and that accepts a decisive-looking wrong answer: measured on a real g-file with psi scaled by one half, the winning hypothesis is off by a factor of 2.00 and the separation is still 3.65, so the legacy returns “weber per radian, decisive” for a hypothesis its own measurement misses by a factor of two. The bar in step 4 is what rejects it (D-04), and it makes the threefold rule unreachable: the two hypotheses sit exactly ln(2*pi) apart, so a winner inside the band leaves a ratio of at least twelve. The separation is reported, not applied.
  2. Sauter and Medvedev (2013) for e_Bp and the storage families.

validate_cocos

Machine-independentConvention-sensitive source
validate_cocos(equilibrium, cocos=None, *, sigma_ip=None, sigma_b0=None)

Check an equilibrium against the Sauter Eq. 23 relations for one COCOS index.

The check that catches a mislabelled file before its signs propagate into derived quantities. Never raises on an inconsistency: it returns a report and lets the caller decide whether a mismatch is fatal.

NameTypeUnitDescription
equilibriumEquilibriumData-

The equilibrium to check.

cocosint, optional-

The convention to check against, 1 to 18. Defaults to the index recorded on the equilibrium’s own convention.

sigma_ipint, optional-

Sign of the plasma current, +1 or -1. Defaults to the sign of the equilibrium’s ip.

sigma_b0int, optional-

Sign of the vacuum toroidal field. Defaults to the sign of bt0.

Returns
—ValidationReport-

One issue per violated relation, plus at most one cocos_unverifiable warning covering every relation whose inputs were missing. An empty report means every checkable relation held.

Convention

Checks consistency with a convention; it does not identify one and does not convert. A mismatch on q is reported at warning severity rather than error, because codes commonly emit abs(q) and a sign disagreement there is not on its own evidence of a wrong index. Every other relation is an error.

Processing steps · Applicability · Limitations · Provenance

Processing steps

  1. Resolve the target index and the two reference signs from the arguments, falling back to the equilibrium’s own convention and field signs.
  2. Measure the observed signs with cocos_consistency_signs.
  3. Compare each against the sign Eq. 23 requires for that index, collecting the mismatches.
  4. Collapse every unverifiable relation into a single warning rather than one issue each.

Applicability

Machine-independent.

Limitations

Only four of Eq. 23’s six relations are checkable against vaft.data.equilibrium.EquilibriumData as it stands; j_phi and phi_tor have no field to read and are always unverifiable. A passing report therefore means “consistent as far as the stored fields can say”, not “the index is correct”.

Provenance

  1. Sauter and Medvedev (2013), Eq. 23 for the relations and Sect. IV for the rule that a q sign mismatch is a warning, not a rejection.

results matching ""

    No results matching ""