Source code for pynbody.simdict

"""
Defines an augmented dictionary class that manages properties of :class:`~pynbody.snapshot.simsnap.SimSnap` objects

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.
"""

import warnings

from . import config

__all__ = ['SimDict']


[docs] class SimDict(dict): """A dictionary class for managing properties of a :class:`~pynbody.snapshot.simsnap.SimSnap` object. Above the standard dictionary methods, this class also provides automatic derivation of properties, such as converting between redshift and scalefactor, and default values for cosmological parameters. 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 """ _getters = {} _setters = {}
[docs] @staticmethod def getter(f): """Define a getter function for all SimDicts See the class documentation for an example of usage. Parameters ---------- f : function The function to be used as a getter. The function should take a single argument, the SimDict object, and return the value of the property. The name of the property is the name of the function. """ SimDict._getters[f.__name__] = f
[docs] @staticmethod def setter(f): """Define a setter function for all SimDicts See the class documentation for an example of usage. Parameters ---------- f : function The function to be used as a setter. The function should take two arguments, the SimDict object and the value. The name of the property is the name of the function. """ 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 '{}'={:.2e}".format( 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]))