Source code for eqtools.core

# This program is distributed under the terms of the GNU General Purpose License (GPL).
# Refer to http://www.gnu.org/licenses/gpl.txt
#
# This file is part of eqtools.
#
# eqtools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# eqtools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with eqtools.  If not, see <http://www.gnu.org/licenses/>.

"""This module provides the core classes for :py:mod:`eqtools`, including the
base :py:class:`Equilibrium` class.
"""
import scipy
import scipy.interpolate
import scipy.integrate
import scipy.constants
import re
import warnings
# Python 2/3 cross compatibility:
import sys
if sys.version_info.major >= 3:
    long = int

# Constants to determine how plot labels are formatted:
B_LABEL = '$B$ [T]'
J_LABEL = '$j$ [MA/m$^2$]'


[docs]class ModuleWarning(Warning): """Warning class to notify the user of unavailable modules. """ pass
try: from . import trispline _has_trispline = True except ImportError: warnings.warn("trispline module could not be loaded -- tricubic spline " "interpolation will not be available.", ModuleWarning) _has_trispline = False try: import matplotlib.pyplot as plt import matplotlib.widgets as mplw import matplotlib.gridspec as mplgs import matplotlib.patches as mpatches import matplotlib.path as mpath from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.axes_grid1 import make_axes_locatable from matplotlib.colorbar import ColorbarBase from matplotlib.colors import Normalize from .filewriter import gfile except Exception: warnings.warn( "matplotlib modules could not be loaded -- plotting and gfile" " writing will not be available.", ModuleWarning )
[docs]class PropertyAccessMixin(object): """Mixin to implement access of getter methods through a property-type interface without the need to apply a decorator to every property. For any getter `obj.getSomething()`, the call `obj.Something` will do the same thing. This is accomplished by overriding :py:meth:`__getattribute__` such that if an attribute `ATTR` does not exist it then attempts to call `self.getATTR()`. If `self.getATTR()` does not exist, an :py:class:`AttributeError` will be raised as usual. Also overrides :py:meth:`__setattr__` such that it will raise an :py:class:`AttributeError` when attempting to write an attribute `ATTR` for which there is already a method `getATTR`. """ def __getattribute__(self, name): """Get an attribute. Tries to get attribute as-written. If this fails, tries to call the method `get<name>` with no arguments. If this fails, raises :py:class:`AttributeError`. This effectively generates a Python 'property' for each getter method. Args: name (String): Name of the attribute to retrieve. If the instance has an attribute with this name, the attribute is returned. If the instance does not have an attribute with this name but does have a method called 'get'+name, this method is called and the result is returned. Returns: The value of the attribute requested. Raises: AttributeError: If neither attribute name or method 'get'+name exist. """ try: return super(Equilibrium, self).__getattribute__(name) except AttributeError: try: return super(Equilibrium, self).__getattribute__('get'+name)() except AttributeError: raise AttributeError( "%(class)s object has no attribute '%(n)s' or method 'get%(n)s'" % {'class': self.__class__.__name__, 'n': name} ) def __setattr__(self, name, value): """Set an attribute. Raises :py:class:`AttributeError` if the object already has a method 'get'+name, as creation of such an attribute would interfere with the automatic property generation in :py:meth:`__getattribute__`. Args: name (String): Name of the attribute to set. value (Object): Value to set the attribute to. Raises: AttributeError: If a method called 'get'+name already exists. """ if hasattr(self, 'get'+name): raise AttributeError( "%(class)s object already has getter method 'get%(n)s', creating " "attribute '%(n)s' will conflict with automatic property " "generation." % {'class': self.__class__.__name__, 'n': name} ) else: super(Equilibrium, self).__setattr__(name, value)
"""The following is a dictionary to implement length unit conversions. The first key is the unit are converting FROM, the second the unit you are converting TO. Supports: m, cm, mm, in, ft, yd, smoot, cubit, hand """ _length_conversion = {'m': {'m': 1.0, 'cm': 100.0, 'mm': 1000.0, 'in': 39.37, 'ft': 39.37 / 12.0, 'yd': 39.37 / (12.0 * 3.0), 'smoot': 39.37 / 67.0, 'cubit': 39.37 / 18.0, 'hand': 39.37 / 4.0}, 'cm': {'m': 0.01, 'cm': 1.0, 'mm': 10.0, 'in': 39.37 / 100.0, 'ft': 39.37 / (100.0 * 12.0), 'yd': 39.37 / (100.0 * 12.0 * 3.0), 'smoot': 39.37 / (100.0 * 67.0), 'cubit': 39.37 / (100.0 * 18.0), 'hand': 39.37 / (100.0 * 4.0)}, 'mm': {'m': 0.001, 'cm': 0.1, 'mm': 1.0, 'in': 39.37 / 1000.0, 'ft': 39.37 / (1000.0 * 12.0), 'yd': 39.37 / (1000.0 * 12.0 * 3.0), 'smoot': 39.37 / (1000.0 * 67.0), 'cubit': 39.37 / (1000.0 * 18.0), 'hand': 39.37 / (1000.0 * 4.0)}, 'in': {'m': 1.0 / 39.37, 'cm': 100.0 / 39.37, 'mm': 1000.0 / 39.37, 'in': 1.0, 'ft': 1.0 / 12.0, 'yd': 1.0 / (12.0 * 3.0), 'smoot': 1.0 / 67.0, 'cubit': 1.0 / 18.0, 'hand': 1.0 / 4.0}, 'ft': {'m': 12.0 / 39.37, 'cm': 12.0 * 100.0 / 39.37, 'mm': 12.0 * 1000.0 / 39.37, 'in': 12.0, 'ft': 1.0, 'yd': 1.0 / 3.0, 'smoot': 12.0 / 67.0, 'cubit': 12.0 / 18.0, 'hand': 12.0 / 4.0}, 'yd': {'m': 3.0 * 12.0 / 39.37, 'cm': 3.0 * 12.0 * 100.0 / 39.37, 'mm': 3.0 * 12.0 * 1000.0 / 39.37, 'in': 3.0 * 12.0, 'ft': 3.0, 'yd': 1.0, 'smoot': 3.0 * 12.0 / 67.0, 'cubit': 3.0 * 12.0 / 18.0, 'hand': 3.0 * 12.0 / 4.0}, 'smoot': {'m': 67.0 / 39.37, 'cm': 67.0 * 100.0 / 39.37, 'mm': 67.0 * 1000.0 / 39.37, 'in': 67.0, 'ft': 67.0 / 12.0, 'yd': 67.0 / (12.0 * 3.0), 'smoot': 1.0, 'cubit': 67.0 / 18.0, 'hand': 67.0 / 4.0}, 'cubit': {'m': 18.0 / 39.37, 'cm': 18.0 * 100.0 / 39.37, 'mm': 18.0 * 1000.0 / 39.37, 'in': 18.0, 'ft': 18.0 / 12.0, 'yd': 18.0 / (12.0 * 3.0), 'smoot': 18.0 / 67.0, 'cubit': 1.0, 'hand': 18.0 / 4.0}, 'hand': {'m': 4.0 / 39.37, 'cm': 4.0 * 100.0 / 39.37, 'mm': 4.0 * 1000.0 / 39.37, 'in': 4.0, 'ft': 4.0 / 12.0, 'yd': 4.0 / (12.0 * 3.0), 'smoot': 4.0 / 67.0, 'cubit': 4.0 / 18.0, 'hand': 1.0}}
[docs]def inPolygon(polyx, polyy, pointx, pointy): """Function calculating whether a given point is within a 2D polygon. Given an array of X,Y coordinates describing a 2D polygon, checks whether a point given by x,y coordinates lies within the polygon. Operates via a ray-casting approach - the function projects a semi-infinite ray parallel to the positive horizontal axis, and counts how many edges of the polygon this ray intersects. For a simply-connected polygon, this determines whether the point is inside (even number of crossings) or outside (odd number of crossings) the polygon, by the Jordan Curve Theorem. Args: polyx (Array-like): Array of x-coordinates of the vertices of the polygon. polyy (Array-like): Array of y-coordinates of the vertices of the polygon. pointx (Int or float): x-coordinate of test point. pointy (Int or float): y-coordinate of test point. Returns: result (Boolean): True/False result for whether the point is contained within the polygon. """ # generator function for "lines" - pairs of (x,y) coords describing each edge of the polygon. def lines(): p0x = polyx[-1] p0y = polyy[-1] p0 = (p0x, p0y) for i, x in enumerate(polyx): y = polyy[i] p1 = (x, y) yield p0, p1 p0 = p1 result = False for p0, p1 in lines(): if ( (p0[1] > pointy) != (p1[1] > pointy) ) and ( pointx < ((p1[0]-p0[0])*(pointy-p0[1])/(p1[1]-p0[1]) + p0[0]) ): result = not result return result
[docs]class Equilibrium(object): """Abstract class of data handling object for magnetic reconstruction outputs. Defines the mapping routines and method fingerprints necessary. Each variable or set of variables is recovered with a corresponding getter method. Essential data for mapping are pulled on initialization (psirz grid, for example) to frontload overhead. Additional data are pulled at the first request and stored for subsequent usage. .. note:: This abstract class should not be used directly. Device- and code- specific subclasses are set up to account for inter-device/-code differences in data storage. Keyword Args: length_unit (String): Sets the base unit used for any quantity whose dimensions are length to any power. Valid options are: =========== =========================================================================================== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' whatever the default in the tree is (no conversion is performed, units may be inconsistent) =========== =========================================================================================== Default is 'm' (all units taken and returned in meters). tspline (Boolean): Sets whether or not interpolation in time is performed using a tricubic spline or nearest-neighbor interpolation. Tricubic spline interpolation requires at least four complete equilibria at different times. It is also assumed that they are functionally correlated, and that parameters do not vary out of their boundaries (derivative = 0 boundary condition). Default is False (use nearest-neighbor interpolation). monotonic (Boolean): Sets whether or not the "monotonic" form of time window finding is used. If True, the timebase must be monotonically increasing. Default is False (use slower, safer method). verbose (Boolean): Allows or blocks console readout during operation. Defaults to True, displaying useful information for the user. Set to False for quiet usage or to avoid console clutter for multiple instances. Raises: ValueError: If `length_unit` is not a valid unit specifier. ValueError: If `tspline` is True but module trispline did not load successfully. """ def __init__( self, length_unit='m', tspline=False, monotonic=True, verbose=True ): if ( (length_unit != 'default') and (not (length_unit in _length_conversion)) ): raise ValueError( "Unit '%s' not a valid unit specifier!" % length_unit ) else: self._length_unit = length_unit self._tricubic = bool(tspline) self._monotonic = bool(monotonic) self._verbose = bool(verbose) # These are indexes of splines, and become higher dimensional splines # with the setting of the tspline keyword. self._psiOfRZSpline = {} self._phiNormSpline = {} self._volNormSpline = {} self._RmidSpline = {} self._magRSpline = {} self._magZSpline = {} self._RmidOutSpline = {} self._psiOfPsi0Spline = {} self._psiOfLCFSSpline = {} self._RmidToPsiNormSpline = {} self._phiNormToPsiNormSpline = {} self._volNormToPsiNormSpline = {} self._AOutSpline = {} self._qSpline = {} self._FSpline = {} self._FToPsinormSpline = {} self._FFPrimeSpline = {} self._pSpline = {} self._pPrimeSpline = {} self._vSpline = {} self._BtVacSpline = {} def __str__(self): """String representation of this instance. Returns: string (String): String describing this object. """ return 'This is an abstract class. Please use machine-specific subclass.' def __getstate__(self): """Deletes all of the stored splines, since they aren't pickleable. """ self._psiOfRZSpline = {} self._phiNormSpline = {} self._volNormSpline = {} self._RmidSpline = {} self._magRSpline = {} self._magZSpline = {} self._RmidOutSpline = {} self._psiOfPsi0Spline = {} self._psiOfLCFSSpline = {} self._RmidToPsiNormSpline = {} self._phiNormToPsiNormSpline = {} self._volNormToPsiNormSpline = {} self._AOutSpline = {} self._qSpline = {} self._FSpline = {} self._FToPsinormSpline = {} self._FFPrimeSpline = {} self._pSpline = {} self._pPrimeSpline = {} self._vSpline = {} self._BtVacSpline = {} return self.__dict__ #################### # Mapping routines # ####################
[docs] def rho2rho(self, origin, destination, *args, **kwargs): r"""Convert from one coordinate to another. Args: origin (String): Indicates which coordinates the data are given in. Valid options are: ======= ======================== RZ R,Z coordinates psinorm Normalized poloidal flux phinorm Normalized toroidal flux volnorm Normalized volume Rmid Midplane major radius r/a Normalized minor radius ======= ======================== Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. destination (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= psinorm Normalized poloidal flux phinorm Normalized toroidal flux volnorm Normalized volume Rmid Midplane major radius r/a Normalized minor radius q Safety factor F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. rho (Array-like or scalar float): Values of the starting coordinate to map to the new coordinate. Will be two arguments `R`, `Z` if `origin` is 'RZ'. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `rho`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `rho` (or the meshgrid of `R` and `Z` if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of `rho`. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `rho` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `rho` or be a scalar. Default is True (evaluate ALL `rho` at EACH element in `t`). make_grid (Boolean): Only applicable if `origin` is 'RZ'. Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid when `destination` is Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that quantities are given/returned in, as applicable. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Raises: ValueError: If `origin` is not one of the supported values. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at r/a=0.6, t=0.26s:: psi_val = Eq_instance.rho2rho('r/a', 'psinorm', 0.6, 0.26) Find psinorm values at r/a points 0.6 and 0.8 at the single time t=0.26s:: psi_arr = Eq_instance.rho2rho('r/a', 'psinorm', [0.6, 0.8], 0.26) Find psinorm values at r/a of 0.6 at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.rho2rho('r/a', 'psinorm', 0.6, [0.2, 0.3]) Find psinorm values at (r/a, t) points (0.6, 0.2s) and (0.5, 0.3s):: psi_arr = Eq_instance.rho2rho('r/a', 'psinorm', [0.6, 0.5], [0.2, 0.3], each_t=False) """ if origin.startswith('sqrt'): args = list(args) args[0] = scipy.asarray(args[0])**2 origin = origin[4:] if destination.startswith('sqrt'): kwargs['sqrt'] = True destination = destination[4:] if origin == 'RZ': return self.rz2rho(destination, *args, **kwargs) elif origin == 'Rmid': return self.rmid2rho(destination, *args, **kwargs) elif origin == 'r/a': return self.roa2rho(destination, *args, **kwargs) elif origin == 'psinorm': return self.psinorm2rho(destination, *args, **kwargs) elif origin == 'phinorm': return self.phinorm2rho(destination, *args, **kwargs) elif origin == 'volnorm': return self.volnorm2rho(destination, *args, **kwargs) else: raise ValueError( "rho2rho: Unsupported origin coordinate method '%s'!" % origin )
[docs] def rz2psi( self, R, Z, t, return_t=False, make_grid=False, each_t=True, length_unit=1 ): r"""Converts the passed R, Z, t arrays to psi (unnormalized poloidal flux) values. What is usually returned by EFIT is the stream function, :math:`\psi=\psi_p/(2\pi)` which has units of Wb/rad. Args: R (Array-like or scalar float): Values of the radial coordinate to map to poloidal flux. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to poloidal flux. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `psi` or (`psi`, `time_idxs`) * **psi** (`Array or scalar float`) - The unnormalized poloidal flux. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `psi` has this shape as well, unless the `make_grid` keyword was True, in which case `psi` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `psi`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psi value at R=0.6m, Z=0.0m, t=0.26s:: psi_val = Eq_instance.rz2psi(0.6, 0, 0.26) Find psi values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: psi_arr = Eq_instance.rz2psi([0.6, 0.8], [0, 0], 0.26) Find psi values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.rz2psi(0.6, 0, [0.2, 0.3]) Find psi values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: psi_arr = Eq_instance.rz2psi([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find psi values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: psi_mat = Eq_instance.rz2psi(R, Z, 0.2, make_grid=True) """ # Check inputs and process into flat arrays with units of meters: ( R, Z, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( R, Z, t, make_grid=make_grid, each_t=each_t, length_unit=length_unit, compute_unique=True ) if self._tricubic: out_vals = scipy.reshape( self._getFluxTriSpline().ev(t, Z, R), original_shape ) else: if single_time: out_vals = self._getFluxBiSpline(time_idxs[0]).ev(Z, R) if single_val: out_vals = out_vals[0] else: out_vals = scipy.reshape(out_vals, original_shape) elif each_t: out_vals = scipy.zeros( scipy.concatenate( ([len(time_idxs), ], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): out_vals[idx] = self._getFluxBiSpline( t_idx ).ev(Z, R).reshape(original_shape) else: out_vals = scipy.zeros_like(t, dtype=float) for t_idx in unique_idxs: t_mask = (time_idxs == t_idx) out_vals[t_mask] = self._getFluxBiSpline( t_idx ).ev(Z[t_mask], R[t_mask]) out_vals = scipy.reshape(out_vals, original_shape) # Correct for current sign: out_vals = -1.0 * out_vals * self.getCurrentSign() if return_t: if self._tricubic: return out_vals, (t, single_time, single_val, original_shape) else: return out_vals, ( time_idxs, unique_idxs, single_time, single_val, original_shape ) else: return out_vals
[docs] def rz2psinorm(self, R, Z, t, return_t=False, sqrt=False, make_grid=False, each_t=True, length_unit=1): r"""Calculates the normalized poloidal flux at the given (R, Z, t). Uses the definition: .. math:: \texttt{psi\_norm} = \frac{\psi - \psi(0)}{\psi(a) - \psi(0)} Args: R (Array-like or scalar float): Values of the radial coordinate to map to psinorm. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to psinorm. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of psinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `psinorm` or (`psinorm`, `time_idxs`) * **psinorm** (`Array or scalar float`) - The normalized poloidal flux. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `psinorm` has this shape as well, unless the `make_grid` keyword was True, in which case `psinorm` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `psinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at R=0.6m, Z=0.0m, t=0.26s:: psi_val = Eq_instance.rz2psinorm(0.6, 0, 0.26) Find psinorm values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: psi_arr = Eq_instance.rz2psinorm([0.6, 0.8], [0, 0], 0.26) Find psinorm values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.rz2psinorm(0.6, 0, [0.2, 0.3]) Find psinorm values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: psi_arr = Eq_instance.rz2psinorm([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find psinorm values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: psi_mat = Eq_instance.rz2psinorm(R, Z, 0.2, make_grid=True) """ psi, blob = self.rz2psi( R, Z, t, return_t=True, make_grid=make_grid, each_t=each_t, length_unit=length_unit ) if self._tricubic: psi_boundary = self._getLCFSPsiSpline()(blob[0]).reshape(blob[-1]) psi_0 = self._getPsi0Spline()(blob[0]).reshape(blob[-1]) else: psi_boundary = self.getFluxLCFS()[blob[0]] psi_0 = self.getFluxAxis()[blob[0]] # If there is more than one time point, we need to expand these # arrays to be broadcastable: if not blob[-3]: if each_t: for k in range(0, len(blob[-1])): psi_boundary = scipy.expand_dims(psi_boundary, -1) psi_0 = scipy.expand_dims(psi_0, -1) else: psi_boundary = psi_boundary.reshape(blob[-1]) psi_0 = psi_0.reshape(blob[-1]) psi_norm = (psi - psi_0) / (psi_boundary - psi_0) if sqrt: if psi_norm.ndim == 0: if psi_norm < 0.0: psi_norm = 0.0 else: scipy.place(psi_norm, psi_norm < 0, 0) out = scipy.sqrt(psi_norm) else: out = psi_norm # Unwrap single values to ensure least surprise: if blob[-2] and blob[-3] and not self._tricubic: out = out[0] if return_t: return out, blob else: return out
[docs] def rz2phinorm(self, *args, **kwargs): r"""Calculates the normalized toroidal flux. Uses the definitions: .. math:: \texttt{phi} &= \int q(\psi)\,d\psi\\ \texttt{phi\_norm} &= \frac{\phi}{\phi(a)} This is based on the IDL version efit_rz2rho.pro by Steve Wolfe. Args: R (Array-like or scalar float): Values of the radial coordinate to map to phinorm. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to phinorm. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of phinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting psinorm to phinorm. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `phinorm` or (`phinorm`, `time_idxs`) * **phinorm** (`Array or scalar float`) - The normalized toroidal flux. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `phinorm` has this shape as well, unless the `make_grid` keyword was True, in which case `phinorm` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `phinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single phinorm value at R=0.6m, Z=0.0m, t=0.26s:: phi_val = Eq_instance.rz2phinorm(0.6, 0, 0.26) Find phinorm values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: phi_arr = Eq_instance.rz2phinorm([0.6, 0.8], [0, 0], 0.26) Find phinorm values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: phi_arr = Eq_instance.rz2phinorm(0.6, 0, [0.2, 0.3]) Find phinorm values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: phi_arr = Eq_instance.rz2phinorm([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find phinorm values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: phi_mat = Eq_instance.rz2phinorm(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getPhiNormSpline, *args, **kwargs)
[docs] def rz2volnorm(self, *args, **kwargs): """Calculates the normalized flux surface volume. Based on the IDL version efit_rz2rho.pro by Steve Wolfe. Args: R (Array-like or scalar float): Values of the radial coordinate to map to volnorm. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to volnorm. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of volnorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting psinorm to volnorm. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `volnorm` or (`volnorm`, `time_idxs`) * **volnorm** (`Array or scalar float`) - The normalized volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `volnorm` has this shape as well, unless the `make_grid` keyword was True, in which case `volnorm` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `volnorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single volnorm value at R=0.6m, Z=0.0m, t=0.26s:: psi_val = Eq_instance.rz2volnorm(0.6, 0, 0.26) Find volnorm values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: vol_arr = Eq_instance.rz2volnorm([0.6, 0.8], [0, 0], 0.26) Find volnorm values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: vol_arr = Eq_instance.rz2volnorm(0.6, 0, [0.2, 0.3]) Find volnorm values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: vol_arr = Eq_instance.rz2volnorm([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find volnorm values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: vol_mat = Eq_instance.rz2volnorm(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getVolNormSpline, *args, **kwargs)
[docs] def rz2rmid(self, *args, **kwargs): """Maps the given points to the outboard midplane major radius, Rmid. Based on the IDL version efit_rz2rmid.pro by Steve Wolfe. Args: R (Array-like or scalar float): Values of the radial coordinate to map to Rmid. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to Rmid. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of Rmid. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `R`, `Z` are given in, AND that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting psinorm to Rmid. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `Rmid` or (`Rmid`, `time_idxs`) * **Rmid** (`Array or scalar float`) - The outboard midplan major radius. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `Rmid` has this shape as well, unless the `make_grid` keyword was True, in which case `Rmid` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `Rmid`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single Rmid value at R=0.6m, Z=0.0m, t=0.26s:: R_mid_val = Eq_instance.rz2rmid(0.6, 0, 0.26) Find R_mid values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: R_mid_arr = Eq_instance.rz2rmid([0.6, 0.8], [0, 0], 0.26) Find Rmid values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: R_mid_arr = Eq_instance.rz2rmid(0.6, 0, [0.2, 0.3]) Find Rmid values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: R_mid_arr = Eq_instance.rz2rmid([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find Rmid values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: R_mid_mat = Eq_instance.rz2rmid(R, Z, 0.2, make_grid=True) """ # Steve Wolfe's version has an extra (linear) interpolation step for # small psi_norm. Should check to see if we need this still with the # scipy spline. So far looks fine... # Convert units from meters to desired target but keep units consistent # with rho keyword: if kwargs.get('rho', False): unit_factor = 1 else: unit_factor = self._getLengthConversionFactor( 'm', kwargs.get('length_unit', 1) ) return unit_factor * self._RZ2Quan( self._getRmidSpline, *args, **kwargs )
[docs] def rz2roa(self, *args, **kwargs): """Maps the given points to the normalized minor radius, r/a. Based on the IDL version efit_rz2rmid.pro by Steve Wolfe. Args: R (Array-like or scalar float): Values of the radial coordinate to map to r/a. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to r/a. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of r/a. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting psinorm to Rmid. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `roa` or (`roa`, `time_idxs`) * **roa** (`Array or scalar float`) - The normalized minor radius. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `roa` has this shape as well, unless the `make_grid` keyword was True, in which case `roa` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `roa`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single r/a value at R=0.6m, Z=0.0m, t=0.26s:: roa_val = Eq_instance.rz2roa(0.6, 0, 0.26) Find r/a values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the Z vector must be fully specified, even if the values are all the same:: roa_arr = Eq_instance.rz2roa([0.6, 0.8], [0, 0], 0.26) Find r/a values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: roa_arr = Eq_instance.rz2roa(0.6, 0, [0.2, 0.3]) Find r/a values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: roa_arr = Eq_instance.rz2roa([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find r/a values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: roa_mat = Eq_instance.rz2roa(R, Z, 0.2, make_grid=True) """ # Steve Wolfe's version has an extra (linear) interpolation step for # small psi_norm. Should check to see if we need this still with the # scipy spline. So far looks fine... kwargs['rho'] = True return self._RZ2Quan(self._getRmidSpline, *args, **kwargs)
[docs] def rz2rho(self, method, *args, **kwargs): r"""Convert the passed (R, Z, t) coordinates into one of several coordinates. Args: method (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= psinorm Normalized poloidal flux phinorm Normalized toroidal flux volnorm Normalized volume Rmid Midplane major radius r/a Normalized minor radius q Safety factor F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. R (Array-like or scalar float): Values of the radial coordinate to map to `rho`. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to `rho`. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of `rho`. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid when `destination` is Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `R`, `Z` are given in, AND that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Raises: ValueError: If `method` is not one of the supported values. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at R=0.6m, Z=0.0m, t=0.26s:: psi_val = Eq_instance.rz2rho('psinorm', 0.6, 0, 0.26) Find psinorm values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: psi_arr = Eq_instance.rz2rho('psinorm', [0.6, 0.8], [0, 0], 0.26) Find psinorm values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.rz2rho('psinorm', 0.6, 0, [0.2, 0.3]) Find psinorm values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: psi_arr = Eq_instance.rz2rho('psinorm', [0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find psinorm values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: psi_mat = Eq_instance.rz2rho('psinorm', R, Z, 0.2, make_grid=True) """ if method.startswith('sqrt'): kwargs['sqrt'] = True method = method[4:] if method == 'psinorm': return self.rz2psinorm(*args, **kwargs) elif method == 'phinorm': return self.rz2phinorm(*args, **kwargs) elif method == 'volnorm': return self.rz2volnorm(*args, **kwargs) elif method == 'Rmid': return self.rz2rmid(*args, **kwargs) elif method == 'r/a': kwargs['rho'] = True return self.rz2rmid(*args, **kwargs) elif method == 'q': return self.rz2q(*args, **kwargs) elif method == 'F': return self.rz2F(*args, **kwargs) elif method == 'FFPrime': return self.rz2FFPrime(*args, **kwargs) elif method == 'p': return self.rz2p(*args, **kwargs) elif method == 'pprime': return self.rz2pprime(*args, **kwargs) elif method == 'v': return self.rz2v(*args, **kwargs) else: raise ValueError( "rz2rho: Unsupported normalized coordinate method '%s'!" % method )
[docs] def rmid2roa( self, R_mid, t, each_t=True, return_t=False, sqrt=False, blob=None, length_unit=1 ): """Convert the passed (R_mid, t) coordinates into r/a. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to r/a. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of r/a. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `roa` or (`roa`, `time_idxs`) * **roa** (`Array or scalar float`) - Normalized midplane minor radius. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `roa`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single r/a value at R_mid=0.6m, t=0.26s:: roa_val = Eq_instance.rmid2roa(0.6, 0.26) Find roa values at R_mid points 0.6m and 0.8m at the single time t=0.26s.:: roa_arr = Eq_instance.rmid2roa([0.6, 0.8], 0.26) Find roa values at R_mid of 0.6m at times t=[0.2s, 0.3s]:: roa_arr = Eq_instance.rmid2roa(0.6, [0.2, 0.3]) Find r/a values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: roa_arr = Eq_instance.rmid2roa([0.6, 0.5], [0.2, 0.3], each_t=False) """ # TODO: Make this map inboard to outboard! # It looks like this is never actually called with pre-computed time # indices internally, so I am going to not support that functionality # for now. if blob is not None: raise NotImplementedError("Passing of time indices not supported!") ( R_mid, dum, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( R_mid, R_mid, t, make_grid=False, each_t=each_t, length_unit=length_unit, compute_unique=False, convert_only=True ) if self._tricubic: roa = self._rmid2roa(R_mid, t).reshape(original_shape) else: if single_time: roa = self._rmid2roa(R_mid, time_idxs[0]) if single_val: roa = roa[0] else: roa = roa.reshape(original_shape) elif each_t: roa = scipy.zeros( scipy.concatenate( ([len(time_idxs), ], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): roa[idx] = self._rmid2roa( R_mid, t_idx ).reshape(original_shape) else: roa = self._rmid2roa(R_mid, time_idxs).reshape(original_shape) if sqrt: if roa.ndim == 0: if roa < 0: roa = 0.0 else: scipy.place(roa, roa < 0, 0.0) roa = scipy.sqrt(roa) if return_t: if self._tricubic: return roa, (t, single_time, single_val, original_shape) else: return roa, ( time_idxs, unique_idxs, single_time, single_val, original_shape ) else: return roa
[docs] def rmid2psinorm(self, R_mid, t, **kwargs): """Calculates the normalized poloidal flux corresponding to the passed R_mid (mapped outboard midplane major radius) values. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to psinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of psinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `psinorm` or (`psinorm`, `time_idxs`) * **psinorm** (`Array or scalar float`) - Normalized poloidal flux. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `psinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value for Rmid=0.7m, t=0.26s:: psinorm_val = Eq_instance.rmid2psinorm(0.7, 0.26) Find psinorm values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: psinorm_arr = Eq_instance.rmid2psinorm([0.5, 0.7], 0.26) Find psinorm values at R_mid=0.5m at times t=[0.2s, 0.3s]:: psinorm_arr = Eq_instance.rmid2psinorm(0.5, [0.2, 0.3]) Find psinorm values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: psinorm_arr = Eq_instance.rmid2psinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan( self._getRmidToPsiNormSpline, R_mid, t, check_space=True, **kwargs )
[docs] def rmid2phinorm(self, *args, **kwargs): r"""Calculates the normalized toroidal flux. Uses the definitions: .. math:: \texttt{phi} &= \int q(\psi)\,d\psi \texttt{phi\_norm} &= \frac{\phi}{\phi(a)} This is based on the IDL version efit_rz2rho.pro by Steve Wolfe. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to phinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of phinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `phinorm` or (`phinorm`, `time_idxs`) * **phinorm** (`Array or scalar float`) - Normalized toroidal flux. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `phinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single phinorm value at R_mid=0.6m, t=0.26s:: phi_val = Eq_instance.rmid2phinorm(0.6, 0.26) Find phinorm values at R_mid points 0.6m and 0.8m at the single time t=0.26s:: phi_arr = Eq_instance.rmid2phinorm([0.6, 0.8], 0.26) Find phinorm values at R_mid point 0.6m at times t=[0.2s, 0.3s]:: phi_arr = Eq_instance.rmid2phinorm(0.6, [0.2, 0.3]) Find phinorm values at (R, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: phi_arr = Eq_instance.rmid2phinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getPhiNormSpline, *args, **kwargs)
[docs] def rmid2volnorm(self, *args, **kwargs): """Calculates the normalized flux surface volume. Based on the IDL version efit_rz2rho.pro by Steve Wolfe. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to volnorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of volnorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `volnorm` or (`volnorm`, `time_idxs`) * **volnorm** (`Array or scalar float`) - Normalized volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `volnorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single volnorm value at R_mid=0.6m, t=0.26s:: vol_val = Eq_instance.rmid2volnorm(0.6, 0.26) Find volnorm values at R_mid points 0.6m and 0.8m at the single time t=0.26s:: vol_arr = Eq_instance.rmid2volnorm([0.6, 0.8], 0.26) Find volnorm values at R_mid points 0.6m at times t=[0.2s, 0.3s]:: vol_arr = Eq_instance.rmid2volnorm(0.6, [0.2, 0.3]) Find volnorm values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: vol_arr = Eq_instance.rmid2volnorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getVolNormSpline, *args, **kwargs)
[docs] def rmid2rho(self, method, R_mid, t, **kwargs): r"""Convert the passed (R_mid, t) coordinates into one of several coordinates. Args: method (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= psinorm Normalized poloidal flux phinorm Normalized toroidal flux volnorm Normalized volume r/a Normalized minor radius F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to rho. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of rho. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at R_mid=0.6m, t=0.26s:: psi_val = Eq_instance.rmid2rho('psinorm', 0.6, 0.26) Find psinorm values at R_mid points 0.6m and 0.8m at the single time t=0.26s.:: psi_arr = Eq_instance.rmid2rho('psinorm', [0.6, 0.8], 0.26) Find psinorm values at R_mid of 0.6m at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.rmid2rho('psinorm', 0.6, [0.2, 0.3]) Find psinorm values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: psi_arr = Eq_instance.rmid2rho('psinorm', [0.6, 0.5], [0.2, 0.3], each_t=False) """ if method.startswith('sqrt'): kwargs['sqrt'] = True method = method[4:] if method == 'psinorm': return self.rmid2psinorm(R_mid, t, **kwargs) elif method == 'r/a': return self.rmid2roa(R_mid, t, **kwargs) elif method == 'phinorm': return self.rmid2phinorm(R_mid, t, **kwargs) elif method == 'volnorm': return self.rmid2volnorm(R_mid, t, **kwargs) elif method == 'q': return self.rmid2q(R_mid, t, **kwargs) elif method == 'F': return self.rmid2F(R_mid, t, **kwargs) elif method == 'FFPrime': return self.rmid2FFPrime(R_mid, t, **kwargs) elif method == 'p': return self.rmid2p(R_mid, t, **kwargs) elif method == 'pprime': return self.rmid2pprime(R_mid, t, **kwargs) elif method == 'v': return self.rmid2v(R_mid, t, **kwargs) else: # Default back to the old kludge that wastes time in rz2psi: # TODO: This doesn't handle length units properly! Z_mid = self.getMagZSpline()(t) if kwargs.get('each_t', True): # Need to override the default in _processRZt, since we are doing # the shaping here: kwargs['each_t'] = False try: iter(t) except TypeError: # For a single t, there will only be a single value of Z_mid and # we only need to make it have the same shape as R_mid. Note # that ones_like appears to be clever enough to handle the case # of a scalar R_mid. Z_mid = Z_mid * scipy.ones_like(R_mid, dtype=float) else: # For multiple t, we need to repeat R_mid for every t, then # repeat the corresponding Z_mid that many times for each such # entry. t = scipy.asarray(t) if t.ndim != 1: raise ValueError( "rmid2rho: When using the each_t keyword, " "t must have only one dimension." ) R_mid = scipy.tile( R_mid, scipy.concatenate( ( [len(t), ], scipy.ones_like( scipy.shape(R_mid), dtype=float ) ) ) # may need to be declared as ints ) # TODO: Is there a clever way to do this without a loop? Z_mid_temp = scipy.ones_like(R_mid, dtype=float) t_temp = scipy.ones_like(R_mid, dtype=float) for k in range(0, len(Z_mid)): Z_mid_temp[k] *= Z_mid[k] t_temp[k] *= t[k] Z_mid = Z_mid_temp t = t_temp return self.rz2rho(method, R_mid, Z_mid, t, **kwargs)
[docs] def roa2rmid( self, roa, t, each_t=True, return_t=False, blob=None, length_unit=1 ): """Convert the passed (r/a, t) coordinates into Rmid. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to Rmid. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `Rmid` or (`Rmid`, `time_idxs`) * **Rmid** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `Rmid`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single R_mid value at r/a=0.6, t=0.26s:: R_mid_val = Eq_instance.roa2rmid(0.6, 0.26) Find R_mid values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: R_mid_arr = Eq_instance.roa2rmid([0.6, 0.8], 0.26) Find R_mid values at r/a of 0.6 at times t=[0.2s, 0.3s]:: R_mid_arr = Eq_instance.roa2rmid(0.6, [0.2, 0.3]) Find R_mid values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: R_mid_arr = Eq_instance.roa2rmid([0.6, 0.5], [0.2, 0.3], each_t=False) """ # It looks like this is never actually called with pre-computed time # indices internally, so I am going to not support that functionality # for now. if blob is not None: raise NotImplementedError("Passing of time indices not supported!") ( roa, dum, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( roa, roa, t, make_grid=False, each_t=each_t, length_unit=length_unit, compute_unique=False, check_space=False ) if self._tricubic: R_mid = self._roa2rmid(roa, t).reshape(original_shape) else: if single_time: R_mid = self._roa2rmid(roa, time_idxs[0]) if single_val: R_mid = R_mid[0] else: R_mid = R_mid.reshape(original_shape) elif each_t: R_mid = scipy.zeros( scipy.concatenate( ([len(time_idxs), ], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): R_mid[idx] = self._roa2rmid( roa, t_idx ).reshape(original_shape) else: R_mid = self._roa2rmid(roa, time_idxs).reshape(original_shape) R_mid *= self._getLengthConversionFactor('m', length_unit) if return_t: if self._tricubic: return R_mid, (t, single_time, single_val, original_shape) else: return R_mid, ( time_idxs, unique_idxs, single_time, single_val, original_shape ) else: return R_mid
[docs] def roa2psinorm(self, *args, **kwargs): """Convert the passed (r/a, t) coordinates into psinorm. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to psinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of psinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `psinorm` or (`psinorm`, `time_idxs`) * **psinorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `psinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at r/a=0.6, t=0.26s:: psinorm_val = Eq_instance.roa2psinorm(0.6, 0.26) Find psinorm values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: psinorm_arr = Eq_instance.roa2psinorm([0.6, 0.8], 0.26) Find psinorm values at r/a of 0.6 at times t=[0.2s, 0.3s]:: psinorm_arr = Eq_instance.roa2psinorm(0.6, [0.2, 0.3]) Find psinorm values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: psinorm_arr = Eq_instance.roa2psinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('psinorm', *args, **kwargs)
[docs] def roa2phinorm(self, *args, **kwargs): """Convert the passed (r/a, t) coordinates into phinorm. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to phinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of phinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `phinorm` or (`phinorm`, `time_idxs`) * **phinorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `phinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single phinorm value at r/a=0.6, t=0.26s:: phinorm_val = Eq_instance.roa2phinorm(0.6, 0.26) Find phinorm values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: phinorm_arr = Eq_instance.roa2phinorm([0.6, 0.8], 0.26) Find phinorm values at r/a of 0.6 at times t=[0.2s, 0.3s]:: phinorm_arr = Eq_instance.roa2phinorm(0.6, [0.2, 0.3]) Find phinorm values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: phinorm_arr = Eq_instance.roa2phinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('phinorm', *args, **kwargs)
[docs] def roa2volnorm(self, *args, **kwargs): """Convert the passed (r/a, t) coordinates into volnorm. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to volnorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of volnorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `volnorm` or (`volnorm`, `time_idxs`) * **volnorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `volnorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single volnorm value at r/a=0.6, t=0.26s:: volnorm_val = Eq_instance.roa2volnorm(0.6, 0.26) Find volnorm values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: volnorm_arr = Eq_instance.roa2volnorm([0.6, 0.8], 0.26) Find volnorm values at r/a of 0.6 at times t=[0.2s, 0.3s]:: volnorm_arr = Eq_instance.roa2volnorm(0.6, [0.2, 0.3]) Find volnorm values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: volnorm_arr = Eq_instance.roa2volnorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('volnorm', *args, **kwargs)
[docs] def roa2rho(self, method, *args, **kwargs): r"""Convert the passed (r/a, t) coordinates into one of several coordinates. Args: method (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= psinorm Normalized poloidal flux phinorm Normalized toroidal flux volnorm Normalized volume Rmid Midplane major radius q Safety factor F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. roa (Array-like or scalar float): Values of the normalized minor radius to map to rho. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of rho. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at r/a=0.6, t=0.26s:: psi_val = Eq_instance.roa2rho('psinorm', 0.6, 0.26) Find psinorm values at r/a points 0.6 and 0.8 at the single time t=0.26s:: psi_arr = Eq_instance.roa2rho('psinorm', [0.6, 0.8], 0.26) Find psinorm values at r/a of 0.6 at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.roa2rho('psinorm', 0.6, [0.2, 0.3]) Find psinorm values at (r/a, t) points (0.6, 0.2s) and (0.5, 0.3s):: psi_arr = Eq_instance.roa2rho('psinorm', [0.6, 0.5], [0.2, 0.3], each_t=False) """ if method == 'Rmid': return self.roa2rmid(*args, **kwargs) else: kwargs['convert_roa'] = True return self.rmid2rho(method, *args, **kwargs)
[docs] def psinorm2rmid(self, psi_norm, t, **kwargs): """Calculates the outboard R_mid location corresponding to the passed psinorm (normalized poloidal flux) values. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to Rmid. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of Rmid. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `Rmid` or (`Rmid`, `time_idxs`) * **Rmid** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `Rmid`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single R_mid value for psinorm=0.7, t=0.26s:: R_mid_val = Eq_instance.psinorm2rmid(0.7, 0.26) Find R_mid values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: R_mid_arr = Eq_instance.psinorm2rmid([0.5, 0.7], 0.26) Find R_mid values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: R_mid_arr = Eq_instance.psinorm2rmid(0.5, [0.2, 0.3]) Find R_mid values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: R_mid_arr = Eq_instance.psinorm2rmid([0.6, 0.5], [0.2, 0.3], each_t=False) """ # Convert units from meters to desired target but keep units consistent # with rho keyword: if kwargs.get('rho', False): unit_factor = 1 else: unit_factor = self._getLengthConversionFactor( 'm', kwargs.get('length_unit', 1) ) return unit_factor * self._psinorm2Quan( self._getRmidSpline, psi_norm, t, **kwargs )
[docs] def psinorm2roa(self, psi_norm, t, **kwargs): """Calculates the normalized minor radius location corresponding to the passed psi_norm (normalized poloidal flux) values. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to r/a. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of r/a. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `roa` or (`roa`, `time_idxs`) * **roa** (`Array or scalar float`) - Normalized midplane minor radius. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `roa`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single r/a value for psinorm=0.7, t=0.26s:: roa_val = Eq_instance.psinorm2roa(0.7, 0.26) Find r/a values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: roa_arr = Eq_instance.psinorm2roa([0.5, 0.7], 0.26) Find r/a values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: roa_arr = Eq_instance.psinorm2roa(0.5, [0.2, 0.3]) Find r/a values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: roa_arr = Eq_instance.psinorm2roa([0.6, 0.5], [0.2, 0.3], each_t=False) """ kwargs['rho'] = True return self._psinorm2Quan(self._getRmidSpline, psi_norm, t, **kwargs)
[docs] def psinorm2volnorm(self, psi_norm, t, **kwargs): """Calculates the normalized volume corresponding to the passed psi_norm (normalized poloidal flux) values. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to volnorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of volnorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `volnorm` or (`volnorm`, `time_idxs`) * **volnorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `volnorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single volnorm value for psinorm=0.7, t=0.26s:: volnorm_val = Eq_instance.psinorm2volnorm(0.7, 0.26) Find volnorm values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: volnorm_arr = Eq_instance.psinorm2volnorm([0.5, 0.7], 0.26) Find volnorm values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: volnorm_arr = Eq_instance.psinorm2volnorm(0.5, [0.2, 0.3]) Find volnorm values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: volnorm_arr = Eq_instance.psinorm2volnorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan( self._getVolNormSpline, psi_norm, t, **kwargs )
[docs] def psinorm2phinorm(self, psi_norm, t, **kwargs): """Calculates the normalized toroidal flux corresponding to the passed psi_norm (normalized poloidal flux) values. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to phinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of phinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `phinorm` or (`phinorm`, `time_idxs`) * **phinorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `phinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single phinorm value for psinorm=0.7, t=0.26s:: phinorm_val = Eq_instance.psinorm2phinorm(0.7, 0.26) Find phinorm values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: phinorm_arr = Eq_instance.psinorm2phinorm([0.5, 0.7], 0.26) Find phinorm values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: phinorm_arr = Eq_instance.psinorm2phinorm(0.5, [0.2, 0.3]) Find phinorm values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: phinorm_arr = Eq_instance.psinorm2phinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getPhiNormSpline, psi_norm, t, **kwargs)
[docs] def psinorm2rho(self, method, *args, **kwargs): r"""Convert the passed (psinorm, t) coordinates into one of several coordinates. Args: method (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= phinorm Normalized toroidal flux volnorm Normalized volume Rmid Midplane major radius r/a Normalized minor radius q Safety factor F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to rho. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of rho. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Raises: ValueError: If `method` is not one of the supported values. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single phinorm value at psinorm=0.6, t=0.26s:: phi_val = Eq_instance.psinorm2rho('phinorm', 0.6, 0.26) Find phinorm values at phinorm of 0.6 and 0.8 at the single time t=0.26s:: phi_arr = Eq_instance.psinorm2rho('phinorm', [0.6, 0.8], 0.26) Find phinorm values at psinorm of 0.6 at times t=[0.2s, 0.3s]:: phi_arr = Eq_instance.psinorm2rho('phinorm', 0.6, [0.2, 0.3]) Find phinorm values at (psinorm, t) points (0.6, 0.2s) and (0.5m, 0.3s):: phi_arr = Eq_instance.psinorm2rho('phinorm', [0.6, 0.5], [0.2, 0.3], each_t=False) """ if method.startswith('sqrt'): kwargs['sqrt'] = True method = method[4:] if method == 'phinorm': return self.psinorm2phinorm(*args, **kwargs) elif method == 'volnorm': return self.psinorm2volnorm(*args, **kwargs) elif method == 'Rmid': return self.psinorm2rmid(*args, **kwargs) elif method == 'r/a': kwargs['rho'] = True return self.psinorm2rmid(*args, **kwargs) elif method == 'q': return self.psinorm2q(*args, **kwargs) elif method == 'F': return self.psinorm2F(*args, **kwargs) elif method == 'FFPrime': return self.psinorm2FFPrime(*args, **kwargs) elif method == 'p': return self.psinorm2p(*args, **kwargs) elif method == 'pprime': return self.psinorm2pprime(*args, **kwargs) elif method == 'v': return self.psinorm2v(*args, **kwargs) else: raise ValueError( "psinorm2rho: Unsupported normalized coordinate method '%s'!" % method )
[docs] def phinorm2psinorm(self, phinorm, t, **kwargs): """Calculates the normalized poloidal flux corresponding to the passed phinorm (normalized toroidal flux) values. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to psinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of psinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `psinorm` or (`psinorm`, `time_idxs`) * **psinorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `psinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value for phinorm=0.7, t=0.26s:: psinorm_val = Eq_instance.phinorm2psinorm(0.7, 0.26) Find psinorm values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: psinorm_arr = Eq_instance.phinorm2psinorm([0.5, 0.7], 0.26) Find psinorm values at phinorm=0.5 at times t=[0.2s, 0.3s]:: psinorm_arr = Eq_instance.phinorm2psinorm(0.5, [0.2, 0.3]) Find psinorm values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: psinorm_arr = Eq_instance.phinorm2psinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan( self._getPhiNormToPsiNormSpline, phinorm, t, **kwargs )
[docs] def phinorm2volnorm(self, *args, **kwargs): """Calculates the normalized flux surface volume corresponding to the passed phinorm (normalized toroidal flux) values. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to volnorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of volnorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `volnorm` or (`volnorm`, `time_idxs`) * **volnorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `volnorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single volnorm value for phinorm=0.7, t=0.26s:: volnorm_val = Eq_instance.phinorm2volnorm(0.7, 0.26) Find volnorm values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: volnorm_arr = Eq_instance.phinorm2volnorm([0.5, 0.7], 0.26) Find volnorm values at phinorm=0.5 at times t=[0.2s, 0.3s]:: volnorm_arr = Eq_instance.phinorm2volnorm(0.5, [0.2, 0.3]) Find volnorm values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: volnorm_arr = Eq_instance.phinorm2volnorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getVolNormSpline, *args, **kwargs)
[docs] def phinorm2rmid(self, *args, **kwargs): """Calculates the mapped outboard midplane major radius corresponding to the passed phinorm (normalized toroidal flux) values. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to Rmid. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of Rmid. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `Rmid` or (`Rmid`, `time_idxs`) * **Rmid** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `Rmid`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single Rmid value for phinorm=0.7, t=0.26s:: Rmid_val = Eq_instance.phinorm2rmid(0.7, 0.26) Find Rmid values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: Rmid_arr = Eq_instance.phinorm2rmid([0.5, 0.7], 0.26) Find Rmid values at phinorm=0.5 at times t=[0.2s, 0.3s]:: Rmid_arr = Eq_instance.phinorm2rmid(0.5, [0.2, 0.3]) Find Rmid values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: Rmid_arr = Eq_instance.phinorm2rmid([0.6, 0.5], [0.2, 0.3], each_t=False) """ # Convert units from meters to desired target but keep units consistent # with rho keyword: if kwargs.get('rho', False): unit_factor = 1 else: unit_factor = self._getLengthConversionFactor( 'm', kwargs.get('length_unit', 1) ) return unit_factor * self._phinorm2Quan( self._getRmidSpline, *args, **kwargs )
[docs] def phinorm2roa(self, phi_norm, t, **kwargs): """Calculates the normalized minor radius corresponding to the passed phinorm (normalized toroidal flux) values. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to r/a. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of r/a. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `roa` or (`roa`, `time_idxs`) * **roa** (`Array or scalar float`) - Normalized midplane minor radius. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `roa`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single r/a value for phinorm=0.7, t=0.26s:: roa_val = Eq_instance.phinorm2roa(0.7, 0.26) Find r/a values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: roa_arr = Eq_instance.phinorm2roa([0.5, 0.7], 0.26) Find r/a values at phinorm=0.5 at times t=[0.2s, 0.3s]:: roa_arr = Eq_instance.phinorm2roa(0.5, [0.2, 0.3]) Find r/a values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: roa_arr = Eq_instance.phinorm2roa([0.6, 0.5], [0.2, 0.3], each_t=False) """ kwargs['rho'] = True return self._phinorm2Quan(self._getRmidSpline, phi_norm, t, **kwargs)
[docs] def phinorm2rho(self, method, *args, **kwargs): r"""Convert the passed (phinorm, t) coordinates into one of several coordinates. Args: method (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= psinorm Normalized poloidal flux volnorm Normalized volume Rmid Midplane major radius r/a Normalized minor radius q Safety factor F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to rho. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of rho. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Raises: ValueError: If `method` is not one of the supported values. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at phinorm=0.6, t=0.26s:: psi_val = Eq_instance.phinorm2rho('psinorm', 0.6, 0.26) Find psinorm values at phinorm of 0.6 and 0.8 at the single time t=0.26s:: psi_arr = Eq_instance.phinorm2rho('psinorm', [0.6, 0.8], 0.26) Find psinorm values at phinorm of 0.6 at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.phinorm2rho('psinorm', 0.6, [0.2, 0.3]) Find psinorm values at (phinorm, t) points (0.6, 0.2s) and (0.5m, 0.3s):: psi_arr = Eq_instance.phinorm2rho('psinorm', [0.6, 0.5], [0.2, 0.3], each_t=False) """ if method.startswith('sqrt'): kwargs['sqrt'] = True method = method[4:] if method == 'psinorm': return self.phinorm2psinorm(*args, **kwargs) elif method == 'volnorm': return self.phinorm2volnorm(*args, **kwargs) elif method == 'Rmid': return self.phinorm2rmid(*args, **kwargs) elif method == 'r/a': return self.phinorm2roa(*args, **kwargs) elif method == 'q': return self.phinorm2q(*args, **kwargs) elif method == 'F': return self.phinorm2F(*args, **kwargs) elif method == 'FFPrime': return self.phinorm2FFPrime(*args, **kwargs) elif method == 'p': return self.phinorm2p(*args, **kwargs) elif method == 'pprime': return self.phinorm2pprime(*args, **kwargs) elif method == 'v': return self.phinorm2v(*args, **kwargs) else: raise ValueError( "phinorm2rho: Unsupported normalized coordinate method '%s'!" % method )
[docs] def volnorm2psinorm(self, *args, **kwargs): """Calculates the normalized poloidal flux corresponding to the passed volnorm (normalized flux surface volume) values. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to psinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of psinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `psinorm` or (`psinorm`, `time_idxs`) * **psinorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `psinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value for volnorm=0.7, t=0.26s:: psinorm_val = Eq_instance.volnorm2psinorm(0.7, 0.26) Find psinorm values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: psinorm_arr = Eq_instance.volnorm2psinorm([0.5, 0.7], 0.26) Find psinorm values at volnorm=0.5 at times t=[0.2s, 0.3s]:: psinorm_arr = Eq_instance.volnorm2psinorm(0.5, [0.2, 0.3]) Find psinorm values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: psinorm_arr = Eq_instance.volnorm2psinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan( self._getVolNormToPsiNormSpline, *args, **kwargs )
[docs] def volnorm2phinorm(self, *args, **kwargs): """Calculates the normalized toroidal flux corresponding to the passed volnorm (normalized flux surface volume) values. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to phinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of phinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `phinorm` or (`phinorm`, `time_idxs`) * **phinorm** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `phinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single phinorm value for volnorm=0.7, t=0.26s:: phinorm_val = Eq_instance.volnorm2phinorm(0.7, 0.26) Find phinorm values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: phinorm_arr = Eq_instance.volnorm2phinorm([0.5, 0.7], 0.26) Find phinorm values at volnorm=0.5 at times t=[0.2s, 0.3s]:: phinorm_arr = Eq_instance.volnorm2phinorm(0.5, [0.2, 0.3]) Find phinorm values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: phinorm_arr = Eq_instance.volnorm2phinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getPhiNormSpline, *args, **kwargs)
[docs] def volnorm2rmid(self, *args, **kwargs): """Calculates the mapped outboard midplane major radius corresponding to the passed volnorm (normalized flux surface volume) values. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to Rmid. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of Rmid. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `Rmid` or (`Rmid`, `time_idxs`) * **Rmid** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `Rmid`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single Rmid value for volnorm=0.7, t=0.26s:: Rmid_val = Eq_instance.volnorm2rmid(0.7, 0.26) Find Rmid values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: Rmid_arr = Eq_instance.volnorm2rmid([0.5, 0.7], 0.26) Find Rmid values at volnorm=0.5 at times t=[0.2s, 0.3s]:: Rmid_arr = Eq_instance.volnorm2rmid(0.5, [0.2, 0.3]) Find Rmid values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: Rmid_arr = Eq_instance.volnorm2rmid([0.6, 0.5], [0.2, 0.3], each_t=False) """ # Convert units from meters to desired target but keep units consistent # with rho keyword: if kwargs.get('rho', False): unit_factor = 1 else: unit_factor = self._getLengthConversionFactor( 'm', kwargs.get('length_unit', 1) ) return unit_factor * self._volnorm2Quan( self._getRmidSpline, *args, **kwargs )
[docs] def volnorm2roa(self, *args, **kwargs): """Calculates the normalized minor radius corresponding to the passed volnorm (normalized flux surface volume) values. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to r/a. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of r/a. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `roa` or (`roa`, `time_idxs`) * **roa** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `roa`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single r/a value for volnorm=0.7, t=0.26s:: roa_val = Eq_instance.volnorm2roa(0.7, 0.26) Find r/a values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: roa_arr = Eq_instance.volnorm2roa([0.5, 0.7], 0.26) Find r/a values at volnorm=0.5 at times t=[0.2s, 0.3s]:: roa_arr = Eq_instance.volnorm2roa(0.5, [0.2, 0.3]) Find r/a values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: roa_arr = Eq_instance.volnorm2roa([0.6, 0.5], [0.2, 0.3], each_t=False) """ kwargs['rho'] = True return self._volnorm2Quan(self._getRmidSpline, *args, **kwargs)
[docs] def volnorm2rho(self, method, *args, **kwargs): r"""Convert the passed (volnorm, t) coordinates into one of several coordinates. Args: method (String): Indicates which coordinates to convert to. Valid options are: ======= ================================= psinorm Normalized poloidal flux phinorm Normalized toroidal flux Rmid Midplane major radius r/a Normalized minor radius q Safety factor F Flux function :math:`F=RB_{\phi}` FFPrime Flux function :math:`FF'` p Pressure pprime Pressure gradient v Flux surface volume ======= ================================= Additionally, each valid option may be prepended with 'sqrt' to specify the square root of the desired unit. volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to rho. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of rho. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). length_unit (String or 1): Length unit that `Rmid` is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). Returns: `rho` or (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted coordinates. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Raises: ValueError: If `method` is not one of the supported values. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value at volnorm=0.6, t=0.26s:: psi_val = Eq_instance.volnorm2rho('psinorm', 0.6, 0.26) Find psinorm values at volnorm of 0.6 and 0.8 at the single time t=0.26s:: psi_arr = Eq_instance.volnorm2rho('psinorm', [0.6, 0.8], 0.26) Find psinorm values at volnorm of 0.6 at times t=[0.2s, 0.3s]:: psi_arr = Eq_instance.volnorm2rho('psinorm', 0.6, [0.2, 0.3]) Find psinorm values at (volnorm, t) points (0.6, 0.2s) and (0.5m, 0.3s):: psi_arr = Eq_instance.volnorm2rho('psinorm', [0.6, 0.5], [0.2, 0.3], each_t=False) """ if method.startswith('sqrt'): kwargs['sqrt'] = True method = method[4:] if method == 'psinorm': return self.volnorm2psinorm(*args, **kwargs) elif method == 'phinorm': return self.volnorm2phinorm(*args, **kwargs) elif method == 'Rmid': return self.volnorm2rmid(*args, **kwargs) elif method == 'r/a': return self.volnorm2roa(*args, **kwargs) elif method == 'q': return self.volnorm2q(*args, **kwargs) elif method == 'F': return self.volnorm2F(*args, **kwargs) elif method == 'FFPrime': return self.volnorm2FFPrime(*args, **kwargs) elif method == 'p': return self.volnorm2p(*args, **kwargs) elif method == 'pprime': return self.volnorm2pprime(*args, **kwargs) elif method == 'v': return self.volnorm2v(*args, **kwargs) else: raise ValueError( "volnorm2rho: Unsupported normalized coordinate method '%s'!" % method )
################################## # Profile interpolation routines # ################################## # Safety factor ("q") profile:
[docs] def rz2q(self, R, Z, t, **kwargs): r"""Calculates the safety factor ("q") at the given (R, Z, t). By default, EFIT only computes this inside the LCFS. Args: R (Array-like or scalar float): Values of the radial coordinate to map to q. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to q. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of q. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`q`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `q` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `q`). Returns: `q` or (`q`, `time_idxs`) * **q** (`Array or scalar float`) - The safety factor ("q"). If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `q` has this shape as well, unless the `make_grid` keyword was True, in which case `q` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `q`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single q value at R=0.6m, Z=0.0m, t=0.26s:: q_val = Eq_instance.rz2q(0.6, 0, 0.26) Find q values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: q_arr = Eq_instance.rz2q([0.6, 0.8], [0, 0], 0.26) Find q values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: q_arr = Eq_instance.rz2q(0.6, 0, [0.2, 0.3]) Find q values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: q_arr = Eq_instance.rz2q([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find q values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: q_mat = Eq_instance.rz2q(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getQSpline, R, Z, t, **kwargs)
[docs] def rmid2q(self, R_mid, t, **kwargs): """Calculates the safety factor ("q") corresponding to the passed R_mid (mapped outboard midplane major radius) values. By default, EFIT only computes this inside the LCFS. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to q. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of q. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`q`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `q` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `q`). Returns: `q` or (`q`, `time_idxs`) * **q** (`Array or scalar float`) - The safety factor ("q"). If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `q`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single q value for Rmid=0.7m, t=0.26s:: q_val = Eq_instance.rmid2q(0.7, 0.26) Find q values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: q_arr = Eq_instance.rmid2q([0.5, 0.7], 0.26) Find q values at R_mid=0.5m at times t=[0.2s, 0.3s]:: q_arr = Eq_instance.rmid2q(0.5, [0.2, 0.3]) Find q values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: q_arr = Eq_instance.rmid2q([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getQSpline, R_mid, t, **kwargs)
[docs] def roa2q(self, roa, t, **kwargs): """Convert the passed (r/a, t) coordinates into safety factor ("q"). By default, EFIT only computes this inside the LCFS. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to q. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of q. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`q`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `q` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `q`). Returns: `q` or (`q`, `time_idxs`) * **q** (`Array or scalar float`) - The safety factor ("q"). If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `q`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single q value at r/a=0.6, t=0.26s:: q_val = Eq_instance.roa2q(0.6, 0.26) Find q values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: q_arr = Eq_instance.roa2q([0.6, 0.8], 0.26) Find q values at r/a of 0.6 at times t=[0.2s, 0.3s]:: q_arr = Eq_instance.roa2q(0.6, [0.2, 0.3]) Find q values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: q_arr = Eq_instance.roa2q([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('q', roa, t, **kwargs)
[docs] def psinorm2q(self, psinorm, t, **kwargs): """Calculates the safety factor ("q") corresponding to the passed psi_norm (normalized poloidal flux) values. By default, EFIT only computes this inside the LCFS. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to q. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of q. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`q`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `q` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `q`). Returns: `q` or (`q`, `time_idxs`) * **q** (`Array or scalar float`) - The safety factor ("q"). If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `q`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single q value for psinorm=0.7, t=0.26s:: q_val = Eq_instance.psinorm2q(0.7, 0.26) Find q values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: q_arr = Eq_instance.psinorm2q([0.5, 0.7], 0.26) Find q values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: q_arr = Eq_instance.psinorm2q(0.5, [0.2, 0.3]) Find q values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: q_arr = Eq_instance.psinorm2q([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getQSpline, psinorm, t, **kwargs)
[docs] def phinorm2q(self, phinorm, t, **kwargs): """Calculates the safety factor ("q") corresponding to the passed phinorm (normalized toroidal flux) values. By default, EFIT only computes this inside the LCFS. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to q. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of q. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`q`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `q` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `q`). Returns: `q` or (`q`, `time_idxs`) * **q** (`Array or scalar float`) - The safety factor ("q"). If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `q`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single q value for phinorm=0.7, t=0.26s:: q_val = Eq_instance.phinorm2q(0.7, 0.26) Find q values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: q_arr = Eq_instance.phinorm2q([0.5, 0.7], 0.26) Find q values at phinorm=0.5 at times t=[0.2s, 0.3s]:: q_arr = Eq_instance.phinorm2q(0.5, [0.2, 0.3]) Find q values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: q_arr = Eq_instance.phinorm2q([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getQSpline, phinorm, t, **kwargs)
[docs] def volnorm2q(self, volnorm, t, **kwargs): """Calculates the safety factor ("q") corresponding to the passed volnorm (normalized flux surface volume) values. By default, EFIT only computes this inside the LCFS. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to q. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of q. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`q`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `q` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `q`). Returns: `q` or (`q`, `time_idxs`) * **q** (`Array or scalar float`) - The safety factor ("q"). If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `q`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single q value for volnorm=0.7, t=0.26s:: q_val = Eq_instance.volnorm2q(0.7, 0.26) Find q values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: q_arr = Eq_instance.volnorm2q([0.5, 0.7], 0.26) Find q values at volnorm=0.5 at times t=[0.2s, 0.3s]:: q_arr = Eq_instance.volnorm2q(0.5, [0.2, 0.3]) Find q values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: q_arr = Eq_instance.volnorm2q([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getQSpline, volnorm, t, **kwargs)
# Flux function ("F") profile:
[docs] def rz2F(self, R, Z, t, **kwargs): r"""Calculates the flux function :math:`F=RB_{\phi}` at the given (R, Z, t). By default, EFIT only computes this inside the LCFS. Args: R (Array-like or scalar float): Values of the radial coordinate to map to F. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to F. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of F. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`F`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `F` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `F`). Returns: `F` or (`F`, `time_idxs`) * **F** (`Array or scalar float`) - The flux function :math:`F=RB_{\phi}`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `F` has this shape as well, unless the `make_grid` keyword was True, in which case `F` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `F`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single F value at R=0.6m, Z=0.0m, t=0.26s:: F_val = Eq_instance.rz2F(0.6, 0, 0.26) Find F values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: F_arr = Eq_instance.rz2F([0.6, 0.8], [0, 0], 0.26) Find F values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: F_arr = Eq_instance.rz2F(0.6, 0, [0.2, 0.3]) Find F values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: F_arr = Eq_instance.rz2F([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find F values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: F_mat = Eq_instance.rz2F(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getFSpline, R, Z, t, **kwargs)
[docs] def rmid2F(self, R_mid, t, **kwargs): r"""Calculates the flux function :math:`F=RB_{\phi}` corresponding to the passed R_mid (mapped outboard midplane major radius) values. By default, EFIT only computes this inside the LCFS. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to F. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of F. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`F`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `F` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `F`). Returns: `F` or (`F`, `time_idxs`) * **F** (`Array or scalar float`) - The flux function :math:`F=RB_{\phi}`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `F`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single F value for Rmid=0.7m, t=0.26s:: F_val = Eq_instance.rmid2F(0.7, 0.26) Find F values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: F_arr = Eq_instance.rmid2F([0.5, 0.7], 0.26) Find F values at R_mid=0.5m at times t=[0.2s, 0.3s]:: F_arr = Eq_instance.rmid2F(0.5, [0.2, 0.3]) Find F values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: F_arr = Eq_instance.rmid2F([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getFSpline, R_mid, t, **kwargs)
[docs] def roa2F(self, roa, t, **kwargs): r"""Convert the passed (r/a, t) coordinates into the flux function :math:`F=RB_{\phi}`. By default, EFIT only computes this inside the LCFS. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to F. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of F. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`F`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `F` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `F`). Returns: `F` or (`F`, `time_idxs`) * **F** (`Array or scalar float`) - The flux function :math:`F=RB_{\phi}`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `F`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single F value at r/a=0.6, t=0.26s:: F_val = Eq_instance.roa2F(0.6, 0.26) Find F values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: F_arr = Eq_instance.roa2F([0.6, 0.8], 0.26) Find F values at r/a of 0.6 at times t=[0.2s, 0.3s]:: F_arr = Eq_instance.roa2F(0.6, [0.2, 0.3]) Find F values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: F_arr = Eq_instance.roa2F([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('F', roa, t, **kwargs)
[docs] def psinorm2F(self, psinorm, t, **kwargs): r"""Calculates the flux function :math:`F=RB_{\phi}` corresponding to the passed psi_norm (normalized poloidal flux) values. By default, EFIT only computes this inside the LCFS. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to F. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of F. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`F`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `F` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `F`). Returns: `F` or (`F`, `time_idxs`) * **F** (`Array or scalar float`) - The flux function :math:`F=RB_{\phi}`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `F`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single F value for psinorm=0.7, t=0.26s:: F_val = Eq_instance.psinorm2F(0.7, 0.26) Find F values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: F_arr = Eq_instance.psinorm2F([0.5, 0.7], 0.26) Find F values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: F_arr = Eq_instance.psinorm2F(0.5, [0.2, 0.3]) Find F values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: F_arr = Eq_instance.psinorm2F([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getFSpline, psinorm, t, **kwargs)
[docs] def phinorm2F(self, phinorm, t, **kwargs): r"""Calculates the flux function :math:`F=RB_{\phi}` corresponding to the passed phinorm (normalized toroidal flux) values. By default, EFIT only computes this inside the LCFS. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to F. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of F. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`F`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `F` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `F`). Returns: `F` or (`F`, `time_idxs`) * **F** (`Array or scalar float`) - The flux function :math:`F=RB_{\phi}`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `F`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single F value for phinorm=0.7, t=0.26s:: F_val = Eq_instance.phinorm2F(0.7, 0.26) Find F values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: F_arr = Eq_instance.phinorm2F([0.5, 0.7], 0.26) Find F values at phinorm=0.5 at times t=[0.2s, 0.3s]:: F_arr = Eq_instance.phinorm2F(0.5, [0.2, 0.3]) Find F values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: F_arr = Eq_instance.phinorm2F([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getFSpline, phinorm, t, **kwargs)
[docs] def volnorm2F(self, volnorm, t, **kwargs): r"""Calculates the flux function :math:`F=RB_{\phi}` corresponding to the passed volnorm (normalized flux surface volume) values. By default, EFIT only computes this inside the LCFS. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to F. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of F. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`F`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `F` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `F`). Returns: `F` or (`F`, `time_idxs`) * **F** (`Array or scalar float`) - The flux function :math:`F=RB_{\phi}`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `F`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single F value for volnorm=0.7, t=0.26s:: F_val = Eq_instance.volnorm2F(0.7, 0.26) Find F values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: F_arr = Eq_instance.volnorm2F([0.5, 0.7], 0.26) Find F values at volnorm=0.5 at times t=[0.2s, 0.3s]:: F_arr = Eq_instance.volnorm2F(0.5, [0.2, 0.3]) Find F values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: F_arr = Eq_instance.volnorm2F([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getFSpline, volnorm, t, **kwargs)
[docs] def Fnorm2psinorm(self, F, t, **kwargs): """Calculates the psinorm (normalized poloidal flux) corresponding to the passed normalized flux function :math:`F=RB_{\phi}` values. This is provided as a convenience method to plot current lines with the correct spacing: current lines launched from a grid uniformly-spaced in Fnorm will have spacing directly proportional to the magnitude. By default, EFIT only computes this inside the LCFS. Furthermore, it is truncated at the radius at which is becomes non-monotonic. Args: F (Array-like or scalar float): Values of F to map to psinorm. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of psinorm. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `F` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `F` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`psinorm`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `psinorm` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `psinorm`). Returns: `psinorm` or (`psinorm`, `time_idxs`) * **psinorm** (`Array or scalar float`) - The normalized poloidal flux. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `psinorm`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single psinorm value for F=0.7, t=0.26s:: psinorm_val = Eq_instance.F2psinorm(0.7, 0.26) Find psinorm values at F values of 0.5 and 0.7 at the single time t=0.26s:: psinorm_arr = Eq_instance.F2psinorm([0.5, 0.7], 0.26) Find psinorm values at F=0.5 at times t=[0.2s, 0.3s]:: psinorm_arr = Eq_instance.F2psinorm(0.5, [0.2, 0.3]) Find psinorm values at (F, t) points (0.6, 0.2s) and (0.5, 0.3s):: psinorm_arr = Eq_instance.F2psinorm([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan( self._getFNormToPsiNormSpline, F, t, **kwargs )
# Flux function ("FF'") profile:
[docs] def rz2FFPrime(self, R, Z, t, **kwargs): r"""Calculates the flux function :math:`FF'` at the given (R, Z, t). By default, EFIT only computes this inside the LCFS. Args: R (Array-like or scalar float): Values of the radial coordinate to map to FFPrime. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to FFPrime. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of FFPrime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`FFPrime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `FFPrime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `FFPrime`). Returns: `FFPrime` or (`FFPrime`, `time_idxs`) * **FFPrime** (`Array or scalar float`) - The flux function :math:`FF'`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `FFPrime` has this shape as well, unless the `make_grid` keyword was True, in which case `FFPrime` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `FFPrime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single FFPrime value at R=0.6m, Z=0.0m, t=0.26s:: FFPrime_val = Eq_instance.rz2FFPrime(0.6, 0, 0.26) Find FFPrime values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: FFPrime_arr = Eq_instance.rz2FFPrime([0.6, 0.8], [0, 0], 0.26) Find FFPrime values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: FFPrime_arr = Eq_instance.rz2FFPrime(0.6, 0, [0.2, 0.3]) Find FFPrime values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: FFPrime_arr = Eq_instance.rz2FFPrime([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find FFPrime values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: FFPrime_mat = Eq_instance.rz2FFPrime(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getFFPrimeSpline, R, Z, t, **kwargs)
[docs] def rmid2FFPrime(self, R_mid, t, **kwargs): r"""Calculates the flux function :math:`FF'` corresponding to the passed R_mid (mapped outboard midplane major radius) values. By default, EFIT only computes this inside the LCFS. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to FFPrime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of FFPrime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`FFPrime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `FFPrime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `FFPrime`). Returns: `FFPrime` or (`FFPrime`, `time_idxs`) * **FFPrime** (`Array or scalar float`) - The flux function :math:`FF'`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `FFPrime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single FFPrime value for Rmid=0.7m, t=0.26s:: FFPrime_val = Eq_instance.rmid2FFPrime(0.7, 0.26) Find FFPrime values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: FFPrime_arr = Eq_instance.rmid2FFPrime([0.5, 0.7], 0.26) Find FFPrime values at R_mid=0.5m at times t=[0.2s, 0.3s]:: FFPrime_arr = Eq_instance.rmid2FFPrime(0.5, [0.2, 0.3]) Find FFPrime values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: FFPrime_arr = Eq_instance.rmid2FFPrime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getFFPrimeSpline, R_mid, t, **kwargs)
[docs] def roa2FFPrime(self, roa, t, **kwargs): r"""Convert the passed (r/a, t) coordinates into the flux function :math:`FF'`. By default, EFIT only computes this inside the LCFS. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to FFPrime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of FFPrime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`FFPrime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `FFPrime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `FFPrime`). Returns: `FFPrime` or (`FFPrime`, `time_idxs`) * **FFPrime** (`Array or scalar float`) - The flux function :math:`FF'`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `FFPrime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single FFPrime value at r/a=0.6, t=0.26s:: FFPrime_val = Eq_instance.roa2FFPrime(0.6, 0.26) Find FFPrime values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: FFPrime_arr = Eq_instance.roa2FFPrime([0.6, 0.8], 0.26) Find FFPrime values at r/a of 0.6 at times t=[0.2s, 0.3s]:: FFPrime_arr = Eq_instance.roa2FFPrime(0.6, [0.2, 0.3]) Find FFPrime values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: FFPrime_arr = Eq_instance.roa2FFPrime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('FFPrime', roa, t, **kwargs)
[docs] def psinorm2FFPrime(self, psinorm, t, **kwargs): r"""Calculates the flux function :math:`FF'` corresponding to the passed psi_norm (normalized poloidal flux) values. By default, EFIT only computes this inside the LCFS. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to FFPrime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of FFPrime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`FFPrime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `FFPrime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `FFPrime`). Returns: `FFPrime` or (`FFPrime`, `time_idxs`) * **FFPrime** (`Array or scalar float`) - The flux function :math:`FF'`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `FFPrime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single FFPrime value for psinorm=0.7, t=0.26s:: FFPrime_val = Eq_instance.psinorm2FFPrime(0.7, 0.26) Find FFPrime values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: FFPrime_arr = Eq_instance.psinorm2FFPrime([0.5, 0.7], 0.26) Find FFPrime values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: FFPrime_arr = Eq_instance.psinorm2FFPrime(0.5, [0.2, 0.3]) Find FFPrime values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: FFPrime_arr = Eq_instance.psinorm2FFPrime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getFFPrimeSpline, psinorm, t, **kwargs)
[docs] def phinorm2FFPrime(self, phinorm, t, **kwargs): r"""Calculates the flux function :math:`FF'` corresponding to the passed phinorm (normalized toroidal flux) values. By default, EFIT only computes this inside the LCFS. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to FFPrime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of FFPrime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`FFPrime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `FFPrime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `FFPrime`). Returns: `FFPrime` or (`FFPrime`, `time_idxs`) * **FFPrime** (`Array or scalar float`) - The flux function :math:`FF'`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `FFPrime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single FFPrime value for phinorm=0.7, t=0.26s:: FFPrime_val = Eq_instance.phinorm2FFPrime(0.7, 0.26) Find FFPrime values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: FFPrime_arr = Eq_instance.phinorm2FFPrime([0.5, 0.7], 0.26) Find FFPrime values at phinorm=0.5 at times t=[0.2s, 0.3s]:: FFPrime_arr = Eq_instance.phinorm2FFPrime(0.5, [0.2, 0.3]) Find FFPrime values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: FFPrime_arr = Eq_instance.phinorm2FFPrime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getFFPrimeSpline, phinorm, t, **kwargs)
[docs] def volnorm2FFPrime(self, volnorm, t, **kwargs): """Calculates the flux function :math:`FF'` corresponding to the passed volnorm (normalized flux surface volume) values. By default, EFIT only computes this inside the LCFS. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to FFPrime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of FFPrime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`FFPrime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `FFPrime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `FFPrime`). Returns: `FFPrime` or (`FFPrime`, `time_idxs`) * **FFPrime** (`Array or scalar float`) - The flux function :math:`FF'`. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `FFPrime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single FFPrime value for volnorm=0.7, t=0.26s:: FFPrime_val = Eq_instance.volnorm2FFPrime(0.7, 0.26) Find FFPrime values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: FFPrime_arr = Eq_instance.volnorm2FFPrime([0.5, 0.7], 0.26) Find FFPrime values at volnorm=0.5 at times t=[0.2s, 0.3s]:: FFPrime_arr = Eq_instance.volnorm2FFPrime(0.5, [0.2, 0.3]) Find FFPrime values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: FFPrime_arr = Eq_instance.volnorm2FFPrime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getFFPrimeSpline, volnorm, t, **kwargs)
# Pressure profile:
[docs] def rz2p(self, R, Z, t, **kwargs): r"""Calculates the pressure at the given (R, Z, t). By default, EFIT only computes this inside the LCFS. Args: R (Array-like or scalar float): Values of the radial coordinate to map to p. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to p. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of p. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `p` or (`p`, `time_idxs`) * **p** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `p` has this shape as well, unless the `make_grid` keyword was True, in which case `p` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `p`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single p value at R=0.6m, Z=0.0m, t=0.26s:: p_val = Eq_instance.rz2p(0.6, 0, 0.26) Find p values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: p_arr = Eq_instance.rz2p([0.6, 0.8], [0, 0], 0.26) Find p values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: p_arr = Eq_instance.rz2p(0.6, 0, [0.2, 0.3]) Find p values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: p_arr = Eq_instance.rz2p([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find p values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: p_mat = Eq_instance.rz2p(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getPSpline, R, Z, t, **kwargs)
[docs] def rmid2p(self, R_mid, t, **kwargs): """Calculates the pressure corresponding to the passed R_mid (mapped outboard midplane major radius) values. By default, EFIT only computes this inside the LCFS. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to p. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of p. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `p` or (`p`, `time_idxs`) * **p** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `p`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single p value for Rmid=0.7m, t=0.26s:: p_val = Eq_instance.rmid2p(0.7, 0.26) Find p values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: p_arr = Eq_instance.rmid2p([0.5, 0.7], 0.26) Find p values at R_mid=0.5m at times t=[0.2s, 0.3s]:: p_arr = Eq_instance.rmid2p(0.5, [0.2, 0.3]) Find p values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: p_arr = Eq_instance.rmid2p([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getPSpline, R_mid, t, **kwargs)
[docs] def roa2p(self, roa, t, **kwargs): """Convert the passed (r/a, t) coordinates into pressure. By default, EFIT only computes this inside the LCFS. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to p. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of p. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `p` or (`p`, `time_idxs`) * **p** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `p`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single p value at r/a=0.6, t=0.26s:: p_val = Eq_instance.roa2p(0.6, 0.26) Find p values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: p_arr = Eq_instance.roa2p([0.6, 0.8], 0.26) Find p values at r/a of 0.6 at times t=[0.2s, 0.3s]:: p_arr = Eq_instance.roa2p(0.6, [0.2, 0.3]) Find p values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: p_arr = Eq_instance.roa2p([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('p', roa, t, **kwargs)
[docs] def psinorm2p(self, psinorm, t, **kwargs): """Calculates the pressure corresponding to the passed psi_norm (normalized poloidal flux) values. By default, EFIT only computes this inside the LCFS. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to p. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of p. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `p` or (`p`, `time_idxs`) * **p** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `p`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single p value for psinorm=0.7, t=0.26s:: p_val = Eq_instance.psinorm2p(0.7, 0.26) Find p values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: p_arr = Eq_instance.psinorm2p([0.5, 0.7], 0.26) Find p values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: p_arr = Eq_instance.psinorm2p(0.5, [0.2, 0.3]) Find p values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: p_arr = Eq_instance.psinorm2p([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getPSpline, psinorm, t, **kwargs)
[docs] def phinorm2p(self, phinorm, t, **kwargs): """Calculates the pressure corresponding to the passed phinorm (normalized toroidal flux) values. By default, EFIT only computes this inside the LCFS. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to p. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of p. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `p` or (`p`, `time_idxs`) * **p** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `p`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single p value for phinorm=0.7, t=0.26s:: p_val = Eq_instance.phinorm2p(0.7, 0.26) Find p values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: p_arr = Eq_instance.phinorm2p([0.5, 0.7], 0.26) Find p values at phinorm=0.5 at times t=[0.2s, 0.3s]:: p_arr = Eq_instance.phinorm2p(0.5, [0.2, 0.3]) Find p values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: p_arr = Eq_instance.phinorm2p([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getPSpline, phinorm, t, **kwargs)
[docs] def volnorm2p(self, volnorm, t, **kwargs): """Calculates the pressure corresponding to the passed volnorm (normalized flux surface volume) values. By default, EFIT only computes this inside the LCFS. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to p. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of p. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `p` or (`p`, `time_idxs`) * **p** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `p`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single p value for volnorm=0.7, t=0.26s:: p_val = Eq_instance.volnorm2p(0.7, 0.26) Find p values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: p_arr = Eq_instance.volnorm2p([0.5, 0.7], 0.26) Find p values at volnorm=0.5 at times t=[0.2s, 0.3s]:: p_arr = Eq_instance.volnorm2p(0.5, [0.2, 0.3]) Find p values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: p_arr = Eq_instance.volnorm2p([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getPSpline, volnorm, t, **kwargs)
# Pressure gradient profile:
[docs] def rz2pprime(self, R, Z, t, **kwargs): r"""Calculates the pressure gradient at the given (R, Z, t). By default, EFIT only computes this inside the LCFS. Args: R (Array-like or scalar float): Values of the radial coordinate to map to pprime. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to pprime. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of pprime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`pprime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `pprime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `pprime`). Returns: `pprime` or (`pprime`, `time_idxs`) * **pprime** (`Array or scalar float`) - The pressure gradient. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `p` has this shape as well, unless the `make_grid` keyword was True, in which case `p` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `pprime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single pprime value at R=0.6m, Z=0.0m, t=0.26s:: pprime_val = Eq_instance.rz2pprime(0.6, 0, 0.26) Find pprime values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: pprime_arr = Eq_instance.rz2pprime([0.6, 0.8], [0, 0], 0.26) Find pprime values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: pprime_arr = Eq_instance.rz2pprime(0.6, 0, [0.2, 0.3]) Find pprime values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: pprime_arr = Eq_instance.rz2pprime([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find pprime values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: pprime_mat = Eq_instance.rz2pprime(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getPPrimeSpline, R, Z, t, **kwargs)
[docs] def rmid2pprime(self, R_mid, t, **kwargs): """Calculates the pressure gradient corresponding to the passed R_mid (mapped outboard midplane major radius) values. By default, EFIT only computes this inside the LCFS. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to pprime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of pprime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`pprime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `pprime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `pprime`). Returns: `pprime` or (`pprime`, `time_idxs`) * **pprime** (`Array or scalar float`) - The pressure gradient. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `pprime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single pprime value for Rmid=0.7m, t=0.26s:: pprime_val = Eq_instance.rmid2pprime(0.7, 0.26) Find pprime values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: pprime_arr = Eq_instance.rmid2pprime([0.5, 0.7], 0.26) Find pprime values at R_mid=0.5m at times t=[0.2s, 0.3s]:: pprime_arr = Eq_instance.rmid2pprime(0.5, [0.2, 0.3]) Find pprime values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: pprime_arr = Eq_instance.rmid2pprime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getPPrimeSpline, R_mid, t, **kwargs)
[docs] def roa2pprime(self, roa, t, **kwargs): """Convert the passed (r/a, t) coordinates into pressure gradient. By default, EFIT only computes this inside the LCFS. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to pprime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of pprime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`pprime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `pprime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `pprime`). Returns: `pprime` or (`pprime`, `time_idxs`) * **pprime** (`Array or scalar float`) - The pressure gradient. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `pprime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single pprime value at r/a=0.6, t=0.26s:: pprime_val = Eq_instance.roa2pprime(0.6, 0.26) Find pprime values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: pprime_arr = Eq_instance.roa2pprime([0.6, 0.8], 0.26) Find pprime values at r/a of 0.6 at times t=[0.2s, 0.3s]:: pprime_arr = Eq_instance.roa2pprime(0.6, [0.2, 0.3]) Find pprime values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: pprime_arr = Eq_instance.roa2pprime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('pprime', roa, t, **kwargs)
[docs] def psinorm2pprime(self, psinorm, t, **kwargs): """Calculates the pressure gradient corresponding to the passed psi_norm (normalized poloidal flux) values. By default, EFIT only computes this inside the LCFS. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to pprime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of pprime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`pprime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `pprime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `pprime`). Returns: `pprime` or (`pprime`, `time_idxs`) * **pprime** (`Array or scalar float`) - The pressure gradient. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `pprime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single pprime value for psinorm=0.7, t=0.26s:: pprime_val = Eq_instance.psinorm2pprime(0.7, 0.26) Find pprime values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: pprime_arr = Eq_instance.psinorm2pprime([0.5, 0.7], 0.26) Find pprime values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: pprime_arr = Eq_instance.psinorm2pprime(0.5, [0.2, 0.3]) Find pprime values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: pprime_arr = Eq_instance.psinorm2pprime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getPPrimeSpline, psinorm, t, **kwargs)
[docs] def phinorm2pprime(self, phinorm, t, **kwargs): """Calculates the pressure gradient corresponding to the passed phinorm (normalized toroidal flux) values. By default, EFIT only computes this inside the LCFS. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to pprime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of pprime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`pprime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `pprime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `pprime`). Returns: `pprime` or (`pprime`, `time_idxs`) * **pprime** (`Array or scalar float`) - The pressure gradient. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `pprime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single pprime value for phinorm=0.7, t=0.26s:: pprime_val = Eq_instance.phinorm2pprime(0.7, 0.26) Find pprime values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: pprime_arr = Eq_instance.phinorm2pprime([0.5, 0.7], 0.26) Find pprime values at phinorm=0.5 at times t=[0.2s, 0.3s]:: pprime_arr = Eq_instance.phinorm2pprime(0.5, [0.2, 0.3]) Find pprime values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: pprime_arr = Eq_instance.phinorm2pprime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getPPrimeSpline, phinorm, t, **kwargs)
[docs] def volnorm2pprime(self, volnorm, t, **kwargs): """Calculates the pressure gradient corresponding to the passed volnorm (normalized flux surface volume) values. By default, EFIT only computes this inside the LCFS. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to pprime. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of pprime. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`pprime`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `pprime` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `pprime`). Returns: `pprime` or (`pprime`, `time_idxs`) * **pprime** (`Array or scalar float`) - The pressure gradient. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `pprime`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single pprime value for volnorm=0.7, t=0.26s:: pprime_val = Eq_instance.volnorm2pprime(0.7, 0.26) Find pprime values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: pprime_arr = Eq_instance.volnorm2pprime([0.5, 0.7], 0.26) Find pprime values at volnorm=0.5 at times t=[0.2s, 0.3s]:: pprime_arr = Eq_instance.volnorm2pprime(0.5, [0.2, 0.3]) Find pprime values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: pprime_arr = Eq_instance.volnorm2pprime([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getPPrimeSpline, volnorm, t, **kwargs)
# Flux surface volume profile:
[docs] def rz2v(self, R, Z, t, **kwargs): r"""Calculates the flux surface volume at the given (R, Z, t). By default, EFIT only computes this inside the LCFS. Args: R (Array-like or scalar float): Values of the radial coordinate to map to v. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to v. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: sqrt (Boolean): Set to True to return the square root of v. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`v`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `v` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `v`). Returns: `v` or (`v`, `time_idxs`) * **v** (`Array or scalar float`) - The flux surface volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `v` has this shape as well, unless the `make_grid` keyword was True, in which case `v` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `v`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single v value at R=0.6m, Z=0.0m, t=0.26s:: v_val = Eq_instance.rz2v(0.6, 0, 0.26) Find v values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: v_arr = Eq_instance.rz2v([0.6, 0.8], [0, 0], 0.26) Find v values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: v_arr = Eq_instance.rz2v(0.6, 0, [0.2, 0.3]) Find v values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: v_arr = Eq_instance.rz2v([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find v values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: v_mat = Eq_instance.rz2v(R, Z, 0.2, make_grid=True) """ return self._RZ2Quan(self._getVSpline, R, Z, t, **kwargs)
[docs] def rmid2v(self, R_mid, t, **kwargs): """Calculates the flux surface volume corresponding to the passed R_mid (mapped outboard midplane major radius) values. By default, EFIT only computes this inside the LCFS. Args: R_mid (Array-like or scalar float): Values of the outboard midplane major radius to map to v. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R_mid`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R_mid`. Keyword Args: sqrt (Boolean): Set to True to return the square root of v. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `R_mid` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R_mid` or be a scalar. Default is True (evaluate ALL `R_mid` at EACH element in `t`). length_unit (String or 1): Length unit that `R_mid` is given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`p`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `p` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `p`). Returns: `v` or (`v`, `time_idxs`) * **v** (`Array or scalar float`) - The flux surface volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `v`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single v value for Rmid=0.7m, t=0.26s:: v_val = Eq_instance.rmid2v(0.7, 0.26) Find v values at R_mid values of 0.5m and 0.7m at the single time t=0.26s:: v_arr = Eq_instance.rmid2v([0.5, 0.7], 0.26) Find v values at R_mid=0.5m at times t=[0.2s, 0.3s]:: v_arr = Eq_instance.rmid2v(0.5, [0.2, 0.3]) Find v values at (R_mid, t) points (0.6m, 0.2s) and (0.5m, 0.3s):: v_arr = Eq_instance.rmid2v([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._Rmid2Quan(self._getVSpline, R_mid, t, **kwargs)
[docs] def roa2v(self, roa, t, **kwargs): """Convert the passed (r/a, t) coordinates into flux surface volume. By default, EFIT only computes this inside the LCFS. Args: roa (Array-like or scalar float): Values of the normalized minor radius to map to v. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `roa`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `roa`. Keyword Args: sqrt (Boolean): Set to True to return the square root of v. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `roa` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `roa` or be a scalar. Default is True (evaluate ALL `roa` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`v`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `v` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `v`). Returns: `v` or (`v`, `time_idxs`) * **v** (`Array or scalar float`) - The flux surface volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `v`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single v value at r/a=0.6, t=0.26s:: v_val = Eq_instance.roa2v(0.6, 0.26) Find v values at r/a points 0.6 and 0.8 at the single time t=0.26s.:: v_arr = Eq_instance.roa2v([0.6, 0.8], 0.26) Find v values at r/a of 0.6 at times t=[0.2s, 0.3s]:: v_arr = Eq_instance.roa2v(0.6, [0.2, 0.3]) Find v values at (roa, t) points (0.6, 0.2s) and (0.5, 0.3s):: v_arr = Eq_instance.roa2v([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self.roa2rho('v', roa, t, **kwargs)
[docs] def psinorm2v(self, psinorm, t, **kwargs): """Calculates the flux surface volume corresponding to the passed psi_norm (normalized poloidal flux) values. By default, EFIT only computes this inside the LCFS. Args: psi_norm (Array-like or scalar float): Values of the normalized poloidal flux to map to v. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `psi_norm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `psi_norm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of v. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`v`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `v` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `v`). Returns: `v` or (`v`, `time_idxs`) * **v** (`Array or scalar float`) - The pressure. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `v`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single v value for psinorm=0.7, t=0.26s:: v_val = Eq_instance.psinorm2v(0.7, 0.26) Find v values at psi_norm values of 0.5 and 0.7 at the single time t=0.26s:: v_arr = Eq_instance.psinorm2v([0.5, 0.7], 0.26) Find v values at psi_norm=0.5 at times t=[0.2s, 0.3s]:: v_arr = Eq_instance.psinorm2v(0.5, [0.2, 0.3]) Find v values at (psinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: v_arr = Eq_instance.psinorm2v([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._psinorm2Quan(self._getVSpline, psinorm, t, **kwargs)
[docs] def phinorm2v(self, phinorm, t, **kwargs): """Calculates the flux surface volume corresponding to the passed phinorm (normalized toroidal flux) values. By default, EFIT only computes this inside the LCFS. Args: phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to v. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `phinorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `phinorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of v. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`v`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `v` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `v`). Returns: `v` or (`v`, `time_idxs`) * **v** (`Array or scalar float`) - The flux surface volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `v`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single v value for phinorm=0.7, t=0.26s:: v_val = Eq_instance.phinorm2v(0.7, 0.26) Find v values at phinorm values of 0.5 and 0.7 at the single time t=0.26s:: v_arr = Eq_instance.phinorm2v([0.5, 0.7], 0.26) Find v values at phinorm=0.5 at times t=[0.2s, 0.3s]:: v_arr = Eq_instance.phinorm2v(0.5, [0.2, 0.3]) Find v values at (phinorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: v_arr = Eq_instance.phinorm2v([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._phinorm2Quan(self._getVSpline, phinorm, t, **kwargs)
[docs] def volnorm2v(self, volnorm, t, **kwargs): """Calculates the flux surface volume corresponding to the passed volnorm (normalized flux surface volume) values. By default, EFIT only computes this inside the LCFS. Args: volnorm (Array-like or scalar float): Values of the normalized flux surface volume to map to v. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `volnorm`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `volnorm`. Keyword Args: sqrt (Boolean): Set to True to return the square root of v. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at EACH element in `t`). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. return_t (Boolean): Set to True to return a tuple of (`v`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `v` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `v`). Returns: `v` or (`v`, `time_idxs`) * **v** (`Array or scalar float`) - The flux surface volume. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `v`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single v value for volnorm=0.7, t=0.26s:: v_val = Eq_instance.volnorm2p(0.7, 0.26) Find v values at volnorm values of 0.5 and 0.7 at the single time t=0.26s:: v_arr = Eq_instance.volnorm2v([0.5, 0.7], 0.26) Find v values at volnorm=0.5 at times t=[0.2s, 0.3s]:: v_arr = Eq_instance.volnorm2v(0.5, [0.2, 0.3]) Find v values at (volnorm, t) points (0.6, 0.2s) and (0.5, 0.3s):: v_arr = Eq_instance.volnorm2v([0.6, 0.5], [0.2, 0.3], each_t=False) """ return self._volnorm2Quan(self._getVSpline, volnorm, t, **kwargs)
########################### # Magnetic field routines # ###########################
[docs] def rz2BR( self, R, Z, t, return_t=False, make_grid=False, each_t=True, length_unit=1 ): r"""Calculates the major radial component of the magnetic field at the given (R, Z, t) coordinates. Uses .. math:: B_R = -\frac{1}{R}\frac{\partial \psi}{\partial Z} Args: R (Array-like or scalar float): Values of the radial coordinate to map to radial field. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to radial field. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`BR`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `BR` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `BR`). Returns: `BR` or (`BR`, `time_idxs`) * **BR** (`Array or scalar float`) - The major radial component of the magnetic field. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `BR` has this shape as well, unless the `make_grid` keyword was True, in which case `BR` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `BR`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single BR value at R=0.6m, Z=0.0m, t=0.26s:: BR_val = Eq_instance.rz2BR(0.6, 0, 0.26) Find BR values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: BR_arr = Eq_instance.rz2BR([0.6, 0.8], [0, 0], 0.26) Find BR values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: BR_arr = Eq_instance.rz2BR(0.6, 0, [0.2, 0.3]) Find BR values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: BR_arr = Eq_instance.rz2BR([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find BR values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: BR_mat = Eq_instance.rz2BR(R, Z, 0.2, make_grid=True) """ # Check inputs and process into flat arrays with units of meters: ( R, Z, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( R, Z, t, make_grid=make_grid, each_t=each_t, length_unit=length_unit, compute_unique=True ) if self._tricubic: out_vals = scipy.reshape( -1.0 / R * self._getFluxTriSpline().ev( t, Z, R, dx=0, dy=1, dz=0 ), original_shape ) else: if single_time: out_vals = -1.0 / R * self._getFluxBiSpline(time_idxs[0]).ev( Z, R, dx=1, dy=0 ) if single_val: out_vals = out_vals[0] else: out_vals = scipy.reshape(out_vals, original_shape) elif each_t: out_vals = scipy.zeros( scipy.concatenate( ([len(time_idxs), ], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): out_vals[idx] = scipy.reshape( -1.0 / R * self._getFluxBiSpline(t_idx).ev( Z, R, dx=1, dy=0 ), original_shape ) else: out_vals = scipy.zeros_like(t, dtype=float) for t_idx in unique_idxs: t_mask = (time_idxs == t_idx) out_vals[t_mask] = ( -1.0 / R[t_mask] * self._getFluxBiSpline(t_idx).ev( Z[t_mask], R[t_mask], dx=1, dy=0 ) ) out_vals = scipy.reshape(out_vals, original_shape) # Correct for current sign: out_vals = -1.0 * out_vals * self.getCurrentSign() if return_t: if self._tricubic: return out_vals, (t, single_time, single_val, original_shape) else: return out_vals, ( time_idxs, unique_idxs, single_time, single_val, original_shape ) else: return out_vals
[docs] def rz2BZ( self, R, Z, t, return_t=False, make_grid=False, each_t=True, length_unit=1 ): r"""Calculates the vertical component of the magnetic field at the given (R, Z, t) coordinates. Uses .. math:: B_Z = \frac{1}{R}\frac{\partial \psi}{\partial R} Args: R (Array-like or scalar float): Values of the radial coordinate to map to vertical field. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to vertical field. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`BZ`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `BZ` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `BZ`). Returns: `BZ` or (`BZ`, `time_idxs`) * **BZ** (`Array or scalar float`) - The vertical component of the magnetic field. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `BZ` has this shape as well, unless the `make_grid` keyword was True, in which case `BZ` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `BZ`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single BZ value at R=0.6m, Z=0.0m, t=0.26s:: BZ_val = Eq_instance.rz2BZ(0.6, 0, 0.26) Find BZ values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: BZ_arr = Eq_instance.rz2BZ([0.6, 0.8], [0, 0], 0.26) Find BZ values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: BZ_arr = Eq_instance.rz2BZ(0.6, 0, [0.2, 0.3]) Find BZ values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: BZ_arr = Eq_instance.rz2BZ([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find BZ values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: BZ_mat = Eq_instance.rz2BZ(R, Z, 0.2, make_grid=True) """ # Check inputs and process into flat arrays with units of meters: ( R, Z, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( R, Z, t, make_grid=make_grid, each_t=each_t, length_unit=length_unit, compute_unique=True ) if self._tricubic: out_vals = scipy.reshape( 1.0 / R * self._getFluxTriSpline().ev( t, Z, R, dx=0, dy=0, dz=1 ), original_shape ) else: if single_time: out_vals = 1.0 / R * self._getFluxBiSpline(time_idxs[0]).ev( Z, R, dx=0, dy=1 ) if single_val: out_vals = out_vals[0] else: out_vals = scipy.reshape(out_vals, original_shape) elif each_t: out_vals = scipy.zeros( scipy.concatenate( ([len(time_idxs), ], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): out_vals[idx] = scipy.reshape( 1.0 / R * self._getFluxBiSpline(t_idx).ev( Z, R, dx=0, dy=1 ), original_shape ) else: out_vals = scipy.zeros_like(t, dtype=float) for t_idx in unique_idxs: t_mask = (time_idxs == t_idx) out_vals[t_mask] = 1.0 / R[t_mask] * self._getFluxBiSpline( t_idx ).ev(Z[t_mask], R[t_mask], dx=0, dy=1) out_vals = scipy.reshape(out_vals, original_shape) # Correct for current sign: out_vals = -1.0 * out_vals * self.getCurrentSign() if return_t: if self._tricubic: return out_vals, (t, single_time, single_val, original_shape) else: return out_vals, ( time_idxs, unique_idxs, single_time, single_val, original_shape ) else: return out_vals
[docs] def rz2BT(self, R, Z, t, **kwargs): r"""Calculates the toroidal component of the magnetic field at the given (R, Z, t). Uses :math:`B_\phi = F / R`. By default, EFIT only computes this inside the LCFS. To approximate the field outside of the LCFS, :math:`B_\phi \approx B_{t, vac} R_0 / R` is used, where :math:`B_{t, vac}` is obtained with :py:meth:`getBtVac` and :math:`R_0` is the major radius of the magnetic axis obtained from :py:meth:`getMagR`. The coordinate system used is right-handed, such that "forward" field on Alcator C-Mod (clockwise when seen from above) has negative BT. Args: R (Array-like or scalar float): Values of the radial coordinate to map to BT. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to BT. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`BT`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `BT` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `BT`). Returns: `BT` or (`BT`, `time_idxs`) * **BT** (`Array or scalar float`) - The toroidal magnetic field. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `BT` has this shape as well, unless the `make_grid` keyword was True, in which case `BT` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `BT`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single BT value at R=0.6m, Z=0.0m, t=0.26s:: BT_val = Eq_instance.rz2BT(0.6, 0, 0.26) Find BT values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: BT_arr = Eq_instance.rz2BT([0.6, 0.8], [0, 0], 0.26) Find BT values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: BT_arr = Eq_instance.rz2BT(0.6, 0, [0.2, 0.3]) Find BT values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: BT_arr = Eq_instance.rz2BT([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find BT values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: BT_mat = Eq_instance.rz2BT(R, Z, 0.2, make_grid=True) """ return_t = kwargs.get('return_t', False) unit_factor = self._getLengthConversionFactor( 'm', kwargs.get('length_unit', 1) ) out = self.rz2F(R, Z, t, **kwargs) if return_t: F, blob = out else: F = out B_T = F / R # This will have NaN anywhere outside of the LCFS. Only handle if we # we need to. if scipy.isnan(B_T).any(): warnings.warn( "Flux function F not provided outside of LCFS, assuming field " "goes like 1/R there to compute BT! This may be inaccurate!", RuntimeWarning ) # This unfortunately requires a second call to _processRZt: ( R, Z, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( R, Z, t, make_grid=kwargs.get('make_grid', False), each_t=kwargs.get('each_t', True), length_unit=kwargs.get('length_unit', 1), compute_unique=True ) if self._tricubic: B_T = B_T.ravel() mask = scipy.isnan(B_T) B_T[mask] = ( self.getBtVacSpline()(t[mask]) * self.getMagRSpline()(t[mask]) / R[mask] ) B_T = scipy.reshape(B_T, original_shape) else: if single_time: B_T = B_T.ravel() mask = scipy.isnan(B_T) B_T[mask] = ( self.getBtVac()[time_idxs] * self.getMagR()[time_idxs] / R[mask] ) if single_val: B_T = B_T[0] else: B_T = scipy.reshape(B_T, original_shape) elif kwargs.get('each_t', True): for idx, t_idx in enumerate(time_idxs): tmp_out = B_T[idx].ravel() mask = scipy.isnan(tmp_out) tmp_out[mask] = ( self.getBtVac()[t_idx] * self.getMagR()[t_idx] / R[mask] ) B_T[idx] = scipy.reshape(tmp_out, original_shape) else: B_T = B_T.ravel() for t_idx in unique_idxs: t_mask = (time_idxs == t_idx) tmp_out = B_T[t_mask] mask = scipy.isnan(tmp_out) tmp_out[mask] = ( self.getBtVac()[t_idx] * self.getMagR()[t_idx] / R[t_mask][mask] ) B_T[t_mask] = tmp_out B_T = scipy.reshape(B_T, original_shape) if return_t: return unit_factor * B_T, blob else: return unit_factor * B_T
[docs] def rz2B(self, R, Z, t, **kwargs): r"""Calculates the magnitude of the magnetic field at the given (R, Z, t). Args: R (Array-like or scalar float): Values of the radial coordinate to map to B. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to B. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`B`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `B` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `B`). Returns: `B` or (`B`, `time_idxs`) * **B** (`Array or scalar float`) - The magnitude of the magnetic field. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `B` has this shape as well, unless the `make_grid` keyword was True, in which case `B` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `B`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single B value at R=0.6m, Z=0.0m, t=0.26s:: B_val = Eq_instance.rz2B(0.6, 0, 0.26) Find B values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: B_arr = Eq_instance.rz2B([0.6, 0.8], [0, 0], 0.26) Find B values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: B_arr = Eq_instance.rz2B(0.6, 0, [0.2, 0.3]) Find B values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: B_arr = Eq_instance.rz2B([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find B values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: B_mat = Eq_instance.rz2B(R, Z, 0.2, make_grid=True) """ # TODO: This doesn't handle return_t properly! BR = self.rz2BR(R, Z, t, **kwargs) BZ = self.rz2BZ(R, Z, t, **kwargs) BT = self.rz2BT(R, Z, t, **kwargs) return scipy.sqrt(BR**2.0 + BZ**2.0 + BT**2.0)
############################ # Current density routines # ############################
[docs] def rz2jR(self, R, Z, t, **kwargs): r"""Calculates the major radial component of the current density at the given (R, Z, t) coordinates. .. math:: j_R = -\frac{1}{\mu_0 R}F'\frac{\partial \psi}{\partial Z} = \frac{F' B_R}{\mu_0} Args: R (Array-like or scalar float): Values of the radial coordinate to map to radial current density. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to radial current density. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`jR`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `jR` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `jR`). Returns: `jR` or (`jR`, `time_idxs`) * **jR** (`Array or scalar float`) - The major radial component of the current density. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `jR` has this shape as well, unless the `make_grid` keyword was True, in which case `jR` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `jR`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single jR value at R=0.6m, Z=0.0m, t=0.26s:: jR_val = Eq_instance.rz2jR(0.6, 0, 0.26) Find jR values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: jR_arr = Eq_instance.rz2jR([0.6, 0.8], [0, 0], 0.26) Find jR values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: jR_arr = Eq_instance.rz2jR(0.6, 0, [0.2, 0.3]) Find jR values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: jR_arr = Eq_instance.rz2jR([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find jR values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: jR_mat = Eq_instance.rz2jR(R, Z, 0.2, make_grid=True) """ # TODO: This doesn't handle return_t properly! # NOTE: Alcator C-Mod requires the extra factor to correct FF'. # You should check this for your implementation. return -1.0 * self.getCurrentSign() * ( self.rz2FFPrime(R, Z, t, **kwargs) * self.rz2BR(R, Z, t, **kwargs) / (scipy.constants.mu_0 * self.rz2F(R, Z, t, **kwargs)) )
[docs] def rz2jZ(self, R, Z, t, **kwargs): r"""Calculates the vertical component of the current density at the given (R, Z, t) coordinates. Uses .. math:: j_Z = \frac{1}{\mu_0 R}F'\frac{\partial \psi}{\partial R} = \frac{F' B_Z}{\mu_0} Note that this function includes a factor of -1 to correct the FF' from Alcator C-Mod's EFIT implementation. You should check the sign of your data. Args: R (Array-like or scalar float): Values of the radial coordinate to map to vertical current density. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to vertical current density. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`jZ`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `jZ` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `jZ`). Returns: `jZ` or (`jZ`, `time_idxs`) * **jZ** (`Array or scalar float`) - The vertical component of the current density. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `jZ` has this shape as well, unless the `make_grid` keyword was True, in which case `jZ` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `jZ`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single jZ value at R=0.6m, Z=0.0m, t=0.26s:: jZ_val = Eq_instance.rz2jZ(0.6, 0, 0.26) Find jZ values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: jZ_arr = Eq_instance.rz2jZ([0.6, 0.8], [0, 0], 0.26) Find jZ values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: jZ_arr = Eq_instance.rz2jZ(0.6, 0, [0.2, 0.3]) Find jZ values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: jZ_arr = Eq_instance.rz2jZ([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find jZ values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: jZ_mat = Eq_instance.rz2jZ(R, Z, 0.2, make_grid=True) """ # TODO: This doesn't handle return_t properly! # NOTE: Alcator C-Mod requires the extra factor to correct FF'. # You should check this for your implementation. return -1.0 * self.getCurrentSign() * ( self.rz2FFPrime(R, Z, t, **kwargs) * self.rz2BZ(R, Z, t, **kwargs) / (scipy.constants.mu_0 * self.rz2F(R, Z, t, **kwargs)) )
[docs] def rz2jT(self, R, Z, t, **kwargs): r"""Calculates the toroidal component of the current density at the given (R, Z, t) coordinates. Uses .. math:: j_\phi = Rp' + \frac{FF'}{\mu_0 R} The coordinate system used is right-handed, such that "forward" field on Alcator C-Mod (clockwise when seen from above) has negative jT. Args: R (Array-like or scalar float): Values of the radial coordinate to map to toroidal current density. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to toroidal current density. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`jT`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `jT` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `jT`). Returns: `jT` or (`jT`, `time_idxs`) * **jT** (`Array or scalar float`) - The major radial component of the current density. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `jT` has this shape as well, unless the `make_grid` keyword was True, in which case `jT` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `jT`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single jT value at R=0.6m, Z=0.0m, t=0.26s:: jT_val = Eq_instance.rz2jT(0.6, 0, 0.26) Find jT values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: jT_arr = Eq_instance.rz2jT([0.6, 0.8], [0, 0], 0.26) Find jT values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: jT_arr = Eq_instance.rz2jT(0.6, 0, [0.2, 0.3]) Find jT values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: jT_arr = Eq_instance.rz2jT([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find jT values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: jT_mat = Eq_instance.rz2jT(R, Z, 0.2, make_grid=True) """ # TODO: This doesn't handle return_t properly! # NOTE: Alcator C-Mod requires the extra factor to correct FF'. # You should check this for your implementation. unit_factor = self._getLengthConversionFactor( 'm', kwargs.get('length_unit', 1) ) return -1.0 * self.getCurrentSign() * ( R / unit_factor * self.rz2pprime(R, Z, t, **kwargs) + unit_factor * self.rz2FFPrime(R, Z, t, **kwargs) / (scipy.constants.mu_0 * R) )
[docs] def rz2j(self, R, Z, t, **kwargs): r"""Calculates the magnitude of the current density at the given (R, Z, t) coordinates. Args: R (Array-like or scalar float): Values of the radial coordinate to map to current density magnitude. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `R` must have exactly one dimension. Z (Array-like or scalar float): Values of the vertical coordinate to map to current density magnitude. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is set. If the `make_grid` keyword is True, `Z` must have exactly one dimension. t (Array-like or scalar float): Times to perform the conversion at. If `t` is a single value, it is used for all of the elements of `R`, `Z`. If the `each_t` keyword is True, then `t` must be scalar or have exactly one dimension. If the `each_t` keyword is False, `t` must have the same shape as `R` and `Z` (or their meshgrid if `make_grid` is True). Keyword Args: each_t (Boolean): When True, the elements in `R`, `Z` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` or be a scalar. Default is True (evaluate ALL `R`, `Z` at EACH element in `t`). make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`scipy.meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). length_unit (String or 1): Length unit that `R`, `Z` are given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (use meters). return_t (Boolean): Set to True to return a tuple of (`j`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `j` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `j`). Returns: `j` or (`j`, `time_idxs`) * **j** (`Array or scalar float`) - The magnitude of the current density. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. If `R` and `Z` both have the same shape then `j` has this shape as well, unless the `make_grid` keyword was True, in which case `j` has shape (len(`Z`), len(`R`)). * **time_idxs** (Array with same shape as `j`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class. Find single j value at R=0.6m, Z=0.0m, t=0.26s:: j_val = Eq_instance.rz2j(0.6, 0, 0.26) Find j values at (R, Z) points (0.6m, 0m) and (0.8m, 0m) at the single time t=0.26s. Note that the `Z` vector must be fully specified, even if the values are all the same:: j_arr = Eq_instance.rz2j([0.6, 0.8], [0, 0], 0.26) Find j values at (R, Z) points (0.6m, 0m) at times t=[0.2s, 0.3s]:: j_arr = Eq_instance.rz2j(0.6, 0, [0.2, 0.3]) Find j values at (R, Z, t) points (0.6m, 0m, 0.2s) and (0.5m, 0.2m, 0.3s):: j_arr = Eq_instance.rz2j([0.6, 0.5], [0, 0.2], [0.2, 0.3], each_t=False) Find j values on grid defined by 1D vector of radial positions `R` and 1D vector of vertical positions `Z` at time t=0.2s:: j_mat = Eq_instance.rz2j(R, Z, 0.2, make_grid=True) """ # TODO: This doesn't handle return_t properly! jR = self.rz2jR(R, Z, t, **kwargs) jZ = self.rz2jZ(R, Z, t, **kwargs) jT = self.rz2jT(R, Z, t, **kwargs) return scipy.sqrt(jR**2.0 + jZ**2.0 + jT**2.0)
########################## # Field mapping routines # ########################## def _fl_func(self, phi, RZ, t, field='B'): r"""Function which implements the differential equation for field line tracing. .. math:: \frac{dR}{d\phi} = \frac{u_R}{u_\phi}R \frac{dZ}{d\phi} = \frac{u_Z}{u_\phi}R Args: phi (float): Toroidal location to use. RZ (array of float, (2,)): Array containing R, Z. t (float): The time to use. Keyword Args: field ({'B', 'j'}): The field to use. Can be magnetic field ('B') or current density ('j'). Default is 'B' (magnetic field). Returns: list: containing [:math:`dR/d\phi`, :math:`dZ/d\phi`] """ R = RZ[0] Z = RZ[1] if field == 'B': uR = self.rz2BR(R, Z, t) uZ = self.rz2BZ(R, Z, t) uT = self.rz2BT(R, Z, t) elif field == 'j': uR = self.rz2jR(R, Z, t) uZ = self.rz2jZ(R, Z, t) uT = self.rz2jT(R, Z, t) return [uR * R / uT, uZ * R / uT]
[docs] def rz2FieldLineTrace(self, R0, Z0, t, phi0=0.0, field='B', num_rev=1.0, rev_method='toroidal', dphi=2.0 * scipy.pi / 100.0, integrator='dopri5'): """Trace a field line starting from a given (R, phi, Z) point. Args: R0 (float): Major radial coordinate of starting point. Z0 (float): Vertical coordinate of starting point. t (float): Time to trace field line at. Keyword Args: phi0 (float): Toroidal angle of starting point in radians. Default is 0.0. field ({'B', 'j'}): The field to use. Can be magnetic field ('B') or current density ('j'). Default is 'B' (magnetic field). num_rev (float): The number of revolutions to trace the field line through. Whether this refers to toroidal or poloidal revolutions is determined by the `rev_method` keyword. Default is 1.0. rev_method ('toroidal', 'poloidal'): Whether `num_rev` refers to the number of toroidal or poloidal revolutions the field line should make. Note that 'poloidal' only makes sense for close field lines. Default is 'toroidal'. dphi (float): Toroidal step size, in radians. Default is 0.02*pi. The number of steps taken is then 2*pi times the number of toroidal rotations divided by dphi. This can be negative to trace a field line clockwise instead of counterclockwise. integrator (str): The integrator to use with :py:class:`scipy.integrate.ode`. Default is 'dopri5' (explicit Dormand-Prince of order (4)5). Can also be an instance of :py:class:`scipy.integrate.ode` for which the integrator and its options has been set. Returns: array, (`nsteps` + 1, 3): Containing the (R, Z, phi) coordinates. """ if field not in ['B', 'j']: raise ValueError("Invalid field {field}!".format(field=field)) if rev_method not in ['toroidal', 'poloidal']: raise ValueError("Invalid rev_method {rm}!".format(rm=rev_method)) if rev_method == 'poloidal': q = self.rz2q(R0, Z0, t) num_rev = num_rev * q nsteps = int( scipy.absolute(scipy.ceil(num_rev * 2.0 * scipy.pi / dphi)) ) if isinstance(integrator, scipy.integrate.ode): r = integrator else: r = scipy.integrate.ode(self._fl_func) r.set_integrator(integrator) r.set_f_params(t, field) r.set_initial_value([R0, Z0], phi0) out = scipy.zeros((nsteps + 1, 3)) # R, Z, Phi out[0, :] = [R0, Z0, phi0] for i in range(1, nsteps + 1): out[i, 0:2] = r.integrate(r.t + dphi) out[i, 2] = r.t return out
[docs] def rho2FieldLineTrace(self, rho, t, origin='psinorm', **kwargs): """Trace a field line starting from a given normalized coordinate point. The field line is started at the outboard midplane. Args: rho (float): Flux surface label of starting point. t (float): Time to trace field line at. Keyword Args: origin ({'psinorm', 'phinorm', 'volnorm', 'r/a', 'Rmid', 'Fnorm'}): The flux surface coordinates which `rhovals` is given in. Default is 'psinorm'. phi0 (float): Toroidal angle of starting point in radians. Default is 0.0. field ({'B', 'j'}): The field to use. Can be magnetic field ('B') or current density ('j'). Default is 'B' (magnetic field). num_rev (float): The number of revolutions to trace the field line through. Whether this refers to toroidal or poloidal revolutions is determined by the `rev_method` keyword. Default is 1.0. rev_method ('toroidal', 'poloidal'): Whether `num_rev` refers to the number of toroidal or poloidal revolutions the field line should make. Note that 'poloidal' only makes sense for close field lines. Default is 'toroidal'. dphi (float): Toroidal step size, in radians. Default is 0.02*pi. The number of steps taken is then 2*pi times the number of toroidal rotations divided by dphi. This can be negative to trace a field line clockwise instead of counterclockwise. integrator (str): The integrator to use with :py:class:`scipy.integrate.ode`. Default is 'dopri5' (explicit Dormand-Prince of order (4)5). Can also be an instance of :py:class:`scipy.integrate.ode` for which the integrator and its options has been set. Returns: array, (`nsteps` + 1, 3): Containing the (R, Z, phi) coordinates. """ # Handle Fnorm specially since it doesn't support all of the routines: if origin == 'Fnorm': rho = self.Fnorm2psinorm(rho, t) origin = 'psinorm' Rmid = self.rho2rho(origin, 'Rmid', rho, t) Zmid = self.getMagZSpline()(t) # Intercept the poloidal rev_method here to avoid numerical issues at # the boundaries: if kwargs.get('rev_method', 'toroidal') == 'poloidal': kwargs['rev_method'] = 'toroidal' q = self.rho2rho(origin, 'q', rho, t) kwargs['num_rev'] = kwargs.get('num_rev', 1.0) * q return self.rz2FieldLineTrace(Rmid, Zmid, t, **kwargs)
[docs] def plotField(self, t, rhovals=6, rhomin=0.05, rhomax=0.95, color='b', cmap='plasma', alpha=0.5, arrows=True, linewidth=1.0, arrowlinewidth=3.0, a=None, **kwargs): """Plot the field lines starting from a number of points. The field lines are started at the outboard midplane. If uniformly-spaced psinorm points are used, the spacing of the magnetic field lines will be directly proportional to the field strength, assuming a sufficient number of revolutions is traced. Args: t (float): Time to trace field line at. Keyword Args: rhovals (int or array of int): The number of uniformly-spaced rho points between `rhomin` and `rhomax` to use, or an explicit grid of rho points to use. Default is 6. rhomin (float): The minimum value of rho to use when using a uniformly-spaced grid. Default is 0.05. rhomax (float): The maximum value of rho to use when using a uniformly-spaced grid. Default is 0.95. color (str): The color to plot the field lines in. Default is 'b'. If set to 'sequential', each field line will be a different color, in the sequence matplotlib assigns them. If set to 'magnitude', the coloring will be proportional to the magnitude of the field. Note that this is very time-consuming, as the limitations of matplotlib mean that each line segment must be plotted individually. cmap (str): The colormap to use when `color` is 'magnitude'. Default is 'plasma', a perceptually uniform sequential colormap. alpha (float): The transparency to plot the field lines with. Default is 0.5. arrows (bool): If True, an arrowhead indicating the field direction will be drawn at the start of each field line. Default is True. linewidth (float): The line width to use when plotting the field lines. Default is 1.0. arrowlinewidth (float): The line width to use when plotting the arrows. Default is 3.0 a (:py:class:`matplotlib.axes._subplots.Axes3DSubplot`): The axes to plot the field lines on. Default is to make a new figure. Note that a colorbar will be drawn when `color` is magnitude, but only if `a` is not provided. origin ({'psinorm', 'phinorm', 'volnorm', 'r/a', 'Rmid', 'Fnorm'}): The flux surface coordinates which `rhovals` is given in. Default is 'psinorm'. phi0 (float): Toroidal angle of starting point in radians. Default is 0.0. field ({'B', 'j'}): The field to use. Can be magnetic field ('B') or current density ('j'). Default is 'B' (magnetic field). num_rev (float): The number of revolutions to trace the field line through. Whether this refers to toroidal or poloidal revolutions is determined by the `rev_method` keyword. Default is 1.0. rev_method ('toroidal', 'poloidal'): Whether `num_rev` refers to the number of toroidal or poloidal revolutions the field line should make. Note that 'poloidal' only makes sense for close field lines. Default is 'toroidal'. dphi (float): Toroidal step size, in radians. Default is 0.02*pi. The number of steps taken is then 2*pi times the number of toroidal rotations divided by dphi. This can be negative to trace a field line clockwise instead of counterclockwise. integrator (str): The integrator to use with :py:class:`scipy.integrate.ode`. Default is 'dopri5' (explicit Dormand-Prince of order (4)5). Can also be an instance of :py:class:`scipy.integrate.ode` for which the integrator and its options has been set. Returns: (figure, axis): The figure and axis which the field lines were plotted in. """ rhovals = scipy.asarray(rhovals, dtype=float) if rhovals.ndim == 0: rhovals = scipy.linspace(rhomin, rhomax, int(rhovals)) rzt = [] for rho in rhovals: rzt.append(self.rho2FieldLineTrace(rho, t, **kwargs)) if a is None: f = plt.figure() if color == 'magnitude': gs = mplgs.GridSpec(1, 2, width_ratios=[10, 1]) a = f.add_subplot(gs[0, 0], projection='3d') a_cb = f.add_subplot(gs[0, 1]) else: a = f.add_subplot(111, projection='3d') else: f = a.get_figure() # Don't make colorbar for existing figure: if color == 'magnitude': a_cb = None # Need to do this ahead of time to get the right scaling for all lines: if color == 'magnitude': mag_max = 0.0 mag_min = scipy.inf mag = [] for v in rzt: if kwargs.get('field', 'B') == 'B': mag.append(self.rz2B(v[:, 0], v[:, 1], t)) else: mag.append(self.rz2j(v[:, 0], v[:, 1], t)) m = mag[-1].max() if m > mag_max: mag_max = m m = mag[-1].min() if m < mag_min: mag_min = m if a_cb is not None: scale = 1.0 if kwargs.get('field', 'B') == 'B' else 1e-6 cb = ColorbarBase( a_cb, cmap=plt.get_cmap(cmap), norm=Normalize(vmin=mag_min * scale, vmax=mag_max * scale), label=B_LABEL if kwargs.get('field', 'B') == 'B' else J_LABEL ) v_ext = max( scipy.absolute(self.getRGrid()).max(), scipy.absolute(self.getZGrid()).max() ) for j, v in enumerate(rzt): if color == 'magnitude': # Hack from https://stackoverflow.com/questions/15617207/line-colour-of-3d-parametric-curve-in-pythons-matplotlib-pyplot for i in range(0, v.shape[0] - 1): c = plt.get_cmap(cmap)( int( scipy.around( 255 * ( (mag[j][i] + mag[j][i + 1]) / 2.0 - mag_min ) / (mag_max - mag_min) ) ) )[:3] a.plot( v[i:i + 2, 0] * scipy.cos(v[i:i + 2, 2]), v[i:i + 2, 0] * scipy.sin(v[i:i + 2, 2]), v[i:i + 2, 1], color=c, alpha=alpha, linewidth=linewidth ) else: l, = a.plot( v[:, 0] * scipy.cos(v[:, 2]), v[:, 0] * scipy.sin(v[:, 2]), v[:, 1], color=None if color == 'sequential' else color, alpha=alpha, linewidth=linewidth ) c = l.get_color() if arrows: if kwargs.get('field', 'B') == 'B': uR = self.rz2BR(v[0, 0], v[0, 1], t) uZ = self.rz2BZ(v[0, 0], v[0, 1], t) uT = self.rz2BT(v[0, 0], v[0, 1], t) else: uR = self.rz2jR(v[0, 0], v[0, 1], t) uZ = self.rz2jZ(v[0, 0], v[0, 1], t) uT = self.rz2jT(v[0, 0], v[0, 1], t) u = scipy.sqrt(uR**2.0 + uZ**2.0 + uT**2.0) a.quiver( v[0, 0] * scipy.cos(v[0, 2]), v[0, 0] * scipy.sin(v[0, 2]), v[0, 1], (uR * scipy.cos(v[0, 2]) - uT * scipy.sin(v[0, 2])) / u, (uR * scipy.sin(v[0, 2]) + uT * scipy.cos(v[0, 2])) / u, uZ / u, color=c, alpha=alpha, length=v_ext / 10.0, arrow_length_ratio=1.0, pivot='tail', linewidth=arrowlinewidth ) a.set_aspect('equal') # equal doesn't equalize the Z-axis, so fake it with axis limits: a.set_xlim(-v_ext, v_ext) a.set_ylim(-v_ext, v_ext) a.set_zlim(-v_ext, v_ext) a.set_xlabel('$X$ [m]') a.set_ylabel('$Y$ [m]') a.set_zlabel('$Z$ [m]') plt.ion() f.show() return f, a
########################### # Backend Mapping Drivers # ########################### def _psinorm2Quan(self, spline_func, psi_norm, t, each_t=True, return_t=False, sqrt=False, rho=False, k=3, blob=None, check_space=False, convert_only=True, length_unit=1, convert_roa=False): """Convert psinorm to a given quantity. Utility function for computing a variety of quantities given psi_norm and the relevant time indices. Args: spline_func (callable): Function which returns a 1d spline for the quantity you want to convert into as a function of `psi_norm` given a time index. psi_norm (Array or scalar float): `psi_norm` values to evaluate at. time_idxs (Array or scalar float): Time indices for each of the `psi_norm` values. Shape must match that of `psi_norm`. t: Array or scalar float. Representative time array that `psi_norm` and `time_idxs` was formed from (used to determine output shape). Keyword Args: each_t (Boolean): When True, the elements in `psi_norm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `psi_norm` or be a scalar. Default is True (evaluate ALL `psi_norm` at EACH element in `t`). return_t (Boolean): Set to True to return a tuple of (`rho`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `rho` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `rho`). sqrt (Boolean): Set to True to return the square root of `rho`. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False. rho (Boolean): Set to True to return r/a (normalized minor radius) instead of Rmid. Default is False (return major radius, Rmid). Note that this will have unexpected results if `spline_func` returns anything other than R_mid. k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. time_idxs (Array with same shape as `psi_norm` or None): The time indices to use (as computed by :py:meth:`_processRZt`). Default is None (compute time indices in method). convert_roa (Boolean): When True, it is assumed that `psi_norm` is actually given as r/a and should be converted to Rmid before being passed to the spline for conversion. Default is False. Returns: (`rho`, `time_idxs`) * **rho** (`Array or scalar float`) - The converted quantity. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array is returned. * **time_idxs** (Array with same shape as `rho`) - The indices (in :py:meth:`self.getTimeBase`) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. """ if blob is None: # When called in this manner, this is just like what was done with # rz2psi. ( psi_norm, dum, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) = self._processRZt( psi_norm, psi_norm, t, make_grid=False, check_space=check_space, each_t=each_t, length_unit=length_unit, convert_only=convert_only, compute_unique=True ) if self._tricubic: if convert_roa: psi_norm = self._roa2rmid(psi_norm, t) quan_norm = spline_func(t).ev(t, psi_norm) if rho: quan_norm = self._rmid2roa(quan_norm, t) quan_norm = quan_norm.reshape(original_shape) else: if single_time: if convert_roa: psi_norm = self._roa2rmid(psi_norm, time_idxs[0]) quan_norm = spline_func(time_idxs[0], k=k)(psi_norm) if rho: quan_norm = self._rmid2roa(quan_norm, time_idxs[0]) if single_val: quan_norm = quan_norm[0] else: quan_norm = scipy.reshape(quan_norm, original_shape) elif each_t: quan_norm = scipy.zeros( scipy.concatenate( ([len(time_idxs), ], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): if convert_roa: psi_tmp = self._roa2rmid(psi_norm, t_idx) else: psi_tmp = psi_norm tmp = spline_func(t_idx, k=k)(psi_tmp) if rho: tmp = self._rmid2roa(tmp, t_idx) quan_norm[idx] = tmp.reshape(original_shape) else: if convert_roa: psi_norm = self._roa2rmid(psi_norm, time_idxs) quan_norm = scipy.zeros_like(t, dtype=float) for t_idx in unique_idxs: t_mask = (time_idxs == t_idx) tmp = spline_func(t_idx, k=k)(psi_norm[t_mask]) if rho: tmp = self._rmid2roa(tmp, t_idx) quan_norm[t_mask] = tmp quan_norm = quan_norm.reshape(original_shape) if sqrt: if quan_norm.ndim == 0: if quan_norm < 0.0: quan_norm = 0.0 else: scipy.place(quan_norm, quan_norm < 0, 0.0) quan_norm = scipy.sqrt(quan_norm) if return_t: if self._tricubic: return quan_norm, ( t, single_time, single_val, original_shape ) else: return quan_norm, ( time_idxs, unique_idxs, single_time, single_val, original_shape ) else: return quan_norm else: # When called in this manner, psi_norm has already been expanded # through a pass through rz2psinorm, so we need to be more clever. if self._tricubic: t_proc, single_time, single_val, original_shape = blob else: ( time_idxs, unique_idxs, single_time, single_val, original_shape ) = blob # Override original_shape with shape of psi_norm: # psi_norm_shape = psi_norm.shape psi_norm_flat = psi_norm.reshape(-1) if self._tricubic: tt = t_proc.reshape(-1) if convert_roa: psi_norm_flat = self._roa2rmid(psi_norm_flat, tt) quan_norm = spline_func(t).ev(t_proc, psi_norm_flat) if rho: quan_norm = self._rmid2roa(quan_norm, tt) quan_norm = quan_norm.reshape(original_shape) else: if convert_roa: psi_norm_flat = self._roa2rmid(psi_norm_flat, time_idxs) if each_t: psi_norm = psi_norm_flat.reshape(-1) if single_time: quan_norm = spline_func(time_idxs[0], k=k)(psi_norm_flat) if rho: quan_norm = self._rmid2roa(quan_norm, time_idxs[0]) if single_val: quan_norm = quan_norm[0] else: quan_norm = scipy.reshape(quan_norm, original_shape) elif each_t: quan_norm = scipy.zeros( scipy.concatenate( ([len(time_idxs),], original_shape) ).astype(int) ) for idx, t_idx in enumerate(time_idxs): tmp = spline_func(t_idx, k=k)( psi_norm[idx].reshape(-1) ) if rho: tmp = self._rmid2roa(tmp, t_idx) quan_norm[idx] = tmp.reshape(original_shape) else: quan_norm = scipy.zeros_like(time_idxs, dtype=float) for t_idx in unique_idxs: t_mask = (time_idxs == t_idx) tmp = spline_func(t_idx, k=k)(psi_norm_flat[t_mask]) if rho: tmp = self._rmid2roa(tmp, t_idx) quan_norm[t_mask] = tmp quan_norm = quan_norm.reshape(original_shape) if sqrt: if quan_norm.ndim == 0: if quan_norm < 0: quan_norm = 0.0 else: scipy.place(quan_norm, quan_norm < 0, 0.0) quan_norm = scipy.sqrt(quan_norm) if return_t: return quan_norm, blob else: return quan_norm def _rmid2roa(self, R_mid, time_idxs): r"""Covert the given `R_mid` at the given `time_idxs` to r/a. If you want to use a different definition of r/a, you should override this function and :py:meth:`_roa2rmid`. The definition used here is .. math:: r/a = \frac{R_{mid} - R_0}{R_a - R_0} = \frac{R_{mid} - R_0}{a} Args: R_mid (Array or scalar float): Values of outboard midplane major radius to evaluate r/a at. time_idxs (Array, same shape as `R_mid`): If :py:attr:`self._tricubic` is True, this should be an array of the time points to evaluate at. Otherwise, this should be an array of the time INDICES in :py:meth:`getTimeBase` to evaluate at. Returns: roa (Array): Same shape as `R_mid` and `time_idxs`. The normalized minor radius at the given `R_mid`, `t` points. """ # Get necessary quantities at the relevant times: if not self._tricubic: magR = self.getMagR(length_unit='m')[time_idxs] Rout = self.getRmidOut(length_unit='m')[time_idxs] else: magR = self.getMagRSpline(length_unit='m')(time_idxs) Rout = self.getRmidOutSpline(length_unit='m')(time_idxs) # Compute r/a according to our definition: return (R_mid - magR) / (Rout - magR) def _roa2rmid(self, roa, time_idxs): r"""Covert the given r/a at the given time_idxs to R_mid. If you want to use a different definition of r/a, you should override this function and :py:meth:`_rmid2roa`. The definition used here is .. math:: r/a = \frac{R_{mid} - R_0}{R_a - R_0} = \frac{R_{mid} - R_0}{a} Args: roa (Array or scalar float): Values of normalized minor radius to evaluate R_mid at. time_idxs (Array, same shape as `roa`): If :py:attr:`self._tricubic` is True, this should be an array of the time points to evaluate at. Otherwise, this should be an array of the time INDICES in :py:meth:`getTimeBase` to evaluate at. Returns: R_mid (Array): Same shape as `roa` and `time_idxs`. The mapped midplane major radius at the given `roa`, `t` points. """ # Get necessary quantities at the relevant times: if not self._tricubic: magR = self.getMagR(length_unit='m')[time_idxs] Rout = self.getRmidOut(length_unit='m')[time_idxs] else: magR = self.getMagRSpline(length_unit='m')(time_idxs) Rout = self.getRmidOutSpline(length_unit='m')(time_idxs) # Compute R_mid according to our definition: return roa * (Rout - magR) + magR def _RZ2Quan(self, spline_func, R, Z, t, **kwargs): """Convert RZ to a given quantity. Utility function for converting R, Z coordinates to a variety of things that are interpolated from something measured on a uniform normalized flux grid, in particular phi_norm, vol_norm and R_mid. If tspline is False for this Equilibrium instance, uses scipy.interpolate.RectBivariateSpline to interpolate in terms of R and Z. Finds the nearest time slices to those given: nearest-neighbor interpolation in time. Otherwise, uses the tricubic package to perform a trivariate interpolation in space and time. Args: spline_func (callable): Function which returns a 1d spline for the quantity you want to convert into as a function of psi_norm given a time index. R (Array-like or scalar float): Values of the radial coordinate to map to Quan. If R and Z are both scalar values, they are used as the coordinate pair for all of the values in t. Must have the same shape as Z unless the make_grid keyword is set. If the make_grid keyword is True, R must have shape (len_R,). Z (Array-like or scalar float): Values of the vertical coordinate to map to Quan. If R and Z are both scalar values, they are used as the coordinate pair for all of the values in t. Must have the same shape as R unless the make_grid keyword is set. If the make_grid keyword is True, Z must have shape (len_Z,). t (Array-like or single value): If t is a single value, it is used for all of the elements of R, Z. If t is array-like and the make_grid keyword is False, t must have the same dimensions as R and Z. If t is array-like and the make_grid keyword is True, t must have shape (len(Z), len(R)). Keyword Args: each_t (Boolean): When True, the elements in `R` and `Z` (or the meshgrid thereof if `make_grid` is True) are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` (or their meshgrid if `make_grid` is True) or be a scalar. Default is True (evaluate ALL `R`, `Z` at each element in `t`). return_t (Boolean): Set to True to return a tuple of (Quan, time_idxs), where time_idxs is the array of time indices actually used in evaluating R_mid with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return Quan). sqrt (Boolean): Set to True to return the square root of Quan. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False (return Quan itself). make_grid (Boolean): Set to True to pass R and Z through meshgrid before evaluating. If this is set to True, R and Z must each only have a single dimension, but can have different lengths. When using this option, it is highly recommended to only pass a scalar value for t (such that each point in the flux grid is evaluated at this same value t). Otherwise, t must have the same shape as the resulting meshgrid, and each element in the returned psi array will be at the corresponding time in the t array. Default is False (do not form meshgrid). rho (Boolean): Set to True to return r/a (normalized minor radius) instead of R_mid. Default is False (return major radius, R_mid). Note that this will have unexpected results if spline_func returns anything other than R_mid. k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. length_unit (String or 1): Length unit that R and Z are being given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (R and Z given in meters). Note that this factor is ONLY applied to the inputs in this function -- if Quan needs to be corrected, it must be done in the calling function. Returns: Quan: Array or scalar float. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array instance is returned. If R and Z both have the same shape then Quand has this shape as well. If the make_grid keyword was True then R_mid has shape (len(Z), len(R)). time_idxs: Array with same shape as R_mid. The indices (in self.getTimeBase()) that were used for nearest-neighbor interpolation. Only returned if return_t is True. """ return_t = kwargs.get('return_t', False) kwargs['return_t'] = True # Not used by rz2psinorm: k = kwargs.pop('k', 3) rho = kwargs.pop('rho', False) # Make sure we don't convert to sqrtpsinorm first! sqrt = kwargs.pop('sqrt', False) psi_norm, blob = self.rz2psinorm(R, Z, t, **kwargs) kwargs['sqrt'] = sqrt kwargs['return_t'] = return_t # Not used by _psinorm2Quan kwargs.pop('length_unit', 1) kwargs.pop('make_grid', False) kwargs['rho'] = rho return self._psinorm2Quan( spline_func, psi_norm, t, blob=blob, k=k, **kwargs ) def _Rmid2Quan(self, spline_func, R_mid, t, **kwargs): """Convert R_mid to a given quantity. Utility function for converting R, Z coordinates to a variety of things that are interpolated from something measured on a uniform normalized flux grid, in particular phi_norm and vol_norm. If tspline is False for this Equilibrium instance, uses scipy.interpolate.RectBivariateSpline to interpolate in terms of R and Z. Finds the nearest time slices to those given: nearest-neighbor interpolation in time. Otherwise, uses the tricubic package to perform a trivariate interpolation in space and time. Args: spline_func (callable): Function which returns a 1d spline for the quantity you want to convert into as a function of psi_norm given a time index. R_mid (Array-like or scalar float): Values of the radial coordinate to map to Quan. t (Array-like or single value): If t is a single value, it is used for all of the elements of R_mid. If t is array-like it must have the same dimensions as R_mid. Keyword Args: each_t (Boolean): When True, the elements in `R` and `Z` (or the meshgrid thereof if `make_grid` is True) are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` (or their meshgrid if `make_grid` is True) or be a scalar. Default is True (evaluate ALL `R`, `Z` at each element in `t`). return_t (Boolean): Set to True to return a tuple of (Quan, time_idxs), where time_idxs is the array of time indices actually used in evaluating R_mid with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return Quan). sqrt (Boolean): Set to True to return the square root of Quan. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False (return Quan itself). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. length_unit (String or 1): Length unit that R and Z are being given in. If a string is given, it must be a valid unit specifier: 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters If length_unit is 1 or None, meters are assumed. The default value is 1 (R_mid given in meters). Note that this factor is ONLY applied to the inputs in this function -- if Quan needs to be corrected, it must be done in the calling function. Returns: Quan: Array or scalar float. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array instance is returned. Has the same shape as R_mid. time_idxs: Array with same shape as Quan. The indices (in self.getTimeBase()) that were used for nearest-neighbor interpolation. Only returned if return_t is True. """ return_t = kwargs.get('return_t', False) kwargs['return_t'] = True # Not used by rmid2psinorm: k = kwargs.pop('k', 3) rho = kwargs.pop('rho', False) sqrt = kwargs.pop('sqrt', False) psi_norm, blob = self.rmid2psinorm(R_mid, t, **kwargs) kwargs['sqrt'] = sqrt kwargs.pop('convert_roa', False) kwargs['blob'] = blob kwargs['k'] = k kwargs['return_t'] = return_t kwargs['rho'] = rho # Not used by _psinorm2Quan kwargs.pop('length_unit', 1) kwargs.pop('make_grid', False) return self._psinorm2Quan( spline_func, psi_norm, t, **kwargs ) def _phinorm2Quan(self, spline_func, phinorm, t, **kwargs): """Convert phinorm to a given quantity. Utility function for converting phinorm coordinates to a variety of things that are interpolated from something measured on a uniform normalized flux grid, in particular psi_norm and vol_norm. If tspline is False for this Equilibrium instance, uses scipy.interpolate.RectBivariateSpline to interpolate in terms of R and Z. Finds the nearest time slices to those given: nearest-neighbor interpolation in time. Otherwise, uses the tricubic package to perform a trivariate interpolation in space and time. Args: spline_func (callable): Function which returns a 1d spline for the quantity you want to convert into as a function of psi_norm given a time index. phinorm (Array-like or scalar float): Values of the normalized toroidal flux to map to `Quan`. t (Array-like or single value): If `t` is a single value, it is used for all of the elements of `phinorm`. If `t` is array-like it must have the same dimensions as `phinorm`. Keyword Args: each_t (Boolean): When True, the elements in `phinorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `phinorm` or be a scalar. Default is True (evaluate ALL `phinorm` at each element in `t`). return_t (Boolean): Set to True to return a tuple of (`Quan`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `phinorm` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `Quan`). sqrt (Boolean): Set to True to return the square root of `Quan`. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False (return Quan itself). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. Returns: Quan: Array or scalar float. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array instance is returned. Has the same shape as `phinorm`. time_idxs: Array with same shape as `Quan`. The indices (in self.getTimeBase()) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. """ return_t = kwargs.get('return_t', False) kwargs['return_t'] = True # Not used by phinorm2psinorm: k = kwargs.pop('k', 3) rho = kwargs.pop('rho', False) sqrt = kwargs.pop('sqrt', False) psi_norm, blob = self.phinorm2psinorm(phinorm, t, **kwargs) kwargs['sqrt'] = sqrt kwargs['return_t'] = return_t kwargs['rho'] = rho kwargs['k'] = k # Not used by _psinorm2Quan kwargs.pop('length_unit', 1) return self._psinorm2Quan( spline_func, psi_norm, t, blob=blob, **kwargs ) def _volnorm2Quan(self, spline_func, volnorm, t, **kwargs): """Convert volnorm to a given quantity. Utility function for converting volnorm coordinates to a variety of things that are interpolated from something measured on a uniform normalized flux grid, in particular psi_norm and phi_norm. If tspline is False for this Equilibrium instance, uses scipy.interpolate.RectBivariateSpline to interpolate in terms of R and Z. Finds the nearest time slices to those given: nearest-neighbor interpolation in time. Otherwise, uses the tricubic package to perform a trivariate interpolation in space and time. Args: spline_func (callable): Function which returns a 1d spline for the quantity you want to convert into as a function of psi_norm given a time index. volnorm (Array-like or scalar float): Values of the normalized volume to map to `Quan`. t (Array-like or single value): If `t` is a single value, it is used for all of the elements of `volnorm`. If `t` is array-like it must have the same dimensions as `volnorm`. Keyword Args: each_t (Boolean): When True, the elements in `volnorm` are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `volnorm` or be a scalar. Default is True (evaluate ALL `volnorm` at each element in `t`). return_t (Boolean): Set to True to return a tuple of (`Quan`, `time_idxs`), where `time_idxs` is the array of time indices actually used in evaluating `phinorm` with nearest-neighbor interpolation. (This is mostly present as an internal helper.) Default is False (only return `Quan`). sqrt (Boolean): Set to True to return the square root of `Quan`. Only the square root of positive values is taken. Negative values are replaced with zeros, consistent with Steve Wolfe's IDL implementation efit_rz2rho.pro. Default is False (return Quan itself). k (positive int): The degree of polynomial spline interpolation to use in converting coordinates. Returns: Quan: Array or scalar float. If all of the input arguments are scalar, then a scalar is returned. Otherwise, a scipy Array instance is returned. Has the same shape as `volnorm`. time_idxs: Array with same shape as `Quan`. The indices (in self.getTimeBase()) that were used for nearest-neighbor interpolation. Only returned if `return_t` is True. """ return_t = kwargs.get('return_t', False) kwargs['return_t'] = True # Not used by phinorm2psinorm: k = kwargs.pop('k', 3) rho = kwargs.pop('rho', False) sqrt = kwargs.pop('sqrt', False) psi_norm, blob = self.volnorm2psinorm(volnorm, t, **kwargs) kwargs['sqrt'] = sqrt kwargs['return_t'] = return_t kwargs['rho'] = rho kwargs['k'] = k # Not used by _psinorm2Quan kwargs.pop('length_unit', 1) return self._psinorm2Quan( spline_func, psi_norm, t, blob=blob, **kwargs ) #################### # Helper Functions # #################### def _getLengthConversionFactor(self, start, end, default=None): """Gets the conversion factor to convert from units start to units end. Uses a regex to parse units of the form: 'm' 'm^2' 'm2' Leading and trailing spaces are NOT allowed. Valid unit specifiers are: 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands Args: start (String, int or None): Starting unit for the conversion. - If None, uses the unit specified when the instance was created. - If start is an int, the starting unit is taken to be the unit specified when the instance was created raised to that power. - If start is 'default', either explicitly or because of reverting to the instance-level unit, then the value passed in the kwarg default is used. In this case, default must be a complete unit string (i.e., not None, not an int and not 'default'). - Otherwise, start must be a valid unit specifier as given above. end (String, int or None): Target (ending) unit for the conversion. - If None, uses the unit specified when the instance was created. - If end is an int, the target unit is taken to be the unit specified when the instance was created raised to that power. - If end is 'default', either explicitly or because of reverting to the instance-level unit, then the value passed in the kwarg default is used. In this case, default must be a complete unit string (i.e., not None, not an int and not 'default'). - Otherwise, end must be a valid unit specifier as given above. In this case, if end does not specify an exponent, it uses whatever the exponent on start is. This allows a user to ask for an area in units of m^2 by specifying length_unit='m', for instance. An error will still be raised if the user puts in a completely inconsistent specification such as length_unit='m^3' or length_unit='m^1'. Keyword Args: default (String, int or None): The default unit to use in cases where start or end is 'default'. If default is None, an int, or 'default', then the value given for start is used. (A circular definition is prevented for cases in which start is default by checking for this case during the handling of the case start=='default'.) Returns: Conversion factor: Scalar float. The conversion factor to get from the start unit to the end unit. Raises: ValueError: If start is 'default' and default is None, an int, or 'default'. ValueError: If the (processed) exponents of start and end or start and default are incompatible. ValueError: If the processed units for start and end are not valid. """ # Input handling: # Starting unit: if start is None: # If start is None, it means to use the instance's default unit (implied to the power of 1): start = self._length_unit elif isinstance(start, (int, long)): # If start is an integer type, this is used as the power applied to the instance's default unit: if self._length_unit != 'default': start = self._length_unit + '^' + str(start) else: # If the instance's default unit is 'default', this is handled next: start = self._length_unit if start == 'default': # If start is 'default', the thing passed to default is used, but only if it is a complete unit specification: if ( default is None or isinstance(default, (int, long)) or default == 'default' ): raise ValueError("You must specify a complete unit (i.e., " "non-None, non-integer and not 'default') " "when using 'default' for the starting unit.") else: start = default # Default unit: if ( default is None or isinstance(default, (int, long)) or default == 'default' ): # If start is 'default', these cases have already been caught above. default = start # Target (ending) unit: if end is None: # If end is None, it means to use the instance's default unit (implied to the power of 1): end = self._length_unit elif isinstance(end, (int, long)): # If end is an integer type, this is used as the power applied to the instance's default unit: if self._length_unit != 'default': end = self._length_unit + '^' + str(end) else: # If the instance's default unit is 'default', this is handled next: end = self._length_unit if end == 'default': # If end is 'default', the thing passed to default is used, which # defaults to start, which itself is not allowed to be 'default': end = default unit_regex = r'^([A-Za-z]+)\^?([0-9]*)$' # Need to explicitly cast because MDSplus returns its own classes and # re.split doesn't seem to handle the polymorphism properly: start = str(start) end = str(end) default = str(default) dum1, start_u, start_pow, dum2 = re.split(unit_regex, start) dum1, end_u, end_pow, dum2 = re.split(unit_regex, end) dum1, default_u, default_pow, dum2 = re.split(unit_regex, default) start_pow = 1.0 if start_pow == '' else float(start_pow) if end_pow == '': end_pow = start_pow else: end_pow = float(end_pow) default_pow = 1.0 if default_pow == '' else float(default_pow) if start_pow != end_pow or start_pow != default_pow: raise ValueError( "Incompatible exponents between '%s', '%s' and '%s'!" % ( start, end, default ) ) try: return (_length_conversion[start_u][end_u])**start_pow except KeyError: raise ValueError( "Unit '%s' is not a recognized length unit!" % end ) def _processRZt( self, R, Z, t, make_grid=False, each_t=True, check_space=True, length_unit=1, convert_only=False, compute_unique=False ): """Input checker/processor. Takes R, Z and t. Appropriately packages them into scipy arrays. Checks the validity of the R, Z ranges. If there is a single time value but multiple R, Z values, creates matching time vector. If there is a single R, Z value but multiple t values, creates matching R and Z vectors. Finds list of nearest-neighbor time indices. Args: R (Array-like or scalar float): Values of the radial coordinate. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `Z` unless the `make_grid` keyword is True. If `make_grid` is True, `R` must have only one dimension (or be a scalar). Z (Array-like or scalar float): Values of the vertical coordinate. If `R` and `Z` are both scalar values, they are used as the coordinate pair for all of the values in `t`. Must have the same shape as `R` unless the `make_grid` keyword is True. If `make_grid` is True, `Z` must have only one dimension. t (Array-like or single value): If `t` is a single value, it is used for all of the elements of `R`, `Z`. If `t` is array-like and `make_grid` is False, `t` must have the same dimensions as `R` and `Z`. If `t` is array-like and `make_grid` is True, `t` must have shape (len(Z), len(R)). Keyword Args: make_grid (Boolean): Set to True to pass `R` and `Z` through :py:func:`meshgrid` before evaluating. If this is set to True, `R` and `Z` must each only have a single dimension, but can have different lengths. Default is False (do not form meshgrid). each_t (Boolean): When True, the elements in `R` and `Z` (or the meshgrid thereof if `make_grid` is True) are evaluated at each value in `t`. If True, `t` must have only one dimension (or be a scalar). If False, `t` must match the shape of `R` and `Z` (or their meshgrid if `make_grid` is True) or be a scalar. Default is True (evaluate ALL `R`, `Z` at each element in `t`). check_space (Boolean): If True, `R` and `Z` are converted to meters and checked against the extents of the spatial grid. length_unit (String or 1): Length unit that `R` and `Z` are being given in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (R and Z given in meters). Note that this factor is ONLY applied to the inputs in this function -- if Quan needs to be corrected, it must be done in the calling function. Returns: Tuple of: * **R** - Flattened `R` array with out-of-range values replaced with NaN. * **Z** - Flattened `Z` array with out-of-range values replaced with NaN. * **t** - Flattened `t` array with out-of-range values replaced with NaN. * **time_idxs** - Flattened array of nearest-neighbor time indices. None if :py:attr:`self._tricubic`. * **unique_idxs** - 1d array of the unique values in time_idxs, can be used to save time elsewhere. None if :py:attr:`self._tricubic`. * **single_time** - Boolean indicating whether a single time value is used. If True, then certain simplifying steps can be made and the output should be unwrapped before returning to ensure the least surprise. * **original_shape** - Original shape tuple, used to return the arrays to their starting form. If `single_time` or `each_t` is True, this is the shape of the (expanded) `R`, `Z` arrays. It is assumed that time will be added as the leading dimension. """ # Get everything into sensical datatypes. Must force it to be float to # keep scipy.interpolate happy. R = scipy.asarray(R, dtype=float) Z = scipy.asarray(Z, dtype=float) t = scipy.asarray(t, dtype=float) single_time = (t.ndim == 0) single_val = (R.ndim == 0) and (Z.ndim == 0) # Check the shape of t: if each_t and t.ndim > 1: raise ValueError( "_processRZt: When using the each_t keyword, t can have at most " "one dimension!" ) # Form the meshgrid and check the input dimensions as needed: if make_grid: if R.ndim != 1 or Z.ndim != 1: raise ValueError( "_processRZt: When using the make_grid keyword, the number " "of dimensions of R and Z must both be one!" ) R, Z = scipy.meshgrid(R, Z) else: if R.shape != Z.shape: raise ValueError( "_processRZt: Shape of R and Z arrays must match! Use " "make_grid=True to form a meshgrid from 1d R, Z arrays." ) if not single_time and not each_t and t.shape != R.shape: raise ValueError( "_processRZt: Shape of t does not match shape of R and Z!" ) # Check that the R, Z points lie within the grid: if check_space: # Convert units to meters: unit_factor = self._getLengthConversionFactor( length_unit, 'm', default='m' ) R = unit_factor * R Z = unit_factor * Z if not convert_only: good_points, num_good = self._checkRZ(R, Z) if num_good < 1: raise ValueError('_processRZt: No valid points!') # Handle bug in older scipy: if R.ndim == 0: if not good_points: R = scipy.nan else: scipy.place(R, ~good_points, scipy.nan) if Z.ndim == 0: if not good_points: Z = scipy.nan else: scipy.place(Z, ~good_points, scipy.nan) if self._tricubic: # When using tricubic spline interpolation, the arrays must be # replicated when using the each_t keyword. if single_time: t = t * scipy.ones_like(R, dtype=float) elif each_t: R = scipy.tile(R, [len(t), ] + [1, ] * R.ndim) Z = scipy.tile(Z, [len(t), ] + [1, ] * Z.ndim) t = t[scipy.indices(R.shape)[0]] time_idxs = None unique_idxs = None t = scipy.reshape(t, -1) else: t = scipy.reshape(t, -1) timebase = self.getTimeBase() # Get nearest-neighbor points: time_idxs = self._getNearestIdx(t, timebase) # Check errors and warn if needed: t_errs = scipy.absolute(t - timebase[time_idxs]) # Assume a constant sampling rate to save time: if ( len(time_idxs) > 1 and (t_errs > ((timebase[1] - timebase[0]) / 3.0)).any() ): warnings.warn( "Some time points are off by more than 1/3 the EFIT point " "spacing. Using nearest-neighbor interpolation between time " "points. You may want to run EFIT on the timebase you need. " "Max error: %.3fs" % (max(t_errs),), RuntimeWarning ) if compute_unique and not single_time and not each_t: unique_idxs = scipy.unique(time_idxs) else: unique_idxs = None original_shape = R.shape R = scipy.reshape(R, -1) Z = scipy.reshape(Z, -1) return ( R, Z, t, time_idxs, unique_idxs, single_time, single_val, original_shape ) def _checkRZ(self, R, Z): """Checks whether or not the passed arrays of (R, Z) are within the bounds of the reconstruction data. Returns the mask array of booleans indicating the goodness of each point at the corresponding index. Raises warnings if there are no good_points and if there are some values out of bounds. Assumes R and Z are in meters and that the R and Z arrays returned by this instance's getRGrid() and getZGrid() are monotonically increasing. Args: R (Array): Radial coordinate to check. Must have the same size as Z. Z (Array) Vertical coordinate to check. Must have the same size as R. Returns: good_points: Boolean array. True where points are within the bounds defined by self.getRGrid and self.getZGrid. num_good: The number of good points. """ good_points = ((R <= self.getRGrid(length_unit='m')[-1]) & (R >= self.getRGrid(length_unit='m')[0]) & (Z <= self.getZGrid(length_unit='m')[-1]) & (Z >= self.getZGrid(length_unit='m')[0])) # Gracefully handle single-value versus array inputs, returning in the # corresponding type. num_good = scipy.sum(good_points) test = scipy.array(R) if len(test.shape) > 0: num_pts = test.size else: num_good = good_points num_pts = 1 if num_good == 0: warnings.warn("Warning: _checkRZ: No valid (R, Z) points!", RuntimeWarning) elif num_good != num_pts: warnings.warn("Warning: _checkRZ: Some (R, Z) values out of bounds. " "(%(bad)d bad out of %(tot)d)" % {'bad': num_pts - num_good, 'tot': num_pts}, RuntimeWarning) return (good_points, num_good) def _getNearestIdx(self, v, a): """Returns the array of indices of the nearest value in a corresponding to each value in v. If the monotonic keyword in the instance is True, then this is done using scipy.digitize under the assumption that a is monotonic. Otherwise, this is done in a general manner by looking for the minimum distance between the points in v and a. Args: v (Array): Input values to match to nearest neighbors in a. a (Array): Given values to match against. Returns: Indices in a of the nearest values to each value in v. Has the same shape as v. """ # Gracefully handle single-value versus array inputs, returning in the # corresponding type. if not self._monotonic: try: return scipy.array( [(scipy.absolute(a - val)).argmin() for val in v] ) except TypeError: return (scipy.absolute(a - v)).argmin() else: try: return scipy.digitize(v, (a[1:] + a[:-1]) / 2.0) except ValueError: return scipy.digitize( scipy.atleast_1d(v), (a[1:] + a[:-1]) / 2.0 ).reshape(()) def _getFluxBiSpline(self, idx): """Gets the spline corresponding to the given time index, generating as needed. This returns a bivariate spline for when the instance is created with keyword tspline=False. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Returns: An instance of scipy.interpolate.RectBivariateSpline corresponding to the given time index idx. """ try: return self._psiOfRZSpline[idx] except KeyError: # Note the order of the arguments -- psiRZ is stored with t along # the first dimension, Z along the second and R along the third. # This leads to intuitive behavior when contour plotting, but # mandates the syntax here. self._psiOfRZSpline[idx] = scipy.interpolate.RectBivariateSpline( self.getZGrid(length_unit='m'), self.getRGrid(length_unit='m'), self.getFluxGrid()[idx, :, :], s=0 ) return self._psiOfRZSpline[idx] def _getFluxTriSpline(self): """Gets the tricubic interpolating spline for the flux. This is for use when the instance is created with keyword tspline=True. Returns: trispline.spline to give the flux as a function of R, Z and t. """ if self._psiOfRZSpline: return self._psiOfRZSpline else: self._psiOfRZSpline = trispline.Spline( self.getTimeBase(), self.getZGrid(length_unit='m'), self.getRGrid(length_unit='m'), self.getFluxGrid() ) return self._psiOfRZSpline def _getPhiNormSpline(self, idx, k=3): """Get spline to convert psinorm to phinorm. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._phiNormSpline[idx][k] except KeyError: # Insert zero at beginning because older versions of cumtrapz # don't support the initial keyword to make the initial value # zero: # we need to add the psi axis x = ( scipy.linspace(0, 1, num=self.getQProfile()[idx].size) * (self.getFluxLCFS()[idx] - self.getFluxAxis()[idx]) ) phi_norm_meas = scipy.insert( scipy.integrate.cumtrapz(self.getQProfile()[idx], x=x), 0, 0 ) phi_norm_meas = phi_norm_meas / phi_norm_meas[-1] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(phi_norm_meas)), phi_norm_meas, k=k ) try: self._phiNormSpline[idx][k] = spline except KeyError: self._phiNormSpline[idx] = {k: spline} return self._phiNormSpline[idx][k] else: if self._phiNormSpline: return self._phiNormSpline else: # Insert zero at beginning because older versions of cumtrapz # don't support the initial keyword to make the initial value # zero: phi_norm_meas = scipy.insert( scipy.integrate.cumtrapz(self.getQProfile(), axis=1), 0, 0, axis=1 ) phi_norm_meas = phi_norm_meas / phi_norm_meas[:, -1, scipy.newaxis] self._phiNormSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0, 1, len(phi_norm_meas[0, :])), phi_norm_meas, bounds_error=False, s=0 ) return self._phiNormSpline def _getPhiNormToPsiNormSpline(self, idx, k=3): """Get spline to convert phinorm to psinorm. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._phiNormToPsiNormSpline[idx][k] except KeyError: # Insert zero at beginning because older versions of cumtrapz # don't support the initial keyword to make the initial value # zero: x = ( scipy.linspace(0, 1, num=self.getQProfile()[idx].size) * (self.getFluxLCFS()[idx] - self.getFluxAxis()[idx]) ) phi_norm_meas = scipy.insert( scipy.integrate.cumtrapz(self.getQProfile()[idx], x=x), 0, 0 ) phi_norm_meas = phi_norm_meas / phi_norm_meas[-1] spline = trispline.UnivariateInterpolator( phi_norm_meas, scipy.linspace(0.0, 1.0, len(phi_norm_meas)), k=k ) try: self._phiNormToPsiNormSpline[idx][k] = spline except KeyError: self._phiNormToPsiNormSpline[idx] = {k: spline} return self._phiNormToPsiNormSpline[idx][k] else: if self._phiNormToPsiNormSpline: return self._phiNormToPsiNormSpline else: # Insert zero at beginning because older versions of cumtrapz # don't support the initial keyword to make the initial value # zero: phi_norm_meas = scipy.insert( scipy.integrate.cumtrapz(self.getQProfile(), axis=1), 0, 0, axis=1 ) phi_norm_meas = phi_norm_meas / phi_norm_meas[:, -1, scipy.newaxis] psinorm_grid, t_grid = scipy.meshgrid( scipy.linspace(0, 1, phi_norm_meas.shape[1]), self.getTimeBase() ) self._phiNormToPsiNormSpline = trispline.BivariateInterpolator( t_grid.ravel(), phi_norm_meas.ravel(), psinorm_grid.ravel() ) return self._phiNormToPsiNormSpline def _getVolNormSpline(self, idx, k=3): """Get spline to convert psinorm to volnorm. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._volNormSpline[idx][k] except KeyError: vol_norm_meas = self.getFluxVol()[idx] vol_norm_meas = vol_norm_meas / vol_norm_meas[-1] spline = trispline.UnivariateInterpolator( scipy.linspace(0, 1, len(vol_norm_meas)), vol_norm_meas, k=k ) try: self._volNormSpline[idx][k] = spline except KeyError: self._volNormSpline[idx] = {k: spline} return self._volNormSpline[idx][k] else: # BiSpline for time variant interpolation if self._volNormSpline: return self._volNormSpline else: vol_norm_meas = self.getFluxVol() vol_norm_meas = vol_norm_meas / vol_norm_meas[:, -1, scipy.newaxis] self._volNormSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0, 1, len(vol_norm_meas[0, :])), vol_norm_meas, bounds_error=False, s=0 ) return self._volNormSpline def _getVolNormToPsiNormSpline(self, idx, k=3): """Get spline to convert volnorm to psinorm. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._volNormToPsiNormSpline[idx][k] except KeyError: vol_norm_meas = self.getFluxVol()[idx] vol_norm_meas = vol_norm_meas / vol_norm_meas[-1] spline = trispline.UnivariateInterpolator( vol_norm_meas, scipy.linspace(0.0, 1.0, len(vol_norm_meas)), k=k ) try: self._volNormToPsiNormSpline[idx][k] = spline except KeyError: self._volNormToPsiNormSpline[idx] = {k: spline} return self._volNormToPsiNormSpline[idx][k] else: # BiSpline for time variant interpolation if self._volNormToPsiNormSpline: return self._volNormToPsiNormSpline else: vol_norm_meas = self.getFluxVol() vol_norm_meas = vol_norm_meas / vol_norm_meas[:, -1, scipy.newaxis] psinorm_grid, t_grid = scipy.meshgrid( scipy.linspace(0, 1, len(vol_norm_meas[0, :])), self.getTimeBase() ) self._volNormToPsiNormSpline = trispline.BivariateInterpolator( t_grid.ravel(), vol_norm_meas.ravel(), psinorm_grid.ravel() ) return self._volNormToPsiNormSpline def _getRmidSpline(self, idx, k=3): """Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. There are two approaches that come to mind: -- In Steve Wolfe's implementation of efit_rz2mid and efit_psi2rmid, he uses the EFIT output Rmid as a function of normalized flux (i.e., what is returned by self.getRmidPsi()) in the core, then expands the grid beyond this manually. -- A simpler approach would be to just compute the psi_norm(R_mid) grid directly from the radial grid. The latter approach is selected for simplicity. The units of R_mid are always meters, and are converted by the wrapper functions to whatever the user wants. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._RmidSpline[idx][k] except KeyError: # New approach: create a fairly dense radial grid from the # global flux grid to avoid 1d interpolation problems in the # core. The bivariate spline seems to be a little more robust # in this respect. resample_factor = 3 R_grid = scipy.linspace( self.getMagR(length_unit='m')[idx], self.getRGrid(length_unit='m')[-1], resample_factor * len(self.getRGrid(length_unit='m')) ) psi_norm_on_grid = self.rz2psinorm( R_grid, self.getMagZ(length_unit='m')[idx] * scipy.ones(R_grid.shape), self.getTimeBase()[idx] ) # Correct for the slight issues at the magnetic axis: psi_norm_on_grid[0] = 0.0 # Find if it ever goes non-monotonic: psinorm is assumed to be # strictly INCREASING from the magnetic axis out. decr_idx, = scipy.where( (psi_norm_on_grid[1:] - psi_norm_on_grid[:-1]) < 0 ) if len(decr_idx) > 0: psi_norm_on_grid = psi_norm_on_grid[:decr_idx[0] + 1] R_grid = R_grid[:decr_idx[0] + 1] spline = trispline.UnivariateInterpolator( psi_norm_on_grid, R_grid, k=k ) try: self._RmidSpline[idx][k] = spline except KeyError: self._RmidSpline[idx] = {k: spline} return self._RmidSpline[idx][k] else: if self._RmidSpline: return self._RmidSpline else: resample_factor = 3 * len(self.getRGrid(length_unit='m')) # generate timebase and R_grid through a meshgrid t, R_grid = scipy.meshgrid( self.getTimeBase(), scipy.zeros((resample_factor,)) ) Z_grid = scipy.dot( scipy.ones((resample_factor, 1)), scipy.atleast_2d(self.getMagZ(length_unit='m')) ) for idx in scipy.arange(self.getTimeBase().size): R_grid[:, idx] = scipy.linspace( self.getMagR(length_unit='m')[idx], self.getRGrid(length_unit='m')[-1], resample_factor ) psi_norm_on_grid = self.rz2psinorm( R_grid, Z_grid, t, each_t=False ) # Correct for the slight issues at the magnetic axis: psi_norm_on_grid[0, :] = 0.0 self._RmidSpline = trispline.BivariateInterpolator( t.ravel(), psi_norm_on_grid.ravel(), R_grid.ravel() ) return self._RmidSpline def _getRmidToPsiNormSpline(self, idx, k=3): """Get the spline which converts Rmid to psinorm. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. There are two approaches that come to mind: -- In Steve Wolfe's implementation of efit_rz2mid and efit_psi2rmid, he uses the EFIT output Rmid as a function of normalized flux (i.e., what is returned by self.getRmidPsi()) in the core, then expands the grid beyond this manually. -- A simpler approach would be to just compute the psi_norm(R_mid) grid directly from the radial grid. The latter approach is selected for simplicity. The units of R_mid are always meters, and are converted by the wrapper functions to whatever the user wants. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._RmidToPsiNormSpline[idx][k] except KeyError: # New approach: create a fairly dense radial grid from the global # flux grid to avoid 1d interpolation problems in the core. The # bivariate spline seems to be a little more robust in this respect. resample_factor = 3 R_grid = scipy.linspace( # self.getMagR(length_unit='m')[idx], self.getRGrid(length_unit='m')[0], self.getRGrid(length_unit='m')[-1], resample_factor * len(self.getRGrid(length_unit='m')) ) psi_norm_on_grid = self.rz2psinorm( R_grid, self.getMagZ(length_unit='m')[idx] * scipy.ones(R_grid.shape), self.getTimeBase()[idx] ) spline = trispline.UnivariateInterpolator( R_grid, psi_norm_on_grid, k=k ) try: self._RmidToPsiNormSpline[idx][k] = spline except KeyError: self._RmidToPsiNormSpline[idx] = {k: spline} return self._RmidToPsiNormSpline[idx][k] else: if self._RmidToPsiNormSpline: return self._RmidToPsiNormSpline else: resample_factor = 3 * len(self.getRGrid(length_unit='m')) # generate timebase and R_grid through a meshgrid t, R_grid = scipy.meshgrid( self.getTimeBase(), scipy.zeros((resample_factor,)) ) Z_grid = scipy.dot( scipy.ones((resample_factor, 1)), scipy.atleast_2d(self.getMagZ(length_unit='m')) ) for idx in scipy.arange(self.getTimeBase().size): # TODO: This can be done much more efficiently! R_grid[:, idx] = scipy.linspace( self.getRGrid(length_unit='m')[0], self.getRGrid(length_unit='m')[-1], resample_factor ) psi_norm_on_grid = self.rz2psinorm( R_grid, Z_grid, t, each_t=False ) self._RmidToPsiNormSpline = trispline.BivariateInterpolator( t.flatten(), R_grid.flatten(), psi_norm_on_grid.flatten() ) return self._RmidToPsiNormSpline def _getQSpline(self, idx, k=3): """Get spline to convert psinorm to q. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._qSpline[idx][k] except KeyError: q = self.getQProfile()[idx] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(q)), q, k=k ) try: self._qSpline[idx][k] = spline except KeyError: self._qSpline[idx] = {k: spline} return self._qSpline[idx][k] else: if self._qSpline: return self._qSpline else: q = self.getQProfile() self._qSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0.0, 1.0, q.shape[1]), q, bounds_error=False, s=0 ) return self._qSpline def _getFSpline(self, idx, k=3): """Get spline to convert psinorm to F. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._FSpline[idx][k] except KeyError: F = self.getF()[idx] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(F)), F, k=k ) try: self._FSpline[idx][k] = spline except KeyError: self._FSpline[idx] = {k: spline} return self._FSpline[idx][k] else: if self._FSpline: return self._FSpline else: F = self.getF() self._FSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0.0, 1.0, F.shape[1]), F, bounds_error=False, s=0 ) return self._FSpline def _getFNormToPsiNormSpline(self, idx, k=3): """Get spline to convert normalized F to psinorm. This is provided to help plot current densities. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the spline for. This is ASSUMED to be a valid index for the first dimension of :py:meth:`getFluxGrid`, otherwise an :py:class:`IndexError` will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._FToPsinormSpline[idx][k] except KeyError: F = self.getF()[idx] F = (F - F.min()) / (F.max() - F.min()) psinorm_grid = scipy.linspace(0.0, 1.0, len(F)) # Find if it ever goes non-monotonic: F hacked to be # strictly INCREASING from the magnetic axis out. if self.getCurrentSign() == 1.0: incr_idx, = scipy.where((F[1:] - F[:-1]) > 0) if len(incr_idx) > 0: F = F[:incr_idx[0] + 1] psinorm_grid = psinorm_grid[:incr_idx[0] + 1] # Flip it to be INCREASING: F = F[::-1] psinorm_grid = psinorm_grid[::-1] else: decr_idx, = scipy.where((F[1:] - F[:-1]) < 0) if len(decr_idx) > 0: F = F[:decr_idx[0] + 1] psinorm_grid = psinorm_grid[:decr_idx[0] + 1] spline = trispline.UnivariateInterpolator(F, psinorm_grid, k=k) try: self._FToPsinormSpline[idx][k] = spline except KeyError: self._FToPsinormSpline[idx] = {k: spline} return self._FToPsinormSpline[idx][k] else: if self._FToPsinormSpline: return self._FToPsinormSpline else: F = self.getF() F = (F - F.min(axis=1)[:, None]) / (F.max(axis=1) - F.min(axis=1))[:, None] self._FToPsinormSpline = trispline.RectBivariateSpline( self.getTimeBase(), F, scipy.linspace(0.0, 1.0, F.shape[1]), bounds_error=False, s=0 ) return self._FToPsinormSpline def _getFFPrimeSpline(self, idx, k=3): """Get spline to convert psinorm to FFPrime. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._FFPrimeSpline[idx][k] except KeyError: FFPrime = self.getFFPrime()[idx] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(FFPrime)), FFPrime, k=k ) try: self._FFPrimeSpline[idx][k] = spline except KeyError: self._FFPrimeSpline[idx] = {k: spline} return self._FFPrimeSpline[idx][k] else: if self._FFPrimeSpline: return self._FFPrimeSpline else: FFPrime = self.getFFPrime() self._FFPrimeSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0.0, 1.0, FFPrime.shape[1]), FFPrime, bounds_error=False, s=0 ) return self._FFPrimeSpline def _getPSpline(self, idx, k=3): """Get spline to convert psinorm to pressure. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._pSpline[idx][k] except KeyError: p = self.getFluxPres()[idx] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(p)), p, k=k ) try: self._pSpline[idx][k] = spline except KeyError: self._pSpline[idx] = {k: spline} return self._pSpline[idx][k] else: if self._pSpline: return self._pSpline else: p = self.getFluxPres() self._pSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0.0, 1.0, p.shape[1]), p, bounds_error=False, s=0 ) return self._pSpline def _getPPrimeSpline(self, idx, k=3): """Get spline to convert psinorm to pressure gradient. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._pPrimeSpline[idx][k] except KeyError: pprime = self.getPPrime()[idx] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(pprime)), pprime, k=k ) try: self._pPrimeSpline[idx][k] = spline except KeyError: self._pPrimeSpline[idx] = {k: spline} return self._pPrimeSpline[idx][k] else: if self._pPrimeSpline: return self._pPrimeSpline else: pprime = self.getPPrime() self._pPrimeSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0.0, 1.0, pprime.shape[1]), pprime, bounds_error=False, s=0 ) return self._pPrimeSpline def _getVSpline(self, idx, k=3): """Get spline to convert psinorm to flux surface volume. Returns the spline object corresponding to the passed time index idx, generating it if it does not already exist. Args: idx (Scalar int): The time index to retrieve the flux spline for. This is ASSUMED to be a valid index for the first dimension of self.getFluxGrid(), otherwise an IndexError will be raised. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`tripline.RectBivariateSpline` depending on whether or not the instance was created with the `tspline` keyword. """ if not self._tricubic: try: return self._vSpline[idx][k] except KeyError: v = self.getFluxVol()[idx] spline = trispline.UnivariateInterpolator( scipy.linspace(0.0, 1.0, len(v)), v, k=k ) try: self._vSpline[idx][k] = spline except KeyError: self._vSpline[idx] = {k: spline} return self._vSpline[idx][k] else: if self._vSpline: return self._vSpline else: v = self.getFluxVol() self._vSpline = trispline.RectBivariateSpline( self.getTimeBase(), scipy.linspace(0.0, 1.0, v.shape[1]), v, bounds_error=False, s=0 ) return self._vSpline def _getPsi0Spline(self, k=3): """Gets the univariate spline to interpolate psi0 as a function of time. Only used if the instance was created with keyword tspline=True. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` """ if self._psiOfPsi0Spline: return self._psiOfPsi0Spline else: try: self._psiOfPsi0Spline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getFluxAxis(), k=k ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._psiOfPsi0Spline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getFluxAxis() ) return self._psiOfPsi0Spline def _getLCFSPsiSpline(self, k=3): """Gets the univariate spline to interpolate psi_a as a function of time. Only used if the instance was created with keyword tspline=True. Keyword Args: k (positive int) Polynomial degree of spline to use. Default is 3. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` """ if self._psiOfLCFSSpline: return self._psiOfLCFSSpline else: try: self._psiOfLCFSSpline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getFluxLCFS(), k=k ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._psiOfLCFSSpline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getFluxLCFS() ) return self._psiOfLCFSSpline
[docs] def getMagRSpline(self, length_unit=1, kind='nearest'): """Gets the univariate spline to interpolate R_mag as a function of time. Only used if the instance was created with keyword tspline=True. Keyword Args: length_unit (String or 1): Length unit that R_mag is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (R_out returned in meters). kind (String or non-negative int): Specifies the type of interpolation to be performed in getting from t to R_mag. This is passed to :py:class:`scipy.interpolate.interp1d`. Valid options are: 'linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic' If this keyword is an integer, it specifies the order of spline to use. See the documentation for interp1d for more details. Default value is 'cubic' (3rd order spline interpolation) when `trispline` is True, 'nearest' otherwise. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` to convert from t to MagR. """ if self._magRSpline: return self._magRSpline else: try: if self._tricubic: self._magRSpline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getMagR(length_unit=length_unit), k=3 ) else: self._magRSpline = scipy.interpolate.interp1d( self.getTimeBase(), self.getMagR(length_unit=length_unit), kind=kind, bounds_error=False ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._magRSpline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getMagR(length_unit=length_unit) ) return self._magRSpline
[docs] def getMagZSpline(self, length_unit=1, kind='nearest'): """Gets the univariate spline to interpolate Z_mag as a function of time. Generated for completeness of the core position calculation when using tspline = True Keyword Args: length_unit (String or 1): Length unit that R_mag is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (R_out returned in meters). kind (String or non-negative int): Specifies the type of interpolation to be performed in getting from t to Z_mag. This is passed to :py:class:`scipy.interpolate.interp1d`. Valid options are: 'linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic' If this keyword is an integer, it specifies the order of spline to use. See the documentation for interp1d for more details. Default value is 'cubic' (3rd order spline interpolation) when `trispline` is True, 'nearest' otherwise. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` to convert from t to MagZ. """ if self._magZSpline: return self._magZSpline else: try: if self._tricubic: self._magZSpline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getMagZ(length_unit=length_unit), k=3 ) else: self._magZSpline = scipy.interpolate.interp1d( self.getTimeBase(), self.getMagZ(length_unit=length_unit), kind=kind, bounds_error=False ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._magZSpline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getMagZ(length_unit=length_unit) ) return self._magZSpline
[docs] def getRmidOutSpline(self, length_unit=1, kind='nearest'): """Gets the univariate spline to interpolate R_mid_out as a function of time. Generated for completeness of the core position calculation when using tspline = True Keyword Args: length_unit (String or 1): Length unit that R_mag is returned in. If a string is given, it must be a valid unit specifier: =========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters =========== =========== If length_unit is 1 or None, meters are assumed. The default value is 1 (R_out returned in meters). kind (String or non-negative int): Specifies the type of interpolation to be performed in getting from t to R_mid_out. This is passed to :py:class:`scipy.interpolate.interp1d`. Valid options are: 'linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic' If this keyword is an integer, it specifies the order of spline to use. See the documentation for interp1d for more details. Default value is 'cubic' (3rd order spline interpolation) when `trispline` is True, 'nearest' otherwise. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` to convert from t to R_mid. """ if self._RmidOutSpline: return self._RmidOutSpline else: try: if self._tricubic: self._RmidOutSpline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getRmidOut(length_unit=length_unit), k=3 ) else: self._RmidOutSpline = scipy.interpolate.interp1d( self.getTimeBase(), self.getRmidOut(length_unit=length_unit), kind=kind, bounds_error=False ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._RmidOutSpline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getRmidOut(length_unit=length_unit) ) return self._RmidOutSpline
[docs] def getAOutSpline(self, length_unit=1, kind='nearest'): """Gets the univariate spline to interpolate a_out as a function of time. Keyword Args: length_unit (String or 1): Length unit that a_out is returned in. If a string is given, it must be a valid unit specifier: ========== =========== 'm' meters 'cm' centimeters 'mm' millimeters 'in' inches 'ft' feet 'yd' yards 'smoot' smoots 'cubit' cubits 'hand' hands 'default' meters ========== =========== If `length_unit` is 1 or None, meters are assumed. The default value is 1 (a_out returned in meters). kind (String or non-negative int): Specifies the type of interpolation to be performed in getting from t to a_out. This is passed to :py:class:`scipy.interpolate.interp1d`. Valid options are: 'linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic' If this keyword is an integer, it specifies the order of spline to use. See the documentation for interp1d for more details. Default value is 'cubic' (3rd order spline interpolation) when `trispline` is True, 'nearest' otherwise. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` to convert from t to a_out. """ if self._AOutSpline: return self._AOutSpline else: try: if self._tricubic: self._AOutSpline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getAOut(length_unit=length_unit), k=3 ) else: self._AOutSpline = scipy.interpolate.interp1d( self.getTimeBase(), self.getAOut(length_unit=length_unit), kind=kind, bounds_error=False ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._RmidOutSpline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getAOut(length_unit=length_unit) ) return self._AOutSpline
[docs] def getBtVacSpline(self, kind='nearest'): """Gets the univariate spline to interpolate BtVac as a function of time. Only used if the instance was created with keyword tspline=True. Keyword Args: kind (String or non-negative int): Specifies the type of interpolation to be performed in getting from t to BtVac. This is passed to :py:class:`scipy.interpolate.interp1d`. Valid options are: 'linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic' If this keyword is an integer, it specifies the order of spline to use. See the documentation for interp1d for more details. Default value is 'cubic' (3rd order spline interpolation) when `trispline` is True, 'nearest' otherwise. Returns: :py:class:`trispline.UnivariateInterpolator` or :py:class:`scipy.interpolate.interp1d` to convert from t to BtVac. """ if self._BtVacSpline: return self._BtVacSpline else: try: if self._tricubic: self._BtVacSpline = trispline.UnivariateInterpolator( self.getTimeBase(), self.getBtVac(), k=3 ) else: self._BtVacSpline = scipy.interpolate.interp1d( self.getTimeBase(), self.getBtVac(), kind=kind, bounds_error=False ) except ValueError: # created to allow for single time (such as gfiles) to properly # call this method self._BtVacSpline = scipy.interpolate.interp1d( [0.], [0.], kind='zero', bounds_error=False, fill_value=self.getBtVac() ) return self._BtVacSpline
[docs] def getInfo(self): """ Abstract method. See child classes for implementation. Returns namedtuple of instance parameters (shot, equilibrium type, size, timebase, etc.) """ raise NotImplementedError()
[docs] def getTimeBase(self): """ Abstract method. See child classes for implementation. Returns timebase array [t] """ raise NotImplementedError()
[docs] def getFluxGrid(self): """ Abstract method. See child classes for implementation. returns 3D grid of psi(r,z,t) The array returned should have the following dimensions: First dimension: time Second dimension: Z Third dimension: R """ raise NotImplementedError()
[docs] def getRGrid(self): """ Abstract method. See child classes for implementation. Returns vector of R-values for psiRZ grid [r] """ raise NotImplementedError()
[docs] def getZGrid(self): """ Abstract method. See child classes for implementation. Returns vector of Z-values for psiRZ grid [z] """ raise NotImplementedError()
[docs] def getFluxAxis(self): """ Abstract method. See child classes for implementation. Returns psi at magnetic axis [t] """ raise NotImplementedError()
[docs] def getFluxLCFS(self): """ Abstract method. See child classes for implementation. Returns psi a separatrix [t] """ raise NotImplementedError()
[docs] def getRLCFS(self): """ Abstract method. See child classes for implementation. Returns R-positions (n points) mapping LCFS [t,n] """ raise NotImplementedError()
[docs] def getZLCFS(self): """ Abstract method. See child classes for implementation. Returns Z-positions (n points) mapping LCFS [t,n] """ raise NotImplementedError()
[docs] def remapLCFS(self): """ Abstract method. See child classes for implementation. Overwrites stored R,Z positions of LCFS with explicitly calculated psinorm=1 surface. This surface is then masked using core.inPolygon() to only draw within vacuum vessel, the end result replacing RLCFS, ZLCFS with an R,Z array showing the divertor legs of the flux surface in addition to the core-enclosing closed flux surface. """ raise NotImplementedError()
[docs] def getFluxVol(self): """ Abstract method. See child classes for implementation. Returns volume contained within flux surface as function of psi [psi,t]. Psi assumed to be evenly-spaced grid on [0,1] """ raise NotImplementedError()
[docs] def getVolLCFS(self): """ Abstract method. See child classes for implementation. Returns plasma volume within LCFS [t] """ raise NotImplementedError()
[docs] def getRmidPsi(self): """ Abstract method. See child classes for implementation. Returns outboard-midplane major radius of flux surface [t,psi] """ raise NotImplementedError()
[docs] def getF(self): r""" Abstract method. See child classes for implementation. Returns F=RB_{\Phi}(\Psi), often calculated for grad-shafranov solutions [psi,t] """ raise NotImplementedError()
[docs] def getFluxPres(self): """ Abstract method. See child classes for implementation. Returns calculated pressure profile [psi,t]. Psi assumed to be evenly-spaced grid on [0,1] """ raise NotImplementedError()
[docs] def getFFPrime(self): """ Abstract method. See child classes for implementation. Returns FF' function used for grad-shafranov solutions [psi,t] """ raise NotImplementedError()
[docs] def getPPrime(self): """ Abstract method. See child classes for implementation. Returns plasma pressure gradient as a function of psi [psi,t] """ raise NotImplementedError()
[docs] def getElongation(self): """ Abstract method. See child classes for implementation. Returns LCFS elongation [t] """ raise NotImplementedError()
[docs] def getUpperTriangularity(self): """ Abstract method. See child classes for implementation. Returns LCFS upper triangularity [t] """ raise NotImplementedError()
[docs] def getLowerTriangularity(self): """ Abstract method. See child classes for implementation. Returns LCFS lower triangularity [t] """ raise NotImplementedError()
[docs] def getShaping(self): """ Abstract method. See child classes for implementation. Returns dimensionless shaping parameters for plasma. Namedtuple containing {LCFS elongation, LCFS upper/lower triangularity} """ raise NotImplementedError()
[docs] def getMagR(self): """ Abstract method. See child classes for implementation. Returns magnetic-axis major radius [t] """ raise NotImplementedError()
[docs] def getMagZ(self): """ Abstract method. See child classes for implementation. Returns magnetic-axis Z [t] """ raise NotImplementedError()
[docs] def getAreaLCFS(self): """ Abstract method. See child classes for implementation. Returns LCFS surface area [t] """ raise NotImplementedError()
[docs] def getAOut(self): """ Abstract method. See child classes for implementation. Returns outboard-midplane minor radius [t] """ raise NotImplementedError()
[docs] def getRmidOut(self): """ Abstract method. See child classes for implementation. Returns outboard-midplane major radius [t] """ raise NotImplementedError()
[docs] def getGeometry(self): """ Abstract method. See child classes for implementation. Returns dimensional geometry parameters Namedtuple containing {mag axis R,Z, LCFS area, volume, outboard-midplane major radius} """ raise NotImplementedError()
[docs] def getQProfile(self): """ Abstract method. See child classes for implementation. Returns safety factor q profile [psi,t] Psi assumed to be evenly-spaced grid on [0,1] """ raise NotImplementedError()
[docs] def getQ0(self): """ Abstract method. See child classes for implementation. Returns q on magnetic axis [t] """ raise NotImplementedError()
[docs] def getQ95(self): """ Abstract method. See child classes for implementation. Returns q on 95% flux surface [t] """ raise NotImplementedError()
[docs] def getQLCFS(self): """ Abstract method. See child classes for implementation. Returns q on LCFS [t] """ raise NotImplementedError()
[docs] def getQ1Surf(self): """ Abstract method. See child classes for implementation. Returns outboard-midplane minor radius of q=1 surface [t] """ raise NotImplementedError()
[docs] def getQ2Surf(self): """ Abstract method. See child classes for implementation. Returns outboard-midplane minor radius of q=2 surface [t] """ raise NotImplementedError()
[docs] def getQ3Surf(self): """ Abstract method. See child classes for implementation. Returns outboard-midplane minor radius of q=3 surface [t] """ raise NotImplementedError()
[docs] def getQs(self): """ Abstract method. See child classes for implementation. Returns specific q-profile values. Namedtuple containing {q0, q95, qLCFS, minor radius of q=1,2,3 surfaces} """ raise NotImplementedError()
[docs] def getBtVac(self): """ Abstract method. See child classes for implementation. Returns vacuum on-axis toroidal field [t] """ raise NotImplementedError()
[docs] def getBtPla(self): """ Abstract method. See child classes for implementation. Returns plasma on-axis toroidal field [t] """ raise NotImplementedError()
[docs] def getBpAvg(self): """ Abstract method. See child classes for implementation. Returns average poloidal field [t] """ raise NotImplementedError()
[docs] def getFields(self): """ Abstract method. See child classes for implementation. Returns magnetic-field values. Namedtuple containing {Btor on magnetic axis (plasma and vacuum), avg Bpol} """ raise NotImplementedError()
[docs] def getIpCalc(self): """ Abstract method. See child classes for implementation. Returns calculated plasma current [t] """ raise NotImplementedError()
[docs] def getIpMeas(self): """ Abstract method. See child classes for implementation. Returns measured plasma current [t] """ raise NotImplementedError()
[docs] def getJp(self): """ Abstract method. See child classes for implementation. Returns grid of calculated toroidal current density [t,z,r] """ raise NotImplementedError()
[docs] def getBetaT(self): """ Abstract method. See child classes for implementation. Returns calculated global toroidal beta [t] """ raise NotImplementedError()
[docs] def getBetaP(self): """ Abstract method. See child classes for implementation. Returns calculated global poloidal beta [t] """ raise NotImplementedError()
[docs] def getLi(self): """ Abstract method. See child classes for implementation. Returns calculated internal inductance of plasma [t] """ raise NotImplementedError()
[docs] def getBetas(self): """ Abstract method. See child classes for implementation. Returns calculated betas and inductance. Namedtuple of {betat,betap,Li} """ raise NotImplementedError()
[docs] def getDiamagFlux(self): """ Abstract method. See child classes for implementation. Returns diamagnetic flux [t] """ raise NotImplementedError()
[docs] def getDiamagBetaT(self): """ Abstract method. See child classes for implementation. Returns diamagnetic-loop toroidal beta [t] """ raise NotImplementedError()
[docs] def getDiamagBetaP(self): """ Abstract method. See child classes for implementation. Returns diamagnetic-loop poloidal beta [t] """ raise NotImplementedError()
[docs] def getDiamagTauE(self): """ Abstract method. See child classes for implementation. Returns diamagnetic-loop energy confinement time [t] """ raise NotImplementedError()
[docs] def getDiamagWp(self): """ Abstract method. See child classes for implementation. Returns diamagnetic-loop plasma stored energy [t] """ raise NotImplementedError()
[docs] def getDiamag(self): """ Abstract method. See child classes for implementation. Returns diamagnetic measurements of plasma parameters. Namedtuple of {diamag. flux, betat, betap from coils, tau_E from diamag., diamag. stored energy} """ raise NotImplementedError()
[docs] def getWMHD(self): """ Abstract method. See child classes for implementation. Returns calculated MHD stored energy [t] """ raise NotImplementedError()
[docs] def getTauMHD(self): """ Abstract method. See child classes for implementation. Returns calculated MHD energy confinement time [t] """ raise NotImplementedError()
[docs] def getPinj(self): """ Abstract method. See child classes for implementation. Returns calculated injected power [t] """ raise NotImplementedError()
[docs] def getCurrentSign(self): """ Abstract method. See child classes for implementation. Returns calculated current direction, where CCW = + """ raise NotImplementedError()
[docs] def getWbdot(self): """ Abstract method. See child classes for implementation. Returns calculated d/dt of magnetic stored energy [t] """ raise NotImplementedError()
[docs] def getWpdot(self): """ Abstract method. See child classes for implementation. Returns calculated d/dt of plasma stored energy [t] """ raise NotImplementedError()
[docs] def getBCentr(self): """ Abstract method. See child classes for implementation. Returns Vacuum Toroidal magnetic field at Rcent point [t] """ raise NotImplementedError()
[docs] def getRCentr(self): """ Abstract method. See child classes for implementation. Radial position for Vacuum Toroidal magnetic field calculation """ raise NotImplementedError()
[docs] def getEnergy(self): """ Abstract method. See child classes for implementation. Returns stored-energy parameters. Namedtuple of {stored energy, confinement time, injected power, d/dt of magnetic, plasma stored energy} """ raise NotImplementedError()
[docs] def getParam(self, path): """ Abstract method. See child classes for implementation. Backup function: takes parameter name for variable, returns variable directly. Acts as wrapper to direct data-access routines from within object. """ # backup function - takes parameter name for EFIT variable, returns that variable # acts as wrapper for EFIT tree access from within object raise NotImplementedError()
[docs] def getMachineCrossSection(self): """ Abstract method. See child classes for implementation. Returns (R,Z) coordinates of vacuum wall cross-section for plotting/masking routines. """ raise NotImplementedError()
[docs] def getMachineCrossSectionFull(self): """ Abstract method. See child classes for implementation. Returns (R,Z) coordinates of machine wall cross-section for plotting routines. Returns a more detailed cross-section than getLimiter(), generally a vector map displaying non-critical cross-section information. If this is unavailable, this should point to self.getMachineCrossSection(), which pulls the limiter outline stored by default in data files e.g. g-eqdsk files. """ raise NotImplementedError( "function to return machine cross-section not implemented for " "this class yet!" )
[docs] def gfile( self, time=None, nw=None, nh=None, shot=None, name=None, tunit='ms', title='EQTOOLS', nbbbs=100 ): """Generates an EFIT gfile with gfile naming convention Keyword Args: time (scalar float): Time of equilibrium to generate the gfile from. This will use the specified spline functionality to do so. Allows for it to be unspecified for single-time-frame equilibria. nw (scalar integer): Number of points in R. R is the major radius, and describes the 'width' of the gfile. nh (scalar integer): Number of points in Z. In cylindrical coordinates Z is the height, and nh describes the 'height' of the gfile. shot (scalar integer): The shot numer of the equilibrium. Used to help generate the gfile name if unspecified. name (String): Name of the gfile. If unspecified, will follow standard gfile naming convention (g+shot.time) under current python operating directory. This allows for it to be saved in other directories, etc. tunit (String): Specified unit for tin. It can only be 'ms' for milliseconds or 's' for seconds. title (String): Title of the gfile on the first line. Name cannot exceed 10 digits. This is so that the style of the first line is preserved. nbbbs (scalar integer): Number of points to define the plasma seperatrix within the gfile. The points are defined equally spaced in angle about the plasma center. This will cause the x-point to be poorly defined. Raises: ValueError: If title is longer than 10 characters. Examples: All assume that `Eq_instance` is a valid instance of the appropriate extension of the :py:class:`Equilibrium` abstract class (example shot number of 1001). Generate a gfile at t=0.26s, output of g1001.26:: Eq_instance.gfile(.26) """ gfile( self, time, nw=nw, nh=nh, shot=shot, name=name, tunit=tunit, title=title, nbbbs=nbbbs )
[docs] def plotFlux(self, fill=True, mask=True, lw=3.0, add_title=True): """Plots flux contours directly from psi grid. Returns the Figure instance created and the time slider widget (in case you need to modify the callback). `f.axes` contains the contour plot as the first element and the time slice slider as the second element. Keyword Args: fill (Boolean): Set True to plot filled contours. Set False (default) to plot white-background color contours. mask (Boolean): Set True (default) to mask the contours according to the vacuum vessel outline. lw (float): Linewidth when plotting LCFS. Default is 3.0. add_title (Boolean): Set True (default) to add a figure title with the time indicated. """ try: psiRZ = self.getFluxGrid() rGrid = self.getRGrid(length_unit='m') zGrid = self.getZGrid(length_unit='m') t = self.getTimeBase() RLCFS = self.getRLCFS(length_unit='m') ZLCFS = self.getZLCFS(length_unit='m') except ValueError: raise AttributeError('cannot plot EFIT flux map.') try: limx, limy = self.getMachineCrossSection() except NotImplementedError: if self._verbose: print('No machine cross-section implemented!') limx = None limy = None try: macx, macy = self.getMachineCrossSectionFull() except Exception: macx = None macy = None # event handler for arrow key events in plot windows. Pass slider object # to update as masked argument using lambda function # lambda evt: arrow_respond(my_slider,evt) def arrowRespond(slider, event): if event.key == 'right': slider.set_val(min(slider.val+1, slider.valmax)) if event.key == 'left': slider.set_val(max(slider.val-1, slider.valmin)) # make time-slice window fluxPlot = plt.figure(figsize=(6, 11)) gs = mplgs.GridSpec(2, 1, height_ratios=[30, 1]) psi = fluxPlot.add_subplot(gs[0, 0]) psi.set_aspect('equal') timeSliderSub = fluxPlot.add_subplot(gs[1, 0]) if add_title: title = fluxPlot.suptitle('') # dummy plot to get x,ylims psi.contour(rGrid, zGrid, psiRZ[0], 1) # generate graphical mask for limiter wall if mask: xlim = psi.get_xlim() ylim = psi.get_ylim() bound_verts = [ (xlim[0], ylim[0]), (xlim[0], ylim[1]), (xlim[1], ylim[1]), (xlim[1], ylim[0]), (xlim[0], ylim[0]) ] poly_verts = [ (limx[i], limy[i]) for i in range(len(limx) - 1, -1, -1) ] bound_codes = [mpath.Path.MOVETO] + (len(bound_verts) - 1) * [mpath.Path.LINETO] poly_codes = [mpath.Path.MOVETO] + (len(poly_verts) - 1) * [mpath.Path.LINETO] path = mpath.Path( bound_verts + poly_verts, bound_codes + poly_codes ) patch = mpatches.PathPatch( path, facecolor='white', edgecolor='none' ) def updateTime(val): psi.clear() t_idx = int(timeSlider.val) if add_title: title.set_text( 'EFIT Reconstruction, $t = %(t).2f$ s' % {'t': t[t_idx]} ) psi.set_xlabel('$R$ [m]') psi.set_ylabel('$Z$ [m]') if macx is not None: psi.plot(macx, macy, 'k', linewidth=lw, zorder=5) elif limx is not None: psi.plot(limx, limy, 'k', linewidth=lw, zorder=5) # catch NaNs separating disjoint sections of R,ZLCFS in mask maskarr = scipy.where( scipy.logical_or(RLCFS[t_idx] > 0.0, scipy.isnan(RLCFS[t_idx])) ) RLCFSframe = RLCFS[t_idx, maskarr[0]] ZLCFSframe = ZLCFS[t_idx, maskarr[0]] psi.plot(RLCFSframe, ZLCFSframe, 'r', linewidth=lw, zorder=3) if fill: psi.contourf(rGrid, zGrid, psiRZ[t_idx], 50, zorder=2) psi.contour( rGrid, zGrid, psiRZ[t_idx], 50, colors='k', linestyles='solid', zorder=3 ) else: psi.contour( rGrid, zGrid, psiRZ[t_idx], 50, linestyles='solid', zorder=2 ) if mask: patchdraw = psi.add_patch(patch) patchdraw.set_zorder(4) fluxPlot.canvas.draw() timeSlider = mplw.Slider( timeSliderSub, 't index', 0, len(t) - 1, valinit=0, valfmt="%d" ) timeSlider.on_changed(updateTime) updateTime(0) plt.ion() fluxPlot.show() fluxPlot.canvas.mpl_connect( 'key_press_event', lambda evt: arrowRespond(timeSlider, evt) ) return (fluxPlot, timeSlider)