Skip to content

array.plasma.analysis

Numerical diagnostics of one labeled xarray.DataArray, as array.plasma.analysis.<method>(...). They return labeled arrays and Datasets, so their results can be plotted with .plasma.plot in turn.

Quantitative diagnostics of one array, as array.plasma.analysis.<quantity>(...).

growth_ratemethod#

def growth_rate(window: tuple[float | None, float | None] = (None, None), amplitude: bool = False)

Fit exp(rate * t + intercept) to this time series within window.

Parameters

NameTypeDefaultDescription
window(float or None, float or None)(None, None)The time interval (t0, t1) of the fitted samples; None for an open end. Default: every sample.
amplitudeboolFalseThe series is quadratic in an amplitude (e.g. an energy): return the amplitude’s rate. Default: False.

Returns

FitResult or None
.rate, .intercept, .time and .fitted; None with fewer than two valid samples.

Examples

>>> energy.plasma.analysis.growth_rate(window=(0.0, 5.0), amplitude=True).rate

damping_ratemethod#

def damping_rate(window: tuple[float | None, float | None] = (None, None), amplitude: bool = False)

Fit exponential decay to the envelope of this oscillating time series.

Parameters

NameTypeDefaultDescription
window(float or None, float or None)(None, None)The time interval (t0, t1) of the peaks that are used; None for an open end. Default: every sample.
amplitudeboolFalseThe series is quadratic in an amplitude (e.g. an energy): return the amplitude’s rate. Default: False.

Returns

FitResult or None
The fit to the peaks; the rate is negative for damping. None with fewer than two valid peaks.

Examples

>>> energy.plasma.analysis.damping_rate(amplitude=True).rate

oscillation_frequencymethod#

def oscillation_frequency(window: tuple[float | None, float | None] = (None, None), method: str = 'zero_crossings', detrend: bool = True)

Measure the frequency of this oscillating time series from its zero crossings or peaks.

Parameters

NameTypeDefaultDescription
window(float or None, float or None)(None, None)The time interval (t0, t1) used; None for an open end. Default: every sample.
method('zero_crossings', 'peaks')"zero_crossings"Count the crossings of the mean (half a period apart), or the maxima (a period apart; for a signal that does not cross its mean, e.g. an energy, whose peaks are half the field’s period apart). Default: "zero_crossings".
detrendboolTrueSubtract the mean over the window first, so that crossings are of the mean. Default: True.

Returns

OscillationFit or None
omega, period and the times of the crossings or peaks used; None with fewer than two.

Examples

>>> probe.plasma.analysis.oscillation_frequency(window=(5.0, 40.0)).omega

map_coordinatemethod#

def map_coordinate(dim: str, mapping, *, name: str | None = None, units: str | None = None, label: str | None = None) -> xr.DataArray

Replace a coordinate by a function of it, e.g. eta1 by the minor radius in meters.

Parameters

NameTypeDefaultDescription
dimstrrequiredThe dimension whose coordinate is mapped, e.g. "eta1".
mappingcallable or floatrequiredA function of the coordinate’s values (lambda eta1: 0.1 + 0.9 * eta1), or a factor (a length, for length * eta1).
namestrNoneThe name of the new dimension, e.g. "r". Default: keep dim.
unitsstrNoneThe new coordinate’s units, e.g. "m". Default: none.
labelstrNoneThe new coordinate’s axis label (its long_name), mathtext allowed. Default: name.

Returns

xarray.DataArray
The array over the new coordinate, which every plot then draws and labels.

Examples

>>> r_T = T.plasma.analysis.map_coordinate(
... "eta1", lambda eta1: 0.1 + 0.9 * eta1, name="r", units="m"
... )
>>> r_T.plasma.plot.profiles(x="r", eta2=0, eta3=0)

envelopemethod#

def envelope() -> xr.DataArray

Return the local maxima of this time series.

Returns

xarray.DataArray
The peaks, over their times t.

normmethod#

def norm(dims=None, squared: bool = False) -> xr.DataArray

Return the L2 norm over dims (default: every dimension except t).

Parameters

NameTypeDefaultDescription
dimsstr or sequence of strNoneThe dimensions summed over. Default: every dimension except t.
squaredboolFalseReturn the squared norm Σ f² instead. Default: False.

Returns

xarray.DataArray
The norm over the remaining dimensions, e.g. t.

Examples

>>> div_B.plasma.analysis.norm()

driftmethod#

def drift(ref=None) -> xr.DataArray

Return the signed deviation of this time series from ref or from its first sample.

Parameters

NameTypeDefaultDescription
reffloat or array_like or xarray.DataArrayNoneThe reference, broadcast against data. Default: data at the first time sample.

Returns

xarray.DataArray
The deviation over t.

Examples

>>> energy.plasma.analysis.drift().plasma.plot.timeseries()

relative_errormethod#

def relative_error(ref=None, skip_first: bool = True) -> xr.DataArray

Return the absolute relative deviation from ref or from this series’ first sample.

Parameters

NameTypeDefaultDescription
reffloat or array_like or xarray.DataArrayNoneThe reference, broadcast against data; must be non-zero everywhere. Default: data at the first time sample.
skip_firstboolTrueLeave out the first time sample (zero against the default reference). Default: True.

Returns

xarray.DataArray
The relative deviation over t.

Examples

>>> energy.plasma.analysis.relative_error(ref=exact_solution)

spatial_averagemethod#

def spatial_average(dims=None) -> xr.DataArray

Return the mean over the logical space dimensions eta1, eta2, eta3 (or dims).

For a binned e1_v1 distribution this is f(v1, t) averaged over space.

Parameters

NameTypeDefaultDescription
dimsstr or sequence of strNoneThe dimensions averaged over. Default: every logical dimension (eta1, eta2, eta3, or GVEC’s rho, theta, zeta) that data has.

Returns

xarray.DataArray
The mean over the remaining dimensions.

Examples

>>> distribution.plasma.analysis.spatial_average()

velocity_momentsmethod#

def velocity_moments(dims=None) -> xr.Dataset

Return density, mean velocity and variance of a binned distribution over its velocity dimensions.

See plasma_plots.analysis.velocity_moments() for the definitions.

Parameters

NameTypeDefaultDescription
dimsstr or sequence of strNoneThe velocity dimensions integrated over, each with a coordinate of at least two bins. Default: every one of v1, v2, v3 that f has.

Returns

xarray.Dataset
The moments, over the remaining dimensions.

Examples

>>> distribution.plasma.analysis.velocity_moments()

dispersionmethod#

def dispersion(dim: str | None = None, detrend: bool = True) -> xr.DataArray

Return the space-time power spectrum of this (t, dim) field.

A plain FFT, as a function of angular frequency and wavenumber: the data behind a dispersion-relation plot (ArrayPlots.dispersion()). dim defaults to the sole dimension other than t; select every other dimension away first. omega comes out in the angular-frequency units implied by t’s spacing (e.g. rad/s for physical seconds, or a normalized angular frequency for normalized time).

Parameters

NameTypeDefaultDescription
dimstrNoneThe spatial dimension. Default: the sole dimension other than t.
detrendboolTrueRemove the time-mean at each point of dim first, which otherwise dominates the spectrum as a spurious zero-frequency line. Default: True.

Returns

xarray.DataArray
The power over omega and the wavenumber.

Examples

>>> spectrum = E.isel(eta2=0, eta3=0).plasma.analysis.dispersion()

fit_branchesmethod#

def fit_branches(n_branches: int, k_range: tuple[float, float] | None = None, noise_level: float = 0.5, order: int = 10)

Fit straight dispersion branches (omega = v * k) to this (omega, k) power spectrum.

Parameters

NameTypeDefaultDescription
n_branchesintrequiredThe number of branches, at least 1.
k_range(float, float)NoneThe interval of non-negative k’s that are scanned. Default: (k.max() / 8, k.max() / 2), which in practice skips both the low-k region where branches have not yet separated, and the folded Nyquist edge.
noise_levelfloat0.5Maxima count only above this fraction of the column’s peak power. Default: 0.5.
orderint10A local maximum must exceed every one of its order neighbors on both sides along omega (out-of-range neighbors are clipped to the edge sample, as in scipy.signal.argrelextrema). Default: 10.

Returns

list of BranchFit
One fit per branch.

Examples

>>> field.plasma.analysis.dispersion().plasma.analysis.fit_branches(
... n_branches=2
... )

fftmethod#

def fft(dim: str, detrend: bool = False, window: str | None = None) -> xr.DataArray

Return the two-sided Fourier coefficients along dim.

Parameters

NameTypeDefaultDescription
dimstrrequiredThe dimension to transform.
detrendboolFalseSubtract the mean along dim first. Default: False.
window(None, 'hann')NoneMultiply by a periodic Hann window (see [hann()][hann]) first. Default: None (boxcar).

Returns

xarray.DataArray
The complex coefficients.

Examples

>>> phi.plasma.analysis.fft(dim="eta1")

time_fftmethod#

def time_fft(detrend: bool = False, window: str | None = None) -> xr.Dataset

Return the one-sided temporal coefficients and the power per bin.

Parameters

NameTypeDefaultDescription
detrendboolFalseSubtract the temporal mean first. Default: False.
window(None, 'hann')NoneMultiply by a periodic Hann window (see [hann()][hann]) first. Default: None (boxcar).

Returns

xarray.Dataset
coefficients and power over omega and the other dimensions.

Examples

>>> phi.plasma.analysis.time_fft(detrend=True)

filter_timemethod#

def filter_time(dims=None, omega_min: float = 1e-08, pad_bins: int = 0)

Return the dominant frequency band, reconstructed.

Parameters

NameTypeDefaultDescription
dimsstr or sequence of strNoneNon-time dimensions to sum the power over before choosing the band. Default: all dimensions except t and component. Pass dims=() for independent filtering at each point.
omega_minfloat1e-08Finite, positive lowest frequency considered, which excludes DC. Default: 1e-8.
pad_binsint0Nonnegative number of extra bins on each side of the band. Default: 0.

Returns

TimeFilterResult
The band and the reconstructed signal.

Examples

>>> band = phi.plasma.analysis.filter_time(dims=("eta1", "eta2", "eta3"))

band_filtermethod#

def band_filter(omega_lo: float, omega_hi: float, *, detrend: bool = False) -> xr.DataArray

Return only the frequencies in [omega_lo, omega_hi].

Parameters

NameTypeDefaultDescription
omega_lofloatrequiredThe lowest angular frequency kept.
omega_hifloatrequiredThe highest angular frequency kept, at least omega_lo.
detrendboolFalseSubtract the temporal mean first; the result then has zero mean even if the band includes DC. Default: False.

Returns

xarray.DataArray
The filtered signal, on this array’s grid.

Examples

>>> phi.plasma.analysis.band_filter(0.08, 0.11)

spectral_peaksmethod#

def spectral_peaks(n_peaks: int = 3, dims=None, omega_min: float = 1e-08, detrend=True, window=None) -> xr.Dataset

Return the strongest spectral peaks, with sub-bin frequencies.

Parameters

NameTypeDefaultDescription
n_peaksint3The number of peaks to return at most. Default: 3.
dimsstr or sequence of strNoneDimensions to sum the power over. Default: every dimension but omega. Only omega may remain.
omega_minfloat1e-08The lowest frequency a peak may have, which excludes DC. Default: 1e-8.
detrendbool or intTrueFor a time series: True subtracts the mean, False nothing, and an integer is the degree of a least-squares polynomial in t removed at every point first. An energy such as LinearMHD’s en_U oscillates at twice the wave frequency around a slow trend, so its peaks with detrend=2 sit at 2 * omega. Ignored for spectra. Default: True.
window(None, 'hann')NoneWindow applied before transforming a time series. Default: None.

Returns

xarray.Dataset
The peaks, strongest first.

Examples

>>> phi.plasma.analysis.spectral_peaks(n_peaks=2)

spectrogrammethod#

def spectrogram(length, step=None, detrend: bool = True, window: str | None = 'hann') -> xr.DataArray

Return power spectra in sliding time windows.

Parameters

NameTypeDefaultDescription
lengthint or floatrequiredThe window length: a sample count (integer, 4 to the number of samples) or a time span (float).
stepint or floatNoneThe shift between windows: a sample count (integer) or a time span (float). Default: a quarter of length.
detrendboolTrueSubtract each window’s mean. Default: True.
window('hann', None)"hann"The taper of each window, not compensated for. Default: "hann".

Returns

xarray.DataArray
The power over (t, omega, ...), t being each window’s center.

Examples

>>> signal.plasma.analysis.spectrogram(length=200.0, step=10.0)

mode_spectrummethod#

def mode_spectrum(dims=None, names=('m', 'n'), periods=None, scale=None) -> xr.DataArray

Return the complex amplitudes over poloidal/toroidal mode numbers.

Parameters

NameTypeDefaultDescription
dimsstr or sequence of strNoneThe periodic dimensions to transform. Default: the two angles of the logical dimensions (see plasma_plots.arrays.logical_dims()), ("eta2", "eta3") for Struphy.
namesstr or sequence of str('m', 'n')The name of the mode number of each dimension, one per dimension. Default: ("m", "n").
periodsfloat or sequence of floatNoneEach direction’s period in its coordinate: one number for all, or one per dimension. Default: the coordinate’s period attribute (see plasma_plots.arrays.angle_period()), else 1.0.
scaleint or sequence of intNoneMultiplies the mode numbers (one number, or one per dimension; cast to integers), e.g. scale=(1, 6) labels a sixth of a torus (Struphy’s tor_period=6) with full-torus toroidal mode numbers. Default: 2π over the period attribute of an angle (nfp for GVEC’s toroidal angle), else 1.

Returns

xarray.DataArray
The amplitudes over the mode numbers names and every remaining dimension.

Examples

>>> modes = phi.plasma.analysis.mode_spectrum()

mode_amplitudesmethod#

def mode_amplitudes(top: int | None = None, real: bool = True, relative: bool = False) -> xr.DataArray

Return the real amplitudes of this mode spectrum along one mode dimension.

Parameters

NameTypeDefaultDescription
topintNoneKeep only the top modes with the largest peak amplitude over every other dimension, strongest first. Default: all modes.
realboolTrueThe field is real: each (m, n) is combined with its conjugate (-m, -n). Only the half with the first nonzero mode number positive is kept, and its amplitude doubled, so a field A cos(...) gives A. A mode without a twin on the grid (the mean, or the Nyquist mode of an even grid) is kept as it is. Default: True.
relativeboolFalseDivide by the amplitude of the mean (the mode with all numbers zero), which is then left out: e.g. density perturbations relative to the background density, as growth plots of an instability often show. NaN where the mean vanishes. Default: False.

Returns

xarray.DataArray
The amplitudes over mode and every remaining dimension.

Examples

>>> phi.plasma.analysis.mode_spectrum().plasma.analysis.mode_amplitudes(top=4)

mode_structuremethod#

def mode_structure(omega: float, *, window: str | None = 'hann', detrend: bool = True) -> xr.DataArray

Return the complex amplitude at the exact frequency omega at every point.

Parameters

NameTypeDefaultDescription
omegafloatrequiredThe angular frequency ω.
window('hann', None)"hann"The weights w(t): a periodic Hann window, or None for uniform weights. Default: "hann".
detrendboolTrueSubtract the temporal mean at every point first. Default: True.

Returns

xarray.DataArray
The complex amplitude over every dimension but t.

Examples

>>> phi.plasma.analysis.mode_structure(omega)

cross_spectrummethod#

def cross_spectrum(other: xr.DataArray, *, dims=None, detrend: bool = True, window=None) -> xr.Dataset

Return the cross-spectrum, phase (of other relative to this) and coherence.

Parameters

NameTypeDefaultDescription
otherxarray.DataArrayrequiredThe second signal, on the same time grid; its phase is relative to this one.
dimsstr or sequence of strNoneDimensions to sum the cross-spectrum over, as an ensemble. Default: none (no coherence).
detrendboolTrueSubtract each signal’s temporal mean first. Default: True.
window(None, 'hann')NoneWindow applied to both signals before transforming. Default: None.

Returns

xarray.Dataset
The cross-spectrum, phase and (with dims) coherence over omega.

Examples

>>> u.plasma.analysis.cross_spectrum(b, dims="eta3")

matrix_pencilmethod#

def matrix_pencil(n_modes: int = 1, pencil: int | None = None, detrend: bool = False) -> xr.Dataset

Return frequencies and growth rates beyond the FFT resolution.

Parameters

NameTypeDefaultDescription
n_modesint1The number of modes to fit and return: real oscillations for a real signal, complex exponentials for a complex one. The fit needs well over 2 * n_modes samples. Default: 1.
pencilintNoneThe pencil parameter (Hankel matrix width minus one), which trades noise robustness against resolution. Default: N // 2.
detrendboolFalseSubtract the mean first. Default: False.

Returns

xarray.Dataset
omega, gamma, amplitude and phase along mode, strongest first.

Examples

>>> probe.plasma.analysis.matrix_pencil(n_modes=1)

gradientmethod#

def gradient(domain=None) -> xr.DataArray

Return the Cartesian gradient of this scalar field on a mapped domain.

Parameters

NameTypeDefaultDescription
domainstruphy domainNoneThe mapping (out.domain), for the exact Jacobian. Default: differentiate the X, Y, Z coordinates numerically.

Returns

xarray.DataArray
The gradient, with a component dimension (x, y, z).

Examples

>>> phi.plasma.analysis.gradient()

surface_averagemethod#

def surface_average(jacobian=None, domain=None, quadrature=None) -> xr.DataArray

Return the flux-surface average of this field over its two angles.

Parameters

NameTypeDefaultDescription
jacobianxarray.DataArrayNone√g on the same grid, e.g. GVEC’s Jac (its absolute value is used). Default: from domain, else the numerical Jacobian of the X, Y, Z coordinates, which needs at least two radial points.
domainstruphy domainNoneThe mapping, for the exact √g of a Struphy run.
quadraturedictNoneExplicit weights for the angles, as for [volume_integral()][volume_integral].

Returns

xarray.DataArray
⟨f⟩ over the radius and every non-spatial dimension.

Examples

>>> ev.mod_B.plasma.analysis.surface_average(jacobian=ev.Jac)

rational_surfacesmethod#

def rational_surfaces(count: int = 4, nfp: int | None = None, max_denominator: int = 12) -> xr.DataArray

Return where this rotational transform (or safety factor) profile is a low-order rational.

Parameters

NameTypeDefaultDescription
countint4The number of rational values. Default: 4.
nfpintNoneThe numerators are multiples of it. Default: the profile’s nfp attribute (GVEC’s, see plasma_plots.gvec.from_gvec()), else 1.
max_denominatorint12The largest m. Default: 12.

Returns

xarray.DataArray
The positions over surface, with the coordinates n, m and value.

Examples

>>> ev.iota.plasma.analysis.rational_surfaces(count=3)

errormethod#

def error(exact, *, norm: str = 'rms', relative: bool = False, dims=None, weighted: bool = False, domain=None, args=None) -> xr.DataArray

Return the error against an exact solution (an array or a function of the coordinates).

Parameters

NameTypeDefaultDescription
exact(callable, array_like, number or xarray.DataArray)requiredThe exact solution: an array (aligned with data, or broadcast to it) or a function of its coordinates, evaluated with [evaluate_on()][evaluate_on], e.g. lambda x, y, z, t: ....
norm('rms', 'max', 'l1', 'l2', 'pointwise')"rms""pointwise" is the difference data − exact itself; "max" the largest absolute difference; "l1" the mean (or, weighted, the integral) of |data − exact|; "l2" the square root of the mean (or integral) of |data − exact|²; "rms" (default) as "l2", divided by the volume when weighted.
relativeboolFalseDivide by the same norm of the exact solution; for "pointwise", by the largest |exact| over the whole array. Default: False.
dimsstr or sequence of strNoneThe dimensions the norm is taken over. Default: every dimension but t. Weighted norms need exactly eta1, eta2, eta3.
weightedboolFalseIntegrate over the physical volume instead of averaging over the grid points (no effect on "max" and "pointwise"). Default: False.
domainstruphy domainNoneThe mapping (out.domain), for the exact |√g| of weighted norms. Default: from the X, Y, Z coordinates.
argssequence of strNoneThe coordinates passed to a callable exact, as in [evaluate_on()][evaluate_on]. Default: X, Y, Z (or the logical dimensions), then t.

Returns

xarray.DataArray
The error, over the dimensions not reduced by norm.

Examples

>>> T.plasma.analysis.error(exact, relative=True)
>>> T.plasma.analysis.error(exact, norm="max")

project_modemethod#

def project_mode(dim: str, number: float, kind: str = 'sin', period: float = 1.0, bin_correction: bool = False) -> xr.DataArray

Return the amplitude of one Fourier mode along dim.

Parameters

NameTypeDefaultDescription
dimstrrequiredThe periodic dimension, e.g. "eta1".
numberfloatrequiredThe mode number, not a wavenumber: k = 2π number / L.
kind('sin', 'cos', 'complex')"sin""sin" (default) gives a of a sin(2π number x / period): 2 ⟨f sin(…)⟩; "cos" the cosine amplitude, and "complex" the complex amplitude 2 ⟨f exp(−i…)⟩ (abs() the amplitude, np.angle() the phase).
periodfloat1.0The period of dim. Default: 1, the logical unit interval.
bin_correctionboolFalseUndo the damping of binned particle data, whose bins average the mode over their width h: divide by sinc(number h / period). Default: False.

Returns

xarray.DataArray
The amplitude over the other dimensions.

Examples

>>> rho.plasma.analysis.project_mode(dim="eta2", number=3, kind="complex")

divergencemethod#

def divergence(components: str = 'cartesian', domain=None) -> xr.DataArray

Return the divergence of this vector field.

Parameters

NameTypeDefaultDescription
components('cartesian', 'contravariant')"cartesian"What the components are, as for the 3-D views: "cartesian" (default) (x, y, z), or "contravariant" components, which are pushed forward first.
domainstruphy domainNoneThe mapping (out.domain), for the exact Jacobian. Default: from the X, Y, Z coordinates.

Returns

xarray.DataArray
The divergence, without the component dimension.

Examples

>>> B.plasma.analysis.divergence()

curlmethod#

def curl(components: str = 'cartesian', domain=None) -> xr.DataArray

Return the curl of this vector field, in Cartesian components.

Parameters

NameTypeDefaultDescription
components('cartesian', 'contravariant')"cartesian"What the components are: "cartesian" (default) (x, y, z), or "contravariant" components, which are pushed forward first.
domainstruphy domainNoneThe mapping (out.domain), for the exact Jacobian. Default: from the X, Y, Z coordinates.

Returns

xarray.DataArray
The curl, with a component dimension.

Examples

>>> B.plasma.analysis.curl()

flux_functionmethod#

def flux_function() -> xr.DataArray

Return the flux (or stream) function of this 2-D in-plane field.

Returns

xarray.DataArray
The flux function, without the component dimension.

Examples

>>> B.plasma.analysis.flux_function()

cylindrical_componentsmethod#

def cylindrical_components() -> xr.DataArray

Return the Cartesian components rotated to (R, phi, Z).

Returns

xarray.DataArray
The vector field in cylindrical components.

Examples

>>> E.plasma.analysis.cylindrical_components()

toroidal_componentsmethod#

def toroidal_components(R0: float, Z0: float = 0.0) -> xr.DataArray

Return the Cartesian components rotated to (radial, poloidal, toroidal) about an axis at R0.

Parameters

NameTypeDefaultDescription
R0floatrequiredThe major radius of the magnetic axis.
Z0float0.0The height of the magnetic axis. Default: 0.

Returns

xarray.DataArray
The vector field in toroidal components.

Examples

>>> u.plasma.analysis.toroidal_components(R0=3.0)

polar_coordinatesmethod#

def polar_coordinates(center=(0.0, 0.0)) -> xr.DataArray

Return this array with coordinates r and theta in the X-Y plane.

Parameters

NameTypeDefaultDescription
center(float, float)(0.0, 0.0)The origin (X, Y) of the polar coordinates. Default: (0.0, 0.0).

Returns

xarray.DataArray
This array with the added coordinates.

Examples

>>> n.plasma.analysis.polar_coordinates(center=(0.0, 0.0))

trace_branchmethod#

def trace_branch(theory, *, window: float = 0.2, k_range=None, threshold: float = 0.001) -> xr.Dataset

Return the measured frequency of a dispersion branch near theory(k) in this (omega, k) spectrum.

Parameters

NameTypeDefaultDescription
theorycallablerequiredThe expected branch omega(k), applied to an array of k; of a complex frequency (as plasma_plots.theory returns), the real part is used.
windowfloat0.2The relative half-width of the search window about the theory. Default: 0.2.
k_range(float, float)NoneThe k interval to trace (negative k are never traced). Default: every k >= 0.
thresholdfloat0.001Maxima weaker than this times the strongest one found count as no wave. Default: 1e-3.

Returns

xarray.Dataset
The measured branch over k.

Examples

>>> spectrum.plasma.analysis.trace_branch(
... bohm_gross, window=0.2, k_range=(1.5, 5.5)
... )

drop_periodic_endpointmethod#

def drop_periodic_endpoint(dim: str, *, period: float = 1.0) -> xr.DataArray

Return this array without a duplicated periodic endpoint along dim.

Parameters

NameTypeDefaultDescription
dimstrrequiredThe periodic dimension.
periodfloat1.0The period in the coordinate of dim. Default: 1.0.

Returns

xarray.DataArray
This array, one point shorter along dim if its last point repeats the first.

field_linesmethod#

def field_lines(seeds=8, turns: float | None = None, length: float | None = None, step: float | None = None, direction: str = 'forward', section: float | None = None, stride: int | None = None, components: str = 'cartesian', **selection) -> xr.Dataset

Trace field lines of this vector field through its mapped grid.

Parameters

NameTypeDefaultDescription
seeds(int, dict, array_like or xarray.Dataset)8Where the lines start, in logical coordinates: a number of seeds spread along the radial coordinate at the first poloidal and toroidal grid values (the outboard midplane of a torus whose angles start at 0); a dict of logical coordinates to values or 1-D arrays, which are combined into a grid of seeds (e.g. {"rho": 0.95, "theta": thetas, "zeta": zetas} for a connection-length map; a missing coordinate takes its first grid value); an (n, 3) array of points in the order of the logical dimensions; or a Dataset with one variable per logical coordinate. Default: 8.
turnsfloatNoneStop a line after this many toroidal transits (turns of the torus: nfp periods of the toroidal logical coordinate, i.e. 2π of GVEC’s toroidal angle, one period of Struphy’s eta3). Default: 20 when the toroidal direction wraps around, else none.
lengthfloatNoneStop a line after this arc length, in the units of X, Y, Z. Default: with turns, 1.5 times the length turns circles through the seeds’ mean major radius would take (a safety net); without, four times the grid’s extent.
stepfloatNoneThe step of arc length of the integrator. Default: the median spacing of the grid points (trilinear interpolation limits the accuracy before the step does).
direction('forward', 'backward', 'both')"forward"Along the field, against it, or each seed in both directions (two lines per seed, with the coordinates seed and direction telling them apart; the connection length is then the sum of both). Default: "forward".
sectionfloatNoneThe toroidal logical coordinate of the poloidal plane whose punctures are recorded. Default: the first toroidal grid value (e.g. zeta = 0).
strideintNoneSave every stride-th step of each line. Default: as many as keep each line at about 20 000 samples at most; the punctures, transits and lengths count every step regardless.
components('cartesian', 'contravariant')"cartesian"What the components are: "cartesian" (default) (x, y, z), or contravariant logical components, as for plasma_plots.analysis.divergence().
**selection{}The other dimensions, e.g. t=-1: an integer is a position, a float the nearest coordinate value.

Returns

xarray.Dataset
The lines over (s, line) with their punctures, rotational transforms and connection lengths; it has .plasma.plot.poincare(), .footprint() and the other field-line plots.

Examples

>>> lines = B.plasma.analysis.field_lines(seeds=12, turns=100, t=-1)
>>> lines.plasma.plot.poincare(color_by="iota")
>>> edge = B.plasma.analysis.field_lines(
... seeds={"eta1": 0.98, "eta2": np.linspace(0, 1, 32)},
... direction="both",
... t=-1,
... )

sample_alongmethod#

def sample_along(lines: xr.Dataset) -> xr.DataArray

Return this scalar field interpolated along traced field lines.

Parameters

NameTypeDescription
linesxarray.DatasetThe lines of [trace_field_lines()][trace_field_lines].

Returns

xarray.DataArray
The field over (s, line) after its other dimensions.

Examples

>>> along = phi.plasma.analysis.sample_along(lines)
>>> along.isel(line=0).plasma.plot.slice(x="s", y="t")

parallel_wavenumbermethod#

def parallel_wavenumber(lines: xr.Dataset | None = None, method: str = 'fft', detrend: bool = True) -> xr.DataArray

Return the dominant parallel wavenumber of this field along field lines.

Parameters

NameTypeDefaultDescription
linesxarray.DatasetNoneTraced lines to sample this field along first. Default: this array already is the samples of sample_along(), over (s, line).
method('fft', 'crossings')"fft"How to estimate it. Default: "fft".
detrendboolTrueRemove the mean along each line first. Default: True.

Returns

xarray.DataArray
k_parallel over line and the other dimensions.

Examples

>>> phi.plasma.analysis.parallel_wavenumber(lines=lines)

boozer_spectrummethod#

def boozer_spectrum(top: int | None = None, angles: str = 'boozer') -> xr.DataArray

Return the Boozer harmonics B_mn of this quantity over the radius.

Parameters

NameTypeDefaultDescription
topintNoneKeep only the top harmonics with the largest peak amplitude over the radius, strongest first. Default: all.
angles('boozer', 'any')"boozer"Require the Boozer angles theta_B, zeta_B (default), or take the harmonics in whatever angles the field has (not a Boozer spectrum then; e.g. for a comparison).

Returns

xarray.DataArray
The real amplitudes over mode (with m, n) and the radius.

Examples

>>> boozer.mod_B.plasma.analysis.boozer_spectrum(top=8)

quasisymmetry_errormethod#

def quasisymmetry_error(helicity='QA', angles: str = 'boozer') -> xr.DataArray

Return the quasi-symmetry error of this |B| on each flux surface.

Parameters

NameTypeDefaultDescription
helicity('QA', 'QP', 'QH')"QA"The symmetry: a name, or (M, N) with N a full-torus toroidal mode number (its sign picks the handedness). Default: "QA".
angles('boozer', 'any')"boozer"As for boozer_spectrum().

Returns

xarray.DataArray
f_QS over the radius.

Examples

>>> boozer.mod_B.plasma.analysis.quasisymmetry_error(helicity="QH")

critical_pointsmethod#

def critical_points(refine: bool = True) -> xr.Dataset

Return the O-points and X-points of this flux function (at every time).

Parameters

NameTypeDefaultDescription
refineboolTrueLocate the zero within the cell by Newton’s method (the cell’s centre otherwise). Default: True.

Returns

xarray.Dataset
The points over point (and t): positions, values and kinds.

Examples

>>> B.plasma.analysis.flux_function().plasma.analysis.critical_points()

reconnected_fluxmethod#

def reconnected_flux(relative: bool = True, o_point=None, x_point=None) -> xr.DataArray

Return the reconnected flux over time: this flux function between an O- and an X-point.

Parameters

NameTypeDefaultDescription
relativeboolTrueSubtract the value at the first time. Default: True.
o_point(float, float)NoneThe logical coordinates near which to look for the O-point. Default: the dominant island’s.
x_point(float, float)NoneThe same for the X-point.

Returns

xarray.DataArray
ΔΨ(t).

Examples

>>> A = B.plasma.analysis.flux_function()
>>> A.plasma.analysis.reconnected_flux().plasma.plot.timeseries(
... fit=(10.0, 30.0)
... )