Source code for pynbody.snapshot.copy_on_access

"""Implements classes to automatically copy data from another snapshot when needed.

Most users will not need to use this module directly. It is used by `tangos <https://pynbody.github.io/tangos>`_
to provide a transparent view of a snapshot that is actually stored in a different location.
"""

import copy

from .simsnap import SimSnap


[docs] class UnderlyingClassMixin: """Mixin for a SimSnap that allows it to derive quantities associated with another class."""
[docs] def __init__(self, underlying_class, *args, **kwargs): super().__init__(*args, **kwargs) self._underlying_class = underlying_class
def find_deriving_function(self, name): cl = self._underlying_class if cl in self._derived_array_registry \ and name in self._derived_array_registry[cl]: return self._derived_array_registry[cl][name] else: return super().find_deriving_function(name)
[docs] class CopyOnAccessSimSnap(UnderlyingClassMixin, SimSnap): """SimSnap that copies data from another SimSnap when that data is needed. To the user, data which is already loaded in the underlying snapshot presents merely as 'loadable' (i.e. in loadable_keys)."""
[docs] def __init__(self, base: SimSnap, underlying_class=None): self._copy_from = base if underlying_class is None: ancestor = base.ancestor if hasattr(ancestor, "_underlying_class"): underlying_class = ancestor._underlying_class else: underlying_class = type(ancestor) super().__init__(underlying_class) self._unifamily = base._unifamily self._file_units_system = base._file_units_system self._num_particles = len(base) self._family_slice = {f: base._get_family_slice(f) for f in base.families()} self._filename = base._filename+":copied_on_access" self._dont_try_accessing = [] self.properties = copy.deepcopy(base.properties)
def _load_array(self, array_name, fam=None): if (array_name, fam) in self._dont_try_accessing: raise OSError("Previously tried to get this array without success; not trying again") try: with self._copy_from.lazy_derive_off, self.lazy_derive_off, self.auto_propagate_off: if fam is None: self[array_name] = self._copy_from[array_name] else: self[fam][array_name] = self._copy_from[fam][array_name] except KeyError as e: self._dont_try_accessing.append((array_name, fam)) raise OSError("Not found in underlying snapshot") from e
[docs] def loadable_keys(self, fam=None): if fam is None: loaded_keys_in_parent = self._copy_from.keys() else: loaded_keys_in_parent = self._copy_from.family_keys(fam) return list(set(self._copy_from.loadable_keys(fam)).union(loaded_keys_in_parent))