Skip to content

Commit 3dac498

Browse files
committed
Merge branch 'rprof' into master
2 parents 13467f5 + 3551dfc commit 3dac498

File tree

14 files changed

+244
-290
lines changed

14 files changed

+244
-290
lines changed

docs/sources/stagyydata.rst

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -86,32 +86,24 @@ are given a default value according to the par file ``~/.config/stagpy/par``.
8686
Radial profiles
8787
---------------
8888

89-
Radial profile data are contained in the
90-
:attr:`~stagpy.stagyydata.StagyyData.rprof` attribute of a
91-
:class:`~stagpy.stagyydata.StagyyData` instance. This attribute is a
92-
:class:`pandas.DataFrame`. Its :attr:`columns` are the names of available
93-
variables (such as e.g. ``'Tmean'`` and ``'ftop'``). Its :attr:`index` is a 2
94-
levels multi-index, the first level being the time step number (:attr:`istep`),
95-
and the second level being the cells number (from ``0`` to ``nz-1``). The list
96-
of available variables can be obtained by running ``% stagpy var``.
89+
Radial profile data are accessible trough the :attr:`~stagpy._step.Step.rprofs`
90+
attribute of a :class:`~stagpy._step.Step` instance. This attribute implements
91+
getitem to access radial profiles. Keys are the names of available
92+
variables (such as e.g. ``'Tmean'`` and ``'ftop'``). Items are named tuples
93+
with three fields:
9794

98-
The radial profile of a given time step can be accessed from :attr:`_Step.rprof
99-
<stagpy.stagyydata._Step.rprof>`. For example, ``sdat.steps[1000].rprof`` is
100-
equivalent to ``sdat.rprof.loc[1000]``. The columns of the obtained dataframe
101-
are the variable names, and its index is the cells number.
95+
- :data:`values`: the profile itself;
96+
- :data:`rad`: the radial position at which the profile is evaluated;
97+
- :data:`meta`: metadata of the profile, also a named tuple with:
10298

103-
As an example, the following lines are two ways of accessing the horizontal
104-
average temperature in the bottom cell, at the 1000th timestep::
99+
- :data:`description`: explanation of what the profile is;
100+
- :data:`kind`: the category of profile;
101+
- :data:`dim`: the dimension of the profile (if applicable) in SI units.
105102

106-
# extract rprof data for the 1000th timestep,
107-
# and then take the temperature in the bottom cell
108-
sdat.rprof.loc[1000].loc[0,'Tmean']
109-
# extract the temperature profile for the 1000th timestep,
110-
# and then take the bottom cell
111-
sdat.rprof.loc[1000,'Tmean'][0]
103+
The list of available variables can be obtained by running ``% stagpy var``.
112104

113-
If the radial profiles of the 1000th timestep are not available, these would
114-
both result in a ``KeyError``.
105+
For example, ``sdat.steps[1000].rprofs['Tmean']`` is the temperature profile of
106+
the 1000th timestep.
115107

116108
Time series
117109
-----------

docs/sources/tuto.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Instantiating and using this class is rather simple::
8787
sdat = StagyyData('path/to/run/')
8888

8989
# absolute vertical velocity profile of last snapshot
90-
last_v_prof = sdat.snaps[-1].rprof['vzabs']
90+
last_v_prof = sdat.snaps[-1].rprof['vzabs'].values
9191

9292
# temperature field of the 10000th time step
9393
# (will be None if no snapshot is available at this timestep)

stagpy/_step.py

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
"""
88

99
from collections.abc import Mapping
10+
from collections import namedtuple
1011
from itertools import chain
1112
import re
1213

1314
import numpy as np
1415

15-
from . import error, phyvars, stagyyparsers
16+
from . import error, misc, phyvars, stagyyparsers
1617

1718

1819
UNDETERMINED = object()
@@ -370,6 +371,103 @@ def __iter__(self):
370371
raise TypeError('tracers collection is not iterable')
371372

372373

374+
Rprof = namedtuple('Rprof', ['values', 'rad', 'meta'])
375+
376+
377+
class _Rprofs:
378+
"""Radial profiles data structure.
379+
380+
The :attr:`Step.rprofs` attribute is an instance of this class.
381+
382+
:class:`_Rprofs` implements the getitem mechanism. Keys are profile names
383+
defined in :data:`stagpy.phyvars.RPROF[_EXTRA]`. An item is a named tuple
384+
('values', 'rad', 'meta'), respectively the profile itself, the radial
385+
position at which it is evaluated, and meta is a
386+
:class:`stagpy.phyvars.Varr` instance with relevant metadata. Note that
387+
profiles are automatically scaled if conf.scaling.dimensional is True.
388+
389+
Attributes:
390+
step (:class:`Step`): the step object owning the :class:`_Rprofs`
391+
instance
392+
"""
393+
394+
def __init__(self, step):
395+
self.step = step
396+
self._data = UNDETERMINED
397+
self._centers = UNDETERMINED
398+
self._walls = UNDETERMINED
399+
self._bounds = UNDETERMINED
400+
401+
@property
402+
def _rprofs(self):
403+
if self._data is UNDETERMINED:
404+
step = self.step
405+
self._data = step.sdat._rprof_and_times[0].get(step.istep)
406+
if self._data is None:
407+
raise error.MissingDataError('No rprof data in step {} of {}'
408+
.format(step.istep, step.sdat))
409+
return self._data
410+
411+
def __getitem__(self, name):
412+
step = self.step
413+
if name in self._rprofs.columns:
414+
rprof = self._rprofs[name].values
415+
rad = self.centers
416+
if name in phyvars.RPROF:
417+
meta = phyvars.RPROF[name]
418+
else:
419+
meta = phyvars.Varr(name, None, '1')
420+
elif name in phyvars.RPROF_EXTRA:
421+
meta = phyvars.RPROF_EXTRA[name]
422+
rprof, rad = meta.description(step)
423+
meta = phyvars.Varr(misc.baredoc(meta.description),
424+
meta.kind, meta.dim)
425+
else:
426+
raise error.UnknownRprofVarError(name)
427+
rprof, _ = step.sdat.scale(rprof, meta.dim)
428+
rad, _ = step.sdat.scale(rad, 'm')
429+
430+
return Rprof(rprof, rad, meta)
431+
432+
@property
433+
def centers(self):
434+
"""Radial position of cell centers."""
435+
if self._centers is UNDETERMINED:
436+
self._centers = self._rprofs['r'].values + self.bounds[0]
437+
return self._centers
438+
439+
@property
440+
def walls(self):
441+
"""Radial position of cell walls."""
442+
if self._walls is UNDETERMINED:
443+
rbot, rtop = self.bounds
444+
centers = self.centers
445+
# assume walls are mid-way between T-nodes
446+
# could be T-nodes at center between walls
447+
self._walls = (centers[:-1] + centers[1:]) / 2
448+
self._walls = np.insert(self._walls, 0, rbot)
449+
self._walls = np.append(self._walls, rtop)
450+
return self._walls
451+
452+
@property
453+
def bounds(self):
454+
"""Radial or vertical position of boundaries.
455+
456+
Radial/vertical positions of boundaries of the domain.
457+
"""
458+
if self._bounds is UNDETERMINED:
459+
step = self.step
460+
if step.geom is not None:
461+
rcmb = step.geom.rcmb
462+
else:
463+
rcmb = step.sdat.par['geometry']['r_cmb']
464+
if step.sdat.par['geometry']['shape'].lower() == 'cartesian':
465+
rcmb = 0
466+
rcmb = max(rcmb, 0)
467+
self._bounds = rcmb, rcmb + 1
468+
return self._bounds
469+
470+
373471
class Step:
374472
"""Time step data structure.
375473
@@ -416,6 +514,7 @@ def __init__(self, istep, sdat):
416514
self.sfields = _Fields(self, phyvars.SFIELD, [],
417515
phyvars.SFIELD_FILES, phyvars.SFIELD_FILES_H5)
418516
self.tracers = _Tracers(self)
517+
self.rprofs = _Rprofs(self)
419518
self._isnap = UNDETERMINED
420519

421520
@property
@@ -438,16 +537,6 @@ def timeinfo(self):
438537
return None
439538
return self.sdat.tseries.loc[self.istep]
440539

441-
@property
442-
def rprof(self):
443-
"""Radial profiles data of the time step.
444-
445-
Set to None if no radial profiles data is available for this time step.
446-
"""
447-
if self.istep not in self.sdat.rprof.index.levels[0]:
448-
return None
449-
return self.sdat.rprof.loc[self.istep]
450-
451540
@property
452541
def isnap(self):
453542
"""Snapshot index corresponding to time step.

stagpy/misc.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -121,26 +121,6 @@ def set_of_vars(lovs):
121121
return set(var for pvars in lovs for svars in pvars for var in svars)
122122

123123

124-
def get_rbounds(step):
125-
"""Radial or vertical position of boundaries.
126-
127-
Args:
128-
step (:class:`~stagpy.stagyydata._Step`): a step of a StagyyData
129-
instance.
130-
Returns:
131-
tuple of floats: radial or vertical positions of boundaries of the
132-
domain.
133-
"""
134-
if step.geom is not None:
135-
rcmb = step.geom.rcmb
136-
else:
137-
rcmb = step.sdat.par['geometry']['r_cmb']
138-
if step.sdat.par['geometry']['shape'].lower() == 'cartesian':
139-
rcmb = 0
140-
rcmb = max(rcmb, 0)
141-
return rcmb, rcmb + 1
142-
143-
144124
class InchoateFiles:
145125
"""Context manager handling files whose names are not known yet.
146126

stagpy/phyvars.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,6 @@
192192
))
193193

194194
RPROF_EXTRA = OrderedDict((
195-
('redges', Varr(processing.r_edges, 'Radius', 'm')),
196195
('dr', Varr(processing.delta_r, 'dr', 'm')),
197196
('diff', Varr(processing.diff_prof, 'Heat flux', 'W/m2')),
198197
('diffs', Varr(processing.diffs_prof, 'Heat flux', 'W/m2')),

stagpy/plates.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -593,12 +593,11 @@ def main_plates(sdat):
593593
"""Plot several plates information."""
594594
# calculating averaged horizontal surface velocity
595595
# needed for redimensionalisation
596-
ilast = sdat.rprof.index.levels[0][-1]
597-
rlast = sdat.rprof.loc[ilast]
596+
rlast = sdat.snaps[-1].rprofs
598597
nprof = 0
599-
uprof_averaged = rlast.loc[:, 'vhrms'] * 0
600-
for step in sdat.walk.filter(rprof=True):
601-
uprof_averaged += step.rprof['vhrms']
598+
uprof_averaged = np.zeros_like(rlast['vhrms'].values)
599+
for step in sdat.walk.filter(rprofs=True):
600+
uprof_averaged += step.rprofs['vhrms'].values
602601
nprof += 1
603602
uprof_averaged /= nprof
604603
radius = rlast['r'].values

0 commit comments

Comments
 (0)