Process reference: profile
Generated from the docstrings of vaft.process.profile:
28 public functions. Each entry is what
vaft.process.describe("profile.<name>") prints.
All process categories
Overview
The chain, and where each step’s state changes::
measured diagnostic points (R, Z, value)
-> equilibrium-mapped coordinates: psi_norm, rho_pol_norm = sqrt(psi_norm),
rho_tor_norm from the equilibrium's own Phi(psi) [MappedPositions]
-> coordinate-selected profile points (default rho_tor_norm)
-> fitted callable in that coordinate [FittedProfile]
-> equilibrium-grid profile, stored on grid.rho_tor_norm / psi /
rho_pol_norm with the fit's provenance beside it [core_profiles]
Everything here is machine-independent. The radial coordinate to fit in,
the statistical Ti/Te ratio for a Thomson-only slice, and their provenance
are arguments; on VEST the pipeline
(vaft.code.efit.build_kinetic_core_profiles) resolves them from
vest.yaml through
vaft.machine_mapping.core_profiles.vest_core_profiles_policy. This
module holds no VEST number (issue #420).
| Symbol | Meaning | Unit |
|---|---|---|
| psi_norm | normalized poloidal flux, (psi - psi_axis)/(psi_boundary - psi_axis) | - |
| rho_pol_norm | sqrt(psi_norm) | - |
| rho_tor_norm | normalized toroidal-flux radius, sqrt(Phi/Phi_boundary), Phi = int q dpsi [-] | |
| T_e, T_i | electron, ion temperature | eV |
| n_e | electron density | m^-3 |
| V_tor | toroidal ion velocity | m/s |
| p | thermal pressure, e n_e (T_e + T_i) | Pa |
Three radial coordinates, never interchangeable: rho_tor_norm is not
sqrt(psi_norm) except for a flat-q cylinder. A fit is a function
of exactly one of them and carries which; core_profiles evaluates it
on the equilibrium grid expressed in that coordinate. Parameter names that
still say rho (rho_points, the deprecated mapped_rho_position)
predate the choice and mean “the fit coordinate”. Quasi-neutral single
main ion H+ with n_i = n_e; all electrons thermal.
Functions
analytic_hmode_itb_state | H-mode + ITB kinetic state: smooth core, internal barrier and edge pedestal composed. Convention |
analytic_hmode_state | H-mode-like kinetic state: a smooth core on an edge-localized pedestal. Convention |
analytic_itb_state | ITB-like kinetic state: a smooth profile with an internal transport barrier per channel. Convention |
analytic_lmode_state | Smooth L-mode-like kinetic state: generalized parabolic profiles with no barrier. Convention |
compare_flux_mapping | Map one diagnostic’s channels through several equilibria, to see how much the mapping moves them. |
compose_analytic_profile | Compose one kinetic profile from a smooth core, an optional edge pedestal and an optional ITB. Convention |
compose_plasma_state | Assemble prescribed n_e, T_e and T_i profiles into one kinetic state with derived pressure.
Convention |
core_profiles | Evaluate fitted kinetic profiles on the equilibrium grid and store them as a profiles_1d slice.
Convention |
core_profiles_from_eq | Build a synthetic core_profiles slice from the equilibrium pressure and an axis T_e.
Convention |
core_profiles_from_eq_ratio | Build a synthetic core_profiles slice from the equilibrium pressure and a fixed n_e/T_e.
Convention |
equilibrium_mapping_charge_exchange | Map charge-exchange channel positions into the equilibrium’s radial coordinates. Convention |
equilibrium_mapping_points | Map arbitrary (R, Z) points into the equilibrium’s radial coordinates.
|
equilibrium_mapping_thomson_scattering | Map Thomson scattering channel positions into the equilibrium’s radial coordinates. Convention |
evaluate_analytic_profile | Evaluate an analytic profile, or its gradient against normalized flux, anywhere in [0, 1].
Convention |
evaluate_plasma_state | Evaluate one quantity of an analytic plasma state at any normalized flux. Convention |
export_electron_profile_txt | Write fitted electron profiles, sampled on a uniform grid, to a text file. Convention |
fit_ti_te_ratio | Fit the proportionality coefficient alpha of Ti = alpha * Te.
|
generate_synthetic_kinetic_profiles | Generate n_e, T_e, T_i and the ion densities from an equilibrium and declared assumptions.
Convention |
pedestal_top | Pedestal-top position of a profile, from an EPED-style fit. Convention |
profile_fit_report_charge_exchange | Fit charge-exchange T_i and V_tor and report how well each fit reproduces its channels.
|
profile_fit_report_thomson_scattering | Fit Thomson T_e and n_e and report how well each fit reproduces its channels.
|
profile_fitting_charge_exchange | Fit charge-exchange T_i and V_tor profiles in a chosen radial coordinate.
Convention |
profile_fitting_thomson_scattering | Fit Thomson-scattering T_e and n_e profiles in a chosen radial coordinate.
Convention |
project_flux_function | Map a flux function f(psi_norm) onto an equilibrium’s (R, Z) grid.
Convention |
project_plasma_state | Project one quantity of an analytic plasma state onto an equilibrium’s (R, Z) grid.
Convention |
spec_from_plasma_state | The generator spec that reproduces a #1045 analytic plasma state on any equilibrium. Convention |
strip_electron_only_pressure | Drop slice-total pressure from every core_profiles slice with no ion temperature. |
write_synthetic_core_profiles | Store a successful synthetic kinetic state as one core_profiles.profiles_1d slice.
Convention |
No function matches.
analytic_hmode_itb_state
Machine-independentConvention-sensitive
source
analytic_hmode_itb_state(*, ne_axis=2e+19, ne_ped=1.2e+19, ne_sep=2e+18, te_axis=250.0, te_ped=80.0, te_sep=10.0, ti_axis=150.0, ti_ped=60.0, ti_sep=10.0, ne_itb_height=4e+18, te_itb_height=120.0, ti_itb_height=60.0, pedestal_position=0.93, pedestal_width=0.05, itb_position=0.3, itb_width=0.08, core_alpha=1.0, core_beta=1.5, z_eff=1.0, impurity_charge=6.0, psi_norm=None)
H-mode + ITB kinetic state: smooth core, internal barrier and edge pedestal composed.
| Name | Type | Unit | Description |
|---|---|---|---|
ne_axis | float, optional | m^-3 | Electron density on axis. |
ne_ped | float, optional | m^-3 | Electron density at the pedestal knee. |
ne_sep | float, optional | m^-3 | Electron density at the separatrix. |
te_axis | float, optional | eV | Electron temperature on axis. |
te_ped | float, optional | eV | Electron temperature at the pedestal knee. |
te_sep | float, optional | eV | Electron temperature at the separatrix. |
ti_axis | float, optional | eV | Ion temperature on axis. |
ti_ped | float, optional | eV | Ion temperature at the pedestal knee. |
ti_sep | float, optional | eV | Ion temperature at the separatrix. |
ne_itb_height | float, optional | m^-3 | Density amplitude of the ITB step, axis side to separatrix side. |
te_itb_height | float, optional | eV | Electron temperature amplitude of the ITB step, axis side to separatrix side. |
ti_itb_height | float, optional | eV | Ion temperature amplitude of the ITB step, axis side to separatrix side. |
pedestal_position | float or mapping, optional | - | Pedestal centre in |
pedestal_width | float or mapping, optional | - | Full pedestal width in |
itb_position | float or mapping, optional | - | ITB centre in |
itb_width | float or mapping, optional | - | Full ITB width in |
core_alpha | float or mapping, optional | - | Core radial exponent. |
core_beta | float or mapping, optional | - | Core peaking exponent. |
z_eff | float, optional | - | Uniform effective charge. |
impurity_charge | float, optional | - | Charge of the single impurity. |
psi_norm | array_like, optional | - | Sampling grid in |
| Returns | |||
| — | AnalyticPlasmaState | - | Labelled |
Convention
Normalized poloidal flux, full-width barrier convention; the pedestal top is the knee. The same composition as the other presets, with both steps.
Raises
ValueErrorAs forcompose_analytic_profileandcompose_plasma_state.
Defaults · Applicability · Limitations · Provenance
Defaults
The illustrative values (assumed value) of analytic_hmode_state
and analytic_itb_state together.
Applicability
Machine-independent.
Limitations
As for analytic_hmode_state and analytic_itb_state.
Provenance
- VAFT issue #1045: composition of an internal barrier and an edge pedestal in one state.
analytic_hmode_state
Machine-independentConvention-sensitive
source
analytic_hmode_state(*, ne_axis=2e+19, ne_ped=1.2e+19, ne_sep=2e+18, te_axis=250.0, te_ped=80.0, te_sep=10.0, ti_axis=150.0, ti_ped=60.0, ti_sep=10.0, pedestal_position=0.93, pedestal_width=0.05, core_alpha=1.0, core_beta=1.5, z_eff=1.0, impurity_charge=6.0, psi_norm=None)
H-mode-like kinetic state: a smooth core on an edge-localized pedestal.
| Name | Type | Unit | Description |
|---|---|---|---|
ne_axis | float, optional | m^-3 | Electron density on axis. |
ne_ped | float, optional | m^-3 | Electron density at the pedestal knee. |
ne_sep | float, optional | m^-3 | Electron density at the separatrix. |
te_axis | float, optional | eV | Electron temperature on axis. |
te_ped | float, optional | eV | Electron temperature at the pedestal knee. |
te_sep | float, optional | eV | Electron temperature at the separatrix. |
ti_axis | float, optional | eV | Ion temperature on axis. |
ti_ped | float, optional | eV | Ion temperature at the pedestal knee. |
ti_sep | float, optional | eV | Ion temperature at the separatrix. |
pedestal_position | float or mapping, optional | - | Centre of the pedestal layer in |
pedestal_width | float or mapping, optional | - | Full pedestal width in |
core_alpha | float or mapping, optional | - | Core radial exponent. |
core_beta | float or mapping, optional | - | Core peaking exponent. |
z_eff | float, optional | - | Uniform effective charge. |
impurity_charge | float, optional | - | Charge of the single impurity. |
psi_norm | array_like, optional | - | Sampling grid in |
| Returns | |||
| — | AnalyticPlasmaState | - | Labelled |
Convention
The pedestal top is the knee, pedestal_position - pedestal_width/2,
in the full-width Groebner-Carlstrom convention; pedestal_position is
the centre of the steep layer, not the top.
Raises
ValueErrorAs forcompose_analytic_profileandcompose_plasma_state.
Defaults · Applicability · Limitations · Provenance
Defaults
Illustrative values (assumed value, not a machine setting): pedestal tops
n_e 1.2e19 m^-3, T_e 80 eV, T_i 60 eV, the axis and separatrix
values of analytic_lmode_state, centre 0.93 and full width 0.05 in
psi_norm.
Applicability
Machine-independent.
Limitations
The pedestal is prescribed: no EPED width or height, no peeling-ballooning limit, and no bootstrap current (#550/#559). The state is not Grad-Shafranov consistent with any geometry.
Provenance
- VAFT issue #1045, canonical confinement-regime presets.
- R. J. Groebner and T. N. Carlstrom, Plasma Phys. Control. Fusion 40, 673 (1998), through
vaft.formula.equilibrium.modified_tanh_profile.
analytic_itb_state
Machine-independentConvention-sensitive
source
analytic_itb_state(*, ne_axis=2e+19, ne_sep=2e+18, te_axis=250.0, te_sep=10.0, ti_axis=150.0, ti_sep=10.0, ne_itb_height=4e+18, te_itb_height=120.0, ti_itb_height=60.0, itb_position=0.3, itb_width=0.08, core_alpha=1.0, core_beta=1.5, z_eff=1.0, impurity_charge=6.0, psi_norm=None)
ITB-like kinetic state: a smooth profile with an internal transport barrier per channel.
| Name | Type | Unit | Description |
|---|---|---|---|
ne_axis | float, optional | m^-3 | Electron density on axis. |
ne_sep | float, optional | m^-3 | Electron density at the separatrix. |
te_axis | float, optional | eV | Electron temperature on axis. |
te_sep | float, optional | eV | Electron temperature at the separatrix. |
ti_axis | float, optional | eV | Ion temperature on axis. |
ti_sep | float, optional | eV | Ion temperature at the separatrix. |
ne_itb_height | float, optional | m^-3 | Density amplitude of the ITB step, axis side to separatrix side; zero switches the ITB off in |
te_itb_height | float, optional | eV | Electron temperature amplitude of the ITB step, axis side to separatrix side; zero for none. |
ti_itb_height | float, optional | eV | Ion temperature amplitude of the ITB step, axis side to separatrix side; zero for none. |
itb_position | float or mapping, optional | - | ITB centre in |
itb_width | float or mapping, optional | - | Full ITB width in |
core_alpha | float or mapping, optional | - | Core radial exponent. |
core_beta | float or mapping, optional | - | Core peaking exponent. |
z_eff | float, optional | - | Uniform effective charge. |
impurity_charge | float, optional | - | Charge of the single impurity. |
psi_norm | array_like, optional | - | Sampling grid in |
| Returns | |||
| — | AnalyticPlasmaState | - | Labelled |
Convention
Positions and widths in normalized poloidal flux, full-width convention. The axis value is held, so the barrier steepens the profile at its centre and flattens it elsewhere; raise the axis value to raise the core.
Raises
ValueErrorAs forcompose_analytic_profileandcompose_plasma_state.
Defaults · Applicability · Limitations · Provenance
Defaults
Illustrative values (assumed value, not a machine setting): step amplitudes of
4e18 m^-3, 120 eV and 60 eV at psi_norm = 0.3 with full width 0.08,
on the axis and separatrix values of analytic_lmode_state.
Applicability
Machine-independent.
Limitations
Nothing about ITB formation (magnetic shear, E x B shear) is modelled, and the state is not Grad-Shafranov consistent with any geometry.
Provenance
- VAFT issue #1045: independent ITB behaviour per channel.
- R. J. Groebner and T. N. Carlstrom, Plasma Phys. Control. Fusion 40, 673 (1998), for the tanh step reused as an interior barrier.
analytic_lmode_state
Machine-independentConvention-sensitive
source
analytic_lmode_state(*, ne_axis=2e+19, ne_sep=2e+18, te_axis=250.0, te_sep=10.0, ti_axis=150.0, ti_sep=10.0, core_alpha=1.0, core_beta=1.5, z_eff=1.0, impurity_charge=6.0, psi_norm=None)
Smooth L-mode-like kinetic state: generalized parabolic profiles with no barrier.
| Name | Type | Unit | Description |
|---|---|---|---|
ne_axis | float, optional | m^-3 | Electron density on axis. |
ne_sep | float, optional | m^-3 | Electron density at the separatrix. |
te_axis | float, optional | eV | Electron temperature on axis. |
te_sep | float, optional | eV | Electron temperature at the separatrix. |
ti_axis | float, optional | eV | Ion temperature on axis. |
ti_sep | float, optional | eV | Ion temperature at the separatrix. |
core_alpha | float or mapping, optional | - | Core radial exponent, shared or keyed by |
core_beta | float or mapping, optional | - | Core peaking exponent, shared or keyed by channel. |
z_eff | float, optional | - | Uniform effective charge. |
impurity_charge | float, optional | - | Charge of the single impurity. |
psi_norm | array_like, optional | - | Sampling grid in |
| Returns | |||
| — | AnalyticPlasmaState | - | Labelled |
Convention
Every position and profile is in normalized poloidal flux psi_norm.
Raises
ValueErrorAs forcompose_analytic_profileandcompose_plasma_state.
Defaults · Applicability · Limitations · Provenance
Defaults
Densities and temperatures are illustrative small-tokamak values (assumed
value, not a machine setting): n_e 2e19 to 2e18 m^-3, T_e 250 to
10 eV, T_i 150 to 10 eV; core_alpha = 1, core_beta = 1.5
(assumed value).
Applicability
Machine-independent. The baseline against which the barrier presets are compared on one fixed geometry.
Limitations
A prescribed shape, not a confinement prediction, and not Grad-Shafranov consistent with any geometry.
Provenance
- VAFT issue #1045, canonical confinement-regime presets.
vaft.formula.equilibrium.generalized_parabolic_profile(#552).
compare_flux_mapping
Machine-independent
source
compare_flux_mapping(ods, equilibria, *, diagnostic='thomson_scattering', time=None)
Show source vaft/process/profile.py, lines 2084–2153
def compare_flux_mapping(ods, equilibria, *, diagnostic="thomson_scattering", time=None):
"""Map one diagnostic's channels through several equilibria, to see how much the mapping moves them.
A profile's radial coordinate is borrowed from an equilibrium, so two
reconstructions of the same instant -- a magnetics-only EFIT and a kinetic
one, say -- place the same channel at different ``psi_norm`` and
``rho_tor_norm``. This maps the channels through each and returns the
records side by side, keyed as the equilibria were.
Parameters
----------
ods : ODS
Carries the diagnostic's channel positions [-].
equilibria : mapping of str to GEQDSK, ODS or mapping
The equilibria to compare, each anything
:func:`equilibrium_mapping_thomson_scattering` accepts; a path to a
GEQDSK file is read with :func:`vaft.data.eqdsk.read_geqdsk` when
that reader is available [-].
diagnostic : str, optional
``"thomson_scattering"`` or ``"charge_exchange"`` [-].
time : float, optional
Map each ODS equilibrium through its slice nearest this time (as the
mappers' ``time``); ``None`` keeps each one's first slice [s].
Returns
-------
dict of str to MappedPositions
One record per equilibrium, in the order given, NaN outside that
equilibrium's LCFS [-].
Raises
------
ValueError
An unknown ``diagnostic``.
Assumptions
-----------
The channels' ``(R, Z)`` are the same for every equilibrium; only the flux
map changes.
Applicability
-------------
Machine-independent.
Limitations
-----------
Each ODS equilibrium contributes its first time slice unless ``time`` is
given; pass the diagnostic's time to pair the slices by time.
Provenance
----------
.. [1] The mappers :func:`equilibrium_mapping_thomson_scattering` and
:func:`equilibrium_mapping_charge_exchange`, applied once per
equilibrium.
"""
mappers = {
"thomson_scattering": equilibrium_mapping_thomson_scattering,
"charge_exchange": equilibrium_mapping_charge_exchange,
}
if diagnostic not in mappers:
raise ValueError(f"diagnostic must be one of {tuple(mappers)}, got {diagnostic!r}")
mapper = mappers[diagnostic]
out = {}
for name, geq in equilibria.items():
if isinstance(geq, (str, os.PathLike)):
from vaft.data.eqdsk import read_geqdsk
geq = read_geqdsk(geq)
out[name] = mapper(ods, geq, time=time)
return outMap one diagnostic’s channels through several equilibria, to see how much the mapping moves them.
A profile’s radial coordinate is borrowed from an equilibrium, so two
reconstructions of the same instant – a magnetics-only EFIT and a kinetic
one, say – place the same channel at different psi_norm and
rho_tor_norm. This maps the channels through each and returns the
records side by side, keyed as the equilibria were.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries the diagnostic’s channel positions. |
equilibria | mapping of str to GEQDSK, ODS or mapping | - | The equilibria to compare, each anything |
diagnostic | str, optional | - |
|
time | float, optional | s | Map each ODS equilibrium through its slice nearest this time (as the mappers’ |
| Returns | |||
| — | dict of str to MappedPositions | - | One record per equilibrium, in the order given, NaN outside that equilibrium’s LCFS. |
Raises
ValueErrorAn unknowndiagnostic.
Assumptions · Applicability · Limitations · Provenance
Assumptions
The channels’ (R, Z) are the same for every equilibrium; only the flux
map changes.
Applicability
Machine-independent.
Limitations
Each ODS equilibrium contributes its first time slice unless time is
given; pass the diagnostic’s time to pair the slices by time.
Provenance
- The mappers
equilibrium_mapping_thomson_scatteringandequilibrium_mapping_charge_exchange, applied once per equilibrium.
compose_analytic_profile
Machine-independentConvention-sensitive
source
compose_analytic_profile(quantity, *, axis_value, separatrix_value, core_alpha=1.0, core_beta=1.5, pedestal_top_value=None, pedestal_position=None, pedestal_width=None, itb_height=0.0, itb_position=None, itb_width=None, unit=None, positive=True)
Compose one kinetic profile from a smooth core, an optional edge pedestal and an optional ITB.
\[f(\psi_N) = f_\mathrm{sep} + A\,C(\psi_N) + H_\mathrm{ped}\,\tilde S_\mathrm{ped}(\psi_N) + H_\mathrm{itb}\,\tilde S_\mathrm{itb}(\psi_N)\]with $C = (1-\psi_N^{\alpha})^{\beta}$ the generalized parabolic core and $\tilde S = (S - S(1))/(S(0) - S(1))$ a Groebner tanh step normalized to exactly one on axis and zero at the separatrix. $A$ and $H_\mathrm{ped}$ are solved so the requested values hold exactly.
| Name | Type | Unit | Description |
|---|---|---|---|
quantity | str | - | Name of the profile, e.g. |
axis_value | float | any | Value on the magnetic axis, |
separatrix_value | float | any | Value at |
core_alpha | float, optional | - | Radial exponent of the core shape, at least one. |
core_beta | float, optional | - | Peaking exponent of the core shape, at least one. |
pedestal_top_value | float, optional | any | Value at the pedestal knee, |
pedestal_position | float, optional | - | Centre of the pedestal’s steep-gradient layer in |
pedestal_width | float, optional | - | Full width of the pedestal layer in |
itb_height | float, optional | any | Whole amplitude of the internal-barrier step, from its separatrix side to its axis side (the knee-to-foot change is about |
itb_position | float, optional | - | Centre of the ITB layer in |
itb_width | float, optional | - | Full width of the ITB layer in |
unit | str, optional | - | Unit label recorded on the profile; |
positive | bool, optional | - | Refuse a profile that is not strictly positive on |
| Returns | |||
| — | AnalyticProfile | - | The requested values, the barrier steps and the solved core amplitude and pedestal height; evaluate it with |
Convention
The coordinate is the normalized poloidal flux $\psi_N$, 0 on axis and 1
at the separatrix, so the profile is independent of the flux sign and of
Wb against Wb/rad storage. Barrier widths are full widths
(Groebner-Carlstrom): the steep layer runs from position - width/2
(the knee) to position + width/2 (the foot), and the steepest gradient
of an isolated step, $-H/(\Delta\,(S(0)-S(1)))$, sits at position.
itb_height is the whole step amplitude (axis side minus separatrix
side), not the knee-to-foot change; the pedestal is specified by its top
value instead. Widths must lie in [1e-3, 0.5]; an ITB layer must lie
inside (0, 1) and end before the pedestal layer begins.
Raises
ValueErrorA non-finite value, an exponent below one, a pedestal given in part, a width outside[1e-3, 0.5], a pedestal knee outside(0, 1), an ITB layer not strictly inside(0, 1)or overlapping the pedestal layer, a pedestal knee where the core and the step cannot be told apart, or a profile that is not positive (checked on a grid refined around each barrier) when positive is set.
Assumptions · Applicability · Limitations · Provenance
Assumptions
The axis value is held fixed: adding an ITB or a pedestal redistributes the profile under it rather than raising the axis. A caller who wants a higher core with an ITB raises axis_value as well.
Applicability
Machine-independent. Synthetic, prescribed profiles for demonstrations, tests and fixtures; not a transport or pedestal model.
Limitations
No pedestal width or height is predicted (EPED), and the ITB carries no
physics of its formation. A large ITB or pedestal with a fixed axis value
can make the core amplitude negative, i.e. a hollow core; that is returned
as asked, and only non-positivity is refused. The steps are rescaled to
vanish exactly at psi_norm = 1, so a layer centred at or beyond the
separatrix is compressed rather than cut.
Provenance
vaft.formula.equilibrium.generalized_parabolic_profileandvaft.formula.equilibrium.modified_tanh_profile(#552), the core shape and the step reused unchanged.- R. J. Groebner and T. N. Carlstrom, Plasma Phys. Control. Fusion 40, 673 (1998), for the tanh step and its full-width convention.
- VAFT issue #1045, which fixes the composition: exact axis, separatrix and pedestal-top values, independent ITB per channel.
compose_plasma_state
Machine-independentConvention-sensitive
source
compose_plasma_state(n_e, T_e, T_i, *, z_eff=1.0, impurity_charge=6.0, psi_norm=None, label='analytic')
Assemble prescribed n_e, T_e and T_i profiles into one kinetic state with derived pressure.
| Name | Type | Unit | Description |
|---|---|---|---|
n_e | AnalyticProfile | m^-3 | Electron density profile. |
T_e | AnalyticProfile | eV | Electron temperature profile. |
T_i | AnalyticProfile | eV | Ion temperature profile, shared by the main ion and the impurity. |
z_eff | float, optional | - | Effective charge, uniform in radius, in |
impurity_charge | float, optional | - | Charge of the single fully stripped impurity, greater than one. |
psi_norm | array_like, optional | - | Grid to sample on, inside |
label | str, optional | - | Name recorded on the state, e.g. |
| Returns | |||
| — | AnalyticPlasmaState | - | The three channels, the ion and impurity densities, the electron, ion and total pressures and their analytic gradients against |
Convention
Coordinate psi_norm; rho_pol_norm = sqrt(psi_norm) is exposed by
the record, never a toroidal radius. Quasi-neutrality
n_e = n_i + Z_I n_impurity with a hydrogenic main ion and
Z_eff n_e = n_i + Z_I^2 n_impurity; pressure p = e n T in Pa with
T in eV, ions at T_i. The pressure is derived, never prescribed,
so it cannot disagree with the stored densities and temperatures.
Raises
ValueErrorA profile whose quantity or unit does not match its slot, z_eff outside[1, impurity_charge], or a grid that is not 1-D, strictly increasing and inside[0, 1].
Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance
Output semantics
Synthetic: prescribed kinetic profiles and quantities derived from them. No measurement, fit or equilibrium is involved.
Defaults
z_eff = 1 (assumed value): a pure hydrogenic plasma, so n_i = n_e.
impurity_charge = 6 (assumed value, carbon) only matters once
z_eff > 1. The 201-point grid is a numerical convenience.
Assumptions
Uniform Z_eff; one impurity charge state; thermal particles only (no
fast-ion pressure).
Applicability
Machine-independent. A lightweight preset layer for demonstrations, tests and synthetic-diagnostic fixtures; the general synthetic kinetic framework is #122.
Limitations
The state is not Grad-Shafranov consistent with any geometry; projecting
it onto one (project_plasma_state) does not change that.
Provenance
- J. Wesson, Tokamaks, 4th ed. (2011), Ch. 2, for quasi-neutrality and the effective charge.
- VAFT issue #1045: pressure derived from the stored kinetic state.
core_profiles
Machine-independentConvention-sensitive
source
core_profiles(ods, time_ms, mapped_positions=None, n_e_function=None, T_e_function=None, tol_ms=0.1, T_i_function=None, V_tor_function=None, ti_mapped_positions=None, rho_points=100, time_tolerance_ms=1.0, geq=None, ti_te_fallback=True, ti_te_ratio=None, *, coordinate=None, ti_te_ratio_record=None, mapped_rho_position=None, ti_mapped_rho_position=None)
Evaluate fitted kinetic profiles on the equilibrium grid and store them as a profiles_1d slice.
The fits are functions of one radial coordinate – the one they were made
in, carried by FittedProfile or named by coordinate for a
plain callable – and are evaluated on the equilibrium’s grid expressed in
that same coordinate, so a fit in rho_tor_norm is never evaluated at a
psi_norm value. What was fitted, in which coordinate, and where any
assumed number came from is written beside the profile.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Mutated in place: gains or replaces the |
time_ms | float | ms | Time of the slice. |
mapped_positions | MappedPositions or np.ndarray, optional | - | Thomson channel positions from |
n_e_function | FittedProfile or callable, optional | m^-3 | Electron density fit. |
T_e_function | FittedProfile or callable, optional | eV | Electron temperature fit. |
tol_ms | float, optional | ms | An existing slice within this of |
T_i_function | FittedProfile or callable, optional | eV | Ion temperature fit from the charge-exchange fitter; when given, the ion block carries the real |
V_tor_function | FittedProfile or callable, optional | m/s | Toroidal ion velocity fit. |
ti_mapped_positions | MappedPositions or np.ndarray, optional | - | Charge-exchange channel positions, for the ion fit metadata. |
rho_points | int, optional | - | Size of the uniform fallback grid when no equilibrium slice matches. |
time_tolerance_ms | float, optional | ms | Tolerance for matching the Thomson and equilibrium times. |
geq | GEQDSK, optional | - | The equilibrium the mapping used; its 1-D grid is preferred over the ODS equilibrium so the profile lands on the same surfaces. |
ti_te_fallback | bool, optional | - | With no ion fit, still write an ion temperature from |
ti_te_ratio | float, optional | - | Coefficient for that fallback: |
coordinate | str, optional | - | Required when the fits are plain callables; must agree with every |
ti_te_ratio_record | str, optional | - | Provenance text for the ratio (value, status, source), stored beside the ion temperature; the pipeline passes the policy’s own record. |
mapped_rho_position | MappedPositions or np.ndarray, optional | - | Deprecated name for mapped_positions. |
ti_mapped_rho_position | MappedPositions or np.ndarray, optional | - | Deprecated name for ti_mapped_positions. |
| Returns | |||
| — | ODS | - | The same object, updated. |
Convention
The fit coordinate is one of rho_tor_norm, rho_pol_norm,
psi_norm; the equilibrium grid supplies all three (rho_pol_norm =
sqrt(psi_norm); rho_tor_norm from the equilibrium, never from
psi_norm). Quasi-neutral single main ion H+, n_i = n_e.
pressure_thermal = e n_e (T_e + T_i) [Pa] with temperatures in eV.
Raises
ValueErrorNo electron and no ion fit; an electron fit without positions; fits in different coordinates; a ratio that is not finite and non-negative; no Thomson time within tolerance.TypeErrorA plain callable withoutcoordinate, or a bare position array withoutcoordinate="psi_norm".CoordinateUnavailableErrorThe mapping cannot supply the fit’s coordinate.
Processing steps · Input semantics · Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Establish the fit coordinate from the fit objects (or
coordinate) and check they agree. - Read the measured Thomson values at the nearest time.
- Take the equilibrium 1-D grid – from
geq, else the ODS slice at this time – as(rho_tor_norm, psi, psi_norm); express it in the fit coordinate; without one, use a uniform grid in that coordinate. - Evaluate every fit on that grid; apply the ion fallback if needed.
- Replace any slice at the same time, write grid, electrons, ions, pressure, per-channel fit metadata and provenance.
Input semantics
Fitted: callables of one radial coordinate, from
profile_fitting_thomson_scattering /
profile_fitting_charge_exchange, plus the measured channel
values and their equilibrium-mapped positions.
Output semantics
Stored, on the equilibrium grid: grid.rho_tor_norm, grid.psi and
grid.rho_pol_norm when an equilibrium slice exists, else only the
coordinate the fit is actually in. *_fit.measured are measured,
*_fit.reconstructed are the fit at the measured points; a
ratio-derived ion temperature is inferred and says so.
Defaults
ti_te_ratio = None is a legacy compatibility value: the pre-#420
behaviour writes T_i = T_e and no pressure. The VEST value is
resolved by vaft.machine_mapping.core_profiles.vest_core_profiles_policy
and passed in by vaft.code.efit.build_kinetic_core_profiles.
tol_ms = 0.1 and time_tolerance_ms = 1.0 are numerical
conveniences.
Assumptions
All electrons are thermal (an ohmic plasma); one hydrogenic main ion with
no impurity dilution; the equilibrium at time_ms is the one the
channels were mapped through.
Applicability
Machine-independent. Every machine-specific number – the coordinate
convention, the Ti/Te ratio, its provenance – arrives as an argument;
for VEST the pipeline resolves them from vest.yaml.
Limitations
Only the first equilibrium time slice of geq is used. The
charge-exchange *_fit metadata is best-effort and its failure is
reported, not raised. A slice produced before #420 has no
*_fit.parameters; that absence is the signature of a legacy product
fitted in psi_norm.
Provenance
- Per-slice fit records in
electrons.{density,temperature}_fit.parametersandion.0.temperature_fit.parameters, and one line per slice incore_profiles.code.parameters; issue #420. A slice whosegrid.psicomes from the equilibrium carriesgrid.psi=Wb(#1292)in that line; a product without it predates the #1292 fix, when this leaf was stored 2*pi too large (#1338).
core_profiles_from_eq
Machine-independentConvention-sensitive
source
core_profiles_from_eq(ods, Te0_eV, rho_fit=None, tol_ms=0.1, eq_time_index=0)
Build a synthetic core_profiles slice from the equilibrium pressure and an axis T_e.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries the equilibrium slice; gains the |
Te0_eV | float | eV | Electron temperature on axis. |
rho_fit | array_like, optional | - |
|
tol_ms | float, optional | ms | An existing slice within this of the equilibrium time is replaced. |
eq_time_index | int, optional | - | Which equilibrium time slice. |
| Returns | |||
| — | ODS | - | The same object, updated. |
Convention
p = 2 n_e T_e e [Pa]: T_i = T_e and n_i = n_e are absorbed in
the factor 2. The grid is the equilibrium’s rho_tor_norm, resolved
the way core_profiles resolves it: a slice that stores the
sqrt(psi_N) proxy under that name (pre-#276 producers) has the real
coordinate re-derived from q, and is refused with
CoordinateUnavailableError when it cannot be.
Raises
ValueErrorNon-1-D or non-finite equilibrium profiles, or non-positive axis pressure.CoordinateUnavailableErrorThe slice stores thesqrt(psi_N)proxy asrho_tor_normand the real coordinate cannot be re-derived fromq.
Processing steps · Input semantics · Output semantics · Assumptions · Applicability · Limitations
Processing steps
- Interpolate the equilibrium
pressure(rho_tor_norm)ontorho_fit. g = sqrt(p / p(0));T_e = Te0 g;n_e = p(0) / (2 e Te0) g.- Write electrons and a quasi-neutral H+ ion with
T_i = T_e.
Input semantics
Reconstructed: the equilibrium pressure profile.
Output semantics
Synthetic: profiles consistent with that pressure under an assumed shape, not measured.
Assumptions
n_e and T_e share one shape, sqrt(p/p(0)); no impurities.
Applicability
Machine-independent.
Limitations
Any split of the pressure between density and temperature is consistent
with the equilibrium; this one is a convention, and Te0_eV fixes it.
core_profiles_from_eq_ratio
Machine-independentConvention-sensitive
source
core_profiles_from_eq_ratio(ods, C_ne_over_Te, rho_fit=None, tol_ms=0.1, eq_time_index=0)
Build a synthetic core_profiles slice from the equilibrium pressure and a fixed n_e/T_e.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries the equilibrium slice; gains the |
C_ne_over_Te | float | m^-3/eV | Density-to-temperature ratio held constant across the profile. |
rho_fit | array_like, optional | - |
|
tol_ms | float, optional | ms | An existing slice within this of the equilibrium time is replaced. |
eq_time_index | int, optional | - | Which equilibrium time slice. |
| Returns | |||
| — | ODS | - | The same object, updated. |
Convention
p = 2 n_e T_e e [Pa] with T_i = T_e; grid is the equilibrium’s
rho_tor_norm.
Raises
ValueErrorNon-positive axis pressure.CoordinateUnavailableErrorThe slice stores thesqrt(psi_N)proxy asrho_tor_normand the real coordinate cannot be re-derived fromq.
Processing steps · Input semantics · Output semantics · Assumptions · Applicability · Limitations
Processing steps
- Interpolate the equilibrium
pressure(rho_tor_norm)ontorho_fit. f = p / p(0);T_e = sqrt(f),n_e = C sqrt(f), then scale both bysqrt(p(0) / (2 C e))so thatp = 2 n_e T_e e.- Write electrons and a quasi-neutral H+ ion with
T_i = T_e.
Input semantics
Reconstructed: the equilibrium pressure profile.
Output semantics
Synthetic.
Assumptions
n_e / T_e is constant across the profile; no impurities.
Applicability
Machine-independent.
Limitations
A constant ratio is a modelling choice, not an observation.
equilibrium_mapping_charge_exchange
Machine-independentConvention-sensitive
source
equilibrium_mapping_charge_exchange(ods, geq, *, time=None)
Map charge-exchange channel positions into the equilibrium’s radial coordinates.
The charge-exchange twin of equilibrium_mapping_thomson_scattering:
the same mapping, from charge_exchange.channel[:].position.(r, z).
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries the channel positions, as |
geq | GEQDSK, ODS or mapping | - | A |
time | float, optional | s | As |
| Returns | |||
| — | MappedPositions | - |
|
Convention
As equilibrium_mapping_thomson_scattering: psi_norm is
normalized poloidal flux and rho_tor_norm is not its square root.
Processing steps · Input semantics · Output semantics · Applicability · Limitations
Processing steps
- Read each channel’s
(R, Z), taking the nominal value of an uncertainty-carrying leaf and the first sample of a time series. - As
equilibrium_mapping_thomson_scattering.
Input semantics
Measured: diagnostic-native (R, Z) channel positions.
Output semantics
Equilibrium-mapped, in three coordinates at once.
Applicability
Machine-independent.
Limitations
As equilibrium_mapping_thomson_scattering. A channel whose
position is a time series is mapped at its first sample only.
equilibrium_mapping_points
Machine-independent
source
equilibrium_mapping_points(geq, r, z, *, time=None)
Show source vaft/process/profile.py, lines 758–807
def equilibrium_mapping_points(geq, r, z, *, time=None):
"""Map arbitrary ``(R, Z)`` points into the equilibrium's radial coordinates.
The mapping :func:`equilibrium_mapping_thomson_scattering` applies to the
channel positions, applied to points the caller names -- a dense set along
a diagnostic chord, say, to draw a fitted flux function against major
radius.
Parameters
----------
geq : GEQDSK, ODS or mapping
As :func:`equilibrium_mapping_thomson_scattering` accepts [-].
r : array_like
Major radius of each point [m].
z : array_like
Height of each point [m].
time : float, optional
As :func:`equilibrium_mapping_thomson_scattering`: the ODS slice
nearest this time; ``None`` keeps the first [s].
Returns
-------
MappedPositions
``psi_norm``, ``rho_pol_norm`` and, when derivable, ``rho_tor_norm`` of
every point; NaN outside the LCFS [-].
Raises
------
ValueError
``geq`` is not an equilibrium the mapper can read.
Applicability
-------------
Machine-independent.
Limitations
-----------
One equilibrium time slice of an ODS is used: the first, unless ``time``
names another.
Provenance
----------
.. [1] The same interpolation and normalisation as
:func:`equilibrium_mapping_thomson_scattering`.
"""
geq, _, _ = _equilibrium_slice_at_time(geq, time)
r = np.asarray(r, dtype=float).reshape(-1)
z = np.asarray(z, dtype=float).reshape(-1)
psi_norm, source = _psi_norm_from_equilibrium_points(geq, r, z)
return _coordinates_from_psi_norm(geq, psi_norm, source)Map arbitrary (R, Z) points into the equilibrium’s radial coordinates.
The mapping equilibrium_mapping_thomson_scattering applies to the
channel positions, applied to points the caller names – a dense set along
a diagnostic chord, say, to draw a fitted flux function against major
radius.
| Name | Type | Unit | Description |
|---|---|---|---|
geq | GEQDSK, ODS or mapping | - | As |
r | array_like | m | Major radius of each point. |
z | array_like | m | Height of each point. |
time | float, optional | s | As |
| Returns | |||
| — | MappedPositions | - |
|
Raises
ValueErrorgeqis not an equilibrium the mapper can read.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
One equilibrium time slice of an ODS is used: the first, unless time
names another.
Provenance
- The same interpolation and normalisation as
equilibrium_mapping_thomson_scattering.
equilibrium_mapping_thomson_scattering
Machine-independentConvention-sensitive
source
equilibrium_mapping_thomson_scattering(ods, geq, *, time=None)
Show source vaft/process/profile.py, lines 691–755
def equilibrium_mapping_thomson_scattering(ods, geq, *, time=None):
"""Map Thomson scattering channel positions into the equilibrium's radial coordinates.
Parameters
----------
ods : ODS
Carries ``thomson_scattering.channel[:].position.r`` and ``.z`` [-].
geq : GEQDSK, ODS or mapping
A ``vaft.data.GEQDSK``, an OMAS equilibrium ODS, or a legacy
``fluxSurfaces`` mapping [-].
time : float, optional
For an ODS, map through the equilibrium slice nearest this time
(paired by time, not by index); ``None`` keeps the first slice.
Ignored for a GEQDSK or mapping, which is one instant [s].
Returns
-------
MappedPositions
``psi_norm``, ``rho_pol_norm`` and, when the equilibrium carries a
usable ``q``, ``rho_tor_norm`` for every channel; NaN outside the LCFS
[-].
Processing steps
----------------
1. Interpolate ``psi(R, Z)`` at each channel and normalize to
``psi_norm = (psi - psi_axis)/(psi_boundary - psi_axis)``; a channel
with ``psi_norm > 1`` is outside the plasma and becomes NaN.
2. ``rho_pol_norm = sqrt(psi_norm)``.
3. ``rho_tor_norm`` from the equilibrium's ``rho_tor_norm(psi_norm)``
table (``Phi = int q dpsi``), interpolated at each channel; recorded
as unavailable, with the reason, when ``q`` cannot supply it.
Input semantics
---------------
Measured: diagnostic-native ``(R, Z)`` channel positions.
Output semantics
----------------
Equilibrium-mapped, in three coordinates at once; the fitter selects one.
Convention
----------
``psi_norm`` is normalized *poloidal* flux; ``rho_tor_norm`` is the
normalized toroidal-flux radius and is **not** ``sqrt(psi_norm)`` except
for a flat-``q`` cylinder. Before issue #420 this function returned a
bare ``psi_norm`` array under the name "rho".
Applicability
-------------
Machine-independent.
Limitations
-----------
``rho_tor_norm`` is unavailable for a legacy ``fluxSurfaces`` mapping and
for a GEQDSK or ODS whose ``q`` is missing, non-finite or gives a
non-monotonic toroidal flux; a fit requested in that coordinate then
raises :class:`CoordinateUnavailableError` rather than falling back.
One equilibrium time slice of an ODS is used: the first, unless ``time``
names another.
"""
geq, _, _ = _equilibrium_slice_at_time(geq, time)
r_t = ods['thomson_scattering.channel.:.position.r']
z_t = ods['thomson_scattering.channel.:.position.z']
psi_norm, source = _psi_norm_from_equilibrium_points(geq, r_t, z_t)
return _coordinates_from_psi_norm(geq, psi_norm, source)Map Thomson scattering channel positions into the equilibrium’s radial coordinates.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries |
geq | GEQDSK, ODS or mapping | - | A |
time | float, optional | s | For an ODS, map through the equilibrium slice nearest this time (paired by time, not by index); |
| Returns | |||
| — | MappedPositions | - |
|
Convention
psi_norm is normalized poloidal flux; rho_tor_norm is the
normalized toroidal-flux radius and is not sqrt(psi_norm) except
for a flat-q cylinder. Before issue #420 this function returned a
bare psi_norm array under the name “rho”.
Processing steps · Input semantics · Output semantics · Applicability · Limitations
Processing steps
- Interpolate
psi(R, Z)at each channel and normalize topsi_norm = (psi - psi_axis)/(psi_boundary - psi_axis); a channel withpsi_norm > 1is outside the plasma and becomes NaN. rho_pol_norm = sqrt(psi_norm).rho_tor_normfrom the equilibrium’srho_tor_norm(psi_norm)table (Phi = int q dpsi), interpolated at each channel; recorded as unavailable, with the reason, whenqcannot supply it.
Input semantics
Measured: diagnostic-native (R, Z) channel positions.
Output semantics
Equilibrium-mapped, in three coordinates at once; the fitter selects one.
Applicability
Machine-independent.
Limitations
rho_tor_norm is unavailable for a legacy fluxSurfaces mapping and
for a GEQDSK or ODS whose q is missing, non-finite or gives a
non-monotonic toroidal flux; a fit requested in that coordinate then
raises CoordinateUnavailableError rather than falling back.
One equilibrium time slice of an ODS is used: the first, unless time
names another.
evaluate_analytic_profile
Machine-independentConvention-sensitive
source
evaluate_analytic_profile(profile, psi_norm, *, derivative=False)
Show source vaft/process/_analytic_plasma_state.py, lines 331–376
def evaluate_analytic_profile(profile: AnalyticProfile, psi_norm, *, derivative: bool = False):
r"""Evaluate an analytic profile, or its gradient against normalized flux, anywhere in ``[0, 1]``.
Parameters
----------
profile : AnalyticProfile
From :func:`compose_analytic_profile` or a state's ``profiles`` [-].
psi_norm : float or array_like
Normalized poloidal flux in ``[0, 1]`` [-].
derivative : bool, optional
Return $df/d\psi_N$ instead of $f$ [-].
Returns
-------
float or np.ndarray
The profile, or its analytic derivative, in the profile's unit (per
unit ``psi_norm`` for the derivative), with the shape of *psi_norm* [any].
Raises
------
ValueError
*psi_norm* is not finite or lies outside ``[0, 1]``.
Convention
----------
The derivative is against $\psi_N$, not $\psi$; divide by
$\psi_\mathrm{boundary}-\psi_\mathrm{axis}$ of a chosen equilibrium, in its
own flux unit and sign, for $df/d\psi$. It is the sum of the kernels'
analytic derivatives, not a finite difference.
Applicability
-------------
Machine-independent.
Provenance
----------
.. [552] :func:`vaft.formula.equilibrium.generalized_parabolic_profile_derivative`
and :func:`vaft.formula.equilibrium.modified_tanh_profile_derivative` (#552).
"""
x = np.asarray(psi_norm, dtype=float)
value = _core(x, profile.core_alpha, profile.core_beta, derivative=derivative) * profile.core_amplitude
if not derivative:
value = value + profile.separatrix_value
for step in profile.barriers:
value = value + _step(x, step, derivative=derivative)
return float(value) if np.ndim(value) == 0 else valueEvaluate an analytic profile, or its gradient against normalized flux, anywhere in [0, 1].
| Name | Type | Unit | Description |
|---|---|---|---|
profile | AnalyticProfile | - | From |
psi_norm | float or array_like | - | Normalized poloidal flux in |
derivative | bool, optional | - | Return $df/d\psi_N$ instead of $f$. |
| Returns | |||
| — | float or np.ndarray | any | The profile, or its analytic derivative, in the profile’s unit (per unit |
Convention
The derivative is against $\psi_N$, not $\psi$; divide by $\psi_\mathrm{boundary}-\psi_\mathrm{axis}$ of a chosen equilibrium, in its own flux unit and sign, for $df/d\psi$. It is the sum of the kernels’ analytic derivatives, not a finite difference.
Raises
ValueErrorpsi_norm is not finite or lies outside[0, 1].
Applicability · Provenance
Applicability
Machine-independent.
Provenance
vaft.formula.equilibrium.generalized_parabolic_profile_derivativeandvaft.formula.equilibrium.modified_tanh_profile_derivative(#552).
evaluate_plasma_state
Machine-independentConvention-sensitive
source
evaluate_plasma_state(state, psi_norm, quantity='p_total')
Show source vaft/process/_analytic_plasma_state.py, lines 388–453
def evaluate_plasma_state(state: AnalyticPlasmaState, psi_norm, quantity: str = "p_total"):
r"""Evaluate one quantity of an analytic plasma state at any normalized flux.
Parameters
----------
state : AnalyticPlasmaState
From :func:`compose_plasma_state` or a preset [-].
psi_norm : float or array_like
Normalized poloidal flux in ``[0, 1]`` [-].
quantity : str, optional
One of ``n_e``, ``n_i``, ``n_impurity``, ``T_e``, ``T_i``, ``p_e``,
``p_i``, ``p_total``, ``dp_e_dpsi_norm``, ``dp_i_dpsi_norm``,
``dp_total_dpsi_norm`` [-].
Returns
-------
float or np.ndarray
The quantity in the unit of :data:`vaft.data.ANALYTIC_STATE_UNITS`
(m^-3, eV, Pa, or Pa per unit ``psi_norm``) [any].
Raises
------
ValueError
An unknown quantity, or *psi_norm* outside ``[0, 1]``.
Convention
----------
``p = e n T`` with *T* in eV and ``e`` the elementary charge, so pressure
is in Pa; ``p_i`` counts the main ion and the impurity, both at ``T_i``.
Gradients are against ``psi_norm`` by the product rule on the channels'
analytic derivatives.
Applicability
-------------
Machine-independent.
Provenance
----------
.. [W11] J. Wesson, *Tokamaks*, 4th ed. (2011), Ch. 2, for quasi-neutrality
and the effective charge that fix the ion densities (through
:func:`vaft.formula.atomic.impurity_fraction_from_effective_charge`).
"""
if quantity not in _STATE_QUANTITIES:
raise ValueError(f"quantity must be one of {_STATE_QUANTITIES}, got {quantity!r}")
x = np.asarray(psi_norm, dtype=float)
impurity, ions = _composition(state.z_eff, state.impurity_charge)
prof = state.profiles
def f(name, d=False):
return np.asarray(evaluate_analytic_profile(prof[name], x, derivative=d), dtype=float)
if quantity in ("n_e", "T_e", "T_i"):
out = f(quantity)
elif quantity == "n_i":
out = f("n_e") * (1.0 - state.impurity_charge * impurity)
elif quantity == "n_impurity":
out = f("n_e") * impurity
else:
n_e, dn_e = f("n_e"), f("n_e", True)
p_e = QE * n_e * f("T_e")
p_i = QE * ions * n_e * f("T_i")
dp_e = QE * (dn_e * f("T_e") + n_e * f("T_e", True))
dp_i = QE * ions * (dn_e * f("T_i") + n_e * f("T_i", True))
out = {"p_e": p_e, "p_i": p_i, "p_total": p_e + p_i, "dp_e_dpsi_norm": dp_e,
"dp_i_dpsi_norm": dp_i, "dp_total_dpsi_norm": dp_e + dp_i}[quantity]
return float(out) if out.ndim == 0 else outEvaluate one quantity of an analytic plasma state at any normalized flux.
| Name | Type | Unit | Description |
|---|---|---|---|
state | AnalyticPlasmaState | - | From |
psi_norm | float or array_like | - | Normalized poloidal flux in |
quantity | str, optional | - | One of |
| Returns | |||
| — | float or np.ndarray | any | The quantity in the unit of |
Convention
p = e n T with T in eV and e the elementary charge, so pressure
is in Pa; p_i counts the main ion and the impurity, both at T_i.
Gradients are against psi_norm by the product rule on the channels’
analytic derivatives.
Raises
ValueErrorAn unknown quantity, or psi_norm outside[0, 1].
Applicability · Provenance
Applicability
Machine-independent.
Provenance
- J. Wesson, Tokamaks, 4th ed. (2011), Ch. 2, for quasi-neutrality and the effective charge that fix the ion densities (through
vaft.formula.atomic.impurity_fraction_from_effective_charge).
export_electron_profile_txt
Machine-independentConvention-sensitive
source
export_electron_profile_txt(n_e_function, T_e_function, n_e_coeff, T_e_coeff, rho_points=100, filename='electron_profiles.txt')
Show source vaft/process/profile.py, lines 3186–3234
def export_electron_profile_txt(
n_e_function,
T_e_function,
n_e_coeff,
T_e_coeff,
rho_points=100,
filename='electron_profiles.txt',
):
"""Write fitted electron profiles, sampled on a uniform grid, to a text file.
Parameters
----------
n_e_function : FittedProfile or callable
``n_e(x)`` [m^-3].
T_e_function : FittedProfile or callable
``T_e(x)`` [eV].
n_e_coeff : np.ndarray or None
Fit coefficients; not written, kept for the legacy signature [-].
T_e_coeff : np.ndarray or None
As ``n_e_coeff`` [-].
rho_points : int, optional
Points of the uniform grid on ``[0, 1]`` [-].
filename : str, optional
Output path [-].
Returns
-------
None
The file is the result [-].
Convention
----------
The first column is labelled with the fit's coordinate when a
:class:`FittedProfile` is given, else ``x``; a plain callable's coordinate
is unknown here.
Applicability
-------------
Machine-independent.
"""
rho_eval = np.linspace(0, 1, rho_points)
n_e_rho = n_e_function(rho_eval)
T_e_rho = T_e_function(rho_eval)
with open(filename, 'w', encoding='utf-8') as f:
label = n_e_function.coordinate if isinstance(n_e_function, FittedProfile) else 'x'
f.write(f'{label}, T_e [eV], n_e [m-3]\n')
for rho, T_e, n_e in zip(rho_eval, T_e_rho, n_e_rho):
f.write(f'{rho}, {T_e}, {n_e}\n')Write fitted electron profiles, sampled on a uniform grid, to a text file.
| Name | Type | Unit | Description |
|---|---|---|---|
n_e_function | FittedProfile or callable | m^-3 |
|
T_e_function | FittedProfile or callable | eV |
|
n_e_coeff | np.ndarray or None | - | Fit coefficients; not written, kept for the legacy signature. |
T_e_coeff | np.ndarray or None | - | As |
rho_points | int, optional | - | Points of the uniform grid on |
filename | str, optional | - | Output path. |
| Returns | |||
| — | None | - | The file is the result. |
Convention
The first column is labelled with the fit’s coordinate when a
FittedProfile is given, else x; a plain callable’s coordinate
is unknown here.
Applicability
Applicability
Machine-independent.
fit_ti_te_ratio
Machine-independent
source
fit_ti_te_ratio(te, ti, te_std=None, ti_std=None, max_iter=200, tol=1e-12)
Fit the proportionality coefficient alpha of Ti = alpha * Te.
Effective-variance weighted through-origin regression with errors in BOTH
variables: minimizes sum_k (Ti_k - a*Te_k)^2 / (sTi_k^2 + a^2*sTe_k^2)
by iterating the weights. This is the estimator the VEST statistical
coefficient was derived with [TITE] (paired Thomson Te and fitted
charge-exchange Ti at the same radial position, on the shots that carry
both diagnostics); use it to re-derive the coefficient as more
two-diagnostic shots become available.
| Name | Type | Unit | Description |
|---|---|---|---|
te | array_like | eV | Electron temperature samples. |
ti | array_like | eV | Ion temperature samples, paired with |
te_std | array_like, optional | eV | 1-sigma uncertainties of |
ti_std | array_like, optional | eV | 1-sigma uncertainties of |
max_iter | int, optional | - | Iterations of the weight update. |
tol | float, optional | - | Change in |
| Returns | |||
| — | dict | - |
|
Raises
ValueErrorMismatched lengths, or fewer than two valid pairs.
Processing steps · Defaults · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Drop pairs with a non-finite value, a non-finite or negative sigma, or
Te <= 0. - Start from the unweighted through-origin estimate.
- Iterate
w = 1 / (sTi^2 + a^2 sTe^2),a = sum(w Te Ti)/sum(w Te^2)to convergence. - Standard error, reduced chi-square, and the weighted scatter of
Ti/Te.
Defaults
max_iter = 200 and tol = 1e-12 are numerical conveniences. A
uniformly zero ti_std is replaced by unit weights, a numerical
convenience that keeps the effective variance finite.
Assumptions
Ti is proportional to Te with no offset, across the whole sample.
Applicability
Machine-independent. The VEST value it produced (0.17, sigma 0.08) is kept
in vest.yaml as superseded_inference; the policy in force there is an
assumed Ti = Te until more ion-diagnostic shots exist (#1331).
Limitations
The derivation script cited by the VEST record, ids_test/fit_ti_te_ratio.py,
is not in the repository; the value is reproducible from this estimator and
the three shots named there, but the script that did it is not tracked.
Provenance
- The VEST Ti/Te policy record [TITE]: shots 48224, 48226, 48233 at 299-301 ms; pressure-matching estimator on the fitted 129-point profiles, cross-checked at 0.170 +/- 0.010 by this regression.
generate_synthetic_kinetic_profiles
Machine-independentConvention-sensitive
source
generate_synthetic_kinetic_profiles(equilibrium, spec, *, time=None, time_index=0, pressure_tolerance=1e-06)
Generate n_e, T_e, T_i and the ion densities from an equilibrium and declared assumptions.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | GEQDSK, ODS, IMAS IDS, EquilibriumData or path | - | The magnetic equilibrium, adapted through |
spec | SyntheticKineticSpec | - | Shapes, normalizations, temperature route, composition and pressure constraint; see |
time | float, optional | s | Time recorded on the result; the equilibrium’s own time when omitted. |
time_index | int, optional | - | Time slice of a multi-slice source. |
pressure_tolerance | float, optional | - | Largest relative local pressure residual a locally closed state may carry. |
| Returns | |||
| — | SyntheticKineticProfiles | - | The profiles on the equilibrium’s |
Convention
The grid is the source equilibrium’s normalized poloidal flux
psi_norm = (psi - psi_axis)/(psi_boundary - psi_axis), independent of
COCOS and of Wb against Wb/rad; rho_pol_norm = sqrt(psi_norm);
rho_tor_norm is derived from q and never assumed equal to
rho_pol_norm. psi is reported in Wb, COCOS 11 (the IMAS DD and
vaft.data.cocos.VAFT_INTERNAL_COCOS), only when every
convention candidate of the source gives the same value, or when an ODS
source declares its own cocos and that is one of the candidates.
p = e n T
in Pa with T in eV; the main ion is hydrogenic and every ion is at
T_i. The line average is along the horizontal chord through the
magnetic axis; the volume average uses the traced V(psi).
Raises
SyntheticProfileErrorA refused input, withstatusinvalid_equilibrium,invalid_profile_model,invalid_gradient_model,invalid_normalization,invalid_compositionorcoordinate_mapping_failed: a missing equilibrium quantity, a channel the closure solves also prescribed, a target fixing an amplitude twice, a Greenwald fraction on a temperature, a tabulated profile that does not cover the grid, an unavailable coordinate.
Processing steps · Input semantics · Output semantics · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Adapt the equilibrium and build the grid (101 points uniform in
rho_pol_normunless the spec givespsi_norm); mapp_eq,rho_tor_norm(fromq) andpsi(Wb, COCOS 11) onto it; trace the flux-surface volume; lay the axis chord. - Resolve each prescribed channel: shape (analytic #1045 composition,
tabulated, or integrated
a/L), then a peaking factor through the core exponent, then one amplitude target by linear scaling. - Apply the pressure constraint: solve the closure’s variable locally
(
equilibrium), one amplitude (thermal_energy), or nothing (kinetic). A local temperature or density closure is exact up to the edge region wherep_eq < edge_floor * max(p_eq), and carries its solved channel toedge_valueacross it (seevaft.data.SyntheticKineticSpec). - Build the ion densities from quasi-neutrality and
Z_eff, the pressures fromp = e n T. - Recompute every target,
Z_eff, quasi-neutrality and the pressure residual from the final arrays; set the status.
Input semantics
Reconstructed or analytic: a magnetic equilibrium, and assumptions.
Output semantics
Synthetic: assumption-driven kinetic profiles consistent with the requested constraints, never measured, fitted or transport-predicted.
Assumptions
Thermal particles only (no fast-ion pressure); uniform local Z_eff;
one fully stripped impurity charge state.
Applicability
Machine-independent. Any equilibrium with a flux map, an LCFS outline, a
magnetic axis and a 1-D flux grid; p_eq is needed for the
equilibrium and thermal_energy constraints, q for
rho_tor_norm, I_p for a Greenwald fraction.
Limitations
Levels 0-3 only: no empirical closure, no pedestal model (EPED) and no
transport solver. The equilibrium is not updated to the kinetic pressure
(#123). A local pressure closure divides by the held variable, so a held
profile that vanishes where p_eq does not fails the closure rather
than being clipped. Across the edge region the solved channel is an
assumption (its declared edge_value), not a closure: p_kin there
differs from p_eq and the difference is reported as
edge_max_relative_residual.
Provenance
- VAFT issue #122: the fidelity ladder, the closure modes and the residuals reported.
vaft.process.profile.compose_analytic_profileandvaft.process.profile.evaluate_analytic_profile, the shape kernels reused unchanged.- J. Wesson, Tokamaks, 4th ed. (2011), Ch. 2, quasi-neutrality and the effective charge (via
vaft.formula.atomic.impurity_fraction_from_effective_charge). - M. Greenwald et al., Nucl. Fusion 28, 2199 (1988), through
vaft.formula.stability.greenwald_density.
pedestal_top
Machine-independentConvention-sensitive
source
pedestal_top(x, values, *, quantity, value_std=None, coordinate='psi_norm', fallback=0.85, window=(0.4, 1.05), min_points=20, max_width=0.15)
Pedestal-top position of a profile, from an EPED-style fit.
Fits the seven-parameter pedestal model
(vaft.formula.fit_profile with fitting_function='eped_tanh')
over window and reports its x_ped. When the profile cannot
support that fit the documented fallback is returned instead, with the
reason recorded – never silently.
| Name | Type | Unit | Description |
|---|---|---|---|
x | array_like | - | Radial coordinate of the profile, in |
values | array_like | any | Profile samples; any quantity with a pedestal. |
quantity | str | n/a | What |
value_std | array_like, optional | any | Per-sample uncertainty, passed to the fit as weights. |
coordinate | str, optional | n/a | Which radial coordinate |
fallback | float, optional | - | Position returned when the fit is not usable. |
window | tuple of float, optional | - |
|
min_points | int, optional | - | Fewest samples inside |
max_width | float, optional | - | Widest tanh still counted as a pedestal, in |
| Returns | |||
| — | PedestalTop | - | Position, the method that produced it, and the fit when there was one. |
Convention
The position is in coordinate, which defaults to psi_norm because
that is what kinetic-profile files carry; a caller working in
rho_tor_norm must say so, and the value is not converted. x_ped
is the tanh’s centre, i.e. the mid-point of the pedestal, not its knee.
Raises
ValueErrorx,valuesorvalue_stddiffer in length, orcoordinateis not one ofCOORDINATES.CoordinateUnavailableErrorThe fit was not usable andcoordinateis notpsi_norm, so the default fallback – a psi_norm position – would be wrong.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Restrict to
windowand drop non-finite samples. - Fit
eped_tanhthere, weighted byvalue_stdwhen given. - Accept
x_pedunless the fit is unusable – too few points, a fit that did not converge,x_pedresting on a bound of the model’s box, or a fitted curve that does not vary across the window byPEDESTAL_RESOLUTION_FACTORtimes the residual scatter, which means no pedestal was resolved. - Otherwise return
fallbackand say which of those it was.
Defaults
fallback = 0.85 is a validated-workflow default: the value decision
D-05 names when profiles are missing or the fit is unreliable, chosen from
the legacy windows rather than derived. window = (0.4, 1.05) and
min_points = 20 are numerical convenience – enough of the edge to
resolve a pedestal, and more samples than the model has parameters.
PEDESTAL_RESOLUTION_FACTOR is an empirical estimate: the measured
separation between a pure-noise fit and a real one.
Applicability
Machine-independent. Any profile with a pedestal, from any source: a kinetic-profile file, a fitted diagnostic profile, or a transport code. It takes arrays rather than an ODS so that a caller holding only a file can use it.
Limitations
An L-mode profile has no pedestal to find and will take the fallback;
that is the intended answer, not a failure. The fit is unweighted in
x, so a grid that is much denser in the core than the edge biases it.
Provenance
- Migration decision D-05 (2026-09-06): no fixed canonical pedestal boundary; pedestal top from an EPED-style profile fit when profiles are available, fallback 0.85 otherwise, and every reduction records which method produced it.
- The seven-parameter model and its parameter box are ported from the legacy implementation’s pedestal-fitting study (
transp_example/pedestal_fitting.ipynb). The olderkinetic_analysis.ped_fittingmodified tanh is deliberately not carried over. Its slope term multiplies the tanh across the whole domain, so the curve runs away in both directions – with that function’s own defaults it reaches -3750 at x = 0.70, i.e. inside its own 0.7-1.0 fit window, and bounding the slope does not remove it. It also cannot fit an all-negative profile such as a rotation: for a narrow-range one its parameter box inverts outright, and otherwise the seed falls outside the box and SciPy refuses it.
profile_fit_report_charge_exchange
Machine-independent
source
profile_fit_report_charge_exchange(ods, time_ms, mapped_positions=None, Ti_order=3, Vtor_order=3, uncertainty_option=1, rho_points=100, fitting_function_ti='polynomial', fitting_function_vtor='polynomial', ion_index=0, time_tolerance_ms=1.0, clamp_to_measured_span=True, *, coordinate='rho_tor_norm')
Fit charge-exchange T_i and V_tor and report how well each fit reproduces its channels.
The ion twin of profile_fit_report_thomson_scattering, around the
fit profile_fitting_charge_exchange makes.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries |
time_ms | float | ms | Time to fit at. |
mapped_positions | MappedPositions | - | Channel positions from |
Ti_order | int, optional | - | Polynomial order for |
Vtor_order | int, optional | - | Polynomial order for |
uncertainty_option | int, optional | - |
|
rho_points | int, optional | - | Points of the grid the report’s |
fitting_function_ti | str, optional | - | Model for |
fitting_function_vtor | str, optional | - | Model for |
ion_index | int, optional | - | Which ion of each channel. |
time_tolerance_ms | float, optional | ms | Largest distance to the nearest charge-exchange sample. |
clamp_to_measured_span | bool, optional | - | Hold the fit at its end values outside the measured span. |
coordinate | str, optional | - | Which coordinate of the mapping to fit in. |
| Returns | |||
| — | dict of str to FitReport | - |
|
Raises
ValueErrorNo charge-exchange sample within tolerance; an unknowncoordinate.CoordinateUnavailableErrorThe mapping cannot supplycoordinate.
Processing steps · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Fit exactly as
profile_fitting_charge_exchangedoes; each quantity keeps its own channel set. - Record why each refused channel was refused: a non-finite value or position, or a non-finite or non-positive sigma while other channels carry usable ones. When no channel carries a usable sigma the fitter gives all of them a uniform one, and the report notes it.
- Residuals, chi-square and
nu = N - kas inFitReport, with the sigmas the fit was weighted with.
Assumptions
Independent, symmetric one-sigma uncertainties.
Applicability
Machine-independent.
Limitations
With clamp_to_measured_span the curve is flat outside the measured
span, which no channel constrains; the residuals only test the span.
Provenance
- The fitting kernel [FIT]; chi-square from
vaft.formula.statistics.chi_squared(Bevington & Robinson).
profile_fit_report_thomson_scattering
Machine-independent
source
profile_fit_report_thomson_scattering(ods, time_ms, mapped_positions=None, Te_order=3, Ne_order=3, uncertainty_option=1, rho_points=100, fitting_function_te='polynomial', fitting_function_ne='polynomial', time_tolerance_ms=1.0, enforce_physical=True, *, coordinate='rho_tor_norm')
Fit Thomson T_e and n_e and report how well each fit reproduces its channels.
The same fit profile_fitting_thomson_scattering makes, with the
same arguments, returned as one FitReport per quantity: every
channel with its normalised residual, the chi-square over the channels
the fit used, the degrees of freedom, and the reason each refused channel
was refused.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries |
time_ms | float | ms | Time to fit at; the nearest Thomson sample within |
mapped_positions | MappedPositions | - | Channel positions from |
Te_order | int, optional | - | Starting order for |
Ne_order | int, optional | - | Starting order for |
uncertainty_option | int, optional | - |
|
rho_points | int, optional | - | Points of the uniform grid the report’s |
fitting_function_te | str, optional | - | Model for |
fitting_function_ne | str, optional | - | Model for |
time_tolerance_ms | float, optional | ms | Largest distance to the nearest Thomson sample. |
enforce_physical | bool, optional | - | Reduce the order until the profile is physical inside the LCFS. |
coordinate | str, optional | - |
|
| Returns | |||
| — | dict of str to FitReport | - |
|
Raises
ValueErrorNo Thomson sample within tolerance; an unknowncoordinate.CoordinateUnavailableErrorThe mapping cannot supplycoordinate.
Processing steps · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Fit exactly as
profile_fitting_thomson_scatteringdoes. - For each channel record why it was refused: a non-finite value, a non-finite or non-positive sigma, an unmapped position (outside the LCFS or the equilibrium grid), or – Thomson measures both quantities on one channel – the other quantity’s refusal.
r_i = (y_i - f(x_i)) / sigma_iat every used channel, with the sigma the fit was weighted with (after its floors);chi2 = sum r_i^2;nu = N - k(seeFitReportfork).
Assumptions
The stored data_error_upper is a symmetric one-sigma uncertainty and
the channels are independent; chi2 / nu ~ 1 then means the model and
the uncertainties agree.
Applicability
Machine-independent.
Limitations
A channel refused because of its partner quantity is not a statement about
its own measurement. The residual is taken against the returned,
non-negative-clipped curve; where clipping bit, r_i is larger than the
optimiser saw.
Provenance
- The fitting kernel [FIT]; chi-square and its reduced form from
vaft.formula.statistics.chi_squared(Bevington & Robinson).
profile_fitting_charge_exchange
Machine-independentConvention-sensitive
source
profile_fitting_charge_exchange(ods, time_ms, mapped_positions=None, Ti_order=3, Vtor_order=3, uncertainty_option=1, rho_points=100, fitting_function_ti='polynomial', fitting_function_vtor='polynomial', ion_index=0, time_tolerance_ms=1.0, clamp_to_measured_span=True, *, coordinate='rho_tor_norm', mapped_rho_position=None)
Fit charge-exchange T_i and V_tor profiles in a chosen radial coordinate.
The ion twin of profile_fitting_thomson_scattering, reading
charge_exchange.channel[:].ion[ion_index].t_i and velocity_tor. By
default the fitted curves are held at their value at the innermost and
outermost measured positions rather than extrapolated beyond them.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries |
time_ms | float | ms | Time to fit at. |
mapped_positions | MappedPositions or np.ndarray, optional | - | Channel positions from |
Ti_order | int, optional | - | Polynomial order for |
Vtor_order | int, optional | - | Polynomial order for |
uncertainty_option | int, optional | - |
|
rho_points | int, optional | - | Points of the uniform evaluation grid the sampled returns are on. |
fitting_function_ti | str, optional | - | Model for |
fitting_function_vtor | str, optional | - | Model for |
ion_index | int, optional | - | Which ion of each channel. |
time_tolerance_ms | float, optional | ms | Largest distance to the nearest charge-exchange sample. |
clamp_to_measured_span | bool, optional | - | Hold the fit at its end values outside the measured span. |
coordinate | str, optional | - | Which coordinate of the mapping to fit in. |
mapped_rho_position | MappedPositions or np.ndarray, optional | - | Deprecated name for |
| Returns | |||
Vtor_function | FittedProfile | m/s |
|
Ti_function | FittedProfile | eV |
|
coeffs_vtor | np.ndarray or None | - | Fit coefficients, |
coeffs_ti | np.ndarray or None | - | As |
Vtor_rho | np.ndarray | m/s |
|
Ti_rho | np.ndarray | eV |
|
Convention
As profile_fitting_thomson_scattering: the fit and its span are in
the selected coordinate. V_tor keeps the sign the diagnostic mapping
gave it.
Raises
ValueErrorNo charge-exchange sample within tolerance; a non-1-D time axis; an unknowncoordinate.TypeErrorA bare position array withoutcoordinate="psi_norm".CoordinateUnavailableErrorThe mapping cannot supplycoordinate.
Processing steps · Input semantics · Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Select the channel positions in
coordinate. - Read
T_iandV_torwith their real per-channel sigmas from thedata_error_upperleaves (OMAS strips the uncertainty from the re-read.data). - Drop channels with a non-finite value or position; replace zero or non-finite sigmas by the median valid sigma so no channel’s weight explodes.
- Fit each with its model; clip
T_inon-negative. - With
clamp_to_measured_span, hold each fit at its value on the nearest measured end outside the span the channels cover.
Input semantics
Measured, at diagnostic-native channels; equilibrium-mapped positions in the selected coordinate.
Output semantics
Fitted: continuous functions of the selected coordinate, span-clamped.
Defaults
coordinate = "rho_tor_norm" is the IMAS convention. Ti_order =
Vtor_order = 3 are legacy compatibility values; uncertainty_option = 1
and clamp_to_measured_span = True are validated-workflow defaults –
the clamp was added after shot 48224 at 298 ms, where only 8 of 40 channels
mapped inside the LCFS and the unclamped cubic gave T_i(axis) = 54 eV
against a 21 eV largest measurement. ion_index = 0 selects the first
ion; rho_points = 100 and time_tolerance_ms = 1.0 are numerical
conveniences.
Assumptions
T_i and V_tor are flux functions; the channel’s (R, Z) is where
the measurement is local.
Applicability
Machine-independent.
Limitations
With the clamp off, a polynomial through a poorly covered span runs away
toward the axis. Every channel’s ion[ion_index] must exist.
Provenance
- The fitting kernel [FIT]; the span clamp from the 48224 @ 298 ms failure, mirroring
vaft.code.efit._ti_weighted_fit_psin.
profile_fitting_thomson_scattering
Machine-independentConvention-sensitive
source
profile_fitting_thomson_scattering(ods, time_ms, mapped_positions=None, Te_order=3, Ne_order=3, uncertainty_option=1, rho_points=100, fitting_function_te='polynomial', fitting_function_ne='polynomial', time_tolerance_ms=1.0, enforce_physical=True, *, coordinate='rho_tor_norm', mapped_rho_position=None)
Fit Thomson-scattering T_e and n_e profiles in a chosen radial coordinate.
Extracts the channel values at the nearest Thomson time, drops unusable
channels, and fits T_e(x) and n_e(x) on x in [0, 1] with the
selected model, where x is the radial coordinate chosen from the mapping
– rho_tor_norm by default. With enforce_physical a fit that goes
non-positive or collapses inside the LCFS is retried at lower order.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries |
time_ms | float | ms | Time to fit at; the nearest Thomson sample within |
mapped_positions | MappedPositions or np.ndarray, optional | - | Channel positions from |
Te_order | int, optional | - | Polynomial order for |
Ne_order | int, optional | - | Polynomial order for |
uncertainty_option | int, optional | - |
|
rho_points | int, optional | - | Points of the uniform evaluation grid the sampled returns are on. |
fitting_function_te | str, optional | - |
|
fitting_function_ne | str, optional | - | The same choice for |
time_tolerance_ms | float, optional | ms | Largest distance to the nearest Thomson sample. |
enforce_physical | bool, optional | - | Retry at lower order until the profile is physical inside the LCFS. |
coordinate | str, optional | - | Which coordinate of the mapping to fit in: |
mapped_rho_position | MappedPositions or np.ndarray, optional | - | Deprecated name for |
| Returns | |||
n_e_function | FittedProfile | m^-3 |
|
T_e_function | FittedProfile | eV |
|
coeffs_ne | np.ndarray or None | - | Fit coefficients; |
coeffs_te | np.ndarray or None | - | As |
n_e_rho | np.ndarray | m^-3 |
|
T_e_rho | np.ndarray | eV |
|
Convention
The fit, its (1 - x) edge factor in the polynomial and exponential
bases, and the physicality checks are all in the selected coordinate; a
cubic in psi_norm is not a cubic in rho_tor_norm, and the edge
factor lands at a different physical radius. Before issue #420 every fit
was in psi_norm while the docstring said rho_tor_norm.
Raises
ValueErrorNo Thomson sample within tolerance; an unknowncoordinate.TypeErrorA bare position array withoutcoordinate="psi_norm".CoordinateUnavailableErrorThe mapping cannot supplycoordinate.
Processing steps · Input semantics · Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance
Processing steps
- Select the channel positions in
coordinatefrom the mapping. - Read
T_e,n_eand their uncertainties at the nearest time. - Drop channels with a non-finite value, a non-finite or zero sigma, or an
unmapped (NaN) position; floor the surviving sigmas at
1e-3of the largest value. - Fit
T_e(x)withfitting_function_te; withenforce_physical, reduce the order untilT_e > 0forx < PHYSICAL_EDGE_MAX. - Fit
n_e(x)onn_e / 1e18; withenforce_physical, reduce the order untiln_e > 0and its dynamic range inside the LCFS is belowNE_DYNAMIC_RANGE_MAX. - Wrap both as
FittedProfilecarryingcoordinate, method and the order actually used.
Input semantics
Measured, at diagnostic-native channels; equilibrium-mapped positions in the selected coordinate.
Output semantics
Fitted: a continuous function of the selected coordinate, plus its sampled
form. Not yet on an equilibrium grid – that is core_profiles.
Defaults
coordinate = "rho_tor_norm" is the IMAS convention; a VEST pipeline
takes it from vest.yaml. Te_order = Ne_order = 3 are legacy
compatibility values. uncertainty_option = 1 and
enforce_physical = True are validated-workflow defaults; the guard’s
PHYSICAL_EDGE_MAX = 0.98 and NE_DYNAMIC_RANGE_MAX = 1e3 are empirical
estimates from shot 48224 at 299 ms, where a cubic extrapolated from five
channels inside psi_N <= 0.27 crossed zero at psi_N = 0.87 and
collapsed n_e by 5e6. rho_points = 100 and
time_tolerance_ms = 1.0 are numerical conveniences.
Assumptions
The profile is a smooth function of one radial coordinate: channel
positions inside the LCFS are on flux surfaces and T_e, n_e are
flux functions.
Applicability
Machine-independent. The coordinate convention is the pipeline’s to
supply; for VEST it is resolved from vest.yaml.
Limitations
Thomson often covers only the inner part of the profile; every model
extrapolates over the rest and the guard can only catch the gross failures.
'gp' imports scikit-learn on first use (#426). A slice with fewer
channels than the order plus one cannot be fitted at that order and the
guard steps down; with enforce_physical=False it raises from the
kernel.
Provenance
- The fitting kernel [FIT]; the physicality guard and its constants from the 48224 failures (
PHYSICAL_EDGE_MAX).
project_flux_function
Machine-independentConvention-sensitive
source
project_flux_function(equilibrium, function, *, outside='nan')
Show source vaft/process/_analytic_plasma_state.py, lines 1026–1095
def project_flux_function(equilibrium, function: Callable, *, outside: str = "nan") -> np.ndarray:
r"""Map a flux function ``f(psi_norm)`` onto an equilibrium's ``(R, Z)`` grid.
Parameters
----------
equilibrium : EquilibriumData
Geometry with ``r``, ``z``, ``psi`` indexed ``(R, Z)``, ``psi_axis``,
``psi_boundary`` and, preferably, ``lcfs`` [-].
function : callable
``f(psi_norm)`` accepting an array in ``[0, 1]`` [-].
outside : str, optional
``"nan"`` to leave points outside the plasma as NaN, ``"edge"`` to
fill them with ``f(1)``, the separatrix value [-].
Returns
-------
np.ndarray
``f`` on the grid, shape ``(r.size, z.size)``, in the function's unit [any].
Raises
------
ValueError
No flux map, equal axis and boundary flux, or an unknown *outside*.
Convention
----------
``psi_norm = (psi - psi_axis)/(psi_boundary - psi_axis)``
(:func:`vaft.formula.equilibrium.psi_normalised`), which is independent of
the COCOS sign and of Wb against Wb/rad because both cancel in the ratio;
no conversion is applied or needed. A point is inside when
``psi_norm <= 1`` *and* it lies within the ``lcfs`` outline, which
excludes the private-flux region below an X-point and any exterior region
where the flux turns back below one. Inside points with ``psi_norm < 0``
-- a stored ``psi_axis`` slightly shallower than the grid's own extremum --
are the plasma centre and are evaluated at ``psi_norm = 0``; without an
outline, ``psi_norm >= -0.05`` stands in for containment on that side.
Applicability
-------------
Machine-independent. Any equilibrium record with a gridded flux map: an
analytic Solov'ev or Guazzotto-Freidberg geometry, a GEQDSK, an ODS slice
through :func:`vaft.process.equilibrium.as_equilibrium`.
Limitations
-----------
Without an ``lcfs`` outline only the flux threshold is used, which can
admit exterior points where the flux turns over near coils. A flux
function is constant on flux surfaces by construction; the projection
adds no poloidal variation.
Provenance
----------
.. [1045] VAFT issue #1045: the explicit ``f(psi_N) -> f(R, Z)`` mapping.
"""
if outside not in ("nan", "edge"):
raise ValueError(f"outside must be 'nan' or 'edge', got {outside!r}")
if getattr(equilibrium, "psi", None) is None or equilibrium.r is None or equilibrium.z is None:
raise ValueError("the equilibrium carries no gridded flux map")
psi_axis = float(equilibrium.psi_axis)
psi_boundary = float(equilibrium.psi_boundary)
if not np.isfinite(psi_axis) or not np.isfinite(psi_boundary) or psi_axis == psi_boundary:
raise ValueError("psi_axis and psi_boundary must be finite and distinct")
from vaft.formula.equilibrium import psi_normalised
psi_n = np.asarray(psi_normalised(np.asarray(equilibrium.psi, dtype=float), psi_axis, psi_boundary))
inside = _inside_boundary(equilibrium, psi_n)
values = np.asarray(function(np.clip(np.where(inside, psi_n, 1.0), 0.0, 1.0)), dtype=float)
if outside == "nan":
return np.where(inside, values, np.nan)
return np.where(inside, values, float(np.asarray(function(np.array([1.0])), dtype=float)[0]))Map a flux function f(psi_norm) onto an equilibrium’s (R, Z) grid.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData | - | Geometry with |
function | callable | - |
|
outside | str, optional | - |
|
| Returns | |||
| — | np.ndarray | any |
|
Convention
psi_norm = (psi - psi_axis)/(psi_boundary - psi_axis)
(vaft.formula.equilibrium.psi_normalised), which is independent of
the COCOS sign and of Wb against Wb/rad because both cancel in the ratio;
no conversion is applied or needed. A point is inside when
psi_norm <= 1 and it lies within the lcfs outline, which
excludes the private-flux region below an X-point and any exterior region
where the flux turns back below one. Inside points with psi_norm < 0
– a stored psi_axis slightly shallower than the grid’s own extremum –
are the plasma centre and are evaluated at psi_norm = 0; without an
outline, psi_norm >= -0.05 stands in for containment on that side.
Raises
ValueErrorNo flux map, equal axis and boundary flux, or an unknown outside.
Applicability · Limitations · Provenance
Applicability
Machine-independent. Any equilibrium record with a gridded flux map: an
analytic Solov’ev or Guazzotto-Freidberg geometry, a GEQDSK, an ODS slice
through vaft.process.equilibrium.as_equilibrium.
Limitations
Without an lcfs outline only the flux threshold is used, which can
admit exterior points where the flux turns over near coils. A flux
function is constant on flux surfaces by construction; the projection
adds no poloidal variation.
Provenance
- VAFT issue #1045: the explicit
f(psi_N) -> f(R, Z)mapping.
project_plasma_state
Machine-independentConvention-sensitive
source
project_plasma_state(state, equilibrium, quantity='p_total', *, outside='nan')
Show source vaft/process/_analytic_plasma_state.py, lines 1098–1148
def project_plasma_state(state: AnalyticPlasmaState, equilibrium, quantity: str = "p_total", *,
outside: str = "nan") -> np.ndarray:
r"""Project one quantity of an analytic plasma state onto an equilibrium's ``(R, Z)`` grid.
Parameters
----------
state : AnalyticPlasmaState
From :func:`compose_plasma_state` or a preset [-].
equilibrium : EquilibriumData
The geometry to project onto; it is read, never changed [-].
quantity : str, optional
Any quantity :func:`evaluate_plasma_state` accepts [-].
outside : str, optional
``"nan"`` or ``"edge"``, as in :func:`project_flux_function` [-].
Returns
-------
np.ndarray
The quantity on the grid, shape ``(r.size, z.size)``, in the unit of
:data:`vaft.data.ANALYTIC_STATE_UNITS` [any].
Raises
------
ValueError
As for :func:`project_flux_function` and :func:`evaluate_plasma_state`.
Convention
----------
Evaluated exactly from the state's analytic definition at each point's
``psi_norm``, not interpolated from the state's sampling grid. The
profile keeps its 1-D definition whatever geometry it is projected onto.
Applicability
-------------
Machine-independent.
Limitations
-----------
The projected pressure is *not* the equilibrium's own pressure: the state
was prescribed, and the geometry was solved for different sources. Making
them agree is a new equilibrium solve (CHEASE refinement, #123).
Provenance
----------
.. [1045] VAFT issue #1045: 2-D projection of a prescribed plasma state.
"""
if quantity not in _STATE_QUANTITIES:
raise ValueError(f"quantity must be one of {_STATE_QUANTITIES}, got {quantity!r}")
return project_flux_function(
equilibrium, lambda x: evaluate_plasma_state(state, x, quantity), outside=outside
)Project one quantity of an analytic plasma state onto an equilibrium’s (R, Z) grid.
| Name | Type | Unit | Description |
|---|---|---|---|
state | AnalyticPlasmaState | - | From |
equilibrium | EquilibriumData | - | The geometry to project onto; it is read, never changed. |
quantity | str, optional | - | Any quantity |
outside | str, optional | - |
|
| Returns | |||
| — | np.ndarray | any | The quantity on the grid, shape |
Convention
Evaluated exactly from the state’s analytic definition at each point’s
psi_norm, not interpolated from the state’s sampling grid. The
profile keeps its 1-D definition whatever geometry it is projected onto.
Raises
ValueErrorAs forproject_flux_functionandevaluate_plasma_state.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
The projected pressure is not the equilibrium’s own pressure: the state was prescribed, and the geometry was solved for different sources. Making them agree is a new equilibrium solve (CHEASE refinement, #123).
Provenance
- VAFT issue #1045: 2-D projection of a prescribed plasma state.
spec_from_plasma_state
Machine-independentConvention-sensitive
source
spec_from_plasma_state(state, *, main_ion='H', label=None)
Show source vaft/process/_synthetic_kinetic_profiles.py, lines 928–986
def spec_from_plasma_state(state: AnalyticPlasmaState, *, main_ion: str = "H",
label: str | None = None) -> SyntheticKineticSpec:
r"""The generator spec that reproduces a #1045 analytic plasma state on any equilibrium.
Parameters
----------
state : AnalyticPlasmaState
From a preset (:func:`vaft.process.profile.analytic_hmode_state`, ...)
or :func:`vaft.process.profile.compose_plasma_state` [-].
main_ion : str, optional
Hydrogenic main-ion label, ``"H"``, ``"D"`` or ``"T"``; the state
itself does not name one [-].
label : str, optional
Label of the spec; the state's label when omitted [-].
Returns
-------
SyntheticKineticSpec
``pressure_constraint="kinetic"``, the state's three channels as
unnormalized :class:`~vaft.data.analytic_plasma_state.AnalyticProfile`
shapes, ``T_i`` as an independent profile, the state's composition, and
its ``psi_norm`` grid when that runs from 0 to 1 [-].
Raises
------
SyntheticProfileError
The state's impurity charge matches no species of
:data:`vaft.data.ION_SPECIES`, or the main ion is not hydrogenic.
Convention
----------
The channels stay in ``psi_norm`` exactly as the state defines them, so
the generator evaluates the same analytic functions: a preset is the
Level 1 special case of the generator with no normalization and no
pressure constraint. The impurity is the element whose nuclear charge
equals ``state.impurity_charge`` (carbon for the default 6).
Applicability
-------------
Machine-independent.
Provenance
----------
.. [1045] VAFT issue #1045, whose presets become special cases of the #122
generator's inputs.
"""
if not isinstance(state, AnalyticPlasmaState):
_fail("invalid_profile_model", "state must be an AnalyticPlasmaState")
from vaft.data.synthetic_kinetic_profiles import _species_for_state
impurity = _species_for_state(state)
composition = Composition(main_ion=main_ion, impurity=impurity, z_eff=state.z_eff,
impurity_charge=state.impurity_charge if impurity else None)
grid = state.psi_norm if state.psi_norm[0] == 0.0 and state.psi_norm[-1] == 1.0 else None
return SyntheticKineticSpec(
temperature=TemperatureAssumption(T_i=ProfileSpec(state.profiles["T_i"]), source=f"#1045 preset {state.label!r}"),
composition=composition, n_e=ProfileSpec(state.profiles["n_e"]), T_e=ProfileSpec(state.profiles["T_e"]),
pressure_constraint="kinetic", psi_norm=grid, label=label or state.label,
)The generator spec that reproduces a #1045 analytic plasma state on any equilibrium.
| Name | Type | Unit | Description |
|---|---|---|---|
state | AnalyticPlasmaState | - | From a preset ( |
main_ion | str, optional | - | Hydrogenic main-ion label, |
label | str, optional | - | Label of the spec; the state’s label when omitted. |
| Returns | |||
| — | SyntheticKineticSpec | - |
|
Convention
The channels stay in psi_norm exactly as the state defines them, so
the generator evaluates the same analytic functions: a preset is the
Level 1 special case of the generator with no normalization and no
pressure constraint. The impurity is the element whose nuclear charge
equals state.impurity_charge (carbon for the default 6).
Raises
SyntheticProfileErrorThe state’s impurity charge matches no species ofvaft.data.ION_SPECIES, or the main ion is not hydrogenic.
Applicability · Provenance
Applicability
Machine-independent.
Provenance
- VAFT issue #1045, whose presets become special cases of the #122 generator’s inputs.
strip_electron_only_pressure
Machine-independent
source
strip_electron_only_pressure(ods)
Show source vaft/process/profile.py, lines 2367–2410
def strip_electron_only_pressure(ods):
"""Drop slice-total pressure from every core_profiles slice with no ion temperature.
Each leaf in :data:`TOTAL_PRESSURE_LEAVES` is a sum over species, so none of
them is meaningful on a slice that never measured an ion. A slice carrying
``ion.0.temperature`` is a real kinetic one and keeps its pressure; the rest
are stripped in place.
Assuming a Ti/Te ratio is a legitimate thing to do -- it is what the
``electron-efit`` lineage exists for -- but the assumption has to be declared
by whoever makes it, rather than reaching a product whose consumers read it
as measured.
Parameters
----------
ods : omas.ODS
Mutated in place. An ODS with no ``core_profiles`` is left alone [n/a].
Returns
-------
None
The ODS is edited in place [n/a].
Assumptions
-----------
Presence of ``ion.0.temperature`` marks a slice whose ion temperature was
measured rather than assumed. The builders uphold that by refusing to write
an ion block from a Ti/Te fallback.
Applicability
-------------
Machine-independent. The rule follows from what the IMAS leaves mean, not
from any VEST diagnostic.
"""
if "core_profiles" not in ods:
return
for index in range(len(ods["core_profiles.profiles_1d"])):
base = f"core_profiles.profiles_1d.{index}"
if f"{base}.ion.0.temperature" in ods: # a real kinetic slice keeps its pressure
continue
for leaf in TOTAL_PRESSURE_LEAVES:
key = f"{base}.{leaf}"
if key in ods:
del ods[key]Drop slice-total pressure from every core_profiles slice with no ion temperature.
Each leaf in TOTAL_PRESSURE_LEAVES is a sum over species, so none of
them is meaningful on a slice that never measured an ion. A slice carrying
ion.0.temperature is a real kinetic one and keeps its pressure; the rest
are stripped in place.
Assuming a Ti/Te ratio is a legitimate thing to do – it is what the
electron-efit lineage exists for – but the assumption has to be declared
by whoever makes it, rather than reaching a product whose consumers read it
as measured.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | omas.ODS | n/a | Mutated in place. An ODS with no |
| Returns | |||
| — | None | n/a | The ODS is edited in place. |
Assumptions · Applicability
Assumptions
Presence of ion.0.temperature marks a slice whose ion temperature was
measured rather than assumed. The builders uphold that by refusing to write
an ion block from a Ti/Te fallback.
Applicability
Machine-independent. The rule follows from what the IMAS leaves mean, not from any VEST diagnostic.
write_synthetic_core_profiles
Machine-independentConvention-sensitive
source
write_synthetic_core_profiles(result, ods=None, *, time=None, time_tolerance=1e-06)
Store a successful synthetic kinetic state as one core_profiles.profiles_1d slice.
| Name | Type | Unit | Description |
|---|---|---|---|
result | SyntheticKineticProfiles | - | From |
ods | ODS, optional | - | Mutated in place; a new ODS when omitted. |
time | float, optional | s | Slice time; the result’s time when omitted. |
time_tolerance | float, optional | s | An existing slice within this of time is replaced. |
| Returns | |||
| — | ODS | - | The ODS with the slice written. |
Convention
grid.rho_pol_norm always; grid.rho_tor_norm only when it was derived
from the equilibrium’s q; grid.psi in Wb, COCOS 11, only when the
source convention fixes it – a coordinate that is not known is left out,
never substituted. grid.volume in m^3. Electrons and each ion
carry density, density_thermal, temperature and
pressure_thermal; ion 0 is the main ion, ion 1 the impurity, with
z_ion, element[0].z_n and element[0].a. The slice also carries
zeff, pressure_thermal, pressure_ion_total and
t_i_average. code.parameters is a JSON object keyed by slice time,
which survives an IMAS round trip as a string.
Raises
SyntheticProfileErrorA result whose status is not"success"(statuscarried over), or no time on either the result or the call.ValueErrorods already holds acore_profilesIDS from another producer – any slice,code.nameorcode.parametersthis writer did not write, e.g.vaft.process.profile.core_profiles_from_eqor the measured-fitvaft.process.profile.core_profiles.
Input semantics · Output semantics · Assumptions · Applicability · Limitations · Provenance
Input semantics
Synthetic: a generated, validated kinetic state.
Output semantics
Stored: the same arrays in standard core_profiles paths, labelled
synthetic and assumption-driven in ids_properties.comment and
code.parameters.
Assumptions
One producer per IDS. ids_properties and code belong to the
whole core_profiles IDS, so a synthetic slice beside a measured or
legacy one would carry, or impose, the wrong label. The writer therefore
writes only into an ODS whose core_profiles is empty or was written by
itself (code.name is this generator and code.parameters its JSON);
there it appends a slice, or replaces the slice at the same time whole.
There is deliberately no opt-in to mix producers: store synthetic profiles
in their own ODS. The measured-fit and legacy writers refuse an IDS
written here for the same reason. Every array is checked finite before
anything is written.
Applicability
Machine-independent.
Limitations
No rotation, fast particles or radiation; nothing in equilibrium is
touched.
Provenance
- IMAS Data Dictionary
core_profiles(COCOS 11), the paths written. - VAFT issue #122: synthetic profiles never labelled as measured or transport-predicted.