Source code for omfit_classes.omfit_mars

try:
    # framework is running
    from .startup_choice import *
except ImportError as _excp:
    # class is imported by itself
    if (
        'attempted relative import with no known parent package' in str(_excp)
        or 'No module named \'omfit_classes\'' in str(_excp)
        or "No module named '__main__.startup_choice'" in str(_excp)
    ):
        from startup_choice import *
    else:
        raise

from omfit_classes.omfit_ascii import OMFITascii

import xarray
import numpy as np

from scipy.interpolate import griddata

__all__ = ['OMFITmars', 'OMFITnColumns', 'OMFITmarsProfile']


[docs]class OMFITmars(SortedDict, OMFITobject): """ Class used to interface with MARS results directory :param filename: directory where the MARS result files are stored :param extra_files: Any extra files that should be loaded :param Nchi: Poloidal grid resolution for real-space """ def __init__(self, filename=None, extra_files=[], Nchi=None, **kw): if Nchi is None: Nchi = 200 printw(f'OMFITmars using default Nchi value of {Nchi}') if isinstance(filename, (list, tuple)): kw['tunnel'] = filename[2] kw['server'] = filename[1] filename = filename[0] if ',' not in filename: outputs = [ 'BPLASMA.OUT', 'BPLASMA', 'JACOBIAN.OUT', 'JACOBIAN', 'RMZM_F.OUT', 'RMZM_F', 'XPLASMA.OUT', 'XPLASMA', 'JPLASMA.OUT', 'JPLASMA', 'PROFEQ.OUT', 'PROFEQ', 'RESULT.OUT', 'RESULT', 'FREQUENCIES.OUT', 'TIMEEVOL.OUT', 'DWK_ENERGY_DENSITY.OUT', 'PROFNTV.OUT', 'TORQUENTV.OUT', 'PROFNUSTAR.OUT', ] outputs += extra_files filename = ','.join([filename + os.sep + x for x in outputs]) kw['file_type'] = 'dir' OMFITobject.__init__(self, filename, **kw) self.OMFITproperties.pop('file_type', 'dir') self.OMFITproperties['Nchi'] = Nchi self.sim = 'sim0' SortedDict.__init__(self) self.dynaLoad = True """ Reading methods, used to read MARS output files. """
[docs] def read_RMZM(self, filename): with open(filename) as fin: x = [ii.strip() for ii in fin.readlines()] RMZM_F = np.zeros((len(x), 4)) for ii, line in enumerate(x): RMZM_F[ii] = line.split() # Number of poloidal harmonics for equilibrium (RMZM) Nm0 = int(RMZM_F[0, 0]) Ns1 = int(RMZM_F[0, 1]) Ns2 = int(RMZM_F[0, 2]) R0EXP = RMZM_F[0, 3] B0EXP = RMZM_F[1, 3] Ns = Ns1 + Ns2 NRATSURF = int(RMZM_F[1, 1]) Iratsurf = np.array(RMZM_F[2 : NRATSURF + 2, 1], int) # s coordinate over full domain s = np.array(RMZM_F[1 : Ns + 1, 0], float) # s coordinate in plasma sp = np.array(RMZM_F[1 : Ns1 + 1, 0], float) # s coordinate in vacuum svac = np.array(RMZM_F[Ns1 + 1 : Ns + 1, 0], float) RM = np.array(RMZM_F[Ns + 1 :, 0] + RMZM_F[Ns + 1 :, 1] * 1j, complex) ZM = np.array(RMZM_F[Ns + 1 :, 2] + RMZM_F[Ns + 1 :, 3] * 1j, complex) RM = np.reshape(RM, (Nm0, Ns)).T ZM = np.reshape(ZM, (Nm0, Ns)).T RM[:, 1:] = 2 * RM[:, 1:] ZM[:, 1:] = 2 * ZM[:, 1:] Nchi = self.OMFITproperties['Nchi'] self[self.sim]['RM'] = xarray.DataArray(RM, dims=['s', 'm'], coords={'m': range(Nm0), 's': s}) self[self.sim]['ZM'] = xarray.DataArray(ZM, dims=['s', 'm'], coords={'m': range(Nm0), 's': s}) self[self.sim]['sp'] = xarray.DataArray(sp, dims=['sp'], coords={'sp': sp}, attrs={'Description': 's-coord in plasma domain'}) self[self.sim]['svac'] = xarray.DataArray( svac, dims=['svac'], coords={'svac': svac}, attrs={'Description': 's-coord in vacuum domain'} ) self[self.sim]['Iratsurf'] = xarray.DataArray(Iratsurf) self[self.sim]['R0EXP'] = xarray.DataArray(R0EXP) self[self.sim]['B0EXP'] = xarray.DataArray(B0EXP) self[self.sim]['Ns1'] = xarray.DataArray(Ns1, attrs={'Description': 'Number of radial points in plasma'}) self[self.sim]['Ns2'] = xarray.DataArray(Ns2, attrs={'Description': 'Number of radial points in vacuum'}) self[self.sim]['Nm0'] = xarray.DataArray(Nm0, attrs={'Description': 'Number of poloidal harmonics for equilibrium'}) self[self.sim]['Nchi'] = xarray.DataArray(Nchi, attrs={'Description': 'Number of points along poloidal angle (from CHEASE)'}) return RM, ZM
[docs] def read_JPLASMA(self, filename, JNORM=1.0): """ Read JPLASMA.OUT file corresponding to perturbed currents :param filename: name of file :param JNORM: normalization """ JPLASMA = np.loadtxt(filename) # Nm1 = Number of poloidal harmonics for stability (perturbed quantities, M1...M2) Nm1, Ns, n, _, _, _ = map(int, JPLASMA[0, :]) JPLASMA = JPLASMA[1:, :] Mm = JPLASMA[:Nm1, 1].astype(int) JM1 = JPLASMA[Nm1:, 0] + 1j * JPLASMA[Nm1:, 1] JM2 = JPLASMA[Nm1:, 2] + 1j * JPLASMA[Nm1:, 3] JM3 = JPLASMA[Nm1:, 4] + 1j * JPLASMA[Nm1:, 5] JM1 = np.reshape(JM1, (Nm1, Ns)).T JM2 = np.reshape(JM2, (Nm1, Ns)).T JM3 = np.reshape(JM3, (Nm1, Ns)).T JM1 = JM1 * JNORM JM2 = JM2 * JNORM JM3 = JM3 * JNORM # Note that JM1 is defined at half-points, recompute at integer-points x = np.asarray((self[self.sim]['s'][0:Ns] + self[self.sim]['s'][1 : Ns + 1]) * 0.5) JM1new = copy.deepcopy(JM1) JM1new[1:-1, :] = griddata(x.flatten(), JM1[0:-1, :], np.asarray(self[self.sim]['s'][1 : Ns - 1]).flatten(), method='cubic') JM1new[0, :] = 0 JM1new[-1, :] = JM1new[-2, :] JM1 = copy.deepcopy(JM1new) # Patch first three points JM1[0:3] = 0.0 JM2[0:3] = 0.0 JM3[0:3] = 0.0 # Remove surface currents if True: II = np.where((self[self.sim]['s'] > 0.9985) & (self[self.sim]['s'] <= 1.0)) JM1[II[0][:]] = 0 JM2[II[0][:]] = 0 JM3[II[0][:]] = 0 # get phase of JM2 for m=2 harmonic at rational surface Iratsurf(1) # and modify phase to remove real part if len(self[self.sim]['Iratsurf']): from cmath import log m0 = 2 I0 = int(self[self.sim]['Iratsurf'][0]) m1 = int(m0 - Mm[0] + 1) p0 = -np.angle(JM2[I0 - 1, m1 - 1]) + np.pi / 2.0 f0 = np.exp(1j * p0) JM1 = JM1 * f0 JM2 = JM2 * f0 JM3 = JM3 * f0 self['JPLASMA'] = xarray.Dataset() self['JPLASMA']['JM1'] = xarray.DataArray(JM1, dims=['s', 'Mm'], coords={'s': self[self.sim]['s'][:Ns], 'Mm': Mm}) self['JPLASMA']['JM2'] = xarray.DataArray(JM2, dims=['s', 'Mm'], coords={'s': self[self.sim]['s'][:Ns], 'Mm': Mm}) self['JPLASMA']['JM3'] = xarray.DataArray(JM3, dims=['s', 'Mm'], coords={'s': self[self.sim]['s'][:Ns], 'Mm': Mm})
[docs] def read_BPLASMA(self, filename, BNORM=1.0): """ Read BPLASMA.OUT file corresponding to perturbed magnetic field :param filename: name of file :param BNORM: normalization """ spline_B23 = 1 BPLASMA = np.loadtxt(filename) Nm1, Ns, n, _, _, _ = map(int, BPLASMA[0, :]) BPLASMA = BPLASMA[1:, :] Mm = BPLASMA[:Nm1, 1].astype(int) BM1 = BPLASMA[Nm1:, 0] + 1j * BPLASMA[Nm1:, 1] BM2 = BPLASMA[Nm1:, 2] + 1j * BPLASMA[Nm1:, 3] BM3 = BPLASMA[Nm1:, 4] + 1j * BPLASMA[Nm1:, 5] BM1 = np.reshape(BM1, (Nm1, Ns)).T BM2 = np.reshape(BM2, (Nm1, Ns)).T BM3 = np.reshape(BM3, (Nm1, Ns)).T BM1 = BM1[0:Ns, :] * BNORM BM2 = BM2[0:Ns, :] * BNORM BM3 = BM3[0:Ns, :] * BNORM if spline_B23 == 2: BM2[1:, :] = BM2[0:-1, :] BM3[1:, :] = BM3[0:-1, :] elif spline_B23 == 1: x = np.asarray((self[self.sim]['s'][0 : Ns - 1] + self[self.sim]['s'][1:Ns]) * 0.5) # B2 BM2new = copy.deepcopy(BM2) BM2new[1:-1, :] = griddata(x.flatten(), BM2[0:-1, :], np.asarray(self[self.sim]['s'][1 : Ns - 1]).flatten(), method='cubic') BM2new[0, :] = 0 BM2new[-1, :] = BM2new[-2, :] BM2 = copy.deepcopy(BM2new) # B3 BM3new = copy.deepcopy(BM3) BM3new[1:-1, :] = griddata(x.flatten(), BM3[0:-1, :], np.asarray(self[self.sim]['s'][1 : Ns - 1]).flatten(), method='cubic') BM3new[0, :] = 0 BM3new[-1, :] = BM3new[-2, :] BM3 = copy.deepcopy(BM3new) self['BPLASMA'] = xarray.Dataset() self['BPLASMA']['BM1'] = xarray.DataArray(BM1, dims=['s', 'Mm'], coords={'s': self[self.sim]['s'][:Ns], 'Mm': Mm}) self['BPLASMA']['BM2'] = xarray.DataArray(BM2, dims=['s', 'Mm'], coords={'s': self[self.sim]['s'][:Ns], 'Mm': Mm}) self['BPLASMA']['BM3'] = xarray.DataArray(BM3, dims=['s', 'Mm'], coords={'s': self[self.sim]['s'][:Ns], 'Mm': Mm})
[docs] def read_XPLASMA(self, filename, XNORM=1.0): """ Read XPLASMA.OUT file corresponding to perturbed plasma displacement :param filename: name of file :param XNORM: normalization """ XPLASMA = np.loadtxt(filename) # Here Ns is the number of grid points in plasma (what elsewhere is Ns1) Nm1, Ns, n, _, _, _ = map(int, XPLASMA[0, :]) XPLASMA = XPLASMA[1:, :] Mm = XPLASMA[:Nm1, 1].astype(int) # dPSIds = XPLASMA[Nm1 : Nm1 + Ns, 0] T = XPLASMA[Nm1 : Nm1 + Ns, 3] XM1 = XPLASMA[Nm1 + Ns :, 0] + 1j * XPLASMA[Nm1 + Ns :, 1] XM2 = XPLASMA[Nm1 + Ns :, 2] + 1j * XPLASMA[Nm1 + Ns :, 3] XM3 = XPLASMA[Nm1 + Ns :, 4] + 1j * XPLASMA[Nm1 + Ns :, 5] XM1 = np.reshape(XM1, (Nm1, Ns)).T XM2 = np.reshape(XM2, (Nm1, Ns)).T XM3 = np.reshape(XM3, (Nm1, Ns)).T XM1 = XM1[0:Ns, :] * XNORM XM2 = XM2[0:Ns, :] * XNORM XM3 = XM3[0:Ns, :] * XNORM # Recalculate XM2 and XM3 at integer points (they are defined at half-points) x = np.asarray((self[self.sim]['s'][0 : Ns - 1] + self[self.sim]['s'][1:Ns]) * 0.5) # X2 XM2new = copy.deepcopy(XM2) XM2new[1:-1, :] = griddata(x.flatten(), XM2[0:-1, :], np.asarray(self[self.sim]['s'][1 : Ns - 1]).flatten(), method='cubic') XM2new[0, :] = 0 XM2new[-1, :] = XM2new[-2, :] XM2 = copy.deepcopy(XM2new) # X3 XM3new = copy.deepcopy(XM3) XM3new[1:-1, :] = griddata(x.flatten(), XM3[0:-1, :], np.asarray(self[self.sim]['s'][1 : Ns - 1]).flatten(), method='cubic') XM3new[0, :] = 0 XM3new[-1, :] = XM3new[-2, :] XM3 = copy.deepcopy(XM3new) # change central points of XM2 (see MacReadVPLASMA) XM2[:, 0] = XM2[:, 2] XM2[:, 1] = XM2[:, 2] self['XPLASMA'] = xarray.Dataset() # Displacement only defined within plasma, radial coordinate is 'sp' self['XPLASMA']['XM1'] = xarray.DataArray(XM1, dims=['sp', 'Mm'], coords={'sp': self[self.sim]['sp'], 'Mm': Mm}) self['XPLASMA']['XM2'] = xarray.DataArray(XM2, dims=['sp', 'Mm'], coords={'sp': self[self.sim]['sp'], 'Mm': Mm}) self['XPLASMA']['XM3'] = xarray.DataArray(XM3, dims=['sp', 'Mm'], coords={'sp': self[self.sim]['sp'], 'Mm': Mm}) self[self.sim]['dPSIds'] = xarray.DataArray(dPSIds, dims=['sp'], coords={'sp': self[self.sim]['sp']}) self[self.sim]['T'] = xarray.DataArray(T, dims=['sp'], coords={'sp': self[self.sim]['sp']})
[docs] def read_RESULTS(self, filename): with open(filename) as fin: lines = fin.read().splitlines() tmp = list(map(float, lines[-1].split())) if len(tmp): self[self.sim]['NITR'] = xarray.DataArray(tmp[1]) self[self.sim]['TALPHA1'] = xarray.DataArray(complex(tmp[2], tmp[3])) self[self.sim]['EIG'] = xarray.DataArray(complex(tmp[4], tmp[5]), attrs={'Description': 'Output eigenvalue', 'units': '-'})
[docs] def read_PROFEQ(self, filename): """ Read equilibrium quantities used for MARS calculation Returns profiles in physical units, not MARS normalization :param filename: name of MARS output file, usually PROFEQ.OUT """ from scipy.constants import mu_0 R0 = self[self.sim]['R0EXP'].values.astype(float) B0 = self[self.sim]['B0EXP'].values.astype(float) data = np.loadtxt(filename) SY = [ ('s_eq', 's equilibrium (no wall included)', None), ('q_prof', 'safety factor', None), ('j_prof', 'current density', B0 / (mu_0 * R0)), ('p_prof', 'pressure', B0 * B0 / mu_0), ('n_prof', 'density', None), ('v_prof', 'toroidal rotation', None), ('eta', 'resistivity=tau_A / tau_R = 1/S', None), ('Gamma', 'Gamma', None), ('visc_prof', 'viscosity', None), ('Ti_prof', 'Ti', None), ('Te_prof', 'Te', None), ('dpsi/ds', 'dpsi/ds', None), ('F', 'F', None), ('omega_*i', 'ion dia. drift freq.', None), ('omega_*e', 'e- dia. drift freq.', None), ('CSV', 'CSV', None), ('erot_prof', 'electron rotation', None), ('nu_i', 'ion eff. collisionality', None), ('nu_e', 'e- eff. collisionality', None), ('zeff', 'Z effective', None), ] x = data[:, 0] self['PROFEQ'] = xarray.Dataset() for k, (name, des, units) in enumerate(SY): if k < data.shape[1]: y = np.array(data[:, k]) if units is not None: y = y * units self['PROFEQ'][name] = xarray.DataArray(y, dims=['s_eq'], coords={'s_eq': x}, attrs={'Description': des}) else: printw('%s information is missing from %s file' % (des, os.path.split(filename)[1]))
[docs] def read_FREQS(self, filename): """ Reads all frequencies related to drift kinetic resonances :param filename: name of MARS output file, usually FREQUENCIES.OUT """ data = np.loadtxt(filename) s = data[:, 0] we = data[:, 1] wsni = data[:, 2] wsne = data[:, 3] wsti = data[:, 4] wste = data[:, 5] awbp = data[:, 6] awbt = data[:, 7] awdi = data[:, 8] awdi[0] = awdi[2] awdi[1] = awdi[2] awde = data[:, 9] awda = data[:, 10] awda[0] = awda[2] awda[1] = awda[2] fracp = data[:, 11] fract = data[:, 12] lam1 = data[:, 13] lam0 = data[:, 14] lam2 = data[:, 15] awda1 = data[:, 16] awda2 = data[:, 17] # Storing data self['FREQUENCIES'] = xarray.Dataset() self['FREQUENCIES']['s'] = xarray.DataArray(s, dims=['s'], coords={'s': s}, attrs={'Description': 's-coord for FREQUENCIES'}) self['FREQUENCIES']['we'] = xarray.DataArray(we, dims=['s'], coords={'s': s}, attrs={'Description': 'ExB velocity'}) self['FREQUENCIES']['wsni'] = xarray.DataArray( wsni, dims=['s'], coords={'s': s}, attrs={'Description': 'Diamagnetic frequency - density gradient'} ) self['FREQUENCIES']['wsti'] = xarray.DataArray( wsti, dims=['s'], coords={'s': s}, attrs={'Description': 'Diamagnetic frequency - temp. gradient'} ) self['FREQUENCIES']['awbt'] = xarray.DataArray(awbt, dims=['s'], coords={'s': s}, attrs={'Description': 'Bounce - trapped'}) self['FREQUENCIES']['awbp'] = xarray.DataArray(awbp, dims=['s'], coords={'s': s}, attrs={'Description': 'Bounce - passing'}) self['FREQUENCIES']['awdi'] = xarray.DataArray(awdi, dims=['s'], coords={'s': s}, attrs={'Description': 'Precession - th ions'}) self['FREQUENCIES']['awde'] = xarray.DataArray(awde, dims=['s'], coords={'s': s}, attrs={'Description': 'Precession - electrons'}) self['FREQUENCIES']['awda'] = xarray.DataArray(awda, dims=['s'], coords={'s': s}, attrs={'Description': 'Precession - hot'})
[docs] def read_TIMEEVOL(self, filename, ncase, NORM=False): """ Reads time evolution output from time-stepping runs :param filename: name of MARS output file, usually TIMEEVOL.OUT :param ncase: input namelist variable defining type of MARS-* run :param NORM: toggle normalization to physical units """ if NORM: from scipy.constants import mu_0 R0 = self[self.sim]['R0EXP'].values.astype(float) B0 = self[self.sim]['B0EXP'].values.astype(float) TAUA0 = 1.0e-7 # Need to parse log_mars to get TAUA0! xnorm = R0 * 1.0e3 # displacement [mm] bnorm = B0 * 1.0e4 # b-field [Gauss] cnorm = R0 * B0 / mu_0 # current [A] tdnorm = (B0**2) / mu_0 / np.pi # torque density [N/m^2] ttnorm = tdnorm * (R0**3) # total torque [Nm] tmnorm = TAUA0 * 1.0e3 # time [ms] unit_t = 'ms' unit_b = 'Gauss' unit_c = 'A' unit_v = 'A.U.' # Implement voltage normalization else: xnorm = 1.0 bnorm = 1.0 cnorm = 1.0 tdnorm = 1.0 ttnorm = 1.0 tmnorm = 1.0 unit_t = 'A.U.' unit_b = 'A.U.' unit_c = 'A.U.' unit_v = 'A.U.' # Implement voltage normalization # tmp = np.atleast_2d(loadtxt(filename, skiprows=0)) tmp = np.loadtxt(filename) ncols = tmp.shape[1] self['TIMEEVOL'] = xarray.Dataset() if ncase == 3: t = np.cumsum(tmp[:, 0]) * tmnorm self['TIMEEVOL']['t'] = xarray.DataArray( t, dims=['t'], coords={'t': t}, attrs={'Description': 'Time axis', 'Units': '%s' % unit_t} ) # Point-like sensor signal self['TIMEEVOL']['PSIS_re'] = xarray.DataArray( tmp[:, 1] * bnorm, dims=['t'], coords={'t': t}, attrs={'Description': 'Sensor signal (Re)', 'Units': '%s' % unit_b} ) self['TIMEEVOL']['PSIS_im'] = xarray.DataArray( tmp[:, 2] * bnorm, dims=['t'], coords={'t': t}, attrs={'Description': 'Sensor signal (Im)', 'Units': '%s' % unit_b} ) # Get number of columns where AIF is stored midcols = tmp.shape[1] - 3 ncoil = midcols // 4 # Feedback current istart = 3 for ii in range(ncoil): self['TIMEEVOL']['AIF_%d_re' % ii] = xarray.DataArray( tmp[:, istart + ii], dims=['t'], coords={'t': t}, attrs={'Description': 'Feedback current coil %s (Re)' % str(ii + 1), 'Units': '%s' % unit_c}, ) self['TIMEEVOL']['AIF_%d_im' % ii] = xarray.DataArray( tmp[:, istart + ncoil + ii], dims=['t'], coords={'t': t}, attrs={'Description': 'Feedback current coil %s (Im)' % str(ii + 1), 'Units': '%s' % unit_c}, ) elif ncase == 4: t = np.cumsum(tmp[:, 0]) * tmnorm self['TIMEEVOL']['t'] = xarray.DataArray( t, dims=['t'], coords={'t': t}, attrs={'Description': 'Time axis', 'Units': '%s' % unit_t} ) # Point-like sensor signal self['TIMEEVOL']['PSIS_re'] = xarray.DataArray( tmp[:, 1] * bnorm, dims=['t'], coords={'t': t}, attrs={'Description': 'Sensor signal (Re)', 'Units': '%s' % unit_b} ) self['TIMEEVOL']['PSIS_im'] = xarray.DataArray( tmp[:, 2] * bnorm, dims=['t'], coords={'t': t}, attrs={'Description': 'Sensor signal (Im)', 'Units': '%s' % unit_b} ) # Sensor noise self['TIMEEVOL']['PSISNOISE_re'] = xarray.DataArray( tmp[:, -2] * bnorm, dims=['t'], coords={'t': t}, attrs={'Description': 'Sensor noise (Re)', 'Units': '%s' % unit_b} ) self['TIMEEVOL']['PSISNOISE_im'] = xarray.DataArray( tmp[:, -1] * bnorm, dims=['t'], coords={'t': t}, attrs={'Description': 'Sensor noise (Im)', 'Units': '%s' % unit_b} ) # Get number of columns where AVF & AIF are stored midcols = tmp.shape[1] - 5 ncoil = midcols // 4 # Feedback voltages istart = 3 for ii in range(ncoil): self['TIMEEVOL']['AVF_%d_re' % ii] = xarray.DataArray( tmp[:, istart + ii], dims=['t'], coords={'t': t}, attrs={'Description': 'Feedback voltage coil %s (Re)' % str(ii + 1), 'Units': '%s' % unit_v}, ) self['TIMEEVOL']['AVF_%d_im' % ii] = xarray.DataArray( tmp[:, istart + ncoil + ii], dims=['t'], coords={'t': t}, attrs={'Description': 'Feedback voltage coil %s (Im)' % str(ii + 1), 'Units': '%s' % unit_v}, ) # Feedback currents istart = 3 + 2 * ncoil for ii in range(ncoil): self['TIMEEVOL']['AIF_%d_re' % ii] = xarray.DataArray( tmp[:, istart + ii], dims=['t'], coords={'t': t}, attrs={'Description': 'Feedback current coil %s (Re)' % str(ii + 1), 'Units': '%s' % unit_c}, ) self['TIMEEVOL']['AIF_%d_im' % ii] = xarray.DataArray( tmp[:, istart + ncoil + ii], dims=['t'], coords={'t': t}, attrs={'Description': 'Feedback current coil %s (Im)' % str(ii + 1), 'Units': '%s' % unit_c}, ) else: print('NCASE=%s not implemented yet' % ncase) return
[docs] def read_dWk_den(self, filename): """ Reads perturbed kinetic energy density :param filename: name of MARS output file, usually DWK_ENERGY_DENSITY.OUT """ data = np.loadtxt(filename, comments='%') NR = len(data[:, 0]) n = len(data[0, :]) // 10 blocks = np.split(data, n, axis=1) self['DWK_ENERGY_DENSITY'] = xarray.Dataset() self['DWK_ENERGY_DENSITY']['FULL_MATRIX'] = xarray.DataArray(data) for l in range(len(blocks)): CSM = blocks[l][:, 2] KP = int(blocks[l][0, 0]) I = int(blocks[l][1, 1]) self['DWK_ENERGY_DENSITY']['%s_%s_REdwppara' % (KP, I)] = xarray.DataArray( blocks[l][:, 4], dims=['s'], coords={'s': CSM}, attrs={'Description': 'Real parallel dWk for species = %s, type = %s' % (KP, I)}, ) self['DWK_ENERGY_DENSITY']['%s_%s_IMdwppara' % (KP, I)] = xarray.DataArray( blocks[l][:, 5], dims=['s'], coords={'s': CSM}, attrs={'Description': f'Imag parallel dWk for species = {KP}, type = {I}'} ) self['DWK_ENERGY_DENSITY']['%s_%s_REdwpperp' % (KP, I)] = xarray.DataArray( blocks[l][:, 6], dims=['s'], coords={'s': CSM}, attrs={'Description': 'Real perp. dWk for specie = %s, type = %s' % (KP, I)} ) self['DWK_ENERGY_DENSITY']['%s_%s_IMdwpperp' % (KP, I)] = xarray.DataArray( blocks[l][:, 7], dims=['s'], coords={'s': CSM}, attrs={'Description': 'Imag. perp. dWk for specie = %s, type = %s' % (KP, I)}, ) self['DWK_ENERGY_DENSITY']['%s_%s_REdwk' % (KP, I)] = xarray.DataArray( blocks[l][:, 8], dims=['s'], coords={'s': CSM}, attrs={'Description': 'Real total dWk for specie = %s, type = %s' % (KP, I)} ) self['DWK_ENERGY_DENSITY']['%s_%s_IMdwk' % (KP, I)] = xarray.DataArray( blocks[l][:, 9], dims=['s'], coords={'s': CSM}, attrs={'Description': 'Imag total dWk for specie = %s, type = %s' % (KP, I)} ) return
[docs] def read_PROFNTV(self, filename): # commented mu_0 might be needed in future extensions # from scipy.constants import mu_0 # read data prof = np.loadtxt(filename) # profiles rho = prof[:, 0] # radial coordinate q = prof[:, 1] # safety factor eps = prof[:, 2] # equivalent r/R0 in Shaing's theory rhoi = prof[:, 3] # thermal ion density nu = prof[:, 4] # collisionality, thermal ion or electron depending on ZCHARGE wti = prof[:, 5] # thermal ion transit frequency wB0 = prof[:, 6] # gradB precession drift frequency, depending on ZCHARGE qwe = prof[:, 7] # ExB drift frequency, =q*omega_E qws = prof[:, 8] # diamagnetic drift frequency, =q*omega_*p, depending on ZCHARGE qwsT = prof[:, 9] # grad T drift frequency, =q*omega_*T, depending on ZCHARGE dB = prof[:, 10] # surface averaged |dB|/B0 psi = rho**2 # some fix-ups dB[0] = dB[2] dB[1] = dB[2] """ calculate "boundary"-frequencies between different NTV regimes first for non-resonant NTV torque nu < nu_n1 : nu-regime nu_n1 < nu < nu_n2 : sqrt(nu)-regime nu_n2 < nu < nu_n3 : 1/nu-regime nu_n3 < nu : violation of assumptions in Shaing's NTV theory """ nu_n1 = np.abs(qwe / q) * ((dB / eps) ** 2) nu_n2 = np.abs(qwe / q) nu_n3 = np.sqrt(eps) * wti """ next for resonant NTV torque nu < nu_r1 : superbanana-regime nu_r1 < nu < nu_r2 : superbanana-plateau-regime nu_r2 < nu < nu_r3 : 1/nu-regime nu_r3 < nu : violation of assumptions in Shaing's NTV theory """ nu_r1 = wB0 * ((dB / eps) ** 1.5) nu_r2 = wB0 / eps nu_r3 = np.sqrt(eps) * wti self['PROFNTV'] = xarray.Dataset() self['PROFNTV']['nu_n1'] = xarray.DataArray( nu_n1, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'nu < nu_n1 : nu-regime'} ) self['PROFNTV']['nu_n2'] = xarray.DataArray( nu_n2, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'nu_n1 < nu < nu_n2 : sqrt(nu)-regime'} ) self['PROFNTV']['nu_n3'] = xarray.DataArray( nu_n3, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'nu_n2 < nu < nu_n3 : 1/nu-regime'} ) self['PROFNTV']['nu_r1'] = xarray.DataArray( nu_r1, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'nu < nu_r1 : superbanana-regime'} ) self['PROFNTV']['nu_r2'] = xarray.DataArray( nu_r2, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'nu_r1 < nu < nu_r2 : superbanana-plateau-regime, nu_r2 < nu < nu_r3 : 1/nu-regime'}, ) self['PROFNTV']['nu'] = xarray.DataArray( nu, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'collisionality, thermal ion or electron depending on ZCHARGE'} ) self['PROFNTV']['eps'] = xarray.DataArray( eps, dims=['psi'], coords={'psi': psi}, attrs={'Description': 'equivalent r/R0 in Shaing theory'} ) return
[docs] def read_TORQUENTV(self, filename): """ Read TORQUENTV.OUT file containing NTV torque densities """ torq = np.loadtxt(filename) # get NTV torque densities s = torq[:, 0] # radial mesh TNTVtot = torq[:, 1] # total NTV torque density = ions + electrons DPNTVTot = torq[:, 2] # particle flux due to total NTV torque DPNTVi = torq[:, 3] # particle flux due to ion NTV torque DPNTVe = torq[:, 4] # particle flux due to electron NTV torque TNTVi = torq[:, 5] # NTV torque due to ions TNTVe = torq[:, 6] # NTV torque due to electrons self['TORQUENTV'] = xarray.Dataset() self['TORQUENTV']['NTV_tot'] = xarray.DataArray( TNTVtot, dims=['s'], coords={'s': s}, attrs={'Description': 'total NTV torque density = ions + electrons'} ) self['TORQUENTV']['NTV_ion'] = xarray.DataArray(TNTVi, dims=['s'], coords={'s': s}, attrs={'Description': 'NTV torque due to ions'}) self['TORQUENTV']['NTV_el'] = xarray.DataArray( TNTVe, dims=['s'], coords={'s': s}, attrs={'Description': 'NTV torque due to electrons'} ) # Particle flux self['TORQUENTV']['DP_NTV_tot'] = xarray.DataArray( DPNTVTot, dims=['s'], coords={'s': s}, attrs={'Description': 'particle flux due to total NTV torque'} ) self['TORQUENTV']['DP_NTV_ion'] = xarray.DataArray( DPNTVi, dims=['s'], coords={'s': s}, attrs={'Description': 'particle flux due to ion NTV torque'} ) self['TORQUENTV']['DP_NTV_el'] = xarray.DataArray( DPNTVe, dims=['s'], coords={'s': s}, attrs={'Description': 'particle flux due to electron NTV torque'} ) return
[docs] def read_NUSTAR(self, filename): """ Read PROFNUSTAR.OUT file containing ion and electron effective collisionality """ # read data nu = np.loadtxt(filename) s = nu[:, 0] nui = nu[:, 1] # nu* ions nue = nu[:, 2] # nu* electrons self['NUSTAR'] = xarray.Dataset() self['NUSTAR']['nustar_i'] = xarray.DataArray( nui, dims=['s'], coords={'s': s}, attrs={'Description': 'nustar for ions calculated in MARS'} ) self['NUSTAR']['nustar_e'] = xarray.DataArray( nue, dims=['s'], coords={'s': s}, attrs={'Description': 'nustar for electrons calculated in MARS'} ) return
""" 'get' methods, calculate quantities from previously read data """
[docs] def get_RZ(self): """ convert RM and ZM into R and Z real space co-ordinates """ Nm2 = self[self.sim]['Nm0'].values.astype(int) Nchi = self[self.sim]['Nchi'].values.astype(int) chi = np.linspace(np.pi * -1, np.pi, Nchi) m = np.arange(0, Nm2, 1) m = np.reshape(m, (len(m), 1)) chi = np.reshape(chi, (len(chi), 1)) expmchi = np.exp(m * chi.T * 1j) R = np.real(np.dot(self[self.sim]['RM'][:, 0:Nm2], expmchi)) Z = np.real(np.dot(self[self.sim]['ZM'][:, 0:Nm2], expmchi)) self[self.sim]['R'] = xarray.DataArray( R, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self[self.sim]['Z'] = xarray.DataArray( Z, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) return R, Z
[docs] def get_SurfS(self, rs, saveCarMadata=False): """ Generate MacSurfS ASCII file containing control surface for Equivalent Surface Current workflow :param rs: radius (r/a) of control surface picked from CHEASE vacuum mesh :param saveCarMadata: flag to save MacDataS for CarMa coupling """ if 'R' not in self[self.sim]: self.get_RZ() II = np.argmin(abs(self[self.sim]['s'].values - rs)) tmp1 = np.array([self[self.sim]['R'].values[II - 1, :], self[self.sim]['Z'].values[II - 1, :]]).T tmp2 = np.array([self[self.sim]['R'].values[II, :], self[self.sim]['Z'].values[II, :]]).T RZrw_CarMa = np.array([(tmp1 + tmp2) / (2 * self[self.sim]['R0EXP'].values), tmp2 * self[self.sim]['R0EXP'].values]) RZrw_EF = tmp2 * self[self.sim]['R0EXP'].values # Save and load into tree np.savetxt('MacSurfS', RZrw_EF) self['CouplingSurfS'] = {} self['CouplingSurfS']['MacSurfS'] = OMFITascii('./MacSurfS') self['CouplingSurfS']['Rs'] = self[self.sim]['R'].values[II, :] self['CouplingSurfS']['Zs'] = self[self.sim]['Z'].values[II, :] self['CouplingSurfS']['s'] = rs if saveCarMadata: np.savetxt('MacDataS', RZrw_CarMa) self['CouplingDataS'] = {} self['CouplingDataS']['MacDataS'] = OMFITascii('./MacDataS') self['CouplingDataS']['RZrw_CarMa'] = RZrw_CarMa return RZrw_EF, RZrw_CarMa else: return RZrw_EF
[docs] def get_UnitVec(self, vacFlag=False, IIgrid=None): """ Get unit vectors e_s and e_chi and jacobian from real space R,Z :param vacFlag: flag to calculate metric elements in all domain (plasma+vacuum) :param IIgrid: specify the radial mesh index to calculate vectors within """ from scipy.interpolate import InterpolatedUnivariateSpline if 'R' not in self[self.sim]: self.get_RZ() Ls = len(self[self.sim]['R'][:, 0]) Lchi = len(self[self.sim]['R'][0, :]) dRds = copy.deepcopy(self[self.sim]['R'].values) dZds = copy.deepcopy(self[self.sim]['Z'].values) dRdchi = copy.deepcopy(self[self.sim]['R'].values) dZdchi = copy.deepcopy(self[self.sim]['Z'].values) jacobian = copy.deepcopy(self[self.sim]['R'].values) # Number of mesh points in plasma Ns1 = self[self.sim]['Ns1'].values.astype(int) # Number of mesh points in vacuum Ns2 = self[self.sim]['Ns2'].values.astype(int) # indexes of full domain: first couple is vacuum, second is plasma domain = [(Ns1, Ns1 + Ns2), (0, Ns1)] if isinstance(IIgrid, int): II = IIgrid else: II = Ns1 # Loop over vacuum and plasma for ii, kk in domain: if ii == Ns1: printi('Partial derivatives in vacuum') s0 = self[self.sim]['svac'].values elif ii == 0: printi('Partial derivatives in plasma') s0 = self[self.sim]['sp'].values else: printi('ERROR! Check Jacobian calculation') return II1 = ii II2 = kk R0 = self[self.sim]['R'].isel(s=range(II1, II2)) Z0 = self[self.sim]['Z'].isel(s=range(II1, II2)) Nchi = self[self.sim]['Nchi'].values.astype(int) chi0 = np.linspace(np.pi * -1, np.pi, Nchi) hs = 0.5 * ((s0[1:] - s0[:-1]).min()) hs = min(hs, 2e-5) hchi = 0.5 * ((chi0[1:] - chi0[:-1]).min()) hchi = min(hchi, 1e-4) s1 = s0 - hs s2 = s0 + hs chi1 = chi0 - hchi chi2 = chi0 + hchi # compute dR/ds using R(s,chi) and spline R1 = np.zeros(np.shape(R0)) R2 = np.zeros(np.shape(R0)) for k in range(len(R0[0, :])): R1[:, k] = InterpolatedUnivariateSpline(s0, R0[:, k], bbox=[s1[0], s0[-1]])(s1) R2[:, k] = InterpolatedUnivariateSpline(s0, R0[:, k], bbox=[s0[0], s2[-1]])(s2) dRds[II1:II2, :] = (R2 - R1) / (2.0 * hs) # compute dZ/ds using Z(s,chi) and spline Z1 = np.zeros(np.shape(Z0)) Z2 = np.zeros(np.shape(Z0)) for k in range(len(R0[0, :])): Z1[:, k] = InterpolatedUnivariateSpline(s0, Z0[:, k], bbox=[s1[0], s0[-1]])(s1) Z2[:, k] = InterpolatedUnivariateSpline(s0, Z0[:, k], bbox=[s0[0], s2[-1]])(s2) dZds[II1:II2, :] = (Z2 - Z1) / (2.0 * hs) # compute dR/dchi using R(s,chi) and spline R1 = np.zeros(np.shape(R0)) R2 = np.zeros(np.shape(R0)) for k in range(len(R0[:, 0])): R1[k, :] = InterpolatedUnivariateSpline(chi0, R0[k, :], bbox=[chi1[0], chi0[-1]])(chi1) R2[k, :] = InterpolatedUnivariateSpline(chi0, R0[k, :], bbox=[chi0[0], chi2[-1]])(chi2) R1[:, 0] = R1[:, -1] R2[:, -1] = R2[:, 0] dRdchi[II1:II2, :] = (R2 - R1) / (2.0 * hchi) # compute dR/dchi using R(s,chi) and spline Z1 = np.zeros(np.shape(Z0)) Z2 = np.zeros(np.shape(Z0)) for k in range(len(R0[:, 0])): Z1[k, :] = InterpolatedUnivariateSpline(chi0, Z0[k, :], bbox=[chi1[0], chi0[-1]])(chi1) Z2[k, :] = InterpolatedUnivariateSpline(chi0, Z0[k, :], bbox=[chi0[0], chi2[-1]])(chi2) Z1[:, 0] = Z1[:, -1] Z2[:, -1] = Z2[:, 0] dZdchi[II1:II2, :] = (Z2 - Z1) / (2.0 * hchi) # Calculate Jacobian J = (self[self.sim]['R'].values) * (-dRdchi * dZds + dRds * dZdchi) J[0, :] = J[1, :] if vacFlag: # Calculate metric elements in both plasma and vacuum G11 = np.square(dRds) + np.square(dZds) G12 = np.multiply(dRds, dRdchi) + np.multiply(dZds, dZdchi) G22 = np.square(dRdchi) + np.square(dZdchi) G22[0, :] = G22[1, :] G33 = np.square(self[self.sim]['R'].values) else: # Calculate metric elements inside the plasma G11 = np.square(dRds[0:II, :]) + np.square(dZds[0:II, :]) G12 = np.multiply(dRds[0:II, :], dRdchi[0:II, :]) + np.multiply(dZds[0:II, :], dZdchi[0:II, :]) G22 = np.square(dRdchi[0:II, :]) + np.square(dZdchi[0:II, :]) G22[0, :] = G22[1, :] G33 = np.square(self[self.sim]['R'].values[0:II, :]) # Store data self['UnitVector'] = xarray.Dataset() self['UnitVector']['dRds'] = xarray.DataArray( dRds, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['UnitVector']['dZds'] = xarray.DataArray( dZds, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['UnitVector']['dRdchi'] = xarray.DataArray( dRdchi, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['UnitVector']['dZdchi'] = xarray.DataArray( dZdchi, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['UnitVector']['Jacobian'] = xarray.DataArray( J, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['Metric'] = xarray.Dataset() if vacFlag: self['Metric']['G11'] = xarray.DataArray( G11, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['Metric']['G12'] = xarray.DataArray( G12, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['Metric']['G22'] = xarray.DataArray( G22, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) self['Metric']['G33'] = xarray.DataArray( G33, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s']} ) else: self['Metric']['G11'] = xarray.DataArray( G11, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s'][0:II]} ) self['Metric']['G12'] = xarray.DataArray( G12, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s'][0:II]} ) self['Metric']['G22'] = xarray.DataArray( G22, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s'][0:II]} ) self['Metric']['G33'] = xarray.DataArray( G33, dims=['s', 'chi'], coords={'chi': np.linspace(np.pi * -1, np.pi, Nchi), 's': self[self.sim]['s'][0:II]} ) return dRds, dZds, dRdchi, dZdchi, jacobian
[docs] def get_X123(self): """ Inverse Fourier transorm of plasma displacement and projection along Chi and Phi """ if 'UnitVector' not in self: self.get_UnitVec() expmchi = np.exp(self['XPLASMA']['Mm'] * self[self.sim]['chi'] * 1j) expmchi_inv = np.exp(-self[self.sim]['chi'] * self['XPLASMA']['Mm'] * 1j) chione = np.ones((1, len(self[self.sim]['chi']))) Ns1 = self[self.sim]['Ns1'].values X1a = np.dot(self['XPLASMA']['XM1'].values, expmchi) X2a = np.dot(self['XPLASMA']['XM2'].values, expmchi) X3a = np.dot(self['XPLASMA']['XM3'].values, expmchi) if np.size(self['Metric']['G22'], 0) != np.size(X1a, 0): self.get_UnitVec(vacFlag=False) # Calculate X1 along e_s X1 = X1a # Calculate X2 along e_chi dPSIds = np.array(self[self.sim]['dPSIds'].values).reshape((len(self[self.sim]['dPSIds'].values), 1)) J = self['UnitVector']['Jacobian'].isel(s=range(Ns1)).values T = np.array(self[self.sim]['T'].values).reshape((len(self[self.sim]['T']), 1)) Bchi = np.divide(np.dot(dPSIds, chione), J) Bphi = np.divide(np.dot(T, chione), np.square(self[self.sim]['R'].values[0:Ns1, :])) B2 = np.multiply(np.square(Bchi), self['Metric']['G22']) + np.multiply(np.square(Bphi), self['Metric']['G33']) X2 = ( np.divide(np.multiply(-X1, np.multiply(self['Metric']['G12'], np.square(Bchi))), B2) + np.divide(np.multiply(X2a, np.multiply(Bphi, self['Metric']['G33'])), B2) - np.multiply(X3a, Bchi) ) # Calculate X3 along e_phi X3 = ( np.divide(np.multiply(-X1, np.multiply(self['Metric']['G12'], np.multiply(Bchi, Bphi))), B2) + np.divide(np.multiply(X2a, np.multiply(Bchi, self['Metric']['G22'])), B2) - np.multiply(X3a, Bphi) ) # Calculate normal plasma displacement Xn = np.divide(np.multiply(X1a, J), np.sqrt(np.multiply(self['Metric']['G33'], self['Metric']['G22']))) # Fourier transorm of Xn XnM = np.dot(Xn, expmchi_inv) * (self[self.sim]['chi'].values[1] - self[self.sim]['chi'].values[0]) / (2 * np.pi) # Radial coordinate name 's' is retained for compatibility, here 's' is 'sp' (within plasma) self['XPLASMA']['Bchi'] = xarray.DataArray( Bchi, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']} ) self['XPLASMA']['Bphi'] = xarray.DataArray( Bphi, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']} ) self['XPLASMA']['B2'] = xarray.DataArray(B2, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['X1'] = xarray.DataArray(X1, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['X2'] = xarray.DataArray(X2, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['X3'] = xarray.DataArray(X3, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['Xn'] = xarray.DataArray(Xn, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['XnM'] = xarray.DataArray(XnM, dims=['sp', 'Mm'], coords={'sp': self[self.sim]['sp'], 'Mm': self['XPLASMA']['Mm']}) self['XPLASMA']['X1a'] = xarray.DataArray( X1a, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']} ) self['XPLASMA']['X2a'] = xarray.DataArray( X2a, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']} ) self['XPLASMA']['X3a'] = xarray.DataArray( X3a, dims=['sp', 'chi'], coords={'sp': self[self.sim]['sp'], 'chi': self[self.sim]['chi']} )
[docs] def get_B123(self): """ Inverse Fourier transorm of perturbed magnetic field and calculate Bn """ if 'UnitVector' not in self: self.get_UnitVec() # Check metric element size # This is needed when IIgrid=None and NV(MARS) != NV(CHEASE) II = np.size(self['BPLASMA']['BM1'], 0) if np.size(self['Metric']['G22'], 0) != II: print("WARNING: NV(MARS) != NV(CHEASE). Calculating metric elements with b-field radial grid size.") self.get_UnitVec(IIgrid=II) # Define DFT matrices expmchi = np.exp(self['BPLASMA']['Mm'] * self[self.sim]['chi'] * 1j) expmchi_inv = np.exp(-self[self.sim]['chi'] * self['BPLASMA']['Mm'] * 1j) chione = np.ones((1, len(self[self.sim]['chi']))) # Calculate inverse Fourier transorm B1 = np.dot(self['BPLASMA']['BM1'].isel(s=range(II)), expmchi) B2 = np.dot(self['BPLASMA']['BM2'].isel(s=range(II)), expmchi) B3 = np.dot(self['BPLASMA']['BM3'].isel(s=range(II)), expmchi) # Calculate normal perturbeb magnetic field Bn = np.divide(B1, np.multiply(np.sqrt(self['Metric']['G22']), self[self.sim]['R'].isel(s=range(II)))) # Fourier transorm of Bn BnM = np.dot(Bn, expmchi_inv) * (self[self.sim]['chi'].values[1] - self[self.sim]['chi'].values[0]) / (2 * np.pi) # Store data self['BPLASMA']['B1'] = xarray.DataArray(B1, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['BPLASMA']['B2'] = xarray.DataArray(B2, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['BPLASMA']['B3'] = xarray.DataArray(B3, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['BPLASMA']['Bn'] = xarray.DataArray(Bn, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['BPLASMA']['BnM'] = xarray.DataArray(BnM, dims=['s', 'Mm'], coords={'s': self['BPLASMA']['s'], 'Mm': self['BPLASMA']['Mm']})
[docs] def get_J123(self): """ Inverse Fourier transorm of perturbed current """ if 'UnitVector' not in self: self.get_UnitVec() # Check metric element size # This is needed when IIgrid=None and NV(MARS) != NV(CHEASE) II = np.size(self['JPLASMA']['JM1'], 0) if np.size(self['Metric']['G22'], 0) != II: print("WARNING: NV(MARS) != NV(CHEASE). Calculating metric elements with b-field radial grid size.") self.get_UnitVec(IIgrid=II) # Define DFT matrices expmchi = np.exp(self['JPLASMA']['Mm'] * self[self.sim]['chi'] * 1j) expmchi_inv = np.exp(-self[self.sim]['chi'] * self['JPLASMA']['Mm'] * 1j) chione = np.ones((1, len(self[self.sim]['chi']))) # Calculate inverse Fourier transorm J1 = np.dot(self['JPLASMA']['JM1'].isel(s=range(II)), expmchi) J2 = np.dot(self['JPLASMA']['JM2'].isel(s=range(II)), expmchi) J3 = np.dot(self['JPLASMA']['JM3'].isel(s=range(II)), expmchi) # Store data self['JPLASMA']['J1'] = xarray.DataArray(J1, dims=['s', 'chi'], coords={'s': self['JPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['JPLASMA']['J2'] = xarray.DataArray(J2, dims=['s', 'chi'], coords={'s': self['JPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['JPLASMA']['J3'] = xarray.DataArray(J3, dims=['s', 'chi'], coords={'s': self['JPLASMA']['s'], 'chi': self[self.sim]['chi']})
[docs] def get_Bcyl(self): """ Get B-field components in cylindrical coordinates """ print('GET: calculating B-field cylindrical components') if 'B1' not in self['BPLASMA']: self.get_B123() if 'R' not in self[self.sim]: self.get_RZ() II = np.size(self['BPLASMA']['BM1'], 0) J = self['UnitVector']['Jacobian'].isel(s=range(II)) dRds = self['UnitVector']['dRds'].isel(s=range(II)) dRdchi = self['UnitVector']['dRdchi'].isel(s=range(II)) dZds = self['UnitVector']['dZds'].isel(s=range(II)) dZdchi = self['UnitVector']['dZdchi'].isel(s=range(II)) R0 = self[self.sim]['R'].isel(s=range(II)) # Calculate Br,z,phi Br = (self['BPLASMA']['B1'] * dRds + self['BPLASMA']['B2'] * dRdchi) / J Br[0:2, :] = Br[2, :] Bz = (self['BPLASMA']['B1'] * dZds + self['BPLASMA']['B2'] * dZdchi) / J Bz[0:2, :] = Bz[2, :] Bphi = (self['BPLASMA']['B3'] * R0) / J Bphi[0:2, :] = Bphi[2, :] self['BPLASMA']['Br'] = xarray.DataArray(Br, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['BPLASMA']['Bz'] = xarray.DataArray(Bz, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']}) self['BPLASMA']['Bphi'] = xarray.DataArray( Bphi, dims=['s', 'chi'], coords={'s': self['BPLASMA']['s'], 'chi': self[self.sim]['chi']} )
[docs] def get_Xcyl(self): """ Get displacement components in cylindrical coordinates """ print('GET: calculating plasma displacement cylindrical components') if 'X1' not in self['XPLASMA']: self.get_X123() if 'R' not in self[self.sim]: self.get_RZ() II = np.size(self['XPLASMA']['XM1'], 0) J = self['UnitVector']['Jacobian'].isel(s=range(II)) dRds = self['UnitVector']['dRds'].isel(s=range(II)) dRdchi = self['UnitVector']['dRdchi'].isel(s=range(II)) dZds = self['UnitVector']['dZds'].isel(s=range(II)) dZdchi = self['UnitVector']['dZdchi'].isel(s=range(II)) R0 = self[self.sim]['R'].isel(s=range(II)) # Calculate Xr,z,phi Xr = self['XPLASMA']['X1'].values * dRds.values + self['XPLASMA']['X2'].values * dRdchi.values Xr[0:2, :] = Xr[2, :] Xz = self['XPLASMA']['X1'].values * dZds.values + self['XPLASMA']['X2'].values * dZdchi.values Xz[0:2, :] = Xz[2, :] Xphi = self['XPLASMA']['X3'].values * R0.values Xphi[0:2, :] = Xphi[2, :] self['XPLASMA']['Xr'] = xarray.DataArray(Xr, dims=['sp', 'chi'], coords={'sp': self['XPLASMA']['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['Xz'] = xarray.DataArray(Xz, dims=['sp', 'chi'], coords={'sp': self['XPLASMA']['sp'], 'chi': self[self.sim]['chi']}) self['XPLASMA']['Xphi'] = xarray.DataArray( Xphi, dims=['sp', 'chi'], coords={'sp': self['XPLASMA']['sp'], 'chi': self[self.sim]['chi']} )
[docs] def get_dWk(self, NFIT=3): """ Calculate dWk components from DWK_ENERGY_DENSITY :param NFIT: integral of energy density skips the first NFIT+1 points """ print('GET: calculating dWk components') if 'DWK_ENERGY_DENSITY' not in self: self.read_dWk_den() den = self['DWK_ENERGY_DENSITY']['FULL_MATRIX'] NR = len(den[:, 0]) n = len(den[0, :]) // 10 blocks = np.split(den, n, axis=1) DWK = np.zeros((n, 8)) for l in range(len(blocks)): REdwppara = 0 IMdwppara = 0 REdwpperp = 0 IMdwpperp = 0 REdwk = 0 IMdwk = 0 # Storing KP (=1...NSPECIES, 0=total) DWK[l, 0] = blocks[l][0, 0] # Storing I (=1...5) DWK[l, 1] = blocks[l][1, 1] for j in range(NFIT + 1, NR): REdwppara = REdwppara + blocks[l][j, 4] * blocks[l][j, 3] IMdwppara = IMdwppara + blocks[l][j, 5] * blocks[l][j, 3] REdwpperp = REdwpperp + blocks[l][j, 6] * blocks[l][j, 3] IMdwpperp = IMdwpperp + blocks[l][j, 7] * blocks[l][j, 3] REdwk = REdwk + blocks[l][j, 8] * blocks[l][j, 3] IMdwk = IMdwk + blocks[l][j, 9] * blocks[l][j, 3] DWK[l, 2] = REdwppara DWK[l, 3] = IMdwppara DWK[l, 4] = REdwpperp DWK[l, 5] = IMdwpperp DWK[l, 6] = REdwk DWK[l, 7] = IMdwk # Total dWk K_tot = [] # Non-adiabatic Trapped precession Drift K_I_NTD = [] K_e_NTD = [] # Non-adiabatic Trapped Bounce K_I_NTB = [] K_e_NTB = [] # Non-adiabatic Passing K_I_NP = [] K_e_NP = [] species = np.unique(DWK[:, 0]) Nspecies = len(species) - 1 self['DWK_COMPONENTS'] = xarray.Dataset() self['DWK_COMPONENTS']['NSPECIES'] = Nspecies for P in species: if P == 0: # Storing total kinetic contribution (i,) = np.where(DWK[:, 0] == 0.0) (j,) = np.where(DWK[i, 1] == 0.0) K_tot = complex(DWK[i[j], 6], DWK[i[j], 7]) self['DWK_COMPONENTS']['K_tot'] = K_tot else: if P == 1: # ions particle = 'I' elif P == 2: # electrons particle = 'e' elif P > 2: # Other particle species particle = str(P) (l,) = np.where(DWK[:, 0] == P) (p,) = np.where(DWK[l, 1] == 3.0) (b,) = np.where(DWK[l, 1] == 4.0) (d,) = np.where(DWK[l, 1] == 5.0) if not p: K_NP = complex(0.0, 0.0) else: K_NP = complex(DWK[l[p], 6], DWK[l[p], 7]) if not b: K_NTB = complex(0.0, 0.0) else: K_NTB = complex(DWK[l[b], 6], DWK[l[b], 7]) if not d: K_NTD = complex(0.0, 0.0) else: K_NTD = complex(DWK[l[d], 6], DWK[l[d], 7]) self['DWK_COMPONENTS']['K_%s_NTD' % particle] = K_NTD self['DWK_COMPONENTS']['K_%s_NTB' % particle] = K_NTB self['DWK_COMPONENTS']['K_%s_NP' % particle] = K_NP
[docs] def get_BatSurf(self, rsurf, kdR=False): """ Calculate normal and tangential components of BPLASMA on given surface (e.g. wall) Calculate Fourier decomposition of Bn,t,phi Method used in CarMa Forward Coupling :param rsurf: normalized radius of surface :param kdR: flag for alternative calculation of unit vectors (default=False) """ print('GET: calculating B-field on r=%s surface' % (rsurf)) if 'B1' not in self['BPLASMA']: self.get_B123() if 'R' not in self[self.sim]: self.get_RZ() if 'Br' not in self['BPLASMA']: self.get_Bcyl() mm = self['BPLASMA']['Mm'].values # Find wall surface index IIsurf = np.argmin(np.abs(self[self.sim]['s'].values - rsurf)) Rw = self[self.sim]['R'].isel(s=IIsurf) Zw = self[self.sim]['Z'].isel(s=IIsurf) Cw = self[self.sim]['chi'].values R = self[self.sim]['R'] Z = self[self.sim]['Z'] Tw = np.arctan2(Zw - Z[0, 0], Rw - R[0, 0]) KK = np.where(np.diff(Tw) < -np.pi)[0] if (len(KK) == 1) & (2 * KK > len(Tw)): Tw[KK[0] + 1 :] = Tw[KK[0] + 1 :] + 2 * np.pi if (len(KK) == 1) & (2 * KK < len(Tw)): Tw[0 : KK[0]] = Tw[0 : KK[0]] - 2 * np.pi Tw = np.sort(Tw) JJ = np.argsort(Tw) try: Bwr = self['BPLASMA']['Br'].isel(s=IIsurf) Bwz = self['BPLASMA']['Bz'].isel(s=IIsurf) Bwphi = self['BPLASMA']['Bphi'].isel(s=IIsurf) except IndexError: print('ERROR: Selected index is out of BPLASMA calculation domain') return # clean Tw,Rw,Zw,Bwr,Bwz,Bwphi [Tw, JJ] = np.unique(Tw, return_index=True) Rw = Rw[JJ] Zw = Zw[JJ] Cw = Cw[JJ] Bwr = Bwr[JJ] Bwz = Bwz[JJ] Bwphi = Bwphi[JJ] # get Gauss quadrature points for Fourier decomposition z, w = np.polynomial.legendre.leggauss(2) x0 = (Tw[:-1] + Tw[1:]) * 0.5 h2 = np.diff(Tw) * 0.5 xx = z[:, np.newaxis] * h2[np.newaxis, :] + np.ones(z.shape)[:, np.newaxis] * x0[np.newaxis, :] wh = w[:, np.newaxis] * h2[np.newaxis, :] xx = xx.reshape(-1, 1) wh = wh.reshape(-1, 1) if kdR == True: # Fourier decompose (Rw,Zw) in Tw-angle expmt = np.exp(-1j * xx * mm) / (2 * np.pi) Rx = scipy.interpolate.pchip(Tw, Rw)(xx) * wh Zx = scipy.interpolate.pchip(Tw, Zw)(xx) * wh Rm = np.dot(Rx.T, expmt) Zm = np.dot(Zx.T, expmt) # compute (dR/dTw,dZ/dTw) via Fourier harmonics expmt = np.exp(1j * mm * Tw[:, np.newaxis]) dR = 1j * np.dot(mm * Rm, expmt.T) dZ = 1j * np.dot(mm * Zm, expmt.T) # res = [dR(:) dZ(:)] dR = np.squeeze(dR.real) dZ = np.squeeze(dZ.real) else: # another way to compute dR,dZ dRT = np.diff(Rw) / np.diff(Tw) x = (Tw[1:] + Tw[0:-1]) * 0.5 x = np.concatenate([[x[-1] - 2 * np.pi], x, [x[0] + 2 * np.pi]]) dRT = np.concatenate([[dRT[-1]], dRT, [dRT[0]]]) dR = scipy.interpolate.pchip(x, dRT)(Tw) dZT = np.diff(Zw) / np.diff(Tw) dZT = np.concatenate([[dZT[-1]], dZT, [dZT[0]]]) dZ = scipy.interpolate.pchip(x, dZT)(Tw) # compute physical Bn & Bt from Bwr & Bwz nA = np.sqrt(dR**2 + dZ**2) Bn = (Bwr * dZ - Bwz * dR) / nA Bt = (Bwr * dR + Bwz * dZ) / nA # Fourier decompose Bn, Bt & Bphi along Tw angle expmt = np.exp(-1j * xx * mm) / (2 * np.pi) Bnx = scipy.interpolate.pchip(Tw, Bn.values)(xx) * wh Btx = scipy.interpolate.pchip(Tw, Bt.values)(xx) * wh Bpx = scipy.interpolate.pchip(Tw, Bwphi.values)(xx) * wh Bnm = np.dot(Bnx.T, expmt).T Btm = np.dot(Btx.T, expmt).T Bpm = np.dot(Bpx.T, expmt).T # Store results self['BPLASMA']['Bn_s'] = xarray.DataArray(Bn, dims=['Tw'], coords={'Tw': Tw}) self['BPLASMA']['Bt_s'] = xarray.DataArray(Bt, dims=['Tw'], coords={'Tw': Tw}) self['BPLASMA']['Bphi_s'] = xarray.DataArray(Bwphi, dims=['Tw'], coords={'Tw': Tw}) self['BPLASMA']['Bnm_s'] = xarray.DataArray(np.squeeze(Bnm), dims=['Mm'], coords={'Mm': self['BPLASMA']['Mm']}) self['BPLASMA']['Btm_s'] = xarray.DataArray(np.squeeze(Btm), dims=['Mm'], coords={'Mm': self['BPLASMA']['Mm']}) self['BPLASMA']['Bpm_s'] = xarray.DataArray(np.squeeze(Bpm), dims=['Mm'], coords={'Mm': self['BPLASMA']['Mm']}) return Bnm, Btm, Bpm
[docs] @dynaLoad def load(self): self[self.sim] = xarray.Dataset() mapper = OrderedDict( ( ('RMZM_F.OUT', self.read_RMZM), ('RMZM_F', self.read_RMZM), ('JPLASMA.OUT', self.read_JPLASMA), ('JPLASMA', self.read_JPLASMA), ('RESULT.OUT', self.read_RESULTS), ('RESULT', self.read_RESULTS), ('BPLASMA.OUT', self.read_BPLASMA), ('BPLASMA', self.read_BPLASMA), ('PROFEQ.OUT', self.read_PROFEQ), ('PROFEQ', self.read_PROFEQ), ('XPLASMA.OUT', self.read_XPLASMA), ('XPLASMA', self.read_XPLASMA), ('FREQUENCIES.OUT', self.read_FREQS), ('DWK_ENERGY_DENSITY.OUT', self.read_dWk_den), ('PROFNTV.OUT', self.read_PROFNTV), ('TORQUENTV.OUT', self.read_TORQUENTV), ('PROFNUSTAR.OUT', self.read_NUSTAR), ) ) for item in mapper: if os.path.exists(self.filename + os.sep + item): try: mapper[item](self.filename + os.sep + item) except Exception as _excp: print(f'Problem parsing {item}: {_excp}')
""" Plotting methods """
[docs] def plot_RMZM(self, fig=None): """ Plot RM-ZM grid :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax1 = pyplot.subplot(2, 2, 1) ax1.plot(self[self.sim]['s'], np.real(self[self.sim]['RM'])) ax1.set_ylabel('Re(R_m)') ax2 = pyplot.subplot(2, 2, 2) ax2.plot(self[self.sim]['s'], np.imag(self[self.sim]['RM'])) ax2.set_ylabel('Im(R_m)') ax3 = pyplot.subplot(2, 2, 3) ax3.plot(self[self.sim]['s'], np.real(self[self.sim]['ZM'])) ax3.set_ylabel('Re(Z_m)') ax3.set_xlabel('s') ax4 = pyplot.subplot(2, 2, 4) ax4.plot(self[self.sim]['s'], np.imag(self[self.sim]['ZM'])) ax4.set_ylabel('Im(Z_m)') ax4.set_xlabel('s') fig.tight_layout()
[docs] def plot_RZ(self, fig=None): """ Plot R-Z grid :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) Ns = self[self.sim]['Ns1'].values.astype(int) + self[self.sim]['Ns2'].values.astype(int) Rplot = self[self.sim]['R'][0:Ns, :].values Zplot = self[self.sim]['Z'][0:Ns, :].values ax.plot(Rplot.T * self[self.sim]['R0EXP'].values, Zplot.T * self[self.sim]['R0EXP'].values, 'g-') ax.plot(Rplot * self[self.sim]['R0EXP'].values, Zplot * self[self.sim]['R0EXP'].values, 'b-') ax.axis('equal') ax.set_xlabel('R [m]') ax.set_ylabel('Z [m]') fig.tight_layout()
[docs] def plot_SurfS(self, fig=None): """ Plot surface stored in ['CouplingSurfS'] :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) Ns = self[self.sim]['Ns1'].values.astype(int) + self[self.sim]['Ns2'].values.astype(int) Ns1 = self[self.sim]['Ns1'].values.astype(int) Rtot = self[self.sim]['R'][0:Ns, :].values Ztot = self[self.sim]['Z'][0:Ns, :].values if 'CouplingSurfS' not in self: self.get_SurfS() Rs = self['CouplingSurfS']['Rs'] Zs = self['CouplingSurfS']['Zs'] Rplasma = self[self.sim]['R'][Ns1, :].values Zplasma = self[self.sim]['Z'][Ns1, :].values # Plot all surfaces ax.plot(Rtot.T * self[self.sim]['R0EXP'].values, Ztot.T * self[self.sim]['R0EXP'].values, color='g') # Plot SurfS ax.plot(Rs * self[self.sim]['R0EXP'].values, Zs * self[self.sim]['R0EXP'].values, linewidth=3, color='r') ax.plot( Rplasma * self[self.sim]['R0EXP'].values, Zplasma * self[self.sim]['R0EXP'].values, linestyle='dashed', linewidth=2, color='b' ) ax.axis('equal') ax.set_xlabel('R [m]') ax.set_ylabel('Z [m]') fig.tight_layout()
[docs] def plot_JPLASMA(self, Mmax=5, fig=None): """ Plot perturbed current components j1,j2,j3 The MARS variable "J*j" is shown, not the physical quantity "j" :param fig: specify target figure """ from matplotlib import pyplot from labellines import labelLine, labelLines if fig is None: fig = pyplot.figure() ax = None label = 'JPLASMA' MM = self[label]['Mm'].values labelstring = [str(m) for m in MM] for k, c in enumerate(['JM1', 'JM2', 'JM3']): ax = ax1 = fig.use_subplot(3, 2, 2 * k + 1, sharex=ax) ax1.plot(self[label]['s'], np.real(self[label][c])) for i, line in enumerate(ax1.lines): line.set_label(labelstring[i]) lines1 = ax1.get_lines() labelLines(lines1[np.abs(np.min(MM)) + 1 : np.abs(np.min(MM)) + Mmax + 1], xvals=(0.0, 1.0), align=False) ax1.set_title('Re($J\cdot j^%d_m$)' % (k + 1), y=0.8) ax2 = fig.use_subplot(3, 2, 2 * (k + 1), sharex=ax) ax2.plot(self[label]['s'], np.imag(self[label][c])) for i, line in enumerate(ax2.lines): line.set_label(labelstring[i]) lines2 = ax2.get_lines() labelLines(lines2[np.abs(np.min(MM)) + 1 : np.abs(np.min(MM)) + Mmax + 1], xvals=(0.0, 1.0), align=False) ax2.set_title('Im($J\cdot j^%d_m$)' % (k + 1), y=0.8) ax1.set_xlabel('s') ax2.set_xlabel('s') fig.tight_layout()
[docs] def plot_FREQUENCIES(self, fig=None): """ Plot frequencies related to drift kinetic resonances :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) label = 'FREQUENCIES' ax.plot(self[label]['s'], self[label]['we'], 'k-', label=r'$\omega_E$') ax.plot(self[label]['s'], self[label]['wsni'] + self[label]['wsti'], 'g-', label=r'$\omega_*^{thi}$') ax.plot(self[label]['s'], self[label]['awbt'], 'b-', label=r'$\omega_b^{thi}$') ax.plot(self[label]['s'], self[label]['awdi'], 'r-', label=r'$\omega_d^{thi}$') ax.plot(self[label]['s'], self[label]['awda'], 'r--', label=r'$\omega_d^{hot}$') ax.set_xlabel('s') ax.set_ylabel('Frequencies') ax.legend(loc=0) fig.tight_layout()
[docs] def plot_BPLASMA(self, Mmax=5, fig=None): """ Plot perturbed field components b1,b2,b3 The MARS variable "J*b" is shown, not the physical quantity "b" :param Mmax: upper poloidal harmonic for labeling :param fig: specify target figure """ from matplotlib import pyplot from labellines import labelLine, labelLines if fig is None: fig = pyplot.figure() ax = None label = 'BPLASMA' MM = self[label]['Mm'].values labelstring = [str(m) for m in MM] for k, c in enumerate(['BM1', 'BM2', 'BM3']): ax = ax1 = fig.use_subplot(3, 2, 2 * k + 1, sharex=ax) ax1.plot(self[label]['s'], np.real(self[label][c])) for i, line in enumerate(ax1.lines): line.set_label(labelstring[i]) lines1 = ax1.get_lines() labelLines(lines1[np.abs(np.min(MM)) + 1 : np.abs(np.min(MM)) + Mmax + 1], xvals=(0.0, 1.0), align=False) ax1.set_title('Re($J\cdot b^%d_m$)' % (k + 1), y=0.8) ax2 = fig.use_subplot(3, 2, 2 * (k + 1), sharex=ax) ax2.plot(self[label]['s'], np.imag(self[label][c])) for i, line in enumerate(ax2.lines): line.set_label(labelstring[i]) lines2 = ax2.get_lines() labelLines(lines2[np.abs(np.min(MM)) + 1 : np.abs(np.min(MM)) + Mmax + 1], xvals=(0.0, 1.0), align=False) ax2.set_title('Im($J\cdot b^%d_m$)' % (k + 1), y=0.8) ax1.set_xlabel('s') ax2.set_xlabel('s') fig.tight_layout()
[docs] def plot_XPLASMA(self, Mmax=5, fig=None): """ Plot plasma displacement components X1,X2,X3 :param Mmax: upper poloidal harmonic for labeling :param fig: specify target figure """ from matplotlib import pyplot from labellines import labelLine, labelLines if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = None label = 'XPLASMA' MM = self[label]['Mm'].values labelstring = [str(m) for m in MM] for k, c in enumerate(['XM1', 'XM2', 'XM3']): ax1 = pyplot.subplot(3, 2, 2 * k + 1, sharex=ax) ax1.plot(self[label]['sp'], np.real(self[label][c])) for i, line in enumerate(ax1.lines): line.set_label(labelstring[i]) lines1 = ax1.get_lines() labelLines(lines1[np.abs(np.min(MM)) + 1 : np.abs(np.min(MM)) + Mmax + 1], xvals=(0.0, 1.0), align=False) ax1.set_title('Re($X^%d_m$)' % (k + 1), y=0.8) ax2 = pyplot.subplot(3, 2, 2 * (k + 1), sharex=ax) ax2.plot(self[label]['sp'], np.imag(self[label][c])) for i, line in enumerate(ax2.lines): line.set_label(labelstring[i]) lines2 = ax2.get_lines() labelLines(lines2[np.abs(np.min(MM)) + 1 : np.abs(np.min(MM)) + Mmax + 1], xvals=(0.0, 1.0), align=False) ax2.set_title('Im($X^%d_m$)' % (k + 1), y=0.8) ax1.set_xlabel('sp') ax2.set_xlabel('sp') fig.tight_layout()
[docs] def plot_Xn(self, fig=None): """ Plot normal plasma displacement :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) label = 'XPLASMA' if 'R' not in self[self.sim]: self.get_RZ() if 'Xn' not in self[label]: self.get_X123() Irat = self[self.sim]['Iratsurf'] # Plasma displacement defined within plasma boundary Ns1 = self[self.sim]['Ns1'].values R = self[self.sim]['R'].isel(s=range(Ns1)) * self[self.sim]['R0EXP'] Z = self[self.sim]['Z'].isel(s=range(Ns1)) * self[self.sim]['R0EXP'] C = np.real(self[label]['Xn']) pc = ax.pcolormesh(R, Z, C, cmap='jet', antialiased=True) for I in Irat.values: ax.plot(R[I, :], Z[I, :], linestyle='dashed', linewidth=2, color='w') ax.set_aspect('equal', adjustable='box') fig.colorbar(pc, ax=ax) ax.set_title('Re($\\xi_n$)') ax.set_xlabel('R [m]') ax.set_ylabel('Z [m]') fig.tight_layout()
[docs] def plot_Bn(self, II=False, fig=None): """ Plot normal field perturbation :param II: plot up to II radial grid index (default is plasma boundary) :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) label = 'BPLASMA' if 'R' not in self[self.sim]: self.get_RZ() if 'Bn' not in self[label]: self.get_B123() Irat = self[self.sim]['Iratsurf'] # Pick last s-grid point for Bn plotting if II: Ns = II else: Ns = self[self.sim]['Ns1'].values R = self[self.sim]['R'].isel(s=range(Ns)) * self[self.sim]['R0EXP'] Z = self[self.sim]['Z'].isel(s=range(Ns)) * self[self.sim]['R0EXP'] C = np.real(self[label]['Bn'].isel(s=range(Ns))) pc = ax.pcolormesh(R, Z, C, cmap='jet', antialiased=True) for I in Irat.values: ax.plot(R[I, :], Z[I, :], linestyle='dashed', linewidth=2, color='w') ax.set_aspect('equal', adjustable='box') fig.colorbar(pc, ax=ax) ax.set_title('Re($B_n$)') ax.set_xlabel('R [m]') ax.set_ylabel('Z [m]') fig.tight_layout()
[docs] def plot_BrzSurf(self, II=False, rsurf=False, fig=None): """ Plot Br Bz (cyl. coords.) along specified surface :param II: plot on II radial grid index (default is plasma boundary) :param rsurf: normalized radius of surface :param fig: specify target figure """ # Pick last s-grid point for Bn plotting from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) if II: Ns = II elif rsurf: # Find surface index Ns = np.argmin(np.abs(self[self.sim]['s'].values - rsurf)) else: Ns = self[self.sim]['Ns1'].values R = (self[self.sim]['R'].values) * self[self.sim]['R0EXP'].values Z = (self[self.sim]['Z'].values) * self[self.sim]['R0EXP'].values Rw = R[Ns, :] Zw = Z[Ns, :] Tw = np.arctan2(Zw - Z[0, 0], Rw - R[0, 0]) * (180 / np.pi) KK = np.where(np.diff(Tw) < -180)[0] if (len(KK) == 1) & (2 * KK > len(Tw)): Tw[KK[0] + 1 :] = Tw[KK[0] + 1 :] + 360 if (len(KK) == 1) & (2 * KK < len(Tw)): Tw[0 : KK[0]] = Tw[0 : KK[0]] - 360 Tw = np.sort(Tw) JJ = np.argsort(Tw) label = 'BPLASMA' BR = self[label]['Br'].values BZ = self[label]['Bz'].values ax1 = pyplot.subplot(2, 2, 1) ax1.plot(Tw, np.real(BR[Ns, JJ]), linewidth=2) ax1.set_ylabel('Re($\delta B_R$)') ax2 = pyplot.subplot(2, 2, 2) ax2.plot(Tw, np.imag(BR[Ns, JJ]), linewidth=2) ax2.set_ylabel('Im($\delta B_R$)') ax3 = pyplot.subplot(2, 2, 3) ax3.plot(Tw, np.real(BZ[Ns, JJ]), linewidth=2) ax3.set_ylabel('Re($\delta B_Z$)') ax3.set_xlabel('GEOM angle') ax4 = pyplot.subplot(2, 2, 4) ax4.plot(Tw, np.imag(BZ[Ns, JJ]), linewidth=2) ax4.set_ylabel('Im($\delta B_Z$)') ax4.set_xlabel('GEOM angle') fig.suptitle(r'$B_r$, $B_z$ vs poloidal angle at s(%s)=%s' % (Ns, self[self.sim]['s'][Ns].values)) fig.tight_layout()
[docs] def plot_BrzAbs(self, fig=None): """ Plot |B| along poloidal angle at plasma surface :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) Ns = self[self.sim]['Ns1'].values chi = self[self.sim]['chi'].values label = 'BPLASMA' AmpB = np.sqrt(abs(self[label]['Br'].values) ** 2 + abs(self[label]['Bz'].values) ** 2 + abs(self[label]['Bphi'].values) ** 2) ax.plot(chi * 180 / np.pi, AmpB[Ns, :], linewidth=2) ax.set_ylabel('$|\delta B|$') ax.set_xlabel('Poloidal angle $[\circ]$') fig.tight_layout()
[docs] def plot_BrzMap(self, fig=None): """ Plot |B| (R,Z) map inside plasma :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) Ns = self[self.sim]['Ns1'].values label = 'BPLASMA' Br = self[label]['Br'].isel(s=range(Ns)).values Bz = self[label]['Bz'].isel(s=range(Ns)).values Bphi = self[label]['Bphi'].isel(s=range(Ns)).values AmpB = np.sqrt(abs(Br) ** 2 + abs(Bz) ** 2 + abs(Bphi) ** 2) R = self[self.sim]['R'].isel(s=range(Ns)) * self[self.sim]['R0EXP'] Z = self[self.sim]['Z'].isel(s=range(Ns)) * self[self.sim]['R0EXP'] pc = ax.pcolormesh(R, Z, AmpB, cmap='jet', antialiased=True) ax.set_aspect('equal', adjustable='box') fig.colorbar(pc, ax=ax) ax.set_title('$|\delta B|$') ax.set_xlabel('R [m]') ax.set_ylabel('Z [m]') fig.tight_layout()
[docs] def plot_XrzMap(self, fig=None): """ Plot |X| (R,Z) map inside plasma :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() Ns = self[self.sim]['Ns1'].values label = 'XPLASMA' ax = fig.use_subplot(1, 1, 1) Xr = self[label]['Xr'].isel(sp=range(Ns)).values.real # Xz = self[label]['Xz'].isel(sp=range(Ns)).values # Xphi = self[label]['Xphi'].isel(sp=range(Ns)).values # AmpX = np.sqrt(abs(Xr) ** 2 + abs(Xz) ** 2 + abs(Xphi) ** 2) * self[self.sim]['R0EXP'].values * 1.0e3 R = self[self.sim]['R'].isel(s=range(Ns)) * self[self.sim]['R0EXP'] Z = self[self.sim]['Z'].isel(s=range(Ns)) * self[self.sim]['R0EXP'] pc = ax.pcolormesh(R, Z, Xr, cmap='jet', antialiased=True) ax.set_aspect('equal', adjustable='box') fig.colorbar(pc, ax=ax) ax.set_title('Radial displacement $X_r$') ax.set_xlabel('R [m]') ax.set_ylabel('Z [m]') fig.tight_layout()
[docs] def plot_dWkDen(self, fig=None): """ Plot total dWk energy density profiles :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) label = 'DWK_ENERGY_DENSITY' csm = self[label]['s'] dWki_re = self[label]['0_0_REdwk'] dWki_im = self[label]['0_0_IMdwk'] pyplot.plot(csm, dWki_re, 'bo-', label=r'Re($\delta W_k$) total') pyplot.plot(csm, dWki_im, 'rs--', label=r'Im($\delta W_k$) total') ax.set_xlabel('s') ax.set_ylabel('dWk energy density') ax.legend(loc=0) fig.tight_layout()
[docs] def plot_dWkComp(self, fig=None): """ Plot dWk components (integral of energy density) :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() else: pyplot.figure(num=fig.number) ax = pyplot.subplot(1, 1, 1) NSPECIES = self['DWK_COMPONENTS']['NSPECIES'].values labels = ['NTD', 'NTB', 'NP'] ions = [self['DWK_COMPONENTS']['K_I_NTD'], self['DWK_COMPONENTS']['K_I_NTB'], self['DWK_COMPONENTS']['K_I_NP']] electrons = [self['DWK_COMPONENTS']['K_e_NTD'], self['DWK_COMPONENTS']['K_e_NTB'], self['DWK_COMPONENTS']['K_e_NP']] if NSPECIES > 2: SP_DICT = {} for II in range(NSPECIES - 2): # +2 to skip ions and electrons, +1 to start counting from 1 P = II + 2 + 1 SP_DICT[P] = [ self['DWK_COMPONENTS']['K_%s_NTD' % float(P)], self['DWK_COMPONENTS']['K_%s_NTB' % float(P)], self['DWK_COMPONENTS']['K_%s_NP' % float(P)], ] x = np.arange(len(labels)) width = 0.35 ax.bar(x - width / 2, ions, width, label='Ions') ax.bar(x + width / 2, electrons, width, label='Electrons') if NSPECIES > 2: for II in range(NSPECIES - 2): P = II + 2 + 1 ax.bar(x - width / 2, SP_DICT[P], width, label='Specie %s' % P) ax.set_ylabel('dWk') ax.set_xticks(x) ax.set_xticklabels(labels) ax.legend(loc=0) fig.tight_layout()
[docs] def plot_BntpSurf(self, fig=None): """ Plot Bn, Bt, Bphi on surface calculated by get_BatSurf :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() Tw = self['BPLASMA']['Tw'] ax1 = fig.use_subplot(3, 2, 1) ax1.plot(Tw * 180 / np.pi, np.real(self['BPLASMA']['Bn_s']), 'b-') ax1.set_ylabel('Re(Bn)') ax2 = fig.use_subplot(3, 2, 2) ax2.plot(Tw * 180 / np.pi, np.imag(self['BPLASMA']['Bn_s']), 'b-') ax2.set_ylabel('Im(Bn)') ax3 = fig.use_subplot(3, 2, 3) ax3.plot(Tw * 180 / np.pi, np.real(self['BPLASMA']['Bt_s']), 'b-') ax3.set_ylabel('Re(Bt)') ax4 = fig.use_subplot(3, 2, 4) ax4.plot(Tw * 180 / np.pi, np.imag(self['BPLASMA']['Bt_s']), 'b-') ax4.set_ylabel('Im(Bt)') ax5 = fig.use_subplot(3, 2, 5) ax5.plot(Tw * 180 / np.pi, np.real(self['BPLASMA']['Bphi_s']), 'b-') ax5.set_ylabel(r'Re($B_{\phi}$)') ax5.set_xlabel(r'$\theta$ [$^{\circ}$]') ax6 = fig.use_subplot(3, 2, 6) ax6.plot(Tw * 180 / np.pi, np.imag(self['BPLASMA']['Bphi_s']), 'b-') ax6.set_ylabel(r'Im($B_{\phi}$)') ax6.set_xlabel(r'$\theta$ [$^{\circ}$]') fig.tight_layout()
[docs] def plot_BntpSurfMm(self, fig=None): """ Plot poloidal Fourier harmonics of Bn, Bt, Bphi on surface calculated by get_BatSurf :param fig: specify target figure """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() Tw = self['BPLASMA']['Tw'] ax1 = fig.use_subplot(3, 2, 1) ax1.plot(self['BPLASMA']['Mm'], np.real(self['BPLASMA']['Bnm_s']), 'bo') ax1.set_ylabel(r'$Re(B^m_n)$') ax1.grid() ax2 = fig.use_subplot(3, 2, 2) ax2.plot(self['BPLASMA']['Mm'], np.imag(self['BPLASMA']['Bnm_s']), 'bo') ax2.set_ylabel(r'$Im(B^m_n)$') ax2.grid() ax3 = fig.use_subplot(3, 2, 3) ax3.plot(self['BPLASMA']['Mm'], np.real(self['BPLASMA']['Btm_s']), 'bo') ax3.set_ylabel(r'$Re(B^m_t)$') ax3.grid() ax4 = fig.use_subplot(3, 2, 4) ax4.plot(self['BPLASMA']['Mm'], np.imag(self['BPLASMA']['Btm_s']), 'bo') ax4.set_ylabel(r'$Im(B^m_t)$') ax4.grid() ax5 = fig.use_subplot(3, 2, 5) ax5.plot(self['BPLASMA']['Mm'], np.real(self['BPLASMA']['Bpm_s']), 'bo') ax5.set_ylabel(r'Re($B^m_{\phi}$)') ax5.set_xlabel('m') ax5.grid() ax6 = fig.use_subplot(3, 2, 6) ax6.plot(self['BPLASMA']['Mm'], np.imag(self['BPLASMA']['Bpm_s']), 'bo') ax6.set_ylabel(r'Im($B^m_{\phi}$)') ax6.set_xlabel('m') ax6.grid() fig.tight_layout()
[docs] def plot_BatSurf3D(self, fig=None, rsurf=1.0, ntor=-1): """ Plot Bn on surface calculated by get_BatSurf, normalized and reconstructed in (chi,phi) real space :param fig: specify target figure :param rsurf: normalized surface radius for plotting, default is plasma boundary :param n: toroidal mode number for inverse Fourier transorm in toroidal angle """ from matplotlib import pyplot from matplotlib.colors import BoundaryNorm from matplotlib.ticker import MaxNLocator if fig is None: fig = pyplot.figure() try: Bn = self['BPLASMA']['Bn_s'] except KeyError: raise ('ERROR: calculate B on surface before plotting') Tw = self['BPLASMA']['Tw'] phi = np.linspace(0, 2 * np.pi, self[self.sim]['Nchi'].values) expnphi = np.exp(1j * ntor * phi) Bna = np.real(np.dot(expnphi[:, np.newaxis], Bn.values[np.newaxis, :])).T / np.max(np.abs(Bn.values)) [pp, cc] = np.meshgrid(phi, Tw) pp = pp * 180 / np.pi cc = cc * 180 / np.pi # Find surface index IIsurf = np.argmin(np.abs(self[self.sim]['s'].values - rsurf)) levels = MaxNLocator(nbins=25).tick_values(Bna.min(), Bna.max()) cmap = pyplot.get_cmap('jet') norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True) ax0 = pyplot.gca() cf = ax0.contourf(pp, cc, Bna, levels=levels, cmap=cmap) cf2 = ax0.contour(cf, levels=cf.levels[::2], colors='k') cbar = fig.colorbar(cf, ax=ax0) cbar.ax.set_ylabel(r'[A.U.]') ax0.set_title(r'$B_{n}$ n=%s - at r/a = %s' % (ntor, str(self[self.sim]['s'][IIsurf].values))) ax0.set_xlabel(r'$\Phi [^\circ]$') ax0.set_ylabel(r'$\Theta [^\circ]$') # Find index of HFS, LFS, TOP, BOT k = self[self.sim]['R'].isel(s=IIsurf).argmin(dim='chi').values chi_HFS = Tw[k] * 180 / np.pi k = self[self.sim]['R'].isel(s=IIsurf).argmax(dim='chi').values chi_LFS = Tw[k] * 180 / np.pi k = self[self.sim]['Z'].isel(s=IIsurf).argmin(dim='chi').values chi_bot = Tw[k] * 180 / np.pi k = self[self.sim]['Z'].isel(s=IIsurf).argmax(dim='chi').values chi_top = Tw[k] * 180 / np.pi ax0.text(10, chi_HFS, 'HFS', bbox={'facecolor': 'white', 'alpha': 1.0, 'pad': 5}) ax0.text(10, chi_LFS, 'LFS', bbox={'facecolor': 'white', 'alpha': 1.0, 'pad': 5}) ax0.text(10, chi_top, 'TOP', bbox={'facecolor': 'white', 'alpha': 1.0, 'pad': 5}) ax0.text(10, chi_bot, 'BOT', bbox={'facecolor': 'white', 'alpha': 1.0, 'pad': 5}) pyplot.tight_layout()
[docs] def plot_Bwarp(self, fig=None, rsurf=1.0): """ Visualize B-field perturbation on specific surface :param fig: specify target figure :param rsurf: normalized surface radius for plotting, default is plasma boundary """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() if 'Br' not in self['BPLASMA']: self.get_Bcyl() # Find surface index IIsurf = np.argmin(np.abs(self[self.sim]['s'].values - rsurf)) Rw = self[self.sim]['R'].isel(s=IIsurf) Zw = self[self.sim]['Z'].isel(s=IIsurf) try: Bwr = self['BPLASMA']['Br'].isel(s=IIsurf) Bwz = self['BPLASMA']['Bz'].isel(s=IIsurf) except IndexError: print('ERROR: Selected index is out of BPLASMA calculation domain') return B0 = self[self.sim]['B0EXP'].values R0 = self[self.sim]['R0EXP'].values h = B0 / self[self.sim]['Ns1'].values Bwr_r = np.real(Bwr) Bwz_r = np.real(Bwz) Bt = np.sqrt(Bwr_r**2 + Bwz_r**2) Bt[np.where(Bt == 0.0)] = 1.0 R1 = Rw + h * Bwr_r / Bt Z1 = Zw + h * Bwz_r / Bt R2 = np.vstack((Rw, R1)) Z2 = np.vstack((Zw, Z1)) pyplot.plot(Rw * R0, Zw * R0, 'c-') pyplot.plot(R2 * R0, Z2 * R0, 'b-') pyplot.axis('equal') pyplot.xlabel('R [m]') pyplot.ylabel('Z [m]')
[docs] def plot_Xwarp(self, fig=None, rsurf=1.0): """ Visualize displacement perturbation on specific surface :param fig: specify target figure :param rsurf: normalized surface radius for plotting, default is plasma boundary """ from matplotlib import pyplot if fig is None: fig = pyplot.figure() if 'Xr' not in self['XPLASMA']: self.get_Xcyl() # Find wall surface index IIsurf = np.argmin(np.abs(self[self.sim]['s'].values - rsurf)) Rw = self[self.sim]['R'].isel(s=IIsurf) Zw = self[self.sim]['Z'].isel(s=IIsurf) try: Xwr = self['XPLASMA']['Xr'].isel(sp=IIsurf) Xwz = self['XPLASMA']['Xz'].isel(sp=IIsurf) except IndexError: print('ERROR: Selected index is out of XPLASMA calculation domain') return B0 = self[self.sim]['B0EXP'].values R0 = self[self.sim]['R0EXP'].values h = R0 / self[self.sim]['Ns1'].values Xwr_r = np.real(Xwr) Xwz_r = np.real(Xwz) Xt = np.sqrt(Xwr_r**2 + Xwz_r**2) Xt[np.where(Xt == 0.0)] = 1.0 R1 = Rw + h * Xwr_r / Xt Z1 = Zw + h * Xwz_r / Xt R2 = np.vstack((Rw, R1)) Z2 = np.vstack((Zw, Z1)) pyplot.plot(Rw * R0, Zw * R0, 'c-') pyplot.plot(R2 * R0, Z2 * R0, 'b-') pyplot.axis('equal') pyplot.xlabel('R [m]') pyplot.ylabel('Z [m]') return R1, Z1
[docs] def plot_PROFNTV(self, fig=None): """ Plot "boundary"-frequencies between different NTV regimes :param fig: specify target figure """ from labellines import labelLines if fig is None: fig = pyplot.figure() ax = fig.gca() pyplot.semilogy(self['PROFNTV']['psi'], self['PROFNTV']['nu_n1'], 'b:', linewidth=1, label=r'$|\omega_E| (\delta B /\epsilon)^{2}$') pyplot.semilogy(self['PROFNTV']['psi'], self['PROFNTV']['nu_n2'], 'b--', linewidth=2, label=r'$|\omega_E|$') pyplot.semilogy(self['PROFNTV']['psi'], self['PROFNTV']['nu_n3'], 'b-', linewidth=3, label=r'$\sqrt{\epsilon}\omega_{ti}$') pyplot.semilogy( self['PROFNTV']['psi'], self['PROFNTV']['nu_r1'], 'r:', linewidth=1, label=r'$\omega_{B0}(\delta B /\epsilon)^{3/2}$' ) pyplot.semilogy(self['PROFNTV']['psi'], self['PROFNTV']['nu_r2'], 'r--', linewidth=2, label=r'$\omega_{B0} / \epsilon$') pyplot.semilogy(self['PROFNTV']['psi'], self['PROFNTV']['nu'] / self['PROFNTV']['eps'], 'k-', linewidth=4, label=r'$\nu /\epsilon$') lines = ax.get_lines() labelLines(lines, yoffsets=0.01, align=False, backgroundcolor="none") pyplot.xlabel(r'$\psi_p$') pyplot.ylabel(r'$freq. / \epsilon$ for NTV regimes [rad/s]')
[docs] def plot_NUSTAR(self, fig=None, kplot=2): """ Plot effective collisionality for ions and electrons :param fig: specify target figure :param kplot: =2 to use logscale, =1 to use linear y-axis """ from labellines import labelLines if fig is None: fig = pyplot.figure() ax = fig.gca() if kplot == 2: pyplot.semilogy(self['NUSTAR']['s'], self['NUSTAR']['nustar_i'], 'r--', linewidth=3, label=r'$\nu^*$ ions') pyplot.semilogy(self['NUSTAR']['s'], self['NUSTAR']['nustar_e'], 'b-', linewidth=3, label=r'$\nu^*$ electrons') else: pyplot.plot(self['NUSTAR']['s'], self['NUSTAR']['nustar_i'], 'r--', linewidth=3, label=r'$\nu^*$ ions') pyplot.plot(self['NUSTAR']['s'], self['NUSTAR']['nustar_e'], 'b-', linewidth=3, label=r'$\nu^*$ electrons') pyplot.xlabel(r'$s=\sqrt{\psi_p}$') pyplot.ylabel(r'$\nu^*$') pyplot.legend(loc=0)
[docs]class OMFITnColumns(SortedDict, OMFITascii): r""" OMFIT class used to interface with n-columns input files :param filename: filename passed to OMFITascii class :param \**kw: keyword dictionary passed to OMFITascii class """ def __init__(self, filename, **kw): SortedDict.__init__(self) OMFITascii.__init__(self, filename, **kw) self.dynaLoad = True
[docs] @dynaLoad def load(self): with open(self.filename, 'r') as f: header = f.readline() if not len(header): return tmp = np.atleast_2d(np.loadtxt(self.filename, skiprows=1)) self['x'] = tmp[:, 0] for k in range(1, tmp.shape[1]): self['y_%d' % k] = tmp[:, k]
[docs] @dynaSave def save(self): with open(self.filename, 'w') as f: if not len(self): f.write('0 0') return tmp = np.vstack(list(self.values())).T shape = list(tmp.shape) shape[1] = shape[1] - 1 f.write(' '.join(map(str, shape)) + '\n') for k in range(tmp.shape[0]): f.write(' '.join(['%5.9e' % x for x in tmp[k, :]]) + '\n')
[docs] def plot(self): from matplotlib import pyplot tmp = np.vstack(list(self.values())).T fignum = pyplot.get_fignums()[-1] for k in range(tmp.shape[1]): # condition to avoid plotting first columnt vs. itself if k == 0: continue pyplot.figure(k + fignum) pyplot.plot(tmp[:, 0], tmp[:, k]) pyplot.ylabel(self._OMFITkeyName) pyplot.tight_layout()
[docs]class OMFITmarsProfile(OMFITnColumns): pass
############################################ if '__main__' == __name__: test_classes_main_header() if os.path.exists('/home/pigatto/Work_2020/RFX-mod2/OUTPUTS/'): tmp = OMFITmars('/home/pigatto/Work_2020/RFX-mod2/OUTPUTS/') tmp.load() print(tmp) tmp.plot_RMZM() tmp.plot_JPLASMA() from matplotlib import pyplot pyplot.show()