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_signs | Observed sign of each Sauter Eq. 23 quantity, or None where not determinable.
Convention |
cocos_field_scales | The two sign multipliers that carry an equilibrium from one COCOS to another. Convention |
identify_convention | Candidate COCOS indices for an equilibrium, from its observable signs. Convention |
identify_flux_exponent | Decide whether psi is stored in weber or weber per radian, from Ampere’s law. Convention |
identify_flux_exponent_from_q | Decide weber versus weber per radian by rebuilding q on closed contours.
Convention |
validate_cocos | Check an equilibrium against the Sauter Eq. 23 relations for one COCOS index. Convention |
No function matches.
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.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData | - | The equilibrium to inspect. Missing fields yield |
| Returns | |||
| — | dict of str to int or None | - | Keys |
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
f,q,j_phiandphi_tor: the sign of the profile’s median, with a deadband so a numerically-zero profile reportsNone.dpsi: the sign ofpsi_boundary - psi_axis.pprime: the storedpprimeprofile’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
- 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.
| Name | Type | Unit | Description |
|---|---|---|---|
source | int | - | The index the equilibrium is in. |
target | int | - | The index it is wanted in. |
| Returns | |||
| — | tuple of int | - |
|
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
ValueErrorEither index is not one of the eighteen COCOS indices.
Processing steps · Applicability · Limitations · Provenance
Processing steps
- Look up both conventions’
sigma_Bpandsigma_RphiZ. - The flux multiplier is the product of the two
sigma_Bp sigma_RphiZproducts; the field multiplier is the product of the twosigma_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
- O. Sauter and S. Yu. Medvedev, Comput. Phys. Commun. 184 (2013) 293, Eq. 12 and Table I.
- 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.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData | - | Must carry |
clockwise_phi | bool, 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
- Reorder
psi_1dandqaxis-to-edge when the stored profile runs the other way. - Get the sign family from
omas.identify_cocos, which reads it off the signs ofip,bt0,qand the psi gradient. - Narrow to 1-8 or 11-18 using
identify_flux_exponent, falling back toidentify_flux_exponent_from_qwhen 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
- Sauter and Medvedev (2013) for the index numbering and the sign relations the identification rests on.
omas.identify_cocossupplies the sign family; its flux-exponent argument is deliberately not used, seeidentify_flux_exponent.- The contour-q fallback is the legacy implementation’s
geqdsk_cocos.py::flux_normalization_diagnostic, ported inidentify_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.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData | - | Must carry |
| Returns | |||
| — | tuple of (int or None, float or None) | - |
|
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
- Close the LCFS contour and compute the poloidal field on it with
vaft.process.equilibrium.poloidal_field_at_boundaryin the weber-per-radian form; only the magnitude matters. - Integrate it along the contour by the trapezoidal rule.
- Divide by
mu0*|Ip|. - Accept 0 or 1 if the ratio is within
FLUX_EXPONENT_TOLERANCEof 1 or2*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
- Sauter and Medvedev (2013) for
e_Bpand the storage families. - Replaces the
aargument ofomas.identify_cocos, which is not usable here: it evaluatespi*B0*(a[i]-a[0])**2/(psi[i]-psi[0])at the node adjacent to the axis, where the minor radius goes assqrt(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.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData | - | Must carry |
levels | array_like, optional | - | Normalized flux levels to trace, defaulting to |
| Returns | |||
| — | ContourQNormalization | - |
|
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
- Trace each requested level with
vaft.process.equilibrium.extract_flux_surface_contoursand keep the longest closed contour that encloses the magnetic axis; a level whose contours are all open or all off-axis contributes nothing. - On each kept contour evaluate
|grad psi| = R * B_pwithvaft.process.equilibrium.poloidal_field_at_boundaryin its weber-per-radian form and integratedl / (R |grad psi|)by the midpoint rule. - Form the two candidate safety factors,
|F|/(2*pi)times that integral and2*pitimes the first, and take each one’s|ln(q_model / q_stored)|against the stored|q|interpolated to the level. - 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
- 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 exactlyln(2*pi)apart, so a winner inside the band leaves a ratio of at least twelve. The separation is reported, not applied. - Sauter and Medvedev (2013) for
e_Bpand 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.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData | - | The equilibrium to check. |
cocos | int, optional | - | The convention to check against, 1 to 18. Defaults to the index recorded on the equilibrium’s own |
sigma_ip | int, optional | - | Sign of the plasma current, |
sigma_b0 | int, optional | - | Sign of the vacuum toroidal field. Defaults to the sign of |
| Returns | |||
| — | ValidationReport | - | One issue per violated relation, plus at most one |
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
- Resolve the target index and the two reference signs from the arguments, falling back to the equilibrium’s own convention and field signs.
- Measure the observed signs with
cocos_consistency_signs. - Compare each against the sign Eq. 23 requires for that index, collecting the mismatches.
- 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
- Sauter and Medvedev (2013), Eq. 23 for the relations and Sect. IV for the rule that a
qsign mismatch is a warning, not a rejection.