From bac550d9d94b7eda67c5a152b11efe791b3edfe4 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Mon, 11 Sep 2023 15:15:42 -0400 Subject: [PATCH 01/22] CustomAction passes Sybil tests. --- hoomd/conftest.py | 1 - hoomd/custom/custom_action.py | 50 +++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/hoomd/conftest.py b/hoomd/conftest.py index 2043706e8b..0547ae2be7 100644 --- a/hoomd/conftest.py +++ b/hoomd/conftest.py @@ -66,7 +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', diff --git a/hoomd/custom/custom_action.py b/hoomd/custom/custom_action.py index 683837e684..09291070a8 100644 --- a/hoomd/custom/custom_action.py +++ b/hoomd/custom/custom_action.py @@ -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 @@ -20,31 +26,36 @@ 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) + + example_action = ExampleAction() + custom_updater = hoomd.update.CustomUpdater( + trigger=hoomd.trigger.Periodic(1000), + action=example_action) + simulation.operations.updaters.append(custom_updater) + simulation.run(2000) 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] @@ -52,23 +63,22 @@ class ExampleActionWithFlag(Action): 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 From 0e802ecb263b5f190eb4f41c7e0b18e7ec951272 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 12 Sep 2023 11:04:18 -0400 Subject: [PATCH 02/22] Add Sybil tests to TypeParameter. --- hoomd/conftest.py | 1 - hoomd/data/typeparam.py | 252 ++++++++++++++++++++----------- hoomd/md/methods/methods.py | 2 +- sphinx-doc/module-hoomd-data.rst | 11 +- 4 files changed, 174 insertions(+), 92 deletions(-) diff --git a/hoomd/conftest.py b/hoomd/conftest.py index 0547ae2be7..dacfc9804b 100644 --- a/hoomd/conftest.py +++ b/hoomd/conftest.py @@ -67,7 +67,6 @@ def setup_sybil_tests(namespace): # exclude files not yet tested with sybil excludes=[ 'data/typeconverter.py', - 'data/typeparam.py', 'hpmc/pair/user.py', ], setup=setup_sybil_tests, diff --git a/hoomd/data/typeparam.py b/hoomd/data/typeparam.py index 42c9d9b93d..372873e5e2 100644 --- a/hoomd/data/typeparam.py +++ b/hoomd/data/typeparam.py @@ -11,87 +11,40 @@ # documentation. For documentation on the mechanics and internal structure go to # the documentation for hoomd.data.parameterdicts.TypeParameterDict. class TypeParameter(MutableMapping): - """Implement a type based mutable mapping. + """Store parameters by type or type pair. - *Implements the* `collections.abc.MutableMapping` *interface - (* ``__delitem__`` *is disallowed).* + *Implements the* `collections.abc.MutableMapping` *interface* (excluding + ``__delitem__``). - `TypeParameter` instances extend the base Python mapping interface with - smart defaults, value/key validation/processing, and advanced indexing. The - class's intended purpose is to store data per type or per unique - combinations of type (such as type pairs for `hoomd.md.pair` potentials) of - a prescribed length. + Many operations in HOOMD-blue utilize parameters that depend on the type or + pairs of types. For example, the Langevin drag coefficient + (`hoomd.md.methods.Langevin.gamma`) are set by **particle type** and + Lennard-Jones pair potential parameters (`hoomd.md.pair.LJ.params`) are set + by **pairs** of particle types. - .. rubric:: Indexing + `TypeParameter` holds the values of these type (or type pair) depdendent + parameters. It also provides convenience methods for setting defaults + and multiple parameters on one line. - For getting and setting values, multiple index formats are supported. The - base case is either a string representing the appropriate type or a tuple of - such strings if multiple types are required per key. This is the exact same - indexing behavior expect from a Python `dict`, and all functions (barring - those that delete keys) should function as expected for a Python - `collections.defaultdict`. + Important: - Two ways to extend this base indexing are supported. First is using an - iterator of the final key types. This will perform the method for all - specified types in the iterator. Likewise, for each item in the final tuple - (if the expected key type is a tuple of multiple string types), an iterator - can be used instead of a string which will result in all permutations of - such iterators in the tuple. Both advanced indexing methods can be combined. + Parameters for all types (or unordered pairs of types) in the simulation + state must be defined prior to calling `Simulation.run()`. Note: - All methods support advanced indexing as well, and behave as one might - expect. Methods that set values will do so for all keys specified, and - methods that return values will return values for all keys (within a - `dict` instance). - Note: - Ordering in tuples does not matter. Values in tuples are sorted before - being stored or queried. + `TypeParameter` removes types (or type pairs) not present in the + simulation state *after* its operation is added to the simulation and + the simulation has been run for 0 or more steps. - Below are some example indexing values for single and multiple key indexing. + The examples below use `hoomd.md.methods.Langevin` and `hoomd.md.pair.LJ` + to demonstrate. + .. skip: next if(not hoomd.version.md_built) .. code-block:: python - # "A", "B", "C" - ["A", "B", "C"] - # ("A", "B") - ("A", "B") - # ("A", "B") and ("B", "C") - [("A", "B"), ("B", "C")] - # ("A", "B"), ("A", "C"), and ("A", "D") - ("A", ["B", "C", "D"]) - - - .. rubric:: Defaults and setting values - - `TypeParameter` instances have default values that can be accessed via - ``default`` which will be used for all types not defined. In addition, when - the type parameter expects a `dict`-like object, the default will be updated - with the set value. This means that values that have defaults do not need to - be explicitly specified. - - An example of "smart"-setting using the MD LJ potential, - - .. code-block:: python - - lj = hoomd.md.pair.LJ(nlist=hoomd.md.nlist.Cell()) - # params is a TypeParameter object. - # We set epsilon to have a default but sigma is still required - lj.params.default = {"epsilon": 4} - print(lj.params.default) - # {"epsilon": 4.0, "sigma": hoomd.data.typeconverter.RequiredArg} - # We do not need to specify epsilon to use new default value when - # setting - lj.params[("A", "B")] = {"sigma": 1.0} - print(lj.params[("A", "B")]) - # {"epsilon": 4.0, "sigma": 1.0} - - Note: - Before calling `hoomd.Simulation.run` for the `TypeParameter` - instance's associated simulation, keys are not checked that their types - exist in the `hoomd.State` object. After calling ``run``, however, all - such data for non-existent types is removed, and querying or attempting - to set those keys will result in a ``KeyError``. + lj = hoomd.md.pair.LJ(nlist=hoomd.md.nlist.Cell(buffer=0.4)) + langevin = hoomd.md.methods.Langevin(filter=hoomd.filter.All(), kT=1.0) """ __slots__ = ("name", "type_kind", "param_dict") @@ -110,33 +63,94 @@ def __getattr__(self, attr): raise AttributeError("'{}' object has no attribute " "'{}'".format(type(self), attr)) - def __getitem__(self, key): - """Access parameters by key.""" - return self.param_dict[key] - def __setitem__(self, key, value): - """Set parameters by key.""" + """Set parameters for a given type (or type pair). + + .. rubric:: Examples + + Index types by name: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + langevin.gamma['A'] = 2.0 + + Set parameters for multiple types: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + langevin.gamma[['B', 'C']] = 3.0 + + Set type pair parameters with a tuple of names: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + lj.params[('A', 'A')] = dict(epsilon=1.5, sigma=2.0) + + Set parameters for multiple pairs (e.g. ('A', 'B') and ('A', 'C')): + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + lj.params[('A', ['B', 'C'])] = dict(epsilon=0, sigma=0) + + Set parameters for multiple pairs (e.g. ('B', 'B'), ('B', 'C'), ('C', + 'B'), and ('C', 'C')): + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + lj.params[(['B', 'C'], ['B', 'C'])] = dict(epsilon=1, sigma=1) + + Note: + + Setting the value for *(a,b)* automatically sets the symmetric + *(b,a)* parameter to the same value. + """ self.param_dict[key] = value + def __getitem__(self, key): + """Access parameters by key. + + .. rubric:: Examples: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + gamma_A = langevin.gamma['A'] + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + lj_epsilon_AB = lj.params[('A', 'B')]['epsilon'] + """ + return self.param_dict[key] + def __delitem__(self, key): """__delitem__ is not available for `TypeParameter` objects.""" raise NotImplementedError("__delitem__ is not defined for this type.") def get(self, key, default): - """Get values for keys with undefined keys returning default. + """Get the value of the key with undefined keys returning default. Args: key: Valid keys specifications (depends on the expected key length). - default (``any``, optional): + default: The value to default to if a key is not found in the mapping. - If not set, the value defaults to the mapping's default. Returns: - values: - Returns a dict of the values for the keys asked for if multiple - keys were specified; otherwise, returns the value for the single - key. + Returns the parameter value for the key when set. Otherwise, returns + the provided default. + + .. rubric:: Example: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + gamma_D = langevin.gamma.get('D', default=5.0) """ return self.param_dict.get(key, default) @@ -146,21 +160,56 @@ def setdefault(self, key, default): Args: key: Valid keys specifications (depends on the expected key length). - default (``any``): The value to default to if a key is not found in - the mapping. Must be compatible with the typing specification - specified on construction. + default: The value to set when the key is not found in + the mapping. + + .. rubric:: Example + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + langevin.gamma.setdefault('D', default=5.0) """ self.param_dict.setdefault(key, default) def __eq__(self, other): - """Test for equality.""" + """Test for equality. + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + langevin.gamma == lj.params + """ return self.name == other.name and \ self.type_kind == other.type_kind and \ self.param_dict == other.param_dict @property def default(self): - """The default value of the parameter.""" + """The default value of the parameter. + + `TypeParameter` uses the default value for any type (or type pair) in + the simulation state that is not explicitly set by `__setitem__` + or `setdefault`. + + .. rubric:: Examples + + Set a default value: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + langevin.gamma.default = 2.0 + + When the parameter is a dictionary, set defaults for zero or more + keys in that dictionary: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + lj.params.default = dict(epsilon=0) + lj.params.default = dict(epsilon=1, sigma=1) + """ return self.param_dict.default @default.setter @@ -177,15 +226,40 @@ def _detach(self): return self def to_base(self): - """Convert to a Python `dict`.""" + """Convert to a Python `dict`. + + .. rubric:: Example: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + plain_dict = lj.params.to_base() + """ return self.param_dict.to_base() def __iter__(self): - """Get the keys in the dictionaty.""" + """Iterate over the keys in the mapping. + + .. rubric:: Example: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + for type_pair in lj.params: + pass + """ yield from self.param_dict.keys() def __len__(self): - """Return mapping length.""" + """Get the number of type parameters in the mapping. + + .. rubric:: Example: + + .. skip: next if(not hoomd.version.md_built) + .. code-block:: python + + n_type_pairs = len(lj.params) + """ return len(self.param_dict) def __getstate__(self): diff --git a/hoomd/md/methods/methods.py b/hoomd/md/methods/methods.py index 2254502c62..13c71d40f1 100644 --- a/hoomd/md/methods/methods.py +++ b/hoomd/md/methods/methods.py @@ -104,7 +104,7 @@ class ConstantVolume(Thermostatted): See Also: `hoomd.md.methods.thermostats`. - .. rubric Examples + .. rubric:: Examples NVE integration: diff --git a/sphinx-doc/module-hoomd-data.rst b/sphinx-doc/module-hoomd-data.rst index cef19d0a88..ccd0084b82 100644 --- a/sphinx-doc/module-hoomd-data.rst +++ b/sphinx-doc/module-hoomd-data.rst @@ -41,7 +41,16 @@ hoomd.data :inherited-members: .. autoclass:: hoomd.data.typeparam.TypeParameter - :members: default + :members: __delitem__, + __eq__, + __getitem__, + __iter__, + __len__, + __setitem__, + default, + get, + setdefault, + to_base .. rubric:: Modules From 60f40b2706a255602a1445ac95157fbb54e199bc Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 12 Sep 2023 11:39:52 -0400 Subject: [PATCH 03/22] Revise Array documentation. Decided that no Sybil examples are needed here beyond those already provided. --- hoomd/data/array.py | 59 ++++++++++------------------- hoomd/data/local_access.py | 68 ++++++++++++++++++++-------------- hoomd/data/local_access_cpu.py | 4 ++ hoomd/data/local_access_gpu.py | 4 ++ 4 files changed, 69 insertions(+), 66 deletions(-) diff --git a/hoomd/data/array.py b/hoomd/data/array.py index b96d02d489..ade757b655 100644 --- a/hoomd/data/array.py +++ b/hoomd/data/array.py @@ -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 `_. 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 @@ -725,41 +716,31 @@ 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__ `_. 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 diff --git a/hoomd/data/local_access.py b/hoomd/data/local_access.py index 0e9180bb8a..f30625b42b 100644 --- a/hoomd/data/local_access.py +++ b/hoomd/data/local_access.py @@ -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. @@ -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 @@ -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. @@ -216,9 +223,6 @@ 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" @@ -226,6 +230,11 @@ class BondLocalAccessBase(_GroupLocalAccess): 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. @@ -238,9 +247,6 @@ 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" @@ -248,6 +254,11 @@ class AngleLocalAccessBase(_GroupLocalAccess): 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. @@ -260,9 +271,6 @@ 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" @@ -270,6 +278,11 @@ class DihedralLocalAccessBase(_GroupLocalAccess): 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. @@ -282,9 +295,6 @@ 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" @@ -292,6 +302,11 @@ class ImproperLocalAccessBase(_GroupLocalAccess): 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. @@ -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', @@ -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. @@ -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" diff --git a/hoomd/data/local_access_cpu.py b/hoomd/data/local_access_cpu.py index e09209fb10..e870b08a61 100644 --- a/hoomd/data/local_access_cpu.py +++ b/hoomd/data/local_access_cpu.py @@ -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): diff --git a/hoomd/data/local_access_gpu.py b/hoomd/data/local_access_gpu.py index 1c2c48f860..e3172a35ed 100644 --- a/hoomd/data/local_access_gpu.py +++ b/hoomd/data/local_access_gpu.py @@ -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 From 8a328ec038d60e65e17e532bf359a63749151a7f Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 12 Sep 2023 14:56:36 -0400 Subject: [PATCH 04/22] Add examples to filter/*.py. --- hoomd/filter/all_.py | 6 +++++ hoomd/filter/custom.py | 56 ++++++++++++++++++++++------------------- hoomd/filter/filter_.py | 43 ++++++++++++++++++++++++++++--- hoomd/filter/null.py | 6 +++++ hoomd/filter/rigid.py | 10 ++++++++ hoomd/filter/set_.py | 27 +++++++++++++++++++- hoomd/filter/tags.py | 6 +++++ hoomd/filter/type_.py | 6 +++++ 8 files changed, 129 insertions(+), 31 deletions(-) diff --git a/hoomd/filter/all_.py b/hoomd/filter/all_.py index da3f05035f..17d4a45b5d 100644 --- a/hoomd/filter/all_.py +++ b/hoomd/filter/all_.py @@ -11,6 +11,12 @@ class All(ParticleFilter, ParticleFilterAll): """Select all particles in the system. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + all_ = hoomd.filter.All() """ def __init__(self): diff --git a/hoomd/filter/custom.py b/hoomd/filter/custom.py index 7e4dc5114e..31a38831b8 100644 --- a/hoomd/filter/custom.py +++ b/hoomd/filter/custom.py @@ -1,18 +1,23 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Contains a class for custom particle filters in Python.""" +"""Contains a class for custom particle filters in Python. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() +""" from abc import abstractmethod from collections.abc import Hashable, Callable class CustomFilter(Hashable, Callable): - """Abstract base class for custom particle filters. + """Base class for custom particle filters. The class allows the definition of particle filters in Python (see `ParticleFilter`). - Subclasses of this class must have ``__hash__``, ``__eq__``, and + Subclasses of this class must implement ``__hash__``, ``__eq__``, and ``__call__`` methods. The ``__hash__`` and ``__eq__`` methods will be used to cache the particle tags associated with a filter, thus ``__eq__`` must correctly disambiguate any filters that would choose different particles. @@ -20,13 +25,11 @@ class CustomFilter(Hashable, Callable): ``_ and ``_. - The example below creates a custom filter that filters out particles above - and below a certain mass, and uses that filter in a `hoomd.write.GSD` - object. + .. rubric:: Example: - Example:: + .. code-block:: python - class MassFilter(hoomd.filter.CustomFilter): + class MassRangeFilter(hoomd.filter.CustomFilter): def __init__(self, min_mass, max_mass): self.min_mass = min_mass self.max_mass = max_mass @@ -35,7 +38,7 @@ def __hash__(self): return hash((self.min_mass, self.max_mass)) def __eq__(self, other): - return (isinstance(other, MassFilter) + return (isinstance(other, MassRangeFilter) and self.min_mass == other.min_mass and self.max_mass == other.max_mass) @@ -44,35 +47,36 @@ def __call__(self, state): masses = snap.particles.mass indices = ((masses > self.min_mass) & (masses < self.max_mass)) - return np.copy(snap.particles.tag[indices]) + return numpy.copy(snap.particles.tag[indices]) - # All particles with 1.0 < mass < 5.0 - filter_ = MassFilter(1.0, 5.0) - gsd = hoomd.write.GSD('example.gsd', 100, filter=filter_) + mass_range_filter = MassRangeFilter(1.0, 5.0) + print(mass_range_filter(simulation.state)) Warning: Custom filters will not work with the set operation particle filters (i.e. `hoomd.filter.Union`, `hoomd.filter.Intersection`, or - `hoomd.filter.SetDifference`). This restriction may be lifted in a - future version. + `hoomd.filter.SetDifference`). Implement any needed logic in your + `__call__` method. """ @abstractmethod def __call__(self, state): """Return the local particle tags that match the filter. - Returns the tags that are local to an MPI rank that match the particle - filter. Tag numbers in a `hoomd.Snapshot` object are just their index. + Returns the tags that match the particle filter. Tag numbers in a + `hoomd.Snapshot` object are equal to their index. Note: - The exact requirements for the tags returned by custom filters on - each MPI rank is that the set union of the returned arrays from each - MPI rank be all particles that match the filter. For general use, - however, it is recommended that each rank only return the tags for - particles that are in the local MPI rank (excluding ghost - particles). This is preferable for ease of use with local snapshots - to avoid accidentally attempting to access invalid array indices - from tags outside of the MPI rank. + In MPI domain decomposition simulation, the set union of the + returned arrays from each MPI rank must contain all particle tags + that match the filter. + + + Tip: + To obtain the best performance, use local snaphots to access + particle data, locally evaluate the filter on each rank, and return + the list of local tags that match. `__call__` should not perform the + set union, that is the caller's responsibility. Args: state (`hoomd.State`): @@ -80,7 +84,7 @@ def __call__(self, state): Returns: (N,) `numpy.ndarray` of `numpy.uint64`: - An array of MPI local tags that match the filter. + An array of particle tags filter. """ pass diff --git a/hoomd/filter/filter_.py b/hoomd/filter/filter_.py index 4a33891659..92efe886b3 100644 --- a/hoomd/filter/filter_.py +++ b/hoomd/filter/filter_.py @@ -1,7 +1,14 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Define ParticleFilter.""" +"""Define ParticleFilter. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + filter = hoomd.filter.All() + other = hoomd.filter.Tags([0]) +""" from hoomd import _hoomd @@ -17,16 +24,38 @@ class ParticleFilter(_hoomd.ParticleFilter): """ def __hash__(self): - """Return a hash of the filter parameters.""" + """Return a hash of the filter parameters. + + .. rubric:: Example: + + .. code-block:: python + + hash(filter) + """ return NotImplementedError("Must implement hash for ParticleFilters.") def __eq__(self, other): - """Test for equality between two particle filters.""" + """Test for equality between two particle filters. + + .. rubric:: Example: + + .. code-block:: python + + if filter == other: + pass + """ raise NotImplementedError("Equality between {} is not defined.".format( self.__class__)) def __str__(self): - """Format a human readable string describing the filter.""" + """Format a human readable string describing the filter. + + .. rubric:: Example: + + .. code-block:: python + + print(str(filter)) + """ return "ParticleFilter.{}".format(self.__class__.__name__) def __call__(self, state): @@ -39,5 +68,11 @@ def __call__(self, state): This method may return tags that are only present on the local MPI rank. The full set of particles selected is the combination of these the lists across ranks with a set union operation. + + .. rubric:: Example: + + .. code-block:: python + + locally_selected_tags = filter(simulation.state) """ return self._get_selected_tags(state._cpp_sys_def) diff --git a/hoomd/filter/null.py b/hoomd/filter/null.py index 13785d90b0..786cf8b0a0 100644 --- a/hoomd/filter/null.py +++ b/hoomd/filter/null.py @@ -11,6 +11,12 @@ class Null(ParticleFilter, ParticleFilterNull): """Select no particles. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + null = hoomd.filter.Null() """ def __init__(self): diff --git a/hoomd/filter/rigid.py b/hoomd/filter/rigid.py index 12719b0521..994896467f 100644 --- a/hoomd/filter/rigid.py +++ b/hoomd/filter/rigid.py @@ -21,6 +21,16 @@ class Rigid(ParticleFilter, ParticleFilterRigid): is ``("center",)`` Base: `ParticleFilter` + + .. rubric:: Examples: + + .. code-block:: python + + rigid_center_and_free = hoomd.filter.Rigid(flags=('center', 'free')) + + .. code-block:: python + + rigid_center = hoomd.filter.Rigid(flags=('center',)) """ def __init__(self, flags=("center",)): diff --git a/hoomd/filter/set_.py b/hoomd/filter/set_.py index ebdf0a8356..a252dd6a73 100644 --- a/hoomd/filter/set_.py +++ b/hoomd/filter/set_.py @@ -1,7 +1,14 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Define particle filter set operations.""" +"""Define particle filter set operations. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + filter1 = hoomd.filter.All() + filter2 = hoomd.filter.Tags([0]) +""" from hoomd.filter.filter_ import ParticleFilter from hoomd import _hoomd @@ -71,6 +78,12 @@ class SetDifference(_ParticleFilterSetOperations, difference :math:`f \setminus g`. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + set_difference = hoomd.filter.SetDifference(filter1, filter2) """ _cpp_cls_name = 'ParticleFilterSetDifference' _symmetric = False @@ -87,6 +100,12 @@ class Union(_ParticleFilterSetOperations, _hoomd.ParticleFilterUnion): union :math:`f \cup g`. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + union = hoomd.filter.Union(filter1, filter2) """ _cpp_cls_name = 'ParticleFilterUnion' _symmetric = True @@ -104,6 +123,12 @@ class Intersection(_ParticleFilterSetOperations, intersection :math:`f \cap g`. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + intersection = hoomd.filter.Intersection(filter1, filter2) """ _cpp_cls_name = 'ParticleFilterIntersection' _symmetric = True diff --git a/hoomd/filter/tags.py b/hoomd/filter/tags.py index 1f250b6a72..1ebbe8bd00 100644 --- a/hoomd/filter/tags.py +++ b/hoomd/filter/tags.py @@ -19,6 +19,12 @@ class Tags(ParticleFilter, ParticleFilterTags): 0 through `N_particles` to the particles in the order provided. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + tags = hoomd.filter.Tags([0, 1, 2]) """ def __init__(self, tags): diff --git a/hoomd/filter/type_.py b/hoomd/filter/type_.py index e7fc910608..68a3bd922f 100644 --- a/hoomd/filter/type_.py +++ b/hoomd/filter/type_.py @@ -14,6 +14,12 @@ class Type(ParticleFilter, ParticleFilterType): types (list[str]): List of particle type names to select. Base: `ParticleFilter` + + .. rubric:: Example: + + .. code-block:: python + + type_A_B = hoomd.filter.Type(['A', 'B']) """ def __init__(self, types): From 24d01f72d831ba6a23e48e25052ac55d4c20f039 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Fri, 15 Sep 2023 11:45:30 -0400 Subject: [PATCH 05/22] Add Sybil examples to Operation. --- hoomd/operation.py | 29 +++++++++++++++++++++++++++ sphinx-doc/module-hoomd-operation.rst | 1 + 2 files changed, 30 insertions(+) diff --git a/hoomd/operation.py b/hoomd/operation.py index e88e7e2458..f4d68d3775 100644 --- a/hoomd/operation.py +++ b/hoomd/operation.py @@ -11,6 +11,12 @@ `hoomd.Operations` `hoomd.Simulation` + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + simulation.operations.integrator = hoomd.md.Integrator(dt=0.001) + operation = simulation.operations.tuners[0] """ # Operation is a parent class of almost all other HOOMD objects. @@ -440,6 +446,16 @@ def kernel_parameters(self): Provided that you use the same HOOMD-blue binary on the same hardware and execute a script with the same parameters, you may save the tuned values from one run and load them in the next. + + .. rubric:: Examples: + + .. code-block:: python + + kernel_parameters = operation.kernel_parameters + + .. code-block:: python + + operation.kernel_parameters = kernel_parameters """ if not self._attached: raise hoomd.error.DataAccessError("kernel_parameters") @@ -457,6 +473,13 @@ def is_tuning_complete(self): ``True`` when tuning is complete and `kernel_parameters` has locked optimal parameters for all active kernels used by this object. + + .. rubric:: Example: + + .. code-block:: python + + while (not operation.is_tuning_complete): + simulation.run(1000) """ if not self._attached: raise hoomd.error.DataAccessError("is_tuning_complete") @@ -469,6 +492,12 @@ def tune_kernel_parameters(self): kernel parameters in subsequent time steps, check the run time of each, and lock to the fastest performing parameters after the scan is complete. + + .. rubric:: Example: + + .. code-block:: python + + operation.tune_kernel_parameters() """ if not self._attached: raise RuntimeError("Call Simulation.run() before " diff --git a/sphinx-doc/module-hoomd-operation.rst b/sphinx-doc/module-hoomd-operation.rst index e090a95bc2..3424ea00bb 100644 --- a/sphinx-doc/module-hoomd-operation.rst +++ b/sphinx-doc/module-hoomd-operation.rst @@ -29,3 +29,4 @@ hoomd.operation .. autoclass:: Operation :inherited-members: + :show-inheritance: From 80945dc2b9b8b2fc1a65a7e7bea716533695281e Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Fri, 15 Sep 2023 12:52:55 -0400 Subject: [PATCH 06/22] Add CustomTuner Sybil example. --- hoomd/custom/custom_action.py | 7 ------- hoomd/tune/__init__.py | 4 ++-- hoomd/tune/custom_tuner.py | 21 ++++++++++++++++++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/hoomd/custom/custom_action.py b/hoomd/custom/custom_action.py index 09291070a8..334c427de7 100644 --- a/hoomd/custom/custom_action.py +++ b/hoomd/custom/custom_action.py @@ -42,13 +42,6 @@ def act(self, timestep): if snapshot.communicator.rank == 0: self.com = snapshot.particles.position.mean(axis=0) - example_action = ExampleAction() - custom_updater = hoomd.update.CustomUpdater( - trigger=hoomd.trigger.Periodic(1000), - action=example_action) - simulation.operations.updaters.append(custom_updater) - simulation.run(2000) - 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: diff --git a/hoomd/tune/__init__.py b/hoomd/tune/__init__.py index bfdd499734..3f1399fd75 100644 --- a/hoomd/tune/__init__.py +++ b/hoomd/tune/__init__.py @@ -12,10 +12,10 @@ This package also defines the `CustomTuner` class and a number of helper classes. Use these to implement custom tuner operations in Python code. -..rubric:: Solver +.. rubric:: Solver Most tuners explicitly involve solving some sort of mathematical problem (e.g. -root-finding or optimizationr). HOOMD provides infrastructure for solving these +root-finding or optimization). HOOMD provides infrastructure for solving these problems as they appear in our provided `hoomd.operation.Tuner` subclasses. All tuners that involve iteratively solving a problem compose a `SolverStep` subclass instance. The `SolverStep` class implements the boilerplate to do diff --git a/hoomd/tune/custom_tuner.py b/hoomd/tune/custom_tuner.py index 443110739e..97e06a7f98 100644 --- a/hoomd/tune/custom_tuner.py +++ b/hoomd/tune/custom_tuner.py @@ -1,7 +1,17 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement CustomTuner.""" +"""Implement CustomTuner. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + class ExampleAction(hoomd.custom.Action): + def act(self, timestep): + pass + + custom_action = ExampleAction() +""" from hoomd.custom import (CustomOperation, _InternalCustomOperation, Action) from hoomd.operation import Tuner @@ -37,6 +47,15 @@ class CustomTuner(CustomOperation, _TunerProperty, Tuner): Tuners modify the parameters of other operations to improve performance. Tuners may read the system state, but not modify it. + .. rubric:: Example: + + .. code-block:: python + + custom_tuner = hoomd.tune.CustomTuner( + action=custom_action, + trigger=hoomd.trigger.Periodic(1000)) + simulation.operations.tuners.append(custom_tuner) + See Also: The base class `hoomd.custom.CustomOperation`. From fe4fa85417e7cb66f1170f0824d6ec8857f78de5 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Mon, 25 Sep 2023 15:17:22 -0400 Subject: [PATCH 07/22] Add examples to updaters. Also make examples more consistent across the base hoomd namespace. --- hoomd/data/array.py | 5 +- hoomd/data/typeparam.py | 7 +-- hoomd/logging.py | 2 +- hoomd/md/methods/methods.py | 2 +- hoomd/operation.py | 9 ++++ hoomd/update/box_resize.py | 91 ++++++++++++++++++++++++++++----- hoomd/update/custom_updater.py | 21 +++++++- hoomd/update/particle_filter.py | 38 ++++++++++---- hoomd/update/remove_drift.py | 22 +++++++- hoomd/write/hdf5.py | 6 +-- 10 files changed, 164 insertions(+), 39 deletions(-) diff --git a/hoomd/data/array.py b/hoomd/data/array.py index ade757b655..0cc395e96b 100644 --- a/hoomd/data/array.py +++ b/hoomd/data/array.py @@ -732,8 +732,9 @@ class HOOMDGPUArray(_NoGPU): pos[:, 2] += 1 Note: - When CuPy can be imported, then this class wraps much of the ``cupy.ndarray`` - class's functionality. Otherwise, this class exposes only the buffer. + 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 diff --git a/hoomd/data/typeparam.py b/hoomd/data/typeparam.py index 372873e5e2..cc86735a3c 100644 --- a/hoomd/data/typeparam.py +++ b/hoomd/data/typeparam.py @@ -27,12 +27,10 @@ class TypeParameter(MutableMapping): and multiple parameters on one line. Important: - Parameters for all types (or unordered pairs of types) in the simulation state must be defined prior to calling `Simulation.run()`. Note: - `TypeParameter` removes types (or type pairs) not present in the simulation state *after* its operation is added to the simulation and the simulation has been run for 0 or more steps. @@ -66,7 +64,7 @@ def __getattr__(self, attr): def __setitem__(self, key, value): """Set parameters for a given type (or type pair). - .. rubric:: Examples + .. rubric:: Examples: Index types by name: @@ -105,7 +103,6 @@ def __setitem__(self, key, value): lj.params[(['B', 'C'], ['B', 'C'])] = dict(epsilon=1, sigma=1) Note: - Setting the value for *(a,b)* automatically sets the symmetric *(b,a)* parameter to the same value. """ @@ -192,7 +189,7 @@ def default(self): the simulation state that is not explicitly set by `__setitem__` or `setdefault`. - .. rubric:: Examples + .. rubric:: Examples: Set a default value: diff --git a/hoomd/logging.py b/hoomd/logging.py index 418cab3631..68390bd515 100644 --- a/hoomd/logging.py +++ b/hoomd/logging.py @@ -639,7 +639,7 @@ class they come from. For instance, the `hoomd.md.pair.LJ` class has a are typically measures of operation performance rather than information about simulation state. - .. rubric:: Examples + .. rubric:: Examples: There are various ways to create a logger with different available loggables. Create a `Logger` with no options to allow all categories. diff --git a/hoomd/md/methods/methods.py b/hoomd/md/methods/methods.py index 13c71d40f1..f43527923e 100644 --- a/hoomd/md/methods/methods.py +++ b/hoomd/md/methods/methods.py @@ -104,7 +104,7 @@ class ConstantVolume(Thermostatted): See Also: `hoomd.md.methods.thermostats`. - .. rubric:: Examples + .. rubric:: Examples: NVE integration: diff --git a/hoomd/operation.py b/hoomd/operation.py index f4d68d3775..7e80e57246 100644 --- a/hoomd/operation.py +++ b/hoomd/operation.py @@ -534,6 +534,15 @@ class TriggeredOperation(Operation): Warning: This class should not be instantiated by users. The class can be used for `isinstance` or `issubclass` checks. + + Attributes: + trigger (hoomd.trigger.Trigger): The trigger to activate this operation. + + .. rubric:: Example + + .. code-block:: python + + operation.trigger = hoomd.trigger.Periodic(10) """ def __init__(self, trigger): diff --git a/hoomd/update/box_resize.py b/hoomd/update/box_resize.py index 8a48d8bdac..8222f5407a 100644 --- a/hoomd/update/box_resize.py +++ b/hoomd/update/box_resize.py @@ -1,7 +1,16 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement BoxResize.""" +"""Implement BoxResize. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + initial_box = simulation.state.box + box = initial_box + final_box = hoomd.Box.from_box(initial_box) + final_box.volume = final_box.volume * 2 +""" import hoomd from hoomd.operation import Updater @@ -16,6 +25,18 @@ class BoxResize(Updater): """Resizes the box between an initial and final box. + Args: + trigger (hoomd.trigger.trigger_like): The trigger to activate this + updater. + box1 (hoomd.box.box_like): The box associated with the minimum of the + passed variant. + box2 (hoomd.box.box_like): The box associated with the maximum of the + passed variant. + variant (hoomd.variant.variant_like): A variant used to interpolate + between the two boxes. + filter (hoomd.filter.filter_like): The subset of particle positions + to update (defaults to `hoomd.filter.All`). + `BoxResize` resizes the box between gradually from the initial box to the final box. The simulation box follows the linear interpolation between the initial and final boxes where the minimum of the variant gives `box1` and @@ -79,28 +100,57 @@ class BoxResize(Updater): deformed. `hoomd.md.Integrator` will run after the last updater and resets the constituent particle positions before computing forces. - Args: - trigger (hoomd.trigger.trigger_like): The trigger to activate this - updater. - box1 (hoomd.box.box_like): The box associated with the minimum of the - passed variant. - box2 (hoomd.box.box_like): The box associated with the maximum of the - passed variant. - variant (hoomd.variant.variant_like): A variant used to interpolate - between the two boxes. - filter (hoomd.filter.filter_like): The subset of particle positions - to update. + .. rubric:: Example: + + .. code-block:: python + + box_resize = hoomd.update.BoxResize(trigger=hoomd.trigger.Periodic(10), + box1=initial_box, + box2=final_box, + variant=hoomd.variant.Ramp( + A=0, + B=1, + t_start=simulation.timestep, + t_ramp=20000)) + simulation.operations.updaters.append(box_resize) Attributes: box1 (hoomd.Box): The box associated with the minimum of the passed variant. + + .. rubric:: Example: + + .. code-block:: python + + box_resize.box1 = initial_box + box2 (hoomd.Box): The box associated with the maximum of the passed variant. + + .. rubric:: Example: + + .. code-block:: python + + box_resize.box2 = final_box + variant (hoomd.variant.Variant): A variant used to interpolate between the two boxes. - trigger (hoomd.trigger.Trigger): The trigger to activate this updater. + + .. rubric:: Example: + + .. code-block:: python + + box_resize.variant = hoomd.variant.Ramp( + A=0, B=1, t_start=simulation.timestep, t_ramp=20000) + filter (hoomd.filter.filter_like): The subset of particles to update. + + .. rubric:: Example: + + .. code-block:: python + + filter = box_resize.filter """ def __init__(self, trigger, box1, box2, variant, filter=All()): @@ -137,6 +187,12 @@ def get_box(self, timestep): Returns: Box: The box used at the given timestep. `None` before the first call to `Simulation.run`. + + .. rubric:: Example: + + .. code-block:: python + + box = box_resize.get_box(1_000_000) """ if self._attached: timestep = int(timestep) @@ -154,7 +210,14 @@ def update(state, box, filter=All()): state (State): System state to scale. box (hoomd.box.box_like): New box. filter (hoomd.filter.filter_like): The subset of particles to - update. + update (defaults to `hoomd.filter.All`). + + .. rubric:: Example: + + .. code-block:: python + + hoomd.update.BoxResize.update(state=simulation.state, + box=box) """ group = state._get_group(filter) diff --git a/hoomd/update/custom_updater.py b/hoomd/update/custom_updater.py index 247f33d89e..17f97a4f55 100644 --- a/hoomd/update/custom_updater.py +++ b/hoomd/update/custom_updater.py @@ -1,7 +1,17 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement CustomUpdater.""" +"""Implement CustomUpdater. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + class ExampleAction(hoomd.custom.Action): + def act(self, timestep): + pass + + custom_action = ExampleAction() +""" from hoomd.custom import (CustomOperation, _InternalCustomOperation, Action) from hoomd.operation import Updater @@ -36,6 +46,15 @@ class CustomUpdater(CustomOperation, _UpdaterProperty, Updater): Updaters modify the system state. + .. rubric:: Example: + + .. code-block:: python + + custom_updater = hoomd.update.CustomUpdater( + action=custom_action, + trigger=hoomd.trigger.Periodic(1000)) + simulation.operations.updaters.append(custom_updater) + See Also: The base class `hoomd.custom.CustomOperation`. diff --git a/hoomd/update/particle_filter.py b/hoomd/update/particle_filter.py index 335da35958..184541fe82 100644 --- a/hoomd/update/particle_filter.py +++ b/hoomd/update/particle_filter.py @@ -1,7 +1,14 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement Python interface for a ParticleFilter updater.""" +"""Implement Python interface for a ParticleFilter updater. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + filter1 = hoomd.filter.All() + filter2 = hoomd.filter.All() +""" import copy @@ -36,6 +43,12 @@ def __getstate__(self): class FilterUpdater(hoomd.operation.Updater): """Update sets of particles associated with a filter. + Args: + trigger (hoomd.trigger.trigger_like): A trigger to use for determining + when to update particles associated with a filter. + filters (list[hoomd.filter.filter_like]): A list of + `hoomd.filter.filter_like` objects to update. + `hoomd.Simulation` caches the particles selected by `hoomd.filter.filter_like` objects to avoid the cost of re-running the filter on every time step. The particles selected by a filter will remain @@ -53,15 +66,13 @@ class FilterUpdater(hoomd.operation.Updater): Some actions automatically recompute all filter particles such as adding or removing particles to the `hoomd.Simulation.state`. - Args: - trigger (hoomd.trigger.trigger_like): A trigger to use for determining - when to update particles associated with a filter. - filters (list[hoomd.filter.filter_like]): A list of - `hoomd.filter.filter_like` objects to update. + .. rubric:: Example: - Attributes: - trigger (hoomd.trigger.Trigger): - The trigger associated with the updater. + .. code-block:: python + + filter_updater = hoomd.update.FilterUpdater( + trigger=hoomd.trigger.Periodic(1_000), + filters=[filter1, filter2]) """ def __init__(self, trigger, filters): @@ -75,7 +86,14 @@ def __init__(self, trigger, filters): @property def filters(self): """list[hoomd.filter.filter_like]: filters to update select \ - particles.""" + particles. + + .. rubric:: Example: + + .. code-block:: python + + filter_updater.filters = [filter1, filter2] + """ return self._filters @filters.setter diff --git a/hoomd/update/remove_drift.py b/hoomd/update/remove_drift.py index 9183db801b..b77f7dce5d 100644 --- a/hoomd/update/remove_drift.py +++ b/hoomd/update/remove_drift.py @@ -1,7 +1,12 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement RemoveDrift.""" +"""Implement RemoveDrift. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() +""" import hoomd from hoomd.operation import Updater @@ -40,10 +45,23 @@ class RemoveDrift(Updater): Use `RemoveDrift` with `hoomd.hpmc.external.field.Harmonic` to improve the accuracy of Frenkel-Ladd calculations. + .. rubric:: Example: + + .. code-block:: python + + remove_drift = hoomd.update.RemoveDrift( + reference_positions=[(0,0,0), (1,0,0)]) + simulation.operations.updaters.append(remove_drift) + Attributes: reference_positions ((*N_particles*, 3) `numpy.ndarray` of `float`): the reference positions :math:`[\mathrm{length}]`. - trigger (hoomd.trigger.Trigger): The timesteps to remove drift. + + .. rubric:: Example: + + .. code-block:: python + + remove_drift.reference_positions = [(0,0,0), (1,0,0)] """ def __init__(self, reference_positions, trigger=1): diff --git a/hoomd/write/hdf5.py b/hoomd/write/hdf5.py index 01015a437a..7eefdfdb31 100644 --- a/hoomd/write/hdf5.py +++ b/hoomd/write/hdf5.py @@ -165,7 +165,7 @@ def flush(self): Without calling this, data may be stored in the h5py.File object without being written to disk yet. - .. rubric:: Examples + .. rubric:: Examples: Flush one writer: @@ -277,7 +277,7 @@ class HDF5Log(_InternalCustomWriter): .. _h5py: https://docs.h5py.org/en/stable/high/file.html#opening-creating-files - .. rubric:: Example + .. rubric:: Example: .. code-block:: python @@ -314,7 +314,7 @@ def write(self, timestep=None): pressure tensor, rotational kinetic energy, or external field virial. - .. rubric:: Example + .. rubric:: Example: .. code-block:: python From 7dde40a48f497fe74c02467143ac01b97bd2c4de Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Mon, 25 Sep 2023 15:33:58 -0400 Subject: [PATCH 08/22] Sybil example in CustomWriter. --- hoomd/util.py | 6 ++++++ hoomd/write/custom_writer.py | 21 ++++++++++++++++++++- sphinx-doc/module-hoomd-write.rst | 10 +++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/hoomd/util.py b/hoomd/util.py index c0cc0d670b..a2439dc0eb 100644 --- a/hoomd/util.py +++ b/hoomd/util.py @@ -286,6 +286,12 @@ def make_example_simulation(device=None, dimensions=3, particle_types=['A']): `make_example_simulation` is intended for use in the documentation and other minimal working examples. Use `hoomd.Simulation` directly in other cases. + + .. rubric:: Example: + + .. code-block:: python + + simulation = hoomd.util.make_example_simulation() """ if device is None: device = hoomd.device.CPU() diff --git a/hoomd/write/custom_writer.py b/hoomd/write/custom_writer.py index 66c2daaba9..377b27fb54 100644 --- a/hoomd/write/custom_writer.py +++ b/hoomd/write/custom_writer.py @@ -1,7 +1,17 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement CustomWriter.""" +"""Implement CustomWriter. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + class ExampleAction(hoomd.custom.Action): + def act(self, timestep): + pass + + custom_action = ExampleAction() +""" from hoomd.custom import (CustomOperation, _InternalCustomOperation, Action) from hoomd.operation import Writer @@ -37,6 +47,15 @@ class CustomWriter(CustomOperation, _WriterProperty, Writer): Writers may read the system state and generate output files or print to output streams. Writers should not modify the system state. + .. rubric:: Example: + + .. code-block:: python + + custom_writer = hoomd.write.CustomWriter( + action=custom_action, + trigger=hoomd.trigger.Periodic(1000)) + simulation.operations.writers.append(custom_writer) + See Also: The base class `hoomd.custom.CustomOperation`. diff --git a/sphinx-doc/module-hoomd-write.rst b/sphinx-doc/module-hoomd-write.rst index 919c1980ba..d9545d9ae7 100644 --- a/sphinx-doc/module-hoomd-write.rst +++ b/sphinx-doc/module-hoomd-write.rst @@ -22,11 +22,11 @@ hoomd.write .. automodule:: hoomd.write :synopsis: Write data out. - :members: Burst, DCD, CustomWriter, GSD + :members: Burst, CustomWriter, DCD, GSD, HDF5Log, Table :show-inheritance: - .. autoclass:: HDF5Log(trigger, filename, logger, mode="a") - :members: + .. .. autoclass:: HDF5Log(trigger, filename, logger, mode="a") + .. :members: - .. autoclass:: Table(trigger, logger, output=stdout, header_sep='.', delimiter=' ', pretty=True, max_precision=10, max_header_len=None) - :members: + .. .. autoclass:: Table(trigger, logger, output=stdout, header_sep='.', delimiter=' ', pretty=True, max_precision=10, max_header_len=None) + .. :members: From cdf84648220dd2ff661e6b955fa6a4bae12d159f Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 07:30:27 -0400 Subject: [PATCH 09/22] Sybil examples in write.Table. --- hoomd/write/table.py | 151 ++++++++++++++++++++---------- sphinx-doc/module-hoomd-write.rst | 28 ++++-- 2 files changed, 124 insertions(+), 55 deletions(-) diff --git a/hoomd/write/table.py b/hoomd/write/table.py index f924925e94..eaa7868e76 100644 --- a/hoomd/write/table.py +++ b/hoomd/write/table.py @@ -1,7 +1,12 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement Table.""" +"""Implement Table. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() +""" from abc import ABCMeta, abstractmethod import copy @@ -338,23 +343,11 @@ def __setstate__(self, state): class Table(_InternalCustomWriter): """Write delimiter separated values to a stream. - Use `Table` to write scalar and string `hoomd.logging.Logger` quantities to - standard out or to a file. - - Warning: - When logger quantities include strings with spaces, the default space - delimiter will result in files that are not machine readable. - - Important: - All attributes for this class are static. They cannot be set to new - values once created. - Args: trigger (hoomd.trigger.trigger_like): The trigger to determine when to run the Table backend. - logger (hoomd.logging.Logger): The logger to query for output. The - 'scalar' categories must be set on the logger, and the 'string' - categories is optional. + logger (hoomd.logging.Logger): The logger to query for output. `Table` + supports only ``'scalar'`` and ``'string'`` logger categories. output (``file-like`` object , optional): A file-like object to output the data from, defaults to standard out. The object must have ``write`` and ``flush`` methods and a ``mode`` attribute. Examples @@ -363,59 +356,113 @@ class Table(_InternalCustomWriter): header_sep (`str`, optional): String to use to separate names in the logger's namespace, defaults to ``'.'``. For example, if logging the total energy of an `hoomd.md.pair.LJ` pair force object, the - default header would be ``md.pair.LJ.energy`` (assuming that - ``max_header_len`` is not set). + default header would be ``md.pair.LJ.energy``. delimiter (`str`, optional): String used to separate elements in the space delimited file, defaults to ``' '``. pretty (`bool`, optional): Flags whether to attempt to make output - prettier and easier to read, defaults to True. To make the output - easier to read, the output will compromise on numerical precision - for improved readability. In many cases, the precision will - still be high with pretty set to ``True``. + prettier and easier to read (defaults to `True`). max_precision (`int`, optional): If pretty is not set, then this controls the maximum precision to use when outputing numerical values, defaults to 10. - max_header_len (`int`, optional): If not None (the default), limit + max_header_len (`int`, optional): If not `None` (the default), limit the outputted header names to length ``max_header_len``. When not - None, names are grabbed from the most specific to the least. For + `None`, names are grabbed from the most specific to the least. For example, if set to 7 the namespace 'hoomd.md.pair.LJ.energy' would - be set to 'energy'. Note that at least the most specific part of the - namespace will be used regardless of this setting (e.g. if set to 5 - in the previous example, 'energy' would still be the header). + be set to 'energy'. + + Note: + At a minimum, the complete most specific part of the namespace + will be used regardless of this setting. + + Use `Table` to write scalar and string `hoomd.logging.Logger` quantities to + standard out or to a file. + + Warning: + When logger quantities include strings with spaces, the default space + delimiter will result in files that are not machine readable. + + .. rubric:: Example: + + .. code-block:: python + + logger = hoomd.logging.Logger(categories=['scalar', 'string']) + table = hoomd.write.Table(trigger=hoomd.trigger.Periodic(10_000), + logger=logger) Attributes: - trigger (hoomd.trigger.Trigger): The trigger to determine when to run - the Table backend. - logger (hoomd.logging.Logger): The logger to query for output. The - 'scalar' categories must be set on the logger, and the 'string' - categories is optional. + logger (hoomd.logging.Logger): The logger to query for output. `Table` + supports only ``'scalar'`` and ``'string'`` logger categories + (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + logger = table.logger + output (``file-like`` object): A file-like object to output the data from. The object must have ``write`` and ``flush`` methods - and a ``mode`` attribute. + and a ``mode`` attribute (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + output = table.output + header_sep (str): String to use to separate names in - the logger's namespace.'. For example, if logging the total energy - of an `hoomd.md.pair.LJ` pair force object, the default header would - be ``md.pair.LJ.energy`` (assuming that ``max_header_len`` is not - set). + the logger's namespace (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + header_sep = table.header_sep + delimiter (str): String used to separate elements in the space - delimited file. + delimited file (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + delimiter = table.delimiter + pretty (bool): Flags whether to attempt to make output - prettier and easier to read. To make the output easier to read, the - output will compromise on outputted precision for improved - readability. In many cases, though the precision will still be high - with pretty set to ``True``. + prettier and easier to read (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + pretty = table.pretty + max_precision (`int`, optional): If pretty is not set, then this controls the maximum precision to use when outputing numerical - values, defaults to 10. + values (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + max_precision = table.max_precision + max_header_len (int): Limits the outputted header names to length - ``max_header_len`` when not ``None``. Names are grabbed from the - most specific to the least. For example, if set to 7 the namespace - 'hoomd.md.pair.LJ.energy' would be set to 'energy'. Note that at - least the most specific part of the namespace will be used - regardless of this setting (e.g. if set to 5 in the previous - example, 'energy' would still be the header). - min_column_width (int): The minimum allowed column width. + ``max_header_len`` when not ``None`` (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + max_header_len = table.max_header_len + min_column_width (int): The minimum allowed column width (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + min_column_width = table.min_column_width """ _internal_class = _TableInternal @@ -423,5 +470,11 @@ def write(self): """Write out data to ``self.output``. Writes a row from given ``hoomd.logging.Logger`` object data. + + .. rubric:: Example: + + .. code-block:: python + + table.write() """ self._action.act() diff --git a/sphinx-doc/module-hoomd-write.rst b/sphinx-doc/module-hoomd-write.rst index d9545d9ae7..6e401bbd01 100644 --- a/sphinx-doc/module-hoomd-write.rst +++ b/sphinx-doc/module-hoomd-write.rst @@ -22,11 +22,27 @@ hoomd.write .. automodule:: hoomd.write :synopsis: Write data out. - :members: Burst, CustomWriter, DCD, GSD, HDF5Log, Table - :show-inheritance: - .. .. autoclass:: HDF5Log(trigger, filename, logger, mode="a") - .. :members: + .. autoclass:: Burst + :show-inheritance: + :members: - .. .. autoclass:: Table(trigger, logger, output=stdout, header_sep='.', delimiter=' ', pretty=True, max_precision=10, max_header_len=None) - .. :members: + .. autoclass:: CustomWriter + :show-inheritance: + :members: + + .. autoclass:: DCD + :show-inheritance: + :members: + + .. autoclass:: GSD + :show-inheritance: + :members: + + .. autoclass:: HDF5Log(trigger, filename, logger, mode="a") + :show-inheritance: + :members: + + .. autoclass:: Table(trigger, logger, output=stdout, header_sep='.', delimiter=' ', pretty=True, max_precision=10, max_header_len=None) + :show-inheritance: + :members: From 5bbba52207df26bc18db5c30a5f29c89cc170c58 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 07:42:45 -0400 Subject: [PATCH 10/22] Sybil examples in HDF5Log. --- hoomd/write/hdf5.py | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/hoomd/write/hdf5.py b/hoomd/write/hdf5.py index 7eefdfdb31..b5b9acb597 100644 --- a/hoomd/write/hdf5.py +++ b/hoomd/write/hdf5.py @@ -162,9 +162,6 @@ def act(self, timestep): def flush(self): """Write out all data currently buffered in memory. - Without calling this, data may be stored in the h5py.File object without - being written to disk yet. - .. rubric:: Examples: Flush one writer: @@ -283,23 +280,48 @@ class HDF5Log(_InternalCustomWriter): logger = hoomd.logging.Logger( hoomd.write.HDF5Log.accepted_categories) - hdf5_writer = hoomd.write.HDF5Log( + hdf5_log = hoomd.write.HDF5Log( trigger=hoomd.trigger.Periodic(10_000), filename=hdf5_filename, logger=logger) - simulation.operations += hdf5_writer + simulation.operations.writers.append(hdf5_log) Attributes: - cls.accepted_categories (hoomd.logging.LoggerCategories): The enum value + accepted_categories (hoomd.logging.LoggerCategories): The enum value for all accepted categories for `HDF5Log` instances which is all categories other than "string", "strings", and "object" (see `hoomd.logging.LoggerCategories`). - trigger (hoomd.trigger.trigger_like): The trigger to determine when to - run the HDF5 backend. - filename (str): The filename of the HDF5 file written to. + + .. rubric:: Example: + + .. code-block:: python + + accepted_categories = hoomd.write.HDF5Log.accepted_categories + + filename (str): The filename of the HDF5 file written to (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + filename = hdf5_log.filename + logger (hoomd.logging.Logger): The logger instance used for querying - log data. - mode (str): The mode the file was opened in. + log data (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + logger = hdf5_log.logger + + mode (str): The mode the file was opened in (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + mode = hdf5_log.mode """ _internal_class = _HDF5LogInternal _wrap_methods = ("flush",) From b4723dfcbc87d0cb50afae49efe34ee4284d7ab3 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 07:56:18 -0400 Subject: [PATCH 11/22] Sybil examples for DCD. --- hoomd/write/dcd.py | 73 ++++++++++++++++++++++++++----- sphinx-doc/module-hoomd-write.rst | 2 +- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/hoomd/write/dcd.py b/hoomd/write/dcd.py index 52911e2701..c36bda0f22 100644 --- a/hoomd/write/dcd.py +++ b/hoomd/write/dcd.py @@ -1,7 +1,12 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement DCD.""" +"""Implement DCD. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() +""" from hoomd import _hoomd from hoomd.filter import ParticleFilter, All @@ -39,12 +44,6 @@ class DCD(Writer): length units, and is limited to simulations where the number of particles is fixed. - Examples:: - - writer = hoomd.write.DCD("trajectory.dcd", hoomd.trigger.Periodic(1000)) - dcd = hoomd.write.DCD(filename="data/dump.dcd", - trigger=hoomd.trigger.Periodic(100, 10)) - Warning: When you use `DCD` to append to an existing DCD file: @@ -53,15 +52,52 @@ class DCD(Writer): * `DCD` will not write out data at time steps that already are present in the DCD file. + .. rubric:: Example: + + .. code-block:: python + + dcd = hoomd.write.DCD(trigger=hoomd.trigger.Periodic(1000), + filename="trajectory.dcd") + simulation.operations.writers.append(dcd) + Attributes: - filename (str): File name to write. - trigger (hoomd.trigger.Periodic): Select the timesteps to write. - filter (hoomd.filter.filter_like): Select the particles to write. + filename (str): File name to write (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + filename = dcd.filename + + filter (hoomd.filter.filter_like): Select the particles to write + (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + filter = dcd.filter + overwrite (bool): When False, an existing DCD file will be appended to. - When True, an existing DCD file *filename* will be overwritten. + When True, an existing DCD file *filename* will be overwritten + (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + overwrite = dcd.overwrite + unwrap_full (bool): When False, particle coordinates are always written inside the simulation box. When True, particles will be unwrapped into their current box image before writing to the DCD file. + + .. rubric:: Example: + + .. code-block:: python + + dcd.unwrap_full = True + unwrap_rigid (bool): When False, individual particles are written inside the simulation box which breaks up rigid bodies near box boundaries. When True, particles belonging to the same rigid body will be @@ -69,8 +105,21 @@ class DCD(Writer): body remains in the simulation box, but some particles may be written just outside it. *unwrap_rigid* is ignored when *unwrap_full* is True. + + .. rubric:: Example: + + .. code-block:: python + + dcd.unwrap_rigid = True + angle_z (bool): When True, the particle orientation angle is written to - the z component + the z component. + + .. rubric:: Example: + + .. code-block:: python + + dcd.angle_z = True """ def __init__(self, diff --git a/sphinx-doc/module-hoomd-write.rst b/sphinx-doc/module-hoomd-write.rst index 6e401bbd01..3b30c95037 100644 --- a/sphinx-doc/module-hoomd-write.rst +++ b/sphinx-doc/module-hoomd-write.rst @@ -31,7 +31,7 @@ hoomd.write :show-inheritance: :members: - .. autoclass:: DCD + .. autoclass:: DCD(trigger, filename, filter=hoomd.filter.All(), overwrite=False, unwrap_full=False, unwrap_rigid=False, angle_z=False) :show-inheritance: :members: From c881343a238934171330918c458d537c1124ca9f Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 09:22:19 -0400 Subject: [PATCH 12/22] GSD Sybil examples and consistency updates. --- hoomd/update/box_resize.py | 2 +- hoomd/write/dcd.py | 7 +-- hoomd/write/gsd.py | 82 ++++++++++++++++++++++++++++--- sphinx-doc/module-hoomd-write.rst | 2 +- 4 files changed, 82 insertions(+), 11 deletions(-) diff --git a/hoomd/update/box_resize.py b/hoomd/update/box_resize.py index 8222f5407a..d3cc1c2e42 100644 --- a/hoomd/update/box_resize.py +++ b/hoomd/update/box_resize.py @@ -150,7 +150,7 @@ class BoxResize(Updater): .. code-block:: python - filter = box_resize.filter + filter_ = box_resize.filter """ def __init__(self, trigger, box1, box2, variant, filter=All()): diff --git a/hoomd/write/dcd.py b/hoomd/write/dcd.py index c36bda0f22..2f8a0ab7fc 100644 --- a/hoomd/write/dcd.py +++ b/hoomd/write/dcd.py @@ -6,6 +6,7 @@ .. invisible-code-block: python simulation = hoomd.util.make_example_simulation() + dcd_filename = tmp_path / 'trajectory.dcd' """ from hoomd import _hoomd @@ -56,8 +57,8 @@ class DCD(Writer): .. code-block:: python - dcd = hoomd.write.DCD(trigger=hoomd.trigger.Periodic(1000), - filename="trajectory.dcd") + dcd = hoomd.write.DCD(trigger=hoomd.trigger.Periodic(1_000_000), + filename=dcd_filename) simulation.operations.writers.append(dcd) Attributes: @@ -76,7 +77,7 @@ class DCD(Writer): .. code-block:: python - filter = dcd.filter + filter_ = dcd.filter overwrite (bool): When False, an existing DCD file will be appended to. When True, an existing DCD file *filename* will be overwritten diff --git a/hoomd/write/gsd.py b/hoomd/write/gsd.py index 9633b25573..b8c8a25689 100644 --- a/hoomd/write/gsd.py +++ b/hoomd/write/gsd.py @@ -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. -"""Write GSD files storing simulation trajectories and logging data.""" +"""Write GSD files storing simulation trajectories and logging data. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + gsd_filename = tmp_path / 'trajectory.gsd' +""" from collections.abc import Mapping, Collection from hoomd.trigger import Periodic @@ -165,20 +171,84 @@ class GSD(Writer): `logger` to `None` or remove specific quantities from the logger, but do not add additional quantities after the first frame. + .. rubric:: Example: + + .. code-block:: python + + gsd = hoomd.write.GSD(trigger=hoomd.trigger.Periodic(1_000_000), + filename=gsd_filename) + simulation.operations.writers.append(gsd) + Attributes: - filename (str): File name to write. - trigger (hoomd.trigger.Trigger): Select the timesteps to write. - filter (hoomd.filter.filter_like): Select the particles to write. - mode (str): The file open mode. + filename (str): File name to write (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + filename = gsd.filename + + filter (hoomd.filter.filter_like): Select the particles to write + (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + filter_ = gsd.filter + + mode (str): The file open mode (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + mode = gsd.mode + truncate (bool): When `True`, truncate the file and write a new frame 0 - each time this operation triggers. + each time this operation triggers (*read-only*). + + .. rubric:: Example: + + .. code-block:: python + + truncate = gsd.truncate + dynamic (list[str]): Field names and/or field categores to save in all frames. + + .. rubric:: Examples: + + .. code-block:: python + + gsd.dynamic = ['property'] + + .. code-block:: python + + gsd.dynamic = ['property', 'momentum'] + + .. code-block:: python + + gsd.dynamic = ['property', 'particles/image', 'particles/typeid'] + write_diameter (bool): When `False`, do not write ``particles/diameter``. Set to `True` to write non-default particle diameters. + + .. rubric:: Example: + + .. code-block:: python + + gsd.write_diameter = True + maximum_write_buffer_size (int): Size (in bytes) to buffer in memory before writing to the file. + + .. rubric:: Example: + + .. code-block:: python + + gsd.maximum_write_buffer_size = 128 * 1024**2 """ def __init__(self, diff --git a/sphinx-doc/module-hoomd-write.rst b/sphinx-doc/module-hoomd-write.rst index 3b30c95037..5ca3d5a2b0 100644 --- a/sphinx-doc/module-hoomd-write.rst +++ b/sphinx-doc/module-hoomd-write.rst @@ -35,7 +35,7 @@ hoomd.write :show-inheritance: :members: - .. autoclass:: GSD + .. autoclass:: GSD(trigger, filename, filter=hoomd.filter.All(), mode='ab', truncate=False, dynamic=None, logger=None) :show-inheritance: :members: From ec573ad2b726ea059682a2fda0229a10910ceaf3 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 09:51:15 -0400 Subject: [PATCH 13/22] Add Sybil examples to Burst. --- hoomd/write/gsd_burst.py | 77 ++++++++++++++++++++++--------- sphinx-doc/module-hoomd-write.rst | 2 +- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/hoomd/write/gsd_burst.py b/hoomd/write/gsd_burst.py index b56f4a07f0..5243c7a564 100644 --- a/hoomd/write/gsd_burst.py +++ b/hoomd/write/gsd_burst.py @@ -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. -"""Write GSD last :math:`N` frames at user direction.""" +"""Write GSD last :math:`N` frames at user direction. + +.. invisible-code-block: python + + simulation = hoomd.util.make_example_simulation() + burst_filename = tmp_path / 'trajectory.gsd' +""" from hoomd import _hoomd from hoomd.filter import All @@ -12,10 +18,10 @@ class Burst(GSD): r"""Write the last :math:`N` stored frames in the GSD format. - When triggered, `Burst` stores up to the last :math:`N` frames in a buffer. - `Burst` writes the contents of the buffer to the file when `dump` is called. - When the the next frame would result in :math:`N + 1` frames being stored, - the oldest frame is removed and the new frame is added. + When triggered, `Burst` adds a frame (up the last :math:`N` frames) in a + buffer. Call `dump` to write the frames to the file. When the the next frame + would result in :math:`N + 1` frames being stored, the oldest frame is + removed and the new frame is added. Args: trigger (hoomd.trigger.trigger_like): Select the timesteps to store @@ -28,7 +34,7 @@ class Burst(GSD): all frames. Defaults to ``['property']``. logger (hoomd.logging.Logger): Provide log quantities to write. Defaults to `None`. - max_burst_frames (int): The maximum number of frames to store before + max_burst_size (int): The maximum number of frames to store before between writes. -1 represents no limit. Defaults to -1. write_at_start (bool): When ``True`` **and** the file does not exist or has 0 frames: write one frame with the current state of the system @@ -36,32 +42,44 @@ class Burst(GSD): Warning: `Burst` errors when attempting to create a file or writing to one with - zero frames, unless ``write_at_start`` is ``True``. + zero frames when ``write_at_start`` is ``False``. Note: When analyzing files created by `Burst`, generally the first frame is not associated with the call to `Burst.dump`. - Note: - For more tips and qualifications see the `hoomd.write.GSD` - documentation. + .. rubric:: Example: + + .. code-block:: python + + burst = hoomd.write.Burst(trigger=hoomd.trigger.Periodic(1_000), + filename=burst_filename, + max_burst_size=100, + write_at_start=True) + simulation.operations.writers.append(burst) + + See Also: + The base class `hoomd.write.GSD` Attributes: - filename (str): File name to write. - trigger (hoomd.trigger.Trigger): Select the timesteps to store - in the buffer. - filter (hoomd.filter.filter_like): Select the particles to write. - mode (str): The file open mode. - dynamic (list[str]): Field names and/or field categores to save in - all frames. - max_burst_frames (int): The maximum number of frames to store before + max_burst_size (int): The maximum number of frames to store before between writes. -1 represents no limit. - write_diameter (bool): When `False`, do not write - ``particles/diameter``. Set to `True` to write non-default particle - diameters. + + .. rubric:: Example: + + .. code-block:: python + + burst.max_burst_size = 200 + write_at_start (bool): When ``True`` **and** the file does not exist or has 0 frames: write one frame with the current state of the system - when `hoomd.Simulation.run` is called. + when `hoomd.Simulation.run` is called (*read only*). + + .. rubric:: Example: + + .. code-block:: python + + write_at_start = burst.write_at_start """ def __init__(self, @@ -101,12 +119,25 @@ def dump(self): This method alllows for custom writing of frames at user specified conditions. + + .. rubric:: Example: + + .. code-block:: python + + burst.dump() """ if self._attached: self._cpp_obj.dump() def __len__(self): - """Get the current length of the internal frame buffer.""" + """Get the current length of the internal frame buffer. + + .. rubric:: Example: + + .. code-block:: python + + buffered_frames = len(burst) + """ if self._attached: return len(self._cpp_obj) return 0 diff --git a/sphinx-doc/module-hoomd-write.rst b/sphinx-doc/module-hoomd-write.rst index 5ca3d5a2b0..8151ff4cbc 100644 --- a/sphinx-doc/module-hoomd-write.rst +++ b/sphinx-doc/module-hoomd-write.rst @@ -23,7 +23,7 @@ hoomd.write .. automodule:: hoomd.write :synopsis: Write data out. - .. autoclass:: Burst + .. autoclass:: Burst(trigger, filename, filter=hoomd.filter.All(), mode='ab', dynamic=None, logger=None, max_burst_size=-1, write_at_start=False) :show-inheritance: :members: From 8554851bbcbf1c2b55bab16d47531f8a0272149f Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 10:33:52 -0400 Subject: [PATCH 14/22] Fix failing test. --- hoomd/write/gsd.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hoomd/write/gsd.py b/hoomd/write/gsd.py index b8c8a25689..364dadc13b 100644 --- a/hoomd/write/gsd.py +++ b/hoomd/write/gsd.py @@ -201,7 +201,7 @@ class GSD(Writer): .. rubric:: Example: - .. code-block:: python + .. code-block:: python mode = gsd.mode @@ -229,7 +229,9 @@ class GSD(Writer): .. code-block:: python - gsd.dynamic = ['property', 'particles/image', 'particles/typeid'] + gsd.dynamic = ['property', + 'particles/image', + 'particles/typeid'] write_diameter (bool): When `False`, do not write ``particles/diameter``. Set to `True` to write non-default particle From d7075b05d00da93c326c456d08763d6d8e6fbc16 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 11:04:22 -0400 Subject: [PATCH 15/22] Fix failing tests with BUILD_MD=off. --- hoomd/data/typeparam.py | 10 +++++++++- hoomd/operation.py | 1 - 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hoomd/data/typeparam.py b/hoomd/data/typeparam.py index cc86735a3c..9c9469d755 100644 --- a/hoomd/data/typeparam.py +++ b/hoomd/data/typeparam.py @@ -1,7 +1,14 @@ # Copyright (c) 2009-2023 The Regents of the University of Michigan. # Part of HOOMD-blue, released under the BSD 3-Clause License. -"""Implement TypeParameter.""" +"""Implement TypeParameter. + +.. invisible-code-block: python + + # This should not be necessary, but without it, the first + # "skip: next if" fails to skip the code block. + pass +""" from collections.abc import MutableMapping @@ -39,6 +46,7 @@ class TypeParameter(MutableMapping): to demonstrate. .. skip: next if(not hoomd.version.md_built) + .. code-block:: python lj = hoomd.md.pair.LJ(nlist=hoomd.md.nlist.Cell(buffer=0.4)) diff --git a/hoomd/operation.py b/hoomd/operation.py index 7e80e57246..6577b0096f 100644 --- a/hoomd/operation.py +++ b/hoomd/operation.py @@ -15,7 +15,6 @@ .. invisible-code-block: python simulation = hoomd.util.make_example_simulation() - simulation.operations.integrator = hoomd.md.Integrator(dt=0.001) operation = simulation.operations.tuners[0] """ From 9fc0a208e017e9e4a2effe543543d48df787cfa8 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 11:34:43 -0400 Subject: [PATCH 16/22] Format typeconverter.py. --- hoomd/conftest.py | 1 - hoomd/data/typeconverter.py | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hoomd/conftest.py b/hoomd/conftest.py index dacfc9804b..4b02d8156a 100644 --- a/hoomd/conftest.py +++ b/hoomd/conftest.py @@ -66,7 +66,6 @@ def setup_sybil_tests(namespace): pattern='*.py', # exclude files not yet tested with sybil excludes=[ - 'data/typeconverter.py', 'hpmc/pair/user.py', ], setup=setup_sybil_tests, diff --git a/hoomd/data/typeconverter.py b/hoomd/data/typeconverter.py index e39ac4e766..fdd550bdfe 100644 --- a/hoomd/data/typeconverter.py +++ b/hoomd/data/typeconverter.py @@ -146,7 +146,7 @@ class Either(_HelpValidate): For instance if a parameter can either be a length 6 tuple or float then - .. code-blocks:: python + Example:: e = Either(to_type_converter((float,) * 6), to_type_converter(float)) @@ -439,7 +439,7 @@ class TypeConverterSequence(TypeConverter): fix length sequences (`TypeConverterFixedLengthSequence` exists for this). An Example, - .. code-block:: python + Example:: # All elements should be floats TypeConverterSequence(float) @@ -480,7 +480,7 @@ class TypeConverterFixedLengthSequence(TypeConverter): When validating, a sequence of the exact length given on instantiation is expected, else an error is raised. - .. code-block:: python + Example:: # Three floats TypeConverterFixedLengthSequence((float, float, float)) @@ -538,7 +538,7 @@ class TypeConverterMapping(TypeConverter, MutableMapping): errors or returns a mapping with all the same keys as the inputted mapping. - .. code-block:: python + Example:: t = TypeConverterMapping({'str': str, 'list_of_floats': [float]}) @@ -600,7 +600,7 @@ def to_type_converter(value): This is the function to use when defining validation not any of the `TypeConverter` subclasses. - .. code-block:: python + Example:: # list take a list of tuples of 3 floats each validation = to_type_converter( From 444db7c4d142fa84641e2573e49d17938fbcca56 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 26 Sep 2023 13:52:36 -0400 Subject: [PATCH 17/22] Fix typo. --- hoomd/write/gsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/write/gsd.py b/hoomd/write/gsd.py index 364dadc13b..6fbdb6a966 100644 --- a/hoomd/write/gsd.py +++ b/hoomd/write/gsd.py @@ -201,7 +201,7 @@ class GSD(Writer): .. rubric:: Example: - .. code-block:: python + .. code-block:: python mode = gsd.mode From 1f5ada6215943906575013ffbc1d58655169825f Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Thu, 28 Sep 2023 08:59:26 -0400 Subject: [PATCH 18/22] Fix typos. --- hoomd/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hoomd/state.py b/hoomd/state.py index 33983c2d8c..c3f710bb1e 100644 --- a/hoomd/state.py +++ b/hoomd/state.py @@ -135,10 +135,10 @@ class State: HOOMD-blue reads and writes particle diameters, but does not use them in any computations. - - :math:`\\vec{v}``: velocity :math:`[\\mathrm{velocity}]` - X,Y,Z + - :math:`\\vec{v}`: velocity :math:`[\\mathrm{velocity}]` - X,Y,Z components of the particle's velocity in the box's reference frame. - - :math:`\\mathbf{P_S}``: angular momentum :math:`[\\mathrm{mass} \\cdot + - :math:`\\mathbf{P_S}`: angular momentum :math:`[\\mathrm{mass} \\cdot \\mathrm{velocity} \\cdot \\mathrm{length}]` - Quaternion defining the particle's angular momentum (see note). From f1a1ef6d697112e49a084a51f1403b3c7e0aa730 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Tue, 3 Oct 2023 08:03:42 -0400 Subject: [PATCH 19/22] Fix more typos. --- hoomd/hpmc/integrate.py | 12 ++++++------ hoomd/state.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hoomd/hpmc/integrate.py b/hoomd/hpmc/integrate.py index c732549d64..8b6ead66e0 100644 --- a/hoomd/hpmc/integrate.py +++ b/hoomd/hpmc/integrate.py @@ -1611,8 +1611,8 @@ class SphereUnion(HPMCIntegrator): S = \\bigcup_k S_k(\\mathbf{q}_k, \\vec{r}_k) Each constituent shape in the union has its own shape parameters - :math:`S_k`, position :math:`\\vec{r}_k``, and orientation - :math:`\\mathbf{q}_k`` (see `shape`). + :math:`S_k`, position :math:`\\vec{r}_k`, and orientation + :math:`\\mathbf{q}_k` (see `shape`). Note: This shape uses an internal OBB tree for fast collision queries. @@ -1740,8 +1740,8 @@ class ConvexSpheropolyhedronUnion(HPMCIntegrator): S = \\bigcup_k S_k(\\mathbf{q}_k, \\vec{r}_k) Each constituent shape in the union has its own shape parameters - :math:`S_k`, position :math:`\\vec{r}_k``, and orientation - :math:`\\mathbf{q}_k`` (see `shape`). + :math:`S_k`, position :math:`\\vec{r}_k`, and orientation + :math:`\\mathbf{q}_k` (see `shape`). Note: This shape uses an internal OBB tree for fast collision queries. @@ -1867,8 +1867,8 @@ class FacetedEllipsoidUnion(HPMCIntegrator): S = \\bigcup_k S_k(\\mathbf{q}_k, \\vec{r}_k) Each constituent shape in the union has its own shape parameters - :math:`S_k`, position :math:`\\vec{r}_k``, and orientation - :math:`\\mathbf{q}_k`` (see `shape`). + :math:`S_k`, position :math:`\\vec{r}_k`, and orientation + :math:`\\mathbf{q}_k` (see `shape`). Note: This shape uses an internal OBB tree for fast collision queries. diff --git a/hoomd/state.py b/hoomd/state.py index c3f710bb1e..11cdbc706b 100644 --- a/hoomd/state.py +++ b/hoomd/state.py @@ -196,7 +196,7 @@ class State: lists the improper types, and `special_pair_types` lists the special pair types. - ``bond_group``: A list of integers in the interval - :math:`[0, \\max(\\mathrm{particle\\_tag})]`` that defines the tags of the + :math:`[0, \\max(\\mathrm{particle\\_tag})]` that defines the tags of the particles in the bond (2), angle in ``angle_group`` (3), dihedral in ``dihedral_group`` (4), improper in ``improper_group`` (4), or special pair in ``pair_group`` (2). From e5b450d0eefb4b4cdb01568793749ec05951ac39 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Wed, 4 Oct 2023 14:10:20 -0400 Subject: [PATCH 20/22] Fix typo. Co-authored-by: Brandon Butler --- hoomd/data/typeparam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/data/typeparam.py b/hoomd/data/typeparam.py index 9c9469d755..5db49f9199 100644 --- a/hoomd/data/typeparam.py +++ b/hoomd/data/typeparam.py @@ -29,7 +29,7 @@ class TypeParameter(MutableMapping): Lennard-Jones pair potential parameters (`hoomd.md.pair.LJ.params`) are set by **pairs** of particle types. - `TypeParameter` holds the values of these type (or type pair) depdendent + `TypeParameter` holds the values of these type (or type pair) dependent parameters. It also provides convenience methods for setting defaults and multiple parameters on one line. From 767068c3aec8ebbfdf93a5b278f1e87b7d75ae62 Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Thu, 5 Oct 2023 10:53:22 -0400 Subject: [PATCH 21/22] Document multiple keys in __getitem__. --- hoomd/data/typeparam.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/hoomd/data/typeparam.py b/hoomd/data/typeparam.py index 5db49f9199..be7a4a58cc 100644 --- a/hoomd/data/typeparam.py +++ b/hoomd/data/typeparam.py @@ -117,7 +117,7 @@ def __setitem__(self, key, value): self.param_dict[key] = value def __getitem__(self, key): - """Access parameters by key. + """Access parameters by key or keys. .. rubric:: Examples: @@ -130,6 +130,21 @@ def __getitem__(self, key): .. code-block:: python lj_epsilon_AB = lj.params[('A', 'B')]['epsilon'] + + .. rubric:: Multiple keys + + When ``key`` denotes multiple pairs (see `__setitem__`), `__getitem__` + returns multiple items in a dictionary: + + .. code-block:: python + + gammas = langevin.gamma[['A', 'B']] + + is equivalent to: + + .. code-block:: python + + gammas = {key: langevin.gamma[key] for key in ['A', 'B']} """ return self.param_dict[key] From 98041de24d5e7b32a1db969cbf26e8554dcefa8a Mon Sep 17 00:00:00 2001 From: "Joshua A. Anderson" Date: Thu, 5 Oct 2023 11:48:40 -0400 Subject: [PATCH 22/22] Fix failing nomd test. --- hoomd/data/typeparam.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hoomd/data/typeparam.py b/hoomd/data/typeparam.py index be7a4a58cc..733f98d641 100644 --- a/hoomd/data/typeparam.py +++ b/hoomd/data/typeparam.py @@ -136,12 +136,14 @@ def __getitem__(self, key): When ``key`` denotes multiple pairs (see `__setitem__`), `__getitem__` returns multiple items in a dictionary: + .. skip: next if(not hoomd.version.md_built) .. code-block:: python gammas = langevin.gamma[['A', 'B']] is equivalent to: + .. skip: next if(not hoomd.version.md_built) .. code-block:: python gammas = {key: langevin.gamma[key] for key in ['A', 'B']}