Skip to content

Commit de11598

Browse files
committed
New rprofs_averaged attribute of _StepsView
This gives access to time-average of radial profiles over the _StepsView. It has the same API as _Rprofs, with an extra steps attribute pointing to the owner of the rprofs_averaged attribute.
1 parent 05b3857 commit de11598

File tree

3 files changed

+60
-34
lines changed

3 files changed

+60
-34
lines changed

stagpy/_step.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,10 @@ def _rprofs(self):
404404
if self._data is UNDETERMINED:
405405
step = self.step
406406
self._data = step.sdat._rprof_and_times[0].get(step.istep)
407-
if self._data is None:
408-
raise error.MissingDataError(
409-
f'No rprof data in step {step.istep} of {step.sdat}')
407+
if self._data is None:
408+
step = self.step
409+
raise error.MissingDataError(
410+
f'No rprof data in step {step.istep} of {step.sdat}')
410411
return self._data
411412

412413
def __getitem__(self, name):

stagpy/rprof.py

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"""Plot radial profiles."""
2+
import re
23

34
import matplotlib.pyplot as plt
4-
import numpy as np
55

66
from . import conf, misc
7-
from ._step import Rprof
87
from .stagyydata import StagyyData
98

109

@@ -86,41 +85,21 @@ def plot_average(sdat, lovs):
8685
conf.core.snapshots: the slice of snapshots.
8786
conf.conf.timesteps: the slice of timesteps.
8887
"""
89-
steps_iter = iter(sdat.walk.filter(rprofs=True))
90-
try:
91-
step = next(steps_iter)
92-
except StopIteration:
93-
return
88+
reg = re.compile(
89+
r'^StagyyData\(.*\)\.(steps|snaps)\[(.*)\](?:.filter\(.*\))?$')
90+
stepstr = repr(sdat.walk)
91+
stepstr = '_'.join(reg.match(stepstr).groups())
92+
rprofs = sdat.walk.rprofs_averaged
9493

9594
sovs = misc.set_of_vars(lovs)
9695

97-
istart = step.istep
98-
nprofs = 1
99-
rprof_averaged = {}
100-
rads = {}
101-
metas = {}
102-
103-
# assume constant z spacing for the moment
104-
for rvar in sovs:
105-
rprof, rads[rvar], metas[rvar] = step.rprofs[rvar]
106-
rprof_averaged[rvar] = np.copy(rprof)
107-
108-
for step in steps_iter:
109-
nprofs += 1
110-
for rvar in sovs:
111-
rprof_averaged[rvar] += step.rprofs[rvar].values
112-
113-
ilast = step.istep
114-
for rvar in sovs:
115-
# cast to float so that division happens in place
116-
rprof_averaged[rvar] = Rprof(rprof_averaged[rvar] / nprofs,
117-
rads[rvar], metas[rvar])
118-
rcmb, rsurf = step.rprofs.bounds
96+
rprof_averaged = {rvar: rprofs[rvar] for rvar in sovs}
97+
98+
rcmb, rsurf = rprofs.bounds
99+
step = rprofs.step
119100
rprof_averaged['bounds'] = (step.sdat.scale(rcmb, 'm')[0],
120101
step.sdat.scale(rsurf, 'm')[0])
121102

122-
stepstr = f'{istart}_{ilast}'
123-
124103
_plot_rprof_list(sdat, lovs, rprof_averaged, stepstr)
125104

126105

stagpy/stagyydata.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from collections import namedtuple
1313
from itertools import zip_longest
1414

15+
import numpy as np
16+
1517
from . import conf, error, misc, parfile, phyvars, stagyyparsers, _step
1618
from ._step import UNDETERMINED
1719

@@ -259,6 +261,43 @@ def at_step(self, istep):
259261
return self._tseries.loc[istep]
260262

261263

264+
class _RprofsAveraged(_step._Rprofs):
265+
"""Radial profiles time-averaged over a :class:`_StepsView`.
266+
267+
The :attr:`_StepsView.rprofs_averaged` attribute is an instance of this
268+
class.
269+
270+
It implements the same interface as :class:`~stagpy._step._Rprofs` but
271+
returns time-averaged profiles instead.
272+
273+
Attributes:
274+
steps (:class:`_StepsView`): the object owning the
275+
:class:`_RprofsAveraged` instance
276+
"""
277+
278+
def __init__(self, steps):
279+
self.steps = steps.filter(rprofs=True)
280+
self._cached_data = {}
281+
super().__init__(next(iter(self.steps)))
282+
283+
def __getitem__(self, name):
284+
# the averaging method has two shortcomings:
285+
# - does not take into account time changing geometry;
286+
# - does not take into account time changing timestep.
287+
if name in self._cached_data:
288+
return self._cached_data[name]
289+
steps_iter = iter(self.steps)
290+
rprof, rad, meta = next(steps_iter).rprofs[name]
291+
rprof = np.copy(rprof)
292+
nprofs = 1
293+
for step in steps_iter:
294+
nprofs += 1
295+
rprof += step.rprofs[name].values
296+
rprof /= nprofs
297+
self._cached_data[name] = _step.Rprof(rprof, rad, meta)
298+
return self._cached_data[name]
299+
300+
262301
class _Steps:
263302
"""Collections of time steps.
264303
@@ -494,6 +533,7 @@ class _StepsView:
494533
def __init__(self, steps_col, items):
495534
self._col = steps_col
496535
self._items = items
536+
self._rprofs_averaged = None
497537
self._flt = {
498538
'snap': False,
499539
'rprofs': False,
@@ -502,6 +542,12 @@ def __init__(self, steps_col, items):
502542
}
503543
self._dflt_func = self._flt['func']
504544

545+
@property
546+
def rprofs_averaged(self):
547+
if self._rprofs_averaged is None:
548+
self._rprofs_averaged = _RprofsAveraged(self)
549+
return self._rprofs_averaged
550+
505551
def __repr__(self):
506552
rep = repr(self._col)
507553
items = []

0 commit comments

Comments
 (0)