Ejemplo n.º 1
0
 def empty_collection(self, item_cls, attached, attach_items):
     list_ = SyncedList(validation=_PartialIsInstance(item_cls),
                        attach_members=attach_items)
     if attached:
         self._synced_list = []
         list_._sync(DummySimulation(), self._synced_list)
     return list_
Ejemplo n.º 2
0
def test_init(op_list):
    def validate(x):
        return isinstance(x, DummyOperation)

    # Test automatic to_synced_list function generation
    slist = SyncedList(validation_func=validate)
    assert slist._validate == validate
    op = DummyOperation()
    assert slist._to_synced_list_conversion(op) is op

    # Test specified to_synced_list
    def cpp_identity(x):
        return x._cpp_obj

    slist = SyncedList(validation_func=validate, to_synced_list=cpp_identity)
    assert slist._to_synced_list_conversion == cpp_identity
    op._cpp_obj = 2
    assert slist._to_synced_list_conversion(op) == 2

    # Test full initialziation
    slist = SyncedList(validation_func=validate,
                       to_synced_list=cpp_identity,
                       iterable=op_list)
    assert len(slist._list) == 3
    assert all(op._added for op in slist)
Ejemplo n.º 3
0
    def __init__(self, walls=None, to_cpp=identity):
        self._walls = []
        self._backend_list_index = []
        self._backend_lists = {
            Sphere:
            SyncedList(Sphere, to_synced_list=to_cpp, attach_members=False),
            Cylinder:
            SyncedList(Cylinder, to_synced_list=to_cpp, attach_members=False),
            Plane:
            SyncedList(Plane, to_synced_list=to_cpp, attach_members=False)
        }

        if walls is None:
            return
        self.extend(walls)
Ejemplo n.º 4
0
    def __init__(self, forces, constraints, methods):
        forces = [] if forces is None else forces
        constraints = [] if constraints is None else constraints
        methods = [] if methods is None else methods
        self._forces = SyncedList(lambda x: isinstance(x, Force),
                                  to_synced_list=lambda x: x._cpp_obj,
                                  iterable=forces)

        self._constraints = SyncedList(
            lambda x: isinstance(x, ConstraintForce),
            to_synced_list=lambda x: x._cpp_obj,
            iterable=constraints)

        self._methods = SyncedList(lambda x: isinstance(x, _Method),
                                   to_synced_list=lambda x: x._cpp_obj,
                                   iterable=methods)
Ejemplo n.º 5
0
    def __init__(self):
        self._compute = list()
        self._scheduled = False
        self._updaters = SyncedList(OnlyType(Updater),
                                    _triggered_op_conversion)
        self._writers = SyncedList(OnlyType(Writer), _triggered_op_conversion)
        self._tuners = SyncedList(OnlyType(Tuner), lambda x: x._cpp_obj)
        self._computes = SyncedList(OnlyType(Compute), lambda x: x._cpp_obj)
        self._integrator = None

        self._tuners.append(ParticleSorter())
Ejemplo n.º 6
0
 def test_synced(self):
     test_list = SyncedList(lambda x: x)
     assert not test_list._synced
     test_list._sync(None, [])
     assert test_list._synced
     test_list._unsync()
     assert not test_list._synced
Ejemplo n.º 7
0
def test_attach():
    triggered_op = DummyTriggeredOp(trigger=1)
    sim = DummySimulation()
    slist = SyncedList(lambda x: isinstance(x, DummyTriggeredOp),
                       lambda x: (x._cpp_obj, x.trigger))
    slist.append(triggered_op)
    triggered_op._cpp_obj = DummyCppObj()
    slist._sync(sim, sim._cpp_sys.dummy_list)
    assert len(sim._cpp_sys.dummy_list) == 1
    assert len(sim._cpp_sys.dummy_list[0]) == 2
    assert triggered_op._cpp_obj == sim._cpp_sys.dummy_list[0][0]
    assert triggered_op.trigger == sim._cpp_sys.dummy_list[0][1]
Ejemplo n.º 8
0
    def test_init(self, generate_plain_collection, item_cls):

        validate = _PartialIsInstance(item_cls)

        # Test automatic to_synced_list function generation
        synced_list = SyncedList(validation=validate)
        assert synced_list._validate == validate
        op = item_cls()
        assert synced_list._to_synced_list_conversion(op) is op

        # Test specified to_synced_list
        def cpp_identity(x):
            return x._cpp_obj

        # Test full initialziation
        plain_list = generate_plain_collection(5)
        synced_list = SyncedList(validation=validate,
                                 to_synced_list=cpp_identity,
                                 iterable=plain_list)
        assert synced_list._to_synced_list_conversion == cpp_identity
        op._cpp_obj = 2
        assert synced_list._to_synced_list_conversion(op) == 2
        assert all(op._added for op in synced_list)
        self.check_equivalent(plain_list, synced_list)
Ejemplo n.º 9
0
class Operations(Collection):
    """A mutable collection of operations which act on a `hoomd.Simulation`.

    The `Operations` class contains all the operations acting on a
    simulation. These operations are classes that perform various actions on a
    `hoomd.Simulation`. Operations can be added and removed at any point from a
    `hoomd.Operations` instance. The class provides the interface defined by
    `collections.abc.Collection`. Other methods for manipulating instances
    attempt to mimic Python objects where possible, but the class is not
    simply a mutable list or set. Since there are multiple types of operations
    in HOOMD-blue, `Operations` objects manage multiple independent
    sequences described below.

    The types of operations which can be added to an `Operations` object are
    tuners, updaters, integrators, writers, and computes. An `Operations` can
    only ever hold one integrator at a time. On the other hand, an `Operations`
    object can hold any number of tuners, updaters, writers, or computes. To
    see examples of these types of operations see `hoomd.tune` (tuners),
    `hoomd.update` (updaters), `hoomd.hpmc.integrate` or `hoomd.md.integrate`
    (integrators), , `hoomd.write` (writers), and `hoomd.md.thermo`
    (computes).

    A given instance of an operation class can only be added to a single
    `Operations` container. Likewise, a single instance cannot be added to the
    same `Operations` container more than once.

    All `Operations` instances start with a `hoomd.tune.ParticleSorter` instance
    in their ``tuners`` attribute. This increases simulation
    performance. However, users can choose to modify or remove this tuner if
    desired.

    Note:
        An `Operations` object is created by default when a new simulation is
        created.
    """
    def __init__(self):
        self._compute = list()
        self._scheduled = False
        self._updaters = SyncedList(OnlyType(Updater),
                                    _triggered_op_conversion)
        self._writers = SyncedList(OnlyType(Writer), _triggered_op_conversion)
        self._tuners = SyncedList(OnlyType(Tuner), lambda x: x._cpp_obj)
        self._computes = SyncedList(OnlyType(Compute), lambda x: x._cpp_obj)
        self._integrator = None

        self._tuners.append(ParticleSorter())

    def _get_proper_container(self, operation):
        if isinstance(operation, Updater):
            return self._updaters
        elif isinstance(operation, Writer):
            return self._writers
        elif isinstance(operation, Tuner):
            return self._tuners
        elif isinstance(operation, Compute):
            return self._computes
        else:
            raise TypeError(
                f"{type(operation)} is not a valid operation type.")

    def add(self, operation):
        """Add an operation to this container.

        Adds the provided operation to the appropriate attribute of the
        `Operations` instance.

        Args:
            operation (`hoomd.operation.Operation`): A HOOMD-blue tuner,
                updater, integrator, writer, or compute,  to add to the
                collection.

        Raises:
            ValueError: If ``operation`` already belongs to this or another
                `Operations` instance.
            TypeError: If ``operation`` is not of a valid type.

        Note:
            Since only one integrator can be associated with an `Operations`
            object at a time, this removes the current integrator when called
            with an integrator operation. Also, the ``integrator`` property
            cannot be set to ``None`` using this function. Use
            ``operations.integrator = None`` explicitly for this.
        """
        # calling _add is handled by the synced lists and integrator property.
        # we raise this error here to provide a more clear error message.
        if operation._added:
            raise ValueError("The provided operation has already been added "
                             "to an Operations instance.")
        if isinstance(operation, hoomd.integrate.BaseIntegrator):
            self.integrator = operation
        else:
            try:
                container = self._get_proper_container(operation)
            except TypeError:
                raise TypeError(f"Type {type(operation)} is not a valid "
                                f"type to add to Operations.")
            container.append(operation)

    def __iadd__(self, operation):
        """Works the same as `Operations.add`.

        Args:
            operation (`hoomd.operation.Operation`): A HOOMD-blue tuner,
                updater, integrator, writer, or compute to add to the object.
        """
        self.add(operation)
        return self

    def remove(self, operation):
        """Remove an operation from the `Operations` object.

        Remove the item from the collection whose id is the same as
        ``operation``. See
        `<https://docs.python.org/3/library/functions.html#id>`_ for the concept
        of a Python object id.

        Args:
            operation (`hoomd.operation.Operation`): A HOOMD-blue integrator,
                tuner, updater, integrator, or compute to remove from the
                container.

        Raises:
            ValueError: If ``operation`` is not found in this container.
            TypeError: If ``operation`` is not of a valid type.
        """
        if isinstance(operation, hoomd.integrate.BaseIntegrator):
            self.integrator = None
        else:
            try:
                container = self._get_proper_container(operation)
            except TypeError:
                raise TypeError(f"Type {type(operation)} is not a valid "
                                f"type to remove from Operations.")
            container.remove(operation)

    def __isub__(self, operation):
        """Works the same as `Operations.remove`.

        Args:
            operation (`hoomd.operation.Operation`): A HOOMD-blue integrator,
                tuner, updater, integrator, analzyer, or compute to remove from
                the collection.
        """
        self.remove(operation)
        return self

    @property
    def _sys_init(self):
        if self._simulation is None or self._simulation.state is None:
            return False
        else:
            return True

    def _schedule(self):
        """Prepares all operations for a `hoomd.Simulation.run` call.

        Creates the internal C++ objects for all operations.

        Raises:
            RuntimeError: raises when not associated with a `hoomd.Simulation`
                object.
        """
        if not self._sys_init:
            raise RuntimeError("System not initialized yet")
        sim = self._simulation
        if not (self.integrator is None or self.integrator._attached):
            self.integrator._attach()
        if not self.updaters._synced:
            self.updaters._sync(sim, sim._cpp_sys.updaters)
        if not self.writers._synced:
            self.writers._sync(sim, sim._cpp_sys.analyzers)
        if not self.tuners._synced:
            self.tuners._sync(sim, sim._cpp_sys.tuners)
        if not self.computes._synced:
            self.computes._sync(sim, sim._cpp_sys.computes)
        self._scheduled = True

    def _unschedule(self):
        """Undo the effects of `Operations._schedule`."""
        self._integrator._detach()
        self._writers._unsync()
        self._updaters._unsync()
        self._tuners._unsync()
        self._computes._unsync()
        self._scheduled = False

    def _store_reader(self, reader):
        # TODO
        pass

    def __contains__(self, operation):
        """Whether an operation is contained in this container.

        Args:
            operation: Returns whether this exact operation is
                contained in the collection.
        """
        return any(op is operation for op in self)

    def __iter__(self):
        """Iterates through all contained operations."""
        integrator = (self._integrator, ) if self._integrator else []
        yield from chain(self._tuners, self._updaters, integrator,
                         self._writers, self._computes)

    def __len__(self):
        """Return the number of operations contained in this collection."""
        return len(list(self))

    @property
    def integrator(self):
        """`hoomd.integrate.BaseIntegrator`: An MD or HPMC integrator object.

        `Operations` objects have an initial ``integrator`` property of
        ``None``. Can be set to MD or HPMC integrators. The property can also be
        set to ``None``.
        """
        return self._integrator

    @integrator.setter
    def integrator(self, op):
        if op is not None:
            if not isinstance(op, hoomd.integrate.BaseIntegrator):
                raise TypeError("Cannot set integrator to a type not derived "
                                "from hoomd.integrate.BaseIntegrator")
            if op._added:
                raise RuntimeError("Integrator cannot be added to twice to "
                                   "Operations collection.")
            else:
                op._add(self._simulation)

        old_ref = self.integrator
        self._integrator = op
        # Handle attaching and detaching integrators dealing with None values
        if self._scheduled:
            if op is not None:
                op._attach()
        if old_ref is not None:
            old_ref._notify_disconnect(self._simulation)
            old_ref._detach()
            old_ref._remove()

    @property
    def updaters(self):
        """list[`hoomd.operation.Updater`]: A list of updater operations.

        Holds the list of updaters associated with this collection. The list can
        be modified as a standard Python list.
        """
        return self._updaters

    @property
    def writers(self):
        """list[`hoomd.operation.Writer`]: A list of writer operations.

        Holds the list of writers associated with this collection. The list
        can be modified as a standard Python list.
        """
        return self._writers

    @property
    def tuners(self):
        """list[`hoomd.operation.Tuner`]: A list of tuner operations.

        Holds the list of tuners associated with this collection. The list can
        be modified as a standard Python list.
        """
        return self._tuners

    @property
    def computes(self):
        """list[`hoomd.operation.Compute`]: A list of tuner operations.

        Holds the list of tuners associated with this collection. The list can
        be modified as a standard Python list.
        """
        return self._computes
Ejemplo n.º 10
0
def islist(slist_empty):
    return SyncedList(lambda x: isinstance(x, int),
                      iterable=[OpInt(i) for i in [1, 2, 3]])
Ejemplo n.º 11
0
def slist_empty():
    return SyncedList(lambda x: isinstance(x, Operation))
Ejemplo n.º 12
0
def islist(slist_empty):
    return SyncedList(_PartialIsInstance(int),
                      iterable=[OpInt(i) for i in [1, 2, 3]])
Ejemplo n.º 13
0
def slist_empty():
    return SyncedList(_PartialIsInstance(Operation))