Source code for openpathsampling.engines.snapshot

"""

@author: JD Chodera
@author: JH Prinz
"""

import abc

from openpathsampling.netcdfplus import StorableObject
from . import features as feats


# =============================================================================
# ABSTRACT SNAPSHOT (IMPLEMENTS ONLY REVERSED SNAPSHOTS)
# =============================================================================

[docs]class BaseSnapshot(StorableObject): """ Simulation snapshot. Contains references to a configuration and momentum Parameters ---------- topology : openpathsamping.Topology, default: None The corresponding topology used with this Snapshot. Can also be None and means no topology is specified. """ __metaclass__ = abc.ABCMeta
[docs] def __init__(self, topology=None): super(BaseSnapshot, self).__init__() self._reversed = None self.topology = topology
# def __eq__(self, other): # if self is other: # return True # # if isinstance(other, BaseSnapshot): # return self.__uuid__ == other.__uuid__ # # return NotImplemented # # def __ne__(self, other): # return not self == other # def __hash__(self): # return self.__uuid__ & 1152921504606846975 @property def reversed(self): """ Get the reversed copy. Returns ------- :class:`openpathsampling.snapshots.AbstractSnapshot` the reversed partner of the current snapshot Snapshots exist in pairs and this returns the reversed counter part. The actual implementation takes care the the reversed version have reversed momenta, etc. Usually these will not be stored separately but flipped when requested. """ if self._reversed is None: self._reversed = self.create_reversed() return self._reversed def __neg__(self): """ Access the reversed snapshot using `-` Returns ------- :class:`BaseSnapshot` the reversed copy """ return self.reversed # ========================================================================== # Utility functions # ========================================================================== def copy(self): """ Returns a shallow copy of the instance itself. The contained configuration and momenta are not copied. Returns ------- :class:`openpathsampling.BaseSnapshot` the shallow copy Notes ----- Shallow here means that content will not be copied but only referenced. Hence if you store the shallow copy it will be stored under a different idx, but the content (e.g. Configuration object) will not. """ this = self.__class__.__new__(self.__class__) BaseSnapshot.__init__(this, topology=self.topology) return this def copy_with_replacement(self, **kwargs): cp = self.copy() # this will copy all, but it is simple for key, value in kwargs.items(): if hasattr(cp, key): setattr(cp, key, value) else: raise TypeError("copy_with_replacement() got an " "unexpected keyword argument '%s'" % key) return cp def create_reversed(self): this = self.copy() this._reversed = self return this
def SnapshotFactory( name, features, description=None, use_lazy_reversed=False, base_class=None): """ Helper to create a new Snapshot class Parameters ---------- name : str name of the Snapshot class features : list of :obj:`openpathsampling.features` the features used to build the snapshot description : str the string to be used as basis for the docstring of the new class it will be merged with the docs for the features use_lazy_reversed : bool still in there for legacy reasons. It will make the .reversed attribute into a descriptor than can treat LoaderProxy objects. This feature is not relly used anymore and can in the best case only save little memory with slowing down construction, etc. Using `False` is faster base_class : :obj:`openpathsampling.BaseSnapshot` The base class the Snapshot is derived from. Default is the `BaseSnapshot` class. Returns ------- :class:`openpathsampling.Snapshot` the created `Snapshot` class """ if base_class is None: base_class = BaseSnapshot if type(base_class) is not tuple: base_class = (base_class,) cls = type(name, base_class, {}) if description is not None: cls.__doc__ = description cls = feats.attach_features( features, use_lazy_reversed=use_lazy_reversed)(cls) return cls
[docs]class SnapshotDescriptor(frozenset, StorableObject): """Container for information about snapshots generated by an engine. Snapshot descriptors are used to define the dimensions of the features used in a snapshot, in order to set correct sizes in storage. For example, the arrays of atomic positions and velocities will each be of shape ``(n_atoms, n_spatial)``. The snapshot descriptor stores the values of ``n_atoms`` and ``n_spatial``. It also knows the class of snapshot to be created by the engine. This is usually created upon initialization of the engine, using information from the engine's initialization parameters. In practice, it is probably easiest to create snapshot descriptors using their :meth:`.construct` method. Parameters ---------- contents : list of 2-tuples Key-value pairs for information to be stored. One must be the key 'class', mapped to a snapshot class. """
[docs] def __init__(self, contents): StorableObject.__init__(self) frozenset.__init__(contents) self._dimensions = dict(self) self._cls = self._dimensions['class'] del self._dimensions['class']
@property def snapshot_class(self): return self._cls @property def dimensions(self): return self._dimensions @classmethod def from_dict(cls, dct): return cls(dct.items()) def to_dict(self): return dict(self) @staticmethod def construct(snapshot_class, snapshot_dimensions): """Convenience method to create a snapshot descriptor. Parameters ---------- snapshot_class : class class that creates snapshots for this engine snapshot_dimensions : dict dictionary mapping dimension name to integer Returns ------- :class:`.SnapshotDescriptor`: descriptor based on the input information Examples -------- >>> from openpathsampling.engines import SnapshotDescriptor, toy >>> descriptor = SnapshotDescriptor.construct( ... snapshot_class=toy.Snapshot, ... snapshot_dimensions={'n_atoms': 1, 'n_spatial': 2} ... ) """ d = {'class': snapshot_class} if set(snapshot_class.__features__.dimensions) > \ set(snapshot_dimensions.keys()): raise RuntimeError( ('Snapshot of type %s needs %s as dimensions, ' 'you only provided %s') % ( snapshot_class.__class__.__name__, str(set(snapshot_class.__features__['dimensions'])), str(set(snapshot_dimensions.keys())) ) ) d.update(snapshot_dimensions) return SnapshotDescriptor(list(d.items()))