import numpy as np
import os
import scipy.interpolate as sint
from magic.libmagic import chebgrid, fd_grid, scanDir
[docs]def get_truncation(n_theta_max, nalias, minc):
"""
This routine determines l_max, m_max and lm_max from the values
of n_theta_max, minc and nalias.
:param n_theta_max: number of points along the colatitude
:type n_theta_max: int
:param nalias: dealiasing paramete (20 is fully dealiased)
:type nalias: int
:param minc: azimuthal symmetry
:type minc: int
:returns: returns a list of three integers: l_max, m_max and lm_max
:rtype: list
"""
lmax = nalias*n_theta_max // 30
mmax = (lmax//minc) * minc
lm_max = mmax*(lmax+1)//minc - \
mmax*(mmax-minc)//(2*minc)+(lmax+1-mmax)
return lmax, mmax, lm_max
[docs]def get_map(lm_max, lmax, mmin, mmax, minc):
"""
This routine determines the look-up tables to convert the indices
(l, m) to the single index lm.
:param lm_max: total number of lm combinations.
:type lm_max: int
:param lmax: maximum spherical harmonic degree
:type lmax: int
:param mmin: minimum spherical harmonic order
:type mmin: int
:param mmax: maximum spherical harmonic order
:type mmax: int
:param minc: azimuthal symmetry
:type minc: int
:returns: returns a list of three look-up tables: idx, lm2l, lm2m
:rtype: list
"""
idx = np.zeros((lmax+1, mmax+1), np.int32)
lm2l = np.zeros(lm_max, np.int16)
lm2m = np.zeros(lm_max, np.int16)
k = 0
for m in range(mmin, mmax+1, minc):
for l in range(m, lmax+1):
idx[l, m] = k
lm2l[k] = l
lm2m[k] = m
k += 1
return idx, lm2l, lm2m
[docs]def interp_one_field(field, rold, rnew, rfac=None):
"""
This routine interpolates a complex input field from an old radial grid
to a new one.
:param field: the field to be interpolated
:type field: numpy.ndarray
:param rold: the old radial grid points
:type rold: numpy.ndarray
:param rnew: the new radial grid points
:type rnew: numpy.ndarray
:param rfac: a rescaling function that depends on the radius
:type rfac: numpy.ndarray
:returns: the field interpolated on the new radial grid
:rtype: numpy.ndarray
"""
nrold = field.shape[0]
lm_max = field.shape[1]
nrnew = rnew.shape[0]
if rfac is None:
rfac = np.ones_like(rold)
if rold[1] > rold[0]:
old_ordering = 'ascending'
else:
old_ordering = 'descending'
rold = rold[::-1]
field = field[::-1, :]
rfac = rfac[::-1]
if rnew[1] > rnew[0]:
new_ordering = 'ascending'
else:
new_ordering = 'descending'
rnew = rnew[::-1]
field_new = np.zeros((nrnew, lm_max), np.complex128)
for lm in range(lm_max):
tckp = sint.splrep(rold, rfac*field[:, lm].real, k=5)
finter_real = sint.splev(rnew, tckp)
tckp = sint.splrep(rold, rfac*field[:, lm].imag, k=5)
finter_imag = sint.splev(rnew, tckp)
field_new[:, lm] = (finter_real+1j*finter_imag)
if old_ordering == 'descending':
rold = rold[::-1]
field = field[::-1, :]
rfac = rfac[::-1]
if new_ordering == 'descending':
field_new = field_new[::-1, :]
return field_new
[docs]def Graph2Rst(gr, filename='checkpoint_ave'):
"""
This function allows to transform an input Graphic file into a checkpoint
file format that can be read by MagIC to restart a simulation.
>>> # Load a Graphic File
>>> gr = MagicGraph()
>>> # Produce the file checkpoint_ave.from_G
>>> Graph2Rst(gr, filename='checkpoint_ave.from_G')
:param gr: the input graphic file one wants to convert into a restart file
:type gr: magic.MagicGraph
:param filename: name of the checkpoint file
:type filename: str
"""
chk = MagicCheckpoint(l_read=False)
chk.graph2rst(gr, filename)
[docs]class MagicCheckpoint:
"""
This class allows to manipulate checkpoint files produced by MagIC. It
can read it as
>>> chk = MagicCheckpoint(filename='checkpoint_end.test')
>>> print(chk.wpol.shape, chk.l_max)
This class can also be used to intepolate from FD to Cheb or the opposite
>>> chk.cheb2fd(96)
>>> chk.write('checkpoint_fd.test')
One can also transform a Graphic file into a checkpoint
>>> gr = MagicGraph()
>>> chk = MagicCheckpoint(l_read=False)
>>> chk.graph2rst(gr)
Finally one can convert checkpoints from XSHELLS
>>> chk = MagicCheckpoint(l_read=False)
>>> chk.xshells2magic('st0', 161, rscheme='cheb', cond_state='deltaT')
"""
[docs] def __init__(self, l_read=True, filename=None, endian='l'):
"""
:param l_read: a boolean to decide whether one reads a checkpoint or not
:type l_read: bool
:param filename: name of the checkpoint file to be read
:type filename: str
"""
if l_read:
if filename is None:
chks = scanDir('checkpoint*')
filename = chks[-1]
self.read(filename, endian=endian)
[docs] def read(self, filename, endian='l'):
"""
This routine is used to read a checkpoint file.
:param filename: name of the checkpoint file
:type filename: str
"""
if endian == 'B':
prefix = '>'
else:
prefix = ''
file = open(filename, 'rb')
fmt = '{}i4'.format(prefix)
self.version = np.fromfile(file, fmt, count=1)[0]
fmt = '{}f8'.format(prefix)
self.time = np.fromfile(file, fmt, count=1)[0]
# Time scheme
self.tscheme_family = file.read(10).decode()
nexp, nimp, nold = np.fromfile(file, dtype=np.int32, count=3)
if self.tscheme_family.startswith('MULTISTEP'):
self.dt = np.fromfile(file, dtype=np.float64, count=nexp)
else:
self.dt = np.fromfile(file, dtype=np.float64, count=1)[0]
n_time_step = np.fromfile(file, dtype=np.int32, count=1)[0]
if self.version <= 2:
self.ra, self.pr, self.raxi, self.sc, self.prmag, self.ek, \
self.radratio, self.sigma_ratio = \
np.fromfile(file, dtype=np.float64, count=8)
self.stef = 0.
else:
self.ra, self.pr, self.raxi, self.sc, self.prmag, self.ek, \
self.stef, self.radratio, self.sigma_ratio = \
np.fromfile(file, dtype=np.float64, count=9)
# Truncation
self.n_r_max, self.n_theta_max, self.n_phi_tot, self.minc,\
self.nalias, self.n_r_ic_max = \
np.fromfile(file, dtype=np.int32, count=6)
if self.version > 3:
self.l_max, self.m_min, self.m_max = np.fromfile(file, dtype=np.int32,
count=3)
self.lm_max = 0
for m in range(self.m_min, self.m_max+1, self.minc):
for l in range(m, self.l_max+1):
self.lm_max += 1
else:
self.l_max, self.m_max, self.lm_max = get_truncation(self.n_theta_max,
self.nalias, self.minc)
self.m_min = 0
# Define maps
self.idx, self.lm2l, self.lm2m = get_map(self.lm_max, self.l_max,
self.m_min, self.m_max, self.minc)
# Radial scheme
self.rscheme_version = file.read(72).decode()
if self.rscheme_version.startswith('cheb'):
self.n_cheb_max, self.map = np.fromfile(file, dtype=np.int32, count=2)
self.alph1, self.alph2 = np.fromfile(file, dtype=np.float64, count=2)
else:
order, obound = np.fromfile(file, dtype=np.int32, count=2)
self.fd_stretch, self.fd_ratio = \
np.fromfile(file, dtype=np.float64, count=2)
# Radial grid
self.radius = np.fromfile(file, dtype=np.float64, count=self.n_r_max)
# Torques
if self.tscheme_family.startswith('MULTISTEP'):
domega_ic = np.fromfile(file, dtype=np.float64, count=(nexp+nimp+nold-3))
domega_ma = np.fromfile(file, dtype=np.float64, count=(nexp+nimp+nold-3))
if self.version < 5:
lotorque_ic = np.fromfile(file, dtype=np.float64, count=(nexp+nimp+nold-3))
lotorque_ma = np.fromfile(file, dtype=np.float64, count=(nexp+nimp+nold-3))
om = np.fromfile(file, dtype=np.float64, count=12)
self.omega_ic = om[0]
self.omega_ma = om[6]
# Logicals
if self.version <= 2:
self.l_heat, self.l_chem, self.l_mag, self.l_press, self.l_cond_ic = \
np.fromfile(file, dtype=np.int32, count=5)
self.l_phase = False
else:
self.l_heat, self.l_chem, self.l_phase, self.l_mag, self.l_press, \
self.l_cond_ic = np.fromfile(file, dtype=np.int32, count=6)
# Fields
self.wpol = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.wpol = self.wpol.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
self.ztor = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.ztor = self.ztor.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
if self.l_press:
self.pre = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.pre = self.pre.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
if self.l_heat:
self.entropy = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.entropy = self.entropy.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
if self.l_chem:
self.xi = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.xi = self.xi.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
if self.l_phase:
self.phase = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.phase = self.phase.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
if self.l_mag:
self.bpol = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.bpol = self.bpol.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
self.btor = np.fromfile(file, dtype=np.complex128,
count=self.n_r_max*self.lm_max)
self.btor = self.btor.reshape((self.n_r_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_max*(nexp+nimp+nold-3))
if self.l_cond_ic:
self.radius_ic = chebgrid(2*self.n_r_ic_max-2, self.radius[-1],
-self.radius[-1])
self.radius_ic = self.radius_ic[:self.n_r_ic_max]
self.radius_ic[-1] = 0.
self.bpol_ic = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_ic_max)
self.bpol_ic = self.bpol_ic.reshape((self.n_r_ic_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_ic_max*(nexp+nimp+nold-3))
self.btor_ic = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_ic_max)
self.btor_ic = self.btor_ic.reshape((self.n_r_ic_max, self.lm_max))
if self.tscheme_family.startswith('MULTISTEP'):
tmp = np.fromfile(file, dtype=np.complex128,
count=self.lm_max*self.n_r_ic_max*(nexp+nimp+nold-3))
file.close()
[docs] def write(self, filename):
"""
This routine is used to store a checkpoint file. It only stores the
state vector not the past quantities required to restart a multistep
scheme.
:param filename: name of the checkpoint file
:type filename: str
"""
file = open(filename, 'wb')
# Header
version = np.array([4], np.int32)
version.tofile(file)
time = np.array([self.time], np.float64)
time.tofile(file)
# Time scheme
tscheme = 'DIRK '.encode()
file.write(tscheme)
par = np.array([1, 1, 1], np.int32)
par.tofile(file)
if hasattr(self, 'dt'):
if isinstance(self.dt, np.ndarray):
dt = np.array([self.dt[0]], np.float64)
else:
dt = np.array([self.dt], np.float64)
else:
dt = np.array([1.0e-6], np.float64)
dt.tofile(file)
par = np.array([1], np.int32)
par.tofile(file)
# Control parameters
if hasattr(self, 'ra') and hasattr(self, 'sc') and hasattr(self, 'prmag'):
x = np.array([self.ra, self.pr, self.raxi, self.sc, self.prmag,
self.ek, self.stef, self.radratio, self.sigma_ratio],
np.float64)
else:
x = np.array([1e5, 1.0, 0.0, 1.0, 5.0, 1.0e-3, self.radratio, 1.0],
np.float64)
x.tofile(file)
# Truncation
x = np.array([self.n_r_max, self.n_theta_max, self.n_phi_tot, self.minc,
self.nalias, self.n_r_ic_max], np.int32)
x.tofile(file)
if not hasattr(self,"m_min"):
self.m_min = 0
x = np.array([self.l_max, self.m_min, self.m_max], np.int32)
x.tofile(file)
# Radial scheme
file.write(self.rscheme_version.encode())
if self.rscheme_version.startswith('cheb'):
x = np.array([self.n_cheb_max, self.map], np.int32)
x.tofile(file)
x = np.array([self.alph1, self.alph2], np.float64)
x.tofile(file)
else:
x = np.array([2, 2], np.int32)
x.tofile(file)
x = np.array([self.fd_stretch, self.fd_ratio], np.float64)
x.tofile(file)
# Radial grid
self.radius.tofile(file)
# torques
dumm = np.zeros(12, np.float64)
dumm[0] = self.omega_ic
dumm[6] = self.omega_ma
dumm.tofile(file)
# Logicals
if not hasattr(self,"l_phase"):
self.l_phase = False
flags = np.array([self.l_heat, self.l_chem, self.l_phase, self.l_mag, False,
self.l_cond_ic], np.int32)
flags.tofile(file)
# Fields
self.wpol.tofile(file)
self.ztor.tofile(file)
if self.l_heat:
self.entropy.tofile(file)
if self.l_chem:
self.xi.tofile(file)
if self.l_phase:
self.phase.tofile(file)
if self.l_mag:
self.bpol.tofile(file)
self.btor.tofile(file)
if self.l_cond_ic:
self.bpol_ic.tofile(file)
self.btor_ic.tofile(file)
file.close()
[docs] def cheb2fd(self, n_r_max, fd_stretch=0.3, fd_ratio=0.1):
"""
This routine is used to convert a checkpoint that has a Gauss-Lobatto
grid into a finite-difference grid.
:param n_r_max: number of radial grid points of the finite difference grid
:type n_r_max: int
:param fd_stretch: stretching of the radial grid
:type fd_stretch: float
:param fd_ratio: ratio of smallest to largest grid spacing
:type fd_ratio: float
"""
self.rscheme_version = 'fd'+'{:>70s}'.format('')
self.fd_stretch = fd_stretch
self.fd_ratio = fd_ratio
rnew = fd_grid(n_r_max, self.radius[0], self.radius[-1],
self.fd_stretch, self.fd_ratio)
tmp = interp_one_field(self.wpol, self.radius, rnew)
self.wpol = tmp
tmp = interp_one_field(self.ztor, self.radius, rnew)
self.ztor = tmp
if self.l_heat:
tmp = interp_one_field(self.entropy, self.radius, rnew)
self.entropy = tmp
if self.l_chem:
tmp = interp_one_field(self.xi, self.radius, rnew)
self.xi = tmp
if self.l_phase:
tmp = interp_one_field(self.phase, self.radius, rnew)
self.phase = tmp
if self.l_mag:
tmp = interp_one_field(self.bpol, self.radius, rnew)
self.bpol = tmp
tmp = interp_one_field(self.btor, self.radius, rnew)
self.btor = tmp
self.radius = rnew
self.n_r_max = n_r_max
[docs] def fd2cheb(self, n_r_max):
"""
This routine is used to convert a checkpoint that has finite differences
in radius into a Gauss-Lobatto grid.
:param n_r_max: number of radial grid points of the Gauss-Lobatto grid
:type n_r_max: int
"""
self.n_cheb_max = n_r_max-2
self.map = 0
self.alph1 = 1
self.alph2 = 0
self.rscheme_version = 'cheb'+'{:>68s}'.format('')
rnew = chebgrid(n_r_max-1, self.radius[0], self.radius[-1])
tmp = interp_one_field(self.wpol, self.radius, rnew)
self.wpol = tmp
tmp = interp_one_field(self.ztor, self.radius, rnew)
self.ztor = tmp
if self.l_heat:
tmp = interp_one_field(self.entropy, self.radius, rnew)
self.entropy = tmp
if self.l_chem:
tmp = interp_one_field(self.xi, self.radius, rnew)
self.xi = tmp
if self.l_phase:
tmp = interp_one_field(self.phase, self.radius, rnew)
self.phase = tmp
if self.l_mag:
tmp = interp_one_field(self.bpol, self.radius, rnew)
self.bpol = tmp
tmp = interp_one_field(self.btor, self.radius, rnew)
self.btor = tmp
self.radius = rnew
self.n_r_max = n_r_max
[docs] def xshells2magic(self, xsh_trailing, n_r_max, rscheme='cheb',
cond_state='deltaT', scale_b=1.,
filename='checkpoint_end.from_xhells'):
"""
This routine is used to convert XSHELLS field[U,B,T].xsh_trailing files
into a MagIC checkpoint file.
>>> chk = MagicCheckPoint()
>>> # Convert field[U,T,B].st1ns_hr2 into a MagIC checkpoint file
>>> chk.xshells2magic('st1ns_hr2', 512, rscheme='fd', cond_state='mixed',
scale_b=4.472136e-4)
:param xsh_trailing: trailing of the field[U,B,T].xsh_trailing files
:type xsh_trailing: str
:param n_r_max: number of radial grid points to be used
:type n_r_max: int
:param rscheme: the type of radial scheme ('cheb' or 'fd')
:type rscheme: str
:param cond_state: the type of conducting state:
- 'deltaT': fixed temperature contrast
- 'mixed': hybrid forcing (STEP1-2 like)
:type cond_state: str
:param scale_b: a rescaling factor for the magnetic field
:type scale_b: float
"""
import pyxshells as pyx
# xshells grid
f = pyx.load_field('fieldU.{}'.format(xsh_trailing))
if os.path.exists('fieldT.{}'.format(xsh_trailing)):
self.l_heat = True
if os.path.exists('fieldB.{}'.format(xsh_trailing)):
self.l_mag = True
self.l_press = False
self.l_chem = False
self.l_phase = False
# Right now don't know where it is stored
self.l_cond_ic = False
rr_xsh = f.grid.r
nr_xsh = len(rr_xsh)
ro = rr_xsh[-1]
ri = rr_xsh[0]
self.radratio = ri/ro
self.n_r_max = n_r_max
if rscheme.startswith('cheb'):
self.radius = chebgrid(self.n_r_max-1, ro, ri)
self.n_cheb_max = self.n_r_max-2
self.map = 0
self.alph1 = 1.
self.alph2 = 0.
self.rscheme_version = 'cheb'+'{:>68s}'.format('')
else:
self.radius = fd_grid(n_r_max, ro, ri)
self.fd_stretch = 0.3
self.fd_ratio = 0.1
self.rscheme_version = 'fd'+'{:>70s}'.format('')
self.l_max = f.lmax
self.m_max = f.mmax
self.minc = f.mres
self.lm_max = f.pol_full().shape[-1]
# When nalias=60 ntheta=lmax: trick to have lmax in MagIC's header
self.nalias = 60
self.n_theta_max = self.l_max
self.n_phi_tot = self.l_max
self.n_r_ic_max = 1
self.time = f.time
# Dummy rotation rates: don't know where to get them from xSHELLs
self.omega_ic = 0.
self.omega_ma = 0.
self.wpol = interp_one_field(f.pol_full(), rr_xsh, self.radius,
rfac=rr_xsh)
self.ztor = interp_one_field(f.tor_full(), rr_xsh, self.radius,
rfac=rr_xsh)
if self.l_heat:
f = pyx.load_field('fieldT.{}'.format(xsh_trailing))
field_xsh = np.zeros((nr_xsh, self.lm_max), np.complex128)
field_xsh = f.data[1:-1, 0, :]
self.entropy = interp_one_field(field_xsh, rr_xsh, self.radius)
if cond_state == 'deltaT':
#temp0 = -ri**2/(ri**2+ro**2)
temp0 = 0.
tcond = ro*ri/(ro-ri)/self.radius+temp0-ri/(ro-ri)
elif cond_state == 'mixed':
fi = 0.75
ci = (2.*fi-1.)/(ro**3-ri**3)
co = (fi*ro**3-(1.-fi)*ri**3)/(ro**3-ri**3)
tcond = ci*self.radius**2/2.+co/self.radius
tcondo = ci*ro**2/2.+co/ro
tcond = tcond-tcondo
self.entropy[:, 0] += np.sqrt(4.*np.pi) * tcond
if self.l_mag:
f = pyx.load_field('fieldB.{}'.format(xsh_trailing))
field_xsh = scale_b * f.pol_full()
self.bpol = interp_one_field(field_xsh, rr_xsh, self.radius,
rfac=rr_xsh)
field_xsh = scale_b * f.tor_full()
self.btor = interp_one_field(field_xsh, rr_xsh, self.radius,
rfac=rr_xsh)
self.write(filename)
[docs] def graph2rst(self, gr, filename='checkpoint_ave.from_chk'):
"""
:param gr: the input graphic file one wants to convert into a restart
file
:type gr: magic.MagicGraph
:param filename: name of the checkpoint file
:type filename: str
"""
from magic import SpectralTransforms, thetaderavg, phideravg, MagicRadial
if hasattr(gr, 'tag'):
tag = gr.tag
if os.path.exists('anel.{}'.format(tag)):
r = MagicRadial(field='anel', iplot=False)
rho0 = r.rho0
else:
rho0 = np.ones_like(gr.radius)
else:
rho0 = np.ones_like(gr.radius)
self.n_r_max = gr.n_r_max
self.n_theta_max = gr.n_theta_max
self.minc = gr.minc
self.n_phi_tot = gr.n_phi_max*gr.minc+1
self.n_r_ic_max = gr.n_r_ic_max+1
self.nalias = 20
# Spectral truncation
self.l_max, self.m_max, self.lm_max = get_truncation(self.n_theta_max,
self.nalias, self.minc)
# Define maps
self.idx, self.lm2l, self.lm2m = get_map(self.lm_max, self.l_max,
0, self.m_max, self.minc)
self.radius = gr.radius.astype(np.float64)
ri = self.radius[-1]
ro = self.radius[0]
self.radratio = ri/ro
if not hasattr(gr, 'radial_scheme') or gr.radial_scheme == 'CHEB':
self.rscheme_version = 'cheb'+'{:>68s}'.format('')
self.n_cheb_max = self.n_r_max-2
if gr.l_newmap == 'F':
self.map = 0
else:
self.map = 1
self.alph1 = gr.alph1
self.alph2 = gr.alph2
else:
self.rscheme_version = 'fd'+'{:>70s}'.format('')
self.fd_stretch = gr.fd_stretch
self.fd_ratio = gr.fd_ratio
# Flags
if gr.mode in [2, 3, 7, 8, 9, 10] or gr.ra == 0.:
self.l_heat = False
else:
self.l_heat = True
if not hasattr(gr, 'raxi'):
self.l_chem = False
else:
if gr.raxi > 0. or gr.raxi < 0.:
self.l_chem = True
else:
self.l_chem = False
if gr.mode in [0, 2, 3, 6, 8, 9]:
self.l_mag = True
else:
self.l_mag = False
if gr.sigma_ratio == 0.:
self.l_cond_ic = False
else:
self.l_cond_ic = True
self.l_press = False
if self.l_cond_ic:
self.radius_ic = np.zeros(self.n_r_ic_max, np.float64)
self.radius_ic[0] = ri
self.radius_ic[1:] = gr.radius_ic
self.time = gr.time.astype(np.float64)
# Rotation rates: dummy
self.omega_ic = 0.
self.omega_ma = 0.
sh = SpectralTransforms(l_max=self.l_max, minc=self.minc,
n_theta_max=self.n_theta_max)
# Calculate and store the poloidal potential using vr
self.wpol = np.zeros((self.n_r_max, self.lm_max), dtype=np.complex128)
for i in range(self.n_r_max):
vr = sh.spat_spec(gr.vr[:, :, i])
self.wpol[i, 1:] = vr[1:]/(sh.ell[1:]*(sh.ell[1:]+1)) * \
self.radius[i]**2 * rho0[i]
# Calculate the toroidal potential using wr
self.ztor = np.zeros_like(self.wpol)
th3D = np.zeros_like(gr.vr)
rr3D = np.zeros_like(th3D)
for i in range(self.n_theta_max):
th3D[:, i, :] = gr.colatitude[i]
for i in range(self.n_r_max):
rr3D[:, :, i] = self.radius[i]
s3D = rr3D*np.sin(th3D)
omr = 1./s3D*(thetaderavg(np.sin(th3D)*gr.vphi, order=4) -
phideravg(gr.vtheta, minc=self.minc))
for i in range(self.n_r_max):
om = sh.spat_spec(omr[:, :, i])
self.ztor[i, 1:] = om[1:]/(sh.ell[1:]*(sh.ell[1:]+1)) * \
self.radius[i]**2 * rho0[i]
# Calculate the entropy
if self.l_heat:
self.entropy = np.zeros_like(self.wpol)
for i in range(self.n_r_max):
p = sh.spat_spec(gr.entropy[:, :, i])
self.entropy[i, :] = p[:]
# Calculate the chemical composition
if self.l_chem:
self.xi = np.zeros_like(self.wpol)
for i in range(self.n_r_max):
p = sh.spat_spec(gr.xi[:, :, i])
self.xi[i, :] = p[:]
# Calculate the magnetic field
if self.l_mag:
self.bpol = np.zeros_like(self.wpol)
for i in range(self.n_r_max):
Br = sh.spat_spec(gr.Br[:, :, i])
self.bpol[i, 1:] = Br[1:]/(sh.ell[1:]*(sh.ell[1:]+1)) * \
self.radius[i]**2
self.btor = np.zeros_like(self.ztor)
jr = 1./s3D*(thetaderavg(np.sin(th3D)*gr.Bphi, order=4) -
phideravg(gr.Btheta, minc=self.minc))
for i in range(self.n_r_max):
om = sh.spat_spec(jr[:, :, i])
self.btor[i, 1:] = om[1:]/(sh.ell[1:]*(sh.ell[1:]+1)) * \
self.radius[i]**2
if self.l_mag and self.l_cond_ic:
self.bpol_ic = np.zeros((self.n_r_ic_max, self.lm_max), np.complex128)
for i in range(self.n_r_ic_max):
rdep = np.ones(sh.ell.shape, dtype=np.float64)
if i == 0: # ICB radius
vr = sh.spat_spec(gr.Br[:, :, -1])
rr = self.radius[-1]
rdep[:] = 1.
else:
vr = sh.spat_spec(gr.Br_ic[:, :, i-1])
rr = self.radius_ic[i-1]
rdep[1:] = (self.radius_ic[i-1]/ri)**(sh.ell[1:]+1)
self.bpol_ic[i, 1:] = vr[1:]/(sh.ell[1:]*(sh.ell[1:]+1))*rr**2
# Not stable:
#if self.radius_ic[i] >= 0.01:
# mask = ( self.lm2l <= 2 ) * ( self.lm2m <= 2)
# self.bpol_ic[i, mask] /= rdep[mask]
# Calculate the toroidal potential using jr
self.btor_ic = np.zeros_like(self.bpol_ic)
th3D = np.zeros_like(gr.Br_ic)
rr3D = np.zeros_like(th3D)
for i in range(self.n_theta_max):
th3D[:, i, :] = gr.colatitude[i]
for i in range(self.n_r_ic_max-1):
rr3D[:, :, i] = self.radius_ic[i]
rr3D[:, :, -1] = 1e-4
s3D = rr3D*np.sin(th3D)
jr_ic = np.zeros_like(th3D)
jr_ic = 1./s3D*(thetaderavg(np.sin(th3D)*gr.Bphi_ic, order=4) -
phideravg(gr.Btheta_ic, minc=self.minc))
for i in range(self.n_r_ic_max):
rdep = np.ones(sh.ell.shape, dtype=np.float64)
if i == 0: # ICB radius
om = sh.spat_spec(jr[:, :, -1])
rr = self.radius[-1]
rdep[:] = 1.
else:
om = sh.spat_spec(jr_ic[:, :, i-1])
rr = self.radius_ic[i-1]
rdep[1:] = (self.radius_ic[i-1]/ri)**(sh.ell[1:]+1)
self.btor_ic[i, 1:] = om[1:]/(sh.ell[1:]*(sh.ell[1:]+1))*rr**2
# Not stable
#if self.radius_ic[i] >= 0.1:
# mask = ( self.lm2l <= 5 ) * ( self.lm2m <= 5)
# self.btor_ic[i, mask] /= rdep[mask]
self.write(filename)
if __name__ == '__main__':
from magic import MagicGraph
chk = MagicCheckpoint(l_read=False)
#chk.fd2cheb(33)
#chk.write('checkpoint_cheb.tmp')
gr = MagicGraph()
chk.graph2rst(gr)
#chk.cheb2fd(96)
#chk.write('checkpoint_alpha.tmp')