# -*- coding: utf-8 -*-
import glob
import re
import os
import copy
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
from .npfile import npfile
from magic.libmagic import symmetrize, chebgrid
from magic.plotlib import hammer2cart
def getNlines(file_name, endian='B', precision=np.float32):
"""
This function determines the number of lines of a binary file.
:param file_name: name of the input file
:type file_name: str
:param endian: endianness of the file ('B' or 'l')
:type endian: str
:param precision: precision of the data contained in the input file
(np.float32 or np.float64)
:type endian: str
:returns: the number of lines
:rtype: int
"""
f = npfile(file_name, endian=endian)
n_lines = 0
while 1:
try:
f.fort_read(precision)
n_lines += 1
except TypeError:
break
f.close()
return n_lines
[docs]
class Movie:
"""
This class allows to read the :ref:`movie files <secMovieFile>` generated
by the MagIC code.
>>> m = Movie()
>>> # This returns a list of the available movies in the directory
>>> # and lets you decide which one you want to read
>>> # Reads and display AV_mov.test
>>> m = Movie(file='AV_mov.test')
>>> print(m.data) # access to the data
>>> # Read three movie files (no display)
>>> m1 = Movie(file='AV_mov.testa', iplot=False)
>>> m2 = Movie(file='AV_mov.testb', iplot=False)
>>> m3 = Movie(file='AV_mov.testc', iplot=False)
>>> # Stack them together
>>> m = m1+m2+m3
>>> # Display
>>> m.plot(levels=33, cm='seismic', cut=0.5)
>>> # Store the outputs in movie/img_#.png
>>> # Only from the timesteps 280 to 380
>>> m = Movie(file='AB_mov.test', png=True, nvar=100, lastvar=380)
"""
[docs]
def __init__(self, file=None, iplot=True, nstep=1, png=False,
lastvar=None, nvar='all', levels=12, cm='RdYlBu_r', cut=0.5,
bgcolor=None, fluct=False, normed=False, avg=False,
std=False, dpi=80, normRad=False, precision=np.float32,
deminc=True, ifield=0, centeredCm=None, datadir='.'):
"""
:param nvar: the number of timesteps of the movie file we want to plot
starting from the last line
:type nvar: int
:param png: if png=True, write the png files instead of display
:type png: bool
:param iplot: if iplot=True, display otherwise just read
:type iplot: bool
:param lastvar: the number of the last timesteps to be read
:type lastvar: int
:param nstep: the stepping between two timesteps
:type nstep: int
:param levels: the number of contour levels
:type levels: int
:param cm: the name of the color map
:type cm: str
:param fluct: if fluct=True, substract the axisymmetric part
:type fluct: bool
:param normed: the colormap is rescaled every timestep when set to True,
otherwise it is calculated from the global extrema
:type normed: bool
:param avg: if avg=True, time-average is displayed
:type avg: bool
:param centeredCm: when set to True, the colormap is centered between
-vmax and vmax. By default, this is None, it
tries to guess by itself.
:type centeredCm: bool
:param std: if std=True, standard deviation is displayed
:type std: bool
:param dpi: dot per inch when saving PNGs
:type dpi: int
:param normRad: if normRad=True, then we normalise for each radial level
:type normRad: bool
:param precision: precision of the input file, np.float32 for single
precision, np.float64 for double precision
:type precision: str
:param cut: adjust the contour extrema to max(abs(data))*cut
:type cut: float
:param bgcolor: background color of the figure
:type bgcolor: str
:param deminc: a logical to indicate if one wants do get rid of the
possible azimuthal symmetry
:type deminc: bool
:param ifield: in case of a multiple-field movie file, you can change
the default field displayed using the parameter ifield
:type ifield: int
:param datadir: working directory
:type datadir: str
"""
if avg or std:
iplot = False
if file is None:
dat = glob.glob('*[Mm]ov.*')
# Get prefix for movie type
prefix = []
for entry in dat:
prefix.append(entry.split('.')[0])
prefix = set(prefix)
# First sort: alpha: return to a list (set are unsortable when looping)
#dat.sort()
prefix = list(prefix)
prefix.sort()
# Then sort with os time for each type of movie
datSorted = []
for pre in prefix:
pattern = re.compile(r"{}.*".format(pre))
shortList = []
for entry in dat:
if pattern.match(entry):
shortList.append(entry)
dat1 = [(os.stat(i).st_mtime, i) for i in shortList]
dat1.sort()
datSorted.extend([i[1] for i in dat1])
str1 = 'Which movie do you want ?\n'
for k, movie in enumerate(datSorted):
str1 += ' {}) {}\n'.format(k+1, movie)
index = int(input(str1))
try:
filename = datSorted[index-1]
except IndexError:
print('Non valid index: {} has been chosen instead'.format(
datSorted[0]))
filename = datSorted[0]
else:
filename = file
filename = os.path.join(datadir, filename)
mot = re.compile(r'.*[Mm]ov\.(.*)')
end = mot.findall(filename)[0]
# Read the movie file
infile = npfile(filename, endian='B')
# Header
version = infile.fort_read('|S64')
n_type, n_surface, const, n_fields = infile.fort_read(precision)
movtype = infile.fort_read(precision)
self.n_fields = int(n_fields)
if self.n_fields > 1:
print('!!! Warning: several fields in the movie file !!!')
print('!!! {} fields !!!'.format(self.n_fields))
print('!!! The one displayed is controlled by the !!!')
print('!!! input parameter ifield (=0 by default) !!!')
self.movtype = int(movtype[ifield])
n_surface = int(n_surface)
# Run parameters
runid = infile.fort_read('|S64')
n_r_mov_tot, n_r_max, n_theta_max, n_phi_tot, self.minc, self.ra, \
self.ek, self.pr, self.prmag, self.radratio, self.tScale = \
infile.fort_read(precision)
self.minc = int(self.minc)
n_r_mov_tot = int(n_r_mov_tot)
self.n_r_max = int(n_r_max)
self.n_r_ic_max = n_r_mov_tot-self.n_r_max
self.n_theta_max = int(n_theta_max)
self.n_phi_tot = int(n_phi_tot)
# Grid
if self.movtype in [100, 101, 102]:
self.cylRad = infile.fort_read(precision)
self.n_s_max = len(self.cylRad)
else:
self.n_s_max = 0
self.radius = infile.fort_read(precision)
self.radius_ic = np.zeros((self.n_r_ic_max+2), precision)
self.radius_ic[:-1] = self.radius[self.n_r_max-1:]
self.radius = self.radius[:self.n_r_max] # remove inner core
# Overwrite radius to ensure double-precision of the
# grid (useful for Cheb der)
rout = 1./(1.-self.radratio)
# rin = self.radratio/(1.-self.radratio)
self.radius *= rout
self.radius_ic *= rout
# self.radius = chebgrid(self.n_r_max-1, rout, rin)
self.theta = infile.fort_read(precision)
self.phi = infile.fort_read(precision)
if filename.split('.')[-2].endswith('TO_mov'):
l_TOmov = True
else:
l_TOmov = False
# Determine the number of lines by reading the log.TAG file
logfile = open(os.path.join(datadir, 'log.{}'.format(end)), 'r')
mot = re.compile(r' ! WRITING MOVIE FRAME NO\s*(\d*).*')
mot2 = re.compile(r' ! WRITING TO MOVIE FRAME NO\s*(\d*).*')
nlines = 0
for line in logfile.readlines():
if not l_TOmov and mot.match(line):
nlines = int(mot.findall(line)[0])
elif l_TOmov and mot2.match(line):
nlines = int(mot2.findall(line)[0])
logfile.close()
# In case no 'nlines' can be determined from the log file:
if nlines == 0:
nlines = getNlines(filename, endian='B', precision=precision)
nlines -= 8 # Remove 8 lines of header
nlines = nlines//(self.n_fields+1)
if lastvar is None:
self.var2 = nlines
else:
self.var2 = lastvar
if str(nvar) == 'all':
self.nvar = nlines
self.var2 = nlines
else:
self.nvar = nvar
if n_surface == 0:
self.surftype = '3d volume'
if self.movtype in [1, 2, 3]:
shape = (self.n_phi_tot, self.n_theta_max, n_r_mov_tot+2)
else:
shape = (self.n_phi_tot, self.n_theta_max, self.n_r_max)
self.data = np.zeros((self.n_fields, self.nvar, self.n_phi_tot,
self.n_theta_max, self.n_r_max), precision)
self.data_ic = np.zeros((self.n_fields, self.nvar, self.n_phi_tot,
self.n_theta_max, self.n_r_ic_max+2),
precision)
elif n_surface == 1 or n_surface == -1:
self.surftype = 'r_constant'
shape = (self.n_phi_tot, self.n_theta_max)
self.data = np.zeros((self.n_fields, self.nvar, self.n_phi_tot,
self.n_theta_max), precision)
elif n_surface == 2:
self.surftype = 'theta_constant'
if self.movtype in [1, 2, 3, 14]: # read inner core
shape = (self.n_phi_tot, n_r_mov_tot+2)
else:
shape = (self.n_phi_tot, self.n_r_max)
self.data = np.zeros((self.n_fields, self.nvar, self.n_phi_tot,
self.n_r_max), precision)
self.data_ic = np.zeros((self.n_fields, self.nvar, self.n_phi_tot,
self.n_r_ic_max+2), precision)
elif n_surface == -2:
self.surftype = 'theta_constant'
shape = (self.n_phi_tot, self.n_s_max)
self.data = np.zeros((self.n_fields, self.nvar, self.n_phi_tot,
self.n_s_max), precision)
elif n_surface == 3:
self.surftype = 'phi_constant'
if self.movtype in [1, 2, 3, 14]: # read inner core
shape = (self.n_theta_max, 2*(n_r_mov_tot+2))
self.n_theta_plot = 2*self.n_theta_max
elif self.movtype in [8, 9]:
shape = (self.n_theta_max, n_r_mov_tot+2)
self.n_theta_plot = self.n_theta_max
elif self.movtype in [4, 5, 6, 7, 15, 16, 17, 18, 47, 54,
109, 112]:
shape = (self.n_theta_max, self.n_r_max, 2)
self.n_theta_plot = 2*self.n_theta_max
elif self.movtype in [10, 11, 12, 19, 92, 94, 95, 110, 111, 114,
115, 116]:
shape = (self.n_theta_max, self.n_r_max)
self.n_theta_plot = self.n_theta_max
# Inner core is not stored here
self.data = np.zeros((self.n_fields, self.nvar, self.n_theta_plot,
self.n_r_max), precision)
self.data_ic = np.zeros((self.n_fields, self.nvar,
self.n_theta_plot, self.n_r_ic_max+2),
precision)
self.time = np.zeros(self.nvar, precision)
# Read the data
# If one skip the beginning, nevertheless read but do not store
for i in range(self.var2-self.nvar):
n_frame, t_movieS, omega_ic, omega_ma, movieDipColat, \
movieDipLon, movieDipStrength, movieDipStrengthGeo = \
infile.fort_read(precision)
for ll in range(self.n_fields):
dat = infile.fort_read(precision, shape=shape, order='F')
# then read the remaining requested nvar lines
for k in range(self.nvar):
n_frame, t_movieS, omega_ic, omega_ma, movieDipColat, \
movieDipLon, movieDipStrength, movieDipStrengthGeo = \
infile.fort_read(precision)
self.time[k] = t_movieS
for ll in range(self.n_fields):
dat = infile.fort_read(precision, shape=shape, order='F')
if n_surface == 0:
if self.movtype in [1, 2, 3]:
self.data[ll, k, ...] = dat[:, :, :self.n_r_max]
self.data_ic[ll, k, ...] = dat[:, :, self.n_r_max:]
else:
self.data[ll, k, ...] = dat
elif n_surface == 2:
if self.movtype in [1, 2, 3, 14]:
self.data[ll, k, ...] = dat[:, :self.n_r_max]
self.data_ic[ll, k, ...] = dat[:, self.n_r_max:]
else:
self.data[ll, k, ...] = dat
elif n_surface == -2:
self.data[ll, k, ...] = dat
elif n_surface == 3:
if self.movtype in [1, 2, 3, 14]:
datoc0 = dat[:, :self.n_r_max]
datoc1 = dat[:, self.n_r_max:2*self.n_r_max]
datic0 = dat[:, 2*self.n_r_max:2*self.n_r_max+self.n_r_ic_max+2]
datic1 = dat[:, 2*self.n_r_max+self.n_r_ic_max+2:]
self.data[ll, k, ...] = np.vstack((datoc0, datoc1))
self.data_ic[ll, k, ...] = np.vstack((datic0, datic1))
elif self.movtype in [8, 9]:
self.data_ic[ll, k, ...] = dat[:, self.n_r_max:]
self.data[ll, k, ...] = dat[:, :self.n_r_max]
elif self.movtype in [4, 5, 6, 7, 15, 16, 17, 18, 47, 54, 91,
109, 112]:
dat0 = dat[..., 0]
dat1 = dat[..., 1]
self.data[ll, k, ...] = np.vstack((dat0, dat1))
elif self.movtype in [10, 11, 12, 19, 92, 94, 95, 110, 111,
114, 115, 116]:
self.data[ll, k, ...] = dat
else:
self.data[ll, k, ...] = dat
if fluct:
self.data[ll, k, ...] -= self.data[ll, k, ...].mean(axis=0)
infile.close()
if normRad:
for ll in range(self.n_fields):
norm = np.sqrt(np.mean(self.data[ll, ...]**2, axis=1))
norm = norm.mean(axis=0)
self.data[ll, :, :, norm != 0.] /= norm[norm != 0.]
if nstep != 1:
self.time = self.time[::nstep]
self.data = self.data[:, ::nstep, ...]
if hasattr(self, 'data_ic'):
self.data_ic = self.data_ic[:, ::nstep, ...]
self.nvar = self.data.shape[1]
self.var2 = self.nvar
if iplot:
cmap = plt.get_cmap(cm)
self.plot(ifield, cut, centeredCm, levels, cmap, png, nstep=1,
normed=normed, dpi=dpi, bgcolor=bgcolor, deminc=deminc)
if avg or std:
cmap = plt.get_cmap(cm)
self.avgStd(ifield, std, cut, centeredCm, levels, cmap)
[docs]
def __add__(self, new):
"""
Built-in function to sum two movies. In case, the spatial grid have been
changed a spline interpolation onto the new grid is used.
:param new: the new movie file to be added
:type new: magic.Movie
"""
out = copy.deepcopy(new)
# Interpolate on the new grid whenever required
if self.data[0, 0, ...].shape != new.data[0, 0, ...].shape:
new_shape = new.data[0, 0, ...].shape
old_shape = self.data[0, 0, ...].shape
if self.surftype == 'r_constant':
if (new_shape[0] != old_shape[0]) and (new_shape[1] != old_shape[1]):
ip = interp1d(self.phi, self.data, axis=-2,
fill_value='extrapolate')
tmp = ip(new.phi)
it = interp1d(self.theta, tmp, axis=-1,
fill_value='extrapolate')
self.data = it(new.theta)
elif (new_shape[0] != old_shape[0]) and (new_shape[1] == old_shape[1]):
ip = interp1d(self.phi, self.data, axis=-2,
fill_value='extrapolate')
self.data = ip(new.phi)
elif (new_shape[0] == old_shape[0]) and (new_shape[1] != old_shape[1]):
it = interp1d(self.theta, self.data, axis=-1,
fill_value='extrapolate')
self.data = it(new.theta)
elif self.surftype == 'theta_constant':
if (new_shape[0] != old_shape[0]) and (new_shape[1] != old_shape[1]):
ip = interp1d(self.phi, self.data, axis=-2,
fill_value='extrapolate')
tmp = ip(new.phi)
ir = interp1d(self.radius[::-1], tmp[..., ::-1], axis=-1)
tmp = ir(new.radius[::-1])
self.data = tmp[..., ::-1]
elif (new_shape[0] != old_shape[0]) and (new_shape[1] == old_shape[1]):
ip = interp1d(self.phi, self.data, axis=-2,
fill_value='extrapolate')
self.data = ip(new.phi)
elif (new_shape[0] == old_shape[0]) and (new_shape[1] != old_shape[1]):
ir = interp1d(self.radius[::-1], self.data[..., ::-1], axis=-1)
tmp = ir(new.radius[::-1])
self.data = self.data[..., ::-1]
elif self.surftype == 'phi_constant' and \
self.movtype in [10, 11, 12, 19, 92, 94, 95, 110, 111]:
if (new_shape[0] != old_shape[0]) and (new_shape[1] != old_shape[1]):
it = interp1d(self.theta, self.data, axis=-2,
fill_value='extrapolate')
tmp = it(new.theta)
ir = interp1d(self.radius[::-1], tmp[..., ::-1], axis=-1)
tmp = ir(new.radius[::-1])
self.data = tmp[..., ::-1]
elif (new_shape[0] != old_shape[0]) and (new_shape[1] == old_shape[1]):
it = interp1d(self.theta, self.data, axis=-2,
fill_value='extrapolate')
self.data = it(new.theta)
elif (new_shape[0] == old_shape[0]) and (new_shape[1] != old_shape[1]):
ir = interp1d(self.radius[::-1], self.data[..., ::-1], axis=-1)
tmp = ir(new.radius[::-1])
self.data = tmp[..., ::-1]
elif self.surftype == 'phi_constant' and \
self.movtype not in [10, 11, 12, 19, 92, 94, 95, 110, 111]:
if (new_shape[0] != old_shape[0]) and (new_shape[1] != old_shape[1]):
it = interp1d(self.theta, self.data[..., :self.n_theta_max, :],
axis=-2, fill_value='extrapolate')
tmp1 = it(new.theta)
it = interp1d(self.theta, self.data[..., self.n_theta_max:, :],
axis=-2, fill_value='extrapolate')
tmp2 = it(new.theta)
tmp = np.concatenate((tmp1, tmp2), axis=-2)
ir = interp1d(self.radius[::-1], tmp[..., ::-1], axis=-1)
tmp = ir(new.radius[::-1])
self.data = tmp[..., ::-1]
elif (new_shape[0] != old_shape[0]) and (new_shape[1] == old_shape[1]):
it = interp1d(self.theta, self.data[..., :self.n_theta_max, :],
axis=-2, fill_value='extrapolate')
tmp1 = it(new.theta)
it = interp1d(self.theta, self.data[..., self.n_theta_max:, :],
axis=-2, fill_value='extrapolate')
tmp2 = it(new.theta)
self.data = np.concatenate((tmp1, tmp2), axis=-2)
elif (new_shape[0] == old_shape[0]) and (new_shape[1] != old_shape[1]):
ir = interp1d(self.radius[::-1], self.data[..., ::-1], axis=-1)
tmp = ir(new.radius[::-1])
self.data = tmp[..., ::-1]
# Stack the data
if abs(new.time[0]-self.time[-1]) <= 1e-10:
out.data = np.concatenate((self.data, new.data[:, 1:, ...]), axis=1)
out.time = np.concatenate((self.time, new.time[1:]), axis=0)
out.nvar = self.nvar+new.nvar-1
else:
out.data = np.concatenate((self.data, new.data), axis=1)
out.time = np.concatenate((self.time, new.time), axis=0)
out.nvar = self.nvar+new.nvar
out.var2 = out.nvar
return out
[docs]
def avgStd(self, ifield=0, std=False, cut=0.5, centeredCm=None,
levels=12, cmap='RdYlBu_r', ic=False):
"""
Plot time-average or standard deviation
:param ifield: in case of a multiple-field movie file, you can change
the default field displayed using the parameter ifield
:type ifield: int
:param std: the standard deviation is computed instead the average
when std is True
:type std: bool
:param levels: number of contour levels
:type levels: int
:param cmap: name of the colormap
:type cmap: str
:param cut: adjust the contour extrema to max(abs(data))*cut
:type cut: float
:param centeredCm: when set to True, the colormap is centered between
-vmax and vmax
:type centeredCm: bool
"""
if std:
avg = self.data[ifield, ...].std(axis=0)
if ic:
avg_ic = self.data_ic[ifield, ...].std(axis=0)
else:
avg = self.data[ifield, ...].mean(axis=0)
if ic:
avg_ic = self.data_ic[ifield, ...].mean(axis=0)
if centeredCm is None:
if avg.min() < 0 and avg.max() > 0:
centeredCm = True
else:
centeredCm = False
if centeredCm:
vmin = - max(abs(avg.max()), abs(avg.min()))
vmin = cut * vmin
vmax = -vmin
else:
vmax = cut * avg.max()
vmin = cut * avg.min()
cs = np.linspace(vmin, vmax, levels)
if self.surftype == 'phi_constant':
if self.n_theta_plot == self.n_theta_max:
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
fig = plt.figure(figsize=(4, 8))
th0 = th
else:
th0 = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
th1 = np.linspace(np.pi/2., 3.*np.pi/2., self.n_theta_max)
th = np.concatenate((th0, th1))
fig = plt.figure(figsize=(6.5, 6))
# Plotting trick using th0
th0 = np.linspace(np.pi/2, np.pi/2+2.*np.pi, self.n_theta_plot)
rr, tth = np.meshgrid(self.radius, th)
xx = rr * np.cos(tth)
yy = rr * np.sin(tth)
xxout = rr.max() * np.cos(th0)
yyout = rr.max() * np.sin(th0)
xxin = rr.min() * np.cos(th0)
yyin = rr.min() * np.sin(th0)
if ic:
rr, tth = np.meshgrid(self.radius_ic, th)
xx_ic = rr * np.cos(tth)
yy_ic = rr * np.sin(tth)
elif self.surftype == 'r_constant':
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
phi = np.linspace(-np.pi, np.pi, self.n_phi_tot)
ttheta, pphi = np.meshgrid(th, phi)
xx, yy = hammer2cart(ttheta, pphi)
xxout, yyout = hammer2cart(th, -np.pi)
xxin, yyin = hammer2cart(th, np.pi)
fig = plt.figure(figsize=(8, 4))
elif self.surftype == 'theta_constant':
phi = np.linspace(0., 2.*np.pi, self.n_phi_tot)
rr, pphi = np.meshgrid(self.radius, phi)
xx = rr * np.cos(pphi)
yy = rr * np.sin(pphi)
xxout = rr.max() * np.cos(pphi)
yyout = rr.max() * np.sin(pphi)
xxin = rr.min() * np.cos(pphi)
yyin = rr.min() * np.sin(pphi)
fig = plt.figure(figsize=(6, 6))
elif self.surftype == '3d volume':
self.data = self.data[ifield, ..., 0]
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
phi = np.linspace(-np.pi, np.pi, self.n_phi_tot)
ttheta, pphi = np.meshgrid(th, phi)
xx, yy = hammer2cart(ttheta, pphi)
xxout, yyout = hammer2cart(th, -np.pi)
xxin, yyin = hammer2cart(th, np.pi)
fig = plt.figure(figsize=(8, 4))
fig.subplots_adjust(top=0.99, right=0.99, bottom=0.01, left=0.01)
ax = fig.add_subplot(111, frameon=False)
ax.contourf(xx, yy, avg, cs, cmap=cmap, extend='both')
if ic:
ax.contourf(xx_ic, yy_ic, avg_ic, cs, cmap=cmap, extend='both')
ax.plot(xxout, yyout, 'k-', lw=1.5)
ax.plot(xxin, yyin, 'k-', lw=1.5)
ax.axis('off')
[docs]
def plot(self, ifield=0, cut=0.5, centeredCm=None, levels=12,
cmap='RdYlBu_r', png=False, nstep=1, normed=False, dpi=80,
bgcolor=None, deminc=True, ic=False):
"""
Plotting function (it can also write the png files)
:param ifield: in case of a multiple-field movie file, you can change
the default field displayed using the parameter ifield
:type ifield: int
:param levels: number of contour levels
:type levels: int
:param cmap: name of the colormap
:type cmap: str
:param cut: adjust the contour extrema to max(abs(data))*cut
:type cut: float
:param png: save the movie as a series of png files when
set to True
:type png: bool
:param dpi: dot per inch when saving PNGs
:type dpi: int
:param bgcolor: background color of the figure
:type bgcolor: str
:param normed: the colormap is rescaled every timestep when set to True,
otherwise it is calculated from the global extrema
:type normed: bool
:param nstep: the stepping between two timesteps
:type nstep: int
:param deminc: a logical to indicate if one wants do get rid of the
possible azimuthal symmetry
:type deminc: bool
:param centeredCm: when set to True, the colormap is centered between
-vmax and vmax. By default, it tries to guess by
itself.
:type centeredCm: bool
"""
if png:
plt.ioff()
if not os.path.exists('movie'):
os.mkdir('movie')
else:
plt.ion()
if centeredCm is None:
if self.data[ifield, ...].min() < 0 and self.data[ifield, ...].max() > 0:
centeredCm = True
else:
centeredCm = False
if not normed:
if centeredCm:
vmin = - max(abs(self.data[ifield, ...].max()),
abs(self.data[ifield, ...].min()))
vmin = cut * vmin
vmax = -vmin
else:
vmax = cut * self.data[ifield, ...].max()
vmin = cut * self.data[ifield, ...].min()
# vmin, vmax = self.data.min(), self.data.max()
cs = np.linspace(vmin, vmax, levels)
if self.surftype == 'phi_constant':
if self.n_theta_plot == self.n_theta_max:
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
fig = plt.figure(figsize=(4, 8))
th0 = th
else:
th0 = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
th1 = np.linspace(np.pi/2., 3.*np.pi/2., self.n_theta_max)
th = np.concatenate((th0, th1))
fig = plt.figure(figsize=(6.5, 6))
# Plotting trick using th0
th0 = np.linspace(np.pi/2, np.pi/2+2.*np.pi, 2*self.n_theta_max)
rr, tth = np.meshgrid(self.radius, th)
xx = rr * np.cos(tth)
yy = rr * np.sin(tth)
xxout = rr.max() * np.cos(th0)
yyout = rr.max() * np.sin(th0)
xxin = rr.min() * np.cos(th0)
yyin = rr.min() * np.sin(th0)
if ic:
rr, tth = np.meshgrid(self.radius_ic, th)
xx_ic = rr * np.cos(tth)
yy_ic = rr * np.sin(tth)
elif self.surftype == 'r_constant':
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
if deminc:
phi = np.linspace(-np.pi, np.pi, self.n_phi_tot*self.minc+1)
xxout, yyout = hammer2cart(th, -np.pi)
xxin, yyin = hammer2cart(th, np.pi)
else:
phi = np.linspace(-np.pi/self.minc, np.pi/self.minc,
self.n_phi_tot)
xxout, yyout = hammer2cart(th, -np.pi/self.minc)
xxin, yyin = hammer2cart(th, np.pi/self.minc)
ttheta, pphi = np.meshgrid(th, phi)
xx, yy = hammer2cart(ttheta, pphi)
fig = plt.figure(figsize=(8, 4))
elif self.surftype == 'theta_constant':
if deminc:
phi = np.linspace(0., 2.*np.pi, self.n_phi_tot*self.minc+1)
else:
phi = np.linspace(0., 2.*np.pi/self.minc, self.n_phi_tot)
if self.movtype in [100, 101, 102]:
rr, pphi = np.meshgrid(self.cylRad, phi)
else:
rr, pphi = np.meshgrid(self.radius, phi)
xx = rr * np.cos(pphi)
yy = rr * np.sin(pphi)
xxout = rr.max() * np.cos(pphi)
yyout = rr.max() * np.sin(pphi)
xxin = rr.min() * np.cos(pphi)
yyin = rr.min() * np.sin(pphi)
if ic:
rr, pphi = np.meshgrid(self.radius_ic, phi)
xx_ic = rr * np.cos(pphi)
yy_ic = rr * np.sin(pphi)
fig = plt.figure(figsize=(6, 6))
elif self.surftype == '3d volume':
self.data = self.data[ifield, ..., 0]
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
phi = np.linspace(-np.pi, np.pi, self.n_phi_tot)
ttheta, pphi = np.meshgrid(th, phi)
xx, yy = hammer2cart(ttheta, pphi)
xxout, yyout = hammer2cart(th, -np.pi)
xxin, yyin = hammer2cart(th, np.pi)
fig = plt.figure(figsize=(8, 4))
fig.subplots_adjust(top=0.99, right=0.99, bottom=0.01, left=0.01)
ax = fig.add_subplot(111, frameon=False)
for k in range(self.nvar):
if k == 0:
if normed:
vmin = - max(abs(self.data[ifield, k, ...].max()),
abs(self.data[ifield, k, ...].min()))
vmin = cut * vmin
vmax = -vmin
cs = np.linspace(vmin, vmax, levels)
if self.surftype in ['r_constant', 'theta_constant']:
if deminc:
dat = symmetrize(self.data[ifield, k, ...], self.minc)
if ic:
datic = symmetrize(self.data_ic[ifield, k, ...],
self.minc)
else:
dat = self.data[ifield, k, ...]
if ic:
datic = self.data_ic[ifield, k, ...]
im = ax.contourf(xx, yy, dat, cs, cmap=cmap, extend='both')
if ic:
ax.contourf(xx_ic, yy_ic, datic, cs, cmap=cmap,
extend='both')
else:
im = ax.contourf(xx, yy, self.data[ifield, k, ...], cs,
cmap=cmap, extend='both')
if ic:
im_ic = ax.contourf(xx_ic, yy_ic,
self.data_ic[ifield, k, ...], cs,
cmap=cmap, extend='both')
ax.plot(xxout, yyout, 'k-', lw=1.5)
ax.plot(xxin, yyin, 'k-', lw=1.5)
ax.axis('off')
man = plt.get_current_fig_manager()
man.canvas.draw()
if k != 0 and k % nstep == 0:
if not png:
print(k+self.var2-self.nvar)
plt.cla()
if normed:
if centeredCm:
vmin = - max(abs(self.data[ifield, k, ...].max()),
abs(self.data[ifield, k, ...].min()))
vmin = cut * vmin
vmax = -vmin
else:
vmax = cut * self.data[ifield, k, ...].max()
vmin = cut * self.data[ifield, k, ...].min()
cs = np.linspace(vmin, vmax, levels)
if self.surftype in ['r_constant', 'theta_constant']:
if deminc:
dat = symmetrize(self.data[ifield, k, ...], self.minc)
if ic:
datic = symmetrize(self.data_ic[ifield, k, ...],
self.minc)
else:
dat = self.data[ifield, k, ...]
if ic:
datic = self.data_ic[ifield, k, ...]
ax.contourf(xx, yy, dat, cs, cmap=cmap, extend='both')
if ic:
ax.contourf(xx_ic, yy_ic, datic, cs, cmap=cmap,
extend='both')
else:
ax.contourf(xx, yy, self.data[ifield, k, ...], cs,
cmap=cmap, extend='both')
if ic:
ax.contourf(xx_ic, yy_ic, self.data_ic[ifield, k, ...],
cs, cmap=cmap, extend='both')
ax.plot(xxout, yyout, 'k-', lw=1.5)
ax.plot(xxin, yyin, 'k-', lw=1.5)
ax.axis('off')
man.canvas.draw()
if png:
filename = 'movie/img{:05d}.png'.format(k)
print('write {}'.format(filename))
# st = 'echo {}'.format(ivar) + ' > movie/imgmax'
if bgcolor is not None:
fig.savefig(filename, facecolor=bgcolor, dpi=dpi)
else:
fig.savefig(filename, dpi=dpi)
[docs]
def timeLongitude(self, ifield=0, removeMean=True, lat0=0., levels=12,
cm='RdYlBu_r', deminc=True):
"""
Plot the time-longitude diagram (input latitude can be chosen)
:param ifield: in case of a multiple-field movie file, you can change
the default field displayed using the parameter ifield
:type ifield: int
:param lat0: value of the latitude
:type lat0: float
:param levels: number of contour levels
:type levels: int
:param cm: name of the colormap
:type cm: str
:param deminc: a logical to indicate if one wants do get rid of the
possible azimuthal symmetry
:type deminc: bool
:param removeMean: remove the time-averaged part when set to True
:type removeMean: bool
"""
if removeMean:
datCut = self.data[ifield, ...]-self.data[ifield, ...].mean(axis=0)
else:
datCut = self.data[ifield, ...]
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
lat0 *= np.pi/180.
mask = np.where(abs(th-lat0) == abs(th-lat0).min(), 1, 0)
idx = np.nonzero(mask)[0][0]
th = np.linspace(np.pi/2., -np.pi/2., self.n_theta_max)
if deminc:
phi = np.linspace(-np.pi, np.pi, self.minc*self.n_phi_tot+1)
else:
phi = np.linspace(-np.pi/self.minc, np.pi/self.minc,
self.n_phi_tot)
if deminc:
dat = np.zeros((self.nvar, self.minc*self.n_phi_tot+1), np.float64)
else:
dat = np.zeros((self.nvar, self.n_phi_tot), np.float64)
for k in range(self.nvar):
if deminc:
dat[k, :] = symmetrize(datCut[k, :, idx], self.minc)
else:
dat[k, :] = datCut[k, :, idx]
fig = plt.figure()
ax = fig.add_subplot(111)
vmin = -max(abs(dat.max()), abs(dat.min()))
vmax = -vmin
cs = np.linspace(vmin, vmax, levels)
ax.contourf(phi, self.time, dat, cs, cmap=plt.get_cmap(cm))
ax.set_xlabel('Longitude')
ax.set_ylabel('Time')
m_max = self.n_phi_tot//3
w2 = np.fft.fft2(dat)
w2 = abs(w2[1:self.nvar//2+1, 0:m_max+1])
dw = 2.*np.pi/(self.time[-1]-self.time[0])
omega = dw*np.arange(self.nvar)
omega = omega[1:self.nvar//2+1]
ms = np.arange(m_max+1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.contourf(ms, omega, np.log10(w2), 65, cmap=plt.get_cmap('jet'))
ax1.set_yscale('log')
ax1.set_xlabel(r'Azimuthal wavenumber')
ax1.set_ylabel(r'Frequency')
if __name__ == '__main__':
Movie(nstep=1)
plt.show()