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).

SymbolMeaningUnit
psi_normnormalized poloidal flux, (psi - psi_axis)/(psi_boundary - psi_axis)-
rho_pol_normsqrt(psi_norm)-
rho_tor_normnormalized toroidal-flux radius, sqrt(Phi/Phi_boundary), Phi = int q dpsi [-]
T_e, T_ielectron, ion temperatureeV
n_eelectron densitym^-3
V_tortoroidal ion velocitym/s
pthermal 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_stateH-mode + ITB kinetic state: smooth core, internal barrier and edge pedestal composed. Convention
analytic_hmode_stateH-mode-like kinetic state: a smooth core on an edge-localized pedestal. Convention
analytic_itb_stateITB-like kinetic state: a smooth profile with an internal transport barrier per channel. Convention
analytic_lmode_stateSmooth L-mode-like kinetic state: generalized parabolic profiles with no barrier. Convention
compare_flux_mappingMap one diagnostic’s channels through several equilibria, to see how much the mapping moves them.
compose_analytic_profileCompose one kinetic profile from a smooth core, an optional edge pedestal and an optional ITB. Convention
compose_plasma_stateAssemble prescribed n_e, T_e and T_i profiles into one kinetic state with derived pressure. Convention
core_profilesEvaluate fitted kinetic profiles on the equilibrium grid and store them as a profiles_1d slice. Convention
core_profiles_from_eqBuild a synthetic core_profiles slice from the equilibrium pressure and an axis T_e. Convention
core_profiles_from_eq_ratioBuild a synthetic core_profiles slice from the equilibrium pressure and a fixed n_e/T_e. Convention
equilibrium_mapping_charge_exchangeMap charge-exchange channel positions into the equilibrium’s radial coordinates. Convention
equilibrium_mapping_pointsMap arbitrary (R, Z) points into the equilibrium’s radial coordinates.
equilibrium_mapping_thomson_scatteringMap Thomson scattering channel positions into the equilibrium’s radial coordinates. Convention
evaluate_analytic_profileEvaluate an analytic profile, or its gradient against normalized flux, anywhere in [0, 1]. Convention
evaluate_plasma_stateEvaluate one quantity of an analytic plasma state at any normalized flux. Convention
export_electron_profile_txtWrite fitted electron profiles, sampled on a uniform grid, to a text file. Convention
fit_ti_te_ratioFit the proportionality coefficient alpha of Ti = alpha * Te.
generate_synthetic_kinetic_profilesGenerate n_e, T_e, T_i and the ion densities from an equilibrium and declared assumptions. Convention
pedestal_topPedestal-top position of a profile, from an EPED-style fit. Convention
profile_fit_report_charge_exchangeFit charge-exchange T_i and V_tor and report how well each fit reproduces its channels.
profile_fit_report_thomson_scatteringFit Thomson T_e and n_e and report how well each fit reproduces its channels.
profile_fitting_charge_exchangeFit charge-exchange T_i and V_tor profiles in a chosen radial coordinate. Convention
profile_fitting_thomson_scatteringFit Thomson-scattering T_e and n_e profiles in a chosen radial coordinate. Convention
project_flux_functionMap a flux function f(psi_norm) onto an equilibrium’s (R, Z) grid. Convention
project_plasma_stateProject one quantity of an analytic plasma state onto an equilibrium’s (R, Z) grid. Convention
spec_from_plasma_stateThe generator spec that reproduces a #1045 analytic plasma state on any equilibrium. Convention
strip_electron_only_pressureDrop slice-total pressure from every core_profiles slice with no ion temperature.
write_synthetic_core_profilesStore a successful synthetic kinetic state as one core_profiles.profiles_1d slice. Convention

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.

NameTypeUnitDescription
ne_axisfloat, optionalm^-3

Electron density on axis.

ne_pedfloat, optionalm^-3

Electron density at the pedestal knee.

ne_sepfloat, optionalm^-3

Electron density at the separatrix.

te_axisfloat, optionaleV

Electron temperature on axis.

te_pedfloat, optionaleV

Electron temperature at the pedestal knee.

te_sepfloat, optionaleV

Electron temperature at the separatrix.

ti_axisfloat, optionaleV

Ion temperature on axis.

ti_pedfloat, optionaleV

Ion temperature at the pedestal knee.

ti_sepfloat, optionaleV

Ion temperature at the separatrix.

ne_itb_heightfloat, optionalm^-3

Density amplitude of the ITB step, axis side to separatrix side.

te_itb_heightfloat, optionaleV

Electron temperature amplitude of the ITB step, axis side to separatrix side.

ti_itb_heightfloat, optionaleV

Ion temperature amplitude of the ITB step, axis side to separatrix side.

pedestal_positionfloat or mapping, optional-

Pedestal centre in psi_norm, shared or per channel.

pedestal_widthfloat or mapping, optional-

Full pedestal width in psi_norm, shared or per channel.

itb_positionfloat or mapping, optional-

ITB centre in psi_norm, shared or per channel.

itb_widthfloat or mapping, optional-

Full ITB width in psi_norm, shared or per channel.

core_alphafloat or mapping, optional-

Core radial exponent.

core_betafloat or mapping, optional-

Core peaking exponent.

z_efffloat, optional-

Uniform effective charge.

impurity_chargefloat, optional-

Charge of the single impurity.

psi_normarray_like, optional-

Sampling grid in [0, 1].

Returns
—AnalyticPlasmaState-

Labelled "H-mode + ITB"; axis, pedestal-knee and separatrix values hold exactly.

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

  • ValueError As for compose_analytic_profile and compose_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

  1. 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.

NameTypeUnitDescription
ne_axisfloat, optionalm^-3

Electron density on axis.

ne_pedfloat, optionalm^-3

Electron density at the pedestal knee.

ne_sepfloat, optionalm^-3

Electron density at the separatrix.

te_axisfloat, optionaleV

Electron temperature on axis.

te_pedfloat, optionaleV

Electron temperature at the pedestal knee.

te_sepfloat, optionaleV

Electron temperature at the separatrix.

ti_axisfloat, optionaleV

Ion temperature on axis.

ti_pedfloat, optionaleV

Ion temperature at the pedestal knee.

ti_sepfloat, optionaleV

Ion temperature at the separatrix.

pedestal_positionfloat or mapping, optional-

Centre of the pedestal layer in psi_norm, shared or keyed by n_e/T_e/T_i.

pedestal_widthfloat or mapping, optional-

Full pedestal width in psi_norm, shared or keyed by channel.

core_alphafloat or mapping, optional-

Core radial exponent.

core_betafloat or mapping, optional-

Core peaking exponent.

z_efffloat, optional-

Uniform effective charge.

impurity_chargefloat, optional-

Charge of the single impurity.

psi_normarray_like, optional-

Sampling grid in [0, 1].

Returns
—AnalyticPlasmaState-

Labelled "H-mode"; axis, knee and separatrix values hold exactly.

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

  • ValueError As for compose_analytic_profile and compose_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

  1. VAFT issue #1045, canonical confinement-regime presets.
  2. 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.

NameTypeUnitDescription
ne_axisfloat, optionalm^-3

Electron density on axis.

ne_sepfloat, optionalm^-3

Electron density at the separatrix.

te_axisfloat, optionaleV

Electron temperature on axis.

te_sepfloat, optionaleV

Electron temperature at the separatrix.

ti_axisfloat, optionaleV

Ion temperature on axis.

ti_sepfloat, optionaleV

Ion temperature at the separatrix.

ne_itb_heightfloat, optionalm^-3

Density amplitude of the ITB step, axis side to separatrix side; zero switches the ITB off in n_e.

te_itb_heightfloat, optionaleV

Electron temperature amplitude of the ITB step, axis side to separatrix side; zero for none.

ti_itb_heightfloat, optionaleV

Ion temperature amplitude of the ITB step, axis side to separatrix side; zero for none.

itb_positionfloat or mapping, optional-

ITB centre in psi_norm, shared or keyed by n_e/T_e/T_i, so each channel can have its own.

itb_widthfloat or mapping, optional-

Full ITB width in psi_norm, shared or keyed by channel.

core_alphafloat or mapping, optional-

Core radial exponent.

core_betafloat or mapping, optional-

Core peaking exponent.

z_efffloat, optional-

Uniform effective charge.

impurity_chargefloat, optional-

Charge of the single impurity.

psi_normarray_like, optional-

Sampling grid in [0, 1].

Returns
—AnalyticPlasmaState-

Labelled "ITB"; axis and separatrix values hold exactly.

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

  • ValueError As for compose_analytic_profile and compose_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

  1. VAFT issue #1045: independent ITB behaviour per channel.
  2. 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.

NameTypeUnitDescription
ne_axisfloat, optionalm^-3

Electron density on axis.

ne_sepfloat, optionalm^-3

Electron density at the separatrix.

te_axisfloat, optionaleV

Electron temperature on axis.

te_sepfloat, optionaleV

Electron temperature at the separatrix.

ti_axisfloat, optionaleV

Ion temperature on axis.

ti_sepfloat, optionaleV

Ion temperature at the separatrix.

core_alphafloat or mapping, optional-

Core radial exponent, shared or keyed by n_e/T_e/T_i.

core_betafloat or mapping, optional-

Core peaking exponent, shared or keyed by channel.

z_efffloat, optional-

Uniform effective charge.

impurity_chargefloat, optional-

Charge of the single impurity.

psi_normarray_like, optional-

Sampling grid in [0, 1].

Returns
—AnalyticPlasmaState-

Labelled "L-mode"; see compose_plasma_state.

Convention

Every position and profile is in normalized poloidal flux psi_norm.

Raises

  • ValueError As for compose_analytic_profile and compose_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

  1. VAFT issue #1045, canonical confinement-regime presets.
  2. 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 out

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.

NameTypeUnitDescription
odsODS-

Carries the diagnostic’s channel positions.

equilibriamapping of str to GEQDSK, ODS or mapping-

The equilibria to compare, each anything equilibrium_mapping_thomson_scattering accepts; a path to a GEQDSK file is read with vaft.data.eqdsk.read_geqdsk when that reader is available.

diagnosticstr, optional-

"thomson_scattering" or "charge_exchange".

timefloat, optionals

Map each ODS equilibrium through its slice nearest this time (as the mappers’ time); None keeps each one’s first slice.

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 · 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

  1. The mappers equilibrium_mapping_thomson_scattering and equilibrium_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.

NameTypeUnitDescription
quantitystr-

Name of the profile, e.g. "n_e", "T_e" or "T_i".

axis_valuefloatany

Value on the magnetic axis, psi_norm = 0; holds exactly.

separatrix_valuefloatany

Value at psi_norm = 1; holds exactly.

core_alphafloat, optional-

Radial exponent of the core shape, at least one.

core_betafloat, optional-

Peaking exponent of the core shape, at least one.

pedestal_top_valuefloat, optionalany

Value at the pedestal knee, pedestal_position - pedestal_width/2; holds exactly. None for no edge pedestal.

pedestal_positionfloat, optional-

Centre of the pedestal’s steep-gradient layer in psi_norm; required with pedestal_top_value.

pedestal_widthfloat, optional-

Full width of the pedestal layer in psi_norm, positive.

itb_heightfloat, optionalany

Whole amplitude of the internal-barrier step, from its separatrix side to its axis side (the knee-to-foot change is about tanh(1) = 0.76 of it); zero for no ITB.

itb_positionfloat, optional-

Centre of the ITB layer in psi_norm, strictly inside (0, 1); required when itb_height is non-zero.

itb_widthfloat, optional-

Full width of the ITB layer in psi_norm, positive.

unitstr, optional-

Unit label recorded on the profile; m^-3 for n_* and eV for T_* when omitted.

positivebool, optional-

Refuse a profile that is not strictly positive on [0, 1].

Returns
—AnalyticProfile-

The requested values, the barrier steps and the solved core amplitude and pedestal height; evaluate it with evaluate_analytic_profile.

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

  • ValueError A 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

  1. vaft.formula.equilibrium.generalized_parabolic_profile and vaft.formula.equilibrium.modified_tanh_profile (#552), the core shape and the step reused unchanged.
  2. R. J. Groebner and T. N. Carlstrom, Plasma Phys. Control. Fusion 40, 673 (1998), for the tanh step and its full-width convention.
  3. 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.

NameTypeUnitDescription
n_eAnalyticProfilem^-3

Electron density profile.

T_eAnalyticProfileeV

Electron temperature profile.

T_iAnalyticProfileeV

Ion temperature profile, shared by the main ion and the impurity.

z_efffloat, optional-

Effective charge, uniform in radius, in [1, impurity_charge].

impurity_chargefloat, optional-

Charge of the single fully stripped impurity, greater than one.

psi_normarray_like, optional-

Grid to sample on, inside [0, 1]; 201 uniform points when omitted.

labelstr, optional-

Name recorded on the state, e.g. "H-mode".

Returns
—AnalyticPlasmaState-

The three channels, the ion and impurity densities, the electron, ion and total pressures and their analytic gradients against psi_norm, sampled on psi_norm, with the channel definitions for exact evaluation anywhere.

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

  • ValueError A 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

  1. J. Wesson, Tokamaks, 4th ed. (2011), Ch. 2, for quasi-neutrality and the effective charge.
  2. 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.

NameTypeUnitDescription
odsODS-

Mutated in place: gains or replaces the core_profiles.profiles_1d slice at time_ms.

time_msfloatms

Time of the slice.

mapped_positionsMappedPositions or np.ndarray, optional-

Thomson channel positions from equilibrium_mapping_thomson_scattering; required with an electron fit. A bare array is the deprecated pre-#420 form and is accepted only with coordinate="psi_norm".

n_e_functionFittedProfile or callable, optionalm^-3

Electron density fit.

T_e_functionFittedProfile or callable, optionaleV

Electron temperature fit.

tol_msfloat, optionalms

An existing slice within this of time_ms is replaced.

T_i_functionFittedProfile or callable, optionaleV

Ion temperature fit from the charge-exchange fitter; when given, the ion block carries the real T_i and pressure_thermal is written.

V_tor_functionFittedProfile or callable, optionalm/s

Toroidal ion velocity fit.

ti_mapped_positionsMappedPositions or np.ndarray, optional-

Charge-exchange channel positions, for the ion fit metadata.

rho_pointsint, optional-

Size of the uniform fallback grid when no equilibrium slice matches.

time_tolerance_msfloat, optionalms

Tolerance for matching the Thomson and equilibrium times.

geqGEQDSK, 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_fallbackbool, optional-

With no ion fit, still write an ion temperature from T_e.

ti_te_ratiofloat, optional-

Coefficient for that fallback: T_i = ratio * T_e and pressure_thermal = e n_e (1 + ratio) T_e; None keeps the legacy T_i = T_e and writes no pressure. Resolved by the pipeline from the machine policy; this function holds no value.

coordinatestr, optional-

Required when the fits are plain callables; must agree with every FittedProfile given.

ti_te_ratio_recordstr, optional-

Provenance text for the ratio (value, status, source), stored beside the ion temperature; the pipeline passes the policy’s own record.

mapped_rho_positionMappedPositions or np.ndarray, optional-

Deprecated name for mapped_positions.

ti_mapped_rho_positionMappedPositions 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

  • ValueError No 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.
  • TypeError A plain callable without coordinate, or a bare position array without coordinate="psi_norm".
  • CoordinateUnavailableError The mapping cannot supply the fit’s coordinate.
Processing steps · Input semantics · Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance

Processing steps

  1. Establish the fit coordinate from the fit objects (or coordinate) and check they agree.
  2. Read the measured Thomson values at the nearest time.
  3. 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.
  4. Evaluate every fit on that grid; apply the ion fallback if needed.
  5. 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

  1. Per-slice fit records in electrons.{density,temperature}_fit.parameters and ion.0.temperature_fit.parameters, and one line per slice in core_profiles.code.parameters; issue #420. A slice whose grid.psi comes from the equilibrium carries grid.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.

NameTypeUnitDescription
odsODS-

Carries the equilibrium slice; gains the core_profiles slice.

Te0_eVfloateV

Electron temperature on axis.

rho_fitarray_like, optional-

rho_tor_norm grid to write on; None for 100 uniform points.

tol_msfloat, optionalms

An existing slice within this of the equilibrium time is replaced.

eq_time_indexint, 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

  • ValueError Non-1-D or non-finite equilibrium profiles, or non-positive axis pressure.
  • CoordinateUnavailableError The slice stores the sqrt(psi_N) proxy as rho_tor_norm and the real coordinate cannot be re-derived from q.
Processing steps · Input semantics · Output semantics · Assumptions · Applicability · Limitations

Processing steps

  1. Interpolate the equilibrium pressure(rho_tor_norm) onto rho_fit.
  2. g = sqrt(p / p(0)); T_e = Te0 g; n_e = p(0) / (2 e Te0) g.
  3. 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.

NameTypeUnitDescription
odsODS-

Carries the equilibrium slice; gains the core_profiles slice.

C_ne_over_Tefloatm^-3/eV

Density-to-temperature ratio held constant across the profile.

rho_fitarray_like, optional-

rho_tor_norm grid to write on; None for 100 uniform points.

tol_msfloat, optionalms

An existing slice within this of the equilibrium time is replaced.

eq_time_indexint, 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

  • ValueError Non-positive axis pressure.
  • CoordinateUnavailableError The slice stores the sqrt(psi_N) proxy as rho_tor_norm and the real coordinate cannot be re-derived from q.
Processing steps · Input semantics · Output semantics · Assumptions · Applicability · Limitations

Processing steps

  1. Interpolate the equilibrium pressure(rho_tor_norm) onto rho_fit.
  2. f = p / p(0); T_e = sqrt(f), n_e = C sqrt(f), then scale both by sqrt(p(0) / (2 C e)) so that p = 2 n_e T_e e.
  3. 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).

NameTypeUnitDescription
odsODS-

Carries the channel positions, as .data leaves (what the VEST mapper writes) or as bare values.

geqGEQDSK, ODS or mapping-

A vaft.data.GEQDSK, an OMAS equilibrium ODS, or a legacy fluxSurfaces mapping.

timefloat, optionals

As equilibrium_mapping_thomson_scattering: the ODS slice nearest this time; None keeps the first.

Returns
—MappedPositions-

psi_norm, rho_pol_norm and, when derivable, rho_tor_norm per channel; NaN outside the LCFS.

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

  1. Read each channel’s (R, Z), taking the nominal value of an uncertainty-carrying leaf and the first sample of a time series.
  2. 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.

NameTypeUnitDescription
geqGEQDSK, ODS or mapping-

As equilibrium_mapping_thomson_scattering accepts.

rarray_likem

Major radius of each point.

zarray_likem

Height of each point.

timefloat, optionals

As equilibrium_mapping_thomson_scattering: the ODS slice nearest this time; None keeps the first.

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 · Limitations · Provenance

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 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.

NameTypeUnitDescription
odsODS-

Carries thomson_scattering.channel[:].position.r and .z.

geqGEQDSK, ODS or mapping-

A vaft.data.GEQDSK, an OMAS equilibrium ODS, or a legacy fluxSurfaces mapping.

timefloat, optionals

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.

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

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

  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.

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 value

Evaluate an analytic profile, or its gradient against normalized flux, anywhere in [0, 1].

NameTypeUnitDescription
profileAnalyticProfile-

From compose_analytic_profile or a state’s profiles.

psi_normfloat or array_like-

Normalized poloidal flux in [0, 1].

derivativebool, optional-

Return $df/d\psi_N$ instead of $f$.

Returns
—float or np.ndarrayany

The profile, or its analytic derivative, in the profile’s unit (per unit psi_norm for the derivative), with the shape of psi_norm.

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

  • ValueError psi_norm is not finite or lies outside [0, 1].
Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. vaft.formula.equilibrium.generalized_parabolic_profile_derivative and vaft.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 out

Evaluate one quantity of an analytic plasma state at any normalized flux.

NameTypeUnitDescription
stateAnalyticPlasmaState-

From compose_plasma_state or a preset.

psi_normfloat or array_like-

Normalized poloidal flux in [0, 1].

quantitystr, 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.ndarrayany

The quantity in the unit of vaft.data.ANALYTIC_STATE_UNITS (m^-3, eV, Pa, or Pa per unit psi_norm).

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

  • ValueError An unknown quantity, or psi_norm outside [0, 1].
Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. 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.

NameTypeUnitDescription
n_e_functionFittedProfile or callablem^-3

n_e(x).

T_e_functionFittedProfile or callableeV

T_e(x).

n_e_coeffnp.ndarray or None-

Fit coefficients; not written, kept for the legacy signature.

T_e_coeffnp.ndarray or None-

As n_e_coeff.

rho_pointsint, optional-

Points of the uniform grid on [0, 1].

filenamestr, 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.

NameTypeUnitDescription
tearray_likeeV

Electron temperature samples.

tiarray_likeeV

Ion temperature samples, paired with te.

te_stdarray_like, optionaleV

1-sigma uncertainties of te; None for zero.

ti_stdarray_like, optionaleV

1-sigma uncertainties of ti; None for unit weights, a plain least-squares fit.

max_iterint, optional-

Iterations of the weight update.

tolfloat, optional-

Change in alpha below which the iteration stops.

Returns
—dict-

alpha the fitted ratio; alpha_se its formal standard error, scaled by sqrt(chi2_red) when chi2_red > 1; alpha_scatter the error-weighted scatter of the per-point ratios, the predictive per-point sigma; chi2_red; n_points the pairs used.

Raises

  • ValueError Mismatched lengths, or fewer than two valid pairs.
Processing steps · Defaults · Assumptions · Applicability · Limitations · Provenance

Processing steps

  1. Drop pairs with a non-finite value, a non-finite or negative sigma, or Te <= 0.
  2. Start from the unweighted through-origin estimate.
  3. Iterate w = 1 / (sTi^2 + a^2 sTe^2), a = sum(w Te Ti)/sum(w Te^2) to convergence.
  4. 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

  1. 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.

NameTypeUnitDescription
equilibriumGEQDSK, ODS, IMAS IDS, EquilibriumData or path-

The magnetic equilibrium, adapted through vaft.process.equilibrium.as_equilibrium; read, never changed.

specSyntheticKineticSpec-

Shapes, normalizations, temperature route, composition and pressure constraint; see vaft.data.SyntheticKineticSpec.

timefloat, optionals

Time recorded on the result; the equilibrium’s own time when omitted.

time_indexint, optional-

Time slice of a multi-slice source.

pressure_tolerancefloat, optional-

Largest relative local pressure residual a locally closed state may carry.

Returns
—SyntheticKineticProfiles-

The profiles on the equilibrium’s psi_norm grid with rho_pol_norm, rho_tor_norm, psi [Wb] and the enclosed volume; the species; the pressure-closure report; every requested target beside its recomputed value; validation, resolved parameters, provenance and a status.

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

  • SyntheticProfileError A refused input, with status invalid_equilibrium, invalid_profile_model, invalid_gradient_model, invalid_normalization, invalid_composition or coordinate_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

  1. Adapt the equilibrium and build the grid (101 points uniform in rho_pol_norm unless the spec gives psi_norm); map p_eq, rho_tor_norm (from q) and psi (Wb, COCOS 11) onto it; trace the flux-surface volume; lay the axis chord.
  2. 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.
  3. 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 where p_eq < edge_floor * max(p_eq), and carries its solved channel to edge_value across it (see vaft.data.SyntheticKineticSpec).
  4. Build the ion densities from quasi-neutrality and Z_eff, the pressures from p = e n T.
  5. 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

  1. VAFT issue #122: the fidelity ladder, the closure modes and the residuals reported.
  2. vaft.process.profile.compose_analytic_profile and vaft.process.profile.evaluate_analytic_profile, the shape kernels reused unchanged.
  3. J. Wesson, Tokamaks, 4th ed. (2011), Ch. 2, quasi-neutrality and the effective charge (via vaft.formula.atomic.impurity_fraction_from_effective_charge).
  4. 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.

NameTypeUnitDescription
xarray_like-

Radial coordinate of the profile, in coordinate.

valuesarray_likeany

Profile samples; any quantity with a pedestal.

quantitystrn/a

What values is, recorded on the result. Required: EPED defines the pedestal from total pressure, and a fit to a density or a temperature puts the top somewhere else, so the caller must say which one this boundary came from.

value_stdarray_like, optionalany

Per-sample uncertainty, passed to the fit as weights.

coordinatestr, optionaln/a

Which radial coordinate x is, one of COORDINATES.

fallbackfloat, optional-

Position returned when the fit is not usable.

windowtuple of float, optional-

(low, high) slice of x the fit sees; the core is excluded because the model’s core term is only a shape, not a physical description.

min_pointsint, optional-

Fewest samples inside window that can support seven parameters.

max_widthfloat, optional-

Widest tanh still counted as a pedestal, in coordinate.

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

  • ValueError x, values or value_std differ in length, or coordinate is not one of COORDINATES.
  • CoordinateUnavailableError The fit was not usable and coordinate is not psi_norm, so the default fallback – a psi_norm position – would be wrong.
Processing steps · Defaults · Applicability · Limitations · Provenance

Processing steps

  1. Restrict to window and drop non-finite samples.
  2. Fit eped_tanh there, weighted by value_std when given.
  3. Accept x_ped unless the fit is unusable – too few points, a fit that did not converge, x_ped resting on a bound of the model’s box, or a fitted curve that does not vary across the window by PEDESTAL_RESOLUTION_FACTOR times the residual scatter, which means no pedestal was resolved.
  4. Otherwise return fallback and 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

  1. 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.
  2. The seven-parameter model and its parameter box are ported from the legacy implementation’s pedestal-fitting study (transp_example/pedestal_fitting.ipynb). The older kinetic_analysis.ped_fitting modified 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.

NameTypeUnitDescription
odsODS-

Carries charge_exchange.time and per-channel ion t_i and velocity_tor with data_error_upper.

time_msfloatms

Time to fit at.

mapped_positionsMappedPositions-

Channel positions from equilibrium_mapping_charge_exchange.

Ti_orderint, optional-

Polynomial order for T_i.

Vtor_orderint, optional-

Polynomial order for V_tor.

uncertainty_optionint, optional-

1 weights the fit by the per-channel uncertainties.

rho_pointsint, optional-

Points of the grid the report’s curve is sampled on.

fitting_function_tistr, optional-

Model for T_i.

fitting_function_vtorstr, optional-

Model for V_tor.

ion_indexint, optional-

Which ion of each channel.

time_tolerance_msfloat, optionalms

Largest distance to the nearest charge-exchange sample.

clamp_to_measured_spanbool, optional-

Hold the fit at its end values outside the measured span.

coordinatestr, optional-

Which coordinate of the mapping to fit in.

Returns
—dict of str to FitReport-

{"t_i": ..., "velocity_tor": ...}, values in eV and m/s.

Raises

  • ValueError No charge-exchange sample within tolerance; an unknown coordinate.
  • CoordinateUnavailableError The mapping cannot supply coordinate.
Processing steps · Assumptions · Applicability · Limitations · Provenance

Processing steps

  1. Fit exactly as profile_fitting_charge_exchange does; each quantity keeps its own channel set.
  2. 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.
  3. Residuals, chi-square and nu = N - k as in FitReport, 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

  1. 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.

NameTypeUnitDescription
odsODS-

Carries thomson_scattering.time and per-channel t_e / n_e data with data_error_upper.

time_msfloatms

Time to fit at; the nearest Thomson sample within time_tolerance_ms

mapped_positionsMappedPositions-

Channel positions from equilibrium_mapping_thomson_scattering.

Te_orderint, optional-

Starting order for T_e.

Ne_orderint, optional-

Starting order for n_e.

uncertainty_optionint, optional-

1 weights the fit by the per-channel uncertainties.

rho_pointsint, optional-

Points of the uniform grid the report’s curve is sampled on.

fitting_function_testr, optional-

Model for T_e, as profile_fitting_thomson_scattering.

fitting_function_nestr, optional-

Model for n_e.

time_tolerance_msfloat, optionalms

Largest distance to the nearest Thomson sample.

enforce_physicalbool, optional-

Reduce the order until the profile is physical inside the LCFS.

coordinatestr, optional-

rho_tor_norm, rho_pol_norm or psi_norm.

Returns
—dict of str to FitReport-

{"t_e": ..., "n_e": ...}; residuals are dimensionless, values in eV and m^-3.

Raises

  • ValueError No Thomson sample within tolerance; an unknown coordinate.
  • CoordinateUnavailableError The mapping cannot supply coordinate.
Processing steps · Assumptions · Applicability · Limitations · Provenance

Processing steps

  1. Fit exactly as profile_fitting_thomson_scattering does.
  2. 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.
  3. r_i = (y_i - f(x_i)) / sigma_i at every used channel, with the sigma the fit was weighted with (after its floors); chi2 = sum r_i^2; nu = N - k (see FitReport for k).

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

  1. 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.

NameTypeUnitDescription
odsODS-

Carries charge_exchange.time and per-channel ion t_i and velocity_tor data with data_error_upper.

time_msfloatms

Time to fit at.

mapped_positionsMappedPositions or np.ndarray, optional-

Channel positions from equilibrium_mapping_charge_exchange; a bare array only with coordinate="psi_norm".

Ti_orderint, optional-

Polynomial order for T_i.

Vtor_orderint, optional-

Polynomial order for V_tor.

uncertainty_optionint, optional-

1 weights the fit by the per-channel uncertainties.

rho_pointsint, optional-

Points of the uniform evaluation grid the sampled returns are on.

fitting_function_tistr, optional-

Model for T_i, as the Thomson fitter’s choices.

fitting_function_vtorstr, optional-

Model for V_tor.

ion_indexint, optional-

Which ion of each channel.

time_tolerance_msfloat, optionalms

Largest distance to the nearest charge-exchange sample.

clamp_to_measured_spanbool, optional-

Hold the fit at its end values outside the measured span.

coordinatestr, optional-

Which coordinate of the mapping to fit in.

mapped_rho_positionMappedPositions or np.ndarray, optional-

Deprecated name for mapped_positions.

Returns
Vtor_functionFittedProfilem/s

V_tor(x).

Ti_functionFittedProfileeV

T_i(x), clipped non-negative.

coeffs_vtornp.ndarray or None-

Fit coefficients, None for methods without them.

coeffs_tinp.ndarray or None-

As coeffs_vtor.

Vtor_rhonp.ndarraym/s

V_tor sampled on rho_points uniform points of x.

Ti_rhonp.ndarrayeV

T_i sampled on the same grid.

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

  • ValueError No charge-exchange sample within tolerance; a non-1-D time axis; an unknown coordinate.
  • TypeError A bare position array without coordinate="psi_norm".
  • CoordinateUnavailableError The mapping cannot supply coordinate.
Processing steps · Input semantics · Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance

Processing steps

  1. Select the channel positions in coordinate.
  2. Read T_i and V_tor with their real per-channel sigmas from the data_error_upper leaves (OMAS strips the uncertainty from the re-read .data).
  3. 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.
  4. Fit each with its model; clip T_i non-negative.
  5. 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

  1. 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.

NameTypeUnitDescription
odsODS-

Carries thomson_scattering.time and per-channel t_e / n_e data with data_error_upper.

time_msfloatms

Time to fit at; the nearest Thomson sample within time_tolerance_ms

mapped_positionsMappedPositions or np.ndarray, optional-

Channel positions from equilibrium_mapping_thomson_scattering. A bare array is the deprecated pre-#420 form, accepted only with coordinate="psi_norm".

Te_orderint, optional-

Polynomial order for T_e.

Ne_orderint, optional-

Polynomial order for n_e.

uncertainty_optionint, optional-

1 weights the fit by the per-channel uncertainties.

rho_pointsint, optional-

Points of the uniform evaluation grid the sampled returns are on.

fitting_function_testr, optional-

'polynomial', 'exponential', 'core_poly_edge_exp', 'linear' or 'gp' for T_e.

fitting_function_nestr, optional-

The same choice for n_e.

time_tolerance_msfloat, optionalms

Largest distance to the nearest Thomson sample.

enforce_physicalbool, optional-

Retry at lower order until the profile is physical inside the LCFS.

coordinatestr, optional-

Which coordinate of the mapping to fit in: rho_tor_norm, rho_pol_norm or psi_norm.

mapped_rho_positionMappedPositions or np.ndarray, optional-

Deprecated name for mapped_positions.

Returns
n_e_functionFittedProfilem^-3

n_e(x), clipped non-negative, with its coordinate and method.

T_e_functionFittedProfileeV

T_e(x), clipped non-negative.

coeffs_nenp.ndarray or None-

Fit coefficients; None for the Gaussian-process and linear methods.

coeffs_tenp.ndarray or None-

As coeffs_ne.

n_e_rhonp.ndarraym^-3

n_e sampled on rho_points uniform points of x.

T_e_rhonp.ndarrayeV

T_e sampled on the same grid.

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

  • ValueError No Thomson sample within tolerance; an unknown coordinate.
  • TypeError A bare position array without coordinate="psi_norm".
  • CoordinateUnavailableError The mapping cannot supply coordinate.
Processing steps · Input semantics · Output semantics · Defaults · Assumptions · Applicability · Limitations · Provenance

Processing steps

  1. Select the channel positions in coordinate from the mapping.
  2. Read T_e, n_e and their uncertainties at the nearest time.
  3. Drop channels with a non-finite value, a non-finite or zero sigma, or an unmapped (NaN) position; floor the surviving sigmas at 1e-3 of the largest value.
  4. Fit T_e(x) with fitting_function_te; with enforce_physical, reduce the order until T_e > 0 for x < PHYSICAL_EDGE_MAX.
  5. Fit n_e(x) on n_e / 1e18; with enforce_physical, reduce the order until n_e > 0 and its dynamic range inside the LCFS is below NE_DYNAMIC_RANGE_MAX.
  6. Wrap both as FittedProfile carrying coordinate, 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

  1. 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.

NameTypeUnitDescription
equilibriumEquilibriumData-

Geometry with r, z, psi indexed (R, Z), psi_axis, psi_boundary and, preferably, lcfs.

functioncallable-

f(psi_norm) accepting an array in [0, 1].

outsidestr, optional-

"nan" to leave points outside the plasma as NaN, "edge" to fill them with f(1), the separatrix value.

Returns
—np.ndarrayany

f on the grid, shape (r.size, z.size), in the function’s unit.

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

  • ValueError No 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

  1. 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.

NameTypeUnitDescription
stateAnalyticPlasmaState-

From compose_plasma_state or a preset.

equilibriumEquilibriumData-

The geometry to project onto; it is read, never changed.

quantitystr, optional-

Any quantity evaluate_plasma_state accepts.

outsidestr, optional-

"nan" or "edge", as in project_flux_function.

Returns
—np.ndarrayany

The quantity on the grid, shape (r.size, z.size), in the unit of vaft.data.ANALYTIC_STATE_UNITS.

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

  • ValueError As for project_flux_function and evaluate_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

  1. 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.

NameTypeUnitDescription
stateAnalyticPlasmaState-

From a preset (vaft.process.profile.analytic_hmode_state, …) or vaft.process.profile.compose_plasma_state.

main_ionstr, optional-

Hydrogenic main-ion label, "H", "D" or "T"; the state itself does not name one.

labelstr, optional-

Label of the spec; the state’s label when omitted.

Returns
—SyntheticKineticSpec-

pressure_constraint="kinetic", the state’s three channels as unnormalized 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.

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

  • SyntheticProfileError The state’s impurity charge matches no species of vaft.data.ION_SPECIES, or the main ion is not hydrogenic.
Applicability · Provenance

Applicability

Machine-independent.

Provenance

  1. 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.

NameTypeUnitDescription
odsomas.ODSn/a

Mutated in place. An ODS with no core_profiles is left alone.

Returns
—Nonen/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.

NameTypeUnitDescription
resultSyntheticKineticProfiles-

From generate_synthetic_kinetic_profiles; must have status "success".

odsODS, optional-

Mutated in place; a new ODS when omitted.

timefloat, optionals

Slice time; the result’s time when omitted.

time_tolerancefloat, optionals

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

  • SyntheticProfileError A result whose status is not "success" (status carried over), or no time on either the result or the call.
  • ValueError ods already holds a core_profiles IDS from another producer – any slice, code.name or code.parameters this writer did not write, e.g. vaft.process.profile.core_profiles_from_eq or the measured-fit vaft.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

  1. IMAS Data Dictionary core_profiles (COCOS 11), the paths written.
  2. VAFT issue #122: synthetic profiles never labelled as measured or transport-predicted.

results matching ""

    No results matching ""