Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Sybil examples to most classes in the root hoomd namespace. #1628

Merged
merged 22 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions hoomd/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ def setup_sybil_tests(namespace):
pattern='*.py',
# exclude files not yet tested with sybil
excludes=[
'custom/custom_action.py',
'data/typeconverter.py',
'data/typeparam.py',
'hpmc/pair/user.py',
],
setup=setup_sybil_tests,
Expand Down
43 changes: 23 additions & 20 deletions hoomd/custom/custom_action.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Copyright (c) 2009-2023 The Regents of the University of Michigan.
# Part of HOOMD-blue, released under the BSD 3-Clause License.

"""Implement Action."""
"""Implement Action.

.. invisible-code-block: python

simulation = hoomd.util.make_example_simulation()
logger = hoomd.logging.Logger()
"""

from abc import ABCMeta, abstractmethod
from enum import IntEnum
Expand All @@ -20,55 +26,52 @@ def __init__(cls, name, base, dct):
class Action(metaclass=_AbstractLoggable):
"""Base class for user-defined actions.

To implement a custom operation in Python, subclass `Action` and
implement the :meth:`~.act` method to perform the desired action. To
To implement a custom operation in Python, subclass `hoomd.custom.Action`
and implement the :meth:`~.act` method to perform the desired action. To
include the action in the simulation run loop, pass an instance of the
action to `hoomd.update.CustomUpdater`, `hoomd.write.CustomWriter`, or
`hoomd.tune.CustomTuner`.

.. code-block:: python

from hoomd.custom import Action
.. rubric:: Examples:

.. code-block:: python

class ExampleAction(Action):
class ExampleAction(hoomd.custom.Action):
def act(self, timestep):
self.com = self._state.snapshot.particles.position.mean(axis=0)
snapshot = self._state.get_snapshot()
if snapshot.communicator.rank == 0:
self.com = snapshot.particles.position.mean(axis=0)

To request that HOOMD-blue compute virials, pressure, the rotational kinetic
energy, or the external field virial, set the flags attribute with the
appropriate flags from the internal `Action.Flags` enumeration.
appropriate flags from the internal `Action.Flags` enumeration:

.. code-block:: python

from hoomd.custom import Action


class ExampleActionWithFlag(Action):
class ExampleAction(hoomd.custom.Action):
flags = [Action.Flags.ROTATIONAL_KINETIC_ENERGY,
Action.Flags.PRESSURE_TENSOR,
Action.Flags.EXTERNAL_FIELD_VIRIAL]

def act(self, timestep):
pass

Use the `hoomd.logging.log` decorator to define loggable properties.
Use the `hoomd.logging.log` decorator to define loggable properties:

.. code-block:: python

from hoomd.python_action import Action
from hoomd.logging import log

class ExampleAction(hoomd.custom.Action):

class ExampleActionWithFlag(Action):

@log
@hoomd.logging.log
def answer(self):
return 42

def act(self, timestep):
pass

example_action = ExampleAction()
logger.add(example_action, quantities=['answer'])

Attributes:
flags (list[Action.Flags]): List of flags from the
`Action.Flags`. Used to tell the integrator if
Expand Down
60 changes: 21 additions & 39 deletions hoomd/data/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,44 +334,35 @@ def coerce_mock_to_array(val):


class HOOMDArray(metaclass=_wrap_class_factory(_wrap_list)):
"""A NumPy like interface to internal HOOMD-blue data.
"""A numpy.ndarray-like interface to internal HOOMD-blue data.

These objects are returned by HOOMD-blue's zero copy local snapshot API
(`hoomd.State.cpu_local_snapshot`).
This class acts like a `numpy.ndarray` object through NumPy's provided
HOOMD-blue's zero copy local snapshot API
(`hoomd.State.cpu_local_snapshot`) returns `HOOMDArray` objects.
`HOOMDArray` acts like `numpy.ndarray` through NumPy's provided
`interface <https://numpy.org/doc/stable/reference/arrays.classes.html>`_.
Some exceptions are the ``view``, ``resize``, ``flat`` and ``flatiter``
methods and the ``data`` and ``base`` properties. For typical use cases,
understanding this class is not necessary. Treat it as a ``numpy.ndarray``.
methods and the ``data`` and ``base`` properties.

In general, whenever possible (when an array pointing to a new buffer is
returned) we return a `numpy.ndarray`. However, any array pointing to the
same data will be returned as a `HOOMDArray`. To ensure memory safety, a
`HOOMDArray` object cannot be accessed outside of the context manager in
which it was created. To have access outside the manager an explicit copy
must be made (e.g. ``numpy.array(obj, copy=True)``).
To ensure memory safety, a `HOOMDArray` object cannot be accessed outside of
the context manager in which it was created. Make an explicit copy to use
the array elsewhere (e.g. ``numpy.array(obj, copy=True)``).

In general this class should be nearly as fast as a standard NumPy array,
but there is some overhead. This is mitigated by returning a
``numpy.ndarray`` whenever possible. If every ounce of performance is
necessary, ``HOOMDArray._coerce_to_ndarray`` can provide a ``numpy.ndarray``
object inside the context manager. **References to a HOOMDArray object's
buffer after leaving the context manager is UNSAFE.** It can cause SEGFAULTs
and cause your program to crash. Use this function only if absolutely
necessary.
``numpy.ndarray`` whenever possible.

.. rubric:: Performance Tips

*Assume* ``a`` *represents a* `HOOMDArray` *for examples given.*
*Let* ``a`` *represent a* `HOOMDArray`.

* Place the ``HOOMDArray`` to the left of the expression
(e.g. ``a + b + c`` is faster than ``b + a + c``). This has to do with
the mechanisms ``HOOMDArray`` has to do to hook into NumPy's
functionality.

* If a copy will need to be made, do it as early as possible. In other
words, if you will need access outside the context manager, use
``numpy.array(a, copy=True)`` before doing any calculations.
* Make copies as early as possible. In other words, if you will need access
outside the context manager, use ``numpy.array(a, copy=True)`` before
doing any calculations.

* If you know that your access of the internal buffer is safe and we
cannot detect this (i.e. we return a ``HOOMDArray``), using
Expand Down Expand Up @@ -725,41 +716,32 @@ class HOOMDGPUArray(_NoGPU):


_gpu_array_docs = """
Exposes an internal HOOMD-blue GPU buffer.
A __cuda_array_interface__ to internal HOOMD-blue data on the GPU.

The HOOMDGPUArray object exposes a GPU data buffer using the
The HOOMDGPUArray object exposes a GPU data buffer using
`__cuda_array_interface__
<https://numba.pydata.org/numba-doc/latest/cuda/cuda_array_interface.html>`_.
This class provides buffer access through a context manager to prevent invalid
memory accesses (`hoomd.State.gpu_local_snapshot`). To avoid errors, do not use
references to the data outside the context manager. For example:
memory accesses (`hoomd.State.gpu_local_snapshot`). To avoid errors, use arrays
only within the relevant context manager. For example:

.. code-block:: python

with sim.state.gpu_local_snapshot as data:
# valid within context manager
pos = cupy.array(data.particles.position, copy=False)
# can use pos within manager
pos[:, 2] += 1
# invalid data access can cause SEGFAULTs and other issues
pos[:, 2] -= 1

In general, it is safer to not store any `HOOMDGPUArray` references to a data
buffer. This can be done when necessary, but care must be taken not to use
references to the data outside the context manager.

Note:
The full functionality of this class depends on whether, HOOMD-blue can
import CuPy. If CuPy can be imported then, we wrap much of the
``cupy.ndarray`` class's functionality. Otherwise, we just expose the buffer
and provide a few basic properties.
When CuPy can be imported, then this class wraps much of the
``cupy.ndarray`` class's functionality. Otherwise, this class exposes only
the buffer.

`HOOMDGPUArray` always supports getting (but not setting) the ``shape``,
``strides``, and ``ndim`` properties. `HOOMDGPUArray` never supports standard
binary operators like (``+``, ``-``, ``*``). This is a current limitation on
external classes hooking into CuPy.

When CuPy is imported, slice/element assignment (e.g.
When CuPy can be imported, slice/element assignment (e.g.
``array[0] = 1; array[:2] = 4``) and compound assignment operators (e.g. ``+=``,
``-=``, ``*=``) are available. In addition, most methods besides ``view``,
``resize``, ``flat``, ``flatiter`` are available. The same is true for
Expand Down
68 changes: 41 additions & 27 deletions hoomd/data/local_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ def _exit(self):
class ParticleLocalAccessBase(_LocalAccess):
"""Class for directly accessing HOOMD-blue particle data.

Note:
Changing some attributes (such as ``velocity`` and ``acceleration``)
may not alter the trajectory of the system as you would expect.
The `md.Integrator` is responsible for integrating the equations of
motion and manages the values in these arrays.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
typeid ((N_particles) `hoomd.data.array` object of ``float``):
The integer type of a particle.
Expand Down Expand Up @@ -133,15 +144,6 @@ class ParticleLocalAccessBase(_LocalAccess):
Net virial on particle :math:`[\\mathrm{energy}]`.
net_energy ((N_particles,) `hoomd.data.array` object of ``float``):
Net energy of a particle :math:`[\\mathrm{energy}]`.

Note:
Changing some attributes (such as ``velocity`` and ``acceleration``)
may not alter the trajectory of the system as you would expect.
The `md.Integrator` is responsible for integrating the equations of
motion and manages the values in these arrays.

See Also:
`hoomd.State`
"""

@property
Expand Down Expand Up @@ -203,6 +205,11 @@ def __init__(self, state):
class BondLocalAccessBase(_GroupLocalAccess):
"""Class for directly accessing HOOMD-blue bond data.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
typeid ((N_bonds) `hoomd.data.array` object of ``int``):
The integer type of a bond.
Expand All @@ -216,16 +223,18 @@ class BondLocalAccessBase(_GroupLocalAccess):
The bond reverse tags. For a given bond tag ``tag``,
``i = bonds.rtag[tag]`` is the array index holding that
bond.

See Also:
`hoomd.State`
"""
_cpp_get_data_method_name = "getBondData"


class AngleLocalAccessBase(_GroupLocalAccess):
"""Class for directly accessing HOOMD-blue angle data.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
typeid ((N_angles) `hoomd.data.array` object of ``int``):
The integer type of a angle.
Expand All @@ -238,16 +247,18 @@ class AngleLocalAccessBase(_GroupLocalAccess):
rtag ((N_angles_global) `hoomd.data.array` object of ``int``):
The angle reverse tags. For a given angle tag ``tag``, ``i =
angles.rtag[tag]`` is the array index holding that angle.

See Also:
`hoomd.State`
"""
_cpp_get_data_method_name = "getAngleData"


class DihedralLocalAccessBase(_GroupLocalAccess):
"""Class for directly accessing HOOMD-blue dihedral data.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
typeid ((N_dihedrals) `hoomd.data.array` object of ``int``): The integer
type of a dihedral.
Expand All @@ -260,16 +271,18 @@ class DihedralLocalAccessBase(_GroupLocalAccess):
rtag ((N_dihedrals_global) `hoomd.data.array` object of ``int``):
The dihedral reverse tags. For a given dihedral tag ``tag``, ``i
= dihedrals.rtag[tag]`` is the array index holding that dihedral.

See Also:
`hoomd.State`
"""
_cpp_get_data_method_name = "getDihedralData"


class ImproperLocalAccessBase(_GroupLocalAccess):
"""Class for directly accessing HOOMD-blue improper data.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
typeid ((N_impropers) `hoomd.data.array` object of ``int``):
The integer type of a improper.
Expand All @@ -282,16 +295,18 @@ class ImproperLocalAccessBase(_GroupLocalAccess):
rtag ((N_impropers_global) `hoomd.data.array` object of ``int``):
The improper reverse tags. For a given improper tag ``tag``, ``i
= impropers.rtag[tag]`` is the array index holding that improper.

See Also:
`hoomd.State`
"""
_cpp_get_data_method_name = "getImproperData"


class ConstraintLocalAccessBase(_GroupLocalAccess):
"""Class for directly accessing HOOMD-blue constraint data.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
value ((N_constraints) `hoomd.data.array` object of ``float``): The
constaint value.
Expand All @@ -305,9 +320,6 @@ class ConstraintLocalAccessBase(_GroupLocalAccess):
The constraint reverse tags. For a given constraint tag ``tag``,
``i = constraints.rtag[tag]`` is the array index holding that
constraint.

See Also:
`hoomd.State`
"""
_fields = {
'value': 'getTypeVal',
Expand All @@ -321,6 +333,11 @@ class ConstraintLocalAccessBase(_GroupLocalAccess):
class PairLocalAccessBase(_GroupLocalAccess):
"""Class for directly accessing HOOMD-blue special pair data.

See Also:
* `hoomd.State`
* `hoomd.data.LocalSnapshot`
* `hoomd.data.LocalSnapshotGPU`

Attributes:
typeid ((N_pairs) `hoomd.data.array` object of ``float``): The type of
special pair.
Expand All @@ -334,9 +351,6 @@ class PairLocalAccessBase(_GroupLocalAccess):
The special pair reverse tags. For a given special pair tag
``tag``, ``i = pairs.rtag[tag]`` is the array index holding that
special pair.

See Also:
`hoomd.State`
"""
_cpp_get_data_method_name = "getPairData"

Expand Down
4 changes: 4 additions & 0 deletions hoomd/data/local_access_cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ class LocalSnapshot(_LocalSnapshot):
For the ``LocalAccess`` classes the affixed attributes mentioned above
are not shown. Also of interest, ghost data always come immediately
after the regular data.

See Also:
Access the local snapshot of a state via
`hoomd.State.cpu_local_snapshot`.
"""

def __init__(self, state):
Expand Down
4 changes: 4 additions & 0 deletions hoomd/data/local_access_gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class LocalSnapshotGPU(_NoGPU, _LocalSnapshot):

All array-like properties return a `hoomd.data.array.HOOMDGPUArray` object which
prevents invalid memory accesses.

See Also:
Access the local snapshot of a state via
`hoomd.State.gpu_local_snapshot`.
"""

LocalSnapshotGPU.__doc__ = _gpu_snapshot_docs
Loading