77"""
88
99from collections .abc import Mapping
10+ from collections import namedtuple
1011from itertools import chain
1112import re
1213
1314import numpy as np
1415
15- from . import error , phyvars , stagyyparsers
16+ from . import error , misc , phyvars , stagyyparsers
1617
1718
1819UNDETERMINED = 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+
373471class 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.
0 commit comments