Source code for pynbody.simdict

"""
simdict
=======

This submodule defines an augmented dictionary class
(:class:`SimDict`) for :class:`~pynbody.snapshot.SimSnap` properties
where entries need to be managed e.g.  for defining default entries,
or for ensuring consistency between equivalent properties like
redshift and scalefactor.

By default, a :class:`SimDict` automatically converts between
redshift ('z') and scalefactor ('a') and implements default entries
for cosmological values listed in the [default-cosmology] section of
the `pynbody` configuration files.

Adding further properties
-------------------------

To add further properties use the SimDict.getter and SimDict.setter decorators.
For instance, to add a property 'X_copy' which just reflects the value of the
property 'X', you would use the following code:

.. code-block:: python

 @SimDict.getter
 def X_copy(d) :
     return d['X']

 @SimDict.setter
 def X_copy(d, value) :
     d['X'] = value
   
"""

import warnings
from . import config

__all__ = ['SimDict']


[docs]class SimDict(dict): _getters = {} _setters = {}
[docs] @staticmethod def getter(f): """Define a getter function for all SimDicts""" SimDict._getters[f.__name__] = f
[docs] @staticmethod def setter(f): """Define a setter function for all SimDicts""" SimDict._setters[f.__name__] = f
def __getitem__(self, k): if k in self: return dict.__getitem__(self, k) elif k in SimDict._getters: return SimDict._getters[k](self) else: raise KeyError(k) def __setitem__(self, k, v): if k in SimDict._setters: SimDict._setters[k](self, v) else: dict.__setitem__(self, k, v)
@SimDict.getter def z(d): if d["a"] is None: return None try: return 1.0 / d["a"] - 1.0 except ZeroDivisionError: return None @SimDict.setter def z(d, z): if z is None: d["a"] = None else: d["a"] = 1.0 / (1.0 + z) def default_fn(name, value): """Return a getter function for the default name/value pair""" def f(d): warnings.warn("Assuming default value for property '%s'=%.2e" % ( name, value), RuntimeWarning) d[name] = value return value f.__name__ = name return f for k in config['default-cosmology']: SimDict.getter(default_fn(k, config['default-cosmology'][k]))