HOOMD-blue#

Citing-HOOMD conda-forge conda-forge-Downloads GitHub Actions Contributors License

HOOMD-blue is a Python package that runs simulations of particle systems on CPUs and GPUs. It performs hard particle Monte Carlo simulations of a variety of shape classes and molecular dynamics simulations of particles with a range of pair, bond, angle, and other potentials. Many features are targeted at the soft matter research community, though the code is general and capable of many types of particle simulations.

Resources#

Example scripts#

These examples demonstrate some of the Python API.

Hard particle Monte Carlo:

import hoomd

mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape['octahedron'] = dict(vertices=[
    (-0.5, 0, 0),
    (0.5, 0, 0),
    (0, -0.5, 0),
    (0, 0.5, 0),
    (0, 0, -0.5),
    (0, 0, 0.5),
])

cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=20)
sim.operations.integrator = mc
# The tutorial describes how to construct an initial configuration 'init.gsd'.
sim.create_state_from_gsd(filename='init.gsd')

sim.run(1e5)

Molecular dynamics:

import hoomd

cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5

integrator = hoomd.md.Integrator(dt=0.005)
integrator.forces.append(lj)
bussi = hoomd.md.methods.thermostats.Bussi(kT=1.5)
nvt = hoomd.md.methods.ConstantVolume(filter=hoomd.filter.All(), thermostat=bussi)
integrator.methods.append(nvt)

gpu = hoomd.device.GPU()
sim = hoomd.Simulation(device=gpu)
sim.operations.integrator = integrator
# The tutorial describes how to construct an initial configuration 'init.gsd'.
sim.create_state_from_gsd(filename='init.gsd')
sim.state.thermalize_particle_momenta(filter=hoomd.filter.All(), kT=1.5)

sim.run(1e5)

Contents

Getting started#

Features#

Hard particle Monte Carlo#

HOOMD-blue can perform simulations of hard particles using the Monte Carlo method (hpmc). Hard particles are defined by their shape, and the HPMC integrator supports polygons, spheropolygons, polyhedra, spheropolyhedra, ellipsoids, faceted ellipsoids, spheres, indented spheres, and unions of shapes. HPMC can make both constant volume and constant pressure box moves (hpmc.update.BoxMC), perform cluster moves (hpmc.update.Clusters) and can compute the pressure during constant volume simulations (hpmc.compute.SDF).

HPMC can also apply external and pair potentials to the particles. Use hpmc.external.field.Harmonic to restrain particles to a lattice (e.g. for Frenkel-Ladd calculations) or hpmc.external.user.CPPExternalPotential to implement arbitrary external fields (e.g. gravity). Use hpmc.pair.user to define arbitrary pairwise interactions between particles. At runtime, hoomd.version.hpmc_built indicates whether the build supports HPMC simulations.

See also

Tutorial: Introducing HOOMD-blue

Molecular dynamics#

HOOMD-blue can perform molecular dynamics simulations (md) with constant volume, constant pressure, Langevin, Brownian, overdamped viscous integration methods (md.methods), and energy minimization (md.minimize). The constant volume and constant pressure methods may be applied with or without a thermostat (md.methods.thermostats). Unless otherwise stated in the documentation, all integration methods integrate both translational and rotational degrees of freedom. Some integration methods support manifold constraints (md.methods.rattle). HOOMD-blue provides a number of cutoff potentials including pair potentials (md.pair), pair potentials that depend on particle orientation (md.pair.aniso), and many body potentials (md.many_body). HOOMD-blue also provides bond potentials and distance constraints commonly used in atomistic/coarse-grained force fields (md.angle, md.bond, md.constrain.Distance, md.dihedral, md.improper, md.special_pair) and can model rigid bodies (md.constrain.Rigid). External fields md.external.field apply potentials based only on the particle’s position and orientation, including walls (md.external.wall) to confine particles in a specific region of space. md.long_range provides long ranged interactions, including the PPPM method for electrostatics. HOOMD-blue enables active matter simulations with md.force.Active and md.update.ActiveRotationalDiffusion. At runtime, hoomd.version.md_built indicates whether the build supports MD simulations.

See also

Tutorial: Introducing Molecular Dynamics

Python package#

HOOMD-blue is a Python package and is designed to interoperate with other packages in the scientific Python ecosystem and to be extendable in user scripts. To enable interoperability, all operations provide access to useful computed quantities as properties in native Python types or numpy arrays where appropriate. Additionally, State and md.force.Force provide direct access to particle properties and forces using Python array protocols. Users can customize their simulation or extend HOOMD-blue with functionality implemented in Python code by subclassing trigger.Trigger, variant.Variant, hoomd.update.CustomUpdater, hoomd.write.CustomWriter, hoomd.tune.CustomTuner, or by using the HOOMD-blue API in combination with other Python packages to implement methods that couple simulation, analysis, and multiple simulations (such as umbrella sampling).

See also

Tutorial: Custom Actions in Python

CPU and GPU devices#

HOOMD-blue can execute simulations on CPUs or GPUs. Typical simulations run more efficiently on GPUs for system sizes larger than a few thousand particles, although this strongly depends on the details of the simulation. The provided binaries support NVIDIA GPUs. Build from source to enable preliminary support for AMD GPUs. CPU support is always enabled. GPU support must be enabled at compile time with the ENABLE_GPU CMake option (see Building from source). Select the device to use at run time with the device module. Unless otherwise stated in the documentation, all operations and methods support GPU execution. At runtime, hoomd.version.gpu_enabled indicates whether the build supports GPU devices.

Autotuned kernel parameters#

HOOMD-blue automatically tunes kernel parameters to improve performance when executing on a GPU device. During the first 1,000 - 20,000 timesteps of the simulation run, HOOMD-blue will change kernel parameters each time it calls a kernel. Kernels compute the same output regardless of the parameter (within floating point precision), but the parameters have a large impact on performance.

Check to see whether tuning is complete with the is_tuning_complete attribute of your simulation’s Operations. For example, use this to run timed benchmarks after the performance stabilizes.

The optimal parameters can depend on the number of particles in the simulation and the density, and may vary weakly with other system properties. To maintain peak performance, call tune_kernel_parmeters to tune the parameters again after making a change to your system.

AutotunedObject provides a settable dictionary parameter with the current kernel parameters in kernel_parameters. Use this to inspect the autotuner’s behavior or override with specific values (e.g. values saved from a previous execution).

MPI#

HOOMD-blue can use the message passing interface (MPI) to execute simulations in less time using more than one CPU core or GPU. Unless otherwise stated in the documentation, all operations and methods support MPI parallel execution. MPI support is optional, requires a compatible MPI library, and must be enabled at compile time with the ENABLE_MPI CMake option (see Building from source). At runtime, hoomd.version.mpi_enabled indicates whether the build supports MPI.

See also

Tutorial: Parallel Simulation With MPI

Threading#

Some operations in HOOMD-blue can use multiple CPU threads in a single process. Control this with the device.Device.num_cpu_threads property. In this release, threading support in HOOMD-blue is very limited and only applies to implicit depletants in hpmc.integrate.HPMCIntegrator, and hpmc.pair.user.CPPPotentialUnion. Threading must must be enabled at compile time with the ENABLE_TBB CMake option (see Building from source). At runtime, hoomd.version.tbb_enabled indicates whether the build supports threaded execution.

Run time compilation#

Some operations allow the user to provide arbitrary C++ code that HOOMD-blue compiles at run time and executes during the simulation. hpmc.pair.user and hpmc.external.user enable users to apply arbitrary pair and external potentials to particles in HPMC simulations. hpmc.pair.user supports both CPUs and NVIDIA GPUs while hpmc.external.user only supports CPUs. Run time compilation must be enabled at compile time with the ENABLE_LLVM CMake option (see Building from source). At runtime, hoomd.version.llvm_enabled indicates whether the build supports run time compilation.

Mixed precision#

HOOMD-blue performs computations with mixed floating point precision. There is a high precision type and a reduced precision type. All particle properties are stored in the high precision type, and most operations also perform all computations with high precision. Operations that do not mention “Mixed precision” in their documentation perform all calculations in high percision. Some operations use reduced precision when possible to improve performance, as detailed in the documentation for each operation.

The precision is set at compile time with the HOOMD_LONGREAL_SIZE and HOOMD_SHORTREAL_SIZE CMake options (see Building from source). By default, the high precision width is 64 bits and the reduced precision width is 32 bits. At runtime, hoomd.version.floating_point_precision indicates the width of the floating point types.

Plugins#

Plugin code that provides additional functionality to HOOMD-blue may be implemented in pure Python or as a package with C++ compiled libraries.

See also

Components

Installing binaries#

HOOMD-blue binaries are available in the glotzerlab-software Docker/Singularity images and in packages on conda-forge

Singularity / Docker images#

See the glotzerlab-software documentation for instructions to install and use the containers on supported HPC clusters.

Conda package#

HOOMD-blue is available on conda-forge on the linux-64, osx-64, and osx-arm64 platforms. Install the hoomd package from the conda-forge channel into a conda environment:

$ conda install hoomd=4.0.1

conda auto-detects whether your system has a GPU and attempts to install the appropriate package. Override this and force the GPU enabled package installation with:

$ export CONDA_OVERRIDE_CUDA="11.2"
$ conda install "hoomd=4.0.1=*gpu*"

Similarly, you can force CPU only package installation with:

$ conda install "hoomd=4.0.1=*cpu*"

Note

To use Run time compilation on macOS, install the compilers package:

$ conda install compilers

Without this package you will get file not found errors when HOOMD-blue performs the run time compilation.

Tip

Use mambaforge, miniforge or miniconda instead of the full Anaconda distribution to avoid package conflicts with conda-forge packages. When using miniconda, follow the instructions provided in the conda-forge documentation to configure the channel selection so that all packages are installed from the conda-forge channel.

Building from source#

To build the HOOMD-blue Python package from source:

  1. Install prerequisites:

    $ <package-manager> install cmake eigen git python numpy pybind11
    
  2. Obtain the source:

    $ git clone --recursive https://github.com/glotzerlab/hoomd-blue
    
  3. Configure:

    $ cmake -B build/hoomd -S hoomd-blue
    
  4. Build the package:

    $ cmake --build build/hoomd
    
  5. Install the package (optional):

    $ cmake --install build/hoomd
    

To build the documentation from source (optional):

  1. Install prerequisites:

    $ <package-manager> install sphinx furo nbsphinx ipython
    

Note

nbsphinx requires pandoc>=1.12.1, which you may need to install separately.

  1. Build the documentation:

    $ sphinx-build -b html hoomd-blue/sphinx-doc build/hoomd-documentation
    

The sections below provide details on each of these steps.

Install prerequisites#

HOOMD-blue requires a number of tools and libraries to build. The options ENABLE_MPI, ENABLE_GPU, ENABLE_TBB, and ENABLE_LLVM each require additional libraries when enabled.

Note

This documentation is generic. Replace <package-manager> with your package or module manager. You may need to adjust package names and/or install additional packages, such as -dev packages that provide headers needed to build hoomd.

Tip

Create a virtual environment, one place where you can install dependencies and HOOMD-blue:

$ python3 -m venv hoomd-venv

You will need to activate your environment before configuring HOOMD-blue:

$ source hoomd-venv/bin/activate

Note

Some package managers (such as pip) and many clusters are missing some or all of pybind11, eigen, and cereal. install-prereq-headers.py will install these packages into your virtual environment:

$ python3 hoomd-blue/install-prereq-headers.py

General requirements:

  • C++17 capable compiler (tested with gcc 9 - 12 and clang 10 - 14)

  • Python >= 3.8

  • NumPy >= 1.17.3

  • pybind11 >= 2.2

  • Eigen >= 3.2

  • CMake >= 3.9

For MPI parallel execution (required when ENABLE_MPI=on):

  • MPI (tested with OpenMPI, MVAPICH)

  • cereal >= 1.1

For GPU execution (required when ENABLE_GPU=on):

  • NVIDIA CUDA Toolkit >= 9.0

    OR

  • AMD ROCm >= 3.5.0 with additional dependencies:

    • HIP [with hipcc and hcc as backend]

    • rocFFT

    • rocPRIM

    • rocThrust

    • hipCUB, included for NVIDIA GPU targets, but required as an external dependency when building for AMD GPUs

    • roctracer-dev

    • Linux kernel >= 3.5.0

    • CMake >= 3.21

    For HOOMD-blue on AMD GPUs, the following limitations currently apply.

    1. Certain kernels trigger an unknown HSA error.

    2. The mpcd component is disabled on AMD GPUs.

    3. Multi-GPU execution via unified memory is not available.

Note

When ENABLE_GPU=on, HOOMD-blue will default to CUDA. Set HOOMD_GPU_PLATFORM=HIP to choose HIP.

For threaded parallelism on the CPU (required when ENABLE_TBB=on):

  • Intel Threading Building Blocks >= 4.3

For runtime code generation (required when ENABLE_LLVM=on):

  • LLVM >= 10.0

  • libclang-cpp >= 10.0

To build the documentation:

  • sphinx

  • furo

  • nbsphinx

  • ipython

Obtain the source#

Clone using Git:

$ git clone --recursive https://github.com/glotzerlab/hoomd-blue

Release tarballs are also available as GitHub release assets: Download hoomd-4.0.1.tar.gz.

See also

See the git book to learn how to work with Git repositories.

Warning

HOOMD-blue uses Git submodules. Clone with the --recursive to clone the submodules.

Execute git submodule update --init to fetch the submodules each time you switch branches and the submodules show as modified.

Configure#

Use CMake to configure a HOOMD-blue build in the given directory. Pass -D<option-name>=<value> to cmake to set options on the command line. When modifying code, you only need to repeat the build step to update your build - it will automatically reconfigure as needed.

Tip

Use Ninja to perform incremental builds in less time:

$ cmake -B build/hoomd -S hoomd-blue -GNinja

Tip

Place your build directory in /tmp or /scratch for faster builds. CMake performs out-of-source builds, so the build directory can be anywhere on the filesystem.

Tip

Pass the following options to cmake to optimize the build for your processor: -DCMAKE_CXX_FLAGS=-march=native -DCMAKE_C_FLAGS=-march=native.

Important

When using a virtual environment, activate the environment and set the cmake prefix path before running CMake: $ export CMAKE_PREFIX_PATH=<path-to-environment>.

HOOMD-blue’s cmake configuration accepts a number of options.

Options that find libraries and executables only take effect on a clean invocation of CMake. To set these options, first remove CMakeCache.txt from the build directory and then run cmake with these options on the command line.

  • PYTHON_EXECUTABLE - Specify which python to build against. Example: /usr/bin/python3.

    • Default: python3.X detected on $PATH.

  • CMAKE_CUDA_COMPILER - Specify which nvcc or hipcc to build with.

    • Default: location of nvcc detected on $PATH.

  • MPI_HOME (env var) - Specify the location where MPI is installed.

    • Default: location of mpicc detected on the $PATH.

  • <package-name>_ROOT - Specify the location of a package.

    • Default: Found on the CMake search path.

Other option changes take effect at any time:

  • BUILD_HPMC - When enabled, build the hoomd.hpmc module (default: on).

  • BUILD_MD - When enabled, build the hoomd.md module (default: on).

  • BUILD_METAL - When enabled, build the hoomd.metal module (default: on).

  • BUILD_TESTING - When enabled, build unit tests (default: on).

  • CMAKE_BUILD_TYPE - Sets the build type (case sensitive) Options:

    • Debug - Compiles debug information into the library and executables. Enables asserts to check for programming mistakes. HOOMD-blue will run slow when compiled in Debug mode, but problems are easier to identify.

    • RelWithDebInfo - Compiles with optimizations and debug symbols.

    • Release - (default) All compiler optimizations are enabled and asserts are removed. Recommended for production builds.

  • CMAKE_INSTALL_PREFIX - Directory to install HOOMD-blue. Defaults to the root path of the found Python executable.

  • ENABLE_LLVM - Enable run time code generation with LLVM.

  • ENABLE_GPU - When enabled, compiled GPU accelerated computations (default: off).

  • HOOMD_GPU_PLATFORM - Choose either CUDA or HIP as a GPU backend (default: CUDA).

  • HOOMD_SHORTREAL_SIZE - Size in bits of the ShortReal type (default: 32).

    • When set to 32, perform force computations, overlap checks, and other local calculations in single precision.

    • When set to 64, perform all calculations in double precision.

  • HOOMD_LONGREAL_SIZE - Size in bits of the LongReal type (default: 64).

    • When set to 64, store particle coordinates, sum quantities, and perform integration in double precision.

    • When set to 32, store particle coordinates, sum quantities, and perform integration in single precision. NOT RECOMMENDED, HOOMD-blue fails validation tests when HOOMD_LONGREAL_SIZE == HOOMD_SHORTREAL_SIZE == 32.

  • ENABLE_MPI - Enable multi-processor/GPU simulations using MPI.

    • When set to on, multi-processor/multi-GPU simulations are supported.

    • When set to off (the default), always run in single-processor/single-GPU mode.

  • ENABLE_TBB - Enable support for Intel’s Threading Building Blocks (TBB).

    • When set to on, HOOMD-blue will use TBB to speed up calculations in some classes on multiple CPU cores.

  • PYTHON_SITE_INSTALL_DIR - Directory to install hoomd to relative to CMAKE_INSTALL_PREFIX. Defaults to the site-packages directory used by the found Python executable.

These options control CUDA compilation via nvcc:

  • CUDA_ARCH_LIST - A semicolon-separated list of GPU architectures to compile.

Build the package#

The command cmake --build build/hoomd will build the HOOMD-blue Python package in the given build directory. After the build completes, the build directory will contain a functioning Python package.

Install the package#

The command cmake --install build/hoomd installs the given HOOMD-blue build to ${CMAKE_INSTALL_PREFIX}/${PYTHON_SITE_INSTALL_DIR}. CMake autodetects these paths, but you can set them manually in CMake.

Build the documentation#

Run Sphinx to build the documentation with the command sphinx-build -b html hoomd-blue/sphinx-doc build/hoomd-documentation. Open the file build/hoomd-documentation/index.html in your web browser to view the documentation.

Tip

When iteratively modifying the documentation, the sphinx options -a -n -W -T --keep-going are helpful to produce docs with consistent links in the side panel and to see more useful error messages:

$ sphinx-build -a -n -W -T --keep-going -b html \
    hoomd-blue/sphinx-doc build/hoomd-documentation

Citing HOOMD-blue#

Please cite this publication in any work that uses HOOMD-blue:

J. A. Anderson, J. Glaser, and S. C. Glotzer. HOOMD-blue: A Python package for high-performance molecular dynamics and hard particle Monte Carlo simulations. Computational Materials Science 173: 109363, Feb 2020. 10.1016/j.commatsci.2019.109363


The following publications document significant contributions to features in HOOMD-blue. We encourage you to cite these, if possible, when you make use of these specific functionalities.

HPMC:

J. A. Anderson, M. E. Irrgang, and S. C. Glotzer. Scalable Metropolis Monte Carlo for simulation of hard shapes. Computer Physics Communications 204: 21-30, July 2016. 10.1016/j.cpc.2016.02.024

Implicit depletants in HPMC:

J. Glaser, A. S. Karas, and S. C. Glotzer. A parallel algorithm for implicit depletant simulations. The Journal of Chemical Physics 143: 184110, 2015. 10.1063/1.4935175

MPI scaling:

J. Glaser, T. D. Nguyen, J. A. Anderson, P. Lui, F. Spiga, J. A. Millan, D. C. Morse, S. C. Glotzer. Strong scaling of general-purpose molecular dynamics simulations on GPUs. Computer Physics Communications 192: 97-107, July 2015. 10.1016/j.cpc.2015.02.028

Intra-node scaling on multiple GPUs:

J. Glaser, P. S. Schwendeman, J. A. Anderson, S. C. Glotzer. Unified memory in HOOMD-blue improves node-level strong scaling. Computational Materials Science 173: 109359, Feb 2020. 10.1016/j.commatsci.2019.109359

Alchemical MD simulations:

G. van Anders, D. Klotsa, A. S. Karas, P. M. Dodd, S. C. Glotzer. Digital Alchemy for Materials Design: Colloids and Beyond. ACS Nano 2015, 9, 10, 9542-9553 10.1021/acsnano.5b04181

P. Zhou, J. C. Proctor, G. van Anders, S. C. Glotzer. Alchemical molecular dynamics for inverse design. Molecular Physics, 117:23-24, 3968-3980 2019. 10.1080/00268976.2019.1680886

Alchemical HPMC simulations:

G. van Anders, D. Klotsa, A. S. Karas, P. M. Dodd, S. C. Glotzer. Digital Alchemy for Materials Design: Colloids and Beyond. ACS Nano 2015, 9, 10, 9542-9553 10.1021/acsnano.5b04181

Y. Geng, G. van Anders, P. M. Dodd, J. Dshemuchadse, S. C. Glotzer. Engineering entropy for the inverse design of colloidal crystals from hard shapes. Science Advances 2019, 5, 7, eaaw051 10.1126/sciadv.aaw0514

When including historical development of HOOMD-blue, or noting that HOOMD-blue was first implemented on GPUs, please also cite:

J. A. Anderson, C. D. Lorenz, and A. Travesset. General purpose molecular dynamics simulations fully implemented on graphics processing units. Journal of Computational Physics 227(10): 5342-5359, May 2008. 10.1016/j.jcp.2008.01.047

DEM:

M. Spellings, R. L. Marson, J. A. Anderson, and S. C. Glotzer. GPU accelerated Discrete Element Method (DEM) molecular dynamics for conservative, faceted particle simulations. Journal of Computational Physics 334: 460-467, Apr 2017. 10.1016/j.jcp.2017.01.014

The tree or stencil MD neighbor list:

M. P. Howard, J. A. Anderson, A. Nikoubashman, S. C. Glotzer, and A. Z. Panagiotopoulos. Efficient neighbor list calculation for molecular simulation of colloidal systems using graphics processing units. Computer Physics Communications 203: 45-52, Mar 2016. 10.1016/j.cpc.2016.02.003

M. P. Howard, A. Statt, F. Madutsa, T. M. Truskett, and A. Z. Panagiotopoulos. Quantized bounding volume hierarchies for neighbor search in molecular simulations on graphics processing units. Computational Materials Science 164(15): 139-146, June 2019. 10.1016/j.commatsci.2019.04.004

MPCD:

M. P. Howard, A. Z. Panagiotopoulos, and A. Nikoubashman. Efficient mesoscale hydrodynamics: Multiparticle collision dynamics with massively parallel GPU acceleration Computer Physics Communications 230: 10-20, Sep. 2018. 10.1016/j.cpc.2018.04.009

Rigid bodies in MD:

T. D. Nguyen, C. L. Phillips, J. A. Anderson, and S. C. Glotzer. Rigid body constraints realized in massively-parallel molecular dynamics on graphics processing units. Computer Physics Communications 182(11): 2313-2307, June 2011. 10.1016/j.cpc.2011.06.005

J. Glaser, X. Zha, J. A. Anderson, S. C. Glotzer, A. Travesset. Pressure in rigid body molecular dynamics. Computational Materials Science Computational Materials Science 173: 109430, Feb 2020. 10.1016/j.commatsci.2019.109430

DPD:

C. L. Phillips, J. A. Anderson, and S. C. Glotzer. Pseudo-random number generation for Brownian Dynamics and Dissipative Particle Dynamics simulations on GPU devices Journal of Computational Physics 230(19): 7191-7201, Aug. 2011. 10.1016/j.jcp.2011.05.021

EAM:

I.V. Morozov, A.M. Kazennova, R.G. Bystryia, G.E. Normana, V.V. Pisareva, and V.V. Stegailova. Molecular dynamics simulations of the relaxation processes in the condensed matter on GPUs. Computer Physics Communications 182(9): 1974-1978, 2011. 10.1016/j.cpc.2010.12.026

L. Yang, F. Zhang, C. Wang, K. Ho, and A. Travesset. Implementation of metal-friendly EAM/FS-type semi-empirical potentials in HOOMD-blue: A GPU-accelerated molecular dynamics software. Journal of Computational Physics 359(15): 352-360, 2018. 10.1016/j.jcp.2018.01.015

PPPM:

D. N. LeBard, B. G. Levine, P. Mertmann, S. A. Barr, A. Jusufi, S. Sanders, M. L. Klein, and A. Z. Panagiotopoulos. Self-assembly of coarse-grained ionic surfactants accelerated by graphics processing units. Soft Matter 8: 2385-2397, 2012. 10.1039/c1sm06787g

CGCMM potential:

B. G. Levine, D. N. LeBard, R. DeVane, W. Shinoda, A. Kohlmeyer, and M. L. Klein. Micellization studied by GPU-accelerated coarse-grained molecular dynamics. Journal of Chemical Theory and Computation 7(12): 4135-4145, Oct. 2011. 10.1021/ct2005193

Tutorials#

Introducing HOOMD-blue#

HOOMD-blue is a Python package that performs Molecular Dynamics and hard particle Monte Carlo simulations. HOOMD-blue is general and can be used to model nanoparticles, bead-spring polymers, active mater, and many other types of systems. This tutorial introduces the core concepts in HOOMD-blue using hard particle self-assembly as an example. Later tutorials will expand on these concepts for other types of simulations.

Prerequisites:

This tutorial assumes you have some familiarity with the Python programming language.

The Simulation Object#
Overview#
Questions#
  • How can I configure and control a simulation?

  • How do I choose which processor to use?

Objectives#
  • Explain the parts of the Simulation object and how they relate.

  • Explain how the device object influences how the simulation executes.

  • Demonstrate the creation of these objects.

Core objects#

HOOMD-blue is an object-oriented Python package. First, import the package:

[1]:
import hoomd

The Simulation object combines all the elements of a simulation together and provides an interface to run the simulation. It consists of the simulation state and operations which act on that state. The simulation state includes the current box, bonds, particle positions, velocities, orientations, and other particle properties. Operations examine or modify the state. A simulation has one state, and any number of operations.

Selecting a device#

You must specify a device when constructing a Simulation. The device tells the simulation where to store the state and what processor to use when executing operations. HOOMD-blue can execute on the CPU:

[2]:
cpu = hoomd.device.CPU()

Or the GPU:

[3]:
gpu = hoomd.device.GPU()

GPUs are highly parallel processors best suited for larger workloads. In typical systems with more than 4,000 particles a single GPU performs an order of magnitude faster than an entire CPU (all cores). Try your simulation on both to see what hardware can run the same number of time steps in less time.

Creating a Simulation#

Now, you can instantiate a Simulation with the chosen device.

[4]:
sim = hoomd.Simulation(device=cpu)

A newly constructed Simulation has no state:

[5]:
print(sim.state)
None

And no integrator, updaters, or writers, which are types of operations:

[6]:
print(sim.operations.integrator)
None
[7]:
print(sim.operations.updaters[:])
[]
[8]:
print(sim.operations.writers[:])
[]

The remaining sections in this tutorial will show you how to populate a Simulation with operations, initialize the state, and run the simulation.

Performing Hard Particle Monte Carlo Simulations#
Overview#
Questions#
  • What is hard particle Monte Carlo?

  • How do I set up a hard particle Monte Carlo simulation?

Objectives#
  • Describe hard particle Monte Carlo simulations, particle shape, and trial moves.

  • Show how to initialize the ConvexPolyhedron integrator.

  • Explain the integrator parameters.

  • Introduce time steps.

Boilerplate code#
[1]:
import math

import hoomd
Particle shape#

A hard particle Monte Carlo (HPMC) simulation represents particles as extended objects which are not allowed to overlap. There are no attractive or repulsive forces in the system. The shape of the particle alone controls how it interacts with other particles. Formally, the potential energy of the system is zero when there are no overlaps and infinite when there are. Purely hard interactions induce effective attractions between particles which can lead to ordered structures. For example, hard regular octahedra will self-assemble into a bcc structure. In this tutorial, you will learn how to run a simulation of hard octahedra and observe this behavior.

Octahedra self assembly

The integrator#

The ConvexPolyhedron integrator implements HPMC simulations - Create one:

[2]:
mc = hoomd.hpmc.integrate.ConvexPolyhedron()

Set the shape property to define the particle shape. A convex polyhedron is defined by the convex hull of a set of vertices:

[3]:
mc.shape['octahedron'] = dict(vertices=[
    (-0.5, 0, 0),
    (0.5, 0, 0),
    (0, -0.5, 0),
    (0, 0.5, 0),
    (0, 0, -0.5),
    (0, 0, 0.5),
])
Trial moves#

During each time step, HPMC attempts nselect trial moves on each particle in the system. Each trial move is drawn from a pseudorandom number stream and may be either a translation or rotation move. Translation moves displace a particle a random distance (up to d) in a random direction. Rotation moves rotate the particle by a random angle about a random axis. Larger values of a lead to larger possible rotation moves.

Any trial move whose shape overlaps with another particle is rejected, leaving the particle’s position and orientation unchanged. Any trial move whose shape does not overlap with any other particle is accepted, setting the particle’s position or orientation to the new value.

nselect, d, and a are properties of the integrator:

[4]:
mc.nselect = 2
mc.d['octahedron'] = 0.15
mc.a['octahedron'] = 0.2
Setting the integrator#
[5]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)

An integrator is a type of operation. There can only be one integrator in a Simulation and it operates on the system state on every time step. Assign the HPMC integrator to the Simulation to use it:

[6]:
sim.operations.integrator = mc

The seed value (passed to the simulation constructor above) selects the sequence of values in the pseudorandom number stream. Given the same initial condition and seed, HPMC simulations will produce exactly the same results.

All operations that generate psuedorandom numbers use the seed set in the simulation. Whenever you add operations that utilize random numbers, you should set the seed to a non-default value.

Now you have a Simulation and a ConvexPolyhedron integrator, but can’t run the simulation yet. You first need to define the system state for the integrator to operate on. The next section in this tutorial will show you how to initialize the state.

Initializing the System State#
Overview#
Questions#
  • How do I place particles in the initial condition?

  • What units does HOOMD-blue use?

Objectives#
  • Describe the basic properties of the initial condition, including particle position, orientation, type and the periodic box.

  • Briefly describe HOOMD-blue’s system of units.

  • Demonstrate writing a system to a GSD file.

  • Show how to initialize Simulation state from a GSD file.

Boilerplate code#
[1]:
import itertools
import math

import hoomd
import numpy

The render function in the next (hidden) cell will render the initial condition using fresnel. Find the source in the hoomd-examples repository.

Components of the system state#

You need to initialize the system state before you can run a simulation. The initial condition describes the the position and orientation of every particle in the system and the periodic box at the start of the simulation.

The hard regular octahedra system self-assembles the the bcc structure. Self-assembly is a process where particles will organize themselves into an ordered structure at equilibrium. Most self-assembly studies run simulations of many thousands of particles for tens of hours. To keep this tutorial short, it simulations a small number of particles commensurate with the bcc structure (2 * m**3, where m is an integer).

[4]:
m = 4
N_particles = 2 * m**3
Placing particles#

In hard particle Monte Carlo, valid particle configurations have no overlaps. The octahedron particle in this tutorial sits inside a sphere of diameter 1, so place particles a little bit further than that apart on a KxKxK simple cubic lattice of width L. The following sections of this tutorial will demonstrate how to randomize this ordered configuration and compress it to a higher density.

[5]:
spacing = 1.2
K = math.ceil(N_particles**(1 / 3))
L = K * spacing

In HOOMD, particle positions must be placed inside a periodic box. Cubic boxes range from -L/2 to L/2. Use itertools and numpy to place the positions on the lattice in this range.

[6]:
x = numpy.linspace(-L / 2, L / 2, K, endpoint=False)
position = list(itertools.product(x, repeat=3))
print(position[0:4])
[(-3.5999999999999996, -3.5999999999999996, -3.5999999999999996), (-3.5999999999999996, -3.5999999999999996, -2.3999999999999995), (-3.5999999999999996, -3.5999999999999996, -1.1999999999999997), (-3.5999999999999996, -3.5999999999999996, 0.0)]

Filter this list down to N particles because K*K*K >= N_particles .

[7]:
position = position[0:N_particles]

You also need to set the orientation for each particle. HOOMD represents orientations with quaternions. The quaternion (1, 0, 0, 0) represents no rotation. Set that for all particles:

[8]:
orientation = [(1, 0, 0, 0)] * N_particles

Here is what the system looks like now:

[9]:
render(position, orientation, L)
[9]:
_images/tutorial_00-Introducing-HOOMD-blue_03-Initializing-the-System-State_16_0.png
Units#

HOOMD-blue does not adopt any particular real system of units. Instead, HOOMD-blue uses an internally self-consistent system of units and is compatible with many systems of units. For example: if you select the units of meter, Joule, and kilogram for length, energy and mass then the units of force will be Newtons and velocity will be meters/second. A popular system of units for nano-scale systems is nanometers, kilojoules/mol, and atomic mass units.

In HPMC, the primary unit is that of length. Mass exists, but is factored out of the partition function and does not enter into the simulation. The scale of energy is irrelevant in athermal HPMC systems where overlapping energies are infinite and valid configurations have zero potential energy. However, energy does appear implicitly in derived units like \([\mathrm{pressure}] = \left(\frac{\mathrm{[energy]}}{\mathrm{[length]}^3}\right)\). In HPMC, \(kT\) is assumed to be 1 energy. You can convert a pressure \(P\) in HPMC’s units to a non-dimensional value with \(P^* = \frac{P\sigma^3}{kT}\) where \(\sigma\) is a representative length in your system, such as the particle’s diameter or edge length.

Writing the configuration to the file system#

GSD files store the periodic box, particle positions, orientations, and other properties of the state. Use the GSD Python package to write this file.

[10]:
import gsd.hoomd

The Frame object stores the state of the system.

[11]:
frame = gsd.hoomd.Frame()
frame.particles.N = N_particles
frame.particles.position = position
frame.particles.orientation = orientation

Each particle also has a type. In HPMC, each type has its own shape parameters. There is a single type in this tutorial, so set a type id of 0 for all particles (type ids are 0-indexed):

[12]:
frame.particles.typeid = [0] * N_particles

Every particle type needs a name. Names can be any string. HOOMD-blue uses the type names to match the parameters you specify in operations with the type names present in the state. Give the name 'octahedron' to the type id 0:

[13]:
frame.particles.types = ['octahedron']

GSD represents boxes with a 6-element array. Three box lengths L_x, L_y, L_z, and 3 tilt factors. Set equal box lengths and 0 tilt factors to define a cubic box.

[14]:
frame.configuration.box = [L, L, L, 0, 0, 0]

Write this snapshot to lattice.gsd:

[15]:
with gsd.hoomd.open(name='lattice.gsd', mode='x') as f:
    f.append(frame)
Initializing a Simulation#

You can use the file to initialize the Simulation state. First, create a Simulation:

[16]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu)

Then use the create_state_from_gsd factory function to read in the GSD file and populate the state with the particles and box from the file:

[17]:
sim.create_state_from_gsd(filename='lattice.gsd')

The next section in this tutorial will show you how to use HPMC to randomize the particle positions and orientations.

Randomizing the System#
Overview#
Questions#
  • How can I generate a random initial condition?

Objectives#
  • Show how to use HPMC to randomize the initial condition.

  • Demonstrate how to run a simulation.

  • Show how to use HPMC integrator properties to examine the acceptance ratio.

  • Explain that short simulations at low density effectively randomize the system.

Boilerplate code#
[1]:
import math

import hoomd

The render function in the next (hidden) cell will render a snapshot using fresnel. Find the source in the hoomd-examples repository.

Method#

The previous section of this tutorial placed all the particles on a simple cubic lattice. This is a convenient way to place non-overlapping particles, but it starts the simulation in a highly ordered state. You should randomize the the system enough so that it forgets this initial state and self-assembly can proceed without influence by the initial condition.

You cannot draw random numbers trivially for the particle positions, as that will result in overlaps between particles. Instead, start from the lattice and use HPMC to move particles randomly while ensuring that they do not overlap. In low density configurations, like the lattice generated in the previous section, a short simulation will quickly randomize the system.

Set up the simulation#

The following code block creates the Simulation, configures the HPMC integrator, and initializes the system state from lattice.gsd as has been discussed in previous sections in this tutorial:

[4]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=20)

mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape['octahedron'] = dict(vertices=[
    (-0.5, 0, 0),
    (0.5, 0, 0),
    (0, -0.5, 0),
    (0, 0.5, 0),
    (0, 0, -0.5),
    (0, 0, 0.5),
])

sim.operations.integrator = mc
sim.create_state_from_gsd(filename='lattice.gsd')
Run the simulation#

Save a snapshot of the current state of the system. This tutorial uses this later to see how far particles have moved.

[5]:
initial_snapshot = sim.state.get_snapshot()

Run the simulation to randomize the particle positions and orientations. The run method takes the number of steps to run as an argument. 10,000 steps is enough to randomize a low density system:

[6]:
sim.run(10e3)

You can query properties of the HPMC integrator to see what it did. translate_moves is a tuple with the number of accepted and rejected translation moves. The acceptance ratio, the fraction of attempted moves which are accepted, is very high at this low density.

[7]:
mc.translate_moves
[7]:
(2412359, 147260)
[8]:
mc.translate_moves[0] / sum(mc.translate_moves)
[8]:
0.9424680001203304

rotate_moves similarly provides the number of accepted and rejected rotation moves.

[9]:
mc.rotate_moves
[9]:
(2489315, 71066)
[10]:
mc.rotate_moves[0] / sum(mc.rotate_moves)
[10]:
0.9722439746272137

overlaps reports the number of overlapping particle pairs in the state. There are no overlaps in the final configuration:

[11]:
mc.overlaps
[11]:
0
The final configuration#

Look at the final particle positions and orientations and see how they have changed:

[12]:
final_snapshot = sim.state.get_snapshot()
render(final_snapshot)
[12]:
_images/tutorial_00-Introducing-HOOMD-blue_04-Randomizing-the-System_21_0.png
[13]:
initial_snapshot.particles.position[0:4]
[13]:
array([[-3.5999999 , -3.5999999 , -3.5999999 ],
       [-3.5999999 , -3.5999999 , -2.4000001 ],
       [-3.5999999 , -3.5999999 , -1.20000005],
       [-3.5999999 , -3.5999999 ,  0.        ]])
[14]:
final_snapshot.particles.position[0:4]
[14]:
array([[-0.34045062, -3.40372881,  0.97162443],
       [ 0.37658316,  2.24546797, -1.57884474],
       [ 2.89672535, -0.69444436, -3.18158696],
       [-1.60254438, -1.12832378, -0.05738665]])
[15]:
initial_snapshot.particles.orientation[0:4]
[15]:
array([[1., 0., 0., 0.],
       [1., 0., 0., 0.],
       [1., 0., 0., 0.],
       [1., 0., 0., 0.]])
[16]:
final_snapshot.particles.orientation[0:4]
[16]:
array([[-0.1604707 ,  0.00679003,  0.56703214,  0.80788464],
       [ 0.30537333,  0.06005637,  0.66613445, -0.6777944 ],
       [-0.83000904, -0.09179543,  0.40795323, -0.36909723],
       [ 0.52359268, -0.49392678, -0.68970674, -0.07868712]])

The particle positions and orientations have indeed changed significantly, telling us that the system is well randomized.

Save the final configuration to a GSD file for use in the next stage of the simulation:

[17]:
hoomd.write.GSD.write(state=sim.state, mode='xb', filename='random.gsd')

The next section of the tutorial takes random.gsd and compresses it down to a higher density.

Compressing the System#
Overview#
Questions#
  • How do I compress the system to a target density?

  • What is a volume fraction?

Objectives#
  • Show how to compute the volume fraction of a system.

  • Explain how how an Updater is an operation that modifies the system when its Trigger returns True.

  • Demonstrate using the QuickCompress updater to achieve a target volume fraction.

  • Demonstrate using the MoveSize tuner to adjust the trial move size.

Boilerplate code#
[1]:
import copy
import math

import hoomd

The render function in the next (hidden) cell will render a snapshot using fresnel. Find the source in the hoomd-examples repository.

Volume fraction#

Self-assembly in hard particle systems typically occurs at a volume fraction above 0.5. The volume fraction is the ratio of the volume occupied by the particles to the volume of the periodic box.

So far, this tutorial as randomized a system of N octahedra in a box with a very low volume fraction and stored that in random.gsd. Initialize a Simulation with this configuration and see what volume fraction it is at:

[4]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=20)
sim.create_state_from_gsd(filename='random.gsd')

Compute the volume of the octahedron:

[5]:
a = math.sqrt(2) / 2
V_particle = 1 / 3 * math.sqrt(2) * a**3

Compute the volume fraction:

[6]:
initial_volume_fraction = (sim.state.N_particles * V_particle
                           / sim.state.box.volume)
print(initial_volume_fraction)
0.05715592589579699

As you can see, this volume fraction is very low and the box volume needs to be significantly reduced to achieve a volume fraction above 0.5.

Use HPMC to move particles into non-overlapping configurations while you compress the system. Set up the HPMC integrator for the octahedron simulations:

[7]:
mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape['octahedron'] = dict(vertices=[
    (-0.5, 0, 0),
    (0.5, 0, 0),
    (0, -0.5, 0),
    (0, 0.5, 0),
    (0, 0, -0.5),
    (0, 0, 0.5),
])
sim.operations.integrator = mc
The QuickCompress updater#

An Updater is a type of operation in HOOMD-blue that makes changes to the state. To use an Updater, first instantiate the object, assign a Trigger, and add it to the Simulation. Simulation will apply the Updater on time steps where the Trigger returns True. The Periodic trigger returns True every period steps.

QuickCompress is an Updater that works with HPMC to quickly compress the box to a target volume. When triggered, QuickCompress reduces the box volume by a scale factor, while allowing slight overlaps between the particles. It then waits for the translation and rotation trial moves to remove these overlaps before it reduces the volume again. This process temporarily produces invalid system configurations, but is much quicker than a process that does not allow temporary overlaps.

Compute the final box size with a volume fraction above 0.5 and configure a QuickCompress to trigger every 10 time steps.

[8]:
initial_box = sim.state.box
final_box = hoomd.Box.from_box(initial_box)
final_volume_fraction = 0.57
final_box.volume = sim.state.N_particles * V_particle / final_volume_fraction
compress = hoomd.hpmc.update.QuickCompress(trigger=hoomd.trigger.Periodic(10),
                                           target_box=final_box)

Add the Updater to the Simulation:

[9]:
sim.operations.updaters.append(compress)
The MoveSize tuner#

A Tuner is another type of operation. Tuners make changes to other operations to improve performance. In HPMC, the translation and rotation trial move sizes have a huge performance impact. When the move size is too small it takes many time steps to make appreciable changes to the system. When the move size is too large very few moves are accepted and it again takes many time steps to make appreciable changes. The system makes the most progress at moderate move sizes and, in most cases, the optimal acceptance ratio is 20%. The MoveSize tuner monitors the acceptance ratio and adjusts d and a to achieve the target.

The optimal move size depends on the density of the system. QuickCompress changes the density rapidly during compression, so use the MoveSize tuner to adjust the move sizes regularly:

[10]:
periodic = hoomd.trigger.Periodic(10)
tune = hoomd.hpmc.tune.MoveSize.scale_solver(moves=['a', 'd'],
                                             target=0.2,
                                             trigger=periodic,
                                             max_translation_move=0.2,
                                             max_rotation_move=0.2)
sim.operations.tuners.append(tune)
Run until complete#

When the QuickCompress updater achieves the target box size and there are no overlaps between particles, the compression process is complete. The number of time steps needed to achieve this varies based on parameters. Check the compress.complete property regularly and stop running the simulation when the compression completes:

[11]:
while not compress.complete and sim.timestep < 1e6:
    sim.run(1000)

The sim.timestep < 1e6 check ensures that this while loop will not waste resources in cases where the compression will never complete. The loop should complete before that point:

[12]:
sim.timestep
[12]:
13000

Check to see if the compression completed successfully:

[13]:
if not compress.complete:
    raise RuntimeError("Compression failed to complete")

The MoveSize tuner should have adjusted the move sizes to relatively small values at the final density:

[14]:
mc.a['octahedron']
[14]:
0.0573165403351847
[15]:
mc.d['octahedron']
[15]:
0.031253275743820426

Now that the compression is complete, the particles are much closer together and not overlapping, but still arranged randomly.

[16]:
render(sim.state.get_snapshot())
[16]:
_images/tutorial_00-Introducing-HOOMD-blue_05-Compressing-the-System_30_0.png

Save the final configuration to a GSD file for use in the next stage of the simulation:

[17]:
hoomd.write.GSD.write(state=sim.state, mode='xb', filename='compressed.gsd')
Equilibrating the System#
Overview#
Questions#
  • What is equilibration?

  • How do I save simulation results?

Objectives#
  • Explain the process of equilibration.

  • Demonstrate using GSD to write the simulation trajectory to a file.

  • Demonstrate best practices for move size tuning using Before and And Triggers.

Boilerplate code#
[1]:
import math

import hoomd

The render function in the next (hidden) cell will render a snapshot using fresnel. Find the source in the hoomd-examples repository.

Equilibration#

So far, this tutorial has placed N non-overlapping octahedra randomly in a box and then compressed it to a moderate volume fraction. The resulting configuration of particles is valid, but strongly dependent on the path taken to create it. There are many more equilibrium configurations in the set of possible configurations that do not depend on the path. Equilibrating the system is the process of taking an artificially prepared state and running a simulation. During the simulation run, the system will relax to equilibrium. Initialize the Simulation first:

[4]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=20)
mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape['octahedron'] = dict(vertices=[
    (-0.5, 0, 0),
    (0.5, 0, 0),
    (0, -0.5, 0),
    (0, 0.5, 0),
    (0, 0, -0.5),
    (0, 0, 0.5),
])
sim.operations.integrator = mc

The previous section of this tutorial wrote the compressed system to compressed.gsd. Initialize the system state from this file:

[5]:
sim.create_state_from_gsd(filename='compressed.gsd')
Writing simulation trajectories#

Save the system state to a file periodically so that you can observe the equilibration process. This tutorial previously used GSD files to store a single frame of the system state using either the GSD Python package or GSD.write. The GSD Writer (another operation) will create a GSD file with many frames in a trajectory.

We use the 'xb' mode to open the file to ensure that the file does not exist before opening it. If the file does exist an error will be raised rather than overwriting or appending to the file.

[6]:
gsd_writer = hoomd.write.GSD(filename='trajectory.gsd',
                             trigger=hoomd.trigger.Periodic(1000),
                             mode='xb')
sim.operations.writers.append(gsd_writer)
Tuning the trial move size#

The previous section used the MoveSize tuner regularly during compression to adjust d and a to achieve a target acceptance ratio while the system density changed rapidly. Use it again during the equilibration run to ensure that HPMC is working optimally.

Move sizes should be tuned briefly at the beginning, then left constant for the duration of the run. Changing the move size throughout the simulation run violates detailed balance and can lead to incorrect results. Trigger the tuner every 100 steps but only for the first 5000 steps of the simulation by combining a Periodic and Before trigger with an And operation. Before returns True for all time steps t < value and the And trigger returns True when all of its child triggers also return True.

[7]:
tune = hoomd.hpmc.tune.MoveSize.scale_solver(
    moves=['a', 'd'],
    target=0.2,
    trigger=hoomd.trigger.And([
        hoomd.trigger.Periodic(100),
        hoomd.trigger.Before(sim.timestep + 5000)
    ]))
sim.operations.tuners.append(tune)
[8]:
sim.run(5000)

Check the acceptance ratios over the next 100 steps to verify that the tuner achieved the target acceptance ratios:

[9]:
sim.run(100)
[10]:
rotate_moves = mc.rotate_moves
mc.rotate_moves[0] / sum(mc.rotate_moves)
[10]:
0.18988232534500957
[11]:
translate_moves = mc.translate_moves
mc.translate_moves[0] / sum(mc.translate_moves)
[11]:
0.1901174817532493
Equilibrating the system#

To equilibrate the system, run the simulation. The length of the run needed is strongly dependent on the particular model, the system size, the density, and many other factors. Hard particle Monte Carlo self-assembly often takes tens of millions of time steps for systems with ~10,000 particles. This system is much smaller, so it takes fewer steps.

This cell may require several minutes to complete.

[12]:
sim.run(1e5)

Here is the final state of the system after the run.

[13]:
render(sim.state.get_snapshot())
[13]:
_images/tutorial_00-Introducing-HOOMD-blue_06-Equilibrating-the-System_21_0.png

Is the final state an equilibrium state? The next section in this tutorial shows you how to analyze the trajectory and answer this question.

Flush the GSD write buffer. This is necessary if you run the notebook in the next section without shutting down this notebook first.

[14]:
gsd_writer.flush()
Analyzing Trajectories#
Overview#
Questions#
  • How can I analyze trajectories?

Objectives#
  • Describe how to access trajectory frames in GSD.

  • Examine the trajectory with freud and fresnel.

Boilerplate code#
[1]:
import math

import fresnel
import freud
import gsd.hoomd
import matplotlib

%matplotlib inline
matplotlib.style.use('ggplot')
import matplotlib_inline

matplotlib_inline.backend_inline.set_matplotlib_formats('svg')

The render function in the next (hidden) cell will render a snapshot using fresnel. render_movie will render a sequence of frames as an animated GIF. These methods accept a particles argument that filters out which particles to display. Find the source in the hoomd-examples repository.

Equilibration challenges#

In the previous section, you ran the hard octahedra system for many time steps to equilibrate it and saved the trajectory in trajectory.gsd. Is the final state you obtained actually an equilibrium state? Statistical mechanics tells us that as long as our system is ergodic it will eventually achieve equilibrium. You need to analyze this trajectory to determine if you have achieved the ordered equilibrium structure.

Tools#

There are many tools that can read GSD files and analyze or visualize the simulations, and many more Python packages that can work with the numerical data. This tutorial will show you how to use freud to determine which particles are in a solid-like environment and fresnel to render system configurations. The freud Python package provides a simple, flexible, powerful set of tools for analyzing trajectories obtained from molecular dynamics or Monte Carlo simulations. The fresnel Python package produces publication quality renders with soft lighting, depth of field and other effects.

While outside the scope of this tutorial, you might want to use tools such as OVITO or VMD to visualize the trajectory interactively. OVITO has built-in support for GSD files. The gsd-vmd plugin adds support to VMD.

Read the trajectory#

Use GSD to open the trajectory generated by the previous section of this tutorial.

[3]:
traj = gsd.hoomd.open('trajectory.gsd')

You can index into the frames of the trajectory like a list. See how many frames exist in the trajectory:

[4]:
len(traj)
[4]:
105
Ergodicity#

A system is ergodic when it can explore all possible states by making small moves from one to another. In HPMC simulations, low volume fraction simulations are ergodic while very high volume fraction ones are not. At high volume fractions, there isn’t enough free space for the particles to rearrange so they get stuck in local configurations.

Visualize the motion of just a few particles to see if they appear stuck or if they are freely moving about the box:

[5]:
render_movie(traj[0:50:5], particles=[12, 18])
_images/tutorial_00-Introducing-HOOMD-blue_07-Analyzing-Trajectories_11_0.png

Good! Over the first part of the simulation (while the system is still fluid), individual particles are able to move a significant distance and explore many different orientations. This indicates that our system is ergodic.

Simulation length#

How can you tell if you have run long enough to equilibrate the system? The hard octahedra system forms the bcc structure by nucleation and growth. Nucleation is a rare event, so you need to keep running the simulation until it occurs. If you ran this simulation many times with different random seeds, each would take a different number of steps to nucleate. You need to examine the simulation trajectory in detail to determine if you have run it long enough.

[6]:
render_movie(traj[0:100:12])
_images/tutorial_00-Introducing-HOOMD-blue_07-Analyzing-Trajectories_14_0.png

Can you see the system ordering? The orientations of the octahedra appear to quickly snap to face the same direction and the particle positions line up on evenly spaced planes. You can use freud’s SolidLiquid analysis method to quantitatively identify which particles are in the solid structure.

Loop over all of the frames in the file and create a boolean array that indicates which particles are in a solid environment:

[7]:
solid = freud.order.SolidLiquid(l=6, q_threshold=0.7, solid_threshold=6)
is_solid = []
for frame in traj:
    solid.compute(system=(frame.configuration.box, frame.particles.position),
                  neighbors=dict(mode='nearest', num_neighbors=8))
    is_solid.append(solid.num_connections > solid.solid_threshold)

Plot the total number of particles in a solid environment over time:

[8]:
fig = matplotlib.figure.Figure(figsize=(5, 3.09))
ax = fig.add_subplot()
num_solid = numpy.array([numpy.sum(a) for a in is_solid])
ax.plot(num_solid)
ax.set_xlabel('frame')
ax.set_ylabel('number of particles in a solid environment')
fig
[8]:
_images/tutorial_00-Introducing-HOOMD-blue_07-Analyzing-Trajectories_18_0.svg

This plot confirms what you saw visually and what you should expect in a system that nucleates and grows a crystal. There is no solid at the beginning of the simulation. Then a solid cluster forms and grows to fill the box.

Visualize just the solid particles to see this more clearly:

[9]:
start_frame = int(numpy.argmax(num_solid > 4))
end_frame = int(numpy.argmax(num_solid == numpy.max(num_solid)))
step = int((end_frame - start_frame) / 6)
render_movie(traj[start_frame:end_frame:step],
             is_solid=is_solid[start_frame:end_frame:step])
_images/tutorial_00-Introducing-HOOMD-blue_07-Analyzing-Trajectories_20_0.png

This is the end of the first tutorial! It covered the core HOOMD-blue objects, described hard particle Monte Carlo simulations, and demonstrated how to initialize, randomize, compress, equilibrate, and analyze a system of self-assembling hard octahedra. See the other HOOMD-blue tutorials to learn about other concepts, or browse the reference documentation for more information.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Introducing Molecular Dynamics#

This tutorial introduces the molecular dynamics simulation in HOOMD-blue using the Lennard-Jones system as an example.

Prerequisites:

This tutorial assumes you are familiar with the concepts taught in the tutorial Introducing HOOMD-blue and have some background knowledge on statistical mechanics.

Molecular Dynamics Simulations#
Overview#
Questions#
  • What is molecular dynamics?

  • How do I set up a molecular dynamics simulation in HOOMD-blue?

Objectives#
  • Describe the equations of motion of the system and HOOMD-blue solves them with time steps.

  • Define forces, potential energy and explain how HOOMD-blue evaluates pair potentials within a cutoff.

  • Explain how the MD Integrator and integration methods solve the equations of motion and allow for different thermodynamic ensembles.

Boilerplate code#
[1]:
import hoomd
import matplotlib
import numpy

%matplotlib inline
matplotlib.style.use('ggplot')
import matplotlib_inline

matplotlib_inline.backend_inline.set_matplotlib_formats('svg')
Equations of motion#

Molecular dynamics simulations model the movement of particles over time by solving the equations of motion numerically, advancing the state of the system forward by time dt on each time step. You can use molecular dynamics to model dynamic, time dependent processes (like fluid flow) or thermodynamic equilibrium states (like crystals). This tutorial models a system of Lennard-Jones particles crystallizing.

The Integrator class in the md package implements molecular dynamics integration in HOOMD-blue:

[2]:
integrator = hoomd.md.Integrator(dt=0.005)

The dt property sets the step size \(\Delta t\):

[3]:
integrator.dt
[3]:
0.005
Forces#

The force term in the equations of motion determines how particles interact. The forces Integrator property is the list of forces applied to the system. The default is no forces:

[4]:
integrator.forces[:]
[4]:
[]

You can add any number of Force objects to this list. Each will compute forces on all particles in the system state. Integrator will add all of the forces together into the net force used in the equations of motion.

HOOMD-blue provides a number of forces that are derived from potential energy. Pair potentials define the functional form of the potential energy between a single pair of particles given their separation distance r. The Lennard-Jones potential is:

\[V_{\mathrm{LJ}}(r) = 4 \varepsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - \left(\frac{\sigma}{r}\right)^6 \right]\]
[5]:
sigma = 1
epsilon = 1
r = numpy.linspace(0.95, 3, 500)
V_lj = 4 * epsilon * ((sigma / r)**12 - (sigma / r)**6)

fig = matplotlib.figure.Figure(figsize=(5, 3.09))
ax = fig.add_subplot()
ax.plot(r, V_lj)
ax.set_xlabel('r')
ax.set_ylabel('V')
fig
[5]:
_images/tutorial_01-Introducing-Molecular-Dynamics_01-Molecular-Dynamics-Simulations_10_0.svg

While pair potentials are nominally defined between all pairs of particles, Molecular dynamics simulations evaluate short ranged pair potentials only for \(r \lt r_{\mathrm{cut}}\) to make the computation fast through the use of a neighbor list. By default, HOOMD-blue introduces a discontinuity in V at \(r=r_{\mathrm{cut}}\), though there are options to shift or smooth the potential at the cutoff.

HOOMD-blue provides several neighbor list options to choose from. Cell performs well in most situations. The buffer parameter sets an extra distance to include in the neighbor list, so it can be used for multiple timesteps without recomputing neighbors. Choose a value that minimizes the time to execute your simulation.

[6]:
cell = hoomd.md.nlist.Cell(buffer=0.4)

Construct the LJ pair force object to compute the Lennard-Jones interactions:

[7]:
lj = hoomd.md.pair.LJ(nlist=cell)

Pair potentials accept parameters for every pair of particle types in the simulation. Define a single A-A interaction for this tutorial:

[8]:
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5

Add the force to the Integrator:

[9]:
integrator.forces.append(lj)

Now, the Integrator will compute the net force term using the Lennard-Jones pair force.

Integration methods#

HOOMD-blue provides a number of integration methods, which define the equations of motion that apply to a subset of the particles in the system. The ConstantVolume method implements Newton’s laws while the thermostat scales the velocities to sample the canonical ensemble.

Lennard-Jones particles crystallize readily at constant temperature and volume. One of the points in the solid area of the phase diagram is \(kT=1.5\) at a number density \(\rho=1.2\) Apply the ConstantVolume method with the Bussi thermostat to all particles (later sections in this tutorial will set the density):

[10]:
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))

kT is the temperature multiplied by Boltzmann’s constant and has units of energy. tau is a time constant that controls the amount of coupling between the thermostat and particle’s degrees of freedom. filter is a particle filter object that selects which particles this integration method applies to. You can apply multiple integration methods to different sets of particles or leave some particles fixed.

Add the method to the Integrator:

[11]:
integrator.methods.append(nvt)

Now, you have defined a molecular dynamics integrator with a step size dt that will use the ConstantVolume integration method with the Bussi thermostat on all particles interacting via the Lennard-Jones potential.

The remaining sections in this tutorial will show you how to initialize a random low density state, compress the system to a target density, and run the simulation long enough to self-assemble an ordered state.

Initializing a Random System#
Overview#
Questions#
  • How can I generate a random initial condition?

  • What units does HOOMD-blue use?

Objectives#
  • Describe the units HOOMD employs in molecular dynamics simulations.

  • Demonstrate how to place particles on an initial lattice and randomize the configuration with an MD simulation.

  • Explain why initial random velocities are important when using the ConstantVolume integration method.

  • Show how to use ThermodynamicQuantities to compute properties of the system.

  • Address the difference between kinetic temperature and temperature.

Boilerplate code#
[1]:
import itertools
import math

import gsd.hoomd
import hoomd
import numpy

The render function in the next (hidden) cell will render the system state using fresnel. Find the source in the hoomd-examples repository.

Procedure#

One effective way to initialize a random configuration of particles is to start with a low density non-overlapping configuration and run a simulation that compresses the system to the target density. This section of the tutorial will place particles on a simple cubic lattice and run a short simulation allowing them to relax into the fluid state.

Units#

You need to know what system of units HOOMD-blue uses so that you can place particles at appropriate separations in the initial configuration.

HOOMD-blue does not adopt any particular real system of units. Instead, HOOMD-blue uses an internally self-consistent system of units and is compatible with many systems of units. For example: if you select the units of meter, Joule, and kilogram for length, energy and mass then the units of force will be Newtons and velocity will be meters/second. A popular system of units for nano-scale systems is nanometers, kilojoules/mol, and atomic mass units.

In molecular dynamics, the primary units are length, energy, and mass. Other units are derived from these, for example \([\mathrm{pressure}] = \left(\frac{\mathrm{[energy]}}{\mathrm{[length]}^3}\right)\) and \([\mathrm{time}] = \sqrt{\frac{\mathrm{[mass]}\cdot\mathrm{[length]}^2}{\mathrm{[energy]}}}\). Some quantities involve physical constants as well, such as charge which has units of \(\sqrt{4\pi\epsilon_0\cdot\mathrm{[length]}\cdot\mathrm{[energy]}}\) (where \(\epsilon_0\) is the permittivity of free space), and thermal energy \(kT\) (where k is Boltzmann’s constant). HOOMD-blue never uses the temperature T directly. Instead it always appears indirectly in the value \(kT\) which has units of energy.

HOOMD-blue does not perform unit conversions. You provide all parameters in this system of units and all outputs will be given in these units. The documentation for each property and parameter will list the units. For the parameters set in this tutorial so far, the integrator’s dt is in time units, the pair potentials epsilon is in energy units while sigma and r_cut are in length units.

You can interpret these values in the nano-scale units mentioned previously:

Unit

Value

[length]

nanometer

[energy]

kilojoules/mol

[mass]

atomic mass unit

[time]

picoseconds

[volume]

cubic nanometers

[velocity]

nm/picosecond

[momentum]

amu nm/picosecond

[acceleration]

nm/picosecond^2

[force]

kilojoules/mol/nm

[pressure]

kilojoules/mol/nm^3

k

0.0083144626181532 kJ/mol/Kelvin

For example, the values used in this tutorial could represent a system with 1 nanometer diameter particles that interact with a well depth of 1 kilojoule/mol at a thermal energy pf 1.5 kilojoules/mol (which implies \(T \approx 180\) Kelvin).

Initial condition#

The Lennard-Jones system self-assembles the the fcc structure at moderately high densities. To keep this tutorial’s run time short, it simulates a small number of particles commensurate with the fcc structure (4 * m**3, where m is an integer).

[4]:
m = 4
N_particles = 4 * m**3

In molecular dynamics, particles can theoretically have any position in the periodic box. However, the steepness of the Lennard-Jones potential near \(r \approx \sigma\) leads to extremely large forces that destabilize the numerical integration method. Practically, you need to choose an initial condition with particles where their hard cores do not overlap. The Lennard-Jones potential used in this tutorial represents a sphere with diameter ~1, so place particles a little bit further than that apart on a KxKxK simple cubic lattice of width L. Later, this section will run an MD simulation allowing the particles to expand and fill the box randomly.

This is the same code you used in Introducing HOOMD-blue tutorial. See that tutorial for a more detailed description.

[5]:
spacing = 1.3
K = math.ceil(N_particles**(1 / 3))
L = K * spacing
x = numpy.linspace(-L / 2, L / 2, K, endpoint=False)
position = list(itertools.product(x, repeat=3))

frame = gsd.hoomd.Frame()
frame.particles.N = N_particles
frame.particles.position = position[0:N_particles]
frame.particles.typeid = [0] * N_particles
frame.configuration.box = [L, L, L, 0, 0, 0]

The single particle type needs a name. Call it A because it is short and the first letter of the alphabet:

[6]:
frame.particles.types = ['A']

Here is what the system looks like now:

[7]:
render(frame)
[7]:
_images/tutorial_01-Introducing-Molecular-Dynamics_02-Initializing-a-Random-System_14_0.png

Write this snapshot to lattice.gsd:

[8]:
with gsd.hoomd.open(name='lattice.gsd', mode='x') as f:
    f.append(frame)
Initialize the simulation#

Configure this simulation to run on the CPU:

[9]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)
sim.create_state_from_gsd(filename='lattice.gsd')

The simulation seed will be used when randomizing velocities later in the notebook.

Set up the molecular dynamics simulation, as discussed in the previous section of this tutorial:

[10]:
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)

Assign the integrator to the simulation:

[11]:
sim.operations.integrator = integrator
Setting random velocities#

In HOOMD-blue, velocities default to 0:

[12]:
snapshot = sim.state.get_snapshot()
snapshot.particles.velocity[0:5]
[12]:
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

When using the ConstantVolume or ConstantPressure method with a thermostat, you must specify non-zero initial velocities. The thermostat modifies particle velocities by a scale factor so it cannot scale a zero velocity to a non-zero one. The thermalize_particle_momenta method will assign Gaussian distributed velocities consistent with the the canonical ensemble. It also sets the velocity of the center of mass to 0:

[13]:
sim.state.thermalize_particle_momenta(filter=hoomd.filter.All(), kT=1.5)

You can inspect the snapshot to see the changes that thermalize_particle_momenta produced. Use the ThermodynamicQuantities class to compute properties of the system:

[14]:
thermodynamic_properties = hoomd.md.compute.ThermodynamicQuantities(
    filter=hoomd.filter.All())

ThermodynamicQuantities is a Compute, an Operation that computes properties of the system state. Some computations can only be performed during or after a simulation run has started. Add the compute to the operations list and call run(0) to make all all properties available without changing the system state:

[15]:
sim.operations.computes.append(thermodynamic_properties)
sim.run(0)

There are \((3 N_{\mathrm{particles}} - 3)\) degrees of freedom in the system. The ConstantVolume integration method conserves linear momentum, so the - 3 accounts for the effectively pinned center of mass.

[16]:
thermodynamic_properties.degrees_of_freedom
[16]:
765.0

Following the equipartition theorem, the average kinetic energy of the system should be approximately \(\frac{1}{2}kTN_{\mathrm{dof}}\).

[17]:
1 / 2 * 1.5 * thermodynamic_properties.degrees_of_freedom
[17]:
573.75
[18]:
thermodynamic_properties.kinetic_energy
[18]:
566.7599495184154

Why isn’t this exactly equal? Doesn’t this kinetic energy correspond to a different temperature than was set?

[19]:
thermodynamic_properties.kinetic_temperature
[19]:
1.4817253582180794

No, it doesn’t. The instantaneous kinetic temperature \(T_k\) (\(kT_k\) in energy units here) of a finite number of particles fluctuates! The canonical ensemble holds the number of particles, volume, and the thermodynamic temperature constant. Other thermodynamic quantities like kinetic energy (and thus kinetic temperature) will fluctuate about some average. Both that average and the scale of the fluctuations are well defined by statistical mechanics.

Run the simulation#

Run the simulation forward in time to randomize the particle positions. As the simulation progresses, it will move from the initial highly ordered state to a random fluid that fills the box.

[20]:
sim.run(10000)

Here is the final random configuration of particles:

[21]:
render(sim.state.get_snapshot())
[21]:
_images/tutorial_01-Introducing-Molecular-Dynamics_02-Initializing-a-Random-System_42_0.png
[22]:
thermodynamic_properties.kinetic_energy
[22]:
605.8748723167911

Here, you can see that the instantaneous kinetic energy of the system has taken on a different value. Depending on the random number seed and other conditions when this notebook runs, this value may be smaller or larger than the expected average value, but it should remain relatively close to the expected average.

Now, you’ve created an initial random configuration of Lennard-Jones particles in a low density fluid. Save the final configuration to a GSD file for use in the next stage of the simulation:

[23]:
hoomd.write.GSD.write(state=sim.state, filename='random.gsd', mode='xb')

The next section of this tutorial will compress this initial condition to a higher density where it will assemble an ordered structure.

Compressing the System#
Overview#
Questions#
  • How do I compress the system to a target density?

Objectives#
  • Describe how Variants describe values that vary with the timestep.

  • Show how to use BoxResize with a Ramp variant to slowly compress the system to the target volume.

  • Demonstrate the crystallization of Lennard-Jones particles

Boilerplate code#
[1]:
import math

import fresnel
import hoomd
import matplotlib

%matplotlib inline
matplotlib.style.use('ggplot')
import matplotlib_inline

matplotlib_inline.backend_inline.set_matplotlib_formats('svg')

The render function in the next (hidden) cell will render the system state using fresnel. Find the source in the hoomd-examples repository.

Procedure#

random.gsd, generated by the previous section of this tutorial has particles randomly placed in a low density fluid state. To find the crystalline state, you need to compress the system to a higher density. If you were to immediately scale the system to the target density, the particle’s hard cores would overlap and the integrator would be become unstable. A more effective strategy gradually resizes the simulation box a little at a time over the course of a simulation, allowing any slight overlaps to relax.

Initialize the simulation#

Configure this simulation to run on the CPU.

[3]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)
sim.create_state_from_gsd(filename='random.gsd')

Set up the molecular dynamics simulation, as discussed in the previous sections of this tutorial:

[4]:
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator
Variants#

The BoxResize class performs scales the simulation box. You provide a Variant that tells BoxResize how to interpolate between two boxes, box1 and box2, over time. A Variant is a scalar-valued function of the simulation timestep. BoxResize sets box1 when the function is at its minimum, box2 when the function is at its maximum, and linearly interpolates between the two boxes for intermediate values.

Use the Ramp variant to define a function that ramps from one value to another over a given number of steps. Note that this simulation does not start at timestep 0, random.gsd was saved after running a number of steps to randomize the system in the previous section:

[5]:
sim.timestep
[5]:
10000

Create a Ramp that starts at this step and ends 100,000 steps later:

[6]:
ramp = hoomd.variant.Ramp(A=0, B=1, t_start=sim.timestep, t_ramp=20000)

Here is what the ramp looks like as a function of timestep:

[7]:
steps = range(0, 40000, 20)
y = [ramp(step) for step in steps]

fig = matplotlib.figure.Figure(figsize=(5, 3.09))
ax = fig.add_subplot()
ax.plot(steps, y)
ax.set_xlabel('timestep')
ax.set_ylabel('ramp')
ax.tick_params('x', labelrotation=30)
fig
[7]:
_images/tutorial_01-Introducing-Molecular-Dynamics_03-Compressing-the-System_14_0.svg
Gradually resize the simulation box#

Now, you need to determine the initial simulation box box1 and final simulation box at the target density box2. This is the initial number density \(\rho\) of the current simulation box:

[8]:
rho = sim.state.N_particles / sim.state.box.volume
rho
[8]:
0.3397157902913389

Create a new Box at the target number density:

[9]:
initial_box = sim.state.box
final_box = hoomd.Box.from_box(initial_box)  # make a copy of initial_box
final_rho = 1.2
final_box.volume = sim.state.N_particles / final_rho

To avoid destabilizing the integrator with large forces due to large box size changes, scale the box with a small period.

[10]:
box_resize_trigger = hoomd.trigger.Periodic(10)

Construct the BoxResize updater and add it to the simulation.

[11]:
box_resize = hoomd.update.BoxResize(box1=initial_box,
                                    box2=final_box,
                                    variant=ramp,
                                    trigger=box_resize_trigger)
sim.operations.updaters.append(box_resize)

Run the simulation to compress the box.

[12]:
sim.run(10001)

At the half way point of the ramp, the variant is 0.5 and the current box lengths are half way between the initial and final ones:

[13]:
ramp(sim.timestep - 1)
[13]:
0.5
[14]:
current_box = sim.state.box
(current_box.Lx - initial_box.Lx) / (final_box.Lx - initial_box.Lx)
[14]:
0.5

Finish the rest of the compression:

[15]:
sim.run(10000)

The current box matches the final box:

[16]:
sim.state.box == final_box
[16]:
True

The system is at a higher density:

[17]:
render(sim.state.get_snapshot())
[17]:
_images/tutorial_01-Introducing-Molecular-Dynamics_03-Compressing-the-System_33_0.png

Now that the system has reached the target volume, remove the BoxResize updater from the simulation:

[18]:
sim.operations.updaters.remove(box_resize)
Equilibrating the system#

Run the simulation for a longer time and see if it self assembles the ordered fcc structure:

This cell may require several minutes to complete.

[19]:
sim.run(5e5)

Here is what the final state of the system looks like:

[20]:
render(sim.state.get_snapshot())
[20]:
_images/tutorial_01-Introducing-Molecular-Dynamics_03-Compressing-the-System_39_0.png
Analyzing the simulation results#

Is this the fcc structure? Did the system reach equilibrium? These are topics covered in the Introducing HOOMD-blue tutorial. Consider it an exercise to modify this example and implement that analysis here. You will need to save a GSD file with the simulation trajectory, then use freud’s SolidLiquid order parameter to identify when the ordered structure appears.

This is the end of the introducing molecular dynamics tutorial! It described molecular dynamics simulations, demonstrated how to initialize, randomize, compress, and equilibrate a system of Lennard-Jones particles. See the other HOOMD-blue tutorials to learn about other concepts, or browse the reference documentation for more information.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Logging#

This tutorial explains how to log quantities computed during the simulation.

Prerequisites:

While logging is a general topic, this tutorial uses MD and HPMC simulations to demonstrate. The tutorials Introducing HOOMD blue and Introducing Molecular Dynamics teach these concepts.

Logging to a GSD file#
Overview#
Questions#
  • What is a Logger?

  • How can I write thermodynamic and other quantities to a file?

  • How can I access that data?

Objectives#
  • Describe and give examples of loggable quantities.

  • Show how to add quantities to a Logger.

  • Demonstrate GSD as a log writer.

  • Explain how to read logged quantities from GSD files.

  • Describe how namespaces appear in the names of the logged quantities.

Boilerplate code#
[1]:
import gsd.hoomd
import hoomd
import matplotlib

%matplotlib inline
matplotlib.style.use('ggplot')
import matplotlib_inline

matplotlib_inline.backend_inline.set_matplotlib_formats('svg')
Introduction#

HOOMD separates logging into three parts: Loggable quantities, the Logger class, and Writers.

  • Loggable quantities are values computed during a simulation.

  • The Logger class provides a way to collect and name quantities of interest.

  • Writers write these values out in a format you can use.

In this section, you will use the GSD Writer to capture the values of quantities during a simulation run for later analysis.

Define the Simulation#

This tutorial executes the Lennard-Jones particle simulation from a previous tutorial. See Introducing Molecular Dyamics for a complete description of this code.

[3]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)
sim.create_state_from_gsd(
    filename='../01-Introducing-Molecular-Dynamics/random.gsd')

integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator
sim.run(0)
Loggable quantities#

Many classes in HOOMD-blue provide special properties called loggable quantities. For example, the Simulation class provides timestep, tps, and others. The reference documentation labels each of these as Loggable. You can also examine the loggables property to determine the loggable quantities:

[4]:
sim.loggables
[4]:
{'timestep': 'scalar',
 'seed': 'scalar',
 'tps': 'scalar',
 'walltime': 'scalar',
 'final_timestep': 'scalar',
 'initial_timestep': 'scalar'}

The ThermodynamicQuantities class computes a variety of thermodynamic properties in MD simulations. These are all loggable.

[5]:
thermodynamic_properties = hoomd.md.compute.ThermodynamicQuantities(
    filter=hoomd.filter.All())
sim.operations.computes.append(thermodynamic_properties)
thermodynamic_properties.loggables
[5]:
{'kinetic_temperature': 'scalar',
 'pressure': 'scalar',
 'pressure_tensor': 'sequence',
 'kinetic_energy': 'scalar',
 'translational_kinetic_energy': 'scalar',
 'rotational_kinetic_energy': 'scalar',
 'potential_energy': 'scalar',
 'degrees_of_freedom': 'scalar',
 'translational_degrees_of_freedom': 'scalar',
 'rotational_degrees_of_freedom': 'scalar',
 'num_particles': 'scalar',
 'volume': 'scalar'}

Loggable quantities are class properties or methods. You can directly access them in your code.

[6]:
sim.timestep
[6]:
10000
[7]:
thermodynamic_properties.kinetic_temperature
[7]:
1.590511952800884

Each loggable quantity has a category, which is listed both in the reference documentation and in loggables. The category is a string that identifies the quantity’s type or category. Example categories include: * scalar - numbers * sequence - arrays of numbers * string - strings of characters * particle - arrays of per-particle values

Add quantities to a Logger#

Add each of the quantities you would like to store to a Logger. The Logger will maintain these quantities in a list and provide them to the Writer when needed.

[8]:
logger = hoomd.logging.Logger()

You can add loggable quantities from any number of objects to a Logger. Logger uses the namespace of the class to assign a unique name for each quantity. Call add to add all quantities provided by thermodynamic_properties:

[9]:
logger.add(thermodynamic_properties)

You can also select specific quantities to add with the quantities argument. Add only the timestep and walltime quantities from Simulation:

[10]:
logger.add(sim, quantities=['timestep', 'walltime'])
Writing log quantities to a GSD file#

GSD files always store trajectories of particle properties. Set the logger attribute and GSD will also store the selected quantities.

You can store only the logged quantities by using the Null filter to select no particles for the trajectory. This way, you can log thermodynamic properties at a high rate and keep the file size small.

[11]:
gsd_writer = hoomd.write.GSD(filename='log.gsd',
                             trigger=hoomd.trigger.Periodic(1000),
                             mode='xb',
                             filter=hoomd.filter.Null())
sim.operations.writers.append(gsd_writer)

Assign the logger to include the logged quanties in the GSD file:

[12]:
gsd_writer.logger = logger

The writer triggers and writes to the log file when the simulation runs:

[13]:
sim.run(100000)

Flush the GSD buffer so it is readable in the next code cell. In typical workflows, you will run separate simulation and analysis scripts and the buffered writes will automatically flush when your simulation script exits.

[14]:
gsd_writer.flush()
Reading logged data from a GSD file#

Use the gsd package to open read the logged data from the file as a time series:

[15]:
data = gsd.hoomd.read_log('log.gsd')

The data is given as a dictionary of logged quantities:

[16]:
list(data.keys())
[16]:
['configuration/step',
 'log/md/compute/ThermodynamicQuantities/kinetic_temperature',
 'log/md/compute/ThermodynamicQuantities/pressure',
 'log/md/compute/ThermodynamicQuantities/pressure_tensor',
 'log/md/compute/ThermodynamicQuantities/kinetic_energy',
 'log/md/compute/ThermodynamicQuantities/translational_kinetic_energy',
 'log/md/compute/ThermodynamicQuantities/rotational_kinetic_energy',
 'log/md/compute/ThermodynamicQuantities/potential_energy',
 'log/md/compute/ThermodynamicQuantities/degrees_of_freedom',
 'log/md/compute/ThermodynamicQuantities/translational_degrees_of_freedom',
 'log/md/compute/ThermodynamicQuantities/rotational_degrees_of_freedom',
 'log/md/compute/ThermodynamicQuantities/num_particles',
 'log/md/compute/ThermodynamicQuantities/volume',
 'log/Simulation/timestep',
 'log/Simulation/walltime']

The dictionary keys are verbose names that include the namespace of the class which computed the quantity, where . has been replaced with /. For example, access the potential energy computed by ThermodynamicQuantities with the key log/md/compute/ThermodynamicQuantities/potential_energy.

[17]:
data['log/md/compute/ThermodynamicQuantities/potential_energy']
[17]:
array([-541.16848184, -538.2510157 , -555.92434656, -545.85893653,
       -535.23006039, -517.12432502, -544.13966979, -526.39814447,
       -555.8345156 , -537.94766979, -528.2843952 , -586.89526502,
       -541.78340471, -551.94749262, -540.15786035, -553.39114322,
       -549.19073356, -533.78995747, -490.44927437, -541.89523309,
       -520.00291281, -561.04781262, -555.321412  , -543.77743957,
       -537.07698784, -525.72987505, -532.17699725, -534.24742613,
       -552.93672737, -526.5424858 , -536.01512988, -527.03996855,
       -537.68239475, -545.6297033 , -531.31734526, -549.33126689,
       -510.01236357, -544.83615939, -555.9788542 , -547.60028678,
       -542.20816805, -526.11290036, -547.80857561, -531.07254792,
       -541.76204956, -564.17450166, -554.16721091, -557.83533812,
       -562.81678997, -543.18762873, -545.52509576, -543.26962892,
       -549.75278914, -538.75984436, -498.93301358, -525.00576342,
       -544.03644451, -551.76388105, -540.999235  , -541.55498537,
       -521.35958306, -558.43677019, -522.18038932, -541.58546889,
       -547.02938277, -534.05607078, -534.24364094, -548.82765062,
       -543.16414534, -540.0076651 , -521.09221351, -535.69377016,
       -549.78199477, -526.4089212 , -527.43428002, -529.95301829,
       -549.71364237, -534.89772327, -544.17166858, -541.59504569,
       -546.11342335, -554.93353858, -559.46632487, -561.81775964,
       -545.3551808 , -549.83058806, -518.60342943, -548.34210972,
       -520.02792936, -557.97294113, -557.40197179, -533.75834644,
       -541.75305176, -542.5855048 , -577.84045184, -519.09917071,
       -539.70534188, -547.54595226, -546.86513524, -535.34224068])

GSD provides logged quantities as an array with one entry per frame. For example, you can use this to plot the data:

[18]:
timestep = data['configuration/step']
potential_energy = data[
    'log/md/compute/ThermodynamicQuantities/potential_energy']

fig = matplotlib.figure.Figure(figsize=(5, 3.09))
ax = fig.add_subplot()
ax.plot(timestep, potential_energy)
ax.set_xlabel('timestep')
ax.set_ylabel('potential energy')
fig
[18]:
_images/tutorial_02-Logging_01-Logging-to-a-GSD-file_37_0.svg

In this section, you have logged quantities to a GSD file during a simulation run and analyzed that data as a time series. The next section of this tutorial shows you how to save per-particle quantities associated with specific system configurations.

Saving Array Quantities#
Overview#
Questions#
  • How can I save per-particle quantities for later analysis?

  • How can I access that data?

Objectives#
  • Show how to log per-particle properties to a GSD file.

  • Explain how to read logged quantities from a GSD file.

  • Mention that OVITO reads these quantities.

Boilerplate code#
[1]:
import gsd.hoomd
import hoomd
import matplotlib
import numpy

%matplotlib inline
matplotlib.style.use('ggplot')
import matplotlib_inline

matplotlib_inline.backend_inline.set_matplotlib_formats('svg')

The render function in the next (hidden) cell will render the system state using fresnel. Find the source in the hoomd-examples repository.

Array quantities#

You logged a 6-element array quantity in the previous section, the pressure tensor. You can also log larger arrays and per-particle quantities (e.g. energy and force) in a GSD file along with the trajectory. Then you can use utilize the data in your analysis and visualization workflow, such as using OVITO to color particles by energy or display force vectors. When using OVITO, open the GSD file and all logged quantities will be available in the inspector and for use in the pipeline.

Define the Simulation#

This tutorial executes the Lennard-Jones particle simulation from a previous tutorial. See Introducing Molecular Dyamics for a complete description of this code.

[4]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)
sim.create_state_from_gsd(
    filename='../01-Introducing-Molecular-Dynamics/random.gsd')

integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator
sim.run(0)
Logging per-particle quantities#

MD forces provide a number of loggable quantities including their contribution to the system energy, but also per-particle energy contributions (in energies) and per-particle forces, torques, and virials.

[5]:
lj.loggables
[5]:
{'energy': 'scalar',
 'energies': 'particle',
 'additional_energy': 'scalar',
 'forces': 'particle',
 'torques': 'particle',
 'virials': 'particle',
 'additional_virial': 'sequence'}

Add the per-particle LJ energies and forces to a logger:

[6]:
logger = hoomd.logging.Logger()
logger.add(lj, quantities=['energies', 'forces'])
Writing per-particle quantities to a GSD file#

In the previous section, you used the Null filter to produce GSD file with only logged data. In this section, include all particles so that you can associate logged per-particle quantities with the particle properties.

[7]:
gsd_writer = hoomd.write.GSD(filename='trajectory.gsd',
                             trigger=hoomd.trigger.Periodic(10000),
                             mode='xb',
                             filter=hoomd.filter.All(),
                             logger=logger)
sim.operations.writers.append(gsd_writer)

Run the simulation:

[8]:
sim.run(100000)

As discussed in the previous section, flush the write buffer (this is not necessary in typical workflows).

[9]:
gsd_writer.flush()
Reading logged data from a GSD file#

Use the gsd package to open the file:

[10]:
traj = gsd.hoomd.open('trajectory.gsd', mode='r')

The previous section demonstrated how read_log provides time-series data for plotting and analysis. This section shows how the log data for a specific frame is stored in the log dictionary for that frame.

[11]:
traj[0].log.keys()
[11]:
dict_keys(['particles/md/pair/LJ/energies', 'particles/md/pair/LJ/forces'])

GSD prepends particles/ to the logged name of per-particle quantities. The quantities are numpy arrays with N_particles elements. Here are a few slices:

[12]:
traj[-1].log['particles/md/pair/LJ/energies'][0:10]
[12]:
array([-2.56391048, -1.88822176, -1.41906894, -1.62426695, -2.26188433,
       -1.64826228, -1.86217053, -0.9897792 , -2.7154282 , -1.88687963])
[13]:
traj[-1].log['particles/md/pair/LJ/forces'][0:10]
[13]:
array([[ -2.13808166, -19.36630853,  -8.67495909],
       [ -3.28842103,   7.45784515, -12.86546371],
       [  1.46057136,   0.0920419 ,   0.60696098],
       [  3.43611667,  -2.53969686,   1.88552897],
       [  2.66370616,   7.12540725,   8.06113434],
       [ -3.0789833 ,  -6.1846985 ,  -2.16331169],
       [ -7.16193864,   0.16041416,   3.28611542],
       [-21.36195463,   1.10226678,  26.49873349],
       [ -9.56284366,   0.84839853,   0.09193915],
       [  3.31583343,  -1.10904533,  -1.44974825]])

You can use these arrays as inputs to any computation or plotting tools:

[14]:
numpy.mean(traj[-1].log['particles/md/pair/LJ/forces'], axis=0)
[14]:
array([ 1.63064007e-16, -9.71445147e-17, -7.63278329e-17])
[15]:
fig = matplotlib.figure.Figure(figsize=(5, 3.09))
ax = fig.add_subplot()
ax.hist(traj[-1].log['particles/md/pair/LJ/energies'], 100)
ax.set_xlabel('potential energy')
ax.set_ylabel('count')
fig
[15]:
_images/tutorial_02-Logging_02-Saving-Array-Quantities_27_0.svg

As with scalar quantities, the array quantities are stored separately in each frame. Use a loop to access a range of frames and compute time-series data or averages.

This is what the system looks like when you color the particles by the values in particles/md/pair/LJ/energies:

[16]:
render(traj[-1])
[16]:
_images/tutorial_02-Logging_02-Saving-Array-Quantities_30_0.png

In this section, you have logged per-particle quantities to a GSD file during a simulation run and accessed that data with a script. The next section of this tutorial demonstrates how to log particle shape information that OVITO can use.

Storing Particle Shape#
Overview#
Questions#
  • How can I store particle shape for use with visualization tools?

Objectives#
  • Demonstrate logging type_shapes to a GSD file.

  • Explain that OVITO can read this information.

Boilerplate code#
[1]:
import gsd.hoomd
import hoomd
Particle Shape#

HPMC integrators and some anisotropic MD pair potentials model particles that have a well defined shape. You can save this shape definition to a GSD file for use in analysis and visualization workflows. In particular, OVITO will read this shape information and render particles appropriately.

Define the Simulation#

This section executes the hard particle simulation from a previous tutorial. See Introducing HOOMD-blue for a complete description of this code.

[3]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=2)
mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape['octahedron'] = dict(vertices=[
    (-0.5, 0, 0),
    (0.5, 0, 0),
    (0, -0.5, 0),
    (0, 0.5, 0),
    (0, 0, -0.5),
    (0, 0, 0.5),
])
sim.operations.integrator = mc
sim.create_state_from_gsd(
    filename='../00-Introducing-HOOMD-blue/compressed.gsd')
sim.run(0)
Logging particle shape to a GSD file#

The type_shapes loggable quantity is a representation of the particle shape for each type following the type_shapes specification for the GSD file format. In HPMC simulations, the integrator provides type_shapes:

[4]:
mc.loggables
[4]:
{'map_overlaps': 'sequence',
 'overlaps': 'scalar',
 'translate_moves': 'sequence',
 'rotate_moves': 'sequence',
 'mps': 'scalar',
 'type_shapes': 'object'}
[5]:
mc.type_shapes
[5]:
[{'type': 'ConvexPolyhedron',
  'rounding_radius': 0,
  'vertices': [[-0.5, 0, 0],
   [0.5, 0, 0],
   [0, -0.5, 0],
   [0, 0.5, 0],
   [0, 0, -0.5],
   [0, 0, 0.5]]}]

Add the type_shapes quantity to a Logger.

[6]:
logger = hoomd.logging.Logger()
logger.add(mc, quantities=['type_shapes'])

Write the simulation trajectory to a GSD file along with the logged quantities:

[7]:
gsd_writer = hoomd.write.GSD(filename='trajectory.gsd',
                             trigger=hoomd.trigger.Periodic(10000),
                             mode='xb',
                             filter=hoomd.filter.All(),
                             logger=logger)
sim.operations.writers.append(gsd_writer)

Run the simulation:

[8]:
sim.run(20000)

As discussed in the previous section, flush the write buffer (this is not necessary in typical workflows).

[9]:
gsd_writer.flush()
Reading logged shapes from a GSD file#

You can access the shape from scripts using the gsd package:

[10]:
traj = gsd.hoomd.open('trajectory.gsd', mode='r')

type_shapes is a special quantity available via particles.type_shapes rather than the log dictionary:

[11]:
traj[0].particles.type_shapes
[11]:
[{'type': 'ConvexPolyhedron',
  'rounding_radius': 0,
  'vertices': [[-0.5, 0, 0],
   [0.5, 0, 0],
   [0, -0.5, 0],
   [0, 0.5, 0],
   [0, 0, -0.5],
   [0, 0, 0.5]]}]

Open the file in OVITO and it will read the shape definition and render particles appropriately.

In this section, you have logged particle shape to a GSD file during a simulation so that visualization and analysis tools can access it. The next section shows how to write formatted output.

Writing Formatted Output#
Overview#
Questions#
  • How do I display status information during a simulation?

  • How can I log user-defined quantities?

  • How can I write formatted output to a text file?

Objectives#
  • Demonstrate user-defined log quantities.

  • Explain the use of Table to display status information during a simulation run.

  • Show that Table can write to a file.

Boilerplate code#
[1]:
import datetime

import hoomd
Define the Simulation#

This tutorial executes the Lennard-Jones particle simulation from a previous tutorial. See Introducing Molecular Dyamics for a complete description of this code.

[3]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)
sim.create_state_from_gsd(
    filename='../01-Introducing-Molecular-Dynamics/random.gsd')

integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator
Formatted output#

The Table writer formats log quantities in human-readable text and writes them to stdout or a file. Table only supports scalar and string quantities due to the limitations of this format. This section shows you how to use Table to display status information during a simulation run.

Add quantities to a Logger#

The categories argument to Logger defines the categories that it will accept.

[4]:
logger = hoomd.logging.Logger(categories=['scalar', 'string'])

Log the and simulation timestep and tps quantities:

[5]:
logger.add(sim, quantities=['timestep', 'tps'])

You can also log user-defined quantities using functions, callable class instances, or class properties. For example, this class computes the estimated time remaining:

[6]:
class Status():

    def __init__(self, sim):
        self.sim = sim

    @property
    def seconds_remaining(self):
        try:
            return (self.sim.final_timestep - self.sim.timestep) / self.sim.tps
        except ZeroDivisionError:
            return 0

    @property
    def etr(self):
        return str(datetime.timedelta(seconds=self.seconds_remaining))

Assign the loggable quantity using the tuple (object, property_name, flag), where flag is the string name of the flag for this quantity. (The tuple for callable objects would be (callable, flag)).

[7]:
status = Status(sim)
logger[('Status', 'etr')] = (status, 'etr', 'string')

Represent the namespace of your user-defined quantity with a tuple of strings - ('Status', 'etr') above. You can use any number of arbitrary strings in the tuple to name your quantity.

Display quantities with Table#

Table is a Writer that formats the quantities in a Logger into a human readable table. Create one that triggers periodically:

[8]:
table = hoomd.write.Table(trigger=hoomd.trigger.Periodic(period=5000),
                          logger=logger)

Add it to the simulation:

[9]:
sim.operations.writers.append(table)

Run the simulation and see the output:

[10]:
sim.run(100000)
Simulation.timestep  Simulation.tps     Status.etr
       15000           7265.44980     0:00:13.075584
       20000           7928.10708     0:00:11.352016
       25000           8212.82940     0:00:10.349661
       30000           8347.23914     0:00:09.584007
       35000           8415.05520     0:00:08.912598
       40000           8442.75984     0:00:08.291128
       45000           8493.75873     0:00:07.652678
       50000           8532.47563     0:00:07.031957
       55000           8563.96280     0:00:06.422260
       60000           8571.47951     0:00:05.833299
       65000           8598.56480     0:00:05.233432
       70000           8627.01996     0:00:04.636595
       75000           8636.41757     0:00:04.052606
       80000           8647.71201     0:00:03.469126
       85000           8653.31308     0:00:02.889067
       90000           8664.12848     0:00:02.308368
       95000           8659.11603     0:00:01.732278
      100000           8663.85839     0:00:01.154220
      105000           8670.02276     0:00:00.576700
      110000           8674.88580        0:00:00

Later in this notebook, you are going to create another Table Writer. Remove table now to avoid confusing the two:

[11]:
sim.operations.writers.remove(table)
Save Table output to a file#

Table writes to stdout by default. It can write to a file (or any Python file-like object with write and flush methods) instead.

Open the file to write:

[12]:
file = open('log.txt', mode='x', newline='\n')

Create a Table Writer that outputs to this file and add it to the Simulation:

[13]:
table_file = hoomd.write.Table(output=file,
                               trigger=hoomd.trigger.Periodic(period=5000),
                               logger=logger)
sim.operations.writers.append(table_file)

Run the simulation:

[14]:
sim.run(100000)

You can read the file with standard tools:

[15]:
!tail log.txt
      165000           8794.29467     0:00:05.116954
      170000           8809.97435     0:00:04.540308
      175000           8808.18898     0:00:03.973575
      180000           8803.84588     0:00:03.407602
      185000           8793.11174     0:00:02.843135
      190000           8808.44379     0:00:02.270549
      195000           8812.89983     0:00:01.702050
      200000           8815.85406     0:00:01.134320
      205000           8819.50353     0:00:00.566925
      210000           8823.62751        0:00:00

In this section, you have displayed loggable quantities during a simulation run and saved them to a text file. This is the last section in the logging tutorial.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Parallel Simulation With MPI#

This tutorial explains how to run simulations in parallel using MPI.

Prerequisites:

  • This tutorial assumes you are familiar with terms relating to high performance computing clusters, specifically job and scheduler.

  • This tutorial uses molecular dynamics simulations to demonstrate parallel jobs. The tutorial Introducing Molecular Dynamics teaches these concepts.

  • To execute these notebooks locally, you need an MPI enabled version of HOOMD-blue. You can check this by checking that hoomd.version.mpi_enabled is True:

[1]:
import hoomd

hoomd.version.mpi_enabled
[1]:
True

The HOOMD-blue binaries on conda-forge do not enable MPI due to technical limitations.

The system used in Introducing Molecular Dynamics is small. Replicate the state of that system, as MPI parallel simulations require a minimum system size (this requirement is explained in more details in the next section).

[2]:
import hoomd

sim = hoomd.Simulation(device=hoomd.device.CPU())
sim.create_state_from_gsd(
    filename='../01-Introducing-Molecular-Dynamics/random.gsd')
sim.state.replicate(3, 3, 3)
hoomd.write.GSD.write(filename="random.gsd", state=sim.state, mode='wb')
Introduction to MPI#
Overview#
Questions#
  • What is MPI?

  • Why should I run my simulations in parallel?

  • How can I execute scripts in parallel?

Objectives#
  • Describe MPI.

  • Explain how MPI can provide faster performance on HPC systems.

  • Show how to write a single program that can execute in serial or parallel.

  • Demonstrate how to execute that program with mpirun.

  • Explain how strong scaling enables higher performance at the cost of some efficiency.

Introduction#

MPI (message passing interface) is a library that enables programs to execute in parallel. MPI is commonly available on HPC (high performance computing) clusters. HOOMD-blue uses MPI to execute on many CPUs and/or GPUs. Using more resources in parallel can provide higher performance than the same simulation run on one CPU core or one GPU.

The Simulation Script#

This tutorial executes the Lennard-Jones particle simulation from a previous tutorial. See Introducing Molecular Dyamics for a complete description of this code.

You can also run HPMC and other types of simulations in HOOMD-blue using MPI. All operations in HOOMD-blue support MPI unless otherwise noted in their documentation.

[1]:
%pycat lj_performance.py
import hoomd

# Initialize the simulation.
device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device, seed=1)
sim.create_state_from_gsd(filename='random.gsd')

# Set the operations for a Lennard-Jones particle simulation.
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator

# Run a short time before measuring performance.
sim.run(100)

# Run the simulation and print the performance.
sim.run(1000)
device.notice(f'{sim.tps}')

lj_performance.py is a file in the same directory as this notebook. Due to the way MPI launches parallel jobs, the code must be in a file instead of a notebook cell. %pycat is an IPython magic command that displays the contents of a Python file with syntax highlighting.

Compare this script to the one used in Introducing Molecular Dyamics. The only difference is the addition of device.notice(f'{sim.tps}') which prints the performance in time steps per second. The same script can be run in serial or in parallel on different numbers of CPU cores.

Run the simulation with MPI#

Use the MPI launcher mpirun to execute this script in parallel on any number of CPU cores given by the -n option.

Your HPC cluster may use a different launcher that may take different arguments, such as srun, mpiexec, ibrun, or jsrun. See your cluster’s documentation to find the right launcher to use.

In Jupyter, the “!” magic command is equivalent to typing the given command in a shell.

[2]:
!mpirun -n 1 python3 lj_performance.py
336.00885988161735
[3]:
!mpirun -n 2 python3 lj_performance.py
notice(2): Using domain decomposition: n_x = 1 n_y = 1 n_z = 2.
604.2365441053402
[4]:
!mpirun -n 4 python3 lj_performance.py
notice(2): Using domain decomposition: n_x = 1 n_y = 2 n_z = 2.
1086.799408346402

The simulation runs faster on more CPU cores. This sequence of simulations demonstrates strong scaling where a simulation of a fixed number of particles executes in less time on more parallel resources. You can compute the efficiency of the scaling by taking the performance on n cores divided by the performance on one core divided by n. Strong scaling rarely nears 100% efficiency, so it will use more total resources than executing with -n 1. However, a -n 1 simulation may take months to complete while a -n 64 one takes days - making your research much more productive even it if uses a moderately larger amount of HPC resources.

Summary#

In this section, you have executed a HOOMD-blue simulation script on 1, 2, and 4 CPU cores using MPI and observed the performance. The next section of this tutorial explains how HOOMD-blue splits the domain of the simulation and how you should structure your scripts.

Domain Decomposition#
Overview#
Questions#
  • What is a MPI rank?

  • How does HOOMD-blue divide the simulation among the ranks?

  • What limitations prevent parallel execution?

  • How should I structure my scripts?

Objectives#
  • Demonstrate how MPI ranks are assigned to processes.

  • Explain how HOOMD-blue divides the simulation State with a domain decomposition and how operations execute only on the local particles.

  • Demonstrate the minimum domain size.

  • Discuss how particles are placed in domains and how this can lead to uneven load balancing.

  • Emphasize that scripts are a single program that can execute in serial or parallel.

  • Show how to avoid deadlock when using the HOOMD-blue API.

Ranks and processes#

When you call mpirun -n 4 python3 script.py, mpirun launches 4 separate instances of python all executing script.py at the same time. For example, a script that prints a message will repeat the output:

[1]:
%pycat hello_world.py
print('Hello, world')

[2]:
!mpirun -n 4 python3 hello_world.py
Hello, world
Hello, world
Hello, world
Hello, world

MPI launches n separate processes. These may or may not be on the same node in a HPC cluster, depending on how you request resources in your job script. Each process launched this way is called a rank and is given a rank index. In HOOMD-blue, the Communicator class (created by default with Device) gives you access to the rank index.

[3]:
%pycat hello_hoomd.py
import os

import hoomd

device = hoomd.device.CPU()
rank = device.communicator.rank
pid = os.getpid()
print(f'Hello HOOMD-blue rank {rank} from process id {pid}')

[4]:
!mpirun -n 4 python3 hello_hoomd.py
Hello HOOMD-blue rank 2 from process id 965308
Hello HOOMD-blue rank 3 from process id 965309
Hello HOOMD-blue rank 0 from process id 965306
Hello HOOMD-blue rank 1 from process id 965307

os.getpid is Python method that returns the process id, a number assigned to every executing process by the operating system.

Domain decomposition#

When you create the State object in an MPI simulation on more than 1 rank, HOOMD-blue splits the simulation box into k x l x m domains. The product of k, l and m is equal to the number of ranks you execute. Chose n values that factorize given the constraints of your HPC system, such as the number of cores per node. The domains are defined by planes that split the box. By default, the planes are evenly spaced and chosen to minimize the surface area between the domains.

[5]:
%pycat domain_decomposition.py
import hoomd

# Initialize the system.
device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device)
sim.create_state_from_gsd(filename='random.gsd')

# Print the domain decomposition.
domain_decomposition = sim.state.domain_decomposition
device.notice(f'domain_decomposition={domain_decomposition}')

# Print the location of the split planes.
split_fractions = sim.state.domain_decomposition_split_fractions
device.notice(f'split_fractions={split_fractions}')

# Print the number of particles on each rank.
with sim.state.cpu_local_snapshot as snap:
    N = len(snap.particles.position)
    print(f'{N} particles on rank {device.communicator.rank}')

[6]:
!mpirun -n 4 python3 domain_decomposition.py
notice(2): Using domain decomposition: n_x = 1 n_y = 2 n_z = 2.
1749 particles on rank 2
1695 particles on rank 1
domain_decomposition=(1, 2, 2)
1707 particles on rank 3
split_fractions=([], [0.5], [0.5])
1761 particles on rank 0

For example, this script chooses a 1 x 2 x 2 decomposition with the split planes in the center of the box when launched with 4 ranks. domain_decomposition_split_fractions reports relative values between 0 and 1, so in this case a hypothetical 10 x 10 x 10 box would have split planes at y=0 and z=0 creating 4 domains.

Each rank is assigned one of these domains and stores the particles located inside it. The operations execute on the particles local to each rank. When the density of the system is uniform, each rank has approximately the same number of particles (as in the example above). This is what allows the parallel simulations to run with faster performance: the same operation is being run on fewer particles so it takes less time.

However, when the density of the system is not uniform the default split planes lead to an uneven load balancing with a much greater number of particles on one rank compared to the others. The performance of the overall simulation is limited by that of the slowest rank. In the extreme case, imagine all the particles in the lower left of a very large box. In this 1 x 2 x 2 domain decomposition, all particles would be on one rank and the parallel simulation would take just as much time to execute as one rank alone.

Some computations, such as pair forces in MD or hard particle overlap checks in HPMC, need to compute interactions with particles from a neighboring domain. This establishes a lower limit on the domain size. Given an interaction range r_interaction (for MD, this is the sum of the largest pair potential r_cut and the neighbor list buffer), each x,y,z dimension of the domain must be larger than 2 * r_interaction. HOOMD-blue raises an exception when this is violated. For example, here is the Lennard-Jones script run on the random.gsd file before replicating to a larger size:

[7]:
%pycat lj_domain_error.py
import hoomd

device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device, seed=1)
sim.create_state_from_gsd(
    filename='../01-Introducing-Molecular-Dynamics/random.gsd')

integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator
sim.run(0)

[8]:
!mpirun -n 2 python3 lj_domain_error.py
notice(2): Using domain decomposition: n_x = 1 n_y = 1 n_z = 2.
Traceback (most recent call last):
  File "03-Parallel-Simulations-With-MPI/lj_domain_error.py", line 19, in <module>
Traceback (most recent call last):
  File "03-Parallel-Simulations-With-MPI/lj_domain_error.py", line 19, in <module>
    sim.run(0)
  File "/home/joaander/build/hoomd/hoomd/simulation.py", line 462, in run
    sim.run(0)
  File "/home/joaander/build/hoomd/hoomd/simulation.py", line 462, in run
    self._cpp_sys.run(steps_int, write_at_start)
RuntimeError: Communication error -
Simulation box too small for domain decomposition.
r_ghost_max: 2.9
d.z/2: 2.275

    self._cpp_sys.run(steps_int, write_at_start)
RuntimeError: Communication error -
Simulation box too small for domain decomposition.
r_ghost_max: 2.9
d.z/2: 2.275

--------------------------------------------------------------------------
MPI_ABORT was invoked on rank 0 in communicator MPI_COMM_WORLD
with errorcode 1.

NOTE: invoking MPI_ABORT causes Open MPI to kill all MPI processes.
You may or may not see output from other processes, depending on
exactly when Open MPI kills them.
--------------------------------------------------------------------------
[cheme-hodges:965676] 1 more process has sent help message help-mpi-api.txt / mpi-abort
[cheme-hodges:965676] Set MCA parameter "orte_base_help_aggregate" to 0 to see all help / error messages
Single program#

HOOMD-blue scripts must be written as a single program. All ranks must load the same input file, define the same operations with the same parameters and triggers, and run the same number of time steps. HOOMD-blue requires this because it splits the system into smaller domains, one assigned to each rank, and executes same operations on each domain.

While there are many processes executing the same Python script in parallel, they are not independent. The ranks send messages back and forth as needed to combine the decomposed parts of simulation into a whole. If your script does not follow the single program requirement, it is likely at least one rank will deadlock while it waits for a message to be sent from another rank that will never be sent. A deadlock means that the execution continues while waiting for a condition that will never be true.

While you must create all HOOMD-blue operations, access properties, and call methods on all ranks, this may not be the case for other libraries used in your script. For example, calling print on all ranks results in duplicated output. The same would occur when using open() to open and write to a file. In cases like these, place your code in a if device.communicator.rank == 0: check so that it only runs once on rank 0. For example, this script prints the total kinetic energy of the system only once:

[9]:
%pycat lj_kinetic_energy.py
import hoomd

# Initialize the simulation.
device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device, seed=1)
sim.create_state_from_gsd(filename='random.gsd')

# Set the operations for a Lennard-Jones particle simulation.
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator

# Instantiate a ThermodyanmicQuantities object to compute kinetic energy.
thermodynamic_properties = hoomd.md.compute.ThermodynamicQuantities(
    filter=hoomd.filter.All())
sim.operations.computes.append(thermodynamic_properties)

# Run the simulation.
sim.run(1000)

# Access the system kinetic energy on all ranks.
kinetic_energy = thermodynamic_properties.kinetic_energy

# Print the kinetic energy only on rank 0.
if device.communicator.rank == 0:
    print(kinetic_energy)

[10]:
!mpirun -n 4 python3 lj_kinetic_energy.py
notice(2): Using domain decomposition: n_x = 1 n_y = 2 n_z = 2.
15406.242760147874

The pattern used here is important:

kinetic_energy = thermodynamic_properties.kinetic_energy
if device.communicator.rank == 0:
    print(kinetic_energy)

The property thermodynamic_properties.kinetic_energy is accessed on all ranks, but printed only on rank 0. You must use this same pattern any time you access operation’s properties or call their methods, not just when calling print.

To see why this is important, try the following code in an interactive job:

if device.communicator.rank == 0:
    print(thermodynamic_properties.kinetic_energy)

When you execute this, you will find that it prints nothing and the execution continues indefinitely (press Ctrl-C to stop it).

Each rank stores only a fraction of the total particles in the system. ThermodynamicProperties first computes the kinetic energy from the particles local to each rank, then communicates between the ranks to sum the total system kinetic energy. When you access kinetic_energy only on rank 0, rank 0 sums the local kinetic energy and then deadlocks while it waits for messages from the other ranks. The messages will never arrive because none of the other ranks access the kinetic_energy property, so they do not compute the kinetic energy on their local particles, nor do they communicate with the other ranks.

So, be careful using if device.communicator.rank == 0:. HOOMD-blue has a rich Python API, but any property access or method call on a HOOMD-blue object may result in a MPI communication that will deadlock when inside this condition.

Scripts using if device.communicator.rank == 0: are compatible with serial execution where rank is always 0.

This demonstration uses print as an example for pedagogical purposes. Note that you can use device.notice(f’{thermodynamic_properties.kinetic_energy}’)) to print messages as well. In this case, notice checks the rank index itself and only prints on one rank.

Summary#

In this section, you have seen how MPI ranks run as independent processes, learned how HOOMD splits particles across domains, understand why that HOOMD-blue scripts need to execute all operations identically on all ranks, and identified how to to print output only once in MPI simulations without causing deadlock. The next section of this tutorial shows you how to access the system configuration in MPI simulations.

Accessing System Configurations With MPI#
Overview#
Questions#
  • How can I access the state of the simulation in parallel simulations?

  • What are the differences between local and global snapshots?

Objectives#
  • Describe how to write GSD files in MPI simulations.

  • Show examples using local snapshots.

  • Show examples using global snapshots.

Writing GSD files in parallel jobs#

You can write GSD files in parallel jobs just as you do in serial. Saving the simulation trajectory to a file is useful for visualization and analysis after the simulation completes. As mentioned in the previous section, write a single program and add the write.GSD operation with identical parameters on all ranks:

[2]:
%pycat lj_trajectory.py
import hoomd

# Initialize the simulation.
device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device, seed=1)
sim.create_state_from_gsd(filename='random.gsd')

# Set the operations for a Lennard-Jones particle simulation.
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
sim.operations.integrator = integrator

# Define and add the GSD operation.
gsd_writer = hoomd.write.GSD(filename='trajectory.gsd',
                             trigger=hoomd.trigger.Periodic(1000),
                             mode='xb')
sim.operations.writers.append(gsd_writer)

# Run the simulation.
sim.run(1000)

[3]:
!mpirun -n 4 python3 lj_trajectory.py
notice(2): Using domain decomposition: n_x = 1 n_y = 2 n_z = 2.
Modifying particle properties with local snapshots#

Use snapshots when you need to modify particle properties during a simulation, or perform analysis where the results need to be known as the simulation progresses (e.g. umbrella sampling). Local snapshots provide high performance direct access to the particle data stored in HOOMD-blue. The direct access comes with several costs. Your script can only access particles local to the domain of the current rank. These particles may appear in any order in the local snapshot and a given particle is only present on one rank. To access the properties of a specific particle, find the index given the particle’s tag and handle the condition where it is not present on the rank.

The example below demonstrates this with an example that doubles the mass of all particles, and quadruples the mass of the particle with tag 100:

[4]:
%pycat local_snapshot.py
import hoomd

# Initialize the simulation.
device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device)
sim.create_state_from_gsd(filename='random.gsd')

# Access the local snapshot.
with sim.state.cpu_local_snapshot as snapshot:
    N = len(snapshot.particles.position)

    # Double the mass of every particle.
    snapshot.particles.mass *= 2

    # Look up the index of the particle with tag 100.
    idx = snapshot.particles.rtag[100]

    # Modify the particle, but only if it is found.
    # This condition will be true on one rank and false on the others.
    if idx < N:
        snapshot.particles.mass[idx] *= 2

[5]:
!mpirun -n 4 python3 local_snapshot.py
notice(2): Using domain decomposition: n_x = 1 n_y = 2 n_z = 2.

Notice how the example uses the rtag lookup array to efficiently find the index of the particle with the given tag. When the particle is not present on the local rank, rtag is set to a number greater than the local number of particles.

Any analysis you perform may require MPI communication to combine results across ranks using mpi4py (this is beyond the scope of this tutorial).

Using global snapshots with MPI#

Global snapshots collect all particles onto rank 0 and sort them by tag. This removes a number of the inconveniences of the local snapshot API, but at the cost of much slower performance. When you use global snapshots in MPI simulations, you need to add if snapshot.communicator.rank == 0: checks around all the code that accesses the data in the snapshot. The get_snapshot() call itself MUST be made on all ranks. Here is an example that computes the total mass of the system using a global snapshot:

[6]:
%pycat global_snapshot.py
import hoomd
import numpy

# Initialize the simulation.
device = hoomd.device.CPU()
sim = hoomd.Simulation(device=device)
sim.create_state_from_gsd(filename='random.gsd')

# Call get_snapshot on all ranks.
snapshot = sim.state.get_snapshot()

# Access particle data on rank 0 only.
if snapshot.communicator.rank == 0:
    total_mass = numpy.sum(snapshot.particles.mass)
    print(total_mass)

[7]:
!mpirun -n 4 python3 global_snapshot.py
notice(2): Using domain decomposition: n_x = 1 n_y = 2 n_z = 2.
6912.0
Summary#

In this section, you have written trajectories to a GSD file, modified the state of the system efficiently using local snapshots, and analyzed the state of the system with a global snapshot - all with conditions that work in both MPI parallel and serial simulations. The next section of this tutorial shows you how to use MPI to run many independent simulations with different inputs.

Running Multiple Simulations With Partitions#
Overview#
Questions#
  • How can I partition a MPI communicator to run many independent simulations?

  • When are partitions useful?

Objectives#
  • Show how to define a custom Communicator with more than one partition.

  • Demonstrate how to use this to run many independent simulations with one mpirun.

  • Explain how this is useful to aggregate jobs on HPC systems.

Partitioning communicators#

So far in this tutorial you have seen how executing mpirun -n 4 python3 script.py will use domain decomposition to run 1 simulation split across 4 ranks via domain decomposition. What if you wanted to run 2 different simulations, each on 2 ranks with this command? Or 4 different simulations each on 1 rank? This is called partitioning the MPI communicator.

In HOOMD-blue, you can do this by defining a non-default Communicator and specifying the ranks_per_partition argument. Then use communicator.partition as an identifier in your script to change input parameters.

[2]:
%pycat hello_partition.py
import hoomd

communicator = hoomd.communicator.Communicator(ranks_per_partition=2)
print(f'Hello from partition {communicator.partition} rank {communicator.rank}')

[3]:
!mpirun -n 4 python3 hello_partition.py
Hello from partition 0 rank 0
Hello from partition 0 rank 1
Hello from partition 1 rank 0
Hello from partition 1 rank 1

In partitioned simulations, all ranks within a given partition must have the same input file, operations, parameters, and otherwise follow the single program guidelines outlined in the previous sections of this tutorial. However, the input file, operations and/or their parameters can vary from one partition to the next. For example, you could run many simulations with different temperatures, different initial configurations, or different random number seeds. The following example shows how to set different temperatures and random number seeds based on the partition index.

You MUST pass the partitioned Communicator object to the device constructor: hoomd.device.CPU(communicator=communicator) or hoomd.device.GPU(communicator=communicator)

[4]:
%pycat lj_partition.py
import hoomd

# kT values to execute at:
kT_values = [1.5, 2.0]

# Instantiate a Communicator with 2 ranks in each partition.
communicator = hoomd.communicator.Communicator(ranks_per_partition=2)

# Pass the communicator to the device.
device = hoomd.device.CPU(communicator=communicator)

# Initialize the simulation.
sim = hoomd.Simulation(device=device, seed=1)
sim.create_state_from_gsd(filename='random.gsd')

# Choose system parameters based on the partition
sim.seed = communicator.partition
kT = kT_values[communicator.partition]

# Set the operations for a Lennard-Jones particle simulation.
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.ConstantVolume(
    filter=hoomd.filter.All(),
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=kT))
integrator.methods.append(nvt)
sim.operations.integrator = integrator

# Use the partition id in the output file name.
gsd_writer = hoomd.write.GSD(filename=f'trajectory{communicator.partition}.gsd',
                             trigger=hoomd.trigger.Periodic(1000),
                             mode='xb')
sim.operations.writers.append(gsd_writer)

# Run the simulation.
sim.run(1000)

[5]:
!mpirun -n 4 python3 lj_partition.py
notice(2): Using domain decomposition: n_x = 1 n_y = 1 n_z = 2.
notice(2): Using domain decomposition: n_x = 1 n_y = 1 n_z = 2.

Each partition is a separate Simulation that produces its own trajectory. You must choose filenames or directories so that different partitions produce different output files. The above example places the partition index in the filename:

[6]:
!ls trajectory?.gsd
trajectory0.gsd  trajectory1.gsd
Motivation#

Why use partitions in simulations where you can just write one script with parameters and execute it more than once? Some HPC systems only allow jobs to use whole nodes, and/or policies prefer fewer large jobs over many smaller jobs in the scheduler. On these systems, you can obtain better throughput for your research when you use partitions to aggregate many independent simulations together into one scheduler job.

While the details are beyond the scope of this tutorial, signac-flow can automate the aggregation process.

Summary#

In this section, you have learned how to run many simulations with different parameters using a single mpirun invocation. This is the end of the MPI tutorial.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Custom Actions in Python#

This tutorial introduces the necessary information to create custom actions in Python. Briefly, custom actions allow users and developers to implement new functionality into HOOMD-blue without having to write C++ code.

Prerequisites:

This tutorial assumes you are familiar with the concepts presented in Introducting HOOMD-blue and Introducing Molecular Dyanamics. Throughout this tutorial we may use other libraries to introduce writing performant actions in Python. Familiarity with these packages may help, but are not necessary to learn from this tutorial.

What are Actions?#
Overview#
Questions#
  • What are actions?

  • Why would I want to use custom actions?

  • What categories of actions exist for customization in HOOMD-blue?

Objectives#
  • Explain the concept of an action in HOOMD-blue.

  • Discuss potential use cases for custom Python actions.

  • Provide the categories of actions in HOOMD-blue.

Actions#

Actions are the objects that act or operate on a hoomd.Simulation object. Looking at HOOMD-blue from the Python perspective, actions are wrapped or composed by operations. For example, objects like hoomd.update.BoxResize and hoomd.hpmc.tune.MoveSize contain actions internally. In other words, the actions implement the logic repsonsible for implementing the functionality of an operation (e.g. resizing the box for hoomd.update.BoxResize), while the operation handles some logistics like determining when the action will run using a hoomd.Trigger object.

Actions can be written in Python using hoomd.custom.Action. Through creating a subclass of Action HOOMD-blue’s capabilities can be augmented and customized.

Why Python Custom Actions?#

HOOMD-blue offers Python Actions for a variety of reasons.

  • Enable more customization in Python.

  • Quicker prototyping of new simulation techniques.

  • Allow use of SciPy libraries for use cases like on-the-fly machine learning forcefields.

  • Serve as a foreign function interface from a compiled library through Python to HOOMD-blue’s run loop. For instance, a Python library that uses Rust as a backend could be used in a Python custom action.

Some example use cases are storing simulation data in a user’s desired format whether that is a database, file format like HDF5, or other storage medium, simulating a system under a radiation source, or advanced sampling techniques.

Categories of Actions?#

Currently, HOOMD-blue offers three types of actions: updaters, writers, and tuners. These categories serve to distinguish how an action interacts with a simulation and its state attribute.

  • Updaters modify the simulation state when triggered. hoomd.update.BoxResize is an example of an updater as it changes the simulation box.

  • Writers observe the simulation state and write that data to a file or some other object (writers should not modify the simulation state). hoomd.write.GSD is an example of a writer; it does not change the simulation state, but writes it out to a GSD file.

  • Tuners modify another object’s hyperparameters (or object attributes). Tuners should not modify state, but can modify another object to improve performance. hoomd.hpmc.tune.MoveSize is an example of this type of action. MoveSize tunes the integrator’s trial move sizes to reach a specific acceptance rate performance but does not modify the simulation state.

Recap#
  • Actions are objects that act on a hoomd.Simulation object.

  • Actions can be written in Python using hoomd.custom.Action.

  • There are three categories of actions.

    • Updaters: modify simulation state

    • Writers: doesn’t modify simulation state, writes out data

    • Tuners: doesn’t modify simulation state, modifies object hyperparameters

In the next section we start writing custom actions and using them in HOOMD-blue simulations.

An Initial Custom Action#
Overview#
Questions#
  • How do I write a custom action in Python?

  • How do I wrap a custom action object?

  • How do I use a custom action in a simulation?

Objectives#
  • Explain the steps in writing a custom action.

  • Demonstrate using a custom action in a simulation.

Writing a Custom Action#

First, import hoomd.

[1]:
import hoomd

We create a single particle snapshot for initializing a simulation’s state further down.

[2]:
snap = hoomd.Snapshot()
snap.particles.N = 1
snap.particles.position[:] = [0, 0, 0]
snap.particles.types = ['A']
snap.particles.typeid[:] = [0]
snap.configuration.box = [10, 10, 10, 0, 0, 0]

Create a custom action as a subclass of hoomd.custom.Action. Here we will create an action that prints the timestep to standard out.

[3]:
class PrintTimestep(hoomd.custom.Action):

    def act(self, timestep):
        print(timestep)

We now have an action that can print out the simulation timestep. The logic of the action goes inside the act method. All actions must define this function, and it must take in the simulation timestep; this is passed in when the action is called in the HOOMD-blue run loop. (If you are wondering how to access simulation data, there is a mechanism for that which we will go over in the next section).

Let’s go ahead and create a PrintTimestep object.

[4]:
custom_action = PrintTimestep()
Wrapping Custom Actions#

To let an Operations object know what kind of action our custom action is, we must wrap it in a subclass of hoomd.custom.CustomOperation. We have three options as discussed in the previous section: an updater, writer, or tuner. Since our object does not modify simulation state or an object’s hyperparameters, but writes the timestep to standard out, our action is a writer. hoomd.write.CustomWriter then is the correct class to wrap our custom action (hoomd.update.CustomUpdater and hoomd.tune.CustomTuner are for updaters and tuners respectively).

Create a CustomWriter operation that will call the custom action when triggered:

[5]:
custom_op = hoomd.write.CustomWriter(action=custom_action,
                                     trigger=hoomd.trigger.Periodic(100))

Notice that custom operations take triggers like other operations.

Using Custom Actions#

To use a custom opeation we must add it to a hoomd.Operations object. Thus, the steps to use a custom action in a simuluation are 1. Instantiate the custom action object. 2. Wrap the custom action in the appropriate custom operation class. 3. Add the custom operation object to the appropriate container in a hoomd.Operations object.

[6]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu)

Initialize the state

[7]:
sim.create_state_from_snapshot(snap)

Add the custom action wrapped by a CustomWriter:

[8]:
sim.operations.writers.append(custom_op)

We can now run our simulation to see our custom action in work!

[9]:
sim.run(1000)
100
200
300
400
500
600
700
800
900
1000

In the next section we discuss some of the features of custom actions, before getting into non-trival examples in later sections.

Custom Action Features#
Overview#
Questions#
  • How do I access simulation state information?

  • How do I create loggable quantities in custom actions?

  • What are other features provided by the custom action/operation API?

Objectives#
  • Explain how to access simulation state in a custom action.

  • Explain how to expose loggable quantities in a custom action.

  • Demonstrate other miscellaneous features of custom actions.

Boilerplate Code#
[1]:
import hoomd

cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu)

snap = hoomd.Snapshot()
snap.particles.N = 1
snap.particles.position[:] = [0, 0, 0]
snap.particles.types = ['A']
snap.particles.typeid[:] = [0]
snap.configuration.box = [10, 10, 10, 0, 0, 0]

sim.create_state_from_snapshot(snap)
How do I access simulation state?#

By the time that a custom action will have its act method called it will have an attribute _state accessible to it which is the simulation state for the simulation it is associated with. The behavior of this is controlled in the hoomd.custom.Action.attach method. The method takes in a simulation object and performs any necessary set-up for the action call act. By default, the method stores the simulation state in the _state attribute.

We will create two custom actions class to show this. In one, we will not modify the attach method, and in the other we will make attach method also print out some information.

[2]:
class PrintTimestep(hoomd.custom.Action):

    def act(self, timestep):
        print(timestep)


class NotifyAttachWithPrint(hoomd.custom.Action):

    def attach(self, simulation):
        print(f"Has '_state' attribute {hasattr(self, '_state')}.")
        super().attach(simulation)
        print(f"Has '_state' attribute {hasattr(self, '_state')}.")

    def act(self, timestep):
        print(timestep)

Like in the previous section these are both writers. We will go ahead and wrap them and see what happens when we try to run the simulation.

[3]:
print_timestep = PrintTimestep()
print_timestep_operation = hoomd.write.CustomWriter(
    action=print_timestep, trigger=hoomd.trigger.Periodic(10))
sim.operations.writers.append(print_timestep_operation)
sim.run(0)
[4]:
sim.operations -= print_timestep_operation
print_timestep_with_notify = NotifyAttachWithPrint()
sim.operations.writers.append(
    hoomd.write.CustomWriter(action=print_timestep_with_notify,
                             trigger=hoomd.trigger.Periodic(10)))
sim.run(0)
Has '_state' attribute False.
Has '_state' attribute True.
Loggable Quantities in Custom Actions#

Custom actions can hook into HOOMD-blue’s logging subsystem by using the hoomd.logging.log decorator to document which methods/properties of a custom action are loggable. See the documentation on hoomd.logging.log and hoomd.logging.TypeFlags for complete documenation of the decorator and loggable types.

In general, log as a decorator takes optional arguments that control whether to make a method a property, what type the loggable quantity is, and whether the quantity should be logged by default.

Rather than elaborate, we will use an example to explain these attributes.

[5]:
class ActionWithLoggables(hoomd.custom.Action):

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

    @hoomd.logging.log(category='string')
    def string_loggable(self):
        return "I am a string loggable."

    def act(self, timestep):
        pass


action = ActionWithLoggables()
[6]:
action.scalar_property_loggable
[6]:
42
[7]:
action.string_loggable
[7]:
'I am a string loggable.'
Custom Operation Wrapping#

Another feature of the custom action API is that when an object is wrapped by a custom operation object (which is necessary to add a custom action to a simulation), the action’s attributes are available through the operation object as if the operation were the action. For example, we will wrap action from the previous code block in a CustomWriter and access its attributes that way.

Due to this wrapping the attribute trigger should not exist in your custom action.

[8]:
custom_op = hoomd.write.CustomWriter(action=action, trigger=100)
custom_op.scalar_property_loggable
[8]:
42
[9]:
custom_op.string_loggable
[9]:
'I am a string loggable.'
Summary#

These summarize most of the unique features of custom actions in Python. They are - Accessing simulation state through _state - Exposing loggable quantities - Accessing action attributes through custom operation wrapper

With this information, you could write almost any action that is possible to write in Python for use in HOOMD-blue. The remain tutorial sections will focus on concrete examples and show some tricks to get the best performance. For the full list of accessible features for custom actions see the reference documentation.

Custom Updater#
Overview#
Questions#
  • How can I modify the state of a system in a custom updater?

Objectives#
  • Show an example of a non-trival custom updater.

Boilerplate Code#
[1]:
from numbers import Number

import hoomd
import hoomd.md as md
import numpy as np

cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)

# Create a simple cubic configuration of particles
N = 5  # particles per box direction
box_L = 20  # box dimension

snap = hoomd.Snapshot(cpu.communicator)
snap.configuration.box = [box_L] * 3 + [0, 0, 0]
snap.particles.N = N**3
x, y, z = np.meshgrid(*(np.linspace(-box_L / 2, box_L / 2, N, endpoint=False),)
                      * 3)
positions = np.array((x.ravel(), y.ravel(), z.ravel())).T
snap.particles.position[:] = positions
snap.particles.types = ['A']
snap.particles.typeid[:] = 0

sim.create_state_from_snapshot(snap)
rng = np.random.default_rng(1245)
Problem#

In this section, we will show how to create a custom updater that modifies the system state. To show this, we will create a custom updater that adds a prescribed amount of energy to a single particle simulating the bombardment of radioactive material into our system. For this problem, we pick a random particle and modify its velocity according to the radiation energy in a random direction.

[2]:
class InsertEnergyUpdater(hoomd.custom.Action):

    def __init__(self, energy):
        self.energy = energy

    def act(self, timestep):
        snap = self._state.get_snapshot()
        if snap.communicator.rank == 0:
            particle_i = rng.integers(snap.particles.N)
            mass = snap.particles.mass[particle_i]
            direction = self._get_direction()
            magnitude = np.sqrt(2 * self.energy / mass)
            velocity = direction * magnitude
            old_velocity = snap.particles.velocity[particle_i]
            new_velocity = old_velocity + velocity
            snap.particles.velocity[particle_i] = velocity
        self._state.set_snapshot(snap)

    @staticmethod
    def _get_direction():
        theta, z = rng.random(2)
        theta *= 2 * np.pi
        z = 2 * (z - 0.5)
        return np.array([
            np.sqrt(1 - (z * z)) * np.cos(theta),
            np.sqrt(1 - (z * z)) * np.sin(theta), z
        ])

We will now use our custom updater with an NVE integrator. Particles will interact via a Lennard-Jones potential. Using the Table writer and a hoomd.logging.Logger, we will monitor the energy, which should be increasing as we are adding energy to the system. We will also thermalize our system to a kT == 1.

[3]:
sim.state.thermalize_particle_momenta(filter=hoomd.filter.All(), kT=1.)

lj = md.pair.LJ(nlist=md.nlist.Cell(buffer=0.4))
lj.params[('A', 'A')] = {'epsilon': 1., 'sigma': 1.}
lj.r_cut[('A', 'A')] = 2.5
integrator = md.Integrator(
    methods=[md.methods.ConstantVolume(hoomd.filter.All())],
    forces=[lj],
    dt=0.005)

thermo = md.compute.ThermodynamicQuantities(hoomd.filter.All())
logger = hoomd.logging.Logger(categories=['scalar'])
logger.add(thermo, ['kinetic_energy', 'potential_energy'])
logger['total_energy'] = (
    lambda: thermo.kinetic_energy + thermo.potential_energy, 'scalar')

table = hoomd.write.Table(100, logger, max_header_len=1)

sim.operations += integrator
sim.operations += thermo
sim.operations += table

# Create and add our custom updater
energy_operation = hoomd.update.CustomUpdater(action=InsertEnergyUpdater(10.),
                                              trigger=100)

sim.operations += energy_operation
[4]:
sim.run(1000)
 kinetic_energy  potential_energy   total_energy
   189.55469         -0.16021        189.39447
   203.13934         -5.51636        197.62298
   214.05941         -7.90628        206.15314
   219.49181         -8.47534        211.01647
   230.38656         -9.71804        220.66852
   237.66638         -9.07038        228.59601
   245.73067        -10.18110        235.54957
   254.95301        -12.21494        242.73808
   258.55741         -6.01446        252.54296
   269.38334         -8.12332        261.26002

As we can see the total energy of the system is indeed increasing. The energy isn’t increasing by 10 every time since we are adding the velocity in a random direction which may be against the current velocity.

Improving upon our Custom Action#

Maybe we want to allow for the energy to be from a distribution. HOOMD-blue has a concept called a variant which allows for quantities that vary over time. Let’s change the InsertEnergyupdater to use variants and create a custom variant that grabs a random number from a Gaussian distribution. (If you don’t understand the variant code, that is fine. We are just using this to showcase how you can iteratively improve custom actions).

Note:

Variant objects model a parameter as a function of the timestep, so to get the value for a particular timestep we have to call the variant. For more information see the documentation for hoomd.variant.

[5]:
class InsertEnergyUpdater(hoomd.custom.Action):

    def __init__(self, energy):
        self._energy = energy

    @property
    def energy(self):
        """A `hoomd.variant.Variant` object."""
        return self._energy

    @energy.setter
    def energy(self, new_energy):
        if isinstance(new_energy, Number):
            self._energy = hoomd.variant.Constant(new_energy)
        elif isinstance(new_energy, hoomd.variant.Variant):
            self._energy = new_energy
        else:
            raise ValueError("energy must be a variant or real number.")

    def act(self, timestep):
        snap = self._state.get_snapshot()
        if snap.communicator.rank == 0:
            particle_i = rng.integers(snap.particles.N)
            mass = snap.particles.mass[particle_i]
            direction = self._get_direction()
            magnitude = np.sqrt(2 * self.energy(timestep) / mass)
            velocity = direction * magnitude
            old_velocity = snap.particles.velocity[particle_i]
            new_velocity = old_velocity + velocity
            snap.particles.velocity[particle_i] = velocity
        self._state.set_snapshot(snap)

    @staticmethod
    def _get_direction():
        theta, z = rng.random(2)
        theta *= 2 * np.pi
        z = 2 * (z - 0.5)
        return np.array([
            np.sqrt(1 - (z * z)) * np.cos(theta),
            np.sqrt(1 - (z * z)) * np.sin(theta), z
        ])


class GaussianVariant(hoomd.variant.Variant):

    def __init__(self, mean, std):
        hoomd.variant.Variant.__init__(self)
        self.mean = mean
        self.std = std

    def __call__(self, timestep):
        return rng.normal(self.mean, self.std)

We briefly show that the Gaussian Variant works.

[6]:
energy = GaussianVariant(mean=10., std=2.)
sample_energies = np.array([energy(0) for _ in range(1000)])
f"Mean: {sample_energies.mean()}, std. dev. {sample_energies.std()}"
[6]:
'Mean: 10.069550459202723, std. dev. 1.9965744919420398'

We now use the updated InsertEnergyUpdater in the simulation.

[7]:
sim.operations.updaters.remove(energy_operation)
# Create and add our custom updater
energy_operation = hoomd.update.CustomUpdater(
    action=InsertEnergyUpdater(energy), trigger=100)
sim.operations.updaters.append(energy_operation)
sim.run(1000)
   279.83085        -11.21077        268.62009
   289.14791         -9.62083        279.52708
   302.04414         -9.22880        292.81534
   312.06778        -11.05103        301.01675
   324.69061        -11.95850        312.73211
   332.29403         -9.80310        322.49093
   345.55571        -14.83428        330.72143
   357.07548        -16.49285        340.58263
   357.62391        -11.70456        345.91935
   372.21959        -15.91459        356.30500

We could continue to improve upon this updater and the execution of this operation. However, this suffices to showcase the ability of non-trivial updaters to affect the simulation state.

Custom Writer#
Overview#
Questions#
  • How could I write a custom trajectory writer?

Objectives#
  • Show an example custom writer

Boilerplate Code#
[1]:
import h5py
import hoomd
import hoomd.hpmc as hpmc
import numpy as np

cpu = hoomd.device.CPU()
sim = hoomd.Simulation(cpu, seed=1)

# Create a simple cubic configuration of particles
N = 5  # particles per box direction
box_L = 20  # box dimension

snap = hoomd.Snapshot(cpu.communicator)
snap.configuration.box = [box_L] * 3 + [0, 0, 0]
snap.particles.N = N**3
x, y, z = np.meshgrid(*(np.linspace(-box_L / 2, box_L / 2, N, endpoint=False),)
                      * 3)
positions = np.array((x.ravel(), y.ravel(), z.ravel())).T
snap.particles.position[:] = positions
snap.particles.types = ['A']
snap.particles.typeid[:] = 0

sim.create_state_from_snapshot(snap)
Problem#

For this section, we will demonstrate writing a custom trajectory writer using h5py. We will start by implementing the ability to store positions, timesteps, and box dimensions in an HDF5 file.

[2]:
class HDF5Writer(hoomd.custom.Action):

    def __init__(self, filename, mode):
        self.filename = filename
        if mode not in {'w', 'w-', 'x', 'a', 'r+'}:
            raise ValueError("mode must be writtable")
        self.file = h5py.File(filename, mode)
        self.write_metadata()
        frames = list(self.file.keys())
        if frames:
            self._cur_frame = max(map(int, frames)) + 1
        else:
            self._cur_frame = 1

    def write_metadata(self):
        """Write the file metadata that defines the type of hdf5 file"""
        if 'app' in self.file.attrs:
            if self.file.attrs.app != 'hoomd-v3':
                raise RuntimeError(
                    'HDF5 file metadata "app" is not "hoomd-v3".')
        else:
            self.file.attrs.app = 'hoomd-v3'

        if 'version' not in self.file.attrs:
            self.file.attrs.version = '1.0'

    def act(self, timestep):
        """Write out a new frame to the trajectory."""
        new_frame = self.file.create_group(str(self._cur_frame))
        self._cur_frame += 1
        positions = new_frame.create_dataset('positions',
                                             (self._state.N_particles, 3),
                                             dtype='f8')
        snapshot = self._state.get_snapshot()
        positions[:] = snapshot.particles.position
        new_frame.attrs['timestep'] = timestep
        box_array = np.concatenate((self._state.box.L, self._state.box.tilts))
        new_frame.attrs['box'] = box_array

    def __del__(self):
        self.file.close()

Define a function that creates a HDF5Writer wrapped in a custom writer.

This function will make creating our custom writer easier. We will now add an HPMC sphere integrator and our custom writer to our simulation and run for 1000 steps.

(Note that the ‘w’ mode will truncate any existing file.)

[3]:
h5_writer = hoomd.write.CustomWriter(action=HDF5Writer('traj.h5', 'w'),
                                     trigger=100)
integrator = hpmc.integrate.Sphere()
integrator.shape['A'] = {'diameter': 1.}

sim.operations += integrator
sim.operations += h5_writer

sim.run(1000)

We have run the simulation, and our HDF5 file has been written. Lets check the groups our file contains now.

[4]:
list(h5_writer.file.keys())
[4]:
['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']

Ten frames have been written as expected. Let’s check the properties from the last frame and compare them to the simulation currently. We will open the file again in read only mode to check these properties. First we flush the open HDF5 file to ensure the data has been written to the OS buffer at least.

[5]:
h5_writer.file.flush()

with h5py.File('traj.h5', 'r') as traj:
    assert traj['10'].attrs['timestep'] == sim.timestep
    box_array = np.concatenate((sim.state.box.L, sim.state.box.tilts))
    assert np.allclose(traj['10'].attrs['box'], box_array)
    snapshot = sim.state.get_snapshot()
    assert np.allclose(snapshot.particles.position, traj['10']['positions'][:])
Expanding on HDF5Writer#

Our HDF5Writer class is already sufficient for storing the trajectory. However, there are plenty of other features we could add. Examples include utilizing the HOOMD-blue logging subsystem to allow logging data to the HDF5 file, and adding support for MPI. Also, we could also add support for other system properties such as images, velocities, and others. We will focus on adding this feature.

We need to decide on a method of specifying properties to write. We will use a tuple system where we signify the property we want to store using a tuple that nests into a snapshot object. For example to write images we will use the tuple ('particles', 'image') to signify we want to store images. We will let an user pass in a list of tuples of any length to specify what they want to store. (Positions will always be stored, and we will move them to the particles group).

[6]:
class HDF5Writer(hoomd.custom.Action):

    def __init__(self, filename, mode, properties):
        self.filename = filename
        self.properties = set(properties) | {('particles', 'position')}
        if mode not in {'w', 'w-', 'x', 'a', 'r+'}:
            raise ValueError("mode must be writtable")
        self.file = h5py.File(filename, mode)
        self.write_metadata()
        frames = list(self.file.keys())
        if frames:
            self._cur_frame = max(map(int, frames)) + 1
        else:
            self._cur_frame = 1

    def write_metadata(self):
        """Write the file metadata that defines the type of hdf5 file"""
        if 'app' in self.file.attrs:
            if self.file.attrs.app != 'hoomd-v3':
                raise RuntimeError(
                    'HDF5 file metadata "app" is not "hoomd-v3".')
        else:
            self.file.attrs.app = 'hoomd-v3'

        if 'version' not in self.file.attrs:
            self.file.attrs.version = '1.0'

    def _set_property(self, base_group, prop):
        # Get data array
        data = self._state.get_snapshot()
        for name in prop:
            data = getattr(data, name)
        # Get dataset
        use_group = base_group
        for name in prop[:-1]:
            if name not in use_group:
                use_group = base_group.create_group(name)
            else:
                use_group = base_group[name]
        dataset = use_group.create_dataset(prop[-1],
                                           data.shape,
                                           dtype=str(data.dtype))
        dataset[:] = data

    def act(self, timestep):
        """Write out a new frame to the trajectory."""
        new_frame = self.file.create_group(str(self._cur_frame))
        self._cur_frame += 1
        for prop in self.properties:
            self._set_property(new_frame, prop)
        new_frame.attrs['timestep'] = timestep
        box_array = np.concatenate((self._state.box.L, self._state.box.tilts))
        new_frame.attrs['box'] = box_array

    def __del__(self):
        self.file.close()

We will now use our extended trajectory writer to write out particle images as well.

[7]:
h5_writer.file.close()
sim.operations -= h5_writer
h5_writer = hoomd.write.CustomWriter(action=HDF5Writer(
    'traj.h5', 'w', [('particles', 'image')]),
                                     trigger=100)
sim.operations.writers.append(h5_writer)
sim.run(1000)

To see that this worked we will check the first frame for particle images.

[8]:
h5_writer.file.flush()

with h5py.File('traj.h5', 'r') as traj:
    display(traj['1']['particles']['image'][:10])
    display(traj['1']['particles']['position'][:10])
array([[-1,  0,  0],
       [-1,  0,  0],
       [-1, -1,  0],
       [-1,  0,  0],
       [-1, -1,  0],
       [ 0,  0,  0],
       [ 0,  0,  0],
       [ 0,  0,  0],
       [ 0,  0,  0],
       [ 0,  0,  0]], dtype=int32)
array([[ 7.08916892, -9.1162494 , -9.03166465],
       [ 7.17894751, -7.55565503, -4.1420896 ],
       [ 6.84048969,  9.85875838, -0.14319672],
       [ 9.42302572, -7.66224406,  1.71042043],
       [ 4.04383384,  8.15467659,  9.35673311],
       [-5.21819354, -9.57761671, -7.17922194],
       [-6.56869188, -9.00928178, -7.91171588],
       [-1.41025576, -9.14286987, -3.21326451],
       [-3.29261443, -8.20593309,  2.56455928],
       [-2.02993862, -3.93072604,  4.98365   ]])

We could continue add more features such as argument validation in the constructor, support for the logging subsystem of HOOMD-blue, a classmethod, or a number of other things. However, these are left as exercises. This section has shown a non-trivial application of the custom action feature in HOOMD-blue for custom writers.

Improving Performance#
Overview#
Questions#
  • How can I write custom actions to be as efficient as possible?

Objectives#
  • Mention common means for improving performance.

  • Demonstrate using the local snapshot API for increased performance.

Boilerplate Code#
[1]:
from numbers import Number

import hoomd
import hoomd.md as md
import numpy as np

cpu = hoomd.device.CPU()
sim = hoomd.Simulation(cpu, seed=1)

# Create a simple cubic configuration of particles
N = 12  # particles per box direction
box_L = 50  # box dimension

snap = hoomd.Snapshot(cpu.communicator)
snap.configuration.box = [box_L] * 3 + [0, 0, 0]
snap.particles.N = N**3
x, y, z = np.meshgrid(*(np.linspace(-box_L / 2, box_L / 2, N, endpoint=False),)
                      * 3)
positions = np.array((x.ravel(), y.ravel(), z.ravel())).T
snap.particles.position[:] = positions
snap.particles.types = ['A']
snap.particles.typeid[:] = 0

sim.create_state_from_snapshot(snap)

sim.state.thermalize_particle_momenta(hoomd.filter.All(), 1.)

lj = md.pair.LJ(nlist=md.nlist.Cell(buffer=0.4))
lj.params[('A', 'A')] = {'epsilon': 1., 'sigma': 1.}
lj.r_cut[('A', 'A')] = 2.5
integrator = md.Integrator(
    methods=[md.methods.ConstantVolume(hoomd.filter.All())],
    forces=[lj],
    dt=0.005)

sim.operations += integrator


class GaussianVariant(hoomd.variant.Variant):

    def __init__(self, mean, std):
        hoomd.variant.Variant.__init__(self)
        self.mean = mean
        self.std = std

    def __call__(self, timestep):
        return rng.normal(self.mean, self.std)


energy = GaussianVariant(0.1, 0.001)
sim.run(0)
rng = np.random.default_rng(1245)
General Guidelines#

When trying to improve the performance of custom actions, the first step is always to profile the class. Python comes with profiling tools that can be used to determine bottlenecks in a custom action’s performance. In addition, there are many external visualization and profiling tools available. However, after profiling here are some tips that should help improve performance.

  • State.get_snapshot aggregates data across MPI ranks and is \(O(n)\) to construct and setting the state to a new snapshot \(O(n)\) as well. However, hoomd.State.cpu_local_snaphshot or hoomd.State.gpu_local_snapshot are on order \(O(1)\) to construct and modifying data in a local snapshot is \(O(1)\) as well.

  • HOOMD-blue makes use of properties heavily. Since users can change the system state in Python at any point, we must recompute many of these quantities every time they are queried. If you are using something like hoomd.md.pair.LJ.energies multiple times, it will be more performant to first store the values and then use that copy.

  • Avoid for loops for numerical calculation. Try to utilize NumPy broadcasting or existing functions in NumPy or Scipy on the CPU or CuPy on the GPU.

Improve InsertEnergyUpdater#

As an example, we will improve the performance of the InsertEnergyUpdater. Specifically we will change to use the cpu_local_snapshot to update particle velocity. We will use the %%timeit magic function for timing the simulation’s run time before and after our optimization. To highlight the differnce, we will run the updater every timestep.

[2]:
class InsertEnergyUpdater(hoomd.custom.Action):

    def __init__(self, energy):
        self._energy = energy

    @property
    def energy(self):
        return self._energy

    @energy.setter
    def energy(self, new_energy):
        if isinstance(new_energy, Number):
            self._energy = hoomd.variant.Constant(new_energy)
        elif isinstance(new_energy, hoomd.variant.Variant):
            self._energy = new_energy
        else:
            raise ValueError("energy must be a variant or real number.")

    def act(self, timestep):
        snap = self._state.get_snapshot()
        if snap.communicator.rank == 0:
            particle_i = rng.integers(snap.particles.N)
            mass = snap.particles.mass[particle_i]
            direction = self._get_direction()
            magnitude = np.sqrt(2 * self.energy(timestep) / mass)
            velocity = direction * magnitude
            old_velocity = snap.particles.velocity[particle_i]
            new_velocity = old_velocity + velocity
            snap.particles.velocity[particle_i] = velocity
        self._state.set_snapshot(snap)

    @staticmethod
    def _get_direction():
        theta, z = rng.random(2)
        theta *= 2 * np.pi
        z = 2 * (z - 0.5)
        return np.array([
            np.sqrt(1 - (z * z)) * np.cos(theta),
            np.sqrt(1 - (z * z)) * np.sin(theta), z
        ])
[3]:
energy_action = InsertEnergyUpdater(energy)
energy_operation = hoomd.update.CustomUpdater(action=energy_action, trigger=1)
sim.operations.updaters.append(energy_operation)
[4]:
%%timeit
sim.run(100)
83.8 ms ± 1.98 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

We now show the profile for the optimized code which uses the cpu_local_snapshot for updating velocities.

[5]:
class InsertEnergyUpdater(hoomd.custom.Action):

    def __init__(self, energy):
        self._energy = energy

    @property
    def energy(self):
        return self._energy

    @energy.setter
    def energy(self, new_energy):
        if isinstance(new_energy, Number):
            self._energy = hoomd.variant.Constant(new_energy)
        elif isinstance(new_energy, hoomd.variant.Variant):
            self._energy = new_energy
        else:
            raise ValueError("energy must be a variant or real number.")

    def attach(self, simulation):
        self._state = simulation.state
        self._comm = simulation.device.communicator

    def detach(self):
        del self._state
        del self._comm

    def act(self, timestep):
        part_tag = rng.integers(self._state.N_particles)
        direction = self._get_direction()
        energy = self.energy(timestep)
        with self._state.cpu_local_snapshot as snap:
            # We restrict the computation to the MPI
            # rank containing the particle if applicable.
            # By checking if multiple MPI ranks exist first
            # we can avoid for checking inclusion of a tag id
            # in an array.
            if (self._comm.num_ranks <= 1 or part_tag in snap.particles.tag):
                i = snap.particles.rtag[part_tag]
                mass = snap.particles.mass[i]
                magnitude = np.sqrt(2 * energy / mass)
                velocity = direction * magnitude
                old_velocity = snap.particles.velocity[i]
                new_velocity = old_velocity + velocity
                snap.particles.velocity[i] = new_velocity

    @staticmethod
    def _get_direction():
        theta, z = rng.random(2)
        theta *= 2 * np.pi
        z = 2 * (z - 0.5)
        return np.array([
            np.sqrt(1 - (z * z)) * np.cos(theta),
            np.sqrt(1 - (z * z)) * np.sin(theta), z
        ])
[6]:
# Create and add our modified custom updater
sim.operations -= energy_operation
energy_action = InsertEnergyUpdater(energy)
energy_operation = hoomd.update.CustomUpdater(action=energy_action, trigger=1)
sim.operations.updaters.append(energy_operation)
[7]:
%%timeit
sim.run(100)
22.6 ms ± 180 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

As can be seen the simulation with the new EnergyInsertUpdater about an order of magnitude faster with a system size of \(12^3 = 1728\), by virtue of the local snapshot modification having \(O(1)\) time complexity. At larger system sizes this change will grow to be even more substantial.

This concludes the tutorial on custom actions in Python. For more information see the API documentation.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Organizing and Executing Simulations#

This tutorial explains how to organize and execute many simulations.

Prerequisites:

You should be familiar with the concepts taught in Introducing HOOMD-blue. The “Submitting Cluster Jobs” section assumes you are familiar with HPC resources and schedulers.

Organizing Data#
Overview#
Questions#
  • How can I organize data from many simulations?

  • How do I relate the parameters of the simulation to the data?

Objectives#
  • Define a data space that organizes simulation output into directories based on state point parameters.

  • Demonstrate how to use signac to create a data space.

  • Initialize a data space with hard particle Monte Carlo simulations at a selected volume fractions.

  • Show how to store computed results in the job document.

Boilerplate code#
[1]:
import itertools
import math

import gsd.hoomd
import hoomd
import numpy
Research question#

The Introducing HOOMD-blue tutorial shows how to execute a single simulation of hard octahedra and how they self-assemble into a crystal structure. You might want to answer the question “At what volume fraction is the phase transition from fluid to crystal?”. One way to find out is to execute simulations at many volume fractions and examine the resulting equilibrium structures. When performing such a study, you may want to explore simulations at different system sizes, repeat the simulation with different random number seeds, or examine the effects of changing other parameters.

The unique set of parameters for each simulation is a state point which you can represent in a Python dictionary:

[3]:
statepoint = dict(N_particles=128, volume_fraction=0.6, seed=20)
statepoint
[3]:
{'N_particles': 128, 'volume_fraction': 0.6, 'seed': 20}

In your own research, you will execute different types of simulation with different parameters. Follow the example provided in this tutorial and apply the same concepts organize and execute the simulations for your work.

Data space#

Each simulation you execute will generate several output files. Store these in a directory uniquely assigned to each state point. The collection of directories is a data space. Use signac to automatically name and create the directories.

[4]:
import signac

A signac project represents the entire data space stored on disk with associated metadata. The method init_project creates a signac project in the current working directory by placing a signac.rc file with the project metadata and a workspace directory to hold the directories of the data space. The name argument is required with signac 1.x, but the value of the name is used only to populate signac.rc.

Create the project:

[5]:
project = signac.init_project()
[6]:
!cat signac.rc
project = None
schema_version = 1

A signac job is a container that holds the state point, assigned directory, and a job document.

[7]:
job = project.open_job(statepoint)
[8]:
job.statepoint
[8]:
{'N_particles': 128, 'volume_fraction': 0.6, 'seed': 20}

The job document is a persistent dictionary where you can record the job’s status.

[9]:
job.document
[9]:
{}

The first file for each simulation is the initial condition. Here is the initialization code from the Introducing HOOMD-blue tutorial, encapsulated in a function that takes a signac job as an argument:

[10]:
def init(job):
    # Place a number of particles as indicated by the signac job's state point.
    K = math.ceil(job.statepoint.N_particles**(1 / 3))
    spacing = 1.2
    L = K * spacing
    x = numpy.linspace(-L / 2, L / 2, K, endpoint=False)
    position = list(itertools.product(x, repeat=3))
    position = position[0:job.statepoint.N_particles]
    orientation = [(1, 0, 0, 0)] * job.statepoint.N_particles

    frame = gsd.hoomd.Frame()
    frame.particles.N = job.statepoint.N_particles
    frame.particles.position = position
    frame.particles.orientation = orientation
    frame.particles.typeid = [0] * job.statepoint.N_particles
    frame.particles.types = ['octahedron']
    frame.configuration.box = [L, L, L, 0, 0, 0]

    # Write `lattice.gsd` to the signac job's directory.
    with gsd.hoomd.open(name=job.fn('lattice.gsd'), mode='x') as f:
        f.append(frame)

    # Set the 'initialized' item in the job document.
    job.document['initialized'] = True

The init function uses job.statepoint.N_particles to access the state point parameter and job.fn to construct a filename in the assigned directory. init also sets the 'initialized' item in the job document to True which will be used in the next section of the tutorial.

Call init to initialize signac jobs at various volume fractions in the data space:

[11]:
for volume_fraction in [0.4, 0.5, 0.6]:
    statepoint = dict(N_particles=128, volume_fraction=volume_fraction, seed=20)
    job = project.open_job(statepoint)
    job.init()
    init(job)

This tutorial initializes only three jobs in the data space to keep the execution time and output short. In your own research, signac can help you organize and execute as many jobs as you need.

signac places the data space in a directory named workspace. Here are the files the loop generated:

[12]:
!ls workspace/*
workspace/59363805e6f46a715bc154b38dffc4e4:
lattice.gsd              signac_job_document.json signac_statepoint.json

workspace/972b10bd6b308f65f0bc3a06db58cf9d:
lattice.gsd              signac_job_document.json signac_statepoint.json

workspace/c1a59a95a0e8b4526b28cf12aa0a689e:
lattice.gsd              signac_job_document.json signac_statepoint.json

Each directory now contains the lattice.gsd file created by init as well as a signac_statepoint.json and signac_job_document.json files created by signac. The directory assigned to each signac job is a hash of the state point and is generated automatically by signac.

Summary#

In this section of the tutorial, you created a data space with directories to store the simulation results for a number of state points. So far, the directory for each simulation contains only the initial configuration file lattice.gsd.

The remaining sections in this tutorial show you how to execute a workflow on this data space that randomizes, compresses, and equilibrates each simulation.

This tutorial only teaches the basics of signac. Read the signac documentation to learn how to loop through all signac jobs, search, filter, and much more.

Executing Simulations#
Overview#
Questions#
  • How can I execute a series of workflow steps on many simulations?

Objectives#
  • Introduce workflows.

  • Demonstrate how to use signac-flow to define workflow steps and their associated pre-conditions and post-conditions.

  • Execute the workflow to randomize and compress all state points in the data space.

Boilerplate code#
[1]:
import math

import hoomd
import signac
Workflow steps#

The Introducing HOOMD-blue tutorial employs distinct workflow steps that must be performed in sequence to complete the self-assembly study at a given state point. These are initialization, randomization, compression, equilibration, and analysis. The previous section in this tutorial initialized every state point in the data space. This section will randomize and compress them and the next section will equilibrate them. Analysis can also be implemented as a workflow step, but this is left as an exercise for the reader.

Use signac-flow to define these workflow steps as Python functions and execute them in the proper sequence on all state points in the data space.

[2]:
import flow

Define a function that creates a Simulation object based on the signac job:

[3]:
def create_simulation(job):
    cpu = hoomd.device.CPU()

    # Set the simulation seed from the statepoint.
    sim = hoomd.Simulation(device=cpu, seed=job.statepoint.seed)
    mc = hoomd.hpmc.integrate.ConvexPolyhedron()
    mc.shape['octahedron'] = dict(vertices=[
        (-0.5, 0, 0),
        (0.5, 0, 0),
        (0, -0.5, 0),
        (0, 0.5, 0),
        (0, 0, -0.5),
        (0, 0, 0.5),
    ])
    sim.operations.integrator = mc

    return sim

This is the code from Introducing HOOMD-blue, adapted to use the seed for the current signac job with job.statepoint.seed.

Subclass FlowProject by convention.

[4]:
class Project(flow.FlowProject):
    pass

Define a function that executes the randomization step:

[5]:
@Project.pre.true('initialized')  # Pre-condition in job document.
@Project.post.true('randomized')  # Post-condition in job document.
@Project.operation  # Workflow step.
def randomize(job):
    sim = create_simulation(job)

    # Read `lattice.gsd` from the signac job's directory.
    sim.create_state_from_gsd(filename=job.fn('lattice.gsd'))
    sim.run(10e3)

    # Write `random.gsd` to the signac job's directory.
    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('random.gsd'))

    # Set the 'randomized' to satisfy the post-condition.
    job.document['randomized'] = True

In signac-flow’s terminology, a project operation is a complete workflow step that modifies the signac job’s state. Recall that the similarly named HOOMD-blue Operation is a class that acts on the state of the simulation at defined time steps. This tutorial uses the term workflow step wherever possible to avoid ambiguity.

@Project.operation is a decorator that declares the randomize function is a workflow step. @Project.pre and @Project.post define pre-conditions and post-conditions for this step, which return a boolean to indicate whether a workflow step is ready to start (pre-condition) or complete (post-condition). In this block, both conditions are evaluated by pre.true and post.true which examine the job document and check whether the item with the given key evaluates to True. Use pre- and post-conditions to define the sequence in which the workflow steps will execute. Here, the pre-condition checking 'initialized' is satisfied for those signac jobs that were initialized in the previous section which set job.document['initialize'] = True.

The body of the function creates the Simulation object using the create_simulation method from above, completes the randomization as in the Introducing HOOMD-blue tutorial, and sets the 'randomized' item in the job document to True. The function writes randomized.gsd to the signac job’s assigned directory using the job.fn method.

Similarly define a function that executes the compression step:

[6]:
@Project.pre.after(randomize)  # Execute after randomize completes.
@Project.post.true('compressed_step')
@Project.operation
def compress(job):
    sim = create_simulation(job)

    # Read `random.gsd` from the signac job directory.
    sim.create_state_from_gsd(filename=job.fn('random.gsd'))

    a = math.sqrt(2) / 2
    V_particle = 1 / 3 * math.sqrt(2) * a**3

    initial_box = sim.state.box
    final_box = hoomd.Box.from_box(initial_box)

    # Set the final box volume to the volume fraction for this signac job.
    final_box.volume = (sim.state.N_particles * V_particle
                        / job.statepoint.volume_fraction)
    compress = hoomd.hpmc.update.QuickCompress(
        trigger=hoomd.trigger.Periodic(10), target_box=final_box)
    sim.operations.updaters.append(compress)

    periodic = hoomd.trigger.Periodic(10)
    tune = hoomd.hpmc.tune.MoveSize.scale_solver(moves=['a', 'd'],
                                                 target=0.2,
                                                 trigger=periodic,
                                                 max_translation_move=0.2,
                                                 max_rotation_move=0.2)
    sim.operations.tuners.append(tune)

    while not compress.complete and sim.timestep < 1e6:
        sim.run(1000)

    if not compress.complete:
        raise RuntimeError("Compression failed to complete")

    # Write `compressed.gsd` to the job document.
    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('compressed.gsd'))

    # Set 'compressed step' in the signac job document.
    job.document['compressed_step'] = sim.timestep

This workflow step executes after the randomize step completes using the pre.after(randomize) pre-condition. The body of the function contains the code from the Introducing HOOMD-blue tutorial, changed to use the volume fraction for the current signac job with job.statepoint.volume_fraction and to read and write files from the signac job’s directory with job.fn.

The compress operation sets the compressed_step item in the job document and uses that to evaluate the post-condition. The next section of the tutorial will use the value of compressed_step.

Run the workflow#

Now that you have defined the workflow steps, check the status of the workflow:

[7]:
project = Project()
project.print_status(overview=False,
                     detailed=True,
                     parameters=['volume_fraction'])

Detailed View:

job id                            operation/group      volume_fraction  labels
--------------------------------  -----------------  -----------------  --------
59363805e6f46a715bc154b38dffc4e4  randomize [U]                    0.6
972b10bd6b308f65f0bc3a06db58cf9d  randomize [U]                    0.4
c1a59a95a0e8b4526b28cf12aa0a689e  randomize [U]                    0.5

[U]:unknown [R]:registered [I]:inactive [S]:submitted [H]:held [Q]:queued [A]:active [E]:error [GR]:group_registered [GI]:group_inactive [GS]:group_submitted [GH]:group_held [GQ]:group_queued [GA]:group_active [GE]:group_error


Each signac job is ready to execute randomize, the first step in the workflow. Run it:

[8]:
project.run(names=['randomize'])

Every signac job directory in the data space now has a random.gsd file produced by randomize:

[9]:
!ls workspace/*
workspace/59363805e6f46a715bc154b38dffc4e4:
lattice.gsd  random.gsd  signac_job_document.json  signac_statepoint.json

workspace/972b10bd6b308f65f0bc3a06db58cf9d:
lattice.gsd  random.gsd  signac_job_document.json  signac_statepoint.json

workspace/c1a59a95a0e8b4526b28cf12aa0a689e:
lattice.gsd  random.gsd  signac_job_document.json  signac_statepoint.json

Now, the status shows that the compress step is ready:

[10]:
project.print_status(overview=False,
                     detailed=True,
                     parameters=['volume_fraction'])

Detailed View:

job id                            operation/group      volume_fraction  labels
--------------------------------  -----------------  -----------------  --------
59363805e6f46a715bc154b38dffc4e4  compress [U]                     0.6
972b10bd6b308f65f0bc3a06db58cf9d  compress [U]                     0.4
c1a59a95a0e8b4526b28cf12aa0a689e  compress [U]                     0.5

[U]:unknown [R]:registered [I]:inactive [S]:submitted [H]:held [Q]:queued [A]:active [E]:error [GR]:group_registered [GI]:group_inactive [GS]:group_submitted [GH]:group_held [GQ]:group_queued [GA]:group_active [GE]:group_error


Execute it:

[11]:
project.run(names=['compress'])

Every signac job directory in the data space now has a compressed.gsd file produced by compress:

[12]:
!ls workspace/*
workspace/59363805e6f46a715bc154b38dffc4e4:
compressed.gsd  random.gsd                signac_statepoint.json
lattice.gsd     signac_job_document.json

workspace/972b10bd6b308f65f0bc3a06db58cf9d:
compressed.gsd  random.gsd                signac_statepoint.json
lattice.gsd     signac_job_document.json

workspace/c1a59a95a0e8b4526b28cf12aa0a689e:
compressed.gsd  random.gsd                signac_statepoint.json
lattice.gsd     signac_job_document.json
Summary#

In this section of the tutorial, you defined the workflow steps to randomize and compress the initial configuration using signac-flow, along with the pre- and post-conditions needed to sequence the steps. Then you executed the workflow steps on all state points in the dataset. The directory for each simulation now contains compressed.gsd and is ready for equilibration at the target volume fraction.

The next section in this tutorial teaches you how to write a workflow step that can continue itself and complete over several submissions.

This tutorial only teaches the basics of signac-flow. Read the signac-flow documentation to learn more.

Continuing Simulations#
Overview#
Questions#
  • How do I continue running a simulation?

Objectives#
  • Explain why you may want to continue running a simulation, such as wall time limits for cluster jobs.

  • Describe what you need to consider when writing a workflow step that can continue.

  • Demonstrate how to append to trajectory files, write needed data to a restart file and limit the simulation run to a given wall time.

Boilerplate code#
[1]:
import math

import flow
import hoomd
import signac
Workflow steps from the previous section#

The code in the next block collects the workflow steps the previous tutorial section to define the whole workflow.

[2]:
def create_simulation(job):
    cpu = hoomd.device.CPU()
    sim = hoomd.Simulation(device=cpu, seed=job.statepoint.seed)
    mc = hoomd.hpmc.integrate.ConvexPolyhedron()
    mc.shape['octahedron'] = dict(vertices=[
        (-0.5, 0, 0),
        (0.5, 0, 0),
        (0, -0.5, 0),
        (0, 0.5, 0),
        (0, 0, -0.5),
        (0, 0, 0.5),
    ])
    sim.operations.integrator = mc

    return sim


class Project(flow.FlowProject):
    pass


@Project.pre.true('initialized')
@Project.post.true('randomized')
@Project.operation
def randomize(job):
    sim = create_simulation(job)
    sim.create_state_from_gsd(filename=job.fn('lattice.gsd'))
    sim.run(10e3)
    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('random.gsd'))
    job.document['randomized'] = True


@Project.pre.after(randomize)
@Project.post.true('compressed_step')
@Project.operation
def compress(job):
    sim = create_simulation(job)
    sim.create_state_from_gsd(filename=job.fn('random.gsd'))

    a = math.sqrt(2) / 2
    V_particle = 1 / 3 * math.sqrt(2) * a**3

    initial_box = sim.state.box
    final_box = hoomd.Box.from_box(initial_box)
    final_box.volume = (sim.state.N_particles * V_particle
                        / job.statepoint.volume_fraction)
    compress = hoomd.hpmc.update.QuickCompress(
        trigger=hoomd.trigger.Periodic(10), target_box=final_box)
    sim.operations.updaters.append(compress)

    periodic = hoomd.trigger.Periodic(10)
    tune = hoomd.hpmc.tune.MoveSize.scale_solver(moves=['a', 'd'],
                                                 target=0.2,
                                                 trigger=periodic,
                                                 max_translation_move=0.2,
                                                 max_rotation_move=0.2)
    sim.operations.tuners.append(tune)

    while not compress.complete and sim.timestep < 1e6:
        sim.run(1000)

    if not compress.complete:
        raise RuntimeError("Compression failed to complete")

    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('compressed.gsd'))
    job.document['compressed_step'] = sim.timestep
Motivation#

Let’s say your workflow’s equilibration step takes 96 hours to complete and your HPC resource limits wall times to 24 hours. What do you do?

One solution is to write the equilibration step so that it can continue where it left off. When you execute the workflow, each incomplete signac job will move toward completing the step’s post condition. After several rounds of submissions, all signac jobs will be complete.

This section of the tutorial teaches you how to write a workflow step that can limit its run time and continue. The next section will cover effectively run workflow steps in cluster jobs on HPC resources.

Considerations#

You must carefully design your workflow step so that it can continue from where it left off:

  • Write the current state of the system to a GSD file and dynamic parameters to the job document (or other appropriate storage location).

  • Perform this write in a finally: block to ensure that it is written even when an exception is thrown.

  • Use the saved state when continuing the workflow step.

  • Open output files in append mode so that the final file includes output from the first and all continued executions.

  • Use absolute time step values for triggers so they run consistently before and after continuing the workflow step.

  • Check the elapsed wall time in a loop and stop executing before the cluster job’s wall time limit. Provide some buffer to write the simulation state and exit cleanly.

Here is the equilibration code from the Introducing HOOMD-blue tutorial as a signac-flow operation that can continue:

[3]:
N_EQUIL_STEPS = 200000  # Number of timesteps to run during equilibration.
HOOMD_RUN_WALLTIME_LIMIT = 30  # Time in seconds at which to stop the operation.


@Project.pre.after(compress)  # Execute after compress completes.
# Complete after N_EQUIL_STEPS made by this workflow step.
@Project.post(lambda job: job.document.get('timestep', 0) - job.document[
    'compressed_step'] >= N_EQUIL_STEPS)
@Project.operation
def equilibrate(job):
    end_step = job.document['compressed_step'] + N_EQUIL_STEPS

    sim = create_simulation(job)

    # Restore the tuned move size parameters from a previous execution.
    sim.operations.integrator.a = job.document.get('a', {})
    sim.operations.integrator.d = job.document.get('d', {})

    if job.isfile('restart.gsd'):
        # Read the final system configuration from a previous execution.
        sim.create_state_from_gsd(filename=job.fn('restart.gsd'))
    else:
        # Or read `compressed.gsd` for the first execution of equilibrate.
        sim.create_state_from_gsd(filename=job.fn('compressed.gsd'))

    # Write `trajectory.gsd` in append mode.
    gsd_writer = hoomd.write.GSD(filename=job.fn('trajectory.gsd'),
                                 trigger=hoomd.trigger.Periodic(10_000),
                                 mode='ab')
    sim.operations.writers.append(gsd_writer)

    # Tune move for the first 5000 steps of the equilibration step.
    tune = hoomd.hpmc.tune.MoveSize.scale_solver(
        moves=['a', 'd'],
        target=0.2,
        trigger=hoomd.trigger.And([
            hoomd.trigger.Periodic(100),
            hoomd.trigger.Before(job.document['compressed_step'] + 5_000)
        ]))
    sim.operations.tuners.append(tune)

    try:
        # Loop until the simulation reaches the target timestep.
        while sim.timestep < end_step:
            # Run the simulation in chunks of 10,000 time steps.
            sim.run(min(10_000, end_step - sim.timestep))

            # End the workflow step early if the next run would exceed the
            # alotted walltime. Use the walltime of the current run as
            # an estimate for the next.
            if (sim.device.communicator.walltime + sim.walltime
                    >= HOOMD_RUN_WALLTIME_LIMIT):
                break
    finally:
        # Write the state of the system to `restart.gsd`.
        hoomd.write.GSD.write(state=sim.state,
                              mode='wb',
                              filename=job.fn('restart.gsd'))

        # Store the current timestep and tuned trial move sizes.
        job.document['timestep'] = sim.timestep
        job.document['a'] = sim.operations.integrator.a.to_base()
        job.document['d'] = sim.operations.integrator.d.to_base()

        walltime = sim.device.communicator.walltime
        sim.device.notice(f'{job.id} ended on step {sim.timestep} '
                          f'after {walltime} seconds')

When this workflow step is executed, it stores the trial move sizes a, d and the current timestep in the job document as well as the the state of the simulation in restart.gsd. It reads these when starting again to continue from where the previous execution stopped. This is a large code block, see the comments for more details on how this workflow step can continue from where it stopped.

To limit the execution time, it splits the total simulation length into chunks and executes them in a loop. After each loop iteration, it checks to see whether the next call to run is likely to exceed the given time limit. sim.device.communicator.walltime gives the elapsed time from the start of the workflow step’s execution, and is identical on all MPI ranks. Using another source of time might lead to deadlocks. As a pedagogical example, this tutorial sets a 30 second wall time limit and uses 10,000 timestep chunks - in practice you will likely set limits from hours to days and use larger 100,000 or 1,000,000 step sized chunks depending on your simulation’s performance. You should set the chunk size large enough to avoid the small overhead from each call to run while at the same time breaking the complete execution into many chunks.

The equilibrate step is ready to execute:

[4]:
project = Project()
project.print_status(overview=False,
                     detailed=True,
                     parameters=['volume_fraction'])

Detailed View:

job id                            operation/group      volume_fraction  labels
--------------------------------  -----------------  -----------------  --------
59363805e6f46a715bc154b38dffc4e4  equilibrate [U]                  0.6
972b10bd6b308f65f0bc3a06db58cf9d  equilibrate [U]                  0.4
c1a59a95a0e8b4526b28cf12aa0a689e  equilibrate [U]                  0.5

[U]:unknown [R]:registered [I]:inactive [S]:submitted [H]:held [Q]:queued [A]:active [E]:error [GR]:group_registered [GI]:group_inactive [GS]:group_submitted [GH]:group_held [GQ]:group_queued [GA]:group_active [GE]:group_error


Execute it:

[5]:
project.run()
972b10bd6b308f65f0bc3a06db58cf9d ended on step 32000 after 21.360734 seconds
59363805e6f46a715bc154b38dffc4e4 ended on step 23000 after 15.127837 seconds
c1a59a95a0e8b4526b28cf12aa0a689e ended on step 32000 after 25.856547 seconds

The equilibrate step executed for less than HOOMD_RUN_WALLTIME_LIMIT seconds for each of the signac jobs in the dataspace. In a production environment, you would run the project repeatedly until it completes.

See that equilibrate step produced the trajectory.gsd file and the 'a', 'd', and 'timestep' items in the job document:

[6]:
!ls workspace/*
workspace/59363805e6f46a715bc154b38dffc4e4:
compressed.gsd  random.gsd   signac_job_document.json  trajectory.gsd
lattice.gsd     restart.gsd  signac_statepoint.json

workspace/972b10bd6b308f65f0bc3a06db58cf9d:
compressed.gsd  random.gsd   signac_job_document.json  trajectory.gsd
lattice.gsd     restart.gsd  signac_statepoint.json

workspace/c1a59a95a0e8b4526b28cf12aa0a689e:
compressed.gsd  random.gsd   signac_job_document.json  trajectory.gsd
lattice.gsd     restart.gsd  signac_statepoint.json
[7]:
job = project.open_job(dict(N_particles=128, volume_fraction=0.6, seed=20))
print(job.document)
{'initialized': True, 'randomized': True, 'compressed_step': 13000, 'timestep': 23000, 'a': {'octahedron': 0.04564840324176478}, 'd': {'octahedron': 0.02567136340037109}}
Summary#

In this section of the tutorial, you defined the workflow step to equilibreate the hard particle simulation. It stores dynamic parameters and the state of the system needed to continue execution when executed again. Now, the directory for each simulation contains trajectory.gsd, and would be ready for analysis after executed to completion.

The next section in this tutorial will show you how to implement this workflow on the command line and submit cluster jobs that effectively use dense nodes.

This tutorial only teaches the basics of signac-flow. Read the signac-flow documentation to learn more.

Submitting Cluster Jobs#
Overview#
Questions#
  • How do I submit workflows on HPC resources?

  • How can I combine many simulations into a single cluster job?

Objectives#
  • Show how to structure the workflow in project.py and use signac-flow’s command line interface.

  • Demonstrate the use of directives to set walltime limits and execute with MPI domain decomposition.

  • Explain how to use aggregate operations with MPI partitions to increase throughput.

Cluster jobs#

On HPC resources, you submit cluster jobs to the queue which execute on the compute nodes. You can use signac-flow to generate cluster job submission scripts that execute the steps in your workflow. Use this to execute the expensive or time consuming workflow steps on HPC resources that provide access to many more CPU cores or GPUs than are available on the typical workstation. You can use these resources for to increase throughput (number of simulations per unit time) by executing many simulations at the same time, reduce latency (time to complete a single simulation) by executing each simulation on more than one MPI rank with domain decomposition, or some combination of the two.

This tutorial will demonstrate how to use signac-flow to submit HOOMD-blue workflow steps in cluster jobs. See Parallel Simulations with MPI to learn more about MPI domain decomposition in HOOMD-blue.

Command line interface#

Use the command line interface to submit cluster jobs on HPC resources. Place the entire worfklow in a Python file and add a __main__ entry point that calls Project().main(). project.py contains the workflow step code from the previous two tutorial sections and the additional code.

Define parameters:

N_RANKS = 2
N_EQUIL_STEPS = 200000
CLUSTER_JOB_WALLTIME = 1
HOOMD_RUN_WALLTIME_LIMIT = CLUSTER_JOB_WALLTIME * 3600 - 10 * 60

The values used in this tutorial are for example purposes only. You should choose a number of MPI ranks, equilibration steps, and cluster job walltime appropriate for your project. In this tutorial, the workflow step stops 10 minutes before the end of the cluster job. In your own workflows you may need more or less time depending on how long it takes to write out the final system state and exit cleanly.

Set the number of MPI ranks and cluster job walltime for the equilibrate operation:

@Project.operation(directives=dict(nranks=N_RANKS, walltime=CLUSTER_JOB_WALLTIME))

signac flow directives set options for the generated cluster job. Here, nranks sets the number of MPI ranks that the workflow step uses and waltime sets the cluster job walltime in hours.

Execute the entrypoint:

if __name__ == '__main__':
    Project().main()
[1]:
%pycat project.py
import math

import flow
import hoomd

# parameters
N_RANKS = 2
N_EQUIL_STEPS = 200000
CLUSTER_JOB_WALLTIME = 1
HOOMD_RUN_WALLTIME_LIMIT = CLUSTER_JOB_WALLTIME * 3600 - 10 * 60


def create_simulation(job):
    cpu = hoomd.device.CPU()
    sim = hoomd.Simulation(device=cpu, seed=job.statepoint.seed)
    mc = hoomd.hpmc.integrate.ConvexPolyhedron()
    mc.shape['octahedron'] = dict(vertices=[
        (-0.5, 0, 0),
        (0.5, 0, 0),
        (0, -0.5, 0),
        (0, 0.5, 0),
        (0, 0, -0.5),
        (0, 0, 0.5),
    ])
    sim.operations.integrator = mc

    return sim


class Project(flow.FlowProject):
    pass


@Project.pre.true('initialized')
@Project.post.true('randomized')
@Project.operation
def randomize(job):
    sim = create_simulation(job)
    sim.create_state_from_gsd(filename=job.fn('lattice.gsd'))
    sim.run(10e3)
    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('random.gsd'))
    job.document['randomized'] = True


@Project.pre.after(randomize)
@Project.post.true('compressed_step')
@Project.operation
def compress(job):
    sim = create_simulation(job)
    sim.create_state_from_gsd(filename=job.fn('random.gsd'))

    a = math.sqrt(2) / 2
    V_particle = 1 / 3 * math.sqrt(2) * a**3

    initial_box = sim.state.box
    final_box = hoomd.Box.from_box(initial_box)
    final_box.volume = (sim.state.N_particles * V_particle
                        / job.statepoint.volume_fraction)
    compress = hoomd.hpmc.update.QuickCompress(
        trigger=hoomd.trigger.Periodic(10), target_box=final_box)
    sim.operations.updaters.append(compress)

    periodic = hoomd.trigger.Periodic(10)
    tune = hoomd.hpmc.tune.MoveSize.scale_solver(moves=['a', 'd'],
                                                 target=0.2,
                                                 trigger=periodic,
                                                 max_translation_move=0.2,
                                                 max_rotation_move=0.2)
    sim.operations.tuners.append(tune)

    while not compress.complete and sim.timestep < 1e6:
        sim.run(1000)

    if not compress.complete:
        raise RuntimeError("Compression failed to complete")

    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('compressed.gsd'))
    job.document['compressed_step'] = sim.timestep


@Project.pre.after(compress)
@Project.post(lambda job: job.document.get('timestep', 0) - job.document[
    'compressed_step'] >= N_EQUIL_STEPS)
# Cluster job directives.
@Project.operation(directives=dict(nranks=N_RANKS,
                                   walltime=CLUSTER_JOB_WALLTIME))
def equilibrate(job):
    end_step = job.document['compressed_step'] + N_EQUIL_STEPS

    sim = create_simulation(job)

    sim.operations.integrator.a = job.document.get('a', {})
    sim.operations.integrator.d = job.document.get('d', {})

    if job.isfile('restart.gsd'):
        sim.create_state_from_gsd(filename=job.fn('restart.gsd'))
    else:
        sim.create_state_from_gsd(filename=job.fn('compressed.gsd'))

    gsd_writer = hoomd.write.GSD(filename=job.fn('trajectory.gsd'),
                                 trigger=hoomd.trigger.Periodic(10_000),
                                 mode='ab')
    sim.operations.writers.append(gsd_writer)

    tune = hoomd.hpmc.tune.MoveSize.scale_solver(
        moves=['a', 'd'],
        target=0.2,
        trigger=hoomd.trigger.And([
            hoomd.trigger.Periodic(100),
            hoomd.trigger.Before(job.document['compressed_step'] + 5_000)
        ]))
    sim.operations.tuners.append(tune)

    try:
        while sim.timestep < end_step:
            sim.run(min(100_000, end_step - sim.timestep))

            if (sim.device.communicator.walltime + sim.walltime >=
                    HOOMD_RUN_WALLTIME_LIMIT):
                break
    finally:
        hoomd.write.GSD.write(state=sim.state,
                              mode='wb',
                              filename=job.fn('restart.gsd'))

        job.document['timestep'] = sim.timestep
        job.document['a'] = sim.operations.integrator.a.to_base()
        job.document['d'] = sim.operations.integrator.d.to_base()

        walltime = sim.device.communicator.walltime
        sim.device.notice(f'{job.id} ended on step {sim.timestep} '
                          f'after {walltime} seconds')


# Entrypoint.
if __name__ == '__main__':
    Project().main()

Check the status using python3 project.py status:

[2]:
!python3 project.py status --detailed --no-overview -p volume_fraction
Using environment configuration: StandardEnvironment
Fetching status: 100%|██████████████████████████| 9/9 [00:00<00:00, 7561.85it/s]
Fetching labels: 100%|████████████████████████| 3/3 [00:00<00:00, 144631.17it/s]

Detailed View:

job id                            operation/group      volume_fraction  labels
--------------------------------  -----------------  -----------------  --------
59363805e6f46a715bc154b38dffc4e4  equilibrate [U]                  0.6
972b10bd6b308f65f0bc3a06db58cf9d  equilibrate [U]                  0.4
c1a59a95a0e8b4526b28cf12aa0a689e  equilibrate [U]                  0.5

[U]:unknown [R]:registered [I]:inactive [S]:submitted [H]:held [Q]:queued [A]:active [E]:error [GR]:group_registered [GI]:group_inactive [GS]:group_submitted [GH]:group_held [GQ]:group_queued [GA]:group_active [GE]:group_error


The equilibrate step is ready to execute. signac-flow automates the cluster job submission process with python3 project.py submit. Use the --pretend flag first to ensure that the generated cluster jobs are correct (this displays the generated submission scripts without submitting them):

$ python3 project.py submit --pretend

Submitting cluster job 'octahedra_se/972b10bd6b308f65f0bc3a06db58cf9d/equilibrate/cdc78829a46f27e11ee8a98049bf0575':
 - Group: equilibrate(972b10bd6b308f65f0bc3a06db58cf9d)

# Submit command: sbatch
#!/bin/bash
#SBATCH --job-name="octahedra_se/972b10bd6b308f65f0bc3a06db58cf9d/equilibrate/cdc78829a46f27e11ee8a98049bf0575"
#SBATCH --partition=standard
#SBATCH -t 01:00:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=2

set -e
set -u

# equilibrate(972b10bd6b308f65f0bc3a06db58cf9d)
python project.py run -o equilibrate -j 972b10bd6b308f65f0bc3a06db58cf9d
# Eligible to run:
# mpiexec -n 2  python project.py exec equilibrate 972b10bd6b308f65f0bc3a06db58cf9d


Submitting cluster job 'octahedra_se/59363805e6f46a715bc154b38dffc4e4/equilibrate/2c15943de4918753dc2373cd33d527ec':
 - Group: equilibrate(59363805e6f46a715bc154b38dffc4e4)
# Submit command: sbatch
#!/bin/bash
#SBATCH --job-name="octahedra_se/59363805e6f46a715bc154b38dffc4e4/equilibrate/2c15943de4918753dc2373cd33d527ec"
#SBATCH --partition=standard
#SBATCH -t 01:00:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=2

set -e
set -u

# equilibrate(59363805e6f46a715bc154b38dffc4e4)
python project.py run -o equilibrate -j 59363805e6f46a715bc154b38dffc4e4
# Eligible to run:
# mpiexec -n 2  python project.py exec equilibrate 59363805e6f46a715bc154b38dffc4e4


Submitting cluster job 'octahedra_se/c1a59a95a0e8b4526b28cf12aa0a689e/equilibrate/e1ffbf0eafe27af17b2ffc6e0c4c6dd1':
 - Group: equilibrate(c1a59a95a0e8b4526b28cf12aa0a689e)
# Submit command: sbatch
#!/bin/bash
#SBATCH --job-name="octahedra_se/c1a59a95a0e8b4526b28cf12aa0a689e/equilibrate/e1ffbf0eafe27af17b2ffc6e0c4c6dd1"
#SBATCH --partition=standard
#SBATCH -t 01:00:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=2

set -e
set -u

# equilibrate(c1a59a95a0e8b4526b28cf12aa0a689e)
python project.py run -o equilibrate -j c1a59a95a0e8b4526b28cf12aa0a689e
# Eligible to run:
# mpiexec -n 2  python project.py exec equilibrate c1a59a95a0e8b4526b28cf12aa0a689e

In this configuration, signac flow submits one cluster job for each signac job. Each cluster job executes HOOMD-blue with 2 MPI ranks to domain decompose the simulation. You can use one cluster job for each signac job on HPC resources that have shared queues and allow you to submit many cluster jobs.

Partitioning jobs#

Some HPC resources schedule jobs only by full node or limit the number of cluster jobs you can queue at one time. Or you may have many thousands of signac jobs and want to reduce time spent waiting in queue. In these cases, use MPI to partition one cluster job to executes many signac jobs in parallel (see Parallel Simulations with MPI for an introduction to MPI partitions). You can use MPI partitions alone (one rank per signac job) or in combination with MPI domain decomposition (more than one rank per signac job).

Aggregate operations in signac-flow are workflow steps that execute on a list of signac jobs. For example, you could use aggregate operations to loop over simulations and average results generated with different random number seeds. See the signac-flow documentation for more information on aggregation in general

This tutorial aggregates signac jobs in groups of a defined size and executes the group in parallel using MPI partitions. The example is small for demonstration purposes. It uses 2 MPI ranks per signac job and executes all three signac jobs in one cluster job. In production work you should choose the number of ranks per signac job (RANKS_PER_PARTITION) and the number of signac jobs per cluster job (JOBS_PER_AGGREGATE) to utilize an integer number of whole nodes in each cluster job leaving no empty cores or GPUs. For example use 16 ranks per signac job and 32 signac jobs per cluster job to use 4 whole 128-core nodes per cluster job.

project_partitioned.py modifies project.py so that the equilibrate step executes in a partition:

[3]:
%pycat project_partitioned.py
import math

import flow
import hoomd

RANKS_PER_PARTITION = 2
JOBS_PER_AGGREGATE = 3
N_EQUIL_STEPS = 200000
CLUSTER_JOB_WALLTIME = 1
HOOMD_RUN_WALLTIME_LIMIT = CLUSTER_JOB_WALLTIME * 3600 - 10 * 60


def create_simulation(job, communicator):
    cpu = hoomd.device.CPU(communicator=communicator)
    sim = hoomd.Simulation(device=cpu, seed=job.statepoint.seed)
    mc = hoomd.hpmc.integrate.ConvexPolyhedron()
    mc.shape['octahedron'] = dict(vertices=[
        (-0.5, 0, 0),
        (0.5, 0, 0),
        (0, -0.5, 0),
        (0, 0.5, 0),
        (0, 0, -0.5),
        (0, 0, 0.5),
    ])
    sim.operations.integrator = mc

    return sim


class Project(flow.FlowProject):
    pass


@Project.pre.true('initialized')
@Project.post.true('randomized')
@Project.operation
def randomize(job):
    sim = create_simulation(job)
    sim.create_state_from_gsd(filename=job.fn('lattice.gsd'))
    sim.run(10e3)
    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('random.gsd'))
    job.document['randomized'] = True


@Project.pre.after(randomize)
@Project.post.true('compressed_step')
@Project.operation
def compress(job):
    sim = create_simulation(job)
    sim.create_state_from_gsd(filename=job.fn('random.gsd'))

    a = math.sqrt(2) / 2
    V_particle = 1 / 3 * math.sqrt(2) * a**3

    initial_box = sim.state.box
    final_box = hoomd.Box.from_box(initial_box)
    final_box.volume = (sim.state.N_particles * V_particle
                        / job.statepoint.volume_fraction)
    compress = hoomd.hpmc.update.QuickCompress(
        trigger=hoomd.trigger.Periodic(10), target_box=final_box)
    sim.operations.updaters.append(compress)

    periodic = hoomd.trigger.Periodic(10)
    tune = hoomd.hpmc.tune.MoveSize.scale_solver(moves=['a', 'd'],
                                                 target=0.2,
                                                 trigger=periodic,
                                                 max_translation_move=0.2,
                                                 max_rotation_move=0.2)
    sim.operations.tuners.append(tune)

    while not compress.complete and sim.timestep < 1e6:
        sim.run(1000)

    if not compress.complete:
        raise RuntimeError("Compression failed to complete")

    hoomd.write.GSD.write(state=sim.state,
                          mode='xb',
                          filename=job.fn('compressed.gsd'))
    job.document['compressed_step'] = sim.timestep


def equilibrated(job):
    return job.document.get(
        'timestep', 0) - job.document['compressed_step'] >= N_EQUIL_STEPS


@Project.pre.true('compressed_step')
@Project.post(lambda *jobs: all(equilibrated(job) for job in jobs))
@Project.operation(directives=dict(
    nranks=lambda *jobs: RANKS_PER_PARTITION * len(jobs),
    walltime=CLUSTER_JOB_WALLTIME),
                   aggregator=flow.aggregator.groupsof(num=JOBS_PER_AGGREGATE))
def equilibrate(*jobs):
    communicator = hoomd.communicator.Communicator(
        ranks_per_partition=RANKS_PER_PARTITION)
    job = jobs[communicator.partition]

    end_step = job.document['compressed_step'] + N_EQUIL_STEPS

    sim = create_simulation(job)

    sim.operations.integrator.a = job.document.get('a', {})
    sim.operations.integrator.d = job.document.get('d', {})

    if job.isfile('restart.gsd'):
        sim.create_state_from_gsd(filename=job.fn('restart.gsd'))
    else:
        sim.create_state_from_gsd(filename=job.fn('compressed.gsd'))

    gsd_writer = hoomd.write.GSD(filename=job.fn('trajectory.gsd'),
                                 trigger=hoomd.trigger.Periodic(10_000),
                                 mode='ab')
    sim.operations.writers.append(gsd_writer)

    tune = hoomd.hpmc.tune.MoveSize.scale_solver(
        moves=['a', 'd'],
        target=0.2,
        trigger=hoomd.trigger.And([
            hoomd.trigger.Periodic(100),
            hoomd.trigger.Before(job.document['compressed_step'] + 5_000)
        ]))
    sim.operations.tuners.append(tune)

    try:
        while sim.timestep < end_step:
            sim.run(min(100_000, end_step - sim.timestep))

            if (sim.device.communicator.walltime + sim.walltime >=
                    HOOMD_RUN_WALLTIME_LIMIT):
                break
    finally:
        hoomd.write.GSD.write(state=sim.state,
                              mode='wb',
                              filename=job.fn('restart.gsd'))

        job.document['timestep'] = sim.timestep
        job.document['a'] = sim.operations.integrator.a.to_base()
        job.document['d'] = sim.operations.integrator.d.to_base()

        walltime = sim.device.communicator.walltime
        sim.device.notice(f'{job.id} ended on step {sim.timestep} '
                          f'after {walltime} seconds')


if __name__ == '__main__':
    Project().main()

Here are the differences between project.py and project_partitioned.py:

  • The variables RANKS_PER_PARTITION and JOBS_PER_AGGREGATE set how signac-flow partitions signac jobs into cluster jobs.

  • create_simulation takes the communicator argument and passes it to the device constructor.

  • The operation argument aggregator=flow.aggregator.groupsof(num=JOBS_PER_AGGREGATE) defines equilibrate as an aggregate with up to JOBS_PER_AGGREGATE signac jobs contained in it.

  • The pre and post conditions on equilibrated are now functions of an array of signac jobs:

    @Project.pre.true('compressed_step')
    @Project.post(lambda *jobs: all(equilibrated(job) for job in jobs))
    
  • The directives argument sets the number of ranks needed by all jobs in the aggregate:

    directives=dict(nranks=lambda *jobs: RANKS_PER_PARTITION * len(jobs),
                    walltime=CLUSTER_JOB_WALLTIME)
    
  • equilibrate is now a function of an array of jobs and chooses the job based on the communicator’s partition.

    def equilibrate(*jobs):
        communicator = hoomd.communicator.Communicator(ranks_per_partition=RANKS_PER_PARTITION)
        job = jobs[communicator.partition]
    

    (the remainder of equilibrate is unchanged from project.py.

Here is the cluster job generated by project_partitioned.py

$ python3 project_partitioned.py submit --pretend

Submitting cluster job 'octahedra_se/agg-e202cc8c2ce0bc1ef7a9d9fcdcd62b6d/equilibrate/614e7ec5470deb1e958ac9863ed1fb07':
 - Group: equilibrate(agg-e202cc8c2ce0bc1ef7a9d9fcdcd62b6d)

# Submit command: sbatch
#!/bin/bash
#SBATCH --job-name="octahedra_se/agg-e202cc8c2ce0bc1ef7a9d9fcdcd62b6d/equilibrate/614e7ec5470deb1e958ac9863ed1fb07"
#SBATCH --partition=standard
#SBATCH -t 01:00:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=6

set -e
set -u

# equilibrate(agg-e202cc8c2ce0bc1ef7a9d9fcdcd62b6d)
python project_partitioned.py run -o equilibrate -j agg-e202cc8c2ce0bc1ef7a9d9fcdcd62b6d
# Eligible to run:
# mpiexec -n 6  python project_partitioned.py exec equilibrate agg-e202cc8c2ce0bc1ef7a9d9fcdcd62b6d

It generates only one cluster job that uses MPI to execute the workflow step on 6 ranks which equilibrate splits into 3 partitions that each execute one signac job on 2 ranks each.

Esnure that your partitioned jobs set the product RANKS_PER_PARTITION * JOBS_PER_AGGREGATE to a number of CPU cores or GPUs equal to a whole number of cluster nodes on your HPC resource. Failure to do so will waste resources on HPC resources that schedule by node.

Summary#

In this section of the tutorial, you defined the workflow in a file and used the signac flow command line interface to generate cluster jobs for submission. You also learned how to use partitions to more effectively use HPC resources by fully utilizing compute nodes with fewer cluster jobs.

This is the end of the tutorial on organizing and executing simulations.

This tutorial only teaches the basics of signac-flow. Read the signac-flow documentation to learn more.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Modelling Rigid Bodies#

This tutorial shows you how to run simulations of rigid bodies.

Prerequisites:

You should be familiar with the concepts taught in the tutorial Introducing HOOMD-blue, Introducing Molecular Dynamics, and have some background knowledge on statistical mechanics as well as linear algebra.

Introduction to Rigid Bodies#
Overview#
Questions#
  • What is a rigid body?

  • How do I set rigid body parameters?

  • How do the rigid body parameters translate into the simulation box?

Objectives#
  • Define a rigid body as central particle and a set of constituent particles.

  • Describe how body coordinates relate to global coordinates.

  • Enumerate the properties of rigid bodies.

  • Demonstrate setting the properties of a rigid dimer and creating an initial condition.

Boilerplate code#
[1]:
import itertools
import math

import gsd.hoomd
import hoomd
import matplotlib
import numpy

%matplotlib inline
matplotlib.style.use('ggplot')
import matplotlib_inline

matplotlib_inline.backend_inline.set_matplotlib_formats('svg')

The render function in the next (hidden) cell will render the system state using fresnel. Find the source in the hoomd-examples repository.

Introduction#

A rigid body is an incompressible body composed of one central and one or more constituent particles. All particles in a given rigid body interact with all other particles in the simulation. In molecular dynamics simulations, the central particle translates and rotates in response to the net force and torque on the body. The constituent particles follow the central particle.

Coordinate systems#

You define the positions and orientations of the constituent particles in body coordinates, a coordinate system where the (0,0,0) is at the position of the central particle and the body is in a reference orientation.

For example, define the positions of two points in a rigid dimer:

[4]:
dimer_positions = [[-1.2, 0, 0], [1.2, 0, 0]]

Each instance of a rigid body in a simulation is placed in the system global coordinates, located by the position and orientation of the central particle.

[5]:
central_position = [10, 5, 0]
central_rotation = 0.9

To demonstrate, the following code block computes the global positions of the the dimer at the given central position and rotation (in 2D).

[6]:
cos_theta = math.cos(central_rotation)
sin_theta = math.sin(central_rotation)

global_positions = []
for i in range(len(dimer_positions)):
    x, y = dimer_positions[i][:2]

    global_positions.append(
        [[central_position[0] + (x * cos_theta - y * sin_theta)],
         [central_position[1] + (y * cos_theta + x * sin_theta)]])

Visualize the configuration:

[7]:
fig = matplotlib.figure.Figure(figsize=(5, 3.09), dpi=100)
ax = fig.add_subplot(aspect='equal')

ax.plot([central_position[0], central_position[0] - 3 * sin_theta],
        [central_position[1], central_position[1] + 3 * cos_theta],
        color='k')

ax.plot([central_position[0], central_position[0] + 3 * cos_theta],
        [central_position[1], central_position[1] + 3 * sin_theta],
        color='k')

ax.text(central_position[0] + 1.5 * cos_theta,
        central_position[1] + 1.5 * sin_theta,
        'Body X',
        rotation=central_rotation * 180 / math.pi,
        verticalalignment='center')

ax.text(central_position[0] - 2 * sin_theta,
        central_position[1] + 2 * cos_theta,
        'Body Y',
        rotation=central_rotation * 180 / math.pi + 90,
        verticalalignment='center')

ax.add_patch(
    matplotlib.patches.Circle((central_position[0], central_position[1]),
                              0.1,
                              color='C0'))

for position in global_positions:
    ax.add_patch(
        matplotlib.patches.Circle((position[0], position[1]), 1.0, color='C1'))

ax.set_xlim(0, 20)
ax.set_ylim(0, 12)

ax.set_xlabel('Global X')
ax.set_ylabel('Global Y')

fig
[7]:
_images/tutorial_06-Modelling-Rigid-Bodies_01-Introduction-to-Rigid-Bodies_12_0.svg
Properties of rigid bodies#

The following rigid body properties are given by the properties of the central particle:

  • Mass - the total mass of the rigid body.

  • Moment of inertia tensor - how mass is distributed throughout the rigid body.

  • Velocity - velocity of the center of mass of the rigid body.

  • Angular momentum - angular momentum of the rigid body.

  • Position - the position in global coordinates. Example: position = [1, 2, -3]

  • Orientation - a quaternion that rotates the rigid body about the central particle. Example: orientation = [1, 0, 0, 0]

The following constituent particle properties are given by the properties of a given rigid body type:

  • Constituent Particle Positions - The vector from the center of the rigid body to the constituent particle in body coordinates.

  • Constituent Particle Orientation - A quaternion that rotates the constituent particle about its center.

Defining properties of the rigid dimer#

Let each constituent particle in the dimer be a point particle of type A with mass 1 at the constituent positions previously defined in dimer_positions. Each dimer will be located at the position of a particle of type dimer.

Let’s create an initial configuration of dimers. Start with a snapshot containing both particle types:

[8]:
frame = gsd.hoomd.Frame()
frame.particles.types = ['dimer', 'A']

Place dimer particles (typeid=0) in the simulation box. Place them far enough apart so that the A particles will not touch in the initial condition:

[9]:
m = 4
N_particles = m**3
spacing = 5
K = math.ceil(N_particles**(1 / 3))
L = K * spacing
x = numpy.linspace(-L / 2, L / 2, K, endpoint=False)
position = list(itertools.product(x, repeat=3))
position = numpy.array(position) + [spacing / 2, spacing / 2, spacing / 2]
frame.particles.N = N_particles
frame.particles.position = position[0:N_particles, :]
frame.particles.typeid = [0] * N_particles
frame.configuration.box = [L, L, L, 0, 0, 0]

With two mass 1 particles, the total mass of the body is 2. Set the mass of each instance of the body:

[10]:
frame.particles.mass = [2] * N_particles

The moment of inertia of a point particle about a given axis is given by \(I_i = m r_i^2\), where \(r_i\) is the distance of the point from the axis. More generally, the moment of inertia is a tensor and includes off-diagonal values (you will learn more about this in a later tutorial section).

Compute the moment of inertia of the dimer:

[11]:
mass = 1
I = numpy.zeros(shape=(3, 3))
for r in dimer_positions:
    I += mass * (numpy.dot(r, r) * numpy.identity(3) - numpy.outer(r, r))
I
[11]:
array([[0.  , 0.  , 0.  ],
       [0.  , 2.88, 0.  ],
       [0.  , 0.  , 2.88]])

In this case, the tensor is diagonal. This is important as HOOMD-blue assumes that bodies have a diagonal moment of inertia in body coordinates in the form: \([I_{xx}, I_{yy}, I_{zz}]\). Set the moments of inertia of each body in the snapshot:

[12]:
frame.particles.moment_inertia = [I[0, 0], I[1, 1], I[2, 2]] * N_particles

Notice that \(I_{xx}\) is zero for this dimer while \(I_{yy}\) and \(I_{zz}\) are non-zero. HOOMD-blue checks which moments of inertia are non-zero and integrates degrees of freedom only for those axes with non-zero moments of inertia. In this example, the dimer will rotate about the body’s y and z axes, but not x.

HOOMD-blue represents orientations with quaternions. The quaternion \([1, 0, 0, 0]\) is the identity. Set the orientation of each body in the snapshot to the identity:

[13]:
frame.particles.orientation = [(1, 0, 0, 0)] * N_particles

Write the rigid centers to a GSD file for later use:

[14]:
with gsd.hoomd.open(name='dimer_centers.gsd', mode='x') as f:
    f.append(frame)

The hoomd.md.constrain.Rigid class is responsible for applying the rigid body constraints:

[15]:
rigid = hoomd.md.constrain.Rigid()

Set the constituent particle properties in body coordinates for the rigid body type:

[16]:
rigid.body['dimer'] = {
    "constituent_types": ['A', 'A'],
    "positions": dimer_positions,
    "orientations": [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)],
}

Rigid will use the body definition to update particle type, positions, and orientations each time step.

Placing constituent particles in the initial condition#

So far, our snapshot has only the dimer central particles:

[17]:
sim = hoomd.Simulation(device=hoomd.device.CPU(), seed=4)
sim.create_state_from_gsd(filename='dimer_centers.gsd')
render(sim.state.get_snapshot())
[17]:
_images/tutorial_06-Modelling-Rigid-Bodies_01-Introduction-to-Rigid-Bodies_35_0.png

Rigid.create_bodies will place constituent particles in the simulation state:

[18]:
rigid.create_bodies(sim.state)

Each central particle now has the two constituent particles of the dimer placed around it:

[19]:
render(sim.state.get_snapshot())
[19]:
_images/tutorial_06-Modelling-Rigid-Bodies_01-Introduction-to-Rigid-Bodies_39_0.png

Understand that Rigid will overwrite the positions and orientations of the constituent particles in the simulation state. To demonstrate, let’s modify the positions of the constituents:

[20]:
with sim.state.cpu_local_snapshot as snapshot:
    typeid = snapshot.particles.typeid
    snapshot.particles.position[typeid == 1] = [0, 0, 0]
[21]:
render(sim.state.get_snapshot())
[21]:
_images/tutorial_06-Modelling-Rigid-Bodies_01-Introduction-to-Rigid-Bodies_42_0.png

Set the rigid constraint with the MD integrator so it will take effect on the simulation. The next section of this tutorial will explain these steps in more detail:

[22]:
integrator = hoomd.md.Integrator(dt=0.005, integrate_rotational_dof=True)
integrator.rigid = rigid
sim.operations.integrator = integrator

Rigid will apply the rigid body constraints at the start of a simulation run and on every timestep. Calling sim.run(0) will restore the constituent particle positions:

[23]:
sim.run(0)
render(sim.state.get_snapshot())
[23]:
_images/tutorial_06-Modelling-Rigid-Bodies_01-Introduction-to-Rigid-Bodies_46_0.png

To change the position or orientation of a given body, change the properties of the central particle:

[24]:
with sim.state.cpu_local_snapshot as snapshot:
    typeid = snapshot.particles.typeid
    snapshot.particles.orientation[typeid == 0] = [
        0.70710678, 0., 0.70710678, 0.
    ]

Again, execute sim.run(0) for the changes to take effect on the constituent particles.

[25]:
sim.run(0)
render(sim.state.get_snapshot())
[25]:
_images/tutorial_06-Modelling-Rigid-Bodies_01-Introduction-to-Rigid-Bodies_50_0.png

Write the configuration to a file for use in the next tutorial section:

[26]:
hoomd.write.GSD.write(state=sim.state, mode='xb', filename='lattice.gsd')

In this section, you learned how HOOMD-blue composes rigid bodies of central and constituent particles and about all the properties of those bodies. You also saw how to define these parameters and how Rigid updates them in the simulation state. The next section will explain how to run a molecular dynamics simulation of this system.

Running Rigid Body Simulations#
Overview#
Questions#
  • How do I initialize rigid bodies from a GSD file?

  • How do I integrate the rigid bodies in my simulation?

  • How are thermodynamic quantities of rigid bodies measured?

Objectives#
  • Describe how to continue simulations from a GSD file.

  • Explain integration of rotational degrees of freedom.

  • Show how to exclude intra-body pairwise interactions.

  • Run a rigid body MD simulation at constant temperature.

  • Demonstrate that rigid bodies equilibrate both translational and rotational degrees of freedom.

Boilerplate code#
[1]:
import math

import hoomd

The render function in the next (hidden) cell will render the system state using fresnel. Find the source in the hoomd-examples repository.

Continuing the simulation from a GSD file.#

The previous section created an initial condition containing dimer particles in lattice.gsd. Initialize a new simulation from this file:

[3]:
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=1)
sim.create_state_from_gsd(filename='lattice.gsd')

hoomd.md.constrain.Rigid is responsible for applying the rigid body constraints to the particles in the simulation.

Create the rigid constraint:

[4]:
rigid = hoomd.md.constrain.Rigid()

The body property of Rigid is not saved to the GSD file. You need to define the parameters again in the new simulation:

[5]:
rigid.body['dimer'] = {
    "constituent_types": ['A', 'A'],
    "positions": [[-1.2, 0, 0], [1.2, 0, 0]],
    "orientations": [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)],
}

In workflows, you can store this in a file of your choosing or use the project document in signac.

Integrating rigid body degrees of freedom#

Create an Integrator with the option integrate_rotational_dof=True:

[6]:
integrator = hoomd.md.Integrator(dt=0.005, integrate_rotational_dof=True)
sim.operations.integrator = integrator

The default value of integrate_rotational_dof is False, When False, the integrator will ignore all torques on particles and integrate only the translational degrees of freedom. When True, the integrator will integrate both the translational and rotational degrees of freedom.

Assign the rigid constraint to the integrator’s rigid attribute to apply the constraints during the simulation.

[7]:
integrator.rigid = rigid

The translational and rotational degrees of freedom are given to the central particles of the rigid bodies. Select only the rigid centers and free particles for the integration method:

[8]:
kT = 1.5
rigid_centers_and_free = hoomd.filter.Rigid(("center", "free"))
nvt = hoomd.md.methods.ConstantVolume(
    filter=rigid_centers_and_free,
    thermostat=hoomd.md.methods.thermostats.Bussi(kT=kT))
integrator.methods.append(nvt)
Defining Pair Potentials Between Bodies#

Create a neighbor list with body exclusions so that the pair potential does not compute intra-body interactions:

[9]:
cell = hoomd.md.nlist.Cell(buffer=0, exclusions=['body'])

Without body exclusions, the simulation may be numerically unstable due to round-off errors when subtracting large numbers. In either case, the intra-body forces contribute 0 to the net force and 0 to the net torque, so there is no need to compute them.

Apply the Lennard-Jones potential between A-A particle pairs.

[10]:
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5

The central particles (type dimer) are also present in the system. Make the dimer particles non-interacting with a 0 r_cut:

[11]:
lj.params[('dimer', ['dimer', 'A'])] = dict(epsilon=0, sigma=0)
lj.r_cut[('dimer', ['dimer', 'A'])] = 0

Central particles may be interacting or non-interacting. You can choose any potential parameters suitable for your model.

[12]:
integrator.forces.append(lj)
Compressing the system#

We have initialized the system state, added the integrator, set the rigid constraint, and defined the pairwise particle interactions. Before we run the simulation, we need to set initial velocities and angular momenta of the rigid body central particles and free particles:

[13]:
sim.state.thermalize_particle_momenta(filter=rigid_centers_and_free, kT=kT)
sim.run(0)

thermalize_particle_momenta assigns gaussian distributed momenta to each translational and rotational degree of freedom for each particle given in the filter. In this case, it wil assign momenta about the y and z axes, but not x because \(I_{xx} = 0\).

Now we can run the simulation to randomize the body positions and orientations:

[14]:
sim.run(1000)
[15]:
render(sim.state.get_snapshot())
[15]:
_images/tutorial_06-Modelling-Rigid-Bodies_02-Running-Rigid-Body-Simulations_32_0.png

This simulation box is dilute. Compress the box to a higher density state before continuing:

[16]:
initial_box = sim.state.box
final_box = hoomd.Box.from_box(initial_box)  # make a copy of initial_box
final_box.volume = initial_box.volume / 16
box_resize_trigger = hoomd.trigger.Periodic(10)
ramp = hoomd.variant.Ramp(A=0, B=1, t_start=sim.timestep, t_ramp=20000)
box_resize = hoomd.update.BoxResize(box1=initial_box,
                                    box2=final_box,
                                    variant=ramp,
                                    trigger=box_resize_trigger)
sim.operations.updaters.append(box_resize)

Run the simulation to compress the box:

[17]:
sim.run(30000)
[18]:
render(sim.state.get_snapshot())
[18]:
_images/tutorial_06-Modelling-Rigid-Bodies_02-Running-Rigid-Body-Simulations_37_0.png
Thermodynamic properties of rigid bodies#

Add the ThermodynamicQuantities compute to the simulation:

[19]:
thermodynamic_quantities = hoomd.md.compute.ThermodynamicQuantities(
    filter=hoomd.filter.All())

sim.operations.computes.append(thermodynamic_quantities)

ThermodynamicQuantities computes translational and rotational kinetic energy separately:

[20]:
thermodynamic_quantities.translational_kinetic_energy
[20]:
137.81241341810505
[21]:
thermodynamic_quantities.rotational_kinetic_energy
[21]:
106.88990898579644

These values are consistent (within exepected thermodynamic fluctuations) with the equipartition theorem:

[22]:
translational_degrees_of_freedom = thermodynamic_quantities.translational_degrees_of_freedom
print('Translational degrees of freedom:', translational_degrees_of_freedom)
print('1/2 kT * translational degrees of freedom:',
      1 / 2 * kT * translational_degrees_of_freedom)
Translational degrees of freedom: 189.0
1/2 kT * translational degrees of freedom: 141.75
[23]:
rotational_degrees_of_freedom = thermodynamic_quantities.rotational_degrees_of_freedom
print('Rotataional degrees of freedom:', rotational_degrees_of_freedom)
print('1/2 kT * rotational degrees of freedom:',
      1 / 2 * kT * rotational_degrees_of_freedom)
Rotataional degrees of freedom: 128.0
1/2 kT * rotational degrees of freedom: 96.0

Note that the number of rotational degrees is freedom is 2 times the number of particles as we assigned 2 non-zero moments of inertia.

In this section, you learned how to continue running a simulation with rigid bodies in a GSD file, define inter-body pairwise interactions and integrate the translational and rotational degrees of freedom with an integration method. The next section will explain how to prepare general rigid bodies for HOOMD-blue.

Preparing a General Body#
Overview#
Questions#
  • How do I input arbitrary rigid body into HOOMD-blue?

Objectives#
  • Define an rigid body with an arbitrary inertia tensor.

  • Diagonalize the moment of inertia.

  • Reorient the constituent particles in the diagonal body coordinates.

Boilerplate code#
[1]:
import math

import numpy

The render_rigid_body function in the next (hidden) cell will render the rigid body using fresnel. Find the source in the hoomd-examples repository.

Diagonalized bodies:#

HOOMD-blue assumes bodies are provided in a coordinate system where the moment of inertia tensor is diagonal.

Given a body with arbitrarily placed constituent particles, you can follow this procedure to prepare the body for use in HOOMD.

  • Step 1: Get the inertia tensor of your rigid body (non-diagonalized).

  • Step 2: Solve for the orientation of the body that diagonalizes the moment of inertia tensor.

  • Step 3: Reorient the rigid body so that the rigid body inertia tensor is diagonalized in global coordinates.

  • Step 4: Define the moments of inertia using the new diagonalized moments of inertia.

The remainder of this tutorial section demonstrates these steps for this body:

[3]:
general_positions = numpy.array([[.5, .5, 0], [-.5, -.5, 0], [-1, 1, 0],
                                 [1, -1, 0]])
particle_mass = 1
particle_radius = 1
[4]:
render_rigid_body(general_positions)
[4]:
_images/tutorial_06-Modelling-Rigid-Bodies_03-Preparing-a-General-Body_6_0.png
Step 1: Compute the inertia tensor#

HOOMD-blue makes no assumptions about the distribution of mass in your body. For example, you can compute the moment of inertia assuming that each consituent particle is a uniform density ball. The moment of inertia of a single ball computed about the center of the ball is:

[5]:
I_ref = numpy.array([[2 / 5 * particle_mass * particle_radius**2, 0, 0],
                     [0, 2 / 5 * particle_mass * particle_radius**2, 0],
                     [0, 0, 2 / 5 * particle_mass * particle_radius**2]])
I_ref
[5]:
array([[0.4, 0. , 0. ],
       [0. , 0.4, 0. ],
       [0. , 0. , 0.4]])

Using the parallel axis theorem, compute the moment of inertia tensor for the general body as a sum of constituent particle inertia tensors: \(I = I_{ref} + m[(D\cdot D)E_3 - D\otimes D]\)

\(I_{ref}\) is the reference moment of inertia, m is the mass, D is the displacement (i.e. the position of the constituent particle in body coordinates) and \(E_3\) is the identity matrix.

[6]:
I_general = numpy.zeros(shape=(3, 3))
for r in general_positions:
    I_general += I_ref + particle_mass * (numpy.dot(r, r) * numpy.identity(3)
                                          - numpy.outer(r, r))

I_general
[6]:
array([[4.1, 1.5, 0. ],
       [1.5, 4.1, 0. ],
       [0. , 0. , 6.6]])

Notice that some of the off-diagonal elements are non-zero. These body coordinates are not appropriate for use in HOOMD-blue.

Step 2: Diagonalize the moment of inertia#

First, find the eigenvalues of the general moment of inertia:

[7]:
I_diagonal, E_vec = numpy.linalg.eig(I_general)

The diagonalized moment of inertia are the \([I_{xx}, I_{yy}, I_{zz}]\) needed by HOOMD-blue:

[8]:
I_diagonal
[8]:
array([5.6, 2.6, 6.6])

The transpose of the eigenvector matrix rotates the original particles into the frame where the inertia tensor is diagonalized:

[9]:
R = E_vec.T

Rotate the particles by this matrix:

[10]:
diagonal_positions = numpy.dot(R, general_positions.T).T
diagonal_positions
[10]:
array([[ 7.07106781e-01, -5.55111512e-17,  0.00000000e+00],
       [-7.07106781e-01,  5.55111512e-17,  0.00000000e+00],
       [ 1.11022302e-16,  1.41421356e+00,  0.00000000e+00],
       [-1.11022302e-16, -1.41421356e+00,  0.00000000e+00]])
[11]:
render_rigid_body(diagonal_positions)
[11]:
_images/tutorial_06-Modelling-Rigid-Bodies_03-Preparing-a-General-Body_20_0.png

The rigid body has now been aligned its principle rotational axes with the x, y, and z body axes. Use diagonal_positionsas body coordinates along with I_diagonal as the central particle’s moment_inertia.

To check, let’s confirm that the directly calculated moment of inertia of the new coordinates is diagonal.

[12]:
I_check = numpy.zeros(shape=(3, 3))
for r in diagonal_positions:
    I_check += I_ref + particle_mass * (numpy.dot(r, r) * numpy.identity(3)
                                        - numpy.outer(r, r))

I_check
[12]:
array([[ 5.60000000e+00, -2.35513869e-16,  0.00000000e+00],
       [-2.35513869e-16,  2.60000000e+00,  0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  6.60000000e+00]])

This moment of inertia is diagonal within numerical precision.

When the diagonalization process produces very small numerical values for the diagonal elements, set them to 0 explicitly to disable those degrees of freedom. Otherwise, HOOMD-blue will attempt to integrate them, resulting in numerical instabilities.

This is the end of the introduction to the modelling rigid bodies tutorial! It described the properties of rigid bodies, showed how to run a simulation of dimers, and demonstrated how to diagonalize the moment of inertia of general bodies. See the other HOOMD-blue tutorials to learn about other concepts, or browse the reference documentation for more information.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

Modelling Patchy Particles#

In this tutorial you will implement the Kern–Frenkel potential as a model for patchy particle interactions. To do so, you will use the hpmc.pair.user module, which enables the addition of user-defined, arbitrary, pairwise energetic interactions to a HPMC simulation.

Prerequisites:

This tutorial assumes you are familiar with the concepts introduced in Introducing HOOMD-blue and Introducing Molecular Dynamics.

Kern–Frenkel Model#
Overview#
Questions#
  • What are patchy particles?

  • What is the Kern-Frenkel potential?

  • How can I evaluate the Kern-Frenkel potential between two particles?

Objectives#
  • Describe the Kern–Frenkel model mathematically and graphically.

Patchy particles#

In the Introducing Molecular Dynamics tutorial, you simulated a system of particles interacting through the Lennard-Jones pair potential. The Lennard-Jones pair potential is spherically symmetric, that is, the pair potential does not depend on the relative orientation of the interacting particles.

Some systems are better represented by anisotropic pair potentials, where there is a dependence on the relative orientation of particles. The hard octahedra you simulated in Intoducing HOOMD-blue interacted through a purely repulsive anisotropic pair potential. Particles that interact with anisotropic pair potentials where some relative orientations are more attractive than others are known as patchy particles, since we can imagine that there are attractive patches on the surface of the particles.

The Kern–Frenkel model#

One of the simplest patchy particle models is the Kern–Frenkel model, which was introduced in a 2003 Journal of Chemical Physics paper. The Kern–Frenkel model contains directional pairwise energetic interactions in addition to hard sphere-like volume exclusion. The pair potential \(u_{ij}(r_{ij}, \Omega_i, \Omega_j)\) between particles \(i\) and \(j\) at a center-to-center distance \(r_{ij}\) and orientations \(\Omega_i\) and \(\Omega_j\) is of the form

\[\begin{split}\beta u_{ij} = \begin{cases} \infty & r_{ij} < \sigma_{ij} \\ -\beta\varepsilon\cdot f(\Omega_1, \Omega_2) & \sigma_{ij} \leq r_{ij} < \lambda_{ij}\sigma_{ij} \\ 0 & r_{ij} \geq \lambda_{ij}\sigma_{ij} \end{cases}\end{split}\]

where \(\beta = 1/k_BT\), \(\varepsilon\) is the strength of the patchy interaction, \(\sigma_{ij}\) is sum of the radii of particles \(i\) and \(j\), \(\lambda\) is the range of the square well attraction, and \(f(\Omega_i, \Omega_j)\) is an orientational masking function given by

\[\begin{split}f(\Omega_1, \Omega_2) = \begin{cases} 1 & \hat{e}_i \cdot \hat{r}_{ij} > \cos \delta \mathrm{~~and~~} \hat{e}_j \cdot \hat{r}_{ji} > \cos \delta \\ 0 & \mathrm{otherwise} \end{cases}\end{split}\]

where \(\hat{e}_i\) is the director of the patch on particle \(i\) and \(\delta\) is the half-opening angle of the patch.

Graphically, this pair potential corresponds to the following criterion: two particles interact with energy \(\infty\) if the gray shaded regions on the two particles overlap at all, \(-\varepsilon\) if the blue shaded regions on the two particles overlap, and zero otherwise.

Kern–Frenkel

Simulating a System of Patchy Particles#
Overview#
Questions#
  • How do I implement pairwise energetic interactions in HPMC?

Objectives#
  • Run a simulation of particles interacting through the Kern–Frenkel pair potential.

  • Log the potential energy during an HPMC simulation.

Boilerplate code#
[2]:
import itertools
import math

import gsd.hoomd
import hoomd
import matplotlib
import matplotlib_inline
import numpy

%matplotlib inline
matplotlib.style.use('ggplot')
matplotlib_inline.backend_inline.set_matplotlib_formats('svg')

In the previous section, you learned about patchy particles and the the Kern–Frenkel model. In this section, we will initialize a system of particles, add the Kern–Frenkel pair potential to the simulation, and run the simulation while logging the energy.

Constructing the system#

Construct the system using the same code you used in Introducing HOOMD-blue tutorial and then initialize a simulation.

[3]:
m = 4
N_particles = 2 * m**3
spacing = 1.2
K = math.ceil(N_particles**(1 / 3))
L = K * spacing
x = numpy.linspace(-L / 2, L / 2, K, endpoint=False)
position = list(itertools.product(x, repeat=3))
position = position[0:N_particles]
orientation = [(1, 0, 0, 0)] * N_particles

# gsd snapshot
snapshot = gsd.hoomd.Frame()
snapshot.particles.N = N_particles
snapshot.particles.position = position
snapshot.particles.orientation = orientation
snapshot.particles.typeid = [0] * N_particles
snapshot.particles.types = ['A']
snapshot.configuration.box = [L, L, L, 0, 0, 0]
with gsd.hoomd.open(name='initial.gsd', mode='x') as f:
    f.append(snapshot)

# build simulation
cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu, seed=0)
sim.create_state_from_gsd(filename='initial.gsd')
Define interaction parameters#

Define the parameters \(\delta\), \(\varepsilon\), \(\lambda\), and \(\sigma\) of the Kern–Frenkel model to simulate.

[4]:
kf_delta_deg = 45  # half-opening angle of patches
kf_epsilon = 1.0  # strength of patchy interaction in kT
kf_lambda = 1.2  # range of patchy interaction
sigma = 1.0  # hard core diameter
Add HPMC integrator#

Now add an HPMC integrator to the system. Add the Sphere integrator because the cores of the particles are spherical. These particles also have an orientation, so tell HPMC to perform rotation moves on the particles via the orientable key of the shape dictionary.

[5]:
mc = hoomd.hpmc.integrate.Sphere()
mc.shape['A'] = dict(diameter=sigma, orientable=True)
sim.operations.integrator = mc
Add the pair potential#
Write patch code#

The hoomd.hpmc.pair.user classes use strings containing C++ code to evaluate pair potentials. The code you pass in is the body of the function with the following signature:

float eval(const vec3<float>& r_ij,
           unsigned int type_i,
           const quat<float>& q_i,
           float d_i,
           float charge_i,
           unsigned int type_j,
           const quat<float>& q_j,
           float d_j,
           float charge_j
)

The Kern–Frenkel potential only depends on the center-to-center vector r_ij and the orientations of the two particles, represented as the quaternions q_i and q_j. Users have access to other variables, which can be useful for more complicated potentials. Note the type of r_ij, q_i, and q_j: vec3 and quat are classes that represent 3D vectors and quaternions, respectively, and are defined in the HOOMD vector math library. The HOOMD vector math library also contains operations you can use on vectors, e.g., you will use rotate to rotate the particles into the global frame of reference to evaluate the pair potential.

At the beginning of the body of the function, define some constants:

[6]:
patch_code = f"""
const float delta = {kf_delta_deg} * M_PI / 180;  // delta in radians
const float epsilon = {kf_epsilon:f};
const float lambda = {kf_lambda:f};
const float sigma = {sigma:f};  // hard core diameter
"""

Now set the strength \(\varepsilon\) of the patchy interactions. To do so, first define the temperature \(\beta^{-1} = kT\) of the system. HPMC assumes \(\beta = 1\), so to change the temperature of a system, you must change the relative strength of the energetic interactions (\(\varepsilon\) in this case).

Use param_array, which is an array of floats that is declared in the patch kernel that you can use to change the value of variables in the patch code. Later in this section, you will change the temperature of the system by changing the value of param_array[0].

[7]:
patch_code += f"""
const float kT = param_array[0];
const float beta_epsilon = epsilon/kT;
"""

Now compute the patch director in the particle frame of reference (ehat_particle_reference_frame). Use rotate to compute \(\hat{e}_i\) and \(\hat{e}_j\) by rotating ehat_particle_reference_frame by the quaternions q_i and q_j, respectively.

[8]:
patch_code += f"""
const vec3<float> ehat_particle_reference_frame(1, 0, 0);
vec3<float> ehat_i = rotate(q_i, ehat_particle_reference_frame);
vec3<float> ehat_j = rotate(q_j, ehat_particle_reference_frame);
"""

Check to see if the patches on each particle are “facing” the other particle. In other words, evaluate the orientational masking function \(f(\Omega_i, \Omega_j)\) defined in the previous section.

[9]:
patch_code += f"""
vec3<float> r_hat_ij = r_ij / sqrtf(dot(r_ij, r_ij));
bool patch_on_i_is_aligned_with_r_ij = dot(ehat_i, r_hat_ij) >= cos(delta);
bool patch_on_j_is_aligned_with_r_ji = dot(ehat_j, -r_hat_ij) >= cos(delta);
"""

All that’s left now is to actually evaluate the pair potential. In HOOMD, the patch kernel is evaluated after any overlap checks, so we do not need to check for the hard sphere overlap (\(r_{ij} < \sigma_{ij}\)). Instead, we only need to check if they are within range of the patchy interaction; this condition simplifies to \(|\vec{r}_{ij}| < \lambda\sigma\). For clarity, evaluate the expression as it is written in the previous section, but note that you can avoid the square root calculation by evaluating \(|\vec{r}_{ij}|^2 = \vec{r}_{ij} \cdot \vec{r}_{ij} < (\lambda\sigma)^2\).

Note the use of double curly brackets {{..}} for the if..else code block; Python evaluates expressions inside of curly brackets in f-strings, so we must include a second set of curly brackets so that one set of curly brackets remain after evaluation of the f-string.

[10]:
patch_code += f"""
float rsq = dot(r_ij, r_ij);
float r_ij_length = sqrtf(rsq);
if (patch_on_i_is_aligned_with_r_ij
    && patch_on_j_is_aligned_with_r_ji
    && r_ij_length < lambda*sigma)
    {{
    return -beta_epsilon;
    }}
else
    {{
    return 0.0;
    }}
"""
Set cutoff distance for the patchy interaction#

Before creating the pair potential object to add to the Simulation, calculate r_cut. Similar to how HOOMD uses neighbor lists in MD to increase performance by only calculating interactions between nearby particles, the hoomd.hpmc.pair.user classes take an r_cut parameter, which is the center to center distance cutoff beyond which all pair interactions are 0. Here, that distance is the hard core diameter \(\sigma\) plus the radial extent of the patchy interaction \(\sigma(\lambda-1)\).

[11]:
r_cut = sigma + sigma * (kf_lambda - 1)
Set variable parameters for patch kernel#
[12]:
initial_kT = 3.0
patch_param_array = [initial_kT]
Adding the patchy potential to the simulation#

Now create a hoomd.hpmc.pair.user.CPPPotential object that will evaluate the Kern–Frenkel potential in the simulation. Use the patch_code string that you built up that serves as the body of the function that computes patch interaction energy. Initialize the temperature to \(kT = 3\) to randomize the system on the first call to Simulation.run().

[13]:
initial_kT = 3.0
patch_potential = hoomd.hpmc.pair.user.CPPPotential(r_cut=r_cut,
                                                    code=patch_code,
                                                    param_array=[initial_kT])

Finally, attach patch_potential to the HPMC integrator so that the integrator evaluates the pair potential.

[14]:
mc.pair_potential = patch_potential

You can query the energy associated with the patch potential via the energy property of the patch potential object (after running for 0 or more steps). The particles are not interacting in the initial configuration, and hence the initial value of the energy is zero.

[15]:
sim.run(0)
patch_potential.energy
[15]:
0.0
Log the patch energy#

Create a logger and add the patchy potential to it, and then create a GSD writer to write the log values to file during the simulation. Also add the temperature to the logger so that later you can compare energies from parts of the simulation at different temperatures.

[16]:
logger = hoomd.logging.Logger()
logger.add(patch_potential, quantities=[
    'energy',
])
logger[('kT',)] = (lambda: patch_potential.param_array[0], 'scalar')
gsd_writer = hoomd.write.GSD(filename='log.gsd',
                             trigger=hoomd.trigger.Periodic(10),
                             mode='xb',
                             filter=hoomd.filter.Null(),
                             logger=logger)
sim.operations.writers.append(gsd_writer)
Run the simulation#
Randomize the system#

Run for a bit at the high initial temperature to randomize the system.

[17]:
sim.run(500)
Change the temperature#

Now run for a bit at a lower temperature so that the patchy interactions cause the particles to cluster. Recall, the param_array property of the patch potential is the effective temperature of the system.

[18]:
patch_potential.param_array[0] = 0.1
sim.run(2000)

Now, increase the temperature again so that the clusters break apart.

[19]:
patch_potential.param_array[0] = initial_kT
sim.run(2000)

As discussed in the Logging tutorial, flush the write buffer (this is not necessary in typical workflows).

[20]:
gsd_writer.flush()
Analyzing the results#

Plot the energy of the system to analyze the results.

Use the gsd package to read just the log values from the GSD file.

[21]:
data = gsd.hoomd.read_log('log.gsd')
step = data['configuration/step']

Recall, the the value of patch_potential.energy is really the energy divided by the thermal energy scale \(kT\), so multiply the energy by \(kT\) to get the actual energy.

[22]:
beta_potential_energy = data['log/hpmc/pair/user/CPPPotential/energy']
kT = data['log/kT']
potential_energy = beta_potential_energy * kT
[23]:
fig = matplotlib.figure.Figure(figsize=(5, 3.09))
ax = fig.add_subplot()
ll, = ax.plot(step, potential_energy)
ax.set_xlabel('timestep')
ax.set_ylabel('potential energy', c=ll.get_c())

ax2 = ax.twinx()
ax2.grid(False)
ax2._get_lines.get_next_color()
ll, = ax2.plot(step, kT)
ylabel = ax2.set_ylabel('kT', c=ll.get_c())

fig
[23]:
_images/tutorial_07-Modelling-Patchy-Particles_02-Simulating-a-System-of-Patchy-Particles_43_0.svg

Notice the decrease in energy when the temperature was at the lower setting, indicative of particle clustering.

Summary#

In this tutorial, you learned about patchy particles and the Kern–Frenkel model of patchy particles, and you implemented the Kern–Frenkel model in HPMC. You observed the change in potential energy upon changing the temperature in a patchy particle simulation.

For more information on simulating patchy particles, or more generally HPMC simulations with energetic interactions, see the HOOMD-blue documentation on pair potentials in HPMC.

This tutorial is written with jupyter. You can download the source from the hoomd-examples repository.

How-to#

How to model molecular systems#

To model molecular systems using molecular dynamics in HOOMD-blue:

  1. Define the bonds, angles, dihedrals, impropers, and constraints as needed to the system State.

  2. Add the needed potentials and/or constraints to the integrator (see md.bond, md.angle, md.dihedral, md.improper, and md.constrain).

This code demonstrates bonds by modelling a Gaussian chain:

import hoomd
import gsd.hoomd

frame = gsd.hoomd.Frame()

# Place a polymer in the box.
frame.particles.N = 5
frame.particles.position = [[-2, 0, 0], [-1, 0, 0], [0, 0, 0], [1, 0, 0],
                            [2, 0, 0]]
frame.particles.types = ['A']
frame.particles.typeid = [0] * 5
frame.configuration.box = [20, 20, 20, 0, 0, 0]

# Connect particles with bonds.
frame.bonds.N = 4
frame.bonds.types = ['A-A']
frame.bonds.typeid = [0] * 4
frame.bonds.group = [[0, 1], [1, 2], [2, 3], [3, 4]]

with gsd.hoomd.open(name='molecular.gsd', mode='x') as f:
    f.append(frame)

# Apply the harmonic potential on the bonds.
harmonic = hoomd.md.bond.Harmonic()
harmonic.params['A-A'] = dict(k=100, r0=1.0)

# Perform the MD simulation.
sim = hoomd.Simulation(device=hoomd.device.CPU(), seed=1)
sim.create_state_from_gsd(filename='molecular.gsd')
langevin = hoomd.md.methods.Langevin(filter=hoomd.filter.All(), kT=1.0)
integrator = hoomd.md.Integrator(dt=0.005,
                                 methods=[langevin],
                                 forces=[harmonic])
gsd_writer = hoomd.write.GSD(filename='molecular_trajectory.gsd',
                             trigger=hoomd.trigger.Periodic(1000),
                             mode='xb')
sim.operations.integrator = integrator
sim.operations.writers.append(gsd_writer)
sim.run(10e3)

Consider using a tool to build systems, such as the Molecular Simulation Design Framework (MoSDeF). For example, mBuild can assemble reusable components into complex molecular systems, and foyer can perform atom-typing and define classical molecular modeling force fields. The mosdef-workflows demonstrates how to use these tools with HOOMD-blue

How to apply arbitrary pair potentials in HPMC#

To apply arbitrary pair potentials between particles in HPMC simulations:

  1. Write the C++ code that evaluates the potential.

  2. Instantiate a hoomd.hpmc.pair.user.CPPPotential or hoomd.hpmc.pair.user.CPPPotentialUnion with the code.

  3. Set the pair_potential property of the HPMC integrator.

This code demonstrates the hard sphere square well potential.

import hoomd
import gsd.hoomd

frame = gsd.hoomd.Frame()

# Place particles in the box
frame.particles.N = 2
frame.particles.position = [[-0.51, 0, 0], [0.51, 0, 0]]
frame.particles.types = ['S']
frame.particles.typeid = [0] * 2
frame.configuration.box = [20, 20, 20, 0, 0, 0]

with gsd.hoomd.open(name='cpppotential.gsd', mode='x') as f:
    f.append(frame)

# The square well potential
r_interaction = 1.1
evaluate_square_well = f'''float rsq = dot(r_ij, r_ij);
                    if (rsq < {r_interaction * r_interaction}f)
                        return param_array[0];
                    else
                        return 0.0f;
            '''
square_well = hoomd.hpmc.pair.user.CPPPotential(r_cut=r_interaction,
                                                code=evaluate_square_well,
                                                param_array=[-1])

# hpmc.Sphere provides the hard sphere part of the potential
mc = hoomd.hpmc.integrate.Sphere()
mc.shape['S'] = dict(diameter=1.0)

# Compute the square potential when evaluating trial moves
mc.pair_potential = square_well

# Create the simulation.
sim = hoomd.Simulation(device=hoomd.device.CPU(), seed=1)
sim.create_state_from_gsd(filename='cpppotential.gsd')
sim.operations.integrator = mc

# The energy is -1
sim.run(0)
print(square_well.energy)

# Change potential parameters by setting param_array:
square_well.param_array[0] = -2
print(square_well.energy)

Use HPMC with pair potentials to model interactions with discontinuous steps in the potential. Use molecular dynamics for models with continuous potentials.

hoomd#

Overview

Box

Define box dimensions.

Operations

A mutable collection of operations which act on a Simulation.

Simulation

Define a simulation.

Snapshot

Self-contained copy of the simulation State.

State

The state of a Simulation object.

Details

HOOMD-blue python package.

hoomd is the top level HOOMD-blue Python package. It consists of the common code shared among all types of HOOMD-blue simulations. The core data structures used to construct a simulation include:

See the table of contents or the modules section for a full list of classes, methods, and variables in the API.

hoomd also contains subpackages that implement specific types of simulations:

See also

Tutorial: Introducing HOOMD-blue

Signal handling

On import, hoomd installs a SIGTERM signal handler that calls sys.exit so that open gsd files have a chance to flush write buffers (hoomd.write.GSD.flush) when a user’s process is terminated. Use signal.signal to adjust this behavior as needed.

class hoomd.Box(Lx, Ly, Lz=0, xy=0, xz=0, yz=0)#

Define box dimensions.

Parameters:
  • Lx (float) – box extent in the x direction \([\mathrm{length}]\).

  • Ly (float) – box extent in the y direction \([\mathrm{length}]\).

  • Lz (float) – box extent in the z direction \([\mathrm{length}]\).

  • xy (float) – tilt factor xy \([\mathrm{dimensionless}]\).

  • xz (float) – tilt factor xz \([\mathrm{dimensionless}]\).

  • yz (float) – tilt factor yz \([\mathrm{dimensionless}]\).

Example simulation box labelled with lengths and vectors.

Particles in a simulation exist in a triclinic box with periodic boundary conditions. A triclinic box is defined by six values: the extents \(L_x\), \(L_y\) and \(L_z\) of the box in the three directions, and three tilt factors \(xy\), \(xz\) and \(yz\).

The parameter matrix is defined in terms of the lattice vectors \(\vec a_1\), \(\vec a_2\) and \(\vec a_3\):

\[\left( \vec a_1, \vec a_2, \vec a_3 \right)\]

The first lattice vector \(\vec a_1\) is parallel to the unit vector \(\vec e_x = (1,0,0)\). The tilt factor \(xy\) indicates how the second lattice vector \(\vec a_2\) is tilted with respect to the first one. Similarly, \(xz\) and \(yz\) indicate the tilt of the third lattice vector \(\vec a_3\) with respect to the first and second lattice vector.

The full cell parameter matrix is:

\[\begin{split}\left(\begin{array}{ccc} L_x & xy L_y & xz L_z \\ 0 & L_y & yz L_z \\ 0 & 0 & L_z \\ \end{array}\right)\end{split}\]

The tilt factors \(xy\), \(xz\) and \(yz\) are dimensionless. The relationships between the tilt factors and the box angles \(\alpha\), \(\beta\) and \(\gamma\) are as follows:

\[\begin{split}\cos\gamma &= \cos(\angle\vec a_1, \vec a_2) &=& \frac{xy}{\sqrt{1+xy^2}}\\ \cos\beta &= \cos(\angle\vec a_1, \vec a_3) &=& \frac{xz}{\sqrt{1+xz^2+yz^2}}\\ \cos\alpha &= \cos(\angle\vec a_2, \vec a_3) &=& \frac{xy \cdot xz + yz}{\sqrt{1+xy^2} \sqrt{1+xz^2+yz^2}}\end{split}\]

Given an arbitrarily oriented lattice with box vectors \(\vec v_1, \vec v_2, \vec v_3\), the parameters for the rotated box can be found as follows:

\[\begin{split}L_x &= v_1\\ a_{2x} &= \frac{\vec v_1 \cdot \vec v_2}{v_1}\\ L_y &= \sqrt{v_2^2 - a_{2x}^2}\\ xy &= \frac{a_{2x}}{L_y}\\ L_z &= \vec v_3 \cdot \frac{\vec v_1 \times \vec v_2}{\left| \vec v_1 \times \vec v_2 \right|}\\ a_{3x} &= \frac{\vec v_1 \cdot \vec v_3}{v_1}\\ xz &= \frac{a_{3x}}{L_z}\\ yz &= \frac{\vec v_2 \cdot \vec v_3 - a_{2x}a_{3x}}{L_y L_z}\end{split}\]

Box images

HOOMD-blue always stores particle positions \(\vec{r}\) inside the primary box image which includes the origin at the center. The primary box image include the left, bottom, and back face while excluding the right, top, and front face. In cubic boxes, this implies that the particle coordinates in the primary box image are in the interval \(\left[ -\frac{L}{2},\frac{L}{2} \right)\).

Unless otherwise noted in the documentation, operations apply the minimum image convention when computing pairwise interactions between particles:

\[\vec{r}_{ij} = \mathrm{minimum\_image}(\vec{r}_j - \vec{r}_i)\]

When running simulations with a fixed box size, you use the particle images \(\vec{n}\) to compute the unwrapped coordinates:

\[\vec{r}_\mathrm{unwrapped} = \vec{r} + n_x \vec{a}_1 + n_y \vec{a}_2 + n_z \vec{a}_3\]

The Box class

Simulation boxes in hoomd are specified by six parameters, Lx, Ly, Lz, xy, xz, and yz. Box provides a way to specify all six parameters for a given box and perform some common operations with them. A Box can be stored in a GSD file, passed to an initialization method or to assigned to a saved State variable (state.box = new_box) to set the simulation box.

Access attributes directly:

box = hoomd.Box.cube(L=20)
box.xy = 1.0
box.yz = 0.5
box.Lz = 40

Two dimensional systems

Set Lz == 0 to make the box 2D. 2D boxes ignore xz and yz. Changing the box dimensionality from 2D to 3D (or from 3D to 2D) during a simulation will result in undefined behavior.

In 2D boxes, volume is in units of \([\mathrm{length}]^2\).

Factory Methods

Box has factory methods to enable easier creation of boxes: cube, square, from_matrix, and from_box. See the method documentation for usage.

Examples

  • Cubic box with given length: hoomd.Box.cube(L=1)

  • Square box with given length: hoomd.Box.square(L=1)

  • From an upper triangular matrix: hoomd.Box.from_matrix(matrix)

  • Specify values: hoomd.Box(Lx=1., Ly=2., Lz=3., xy=1., xz=2., yz=3.)

property L#

The box lengths, [Lx, Ly, Lz] \([\mathrm{length}]\).

Can be set with a float which sets all lengths, or a length 3 vector.

Type:

(3, ) numpy.ndarray of float

property Lx#

The length of the box in the x dimension \([\mathrm{length}]\).

Type:

float

property Ly#

The length of the box in the y dimension \([\mathrm{length}]\).

Type:

float

property Lz#

The length of the box in the z dimension \([\mathrm{length}]\).

Type:

float

__eq__(other)#

Test if boxes are equal.

__neq__(other)#

Test if boxes are not equal.

__reduce__()#

Reduce values to picklable format.

__repr__()#

Executable representation of the object.

classmethod cube(L)#

Create a cube with side lengths L.

Parameters:

L (float) – The box side length \([\mathrm{length}]\).

Returns:

The created 3D box.

Return type:

hoomd.Box

property dimensions#

The dimensionality of the box.

If Lz == 0, the box is treated as 2D, otherwise it is 3D. This property is not settable.

Type:

int

classmethod from_box(box)#

Initialize a Box instance from a box-like object.

Parameters:

box (box_like) – A box-like object.

Note

If all values are provided, a triclinic box will be constructed. If only Lx, Ly, Lz are provided, an orthorhombic box will be constructed. If only Lx, Ly are provided, a rectangular (2D) box will be constructed.

Returns:

The resulting box object.

Return type:

hoomd.Box

classmethod from_matrix(box_matrix)#

Create a box from an upper triangular matrix.

Parameters:

box_matrix ((3, 3) numpy.ndarray of float) –

An upper triangular matrix representing a box. The values for Lx, Ly, Lz, xy, xz, and yz are related to the matrix by the following expressions.

[[Lx, Ly * xy, Lz * xz],
[0,  Ly,      Lz * yz],
[0,  0,       Lz]]

Returns:

The created box.

Return type:

hoomd.Box

property is2D#

Flag whether the box is 2D.

If Lz == 0, the box is treated as 2D, otherwise it is 3D. This property is not settable.

Type:

bool

property periodic#

The periodicity of each dimension.

Type:

(3, ) numpy.ndarray of bool

scale(s)#

Scale box dimensions.

Scales the box in place by the given scale factors. Tilt factors are not modified.

Parameters:

s (float or list[float]) – scale factors in each dimension. If a single float is given then scale all dimensions by s; otherwise, s must be a sequence of 3 values used to scale each dimension.

Returns:

self

classmethod square(L)#

Create a square with side lengths L.

Parameters:

L (float) – The box side length \([\mathrm{length}]\).

Returns:

The created 2D box.

Return type:

hoomd.Box

property tilts#

The box tilts, [xy, xz, yz].

Can be set using one tilt for all axes or three tilts. If the box is 2D xz and yz will automatically be set to zero.

Type:

(3, ) numpy.ndarray of float

to_matrix()#

(3, 3) numpy.ndarray float: The upper triangular matrix that defines the box.

[[Lx, Ly * xy, Lz * xz],
 [0,  Ly,      Lz * yz],
 [0,  0,       Lz]]
property volume#

Volume of the box.

\([\mathrm{length}]^{2}\) in 2D and \([\mathrm{length}]^{3}\) in 3D.

When setting volume the aspect ratio of the box is maintained while the lengths are changed.

Type:

float

property xy#

The tilt for the xy plane.

Type:

float

property xz#

The tilt for the xz plane.

Type:

float

property yz#

The tilt for the yz plane.

Type:

float

class hoomd.Operations#

A mutable collection of operations which act on a Simulation.

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

The types of operations which can be added to an Operations object are tuners, updaters, integrators, writers, and computes. An Operations instance can have zero or one integrator and any number of tuners, updaters, writers, or computes. To see examples of these types of operations see hoomd.tune (tuners), hoomd.update (updaters), hoomd.hpmc.integrate or hoomd.md.Integrator (integrators), hoomd.write (writers), and hoomd.md.compute.ThermodynamicQuantities (computes).

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

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

Note

An Operations object is created by default when a new simulation is created.

__contains__(operation)#

Whether an operation is contained in this container.

Parameters:

operation – Returns whether this exact operation is contained in the collection.

__getstate__()#

Get the current state of the operations container for pickling.

__iadd__(operation)#

Works the same as Operations.add.

Parameters:

operation (hoomd.operation.Operation) – A HOOMD-blue tuner, updater, integrator, writer, or compute to add to the object.

__isub__(operation)#

Works the same as Operations.remove.

Parameters:

operation (hoomd.operation.Operation) – A HOOMD-blue integrator, tuner, updater, integrator, analyzer, or compute to remove from the collection.

__iter__()#

Iterates through all contained operations.

__len__()#

Return the number of operations contained in this collection.

add(operation)#

Add an operation to this container.

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

Parameters:

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

Raises:

TypeError – If operation is not of a valid type.

Note

Since only one integrator can be associated with an Operations object at a time, this removes the current integrator when called with an integrator operation. Also, the integrator property cannot be set to None using this function. Use operations.integrator = None explicitly for this.

property computes#

A list of compute operations.

Holds the list of computes associated with this collection. The list can be modified as a standard Python list.

Type:

list[hoomd.operation.Compute]

property integrator#

An MD or HPMC integrator object.

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

Type:

hoomd.operation.Integrator

property is_tuning_complete#

Check whether all children have completed tuning.

True when is_tuning_complete is True for all children.

Note

In MPI parallel execution, is_tuning_complete is True only when all children on all ranks have completed tuning.

Type:

bool

remove(operation)#

Remove an operation from the Operations object.

Remove the item from the collection whose Python object id is the same as operation.

Parameters:

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

Raises:
  • ValueError – If operation is not found in this container.

  • TypeError – If operation is not of a valid type.

tune_kernel_parameters()#

Start tuning kernel parameters in all children.

property tuners#

A list of tuner operations.

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

Type:

list[hoomd.operation.Tuner]

property updaters#

A list of updater operations.

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

Type:

list[hoomd.operation.Updater]

property writers#

A list of writer operations.

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

Type:

list[hoomd.operation.Writer]

class hoomd.Simulation(device, seed=None)#

Define a simulation.

Parameters:

Simulation is the central class that defines a simulation, including the state of the system, the operations that apply to the state during a simulation run, and the device to use when executing the simulation.

seed sets the seed for the random number generator used by all operations added to this Simulation.

Newly initialized Simulation objects have no state. Call create_state_from_gsd or create_state_from_snapshot to initialize the simulation’s state.

__del__()#

Clean up dangling references to simulation.

property always_compute_pressure#

Always compute the virial and pressure (defaults to False).

By default, HOOMD only computes the virial and pressure on timesteps where it is needed (when hoomd.write.GSD writes log data to a file or when using an NPT integrator). Set always_compute_pressure to True to make the per particle virial, net virial, and system pressure available to query any time by property or through the hoomd.logging.Logger interface.

Note

Enabling this flag will result in a moderate performance penalty when using MD pair potentials.

Type:

bool

create_state_from_gsd(filename, frame=-1, domain_decomposition=(None, None, None))#

Create the simulation state from a GSD file.

Parameters:
  • filename (str) – GSD file to read

  • frame (int) – Index of the frame to read from the file. Negative values index back from the last frame in the file.

  • domain_decomposition (tuple) – Choose how to distribute the state across MPI ranks with domain decomposition. Provide a tuple of 3 integers indicating the number of evenly spaced domains in the x, y, and z directions (e.g. (8,4,2)). Provide a tuple of 3 lists of floats to set the fraction of the simulation box to include in each domain. The sum of each list of floats must be 1.0 (e.g. ([0.25, 0.75], [0.2, 0.8], [1.0])).

When timestep is None before calling, create_state_from_gsd sets timestep to the value in the selected GSD frame in the file.

Note

Set any or all of the domain_decomposition tuple elements to None and create_state_from_gsd will select a value that minimizes the surface area between the domains (e.g. (2,None,None)). The domains are spaced evenly along each automatically selected direction. The default value of (None, None, None) will automatically select the number of domains in all directions.

create_state_from_snapshot(snapshot, domain_decomposition=(None, None, None))#

Create the simulation state from a Snapshot.

Parameters:
  • snapshot (Snapshot or gsd.hoomd.Frame) – Snapshot to initialize the state from. A gsd.hoomd.Frame will first be converted to a hoomd.Snapshot.

  • domain_decomposition (tuple) – Choose how to distribute the state across MPI ranks with domain decomposition. Provide a tuple of 3 integers indicating the number of evenly spaced domains in the x, y, and z directions (e.g. (8,4,2)). Provide a tuple of 3 lists of floats to set the fraction of the simulation box to include in each domain. The sum of each list of floats must be 1.0 (e.g. ([0.25, 0.75], [0.2, 0.8], [1.0])).

When timestep is None before calling, create_state_from_snapshot sets timestep to 0.

Note

Set any or all of the domain_decomposition tuple elements to None and create_state_from_snapshot will select a value that minimizes the surface area between the domains (e.g. (2,None,None)). The domains are spaced evenly along each automatically selected direction. The default value of (None, None, None) will automatically select the number of domains in all directions.

property device#

Device used to execute the simulation.

Type:

hoomd.device.Device

property final_timestep#

run will end at this timestep.

final_timestep is the timestep on which the currently executing run will complete.

(Loggable: category=”scalar”)

Type:

float

property initial_timestep#

run started at this timestep.

initial_timestep is the timestep on which the currently executing run started.

(Loggable: category=”scalar”)

Type:

float

property loggables#

Name, category mapping of loggable quantities.

Type:

dict[str, str]

property operations#

The operations that apply to the state.

The operations apply to the state during the simulation run when scheduled.

See also

run

Type:

hoomd.Operations

run(steps, write_at_start=False)#

Advance the simulation a number of steps.

Parameters:
  • steps (int) – Number of steps to advance the simulation.

  • write_at_start (bool) – When True, writers with triggers that evaluate True for the initial step will be executed before the time step loop.

Note

Initialize the simulation’s state before calling run.

Simulation applies its operations to the state during each time step in the order: tuners, updaters, integrator, then writers following the logic in this pseudocode:

if write_at_start:
    for writer in operations.writers:
        if writer.trigger(timestep):
            writer.write(timestep)

end_step = timestep + steps
while timestep < end_step:
    for tuner in operations.tuners:
        if tuner.trigger(timestep):
            tuner.tune(timestep)

    for updater in operations.updaters:
        if updater.trigger(timestep):
            updater.update(timestep)

    if operations.integrator is not None:
        operations.integrator(timestep)

    timestep += 1

    for writer in operations.writers:
        if writer.trigger(timestep):
            writer.write(timestep)

This order of operations ensures that writers (such as hoomd.write.GSD) capture the final output of the last step of the run loop. For example, a writer with a trigger hoomd.trigger.Periodic(period=100, phase=0) active during a run(500) would write on steps 100, 200, 300, 400, and 500. Set write_at_start=True on the first call to run to also obtain output at step 0.

Warning

Using write_at_start=True in subsequent calls to run will result in duplicate output frames.

property seed#

Random number seed.

Seeds are in the range [0, 65535]. When set, seed will take only the lowest 16 bits of the given value.

HOOMD-blue uses a deterministic counter based pseudorandom number generator. Any time a random value is needed, HOOMD-blue computes it as a function of the user provided seed seed (16 bits), the current timestep (lower 40 bits), particle identifiers, MPI ranks, and other unique identifying values as needed to sample uncorrelated values: random_value = f(seed, timestep, ...)

(Loggable: category=”scalar”)

Type:

int

property state#

The current simulation state.

Type:

hoomd.State

property timestep#

The current simulation time step.

Note

Methods like create_state_from_gsd will set the initial timestep from the input. Set timestep before creating the simulation state to override values from create_ methods:

sim.timestep = 5000
sim.create_state_from_gsd('gsd_at_step_10000000.gsd')
assert sim.timestep == 5000

(Loggable: category=”scalar”)

Type:

int

property tps#

The average number of time steps per second.

tps is the number of steps executed divided by the elapsed walltime in seconds. It is updated during the run loop and remains fixed after run completes.

Note

The start walltime and timestep are reset at the beginning of each call to run.

(Loggable: category=”scalar”)

Type:

float

property walltime#

The walltime spent during the last call to run.

walltime is the number seconds that the last call to run took to complete. It is updated during the run loop and remains fixed after run completes.

Note

walltime resets to 0 at the beginning of each call to run.

(Loggable: category=”scalar”)

Type:

float

class hoomd.Snapshot(communicator=None)#

Self-contained copy of the simulation State.

Parameters:

communicator (Communicator) – MPI communicator to be used when accessing the snapshot.

See State and gsd.hoomd.Frame for detailed documentation on the components of Snapshot.

Note

Snapshot is duck-type compatible with gsd.hoomd.Frame except that arrays in Snapshot are not assignable. You can edit their contents: e.g. snapshot.particles.typeid[:] == 0.

Warning

Data is only present on the root rank:

if snapshot.communicator.rank == 0:
    pos = snapshot.particles.position[0]
communicator#

MPI communicator.

Type:

Communicator

property angles#

Angles.

angles.N#

Number of angles.

Type:

int

angles.types#

Names of the angle types

Type:

list[str]

angles.typeid#

Angle type id.

Type:

(N,) numpy.ndarray of uint32

angles.group#

Tags of the particles in the angle.

Type:

(N, 3) numpy.ndarray of uint32

Note

Set N to change the size of the arrays.

property bonds#

Bonds.

bonds.N#

Number of bonds.

Type:

int

bonds.types#

Names of the bond types

Type:

list[str]

bonds.typeid#

Bond type id.

Type:

(N,) numpy.ndarray of uint32

bonds.group#

Tags of the particles in the bond.

Type:

(N, 2) numpy.ndarray of uint32

Note

Set N to change the size of the arrays.

property configuration#

Snapshot box configuration.

dimensions#

Number of dimensions

Type:

int

box#

Simulation box parameters [Lx, Ly, Lz, xy, xz, yz].

Type:

tuple[float, float, float, float, float, float]

Note

box accepts any values that Box.from_box allows when setting.

See also

Box

property constraints#

Constraints.

constraints.N#

Number of constraints.

Type:

int

constraints.value#

Constraint length.

Type:

(N, ) numpy.ndarray of float

constraints.group#

Tags of the particles in the constraint.

Type:

(N, 2) numpy.ndarray of uint32

Note

Set N to change the size of the arrays.

property dihedrals#

Dihedrals.

dihedrals.N#

Number of dihedrals.

Type:

int

dihedrals.types#

Names of the dihedral types

Type:

list[str]

dihedrals.typeid#

Dihedral type id.

Type:

(N,) numpy.ndarray of uint32

dihedrals.group#

Tags of the particles in the dihedral.

Type:

(N, 4) numpy.ndarray of uint32

Note

Set N to change the size of the arrays.

classmethod from_gsd_frame(gsd_snap, communicator)#

Constructs a hoomd.Snapshot from a gsd.hoomd.Frame object.

Parameters:

Tip

Use Simulation.create_state_from_gsd to efficiently initialize the system state from a GSD file.

Note

from_gsd_frame only accesses the gsd_snap argument on rank 0. In MPI simulations, avoid duplicating memory and file reads by reading GSD files only on rank 0 and passing gsd_snap=None on other ranks.

classmethod from_gsd_snapshot(gsd_snap, communicator)#

Constructs a hoomd.Snapshot from a gsd.hoomd.Snapshot object.

Deprecated since version 4.0.0: Use from_gsd_frame.

property impropers#

Impropers.

impropers.N#

Number of impropers.

Type:

int

impropers.types#

Names of the improper types

Type:

list[str]

impropers.typeid#

Improper type id.

Type:

(N,) numpy.ndarray of uint32

impropers.group#

Tags of the particles in the improper.

Type:

(N, 4) numpy.ndarray of uint32

Note

Set N to change the size of the arrays.

property pairs#

Special pairs.

pairs.N#

Number of special pairs.

Type:

int

pairs.types#

Names of the special pair types

Type:

list[str]

pairs.typeid#

Special pair type id.

Type:

(N,) numpy.ndarray of uint32

pairs.group#

Tags of the particles in the special pair.

Type:

(N, 2) numpy.ndarray of uint32

Note

Set N to change the size of the arrays.

property particles#

Particles.

particles.N#

Number of particles in the snapshot.

Type:

int

particles.types#

Names of the particle types.

Type:

list[str]

particles.position#

Particle position \([\mathrm{length}]\).

Type:

(N, 3) numpy.ndarray of float

particles.orientation#

Particle orientation.

Type:

(N, 4) numpy.ndarray of float

particles.typeid#

Particle type id.

Type:

(N, ) numpy.ndarray of uint32

particles.mass#

Particle mass \([\mathrm{mass}]\).

Type:

(N, ) numpy.ndarray of float

particles.charge#

Particle charge \([\mathrm{charge}]\).

Type:

(N, ) numpy.ndarray of float

particles.diameter#

Particle diameter \([\mathrm{length}]\).

Type:

(N, ) numpy.ndarray of float

particles.body#

Particle body.

Type:

(N, ) numpy.ndarray of int32

particles.moment_inertia#

Particle moment of inertia \([\mathrm{mass} \cdot \mathrm{length}^2]\).

Type:

(N, 3) numpy.ndarray of float

particles.velocity#

Particle velocity \([\mathrm{velocity}]\).

Type:

(N, 3) numpy.ndarray of float

particles.angmom#

Particle angular momentum \([\mathrm{mass} \cdot \mathrm{velocity} \cdot \mathrm{length}]\).

Type:

(N, 4) numpy.ndarray of float

particles.image#

Particle image.

Type:

(N, 3) numpy.ndarray of int32

Note

Set N to change the size of the arrays.

replicate(nx, ny, nz=1)#

Replicate the snapshot along the periodic box directions.

Parameters:
  • nx (int) – Number of times to replicate in the x direction.

  • ny (int) – Number of times to replicate in the y direction.

  • nz (int) – Number of times to replicate in the z direction.

Performs the same operation as State.replicate on a Snapshot.

Returns:

self

wrap()#

Wrap particles into the snapshot box.

Returns:

self

class hoomd.State(simulation, snapshot, domain_decomposition)#

The state of a Simulation object.

Note

This object cannot be directly instantiated. Use Simulation.create_state_from_gsd and Simulation.create_state_from_snapshot to instantiate a State object as part of a simulation.

Overview

State stores the data that describes the thermodynamic microstate of a Simulation object. This data consists of the box, particles, bonds, angles, dihedrals, impropers, special pairs, and constraints.

Box

The simulation box describes the space that contains the particles as a Box object.

Particles

The state contains N_particles particles. Each particle has a position, orientation, type id, body, mass, moment of inertia, charge, diameter, velocity, angular momentum, image, and tag:

  • \(\vec{r}\): position \([\mathrm{length}]\) - X,Y,Z cartesian coordinates defining the position of the particle in the box.

  • \(\mathbf{q}\): orientation \([\mathrm{dimensionless}]\) - Unit quaternion defining the rotation from the particle’s local reference frame to the box reference frame. The four components are in the order \(s\), \(a_x\), \(a_y\), \(a_z\) for the in complex notation \(s + a_x i + a_y j + a_z k\).

  • particle_typeid: type id \([\mathrm{dimensionless}]\) - An integer in the interval [0,len(particle_types)) that identifies the particle’s type. particle_types maps type ids to names with: name = particle_types[particle_typeid].

  • particle_body: body id \([\mathrm{dimensionless}]\) - An integer that identifies the particle’s rigid body. A value of -1 indicates that this particle does not belong to a body. A positive value indicates that the particle belongs to the body particle_body. This particle is the central particle of a body when the body id is equal to the tag \(\mathrm{particle\_body} = \mathrm{particle\_tag}\). (used by hoomd.md.constrain.Rigid)

  • \(m\): mass \([\mathrm{mass}]\) - The particle’s mass.

  • \(I\): moment of inertia \([\mathrm{mass} \cdot \mathrm{length}^2]\) - \(I_{xx}\), \(I_{yy}\), \(I_{zz}\) elements of the diagonal moment of inertia tensor in the particle’s local reference frame. The off-diagonal elements are 0.

  • \(q\): charge \([\mathrm{charge}]\) - The particle’s charge.

  • \(d\): diameter \([\mathrm{length}]\) - Deprecated in v3.0.0. HOOMD-blue reads and writes particle diameters, but does not use them in any computations.

  • \(\vec{v}`\): velocity \([\mathrm{velocity}]\) - X,Y,Z components of the particle’s velocity in the box’s reference frame.

  • \(\mathbf{P_S}`\): angular momentum \([\mathrm{mass} \cdot \mathrm{velocity} \cdot \mathrm{length}]\) - Quaternion defining the particle’s angular momentum (see note).

  • \(\vec{n}\) : image \([\mathrm{dimensionless}]\) - Integers x,y,z that record how many times the particle has crossed each of the periodic box boundaries.

  • particle_tag : tag \([\mathrm{dimensionless}]\) - An integer that uniquely identifies a given particle. The particles are stored in tag order when writing and initializing to/from a GSD file or snapshot: \(\mathrm{particle\_tag}_i = i\). When accessing data in local snapshots, particles may be in any order.

Note

HOOMD stores angular momentum as a quaternion because that is the form used when integrating the equations of motion (see Kamberaj 2005). The angular momentum quaternion \(\mathbf{P_S}\) is defined with respect to the orientation quaternion of the particle \(\mathbf{q}\) and the vector angular momentum of the particle, lifted into pure imaginary quaternion form \(\mathbf{S}^{(4)}\) as:

\[\mathbf{P_S} = 2 \mathbf{q} \times \mathbf{S}^{(4)}\]

. Following this, the angular momentum vector \(\vec{S}\) in the particle’s local reference frame is:

\[\vec{S} = \frac{1}{2}im(\mathbf{q}^* \times \mathbf{P_S})\]

Bonded groups

The state contains N_bonds bonds, N_angles angles, N_dihedrals dihedrals, N_impropers impropers, and N_special_pairs special pairs. Each of these data structures is similar, differing in the number of particles in the group and what operations use them. Bonds, angles, dihedrals, and impropers contain 2, 3, 4, and 4 particles per group respectively. Bonds specify the toplogy used when computing energies and forces in md.bond, angles define the same for md.angle, dihedrals for md.dihedral and impropers for md.improper. These collectively implement bonding potentials used in molecular dynamics force fields. Like bonds, special pairs define connections between two particles, but special pairs are intended to adjust the 1-4 pairwise interactions in some molecular dynamics force fields: see md.special_pair. Each bonded group is defined by a type id, the group members, and a tag.

  • bond_typeid: type id \([\mathrm{dimensionless}]\) - An integer in the interval [0,len(bond_types)) that identifies the bond’s type. bond_types maps type ids to names with: name = bond_types[bond_typeid]. Similarly, angle_types lists the angle types, dihedral_types lists the dihedral types, improper_types lists the improper types, and special_pair_types lists the special pair types.

  • bond_group: A list of integers in the interval \([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).

  • bond_tag : tag \([\mathrm{dimensionless}]\) - An integer that uniquely identifies a given bond. The bonds are in tag order when writing and initializing to/from a GSD file or snapshot \(\mathrm{bond\_tag}_i = i\). When accessing data in local snapshots, bonds may be in any order. The same applies to angles with angle_tag, dihedrals with dihedral_tag, impropers with improper_tag, and special pairs with pair_tag.

Constraints

The state contains N_constraints distance constraints between particles. These constraints are used by hoomd.md.constrain.Distance. Each distance constraint consists of a distance value and the group members.

  • constraint_group: A list of 2 integers in the interval \([0, \max(\mathrm{particle\_tag})]\) that identifies the tags of the particles in the constraint.

  • \(d\): constraint value \([\mathrm{length}]\) - The distance between particles in the constraint.

MPI domain decomposition

When running in serial or on 1 MPI rank, the entire simulation state is stored in that process. When using more than 1 MPI rank, HOOMD-blue employs a domain decomposition approach to split the simulation box an integer number of times in the x, y, and z directions (domain_decomposition). Each MPI rank stores and operates on the particles local to that rank. Local particles are those contained within the region defined by the split planes (domain_decomposition_split_fractions). Each MPI rank communicates with its neighbors to obtain the properties of particles near the boundary between ranks (ghost particles) so that it can compute interactions across the boundary.

Accessing Data

Two complementary APIs provide access to the state data: local snapshots that access data directly available on the local MPI rank (including the local and ghost particles) and global snapshots that collect the entire state on rank 0. See State.cpu_local_snapshot, State.gpu_local_snapshot, get_snapshot, and set_snapshot for information about these data access patterns.

See also

To write the simulation to disk, use write.GSD.

property N_angles#

The number of angles in the simulation state.

Type:

int

property N_bonds#

The number of bonds in the simulation state.

Type:

int

property N_constraints#

The number of constraints in the simulation state.

Type:

int

property N_dihedrals#

The number of dihedrals in the simulation state.

Type:

int

property N_impropers#

The number of impropers in the simulation state.

Type:

int

property N_particles#

The number of particles in the simulation state.

Type:

int

property N_special_pairs#

The number of special pairs in the simulation state.

Type:

int

property angle_types#

List of all angle types in the simulation state.

Type:

list[str]

property bond_types#

List of all bond types in the simulation state.

Type:

list[str]

property box#

A copy of the current simulation box.

Note

The box property cannot be set. Call set_box to set a new simulation box.

Type:

hoomd.Box

property cpu_local_snapshot#

Expose simulation data on the CPU.

Provides access directly to the system state’s particle, bond, angle, dihedral, improper, constaint, and pair data through a context manager. Data in State.cpu_local_snapshot is MPI rank local, and the hoomd.data.LocalSnapshot object is only usable within a context manager (i.e. with sim.state.cpu_local_snapshot as data:). Attempts to assess data outside the context manager will result in errors. The local snapshot interface is similar to that of Snapshot.

The hoomd.data.LocalSnapshot data access is mediated through hoomd.data.array.HOOMDArray objects. This lets us ensure memory safety when directly accessing HOOMD-blue’s data. The interface provides zero-copy access (zero-copy is guaranteed on CPU, access may be zero-copy if running on GPU).

Changing the data in the buffers exposed by the local snapshot will change the data across the HOOMD-blue simulation. For a trivial example, this example would set all particle z-axis positions to 0.

with sim.state.cpu_local_snapshot as data:
    data.particles.position[:, 2] = 0

Note

The state’s box and the number of particles, bonds, angles, dihedrals, impropers, constaints, and pairs cannot change within the context manager.

Note

Getting a local snapshot object is order \(O(1)\) and setting a single value is of order \(O(1)\).

Type:

hoomd.data.LocalSnapshot

property dihedral_types#

List of all dihedral types in the simulation state.

Type:

list[str]

property domain_decomposition#

Number of domains in the x, y, and z directions.

Type:

tuple(int, int, int)

property domain_decomposition_split_fractions#

Box fractions of the domain split planes in the x, y, and z directions.

Type:

tuple(list[float], list[float], list[float])

get_snapshot()#

Make a copy of the simulation current state.

State.get_snapshot makes a copy of the simulation state and makes it available in a single object. set_snapshot resets the internal state to that in the given snapshot. Use these methods to implement techniques like hybrid MD/MC or umbrella sampling where entire system configurations need to be reset to a previous one after a rejected move.

Note

Data across all MPI ranks and from GPUs is gathered on the root MPI rank’s memory. When accessing data in MPI simulations, use a if snapshot.communicator.rank == 0: conditional to access data arrays only on the root rank.

Note

State.get_snapshot is an order \(O(N_{particles} + N_{bonds} + \ldots)\) operation.

See also

set_snapshot

Returns:

The current simulation state

Return type:

Snapshot

property gpu_local_snapshot#

Expose simulation data on the GPU.

Provides access directly to the system state’s particle, bond, angle, dihedral, improper, constaint, and pair data through a context manager. Data in State.gpu_local_snapshot is GPU local, and the hoomd.data.LocalSnapshotGPU object is only usable within a context manager (i.e. with sim.state.gpu_local_snapshot as data:). Attempts to assess data outside the context manager will result in errors. The local snapshot interface is similar to that of Snapshot.

The hoomd.data.LocalSnapshotGPU data access is mediated through hoomd.data.array.HOOMDGPUArray objects. This helps us maintain memory safety when directly accessing HOOMD-blue’s data. The interface provides zero-copy access on the GPU (assuming data was last accessed on the GPU).

Changing the data in the buffers exposed by the local snapshot will change the data across the HOOMD-blue simulation. For a trivial example, this example would set all particle z-axis positions to 0.

with sim.state.gpu_local_snapshot as data:
    data.particles.position[:, 2] = 0

Warning

This property is only available when running on a GPU(s).

Note

The state’s box and the number of particles, bonds, angles, dihedrals, impropers, constaints, and pairs cannot change within the context manager.

Note

Getting a local snapshot object is order \(O(1)\) and setting a single value is of order \(O(1)\).

Type:

hoomd.data.LocalSnapshotGPU

property improper_types#

List of all improper types in the simulation state.

Type:

list[str]

property particle_types#

List of all particle types in the simulation state.

Type:

list[str]

replicate(nx, ny, nz=1)#

Replicate the state of the system along the periodic box directions.

Parameters:
  • nx (int) – Number of times to replicate in the x direction.

  • ny (int) – Number of times to replicate in the y direction.

  • nz (int) – Number of times to replicate in the z direction.

replicate makes the system state nx * ny * nz times larger. In each of the new periodic box images, it places a copy of the initial state with the particle positions offset to locate them in the image and the bond, angle, dihedral, improper, and pair group tags offset to apply to the copied particles. All other particle properties (mass, typeid, velocity, charge, …) are copied to the new particles without change.

After placing the particles, replicate expands the simulation box by a factor of nx, ny, and nz in the direction of the first, second, and third box lattice vectors respectively and adjusts the particle positions to center them in the new box.

set_box(box)#

Set a new simulation box.

Parameters:

box (hoomd.box.box_like) – New simulation box.

Note

All particles must be inside the new box. set_box does not change any particle properties.

set_snapshot(snapshot)#

Restore the state of the simulation from a snapshot.

Also calls update_group_dof to count the number of degrees in the system with the new state.

Parameters:

snapshot (Snapshot) – Snapshot of the system from get_snapshot

Warning

set_snapshot can only make limited changes to the simulation state. While it can change the number of particles/bonds/etc… or their properties, it cannot change the number or names of the particle/bond/etc.. types.

Note

set_snapshot is an order \(O(N_{particles} + N_{bonds} + \ldots)\) operation and is very expensive when the simulation device is a GPU.

property special_pair_types#

List of all special pair types in the simulation state.

Type:

list[str]

thermalize_particle_momenta(filter, kT)#

Assign random values to particle momenta.

Parameters:

thermalize_particle_momenta assigns the selected particle’s velocities and angular momentum to random values drawn from a Gaussian distribution consistent with the given thermal energy kT.

Velocity

thermalize_particle_momenta assigns random velocities to the x and y components of each particle’s velocity. When the simulation box is 3D, it also assigns a random velocity to the z component. When the simulation box is 2D, it sets the z component to 0. Finally, sets the center of mass velocity of the selected particles to 0.

Angular momentum

thermalize_particle_momenta assigns random angular momenta to each rotational degree of freedom that has a non-zero moment of intertia. Each particle can have 0, 1, 2, or 3 rotational degrees of freedom as determine by its moment of inertia.

property types#

dictionary of all types in the state.

Combines the data from particle_types, bond_types, angle_types, dihedral_types, improper_types, and special_pair_types into a dictionary with keys matching the property names.

Type:

dict[str, list[str]]

update_group_dof()#

Schedule an update to the number of degrees of freedom in each group.

update_group_dof requests that Simulation update the degrees of freedom provided to each group by the Integrator. Simulation will perform this update at the start of Simulation.run or at the start of the next timestep during an ongoing call to Simulation.run.

This method is called automatically when:

Call update_group_dof manually to force an update, such as when you modify particle moments of inertia with cpu_local_snapshot.

Modules

hoomd.box#

Overview

BoxInterface

The class interface which HOOMD considers to be a box-like object.

box_like

Objects that are or can be converted to Box.

Details

Implement Box.

class hoomd.box.BoxInterface#

The class interface which HOOMD considers to be a box-like object.

Note

This class is exclusively used for help with typing and documentation in HOOMD, and is not meant to be used.

hoomd.box.box_like#

Objects that are or can be converted to Box.

This includes

  • hoomd.Box objects.

  • Objects with attributes Lx, Ly, Lz, xy, xz, yz.

  • Lists like [Lx, Ly, Lz, xy, xz, yz].

  • Dictionaries with keys 'Lx', 'Ly', 'Lz', 'xy', 'xz', 'yz'.

  • 3x3 NumPy arrays or objects convertible to a 3x3 array (see hoomd.Box.from_matrix).

Note

If any of Lz, xy, xz, yz for these different types are not provided, they are considered 0.

alias of Union[Box, BoxInterface, Sequence[float], Mapping[str, float], ndarray]

hoomd.communicator#

Overview

Communicator

MPI communicator.

Details

MPI communicator.

When compiled without MPI support, Communicator acts as if there is one MPI rank and 1 partition. To use MPI, compile HOOMD-blue with the option ENABLE_MPI=on and use the appropriate MPI launcher to launch Python. Then the Communicator class will configure and query MPI ranks and partitions. By default, Communicator starts with the MPI_COMM_WOLRD MPI communicator, and the communicator is not available for user scripts.

Communicator also accepts MPI communicators from mpi4py. Use this to implement workflows with multiple simulations that communicate using mpi4py calls in user code (e.g. genetic algorithms, umbrella sampling).

class hoomd.communicator.Communicator(mpi_comm=None, ranks_per_partition=None)#

MPI communicator.

Parameters:
  • mpi_comm – Accepts an mpi4py communicator. Use this argument to perform many independent hoomd simulations where you communicate between those simulations using mpi4py.

  • ranks_per_partition (int) – (MPI) Number of ranks to include in a partition.

The Communicator class initializes MPI communications for a hoomd.Simulation and exposes rank and partition information to the user as properties. To use MPI, launch your Python script with an MPI launcher (e.g. mpirun or mpiexec). By default, Communicator uses all ranks provided by the launcher num_launch_ranks for a single hoomd.Simulation object which decomposes the state onto that many domains.

Set ranks_per_partition to an integer to partition launched ranks into num_launch_ranks / ranks_per_partition communicators, each with their own partition index. Use this to perform many simulations in parallel, for example by using partition as an index into an array of state points to execute.

barrier()#

Perform a barrier synchronization across all ranks in the partition.

Note

Does nothing in builds with ENABLE_MPI=off.

barrier_all()#

Perform a MPI barrier synchronization across all ranks.

Note

Does nothing in builds with ENABLE_MPI=off.

localize_abort()#

Localize MPI_Abort to this partition.

HOOMD calls MPI_Abort to tear down all running MPI processes whenever there is an uncaught exception. By default, this will abort the entire MPI execution. When using partitions, an uncaught exception on one partition will therefore abort all of them.

Use the return value of localize_abort() as a context manager to tell HOOMD that all operations within the context will use only that MPI communicator so that an uncaught exception in one partition will only abort that partition and leave the others running.

property num_partitions#

The number of partitions in this execution.

Create partitions with the ranks_per_partition argument on initialization. Then, the number of partitions is num_launch_ranks / ranks_per_partition.

Note

Returns 1 in builds with ENABLE_MPI=off.

Type:

int

property num_ranks#

The number of ranks in this partition.

When initialized with ranks_per_partition=None, num_ranks is equal to the num_launch_ranks set by the MPI launcher. When using partitions, num_ranks is equal to ranks_per_partition.

Note

Returns 1 in builds with ENABLE_MPI=off.

Type:

int

property partition#

The current partition.

Note

Returns 0 in builds with ENABLE_MPI=off.

Type:

int

property rank#

The current rank within the partition.

Note

Returns 0 in builds with ENABLE_MPI=off.

Type:

int

property walltime#

Wall clock time since creating the Communicator [seconds].

walltime returns the same value on each rank in the current partition.

hoomd.custom#

Overview

Action

Base class for user-defined actions.

CustomOperation

User defined operation.

Details

Custom operations.

CustomOperation provides a mechanism for users to insert Python code via an Action subclass that executes during the simulation’s run loop. Use this to prototype new simulation methods in Python, analyze the system state while the simulation progresses, or write output to custom file formats.

class hoomd.custom.Action#

Bases: object

Base class for user-defined actions.

To implement a custom operation in Python, subclass Action and implement the 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.

from hoomd.custom import Action


class ExampleAction(Action):
    def act(self, timestep):
        self.com = self._state.snapshot.particles.position.mean(axis=0)

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

from hoomd.custom import Action


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

    def act(self, timestep):
        pass

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

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


class ExampleActionWithFlag(Action):

    @log
    def answer(self):
        return 42

    def act(self, timestep):
        pass
flags#

List of flags from the Action.Flags. Used to tell the integrator if specific quantities are needed for the action.

Type:

list[Action.Flags]

class Flags(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: IntEnum

Flags to indictate the integrator should calculate quantities.

  • PRESSURE_TENSOR = 0

  • ROTATIONAL_KINETIC_ENERGY = 1

  • EXTERNAL_FIELD_VIRIAL = 2

abstract act(timestep)#

Performs whatever action a subclass implements.

Parameters:

timestep (int) – The current timestep in a simulation.

Note

Use self._state to access the simulation state via hoomd.State when using the base class attach.

attach(simulation)#

Attaches the Action to the hoomd.Simulation.

Parameters:

simulation (hoomd.Simulation) – The simulation to attach the action to.

Stores the simulation state in self._state. Override this in derived classes to implement other behaviors.

detach()#

Detaches the Action from the hoomd.Simulation.

property loggables#

Name, category mapping of loggable quantities.

Type:

dict[str, str]

class hoomd.custom.CustomOperation(trigger, action)#

Bases: TriggeredOperation

User defined operation.

This is the parent class for hoomd.tune.CustomTuner, hoomd.update.CustomUpdater. and hoomd.write.CustomWriter. These classes wrap Python objects that inherit from hoomd.custom.Action so they can be added to the simulation operations.

This class also implements a “pass-through” system for attributes. Attributes and methods from the passed in action will be available directly in this class. This does not apply to attributes with these names: trigger, _action, and action.

Note

Due to the pass through no attribute should exist both in hoomd.custom.CustomOperation and the hoomd.custom.Action.

Note

This object should not be instantiated or subclassed by an user.

trigger#

A trigger to determine when the wrapped hoomd.custom.Action is run.

Type:

hoomd.trigger.Trigger

__getattr__(attr)#

Pass through attributes/methods of the wrapped object.

__setstate__(state)#

Set object state from pickling or deepcopying.

act(timestep)#

Perform the action of the custom action if attached.

Calls through to the action property of the instance.

Parameters:

timestep (int) – The current timestep of the state.

property action#

hoomd.custom.Action The action the operation wraps.

hoomd.data#

Overview

LocalSnapshot

Provides context manager access to HOOMD-blue CPU data buffers.

LocalSnapshotGPU

Provides context manager access to HOOMD-blue GPU data buffers.

AngleLocalAccessBase

Class for directly accessing HOOMD-blue angle data.

BondLocalAccessBase

Class for directly accessing HOOMD-blue bond data.

ConstraintLocalAccessBase

Class for directly accessing HOOMD-blue constraint data.

DihedralLocalAccessBase

Class for directly accessing HOOMD-blue dihedral data.

ImproperLocalAccessBase

Class for directly accessing HOOMD-blue improper data.

PairLocalAccessBase

Class for directly accessing HOOMD-blue special pair data.

ParticleLocalAccessBase

Class for directly accessing HOOMD-blue particle data.

hoomd.data.typeparam.TypeParameter

Implement a type based mutable mapping.

Details

Access State data on the local rank.

LocalSnapshot, LocalSnapshotGPU, and related classes provide direct access to the data buffers managed by hoomd.State.

See also

hoomd.State

class hoomd.data.LocalSnapshot(state)#

Provides context manager access to HOOMD-blue CPU data buffers.

The interface of a LocalSnapshot is similar to that of the hoomd.Snapshot. Data is MPI rank local so for MPI parallel simulations only the data possessed by a rank is exposed. This means that users must handle the domain decomposition directly. One consequence of this is that access to ghost particle data is provided. A ghost particle is a particle that is not owned by a rank, but nevertheless is required for operations that use particle neighbors. Also, changing the global or local box within a LocalSnapshot context manager is not allowed.

For every property (e.g. data.particles.position), only grabs the data for the regular (non-ghost) particles. The property can be prefixed with ghost_ to grab the ghost particles in a read only manner. Likewise, suffixing with _with_ghost will grab all data on the rank (regular and ghost particles) in a read only array.

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

Note

For the LocalAccess classes the affixed attributes mentioned above are not shown. Also of interest, ghost data always come immediately after the regular data.

property angles#

Local angle data.

Type:

hoomd.data.AngleLocalAccessBase

property bonds#

Local bond data.

Type:

hoomd.data.BondLocalAccessBase

property constraints#

Local constraint data.

Type:

hoomd.data.ConstraintLocalAccessBase

property dihedrals#

Local dihedral data.

Type:

hoomd.data.DihedralLocalAccessBase

property global_box#

The global simulation box.

Type:

hoomd.Box

property impropers#

Local improper data.

Type:

hoomd.data.ImproperLocalAccessBase

property local_box#

The local box according to the domain decomposition.

Type:

hoomd.Box

property pairs#

Local special pair data.

Type:

hoomd.data.PairLocalAccessBase

property particles#

Local particle data.

Type:

hoomd.data.ParticleLocalAccessBase

class hoomd.data.LocalSnapshotGPU(*args, **kwargs)#

Provides context manager access to HOOMD-blue GPU data buffers.

The interface of a LocalSnapshot is similar to that of the hoomd.Snapshot. Data is MPI rank local so for MPI parallel simulations only the data possessed by a rank is exposed. This means that users must handle the domain decomposition directly. One consequence of this is that access to ghost particle data is provided. A ghost particle is a particle that is not owned by a rank, but nevertheless is required for operations that use particle neighbors. Also, changing the global or local box within a LocalSnapshot context manager is not allowed.

For every property (e.g. data.particles.position), only grabs the data for the regular (non-ghost) particles. The property can be prefixed with ghost_ to grab the ghost particles in a read only manner. Likewise, suffixing with _with_ghost will grab all data on the rank (regular and ghost particles) in a read only array.

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

property angles#

Local angle data.

Type:

hoomd.data.AngleLocalAccessBase

property bonds#

Local bond data.

Type:

hoomd.data.BondLocalAccessBase

property constraints#

Local constraint data.

Type:

hoomd.data.ConstraintLocalAccessBase

property dihedrals#

Local dihedral data.

Type:

hoomd.data.DihedralLocalAccessBase

property global_box#

The global simulation box.

Type:

hoomd.Box

property impropers#

Local improper data.

Type:

hoomd.data.ImproperLocalAccessBase

property local_box#

The local box according to the domain decomposition.

Type:

hoomd.Box

property pairs#

Local special pair data.

Type:

hoomd.data.PairLocalAccessBase

property particles#

Local particle data.

Type:

hoomd.data.ParticleLocalAccessBase

class hoomd.data.typeparam.TypeParameter(name, type_kind, param_dict)#

Implement a type based mutable mapping.

Implements the collections.abc.MutableMapping interface ( __delitem__ is disallowed).

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.

Indexing

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.

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.

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.

Below are some example indexing values for single and multiple key indexing.

# "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"])

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,

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.

property default#

The default value of the parameter.

class hoomd.data.AngleLocalAccessBase(state)#

Class for directly accessing HOOMD-blue angle data.

typeid#

The integer type of a angle.

Type:

(N_angles) hoomd.data.array object of int

members#

The tags of particles in a angle.

Type:

(N_angles, 3) hoomd.data.array object of int

tag#

The angle tags. MPI domain migration reorder angles in memory. The angle tag identifies each angle in the order it existed in the initial configuration.

Type:

(N_angles) hoomd.data.array object of int

rtag#

The angle reverse tags. For a given angle tag tag, i = angles.rtag[tag] is the array index holding that angle.

Type:

(N_angles_global) hoomd.data.array object of int

See also

hoomd.State

class hoomd.data.BondLocalAccessBase(state)#

Class for directly accessing HOOMD-blue bond data.

typeid#

The integer type of a bond.

Type:

(N_bonds) hoomd.data.array object of int

members#

The tags of particles in a bond.

Type:

(N_bonds, 2) hoomd.data.array object of int

tag#

The bond tags. MPI domain migration reorder bonds in memory. The bond tag identifies each bond in the order it existed in the initial configuration.

Type:

(N_bonds) hoomd.data.array object of int

rtag#

the The bond reverse tags. For a given bond tag tag, i = bonds.rtag[tag] is the array index holding that bond.

Type:

(N_bonds_global) hoomd.data.array object of int

See also

hoomd.State

class hoomd.data.ConstraintLocalAccessBase(state)#

Class for directly accessing HOOMD-blue constraint data.

value#

The constaint value.

Type:

(N_constraints) hoomd.data.array object of float

members#

the tags of particles in a constraint.

Type:

(N_constraints, 3) hoomd.data.array object of int

tag#

The constraint tags. MPI domain migration reorder constraints in memory. The constraint tag identifies each constraint in the order it existed in the initial configuration.

Type:

(N_constraints) hoomd.data.array object of int

rtag#

The constraint reverse tags. For a given constraint tag tag, i = constraints.rtag[tag] is the array index holding that constraint.

Type:

(N_constraints_global) hoomd.data.array object of int

See also

hoomd.State

class hoomd.data.DihedralLocalAccessBase(state)#

Class for directly accessing HOOMD-blue dihedral data.

typeid#

The integer type of a dihedral.

Type:

(N_dihedrals) hoomd.data.array object of int

members#

the tags of particles in a dihedral.

Type:

(N_dihedrals, 4) hoomd.data.array object of int

tag#

The dihedral tags. MPI domain migration reorder dihedrals in memory. The dihedral tag identifies each dihedral in the order it existed in the initial configuration.

Type:

(N_dihedrals) hoomd.data.array object of int

rtag#

The dihedral reverse tags. For a given dihedral tag tag, i = dihedrals.rtag[tag] is the array index holding that dihedral.

Type:

(N_dihedrals_global) hoomd.data.array object of int

See also

hoomd.State

class hoomd.data.ImproperLocalAccessBase(state)#

Class for directly accessing HOOMD-blue improper data.

typeid#

The integer type of a improper.

Type:

(N_impropers) hoomd.data.array object of int

members#

The tags of particles in a improper.

Type:

(N_impropers, 3) hoomd.data.array object of int

tag#

The improper tags. MPI domain migration reorder impropers in memory. The improper tag identifies each improper in the order it existed in the initial configuration.

Type:

(N_impropers) hoomd.data.array object of int

rtag#

The improper reverse tags. For a given improper tag tag, i = impropers.rtag[tag] is the array index holding that improper.

Type:

(N_impropers_global) hoomd.data.array object of int

See also

hoomd.State

class hoomd.data.PairLocalAccessBase(state)#

Class for directly accessing HOOMD-blue special pair data.

typeid#

The type of special pair.

Type:

(N_pairs) hoomd.data.array object of float

members#

the tags of particles in a special pair.

Type:

(N_pairs, 3) hoomd.data.array object of int

tag#

The special pair tags. MPI domain migration reorder special pairs in memory. The special pair tag identifies each special pair in the order it existed in the initial configuration.

Type:

(N_special_pairs) hoomd.data.array object of int

rtag#

The special pair reverse tags. For a given special pair tag tag, i = pairs.rtag[tag] is the array index holding that special pair.

Type:

(N_special_pairs_global) hoomd.data.array object of int

See also

hoomd.State

class hoomd.data.ParticleLocalAccessBase(state)#

Class for directly accessing HOOMD-blue particle data.

typeid#

The integer type of a particle.

Type:

(N_particles) hoomd.data.array object of float

tag#

The particle tags. Spatial sorting and MPI domain migration reorder particles in memory. The particle tag identifies each particle in the order it existed in the initial configuration.

Type:

(N_particles) hoomd.data.array object of int

rtag#

The particle reverse tags. For a given particle tag tag, i = particles.rtag[tag] is the array index holding that particle.

Type:

(N_particles_global) hoomd.data.array object of int

position#

Particle positions \([\mathrm{length}]\).

Type:

(N_particles, 3) hoomd.data.array object of float

image#

A count of how many times each particle crosses the periodic box boundaries.

Type:

(N_particles, 3) hoomd.data.array object of int

velocity#

Particle velocities \([\mathrm{velocity}]\).

Type:

(N_particles, 3) hoomd.data.array object of float

acceleration#

Particle accelerations \([\mathrm{velocity} \cdot \mathrm{time}^{-1}]\).

Type:

(N_particles, 3) hoomd.data.array object of float

mass#

Particle masses \([\mathrm{mass}]\).

Type:

(N_particles) hoomd.data.array object of float

orientation#

Particle orientations expressed as quaternions.

Type:

(N_particles, 4) hoomd.data.array object of float

angmom#

Particle angular momenta expressed as quaternions \([\mathrm{mass} \cdot \mathrm{velocity} \cdot \mathrm{length}]\).

Type:

(N_particles, 4) hoomd.data.array object of float

moment_inertia#

Particle principal moments of inertia \([\mathrm{mass} \cdot \mathrm{length}^2]\).

Type:

(N_particles, 3) hoomd.data.array object of float

charge#

Particle electrical charges \([\mathrm{charge}]\).

Type:

(N_particles) hoomd.data.array object of float

diameter#

Particle diameters \([\mathrm{length}]\).

Type:

(N_particles) hoomd.data.array object of float

body#

The id of the rigid body the particle is in.

Type:

(N_particles) hoomd.data.array object of int

net_force#

Net force on particle \([\mathrm{force}]\).

Type:

(N_particles, 3) hoomd.data.array object of float

net_torque#

Net torque on particle \([\mathrm{force} \cdot \mathrm{length}]\).

Type:

(N_particles, 3) hoomd.data.array object of float

net_virial#

Net virial on particle \([\mathrm{energy}]\).

Type:

(N_particles, 3) hoomd.data.array object of float

net_energy#

Net energy of a particle \([\mathrm{energy}]\).

Type:

(N_particles,) hoomd.data.array object of float

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

Modules

hoomd.data.array#

Overview

HOOMDArray

A NumPy like interface to internal HOOMD-blue data.

HOOMDGPUArray

Exposes an internal HOOMD-blue GPU buffer.

Details

Implement zero-copy array.

class hoomd.data.array.HOOMDArray(buffer, callback, read_only=None)#

A NumPy 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 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.

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)).

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.

Performance Tips

Assume a represents a HOOMDArray for examples given.

  • 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.

  • If you know that your access of the internal buffer is safe and we cannot detect this (i.e. we return a HOOMDArray), using HOOMDArray._coerce_to_ndarray should help. Note that for large arrays this only gives minimal performance improvements at greater risk of breaking your program.

class hoomd.data.array.HOOMDGPUArray(*args, **kwargs)#

Exposes an internal HOOMD-blue GPU buffer.

The HOOMDGPUArray object exposes a GPU data buffer using the __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:

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.

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. 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 properties except the data and base properties. See CuPy’s documentation for a list of methods.

Tip

Use, cupy.add, cupy.multiply, etc. for binary operations on the GPU.

Note

Packages like Numba and PyTorch can use HOOMDGPUArray without CuPy installed. Any package that supports version 2 of the __cuda_array_interface__ should support the direct use of HOOMDGPUArray objects.

hoomd.device#

Overview

CPU

Select the CPU to execute simulations.

Device

Base class device object.

GPU

Select a GPU or GPU(s) to execute simulations.

NoticeFile

A file-like object that writes to a Device notice stream.

auto_select

Automatically select the hardware device.

Details

Devices.

Use a Device class to choose which hardware device(s) should execute the simulation. Device also sets where to write log messages and how verbose the message output should be. Pass a Device object to hoomd.Simulation on instantiation to set the options for that simulation.

User scripts may instantiate multiple Device objects and use each with a different hoomd.Simulation object. One Device object may also be shared with many hoomd.Simulation objects.

Tip

Reuse Device objects when possible. There is a non-negligible overhead to creating each Device, especially on the GPU.

See also

hoomd.Simulation

class hoomd.device.CPU(num_cpu_threads=None, communicator=None, message_filename=None, notice_level=2)#

Bases: Device

Select the CPU to execute simulations.

Parameters:
  • num_cpu_threads (int) – Number of TBB threads. Set to None to auto-select.

  • communicator (hoomd.communicator.Communicator) – MPI communicator object. When None, create a default communicator that uses all MPI ranks.

  • message_filename (str) – Filename to write messages to. When None, use sys.stdout and sys.stderr. Messages from multiple MPI ranks are collected into this file.

  • notice_level (int) – Minimum level of messages to print.

MPI

In MPI execution environments, create a CPU device on every rank.

class hoomd.device.Device(communicator, notice_level, message_filename)#

Bases: object

Base class device object.

Provides methods and properties common to CPU and GPU, including those that control where status messages are stored (message_filename) how many status messages HOOMD-blue prints (notice_level) and a method for user provided status messages (notice).

Warning

Device cannot be used directly. Instantate a CPU or GPU object.

TBB threads

Set num_cpu_threads to None and TBB will auto-select the number of CPU threads to execute. If the environment variable OMP_NUM_THREADS is set, HOOMD will use this value. You can also set num_cpu_threads explicitly.

Note

At this time very few features use TBB for threading. Most users should employ MPI for parallel simulations. See Features for more information.

property communicator#

The MPI Communicator [read only].

Type:

hoomd.communicator.Communicator

property devices#

Descriptions of the active hardware devices.

Type:

list[str]

property message_filename#

Filename to write messages to.

By default, HOOMD prints all messages and errors to Python’s sys.stdout and sys.stderr (or the system’s stdout and stderr when running in an MPI environment).

Set message_filename to a filename to redirect these messages to that file.

Set message_filename to None to use the system’s stdout and stderr.

Note

All MPI ranks within a given partition must open the same file. To ensure this, the given file name on rank 0 is broadcast to the other ranks. Different partitions may open separate files. For example:

communicator = hoomd.communicator.Communicator(
    ranks_per_partition=2)
filename = f'messages.{communicator.partition}'
device = hoomd.device.GPU(communicator=communicator,
                          message_filename=filename)
Type:

str

notice(message, level=1)#

Write a notice message.

Parameters:
  • message (str) – Message to write.

  • level (int) – Message notice level.

Write the given message string to the output defined by message_filename on MPI rank 0 when notice_level >= level.

Hint

Use notice instead of print to write status messages and your scripts will work well in parallel MPI jobs. notice writes message only on rank 0. Use with a rank-specific message_filename to troubleshoot issues with specific partitions.

property notice_level#

Minimum level of messages to print.

notice_level controls the verbosity of messages printed by HOOMD. The default level of 2 shows messages that the developers expect most users will want to see. Set the level lower to reduce verbosity or as high as 10 to get extremely verbose debugging messages.

Type:

int

property num_cpu_threads#

Number of TBB threads to use.

Type:

int

class hoomd.device.GPU(gpu_ids=None, num_cpu_threads=None, communicator=None, message_filename=None, notice_level=2)#

Bases: Device

Select a GPU or GPU(s) to execute simulations.

Parameters:
  • gpu_ids (list[int]) – List of GPU ids to use. Set to None to let the driver auto-select a GPU.

  • num_cpu_threads (int) – Number of TBB threads. Set to None to auto-select.

  • communicator (hoomd.communicator.Communicator) – MPI communicator object. When None, create a default communicator that uses all MPI ranks.

  • message_filename (str) – Filename to write messages to. When None, use sys.stdout and sys.stderr. Messages from multiple MPI ranks are collected into this file.

  • notice_level (int) – Minimum level of messages to print.

Tip

Call GPU.get_available_devices to get a human readable list of devices. gpu_ids = [0] will select the first device in this list, [1] will select the second, and so on.

The ordering of the devices is determined by the GPU driver and runtime.

Device auto-selection

When gpu_ids is None, HOOMD will ask the GPU driver to auto-select a GPU. In most cases, this will select device 0. When all devices are set to a compute exclusive mode, the driver will choose a free GPU.

MPI

In MPI execution environments, create a GPU device on every rank. When gpu_ids is left None, HOOMD will attempt to detect the MPI local rank environment and choose an appropriate GPU with id = local_rank % num_capable_gpus. Set notice_level to 3 to see status messages from this process. Override this auto-selection by providing appropriate device ids on each rank.

Multiple GPUs

Specify a list of GPUs to gpu_ids to activate a single-process multi-GPU code path.

Note

Not all features are optimized to use this code path, and it requires that all GPUs support concurrent managed memory access and have high bandwidth interconnects.

property compute_capability#

Compute capability of the device.

The tuple includes the major and minor versions of the CUDA compute capability: (major, minor).

Type:

tuple(int, int)

enable_profiling()#

Enable GPU profiling.

When using GPU profiling tools on HOOMD, select the option to disable profiling on start. Initialize and run a simulation long enough that all autotuners have completed, then open enable_profiling() as a context manager and continue the simulation for a time. Profiling stops when the context manager closes.

Example:

with device.enable_profiling():
    sim.run(1000)
static get_available_devices()#

Get the available GPU devices.

Returns:

Descriptions of the available devices (if any).

Return type:

list[str]

static get_unavailable_device_reasons()#

Get messages describing the reasons why devices are unavailable.

Returns:

Messages indicating why some devices are unavailable (if any).

Return type:

list[str]

property gpu_error_checking#

Whether to check for GPU error conditions after every call.

When False (the default), error messages from the GPU may not be noticed immediately. Set to True to increase the accuracy of the GPU error messages at the cost of significantly reduced performance.

Type:

bool

static is_available()#

Test if the GPU device is available.

Returns:

True if this build of HOOMD supports GPUs, False if not.

Return type:

bool

class hoomd.device.NoticeFile(device, level=1)#

Bases: object

A file-like object that writes to a Device notice stream.

Parameters:
  • device (Device) – The Device object.

  • level (int) – Message notice level. Default value is 1.

Note

Use this in combination with Device.message_filename to combine notice messages with output from code that expects file-like objects (such as hoomd.write.Table).

flush()#

Flush the output.

writable()#

Provide file-like API call writable.

write(message)#

Writes data to the associated devices notice stream.

Parameters:

message (str) – Message to write.

hoomd.device.auto_select(communicator=None, message_filename=None, notice_level=2)#

Automatically select the hardware device.

Parameters:
  • communicator (hoomd.communicator.Communicator) – MPI communicator object. When None, create a default communicator that uses all MPI ranks.

  • message_filename (str) – Filename to write messages to. When None, use sys.stdout and sys.stderr. Messages from multiple MPI ranks are collected into this file.

  • notice_level (int) – Minimum level of messages to print.

Returns:

Instance of GPU if availabile, otherwise CPU.

hoomd.error#

Overview

DataAccessError

Raised when data is inaccessible until the simulation is run.

TypeConversionError

Error when converting a parameter.

MutabilityError

Raised when setting an attribute after a simulation has been run.

Details

HOOMD-blue specific error classes.

These classes are subclasses of Python exception types. HOOMD-blue raises these exceptions when documented.

exception hoomd.error.DataAccessError(data_name)#

Bases: RuntimeError

Raised when data is inaccessible until the simulation is run.

__str__()#

Returns the error message.

exception hoomd.error.MutabilityError(attribute_name)#

Bases: AttributeError

Raised when setting an attribute after a simulation has been run.

__str__()#

Returns the error message.

exception hoomd.error.TypeConversionError#

Bases: ValueError

Error when converting a parameter.

hoomd.filter#

Overview

ParticleFilter

Base class for all particle filters.

All

Select all particles in the system.

CustomFilter

Abstract base class for custom particle filters.

Intersection

Set intersection operation.

Null

Select no particles.

Rigid

Select particles based on inclusion in rigid bodies.

SetDifference

Set difference operation.

Tags

Select particles by tag.

Type

Select particles by type.

Union

Set union operation.

filter_like

An object that acts like a particle filter.

Details

Particle filters.

Particle filters describe criteria to select subsets of particles in the system for use by various operations throughout HOOMD. To maintain high performance, filters are not re-evaluated on every use. Instead, each unique particular filter (defined by the class name and hash) is mapped to a group, an internally maintained list of the selected particles. Subsequent uses of the same particle filter specification (in the same hoomd.Simulation) will resolve to the same group and the originally selected particles, even if the state of the system has changed.

Groups are not completely static. HOOMD-blue automatically re-evaluates the filter specifications and updates the group membership whenever the number of particles in the simulation changes. Use hoomd.update.FilterUpdater to manually trigger updates to group membership.

For molecular dynamics simulations, each group maintains a count of the number of degrees of freedom given to the group by integration methods. This count is used by hoomd.md.compute.ThermodynamicQuantities and the integration methods themselves to compute the kinetic temperature. See hoomd.State.update_group_dof for details on when HOOMD-blue updates this count.

class hoomd.filter.ParticleFilter#

Base class for all particle filters.

This class provides methods common to all particle filters.

Attention

Users should instantiate one of the subclasses. Calling ParticleFilter directly may result in an error.

__call__(state)#

Evaluate the filter.

Returns:

The particle tags selected by this filter.

Return type:

list[int]

Note

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.

__eq__(other)#

Test for equality between two particle filters.

__hash__()#

Return a hash of the filter parameters.

__str__()#

Format a human readable string describing the filter.

class hoomd.filter.All#

Select all particles in the system.

Base: ParticleFilter

class hoomd.filter.CustomFilter#

Abstract 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 __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. For more information on the Python data model see https://docs.python.org/3/reference/datamodel.html#object.__hash__ and https://docs.python.org/3/reference/datamodel.html#object.__eq__.

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.

Example:

class MassFilter(hoomd.filter.CustomFilter):
    def __init__(self, min_mass, max_mass):
        self.min_mass = min_mass
        self.max_mass = max_mass

    def __hash__(self):
        return hash((self.min_mass, self.max_mass))

    def __eq__(self, other):
        return (isinstance(other, MassFilter)
                and self.min_mass == other.min_mass
                and self.max_mass == other.max_mass)

    def __call__(self, state):
        with state.cpu_local_snapshot as snap:
            masses = snap.particles.mass
            indices = ((masses > self.min_mass)
                       & (masses < self.max_mass))
            return np.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_)

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.

abstract __call__(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.

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.

Parameters:

state (hoomd.State) – The simulation state to return the filtered tags from.

Returns:

An array of MPI local tags that match the filter.

Return type:

(N,) numpy.ndarray of numpy.uint64

class hoomd.filter.Intersection(f, g)#

Set intersection operation.

Parameters:

Intersection is a composite filter. It selects particles in the set intersection \(f \cap g\).

Base: ParticleFilter

class hoomd.filter.Null#

Select no particles.

Base: ParticleFilter

class hoomd.filter.Rigid(flags=('center',))#

Select particles based on inclusion in rigid bodies.

Parameters:

flags (tuple [str ], optional) – A tuple of strings of values “center”, “constituent”, or “free”. These string flags specify what kinds of particles to filter: “center” will include central particles in a rigid body, “constituent” will include non-central particles in a rigid body, and “free” will include all particles not in a rigid body. Specifying all three is the same as hoomd.filter.All. The default is ("center",)

Base: ParticleFilter

class hoomd.filter.SetDifference(f, g)#

Set difference operation.

Parameters:

SetDifference is a composite filter. It selects particles in the set difference \(f \setminus g\).

Base: ParticleFilter

class hoomd.filter.Tags(tags)#

Select particles by tag.

Parameters:

tags (list[int]) – List of particle tags to select.

A particle tag is a unique identifier assigned to each particle in the simulation state. When the state is first initialized, it assigns tags 0 through N_particles to the particles in the order provided.

Base: ParticleFilter

property tags#

List of particle tags to select.

Type:

list[int]

class hoomd.filter.Type(types)#

Select particles by type.

Parameters:

types (list[str]) – List of particle type names to select.

Base: ParticleFilter

property types#

List of particle type names to select.

Type:

list[str]

class hoomd.filter.Union(f, g)#

Set union operation.

Parameters:

Union is a composite filter. It selects particles in the set union \(f \cup g\).

Base: ParticleFilter

hoomd.filter.filter_like#

An object that acts like a particle filter.

Either a subclass of ParticleFilter or CustomFilter.

alias of Union[ParticleFilter, CustomFilter]

hoomd.logging#

Overview

log

Creates loggable quantities for classes of type Loggable.

modify_namespace

Modify a class's namespace to a manually assigned one.

Logger

Logs HOOMD-blue operation data and custom quantities.

LoggerCategories

Enum that marks all accepted logger types.

Details

Logging infrastructure.

Use the Logger class to collect loggable quantities (e.g. kinetic temperature, pressure, per-particle energy) during the simulation run. Pass the Logger to a backend such as hoomd.write.GSD or hoomd.write.Table to write the logged values to a file.

See also

Tutorial: Logging

Tutorial: Custom Actions in Python

class hoomd.logging.LoggerCategories(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)#

Enum that marks all accepted logger types.

This class does not need to be used by users directly. We directly convert from strings to the enum wherever necessary in the API. This class is documented to show users what types of quantities can be logged, and what categories to use for limiting what data is logged, user specified logged quantities, and custom actions (hoomd.custom.Action).

scalar#

float or int object.

sequence#

Sequence (e.g. list, tuple, numpy.ndarray) of numbers of the same type.

string#

A single Python str object.

strings#

A sequence of Python str objects.

object#

Any Python object outside a sequence, string, or scalar.

angle#

Per-angle quantity.

bond#

Per-bond quantity.

constraint#

Per-constraint quantity.

dihedral#

Per-dihedral quantity.

improper#

Per-improper quantity.

pair#

Per-pair quantity.

particle#

Per-particle quantity.

ALL#

A combination of all other categories.

NONE#

Represents no category.

classmethod any(categories=None)#

Return a LoggerCategories enum representing any of the categories.

Parameters:

categories (list [str ] or list [LoggerCategories]) – A list of str or LoggerCategories objects that should be represented by the returned LoggerCategories object.

Returns:

the LoggerCategories object that represents any of the given categories.

Return type:

LoggerCategories

class hoomd.logging.Logger(categories=None, only_default=True)#

Logs HOOMD-blue operation data and custom quantities.

The Logger class provides an intermediary between a backend such as hoomd.write.GSD or hoomd.write.Table and loggable objects. The Logger class makes use of namespaces which organize logged quantities. For example internally all loggable quantities are ordered by the module and class they come from. For instance, the hoomd.md.pair.LJ class has a namespace ('md', 'pair', 'LJ'). This ensures that logged quantities remain unambiguous. Use add or the += operator to add loggable objects to the Logger.

Example

logger = hoomd.logging.Logger()
lj = md.pair.lj(neighbor_list)
# Log all default quantities of the lj object
logger += lj
logger = hoomd.logging.Logger(categories=['scalar'])
# Log all default scalar quantities of the lj object
logger += lj

The Logger class also supports user specified quantities using namespaces as well.

Example

logger = hoomd.logging.Logger()
# Add quantity to ('custom', 'name') namespace
logger[('custom', 'name')] = (lambda: 42, 'scalar')
# Add quantity to ('custom_name',) namespace
logger[('custom_name',)] = (lambda: 43, 'scalar')

Logger objects support two ways of discriminating what loggable quantities they will accept: categories and only_default (the constructor arguments). Both of these are static, meaning that once instantiated, a Logger object will not change the values of these two properties. categories determines what types of loggable quantities (see LoggerCategories) are appropriate for a given Logger object. This helps logging backends determine if a Logger object is compatible. The only_default flag prevents rarely-used quantities (e.g. the number of neighborlist builds) from being added to the logger when using`Logger.__iadd__` and Logger.add without specifying them explicitly. In Logger.add, you can override the only_default flag by explicitly listing the quantities you want to add. On the other hand, categories is rigidly obeyed as it is a promise to logging backends.

Note

The logger provides a way for users to create their own logger back ends. See log for details on the intermediate representation. LoggerCategories defines the various categories available to specify logged quantities. Custom backends should be a subclass of hoomd.custom.Action and used with hoomd.write.CustomWriter.

Note

When logging multiple instances of the same class add provides a means of specifying the class level of the namespace (e.g. 'LJ in ('md', 'pair', 'LJ')). The default behavior (without specifying a user name) is to just append _{num} where num is the smallest positive integer which makes the full namespace unique. This appending will also occur for user specified names that are reused.

Parameters:
  • categories (list of str, optional) – A list of string categories (list of categories can be found in LoggerCategories). These are the only types of loggable quantities that can be logged by this logger. Defaults to allowing every type.

  • only_default (bool, optional) – Whether to log only quantities that are logged by default. Defaults to True. Non-default quantities are typically measures of operation performance rather than information about simulation state.

__eq__(other)#

Check for equality.

__iadd__(obj)#

Add quantities from object or list of objects to logger.

Adds all quantities compatible with given categories and default value.

Examples

logger += lj
logger += [lj, harmonic_bonds]
__isub__(value)#

Remove log entries for a list of quantities or objects.

Examples

logger -= ('md', 'pair', 'lj')
logger -= [('md', 'pair', 'lj', 'energy'),
           ('md', 'pair', 'lj', 'forces')]
logger -= lj
logger -= [lj, harmonic_bonds]
__setitem__(namespace, value)#

Allows user specified loggable quantities.

Parameters:
  • namespace (tuple[str,] or str) – key or nested key to determine where to store logged quantity.

  • value (tuple[Callable, str] or tuple[object, str, str]) – Either a tuple with a callable and the LoggerCategories object or associated string or a object with a method/property name and category. If using a method it should not take arguments or have defaults for all arguments.

add(obj, quantities=None, user_name=None)#

Add loggables from obj to logger.

Parameters:
  • obj (object of class of type Loggable) – class of type loggable to add loggable quantities from.

  • quantities (Sequence[str]) – list of str names of quantities to log.

  • user_name (str, optional) – A string to replace the class name in the loggable quantities namespace. This allows for easier differentiation in the output of the Logger and any Writer which outputs its data.

Returns:

A list of namespaces added to the logger.

Return type:

list[tuple[str]]

property categories#

The enum representing the acceptable categories for the Logger object.

Type:

LoggerCategories

log()#

Get a nested dictionary of the current values for logged quantities.

The nested dictionary consist of one level for each element of a namespace. The logged value and category for the namespace ('example', 'namespace') would be accessible in the returned dictionary via logger.log()['example']['namespace'].

Returns:

A nested dictionary of the current logged quantities. The end values are (value, category) pairs which hold the value along with its associated LoggerCategories category represented as a string (to get the LoggerCategories enum value use LoggerCategories[category]).

Return type:

dict

property only_default#

Whether the logger object should only grab default loggable quantities.

Type:

bool

remove(obj=None, quantities=None, user_name=None)#

Remove specified quantities from the logger.

Parameters:
  • obj (object of class of type Loggable, optional) – Object to remove quantities from. If quantities is None, obj must be set. If obj is set and quantities is None, all logged quantities from obj will be removed from the logger.

  • quantities (Sequence[tuple]) – a sequence of namespaces to remove from the logger. If specified with obj only remove quantities listed that are exposed from obj. If obj is None, then quantities must be given.

  • user_name (str) – A user name to specify the final entry in the namespace of the object. This must be used in user_name was specified in add.

property string_categories#

A list of the string names of the allowed categories for logging.

Type:

list of str

hoomd.logging.log(func=None, *, is_property=True, category='scalar', default=True, requires_run=False)#

Creates loggable quantities for classes of type Loggable.

Use log with hoomd.custom.Action to expose loggable quantities from a custom action.

Parameters:
  • func (method) – class method to make loggable. If using non-default arguments, func should not be set.

  • is_property (bool, optional) – Whether to make the method a property, defaults to True. Keyword only argument.

  • category (str, optional) – The string represention of the type of loggable quantity, defaults to ‘scalar’. See LoggerCategories for available types. Keyword only argument.

  • default (bool, optional) – Whether the quantity should be logged by default. Defaults to True. This is orthogonal to the loggable quantity’s type. Many users may not want to log such quantities even when logging other quantities of that type. An example would be performance orientated loggable quantities, like the number of neighborlist builds. The default argument allows for these to be skipped by Logger objects by default. Keyword only argument.

  • requires_run (bool, optional) – Whether this property requires the simulation to run before being accessible.

Note

The namespace (where the loggable object is stored in the Logger object’s nested dictionary) is determined by the module/script and class name the loggable class comes from. In creating subclasses of hoomd.custom.Action, for instance, if the module the subclass is defined in is user.custom.action and the class name is Foo then the namespace used will be ('user', 'custom', 'action', 'Foo'). This helps to prevent naming conflicts and automates the logging specification for developers and users.

Example:

# Metaclass specification is not necessary for
# subclasses of HOOMD classes as they already use this
# metaclass.
class LogExample(metaclass=hoomd.logging.Loggable)
    @log(category="string")
    def loggable(self):
        return "log_me"

    @log(is_property=False, default=False)
    def not_property(self, a=4):
        return 2 ** a

See also

Tutorial: Custom Actions in Python

hoomd.logging.modify_namespace(cls, namespace=None)#

Modify a class’s namespace to a manually assigned one.

Parameters:
  • cls (type or tuple[str]) – The class to modify the namespace of or the namespace itself. When passing a namespace (a tuple of strings), the function can be used as a decorator.

  • namespace (tuple [str ], optional) – The namespace to change the class’s namespace to.

Warning

This will only persist for the current class. All subclasses will have the standard namespace assignment.

hoomd.mesh#

Overview

Mesh

Data structure combining multiple particles into a mesh.

Details

Triangulated mesh data structure.

The mesh data structure combines particles into a connected triangulated network. The particles act as vertices of the triangulation and are linked with their neighbors in both pairs via mesh bonds and triplets via mesh triangles.

Mesh triangles and mesh bonds

Mesh.triangles is a list of triangle data that constitutes the triangulation. Each triangle is defined by a triplet of particle tags. For a given triangulation HOOMD-blue also constructs a list of mesh bonds automatically. Each mesh bond is defined by a pair of particle tags. The corresponding vertex particles share a common edge in the triangulation.

Mesh potentials

In MD simulations different bond potentials can be attached which connect the vertex particles with a bond potential. The mesh data structure is designed so that other potentials (like bending potentials or global conservation potentials) can be implemented later.

See also

See the documentation in hoomd.md.mesh for more information on how to apply potentials to the mesh object and in hoomd.md.nlist on adding mesh bond exceptions to the neighbor list.

class hoomd.mesh.Mesh#

Data structure combining multiple particles into a mesh.

The mesh is defined by an array of triangles that make up a triangulated surface of particles. Each triangle consists of three particle tags. The mesh object consists of only one mesh triangle type with the default type name “mesh”.

Examples:

mesh_obj = mesh.Mesh()
mesh_obj.types = ["mesh"]
mesh_obj.triangulation = dict(type_ids = [0,0,0,0],
      triangles = [[0,1,2],[0,2,3],[0,1,3],[1,2,3]])
property bonds#

Mesh bonds.

A list of tuples of particle ids which encodes the bonds within the mesh structure.

(Loggable: category=”sequence”)

Type:

((N, 2) numpy.ndarray of uint32)

property size#

Number of triangles in the mesh.

Type:

(int)

property triangles#

Mesh triangulation.

A list of triplets of particle tags which encodes the triangulation of the mesh structure.

(Loggable: category=”sequence”)

Type:

((N, 3) numpy.ndarray of uint32)

property type_ids#

Triangle type ids.

(Loggable: category=”sequence”)

Type:

((N) numpy.ndarray of uint32)

hoomd.operation#

Overview

AutotunedObject

An object with autotuned kernel parameters.

Compute

Compute properties of the simulation's state.

Integrator

Advance the simulation state forward one time step.

Operation

Represents an operation.

Tuner

Adjust the parameters of other operations to improve performance.

TriggeredOperation

Operations that include a trigger to determine when to run.

Updater

Change the simulation's state.

Writer

Write output that depends on the simulation's state.

Details

Operation class types.

Operations act on the state of the system at defined points during the simulation’s run loop. Add operation objects to the Simulation.operations collection.

class hoomd.operation.Operation#

Represents an operation.

Operations in the HOOMD-blue data scheme are objects that operate on a hoomd.Simulation object. They broadly consist of 5 subclasses: Updater, Writer, Compute, Tuner, and Integrator. All HOOMD-blue operations inherit from one of these five base classes. To find the purpose of each class see its documentation.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

Note

Developers or those contributing to HOOMD-blue, see our architecture file for information on HOOMD-blue’s architecture decisions regarding operations.

__dir__()#

Expose all attributes for dynamic querying in notebooks and IDEs.

property is_tuning_complete#

Check if kernel parameter tuning is complete.

True when tuning is complete and kernel_parameters has locked optimal parameters for all active kernels used by this object.

Type:

bool

property kernel_parameters#

Kernel parameters.

The dictionary maps GPU kernel names to tuples of integers that control how the kernel executes on the GPU. These values will change during the tuning process and remain static after tuning completes. Set the kernel parameters for one or more kernels to force specific values and stop tuning.

Warning

The keys and valid values in this dictionary depend on the hardware device, the HOOMD-blue version, and the value of class attributes. Keys and/or valid values may change even with new patch releases of HOOMD-blue.

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.

Type:

dict[str, tuple[float]]

property loggables#

Name, category mapping of loggable quantities.

Type:

dict[str, str]

tune_kernel_parameters()#

Start tuning kernel parameters.

After calling tune_kernel_parameters, AutotunedObject will vary the kernel parameters in subsequent time steps, check the run time of each, and lock to the fastest performing parameters after the scan is complete.

class hoomd.operation.AutotunedObject#

Bases:

An object with autotuned kernel parameters.

AutotunedObject instances may complete portions of their computation with one or more GPU kernels. Each GPU kernel is executed with a set of parameters (kernel_parameters) that influence the run time of the execution. After initialization, AutotunedObject varies these parameters as the simulation runs and searches for the best performing combination. The optimal parameters depend on your system’s size, density, force field parameters, the specific hardware you execute on, and more.

Check is_tuning_complete to check if the search is complete. After the search is complete, AutotunedObject holds the parameters constant at the optimal values. Typical operations require thousands of time steps to complete tuning. Some may take tens of thousands or more depending on the parameters you set.

Tip

When you significantly change your system during the simulation (e.g. compress to a higher density), then you can tune the parameters again after with tune_kernel_parameters. This step is optional, but may increase performance as the new system parameters may lead to different optimal parameters.

Note

In MPI parallel execution, all methods and attributes of AutotunedObject reference the rank local tuner objects. Different ranks may tune different optimal kernel parameters and may complete tuning at different times. Use only hoomd.Operations.is_tuning_complete in control flow operations, as this method is reduced across all ranks.

property is_tuning_complete#

Check if kernel parameter tuning is complete.

True when tuning is complete and kernel_parameters has locked optimal parameters for all active kernels used by this object.

Type:

bool

property kernel_parameters#

Kernel parameters.

The dictionary maps GPU kernel names to tuples of integers that control how the kernel executes on the GPU. These values will change during the tuning process and remain static after tuning completes. Set the kernel parameters for one or more kernels to force specific values and stop tuning.

Warning

The keys and valid values in this dictionary depend on the hardware device, the HOOMD-blue version, and the value of class attributes. Keys and/or valid values may change even with new patch releases of HOOMD-blue.

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.

Type:

dict[str, tuple[float]]

tune_kernel_parameters()#

Start tuning kernel parameters.

After calling tune_kernel_parameters, AutotunedObject will vary the kernel parameters in subsequent time steps, check the run time of each, and lock to the fastest performing parameters after the scan is complete.

class hoomd.operation.Compute#

Bases: Operation

Compute properties of the simulation’s state.

A compute is an operation which computes some property for another operation or use by a user.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.operation.Integrator#

Bases: Operation

Advance the simulation state forward one time step.

An integrator is the operation which evolves a simulation’s state in time. In hoomd.hpmc, integrators perform particle based Monte Carlo moves. In hoomd.md, the hoomd.md.Integrator class organizes the forces, equations of motion, and other factors of the given simulation.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.operation.TriggeredOperation(trigger)#

Bases: Operation

Operations that include a trigger to determine when to run.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.operation.Tuner(trigger)#

Bases: TriggeredOperation

Adjust the parameters of other operations to improve performance.

A tuner is an operation which tunes the parameters of another operation for performance or other reasons. A tuner does not modify the current microstate of the simulation. That is a tuner does not change quantities like temperature, particle position, or the number of bonds in a simulation.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.operation.Updater(trigger)#

Bases: TriggeredOperation

Change the simulation’s state.

An updater is an operation which modifies a simulation’s state.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.operation.Writer(trigger)#

Bases: TriggeredOperation

Write output that depends on the simulation’s state.

A writer is an operation which writes out a simulation’s state.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

hoomd.trigger#

Overview

After

Trigger on all steps after a given step.

And

Boolean and operation.

Before

Trigger on all steps before a given step.

Not

Negate a trigger.

On

Trigger on a specific timestep.

Or

Boolean or operation.

Periodic

Trigger periodically.

Trigger

Base class trigger.

trigger_like

An object that can serve as a trigger for an operation.

Details

Triggers determine when hoomd.operation.Operation instances activate.

A Trigger is a boolean valued function of the timestep. The operation will perform its action when Trigger returns True. A single trigger object may be assigned to multiple operations.

User defined triggers

You can define your own triggers by subclassing Trigger in Python. When you do so, override the Trigger.compute method and explicitly call the base class constructor in __init__.

Example

Define a custom trigger:

class CustomTrigger(hoomd.trigger.Trigger):

    def __init__(self):
        hoomd.trigger.Trigger.__init__(self)

    def compute(self, timestep):
        return (timestep**(1 / 2)).is_integer()
class hoomd.trigger.After(timestep)#

Bases: Trigger

Trigger on all steps after a given step.

Parameters:

timestep (int) – The step before the trigger will start.

After returns True for all time steps greater than timestep:

return t > timestep

Example:

# trigger every 100 time steps after 1000 time steps.
trigger = hoomd.trigger.And([
        hoomd.trigger.After(1000),
        hoomd.trigger.Periodic(100)])
timestep#

The step before the trigger will start.

Type:

int

class hoomd.trigger.And(triggers)#

Bases: Trigger

Boolean and operation.

Parameters:

triggers (list [Trigger]) – List of triggers.

And returns True when all the input triggers returns True:

return all([f(t) for f in triggers])

Example:

# trigger every 100 time steps after 1000 time steps.
trig = hoomd.trigger.And([
        hoomd.trigger.After(1000),
        hoomd.trigger.Periodic(100)])
triggers#

List of triggers.

Type:

list[hoomd.trigger.Trigger]

class hoomd.trigger.Before(timestep)#

Bases: Trigger

Trigger on all steps before a given step.

Parameters:

timestep (int) – The step after the trigger ends.

Before evaluates True for all time steps less than the timestep:

return t < timestep

Example:

# trigger every 100 time steps at less than first 5000 steps.
trigger = hoomd.trigger.And(
    [hoomd.trigger.Periodic(100),
    hoomd.trigger.Before(sim.timestep + 5000)])
timestep#

The step after the trigger ends.

Type:

int

class hoomd.trigger.Not(trigger)#

Bases: Trigger

Negate a trigger.

Parameters:

trigger (hoomd.trigger.Trigger) – The trigger object to negate.

Not returns the boolean negation of trigger:

return not trigger(t)

Example:

trigger = hoomd.trigger.Not(hoomd.trigger.After(1000))
trigger#

The trigger object to negate.

Type:

hoomd.trigger.Trigger

class hoomd.trigger.On(timestep)#

Bases: Trigger

Trigger on a specific timestep.

Parameters:

timestep (int) – The timestep to trigger on.

On returns True for steps equal to timestep:

return t == timestep

Example:

# trigger at 1000 time steps
trigger = hoomd.trigger.On(1000)
timestep#

The timestep to trigger on.

Type:

int

class hoomd.trigger.Or(triggers)#

Bases: Trigger

Boolean or operation.

Parameters:

triggers (list [Trigger]) – List of triggers.

Or returns True when any of the input triggers returns True:

return any([f(t) for f in triggers])

Example:

# trigger every 100 time steps before at time step of 1000.
# or      every 10  time steps after  at time step of 1000.
trig = hoomd.trigger.Or([hoomd.trigger.And([
                            hoomd.trigger.Before(1000),
                            hoomd.trigger.Periodic(100)]),
                        [hoomd.trigger.And([
                            hoomd.trigger.After(1000),
                            hoomd.trigger.Periodic(10)])
                        ])
triggers#

List of triggers.

Type:

list [Trigger]

class hoomd.trigger.Periodic(period, phase)#

Bases: Trigger

Trigger periodically.

Parameters:
  • period (int) – timesteps for periodicity

  • phase (int) – timesteps for phase

Periodic evaluates True every period steps offset by phase:

return (t - phase) % period == 0

Example:

trig = hoomd.trigger.Periodic(100)
period#

periodicity in time step.

Type:

int

phase#

phase in time step.

Type:

int

class hoomd.trigger.Trigger#

Base class trigger.

Provides methods common to all triggers.

Attention

Users should instantiate the subclasses, using Trigger directly will result in an error.

__call__(timestep)#

Evaluate the trigger.

Parameters:

timestep (int) – The timestep.

Note

When called several times with the same timestep, __call__ calls compute on the first invocation, caches the value, and returns that cached value in subsequent calls.

Returns:

True when the trigger is active, False when it is not.

Return type:

bool

compute(timestep)#

Evaluate the trigger.

Parameters:

timestep (int) – The timestep.

Returns:

True when the trigger is active, False when it is not.

Return type:

bool

hoomd.trigger.trigger_like#

An object that can serve as a trigger for an operation.

Any instance of a Trigger subclass is allowed, as well as an int instance or any object convertible to an int. The integer is converted to a Periodic trigger via Periodic(period=int(a)) where a is the passed integer.

Note

Attributes that are Trigger objects can be set via a trigger_like object.

alias of Union[Trigger, int]

hoomd.tune#

Overview

CustomTuner

User-defined tuner.

GradientDescent

Solves equations of \(min_x f(x)\) using gradient descent.

GridOptimizer

Optimize by consistently narrowing the range where the extrema is.

LoadBalancer

Adjusts the boundaries of the domain decomposition.

ManualTuneDefinition

Class for defining y = f(x) relationships for tuning x for a set y target.

Optimizer

Abstract base class for optimizing \(f(x)\).

ParticleSorter

Order particles in memory to improve performance.

RootSolver

Abstract base class for finding x such that \(f(x) = 0\).

ScaleSolver

Solves equations of f(x) = y using a ratio of y with the target.

SecantSolver

Solves equations of f(x) = y using the secant method.

SolverStep

Abstract base class various solver types.

Details

Tuners.

Tuner operations make changes to the parameters of other operations (or the simulation state) that adjust the performance of the simulation without changing the correctness of the outcome. Every new hoomd.Simulation object includes a ParticleSorter in its operations by default. ParticleSorter rearranges the order of particles in memory to improve cache-coherency.

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

Most tuners explicitly involve solving some sort of mathematical problem (e.g. root-finding or optimizationr). 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 iterative solving given a simulation where calls to the “function” being solves means running potentially 1,000’s of steps.

Every solver regardless of type has a solve method which accepts a list of tunable quantities. The method returns a Boolean indicating whether all quantities are considered tuned or not. Tuners indicate they are tuned when two successive calls to SolverStep.solve return True unless otherwise documented.

Custom solvers can be created from inheriting from the base class of one of the problem types (RootSolver and Optimizer) or SolverStep if solving a different problem type. All that is required is to implement the SolverStep.solve_one method, and the solver can be used by any HOOMD tuner that expects a solver.

Custom Tuners

Through using SolverStep subclasses and ManualTuneDefinition most tuning problems should be solvable for a CustomTuner. To create a tuner define all ManualTuneDefinition interfaces for each tunable and plug into a solver in a CustomTuner.

class hoomd.tune.ManualTuneDefinition(get_y, target, get_x, set_x, domain=None)#

Class for defining y = f(x) relationships for tuning x for a set y target.

This class is made to be used with hoomd.tune.SolverStep subclasses. Here y represents a dependent variable of x. In general, x and y should be of type float, but specific hoomd.tune.SolverStep subclasses may accept other types.

A special case for the return type of y is None. If the value is currently inaccessible or would be invalid, a ManualTuneDefinition object can return a y of None to indicate this. hoomd.tune.SolverStep objects will handle this automatically. Since we check for None internally in hoomd.tune.SolverStep objects, a ManualTuneDefinition object’s y property should be consistant when called multiple times within a timestep.

When setting x the value is clamped between the given domain via,

\[\begin{split}x &= x_{max}, \text{ if } x_n > x_{max},\\ x &= x_{min}, \text{ if } x_n < x_{min},\\ x &= x_n, \text{ otherwise}\end{split}\]
Parameters:
  • get_y (callable) – A callable that gets the current value for y.

  • target (any) – The target y value to approach.

  • get_x (callable) – A callable that gets the current value for x.

  • set_x (callable) – A callable that sets the current value for x.

  • domain (tuple [any, any], optional) – A tuple pair of the minimum and maximum accepted values of x, defaults to None. When, the domain is None then any value of x is accepted. Either the minimum or maximum can be set to None as well which means there is no maximum or minimum. The domain is used to wrap values within the specified domain when setting x.

Note

Placing domain restrictions on x can lead to the target y value being impossible to converge to. This will lead to the hoomd.tune.SolverStep object passed this tunable to never finish solving regardless if all other ManualTuneDefinition objects are converged.

__eq__(other)#

Test for equality.

__hash__()#

Compute a hash of the tune definition.

clamp_into_domain(value)#

Return the closest value within the domain.

Parameters:

value (any) – A value of the same type as x.

Returns:

The value clamps within the domains of x. Clamping here refers to returning the value or minimum or maximum of the domain if value is outside the domain.

property domain#

A tuple pair of the minimum and maximum accepted values of x.

When the domain is None, any value of x is accepted. Either the minimum or maximum can be set to None as well which means there is no maximum or minimum. The domain is used to wrap values within the specified domain when setting x.

Type:

tuple[any, any]

in_domain(value)#

Check whether a value is in the domain.

Parameters:

value (any) – A value that can be compared to the minimum and maximum of the domain.

Returns:

Whether the value is in the domain of x.

Return type:

bool

property max_x#

Maximum allowed x value.

property min_x#

Minimum allowed y value.

property target#

The targetted y value, can be set.

property x#

The dependent variable.

Can be set. When set the setting value is clamped within the provided domain. See clamp_into_domain for further explanation.

property y#

The independent variable, and is unsettable.

class hoomd.tune.CustomTuner(trigger, action)#

Bases: CustomOperation, Tuner

User-defined tuner.

Parameters:

CustomTuner is a hoomd.operation.Tuner that wraps a user-defined hoomd.custom.Action object so the action can be added to a hoomd.Operations instance for use with hoomd.Simulation objects.

Tuners modify the parameters of other operations to improve performance. Tuners may read the system state, but not modify it.

class hoomd.tune.GradientDescent(alpha: float = 0.1, kappa: ndarray | None = None, tol: float = 1e-05, maximize: bool = True, max_delta: float | None = None)#

Bases: Optimizer

Solves equations of \(min_x f(x)\) using gradient descent.

Derivatives are computed using the forward difference.

The solver updates x each step via,

\[x_n = x_{n-1} - \alpha {\left (1 - \kappa) \nabla f + \kappa \Delta_{n-1} \right)}\]

where \(\Delta\) is the last step size. This gives the optimizer a sense of momentum which for noisy (stochastic) optimization can lead to smoother optimization. Due to the need for two values to compute a derivative, then first time this is called it makes a slight jump higher or lower to start the method.

The solver will stop updating when a maximum is detected (i.e. the step size is smaller than tol).

Parameters:
  • alpha (hoomd.variant.variant_like, optional) – Either a number between 0 and 1 used to dampen the rate of change in x or a variant that varies not by timestep but by the number of times solve has been called (i.e. the number of steps taken) (defaults to 0.1). alpha scales the corrections to x each iteration. Larger values of alpha lead to larger changes while a alpha of 0 leads to no change in x at all.

  • kappa (numpy.ndarray, optional) – Real number array that determines how much of the previous steps’ directions to use (defaults to None which does no averaging over past step directions). The array values correspond to weight that the \(N\) last steps are weighted when combined with the current step. The current step is weighted by \(1 - \sum_{i=1}^{N} \kappa_i\).

  • tol (float, optional) – The absolute tolerance for convergence of y, (defaults to 1e-5).

  • maximize (bool, optional) – Whether or not to maximize function (defaults to True).

  • max_delta (float, optional) – The maximum step size to allow (defaults to None which allows a step size of any length).

kappa#

Real number array that determines how much of the previous steps’ directions to use. The array values correspond to weight that the \(N\) last steps are weighted when combined with the current step. The current step is weighted by \(1 - \sum_{i=1}^{N} \kappa_i\).

Type:

numpy.ndarray

tol#

The absolute tolerance for convergence of y.

Type:

float

maximize#

Whether or not to maximize function.

Type:

bool

max_delta#

The maximum step size to allow.

Type:

float

__eq__(other)#

Test for equality.

property alpha#

Number between 0 and 1 that dampens of change in x.

Larger values of alpha lead to larger changes while a alpha of 0 leads to no change in x at all. The property returns the current alpha given the current number of steps.

The property can be set as in the constructor.

Type:

float

reset()#

Reset all solving internals.

solve(tunables)#

Iterates towards a solution for a list of tunables.

If a y for one of the tunables is None then we skip that tunable. Skipping implies that the quantity is not tuned and solve will return False.

Parameters:

tunables (list[hoomd.tune.ManualTuneDefinition]) – A list of tunable objects that represent a relationship f(x) = y.

Returns:

Returns whether or not all tunables were considered tuned by the object.

Return type:

bool

solve_one(tunable)#

Solve one step.

class hoomd.tune.GridOptimizer(n_bins: int = 5, n_rounds: int = 1, maximize: bool = True)#

Bases: Optimizer

Optimize by consistently narrowing the range where the extrema is.

The algorithm is as follows. Given a domain \(d = [a, b]\), \(d\) is broken up into n_bins subsequent bins. For the next n_bins calls, the optimizer tests the function value at each bin center. The next call does one of two things. If the number of rounds has reached n_rounds the optimization is done, and the center of the best bin is the solution. Otherwise, another round is performed where the bin’s extent is the new domain.

Warning

Changing a tunables domain during usage of a GridOptimizer results in incorrect behavior.

Parameters:
  • n_bins (int, optional) – The number of bins in the range to test (defaults to 5).

  • n_rounds (int, optional) – The number of rounds to perform the optimization over (defaults to 1).

  • maximize (bool, optional) – Whether to maximize or minimize the function (defaults to True).

__eq__(other)#

Test for equality.

reset()#

Reset all solving internals.

solve_one(tunable)#

Perform one step of optimization protocol.

class hoomd.tune.LoadBalancer(trigger, x=True, y=True, z=True, tolerance=1.02, max_iterations=1)#

Bases: Tuner

Adjusts the boundaries of the domain decomposition.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Select the timesteps on which to perform load balancing.

  • x (bool) – Balance the x direction when True.

  • y (bool) – Balance the y direction when True.

  • z (bool) – Balance the z direction when True.

  • tolerance (float) – Load imbalance tolerance.

  • max_iterations (int) – Maximum number of iterations to attempt in a single step.

LoadBalancer adjusts the boundaries of the MPI domains to distribute the particle load close to evenly between them. The load imbalance is defined as the number of particles owned by a rank divided by the average number of particles per rank if the particles had a uniform distribution:

\[I = \frac{N_i}{N / P}\]

where \(N_i\) is the number of particles on rank \(i\), \(N\) is the total number of particles, and \(P\) is the number of ranks.

In order to adjust the load imbalance, LoadBalancer scales by the inverse of the imbalance factor. To reduce oscillations and communication overhead, it does not move a domain more than 5% of its current size in a single rebalancing step, and not more than half the distance to its neighbors.

Simulations with interfaces (so that there is a particle density gradient) or clustering should benefit from load balancing. The potential speedup is \(I-1.0\), so that if the largest imbalance is 1.4, then the user can expect a 40% speedup in the simulation. This is of course an estimate that assumes that all algorithms are linear in \(N\), all GPUs are fully occupied, and the simulation is limited by the speed of the slowest processor. If you have a simulation where, for example, some particles have significantly more pair force neighbors than others, this estimate of the load imbalance may not produce the optimal results.

A load balancing adjustment is only performed when the maximum load imbalance exceeds a tolerance. The ideal load balance is 1.0, so setting tolerance less than 1.0 will force an adjustment every update. The load balancer can attempt multiple iterations of balancing on each update, and up to maxiter attempts can be made. The optimal values of update and maxiter will depend on your simulation.

Load balancing can be performed independently and sequentially for each dimension of the simulation box. A small performance increase may be obtained by disabling load balancing along dimensions that are known to be homogeneous. For example, if there is a planar vapor-liquid interface normal to the \(z\) axis, then it may be advantageous to disable balancing along \(x\) and \(y\).

In systems that are well-behaved, there is minimal overhead of balancing with a small update. However, if the system is not capable of being balanced (for example, due to the density distribution or minimum domain size), having a small update and high maxiter may lead to a large performance loss. In such systems, it is currently best to either balance infrequently or to balance once in a short test run and then set the decomposition statically in a separate initialization.

Balancing is ignored if there is no domain decomposition available (MPI is not built or is running on a single rank).

trigger#

Select the timesteps on which to perform load balancing.

Type:

hoomd.trigger.Trigger

x#

Balance the x direction when True.

Type:

bool

y#

Balance the y direction when True.

Type:

bool

z#

Balance the z direction when True.

Type:

bool

tolerance#

Load imbalance tolerance.

Type:

float

max_iterations#

Maximum number of iterations to attempt in a single step.

Type:

int

class hoomd.tune.Optimizer#

Bases: SolverStep

Abstract base class for optimizing \(f(x)\).

class hoomd.tune.ParticleSorter(trigger=200, grid=None)#

Bases: Tuner

Order particles in memory to improve performance.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Select the timesteps on which to sort. Defaults to a hoomd.trigger.Periodic(200) trigger.

  • grid (int) – Resolution of the grid to use when sorting. The default value of None sets grid=4096 in 2D simulations and grid=256 in 3D simulations.

ParticleSorter improves simulation performance by sorting the particles in memory along a space-filling curve. This takes particles that are close in space and places them close in memory, leading to a higher rate of cache hits when computing pair potentials.

Note

New hoomd.Operations instances include a ParticleSorter constructed with default parameters.

trigger#

Select the timesteps on which to sort.

Type:

hoomd.trigger.Trigger

grid#

Set the resolution of the space-filling curve. grid rounds up to the nearest power of 2 when set. Larger values of grid provide more accurate space-filling curves, but consume more memory (grid**D * 4 bytes, where D is the dimensionality of the system).

Type:

int

class hoomd.tune.RootSolver#

Bases: SolverStep

Abstract base class for finding x such that \(f(x) = 0\).

For solving for a non-zero value, \(f(x) - y_t = 0\) is solved.

class hoomd.tune.ScaleSolver(max_scale=2.0, gamma=2.0, correlation='positive', tol=1e-05)#

Bases: RootSolver

Solves equations of f(x) = y using a ratio of y with the target.

Each time this solver is called it takes updates according to the following equation if the correlation is positive:

\[x_n = \min{\left(\frac{\gamma + t}{y + \gamma}, s_{max}\right)} \cdot x\]

and

\[x_n = \min{\left(\frac{y + \gamma}{\gamma + t}, s_{max}\right)} \cdot x\]

if the correlation is negative, where \(t\) is the target and \(x_n\) is the new x.

The solver will stop updating when \(\lvert y - t \rvert \le tol\).

Parameters:
  • max_scale (float, optional) – The maximum amount to scale the current x value with, defaults to 2.0.

  • gamma (float, optional) – nonnegative real number used to dampen or increase the rate of change in x. gamma is added to the numerator and denominator of the y / target ratio. Larger values of gamma lead to smaller changes while a gamma of 0 leads to scaling x by exactly the y / target ratio.

  • correlation (str, optional) – Defines whether the relationship between x and y is of a positive or negative correlation, defaults to ‘positive’. This determines which direction to scale x in for a given y.

  • tol (float, optional) – The absolute tolerance for convergence of y, defaults to 1e-5.

Note

This solver is only usable when quantities are strictly positive.

__eq__(other)#

Test for equality.

reset()#

Reset all solving internals.

solve_one(tunable)#

Solve one step.

class hoomd.tune.SecantSolver(gamma=0.9, tol=1e-05)#

Bases: RootSolver

Solves equations of f(x) = y using the secant method.

The solver updates x each step via,

\[x_n = x - \gamma \cdot (y - t) \cdot \frac{x - x_{o}}{y - y_{old}}\]

where \(o\) represent the old values, \(n\) the new, and \(t\) the target. Due to the need for a previous value, then first time this is called it makes a slight jump higher or lower to start the method.

The solver will stop updating when \(\lvert y - t \rvert \le tol\).

Parameters:
  • gamma (float, optional) – real number between 0 and 1 used to dampen the rate of change in x. gamma scales the corrections to x each iteration. Larger values of gamma lead to larger changes while a gamma of 0 leads to no change in x at all.

  • tol (float, optional) – The absolute tolerance for convergence of y, defaults to 1e-5.

Note

Tempering the solver with a smaller than 1 gamma value is crucial for numeric stability. If instability is found, then lowering gamma accordingly should help.

__eq__(other)#

Test for equality.

reset()#

Reset all solving internals.

solve_one(tunable)#

Solve one step.

class hoomd.tune.SolverStep#

Bases: object

Abstract base class various solver types.

Requires a single method solve_one that steps forward one iteration in solving the given variable relationship. Users can use subclasses of this with hoomd.tune.ManualTuneDefinition to tune attributes with a functional relation.

Note

A SolverStep object requires manual iteration to converge. This is to support the use case of measuring quantities that require running the simulation for some amount of time after one iteration before remeasuring the dependent variable (i.e. the y). SolverStep object can be used in hoomd.custom.Action subclasses for user defined tuners and updaters.

abstract reset()#

Reset all solving internals.

This should put the solver in its initial state as if it has not seen any tunables or done any solving yet.

solve(tunables)#

Iterates towards a solution for a list of tunables.

If a y for one of the tunables is None then we skip that tunable. Skipping implies that the quantity is not tuned and solve will return False.

Parameters:

tunables (list[hoomd.tune.ManualTuneDefinition]) – A list of tunable objects that represent a relationship f(x) = y.

Returns:

Returns whether or not all tunables were considered tuned by the object.

Return type:

bool

abstract solve_one(tunable)#

Takes in a tunable object and attempts to solve x for a specified y.

Parameters:

tunable (hoomd.tune.ManualTuneDefinition) – A tunable object that represents a relationship of f(x) = y.

Returns:

Whether or not the tunable converged to the target.

Return type:

bool

hoomd.update#

Overview

BoxResize

Resizes the box between an initial and final box.

CustomUpdater

User-defined updater.

FilterUpdater

Update sets of particles associated with a filter.

RemoveDrift

Remove the average drift from a restrained system.

Details

Updaters.

Updater operations modify the simulation state when they act.

class hoomd.update.BoxResize(trigger, box1, box2, variant, filter=hoomd._hoomd.ParticleFilter)#

Bases: Updater

Resizes the box between an initial and final box.

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 the maximum gives box2:

\[\begin{split}\begin{align*} L_{x}' &= \lambda L_{2x} + (1 - \lambda) L_{1x} \\ L_{y}' &= \lambda L_{2y} + (1 - \lambda) L_{1y} \\ L_{z}' &= \lambda L_{2z} + (1 - \lambda) L_{1z} \\ xy' &= \lambda xy_{2} + (1 - \lambda) xy_{1} \\ xz' &= \lambda xz_{2} + (1 - \lambda) xz_{1} \\ yz' &= \lambda yz_{2} + (1 - \lambda) yz_{1} \\ \end{align*}\end{split}\]

Where box1 is \((L_{1x}, L_{1y}, L_{1z}, xy_1, xz_1, yz_1)\), box2 is \((L_{2x}, L_{2y}, L_{2z}, xy_2, xz_2, yz_2)\), \(\lambda = \frac{f(t) - \min f}{\max f - \min f}\), \(t\) is the timestep, and \(f(t)\) is given by variant.

For each particle \(i\) matched by filter, BoxResize scales the particle to fit in the new box:

\[\vec{r}_i \leftarrow s_x \vec{a}_1' + s_y \vec{a}_2' + s_z \vec{a}_3' - \frac{\vec{a}_1' + \vec{a}_2' + \vec{a}_3'}{2}\]

where \(\vec{a}_k'\) are the new box vectors determined by \((L_x', L_y', L_z', xy', xz', yz')\) and the scale factors are determined by the current particle position \(\vec{r}_i\) and the old box vectors \(\vec{a}_k\):

\[\vec{r}_i = s_x \vec{a}_1 + s_y \vec{a}_2 + s_z \vec{a}_3 - \frac{\vec{a}_1 + \vec{a}_2 + \vec{a}_3}{2}\]

After scaling particles that match the filter, BoxResize wraps all particles \(j\) back into the new box:

\[\vec{r_j} \leftarrow \mathrm{minimum\_image}_{\vec{a}_k}' (\vec{r}_j)\]

Important

The passed Variant must be bounded on the interval \(t \in [0,\infty)\) or the behavior of the updater is undefined.

Warning

Rescaling particles fails in HPMC simulations with more than one MPI rank.

Note

When using rigid bodies, ensure that the BoxResize updater is last in the operations updater list. Immediately after the BoxResize updater triggers, rigid bodies (hoomd.md.constrain.Rigid) will be temporarily deformed. hoomd.md.Integrator will run after the last updater and resets the constituent particle positions before computing forces.

Parameters:
box1#

The box associated with the minimum of the passed variant.

Type:

hoomd.Box

box2#

The box associated with the maximum of the passed variant.

Type:

hoomd.Box

variant#

A variant used to interpolate between the two boxes.

Type:

hoomd.variant.Variant

trigger#

The trigger to activate this updater.

Type:

hoomd.trigger.Trigger

filter#

The subset of particles to update.

Type:

hoomd.filter.filter_like

get_box(timestep)#

Get the box for a given timestep.

Parameters:

timestep (int) – The timestep to use for determining the resized box.

Returns:

The box used at the given timestep. None before the first call to Simulation.run.

Return type:

Box

static update(state, box, filter=hoomd._hoomd.ParticleFilter)#

Immediately scale the particle in the system state to the given box.

Parameters:
class hoomd.update.CustomUpdater(trigger, action)#

Bases: CustomOperation, Updater

User-defined updater.

Parameters:

CustomUpdater is a hoomd.operation.Updater that wraps a user-defined hoomd.custom.Action object so the action can be added to a hoomd.Operations instance for use with hoomd.Simulation objects.

Updaters modify the system state.

class hoomd.update.FilterUpdater(trigger, filters)#

Bases: Updater

Update sets of particles associated with a filter.

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 static until recomputed. This class provides a mechanism to update the cached list of particles. For example, periodically update a MD integration method’s group so that the integration method applies to particles in a given region of space.

Tip

To improve performance, use a hoomd.trigger.Trigger subclass, to update only when there is a known change to the particles that a filter would select.

Note

Some actions automatically recompute all filter particles such as adding or removing particles to the hoomd.Simulation.state.

Parameters:
trigger#

The trigger associated with the updater.

Type:

hoomd.trigger.Trigger

__eq__(other)#

Return whether two objects are equivalent.

property filters#

filters to update select particles.

Type:

list[hoomd.filter.filter_like]

class hoomd.update.RemoveDrift(reference_positions, trigger=1)#

Bases: Updater

Remove the average drift from a restrained system.

Parameters:

RemoveDrift computes the mean drift \(\vec{D}\) from the given reference_positions (\(\vec{r}_{ref, i}\)):

\[\vec{D} = \frac{1}{\mathrm{N_{particles}}} \sum_{i=0}^\mathrm{N_{particles-1}} \mathrm{minimum\_image}(\vec{r}_i - \vec{r}_{ref,i})\]

RemoveDrift then shifts all particles in the system by \(-\vec{D}\):

\[\vec{r}_i \leftarrow \mathrm{minimum\_image}(\vec{r}_i - \vec{D})\]

Tip

Use RemoveDrift with hoomd.hpmc.external.field.Harmonic to improve the accuracy of Frenkel-Ladd calculations.

reference_positions#

the reference positions \([\mathrm{length}]\).

Type:

(N_particles, 3) numpy.ndarray of float

trigger#

The timesteps to remove drift.

Type:

hoomd.trigger.Trigger

hoomd.variant#

Overview

Constant

A constant value.

Cycle

A cycle of linear ramps.

Power

An approach from initial to final value following t**power.

Ramp

A linear ramp.

Variant

Variant base class.

variant_like

Objects that are like a variant.

Details

Define quantities that vary over the simulation.

A Variant object represents a scalar function of the time step. Some operations accept Variant values for certain parameters, such as the kT parameter to hoomd.md.methods.thermostats.Bussi.

Use one of the built in variant types, or define your own custom function in Python:

class CustomVariant(hoomd.variant.Variant):
    def __init__(self):
        hoomd.variant.Variant.__init__(self)

    def __call__(self, timestep):
        return (float(timestep)**(1 / 2))

    def _min(self):
        return 0.0

    def _max(self):
        return float('inf')

Note

Provide the minimum and maximum values in the _min and _max methods respectively.

class hoomd.variant.Constant(value)#

Bases: Variant

A constant value.

Parameters:

value (float) – The value.

Constant returns value at all time steps.

value#

The value.

Type:

float

__eq__(other)#

Return whether two variants are equivalent.

class hoomd.variant.Cycle(A, B, t_start, t_A, t_AB, t_B, t_BA)#

Bases: Variant

A cycle of linear ramps.

Parameters:
  • A (float) – The first value.

  • B (float) – The second value.

  • t_start (int) – The start time step.

  • t_A (int) – The hold time at the first value.

  • t_AB (int) – The time spent ramping from A to B.

  • t_B (int) – The hold time at the second value.

  • t_BA (int) – The time spent ramping from B to A.

Cycle holds the value A until time t_start. It continues holding that value until t_start + t_A. Then it ramps linearly from A to B over t_AB steps and holds the value B for t_B steps. After this, it ramps back from B to A over t_BA steps and repeats the cycle starting with t_A. Cycle repeats this cycle indefinitely.

Example plot of a cycle variant.
A#

The first value.

Type:

float

B#

The second value.

Type:

float

t_start#

The start time step.

Type:

int

t_A#

The holding time at A.

Type:

int

t_AB#

The time spent ramping from A to B.

Type:

int

t_B#

The holding time at B.

Type:

int

t_BA#

The time spent ramping from B to A.

Type:

int

__eq__(other)#

Return whether two variants are equivalent.

class hoomd.variant.Power(A, B, power, t_start, t_ramp)#

Bases: Variant

An approach from initial to final value following t**power.

Parameters:
  • A (float) – The start value.

  • B (float) – The end value.

  • power (float) – The power of the approach to B.

  • t_start (int) – The start time step.

  • t_ramp (int) – The length of the ramp.

Power holds the value A until time t_start. Then it progresses at \(t^{\mathrm{power}}\) from A to B over t_ramp steps and holds the value B after that.

p = Power(A=2, B-8, power=1 / 10, t_start=10, t_ramp=20)
Example plot of a power variant.
A#

The start value.

Type:

float

B#

The end value.

Type:

float

power#

The power of the approach to B.

Type:

float

t_start#

The start time step.

Type:

int

t_ramp#

The length of the ramp.

Type:

int

__eq__(other)#

Return whether two variants are equivalent.

class hoomd.variant.Ramp(A, B, t_start, t_ramp)#

Bases: Variant

A linear ramp.

Parameters:
  • A (float) – The start value.

  • B (float) – The end value.

  • t_start (int) – The start time step.

  • t_ramp (int) – The length of the ramp.

Ramp holds the value A until time t_start. Then it ramps linearly from A to B over t_ramp steps and holds the value B.

Example plot of a ramp variant.
A#

The start value.

Type:

float

B#

The end value.

Type:

float

t_start#

The start time step.

Type:

int

t_ramp#

The length of the ramp.

Type:

int

__eq__(other)#

Return whether two variants are equivalent.

class hoomd.variant.Variant#

Variant base class.

Variants are scalar valued functions of the simulation time step.

__call__(timestep)#

Evaluate the function.

Parameters:

timestep (int) – The time step.

Returns:

The value of the function at the given time step.

Return type:

float

__getstate__()#

Get the variant’s __dict__ attribute.

__setstate__(state)#

Restore the state of the variant.

property max#

The maximum value of this variant for \(t \in [0,\infty)\).

property min#

The minimum value of this variant for \(t \in [0,\infty)\).

hoomd.variant.variant_like#

Objects that are like a variant.

Any subclass of Variant is accepted along with float instances and objects convertible to float. They are internally converted to variants of type Constant via Constant(float(a)) where a is the float or float convertible object.

Note

Attributes that are Variant objects can be set via a variant_like object.

alias of Union[Variant, float]

hoomd.version#

Version and build information.

Use the values in hoomd.version to query properties of the package set at compile time.

hoomd.version.build_dir#

The directory where this build was compiled.

Type:

str

hoomd.version.compile_date#

The date this build was compiled.

Type:

str

hoomd.version.compile_flags#

Human readable summary of compilation flags.

Type:

str

hoomd.version.cuda_include_path#

CUDA toolkit include directory.

Type:

str

hoomd.version.cuda_devrt_library#

CUDA devrt library.

Type:

str

hoomd.version.cxx_compiler#

Name and version of the C++ compiler used to build HOOMD.

Type:

str

hoomd.version.floating_point_precision#

The high precision floating point width in bits (element 0) and the reduced precision width in bits (element 1).

Type:

tuple[int, int]

hoomd.version.git_branch#

Name of the git branch used when compiling this build.

Type:

str

hoomd.version.git_sha1#

SHA1 of the git commit used when compiling this build.

Type:

str

hoomd.version.gpu_api_version#

The GPU API version this build was compiled against.

Type:

str

hoomd.version.gpu_enabled#

True when this build supports GPUs.

Type:

bool

hoomd.version.gpu_platform#

Name of the GPU platform this build was compiled against.

Type:

str

hoomd.version.hpmc_built#

True when the hpmc component is built.

Type:

bool

hoomd.version.install_dir#

The installation directory.

Type:

str

hoomd.version.llvm_enabled#

True when this build supports LLVM run time compilation.

Type:

bool

hoomd.version.metal_built#

True when the metal component is built.

Type:

bool

hoomd.version.md_built#

True when the md component is built.

Type:

bool

hoomd.version.mpcd_built#

True when the mpcd component is built.

Type:

bool

hoomd.version.mpi_enabled#

True when this build supports MPI parallel runs.

Type:

bool

hoomd.version.source_dir#

The source directory.

Type:

str

hoomd.version.tbb_enabled#

True when this build supports TBB threads.

Type:

bool

hoomd.version.version#

HOOMD-blue package version, following semantic versioning.

Type:

str

hoomd.wall#

Overview

Cylinder

A right circular cylinder.

Plane

A plane.

Sphere

A sphere.

WallGeometry

Abstract base class for a HOOMD wall geometry.

Details

Wall geometries.

Walls define an oriented surface in space. Walls exist only in the primary box image and are not replicated across the periodic boundary conditions. Points on one side of the surface have a positive signed distance to that surface, and points on the other side have a negative signed distance.

Define individual walls with Cylinder, Plane, and Sphere. Create lists of these WallGeometry objects to describe more complex geometries. Use walls to confine particles to specific regions of space in HPMC and MD simulations.

class hoomd.wall.Cylinder(radius, axis, origin=(0.0, 0.0, 0.0), inside=True, open=True)#

Bases: WallGeometry

A right circular cylinder.

Parameters:
  • radius (float) – The radius of the circle faces of the cylinder \([\mathrm{length}]\).

  • axis (tuple [float, float, float]) – A vector perpendicular to the circular faces.

  • origin (tuple [float, float, float], optional) – The origin of the cylinder defined as the center of the circle along the cylinder’s axis \([\mathrm{length}]\).

  • inside (bool, optional) – Whether positive signed distances are inside or outside the cylinder.

  • open (bool, optional) – Whether to include the surface of the cylinder in the space. True means do not include the surface, defaults to True.

Cylinder walls in HOOMD span the simulation box in the direction given by the axis attribute.

The signed distance from the wall surface is

\[d = \left( R - \lvert \left( \vec{r} - \vec{r}_o \right) - \left( \left( \vec{r} - \vec{r}_o \right) \cdot \hat{n} \right) \hat{n} \rvert \right)\]

for inside=True, where \(r\) is the particle position, \(\vec{r}_o\) is the origin of the cylinder, \(\hat{n}\) is the cylinder’s unit axis, and \(R\) is the cylinder’s radius. The distance is negated when inside=False.

Warning

When running MD simulations in 2D simulation boxes, set axis=(0,0,1). Otherwise, the wall force will push particles off the xy plane.

Note

Cylinder objects are immutable.

radius#

The radius of the circle faces of the cylinder \([\mathrm{length}]\).

Type:

float

origin#

The origin of the cylinder defined as the center of the circle along the cylinder’s axis \([\mathrm{length}]\).

Type:

tuple [float, float, float]

axis#

A vector perpendicular to the circular faces.

Type:

tuple [float, float, float]

inside#

Whether positive signed distances are inside or outside the cylinder.

Type:

bool

open#

Whether to include the surface of the cylinder in the space. True means do not include the surface.

Type:

bool, optional

__repr__()#

A string representation of the Cylinder.

__str__()#

A string representation of the Cylinder.

to_dict()#

Convert the wall geometry to a dictionary defining the cylinder.

Returns:

The geometry in a Python dictionary.

Return type:

dict

class hoomd.wall.Plane(origin, normal, open=True)#

Bases: WallGeometry

A plane.

Parameters:
  • origin (tuple [float, float, float]) – A point that lies on the plane \([\mathrm{length}]\).

  • normal (tuple [float, float, float]) – The normal vector to the plane. The vector will be converted to a unit vector \([\mathrm{dimensionless}]\).

  • open (bool, optional) – Whether to include the surface of the plane in the space. True means do not include the surface, defaults to True.

The signed distance from the wall surface is:

\[d = \hat{n} \cdot \left( \vec{r} - \vec{r}_o \right)\]

where \(\vec{r}\) is the particle position, \(\vec{r}_o\) is the origin of the plane, and \(\hat{n}\) is the plane’s unit normal. The normal points toward the points with a positive signed distance to the plane.

Warning

When running MD simulations in 2D simulation boxes, set normal=(nx,ny,0). Otherwise, the wall force will push particles off the xy plane.

Note

Plane objects are immutable.

origin#

A point that lies on the plane \([\mathrm{length}]\).

Type:

tuple [float, float, float]

normal#

The unit normal vector to the plane.

Type:

tuple [float, float, float]

open#

Whether to include the surface of the plane in the space. True means do not include the surface.

Type:

bool

__repr__()#

A string representation of the Plane.

__str__()#

A string representation of the Plane.

to_dict()#

Convert the wall geometry to a dictionary defining the plane.

Returns:

The geometry in a Python dictionary.

Return type:

dict

class hoomd.wall.Sphere(radius, origin=(0.0, 0.0, 0.0), inside=True, open=True)#

Bases: WallGeometry

A sphere.

Parameters:
  • radius (float) – The radius of the sphere \([\mathrm{length}]\).

  • origin (tuple [float, float, float], optional) – The origin of the sphere, defaults to (0, 0, 0) \([\mathrm{length}]\).

  • inside (bool, optional) – Whether positive signed distances are inside or outside the sphere, defaults to True.

  • open (bool, optional) – Whether to include the surface of the sphere in the space. True means do not include the surface, defaults to True.

The signed distance from the wall surface is:

\[d = \left( R - \lvert \vec{r} - \vec{r}_o \rvert \right)\]

for inside=True, where \(r\) is the particle position, \(r_o\) is the origin of the sphere, and \(R\) is the sphere’s radius. The distance is negated when inside=False.

Warning

When running MD simulations in 2D simulation boxes, set origin[2]=(x,y,0). Otherwise, the wall force will push particles off the xy plane.

Note

Sphere objects are immutable.

radius#

The radius of the sphere \([\mathrm{length}]\).

Type:

float

origin#

The origin of the sphere \([\mathrm{length}]\).

Type:

tuple [float, float, float]

inside#

Whether positive signed distances are inside or outside the sphere.

Type:

bool

open#

Whether to include the surface of the sphere in the space. Open means do not include the surface.

Type:

bool

__repr__()#

A string representation of the Sphere.

__str__()#

A string representation of the Sphere.

to_dict()#

Convert the wall geometry to a dictionary defining the sphere.

Returns:

The geometry in a Python dictionary.

Return type:

dict

class hoomd.wall.WallGeometry#

Bases: ABC

Abstract base class for a HOOMD wall geometry.

Walls are used in both HPMC and MD subpackages. Subclasses of WallGeometry abstract over the wall geometries for both use cases.

abstract to_dict()#

Convert the wall geometry to a dictionary defining the geometry.

Returns:

The geometry in a Python dictionary.

Return type:

dict

hoomd.write#

Overview

Burst

Write the last \(N\) stored frames in the GSD format.

DCD

Writes simulation trajectories in the DCD format.

CustomWriter

User-defined writer.

GSD

Write simulation trajectories in the GSD format.

Table

Write delimiter separated values to a stream.

Details

Writers.

Writers write the state of the simulation, logger quantities, or calculated results to output files or streams:

  • GSD and DCD save the simulation trajectory to a file.

  • Combine GSD with a hoomd.logging.Logger to save system properties or per-particle calculated results.

  • Use Table to display the status of the simulation periodically to standard out.

  • Implement custom output formats with CustomWriter.

Writers do not modify the system state.

Tip

OVITO has native support for GSD files, including logged per-particle array quantities and particle shapes.

See also

Tutorial: Introducing HOOMD-blue

Tutorial: Logging

class hoomd.write.Table(trigger, logger, output=stdout, header_sep='.', delimiter=' ', pretty=True, max_precision=10, max_header_len=None)#

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.

Parameters:
  • 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.

  • 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 include sys.stdout, sys.stderr and the return value of open().

  • 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).

  • 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.

  • 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 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).

trigger#

The trigger to determine when to run the Table backend.

Type:

hoomd.trigger.Trigger

logger#

The logger to query for output. The ‘scalar’ categories must be set on the logger, and the ‘string’ categories is optional.

Type:

hoomd.logging.Logger

output#

A file-like object to output the data from. The object must have write and flush methods and a mode attribute.

Type:

file-like object

header_sep#

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).

Type:

str

delimiter#

String used to separate elements in the space delimited file.

Type:

str

pretty#

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.

Type:

bool

max_precision#

If pretty is not set, then this controls the maximum precision to use when outputing numerical values, defaults to 10.

Type:

int, optional

max_header_len#

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).

Type:

int

min_column_width#

The minimum allowed column width.

Type:

int

write()#

Write out data to self.output.

Writes a row from given hoomd.logging.Logger object data.

class hoomd.write.Burst(trigger, filename, filter=hoomd._hoomd.ParticleFilter, mode='ab', dynamic=None, logger=None, max_burst_size=-1, write_at_start=False)#

Bases: GSD

Write the last \(N\) stored frames in the GSD format.

When triggered, Burst stores up to the last \(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 \(N + 1\) frames being stored, the oldest frame is removed and the new frame is added.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Select the timesteps to store in the buffer.

  • filename (str) – File name to write.

  • filter (hoomd.filter.filter_like) – Select the particles to write. Defaults to hoomd.filter.All.

  • mode (str) – The file open mode. Defaults to 'ab'.

  • dynamic (list[str]) – Field names and/or field categores to save in 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 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 when hoomd.Simulation.run is called. Defaults to False.

Warning

Burst errors when attempting to create a file or writing to one with zero frames, unless write_at_start is True.

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.

filename#

File name to write.

Type:

str

trigger#

Select the timesteps to store in the buffer.

Type:

hoomd.trigger.Trigger

filter#

Select the particles to write.

Type:

hoomd.filter.filter_like

mode#

The file open mode.

Type:

str

dynamic#

Field names and/or field categores to save in all frames.

Type:

list[str]

max_burst_frames#

The maximum number of frames to store before between writes. -1 represents no limit.

Type:

int

write_diameter#

When False, do not write particles/diameter. Set to True to write non-default particle diameters.

Type:

bool

write_at_start#

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.

Type:

bool

dump()#

Write all currently stored frames to the file and empties the buffer.

This method alllows for custom writing of frames at user specified conditions.

class hoomd.write.CustomWriter(trigger, action)#

Bases: CustomOperation, Writer

User-defined writer.

Parameters:

CustomWriter is a hoomd.operation.Writer that wraps a user-defined hoomd.custom.Action object so the action can be added to a hoomd.Operations instance for use with hoomd.Simulation objects.

Writers may read the system state and generate output files or print to output streams. Writers should not modify the system state.

class hoomd.write.DCD(trigger, filename, filter=hoomd._hoomd.ParticleFilter, overwrite=False, unwrap_full=False, unwrap_rigid=False, angle_z=False)#

Bases: Writer

Writes simulation trajectories in the DCD format.

Parameters:
  • trigger (hoomd.trigger.Periodic) – Select the timesteps to write.

  • filename (str) – File name to write.

  • filter (hoomd.filter.filter_like) – Select the particles to write. Defaults to hoomd.filter.All.

  • overwrite (bool) – When False, (the default) an existing DCD file will be appended to. When True, an existing DCD file filename will be overwritten.

  • unwrap_full (bool) – When False, (the default) 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.

  • unwrap_rigid (bool) – When False, (the default) 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 unwrapped so that the body is continuous. The center of mass of the body remains in the simulation box, but some particles may be written just outside it. unwrap_rigid is ignored when unwrap_full is True.

  • angle_z (bool) – When True, the particle orientation angle is written to the z component (only useful for 2D simulations)

DCD writes the simulation trajectory to the specified file in the DCD file format. DCD stores only particle positions and the box parameters, in 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:

  • The period must be the same or the time data in the file will not be consistent.

  • DCD will not write out data at time steps that already are present in the DCD file.

filename#

File name to write.

Type:

str

trigger#

Select the timesteps to write.

Type:

hoomd.trigger.Periodic

filter#

Select the particles to write.

Type:

hoomd.filter.filter_like

overwrite#

When False, an existing DCD file will be appended to. When True, an existing DCD file filename will be overwritten.

Type:

bool

unwrap_full#

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.

Type:

bool

unwrap_rigid#

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 unwrapped so that the body is continuous. The center of mass of the body remains in the simulation box, but some particles may be written just outside it. unwrap_rigid is ignored when unwrap_full is True.

Type:

bool

angle_z#

When True, the particle orientation angle is written to the z component

Type:

bool

class hoomd.write.GSD(trigger, filename, filter=hoomd._hoomd.ParticleFilter, mode='ab', truncate=False, dynamic=None, logger=None)#

Bases: Writer

Write simulation trajectories in the GSD format.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Select the timesteps to write.

  • filename (str) – File name to write.

  • filter (hoomd.filter.filter_like) – Select the particles to write. Defaults to hoomd.filter.All.

  • mode (str) – The file open mode. Defaults to 'ab'.

  • truncate (bool) – When True, truncate the file and write a new frame 0 each time this operation triggers. Defaults to False.

  • dynamic (list[str]) – Field names and/or field categores to save in all frames. Defaults to ['property'].

  • logger (hoomd.logging.Logger) – Provide log quantities to write. Defaults to None.

GSD writes the simulation trajectory to the specified file in the GSD format. GSD can store all particle, bond, angle, dihedral, improper, pair, and constraint data fields in every frame of the trajectory. GSD can write trajectories where the number of particles, number of particle types, particle types, diameter, mass, charge, or other quantities change over time. GSD can also store arbitrary, scalar, string, and array quantities provided by a hoomd.logging.Logger instance in logger.

Valid file open modes:

mode

description

'wb'

Open the file for writing. Create the file if needed, or overwrite an existing file.

'xb'

Create a GSD file exclusively. Raise an exception when the file exists.

'ab'

Create the file if needed, or append to an existing file.

To reduce file size, GSD does not write properties that are set to defaults. When masses, orientations, angular momenta, etc… are left default for all particles, these fields will not take up any space in the file, except on frame 1+ when the field is also non-default in frame 0. GSD writes all non-default fields to frame 0 in the file.

To further reduce file sizes, GSD allows the user to select which specific fields will be considered for writing to frame 1+ in the dynamic list. When reading a GSD file, the data in frame 0 is read when a quantity is missing in frame i, so any fields not in dynamic are fixed for the entire trajectory.

The dynamic list can contain one or more of the following strings:

  • 'property'

    • 'configuration/box'

    • 'particles/N'

    • 'particles/position'

    • 'particles/orientation'

  • 'momentum'

    • 'particles/velocity'

    • 'particles/angmom'

    • 'particles/image'

  • 'attribute'

    • 'particles/types'

    • 'particles/typeid'

    • 'particles/mass'

    • 'particles/charge'

    • 'particles/diameter'

    • 'particles/body'

    • 'particles/moment_inertia'

  • 'topology'

    • bonds/*

    • angles/*

    • dihedrals/*

    • impropers/*

    • constraints/*

    • pairs/*

When you set a category string ('property', 'momentum', 'attribute'), GSD makes all the category member’s fields dynamic.

Warning

GSD buffers writes in memory. Abnormal exits (e.g. kill, scancel, reaching walltime limits) may cause loss of data. Ensure that your scripts exit cleanly and call flush() as needed to write buffered frames to the file.

See also

See the GSD documentation, GSD HOOMD Schema, and GSD GitHub project for more information on GSD files.

Note

When you use filter to select a subset of the whole system, GSD writes only the selected particles in ascending tag order and does not write out topology.

Tip

All logged data fields must be present in the first frame in the gsd file to provide the default value. To achieve this, set the logger attribute before the operation is triggered to write the first frame in the file.

Some (or all) fields may be omitted on later frames. You can set logger to None or remove specific quantities from the logger, but do not add additional quantities after the first frame.

filename#

File name to write.

Type:

str

trigger#

Select the timesteps to write.

Type:

hoomd.trigger.Trigger

filter#

Select the particles to write.

Type:

hoomd.filter.filter_like

mode#

The file open mode.

Type:

str

truncate#

When True, truncate the file and write a new frame 0 each time this operation triggers.

Type:

bool

dynamic#

Field names and/or field categores to save in all frames.

Type:

list[str]

write_diameter#

When False, do not write particles/diameter. Set to True to write non-default particle diameters.

Type:

bool

maximum_write_buffer_size#

Size (in bytes) to buffer in memory before writing to the file.

Type:

int

flush()#

Flush the write buffer to the file.

Example:

gsd_writer.flush()

Flush all write buffers:

for writer in simulation.operations.writers:
    if hasattr(writer, 'flush'):
        writer.flush()
property logger#

Provide log quantities to write.

May be None.

Type:

hoomd.logging.Logger

static write(state, filename, filter=hoomd._hoomd.ParticleFilter, mode='wb', logger=None)#

Write the given simulation state out to a GSD file.

Parameters:

The valid file modes for write are 'wb' and 'xb'.

hoomd.hpmc#

Details

Hard particle Monte Carlo.

In hard particle Monte Carlo (HPMC) simulations, the particles in the system state have extended shapes. The potential energy of the system is infinite when any particle shapes overlap. Pair (hoomd.hpmc.pair) and external (hoomd.hpmc.external) potentials compute the potential energy when there are no shape overlaps. hpmc employs the Metropolis Monte Carlo algorithm to sample equilibrium configurations of the system.

To perform HPMC simulations, assign a HPMC integrator (hoomd.hpmc.integrate) to the hoomd.Simulation operations. The HPMC integrator defines the particle shapes and performs local trial moves on the particle positions and orientations. HPMC updaters (hoomd.hpmc.update) interoperate with the integrator to perform additional types of trial moves, including box moves, cluster moves, and particle insertion/removal. Use HPMC computes (hoomd.hpmc.compute) to compute properties of the system state, such as the free volume or pressure.

See also

Anderson 2016 further describes the theory and implementation.

Modules

hoomd.hpmc.compute#

Overview

FreeVolume

Compute the free volume available to a test particle.

SDF

Compute the scale distribution function via volume perturbations.

Details

Compute properties of hard particle configurations.

The HPMC compute classes analyze the system configuration and provide results as loggable quantities for use with hoomd.logging.Logger or by direct access via the Python API. FreeVolume computes the free volume available to small particles, such as depletants, and SDF computes the pressure in system of convex particles with a fixed box size.

class hoomd.hpmc.compute.FreeVolume(test_particle_type, num_samples)#

Compute the free volume available to a test particle.

Parameters:
  • test_particle_type (str) – Test particle type.

  • num_samples (int) – Number of samples to evaluate.

FreeVolume computes the free volume in the simulation state available to a given test particle shape using Monte Carlo integration. Use it in combination with hoomd.hpmc.integrate.HPMCIntegrator, which defines the particle shape parameters. Particles of test_particle_type may or may not be present in the simulation state.

FreeVolume generates num_samples (\(n_\mathrm{samples}\)) trial particle configurations with positions \(\vec{r}^t_j\) uniformly distributed in the simulation box, and orientations \(\mathbf{q}^t_j\) uniformly distributed among rotations matching the box dimensionality. FreeVolume counts the number of successful samples that do not overlap particles in the simulation state:

\[n_\mathrm{success} = \sum_{j=1}^{n_\mathrm{samples}} \prod_{i=0}^{N_\mathrm{particles}-1} \prod_{\vec{A} \in B_\mathrm{images}} \left[ \mathrm{overlap}\left( S_i(\mathbf{q}_i), S_t(\mathbf{q}^t_j, \vec{r}^t_j - (\vec{r}_i + \vec{A})) \right) = \emptyset \right]\]

where \(\mathrm{overlap}\) is the shape overlap function defined in hoomd.hpmc.integrate, \(S_i\) is the shape of particle \(i\), \(S_t\) is the shape of the test particle, \(\vec{A} = h\vec{a}_1 + k\vec{a}_2 + l\vec{a}_3\) is a vector that translates by periodic box images, the set of box images includes all image vectors necessary to find overlaps between particles in the primary image with particles in periodic images, and the square brackets denote the Iverson bracket.

The free volume \(V_\mathrm{free}\) is given by:

\[V_\mathrm{free} = \frac{n_\mathrm{success}} {n_\mathrm{samples}} V_\mathrm{box}\]

where \(V_\mathrm{box}\) is the volume of the simulation box (or area in 2D).

Note

FreeVolume respects the HPMC integrator’s interaction_matrix.

Mixed precision

FreeVolume uses reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

Box images

On CPU devices, FreeVolume does not apply the minimum image convention. It supports small boxes where particles may overlap with non-primary images of other particles, including self overlap. On GPU devices, FreeVolume applies the minimum image convention.

Examples:

fv = hoomd.hpmc.compute.FreeVolume(test_particle_type='B',
                                   num_samples=1000)
test_particle_type#

Test particle type.

Type:

str

num_samples#

Number of samples to evaluate.

Type:

int

property free_volume#

Free volume available to the test particle \([\mathrm{length}^{2}]\) in 2D and \([\mathrm{length}^{3}]\) in 3D.

(Loggable: category=”scalar”)

class hoomd.hpmc.compute.SDF(xmax, dx)#

Compute the scale distribution function via volume perturbations.

Parameters:
  • xmax (float) – Maximum x value at the right hand side of the rightmost bin \([\mathrm{length}]\).

  • dx (float) – Bin width \([\mathrm{length}]\).

SDF computes the probability distributions \(s_{\mathrm{comp}}(x)\) and \(s_{\mathrm{exp}}(x)\) of particles overlapping as a function of separation for compressive and expansive perturbations, respectively. It estimates \(s_{\mathrm{comp}}(x)\) and \(s_{\mathrm{exp}}(x)\) numerically by computing histograms with \(\lfloor x_\mathrm{max}/ \delta x \rfloor\) bins of width dx (\(\delta x\)).

See also

Anderson 2016 describes the theory relating SDF to the system pressure and its implementation in HOOMD-blue. Eppenga and Frenkel 1984 present a derivation relating the scale distribution function to the system pressure for hard, convex particles. Allen 2006 describes the theory for calculating the pressure in systems with discontinuous potential energy functions. The expansive perturbations are based on theory described in de Miguel and Jackson.

Implementation

SDF constructs two histograms, one for compressive volume perturbations and one for expansive volume perturbations. These histograms represent \(s_{\mathrm{comp}}(x)\) and \(s_{\mathrm{exp}}(x)\). The following discussion applies to compressive volume perturbations and the computation of \(s_{\mathrm{comp}}(x)\); the computation of \(s_{\mathrm{exp}}(x)\) proceeds similarly as noted throughout the description.

For each pair of particles \(i\) and \(j\) SDF scales the particle separation vector by the factor \((1 \pm x)\) (\(+\) for expansive perturbations, \(-\) for compressive perturbations) and finds the smallest positive value of \(x\) leading to either an overlap of the particle shapes (a “hard overlap”) or a discontinuous change in the pair energy \(U_{\mathrm{pair},ij}\) (a “soft overlap”). For compressive perturbations:

\[\begin{split}x_{ij}(\vec{A}) = \min \{ & x \in \mathbb{R}_{> 0} : \\ & \mathrm{overlap}\left( S_i(\mathbf{q}_i), S_j(\mathbf{q}_j, (1-x)(\vec{r}_j - (\vec{r}_i + \vec{A}))) \right) \ne \emptyset \\ &\lor \\ & U_{\mathrm{pair},ij}((1-x)(\vec{r}_j - (\vec{r}_i + \vec{A})), \mathbf{q}_i, \mathbf{q}_j) \ne U_{\mathrm{pair},ij}(\vec{r}_j - (\vec{r}_i + \vec{A}), \mathbf{q}_i, \mathbf{q}_j) \\ \} &\end{split}\]

where \(\mathrm{overlap}\) is the shape overlap function defined in hoomd.hpmc.integrate, \(S_i\) is the shape of particle \(i\), and \(\vec{A} = h\vec{a}_1 + k\vec{a}_2 + l\vec{a}_3\) is a vector that translates by periodic box images. For expansive perturbations,

\[\begin{split}x_{ij}(\vec{A}) = \max \{ & x \in \mathbb{R}_{< 0} : \\ & \mathrm{overlap}\left( S_i(\mathbf{q}_i), S_j(\mathbf{q}_j, (1+x)(\vec{r}_j - (\vec{r}_i + \vec{A}))) \right) \ne \emptyset \\ &\lor \\ & U_{\mathrm{pair},ij}((1+x)(\vec{r}_j - (\vec{r}_i + \vec{A})), \mathbf{q}_i, \mathbf{q}_j) \ne U_{\mathrm{pair},ij}(\vec{r}_j - (\vec{r}_i + \vec{A}), \mathbf{q}_i, \mathbf{q}_j) \\ \} &\end{split}\]

For particle \(i\), SDF finds the the minimum (maximum for expansive perturbations) value \(x_i\). For compressive perturbations:

\[x_i = \min \{ x_{ij} : \vec{A} \in B_\mathrm{images}, j \in [0,N_\mathrm{particles}) \}\]

where the set of box images includes all image vectors necessary to find overlaps between particles in the primary image with particles in periodic images. For expansive perturbations:

\[x_i = \max \{ x_{ij} : \vec{A} \in B_\mathrm{images}, j \in [0,N_\mathrm{particles}) \}\]

SDF adds a single count to each histogram for each particle \(i\), weighted by a factor that is a function of the change in energy upon overlap. For compressive perturbations:

\[s_{\mathrm{comp}}(x + \delta x/2) = \frac{1}{N_\mathrm{particles} \cdot \delta x} \sum_{i=0}^{N_\mathrm{particles}-1} [x \le x_i < x + \delta x] \cdot (1 - \exp(-\beta \Delta U_{i}))\]

where \(\Delta U_{i}\) is the change in energy associated with the first overlap involving particle \(i\) (\(\infty\) for hard overlaps), the square brackets denote the Iverson bracket, and \(s_{\mathrm{comp}}(x + \delta x/2)\) is evaluated for \(\{ x \in \mathbb{R}, 0 \le x < x_\mathrm{max}, x = k \cdot \delta x, k \in \mathbb{Z}^* \}\) for compressive perturbations. For expansive perturbations,

\[s_{\mathrm{exp}}(x - \delta x/2) = \frac{1}{N_\mathrm{particles} \cdot \delta x} \sum_{i=0}^{N_\mathrm{particles}-1} [x - \delta x \le x_i < x] \cdot (1 - \exp(-\beta \Delta U_{i}))\]

where \(s_{\mathrm{exp}}(x - \delta x/2)\) is evaluated for \(\{ x \in \mathbb{R}, -|x_\mathrm{max}| < x \le 0, x = (k - \lfloor x_\mathrm{max} / \delta x \rfloor + 1) \cdot \delta x, k \in \mathbb{Z}^* \}\).

Pressure

The pressure \(P\) is related to the one-sided limits \(s_{\mathrm{comp}}(0+)\) and \(s_{\mathrm{exp}}(0-)\), computed by fitting and extrapolating \(s_{\mathrm{comp}}\) and \(s_{\mathrm{exp}}\) to \(x = 0\).

\[\beta P = \rho \left( 1 + \frac{s_{\mathrm{comp}}(0+) - s_{\mathrm{exp}}(0-)}{2d} \right)\]

where \(d\) is the dimensionality of the system, \(\rho\) is the number density, and \(\beta = \frac{1}{kT}\). This measurement of the pressure is inherently noisy due to the nature of the sampling. Average betaP over many timesteps to obtain accurate results.

Assuming particle diameters are ~1, these parameter values typically achieve good results:

  • xmax = 0.02

  • dx = 1e-4

In systems near densest packings, dx=1e-5 may be needed along with smaller xmax. Check that \(\sum_k s_\mathrm{comp}(x_k) \cdot dx \approx 0.5\).

Important

SDF samples pair configurations at discrete separations. Therefore, the computed pressure is correct only for potentials with constant values and step discontinuities.

Note

SDF always runs on the CPU.

Mixed precision

SDF uses reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

Box images

SDF does not apply the minimum image convention. It supports small boxes where particles may overlap with non-primary images of other particles, including self overlap.

xmax#

Maximum x value at the right hand side of the rightmost bin \([\mathrm{length}]\).

Type:

float

dx#

Bin width \([\mathrm{length}]\).

Type:

float

property betaP#

Beta times pressure in NVT simulations \(\left[ \mathrm{length}^{-d} \right]\).

Uses a polynomial curve fit of degree 5 to estimate \(s_\mathrm{comp}(0+)\) (and \(s_\mathrm{exp}(0-)\) if required) and computes the pressure via:

\[\beta P = \rho \left(1 + \frac{s_\mathrm{comp}(0+)}{2d} + \frac{s_\mathrm{exp}(0-)}{2d} \right)\]

where \(d\) is the dimensionality of the system, \(\rho\) is the number density, and \(\beta = \frac{1}{kT}\).

Attention

In MPI parallel execution, betaP is available on rank 0 only. betaP is None on ranks >= 1.

(Loggable: category=”scalar”)

Type:

float

property sdf_compression#

\(s_\mathrm{comp}[k]\) - The scale distribution function for compression moves \([\mathrm{probability\ density}]\).

See also

x_compression defines the bin center locations.

Attention

In MPI parallel execution, the array is available on rank 0 only. sdf_compression is None on ranks >= 1.

(Loggable: category=”sequence”)

Type:

(N_bins,) numpy.ndarray of float)

property sdf_expansion#

\(s_\mathrm{exp}[k]\) - The scale distribution function for the expansion moves \([\mathrm{probability\ density}]\).

See also

x_expansion defines the bin center locations..

Attention

In MPI parallel execution, the array is available on rank 0 only. sdf_expansion is None on ranks >= 1.

(Loggable: category=”sequence”)

Type:

(N_bins,) numpy.ndarray of float)

property x_compression#

The x values at the center of each bin corresponding to the scale distribution function for the compressive perturbations \([\mathrm{length}]\).

(Loggable: category=”sequence”)

Type:

(N_bins,) numpy.ndarray of float)

property x_expansion#

The x values at the center of each bin corresponding to the scale distribution function for the expansion moves \([\mathrm{length}]\).

(Loggable: category=”sequence”)

Type:

(N_bins,) numpy.ndarray of float)

hoomd.hpmc.integrate#

Overview

ConvexPolygon

Convex polygon hard particle Monte Carlo integrator.

ConvexPolyhedron

Convex polyhedron hard particle Monte Carlo integrator.

ConvexSpheropolygon

Convex spheropolygon hard particle Monte Carlo integrator.

ConvexSpheropolyhedron

Convex spheropolyhedron hard particle Monte Carlo integrator.

ConvexSpheropolyhedronUnion

Convex spheropolyhedron union hard particle Monte Carlo integrator.

Ellipsoid

Ellipsoid hard particle Monte Carlo integrator.

FacetedEllipsoid

Faceted ellipsoid hard particle Monte Carlo integrator.

FacetedEllipsoidUnion

Faceted ellispod union hard particle Monte Carlo integrator.

HPMCIntegrator

Base class hard particle Monte Carlo integrator.

Polyhedron

Polyhedron hard particle Monte Carlo integrator.

SimplePolygon

Simple polygon hard particle Monte Carlo integrator.

Sphere

Sphere hard particle Monte Carlo integrator.

SphereUnion

Sphere union hard particle Monte Carlo integrator.

Sphinx

Sphinx hard particle Monte Carlo integrator.

Details

Hard particle Monte Carlo integrators.

Metropolis Monte Carlo

The hard particle Monte Carlo (HPMC) integrator HPMCIntegrator samples equilibrium system states using the Metropolis Monte Carlo method. In this method, HPMCIntegrator takes the existing system state in the configuration \(C = (\vec{r}_0, \vec{r}_1, \ldots \vec{r}_{N_\mathrm{particles}-1}, \mathbf{q}_0, \mathbf{q}_2, \ldots \mathbf{q}_{N_\mathrm{particles}-1})\) with potential energy \(U\) and perturbs it to a trial configuration \(C^t\) with potential energy \(U^t\) leading to an energy difference \(\Delta U = U^t - U\). The trial move is accepted with the probability:

\[\begin{split}p_\mathrm{accept} = \begin{cases} \exp(-\beta \Delta U) & \Delta U > 0 \\ 1 & \Delta U \le 0 \\ \end{cases}\end{split}\]

When the trial move is accepted, the system state is set to the the trial configuration. When it is not accepted, the move is rejected and the state is not modified.

Temperature

HPMC assumes that \(\beta = \frac{1}{kT} = 1\). This is not relevant to systems of purely hard particles where \(\Delta U\) is either 0 or \(\infty\). To adjust the effective temperature in systems with finite interactions (see Energy evaluation below), scale the magnitude of the energetic interactions accordingly.

Local trial moves

HPMCIntegrator generates local trial moves for a single particle \(i\) at a time. The move is either a translation move or a rotation move, selected randomly with the probability of a translation move set by HPMCIntegrator.translation_move_probability (\(p_\mathrm{translation}\)).

The form of the trial move depends on the dimensionality of the system. Let \(u\) be a random value in the interval \([0,1]\), \(\vec{v}\) be a random vector uniformly distributed within the ball of radius 1, and \(\mathbf{w}\) be a random unit quaternion from the set of uniformly distributed rotations. Then the 3D trial move for particle \(i\) is:

\[\begin{split}\begin{cases} \left( \begin{array}{l} \vec{r}^t_i = \vec{r}_i + d_i \vec{v}, \\ \mathbf{q}^t_i = \mathbf{q}_i \end{array} \right) & u \le p_\mathrm{translation} \\ \left( \begin{array}{l} \vec{r}^t_i = \vec{r}_i, \\ \mathbf{q}^t_i = \frac{\mathbf{q}_i + a_i \mathbf{w}} {\vert \mathbf{q}_i + a_i \mathbf{w} \vert} \end{array} \right) & u > p_\mathrm{translation} \\ \end{cases}\end{split}\]

where \(d_i\) is the translation move size for particle \(i\) (set by particle type with HPMCIntegrator.d) and \(a_i\) is the rotation move size (set by particle type with HPMCIntegrator.a).

In 2D boxes, let \(\vec{v}\) be a random vector uniformly distributed within the disk of radius 1 in the x,y plane and \(\alpha\) be a random angle in radians in the interval \([-a_i,a_i]\). Form a quaternion that rotates about the z axis by \(\alpha\): \(\mathbf{w} = (\cos(\alpha/2), 0, 0, \sin(\alpha/2))\). The 2D trial move for particle \(i\) is:

\[\begin{split}\begin{cases} \left( \begin{array}{l} \vec{r}^t_i = \vec{r}_i + d_i \vec{v}, \\ \mathbf{q}^t_i = \mathbf{q}_i \end{array} \right) & u \le p_\mathrm{translation} \\ \left( \begin{array}{l} \vec{r}^t_i = \vec{r}_i, \\ \mathbf{q}^t_i = \frac{\mathbf{q}_i \cdot \mathbf{w}} {\vert \mathbf{q}_i \cdot \mathbf{w} \vert} \end{array} \right) & u > p_\mathrm{translation} \\ \end{cases}\end{split}\]

Note

For non-orientable spheres, \(p_\mathrm{translation} = 1\).

Timesteps

In the serial CPU implementation, HPMCIntegrator performs nselect trial moves per particle in each timestep (which defaults to 4). To achieve detailed balance at the level of a timestep, HPMCIntegrator randomly chooses with equal probability to loop through particles in forward index or reverse index order (random selection severely degrades performance due to cache incoherency). In the GPU and MPI implementations, trial moves are performed in parallel for particles in active domains while leaving particles on the border fixed (see Anderson 2016 for a full description). As a consequence, a single timestep may perform more or less than nselect trial moves per particle when using the parallel code paths. Monitor the number of trial moves performed with HPMCIntegrator.translate_moves and HPMCIntegrator.rotate_moves.

Random numbers

HPMCIntegrator uses a pseudorandom number stream to generate the trial moves. Set the seed using hoomd.Simulation.seed. Given the same seed, the same initial configuration, and the same execution configuration (device and MPI configuration), HPMCIntegrator, will produce exactly the same trajectory.

Note

Due to limited floating point precision, full trajectory reproducibility is only possible with the same binary installation running on the same hardware device. Compiler optimizations, changes to the HOOMD source code, and machine specific code paths may lead to different trajectories.

Energy evaluation

HPMCIntegrator evaluates the energy of a configuration from a number of terms:

\[U = U_{\mathrm{pair}} + U_{\mathrm{shape}} + U_{\mathrm{external}}\]

To enable simulations of small systems, the pair and shape energies evaluate interactions between pairs of particles in multiple box images:

\[\begin{split}U_{\mathrm{pair}} = & \sum_{i=0}^{N_\mathrm{particles}-1} \sum_{j=i+1}^{N_\mathrm{particles}-1} U_{\mathrm{pair},ij}(\vec{r}_j - \vec{r}_i, \mathbf{q}_i, \mathbf{q}_j) \\ + & \sum_{i=0}^{N_\mathrm{particles}-1} \sum_{j=i}^{N_\mathrm{particles}-1} \sum_{\vec{A} \in B_\mathrm{images}, \vec{A} \ne \vec{0}} U_{\mathrm{pair},ij}(\vec{r}_j - (\vec{r}_i + \vec{A}), \mathbf{q}_i, \mathbf{q}_j)\end{split}\]

where \(\vec{A} = h\vec{a}_1 + k\vec{a}_2 + l\vec{a}_3\) is a vector that translates by periodic box images and the set of box images includes all image vectors necessary to find interactions between particles in the primary image with particles in periodic images The first sum evaluates interactions between particle \(i\) with other particles (not itself) in the primary box image. The second sum evaluates interactions between particle \(i\) and all potentially interacting periodic images of all particles (including itself). HPMCIntegrator computes \(U_{\mathrm{shape}}\) similarly (see below).

External potentials apply to each particle individually:

\[U_\mathrm{external} = \sum_{i=0}^\mathrm{N_particles-1} U_{\mathrm{external},i}(\vec{r}_i, \mathbf{q}_i)\]

Potential classes in hoomd.hpmc.pair evaluate \(U_{\mathrm{pair},ij}\). Assign a class instance to HPMCIntegrator.pair_potential to apply it during integration. Similarly, potential classes in hoomd.hpmc.external evaluate \(U_{\mathrm{external},i}\). Assign a class instance to HPMCIntegrator.external_potential to apply it during integration.

Shape overlap tests

HPMCIntegrator performs shape overlap tests to evaluate \(U_{\mathrm{shape}}\). Let \(S\) be the set of all points inside the shape in the local coordinate system of the shape:

\[S = \{ \vec{a} \in \mathbb{R}^3 : \vec{a} \enspace \mathrm{inside\ the\ shape} \}\]

See the subclasses of HPMCIntegrator for formal definitions of the shapes, whose parameters are set by particle type. Let \(S_i\) refer specifically to the shape for particle \(i\).

The quaternion \(\mathbf{q}\) represents a rotation of the shape from its local coordinate system to the given orientation:

\[S(\mathbf{q}) = \{ \mathbf{q}\vec{a}\mathbf{q}^* : \vec{a} \in S \}\]

The full transformation from the local shape coordinate system to the simulation box coordinate system includes a rotation and translation:

\[S(\mathbf{q}, \vec{r}) = \{ \mathbf{q}\vec{a}\mathbf{q}^* + \vec{r} : \vec{a} \in S \}\]

HPMCIntegrator defines the shape overlap test for two shapes:

\[\mathrm{overlap}(S_1, S_2) = S_1 \bigcap S_2\]

To check for overlaps between two particles in the box, rotating both shapes from their local frame to the box frame, and translate \(S_2\) relative to particle 1:

\[\mathrm{overlap}(S_1(\mathbf{q}_1), S_2(\mathbf{q}_2, \vec{r}_2 - \vec{r}_1))\]

The complete hard shape interaction energy for a given configuration is:

\[\begin{split}U_\mathrm{shape} = \quad & \infty \cdot \sum_{i=0}^{N_\mathrm{particles}-1} \sum_{j=i+1}^{N_\mathrm{particles}-1} \left[ \mathrm{overlap}\left( S_i(\mathbf{q}_i), S_j(\mathbf{q}_j, \vec{r}_j - \vec{r}_i) \right) \ne \emptyset \right] \\ + & \infty \cdot \sum_{i=0}^{N_\mathrm{particles}-1} \sum_{j=i}^{N_\mathrm{particles}-1} \sum_{\vec{A} \in B_\mathrm{images}, \vec{A} \ne \vec{0}} \left[ \mathrm{overlap}\left( S_i(\mathbf{q}_i), S_j(\mathbf{q}_j, \vec{r}_j - (\vec{r}_i + \vec{A})) \right) \ne \emptyset \right]\end{split}\]

where the square brackets denote the Iverson bracket.

Note

While this notation is written in as sums over all particles HPMCIntegrator uses spatial data structures to evaluate these calculations efficiently. Similarly, while the overlap test is notated as a set intersection, HPMCIntegrator employs efficient computational geometry algorithms to determine whether there is or is not an overlap.

Implicit depletants

Set HPMCIntegrator.depletant_fugacity to activate the implicit depletant code path. This inerts depletant particles during every trial move and modifies the acceptance criterion accordingly. See Glaser 2015 for details.

class hoomd.hpmc.integrate.ConvexPolygon(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Convex polygon hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of convex polygons. The shape \(S\) of a convex polygon includes the points inside and on the surface of the convex hull of the vertices (see shape). For example:

Example of a convex polygon with vertex labels.

Important

ConvexPolygon simulations must be performed in 2D systems.

See also

Use SimplePolygon for concave polygons.

Wall support.

ConvexPolygon supports no hoomd.wall geometries.

Examples:

mc = hoomd.hpmc.integrate.ConvexPolygon(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(vertices=[(-0.5, -0.5),
                               (0.5, -0.5),
                               (0.5, 0.5),
                               (-0.5, 0.5)]);
print('vertices = ', mc.shape["A"]["vertices"])
shape#

The shape parameters for each particle type. The dictionary has the following keys.

  • vertices (list [tuple [float, float]], required) - vertices of the polygon \([\mathrm{length}]\).

    • Vertices MUST be specified in a counter-clockwise order.

    • The origin MUST be contained within the polygon.

    • Points inside the polygon MUST NOT be included.

    • The origin centered circle that encloses all vertices should be of minimal size for optimal performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (float, default: 0.0) - Ignored, but present because ConvexPolygon shares data structures with ConvexSpheropolygon \([\mathrm{length}]\).

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'Polygon', 'sweep_radius': 0,
  'vertices': [[-0.5, -0.5], [0.5, -0.5], [0.5, 0.5], [-0.5, 0.5]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.ConvexPolyhedron(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Convex polyhedron hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of convex polyhedra. The shape \(S\) of a convex polyhedron includes the points inside and on the surface of the convex hull of the vertices (see shape). For example:

Example of a convex polyhedron with vertex labels.

See also

Use Polyhedron for concave polyhedra.

Wall support.

ConvexPolyhedron supports all hoomd.wall geometries.

Example:

mc = hpmc.integrate.ConvexPolyhedron(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(vertices=[(0.5, 0.5, 0.5),
                               (0.5, -0.5, -0.5),
                               (-0.5, 0.5, -0.5),
                               (-0.5, -0.5, 0.5)]);
print('vertices = ', mc.shape["A"]["vertices"])
shape#

The shape parameters for each particle type. The dictionary has the following keys.

  • vertices (list [tuple [float, float, float]], required) - vertices of the polyhedron \([\mathrm{length}]\).

    • The origin MUST be contained within the polyhedron.

    • The origin centered sphere that encloses all vertices should be of minimal size for optimal performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (float, default: 0.0) - Ignored, but present because ConvexPolyhedron shares data structures with ConvexSpheropolyhedron \([\mathrm{length}]\).

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'ConvexPolyhedron', 'sweep_radius': 0,
  'vertices': [[0.5, 0.5, 0.5], [0.5, -0.5, -0.5],
               [-0.5, 0.5, -0.5], [-0.5, -0.5, 0.5]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.ConvexSpheropolygon(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Convex spheropolygon hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of convex spheropolygons. The shape \(S\) of a convex spheropolygon includes the points inside and on the surface of the convex hull of the vertices plus a disk (with radius sweep_radius)swept along the perimeter (see shape). For example:

Example of a convex spheropolygon with vertex and sweep labels.

Important

ConvexSpheropolygon simulations must be performed in 2D systems.

Tip

To model mixtures of convex polygons and convex spheropolygons, use ConvexSpheropolygon and set the sweep radius to 0 for some shape types.

Tip

A 1-vertex spheropolygon is a disk and a 2-vertex spheropolygon is a rectangle with half disk caps.

Wall support.

ConvexSpheropolygon supports no hoomd.wall geometries.

Examples:

mc = hoomd.hpmc.integrate.ConvexSpheropolygon(default_d=0.3,
                                             default_a=0.4)
mc.shape["A"] = dict(vertices=[(-0.5, -0.5),
                               (0.5, -0.5),
                               (0.5, 0.5),
                               (-0.5, 0.5)],
                     sweep_radius=0.1);

mc.shape["A"] = dict(vertices=[(0,0)],
                     sweep_radius=0.5,
                     ignore_statistics=True);

print('vertices = ', mc.shape["A"]["vertices"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • vertices (list [tuple [float, float]], required) - vertices of the polygon \([\mathrm{length}]\).

    • The origin MUST be contained within the spheropolygon.

    • Points inside the polygon should not be included.

    • The origin centered circle that encloses all vertices should be of minimal size for optimal performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (default: 0.0) - radius of the disk swept around the edges of the polygon \([\mathrm{length}]\). Set a non-zero sweep_radius to create a spheropolygon.

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'Polygon', 'sweep_radius': 0.1,
  'vertices': [[-0.5, -0.5], [0.5, -0.5], [0.5, 0.5], [-0.5, 0.5]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.ConvexSpheropolyhedron(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Convex spheropolyhedron hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of convex spheropolyhedra. The shape \(S\) of a convex spheropolyhedron includes the points inside and on the surface of the convex hull of the vertices plus a sphere (with radius sweep_radius) swept along the perimeter (see shape). See ConvexSpheropolygon for a visual example in 2D.

Tip

A 1-vertex spheropolygon is a sphere and a 2-vertex spheropolygon is a spherocylinder.

Wall support.

ConvexSpheropolyhedron supports the hoomd.wall.Sphere and hoomd.wall.Plane geometries.

Example:

mc = hpmc.integrate.ConvexSpheropolyhedron(default_d=0.3, default_a=0.4)
mc.shape['tetrahedron'] = dict(vertices=[(0.5, 0.5, 0.5),
                                         (0.5, -0.5, -0.5),
                                         (-0.5, 0.5, -0.5),
                                         (-0.5, -0.5, 0.5)]);
print('vertices = ', mc.shape['tetrahedron']["vertices"])

mc.shape['SphericalDepletant'] = dict(vertices=[],
                                      sweep_radius=0.1,
                                      ignore_statistics=True);

Depletants example:

mc = hpmc.integrate.ConvexSpheropolyhedron(default_d=0.3, default_a=0.4)
mc.shape["tetrahedron"] = dict(vertices=[(0.5, 0.5, 0.5),
                                         (0.5, -0.5, -0.5),
                                         (-0.5, 0.5, -0.5),
                                         (-0.5, -0.5, 0.5)]);
mc.shape["SphericalDepletant"] = dict(vertices=[], sweep_radius=0.1);
mc.depletant_fugacity["SphericalDepletant"] = 3.0
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • vertices (list [tuple [float, float, float]], required) - vertices of the polyhedron \([\mathrm{length}]\).

    • The origin MUST be contained within the polyhedron.

    • The origin centered sphere that encloses all vertices should be of minimal size for optimal performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (float, default: 0.0) - radius of the sphere swept around the surface of the polyhedron \([\mathrm{length}]\). Set a non-zero sweep_radius to create a spheropolyhedron.

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'ConvexPolyhedron', 'sweep_radius': 0.1,
  'vertices': [[0.5, 0.5, 0.5], [0.5, -0.5, -0.5],
               [-0.5, 0.5, -0.5], [-0.5, -0.5, 0.5]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.ConvexSpheropolyhedronUnion(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Convex spheropolyhedron union hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of unions of convex sphereopolyhedra. The union shape \(S\) is the set union of the given convex spheropolyhedra:

\[S = \bigcup_k S_k(\mathbf{q}_k, \vec{r}_k)\]

Each constituent shape in the union has its own shape parameters \(S_k\), position \(\vec{r}_k`\), and orientation \(\mathbf{q}_k`\) (see shape).

Note

This shape uses an internal OBB tree for fast collision queries. Depending on the number of constituent spheropolyhedra in the tree, different values of the number of spheropolyhedra per leaf node may yield different performance. The capacity of leaf nodes is configurable.

Wall support.

ConvexSpheropolyhedronUnion supports no hoomd.wall geometries.

Example:

mc = hoomd.hpmc.integrate.ConvexSpheropolyhedronUnion(default_d=0.3,
                                                      default_a=0.4)
cube_verts = [[-1,-1,-1],
              [-1,-1,1],
              [-1,1,1],
              [-1,1,-1],
              [1,-1,-1],
              [1,-1,1],
              [1,1,1],
              [1,1,-1]]
mc.shape["A"] = dict(shapes=[cube_verts, cube_verts],
                     positions=[(0, 0, 0), (0, 0, 1)],
                     orientations=[(1, 0, 0, 0), (1, 0, 0, 0)],
                     overlap=[1, 1]);
print('vertices of the first cube = ',
      mc.shape["A"]["shapes"][0]["vertices"])
print('center of the first cube = ', mc.shape["A"]["positions"][0])
print('orientation of the first cube = ',
      mc.shape_param["A"]["orientations"][0])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • shapes (list [dict], required) - Shape parameters for each spheropolyhedron in the union. See ConvexSpheropolyhedron.shape for the accepted parameters.

  • positions (list [tuple [float, float, float]], required) - Position of each spheropolyhedron in the union. \([\mathrm{length}]\)

  • orientations (list [ tuple [float, float, float, float]], default: None) - Orientation of each spheropolyhedron in the union. When not None, orientations must have a length equal to that of positions. When None (the default), orientations is initialized with all [1,0,0,0]’s.

  • overlap (list [int], default: None) - Check for overlaps between constituent particles when overlap [i] & overlap[j] is nonzero (& is the bitwise AND operator). When not None, overlap must have a length equal to that of positions. When None (the default), overlap is initialized with all 1’s.

  • capacity (int, default: 4) - set the maximum number of particles per leaf node to adjust performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

Type:

TypeParameter [particle type, dict]

class hoomd.hpmc.integrate.Ellipsoid(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Ellipsoid hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of ellipsoids. The shape \(S\) includes all points inside and on the surface of an ellipsoid:

\[S = \left \{ \vec{r} : \frac{r_x^2}{a^2} + \frac{r_y^2}{b^2} + \frac{r_z^2}{c^2} \le 1 \right\}\]

where \(r_x\), \(r_y\), \(r_z\) are the components of \(\vec{r}\), and the parameters \(a\), \(b\), and \(c\) are the half axes of the ellipsoid set in shape.

Wall support.

Ellipsoid supports no hoomd.wall geometries.

Example:

mc = hpmc.integrate.Ellipsoid(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(a=0.5, b=0.25, c=0.125);
print('ellipsoids parameters (a,b,c) = ',
      mc.shape["A"]["a"],
      mc.shape["A"]["b"],
      mc.shape["A"]["c"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • a (float, required) - half axis of ellipsoid in the x direction \([\mathrm{length}]\)

  • b (float, required) - half axis of ellipsoid in the y direction \([\mathrm{length}]\)

  • c (float, required) - half axis of ellipsoid in the z direction \([\mathrm{length}]\)

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'Ellipsoid', 'a': 1.0, 'b': 1.5, 'c': 1}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.FacetedEllipsoid(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Faceted ellipsoid hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of faceted ellipsoids. The shape \(S\) of a faceted ellipsoid is the intersection of an ellipsoid with a convex polyhedron defined through halfspaces (see shape). The equation defining each halfspace is given by:

\[\vec{n}_i\cdot \vec{r} + b_i \le 0\]

where \(\vec{n}_i\) is the face normal, and \(b_i\) is the offset.

Wall support.

FacetedEllipsoid supports no hoomd.wall geometries.

Example:

mc = hpmc.integrate.FacetedEllipsoid(default_d=0.3, default_a=0.4)

# half-space intersection
slab_normals = [(-1,0,0),(1,0,0),(0,-1,0),(0,1,0),(0,0,-1),(0,0,1)]
slab_offsets = [-0.1,-1,-.5,-.5,-.5,-.5]

# polyedron vertices
slab_verts = [[-.1,-.5,-.5],
              [-.1,-.5,.5],
              [-.1,.5,.5],
              [-.1,.5,-.5],
              [1,-.5,-.5],
              [1,-.5,.5],
              [1,.5,.5],
              [1,.5,-.5]]

mc.shape["A"] = dict(normals=slab_normals,
                     offsets=slab_offsets,
                     vertices=slab_verts,
                     a=1.0,
                     b=0.5,
                     c=0.5);
print('a = {}, b = {}, c = {}',
      mc.shape["A"]["a"], mc.shape["A"]["b"], mc.shape["A"]["c"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • normals (list [tuple [float, float, float]], required) - facet normals \(\\vec{n}_i\).

  • offsets (list [float], required) - list of offsets \(b_i\) \([\mathrm{length}^2]\)

  • a (float, required) - half axis of ellipsoid in the x direction \([\mathrm{length}]\)

  • b (float, required) - half axis of ellipsoid in the y direction \([\mathrm{length}]\)

  • c (float, required) - half axis of ellipsoid in the z direction \([\mathrm{length}]\)

  • vertices (list [tuple [float, float, float]], default: []) - list of vertices for intersection polyhedron (see note below). \([\mathrm{length}]\)

  • origin (tuple [float, float, float], default: (0,0,0)) - A point inside the shape. \([\mathrm{length}]\)

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

Important

The origin must be chosen so as to lie inside the shape, or the overlap check will not work. This condition is not checked.

Warning

Planes must not be coplanar.

Note

For simple intersections with planes that do not intersect within the sphere, the vertices list can be left empty. When specified, the half-space intersection of the normals must match the convex polyhedron defined by the vertices (if non-empty), the half-space intersection is not calculated automatically.

Type:

TypeParameter[particle type, dict]

class hoomd.hpmc.integrate.FacetedEllipsoidUnion(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Faceted ellispod union hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of unions of faceted ellipsoids. The union shape \(S\) is the set union of the given faceted ellipsoids:

\[S = \bigcup_k S_k(\mathbf{q}_k, \vec{r}_k)\]

Each constituent shape in the union has its own shape parameters \(S_k\), position \(\vec{r}_k`\), and orientation \(\mathbf{q}_k`\) (see shape).

Note

This shape uses an internal OBB tree for fast collision queries. Depending on the number of constituent faceted ellipsoids in the tree, different values of the number of faceted ellipsoids per leaf node may yield different performance. The capacity of leaf nodes is configurable.

Wall support.

FacetedEllipsoidUnion supports no hoomd.wall geometries.

Example:

mc = hpmc.integrate.FacetedEllipsoidUnion(default_d=0.3, default_a=0.4)

# make a prolate Janus ellipsoid
# cut away -x halfspace
normals = [(-1,0,0)]
offsets = [0]
slab_normals = [(-1,0,0),(1,0,0),(0,-1,0),(0,1,0),(0,0,-1),(0,0,1)]
slab_offsets = [-0.1,-1,-.5,-.5,-.5,-.5)

# polyedron vertices
slab_verts = [[-.1,-.5,-.5],
              [-.1,-.5,.5],
              [-.1,.5,.5],
              [-.1,.5,-.5],
              [1,-.5,-.5],
              [1,-.5,.5],
              [1,.5,.5],
              [1,.5,-.5]]

faceted_ellipsoid1 = dict(normals=slab_normals,
                          offsets=slab_offsets,
                          vertices=slab_verts,
                          a=1.0,
                          b=0.5,
                          c=0.5);
faceted_ellipsoid2 = dict(normals=slab_normals,
                          offsets=slab_offsets,
                          vertices=slab_verts,
                          a=0.5,
                          b=1,
                          c=1);

mc.shape["A"] = dict(shapes=[faceted_ellipsoid1, faceted_ellipsoid2],
                     positions=[(0, 0, 0), (0, 0, 1)],
                     orientations=[(1, 0, 0, 0), (1, 0, 0, 0)],
                     overlap=[1, 1]);

print('offsets of the first faceted ellipsoid = ',
      mc.shape["A"]["shapes"][0]["offsets"])
print('normals of the first faceted ellipsoid = ',
      mc.shape["A"]["shapes"][0]["normals"])
print('vertices of the first faceted ellipsoid = ',
      mc.shape["A"]["shapes"][0]["vertices"]
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • shapes (list [ dict], required) - Shape parameters for each faceted ellipsoid in the union. See FacetedEllipsoid.shape for the accepted parameters.

  • positions (list [tuple [float, float, float]], required) - Position of each faceted ellipsoid in the union. \([\mathrm{length}]\)

  • orientations (list [tuple [float, float, float, float]], default: None) - Orientation of each faceted ellipsoid in the union. When not None, orientations must have a length equal to that of positions. When None (the default), orientations is initialized with all [1,0,0,0]’s.

  • overlap (list [int], default: None) - Check for overlaps between constituent particles when overlap [i] & overlap[j] is nonzero (& is the bitwise AND operator). When not None, overlap must have a length equal to that of positions. When None (the default), overlap is initialized with all 1’s.

  • capacity (int, default: 4) - set the maximum number of particles per leaf node to adjust performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

Type:

TypeParameter [particle type, dict]

class hoomd.hpmc.integrate.HPMCIntegrator(default_d, default_a, translation_move_probability, nselect)#

Bases: Integrator

Base class hard particle Monte Carlo integrator.

HPMCIntegrator is the base class for all HPMC integrators. The attributes documented here are available to all HPMC integrators.

See also

The module level documentation hoomd.hpmc.integrate describes the hard particle Monte Carlo algorithm.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

Ignoring overlap checks

Set elements of interaction_matrix to False to disable overlap checks between specific pairs of particle types.

Writing type_shapes to GSD files.

Use a Logger in combination with a HPMC integrator and a GSD writer to write type_shapes to the GSD file for use with OVITO. For example:

mc = hoomd.hpmc.integrate.Sphere()
log = hoomd.logging.Logger()
log.add(mc, quantities=['type_shapes'])
gsd = hoomd.write.GSD(
    'trajectory.gsd', hoomd.trigger.Periodic(1000), log=log)

Threading

HPMC integrators use threaded execution on multiple CPU cores only when placing implicit depletants (depletant_fugacity != 0).

Mixed precision

All HPMC integrators use reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

Parameters

a#

Maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

Type:

TypeParameter [particle type, float]

d#

Maximum size of displacement trial moves \([\mathrm{length}]\).

Type:

TypeParameter [particle type, float]

depletant_fugacity#

Depletant fugacity \([\mathrm{volume}^{-1}]\) (default: 0)

Allows setting the fugacity per particle type, e.g. 'A' refers to a depletant of type A.

Type:

TypeParameter [ particle type, float]

depletant_ntrial#

Multiplicative factor for the number of times a depletant is inserted. This factor is accounted for in the acceptance criterion so that detailed balance is unchanged. Higher values of ntrial (than one) can be used to reduce the variance of the free energy estimate and improve the acceptance rate of the Markov chain.

Type:

TypeParameter [particle type, int]

interaction_matrix#

Set to False for a pair of particle types to disable overlap checks between particles of those types (default: True).

Type:

TypeParameter [ tuple [particle type, particle type], bool]

translation_move_probability#

Fraction of moves to be selected as translation moves.

Type:

float

nselect#

Number of trial moves to perform per particle per timestep.

Type:

int

Attributes

__dir__()#

Expose all attributes for dynamic querying in notebooks and IDEs.

property counters#

Trial move counters.

The counter object has the following attributes:

  • translate: tuple [int, int] - Number of accepted and rejected translate trial moves.

  • rotate: tuple [int, int] - Number of accepted and rejected rotate trial moves.

  • overlap_checks: int - Number of overlap checks performed.

  • overlap_errors: int - Number of overlap checks that were too close to resolve.

Note

The counts are reset to 0 at the start of each hoomd.Simulation.run.

Type:

dict

property external_potential#

The user-defined potential energy field integrator.

Defines the external energy \(U_{\mathrm{external},i}\). Defaults to None. May be set to an object from hoomd.hpmc.external.

property is_tuning_complete#

Check if kernel parameter tuning is complete.

True when tuning is complete and kernel_parameters has locked optimal parameters for all active kernels used by this object.

Type:

bool

property kernel_parameters#

Kernel parameters.

The dictionary maps GPU kernel names to tuples of integers that control how the kernel executes on the GPU. These values will change during the tuning process and remain static after tuning completes. Set the kernel parameters for one or more kernels to force specific values and stop tuning.

Warning

The keys and valid values in this dictionary depend on the hardware device, the HOOMD-blue version, and the value of class attributes. Keys and/or valid values may change even with new patch releases of HOOMD-blue.

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.

Type:

dict[str, tuple[float]]

property loggables#

Name, category mapping of loggable quantities.

Type:

dict[str, str]

property map_overlaps#

List of overlapping particles.

The list contains one entry for each overlapping pair of particles. When a tuple (i,j) is present in the list, there is an overlap between the particles with tags i and j.

Attention

map_overlaps does not support MPI parallel simulations. It returns None when there is more than one MPI rank.

(Loggable: category=”sequence”)

Type:

list[tuple[int, int]]

property mps#

Number of trial moves performed per second.

Note

The count is reset at the start of each hoomd.Simulation.run.

(Loggable: category=”scalar”)

Type:

float

property overlaps#

Number of overlapping particle pairs.

(Loggable: category=”scalar”)

Type:

int

property pair_potential#

The user-defined pair potential.

Defines the pairwise particle interaction energy \(U_{\mathrm{pair},ij}\). Defaults to None. May be set to an object from hoomd.hpmc.pair.

property rotate_moves#

Count of the accepted and rejected rotate moves.

Note

The counts are reset to 0 at the start of each hoomd.Simulation.run.

(Loggable: category=”sequence”)

Type:

tuple[int, int]

property translate_moves#

Count of the accepted and rejected translate moves.

Note

The counts are reset to 0 at the start of each hoomd.Simulation.run.

(Loggable: category=”sequence”)

Type:

tuple[int, int]

tune_kernel_parameters()#

Start tuning kernel parameters.

After calling tune_kernel_parameters, AutotunedObject will vary the kernel parameters in subsequent time steps, check the run time of each, and lock to the fastest performing parameters after the scan is complete.

class hoomd.hpmc.integrate.Polyhedron(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Polyhedron hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of general polyhedra. The shape \(S\) contains the points inside the polyhedron defined by vertices and faces (see shape). Polyhedron supports triangle meshes and spheres only. The mesh must be free of self-intersections.

See also

Use ConvexPolyhedron for faster performance with convex polyhedra.

Note

This shape uses an internal OBB tree for fast collision queries. Depending on the number of constituent faces in the tree, different values of the number of faces per leaf node may yield different optimal performance. The capacity of leaf nodes is configurable.

Wall support.

Polyhedron supports no hoomd.wall geometries.

Example:

mc = hpmc.integrate.Polyhedron(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(vertices=[(-0.5, -0.5, -0.5),
                               (-0.5, -0.5, 0.5),
                               (-0.5, 0.5, -0.5),
                               (-0.5, 0.5, 0.5),
                               (0.5, -0.5, -0.5),
                               (0.5, -0.5, 0.5),
                               (0.5, 0.5, -0.5),
                               (0.5, 0.5, 0.5)],
                    faces=[[0, 2, 6],
                           [6, 4, 0],
                           [5, 0, 4],
                           [5, 1, 0],
                           [5, 4, 6],
                           [5, 6, 7],
                           [3, 2, 0],
                           [3, 0, 1],
                           [3, 6, 2],
                           [3, 7, 6],
                           [3, 1, 5],
                           [3, 5, 7]])
print('vertices = ', mc.shape["A"]["vertices"])
print('faces = ', mc.shape["A"]["faces"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • vertices (list [tuple [float, float, float]], required) - vertices of the polyhedron \([\mathrm{length}]\).

    • The origin MUST strictly be contained in the generally nonconvex volume defined by the vertices and faces.

    • The origin centered sphere that encloses all vertices should be of minimal size for optimal performance.

  • faces (list [tuple [int, int, int], required) - Vertex indices for every triangle in the mesh.

    • For visualization purposes, the faces MUST be defined with a counterclockwise winding order to produce an outward normal.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (float, default: 0.0) - radius of the sphere swept around the surface of the polyhedron \([\mathrm{length}]\). Set a non-zero sweep_radius to create a spheropolyhedron.

  • overlap (list [int], default: None) - Check for overlaps between faces when overlap [i] & overlap[j] is nonzero (& is the bitwise AND operator). When not None, overlap must have a length equal to that of faces. When None (the default), overlap is initialized with all 1’s.

  • capacity (int, default: 4) - set the maximum number of particles per leaf node to adjust performance.

  • origin (tuple [float, float, float], default: (0,0,0)) - a point strictly inside the shape, needed for correctness of overlap checks.

  • hull_only (bool, default: False) - When True, only check for intersections between the convex hulls.

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'Mesh', 'vertices': [[0.5, 0.5, 0.5], [0.5, -0.5, -0.5],
  [-0.5, 0.5, -0.5], [-0.5, -0.5, 0.5]],
  'faces': [[0, 1, 2], [0, 3, 1], [0, 2, 3], [1, 3, 2]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.SimplePolygon(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Simple polygon hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of simple polygons. The shape \(S\) of a simple polygon includes the points inside and on the surface of the simple polygon defined by the vertices (see shape). For example:

Example of a simple polygon with vertex labels.

Important

SimplePolygon simulations must be performed in 2D systems.

See also

Use ConvexPolygon for faster performance with convex polygons.

Wall support.

SimplePolygon supports no hoomd.wall geometries.

Examples:

mc = hpmc.integrate.SimplePolygon(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(vertices=[(0, 0.5),
                               (-0.5, -0.5),
                               (0, 0),
                               (0.5, -0.5)]);
print('vertices = ', mc.shape["A"]["vertices"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • vertices (list [tuple [float, float]], required) - vertices of the polygon \([\mathrm{length}]\).

    • Vertices MUST be specified in a counter-clockwise order.

    • The polygon may be concave, but edges must not cross.

    • The origin may be inside or outside the shape.

    • The origin centered circle that encloses all vertices should be of minimal size for optimal performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (float, default: 0.0) - Ignored, but present because SimplePolygon shares data structures with ConvexSpheropolygon \([\mathrm{length}]\).

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'Polygon', 'sweep_radius': 0,
  'vertices': [[-0.5, -0.5], [0.5, -0.5], [0.5, 0.5], [-0.5, 0.5]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.Sphere(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Sphere hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of spheres. The shape \(S\) includes all points inside and on the surface of a sphere:

\[S = \left \{ \vec{r} : \frac{\vec{r}\cdot\vec{r}}{(d/2)^2} \le 1 \right\}\]

where \(d\), is the diameter set in shape. When the shape parameter orientable is False (the default), Sphere only applies translation trial moves and ignores translation_move_probability.

Tip

Use spheres with diameter=0 in conjunction with pair potentials for Monte Carlo simulations of particles with no hard core.

Tip

Use Sphere in a 2D simulation to perform Monte Carlo on hard disks.

Wall support.

Sphere supports all hoomd.wall geometries.

Examples:

mc = hoomd.hpmc.integrate.Sphere(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(diameter=1.0)
mc.shape["B"] = dict(diameter=2.0)
mc.shape["C"] = dict(diameter=1.0, orientable=True)
print('diameter = ', mc.shape["A"]["diameter"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • diameter (float, required) - Sphere diameter \([\mathrm{length}]\).

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • orientable (bool, default: False) - set to True to allow rotation moves on this particle type.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Examples

The types will be ‘Sphere’ regardless of dimensionality.

>>> mc.type_shapes
[{'type': 'Sphere', 'diameter': 1},
 {'type': 'Sphere', 'diameter': 2}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.SphereUnion(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Sphere union hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of unions of spheres. The union shape \(S\) is the set union of the given spheres:

\[S = \bigcup_k S_k(\mathbf{q}_k, \vec{r}_k)\]

Each constituent shape in the union has its own shape parameters \(S_k\), position \(\vec{r}_k`\), and orientation \(\mathbf{q}_k`\) (see shape).

Note

This shape uses an internal OBB tree for fast collision queries. Depending on the number of constituent spheres in the tree, different values of the number of spheres per leaf node may yield different performance. The capacity of leaf nodes is configurable.

Wall support.

SphereUnion supports no hoomd.wall geometries.

Example:

mc = hpmc.integrate.SphereUnion(default_d=0.3, default_a=0.4)
sphere1 = dict(diameter=1)
sphere2 = dict(diameter=2)
mc.shape["A"] = dict(shapes=[sphere1, sphere2],
                     positions=[(0, 0, 0), (0, 0, 1)],
                     orientations=[(1, 0, 0, 0), (1, 0, 0, 0)],
                     overlap=[1, 1])
print('diameter of the first sphere = ',
      mc.shape["A"]["shapes"][0]["diameter"])
print('center of the first sphere = ', mc.shape["A"]["positions"][0])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • shapes (list [dict], required) - Shape parameters for each sphere in the union. See Sphere.shape for the accepted parameters.

  • positions (list [tuple [float, float, float]], required) - Position of each sphere in the union. \([\mathrm{length}]\)

  • orientations (list [tuple [float, float, float, float]], default: None) - Orientation of each sphere in the union. When not None, orientations must have a length equal to that of positions. When None (the default), orientations is initialized with all [1,0,0,0]’s.

  • overlap (list [int], default: None) - Check for overlaps between constituent particles when overlap [i] & overlap[j] is nonzero (& is the bitwise AND operator). When not None, overlap must have a length equal to that of positions. When None (the default), overlap is initialized with all 1’s.

  • capacity (int, default: 4) - set the maximum number of particles per leaf node to adjust performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Examples

The type will be ‘SphereUnion’ regardless of dimensionality.

>>> mc.type_shapes
[{'type': 'SphereUnion',
  'centers': [[0, 0, 0], [0, 0, 1]],
  'diameters': [1, 0.5]},
 {'type': 'SphereUnion',
  'centers': [[1, 2, 3], [4, 5, 6]],
  'diameters': [0.5, 1]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.integrate.Sphinx(default_d=0.1, default_a=0.1, translation_move_probability=0.5, nselect=4)#

Bases: HPMCIntegrator

Sphinx hard particle Monte Carlo integrator.

Parameters:
  • default_d (float) – Default maximum size of displacement trial moves \([\mathrm{length}]\).

  • default_a (float) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\).

  • translation_move_probability (float) – Fraction of moves that are translation moves.

  • nselect (int) – Number of trial moves to perform per particle per timestep.

Perform hard particle Monte Carlo of sphere unions and differences, depending on the sign of the diameter. The shape \(S\) is:

\[S = \left(\bigcup_{k,d_k\ge 0} S_k((1, 0, 0, 0), \vec{r}_k) \right) \setminus \left(\bigcup_{k,d_k < 0} S_k((1, 0, 0, 0), \vec{r}_k) \right)\]

Where \(d_k\) is the diameter given in shape, \(\vec{r}_k\) is the center given in shape and \(S_k\) is the set of points in a sphere or diameter \(|d_k|\).

Wall support.

Sphinx supports no hoomd.wall geometries.

Example:

mc = hpmc.integrate.Sphinx(default_d=0.3, default_a=0.4)
mc.shape["A"] = dict(centers=[(0,0,0),(1,0,0)], diameters=[1,.25])
print('diameters = ', mc.shape["A"]["diameters"])
shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • diameters (list [float], required) - diameters of spheres (positive OR negative real numbers) \([\mathrm{length}]\).

  • centers (list [tuple [float, float, float], required) - centers of spheres in local coordinate frame \([\mathrm{length}]\).

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

Type:

TypeParameter [particle type, dict]

hoomd.hpmc.nec#

Newtonian event chain Monte Carlo.

The integrators in hoomd.hpmc.nec implement Newtonian event chain Monte Carlo as described in Klement 2021.

Newtonian event chain Monte Carlo combines rejection free particle chain translation moves with traditional local rotation trial moves to explore phase space. This combination can lead to more efficient simulations. See the paper for a full description of the method.

A chain move is rejection free and changes the positions of many particles, but does not change their orientations. Mix one chain move with many rotation moves to effectively explore phase space. The author suggests setting chain_probability to a low value, such as 0.1. As with traditional HPMC, tune the maximum rotation move size a to achieve a target acceptance ratio, such as 20%.

Important

Chain moves translate particles along their velocity vectors. You must set a non-zero velocity for every particle in the simulation state to use NEC. For example, start with a thermal distribution using:

sim.state.thermalize_particle_momenta(hoomd.filter.All(), kT=1)

The chain_time parameter determines the total length of each chain move. Like the d parameter in HPMC with local trial moves, the value of chain_time greatly impacts the rate at which the simulation explores phase space. See Klement 2021 for a full description on how to choose chain_time optimally. As a starting point, use hoomd.hpmc.nec.tune.ChainTime to attain an average of 20 particles per chain move.

The NEC method uses the d parameter as a search radius for collisions and updates the translation move acceptance counter when it finds a collision within the distance d. Changing d will not change the chain moves NEC makes, but it will adjust the wall time needed to complete the moves. Set d too high and performance will slow due to many narrow phase collisions checks. See d too low and performance will slow due to many broad phase collision checks. Adjust d to obtain optimal performance. The code author suggests tuning d to an “acceptance ratio” of 10% as a starting point.

Modules

hoomd.hpmc.nec.integrate#

Overview

ConvexPolyhedron

HPMC integration for convex polyhedra (3D) with nec.

HPMCNECIntegrator

HPMC Chain Integrator base class.

Sphere

HPMC chain integration for spheres (2D/3D).

Details

Newtonain Event-Chain Integrators for Hard Particle Monte Carlo.

class hoomd.hpmc.nec.integrate.ConvexPolyhedron(default_d=0.1, default_a=0.1, chain_probability=0.5, chain_time=0.5, update_fraction=0.5, nselect=1)#

Bases: HPMCNECIntegrator

HPMC integration for convex polyhedra (3D) with nec.

Parameters:
  • default_d (float, optional) – Default colission search distance \([\mathrm{length}]\), defaults to 0.1.

  • default_a (float, optional) – Default maximum size of rotation trial moves \([\mathrm{dimensionless}]\), defaults to 0.1.

  • chain_probability (float, optional) – Probability of making a chain move instead of a rotation move, defaults to 0.5.

  • chain_time (float, optional) – Length of a chain \([\mathrm{time}]\), defaults to 0.5.

  • update_fraction (float, optional) – Number of chains to be done as fraction of N, defaults to 0.5.

  • nselect (int, optional) – Number of repeated updates for the cell/system, defaults to 1.

Perform Newtonian event chain Monte Carlo integration of convex polyhedra.

Wall support.

ConvexPolyhedron supports no hoomd.wall geometries.

Potential support.

ConvexPolyhedron does not support pair_potential or external_potential.

Attention

ConvexPolyhedron does not support execution on GPUs.

Attention

ConvexPolyhedron does not support MPI parallel simulations.

Example:

mc = hoomd.hpmc.nec.integrate.ConvexPolyhedron(d=1.0, a=0.05,
    chain_probability=0.1, nselect=10)
mc.shape['A'] = dict(vertices=[[1,1,1], [1,1,-1], [1,-1,1], [1,-1,-1],
    [-1,1,1], [-1,1,-1], [-1,-1,1], [-1,-1,-1]])
chain_probability#

Probability of making a chain move instead of a rotation move.

Type:

float

chain_time#

Length of a chain \([\mathrm{time}]\).

Type:

float

update_fraction#

Number of chains to be done as fraction of N.

Type:

float

shape#

The shape parameters for each particle type. The dictionary has the following keys.

  • vertices (list [tuple [float, float, float]], required) - vertices of the polyhedron \([\mathrm{length}]\).

    • The origin MUST be contained within the polyhedron.

    • The origin centered sphere that encloses all vertices should be of minimal size for optimal performance.

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • sweep_radius (float, default: 0.0) - Ignored, but present because ConvexPolyhedron shares data structures with ConvexSpheropolyhedron \([\mathrm{length}]\).

Warning

HPMC does not check that all vertex requirements are met. Undefined behavior will result when they are violated.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Example

>>> mc.type_shapes()
[{'type': 'ConvexPolyhedron', 'sweep_radius': 0,
  'vertices': [[0.5, 0.5, 0.5], [0.5, -0.5, -0.5],
               [-0.5, 0.5, -0.5], [-0.5, -0.5, 0.5]]}]

(Loggable: category=”object”)

Type:

list[dict]

class hoomd.hpmc.nec.integrate.HPMCNECIntegrator(default_d=0.1, default_a=0.1, chain_probability=0.5, chain_time=0.5, update_fraction=0.5, nselect=1)#

Bases: HPMCIntegrator

HPMC Chain Integrator base class.

HPMCNECIntegrator is the base class for all HPMC Newtonian event chain integrators. The attributes documented here are available to all HPMC integrators.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

property chains_in_space#

rate of chain events that did neither collide nor end.

Note

The statistics are reset at every hoomd.Simulation.run.

(Loggable: category=”scalar”)

Type:

float

property nec_counters#

Trial move counters.

The counter object has the following attributes:

  • chain_start_count: int Number of chains

  • chain_at_collision_count: int Number of collisions

  • chain_no_collision_count: int Number of chain events that are no collision (i.e. no collision partner found or end of chain)

  • distance_queries: int Number of sweep distances calculated

  • overlap_errors: int Number of errors during sweep calculations

Note

The counts are reset to 0 at the start of each hoomd.Simulation.run.

property particles_per_chain#

particles per chain.

Note

The statistics are reset at every hoomd.Simulation.run.

(Loggable: category=”scalar”)

Type:

float

property virial_pressure#

virial pressure.

Note

The statistics are reset at every timestep.

(Loggable: category=”scalar”)

Type:

float

class hoomd.hpmc.nec.integrate.Sphere(default_d=0.1, chain_time=0.5, update_fraction=0.5, nselect=1)#

Bases: HPMCNECIntegrator

HPMC chain integration for spheres (2D/3D).

Parameters:
  • default_d (float, optional) – Default colission search distance \([\mathrm{length}]\), defaults to 0.1.

  • chain_time (float, optional) – Length of a chain \([\mathrm{time}]\), defaults to 0.5.

  • update_fraction (float, optional) – Number of chains to be done as fraction of N, defaults to 0.5.

  • nselect (int, optional) – The number of repeated updates to perform in each cell, defaults to 1.

Perform Newtonian event chain Monte Carlo integration of spheres.

Wall support.

Sphere supports no hoomd.wall geometries.

Potential support.

Sphere does not support pair_potential or external_potential.

Attention

Sphere does not support execution on GPUs.

Attention

Sphere does not support MPI parallel simulations.

Example:

mc = hoomd.hpmc.integrate.nec.Sphere(d=0.05, update_fraction=0.05)
mc.chain_time = 0.05
chain_time#

Length of a chain \([\mathrm{time}]\).

Type:

float

update_fraction#

Number of chains to be done as fraction of N.

Type:

float

shape#

The shape parameters for each particle type. The dictionary has the following keys:

  • diameter (float, required) - Sphere diameter \([\mathrm{length}]\).

  • ignore_statistics (bool, default: False) - set to True to ignore tracked statistics.

  • orientable (bool, default: False) - set to True to allow rotation moves on this particle type.

Type:

TypeParameter [particle type, dict]

property type_shapes#

Description of shapes in type_shapes format.

Examples

The types will be ‘Sphere’ regardless of dimensionality.

>>> mc.type_shapes
[{'type': 'Sphere', 'diameter': 1},
 {'type': 'Sphere', 'diameter': 2}]

(Loggable: category=”object”)

Type:

list[dict]

hoomd.hpmc.nec.tune#

Overview

ChainTime

Tunes HPMCNECIntegrator chain time to targeted mean particles per chain.

Details

Tune Newtonian event chain parameters.

class hoomd.hpmc.nec.tune.ChainTime(trigger, *args, **kwargs)#

Tunes HPMCNECIntegrator chain time to targeted mean particles per chain.

Tip

For the most common creation of a ChainTime tuner see ChainTime.secant_solver and ChainTime.scale_solver respectively.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • solver (hoomd.tune.RootSolver) – A solver that tunes chain times to reach the specified target.

  • max_chain_time (float) – The maximum value of chain time to attempt.

trigger#

Trigger to determine when to run the tuner.

Type:

hoomd.trigger.Trigger

target#

The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

Type:

float

solver#

A solver that tunes move sizes to reach the specified target.

Type:

hoomd.tune.RootSolver

max_chain_time#

The maximum value of chain time to attempt.

Type:

float

classmethod scale_solver(trigger, target, max_chain_time=None, max_scale=2.0, gamma=1.0, tol=0.01)#

Create a ChainTime tuner with a hoomd.tune.ScaleSolver.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • target (float) – The number of collisions in a chain that is desired.

  • max_chain_time (float) – The maximum value of chain time to attempt.

  • max_scale (float) – The maximum amount to scale the current chain_time value with.

  • gamma (float) – The value of gamma to pass through to hoomd.tune.ScaleSolver. Controls the size of corrections to the move size (larger values increase stability while increasing convergence time).

  • tol (float) – The absolute tolerance to allow between the current acceptance rate and the target before the move sizes are considered tuned. The tolerance should not be too much lower than the default of 0.01 as acceptance rates can vary significantly at typical tuning rates.

classmethod secant_solver(trigger, target, max_chain_time=None, gamma=0.8, tol=0.01)#

Create a ChainTime tuner with a hoomd.tune.SecantSolver.

This solver can be faster than hoomd.tune.ScaleSolver, but depending on the system slightly less stable. In general, with the default value of gamma this should not be a problem.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • target (float) – The number of collisions in a chain that is desired.

  • max_chain_time (float) – The maximum value of chain time to attempt, defaults to None which represents no maximum chain time.

  • gamma (float) – The value of gamma to pass through to hoomd.tune.SecantSolver. Controls the size of corrections to the move size (smaller values increase stability). Should be between 0 and 1, defaults to 0.8.

  • tol (float) – The absolute tolerance to allow between the current acceptance rate and the target before the move sizes are considered tuned. The tolerance should not be too much lower than the default of 0.01 as acceptance rates can vary significantly at typical tuning rates.

Note

Increasing gamma towards 1 does not necessarily speed up convergence and can slow it done. In addition, large values of gamma can make the solver unstable especially when tuning frequently.

hoomd.hpmc.tune#

Overview

BoxMCMoveSize

Tunes BoxMC move sizes to targeted acceptance rate.

MoveSize

Tunes HPMCIntegrator move sizes to targeted acceptance rate.

Details

Tuners for HPMC.

class hoomd.hpmc.tune.BoxMCMoveSize(trigger, *args, **kwargs)#

Tunes BoxMC move sizes to targeted acceptance rate.

Tip

For most common creation of a BoxMCMoveSize tuner see BoxMCMoveSize.secant_solver and BoxMCMoveSize.scale_solver respectively.

The tuner will continue tuning despite being tuned. Thus, if simulation conditions change the move sizes will continue to change and the tuner will no longer be tuned. The changes to the move size are completely controlled by the given hoomd.tune.RootSolver instance. See the doumentation at hoomd.tune for more information.

Warning

The tuner should be removed from the simulation once tuned to prevent invalid results due to the breaking of balance.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • boxmc (hoomd.hpmc.update.BoxMC) – The hoomd.hpmc.update.BoxMC object to tune.

  • moves (list[str]) – A list of types of moves to tune. Available options are ‘volume’, ‘aspect’, ‘shear_{x,y,z}’, and ‘length_{x,y,z}’ where brackets denote multiple options. For shear and length moves each dimension is tuned independently.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • solver (hoomd.tune.RootSolver) – A solver that tunes move sizes to reach the specified target.

  • max_move_size (dict [str, float ], optional) – The maximum volume move size to attempt for each move time. See the available moves in the moves attribute documentation. Defaults to no maximum None for each move type.

trigger#

Trigger to determine when to run the tuner.

Type:

hoomd.trigger.Trigger

boxmc#

The hoomd.hpmc.update.BoxMC object to tune.

Type:

hoomd.hpmc.update.BoxMC

moves#

A list of types of moves to tune. Available options are ‘volume’, ‘aspect’, ‘shear_{x,y,z}’, and ‘length_{x,y,z}’ where brackets denote multiple options. For shear and length moves each dimension is tuned independently.

Type:

list[str]

target#

The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

Type:

float

solver#

A solver that tunes move sizes to reach the specified target.

Type:

hoomd.tune.RootSolver

max_move_size#

The maximum volume move size to attempt for each move time. See the available moves in the moves attribute documentation.

Type:

float

Warning

Over-limiting the maximum move sizes can lead to the inability to converge to the desired acceptance rate.

Warning

Since each dimension of length and shear moves are tuned independently but the acceptance statistics are collected collectively, the reachable target acceptance rates is limited by the other dimensions.

classmethod scale_solver(trigger, boxmc, moves, target, max_move_size=None, max_scale=2.0, gamma=1.0, tol=0.01)#

Create a BoxMCMoveSize tuner with a hoomd.tune.ScaleSolver.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • boxmc (hoomd.hpmc.update.BoxMC) – The hoomd.hpmc.update.BoxMC object to tune.

  • moves (list[str]) – A list of types of moves to tune. Available options are ‘volume’, ‘aspect’, ‘shear_{x,y,z}’, and ‘length_{x,y,z}’ where brackets denote multiple options. For shear and length moves each dimension is tuned independently.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • max_move_size (float) – The maximum value of a volume move size to attempt.

  • max_scale (float) – Maximum scale factor.

  • gamma (float) – The value of gamma to pass through to hoomd.tune.ScaleSolver. Controls the size of corrections to the move size (larger values increase stability while increasing convergence time).

  • tol (float) – The absolute tolerance to allow between the current acceptance rate and the target before the move sizes are considered tuned. The tolerance should not be too much lower than the default of 0.01 as acceptance rates can vary significantly at typical tuning rates.

classmethod secant_solver(trigger, boxmc, moves, target, max_move_size=None, gamma=0.8, tol=0.01)#

Create a BoxMCMoveSize tuner with a hoomd.tune.SecantSolver.

This solver can be faster than hoomd.tune.ScaleSolver, but depending on the system slightly less stable. In general, with the default value of gamma this should not be a problem.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • boxmc (hoomd.hpmc.update.BoxMC) – The hoomd.hpmc.update.BoxMC object to tune.

  • moves (list[str]) – A list of types of moves to tune. Available options are ‘volume’, ‘aspect’, ‘shear_{x,y,z}’, and ‘length_{x,y,z}’ where brackets denote multiple options. For shear and length moves each dimension is tuned independently.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • max_move_size (float) – The maximum value of a volume move size to attempt, defaults to None which represents no maximum move size.

  • gamma (float) – The value of gamma to pass through to hoomd.tune.SecantSolver. Controls the size of corrections to the move size (smaller values increase stability). Should be between 0 and 1, defaults to 0.8.

  • tol (float) – The absolute tolerance to allow between the current acceptance rate and the target before the move sizes are considered tuned. The tolerance should not be too much lower than the default of 0.01 as acceptance rates can vary significantly at typical tuning rates.

Note

Increasing gamma towards 1 does not necessarily speed up convergence and can slow it done. In addition, large values of gamma can make the solver unstable especially when tuning frequently.

property tuned#

Whether or not the move sizes are considered tuned.

An instance is considered tuned if it the solver tolerance has been met by all tunables for 2 iterations.

Type:

bool

class hoomd.hpmc.tune.MoveSize(trigger, *args, **kwargs)#

Tunes HPMCIntegrator move sizes to targeted acceptance rate.

Tip

Direct instantiation of this class requires a hoomd.tune.RootSolver that determines how move sizes are updated. This class also provides class methods to create a MoveSize tuner with built-in solvers; see MoveSize.secant_solver and MoveSize.scale_solver.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • moves (list[str]) – A list of types of moves to tune. Available options are 'a' and 'd'.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • solver (hoomd.tune.RootSolver) – A solver that tunes move sizes to reach the specified target.

  • types (list[str]) – A list of string particle types to tune the move size for, defaults to None which upon attaching will tune all types in the system currently.

  • max_translation_move (float) – The maximum value of a translational move size to attempt \([\mathrm{length}]\).

  • max_rotation_move (float) – The maximum value of a rotational move size to attempt.

trigger#

Trigger to determine when to run the tuner.

Type:

hoomd.trigger.Trigger

moves#

A list of types of moves to tune. Available options are 'a' and 'd'.

Type:

list[str]

target#

The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

Type:

float

solver#

A solver that tunes move sizes to reach the specified target.

Type:

hoomd.tune.RootSolver

types#

A list of string particle types to tune the move size for, defaults to None which upon attaching will tune all types in the system currently.

Type:

list[str]

max_translation_move#

The maximum value of a translational move size to attempt \([\mathrm{length}]\).

Type:

float

max_rotation_move#

The maximum value of a rotational move size to attempt.

Type:

float

Note

Limiting the maximum move sizes can lead to the inability to converge to the desired acceptance rate. Also, not limiting the move size can lead to move sizes that require the use of multiple periodic images to check for overlaps, especially in low density systems since the acceptance rate tends towards 1. Therefore, it is recommended to pick a moderate maximum move size for at least the translational moves to prevent requiring checking periodic images.

Note

In systems containing disparate particle shapes and/or sizes, move sizes for the different types should be tuned independently so that the acceptances rates for the different particles are each near the target acceptance ratio. Otherwise, the global acceptance ratio, a weighted average of the acceptance ratios for each individual particle type, will approach the target value, while the per-type acceptance ratios may not be close to the target value. This requires setting the types attribute to be one type at a time while setting the ignore_statistics flag of the shape property of the HPMC integrator for all other types to True.

classmethod scale_solver(trigger, moves, target, types=None, max_translation_move=None, max_rotation_move=None, max_scale=2.0, gamma=1.0, tol=0.01)#

Create a MoveSize tuner with a hoomd.tune.ScaleSolver.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • moves (list[str]) – A list of types of moves to tune. Available options are 'a' and 'd'.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • types (list[str]) – A list of string particle types to tune the move size for, defaults to None which upon attaching will tune all types in the system currently.

  • max_translation_move (float) – The maximum value of a translational move size to attempt \([\mathrm{length}]\).

  • max_rotation_move (float) – The maximum value of a rotational move size to attempt.

  • max_scale (float) – Maximum scale factor.

  • gamma (float) – The value of gamma to pass through to hoomd.tune.ScaleSolver. Controls the size of corrections to the move size (larger values increase stability while increasing convergence time).

  • tol (float) – The absolute tolerance to allow between the current acceptance rate and the target before the move sizes are considered tuned. The tolerance should not be too much lower than the default of 0.01 as acceptance rates can vary significantly at typical tuning rates.

classmethod secant_solver(trigger, moves, target, types=None, max_translation_move=None, max_rotation_move=None, gamma=0.8, tol=0.01)#

Create a MoveSize tuner with a hoomd.tune.SecantSolver.

This solver can be faster than hoomd.tune.ScaleSolver, but depending on the system slightly less stable. In general, with the default value of gamma this should not be a problem.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • moves (list[str]) – A list of types of moves to tune. Available options are 'a' and 'd'.

  • target (float) – The acceptance rate for trial moves that is desired. The value should be between 0 and 1.

  • types (list[str]) – A list of string particle types to tune the move size for, defaults to None which upon attaching will tune all types in the system currently.

  • max_translation_move (float) – The maximum value of a translational move size to attempt, defaults to None which represents no maximum move size \([\mathrm{length}]\).

  • max_rotation_move (float) – The maximum value of a rotational move size to attempt, defaults to None which represents no maximum move size.

  • gamma (float) – The value of gamma to pass through to hoomd.tune.SecantSolver. Controls the size of corrections to the move size (smaller values increase stability). Should be between 0 and 1, defaults to 0.8.

  • tol (float) – The absolute tolerance to allow between the current acceptance rate and the target before the move sizes are considered tuned. The tolerance should not be too much lower than the default of 0.01 as acceptance rates can vary significantly at typical tuning rates.

Note

Increasing gamma towards 1 does not necessarily speed up convergence and can slow it down. In addition, large values of gamma can make the solver unstable, especially when tuning frequently.

property tuned#

Whether or not the move sizes are considered tuned.

An instance is considered tuned if it the solver tolerance has been met by all tunables for 2 iterations.

Type:

bool

hoomd.hpmc.update#

Overview

BoxMC

Apply box updates to sample isobaric and related ensembles.

Clusters

Apply geometric cluster algorithm (GCA) moves.

MuVT

Insert and remove particles in the muVT ensemble.

QuickCompress

Quickly compress a hard particle system to a target box.

Shape

Apply shape updates to the shape definitions defined in the integrator.

Details

HPMC updaters.

HPMC updaters work with the hpmc.integrate.HPMCIntegrator to apply changes to the system consistent with the particle shape and defined interaction energies. The BoxMC, Clusters, and MuVT updaters apply trial moves that enable enhanced sampling or the equilibration of different ensembles. QuickCompress helps prepare non-overlapping configurations of particles in a given box shape.

class hoomd.hpmc.update.BoxMC(trigger, betaP)#

Bases: Updater

Apply box updates to sample isobaric and related ensembles.

Parameters:

Use BoxMC in conjunction with an HPMC integrator to allow the simulation box to undergo random fluctuations at constant pressure, or random deformations at constant volume. BoxMC supports both isotropic and anisotropic volume change moves as well as shearing of the simulation box. A single BoxMC instance may apply multiple types of box moves during a simulation run.

Box move types

By default, no moves are applied (the weight values for all move types default to 0). In a given timestep, the type of move is selected randomly with probability:

\[p = \frac{w_k}{\sum_k w_k}\]

where \(w_k\) is the weight of the move type.

A given box move proposes a trial simulation box \((L_x^t, L_y^t, L_z^t, xy^t, xz^t, yz^t)\) as a change from the current box: \((L_x, L_y, L_z, xy, xz, yz)\). The form of the change depends on the selected move type:

  • volume (mode='standard'): Change the volume (or area in 2D) of the simulation box while maining fixed aspect ratios \(Lx/Ly\), \(Lx/Lz\). In 3D:

    \[\begin{split}V^t &= V + u \\ L_x^t &= \left( \frac{Lx}{Ly} \frac{Lx}{Lz} V^t \right)^{1/3} \\ L_y^t &= L_x^t \frac{Ly}{Lx} \\ L_z^t &= L_x^t \frac{Lz}{Lx} \\ xy^t &= xy \\ xz^t &= xz \\ yz^t &= yz \\\end{split}\]

    where \(u\) is a random value uniformly distributed in the interval \([-\delta_\mathrm{volume}, \delta_\mathrm{volume}]\).

    In 2D:

    \[\begin{split}V^t &= V + u \\ L_x^t &= \left( \frac{Lx}{Ly} V^t \right)^{1/2} \\ L_y^t &= L_x^t \frac{Ly}{Lx} \\ xy^t &= xy \\\end{split}\]
  • volume (mode='ln'): Change the volume (or area in 2D) of the simulation box while maining fixed aspect ratios \(Lx/Ly\), \(Lx/Lz\). In 3D:

    \[\begin{split}V^t &= V e^u \\ L_x^t &= \left( \frac{Lx}{Ly} \frac{Lx}{Lz} V^t \right)^{1/3} \\ L_y^t &= L_x^t \frac{Ly}{Lx} \\ L_z^t &= L_x^t \frac{Lz}{Lx} \\ xy^t &= xy \\ xz^t &= xz \\ yz^t &= yz \\\end{split}\]

    where \(u\) is a random value uniformly distributed in the interval \([-\delta_\mathrm{volume}, \delta_\mathrm{volume}]\).

    In 2D:

    \[\begin{split}V^t &= V e^u \\ L_x^t &= \left( \frac{Lx}{Ly} V^t \right)^{1/2} \\ L_y^t &= L_x^t \frac{Ly}{Lx} \\ xy^t &= xy \\\end{split}\]
  • aspect: Change the aspect ratio of the simulation box while maintaining a fixed volume. In 3D:

    \[\begin{split}L_k^t & = \begin{cases} L_k(1 + a) & u < 0.5 \\ L_k \frac{1}{1+a} & u \ge 0.5 \end{cases} \\ L_{m \ne k}^t & = L_m \sqrt{\frac{L_k}{L_k^t}} & xy^t &= xy \\ xz^t &= xz \\ yz^t &= yz \\\end{split}\]

    where \(u\) is a random value uniformly distributed in the interval \([0, 1]\), \(a\) is a random value uniformly distributed in the interval \([0, \delta_\mathrm{aspect}]\) and \(k\) is randomly chosen uniformly from the set \(\{x, y, z\}\).

    In 2D:

    \[\begin{split}L_k^t & = \begin{cases} L_k(1 + a) & u < 0.5 \\ L_k \frac{1}{1+a} & u \ge 0.5 \end{cases} \\ L_{m \ne k}^t & = L_m \frac{L_k}{L_k^t} \\ xy^t &= xy \\\end{split}\]
  • length: Change the box lengths:

    \[L_k^t = L_k + u\]

    where \(u\) is a random value uniformly distributed in the interval \([-\delta_{\mathrm{length},k}, -\delta_{\mathrm{length},k}]\), and \(k\) is randomly chosen uniformly from the set \(\{a : a \in \{x, y, z\}, \delta_{\mathrm{length},a} \ne 0 \}\).

  • shear: Change the box shear parameters. In 3D:

    \[\begin{split}(xy^t, xz^t, yz^t) = \begin{cases} \left(xy + s_{xy}, \enspace xz, \enspace yz \right) & u < \frac{1}{3} \\ \left( xy^t = xy, \enspace xz + s_{xz}, \enspace yz \right) & \frac{1}{3} \le u < \frac{2}{3} \\ \left( xy^t = xy, \enspace xz, \enspace yz + s_{yz} \right) & \frac{2}{3} \le u \le 1 \\ \end{cases} \\\end{split}\]

    where \(u\) is a random value uniformly distributed in the interval \([0, 1]\) and \(s_k\) is a random value uniformly distributed in the interval \([-\delta_{\mathrm{shear},k}, \delta_{\mathrm{shear},k}]\). BoxMC attempts and records trial moves for shear parameters even when \(\delta_{\mathrm{shear},k}=0\).

    In 2D:

    \[xy^t = xy + s_{xy}\]

Acceptance

All particle particle positions are scaled into the trial box to form the trial configuration \(C^t\):

\[\vec{r}_i^t = s_x \vec{a}_1^t + s_y \vec{a}_2^t + s_z \vec{a}_3^t - \frac{\vec{a}_1^t + \vec{a}_2^t + \vec{a}_3^t}{2}\]

where \(\vec{a}_k^t\) are the new box vectors determined by \((L_x^t, L_y^t, L_z^t, xy^t, xz^t, yz^t)\) and the scale factors are determined by the current particle position \(\vec{r}_i\) and the box vectors \(\vec{a}_k\):

\[\vec{r}_i = s_x \vec{a}_1 + s_y \vec{a}_2 + s_z \vec{a}_3 - \frac{\vec{a}_1 + \vec{a}_2 + \vec{a}_3}{2}\]

The trial move is accepted with the probability:

\[\begin{split}p_\mathrm{accept} = \begin{cases} \exp(-(\beta \Delta H + \beta \Delta U)) & \beta \Delta H + \beta \Delta U > 0 \\ 1 & \beta \Delta H + \beta \Delta U \le 0 \\ \end{cases}\end{split}\]

where \(\Delta U = U^t - U\) is the difference in potential energy, \(\beta \Delta H = \beta P (V^t - V) - N_\mathrm{particles} \cdot \ln(V^t / V)\) for most move types. It is \(\beta P (V^t - V) - (N_\mathrm{particles}+1) \cdot \ln(V^t / V)\) for ln volume moves.

When the trial move is accepted, the system state is set to the the trial configuration. When it is not accepted, the move is rejected and the state is not modified.

Mixed precision

BoxMC uses reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

volume#

Parameters for isobaric volume moves that scale the box lengths uniformly. The dictionary has the following keys:

  • weight (float) - Relative weight of volume box moves.

  • mode (str) - standard proposes changes to the box volume and ln proposes changes to the logarithm of the volume. Initially starts off in ‘standard’ mode.

  • delta (float) - Maximum change in V or ln(V) where V is box area (2D) or volume (3D) \(\delta_\mathrm{volume}\).

Type:

dict

aspect#

Parameters for isovolume aspect ratio moves. The dictionary has the following keys:

  • weight (float) - Relative weight of aspect box moves.

  • delta (float) - Maximum relative change of box aspect ratio \(\delta_\mathrm{aspect} [\mathrm{dimensionless}]\).

Type:

dict

length#

Parameters for isobaric box length moves that change box lengths independently. The dictionary has the following keys:

  • weight (float) - Maximum change of HOOMD-blue box parameters Lx, Ly, and Lz.

  • delta (tuple[float, float, float]) - Maximum change of the box lengths \((\delta_{\mathrm{length},x}, \delta_{\mathrm{length},y}, \delta_{\mathrm{length},z}) [\mathrm{length}]\).

Type:

dict

shear#

Parameters for isovolume box shear moves. The dictionary has the following keys:

  • weight (float) - Relative weight of shear box moves.

  • delta (tuple[float, float, float]) - maximum change of the box tilt factor \((\delta_{\mathrm{shear},xy}, \delta_{\mathrm{shear},xz}, \delta_{\mathrm{shear},yz}) [\mathrm{dimensionless}]\).

  • reduce (float) - Maximum number of lattice vectors of shear to allow before applying lattice reduction. Values less than 0.5 disable shear reduction.

Type:

dict

instance#

When using multiple BoxMC updaters in a single simulation, give each a unique value for instance so they generate different streams of random numbers.

Type:

int

property aspect_moves#

The accepted and rejected aspect moves.

(0, 0) before the first call to Simulation.run.

(Loggable: category=”sequence”)

Type:

tuple[int, int]

property counter#

Trial move counters.

The counter object has the following attributes:

  • volume: tuple [int, int] - Number of accepted and rejected volume and length moves.

  • shear: tuple [int, int] - Number of accepted and rejected shear moves.

  • aspect: tuple [int, int] - Number of accepted and rejected aspect moves.

Note

The counts are reset to 0 at the start of each call to hoomd.Simulation.run. Before the first call to Simulation.run, counter is None.

property shear_moves#

The accepted and rejected shear moves.

(0, 0) before the first call to Simulation.run.

(Loggable: category=”sequence”)

Type:

tuple[int, int]

property volume_moves#

The accepted and rejected volume and length moves.

(0, 0) before the first call to Simulation.run.

(Loggable: category=”sequence”)

Type:

tuple[int, int]

class hoomd.hpmc.update.Clusters(pivot_move_probability=0.5, flip_probability=0.5, trigger=1)#

Bases: Updater

Apply geometric cluster algorithm (GCA) moves.

Parameters:
  • pivot_move_probability (float) – Set the probability for attempting a pivot move.

  • flip_probability (float) – Set the probability for transforming an individual cluster.

  • trigger (hoomd.trigger.trigger_like) – Select the timesteps on which to perform cluster moves.

The GCA as described in Liu and Lujten (2004), http://doi.org/10.1103/PhysRevLett.92.035504 is used for hard shape, patch interactions and depletants. Implicit depletants are supported and simulated on-the-fly, as if they were present in the actual system.

Supported moves include pivot moves (point reflection) and line reflections (pi rotation around an axis). With anisotropic particles, the pivot move cannot be used because it would create a chiral mirror image of the particle, and only line reflections are employed. In general, line reflections are not rejection free because of periodic boundary conditions, as discussed in Sinkovits et al. (2012), http://doi.org/10.1063/1.3694271 . However, we restrict the line reflections to axes parallel to the box axis, which makes those moves rejection-free for anisotropic particles, but the algorithm is then no longer ergodic for those and needs to be combined with local moves.

Mixed precision

Clusters uses reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

pivot_move_probability#

Set the probability for attempting a pivot move.

Type:

float

flip_probability#

Set the probability for transforming an individual cluster.

Type:

float

trigger#

Select the timesteps on which to perform cluster moves.

Type:

Trigger

property avg_cluster_size#

the typical size of clusters.

None when not attached.

(Loggable: category=”scalar”)

Type:

float

class hoomd.hpmc.update.MuVT(transfer_types, ngibbs=1, max_volume_rescale=0.1, volume_move_probability=0.5, trigger=1)#

Bases: Updater

Insert and remove particles in the muVT ensemble.

Parameters:
  • trigger (int) – Number of timesteps between grand canonical insertions

  • transfer_types (list) – List of type names that are being transferred from/to the reservoir or between boxes

  • ngibbs (int) – The number of partitions to use in Gibbs ensemble simulations (if == 1, perform grand canonical muVT)

  • max_volume_rescale (float) – maximum step size in ln(V) (applies to Gibbs ensemble)

  • move_ratio (float) – (if set) Set the ratio between volume and exchange/transfer moves (applies to Gibbs ensemble)

The muVT (or grand-canonical) ensemble simulates a system at constant fugacity.

Gibbs ensemble simulations are also supported, where particles and volume are swapped between two or more boxes. Every box correspond to one MPI partition, and can therefore run on multiple ranks. Use the ranks_per_partition argument of hoomd.communicator.Communicator to enable partitioned simulations.

Mixed precision

MuVT uses reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

Note

Multiple Gibbs ensembles are also supported in a single parallel job, with the ngibbs option to update.muvt(), where the number of partitions can be a multiple of ngibbs.

trigger#

Select the timesteps on which to perform cluster moves.

Type:

int

transfer_types#

List of type names that are being transferred from/to the reservoir or between boxes

Type:

list

max_volume_rescale#

Maximum step size in ln(V) (applies to Gibbs ensemble)

Type:

float

move_ratio#

The ratio between volume and exchange/transfer moves (applies to Gibbs ensemble)

Type:

float

ntrial#

(default: 1) Number of configurational bias attempts to swap depletants

Type:

float

fugacity#

Particle fugacity \([\mathrm{volume}^{-1}]\) (default: 0).

Type:

TypeParameter [ particle type, float]

property N#

Map of number of particles per type.

None when not attached.

(Loggable: category=”object”)

Type:

dict

property exchange_moves#

Count of the accepted and rejected paricle exchange moves.

None when not attached

(Loggable: category=”sequence”)

Type:

tuple[int, int]

property insert_moves#

Count of the accepted and rejected paricle insertion moves.

None when not attached

(Loggable: category=”sequence”)

Type:

tuple[int, int]

property remove_moves#

Count of the accepted and rejected paricle removal moves.

None when not attached

(Loggable: category=”sequence”)

Type:

tuple[int, int]

property volume_moves#

Count of the accepted and rejected paricle volume moves.

None when not attached

(Loggable: category=”sequence”)

Type:

tuple[int, int]

class hoomd.hpmc.update.QuickCompress(trigger, target_box, max_overlaps_per_particle=0.25, min_scale=0.99)#

Bases: Updater

Quickly compress a hard particle system to a target box.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Update the box dimensions on triggered time steps.

  • target_box (hoomd.box.box_like) – Dimensions of the target box.

  • max_overlaps_per_particle (float) – The maximum number of overlaps to allow per particle (may be less than 1 - e.g. up to 250 overlaps would be allowed when in a system of 1000 particles when max_overlaps_per_particle=0.25).

  • min_scale (float) – The minimum scale factor to apply to box dimensions.

Use QuickCompress in conjunction with an HPMC integrator to scale the system to a target box size. QuickCompress can typically compress dilute systems to near random close packing densities in tens of thousands of time steps.

It operates by making small changes toward the target_box, but only when there are no particle overlaps in the current simulation state. In 3D:

\[\begin{split}L_x' &= \begin{cases} \max( L_x \cdot s, L_{\mathrm{target},x} ) & L_{\mathrm{target},x} < L_x \\ \min( L_x / s, L_{\mathrm{target},x} ) & L_{\mathrm{target},x} \ge L_x \end{cases} \\ L_y' &= \begin{cases} \max( L_y \cdot s, L_{\mathrm{target},y} ) & L_{\mathrm{target},y} < L_y \\ \min( L_y / s, L_{\mathrm{target},y} ) & L_{\mathrm{target},y} \ge L_y \end{cases} \\ L_z' &= \begin{cases} \max( L_z \cdot s, L_{\mathrm{target},z} ) & L_{\mathrm{target},z} < L_z \\ \min( L_z / s, L_{\mathrm{target},z} ) & L_{\mathrm{target},z} \ge L_z \end{cases} \\ xy' &= \begin{cases} \max( xy \cdot s, xy_\mathrm{target} ) & xy_\mathrm{target} < xy \\ \min( xy / s, xy_\mathrm{target} ) & xy_\mathrm{target} \ge xy \end{cases} \\ xz' &= \begin{cases} \max( xz \cdot s, xz_\mathrm{target} ) & xz_\mathrm{target} < xz \\ \min( xz / s, xz_\mathrm{target} ) & xz_\mathrm{target} \ge xz \end{cases} \\ yz' &= \begin{cases} \max( yz \cdot s, yz_\mathrm{target} ) & yz_\mathrm{target} < yz \\ \min( yz / s, yz_\mathrm{target} ) & yz_\mathrm{target} \ge yz \end{cases} \\\end{split}\]

and in 2D:

\[\begin{split}L_x' &= \begin{cases} \max( L_x \cdot s, L_{\mathrm{target},x} ) & L_{\mathrm{target},x} < L_x \\ \min( L_x / s, L_{\mathrm{target},x} ) & L_{\mathrm{target},x} \ge L_x \end{cases} \\ L_y' &= \begin{cases} \max( L_y \cdot s, L_{\mathrm{target},y} ) & L_{\mathrm{target},y} < L_y \\ \min( L_y / s, L_{\mathrm{target},y} ) & L_{\mathrm{target},y} \ge L_y \end{cases} \\ L_z' &= L_z \\ xy' &= \begin{cases} \max( xy \cdot s, xy_\mathrm{target} ) & xy_\mathrm{target} < xy \\ \min( xy / s, xy_\mathrm{target} ) & xy_\mathrm{target} \ge xy \end{cases} \\ xz' &= xz \\ yz' &= yz \\\end{split}\]

where the current simulation box is \((L_x, L_y, L_z, xy, xz, yz)\), the target is \((L_{\mathrm{target},x}, L_{\mathrm{target},y}, L_{\mathrm{target},z}, xy_\mathrm{target}, xz_\mathrm{target}, yz_\mathrm{target})\), the new simulation box set is \((L_x', L_y', L_z', xy', xz', yz')\) and \(s\) is the scale factor chosen for this step (see below). QuickCompress scales particle coordinates (see BoxMC for details) when it sets a new box.

When there are more than max_overlaps_per_particle * N_particles hard particle overlaps in the system in the new box, the box move is rejected. Otherwise, the small number of overlaps remain when the new box is set. QuickCompress then waits until hoomd.hpmc.integrate.HPMCIntegrator makes local MC trial moves that remove all overlaps.

QuickCompress adjusts the value of \(s\) based on the particle and translational trial move sizes to ensure that the trial moves will be able to remove the overlaps. It randomly chooses a value of \(s\) uniformly distributed between max(min_scale, 1.0 - min_move_size / max_diameter) and 1.0 where min_move_size is the smallest MC translational move size adjusted by the acceptance ratio and max_diameter is the circumsphere diameter of the largest particle type.

Tip

Use the hoomd.hpmc.tune.MoveSize in conjunction with QuickCompress to adjust the move sizes to maintain a constant acceptance ratio as the density of the system increases.

Warning

When the smallest MC translational move size is 0, QuickCompress will scale the box by 1.0 and not progress toward the target box.

Warning

Use QuickCompress OR BoxMC. Do not use both at the same time.

Mixed precision

QuickCompress uses reduced precision floating point arithmetic when checking for particle overlaps in the local particle reference frame.

trigger#

Update the box dimensions on triggered time steps.

Type:

Trigger

target_box#

Dimensions of the target box.

Type:

Box

max_overlaps_per_particle#

The maximum number of overlaps to allow per particle (may be less than 1 - e.g. up to 250 overlaps would be allowed when in a system of 1000 particles when max_overlaps_per_particle=0.25).

Type:

float

min_scale#

The minimum scale factor to apply to box dimensions.

Type:

float

instance#

When using multiple QuickCompress updaters in a single simulation, give each a unique value for instance so that they generate different streams of random numbers.

Type:

int

property complete#

True when the box has achieved the target.

class hoomd.hpmc.update.Shape(trigger, shape_move, pretend=False, type_select=1, nsweeps=1)#

Bases: Updater

Apply shape updates to the shape definitions defined in the integrator.

See also

hoomd.hpmc.shape_move describes the shape alchemy algorithm.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Call the updater on triggered time steps.

  • shape_move (ShapeMove) – Type of shape move to apply when updating shape definitions

  • pretend (bool, optional) – When True the updater will not actually update the shape definitions. Instead, moves will be proposed and the acceptance statistics will be updated correctly (default: False).

  • type_select (int, optional) – Number of types to change every time the updater is called (default: 1).

  • nsweeps (int, optional) – Number of times to update shape definitions during each triggered timesteps (default: 1).

Shape support.

See hoomd.hpmc.shape_move for supported shapes.

Example:

mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape["A"] = dict(vertices=numpy.asarray([(1, 1, 1), (-1, -1, 1),
                                            (1, -1, -1), (-1, 1, -1)]))
vertex_move = hoomd.hpmc.shape_move.Vertex(stepsize={'A': 0.01},
                                           param_ratio=0.2,
                                           volume=1.0)
updater = hoomd.hpmc.update.Shape(shape_move=vertex_move,
                                  trigger=hoomd.trigger.Periodic(1),
                                  type_select=1,
                                  nsweeps=1)
trigger#

Call the updater on triggered time steps.

Type:

Trigger

shape_move#

Type of shape move to apply when updating shape definitions

Type:

ShapeMove

pretend#

When True the updater will not actually update the shape definitions, instead moves will be proposed and the acceptance statistics will be updated correctly.

Type:

bool

type_select#

Number of types to change every time the updater is called.

Type:

int

nsweeps#

Number of times to update shape definitions during each triggered timesteps.

Type:

int

property particle_volumes#

Volume of a single particle for each type.

(Loggable: category=”scalar”)

Type:

list[float]

property shape_move_energy#

Energy penalty due to shape changes.

(Loggable: category=”scalar”)

Type:

float

property shape_moves#

Count of the accepted and rejected shape moves.

(Loggable: category=”sequence”)

Type:

tuple[int, int]

hoomd.hpmc.pair#

Pair Potentials for Monte Carlo.

Define \(U_{\mathrm{pair},ij}\) for use with hoomd.hpmc.integrate.HPMCIntegrator. Assign a pair potential instance to hpmc.integrate.HPMCIntegrator.pair_potential to activate the potential.

Modules

hoomd.hpmc.pair.user#

Overview

CPPPotentialBase

Base class for interaction between pairs of particles given in C++.

CPPPotential

Define an energetic interaction between pairs of particles.

CPPPotentialUnion

Define an arbitrary energetic interaction between unions of particles.

Details

User-defined pair potentials for HPMC simulations.

Set \(U_{\mathrm{pair},ij}\) evaluated in hoomd.hpmc.integrate.HPMCIntegrator to a user-defined expression.

See also

Features explains the compile time options needed for user defined pair potentials.

class hoomd.hpmc.pair.user.CPPPotentialBase#

Base class for interaction between pairs of particles given in C++.

Pair potential energies define energetic interactions between pairs of particles in hoomd.hpmc.integrate.HPMCIntegrator. Particles within a cutoff distance interact with an energy that is a function the type and orientation of the particles and the vector pointing from the i particle to the j particle center.

Classes derived from CPPPotentialBase take C++ code, compile it at runtime, and execute the code natively in the MC loop.

Warning

CPPPotentialBase is experimental and subject to change in future minor releases.

C++ code

Classes derived from CPPPotentialBase will compile the code provided by the user and call it to evaluate the energy \(U_{\mathrm{pair},ij}\). The text provided is the body of a function with the following signature:

float eval(const vec3<float>& r_ij,
           unsigned int type_i,
           const quat<float>& q_i,
           float d_i,
           float charge_i,
           unsigned int type_j,
           const quat<float>& q_j,
           float d_j,
           float charge_j
)
  • r_ij is a vector pointing from the center of particle i to the center of particle j.

  • type_i is the integer type id of particle i

  • q_i is the quaternion orientation of particle i

  • d_i is the diameter of particle i

  • charge_i is the charge of particle i

  • type_j is the integer type id of particle j

  • q_j is the quaternion orientation of particle j

  • d_j is the diameter of particle j

  • charge_j is the charge of particle j

Note

vec3 and quat are defined in the file VectorMath.h in the HOOMD-blue source code.

Note

Your code must return a value.

Mixed precision

CPPPotentialBase uses 32-bit precision floating point arithmetic when computing energies in the local particle reference frame.

class hoomd.hpmc.pair.user.CPPPotential(r_cut, code, param_array)#

Bases: CPPPotentialBase

Define an energetic interaction between pairs of particles.

Adjust parameters within the code with the param_array attribute without requiring a recompile. These arrays are read-only during function evaluation.

Parameters:
  • r_cut (float) – Particle center to center distance cutoff beyond which all pair interactions are 0.

  • code (str) – C++ code defining the function body for pair interactions between particles.

  • param_array (list[float]) – Parameter values to make available in float *param_array in the compiled code. If no adjustable parameters are needed in the C++ code, pass an empty array.

See also

CPPPotentialBase for the documentation of the parent class.

Warning

CPPPotential is experimental and subject to change in future minor releases.

Example

See How to apply arbitrary pair potentials in HPMC.

code#

The C++ code that defines the body of the patch energy function. After running zero or more steps, this property cannot be changed.

Type:

str

param_array#

Numpy array containing dynamically adjustable elements in the potential energy function as defined by the user. After running zero or more steps, the array cannot be set, although individual values can still be changed.

Type:

(N, ) numpy.ndarray of float

energy#

The potential energy resulting from the interactions defind in the C++ code at the current timestep.

Type:

float

class hoomd.hpmc.pair.user.CPPPotentialUnion(r_cut_constituent, code_constituent, r_cut_isotropic, code_isotropic, param_array_constituent, param_array_isotropic)#

Bases: CPPPotentialBase

Define an arbitrary energetic interaction between unions of particles.

Parameters:
  • r_cut_constituent (float) – Constituent particle center to center distance cutoff beyond which all pair interactions are 0.

  • code_constituent (str) – C++ code defining the custom pair interactions between constituent particles.

  • r_cut_isotropic (float) – Cut-off for isotropic interaction between centers of union particles.

  • code_isotropic (str) – C++ code for isotropic part of the interaction. Must be '' when executing on a GPU.

  • param_array_constituent (list[float]) – Parameter values to make available in float *param_array_constituent in the compiled code. Pass an empty array if no adjustable parameters are needed for the constituent interactions.

  • param_array_isotropic (list[float]) – Parameter values to make available in float *param_array_isotropic in the compiled code. Pass an empty array if no adjustable parameters are needed for the isotropic interactions.

Note

Code passed into code_isotropic is not used when executing on the GPU. A RuntimeError is raised on attachment if the value of this argument is anything besides '' on the GPU.

Note

This class uses an internal OBB tree for fast interaction queries between constituents of interacting particles. Depending on the number of constituent particles per type in the tree, different values of the particles per leaf node may yield different optimal performance. The capacity of leaf nodes is configurable.

See also

CPPPotentialBase for the documentation of the parent class.

Warning

CPPPotentialUnion is experimental and subject to change in future minor releases.

Threading

CPPPotentialUnion uses threaded execution on multiple CPU cores.

positions#

The positions of the constituent particles.

Type: TypeParameter [particle type, list [tuple [float, float, float]]]

orientations#

The orientations of the constituent particles.

Type: TypeParameter [particle type, list [tuple [float, float, float, float]]]

diameters#

The diameters of the constituent particles.

Type:

TypeParameter [particle type, list [float]]

charges#

The charges of the constituent particles.

Type:

TypeParameter [particle type, list [float]]

typeids#

The integer types of the constituent particles.

Type:

TypeParameter [particle type, list [float]]

leaf_capacity#

The number of particles in a leaf of the internal tree data structure (default: 4).

Type:

int

code_constituent#

The C++ code that defines the body of the patch energy function between the constituent particles. This property cannot be modified after running for zero or more steps.

Type:

str

code_isotropic#

The C++ code that defines the body of the patch energy function between the centers of the particles. This property cannot be modified after running for zero or more steps.

Type:

str

param_array_isotropic#

Numpy array containing dynamically adjustable elements in the isotropic part of the potential as defined by the user. After running zero or more steps, the array cannot be set, although individual values can still be changed.

Type:

(N, ) numpy.ndarray of float

param_array_constituent#

Numpy array containing dynamically adjustable elements in the constituent part of the potential part of the potential as defined by the user. After running zero or more steps, the array cannot be set, although individual values can still be changed.

Type:

(N, ) numpy.ndarray of float

energy#

The potential energy resulting from the interactions defind in the C++ code at the current timestep.

Type:

float

Example without isotropic interactions:

square_well = '''float rsq = dot(r_ij, r_ij);
                    if (rsq < 1.21f)
                        return -1.0f;
                    else
                        return 0.0f;
              '''
patch = hoomd.hpmc.pair.user.CPPPotentialUnion(
    r_cut_constituent=1.1,
    r_cut_isotropic=0.0
    code_constituent=square_well,
    code_isotropic='',
    param_array_constituent=[],
    param_array_isotropic=[]
)
patch.positions['A'] = [
    (0, 0, -0.5),
    (0, 0, 0.5)
]
patch.diameters['A'] = [0, 0]
patch.typeids['A'] = [0, 0]
mc.pair_potential = patch

Example with added isotropic interactions:

# square well attraction on constituent spheres
square_well = '''float rsq = dot(r_ij, r_ij);
                      float r_cut = param_array_constituent[0];
                      if (rsq < r_cut*r_cut)
                          return param_array_constituent[1];
                      else
                          return 0.0f;
                '''

# soft repulsion between centers of unions
soft_repulsion = '''float rsq = dot(r_ij, r_ij);
                          float r_cut = param_array_isotropic[0];
                          if (rsq < r_cut*r_cut)
                            return param_array_isotropic[1];
                          else
                            return 0.0f;
                 '''

patch = hoomd.hpmc.pair.user.CPPPotentialUnion(
    r_cut_constituent=2.5,
    r_cut_isotropic=5.0,
    code_union=square_well,
    code_isotropic=soft_repulsion,
    param_array_constituent=[2.0, -5.0],
    param_array_isotropic=[2.5, 1.3],
)
patch.positions['A'] = [
    (0, 0, -0.5),
    (0, 0, 0.5)
]
patch.typeids['A'] = [0, 0]
patch.diameters['A'] = [0, 0]
mc.pair_potential = patch

hoomd.hpmc.external#

External fields for Monte Carlo.

Define \(U_{\mathrm{external},i}\) for use with hoomd.hpmc.integrate.HPMCIntegrator. Assign an external field instance to hpmc.integrate.HPMCIntegrator.external_potential to activate the potential.

Modules

hoomd.hpmc.external.user#

Overview

CPPExternalPotential

Define an external potential energy field imposed on all particles in the system.

Details

User-defined external fields for HPMC simulations.

Set \(U_{\mathrm{external},i}\) evaluated in hoomd.hpmc.integrate.HPMCIntegrator to a user-defined expression.

See also

Features explains the compile time options needed for user defined external potentials.

class hoomd.hpmc.external.user.CPPExternalPotential(code)#

Bases: ExternalField

Define an external potential energy field imposed on all particles in the system.

Parameters:

code (str) – C++ function body to compile.

Potentials added using CPPExternalPotential are added to the total energy calculation in hoomd.hpmc.integrate.HPMCIntegrator. CPPExternalPotential takes C++ code, compiles it at runtime, and executes the code natively in the MC loop with full performance. It enables researchers to quickly and easily implement custom energetic field intractions without the need to modify and recompile HOOMD.

C++ code

Supply C++ code to the code argument and CPPExternalPotential will compile the code and call it to evaluate the energy. The text provided in code is the body of a function with the following signature:

float eval(const BoxDim& box,
           unsigned int type_i,
           const vec3<Scalar>& r_i,
           const quat<Scalar>& q_i
           Scalar diameter,
           Scalar charge
)
  • box is the system box.

  • type_i is the (integer) particle type.

  • r_i is the particle position

  • q_i the quaternion representing the particle orientation.

  • diameter the particle diameter.

  • charge the particle charge.

Note

vec3 and quat are defined in the file VectorMath.h in the HOOMD-blue source code, and BoxDim is defined in he file BoxDim.h in the HOOMD-blue source code.

Note

Your code must return a value.

Example

gravity_code = "return r_i.z + box.getL().z/2;"
gravity = hoomd.hpmc.external.user.CPPExternalPotential(
    code=gravity_code)
mc.external_potential = gravity

Note

CPPExternalPotential does not support execution on GPUs.

Warning

CPPExternalPotential is experimental and subject to change in future minor releases.

code#

The code of the body of the external field energy function. After running zero or more steps, this property cannot be modified.

Type:

str

property energy#

Total field energy of the system in the current state.

\[U = \sum_{i=0}^\mathrm{N_particles-1} U_{\mathrm{external},i}\]

Returns None when the patch object and integrator are not attached.

(Loggable: category=”scalar”)

Type:

float

hoomd.hpmc.external.field#

Overview

ExternalField

Base class external field.

Harmonic

Restrain particle positions and orientations with harmonic springs.

Details

Apply external fields to HPMC simulations.

class hoomd.hpmc.external.field.ExternalField#

Bases:

Base class external field.

Provides common methods for all external field subclasses.

Note

Users should use the subclasses and not instantiate ExternalField directly.

class hoomd.hpmc.external.field.Harmonic(reference_positions, reference_orientations, k_translational, k_rotational, symmetries)#

Bases: ExternalField

Restrain particle positions and orientations with harmonic springs.

Parameters:
  • reference_positions ((N_particles, 3) numpy.ndarray of float) – the reference positions to which particles are restrained \([\mathrm{length}]\).

  • reference_orientations ((N_particles, 4) numpy.ndarray of float) – the reference orientations to which particles are restrained \([\mathrm{dimensionless}]\).

  • k_translational (hoomd.variant.variant_like) – translational spring constant \([\mathrm{energy} \cdot \mathrm{length}^{-2}]\).

  • k_rotational (hoomd.variant.variant_like) – rotational spring constant \([\mathrm{energy}]\).

  • symmetries ((N_symmetries, 4) numpy.ndarray of float) – the orientations that are equivalent through symmetry, i.e., the rotation quaternions that leave the particles unchanged. At a minimum, the identity quaternion ([1, 0, 0, 0]) must be included here \([\mathrm{dimensionless}]\).

Harmonic computes harmonic spring energies between the particle positions/orientations and given reference positions/orientations:

\[\begin{split}U_{\mathrm{external},i} & = U_{\mathrm{translational},i} + U_{\mathrm{rotational},i} \\ U_{\mathrm{translational},i} & = \frac{1}{2} k_{translational} \cdot (\vec{r}_i-\vec{r}_{0,i})^2 \\ U_{\mathrm{rotational},i} & = \frac{1}{2} k_{rotational} \cdot \min_j \left[ (\mathbf{q}_i-\mathbf{q}_{0,i} \cdot \mathbf{q}_{\mathrm{symmetry},j})^2 \right]\end{split}\]

where \(k_{translational}\) and \(k_{rotational}\) correspond to the parameters k_translational and k_rotational, respectively, \(\vec{r}_i\) and \(\mathbf{q}_i\) are the position and orientation of particle \(i\), the \(0\) subscripts denote the given reference quantities, and \(\mathbf{q}_{\mathrm{symmetry}}\) is the given set of symmetric orientations from the symmetries parameter.

Note

Harmonic does not support execution on GPUs.

k_translational#

The translational spring constant \([\mathrm{energy} \cdot \mathrm{length}^{-2}]\).

Type:

hoomd.variant.Variant

k_rotational#

The rotational spring constant \([\mathrm{energy}]\).

Type:

hoomd.variant.Variant

reference_positions#

The reference positions to which particles are restrained \([\mathrm{length}]\).

Type:

(N_particles, 3) numpy.ndarray of float

reference_orientations#

The reference orientations to which particles are restrained \([\mathrm{dimensionless}]\).

Type:

(N_particles, 4) numpy.ndarray of float

symmetries#

The orientations that are equivalent through symmetry, i.e., the rotation quaternions that leave the particles unchanged \([\mathrm{dimensionless}]\).

Type:

(N_symmetries, 4) numpy.ndarray of float

property energy#

The total energy of the harmonic field \([\mathrm{energy}]\).

\[\sum_{i=0}^\mathrm{N_particles-1} U_{\mathrm{external},i}\]

(Loggable: category=”scalar”)

Type:

float

property energy_rotational#

The energy associated with rotational fluctuations \([\mathrm{energy}]\).

\[\sum_{i=0}^\mathrm{N_particles-1} U_{\mathrm{rotational},i}\]

(Loggable: category=”scalar”)

Type:

float

property energy_translational#

The energy associated with positional fluctuations \([\mathrm{energy}]\).

\[\sum_{i=0}^\mathrm{N_particles-1} U_{\mathrm{translational},i}\]

(Loggable: category=”scalar”)

Type:

float

hoomd.hpmc.external.wall#

Overview

WallPotential

HPMC wall potential.

Details

Wall potentials HPMC simulations.

Set \(U_{\mathrm{external},i}\) evaluated in hoomd.hpmc.integrate.HPMCIntegrator to a hard particle-wall interaction.

class hoomd.hpmc.external.wall.WallPotential(walls)#

Bases: ExternalField

HPMC wall potential.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions that confine particles to specific regions of space.

WallPotential adds hard walls to HPMC simulations. Define the wall geometry with a collection of wall.WallGeometry objects. These walls break space into forbidden and allowed regions, controlled by the inside argument for spherical and cylindrical walls and the normal argument for planar walls. HPMC rejects trial moves that cause any part of the particle’s shape to enter the the space defined by the points with a negative signed distance from any wall in the collection. Formally, the contribution of the particle-wall interactions to the potential energy of the system is given by

\[U_{\mathrm{walls}} = \sum_{i=0}^{N_{\mathrm{particles}-1}} \sum_{j=0}^{N_{\mathrm{walls}-1}} U_{i,j},\]

where the energy of interaction \(U_{i,j}\) between particle \(i\) and wall \(j\) is given by

\[\begin{split}U_{i,j} = \begin{cases} \infty & d_{i,j} <= 0 \\ 0 & d_{i,j} > 0 \\ \end{cases}\end{split}\]

where \(d_{i,j} = \min{\{(\vec{r}_i - \vec{r}_j) \cdot \vec{n}_j : \vec{r}_i \in V_I, \vec{r}_j \in W_J\}}\) is the minimum signed distance between all pairs of points \(\vec{r}_i\) on the body of the particle \(V_I\) and \(\vec{r}_j\) on the surface of the wall \(W_J\) and \(\vec{n}_j\) is the vector normal to the surface of the wall at \(\vec{r}_j\) pointing to the allowed region of space defined by the wall.

Walls are enforced by the HPMC integrator. Assign a WallPotential instance to hpmc.integrate.HPMCIntegrator.external_potential to activate the wall potential. Not all combinations of HPMC integrators and wall geometries have overlap checks implemented, and a NotImplementedError is raised if a wall geometry is attached to a simulation with a specific HPMC integrator attached and the overlap checks between the specific shape and wall geometry are not implemented. See the individual subclasses of hoomd.hpmc.integrate.HPMCIntegrator for their wall support.

Note

WallPotential does not support execution on GPUs.

See also

hoomd.wall

Example:

mc = hoomd.hpmc.integrate.Sphere()
walls = [hoomd.wall.Sphere(radius=4.0)]
wall_potential = hoomd.hpmc.external.wall.WallPotential(walls)
mc.external_potential = wall_potential
property overlaps#

The total number of overlaps between particles and walls.

(Loggable: category=”scalar”)

Type:

int

property walls#

The wall geometries associated with this potential.

Type:

list [hoomd.wall.WallGeometry]

hoomd.hpmc.shape_move#

Overview

Elastic

Elastic shape move.

ShapeMove

Base class for all shape moves.

ShapeSpace

Apply shape moves in a \(N\) dimensional shape space.

Vertex

Apply shape moves where particle vertices are translated.

Details

Shape moves for a for alchemical simulations in extended ensembles.

ShapeMove subclasses extend the Hamiltonian of the system by adding degrees of freedom to the shape of the hard particle.

class hoomd.hpmc.shape_move.Elastic(stiffness, mc, default_step_size=None, normal_shear_ratio=0.5)#

Bases: ShapeMove

Elastic shape move.

Apply volume preserving normal and shear shape moves to particles with a deformation energy penalty. When volume preserving deformations, the strain energy penalty is approximated as:

\[U \approx \mu \text{Tr}[\boldsymbol{\varepsilon}^2]V\]

where \(\mu\) is the stiffness constant, \(\text{Tr}\) is the trace operator, \(\boldsymbol{\varepsilon}\) is the strain tensor and \(V\) is the particle volume.

Parameters:
  • stiffness (hoomd.variant.variant_like) – Shape stiffness against deformations.

  • mc (type or hoomd.hpmc.integrate.HPMCIntegrator) – The class of the MC shape integrator or an instance (see hoomd.hpmc.integrate) to use with this elastic shape. Must be a compatible class. We use this argument to create validation for reference_shape.

  • default_step_size (float, optional) – Default maximum size of shape trial moves (default: None). By default requires setting step size for all types.

  • normal_shear_ratio (float, optional) – Fraction of normal to shear deformation trial moves (default: 0.5).

Shape support.

The following shapes are supported:

Note

An instance is only able to be used with the passed HPMC integrator class.

Example:

mc = hoomd.hpmc.integrate.ConvexPolyhedron()
verts = [(1, 1, 1), (-1, -1, 1), (1, -1, -1), (-1, 1, -1)]
mc.shape["A"] = dict(vertices=verts)
elastic_move = hoomd.hpmc.shape_move.Elastic(stiffness=10, mc)
elastic_move.stiffness = 100
elastic_move.reference_shape["A"] = verts
stiffness#

Shape stiffness against deformations.

Type:

hoomd.variant.Variant

step_size#

Maximum size of shape trial moves.

Type:

TypeParameter [particle type, float]

reference_shape#

Reference shape against to which compute the deformation energy.

Type:

TypeParameter [particle type, dict]

normal_shear_ratio#

Fraction of normal to shear deformation trial moves (default: 0.5).

Type:

float, optional

class hoomd.hpmc.shape_move.ShapeMove(default_step_size=None)#

Bases:

Base class for all shape moves.

Parameters:

default_step_size (float, optional) – Default maximum size of shape trial moves (default: None). By default requires setting step size for all types.

Note

See the documentation of each derived class for a list of supported shapes.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

step_size#

Maximum size of shape trial moves.

Type:

TypeParameter [particle type, float]

class hoomd.hpmc.shape_move.ShapeSpace(callback, default_step_size=None, param_move_probability=1)#

Bases: ShapeMove

Apply shape moves in a \(N\) dimensional shape space.

Parameters:
  • callback (callable [str, list], dict ]) – The python callable that will be called to map the given shape parameters to a shape definition. The callable takes the particle type and a list of parameters as arguments and return a dictionary with the shape definition whose keys must match the shape definition of the integrator: callable[[str, list], dict]. There is no type validation of the callback.

  • default_step_size (float, optional) – Default maximum size of shape trial moves (default: None). By default requires setting step size for all types.

  • param_move_probability (float, optional) – Average fraction of shape parameters to change each timestep (default: 1).

Shape support.

The following shapes are supported:

Attention

ShapeSpace only works with spheropolyhedra that have zero rounding or are spheres.

Note

Parameters must be given for every particle type and must be between 0 and 1. The class does not performs any consistency checks internally. Therefore, any shape constraint (e.g. constant volume, etc) must be performed within the callback.

Example:

mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape["A"] = dict(vertices=[(1, 1, 1), (-1, -1, 1),
                               (1, -1, -1), (-1, 1, -1)])
# example callback
class ExampleCallback:
    def __init__(self):
        default_dict = dict(sweep_radius=0, ignore_statistics=True)
    def __call__(self, type, param_list):
        # do something with params and define verts
        return dict("vertices":verts, **self.default_dict))
move = hpmc.shape_move.ShapeSpace(callback = ExampleCallback)
callback#

The python function that will be called to map the given shape parameters to a shape definition. The function takes the particle type and a list of parameters as arguments and return a dictionary with the shape definition whose keys must match the shape definition of the integrator: callable[[str, list], dict].

Type:

callable [str, list], dict ]

step_size#

Maximum size of shape trial moves.

Type:

TypeParameter [particle type, float]

params#

List of tunable parameters to be updated. The length of the list defines the dimension of the shape space for each particle type.

Type:

TypeParameter [particle type, list]

param_move_probability#

Average fraction of shape parameters to change each timestep (default: 1).

Type:

float, optional

class hoomd.hpmc.shape_move.Vertex(default_step_size=None, vertex_move_probability=1)#

Bases: ShapeMove

Apply shape moves where particle vertices are translated.

Vertices are rescaled during each shape move to ensure that the shape maintains a constant volume. To preserve detail balance, the maximum step size is rescaled by volume**(1/3) every time a move is accepted.

Parameters:
  • default_step_size (float, optional) – Default maximum size of shape trial moves (default: None). By default requires setting step size for all types.

  • vertex_move_probability (float, optional) – Average fraction of vertices to change during each shape move (default: 1).

Vertex moves apply a uniform move on each vertex with probability vertex_move_probability in a shape up to a maximum displacement of step_size for the composing instance. The shape volume is rescaled at the end of all the displacements to the specified volume. To preserve detail balance, the maximum step size is rescaled by \(V^{1 / 3}\) every time a move is accepted.

Shape support.

The following shapes are supported:

Note

hoomd.hpmc.integrate.ConvexPolyhedron models shapes that are the the convex hull of the given vertices.

Example:

mc = hoomd.hpmc.integrate.ConvexPolyhedron(23456)
cube_verts = [(1, 1, 1), (1, 1, -1), (1, -1, 1), (-1, 1, 1),
              (1, -1, -1), (-1, 1, -1), (-1, -1, 1), (-1, -1, -1)])
mc.shape["A"] = dict(vertices=numpy.asarray(cube_verts) / 2)
vertex_move = shape_move.Vertex()
vertex_move.volume["A"] = 1
step_size#

Maximum size of shape trial moves.

Type:

TypeParameter [particle type, float]

vertex_move_probability#

Average fraction of vertices to change during each shape move.

Type:

float

volume#

Volume of the particles to hold constant. The particles size is always rescaled to maintain this volume.

Type:

TypeParameter [particle type, float]

hoomd.md#

Details

Molecular dynamics.

In molecular dynamics simulations, HOOMD-blue numerically integrates the degrees of freedom in the system as a function of time under the influence of forces. To perform MD simulations, assign a MD Integrator to the hoomd.Simulation operations. Provide the Integrator with lists of integration methods, forces, and constraints to apply during the integration. Use hoomd.md.minimize.FIRE to perform energy minimization.

MD updaters (hoomd.md.update) perform additional operations during the simulation, including rotational diffusion and establishing shear flow. Use MD computes (hoomd.md.compute) to compute the thermodynamic properties of the system state.

See also

Tutorial: Introducing Molecular Dynamics

class hoomd.md.HalfStepHook(*args: Any, **kwargs: Any)#

HalfStepHook base class.

HalfStepHook provides an interface to perform computations during the half-step of a hoomd.md.Integrator.

update(timestep)#

Called during the half-step of a hoomd.md.Integrator.

This method should provide the implementation of any computation that the user wants to execute at each timestep in the middle of the integration routine.

class hoomd.md.Integrator(dt, integrate_rotational_dof=False, forces=None, constraints=None, methods=None, rigid=None, half_step_hook=None)#

Molecular dynamics time integration.

Parameters:
  • dt (float) – Integrator time step size \([\mathrm{time}]\).

  • methods (Sequence[hoomd.md.methods.Method]) – Sequence of integration methods. The default value of None initializes an empty list.

  • forces (Sequence[hoomd.md.force.Force]) – Sequence of forces applied to the particles in the system. The default value of None initializes an empty list.

  • integrate_rotational_dof (bool) – When True, integrate rotational degrees of freedom.

  • constraints (Sequence[hoomd.md.constrain.Constraint]) – Sequence of constraint forces applied to the particles in the system. The default value of None initializes an empty list. Rigid body objects (i.e. hoomd.md.constrain.Rigid) are not allowed in the list.

  • rigid (hoomd.md.constrain.Rigid) – An object defining the rigid bodies in the simulation.

  • half_step_hook (hoomd.md.HalfStepHook) – Enables the user to perform arbitrary computations during the half-step of the integration.

Integrator is the top level class that orchestrates the time integration step in molecular dynamics simulations. The integration methods define the equations of motion to integrate under the influence of the given forces and constraints.

Each method applies the given equations of motion to a subset of particles in the simulation state. See the documentation for each method for details on what equations of motion it solves. The intersection of the subsets must be null.

Integrator computes the net force, torque, energy, and virial on each particle as a sum of those applied by hoomd.md.force.Force objects in the forces and constraints lists:

\[\begin{split}\vec{F}_{\mathrm{net},i} &= \sum_{f \in \mathrm{forces}} \vec{F}_i^f \\ \vec{\tau}_{\mathrm{net},i} &= \sum_{f \in \mathrm{forces}} \vec{\tau}_i^f \\ U_{\mathrm{net},i} &= \sum_{f \in \mathrm{forces}} U_i^f \\ W_{\mathrm{net},i} &= \sum_{f \in \mathrm{forces}} W_i^f \\\end{split}\]

Integrator also computes the net additional energy and virial

\[\begin{split}U_{\mathrm{net},\mathrm{additional}} &= \sum_{f \in \mathrm{forces}} U_\mathrm{additional}^f \\ W_{\mathrm{net},\mathrm{additional}} &= \sum_{f \in \mathrm{forces}} W_\mathrm{additional}^f \\\end{split}\]

See md.force.Force for definitions of these terms. Constraints are a special type of force used to enforce specific constraints on the system state, such as distances between particles with hoomd.md.constrain.Distance. Integrator handles rigid bodies as a special case, as it only integrates the degrees of freedom of each body’s center of mass. See hoomd.md.constrain.Rigid for details.

Degrees of freedom

Integrator always integrates the translational degrees of freedom. It optionally integrates one or more rotational degrees of freedom for a given particle i when all the following conditions are met:

  • The intergration method supports rotational degrees of freedom.

  • integrate_rotational_dof is True.

  • The moment of inertia is non-zero \(I^d_i > 0\).

Each particle may have zero, one, two, or three rotational degrees of freedom.

Note

By default, integrate_rotational_dof is False. gsd and hoomd.Snapshot also set particle moments of inertia to 0 by default.

Classes

Classes of the following modules can be used as elements in methods:

The classes of following modules can be used as elements in forces:

The classes of the following module can be used as elements in constraints:

Examples:

nlist = hoomd.md.nlist.Cell()
lj = hoomd.md.pair.LJ(nlist=nlist)
lj.params.default = dict(epsilon=1.0, sigma=1.0)
lj.r_cut[('A', 'A')] = 2**(1/6)
nve = hoomd.md.methods.NVE(filter=hoomd.filter.All())
integrator = hoomd.md.Integrator(dt=0.001, methods=[nve], forces=[lj])
sim.operations.integrator = integrator
dt#

Integrator time step size \([\mathrm{time}]\).

Type:

float

methods#

List of integration methods.

Type:

list[hoomd.md.methods.Method]

forces#

List of forces applied to the particles in the system.

Type:

list[hoomd.md.force.Force]

integrate_rotational_dof#

When True, integrate rotational degrees of freedom.

Type:

bool

constraints#

List of constraint forces applied to the particles in the system.

Type:

list[hoomd.md.constrain.Constraint]

rigid#

The rigid body definition for the simulation associated with the integrator.

Type:

hoomd.md.constrain.Rigid

half_step_hook#

User defined implementation to perform computations during the half-step of the integration.

Type:

hoomd.md.HalfStepHook

__setattr__(attr, value)#

Hande group DOF update when setting integrate_rotational_dof.

property linear_momentum#

The linear momentum vector of the system \([\mathrm{mass} \cdot \mathrm{velocity}]\).

\[\vec{p} = \sum_{i=0}^\mathrm{N_particles-1} m_i \vec{v}_i\]

(Loggable: category=”sequence”)

Type:

tuple(float,float,float)

Modules

md.alchemy#

Details

Alchemical molecular dynamics.

Implements molecular dynamics simulations of an extended statistical mechanical ensemble that includes alchemical degrees of freedom describing particle attributes as thermodynamic variables.

Example:

nvt = hoomd.md.methods.NVT(...)
integrator.methods.append(nvt)
ljg = hoomd.md.alchemy.pair.LJGauss(...)
integrator.forces.append(ljg)
r0_alchemical_dof = ljg.r0[('A', 'A')]
alchemostat = hoomd.md.alchemy.methods.NVT(
    period=period,
    alchemical_dof=[r0_alchemical_dof],
    alchemical_kT=hoomd.variant.Constant(0.1),
)
integrator.methods.insert(0, alchemostat)
sim.run(n_steps)

New in version 3.1.0.

Modules

md.alchemy.pair#

Overview

AlchemicalDOF

Alchemical degree of freedom \(\alpha_i\) associated with a specific pair force.

AlchemicalDOFStore

A read-only mapping of alchemical degrees of freedom accessed by type.

LJGauss

Alchemical Lennard Jones Gauss pair force.

Details

Alchemical pair forces.

class hoomd.md.alchemy.pair.AlchemicalDOF#

Alchemical degree of freedom \(\alpha_i\) associated with a specific pair force.

AlchemicalDOF represents an alchemical degree of freedom to be numerically integrated via an alchemical integration method.

Note

To access an alchemical degree of freedom for a particular type pair, query the corresponding attribute in the alchemical pair force instance.

New in version 3.1.0.

mass#

The mass of the alchemical degree of freedom.

Type:

float

mu#

The value of the alchemical potential.

Type:

float

alpha#

The value of the dimensionless alchemical degree of freedom \(\alpha_i\).

Type:

float

alchemical_momentum#

The momentum of the alchemical parameter.

Type:

float

property alchemical_forces#

Per particle forces in alchemical alpha space.

\[F_{\mathrm{alchemical},i} = -\frac{\mathrm{d}U_i}{\mathrm{d}\alpha}\]

(Loggable: category=”particle”, default=False)

property net_alchemical_force#

Net force in alchemical alpha space.

\[F_{\mathrm{alchemical}} = \sum_{i=0}^{N_{\mathrm{particles}}-1} F_{\mathrm{alchemical},i}\]

(Loggable: category=”scalar”)

property value#

Current value of alpha multiplied by its corresponding parameter.

(Loggable: category=”scalar”)

class hoomd.md.alchemy.pair.AlchemicalDOFStore(name, pair_instance, dof_cls)#

Bases: Mapping

A read-only mapping of alchemical degrees of freedom accessed by type.

The class acts as a cache so once an alchemical DOF is queried it is returned and not recreated when queried again.

New in version 3.1.0.

__contains__(key)#

Return whether the key is in the mapping.

__getitem__(key)#

Get the alchemical degree of freedom for the given type pair.

__iter__()#

Iterate over keys.

__len__()#

Get the length of the mapping.

class hoomd.md.alchemy.pair.LJGauss(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: LJGauss

Alchemical Lennard Jones Gauss pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

LJGauss computes the Lennard-Jones Gauss force on all particles in the simulation state, with additional alchemical degrees of freedom:

\[U(r) = 1\ [\mathrm{energy}] \cdot \left[ \left ( \frac{1\ [\mathrm{length}]}{r} \right)^{12} - \left ( \frac{2\ [\mathrm{length}]}{r} \right)^{6} \right] - \alpha_{1}\epsilon \exp \left[ - \frac{\left(r - \alpha_{2}r_{0}\right)^{2}}{2 (\alpha_{3}\sigma)^{2}} \right],\]

where \(\alpha_i\) are the alchemical degrees of freedom.

Note

\(\alpha_i\) not accessed are set to 1.

Attention

hoomd.md.alchemy.pair.LJGauss does not support execution on GPUs.

Attention

hoomd.md.alchemy.pair.LJGauss does not support MPI parallel simulations.

New in version 3.1.0.

params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - Gaussian width \(\sigma\) \([\mathrm{length}]\)

  • r0 (float, required) - Gaussian center \(r_0\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

epsilon#

Alchemical degrees of freedom for the potential parameter \(\epsilon\).

Type: AlchemicalDOFStore [tuple [particle_type, particle_type], AlchemicalDOF])

sigma#

Alchemical degrees of freedom for the potential parameter \(\sigma\).

Type: AlchemicalDOFStore [tuple [particle_type, particle_type], AlchemicalDOF])

r0#

Alchemical degrees of freedom for the potential parameter \(r_0\).

Type: AlchemicalDOFStore [tuple [particle_type, particle_type], AlchemicalDOF])

md.alchemy.methods#

Overview

Alchemostat

Alchemostat base class.

NVT

Alchemical NVT integration.

Details

Alchemical MD integration methods.

class hoomd.md.alchemy.methods.Alchemostat(alchemical_dof)#

Alchemostat base class.

Note

Alchemostat is the base class for all alchemical integration methods. Users should use the subclasses and not instantiate Alchemostat directly.

New in version 3.1.0.

property alchemical_dof#

List of alchemical degrees of freedom.

Type:

list [hoomd.md.alchemy.pair.AlchemicalDOF ]

class hoomd.md.alchemy.methods.NVT(alchemical_kT, alchemical_dof, period=1)#

Alchemical NVT integration.

Implements molecular dynamics simulations of an extended statistical mechanical ensemble that includes alchemical degrees of freedom describing particle attributes as thermodynamic variables.

Parameters:

Attention

hoomd.md.alchemy.methods.NVT does not support execution on GPUs.

Attention

hoomd.md.alchemy.methods.NVT does not support MPI parallel simulations.

Attention

hoomd.md.alchemy.methods.NVT objects are not picklable.

Danger

NVT must be the first item in the hoomd.md.Integrator.methods list.

See also

Zhou et al. 2019.

New in version 3.1.0.

alchemical_kT#

Temperature set point for the alchemostat \([\mathrm{energy}]\).

Type:

hoomd.variant.Variant

alchemical_dof#

List of alchemical degrees of freedom.

Type:

list [hoomd.md.alchemy.pair.AlchemicalDOF]

period#

Timesteps between applications of the alchemostat.

Type:

int

md.angle#

Overview

Angle

Base class angle force.

Harmonic

Harmonic angle force.

CosineSquared

Cosine squared angle force.

Table

Tabulated bond force.

Details

Angle forces.

Angle force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{angle} = \sum_{(i,j,k) \in \mathrm{angles}} U_{ijk}(\theta)\]

Each angle is defined by an ordered triplet of particle tags in the hoomd.State member angle_group. HOOMD-blue does not construct angle groups, users must explicitly define angles in the initial condition.

Definition of the angle bond between particles i, j, and k.

In the angle group (i,j,k), \(\theta\) is the angle between the vectors \(\vec{r}_{ij}\) and \(\vec{r}_{kj}\).

Angle force classes assign 1/3 of the potential energy to each of the particles in the angle group:

\[U_l = \frac{1}{3} \sum_{(i,j,k) \in \mathrm{angles}} U_{ijk}(\theta) [l=i \lor l=j \lor l=k]\]

and similarly for virials.

class hoomd.md.angle.Angle#

Bases: Force

Base class angle force.

Angle is the base class for all angle forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.md.angle.CosineSquared#

Bases: Angle

Cosine squared angle force.

CosineSquared computes forces, virials, and energies on all angles in the simulation state with:

\[U(\theta) = \frac{1}{2} k \left( \cos\theta - \cos\theta_0 \right)^2\]

CosineSquared is used in the gromos96 and MARTINI force fields.

params#

The parameter of the harmonic bonds for each particle type. The dictionary has the following keys:

  • k (float, required) - potential constant \(k\) \([\mathrm{energy}]\)

  • t0 (float, required) - rest angle \(\theta_0\) \([\mathrm{radians}]\)

Type:

TypeParameter[angle type, dict]

Examples:

cosinesq = angle.CosineSquared()
cosinesq.params['A-A-A'] = dict(k=3.0, t0=0.7851)
cosinesq.params['A-B-A'] = dict(k=100.0, t0=1.0)
class hoomd.md.angle.Harmonic#

Bases: Angle

Harmonic angle force.

Harmonic computes forces, virials, and energies on all angles in the simulation state with:

\[U(\theta) = \frac{1}{2} k \left( \theta - \theta_0 \right)^2\]
params#

The parameter of the harmonic bonds for each particle type. The dictionary has the following keys:

  • k (float, required) - potential constant \(k\) \([\mathrm{energy} \cdot \mathrm{radians}^{-2}]\)

  • t0 (float, required) - rest angle \(\theta_0\) \([\mathrm{radians}]\)

Type:

TypeParameter[angle type, dict]

Examples:

harmonic = angle.Harmonic()
harmonic.params['A-A-A'] = dict(k=3.0, t0=0.7851)
harmonic.params['A-B-A'] = dict(k=100.0, t0=1.0)
class hoomd.md.angle.Table(width)#

Bases: Angle

Tabulated bond force.

Parameters:

width (int) – Number of points in the table.

Table computes computes forces, virials, and energies on all angles in the simulation given the user defined tables \(U\) and \(\tau\).

The torque \(\tau\) is:

\[\tau(\theta) = \tau_\mathrm{table}(\theta)\]

and the potential \(V(\theta)\) is:

\[U(\theta) =U_\mathrm{table}(\theta)\]

Provide \(\tau_\mathrm{table}(\theta)\) and \(U_\mathrm{table}(\theta)\) on evenly spaced grid points points in the range \(\theta \in [0,\pi]\). Table linearly interpolates values when \(\theta\) lies between grid points. The torque must be specificed commensurate with the potential: \(\tau = -\frac{\partial U}{\partial \theta}\).

params#

The potential parameters. The dictionary has the following keys:

  • U ((width,) numpy.ndarray of float, required) - the tabulated energy values \([\mathrm{energy}]\). Must have a size equal to width.

  • tau ((width,) numpy.ndarray of float, required) - the tabulated torque values \([\mathrm{force} \cdot \mathrm{length}]\). Must have a size equal to width.

Type:

TypeParameter [angle type, dict]

width#

Number of points in the table.

Type:

int

md.bond#

Overview

Bond

Base class bond force.

FENEWCA

FENE and WCA bond force.

Harmonic

Harmonic bond force.

Table

Tabulated bond force.

Tether

Tether bond force.

Details

Bond forces.

Bond force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{bond} = \sum_{(j,k) \in \mathrm{bonds}} U_{jk}(r)\]

Each bond is defined by an ordered pair of particle tags in the hoomd.State member bond_group. HOOMD-blue does not construct bond groups, users must explicitly define bonds in the initial condition.

Definition of the bond between particles j and k.

In the bond group (j,k), \(r\) is the length of the bond between the particle positions \(r= |\mathrm{minimum\_image}(\vec{r}_k - \vec{r}_j)|\).

Bond force classes assign 1/2 of the potential energy to each of the particles in the bond group:

\[U_i = \frac{1}{2} \sum_{(j,k) \in \mathrm{bonds}} U_{jk}(r) [i=j \lor i=k]\]

and similarly for virials.

class hoomd.md.bond.Bond#

Bases: Force

Base class bond force.

Bond is the base class for all bond forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.md.bond.FENEWCA#

Bases: Bond

FENE and WCA bond force.

FENEWCA computes forces, virials, and energies on all bonds in the simulation state with:

\[V(r) = - \frac{1}{2} k r_0^2 \ln \left( 1 - \left( \frac{r - \Delta}{r_0} \right)^2 \right) + U_{\mathrm{WCA}}(r)\]

where

\[\begin{split}U_{\mathrm{WCA}}(r) = \begin{cases} 4 \varepsilon \left[ \left( \frac{\sigma}{r - \Delta} \right)^{12} - \left( \frac{\sigma}{r - \Delta} \right)^{6} \right] + \varepsilon & r-\Delta < 2^{\frac{1}{6}}\sigma\\ 0 & r-\Delta \ge 2^{\frac{1}{6}}\sigma \end{cases}\end{split}\]

, \(k\) is the attractive force strength, \(r_0\) is the size of the bond, \(\varepsilon\) is the repulsive interaction energy, and \(\sigma\) is the repulsive interaction width.

params#

The parameter of the FENEWCA potential bonds. The dictionary has the following keys:

  • k (float, required) - attractive force strength \(k\) \([\mathrm{energy} \cdot \mathrm{length}^{-2}]\).

  • r0 (float, required) - size parameter \(r_0\) \([\mathrm{length}]\).

  • epsilon (float, required) - repulsive force strength \(\varepsilon\) \([\mathrm{energy}]\).

  • sigma (float, required) - repulsive force interaction width \(\sigma\) \([\mathrm{length}]\).

  • delta (float, required) - radial shift \(\Delta\) \([\mathrm{length}]\).

Type:

TypeParameter[bond type, dict]

Examples:

fenewca = bond.FENEWCA()
fenewca.params['A-A'] = dict(k=3.0, r0=2.38, epsilon=1.0, sigma=1.0,
                             delta=0.0)
fenewca.params['A-B'] = dict(k=10.0, r0=1.0, epsilon=0.8, sigma=1.2,
                             delta=0.0)
class hoomd.md.bond.Harmonic#

Bases: Bond

Harmonic bond force.

Harmonic computes forces, virials, and energies on all bonds in the simulation state with:

\[U(r) = \frac{1}{2} k \left( r - r_0 \right)^2\]
params#

The parameter of the harmonic bonds for each particle type. The dictionary has the following keys:

  • k (float, required) - potential constant \([\mathrm{energy} \cdot \mathrm{length}^{-2}]\)

  • r0 (float, required) - rest length \([\mathrm{length}]\)

Type:

TypeParameter[bond type, dict]

Examples:

harmonic = bond.Harmonic()
harmonic.params['A-A'] = dict(k=3.0, r0=2.38)
harmonic.params['A-B'] = dict(k=10.0, r0=1.0)
class hoomd.md.bond.Table(width)#

Bases: Bond

Tabulated bond force.

Parameters:

width (int) – Number of points in the table.

Table computes computes forces, virials, and energies on all bonds in the simulation given the user defined tables \(U\) and \(F\).

Note

For potentials that diverge near r=0, to set r_min to a non-zero value.

The force \(\vec{F}\) is:

\[\begin{split}\vec{F}(\vec{r}) = \begin{cases} 0 & r < r_{\mathrm{min}} \\ F_\mathrm{table}(r)\hat{r} & r_{\mathrm{min}} \le r < r_{\mathrm{max}} \\ 0 & r \ge r_{\mathrm{max}} \\ \end{cases}\end{split}\]

and the potential \(U(r)\) is:

\[\begin{split}U(r) = \begin{cases} 0 & r < r_{\mathrm{min}} \\ U_\mathrm{table}(r) & r_{\mathrm{min}} \le r < r_{\mathrm{max}} \\ 0 & r \ge r_{\mathrm{max}} \\ \end{cases}\end{split}\]

where \(\vec{r}\) is the vector pointing from one particle to the other in the bond.

Warning

Bonds that stretch to a length \(r \ge r_{\mathrm{max}}\) result in an error.

Provide \(F_\mathrm{table}(r)\) and \(U_\mathrm{table}(r)\) on evenly spaced grid points points between \(r_{\mathrm{min}}\) and \(r_{\mathrm{max}}\). Table linearly interpolates values when \(r\) lies between grid points and between the last grid point and \(r=r_{\mathrm{max}}\). The force must be specificed commensurate with the potential: \(F = -\frac{\partial U}{\partial r}\).

params#

The potential parameters. The dictionary has the following keys:

  • r_min (float, required) - the minimum distance to apply the tabulated potential, corresponding to the first element of the energy and force arrays \([\mathrm{length}]\).

  • r_max (float, required) - the minimum distance to apply the tabulated potential, corresponding to the first element of the energy and force arrays \([\mathrm{length}]\).

  • U ((width,) numpy.ndarray of float, required) - the tabulated energy values \([\mathrm{energy}]\). Must have a size equal to width.

  • F ((width,) numpy.ndarray of float, required) - the tabulated force values \([\mathrm{force}]\). Must have a size equal to width.

Type:

TypeParameter [bond type, dict]

width#

Number of points in the table.

Type:

int

class hoomd.md.bond.Tether#

Bases: Bond

Tether bond force.

The tethered network is described in Refs. Gompper, G. & Kroll, D. M. Statistical Mechanics of Membranes and Surfaces 2nd edn (eds Nelson, D. R. et al.) 359-426 (World Scientific, 2004) and Noguchi, H. & Gompper, G., Phys. Rev. E 72 011901 (2005).

Tether computes forces, virials, and energies on all bonds in the simulation state with:

\[U(r) = U_{\mathrm{att}}(r) + U_{\mathrm{rep}}(r)\]

where \(r\) is the distance from one particle to the other in the bond.

\[\begin{split}U_{\mathrm{att}}(r) = \begin{cases} k_b \frac{\exp(1/(l_{c0}-r)}{l_{max}-r} & r > l_{c0} \\ 0 & r \leq l_{c0} \\ \end{cases}\end{split}\]
\[\begin{split}U_{\mathrm{rep}}(r) = \begin{cases} k_b \frac{\exp(1/(r-l_{c1})}{r-l_{min}} & r < l_{c1}\\ 0 & r \ge l_{c1} \end{cases}\end{split}\]
\[l_{min} < l_{c1} < l_{c0} < l_{max}\]
params#

The parameter of the Tethering potential bonds. The dictionary has the following keys:

  • k_b (float, required) - bond stiffness \([\mathrm{energy}]\)

  • l_min (float, required) - minimum bond length \([\mathrm{length}]\)

  • l_c1 (float, required) - cutoff distance of repulsive part \([\mathrm{length}]\)

  • l_c0 (float, required) - cutoff distance of attractive part \([\mathrm{length}]\)

  • l_max (float, required) - maximum bond length \([\mathrm{length}]\)

Type:

TypeParameter[bond type, dict]

Examples:

bond_potential = bond.Tether()
bond_potential.params['A-A'] = dict(k_b=10.0, l_min=0.9, l_c1=1.2,
                                       l_c0=1.8, l_max=2.1)

md.constrain#

Overview

Constraint

Constraint force base class.

Distance

Constrain pairwise particle distances.

Rigid

Constrain particles in rigid bodies.

Details

Constraints.

Constraint force classes apply forces and the resulting virial to particles that enforce specific constraints on the positions of the particles. The constraint is satisfied at all times, so there is no potential energy associated with the constraint.

Each constraint removes a number of degrees of freedom from the system. hoomd.md.compute.ThermodynamicQuantities accounts for these lost degrees of freedom when computing kinetic temperature and pressure. See hoomd.State.update_group_dof for details on when the degrees of freedom for a group are calculated.

Warning

Do not apply multiple constraint class instances to the same particle. Each instance solves for its constraints independently.

class hoomd.md.constrain.Constraint#

Bases: Force

Constraint force base class.

Constraint is the base class for all constraint forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.md.constrain.Distance(tolerance=0.001)#

Bases: Constraint

Constrain pairwise particle distances.

Parameters:

tolerance (float) – Relative tolerance for constraint violation warnings.

Distance applies forces between particles that constrain the distances between particles to specific values. The algorithm implemented is described in:

  1. M. Yoneya, H. J. C. Berendsen, and K. Hirasawa, “A Non-Iterative Matrix Method for Constraint Molecular Dynamics Simulations,” Molecular Simulation, vol. 13, no. 6, pp. 395–405, 1994.

  2. M. Yoneya, “A Generalized Non-iterative Matrix Method for Constraint Molecular Dynamics Simulations,” Journal of Computational Physics, vol. 172, no. 1, pp. 188–197, Sep. 2001.

Each distance constraint takes the form:

\[\chi_{ij}(r) = \mathrm{minimum\_image}(\vec{r}_j - \vec{r}_i)^2 - d_{ij}^2 = 0\]

Where \(i\) and \(j\) are the the particle tags in the constraint_group and \(d_{ij}\) is the constraint distance as given by the system state.

The method sets the second derivative of the Lagrange multipliers with respect to time to zero, such that both the distance constraints and their time derivatives are conserved within the accuracy of the Velocity Verlet scheme (\(O(\delta t^2)\). It solves the corresponding linear system of equations to determine the force. The constraints are satisfied at \(t + 2 \delta t\), so the scheme is self-correcting and avoids drifts.

Add an instance of Distance to the integrator constraints list hoomd.md.Integrator.constraints to apply the force during the simulation.

Warning

In MPI simulations, it is an error when molecules defined by constraints extend over more than half the local domain size because all particles connected through constraints will be communicated between ranks as ghost particles.

Note

tolerance sets the tolerance to detect constraint violations and issue a warning message. It does not influence the computation of the constraint force.

tolerance#

Relative tolerance for constraint violation warnings.

Type:

float

class hoomd.md.constrain.Rigid#

Bases: Constraint

Constrain particles in rigid bodies.

Overview

Rigid bodies are defined by a single central particle and a number of constituent particles. All of these are particles in the simulation state and can interact with other particles via forces. The mass and moment of inertia of the central particle set the full mass and moment of inertia of the rigid body (constituent particle mass is ignored).

The central particle is at the center of mass of the rigid body and the particle’s orientation quaternion defines the rotation from the body space into the simulation box. Body space refers to a rigid body viewed in a particular reference frame. In body space, the center of mass of the body is at \((0,0,0)\) and the moment of inertia is diagonal.

Constituent particles

Select one or more particle types in the simulation to use as the central particles. For each rigid body particle type, set the constituent particle type, position and orientations in body coordinates (see body). Then, Rigid takes control of the constituent particles and sets their position and orientation in the simulation box relative to the position and orientation of the central particle:

\[\begin{split}\vec{r}_c &= \vec{r}_b + \mathbf{q}_b \vec{r}_{c,\mathrm{body}} \mathbf{q}_b^* \\ \mathbf{q}_c &= \mathbf{q}_b \mathbf{q}_{c,\mathrm{body}}\end{split}\]

where \(\vec{r}_c\) and \(\mathbf{q}_c\) are the position and orientation of a constituent particle in the simulation box, \(\vec{r}_{c,\mathrm{body}}\) and \(\mathbf{q}_{c,\mathrm{body}}\) are the position and orientation of that particle in body coordinates, and \(\vec{r}_b\) and \(\mathbf{q}_b\) are the position and orientation of the central particle of that rigid body. Rigid also sets the constituent particle image consistent with the image of the central particle and the location of the constituent particle wrapped back into the box.

Warning

Rigid overwrites the constituent particle type ids, positions and orientations. To change the position and orientation of a body, set the desired position and orientation of the central particle and call run(0) to trigger Rigid to update the particles.

In the simulation state, the body particle property defines the particle tag of the central particle: b = body[c]. In setting the body array, set central particles to their tag \(b_i = t_i\), constituent particles to their central particle’s tag \(b_i = t_{center}\), and free particles to -1: \(b_i = -1\). Free particles are particles that are not part of a rigid body.

The central particle of a rigid body must have a tag smaller than all of its constituent particles. Constituent particles follow in monotonically increasing tag order, corresponding to the order they are defined in the argument to Rigid initialization. The central and constituent particles do not need to be contiguous.

Tip

To create constituent particles, initialize a simulation state containing only central particles (but both rigid body and constituent particle types). Then call create_bodies to add all the constituent particles to the state.

Net force and torque

Rigid transfers forces, energies, and torques from constituent particles to the central particle and adds them to those from the interaction on the central particle itself. The integration methods use these forces and torques to integrate the equations of motion of the central particles (representing the whole rigid body) forward in time.

\[\begin{split}\vec{F}_b' &= \vec{F}_b + \sum_c \vec{F}_c \\ \vec{U}_b' &= U_b + \sum_c U_c \\ \vec{\tau}_b' &= \vec{\tau}_b + \sum_c \vec{\tau}_c + (\mathbf{q}_b \vec{r}_{c,\mathrm{body}} \mathbf{q}_b^*) \times \vec{F}_c\end{split}\]

Rigid also computes the corrected virial accounting for the effective constraint force (see Glaser 2020).

Note

Include 'body' in the Neighborlist exclusions to avoid calculating inter-body forces that will sum to 0. This is required in many cases where nearby particles lead to numerical errors from extremely large forces.

Integrating bodies

Set the rigid attribute of hoomd.md.Integrator to an instance of Rigid to apply rigid body constraints and apply an integration method (or methods) to the central and non-rigid particles (leave the constituent particles out - Rigid will set their position and orientation). Most integration methods support the integration of rotational degrees of freedom.

Example:

rigid_centers_and_free_filter = hoomd.filter.Rigid(
    ("center", "free"))
langevin = hoomd.md.methods.Langevin(
    filter=rigid_centers_and_free_filter, kT=1.0)

Thermodynamic quantities of bodies

hoomd.md.compute.ThermodynamicQuantities computes thermodynamic quantities (temperature, kinetic energy, etc.) over the central and non-rigid particles in the system, ignoring the consitutent particles. The body central particles contribute translational and rotational energies to the total.

Continuing simulations with rigid bodies.

To continue a simulation, write the simulation state to a file with hoomd.write.GSD and initialize the new Simulation using create_state_from_gsd. GSD stores all the particle data fields needed to reconstruct the state of the system, including the body, angular momentum, and orientation of the body. Set the same local body space environment to body as in the earlier simulation - GSD does not store this information.

Example:

rigid = constrain.Rigid()
rigid.body['A'] = {
    "constituent_types": ['A_const', 'A_const'],
    "positions": [(0,0,1),(0,0,-1)],
    "orientations": [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)],
    }
rigid.body['B'] = {
    "constituent_types": ['B_const', 'B_const'],
    "positions": [(0,0,.5),(0,0,-.5)],
    "orientations": [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)],
    }

# Can set rigid body definition to be None explicitly.
rigid.body["A"] = None

Warning

Rigid will significantly slow simulation performance when frequently changing rigid body definitions or adding/removing particles from the simulation.

body#

body is a mapping from the central particle type to a body definition represented as a dictionary. The mapping respects None as meaning that the type is not a rigid body center. All types are set to None by default. The keys for the body definition are:

Of these, Rigid uses constituent_types, positions and orientations to set the constituent particle type ids, positions and orientations every time step. create_bodies uses all these parameters to populate those particle properties when creating constituent particles.

Type: TypeParameter [particle_type, dict]

create_bodies(state, charges=None)#

Create rigid bodies from central particles in state.

Parameters:
  • state (hoomd.State) – The state in which to create rigid bodies.

  • charges (dict[str, list[float]]) – (optional) The charges for each of the constituent particles, defaults to None. If None, all charges are zero. The keys should be the central particles.

create_bodies removes any existing constituent particles and adds new ones based on the body definitions in body. It overwrites all existing particle body tags in the state.

md.compute#

Overview

HarmonicAveragedThermodynamicQuantities

Compute harmonic averaged thermodynamic properties of particles.

ThermodynamicQuantities

Compute thermodynamic properties of a subset of the system.

Details

Compute properties of molecular dynamics simulations.

The MD compute classes compute instantaneous properties of the simulation state and provide results as loggable quantities for use with hoomd.logging.Logger or by direct access via the Python API.

class hoomd.md.compute.HarmonicAveragedThermodynamicQuantities(filter, kT, harmonic_pressure=0)#

Bases: Compute

Compute harmonic averaged thermodynamic properties of particles.

Parameters:
  • filter (hoomd.filter.filter_like) – Particle filter to compute thermodynamic properties for.

  • kT (float) – Temperature of the system \([\mathrm{energy}]\).

  • harmonic_pressure (float) – Harmonic contribution to the pressure \([\mathrm{pressure}]\). If omitted, the HMA pressure can still be computed, but will be similar in precision to the conventional pressure.

HarmonicAveragedThermodynamicQuantities acts on a given subset of particles and calculates harmonically mapped average (HMA) properties of those particles when requested. HMA computes properties more precisely (with less variance) for atomic crystals in NVT simulations. The presence of diffusion (vacancy hopping, etc.) will prevent HMA from providing improvement. HMA tracks displacements from the lattice positions, which are saved either during first call to Simulation.run or when the compute is first added to the simulation, whichever occurs last.

Note

HarmonicAveragedThermodynamicQuantities is an implementation of the methods section of Sabry G. Moustafa, Andrew J. Schultz, and David A. Kofke. (2015). “Very fast averaging of thermal properties of crystals by molecular simulation”. Phys. Rev. E 92, 043303 doi:10.1103/PhysRevE.92.043303

Examples:

hma = hoomd.compute.HarmonicAveragedThermodynamicQuantities(
    filter=hoomd.filter.Type('A'), kT=1.0)
filter#

Subset of particles compute thermodynamic properties for.

Type:

hoomd.filter.filter_like

kT#

Temperature of the system \([\mathrm{energy}]\).

Type:

float

harmonic_pressure#

Harmonic contribution to the pressure \([\mathrm{pressure}]\).

Type:

float

property potential_energy#

Average potential energy \([\mathrm{energy}]\).

(Loggable: category=”scalar”)

property pressure#

Average pressure \([\mathrm{pressure}]\).

(Loggable: category=”scalar”)

class hoomd.md.compute.ThermodynamicQuantities(filter)#

Bases: Compute

Compute thermodynamic properties of a subset of the system.

Parameters:

filter (hoomd.filter) – Particle filter to compute thermodynamic properties for.

ThermodynamicQuantities acts on a subset of particles in the system and calculates thermodynamic properties of those particles. Add a ThermodynamicQuantities instance to a logger to save these quantities to a file, see hoomd.logging.Logger for more details.

Note

For compatibility with hoomd.md.constrain.Rigid, ThermodynamicQuantities performs all sums \(\sum_{i \in \mathrm{filter}}\) over free particles and rigid body centers - ignoring constituent particles to avoid double counting.

Examples:

f = filter.Type('A')
compute.ThermodynamicQuantities(filter=f)
property degrees_of_freedom#

Number of degrees of freedom in the subset \(N_{\mathrm{dof}}\).

\[N_\mathrm{dof} = N_\mathrm{dof, translational} + N_\mathrm{dof, rotational}\]

See also

hoomd.State.update_group_dof describes when \(N_{\mathrm{dof}}\) is updated.

(Loggable: category=”scalar”)

property kinetic_energy#

Total kinetic energy \(K\) of the subset \([\mathrm{energy}]\).

\[K = K_\mathrm{rotational} + K_\mathrm{translational}\]

(Loggable: category=”scalar”)

property kinetic_temperature#

Instantaneous thermal energy \(kT_k\) of the subset \([\mathrm{energy}]\).

\[kT_k = 2 \cdot \frac{K}{N_{\mathrm{dof}}}\]

(Loggable: category=”scalar”)

property num_particles#

Number of particles \(N\) in the subset.

(Loggable: category=”scalar”)

property potential_energy#

Potential energy \(U\) that the subset contributes to the system \([\mathrm{energy}]\).

\[U = U_{\mathrm{net},\mathrm{additional}} + \sum_{i \in \mathrm{filter}} U_{\mathrm{net},i},\]

where the net energy terms are computed by hoomd.md.Integrator over all of the forces in hoomd.md.Integrator.forces.

(Loggable: category=”scalar”)

property pressure#

Instantaneous pressure \(P\) of the subset \([\mathrm{pressure}]\).

\[P = \frac{ 2 \cdot K_{\mathrm{translational}} + W_\mathrm{isotropic} }{D \cdot V},\]

where \(D\) is the dimensionality of the system, \(V\) is the volume of the simulation box (or area in 2D), and \(W_\mathrm{isotropic}\) is the isotropic virial:

\[\begin{split}W_\mathrm{isotropic} = & \left( W_{\mathrm{net},\mathrm{additional}}^{xx} + W_{\mathrm{net},\mathrm{additional}}^{yy} + W_{\mathrm{net},\mathrm{additional}}^{zz} \right) \\ + & \sum_{i \in \mathrm{filter}} \left( W_\mathrm{{net},i}^{xx} + W_\mathrm{{net},i}^{yy} + W_\mathrm{{net},i}^{zz} \right)\end{split}\]

where the net virial terms are computed by hoomd.md.Integrator over all of the forces in hoomd.md.Integrator.forces and \(W^{zz}=0\) in 2D simulations.

(Loggable: category=”scalar”)

property pressure_tensor#

Instantaneous pressure tensor of the subset \([\mathrm{pressure}]\).

The six components of the pressure tensor are given in the order: (\(P^{xx}\), \(P^{xy}\), \(P^{xz}\), \(P^{yy}\), \(P^{yz}\), \(P^{zz}\)):

\[P^{kl} = \frac{1}{V} \left( W_{\mathrm{net},\mathrm{additional}}^{kl} + \sum_{i \in \mathrm{filter}} m_i \cdot v_i^k \cdot v_i^l + W_{\mathrm{net},i}^{kl} \right),\]

where the net virial terms are computed by hoomd.md.Integrator over all of the forces in hoomd.md.Integrator.forces, \(v_i^k\) is the k-th component of the velocity of particle \(i\) and \(V\) is the total simulation box volume (or area in 2D).

(Loggable: category=”sequence”)

property rotational_degrees_of_freedom#

Number of rotational degrees of freedom in the subset \(N_\mathrm{dof, rotational}\).

Integration methods (hoomd.md.methods) determine the number of degrees of freedom they give to each particle. Each integration method operates on a subset of the system \(\mathrm{filter}_m\) that may be distinct from the subset from the subset given to ThermodynamicQuantities.

When hoomd.md.Integrator.integrate_rotational_dof is False, \(N_\mathrm{dof, rotational} = 0\). When it is True, the given degrees of freedom depend on the dimensionality of the system.

In 2D:

\[N_\mathrm{dof, rotational} = \sum_{m \in \mathrm{methods}} \; \sum_{i \in \mathrm{filter} \cup \mathrm{filter}_m} \left[ I_{z,i} > 0 \right]\]

where \(I\) is the particles’s moment of inertia.

In 3D:

\[N_\mathrm{dof, rotational} = \sum_{m \in \mathrm{methods}} \; \sum_{i \in \mathrm{filter} \cup \mathrm{filter}_m} \left[ I_{x,i} > 0 \right] + \left[ I_{y,i} > 0 \right] + \left[ I_{z,i} > 0 \right]\]

See also

hoomd.State.update_group_dof describes when \(N_{\mathrm{dof, rotational}}\) is updated.

(Loggable: category=”scalar”)

property rotational_kinetic_energy#

Rotational kinetic energy \(K_\mathrm{rotational}\) of the subset \([\mathrm{energy}]\).

\[ \begin{align}\begin{aligned}\begin{split}K_\mathrm{rotational,d} = \frac{1}{2} \sum_{i \in \mathrm{filter}} \begin{cases} \frac{L_{d,i}^2}{I_{d,i}} & I^d_i > 0 \\ 0 & I^d_i = 0 \end{cases}\end{split}\\K_\mathrm{rotational} = K_\mathrm{rotational,x} + K_\mathrm{rotational,y} + K_\mathrm{rotational,z}\end{aligned}\end{align} \]

\(I\) is the moment of inertia and \(L\) is the angular momentum in the (diagonal) reference frame of the particle.

(Loggable: category=”scalar”)

property translational_degrees_of_freedom#

Number of translational degrees of freedom in the subset \(N_{\mathrm{dof, translational}}\).

When using a single integration method on all particles that is momentum conserving, the center of mass motion is conserved and the number of translational degrees of freedom is:

\[N_\mathrm{dof, translational} = DN - D\frac{N}{N_\mathrm{particles}} - N_\mathrm{constraints}(\mathrm{filter})\]

where \(D\) is the dimensionality of the system and \(N_\mathrm{constraints}(\mathrm{filter})\) is the number of degrees of freedom removed by constraints (hoomd.md.constrain) in the subset. The fraction \(\frac{N}{N_\mathrm{particles}}\) distributes the momentum conservation constraint evenly when ThermodynamicQuantities is applied to multiple subsets.

Note

When using rigid bodies (hoomd.md.constrain.Rigid), \(N\) is the number of rigid body centers plus free particles selected by the filter and \(N_\mathrm{particles}\) is total number of rigid body centers plus free particles in the whole system.

When hoomd.md.Integrator.rigid is not set, \(N\) is the total number of particles selected by the filter and \(N_\mathrm{particles}\) is the total number of particles in the system, regardless of their body value.

When using multiple integration methods, a single integration method on fewer than all particles, or a single integration method that is not momentum conserving, hoomd.md.Integrator assumes that linear momentum is not conserved and counts the center of mass motion in the degrees of freedom:

\[N_{\mathrm{dof, translational}} = DN - N_\mathrm{constraints}(\mathrm{filter})\]

(Loggable: category=”scalar”)

property translational_kinetic_energy#

Translational kinetic energy \(K_{\mathrm{translational}}\) of the subset \([\mathrm{energy}]\).

\[K_\mathrm{translational} = \frac{1}{2} \sum_{i \in \mathrm{filter}} m_i v_i^2\]

(Loggable: category=”scalar”)

property volume#

Volume \(V\) of the simulation box (area in 2D) \([\mathrm{length}^{D}]\).

(Loggable: category=”scalar”)

md.data#

Overview

ForceLocalAccess

Access HOOMD-Blue force data buffers on the CPU.

ForceLocalAccessGPU

Access HOOMD-Blue force data buffers on the GPU.

NeighborListLocalAccess

Access HOOMD-Blue neighbor list data buffers on the CPU.

NeighborListLocalAccessGPU

Access HOOMD-Blue neighbor list data buffers on the GPU.

Details

Force data local access.

ForceLocalAccess, ForceLocalAccessGPU, and related classes provide direct access to the data buffers managed by hoomd.md.force.Force. This means that MPI rank locality must be considered in accessing the arrays in a multi-rank simulation.

class hoomd.md.data.ForceLocalAccess(force_obj, state)#

Access HOOMD-Blue force data buffers on the CPU.

force#

Local force data. \([\mathrm{force}]\)

Type:

(N_particles, 3) hoomd.data.array of float

potential_energy#

Local potential energy data. \([\mathrm{energy}]\)

Type:

(N_particles,) hoomd.data.array of float

torque#

Local torque data. \([\mathrm{force} \cdot \mathrm{length}]\)

Type:

(N_particles, 3) hoomd.data.array of float

virial#

Local virial data. \([\mathrm{energy}]\)

Type:

(N_particles, 6) hoomd.data.array of float

class hoomd.md.data.ForceLocalAccessGPU(*args, **kwargs)#

Access HOOMD-Blue force data buffers on the GPU.

force#

Local force data. \([\mathrm{force}]\)

Type:

(N_particles, 3) hoomd.data.array of float

potential_energy#

Local potential energy data. \([\mathrm{energy}]\)

Type:

(N_particles,) hoomd.data.array of float

torque#

Local torque data. \([\mathrm{force} \cdot \mathrm{length}]\)

Type:

(N_particles, 3) hoomd.data.array of float

virial#

Local virial data. \([\mathrm{energy}]\)

Type:

(N_particles, 6) hoomd.data.array of float

class hoomd.md.data.NeighborListLocalAccess(nlist_obj, state)#

Access HOOMD-Blue neighbor list data buffers on the CPU.

The internal NeighborList implementation of HOOMD is comprised of essentially three array buffers. The buffers are:

  • nlist: Ragged array of neighbor data.

  • head_list: Indexes for particles to read from the neighbor list.

  • n_neigh: Number of neighbors for each particle.

The neighbor indices of particle \(i\) are stored in the slice nlist[head_list[i]:head_list[i]+n_neigh[i]]. The result of access outside of these bounds is undefined. The half_nlist property is used to query whether the neighbor list stores a single copy for each pair (True), or two copies for each pair (False). Under MPI, pairs that cross domains are stored twice, once in each domain rank.

head_list#

Local head list.

Type:

(N_particles,) hoomd.data.array of unsigned long

n_neigh#

Number of neighbors.

Type:

(N_particles,) hoomd.data.array of unsigned int

nlist#

Raw neighbor list data.

Type:

(…) hoomd.data.array of unsigned int

half_nlist#

Convenience property to check if the storage mode is ‘half’.

Type:

bool

class hoomd.md.data.NeighborListLocalAccessGPU(*args, **kwargs)#

Access HOOMD-Blue neighbor list data buffers on the GPU.

The internal NeighborList implementation of HOOMD is comprised of essentially three array buffers. The buffers are:

  • nlist: Ragged array of neighbor data.

  • head_list: Indexes for particles to read from the neighbor list.

  • n_neigh: Number of neighbors for each particle.

The neighbor indices of particle \(i\) are stored in the slice nlist[head_list[i]:head_list[i]+n_neigh[i]]. The result of access outside of these bounds is undefined. The half_nlist property is used to query whether the neighbor list stores a single copy for each pair (True), or two copies for each pair (False). Under MPI, pairs that cross domains are stored twice, once in each domain rank.

head_list#

Local head list.

Type:

(N_particles,) hoomd.data.array of unsigned long

n_neigh#

Number of neighbors.

Type:

(N_particles,) hoomd.data.array of unsigned int

nlist#

Raw neighbor list data.

Type:

(…) hoomd.data.array of unsigned int

half_nlist#

Convenience property to check if the storage mode is ‘half’.

Type:

bool

Modules

md.dihedral#

Overview

Dihedral

Base class dihedral force.

Periodic

Periodic dihedral force.

OPLS

OPLS dihedral force.

Table

Tabulated dihedral force.

Details

Dihedral forces.

Dihedral force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{dihedral} = \sum_{(i,j,k,l) \in \mathrm{dihedrals}} U_{ijkl}(\phi)\]

Each dihedral is defined by an ordered quadruplet of particle tags in the hoomd.State member dihedral_group. HOOMD-blue does not construct dihedral groups, users must explicitly define dihedrals in the initial condition.

Definition of the dihedral bond between particles i, j, k, and l.

In the dihedral group (i,j,k,l), \(\phi\) is the signed dihedral angle between the planes passing through (\(\vec{r}_i, \vec{r}_j, \vec{r}_k\)) and (\(\vec{r}_j, \vec{r}_k, \vec{r}_l\)).

Dihedral force classes assign 1/4 of the potential energy to each of the particles in the dihedral group:

\[U_m = \frac{1}{4} \sum_{(i,j,k,l) \in \mathrm{dihedrals}} U_{ijkl}(\phi) [m=i \lor m=j \lor m=k \lor m=l]\]

and similarly for virials.

Important

There are multiple conventions pertaining to the dihedral angle in the literature. HOOMD-blue utilizes the convention where \(\phi = \pm \pi\) in the anti-parallel stretched state ( /\/ ) and \(\phi = 0\) in the parallel compact state ( |_| ).

class hoomd.md.dihedral.Dihedral#

Bases: Force

Base class dihedral force.

Dihedral is the base class for all dihedral forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.md.dihedral.OPLS#

Bases: Dihedral

OPLS dihedral force.

OPLS computes forces, virials, and energies on all dihedrals in the simulation state with:

\[U(\phi) = \frac{1}{2}k_1 \left( 1 + \cos\left(\phi \right) \right) + \frac{1}{2}k_2 \left( 1 - \cos\left(2 \phi \right) \right) + \frac{1}{2}k_3 \left( 1 + \cos\left(3 \phi \right) \right) + \frac{1}{2}k_4 \left( 1 - \cos\left(4 \phi \right) \right)\]

\(k_n\) are the force coefficients in the Fourier series.

params#

The parameter of the OPLS bonds for each particle type. The dictionary has the following keys:

  • k1 (float, required) - force constant of the first term \([\mathrm{energy}]\)

  • k2 (float, required) - force constant of the second term \([\mathrm{energy}]\)

  • k3 (float, required) - force constant of the third term \([\mathrm{energy}]\)

  • k4 (float, required) - force constant of the fourth term \([\mathrm{energy}]\)

Type:

TypeParameter [dihedral type, dict]

Examples:

opls = dihedral.OPLS()
opls.params['A-A-A-A'] = dict(k1=1.0, k2=1.0, k3=1.0, k4=1.0)
class hoomd.md.dihedral.Periodic#

Bases: Dihedral

Periodic dihedral force.

Periodic computes forces, virials, and energies on all dihedrals in the simulation state with:

\[U(\phi) = \frac{1}{2}k \left( 1 + d \cos\left(n \phi - \phi_0 \right) \right)\]
params#

The parameter of the harmonic bonds for each dihedral type. The dictionary has the following keys:

  • k (float, required) - potential constant \(k\) \([\mathrm{energy}]\)

  • d (float, required) - sign factor \(d\)

  • n (int, required) - angle multiplicity factor \(n\)

  • phi0 (float, required) - phase shift \(\phi_0\) \([\mathrm{radians}]\)

Type:

TypeParameter [dihedral type, dict]

Examples:

harmonic = dihedral.Periodic()
harmonic.params['A-A-A-A'] = dict(k=3.0, d=-1, n=3, phi0=0)
harmonic.params['A-B-C-D'] = dict(k=100.0, d=1, n=4, phi0=math.pi/2)
class hoomd.md.dihedral.Table(width)#

Bases: Dihedral

Tabulated dihedral force.

Parameters:

width (int) – Number of points in the table.

Table computes computes forces, virials, and energies on all dihedrals in the simulation given the user defined tables \(U\) and \(\tau\).

The torque \(\tau\) is:

\[\tau(\phi) = \tau_\mathrm{table}(\phi)\]

and the potential \(U(\phi)\) is:

\[U(\phi) = U_\mathrm{table}(\phi)\]

Provide \(\tau_\mathrm{table}(\phi)\) and \(U_\mathrm{table}(\phi)\) on evenly spaced grid points points in the range \(\phi \in [-\pi,\pi]\). Table linearly interpolates values when \(\phi\) lies between grid points. The torque must be specificed commensurate with the potential: \(\tau = -\frac{\partial U}{\partial \phi}\).

params#

The potential parameters. The dictionary has the following keys:

  • U ((width,) numpy.ndarray of float, required) - the tabulated energy values \([\mathrm{energy}]\). Must have a size equal to width.

  • tau ((width,) numpy.ndarray of float, required) - the tabulated torque values \([\mathrm{force} \cdot \mathrm{length}]\). Must have a size equal to width.

Type:

TypeParameter [dihedral type, dict]

width#

Number of points in the table.

Type:

int

md.external#

External forces for molecular dynamics.

External force classes apply forces to particles that result from an external field as a function of particle position and orientation:

\[U_\mathrm{external} = \sum_i U(\vec{r}_i, \mathbf{q}_i)\]

Modules

md.external.field#

Overview

Field

Base class external field force.

Electric

Electric field force.

Periodic

One-dimension periodic force.

Details

External field forces.

class hoomd.md.external.field.Electric#

Electric field force.

Electric computes forces, and virials, and energies on all particles in the in the simulation state with consistent with:

\[U_i = - q_i \vec{E} \cdot \vec{r}_i\]

where \(q_i\) is the particle charge and \(\vec{E}\) is the field vector. The field vector \(\vec{E}\) must be set per unique particle type.

E#

The electric field vector \(\vec{E}\) as a tuple \((E_x, E_y, E_z)\) \([\mathrm{energy} \cdot \mathrm{charge}^{-1} \cdot \mathrm{length^{-1}}]\).

Type: TypeParameter [particle_type, tuple [float, float, float]]

Example:

# Apply an electric field in the x-direction
e_field = external.field.Electric()
e_field.E['A'] = (1, 0, 0)
class hoomd.md.external.field.Field#

Base class external field force.

External potentials represent forces which are applied to all particles in the simulation by an external agent.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

class hoomd.md.external.field.Periodic#

One-dimension periodic force.

Periodic computes forces and energies that induce a periodic modulation in the particle concentration. The modulation is one-dimensional and extends along the lattice vector \(\mathbf{a}_i\) of the simulation cell. This force can, for example, be used to induce an ordered phase in a block-copolymer melt.

The force is computed commensurate with the potential energy:

\[U_i(\vec{r_j}) = A \tanh\left[\frac{1}{2 \pi p w} \cos\left( p \vec{b}_i\cdot\vec{r_j}\right)\right]\]

Periodic results in no virial stress due functional dependence on box scaled coordinates.

params#

The Periodic external potential parameters. The dictionary has the following keys:

  • A (float, required) - Ordering parameter \(A\) \([\mathrm{energy}]\).

  • i (int, required) - \(\vec{b}_i\), \(i=0, 1, 2\), is the simulation box’s reciprocal lattice vector in the \(i\) direction \([\mathrm{dimensionless}]\).

  • w (float, required) - The interface width \(w\) relative to the distance \(2\pi/|\mathbf{b_i}|\) between planes in the \(i\)-direction \([\mathrm{dimensionless}]\).

  • p (int, required) - The periodicity \(p\) of the modulation \([\mathrm{dimensionless}]\).

Type: TypeParameter [particle_type, dict]

Example:

# Apply a periodic composition modulation along the first lattice vector
periodic = external.field.Periodic()
periodic.params['A'] = dict(A=1.0, i=0, w=0.02, p=3)
periodic.params['B'] = dict(A=-1.0, i=0, w=0.02, p=3)
md.external.wall#

Overview

ForceShiftedLJ

Force-shifted Lennard-Jones wall force.

Gaussian

Gaussian wall force.

LJ

Lennard-Jones wall force.

Mie

Mie wall force.

Morse

Morse wall force.

Yukawa

Yukawa wall force.

WallPotential

Base class wall force.

Details

Wall forces.

Wall potential classes compute forces, virials, and energies between all particles and the given walls consistent with the energy:

\[U_\mathrm{wall} = \sum_{i=0}^{\mathrm{N_particles-1}} \sum_{w \in walls} U_w(d_i),\]

where \(d_i\) is the signed distance between particle \(i\) and the wall \(w\).

The potential \(U_w(d)\) is a function of the signed cutoff distance between the particle and a wall’s surface \(d\). The resulting force \(\vec{F}\) is is parallel to \(\vec{d}\), the vector pointing from the closest point on the wall’s surface to the particle. \(U_w(d)\) is related to a pair potential \(U_{\mathrm{pair}}\) as defined below and each subclass of WallPotential implements a different functional form of \(U_{\mathrm{pair}}\).

Walls are two-sided surfaces with positive signed distances to points on the active side of the wall and negative signed distances to points on the inactive side. Additionally, the wall’s mode controls how forces and energies are computed for particles on or near the inactive side. The inside flag (or normal in the case of hoomd.wall.Plane) determines which side of the surface is active.

Standard Mode

In the standard mode, when \(r_{\mathrm{extrap}} \le 0\), the potential energy is only computed on the active side. \(U(d)\) is evaluated in the same manner as when the mode is shift for the analogous pair potentials within the boundaries of the active space:

\[U(d) = U_{\mathrm{pair}}(d) - U_{\mathrm{pair}}(r_{\mathrm{cut}})\]

For open=True spaces:

\[\begin{split}\vec{F} = \begin{cases} -\frac{\partial U}{\partial d}\hat{d} & 0 < d < r_{\mathrm{cut}} \\ 0 & d \ge r_{\mathrm{cut}} \\ 0 & d \le 0 \end{cases}\end{split}\]

For open=False (closed) spaces:

\[\begin{split}\vec{F} = \begin{cases} -\frac{\partial U}{\partial d}\hat{d} & 0 \le d < r_{\mathrm{cut}} \\ 0 & d \ge r_{\mathrm{cut}} \\ 0 & d < 0 \end{cases}\end{split}\]

Below we show the potential for a hoomd.wall.Sphere with radius 5 in 2D, using the Gaussian potential with \(\epsilon=1, \sigma=1\) and inside=True:

Example plot of wall potential.

When inside=False, the potential becomes:

Example plot of an outside wall potential.

Extrapolated Mode:

The wall potential can be linearly extrapolated starting at \(d = r_{\mathrm{extrap}}\) on the active side and continuing to the inactive side. This can be useful to move particles from the inactive side to the active side.

The extrapolated potential has the following form:

\[\begin{split}V_{\mathrm{extrap}}(d) = \begin{cases} U(d) & d > r_{\rm extrap} \\ U(r_{\rm extrap}) + (r_{\rm extrap}-r)\vec{F}(r_{\rm extrap}) \cdot \vec{n} & d \le r_{\rm extrap} \end{cases}\end{split}\]

where \(\vec{n}\) is such that the force points towards the active space for repulsive potentials. This gives an effective force on the particle due to the wall:

\[\begin{split}\vec{F}(d) = \begin{cases} \vec{F}(d) & d > r_{\rm extrap} \\ \vec{F}(r_{\rm extrap}) & d \le r_{\rm extrap} \end{cases}\end{split}\]

Below is an example of extrapolation with r_extrap=1.1 for a LJ potential with \(\epsilon=1, \sigma=1\).

Example plot demonstrating potential extrapolation.

To use extrapolated mode r_extrap must be set per particle type.

Attention

Walls are fixed in space and do not adjust with the box size. For example, NPT simulations may not behave as expected.

Note

  • The virial due to walls is computed, but the pressure computed and reported by hoomd.md.compute.ThermodynamicQuantities is not well defined. The volume (or area) of the box enters into the pressure computation, which is not correct in a confined system. It may not even be possible to define an appropriate volume with soft walls.

  • An effective use of wall forces requires considering the geometry of the system. Each wall is only evaluated in one simulation box and thus is not periodic. Forces will be evaluated and added to all particles from all walls. Additionally there are no safeguards requiring a wall to exist inside the box to have interactions. This means that an attractive force existing outside the simulation box would pull particles across the periodic boundary where they would immediately cease to have any interaction with that wall. It is therefore up to the user to use walls in a physically meaningful manner. This includes the geometry of the walls, their interactions, and as noted here their location.

  • When \(r_{\mathrm{cut}} \le 0\) or is set to False the particle type wall interaction is excluded.

  • While wall potentials are based on the same potential energy calculations as pair potentials, features of pair potentials such as specified neighborlists, and alternative force shifting modes are not supported.

class hoomd.md.external.wall.ForceShiftedLJ(walls)#

Force-shifted Lennard-Jones wall force.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions to use for the force.

Wall force evaluated using the Force-shifted Lennard-Jones force. See hoomd.md.pair.ForceShiftedLJ for the functional form of the force and parameter definitions.

Example:

walls = [hoomd.wall.Sphere(radius=4.0)]
shifted_lj_wall = hoomd.md.external.wall.ForceShiftedLJ(
    walls=walls)
shifted_lj_wall.params['A'] = {
    "epsilon": 1.0, "sigma": 1.0, "r_cut": 3.0}
shifted_lj_wall.params[['A','B']] = {
    "epsilon": 0.5, "sigma": 3.0, "r_cut": 3.2}
walls#

A list of wall definitions to use for the force.

Type:

list [hoomd.wall.WallGeometry ]

params#

The potential parameters per type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • r_cut (float, required) - The cut off distance for the wall potential \([\mathrm{length}]\)

  • r_extrap (float, optional) - The distance to extrapolate the potential, defaults to 0 \([\mathrm{length}]\)

Type: TypeParameter [particle_types, dict]

class hoomd.md.external.wall.Gaussian(walls)#

Gaussian wall force.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions to use for the force.

Wall force evaluated using the Gaussian force. See hoomd.md.pair.Gaussian for the functional form of the force and parameter definitions.

Example:

walls = [hoomd.wall.Sphere(radius=4.0)]
gaussian_wall = hoomd.md.external.wall.Gaussian(walls=walls)
gaussian_wall.params['A'] = {"epsilon": 1.0, "sigma": 1.0, "r_cut": 2.5}
gaussian_wall.params[['A','B']] = {
    "epsilon": 2.0, "sigma": 1.0, "r_cut": 1.0}
walls#

A list of wall definitions to use for the force.

Type:

list [hoomd.wall.WallGeometry ]

params#

The potential parameters per type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • r_cut (float, required) - The cut off distance for the wall potential \([\mathrm{length}]\)

  • r_extrap (float, optional) - The distance to extrapolate the potential \([\mathrm{length}]\), defaults to 0.

Type: TypeParameter [particle_types, dict]

class hoomd.md.external.wall.LJ(walls)#

Lennard-Jones wall force.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions to use for the force.

Wall force evaluated using the Lennard-Jones force. See hoomd.md.pair.LJ for the functional form of the force and parameter definitions.

Example:

walls = [hoomd.wall.Sphere(radius=4.0)]
lj = hoomd.md.external.wall.LJ(walls=walls)
lj.params['A'] = {"sigma": 1.0, "epsilon": 1.0, "r_cut": 2.5}
lj.params[['A','B']] = {"epsilon": 2.0, "sigma": 1.0, "r_cut": 2.8}
lj.params["A"] = {"r_extrap": 1.1}
params#

The potential parameters per type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • r_cut (float, required) - The cut off distance for the wall potential \([\mathrm{length}]\)

  • r_extrap (float, optional) - The distance to extrapolate the potential, defaults to 0 \([\mathrm{length}]\).

Type: TypeParameter [particle_types, dict]

class hoomd.md.external.wall.Mie(walls)#

Mie wall force.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions to use for the force.

Wall force evaluated using the Mie force. See hoomd.md.pair.Mie for the functional form of the force and parameter definitions.

Example:

walls = [hoomd.wall.Sphere(radius=4.0)]
mie_wall = hoomd.md.external.wall.Mie(walls=walls)
mie_wall.params['A'] = {
    "epsilon": 1.0, "sigma": 1.0, "n": 12, "m": 6, "r_cut": 3.0}
mie_wall.params[['A','B']] = {
    "epsilon": 0.5, "sigma": 3.0, "n": 49, "m": 50, "r_cut": 3.2}
walls#

A list of wall definitions to use for the force.

Type:

list [hoomd.wall.WallGeometry ]

params#

The potential parameters per type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • r_cut (float, required) - The cut off distance for the wall potential \([\mathrm{length}]\)

  • r_extrap (float, optional) - The distance to extrapolate the potential, defaults to 0 \([\mathrm{length}]\)

Type: TypeParameter [particle_types, dict]

class hoomd.md.external.wall.Morse(walls)#

Morse wall force.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions to use for the force.

Wall force evaluated using the Morse force. See hoomd.md.pair.Morse for the functional form of the force and parameter definitions.

Example:

walls = [hoomd.wall.Sphere(radius=4.0)]
morse_wall = hoomd.md.external.wall.Morse(walls=walls)
morse_wall.params['A'] = {
    "D0": 1.0, "alpha": 1.0, "r0": 1.0, "r_cut": 3.0}
morse_wall.params[['A','B']] = {
    "D0": 0.5, "alpha": 3.0, "r0": 1.0, "r_cut": 3.2}
walls#

A list of wall definitions to use for the force.

Type:

list [hoomd.wall.WallGeometry ]

params#

The potential parameters per type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • r_cut (float, required) - The cut off distance for the wall potential \([\mathrm{length}]\)

  • r_extrap (float, optional) - The distance to extrapolate the potential, defaults to 0 \([\mathrm{length}]\)

Type: TypeParameter [particle_types, dict]

class hoomd.md.external.wall.WallPotential(walls)#

Base class wall force.

Warning

WallPotential should not be used directly. It is a base class that provides features and documentation common to all standard wall potentials.

property walls#

The walls associated with this wall potential.

Type:

list [hoomd.wall.WallGeometry]

class hoomd.md.external.wall.Yukawa(walls)#

Yukawa wall force.

Parameters:

walls (list [hoomd.wall.WallGeometry ]) – A list of wall definitions to use for the force.

Wall force evaluated using the Yukawa force. See hoomd.md.pair.Yukawa for the functional form of the force and parameter definitions.

Example:

walls = [hoomd.wall.Sphere(radius=4.0)]
yukawa_wall = hoomd.md.external.wall.Yukawa(walls=walls)
yukawa_wall.params['A'] = {
    "epsilon": 1.0, "kappa": 1.0, "r_cut": 3.0}
yukawa_wall.params[['A','B']] = {
    "epsilon": 0.5, "kappa": 3.0, "r_cut": 3.2}
walls#

A list of wall definitions to use for the force.

Type:

list [hoomd.wall.WallGeometry ]

params#

The potential parameters per type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • r_cut (float, required) - The cut off distance for the wall potential \([\mathrm{length}]\)

  • r_extrap (float, optional) - The distance to extrapolate the potential, defaults to 0 \([\mathrm{length}]\)

Type: TypeParameter [particle_types, dict]

md.force#

Overview

Force

Defines a force for molecular dynamics simulations.

Active

Active force.

ActiveOnManifold

Active force on a manifold.

Constant

Constant force.

Custom

Custom forces implemented in python.

Details

Apply forces to particles.

class hoomd.md.force.Force#

Bases: Compute

Defines a force for molecular dynamics simulations.

Force is the base class for all molecular dynamics forces and provides common methods.

A Force class computes the force and torque on each particle in the simulation state \(\vec{F}_i\) and \(\vec{\tau}_i\). With a few exceptions (noted in the documentation of the specific force classes), Force subclasses also compute the contribution to the system’s potential energy \(U\) and the the virial tensor \(W\). Force breaks the computation of the total system \(U\) and \(W\) into per-particle and additional terms as detailed in the documentation for each specific Force subclass.

\[\begin{split}U & = U_\mathrm{additional} + \sum_{i=0}^{N_\mathrm{particles}-1} U_i \\ W & = W_\mathrm{additional} + \sum_{i=0}^{N_\mathrm{particles}-1} W_i\end{split}\]

Force represents virial tensors as six element arrays listing the components of the tensor in this order:

\[(W^{xx}, W^{xy}, W^{xz}, W^{yy}, W^{yz}, W^{zz}).\]

The components of the virial tensor for a force on a single particle are:

\[W^{kl}_i = F^k \cdot r_i^l\]

where the superscripts select the x,y, and z components of the vectors. To properly account for periodic boundary conditions, pairwise interactions evaluate the virial:

\[W^{kl}_i = \frac{1}{2} \sum_j F^k_{ij} \cdot \mathrm{minimum\_image}(\vec{r}_j - \vec{r}_i)^l\]

Tip

Add a Force to your integrator’s forces list to include it in the equations of motion of your system. Add a Force to your simulation’s operations.computes list to compute the forces and energy without influencing the system dynamics.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

property additional_energy#

Additional energy term \(U_\mathrm{additional}\) \([\mathrm{energy}]\).

(Loggable: category=”scalar”)

Type:

float

property additional_virial#

Additional virial tensor term \(W_\mathrm{additional}\) \([\mathrm{energy}]\).

(Loggable: category=”sequence”)

Type:

(1, 6) numpy.ndarray of float

property cpu_local_force_arrays#

Expose force arrays on the CPU.

Provides direct access to the force, potential energy, torque, and virial data of the particles in the system on the cpu through a context manager. All data is MPI rank-local.

The hoomd.md.data.ForceLocalAccess object returned by this property has four arrays through which one can modify the force data:

Note

The local arrays are read only for built-in forces. Use Custom to implement custom forces.

Examples:

with self.cpu_local_force_arrays as arrays:
    arrays.force[:] = ...
    arrays.potential_energy[:] = ...
    arrays.torque[:] = ...
    arrays.virial[:] = ...
Type:

hoomd.md.data.ForceLocalAccess

property energies#

Energy contribution \(U_i\) from each particle \([\mathrm{energy}]\).

Attention

In MPI parallel execution, the array is available on rank 0 only. energies is None on ranks >= 1.

(Loggable: category=”particle”)

Type:

(N_particles, ) numpy.ndarray of float

property energy#

The potential energy \(U\) of the system from this force \([\mathrm{energy}]\).

(Loggable: category=”scalar”)

Type:

float

property forces#

The force \(\vec{F}_i\) applied to each particle \([\mathrm{force}]\).

Attention

In MPI parallel execution, the array is available on rank 0 only. forces is None on ranks >= 1.

(Loggable: category=”particle”)

Type:

(N_particles, 3) numpy.ndarray of float

property gpu_local_force_arrays#

Expose force arrays on the GPU.

Provides direct access to the force, potential energy, torque, and virial data of the particles in the system on the gpu through a context manager. All data is MPI rank-local.

The hoomd.md.data.ForceLocalAccessGPU object returned by this property has four arrays through which one can modify the force data:

Note

The local arrays are read only for built-in forces. Use Custom to implement custom forces.

Examples:

with self.gpu_local_force_arrays as arrays:
    arrays.force[:] = ...
    arrays.potential_energy[:] = ...
    arrays.torque[:] = ...
    arrays.virial[:] = ...

Note

GPU local force data is not available if the chosen device for the simulation is hoomd.device.CPU.

Type:

hoomd.md.data.ForceLocalAccessGPU

property torques#

The torque \(\vec{\tau}_i\) applied to each particle \([\mathrm{force} \cdot \mathrm{length}]\).

Attention

In MPI parallel execution, the array is available on rank 0 only. torques is None on ranks >= 1.

(Loggable: category=”particle”)

Type:

(N_particles, 3) numpy.ndarray of float

property virials#

Virial tensor contribution \(W_i\) from each particle \([\mathrm{energy}]\).

Attention

To improve performance Force objects only compute virials when needed. When not computed, virials is None. Virials are computed on every step when using a md.methods.ConstantPressure integrator, on steps where a writer is triggered (such as write.GSD which may log pressure or virials), or when Simulation.always_compute_pressure is True.

Attention

In MPI parallel execution, the array is available on rank 0 only. virials is None on ranks >= 1.

(Loggable: category=”particle”)

Type:

(N_particles, 6) numpy.ndarray of float

class hoomd.md.force.Active(filter)#

Bases: Force

Active force.

Parameters:

filter (hoomd.filter) – Subset of particles on which to apply active forces.

Active computes an active force and torque on all particles selected by the filter:

\[\begin{split}\vec{F}_i = \mathbf{q}_i \vec{f}_i \mathbf{q}_i^* \\ \vec{\tau}_i = \mathbf{q}_i \vec{u}_i \mathbf{q}_i^*,\end{split}\]

where \(\vec{f}_i\) is the active force in the local particle coordinate system (set by type active_force) and \(\vec{u}_i\) is the active torque in the local particle coordinate system (set by type in active_torque.

Note

To introduce rotational diffusion to the particle orientations, use create_diffusion_updater.

Examples:

all = hoomd.filter.All()
active = hoomd.md.force.Active(
    filter=hoomd.filter.All()
    )
active.active_force['A','B'] = (1,0,0)
active.active_torque['A','B'] = (0,0,0)
rotational_diffusion_updater = active.create_diffusion_updater(
    trigger=10)
sim.operations += rotational_diffusion_updater

Note

The energy and virial associated with the active force are 0.

filter#

Subset of particles on which to apply active forces.

Type:

hoomd.filter

active_force#

Active force vector in the local reference frame of the particle \([\mathrm{force}]\). It is defined per particle type and stays constant during the simulation.

Type: TypeParameter [particle_type, tuple [float, float, float]]

active_torque#

Active torque vector in the local reference frame of the particle \([\mathrm{force} \cdot \mathrm{length}]\). It is defined per particle type and stays constant during the simulation.

Type: TypeParameter [particle_type, tuple [float, float, float]]

create_diffusion_updater(trigger, rotational_diffusion)#

Create a rotational diffusion updater for this active force.

Parameters:
Returns:

The rotational diffusion updater.

Return type:

hoomd.md.update.ActiveRotationalDiffusion

class hoomd.md.force.ActiveOnManifold(filter, manifold_constraint)#

Bases: Active

Active force on a manifold.

Parameters:

ActiveOnManifold computes a constrained active force and torque on all particles selected by the filter similar to Active. ActiveOnManifold restricts the forces to the local tangent plane of the manifold constraint. For more information see Active.

Hint

Use ActiveOnManifold with a md.methods.rattle integration method with the same manifold constraint.

Note

To introduce rotational diffusion to the particle orientations, use create_diffusion_updater. The rotational diffusion occurs in the local tangent plane of the manifold.

Examples:

all = filter.All()
sphere = hoomd.md.manifold.Sphere(r=10)
active = hoomd.md.force.ActiveOnManifold(
    filter=hoomd.filter.All(), rotation_diff=0.01,
    manifold_constraint = sphere
    )
active.active_force['A','B'] = (1,0,0)
active.active_torque['A','B'] = (0,0,0)
filter#

Subset of particles on which to apply active forces.

Type:

hoomd.filter

manifold_constraint#

Manifold constraint.

Type:

hoomd.md.manifold.Manifold

active_force#

Active force vector in the local reference frame of the particle \([\mathrm{force}]\). It is defined per particle type and stays constant during the simulation.

Type: TypeParameter [particle_type, tuple [float, float, float]]

active_torque#

Active torque vector in local reference frame of the particle \([\mathrm{force} \cdot \mathrm{length}]\). It is defined per particle type and stays constant during the simulation.

Type: TypeParameter [particle_type, tuple [float, float, float]]

create_diffusion_updater(trigger, rotational_diffusion)#

Create a rotational diffusion updater for this active force.

Parameters:
Returns:

The rotational diffusion updater.

Return type:

hoomd.md.update.ActiveRotationalDiffusion

class hoomd.md.force.Constant(filter)#

Constant force.

Parameters:

filter (hoomd.filter) – Subset of particles on which to apply constant forces.

Constant applies a type dependent constant force and torque on all particles selected by the filter. Constant sets the force and torque to (0,0,0) for particles not selected by the filter.

Examples:

constant = hoomd.md.force.Constant(
    filter=hoomd.filter.All()
    )
constant.constant_force['A'] = (1,0,0)
constant.constant_torque['A'] = (0,0,0)

Note

The energy and virial associated with the constant force are 0.

filter#

Subset of particles on which to apply constant forces.

Type:

hoomd.filter

constant_force#

Constant force vector in the global reference frame of the system \([\mathrm{force}]\). It is defined per particle type and defaults to (0.0, 0.0, 0.0) for all types.

Type: TypeParameter [particle_type, tuple [float, float, float]]

constant_torque#

Constant torque vector in the global reference frame of the system \([\mathrm{force} \cdot \mathrm{length}]\). It is defined per particle type and defaults to (0.0, 0.0, 0.0) for all types.

Type: TypeParameter [particle_type, tuple [float, float, float]]

class hoomd.md.force.Custom(aniso=False)#

Custom forces implemented in python.

Derive a custom force class from Custom, and override the set_forces method to compute forces on particles. Users have direct, zero-copy access to the C++ managed buffers via either the cpu_local_force_arrays or gpu_local_force_arrays property. Choose the property that corresponds to the device you wish to alter the data on. In addition to zero-copy access to force buffers, custom forces have access to the local snapshot API via the _state.cpu_local_snapshot or the _state.gpu_local_snapshot property.

See also

See the documentation in hoomd.State for more information on the local snapshot API.

Examples:

class MyCustomForce(hoomd.force.Custom):
    def __init__(self):
        super().__init__(aniso=True)

    def set_forces(self, timestep):
        with self.cpu_local_force_arrays as arrays:
            arrays.force[:] = -5
            arrays.torque[:] = 3
            arrays.potential_energy[:] = 27
            arrays.virial[:] = np.arange(6)[None, :]

In addition, since data is MPI rank-local, there may be ghost particle data associated with each rank. To access this read-only ghost data, access the property name with either the prefix ghost_ of the suffix _with_ghost.

Note

Pass aniso=True to the md.force.Custom constructor if your custom force produces non-zero torques on particles.

Examples:

class MyCustomForce(hoomd.force.Custom):
    def __init__(self):
        super().__init__()

    def set_forces(self, timestep):
        with self.cpu_local_force_arrays as arrays:
            # access only the ghost particle forces
            ghost_force_data = arrays.ghost_force

            # access torque data on this rank and ghost torque data
            torque_data = arrays.torque_with_ghost

Note

When accessing the local force arrays, always use a context manager.

Note

The shape of the exposed arrays cannot change while in the context manager.

Note

All force data buffers are MPI rank local, so in simulations with MPI, only the data for a single rank is available.

Note

Access to the force buffers is constant (O(1)) time.

Changed in version 3.1.0: Custom zeros the force, torque, energy, and virial arrays before calling the user-provided set_forces.

abstract set_forces(timestep)#

Set the forces in the simulation loop.

Parameters:

timestep (int) – The current timestep in the simulation.

md.improper#

Overview

Improper

Base class improper force.

Harmonic

Harmonic improper force.

Details

Improper forces.

Improper force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{improper} = \sum_{(i,j,k,l) \in \mathrm{impropers}} U_{ijkl}(\chi)\]

Each improper is defined by an ordered quadruplet of particle tags in the hoomd.State member improper_group. HOOMD-blue does not construct improper groups, users must explicitly define impropers in the initial condition.

Definition of the improper bond between particles i, j, k, and l.

In an improper group (i,j,k,l), \(\chi\) is the signed improper angle between the planes passing through (\(\vec{r}_i, \vec{r}_j, \vec{r}_k\)) and (\(\vec{r}_j, \vec{r}_k, \vec{r}_l\)). This is the same definition used in dihedrals. Typically, researchers use impropers to force molecules to be planar.

Improper force classes assign 1/4 of the potential energy to each of the particles in the improper group:

\[U_m = \frac{1}{4} \sum_{(i,j,k,l) \in \mathrm{impropers}} U_{ijkl}(\chi) [m=i \lor m=j \lor m=k \lor m=l]\]

and similarly for virials.

class hoomd.md.improper.Harmonic#

Bases: Improper

Harmonic improper force.

Harmonic computes forces, virials, and energies on all impropers in the simulation state with:

\[U(r) = \frac{1}{2}k \left( \chi - \chi_{0} \right )^2\]
params#

The parameter of the harmonic impropers for each improper type. The dictionary has the following keys:

  • k (float, required), potential constant \(k\) \([\mathrm{energy}]\).

  • chi0 (float, required), equilibrium angle \(\chi_0\) \([\mathrm{radian}]\).

Type:

TypeParameter [improper type, dict]

Example:

harmonic = hoomd.md.improper.Harmonic()
harmonic.params['A-B-C-D'] = dict(k=1.0, chi0=0)
class hoomd.md.improper.Improper#

Bases: Force

Base class improper force.

Improper is the base class for all improper forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

md.long_range#

Overview

Details

Long-range potentials for molecular dynamics.

Modules

md.long_range.pppm#

Overview

Coulomb

Reciprocal space part of the PPPM Coulomb forces.

make_pppm_coulomb_forces

Long range Coulomb interactions evaluated using the PPPM method.

Details

Long-range potentials evaluated using the PPPM method.

class hoomd.md.long_range.pppm.Coulomb(nlist, resolution, order, r_cut, alpha, pair_force)#

Bases: Force

Reciprocal space part of the PPPM Coulomb forces.

Note

Use make_pppm_coulomb_forces to create a connected pair of md.pair.Ewald and md.long_range.pppm.Coulomb instances that together implement the PPPM method for electrostatics.

resolution#

Number of grid points in the x, y, and z directions \(\mathrm{[dimensionless]}\).

Type:

tuple[int, int, int]

order#

Number of grid points in each direction to assign charges to \(\mathrm{[dimensionless]}\).

Type:

int

r_cut#

Cutoff distance between the real space and reciprocal space terms \(\mathrm{[length]}\).

Type:

float

alpha#

Debye screening parameter \(\mathrm{[length^{-1}]}\).

Type:

float

property nlist#

Neighbor list used to compute the real space term.

hoomd.md.long_range.pppm.make_pppm_coulomb_forces(nlist, resolution, order, r_cut, alpha=0)#

Long range Coulomb interactions evaluated using the PPPM method.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • resolution (tuple[int, int, int]) – Number of grid points in the x, y, and z directions \(\mathrm{[dimensionless]}\).

  • order (int) – Number of grid points in each direction to assign charges to \(\mathrm{[dimensionless]}\).

  • r_cut (float) – Cutoff distance between the real space and reciprocal space terms \(\mathrm{[length]}\).

  • alpha (float) – Debye screening parameter \(\mathrm{[length^{-1}]}\).

Evaluate the potential energy \(U_\mathrm{coulomb}\) and apply the corresponding forces to the particles in the simulation.

\[U_\mathrm{coulomb} = \frac{1}{2} \sum_\vec{n} \sum_{i=0}^{N-1} \sum_{j=0}^{N-1} u_\mathrm{coulomb}(\vec{r}_j - \vec{r}_i + n_1 \cdot \vec{a}_1 + n_2 \cdot \vec{a}_2 + n_3 \cdot \vec{a}_3, q_i, q_j)\]
\[u_\mathrm{coulomb}(\vec{r}, q_i, q_j) = \frac{q_i q_j}{r} e^{-\alpha r}\]

where the infinite sum includes all periodic images \(\vec{n}\), \(N\) is the number of particles, \(\vec{r}_i\) is the position of particle \(i\), \(q_i\) is the charge of particle \(i\), \(\alpha\) is the Debye screening parameter, and \(\vec{a}_k\) are the periodic simulation box lattice vectors.

Note

In HOOMD-blue, the \(\frac{1}{4\pi\epsilon_0}\) factor is included in the units of charge.

The particle particle particle mesh (PPPM) method splits this computation into real space and reciprocal space components.

\[U_\mathrm{coulomb} = U_\mathrm{real\ space} + U_\mathrm{reciprocal\ space}\]

md.pair.Ewald to computes the real space term directly and md.long_range.pppm.Coulomb computes the reciprocal space term using fast Fourier transforms performed on a charge density grid. The accuracy of the method is sensitive to the cutoff for the real space part, the order of interpolation and grid resolution.

Exclusions

When nlist contains exclusions, md.pair.Ewald skips the computation of the excluded real space particle-particle interactions. md.long_range.pppm.Coulomb must correct the reciprocal space computation for this. The full energy (Coulomb.energy + Ewald.energy) is the sum of the following terms:

  • \(U_\mathrm{coulomb,additional}\) (Coulomb.additional_energy): Energy from the reciprocal space calculation plus any correction due to 'body' exclusions in the neighbor list.

  • \(U_{\mathrm{coulomb},i}\) (Coulomb.energies): Energies from the non-body neighbor list exclusions.

  • \(U_\mathrm{ewald,additional}\) (Ewald.additional_energy): 0.

  • \(U_\mathrm{ewald,i}\) (Ewald.additional_energy): Energies from the real space calculation for non-excluded particle pairs.

Warning

Do not apply bonds, angles, dihedrals, or impropers between particles in the same rigid body. Doing so will cause the exclusions to be double counted (once in \(U_\mathrm{coulomb,additional}\) and again in \(U_{\mathrm{coulomb},i}\)).

Screening

The Debye screening parameter \(\alpha\) enables the screening of electrostatic interactions with the same functional form as the short range md.pair.Yukawa potential. Use md.long_range.pppm.Coulomb with a non-zeo \(\alpha\) to compute screened electrostatic interactions when the cutoff is so large that the short ranged interactions are inefficient. See Salin, G and Caillol, J. 2000 for details.

Important

In MPI simulations with multiple ranks, the grid resolution must be a power of two in each dimension.

Returns:

real_space_force, reciprocal_space_force

Add both of these forces to the integrator.

Warning

make_pppm_coulomb_forces sets all parameters for the returned Force objects given the input resolution and order. Do not change the parameters of the returned objects directly.

md.manifold#

Overview

Manifold

Base class manifold object.

Cylinder

Cylinder manifold.

Diamond

Triply periodic diamond manifold.

Ellipsoid

Ellipsoid manifold.

Gyroid

Triply periodic gyroid manifold.

Plane

Plane manifold.

Primitive

Triply periodic primitive manifold.

Sphere

Sphere manifold.

Details

Manifolds.

A Manifold defines a lower dimensional manifold embedded in 3D space with an implicit function \(F(x,y,z) = 0\). Use Manifold classes to define positional constraints to a given set of particles with:

class hoomd.md.manifold.Cylinder(r, P=(0, 0, 0))#

Bases: Manifold

Cylinder manifold.

Parameters:
  • r (float) – radius of the cylinder constraint \([\mathrm{length}]\).

  • P (tuple [float, float, float]) – point defining position of the cylinder axis (default origin) \([\mathrm{length}]\).

Cylinder defines a right circular cylinder along the z axis:

\[F(x,y,z) = (x - P_x)^{2} + (y - P_y)^{2} - r^{2}\]

Example:

cylinder1 = manifold.Cylinder(r=10)
cylinder2 = manifold.Cylinder(r=5,P=(1,1,1))
class hoomd.md.manifold.Diamond(N, epsilon=0)#

Bases: Manifold

Triply periodic diamond manifold.

Parameters:
  • N (tuple [int, int, int] or int) – number of unit cells in all 3 directions. \([N_x, N_y, N_z]\). In case number of unit cells u in all direction the same (\([u, u, u]\)), use N = u.

  • epsilon (float) – defines CMC companion of the Diamond surface (default 0)

Diamond defines a periodic diamond surface . The diamond (or Schwarz D) belongs to the family of triply periodic minimal surfaces:

\[F(x,y,z) = \cos{\frac{2 \pi}{B_x} x} \cdot \cos{\frac{2 \pi}{B_y} y} \cdot \cos{\frac{2 \pi}{B_z} z} - \sin{\frac{2 \pi}{B_x} x} \cdot \sin{\frac{2 \pi}{B_y} y} \cdot \sin{\frac{2 \pi}{B_z} z} - \epsilon\]

is the nodal approximation of the diamond surface where \([B_x,B_y,B_z]\) is the periodicity length in the x, y and z direction. The periodicity length B is defined by the current box size L and the number of unit cells N \(B_i=\frac{L_i}{N_i}\).

Example:

diamond1 = manifold.Diamond(N=1)
diamond2 = manifold.Diamond(N=(1,2,2))
class hoomd.md.manifold.Ellipsoid(a, b, c, P=(0, 0, 0))#

Bases: Manifold

Ellipsoid manifold.

Parameters:
  • a (float) – length of the a-axis of the ellipsoidal constraint \([\mathrm{length}]\).

  • b (float) – length of the b-axis of the ellipsoidal constraint \([\mathrm{length}]\).

  • c (float) – length of the c-axis of the ellipsoidal constraint \([\mathrm{length}]\).

  • P (tuple [float, float, float]) – center of the ellipsoid constraint (default origin) \([\mathrm{length}]\).

Ellipsoid defines an ellipsoid:

Implicit function

\[F(x,y,z) = \frac{(x-P_x)^{2}}{a^{2}} + \frac{(y-P_y)^{2}}{b^{2}} + \frac{(z-P_z)^{2}}{c^{2}} - 1\]

Example:

ellipsoid1 = manifold.Ellipsoid(a=10,b=5,c=5)
ellipsoid2 = manifold.Ellipsoid(a=5,b=10,c=10,P=(1,0.5,1))
class hoomd.md.manifold.Gyroid(N, epsilon=0)#

Bases: Manifold

Triply periodic gyroid manifold.

Parameters:
  • N (tuple [int, int, int] or int) – number of unit cells in all 3 directions. \([N_x, N_y, N_z]\). In case number of unit cells u in all direction the same (\([u, u, u]\)), use N = u.

  • epsilon (float) – defines CMC companion of the Gyroid surface (default 0)

Gyroid defines a periodic gyroid surface. The gyroid belongs to the family of triply periodic minimal surfaces:

\[F(x,y,z) = \sin{\frac{2 \pi}{B_x} x} \cdot \cos{\frac{2 \pi}{B_y} y} + \sin{\frac{2 \pi}{B_y} y} \cdot \cos{\frac{2 \pi}{B_z} z} + \sin{\frac{2 \pi}{B_z} z} \cdot \cos{\frac{2 \pi}{B_x} x} - \epsilon\]

is the nodal approximation of the diamond surface where \([B_x,B_y,B_z]\) is the periodicity length in the x, y and z direction. The periodicity length B is defined by the current box size L and the number of unit cells N \(B_i=\frac{L_i}{N_i}\).

Example:

gyroid1 = manifold.Gyroid(N=1)
gyroid2 = manifold.Gyroid(N=(1,2,2))
class hoomd.md.manifold.Manifold#

Bases:

Base class manifold object.

Warning

Users should not instantiate Manifold directly, but should instead instantiate one of its subclasses defining a specific manifold geometry.

Warning

Only one manifold can be applied to a given method or active forces.

__eq__(other)#

Test for equality.

class hoomd.md.manifold.Plane(shift=0)#

Bases: Manifold

Plane manifold.

Parameters:

shift (float) – z-shift of the xy-plane \([\mathrm{length}]\).

Plane defines an xy-plane at a given value of z:

\[F(x,y,z) = z - \textrm{shift}\]

Example:

plane1 = manifold.Plane()
plane2 = manifold.Plane(shift=0.8)
class hoomd.md.manifold.Primitive(N, epsilon=0)#

Bases: Manifold

Triply periodic primitive manifold.

Parameters:
  • N (tuple [int, int, int] or int) – number of unit cells in all 3 directions. \([N_x, N_y, N_z]\). In case number of unit cells u in all direction the same (\([u, u, u]\)), use N = u.

  • epsilon (float) – defines CMC companion of the Primitive surface (default 0)

Primitive specifies a periodic primitive surface as a constraint. The primitive (or Schwarz P) belongs to the family of triply periodic minimal surfaces:

\[F(x,y,z) = \cos{\frac{2 \pi}{B_x} x} + \cos{\frac{2 \pi}{B_y} y} + \cos{\frac{2 \pi}{B_z} z} - \epsilon\]

is the nodal approximation of the diamond surface where \([B_x,B_y,B_z]\) is the periodicity length in the x, y and z direction. The periodicity length B is defined by the current box size L and the number of unit cells N. \(B_i=\frac{L_i}{N_i}\)

Example:

primitive1 = manifold.Primitive(N=1)
primitive2 = manifold.Primitive(N=(1,2,2))
class hoomd.md.manifold.Sphere(r, P=(0, 0, 0))#

Bases: Manifold

Sphere manifold.

Parameters:
  • r (float) – radius of the a-axis of the spherical constraint \([\mathrm{length}]\).

  • P (tuple [float, float, float]) – center of the spherical constraint (default origin) \([\mathrm{length}]\).

Sphere defines a sphere:

\[F(x,y,z) = (x-P_x)^{2} + (y-P_y)^{2} + (z-P_z)^{2} - r^{2}\]

Example:

sphere1 = manifold.Sphere(r=10)
sphere2 = manifold.Sphere(r=5,P=(1,0,1.5))

md.many_body#

Overview

Triplet

Base class triplet force.

RevCross

Reversible crosslinker three-body force.

SquareDensity

Soft force for simulating a van der Waals liquid.

Tersoff

Tersoff force.

Details

Implement many body potentials.

Triplet force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{many-body} = \frac{1}{2} \sum_{i=0}^\mathrm{N_particles-1} \sum_{j \ne i} \sum_{j \ne k} U(\vec{r}_{ij}, \vec{r}_{ik})\]

where \(\vec{r}_{ij} = \mathrm{minimum\_image}(\vec{r}_j - \vec{r}_i)\). Triplet applies a short range cutoff for performance and assumes that both \(U(\vec{r}_{ij}, \vec{r}_{ik})\) and its derivatives are 0 when \(r_{ij} > r_\mathrm{cut}\) or \(r_{ik} > r_\mathrm{cut}\).

Specifically, the force \(\vec{F}\) applied to each particle \(i\) is:

\[\begin{split}\vec{F_i} = \begin{cases} -\nabla V(\vec r_{ij}, \vec r_{ik}) & r_{ij} < r_{\mathrm{cut}} \land r_{ik} < r_{\mathrm{cut}} \\ 0 & \mathrm{otherwise} \end{cases}\end{split}\]

The per particle energy terms are:

\[U_i = \frac{1}{2} \sum_{j \ne i} \sum_{j \ne k} U(\vec{r}_{ij}, \vec{r}_{ik}) [r_{ij} < r_{\mathrm{cut}} \land r_{ik} < r_{\mathrm{cut}}]\]
class hoomd.md.many_body.RevCross(nlist, default_r_cut=None)#

Bases: Triplet

Reversible crosslinker three-body force.

Parameters:

RevCross computes the revcross three-body force on every particle in the simulation state. Despite the fact that the revcross potential accounts for the effects of third bodies, it is actually just a combination of two body potential terms. It can thus use type-pair parameters similar to those of the pair potentials.

The RevCross potential has been described in detail in S. Ciarella and W.G. Ellenbroek 2019. It is based on a generalized Lennard-Jones pairwise attraction to form bonds between interacting particles:

\[\begin{split}U_{ij}(r) = \begin{cases} 4 \varepsilon \left[ \left( \dfrac{ \sigma}{r_{ij}} \right)^{2n} - \left( \dfrac{ \sigma}{r_{ij}} \right)^{n} \right] & r < r_\mathrm{cut} \\ 0 & r \ge r_\mathrm{cut} \end{cases}\end{split}\]

Then an additional three-body repulsion is evaluated to compensate the bond energies imposing single bond per particle condition:

\[v^{\left( 3b \right)}_{ijk} = \lambda \epsilon \hat{v}^{ \left( 2b \right)}_{ij} \left(\vec{r}_{ij}\right) \cdot \hat{v}^{ \left( 2b \right)}_{ik} \left(\vec{r}_{ik}\right)~,\]

where the two body potential is rewritten as:

\[\begin{split}\hat{v}^{ \left( 2b \right)}_{ij}\left(\vec{r}_{ij}\right) = \begin{cases} 1 & r \le r_{min} \\ - \dfrac{v_{ij}\left(\vec{r}_{ij}\right)}{\epsilon} & r > r_{min} \\ \end{cases}\end{split}\]

Attention

The RevCross potential models an asymmetric interaction between two different chemical moieties that can form a reversible bond. This requires the definition of (at least) two different types of particles. A reversible bond is only possible between two different species, otherwise \(v^{\left( 3b \right)}_{ijk}\), would prevent any bond. In our example we then set the interactions for types A and B with rev_c.params[[('A','B'),('A','B')]] to {"sigma": 0.0, "n": 0, "epsilon": 0, "lambda3": 0} and the only non-zero energy only between the different types with setting rev_c.params[('A','B')] to {"sigma":1, "n": 100, "epsilon": 100, "lambda3": 1}. Notice that the number of the minority species corresponds to the maximum number of bonds.

This three-body term also tunes the energy required for a bond swap through the coefficient:- \(\lambda\) - lambda3 (unitless) in S. Ciarella and W.G. Ellenbroek 2019 is explained that setting \(\lambda=1\) corresponds to no energy requirement to initiate bond swap, while this energy barrier scales roughly as \(\beta \Delta E_\text{sw} =\beta \varepsilon(\lambda-1)\).

Note

Choosing \(\lambda=1\) pushes the system to cluster because the three-body term is not enough to compensate the energy of multiple bonds, so it may cause nonphysical situations.

params#

The revcross potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - \(\sigma\) \([\mathrm{length}]\)

  • n (float, required) - \(n\) \([\mathrm{dimensionless}]\)

  • lambda3 (float, required) - \(\lambda_3\) \([\mathrm{dimensionless}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

Example:

nl = md.nlist.Cell()
bond_swap = md.many_body.RevCross(default_r_cut=1.3,nlist=nl)
bond_swap.params[('A', 'A'), ('B', 'B')] = {
    "sigma":0,"n": 0, "epsilon": 0, "lambda3": 0}
# a bond can be made only between A-B and not A-A or B-B
bond_swap.params[('A','B')] = {
    "sigma": 1, "n": 100, "epsilon": 10, "lambda3": 1}
class hoomd.md.many_body.SquareDensity(nlist, default_r_cut=None)#

Bases: Triplet

Soft force for simulating a van der Waals liquid.

Parameters:

SquareDensity that the square density three-body force should on every particle in the simulation state.

The self energy per particle takes the form:

\[\Psi^{ex} = B (\rho - A)^2\]

which gives a pair-wise additive, three-body force:

\[\vec{f}_{ij} = \left( B (n_i - A) + B (n_j - A) \right) w'_{ij} \vec{e}_{ij}\]

Here, \(w_{ij}\) is a quadratic, normalized weighting function,

\[w(x) = \frac{15}{2 \pi r_{c,\mathrm{weight}}^3} (1-r/r_{c,\mathrm{weight}})^2\]

The local density at the location of particle i is defined as

\[n_i = \sum\limits_{j\neq i} w_{ij} \left(\big| \vec r_i - \vec r_j \big|\right)\]
params#

The SquareDensity potential parameters. The dictionary has the following keys:

  • A (float, required) - \(A\) - mean density (default:0) \([\mathrm{length}^{-2}]\) in 2D and \([\mathrm{length}^{-3}]\) in 3D

  • B (float, required) - \(B\) - coefficient of the harmonic density term \([\mathrm{energy} \cdot \mathrm{length}^4]\) in 2D and \([\mathrm{energy} \cdot \mathrm{length}^6]\) in 3D

Type: TypeParameter [tuple [particle_type, particle_type], dict]

Example:

nl = nlist.Cell()
sqd = md.many_body.SquareDensity(nl, default_r_cut=3.0)
sqd.params[('A', 'B')] = dict(A=1.0, B=2.0)
sqd.params[('B', 'B')] = dict(A=2.0, B=2.0, default_r_on=1.0)

For further details regarding this multibody potential, see

[1] P. B. Warren, “Vapor-liquid coexistence in many-body dissipative particle dynamics” Phys. Rev. E. Stat. Nonlin. Soft Matter Phys., vol. 68, no. 6 Pt 2, p. 066702, 2003.

class hoomd.md.many_body.Tersoff(nlist, default_r_cut=None)#

Bases: Triplet

Tersoff force.

Parameters:

The Tersoff potential is a bond-order potential based on the Morse potential that accounts for the weakening of individual bonds with increasing coordination number. It does this by computing a modifier to the attractive term of the potential. The modifier contains the effects of third-bodies on the bond energies. The potential also includes a smoothing function around the cutoff. The implemented smoothing function is exponential in nature as opposed to the sinusoid used by J. Tersoff 1988.

Tersoff computes the Tersoff three-body force on every particle in the simulation state. Despite the fact that the Tersoff potential accounts for the effects of third bodies, the species of the third body is irrelevant. It can thus use type-pair parameters similar to those of the pair potentials:

\[U_{ij}(r) = \frac{1}{2} f_C(r_{ij}) \left[f_R(r_{ij}) + b_{ij}f_A(r_{ij})\right]\]

where

\[ \begin{align}\begin{aligned}f_R(r) = A_1e^{\lambda_1(r_D-r)}\\f_A(r) = A_2e^{\lambda_2(r_D-r)}\end{aligned}\end{align} \]
\[\begin{split}f_C(r) = \begin{cases} 1 & r < r_{\mathrm{cut}} - r_{CT} \\ \exp \left[-\alpha\frac{x(r)^3}{x(r)^3 - 1} \right] & r_{\mathrm{cut}} - r_{CT} < r < r_{\mathrm{cut}} \\ 0 & r > r_{\mathrm{cut}} \end{cases}\end{split}\]
\[b_{ij} = (1 + \gamma^n\chi_{ij}^n)^{\frac{-1}{2n}}\]

In the definition of \(f_C(r)\), there is a quantity \(x(r)\), which is defined as

\[x(r) = \frac{r - (r_{\mathrm{cut}} - r_{CT})}{r_{CT}}\]

which ensures continuity between the different regions of the potential. In the definition of \(b_{ij}\), there is a quantity \(\chi_{ij}\) which is defined as

\[ \begin{align}\begin{aligned}\chi_{ij} = \sum_{k \neq i,j} f_C(r_{ik}) \cdot e^{\lambda_3^3 |r_{ij} - r_{ik}|^3} \cdot g(\theta_{ijk})\\g(\theta_{ijk}) = 1 + \frac{c^2}{d^2} - \frac{c^2}{d^2 + |m - \cos(\theta_{ijk})|^2}\end{aligned}\end{align} \]
params#

The Tersoff potential parameters. The dictionary has the following keys:

  • magnitudes (tuple[float, float]) - \((A_1, A_2)\) - Magnitudes of the repulsive and attractive terms (default: (1.0, 1.0)) \([\mathrm{energy}]\)

  • exp_factors (tuple[float, float]) - \((\lambda_1, \lambda_2)\) - exponential factors of the repulsive and attractive terms (default: 2.0) \([\mathrm{length}^{-1}]\)

  • lambda3 (float) - \(\lambda_3\) - exponential factor in \(\chi_{ij}\) (default: 0.0) \([\mathrm{length}^{-1}]\)

  • dimer_r (float) - \(r_D\) - length shift in attractive and repulsive terms (default: 1.5) \([\mathrm{length}]\)

  • cutoff_thickness (float) - \(r_{CT}\) - distance which defines the different regions of the potential (default: 0.2) \([\mathrm{length}]\)

  • alpha (float) - \(\alpha\) - decay rate of the cutoff term \(f_C(r)\) (default: 3.0) \([\mathrm{dimensionless}]\)

  • n (float) - \(n\) - power in \(b_{ij}\) (default: 0.0) \([\mathrm{dimensionless}]\)

  • gamma (float) - \(\gamma\) - coefficient in \(b_{ij}\) (default: 0.0) \([\mathrm{dimensionless}]\)

  • c (float) - \(c\) - coefficient in \(g(\theta)\) (default: 0.0) \([\mathrm{dimensionless}]\)

  • d (float) - \(d\) - coefficient in \(g(\theta)\) (default: 1.0) \([\mathrm{dimensionless}]\)

  • m (float) - \(m\) - coefficient in \(g(\theta)\) (default: 0.0) \([\mathrm{dimensionless}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

Example:

nl = md.nlist.Cell()
tersoff = md.many_body.Tersoff(default_r_cut=1.3, nlist=nl)
tersoff.params[('A', 'B')] = dict(magnitudes=(2.0, 1.0), lambda3=5.0)
class hoomd.md.many_body.Triplet(nlist, default_r_cut=None)#

Bases: Force

Base class triplet force.

Triplet is the base class for many-body triplet forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

r_cut#

r_cut \([\mathrm{length}]\), optional: defaults to the value default_r_cut specified on construction.

Type: TypeParameter [tuple [particle_type, particle_type], float])

nlist#

Neighbor list used to compute the triplet potential.

Type: hoomd.md.nlist.NeighborList

Warning

Currently HOOMD-blue does not support reverse force communication between MPI domains on the GPU. Since reverse force communication is required for the calculation of three-body forces, attempting to use this potential on the GPU with MPI will result in an error.

md.methods#

Overview

Brownian

Brownian dynamics.

ConstantPressure

Constant pressure dynamics.

ConstantVolume

Constant volume, constant temperature dynamics.

DisplacementCapped

Newtonian dynamics with a cap on the maximum displacement per time step.

Langevin

Langevin dynamics.

Method

Base class integration method.

OverdampedViscous

Overdamped viscous dynamics.

Thermostatted

Base class for thermostatted integrators.

Details

Integration methods for molecular dynamics.

Integration methods work with hoomd.md.Integrator to define the equations of motion for the system. Each individual method applies the given equations of motion to a subset of particles.

Thermostatted methods

Thermostatted methods require usage of a thermostat, see hoomd.md.methods.thermostats.

Integration methods with constraints

For methods that constrain motion to a manifold see hoomd.md.methods.rattle.

class hoomd.md.methods.Brownian(filter, kT, default_gamma=1.0, default_gamma_r=(1.0, 1.0, 1.0))#

Bases: Method

Brownian dynamics.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles to apply this method to.

  • kT (hoomd.variant.variant_like) – Temperature of the simulation \([\mathrm{energy}]\).

  • default_gamma (float) – Default drag coefficient for all particle types \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

  • default_gamma_r ([float, float, float]) – Default rotational drag coefficient tensor for all particles \([\mathrm{time}^{-1}]\).

Brownian integrates particles forward in time according to the overdamped Langevin equations of motion, sometimes called Brownian dynamics or the diffusive limit. It integrates both the translational and rotational degrees of freedom.

The translational degrees of freedom follow:

\[ \begin{align}\begin{aligned}\frac{d\vec{r}}{dt} &= \frac{\vec{F}_\mathrm{C} + \vec{F}_\mathrm{R}}{\gamma},\\\langle \vec{F}_\mathrm{R} \rangle &= 0,\\\langle |\vec{F}_\mathrm{R}|^2 \rangle &= 2 d k T \gamma / \delta t,\\\langle \vec{v}(t) \rangle &= 0,\\\langle |\vec{v}(t)|^2 \rangle &= d k T / m,\end{aligned}\end{align} \]

where \(\vec{F}_\mathrm{C} = \vec{F}_\mathrm{net}\) is the net force on the particle from all forces (hoomd.md.Integrator.forces) and constraints (hoomd.md.Integrator.constraints), \(\gamma\) is the translational drag coefficient (gamma), \(\vec{F}_\mathrm{R}\) is a uniform random force, \(\vec{v}\) is the particle’s velocity, and \(d\) is the dimensionality of the system. The magnitude of the random force is chosen via the fluctuation-dissipation theorem to be consistent with the specified drag and temperature, \(T\).

About axes where \(I^i > 0\), the rotational degrees of freedom follow:

\[ \begin{align}\begin{aligned}\frac{d\mathbf{q}}{dt} &= \frac{\vec{\tau}_\mathrm{C} + \vec{\tau}_\mathrm{R}}{\gamma_r},\\\langle \vec{\tau}_\mathrm{R} \rangle &= 0,\\\langle \tau_\mathrm{R}^i \cdot \tau_\mathrm{R}^i \rangle &= 2 k T \gamma_r^i / \delta t,\\\langle \vec{L}(t) \rangle &= 0,\\\langle L^i(t) \cdot L^i(t) \rangle &= k T \cdot I^i,\end{aligned}\end{align} \]

where \(\vec{\tau}_\mathrm{C} = \vec{\tau}_\mathrm{net}\), \(\gamma_r^i\) is the i-th component of the rotational drag coefficient (gamma_r), \(\tau_\mathrm{R}^i\) is a component of the uniform random the torque, \(L^i\) is the i-th component of the particle’s angular momentum and \(I^i\) is the i-th component of the particle’s moment of inertia. The magnitude of the random torque is chosen via the fluctuation-dissipation theorem to be consistent with the specified drag and temperature, \(T\).

Brownian uses the numerical integration method from I. Snook 2007, The Langevin and Generalised Langevin Approach to the Dynamics of Atomic, Polymeric and Colloidal Systems, section 6.2.5, with the exception that \(\vec{F}_\mathrm{R}\) is drawn from a uniform random number distribution.

In Brownian dynamics, particle velocities and angular momenta are completely decoupled from positions. At each time step, Brownian draws a new velocity distribution consistent with the current set temperature so that hoomd.md.compute.ThermodynamicQuantities will report appropriate temperatures and pressures when logged or used by other methods.

Brownian dynamics neglects the acceleration term in the Langevin equation. This assumption is valid when overdamped: \(\frac{m}{\gamma} \ll \delta t\). Use Langevin if your system is not overdamped.

The attributes gamma and gamma_r set the translational and rotational damping coefficients, respectivley, by particle type.

Examples:

brownian = hoomd.md.methods.Brownian(filter=hoomd.filter.All(), kT=0.2)
brownian.gamma.default = 2.0
brownian.gamma_r.default = [1.0, 2.0, 3.0]
integrator = hoomd.md.Integrator(dt=0.001, methods=[brownian],
forces=[lj])
filter#

Subset of particles to apply this method to.

Type:

hoomd.filter.filter_like

kT#

Temperature of the simulation \([\mathrm{energy}]\).

Type:

hoomd.variant.Variant

gamma#

The drag coefficient for each particle type \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

Type:

TypeParameter[ particle type, float ]

gamma_r#

The rotational drag coefficient tensor for each particle type \([\mathrm{time}^{-1}]\).

Type:

TypeParameter[particle type,[float, float , float]]

class hoomd.md.methods.ConstantPressure(filter, S, tauS, couple, thermostat=None, box_dof=[True, True, True, False, False, False], rescale_all=False, gamma=0.0)#

Bases: Thermostatted

Constant pressure dynamics.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles on which to apply this method.

  • thermostat (hoomd.md.methods.thermostats.Thermostat) – Thermostat used to control temperature. Setting this to None yields NPH integration.

  • S (tuple[variant.variant_like, ...] or variant.variant_like) –

    Stress components set point for the barostat.

    In Voigt notation: \([S_{xx}, S_{yy}, S_{zz}, S_{yz}, S_{xz}, S_{xy}]\) \([\mathrm{pressure}]\). In case of isotropic pressure P (\([p, p, p, 0, 0, 0]\)), use S = p.

  • tauS (float) – Coupling constant for the barostat \([\mathrm{time}]\).

  • couple (str) – Couplings of diagonal elements of the stress tensor, can be “none”, “xy”, “xz”,”yz”, or “xyz”.

  • box_dof (list [ bool ]) – Box degrees of freedom with six boolean elements corresponding to x, y, z, xy, xz, yz, each. Default to [True,True,True,False,False,False]). If True, rescale corresponding lengths or tilt factors and components of particle coordinates and velocities.

  • rescale_all (bool) – if True, rescale all particles, not only those in the group, Default to False.

  • gamma (float) – Friction constant for the box degrees of freedom, Default to 0 \([\mathrm{time}^{-1}]\).

ConstantPressure integrates translational and rotational degrees of freedom of the system held at constant pressure. The barostat introduces additional degrees of freedom in the Hamiltonian that couple with box parameters. Using a thermostat yields an isobaric-isothermal ensemble, whereas its absence (thermostat = None) yields an isoenthalpic-isobaric ensemble.

See also

hoomd.md.methods.thermostats for the available thermostats.

The barostat tensor is \(\nu_{\mathrm{ij}}\). Access these quantities using barostat_dof.

By default, ConstantPressure performs integration in a cubic box under hydrostatic pressure by simultaneously rescaling the lengths Lx, Ly and Lz of the simulation box by the same factors. Set the couplings and/or box degrees of freedom to change this default.

Couplings define which diagonal elements of the pressure tensor \(P_{\alpha,\beta}\) should be averaged over, so that the corresponding box lengths are rescaled by the same amount.

Valid couplings are:

  • 'none' (all box lengths are updated independently)

  • 'xy' (Lx and Ly are coupled)

  • 'xz' (Lx and Lz are coupled)

  • 'yz' (Ly and Lz are coupled)

  • 'xyz' (Lx, Ly, and Lz are coupled)

The degrees of freedom of the box set which lengths and tilt factors of the box should be updated, and how particle coordinates and velocities should be rescaled. The box_dof tuple controls the way the box is rescaled and updated. The first three elements box_dof[:3] controls whether the x, y, and z box lengths are rescaled and updated, respectively. The last three entries box_dof[3:] control the rescaling or the tilt factors xy, xz, and yz. All options also appropriately rescale particle coordinates and velocities.

By default, the x, y, and z degrees of freedom are updated. [True,True,True,False,False,False]

Note

If any of the diagonal x, y, z degrees of freedom is not being integrated, pressure tensor components along that direction are not considered for the remaining degrees of freedom.

For example:

  • Setting all couplings and x, y, and z degrees of freedom amounts to cubic symmetry (default)

  • Setting xy coupling and x, y, and z degrees of freedom amounts to tetragonal symmetry.

  • Setting no couplings and all degrees of freedom amounts to a fully deformable triclinic unit cell

ConstantPressure numerically integrates the equations of motion using the symplectic Martyna-Tobias-Klein integrator with a Langevin piston. The equation of motion of box dimensions is given by:

\[ \begin{align}\begin{aligned}\frac{d^2 L}{dt^2} &= V W^{-1} (S - S_{ext}) - \gamma \frac{dL}{dt} + R(t)\\\langle R \rangle &= 0\\\langle |R|^2 \rangle &= 2 \gamma kT \delta t W^{-1}\end{aligned}\end{align} \]

Where \(\gamma\) is the friction on the barostat piston, which damps unphysical volume oscillations at the cost of non-deterministic integration, and \(R\) is a random force, chosen appropriately for the coupled degrees of freedom.

Note

The barostat coupling constant tauS should be set within a reasonable range to avoid abrupt fluctuations in the box volume and to avoid long time to equilibration. The recommended value for most systems is \(\tau_S = 1000 \delta t\).

Note

If \(\gamma\) is used, its value should be chosen so that the system is near critical damping. A good initial guess is \(\gamma \approx 2 \tau_S^{-1}\). A value too high will result in long relaxation times.

Note

Set gamma = 0 to obtain the same MTK equations of motion used in HOOMD-blue releases prior to v4.0.0.

Examples:

# NPH integrator with cubic symmetry
nph = hoomd.md.methods.ConstantPressure(filter=hoomd.filter.All(),
tauS = 1.2, S=2.0, couple="xyz")
integrator = hoomd.md.Integrator(dt=0.005, methods=[nph], forces=[lj])

# NPT integrator with cubic symmetry
npt = hoomd.md.methods.ConstantPressure(filter=hoomd.filter.All(),
tauS = 1.2, S=2.0, couple="xyz",
thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.0))
integrator = hoomd.md.Integrator(dt=0.005, methods=[npt], forces=[lj])

# NPT integrator with orthorhombic symmetry
npt = hoomd.md.methods.ConstantPressure(filter=hoomd.filter.All(),
tauS = 1.2, S=2.0, couple="none",
thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.0))
integrator = hoomd.md.Integrator(dt=0.005, methods=[npt], forces=[lj])

# NPT integrator with tetragonal symmetry
npt = hoomd.md.methods.ConstantPressure(filter=hoomd.filter.All(),
tauS = 1.2, S=2.0, couple="xy",
thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.0))
integrator = hoomd.md.Integrator(dt=0.005, methods=[npt], forces=[lj])

# NPT integrator with triclinic symmetry
npt = hoomd.md.methods.ConstantPressure(filter=hoomd.filter.All(),
tauS = 1.2, S=2.0, couple="none", rescale_all=True,
thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.0))
integrator = hoomd.md.Integrator(dt=0.005, methods=[npt], forces=[lj])
filter#

Subset of particles on which to apply this method.

Type:

hoomd.filter.filter_like

thermostat#

Temperature control for the integrator.

Type:

hoomd.md.methods.thermostats.Thermostat

S#

Stress components set point for the barostat. In Voigt notation, \([S_{xx}, S_{yy}, S_{zz}, S_{yz}, S_{xz}, S_{xy}]\) \([\mathrm{pressure}]\). Stress can be reset after the method object is created. For example, an isotropic pressure can be set by npt.S = 4.

Type:

tuple[hoomd.variant.Variant,…]

tauS#

Coupling constant for the barostat \([\mathrm{time}]\).

Type:

float

couple#

Couplings of diagonal elements of the stress tensor, can be “none”, “xy”, “xz”,”yz”, or “xyz”.

Type:

str

box_dof#

Box degrees of freedom with six boolean elements corresponding to x, y, z, xy, xz, yz, each.

Type:

list[bool]

rescale_all#

if True, rescale all particles, not only those in the group.

Type:

bool

gamma#

Friction constant for the box degrees of freedom, Default to 0 \([\mathrm{time^{-1}}]\).

Type:

float

barostat_dof#

Additional degrees of freedom for the barostat (\(\nu_{xx}\), \(\nu_{xy}\), \(\nu_{xz}\), \(\nu_{yy}\), \(\nu_{yz}\), \(\nu_{zz}\))

Type:

tuple[float, float, float, float, float, float]

property barostat_energy#

Energy the barostat contributes to the Hamiltonian \([\mathrm{energy}]\).

(Loggable: category=”scalar”)

thermalize_barostat_dof()#

Set the thermostat and barostat momenta to random values.

thermalize_barostat_dof sets a random value for the momentum \(\xi\) and the barostat \(\nu_{\mathrm{ij}}\). When Integrator.integrate_rotational_dof is True, it also sets a random value for the rotational thermostat momentum \(\xi_{\mathrm{rot}}\). Call thermalize_barostat_dof to set a new random state for the thermostat and barostat.

Important

You must call Simulation.run before thermalize_barostat_dof. Call run(steps=0) to prepare a newly created hoomd.Simulation.

class hoomd.md.methods.ConstantVolume(filter, thermostat=None)#

Bases: Thermostatted

Constant volume, constant temperature dynamics.

Parameters:

ConstantVolume Langevin numerically integrates the translational degrees of freedom using Velocity-Verlet and the rotational degrees of freedom with a scheme based on Kamberaj 2005.

When set, the thermostat rescales the particle velocities to control the temperature of the system. When thermostat = None, perform constant energy integration.

See also

hoomd.md.methods.thermostats for the available thermostats.

Examples:

# NVE integration
nve = hoomd.md.methods.ConstantVolume(filter=hoomd.filter.All())
integrator = hoomd.md.Integrator(dt=0.005, methods=[nve], forces=[lj])

# NVT integration using Bussi thermostat
bussi = hoomd.md.methods.thermostats.Bussi(kT=1.0)
nvt = hoomd.md.methods.ConstantVolume(filter=hoomd.filter.All(),
                                    thermostat=bussi)
integrator = hoomd.md.Integrator(dt=0.005, methods=[nvt], forces=[lj])
filter#

Subset of particles on which to apply this method.

Type:

hoomd.filter.filter_like

thermostat#

Temperature control for the integrator

Type:

hoomd.md.methods.thermostats.Thermostat

class hoomd.md.methods.DisplacementCapped(filter, maximum_displacement: Variant | float)#

Bases: ConstantVolume

Newtonian dynamics with a cap on the maximum displacement per time step.

The method employs a maximum displacement allowed each time step. This method can be helpful to relax a system with too much overlaps without “blowing up” the system.

Warning

This method does not conserve energy or momentum.

Parameters:

DisplacementCapped integrates integrates translational and rotational degrees of freedom using modified microcanoncial dynamics. See NVE for the basis of the algorithm.

Examples:

relaxer = hoomd.md.methods.DisplacementCapped(
    filter=hoomd.filter.All(), maximum_displacement=1e-3)
integrator = hoomd.md.Integrator(
    dt=0.005, methods=[relaxer], forces=[lj])
filter#

Subset of particles on which to apply this method.

Type:

hoomd.filter.filter_like

maximum_displacement#

The maximum displacement allowed for a particular timestep \([\mathrm{length}]\).

Type:

hoomd.variant.variant_like

class hoomd.md.methods.Langevin(filter, kT, tally_reservoir_energy=False, default_gamma=1.0, default_gamma_r=(1.0, 1.0, 1.0))#

Bases: Method

Langevin dynamics.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles to apply this method to.

  • kT (hoomd.variant.variant_like) – Temperature of the simulation \([\mathrm{energy}]\).

  • tally_reservoir_energy (bool) – When True, track the energy exchange between the thermal reservoir and the particles. Defaults to False \([\mathrm{energy}]\).

  • default_gamma (float) – Default drag coefficient for all particle types \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

  • default_gamma_r ([float, float, float]) – Default rotational drag coefficient tensor for all particles \([\mathrm{time}^{-1}]\).

Langevin integrates particles forward in time according to the Langevin equations of motion.

The translational degrees of freedom follow:

\[ \begin{align}\begin{aligned}m \frac{d\vec{v}}{dt} &= \vec{F}_\mathrm{C} - \gamma \cdot \vec{v} + \vec{F}_\mathrm{R}\\\langle \vec{F}_\mathrm{R} \rangle &= 0\\\langle |\vec{F}_\mathrm{R}|^2 \rangle &= 2 d kT \gamma / \delta t\end{aligned}\end{align} \]

where \(\vec{F}_\mathrm{C}\) is the force on the particle from all potentials and constraint forces, \(\gamma\) is the drag coefficient, \(\vec{v}\) is the particle’s velocity, \(\vec{F}_\mathrm{R}\) is a uniform random force, and \(d\) is the dimensionality of the system (2 or 3). The magnitude of the random force is chosen via the fluctuation-dissipation theorem to be consistent with the specified drag and temperature, \(T\).

About axes where \(I^i > 0\), the rotational degrees of freedom follow:

\[ \begin{align}\begin{aligned}I \frac{d\vec{L}}{dt} &= \vec{\tau}_\mathrm{C} - \gamma_r \cdot \vec{L} + \vec{\tau}_\mathrm{R}\\\langle \vec{\tau}_\mathrm{R} \rangle &= 0,\\\langle \tau_\mathrm{R}^i \cdot \tau_\mathrm{R}^i \rangle &= 2 k T \gamma_r^i / \delta t,\end{aligned}\end{align} \]

where \(\vec{\tau}_\mathrm{C} = \vec{\tau}_\mathrm{net}\), \(\gamma_r^i\) is the i-th component of the rotational drag coefficient (gamma_r), \(\tau_\mathrm{R}^i\) is a component of the uniform random the torque, \(\vec{L}\) is the particle’s angular momentum and \(I\) is the the particle’s moment of inertia. The magnitude of the random torque is chosen via the fluctuation-dissipation theorem to be consistent with the specified drag and temperature, \(T\).

Langevin numerically integrates the translational degrees of freedom using Velocity-Verlet and the rotational degrees of freedom with a scheme based on Kamberaj 2005.

Langevin dynamics includes the acceleration term in the Langevin equation. This assumption is valid when underdamped: \(\frac{m}{\gamma} \gg \delta t\). Use Brownian if your system is not underdamped.

The attributes gamma and gamma_r set the translational and rotational damping coefficients, respectivley, by particle type.

Example:

langevin = hoomd.md.methods.Langevin(filter=hoomd.filter.All(), kT=0.2)
langevin.gamma.default = 2.0
langevin.gamma_r.default = [1.0,2.0,3.0]
integrator = hoomd.md.Integrator(dt=0.001, methods=[langevin],
forces=[lj])

Warning

When restarting a simulation, the energy of the reservoir will be reset to zero.

filter#

Subset of particles to apply this method to.

Type:

hoomd.filter.filter_like

kT#

Temperature of the simulation \([\mathrm{energy}]\).

Type:

hoomd.variant.Variant

tally_reservoir_energy#

When True, track the energy exchange between the thermal reservoir and the particles. \([\mathrm{energy}]\).

Type:

bool

gamma#

The drag coefficient for each particle type \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

Type:

TypeParameter[ particle type, float ]

gamma_r#

The rotational drag coefficient tensor for each particle type \([\mathrm{time}^{-1}]\).

Type:

TypeParameter[particle type,[float, float , float]]

property reservoir_energy#

Energy absorbed by the reservoir \([\mathrm{energy}]\).

Set tally_reservoir_energy to True to track the reservoir energy.

(Loggable: category=”scalar”)

class hoomd.md.methods.Method#

Bases: AutotunedObject

Base class integration method.

Provides common methods for all subclasses.

Note

Users should use the subclasses and not instantiate Method directly.

class hoomd.md.methods.OverdampedViscous(filter, default_gamma=1.0, default_gamma_r=(1.0, 1.0, 1.0))#

Bases: Method

Overdamped viscous dynamics.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles to apply this method to.

  • default_gamma (float) – Default drag coefficient for all particle types \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

  • default_gamma_r ([float, float, float]) – Default rotational drag coefficient tensor for all particles \([\mathrm{time}^{-1}]\).

OverdampedViscous integrates particles forward in time following Newtonian dynamics in the overdamped limit where there is no inertial term. (in the limit that the mass \(m\) and moment of inertia \(I\) go to 0):

\[ \begin{align}\begin{aligned}\frac{d\vec{r}}{dt} &= \vec{v}\\\vec{v(t)} &= \frac{\vec{F}_\mathrm{C}}{\gamma}\\\frac{d\mathbf{q}}{dt} &= \vec{\tau}\\\tau^i &= \frac{\tau_\mathrm{C}^i}{\gamma_r^i}\end{aligned}\end{align} \]

where \(\vec{F}_\mathrm{C} = \vec{F}_\mathrm{net}\) is the net force on the particle from all forces (hoomd.md.Integrator.forces) and constraints (hoomd.md.Integrator.constraints), \(\gamma\) is the translational drag coefficient (gamma) \(\vec{v}\) is the particle’s velocity, \(d\) is the dimensionality of the system, \(\tau_\mathrm{C}^i\) is the i-th component of the net torque from all forces and constraints, and \(\gamma_r^i\) is the i-th component of the rotational drag coefficient (gamma_r).

The attributes gamma and gamma_r set the translational and rotational damping coefficients, respectivley, by particle type.

Tip

OverdampedViscous can be used to simulate systems of athermal active matter, such as athermal Active Brownian Particles.

Note

Even though OverdampedViscous models systems in the limit that \(m\) and moment of inertia \(I\) go to 0, you must still set non-zero moments of inertia to enable the integration of rotational degrees of freedom.

Examples:

odv = hoomd.md.methods.OverdampedViscous(filter=hoomd.filter.All())
odv.gamma.default = 2.0
odv.gamma_r.default = [1.0, 2.0, 3.0]
filter#

Subset of particles to apply this method to.

Type:

hoomd.filter.filter_like

gamma#

The drag coefficient for each particle type \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

Type:

TypeParameter[ particle type, float ]

gamma_r#

The rotational drag coefficient tensor for each particle type \([\mathrm{time}^{-1}]\).

Type:

TypeParameter[particle type,[float, float , float]]

class hoomd.md.methods.Thermostatted#

Bases: Method

Base class for thermostatted integrators.

Provides a common interface for all methods using thermostats

Note

Users should use the subclasses and not instantiate Thermostatted directly.

Modules

md.methods.thermostats#

Overview

Berendsen

The Berendsen thermostat.

Bussi

The Bussi-Donadio-Parrinello thermostat.

MTTK

The Nosé-Hoover thermostat.

Thermostat

Base thermostat object class.

Details

Provide classes for thermostatting simulations.

Classes are for use with hoomd.md.methods.ConstantVolume and hoomd.md.methods.ConstantPressure.

Important

Ensure that your initial condition includes non-zero particle velocities and angular momenta (when appropriate). The coupling between the thermostat and the velocities / angular momenta occurs via multiplication, so the thermostat cannot convert a zero velocity into a non-zero one except through particle collisions.

class hoomd.md.methods.thermostats.Berendsen(kT, tau)#

The Berendsen thermostat.

Parameters:

Berendsen rescales the velocities of all particles on each time step. The rescaling is performed so that the difference in the current temperature from the set point decays exponentially:

\[\frac{dT_\mathrm{cur}}{dt} = \frac{T - T_\mathrm{cur}}{\tau}\]

Attention

Berendsen does not yield a proper canonical ensemble

Example:

# NVT integration using Berendsen thermostat
dt = 0.005
berendsen = hoomd.md.methods.thermostats.Berendsen(kT=1.0, tau=dt*100)
nvt = hoomd.md.methods.ConstantVolume(filter=hoomd.filter.All(),
                                    thermostat=berendsen)
integrator = hoomd.md.Integrator(dt=dt, methods=[nvt])
kT#

Temperature of the simulation. \([energy]\)

Type:

hoomd.variant.variant_like

tau#

Time constant of thermostat. \([time]\)

Type:

float

class hoomd.md.methods.thermostats.Bussi(kT)#

The Bussi-Donadio-Parrinello thermostat.

Parameters:

kT (hoomd.variant.variant_like) – Temperature set point for the thermostat \([\mathrm{energy}]\).

Provides temperature control by rescaling the velocity by a factor taken from the canonical velocity distribution. On each timestep, velocities are rescaled by a factor \(\alpha=\sqrt{K_t / K}\), where \(K\) is the current kinetic energy, and \(K_t\) is chosen randomly from the distribution

\[P(K_t) \propto K_t^{N_f/2 - 1} \exp(-K_t / kT)\]

where \(N_f\) is the number of degrees of freedom thermalized.

See also

Bussi et. al. 2007.

Example:

# NVT integration using Bussi thermostat
bussi = hoomd.md.methods.thermostats.Bussi(kT=1.0)
nvt = hoomd.md.methods.ConstantVolume(filter=hoomd.filter.All(),
                                    thermostat=bussi)
integrator = hoomd.md.Integrator(dt=0.005, methods=[nvt])
kT#

Temperature set point for the thermostat \([\mathrm{energy}]\).

Type:

hoomd.variant.variant_like

class hoomd.md.methods.thermostats.MTTK(kT, tau)#

The Nosé-Hoover thermostat.

Produces temperature control through a Nosé-Hoover thermostat.

Parameters:
  • kT (hoomd.variant.variant_like) – Temperature set point for the thermostat \([\mathrm{energy}]\).

  • tau (float) – Coupling constant for the thermostat \([\mathrm{time}]\)

The translational thermostat has a momentum \(\xi\) and position \(\eta\). The rotational thermostat has momentum \(\xi_{\mathrm{rot}}\) and position \(\eta_\mathrm{rot}\). Access these quantities using translational_dof and rotational_dof.

Note

The coupling constant tau should be set within a reasonable range to avoid abrupt fluctuations in the kinetic temperature and to avoid long time to equilibration. The recommended value for most systems is \(\tau = 100 \delta t\).

Example:

# NVT integration using MTTK Nose-Hoover thermostat
dt = 0.005
MTTK = hoomd.md.methods.thermostats.Berendsen(kT=1.0, tau=dt*100)
nvt = hoomd.md.methods.ConstantVolume(filter=hoomd.filter.All(),
                                    thermostat=MTTK)
integrator = hoomd.md.Integrator(dt=dt, methods=[nvt])
kT#

Temperature set point for the thermostat \([\mathrm{energy}]\).

Type:

hoomd.variant.variant_like

tau#

Coupling constant for the thermostat \([\mathrm{time}]\)

Type:

float

translational_dof#

Additional degrees of freedom for the translational thermostat (\(\xi\), \(\eta\))

Type:

tuple[float, float]

rotational_dof#

Additional degrees of freedom for the rotational thermostat (\(\xi_\mathrm{rot}\), \(\eta_\mathrm{rot}\))

Type:

tuple[float, float]

property energy#

Energy the thermostat contributes to the Hamiltonian \([\mathrm{energy}]\).

(Loggable: category=”scalar”)

thermalize_dof()#

Set the thermostat momenta to random values.

thermalize_dof sets a random value for the momentum \(\xi\). When Integrator.integrate_rotational_dof is True, it also sets a random value for the rotational thermostat momentum \(\xi_{\mathrm{rot}}\). Call thermalize_dof to set a new random state for the thermostat.

Important

You must call Simulation.run before thermalize_dof. Call run(steps=0) to prepare a newly created hoomd.Simulation.

class hoomd.md.methods.thermostats.Thermostat(kT)#

Base thermostat object class.

Note

Users should use the subclasses and not instantiate Thermostat directly.

md.methods.rattle#

Overview

MethodRATTLE

Base class RATTLE integration method.

Brownian

Brownian dynamics with RATTLE constraint.

DisplacementCapped

Newtonian dynamics with a cap on the maximum displacement per time step.

Langevin

Langevin dynamics with RATTLE constraint.

NVE

NVE Integration via Velocity-Verlet with RATTLE constraint.

OverdampedViscous

Overdamped viscous dynamics with RATTLE constraint.

Details

MD integration methods with manifold constraints.

class hoomd.md.methods.rattle.Brownian(filter, kT, manifold_constraint, tolerance=1e-06)#

Brownian dynamics with RATTLE constraint.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles to apply this method to.

  • kT (hoomd.variant.variant_like) – Temperature of the simulation \([\mathrm{energy}]\).

  • manifold_constraint (hoomd.md.manifold.Manifold) – Manifold constraint.

  • tolerance (float) – Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Brownian uses the same integrator as hoomd.md.methods.Brownian, which follows the overdamped Langevin equations of motion with the additional force term \(- \lambda \vec{F}_\mathrm{M}\). The force \(\vec{F}_\mathrm{M}\) keeps the particles on the manifold constraint, where the Lagrange multiplier \(\lambda\) is calculated via the RATTLE algorithm. For more details about Brownian dynamics see hoomd.md.methods.Brownian.

Examples of using manifold_constraint:

sphere = hoomd.md.manifold.Sphere(r=10)
brownian_rattle = hoomd.md.methods.rattle.Brownian(
filter=hoomd.filter.All(), kT=0.2, manifold_constraint=sphere,
seed=1)
integrator = hoomd.md.Integrator(dt=0.001, methods=[brownian_rattle],
forces=[lj])
filter#

Subset of particles to apply this method to.

Type:

hoomd.filter.filter_like

kT#

Temperature of the simulation \([\mathrm{energy}]\).

Type:

hoomd.variant.Variant

manifold_constraint#

Manifold constraint which is used by and as a trigger for the RATTLE algorithm of this method.

Type:

hoomd.md.manifold.Manifold

tolerance#

Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Type:

float

gamma#

The drag coefficient for each particle type \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

Type:

TypeParameter[ particle type, float ]

gamma_r#

The rotational drag coefficient tensor for each particle type \([\mathrm{time}^{-1}]\).

Type:

TypeParameter[particle type,[float, float , float]]

class hoomd.md.methods.rattle.DisplacementCapped(filter: ParticleFilter | CustomFilter, maximum_displacement: Variant | float, manifold_constraint: Manifold, tolerance: float = 1e-06)#

Newtonian dynamics with a cap on the maximum displacement per time step.

Integration is via a maximum displacement capped Velocity-Verlet with RATTLE constraint. This class is useful to relax a simulation on a manifold.

Warning

This method does not conserve energy or momentum.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles on which to apply this method.

  • maximum_displacement (hoomd.variant.variant_like) – The maximum displacement allowed for a particular timestep \([\mathrm{length}]\).

  • manifold_constraint (hoomd.md.manifold.Manifold) – Manifold constraint.

  • tolerance (float, optional) – Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

DisplacementCapped performs constant volume simulations as described in hoomd.md.methods.DisplacementCapped. In addition the particles are constrained to a manifold by using the RATTLE algorithm.

Examples:

sphere = hoomd.md.manifold.Sphere(r=10)
relax_rattle = hoomd.md.methods.rattle.DisplacementCapped(
    filter=hoomd.filter.All(), maximum_displacement=0.01,
    manifold=sphere)
integrator = hoomd.md.Integrator(
    dt=0.005, methods=[relax_rattle], forces=[lj])
filter#

Subset of particles on which to apply this method.

Type:

hoomd.filter.filter_like

maximum_displacement#

The maximum displacement allowed for a particular timestep \([\mathrm{length}]\).

Type:

hoomd.variant.variant_like

manifold_constraint#

Manifold constraint which is used by and as a trigger for the RATTLE algorithm of this method.

Type:

hoomd.md.manifold.Manifold

tolerance#

Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Type:

float

class hoomd.md.methods.rattle.Langevin(filter, kT, manifold_constraint, tally_reservoir_energy=False, tolerance=1e-06)#

Langevin dynamics with RATTLE constraint.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles to apply this method to.

  • kT (hoomd.variant.variant_like) – Temperature of the simulation \([\mathrm{energy}]\).

  • manifold_constraint (hoomd.md.manifold.Manifold) – Manifold constraint.

  • tally_reservoir_energy (bool) – If true, the energy exchange between the thermal reservoir and the particles is tracked. Total energy conservation can then be monitored by adding langevin_reservoir_energy_groupname to the logged quantities. Defaults to False \([\mathrm{energy}]\).

  • tolerance (float) – Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Translational degrees of freedom

Langevin uses the same integrator as hoomd.md.methods.Langevin, which follows the Langevin equations of motion with the additional force term \(- \lambda \vec{F}_\mathrm{M}\). The force \(\vec{F}_\mathrm{M}\) keeps the particles on the manifold constraint, where the Lagrange multiplier \(\lambda\) is calculated via the RATTLE algorithm. For more details about Langevin dynamics see hoomd.md.methods.Langevin.

Use Brownian if your system is not underdamped.

Example:

sphere = hoomd.md.manifold.Sphere(r=10)
langevin_rattle = hoomd.md.methods.rattle.Langevin(
    filter=hoomd.filter.All(), kT=0.2, manifold_constraint=sphere,
    seed=1)
filter#

Subset of particles to apply this method to.

Type:

hoomd.filter.filter_like

kT#

Temperature of the simulation \([\mathrm{energy}]\).

Type:

hoomd.variant.Variant

manifold_constraint#

Manifold constraint which is used by and as a trigger for the RATTLE algorithm of this method.

Type:

hoomd.md.manifold.Manifold

tolerance#

Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Type:

float

gamma#

The drag coefficient for each particle type \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

Type:

TypeParameter[ particle type, float ]

gamma_r#

The rotational drag coefficient tensor for each particle type \([\mathrm{time}^{-1}]\).

Type:

TypeParameter[particle type,[float, float , float]]

class hoomd.md.methods.rattle.MethodRATTLE(manifold_constraint, tolerance)#

Base class RATTLE integration method.

Provides common methods for all integration methods which implement the RATTLE algorithm to constrain particles to a manifold surface.

Warning

The particles should be initialised close to the implicit surface of the manifold. Even though the particles are mapped to the set surface automatically, the mapping can lead to small inter-particle distances and, hence, large forces between particles!

See Also: * Paquay and Kusters 2016

Note

Users should use the subclasses and not instantiate MethodRATTLE directly.

class hoomd.md.methods.rattle.NVE(filter, manifold_constraint, tolerance=1e-06)#

NVE Integration via Velocity-Verlet with RATTLE constraint.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles on which to apply this method.

  • manifold_constraint (hoomd.md.manifold.Manifold) – Manifold constraint.

  • tolerance (float) – Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

NVE performs constant volume, constant energy simulations as described in hoomd.md.methods.ConstantVolume without any thermostat. In addition the particles are constrained to a manifold by using the RATTLE algorithm.

Examples:

sphere = hoomd.md.manifold.Sphere(r=10)
nve_rattle = hoomd.md.methods.rattle.NVE(
    filter=hoomd.filter.All(),maifold=sphere)
integrator = hoomd.md.Integrator(
    dt=0.005, methods=[nve_rattle], forces=[lj])
filter#

Subset of particles on which to apply this method.

Type:

hoomd.filter.filter_like

manifold_constraint#

Manifold constraint which is used by and as a trigger for the RATTLE algorithm of this method.

Type:

hoomd.md.manifold.Manifold

tolerance#

Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Type:

float

class hoomd.md.methods.rattle.OverdampedViscous(filter, manifold_constraint, tolerance=1e-06)#

Overdamped viscous dynamics with RATTLE constraint.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles to apply this method to.

  • manifold_constraint (hoomd.md.manifold.Manifold) – Manifold constraint.

  • tolerance (float) – Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

OverdampedViscous uses the same integrator as hoomd.md.methods.OverdampedViscous, with the additional force term \(- \lambda \vec{F}_\mathrm{M}\). The force \(\vec{F}_\mathrm{M}\) keeps the particles on the manifold constraint, where the Lagrange multiplier \(\lambda\) is calculated via the RATTLE algorithm. For more details about overdamped viscous dynamics see hoomd.md.methods.OverdampedViscous.

Examples of using manifold_constraint:

sphere = hoomd.md.manifold.Sphere(r=10)
odv_rattle = hoomd.md.methods.rattle.OverdampedViscous(
    filter=hoomd.filter.All(), manifold_constraint=sphere, seed=1)
integrator = hoomd.md.Integrator(
    dt=0.001, methods=[odv_rattle], forces=[lj])
filter#

Subset of particles to apply this method to.

Type:

hoomd.filter.filter_like

manifold_constraint#

Manifold constraint which is used by and as a trigger for the RATTLE algorithm of this method.

Type:

hoomd.md.manifold.Manifold

tolerance#

Defines the tolerated error particles are allowed to deviate from the manifold in terms of the implicit function. The units of tolerance match that of the selected manifold’s implicit function. Defaults to 1e-6

Type:

float

gamma#

The drag coefficient for each particle type \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\).

Type:

TypeParameter[ particle type, float ]

gamma_r#

The rotational drag coefficient tensor for each particle type \([\mathrm{time}^{-1}]\).

Type:

TypeParameter[particle type,[float, float , float]]

md.mesh#

Overview

MeshPotential

Constructs the bond potential applied to a mesh.

Details

Mesh potentials for molecular dynamics.

class hoomd.md.mesh.MeshPotential(mesh)#

Constructs the bond potential applied to a mesh.

MeshPotential is the base class for all bond potentials applied to meshes.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

property mesh#

Mesh data structure used to compute the bond potential.

Modules

md.mesh.bond#

Overview

FENEWCA

FENE and WCA bond potential.

Harmonic

Harmonic bond potential.

Tether

Tethering bond potential.

Details

Mesh Bond forces.

Mesh bond force classes apply a force and virial between every mesh vertex particle and their neighbors based on the given mesh triangulation.

\[U_\mathrm{mesh bond} = \sum_{j \in \mathrm{mesh}} \sum_{k \in \mathrm{Neigh}(j)}U_{jk}(r)\]

The connectivity and, thus the neighbor set \(\mathrm{Neigh}\) of each vertex particle \(j\) is defined by a mesh triangulation.

See also

See the documentation in hoomd.mesh.Mesh for more information on the initialization of the mesh object.

In the mesh bond (j,k), \(r\) is the length of the edge between the mesh vertex particles \(r= |\mathrm{minimum\_image}(\vec{r}_k - \vec{r}_j)|\).

Note

The mesh bond forces are computed over the mesh data structure and not the separate bond data structure. Hence, the mesh bonds are defined exclusively by the mesh triangulation as HOOMD-blue automatically constructs the mesh bond pairs based on triangulation in the hoomd.mesh.Mesh object. The bonds should not be defined separately in the hoomd.State member bond_group!

Mesh bond force classes assign 1/2 of the potential energy to each of the particles in the bond group:

\[U_i = \frac{1}{2} \sum_{k \in \mathrm{Neigh}(i)}U_{ik}(r)\]

and similarly for virials.

class hoomd.md.mesh.bond.FENEWCA(mesh)#

Bases: MeshPotential

FENE and WCA bond potential.

FENEWCA computes forces, virials, and energies on all mesh bonds in mesh with the harmonic potential (see hoomd.md.bond.FENEWCA).

Parameters:

mesh (hoomd.mesh.Mesh) – Mesh data structure constraint.

params#

The parameter of the FENEWCA potential bonds. The mesh type name defaults to “mesh”. The dictionary has the following keys:

  • k (float, required) - attractive force strength \(k\) \([\mathrm{energy} \cdot \mathrm{length}^{-2}]\).

  • r0 (float, required) - size parameter \(r_0\) \([\mathrm{length}]\).

  • epsilon (float, required) - repulsive force strength \(\varepsilon\) \([\mathrm{energy}]\).

  • sigma (float, required) - repulsive force interaction width \(\sigma\) \([\mathrm{length}]\).

  • delta (float, required) - radial shift \(\Delta\) \([\mathrm{length}]\).

Type:

TypeParameter[bond type, dict]

Examples:

bond_potential = hoomd.md.mesh.bond.FENEWCA(mesh)
bond_potential.params["mesh"] = dict(k=10.0, r0=1.0,
                                    epsilon=0.8, sigma=1.2, delta=0.0)
class hoomd.md.mesh.bond.Harmonic(mesh)#

Bases: MeshPotential

Harmonic bond potential.

Harmonic computes forces, virials, and energies on all mesh bonds in mesh with the harmonic potential (see hoomd.md.bond.Harmonic).

Parameters:

mesh (hoomd.mesh.Mesh) – Mesh data structure constraint.

params#

The parameter of the harmonic bonds for the defined mesh. The mesh type name defaults to “mesh”. The dictionary has the following keys:

  • k (float, required) - potential constant \([\mathrm{energy} \cdot \mathrm{length}^{-2}]\)

  • r0 (float, required) - rest length \([\mathrm{length}]\)

Type:

TypeParameter[mesh name,dict]

Examples:

harmonic = hoomd.md.mesh.bond.Harmonic(mesh)
harmonic.params["mesh"] = dict(k=10.0, r0=1.0)
class hoomd.md.mesh.bond.Tether(mesh)#

Bases: MeshPotential

Tethering bond potential.

Tether computes forces, virials, and energies on all mesh bonds in mesh with the harmonic potential (see hoomd.md.bond.Tether).

Parameters:

mesh (hoomd.mesh.Mesh) – Mesh data structure constraint.

params#

The parameter of the Tether bonds for the defined mesh. The mesh type name defaults to “mesh”. The dictionary has the following keys:

  • k_b (float, required) - bond stiffness \([\mathrm{energy}]\)

  • l_min (float, required) - minimum bond length \([\mathrm{length}]\)

  • l_c1 (float, required) - cutoff distance of repulsive part \([\mathrm{length}]\)

  • l_c0 (float, required) - cutoff distance of attractive part \([\mathrm{length}]\)

  • l_max (float, required) - maximum bond length \([\mathrm{length}]\)

Type:

TypeParameter[mesh name,dict]

Examples:

bond_potential = hoomd.md.mesh.bond.Tether(mesh)
bond_potential.params["mesh"] = dict(k_b=10.0, l_min=0.9, l_c1=1.2,
                                 l_c0=1.8, l_max=2.1)

md.minimize#

Overview

FIRE

Energy Minimizer (FIRE).

Details

Energy minimizer for molecular dynamics.

class hoomd.md.minimize.FIRE(dt, force_tol, angmom_tol, energy_tol, integrate_rotational_dof=False, forces=None, constraints=None, methods=None, rigid=None, min_steps_adapt=5, finc_dt=1.1, fdec_dt=0.5, alpha_start=0.1, fdec_alpha=0.99, min_steps_conv=10)#

Energy Minimizer (FIRE).

Parameters:
  • dt (float) – This is the maximum step size the minimizer is permitted to use \([\mathrm{time}]\). Consider the stability of the system when setting.

  • integrate_rotational_dof (bool) – When True, integrate rotational degrees of freedom.

  • forces (Sequence[hoomd.md.force.Force]) – Sequence of forces applied to the particles in the system. All the forces are summed together. The default value of None initializes an empty list.

  • methods (Sequence[hoomd.md.methods.Method]) – Sequence of integration methods. Each integration method can be applied to only a specific subset of particles. The intersection of the subsets must be null. The default value of None initializes an empty list.

  • constraints (Sequence[hoomd.md.constrain.Constraint]) – Sequence of constraint forces applied to the particles in the system. The default value of None initializes an empty list. Rigid body objects (i.e. hoomd.md.constrain.Rigid) are not allowed in the list.

  • rigid (hoomd.md.constrain.Rigid) – A rigid bodies object defining the rigid bodies in the simulation.

  • min_steps_adapt (int) – Number of steps energy change is negative before allowing \(\alpha\) and \(\delta t\) to adapt.

  • finc_dt (float) – Factor to increase \(\delta t\) by \([\mathrm{dimensionless}]\).

  • fdec_dt (float) – Factor to decrease \(\delta t\) by \([\mathrm{dimensionless}]\).

  • alpha_start (float) – Initial (and maximum) \(\alpha [\mathrm{dimensionless}]\).

  • fdec_alpha (float) – Factor to decrease \(\alpha t\) by \([\mathrm{dimensionless}]\).

  • force_tol (float) – Force convergence criteria \([\mathrm{force} / \mathrm{mass}]\).

  • angmom_tol (float) – Angular momentum convergence criteria \([\mathrm{energy} * \mathrm{time}]\).

  • energy_tol (float) – Energy convergence criteria \([\mathrm{energy}]\).

  • min_steps_conv (int) – A minimum number of attempts before convergence criteria are considered.

FIRE is a hoomd.md.Integrator that uses the Fast Inertial Relaxation Engine (FIRE) algorithm to minimize the potential energy for a group of particles while keeping all other particles fixed. This method is published in Bitzek, et. al., PRL, 2006. HOOMD-blue’s implementation extends the original formulation to include rotational degrees of freedom.

At each time step, \(\delta t\), the algorithm uses the supplied integration methods to generate \(\vec{r}\), \(\vec{v}\), and \(\vec{F}\), and then adjusts \(\vec{v}\) according to

\[\vec{v} = (1-\alpha)\vec{v} + \alpha \hat{F}|\vec{v}|\]

where \(\alpha\) and \(\delta t\) are dynamically adaptive quantities. While a current search has been lowering the energy of system for more than \(N_{min}\) steps, \(\alpha\) is decreased by \(\alpha \rightarrow \alpha \cdot \mathrm{fdec}_{\alpha}\) and \(\delta t\) is increased by \(\delta t \rightarrow \max(\delta t \cdot \mathrm{finc}_{dt}, \ \delta t_{max})\). If the energy of the system increases (or stays the same), the velocity of the particles is set to 0, \(\alpha \rightarrow \ \alpha_{start}\) and \(\delta t \rightarrow \delta t \cdot \mathrm{fdec}_{\alpha}\). The method converges when the force per particle is below force_tol, the angular momentum is below angmom_tol and the change in potential energy from one step to the next is below energy_tol:

\[\frac{\sum |F|}{N*\sqrt{N_{dof}}} < \mathrm{\text{force_tol}} \;\;, \;\ \Delta \frac{\sum|E|}{N} < \mathrm{\text{energy_tol}} \;\;, and \;\ \frac{\sum|L|}{N} < \mathrm{\text{angmom_tol}}\]

where \(N_{\mathrm{dof}}\) is the number of degrees of freedom the minimization is acting over. Any of the criterion can be effectively disabled by setting the tolerance to a large number.

If the minimization acts on a subset of all the particles in the system, the other particles will be kept frozen but will still interact with the particles being moved.

Examples:

fire = md.minimize.FIRE(dt=0.05,
                        force_tol=1e-2,
                        angmom_tol=1e-2,
                        energy_tol=1e-7)
fire.methods.append(md.methods.ConstantVolume(hoomd.filter.All()))
sim.operations.integrator = fire
while not(fire.converged):
   sim.run(100)

fire = md.minimize.FIRE(dt=0.05)
fire.methods.append(md.methods.ConstantPressure(
    hoomd.filter.All(), S=1, tauS=1, couple='none'))
sim.operations.integrator = fire
while not(fire.converged):
   sim.run(100)

Note

To use FIRE, set it as the simulation’s integrator in place of the typical hoomd.md.Integrator.

Note

The algorithm requires an integration method to update the particle position and velocities. This should either be either hoomd.md.methods.ConstantVolume (to minimize energy) or hoomd.md.methods.ConstantPressure (to minimize energy and relax the box), without setting any thermostat. The quantity minimized is in any case the potential energy (not the enthalpy or any other quantity).

Note

In practice, the default parameters prevents the simulation from making too aggressive a first step, but also from quitting before having found a good search direction. Adjust the parameters as needed for your simulations.

dt#

This is the maximum step size the minimizer is permitted to use \([\mathrm{time}]\). Consider the stability of the system when setting.

Type:

float

force_tol#

Force convergence criteria \([\mathrm{force} / \mathrm{mass}]\).

Type:

float

angmom_tol#

Angular momentum convergence criteria \([\mathrm{energy} * \mathrm{time}]\).

Type:

float

energy_tol#

Energy convergence criteria \([\mathrm{energy}]\).

Type:

float

integrate_rotational_dof#

When True, integrate rotational degrees of freedom.

Type:

bool

forces#

Sequence of forces applied to the particles in the system. All the forces are summed together. The default value of None initializes an empty list.

Type:

Sequence[hoomd.md.force.Force]

methods#

Sequence of integration methods. Each integration method can be applied to only a specific subset of particles. The intersection of the subsets must be null. The default value of None initializes an empty list.

Type:

Sequence[hoomd.md.methods.Method]

constraints#

Sequence of constraint forces applied to the particles in the system. The default value of None initializes an empty list. Rigid body objects (i.e. hoomd.md.constrain.Rigid) are not allowed in the list.

Type:

Sequence[hoomd.md.constrain.Constraint]

rigid#

A rigid bodies object defining the rigid bodies in the simulation.

Type:

hoomd.md.constrain.Rigid

min_steps_adapt#

Number of steps energy change is negative before allowing \(\alpha\) and \(\delta t\) to adapt.

Type:

int

finc_dt#

Factor to increase \(\delta t\) by \([\mathrm{dimensionless}]\).

Type:

float

fdec_dt#

Factor to decrease \(\delta t\) by \([\mathrm{dimensionless}]\).

Type:

float

alpha_start#

Initial (and maximum) \(\alpha [\mathrm{dimensionless}]\).

Type:

float

fdec_alpha#

Factor to decrease \(\alpha t\) by \([\mathrm{dimensionless}]\).

Type:

float

min_steps_conv#

A minimum number of attempts before convergence criteria are considered.

Type:

int

property converged#

True when the minimizer has converged, else False.

(Loggable: category=”scalar”, default=False)

Type:

bool

property energy#

Get the energy after the last iteration of the minimizer.

(Loggable: category=”scalar”)

Type:

float

reset()#

Reset the minimizer to its initial state.

md.nlist#

Overview

NeighborList

Base class neighbor list.

Cell

Neighbor list computed via a cell list.

Stencil

Cell list based neighbor list using stencils.

Tree

Bounding volume hierarchy based neighbor list.

Details

Neighbor list acceleration structures.

Pair forces (hoomd.md.pair) use neighbor list data structures to find neighboring particle pairs (those within a distance of \(r_\mathrm{cut}\)) efficiently. HOOMD-blue provides a several types of neighbor list construction algorithms that you can select from: Cell, Tree, and Stencil.

Multiple pair force objects can share a single neighbor list, or use independent neighbor list objects. When neighbor lists are shared, they find neighbors within the the maximum \(r_{\mathrm{cut},i,j}\) over the associated pair potentials.

Buffer distance

Set the NeighborList.buffer distance to amortize the cost of the neighbor list build. When buffer > 0, a neighbor list computed on one step can be reused on subsequent steps until a particle moves a distance buffer/2. When NeighborList.check_dist is True, NeighborList starts checking how far particles have moved NeighborList.rebuild_check_delay time steps after the last build and performs a rebuild when any particle has moved a distance buffer/2. When NeighborList.check_dist is False, NeighborList always rebuilds after NeighborList.rebuild_check_delay time steps.

Note

With the default settings (check_dist=True and rebuild_check_delay=1), changing NeighborList.buffer only impacts simulation performance and not correctness.

Set the buffer too small and the neighbor list will need to be updated often, slowing simulation performance. Set the buffer too large, and hoomd.md.pair.Pair will need to needlessly calculate many non-interacting particle pairs and slow the simulation. There is an optimal value for NeighborList.buffer between the two extremes that provides the best performance.

Base distance cutoff

The NeighborList.r_cut attribute can be used to set the base cutoff distance for neighbor list queries. The actual cutoff distance is always the maximum \(r_{\mathrm{cut},i,j}\) of the base cutoff and associated pair potentials.

Note

This attribute is particularly useful for implementing custom pair forces in Python.

Attention

Users should only set this attribute when utilizing the accessor APIs, pair_list, local_pair_list, cpu_local_nlist_arrays, or gpu_local_nlist_arrays.

Exclusions

Neighbor lists nominally include all particles within the chosen cutoff distances. The NeighborList.exclusions attribute defines which particles will be excluded from the list, even if they are within the cutoff. NeighborList.exclusions is a tuple of strings that enable one more more types of exclusions. The valid exclusion types are:

  • 'angle': Exclude the first and third particles in each angle.

  • 'body': Exclude particles that belong to the same rigid body.

  • 'bond': Exclude particles that are directly bonded together.

  • 'meshbond': Exclude particles that are bonded together via a mesh.

  • 'constraint': Exclude particles that have a distance constraint applied between them.

  • 'dihedral': Exclude the first and fourth particles in each dihedral.

  • 'special_pair': Exclude particles that are part of a special pair.

  • '1-3': Exclude particles i and k whenever there is a bond (i,j) and a bond (j,k).

  • '1-4': Exclude particles i and m whenever there are bonds (i,j), (j,k), and (k,m).

class hoomd.md.nlist.NeighborList(buffer, exclusions, rebuild_check_delay, check_dist, mesh, default_r_cut)#

Base class neighbor list.

NeighborList is the base class for all neighbor lists.

Warning

Users should not instantiate this class directly. The class can be used for isinstance or issubclass checks.

buffer#

Buffer width \([\mathrm{length}]\).

Type:

float

exclusions#

Defines which particles to exclude from the neighbor list, see more details above.

Type:

tuple[str]

rebuild_check_delay#

How often to attempt to rebuild the neighbor list.

Type:

int

check_dist#

Flag to enable / disable distance checking.

Type:

bool

mesh#

mesh data structure (optional)

Type:

Mesh

default_r_cut#

Default cutoff distance \([\mathrm{length}]\) (optional).

Type:

float

r_cut#

Base cutoff radius for neighbor list queries. \([\mathrm{length}]\). Optional: defaults to the value default_r_cut specified on construction.

Type: TypeParameter [tuple [particle_type, particle_type], float])

property cpu_local_nlist_arrays#

Expose nlist arrays on the CPU.

Provides direct acces to the neighbor list arrays on the cpu. All data is MPI rank-local.

The hoomd.md.data.NeighborListLocalAccess object exposes the internal data representation to efficently iterate over the neighbor list.

Note

The local arrays are read only.

Examples:

with self.cpu_local_nlist_arrays as arrays:
    nlist_iter = zip(arrays.head_list, arrays.n_neigh)
    for i, (head, nn) in enumerate(nlist_iter):
        for j_idx in range(head, head + nn):
            j = arrays.nlist[j_idx]
            # i and j are "neighbor" indices
Type:

hoomd.md.data.NeighborListLocalAccess

property gpu_local_nlist_arrays#

Expose nlist arrays on the GPU.

Provides direct access to the neighbor list arrays on the gpu. All data is MPI rank-local.

The hoomd.md.data.NeighborListLocalAccessGPU object exposes the internal data representation to efficently iterate over the neighbor list.

Note

The local arrays are read only.

Examples:

get_local_pairs = cupy.RawKernel(r'''
extern "C" __global__
void get_local_pairs(
        const unsigned int N,
        const unsigned long* heads,
        const unsigned int* nns,
        const unsigned int* nlist,
        const unsigned int* tags,
        const unsigned long* offsets,
        unsigned long* pairs) {
    unsigned int i = (unsigned int)
        (blockDim.x * blockIdx.x + threadIdx.x);
    if (i >= N)
        return;
    uint2* pair = (uint2*)pairs;
    unsigned long head = heads[i];
    unsigned int nn = nns[i];
    unsigned long offset = offsets[i];
    unsigned int tag_i = tags[i];
    for (unsigned int idx = 0; idx < nn; idx++) {
        unsigned int j = nlist[head + idx];
        pair[offset + idx] = make_uint2(tag_i, tags[j]);
    }
}
''', 'get_local_pairs')

with nlist.gpu_local_nlist_arrays as data:
    with sim.state.gpu_local_snapshot as snap_data:
        tags = snap_data.particles.tag_with_ghost
        tags = tags._coerce_to_ndarray()

        head_list = data.head_list._coerce_to_ndarray()
        n_neigh = data.n_neigh._coerce_to_ndarray()
        raw_nlist = data.nlist._coerce_to_ndarray()

        N = int(head_list.size)
        n_pairs = int(cupy.sum(n_neigh))
        offsets = cupy.cumsum(n_neigh.astype(cupy.uint64)
        offsets -= n_neigh[0]
        device_local_pairs = cupy.zeros(
            (n_pairs, 2),
            dtype=cupy.uint32)

        block = 256
        n_grid = (N + 255) // 256
        get_local_pairs(
            (n_grid,),
            (block,),
            (
                N,
                head_list,
                n_neigh,
                raw_nlist,
                tags,
                offsets,
                device_local_pairs
            ))

Note

GPU local nlist data is not available if the chosen device for the simulation is hoomd.device.CPU.

Type:

hoomd.md.data.NeighborListLocalAccessGPU

property local_pair_list#

Local pair list.

Note

The local pair list returns rank-local indices, not particle tags.

Type:

(N_pairs, 2) numpy.ndarray of numpy.uint32

property num_builds#

The number of neighbor list builds.

num_builds is the number of neighbor list rebuilds performed since the last call to Simulation.run.

(Loggable: category=”scalar”, default=False)

Type:

int

property pair_list#

Global pair list.

Note

The pair list returns particle tags, not rank-local indices.

Attention

In MPI parallel execution, the array is available on rank 0 only. pair_list is None on ranks >= 1.

Type:

(N_pairs, 2) numpy.ndarray of numpy.uint32

property shortest_rebuild#

The shortest period between neighbor list rebuilds.

shortest_rebuild is the smallest number of time steps between neighbor list rebuilds since the last call to Simulation.run.

(Loggable: category=”scalar”)

Type:

int

class hoomd.md.nlist.Cell(buffer, exclusions=('bond',), rebuild_check_delay=1, check_dist=True, deterministic=False, mesh=None, default_r_cut=0.0)#

Bases: NeighborList

Neighbor list computed via a cell list.

Parameters:
  • buffer (float) – Buffer width \([\mathrm{length}]\).

  • exclusions (tuple[str]) – Defines which particles to exclude from the neighbor list, see more details in NeighborList.

  • rebuild_check_delay (int) – How often to attempt to rebuild the neighbor list.

  • check_dist (bool) – Flag to enable / disable distance checking.

  • deterministic (bool) – When True, sort neighbors to help provide deterministic simulation runs.

  • mesh (Mesh) – When a mesh object is passed, the neighbor list uses the mesh to determine the bond exclusions in addition to all other set exclusions.

  • default_r_cut

Cell finds neighboring particles using a fixed width cell list, allowing for O(kN) construction of the neighbor list where k is the number of particles per cell. Cells are sized to the largest \(r_\mathrm{cut}\). This method is very efficient for systems with nearly monodisperse cutoffs, but performance degrades for large cutoff radius asymmetries due to the significantly increased number of particles per cell. In practice, Cell is usually the best option for most users when the asymmetry between the largest and smallest cutoff radius is less than 2:1.

Cell list schematic

Note

Cell may consume a significant amount of memory, especially on GPU devices. One cause of this can be non-uniform density distributions because the memory allocated for the cell list is proportional the maximum number of particles in any cell. Another common cause is large box volumes combined with small cutoffs, which results in a very large number of cells in the system. In these cases, consider using Stencil or Tree, which can use less memory.

Examples:

cell = nlist.Cell()
deterministic#

When True, sort neighbors to help provide deterministic simulation runs.

Type:

bool

property allocated_particles_per_cell#

Number of particle slots allocated per cell.

The total memory usage of Cell is proportional to the product of the three cell list dimensions and the allocated_particles_per_cell.

(Loggable: category=”scalar”, default=False)

Type:

int

property dimensions#

Cell list dimensions.

dimensions is the number of cells in the x, y, and z directions.

(Loggable: category=”sequence”, default=False)

Type:

tuple[int, int, int]

class hoomd.md.nlist.Stencil(cell_width, buffer, exclusions=('bond',), rebuild_check_delay=1, check_dist=True, deterministic=False, mesh=None, default_r_cut=0.0)#

Bases: NeighborList

Cell list based neighbor list using stencils.

Parameters:
  • cell_width (float) – The underlying stencil bin width for the cell list \([\mathrm{length}]\).

  • buffer (float) – Buffer width \([\mathrm{length}]\).

  • exclusions (tuple[str]) – Defines which particles to exclude from the neighbor list, see more details in NeighborList.

  • rebuild_check_delay (int) – How often to attempt to rebuild the neighbor list.

  • check_dist (bool) – Flag to enable / disable distance checking.

  • deterministic (bool) – When True, sort neighbors to help provide deterministic simulation runs.

  • mesh (Mesh) – When a mesh object is passed, the neighbor list uses the mesh to determine the bond exclusions in addition to all other set exclusions.

Stencil finds neighboring particles using a fixed width cell list, for O(kN) construction of the neighbor list where k is the number of particles per cell. In contrast with Cell, Stencil allows the user to choose the cell width: cell_width instead of fixing it to the largest cutoff radius (P.J. in’t Veld et al. 2008):

Stenciled cell list schematic

This neighbor list style differs from Cell in how the adjacent cells are searched for particles. One stencil is computed per particle type based on the value of cell_width set by the user, which defines the bins that the particle must search in. Distances to the bins in the stencil are precomputed so that certain particles can be quickly excluded from the neighbor list, leading to improved performance compared to Cell when there is size disparity in the cutoff radius. The memory demands of Stencil can also be lower than Cell if your system is large and has many small cells in it; however, Tree is usually a better choice for these systems.

The performance of Stencil depends strongly on the choice of cell_width. The best performance is obtained when the cutoff radii are multiples of the cell_width, and when the cell_width covers the simulation box with a roughly integer number of cells.

Examples:

nl_s = nlist.Stencil(cell_width=1.5)

Important

M.P. Howard et al. 2016 describes this neighbor list implementation. Cite it if you utilize Stencil in your research.

cell_width#

The underlying stencil bin width for the cell list \([\mathrm{length}]\).

Type:

float

deterministic#

When True, sort neighbors to help provide deterministic simulation runs.

Type:

bool

class hoomd.md.nlist.Tree(buffer, exclusions=('bond',), rebuild_check_delay=1, check_dist=True, mesh=None, default_r_cut=0.0)#

Bases: NeighborList

Bounding volume hierarchy based neighbor list.

Parameters:
  • buffer (float) – Buffer width \([\mathrm{length}]\).

  • exclusions (tuple[str]) – Defines which particles to exclude from the neighbor list, see more details in NeighborList.

  • rebuild_check_delay (int) – How often to attempt to rebuild the neighbor list.

  • check_dist (bool) – Flag to enable / disable distance checking.

  • mesh (Mesh) – When a mesh object is passed, the neighbor list uses the mesh to determine the bond exclusions in addition to all other set exclusions.

Tree creates a neighbor list using a bounding volume hierarchy (BVH) tree traversal in \(O(N \log N)\) time. A BVH tree of axis-aligned bounding boxes is constructed per particle type, and each particle queries each tree to determine its neighbors. This method of searching leads to significantly improved performance compared to cell lists in systems with moderate size asymmetry, but has slower performance for monodisperse systems. Tree can also be slower than Cell if there are multiple types in the system, but the cutoffs between types are identical. (This is because one BVH is created per type.) The user should carefully benchmark neighbor list build times to select the appropriate neighbor list construction type.

BVH tree schematic

Tree’s memory requirements scale with the number of particles in the system rather than the box volume, which may be particularly advantageous for large, sparse systems.

Important

M.P. Howard et al. 2016 describes the original implementation of this algorithm for HOOMD-blue. M.P. Howard et al. 2019 describes the improved algorithm that is currently implemented. Cite both if you utilize this neighbor list style in your work.

Examples:

nl_t = nlist.Tree(check_dist=False)

md.pair#

Overview

Buckingham

Buckingham pair force.

DLVO

DLVO colloidal interaction.

DPD

Dissipative Particle Dynamics.

DPDLJ

Dissipative Particle Dynamics with the LJ conservative force.

DPDConservative

DPD Conservative pair force.

Ewald

Ewald pair force.

ExpandedGaussian

Expanded Gaussian pair force.

ExpandedLJ

Expanded Lennard-Jones pair force.

ExpandedMie

Expanded Mie pair force.

ForceShiftedLJ

Force-shifted Lennard-Jones pair force.

Fourier

Fourier pair force.

Gaussian

Gaussian pair force.

LJ

Lennard-Jones pair force.

LJ1208

Lennard-Jones 12-8 pair force.

LJ0804

Lennard-Jones 8-4 pair force.

LJGauss

Lennard-Jones-Gauss pair potential.

Mie

Mie pair force.

Morse

Morse pair force.

Moliere

Moliere pair force.

OPP

Oscillating pair force.

Pair

Base class pair force.

ReactionField

Onsager reaction field pair force.

Table

Tabulated pair force.

TWF

Pair potential model for globular proteins.

Yukawa

Yukawa pair force.

ZBL

ZBL pair force.

Details

Pair Potentials for molecular dynamics.

Pair force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{pair,total} = \frac{1}{2} \sum_{i=0}^\mathrm{N_particles-1} \sum_{j \ne i, (i,j) \notin \mathrm{exclusions}} U_\mathrm{pair}(r_{ij})\]

where \(\vec{r}_{ij} = \mathrm{minimum\_image}(\vec{r}_j - \vec{r}_i)\). Pair applies a short range cutoff using a hoomd.md.nlist.NeighborList for performance and assumes that both \(U(r)\) and its derivatives are 0 when \(r_{ij} \ge r_\mathrm{cut}\). Pair also ignores particle pairs that are excluded in the neighbor list.

Specifically, the force \(\vec{F}\) on each pair of particles \(i,j\) is:

\[\begin{split}\vec{F} = \begin{cases} -\nabla U_\mathrm{pair}(r) & r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases}\end{split}\]

where the cutoff radius \(r_{\mathrm{cut}}\) is given by Pair.r_cut.

Tip

Set Pair.r_cut to 0 to skip computations for non-interacting pairs.

Pair splits half the energy from each pair interaction onto particles \(i\) and \(j\):

\[U_i = \frac{1}{2} \sum_{j \ne i, (i,j) \notin \mathrm{exclusions}} U_\mathrm{pair}(r_{ij}) [r_{ij} < r_\mathrm{cut}]\]

and similarly for virials.

Shifting/smoothing mode

The function \(U_\mathrm{pair}(r)\) depends on the chosen form of the pair potential \(U(r)\) (by the Pair subclass) and the mode (Pair.mode):

\[\begin{split}U_\mathrm{pair}(r) = \begin{cases} U_(r) & \mathrm{mode\ is\ \mathrm{none}} \\ U(r) - U(r_{\mathrm{cut}}) & \mathrm{mode\ is\ shift} \\ S(r) \cdot U_(r) & \mathrm{mode\ is\ xplor} \land r_{\mathrm{on}} < r_{\mathrm{cut}} \\ U(r) - U(r_{\mathrm{cut}}) & \mathrm{mode\ is\ xplor} \land r_{\mathrm{on}} \ge r_{\mathrm{cut}} \end{cases}\end{split}\]

where \(S(r)\) is the XPLOR smoothing function:

\[\begin{split}S(r) = \begin{cases} 1 & r < r_{\mathrm{on}} \\ \frac{(r_{\mathrm{cut}}^2 - r^2)^2 \cdot (r_{\mathrm{cut}}^2 + 2r^2 - 3r_{\mathrm{on}}^2)}{(r_{\mathrm{cut}}^2 - r_{\mathrm{on}}^2)^3} & r_{\mathrm{on}} \le r \le r_{\mathrm{cut}} \\ 0 & r > r_{\mathrm{cut}} \\ \end{cases}\end{split}\]

where \(r_{\mathrm{on}}\) is given by Pair.r_on.

The XPLOR smoothing function \(S(r)\) ensures that both the potential energy and the force going smoothly to 0 at \(r = r_{\mathrm{cut}}\), reducing the rate of energy drift in long simulations. \(r_{\mathrm{on}}\) controls the point at which the smoothing starts. Set it to modify only the tail of the potential. The WCA potential and it’s first derivative already go smoothly to 0 at the cutoff, so there is no need to apply the smoothing function. In such mixed systems, set \(r_{\mathrm{on}}\) to a value greater than \(r_{\mathrm{cut}}\) for those pairs that interact via WCA in order to enable shifting of the WCA potential to 0 at the cutoff.

Tail correction

Some pair potentials can optionally apply isotropic integrated long range tail corrections when the tail_correction parameter is True. These corrections are only valid when the shifting/smoothing mode is set to "none". Following Sun 1998, the pressure and energy corrections \(\Delta P\) and \(\Delta E\) are given by:

\[\Delta P = \frac{-2\pi}{3} \sum_{i=1}^{n} \rho_i \sum_{j=1}^{n} \rho_j \int_{r_\mathrm{cut}}^{\infty} \left( r \frac{\mathrm{d}U_{ij}(r)}{\mathrm{d}r} \right) r^2 \mathrm{d}r\]

and

\[\Delta E = 2\pi \sum_{i=1}^{n} N_i \sum_{j=1}^{n} \rho_j \int_{r_\mathrm{cut}}^{\infty} U_{ij}(r) r^2 \mathrm{d}r,\]

where \(n\) is the number of unique particle types in the system, \(\rho_i\) is the number density of particles of type \(i\) in the system, \(U_{ij}(r)\) is the pair potential between particles of type \(i\) and \(j\), and \(N_i\) is the number of particles of type \(i\) in the system. These expressions assume that the radial pair distribution functions \(g_{ij}(r)\) are unity at the cutoff and beyond.

The pressure shift \(\Delta P\) appears in the additional virial term \(W_\mathrm{additional}\) (Force.additional_virial) and the energy shift appears in the additional energy \(U_\mathrm{additional}\) (Force.additional_energy).

Warning

The value of the tail corrections depends on the number of each type of particle in the system, and these are precomputed when the pair potential object is initialized. If the number of any of the types of particles changes, the tail corrections will yield invalid results.

Anisotropic potentials

For anisotropic potentials see hoomd.md.pair.aniso

class hoomd.md.pair.Buckingham(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Buckingham pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Buckingham computes the Buckingham pair force on every particle in the simulation state with:

\[U(r) = A \exp\left(-\frac{r}{\rho}\right) - \frac{C}{r^6}\]

Example:

nl = nlist.Cell()
buck = pair.Buckingham(nl, default_r_cut=3.0)
buck.params[('A', 'A')] = {'A': 2.0, 'rho'=0.5, 'C': 1.0}
buck.params[('A', 'B')] = dict(A=1.0, rho=1.0, C=1.0)
buck.params[('B', 'B')] = dict(A=2.0, rho=2.0, C=2.0)
params#

The potential parameters. The dictionary has the following keys:

  • A (float, required) - \(A\) \([\mathrm{energy}]\)

  • rho (float, required) - \(\rho\) \([\mathrm{length}]\)

  • C (float, required) - \(C\) \([\mathrm{energy}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.DLVO(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

DLVO colloidal interaction.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • name (str) – Name of the force instance.

  • mode (str) – Energy shifting mode.

DLVO computes the DLVO dispersion and electrostatic interaction pair force on every particle in the simulation state with:

\[\begin{split}V_{\mathrm{DLVO}}(r) = &- \frac{A}{6} \left[ \frac{2a_1a_2}{r^2 - (a_1+a_2)^2} + \frac{2a_1a_2}{r^2 - (a_1-a_2)^2} \\ + \log \left( \frac{r^2 - (a_1+a_2)^2}{r^2 - (a_1-a_2)^2} \right) \right] \\ & + \frac{a_1 a_2}{a_1+a_2} Z e^{-\kappa(r - (a_1+a_2))}\end{split}\]

where \(a_1\) is the radius of first particle in the pair, \(a_2\) is the radius of second particle in the pair, \(A\) is the Hamaker constant, \(Z\) is proportional to the surface electric potential, and \(\kappa\) is the screening parameter.

The first term corresponds to the attractive van der Waals interaction with and the second term to the repulsive double-layer interaction between two spherical surfaces. See “Intermolecular and Surface Forces” Israelachvili 2011, pp. 317.

Example:

nl = hoomd.md.nlist.Cell()
dlvo = hoomd.md.pair.DLVO(nlist=nl)
dlvo.params[('A', 'A')] = dict(A=1.0, kappa=1.0, Z=2, a1=1, a2=1)
dlvo.params[('A', 'B')] = dict(A=2.0, kappa=0.5, Z=3, a1=1, a2=3)
dlvo.params[('B', 'B')] = dict(A=2.0, kappa=0.5, Z=3, a1=3, a2=3)
params#

The potential parameters. The dictionary has the following keys:

  • A (float, required) - Hamaker constant \(A\) \([\mathrm{energy}]\)

  • a1 (float, required) - Radius of first particle \(a_1\) \([\mathrm{length}]\)

  • a2 (float, required) - Radius of second particle \(a_2\) \([\mathrm{length}]\)

  • kappa (float, required) - screening parameter \(\kappa\) \([\mathrm{length}^{-1}]\)

  • Z surface electric potential (float, required) - \(Z\) \([\mathrm{energy} \cdot \mathrm{length}^{-1}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none" or "shift".

Type: str

class hoomd.md.pair.DPD(nlist, kT, default_r_cut=None)#

Bases: Pair

Dissipative Particle Dynamics.

Parameters:

DPD computes the DPD pair force on every particle in the simulation state. DPD includes a an interaction potential, pairwise drag force, and pairwise random force. See Groot and Warren 1997:

\[F = F_{\mathrm{C}}(r) + F_{\mathrm{R,ij}}(r_{ij}) + F_{\mathrm{D,ij}}(v_{ij})\]

where

\[\begin{split}F_{\mathrm{C}}(r) &= A \cdot w(r_{ij}), \\ F_{\mathrm{R, ij}}(r_{ij}) &= - \theta_{ij}\sqrt{3} \sqrt{\frac{2k_b\gamma T}{\Delta t}}\cdot w(r_{ij}), \\ F_{\mathrm{D, ij}}(r_{ij}) &= - \gamma w^2(r_{ij})\left( \hat r_{ij} \circ v_{ij} \right), \\ w(r_{ij}) &= \begin{cases} \left( 1 - r/r_{\mathrm{cut}} \right) & r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases},\end{split}\]

\(\hat r_{ij}\) is a normalized vector from particle i to particle j, \(v_{ij} = v_i - v_j\), and \(\theta_{ij}\) is a uniformly distributed random number in the range \([-1, 1]\).

C. L. Phillips et. al. 2011 describes the DPD implementation details. Cite it if you utilize the DPD functionality in your work.

DPD does not implement any energy shift / smoothing modes due to the function of the force.

To use the DPD thermostat, apply the hoomd.md.methods.ConstantVolume or hoomd.md.methods.ConstantPressure integration method without thermostats along with DPD forces. Use of the DPD thermostat pair force with other integrators will result in nonphysical behavior. To use DPD with a different conservative potential than \(F_C\), set A to zero and define the conservative pair force separately.

Example:

nl = nlist.Cell()
dpd = pair.DPD(nlist=nl, kT=1.0, default_r_cut=1.0)
dpd.params[('A', 'A')] = dict(A=25.0, gamma=4.5)
dpd.params[('A', 'B')] = dict(A=40.0, gamma=4.5)
dpd.params[('B', 'B')] = dict(A=25.0, gamma=4.5)
dpd.params[(['A', 'B'], ['C', 'D'])] = dict(A=40.0, gamma=4.5)
params#

The force parameters. The dictionary has the following keys:

  • A (float, required) - \(A\) \([\mathrm{force}]\)

  • gamma (float, required) - \(\gamma\) \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none".

Type: str

class hoomd.md.pair.DPDConservative(nlist, default_r_cut=None)#

Bases: Pair

DPD Conservative pair force.

Parameters:

DPDConservative computes the conservative part of the DPD pair force on every particle in the simulation state with:

\[U(r) = A \cdot \left( r_{\mathrm{cut}} - r \right) - \frac{1}{2} \cdot \frac{A}{r_{\mathrm{cut}}} \cdot \left(r_{\mathrm{cut}}^2 - r^2 \right).\]

DPDConservative does not implement any energy shift / smoothing modes due to the function of the force.

Example:

nl = nlist.Cell()
dpdc = pair.DPDConservative(nlist=nl, default_r_cut=3.0)
dpdc.params[('A', 'A')] = dict(A=1.0)
dpdc.params[('A', 'B')] = dict(A=2.0, r_cut = 1.0)
dpdc.params[(['A', 'B'], ['C', 'D'])] = dict(A=3.0)
params#

The potential parameters. The dictionary has the following keys:

  • A (float, required) - \(A\) \([\mathrm{force}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none".

Type: str

class hoomd.md.pair.DPDLJ(nlist, kT, default_r_cut=None, mode='none')#

Bases: Pair

Dissipative Particle Dynamics with the LJ conservative force.

Parameters:

DPDLJ computes the DPD thermostat combined with the LJ pair force on every particle in the simulation state with:

\[\begin{split}F &= F_{\mathrm{C}}(r) + F_{\mathrm{R,ij}}(r_{ij}) + F_{\mathrm{D,ij}}(v_{ij}), \\ F_{\mathrm{C}}(r) &= \partial U / \partial r, \\ F_{\mathrm{R, ij}}(r_{ij}) &= - \theta_{ij}\sqrt{3} \sqrt{\frac{2k_b\gamma T}{\Delta t}}\cdot w(r_{ij}), \\ F_{\mathrm{D, ij}}(r_{ij}) &= - \gamma w^2(r_{ij}) \left( \hat r_{ij} \circ v_{ij} \right), \\ U(r) &= 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{6} \right], \\ w(r_{ij}) &= \begin{cases} \left( 1 - r/r_{\mathrm{cut}} \right) & r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases},\end{split}\]

\(\hat r_{ij}\) is a normalized vector from particle i to particle j, \(v_{ij} = v_i - v_j\), and \(\theta_{ij}\) is a uniformly distributed random number in the range [-1, 1].

C. L. Phillips et. al. 2011 describes the DPD implementation details. Cite it if you utilize the DPD functionality in your work.

To use the DPD thermostat, apply the hoomd.md.methods.ConstantVolume or hoomd.md.methods.ConstantPressure integration method without thermostat along with DPD forces. Use of the DPD thermostat pair force with other integrators will result in nonphysical behavior.

Example:

nl = nlist.Cell()
dpdlj = pair.DPDLJ(nlist=nl, kT=1.0, default_r_cut=2.5)
dpdlj.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0, gamma=4.5)
dpdlj.params[(['A', 'B'], ['C', 'D'])] = dict(
    epsilon=3.0, sigma=1.0, gamma=1.2)
dpdlj.r_cut[('B', 'B')] = 2.0**(1.0/6.0)
params#

The DPDLJ potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - \(\sigma\) \([\mathrm{length}]\)

  • gamma (float, required) - \(\gamma\) \([\mathrm{mass} \cdot \mathrm{time}^{-1}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none" or "shift".

Type: str

class hoomd.md.pair.Ewald(nlist, default_r_cut=None)#

Bases: Pair

Ewald pair force.

Parameters:

Ewald computes the Ewald pair force on every particle in the simulation state:

\[U(r) = q_i q_j \left[\mathrm{erfc}\left(\kappa r + \frac{\alpha}{2\kappa}\right) \exp(\alpha r) + \mathrm{erfc}\left(\kappa r - \frac{\alpha}{2 \kappa}\right) \exp(-\alpha r)\right]\]

Call md.long_range.pppm.make_pppm_coulomb_forces to create an instance of Ewald and md.long_range.pppm.Coulomb that together implement the PPPM method for electrostatics.

Example:

nl = nlist.Cell()
ewald = pair.Ewald(default_r_cut=3.0, nlist=nl)
ewald.params[('A', 'A')] = dict(kappa=1.0, alpha=1.5)
ewald.r_cut[('A', 'B')] = 3.0
params#

The Ewald potential parameters. The dictionary has the following keys:

  • kappa (float, required) - Splitting parameter \(\kappa\) \([\mathrm{length}^{-1}]\)

  • alpha (float, required) - Debye screening length \(\alpha\) \([\mathrm{length}^{-1}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none".

Type: str

class hoomd.md.pair.ExpandedGaussian(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Expanded Gaussian pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

ExpandedGaussian computes the radially-shifted Gaussian pair force should on every particle in the simulation state:

\[U(r) = \varepsilon \exp \left( -\frac{1}{2} \left( \frac{r-\Delta}{\sigma} \right)^2 \right)\]

Example:

nl = nlist.Cell()
expanded_gauss = pair.ExpandedGaussian(default_r_cut=3.0, nlist=nl)
expanded_gauss.params[('A', 'A')] = dict(epsilon=1.0,
sigma=1.0, delta=0.5)
expanded_gauss.r_cut[('A', 'B')] = 3.0
params#

The expanded Gaussian potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • delta (float, required) - shift distance \(\delta\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.ExpandedLJ(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Expanded Lennard-Jones pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting mode.

ExpandedLJ computes the radially-shifted Lennard-Jones pair force on every particle in the simulation state:

\[U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r - \Delta} \right)^{12} - \left( \frac{\sigma}{r - \Delta} \right)^{6} \right]\]

Example:

nl = nlist.Cell()
expanded_lj = pair.ExpandedLJ(default_r_cut=3.0, nlist=nl)
expanded_lj.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0, delta=1.0)
expanded_lj.params[('A', 'B')] = dict(
                                     epsilon=2.0,
                                     sigma=1.0,
                                     delta=0.75)
expanded_lj.params[('B', 'B')] = dict(epsilon=1.0, sigma=1.0, delta=0.5)
params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • delta (float, required) - radial shift \(\Delta\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.ExpandedMie(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Expanded Mie pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

ExpandedMie computes the radially shifted Mie pair force on every particle in the simulation state:

\[U(r) = \left( \frac{n}{n-m} \right) {\left( \frac{n}{m} \right)}^{\frac{m}{n-m}} \varepsilon \left[ \left( \frac{\sigma}{r-\Delta} \right)^{n} - \left( \frac {\sigma}{r-\Delta} \right)^{m} \right]\]

Example:

nl = nlist.Cell()
expanded_mie = pair.ExpandedMie(nlist=nl, default_r_cut=3.0)
mie.params[('A', 'B')] = {
    "epsilon": 1.0, "sigma": 1.0, "n": 12, "m": 6,
    "delta": 0.5}
expanded_mie.r_cut[('A', 'B')] = 2**(1.0 / 6.0)
expanded_mie.params[(['A', 'B'], ['C', 'D'])] = {
    "epsilon": 1.5, "sigma": 2.0, "n": 12, "m": 6,
    "delta": 0.5}
params#

The Expanded Mie potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\epsilon\) \([\mathrm{energy}]\).

  • sigma (float, required) - \(\sigma\) \([\mathrm{length}]\).

  • n (float, required) - \(n\) \([\mathrm{dimensionless}]\).

  • m (float, required) - \(m\) \([\mathrm{dimensionless}]\).

  • delta (float, required) - \(\Delta\) \([\mathrm{length}]\).

Type: TypeParameter [ tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.ForceShiftedLJ(nlist, default_r_cut=None)#

Bases: Pair

Force-shifted Lennard-Jones pair force.

Parameters:

ForceShiftedLJ computes the modified Lennard-Jones pair force on every particle in the simulation state.

\[U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{6} \right] + \Delta V(r)\]
\[\Delta V(r) = -(r - r_{\mathrm{cut}}) \frac{\partial V_{\mathrm{LJ}}}{\partial r}(r_{\mathrm{cut}})\]

The force differs from the one calculated by LJ by the subtraction of the value of the force at \(r_{\mathrm{cut}}\), such that the force smoothly goes to zero at the cut-off. The potential is modified by a linear function. See Toxvaerd et. al. 2011 for a discussion of this potential.

Example:

nl = nlist.Cell()
fslj = pair.ForceShiftedLJ(nlist=nl, default_r_cut=1.5)
fslj.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0)
params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - \(\sigma\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none".

Type: str

class hoomd.md.pair.Fourier(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Fourier pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Fourier computes the Fourier pair force on every particle in the simulation state:

\[U(r) = \frac{1}{r^{12}} + \frac{1}{r^2}\sum_{n=1}^4 \left[ a_n cos \left( \frac{n \pi r}{r_{cut}} \right) + b_n sin \left( \frac{n \pi r}{r_{cut}} \right) \right]\]

where

\[\begin{split}a_1 &= \sum_{n=2}^4 (-1)^n a_n \\ b_1 &= \sum_{n=2}^4 n (-1)^n b_n \\\end{split}\]

enforce \(U(r_\mathrm{cut}) = 0\).

Example:

nl = nlist.Cell()
fourier = pair.Fourier(default_r_cut=3.0, nlist=nl)
fourier.params[('A', 'A')] = dict(a=[a2,a3,a4], b=[b2,b3,b4])
params#

The Fourier potential parameters. The dictionary has the following keys:

  • a (float, required) - array of 3 values corresponding to a2, a3 and a4 in the Fourier series \([\mathrm{dimensionless}]\)

  • b (float, required) - array of 3 values corresponding to b2, b3 and b4 in the Fourier series \([\mathrm{dimensionless}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none" or "xplor".

Type: str

class hoomd.md.pair.Gaussian(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Gaussian pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Gaussian computes the Gaussian pair force should on every particle in the simulation state:

\[U(r) = \varepsilon \exp \left( -\frac{1}{2} \left( \frac{r}{\sigma} \right)^2 \right)\]

Example:

nl = nlist.Cell()
gauss = pair.Gaussian(default_r_cut=3.0, nlist=nl)
gauss.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0)
gauss.r_cut[('A', 'B')] = 3.0
params#

The Gauss potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.LJ(nlist, default_r_cut=None, default_r_on=0.0, mode='none', tail_correction=False)#

Bases: Pair

Lennard-Jones pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

  • tail_correction (bool) – Whether to apply the isotropic integrated long range tail correction.

LJ computes the Lennard-Jones pair force on every particle in the simulation state.

\[U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{6} \right]\]

Example:

nl = nlist.Cell()
lj = pair.LJ(nl, default_r_cut=3.0)
lj.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0}
lj.r_cut[('A', 'B')] = 3.0
params#

The LJ potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

tail_correction#

Whether to apply the isotropic integrated long range tail correction.

Type: bool

class hoomd.md.pair.LJ0804(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Lennard-Jones 8-4 pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

LJ0804 computes the Lennard-Jones 8-4 pair force on every particle in the simulation state:

\[U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{8} - \left( \frac{\sigma}{r} \right)^{4} \right]\]

Example:

nl = nlist.Cell()
lj0804 = pair.LJ0804(nl, default_r_cut=3.0)
lj0804.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0}
lj0804.params[('A', 'B')] = dict(epsilon=2.0, sigma=1.0)
lj0804.r_cut[('A', 'B')] = 3.0
params#

The LJ potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.LJ1208(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Lennard-Jones 12-8 pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

LJ1208 computes the Lennard-Jones 12-8 pair force on every particle in the simulation state.

Example:

nl = nlist.Cell()
lj1208 = pair.LJ1208(nl, default_r_cut=3.0)
lj1208.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0}
lj1208.params[('A', 'B')] = dict(epsilon=2.0, sigma=1.0)
\[U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{8} \right]\]
params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.LJGauss(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Lennard-Jones-Gauss pair potential.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

LJGauss computes the Lennard-Jones Gauss force on all particles in the simulation state:

\[U(r) = 1\ [\mathrm{energy}] \cdot \left[ \left ( \frac{1\ [\mathrm{length}]}{r} \right)^{12} - 2\ \left(\frac{1 [\mathrm{length}]}{r} \right)^{6} \right] - \epsilon \exp \left[- \frac{\left(r - r_{0}\right)^{2}}{2 \sigma^{2}} \right]\]
params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - Gaussian width \(\sigma\) \([\mathrm{length}]\)

  • r0 (float, required) - Gaussian center \(r_0\) \([\mathrm{length}]\)

Example:

nl = hoomd.md.nlist.Cell()
ljg = pair.LJGauss(nl)
ljg.params[('A', 'A')] = dict(epsilon=1.0, sigma=0.02, r0=1.6)
ljg.params[('A', 'B')] = {'epsilon' : 2.0, 'sigma' : 0.02, 'r0' : 1.6}
ljg.params[('A', 'B')] = {'epsilon' : 2.0, 'sigma' : 0.02, 'r0' : 1.6}

New in version 3.1.0.

class hoomd.md.pair.Mie(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Mie pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Mie computes the Mie pair force on every particle in the simulation state.

\[U(r) = \left( \frac{n}{n-m} \right) {\left( \frac{n}{m} \right)}^{\frac{m}{n-m}} \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{n} - \left( \frac{\sigma}{r} \right)^{m} \right]\]

Example:

nl = nlist.Cell()
mie = pair.Mie(nlist=nl, default_r_cut=3.0)
mie.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0, n=12, m=6)
mie.r_cut[('A', 'A')] = 2**(1.0/6.0)
mie.r_on[('A', 'A')] = 2.0
mie.params[(['A', 'B'], ['C', 'D'])] = dict(epsilon=1.5, sigma=2.0)
params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - \(\sigma\) \([\mathrm{length}]\)

  • n (float, required) - \(n\) \([\mathrm{dimensionless}]\)

  • m (float, required) - \(m\) \([\mathrm{dimensionless}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.Moliere(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Moliere pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Moliere computes the Moliere pair force on every particle in the simulation state:

\[\begin{split}U(r) = \frac{Z_i Z_j e^2}{4 \pi \epsilon_0 r_{ij}} \left[ 0.35 \exp \left( -0.3 \frac{r_{ij}}{a_F} \right) + \\ 0.55 \exp \left( -1.2 \frac{r_{ij}}{a_F} \right) + 0.10 \exp \left( -6.0 \frac{r_{ij}}{a_F} \right) \right]\end{split}\]

Where each parameter is defined as:

  • \(Z_i\) - Z_i - Atomic number of species i \([\mathrm{dimensionless}]\)

  • \(Z_j\) - Z_j - Atomic number of species j \([\mathrm{dimensionless}]\)

  • \(e\) - elementary_charge - The elementary charge \([\mathrm{charge}]\)

  • \(a_F = \frac{0.8853 a_0}{\left( \sqrt{Z_i} + \sqrt{Z_j} \right)^{2/3}}\), where \(a_0\) is the Bohr radius \([\mathrm{length}]\)

Example:

nl = nlist.Cell()
moliere = pair.Moliere(default_r_cut = 3.0, nlist=nl)

Zi = 54
Zj = 7
e = 1
a0 = 1
aF = 0.8853 * a0 / (np.sqrt(Zi) + np.sqrt(Zj))**(2/3)

moliere.params[('A', 'B')] = dict(qi=Zi*e, qj=Zj*e, aF=aF)
params#

The potential parameters. The dictionary has the following keys:

  • qi (float, required) - \(q_i = Z_i \frac{e}{\sqrt{4 \pi \epsilon_0}}\) \([\mathrm{charge}]\)

  • qj (float, required) - \(q_j = Z_j \frac{e}{\sqrt{4 \pi \epsilon_0}}\) \([\mathrm{charge}]\)

  • aF (float, required) - \(a_F = \frac{0.8853 a_0}{\left( \sqrt{Z_i} + \sqrt{Z_j} \right)^{2/3}}\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.Morse(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Morse pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Morse computes the Morse pair force on every particle in the simulation state:

\[U(r) = D_0 \left[ \exp \left(-2\alpha\left( r-r_0\right)\right) -2\exp \left(-\alpha\left(r-r_0\right) \right) \right]\]

Example:

nl = nlist.Cell()
morse = pair.Morse(default_r_cut=3.0, nlist=nl)
morse.params[('A', 'A')] = dict(D0=1.0, alpha=3.0, r0=1.0)
morse.r_cut[('A', 'B')] = 3.0
params#

The potential parameters. The dictionary has the following keys:

  • D0 (float, required) - depth of the potential at its minimum \(D_0\) \([\mathrm{energy}]\)

  • alpha (float, required) - the width of the potential well \(\alpha\) \([\mathrm{length}^{-1}]\)

  • r0 (float, required) - position of the minimum \(r_0\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.OPP(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Oscillating pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

OPP computes the oscillating pair force on all particles in the simulation state:

\[U(r) = C_1 r^{-\eta_1} + C_2 r^{-\eta_2} \cos{\left(k r - \phi\right)}\]

The potential was introduced in Marek Mihalkovič and C. L. Henley 2012.

Example:

nl = nlist.Cell()
opp = pair.OPP(nl, default_r_cut=3.0)
opp.params[('A', 'A')] = {
    'C1': 1., 'C2': 1., 'eta1': 15,
    'eta2': 3, 'k': 1.0, 'phi': 3.14}
opp.r_cut[('A', 'B')] = 3.0
params#

The OPP potential parameters. The dictionary has the following keys:

  • C1 (float, required) - Energy scale of the first term \(C_1\) \([\mathrm{energy}]\)

  • C2 (float, required) - Energy scale of the second term \(C_2\) \([\mathrm{energy}]\)

  • eta1 (float, required) - The inverse power to take \(r\) to in the first term, \(\eta_1\) \([\mathrm{dimensionless}]\).

  • eta2 (float, required) - The inverse power to take \(r\) to in the second term \(\eta_2\) \([\mathrm{dimensionless}]\).

  • k (float, required) - oscillation frequency \(k\) \([\mathrm{length}^{-1}]\)

  • phi (float, required) - potential phase shift \(\phi\) \([\mathrm{dimensionless}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.Pair(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Force

Base class pair force.

Pair is the base class for all pair forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

r_cut#

Cuttoff radius beyond which the energy and force are 0 \([\mathrm{length}]\). Optional: defaults to the value default_r_cut specified on construction.

Type: TypeParameter [tuple [particle_type, particle_type], float])

r_on#

Radius at which the smoothing modification to the potential starts \([\mathrm{length}]\). Optional: defaults to the value default_r_on specified on construction.

Type: TypeParameter [tuple [particle_type, particle_type], float])

mode#

mode, optional: defaults to "none". Possible values: "none", "shift", "xplor"

Type: str

nlist#

Neighbor list used to compute the pair force.

Type: hoomd.md.nlist.NeighborList

compute_energy(tags1, tags2)#

Compute the energy between two sets of particles.

Parameters:
  • tags1 (ndarray<int32>) – a numpy array of particle tags in the first group.

  • tags2 (ndarray<int32>) – a numpy array of particle tags in the second group.

\[U = \sum_{i \in \mathrm{tags1}, j \in \mathrm{tags2}} V_{ij}(r)\]

where \(V_{ij}(r)\) is the pairwise energy between two particles \(i\) and \(j\).

Assumed properties of the sets tags1 and tags2 are:

  • tags1 and tags2 are disjoint

  • all elements in tags1 and tags2 are unique

  • tags1 and tags2 are contiguous numpy arrays of dtype int32

None of these properties are validated.

Examples:

tags=numpy.linspace(0,N-1,1, dtype=numpy.int32)
# computes the energy between even and odd particles
U = mypair.compute_energy(tags1=numpy.array(tags[0:N:2]),
                          tags2=numpy.array(tags[1:N:2]))
class hoomd.md.pair.ReactionField(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Onsager reaction field pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

ReactionField computes the Onsager reaction field pair force on all particles in the simulation state.

Reaction field electrostatics is an approximation to the screened electrostatic interaction, which assumes that the medium can be treated as an electrostatic continuum of dielectric constant \(\epsilon_{RF}\) outside the cutoff sphere of radius \(r_{\mathrm{cut}}\). See: Barker et. al. 1973.

By default (use_charge=False), the reaction field potential ignores the particle charges. Two parameters, \(\varepsilon\) and \(\epsilon_{RF}\) are needed. If \(\epsilon_{RF}\) is specified as zero, it will represent infinity:

\[U(r) = \varepsilon \left[ \frac{1}{r} + \frac{(\epsilon_{RF}-1) r^2}{(2 \epsilon_{RF} + 1) r_c^3} \right]\]

When use_charge is set to True, the following formula is evaluated instead:

\[U(r) = q_i q_j \varepsilon \left[ \frac{1}{r} + \frac{(\epsilon_{RF}-1) r^2}{(2 \epsilon_{RF} + 1) r_c^3} \right]\]

where \(q_i\) and \(q_j\) are the charges of the particle pair.

Example:

nl = nlist.Cell()
reaction_field = pair.reaction_field(nl, default_r_cut=3.0)
reaction_field.params[('A', 'B')] = dict(epsilon=1.0, eps_rf=1.0)
reaction_field.params[('B', 'B')] = dict(
    epsilon=1.0, eps_rf=0.0, use_charge=True)
params#

The potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\varepsilon\) \([\mathrm{energy} \cdot \mathrm{length}]\)

  • eps_rf (float, required) - \(\epsilon_{RF}\) \([\mathrm{dimensionless}]\)

  • use_charge (bool, optional) - evaluate pair force using particle charges (default: False)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.TWF(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Pair potential model for globular proteins.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

TWF computes the Ten-wolde Frenkel potential on all particles in the simulation state:

\[U(r) = \frac{4 \epsilon}{\alpha^2} {\left[ {\left(\frac{\sigma^2}{r^2} - 1 \right)}^{-6} - \alpha {\left(\frac{\sigma^2}{r^2} - 1 \right)}^{-3}\right]}\]

The potential was introdcued in Pieter Rein ten Wolde and Daan Frenkel 1997.

Example:

nl = nlist.Cell()
twf = hoomd.md.pair.TWF(nl, default_r_cut=3.0)
twf.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0, 'alpha': 50.0}
twf.r_cut[('A', 'B')] = 3.0
params#

The LJ potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \(\sigma\) \([\mathrm{length}]\)

  • alpha (float, required) - controls well-width \(\alpha\) \([\mathrm{dimensionless}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.Table(nlist, default_r_cut=None)#

Bases: Pair

Tabulated pair force.

Parameters:

Table computes the tabulated pair force on every particle in the simulation state.

The force \(\vec{F}\) is:

\[\begin{split}\vec{F}(\vec{r}) = \begin{cases} 0 & r < r_{\mathrm{min}} \\ F_\mathrm{table}(r)\hat{r} & r_{\mathrm{min}} \le r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases}\end{split}\]

and the potential \(U(r)\) is:

\[\begin{split}U(r) = \begin{cases} 0 & r < r_{\mathrm{min}} \\ U_\mathrm{table}(r) & r_{\mathrm{min}} \le r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases}\end{split}\]

where \(\vec{r}\) is the vector pointing from one particle to the other in the pair, r_min is defined in params, and r_cut is defined in Pair.r_cut.

Provide \(F_\mathrm{table}(r)\) and \(U_\mathrm{table}(r)\) on evenly spaced grid points points between \(r_{\mathrm{min}}\) and \(r_{\mathrm{cut}}\). Table linearly interpolates values when \(r\) lies between grid points and between the last grid point and \(r=r_{\mathrm{cut}}\). The force must be specificed commensurate with the potential: \(F = -\frac{\partial U}{\partial r}\).

Table does not support energy shifting or smoothing modes.

Note

For potentials that diverge near r=0, to set r_min to a non-zero value.

Note

The implicitly defined \(r\) values are those that would be returned by numpy.linspace(r_min, r_cut, len(U), endpoint=False).

Tip

Define non-interacting potentials with:

table.params[(type1, type2)] = dict(r_min=0, U=[0], F=[0])
table.r_cut[(type1, type2)] = 0

There must be at least one element in U and F, and the r_cut value of 0 disables the interaction entirely.

params#

The potential parameters. The dictionary has the following keys:

  • r_min (float, required) - the minimum distance to apply the tabulated potential, corresponding to the first element of the energy and force arrays \([\mathrm{length}]\).

  • U ((N,) numpy.ndarray of float, required) - the tabulated energy values \([\mathrm{energy}]\).

  • F ((N,) numpy.ndarray of float, required) - the tabulated force values \([\mathrm{force}]\). Must have the same length as U.

Type:

TypeParameter [ tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none".

Type:

str

class hoomd.md.pair.Yukawa(nlist, default_r_cut=None, default_r_on=0.0, mode='none')#

Bases: Pair

Yukawa pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

  • mode (str) – Energy shifting/smoothing mode.

Yukawa computes the Yukawa pair force son every particle in the simulation state:

\[U(r) = \varepsilon \frac{ \exp \left( -\kappa r \right) }{r}\]

Example:

nl = nlist.Cell()
yukawa = pair.Yukawa(default_r_cut=3.0, nlist=nl)
yukawa.params[('A', 'A')] = dict(epsilon=1.0, kappa=1.0)
yukawa.r_cut[('A', 'B')] = 3.0
params#

The Yukawa potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \(\varepsilon\) \([\mathrm{energy}]\)

  • kappa (float, required) - scaling parameter \(\kappa\) \([\mathrm{length}^{-1}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none", "shift", or "xplor".

Type: str

class hoomd.md.pair.ZBL(nlist, default_r_cut=None, default_r_on=0.0)#

Bases: Pair

ZBL pair force.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list.

  • default_r_cut (float) – Default cutoff radius \([\mathrm{length}]\).

  • default_r_on (float) – Default turn-on radius \([\mathrm{length}]\).

ZBL computes the Ziegler-Biersack-Littmark pair force on every particle in the simulation state:

\[\begin{split}U(r) = \frac{Z_i Z_j e^2}{4 \pi \epsilon_0 r_{ij}} \left[ 0.1818 \exp \left( -3.2 \frac{r_{ij}}{a_F} \right) \right. \\ + 0.5099 \exp \left( -0.9423 \frac{r_{ij}}{a_F} \right) \\ + 0.2802 \exp \left( -0.4029 \frac{r_{ij}}{a_F} \right) \\ + \left. 0.02817 \exp \left( -0.2016 \frac{r_{ij}}{a_F} \right) \right]\end{split}\]

Where each parameter is defined as:

  • \(Z_i\) - Z_i - Atomic number of species i \([\mathrm{dimensionless}]\)

  • \(Z_j\) - Z_j - Atomic number of species j \([\mathrm{dimensionless}]\)

  • \(e\) - elementary_charge - The elementary charge \([\mathrm{charge}]\)

  • \(a_F = \frac{0.8853 a_0}{ Z_i^{0.23} + Z_j^{0.23} }\), where \(a_0\) is the Bohr radius \([\mathrm{length}]\)

Example:

nl = nlist.Cell()
zbl = pair.ZBL(default_r_cut=3.0, nlist=nl)

Zi = 54
Zj = 7
e = 1
a0 = 1
aF = 0.8853 * a0 / (Zi**(0.23) + Zj**(0.23))

zbl.params[('A', 'B')] = dict(qi=Zi*e, qj=Zj*e, aF=aF)
params#

The ZBL potential parameters. The dictionary has the following keys:

  • q_i (float, required) - \(q_i=Z_i \frac{e}{\sqrt{4 \pi \epsilon_0}}\) \([\mathrm{charge}]\)

  • q_j (float, required) - \(q_j=Z_j \frac{e}{\sqrt{4 \pi \epsilon_0}}\) \([\mathrm{charge}]\)

  • a_F (float, required) - \(a_F = \frac{0.8853 a_0}{ Z_i^{0.23} + Z_j^{0.23} }\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mode#

Energy shifting/smoothing mode: "none".

Type: str

Modules

md.pair.aniso#

Overview

ALJ

Anistropic LJ force.

AnisotropicPair

Base class anisotropic pair force.

Dipole

Screened dipole-dipole pair forces.

GayBerne

Gay-Berne anisotropic pair force.

Details

Anisotropic pair forces.

Anisotropic pair force classes apply a force, torque, and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{pair,total} = \frac{1}{2} \sum_{i=0}^\mathrm{N_particles-1} \sum_{j \ne i, (i,j) \notin \mathrm{exclusions}} U_\mathrm{pair}(r_{ij}, \mathbf{q}_i, \mathbf{q}_j)\]

AnisotropicPair applies cuttoffs, exclusions, and assigns per particle energies and virials in the same manner as hoomd.md.pair.Pair

AnisotropicPair does not support the 'xplor' shifting mode or the r_on parameter.

class hoomd.md.pair.aniso.ALJ(nlist, default_r_cut=None)#

Bases: AnisotropicPair

Anistropic LJ force.

Parameters:

ALJ computes the Lennard-Jones force between anisotropic particles as described in Ramasubramani, V. et al. 2020, using the formula:

\[U(r, r_c) = U_0(r) + U_c(r_c)\]

The first term is the central interaction \(U_0\), the standard center-center interaction between two Lennard-Jones particles with center-center distance \(r\). The second term is the contact interaction \(U_c\), computed from the smallest distance between the surfaces of the two shapes \(r_c\). The central and contact interactions are defined as follows:

\[ \begin{align}\begin{aligned}&U_0(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{6} \right]\\&U_c(r_c) = 4 \varepsilon_c(\varepsilon) \left[ \left( \frac{\sigma_c}{r_c} \right)^{12} - \left( \frac{\sigma_c}{r_c} \right)^{6} \right]\end{aligned}\end{align} \]

where \(\varepsilon\) (epsilon) affects strength of both the central and contact interactions, \(\varepsilon_c\) is an energy coefficient set proportional to \(\varepsilon\) to preserve the shape, \(\sigma\) is the interaction distance of the central term computed as the average of \(\sigma_i\) (sigma_i) and \(\sigma_j\) (sigma_j). Lastly, ALJ uses the contact ratios \(\beta_i\) (contact_ratio_i) and \(\beta_j\) (contact_ratio_j) to compute the contact sigma \(\sigma_c\) as follows:

\[ \begin{align}\begin{aligned}\sigma_c &= \frac{1}{2} \left[\sigma_{ci} + \sigma_{cj} \right]\\\sigma_{ci} &= \beta_i \cdot \sigma_i\\\sigma_{cj} &= \beta_j \cdot \sigma_j\end{aligned}\end{align} \]

The total potential energy is therefore the sum of two interactions, a central Lennard-Jones potential and a radially-shifted Lennard-Jones potential where the shift is anisotropic and depends on the extent of the shape in each direction.

Each term has an independent cutoff at which the energy is set to zero. The behavior of these cutoffs is dependent on whether a user requires LJ or Weeks-Chandler-Anderson (WCA)-like (repulsive-only) behavior. This behavior is controlled using the alpha parameter, which can take on the following values:

Set alpha based on range of the center-center and contact-contact interactions.#

center-center repulsive only

center-center full-range

contact-contact repulsive only

alpha = 0

alpha = 1

contact-contact full-range

alpha = 2

alpha = 3

For polytopes, computing interactions using a single contact point leads to significant instabilities in the torques because the contact point can jump from one end of a face to another in an arbitrarily small time interval. To ameliorate this, the ALJ potential performs a local averaging over all the features associated with the closest simplices on two polytopes. This averaging can be turned off by setting the average_simplices key for the type pair to False.

Specifying only rounding_radii creates an ellipsoid, while specifying only vertices creates a convex polytope (set vertices and faces to empty lists to create the ellipsoid).

Important

The repulsive part of the contact interaction \(U_c(r_c)\) prevents two ALJ particles from approaching closely, effectively rounding the shape by a radius \(\sigma_c\). For this reason, the shape written by type_shapes includes the rounding due to rounding_radii and that due to \(\sigma_c\).

Choosing r_cut:

Set r_cut for each pair of particle types so that ALJ can compute interactions for all possible relative placements and orientations of the particles. The farthest apart two particles can be while still interacting depends on the value of alpha.

In the following list, the first argument to the \(\max\) function is for the center-center interaction. The second argument is for the contact-contact interaction, where \(R_i\) is the radius of the shape’s minimal origin-centered bounding sphere of the particle with type \(i\).

Let \(\lambda_{min} = 2^{1/6}\) be the position of the potential energy minimum of the Lennard-Jones potential and \(\lambda_{cut}^{attractive}\) be a larger value, such as 2.5 (typically used in isotropic LJ systems).

  • For alpha=0:

    \[\begin{split}r_{\mathrm{cut},ij} = \max \bigg( & \frac{\lambda_{min}}{2} (\sigma_i + \sigma_j), \\ & R_i + R_j + R_{\mathrm{rounding},i} + R_{\mathrm{rounding},j} + \frac{\lambda_{min}}{2} (\beta_i \cdot \sigma_i + \beta_j \cdot \sigma_j) \bigg)\end{split}\]
  • For alpha=1:

    \[\begin{split}r_{\mathrm{cut},ij} = \max \bigg( & \frac{\lambda_{cut}^{attractive}}{2} (\sigma_i + \sigma_j), \\ & R_i + R_j + R_{\mathrm{rounding},i} + R_{\mathrm{rounding},j}+ \frac{\lambda_{min}}{2} (\beta_i \cdot \sigma_i + \beta_j \cdot \sigma_j) \bigg)\end{split}\]
  • For alpha=2:

    \[\begin{split}r_{\mathrm{cut},ij} = \max \bigg( & \frac{\lambda_{min}}{2} (\sigma_i + \sigma_j)), \\ & R_i + R_j + R_{\mathrm{rounding},i} + R_{\mathrm{rounding},j} + \frac{\lambda_{cut}^{attractive}}{2} (\beta_i \cdot \sigma_i + \beta_j \cdot \sigma_j) \bigg)\end{split}\]
  • For alpha=3:

    \[\begin{split}r_{\mathrm{cut},ij} = \max \bigg( & \frac{\lambda_{cut}^{attractive}}{2} (\sigma_i + \sigma_j), \\ & R_i + R_j + R_{\mathrm{rounding},i} + R_{\mathrm{rounding},j} + \frac{\lambda_{cut}^{attractive}}{2} (\beta_i \cdot \sigma_i + \beta_j \cdot \sigma_j) \bigg)\end{split}\]

Warning

Changing dimension in a simulation will invalidate this force and will lead to error or unrealistic behavior.

params#

The ALJ potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - base energy scale \(\varepsilon\) \([energy]\).

  • sigma_i (float, required) - the insphere diameter of the first particle type, \(\sigma_i\) \([length]\).

  • sigma_j (float, required) - the insphere diameter of the second particle type, \(\sigma_j\) \([length]\).

  • alpha (int, required) - Integer 0-3 indicating whether or not to include the attractive component of the interaction (see above for details).

  • contact_ratio_i (float, optional) - \(\beta_i\), the ratio of the contact sphere diameter of the first type with sigma_i. Defaults to 0.15.

  • contact_ratio_j (float, optional) - \(\beta_j\), the ratio of the contact sphere diameter of the second type with sigma_j. Defaults to 0.15.

  • average_simplices (bool, optional) - Whether to average over simplices. Defaults to True. See class documentation for more information.

Type: hoomd.data.typeparam.TypeParameter [tuple [particle_types, particle_types], dict]

Note

While the evaluation of the potential is symmetric with respect to the potential parameter labels i and j, the parameters which physically represent a specific particle type must appear in all sets of pair parameters which include that particle type.

shape#

The shape of a given type. The dictionary has the following keys per type:

  • vertices (list [tuple [float, float, float]], required) - The vertices of a convex polytope in 2 or 3 dimensions. The third dimension in 2D is ignored.

  • rounding_radii (tuple [float, float, float] or float, required) - The semimajor axes of a rounding ellipsoid \(R_{\mathrm{rounding},i}\). If a single value is specified, the rounding ellipsoid is a sphere. Defaults to (0.0, 0.0, 0.0).

  • faces (list [list [int]], required) - The faces of the polyhedron specified as a list of list of integers. The indices corresponding to the vertices must be ordered counterclockwise with respect to the face normal vector pointing outward from the origin.

Type: hoomd.data.typeparam.TypeParameter [particle_types, dict]

Example:

nl = hoomd.md.nlist.Cell(buffer=0.4)
alj = hoomd.md.pair.aniso.ALJ(nl, r_cut=2.5)

cube_verts = [(-0.5, -0.5, -0.5),
              (-0.5, -0.5, 0.5),
              (-0.5, 0.5, -0.5),
              (-0.5, 0.5, 0.5),
              (0.5, -0.5, -0.5),
              (0.5, -0.5, 0.5),
              (0.5, 0.5, -0.5),
              (0.5, 0.5, 0.5)];

cube_faces = [[0, 2, 6],
              [6, 4, 0],
              [5, 0, 4],
              [5,1,0],
              [5,4,6],
              [5,6,7],
              [3,2,0],
              [3,0,1],
              [3,6,2],
              [3,7,6],
              [3,1,5],
              [3,5,7]]

alj.params[("A", "A")] = dict(epsilon=2.0,
                              sigma_i=1.0,
                              sigma_j=1.0,
                              alpha=1,
                              )
alj.shape["A"] = dict(vertices=cube_verts,
                      faces=cube_faces)

The following example shows how to easily get the faces, with vertex indices properly ordered, for a shape with known vertices by using the coxeter package:

Example:

import coxeter

nl = hoomd.md.nlist.Cell(buffer=0.4)
alj = hoomd.md.pair.aniso.ALJ(nl, r_cut=2.5)

cube_verts = [[-0.5, -0.5, -0.5],
              [-0.5, -0.5, 0.5],
              [-0.5, 0.5, -0.5],
              [-0.5, 0.5, 0.5],
              [0.5, -0.5, -0.5],
              [0.5, -0.5, 0.5],
              [0.5, 0.5, -0.5],
              [0.5, 0.5, 0.5]]

cube = coxeter.shapes.ConvexPolyhedron(cube_verts)

alj.params[("A", "A")] = dict(epsilon=2.0,
                              sigma_i=1.0,
                              sigma_j=1.0,
                              alpha=1,
                              )
alj.shape["A"] = dict(vertices=cube.vertices,
                      faces=cube.faces)
property type_shapes#

The shape specification for use with GSD files for visualization.

This is not meant to be used for access to shape information in Python. See the attribute shape for programatic assess. Use this property to log shape for visualization and storage through the GSD file type.

(Loggable: category=”object”)

Type:

list [dict [str, any]]

class hoomd.md.pair.aniso.AnisotropicPair(nlist, default_r_cut=None, mode='none')#

Bases: Pair

Base class anisotropic pair force.

AnisotropicPair is the base class for all anisotropic pair forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

Parameters:
  • nlist (hoomd.md.nlist.NeighborList) – The neighbor list.

  • default_r_cut (float, optional) – The default cutoff for the potential, defaults to None which means no cutoff \([\mathrm{length}]\).

  • mode (str, optional) – the energy shifting mode, defaults to “none”.

class hoomd.md.pair.aniso.Dipole(nlist, default_r_cut=None)#

Bases: AnisotropicPair

Screened dipole-dipole pair forces.

Parameters:

Dipole computes the (screened) interaction between pairs of particles with dipoles and electrostatic charges:

\[ \begin{align}\begin{aligned}U &= U_{dd} + U_{de} + U_{ee}\\U_{dd} &= A e^{-\kappa r} \left(\frac{\vec{\mu_i}\cdot\vec{\mu_j}}{r^3} - 3\frac{(\vec{\mu_i}\cdot \vec{r_{ji}}) (\vec{\mu_j}\cdot \vec{r_{ji}})} {r^5} \right)\\U_{de} &= A e^{-\kappa r} \left(\frac{(\vec{\mu_j}\cdot \vec{r_{ji}})q_i}{r^3} - \frac{(\vec{\mu_i}\cdot \vec{r_{ji}})q_j}{r^3} \right)\\U_{ee} &= A e^{-\kappa r} \frac{q_i q_j}{r}\end{aligned}\end{align} \]

Note

All units are documented electronic dipole moments. However, Dipole can also be used to represent magnetic dipoles.

Example:

nl = nlist.Cell()
dipole = md.pair.ansio.Dipole(nl, default_r_cut=3.0)
dipole.params[('A', 'B')] = dict(A=1.0, kappa=4.0)
dipole.mu['A'] = (4.0, 1.0, 0.0)
params#

The dipole potential parameters. The dictionary has the following keys:

  • A (float, required) - \(A\) - electrostatic energy scale (default: 1.0) \([\mathrm{energy} \cdot \mathrm{length} \cdot \mathrm{charge}^{-2}]\)

  • kappa (float, required) - \(\kappa\) - inverse screening length \([\mathrm{length}^{-1}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

mu#

\(\mu\) - the magnetic magnitude of the particle local reference frame as a tuple (i.e. \((\mu_x, \mu_y, \mu_z)\)) \([\mathrm{charge} \cdot \mathrm{length}]\).

Type: TypeParameter [particle_type, tuple [float, float, float ]]

class hoomd.md.pair.aniso.GayBerne(nlist, default_r_cut=None, mode='none')#

Bases: AnisotropicPair

Gay-Berne anisotropic pair force.

Parameters:

GayBerne computes the Gay-Berne anisotropic pair force on every particle in the simulation state. This version of the Gay-Berne force supports identical pairs of uniaxial ellipsoids, with orientation-independent energy-well depth. The potential comes from the following paper Allen et. al. 2006.

\[\begin{split}U(\vec r, \vec e_i, \vec e_j) = \begin{cases} 4 \varepsilon \left[ \zeta^{-12} - \zeta^{-6} \right] & \zeta < \zeta_{\mathrm{cut}} \\ 0 & \zeta \ge \zeta_{\mathrm{cut}} \\ \end{cases}\end{split}\]

where

\[ \begin{align}\begin{aligned}\zeta &= \left(\frac{r-\sigma+\sigma_{\mathrm{min}}} {\sigma_{\mathrm{min}}}\right),\\\sigma^{-2} &= \frac{1}{2} \hat{\vec{r}} \cdot \vec{H^{-1}} \cdot \hat{\vec{r}},\\\vec{H} &= 2 \ell_\perp^2 \vec{1} + (\ell_\parallel^2 - \ell_\perp^2) (\vec{e_i} \otimes \vec{e_i} + \vec{e_j} \otimes \vec{e_j}),\end{aligned}\end{align} \]

and \(\sigma_{\mathrm{min}} = 2 \min(\ell_\perp, \ell_\parallel)\).

The cut-off parameter \(r_{\mathrm{cut}}\) is defined for two particles oriented parallel along the long axis, i.e. \(\zeta_{\mathrm{cut}} = \left(\frac{r-\sigma_{\mathrm{max}} + \sigma_{\mathrm{min}}}{\sigma_{\mathrm{min}}}\right)\) where \(\sigma_{\mathrm{max}} = 2 \max(\ell_\perp, \ell_\parallel)\) .

The quantities \(\ell_\parallel\) and \(\ell_\perp\) denote the semi-axis lengths parallel and perpendicular to particle orientation.

Example:

nl = nlist.Cell()
gay_berne = md.pair.aniso.GayBerne(nlist=nl, default_r_cut=2.5)
gay_berne.params[('A', 'A')] = dict(epsilon=1.0, lperp=0.45, lpar=0.5)
gay_berne.r_cut[('A', 'B')] = 2 ** (1.0 / 6.0)
params#

The Gay-Berne potential parameters. The dictionary has the following keys:

  • epsilon (float, required) - \(\varepsilon\) \([\mathrm{energy}]\)

  • lperp (float, required) - \(\ell_\perp\) \([\mathrm{length}]\)

  • lpar (float, required) - \(\ell_\parallel\) \([\mathrm{length}]\)

Type: TypeParameter [tuple [particle_type, particle_type], dict]

property type_shapes#

Get all the types of shapes in the current simulation.

Example

>>> gay_berne.type_shapes
[{'type': 'Ellipsoid', 'a': 1.0, 'b': 1.0, 'c': 1.5}]
Returns:

A list of dictionaries, one for each particle type in the system.

(Loggable: category=”object”)

md.special_pair#

Overview

SpecialPair

Base class special pair forces.

LJ

LJ special pair force.

Coulomb

Coulomb special pair force.

Details

Special pair forces.

Special pair force classes apply a force and virial on every particle in the simulation state commensurate with the potential energy:

\[U_\mathrm{special~pairs} = \sum_{(j,k) \in \mathrm{special~pairs}} U_{jk}(r)\]

Special pairs are used to implement interactions between designated pairs of particles. They act much like bonds, except that the interaction potential is typically a pair potential, such as LJ.

Each special pair is defined by an ordered pair of particle tags in the hoomd.State member pair_group. HOOMD-blue does not compute special pair groups, users must explicitly define special pairs in the initial condition.

Definition of the special pair between particles j and k.

In the special pair group (j,k), \(r\) is the length of the vector between the particle positions \(r= |\mathrm{minimum\_image}(\vec{r}_k - \vec{r}_j)|\).

Special pair force classes assign 1/2 of the potential energy to each of the particles in the bond group:

\[U_i = \frac{1}{2} \sum_{(j,k) \in \mathrm{special~pairs}} U_{jk}(r) [i=j \lor i=k]\]

and similarly for virials.

class hoomd.md.special_pair.Coulomb#

Bases: SpecialPair

Coulomb special pair force.

Coulomb computes forces, virials, and energies on all special pairs in the simulation state with:

\[\begin{split}U(r) = \begin{cases} \alpha \cdot \left[ \frac{q_{a}q_{b}}{r} \right] & r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases}\end{split}\]

Note

Use Coulomb to implement special 1-4 interactions in atomistic force fields, such as the scaled 1-4 interactions in OPLS where both the 1-4 LJ and Coulomb interactions are scaled by 0.5.

params#

The parameter of the Coulomb forces for each particle type. The dictionary has the following keys:

  • alpha (float, required) - Coulomb scaling factor \([\mathrm{energy}]\)

Type:

TypeParameter[special pair type, dict]

r_cut#

The cut-off distance for special pair potential \([\mathrm{length}]\)

Type:

TypeParameter[special pair type, float]

Examples:

coulomb = special_pair.Coulomb()
coulomb.params['cluster'] = dict(alpha=1.0)
coulomb.r_cut['cluster'] = 2
class hoomd.md.special_pair.LJ#

Bases: SpecialPair

LJ special pair force.

LJ computes forces, virials, and energies on all special pairs in the simulation state with:

\[\begin{split}U(r) = \begin{cases} 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{6} \right] & r < r_{\mathrm{cut}} \\ 0 & r \ge r_{\mathrm{cut}} \\ \end{cases}\end{split}\]

Note

Use LJ to implement special 1-4 interactions in atomistic force fields, such as the scaled 1-4 interactions in OPLS where both the 1-4 LJ and Coulomb interactions are scaled by 0.5.

params#

The parameter of the lj forces for each particle type. The dictionary has the following keys:

  • epsilon (float, required) - energy parameter \([\mathrm{energy}]\)

  • sigma (float, required) - particle size \([\mathrm{length}]\)

Type:

TypeParameter[special pair type, dict]

r_cut#

The cut-off distance for special pair potential \([\mathrm{length}]\)

Type:

TypeParameter[special pair type, float]

Examples:

lj = special_pair.LJ()
lj.params['cluster'] = dict(epsilon=3, sigma=0.5)
lj.r_cut['cluster'] = 5
class hoomd.md.special_pair.SpecialPair#

Bases: Force

Base class special pair forces.

SpecialPair is the base class for all special pair forces.

Warning

This class should not be instantiated by users. The class can be used for isinstance or issubclass checks.

md.tune#

Overview

NeighborListBuffer

Optimize neighbor list buffer size for maximum TPS.

Details

Tuners for the MD subpackage.

class hoomd.md.tune.NeighborListBuffer(self, trigger: hoomd.trigger.Trigger, nlist: hoomd.md.nlist.NeighborList, solver: hoomd.tune.solve.Optimizer, maximum_buffer: float)#

Optimize neighbor list buffer size for maximum TPS.

Tip

Direct instantiation of this class requires a hoomd.tune.Optimizer that determines how move sizes are updated. This class also provides class methods to create a NeighborListBuffer tuner with built-in solvers; see NeighborListBuffer.with_grid and NeighborListBuffer.with_gradient_descent.

Parameters:
trigger#

Trigger to determine when to run the tuner.

Type:

hoomd.trigger.Trigger

solver#

A solver that tunes the neighbor list buffer to maximize TPS.

Type:

hoomd.tune.solve.Optimizer

maximum_buffer#

The largest buffer value to allow.

Type:

float

minimum_buffer#

The smallest buffer value to allow.

Type:

float

Warning

When using with a hoomd.device.GPU device, kernel launch parameter autotuning can prevent convergence. Run the simulation for 25,000 steps before adding the tuner to allow the autotuning to converge first results in better TPS optimization.

Note

NeighborListBuffer.with_grid generally performs better than NeighborListBuffer.with_gradient_descent due to the stocastic nature of TPS.

property best_buffer_size#

The buffer size corresponding to max_tps during tuning.

(Loggable: category=”scalar”)

Type:

float

property final_bin#

Boundaries of grid search optimization.

Property is only available when a hoomd.tune.GridOptimizer is used, and tuning is finished. Otherwise, the property is None.

Type:

tuple[float, float]

property last_tps#

The last TPS computed for the tuner.

(Loggable: category=”scalar”)

Type:

int

property max_tps#

The maximum recorded TPS during tuning.

(Loggable: category=”scalar”)

Type:

int

property tuned#

Whether the neighbor list buffer is considered tuned.

The tuner is considered tune when the specified solver returns True when solving twice consecutively. See hoomd.tune for more information on tuning criteria.

Type:

bool

classmethod with_gradient_descent(trigger: Trigger | int, nlist: NeighborList, maximum_buffer: float, minimum_buffer: float = 0.0, alpha: Variant | float = hoomd._hoomd.VariantRamp, kappa: ndarray | None = (0.33, 0.165), tol: float = 1e-05, max_delta: float | None = None)#

Create a NeighborListBuffer with a gradient descent solver.

See hoomd.tune.solve.GradientDescent for more information on the solver.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list buffer to maximize TPS.

  • maximum_buffer (float) – The largest buffer value to allow.

  • minimum_buffer (float, optional) – The smallest buffer value to allow (defaults to 0).

  • alpha (hoomd.variant.variant_like, optional) – Number between 0 and 1 or variant used to dampen the rate of change in x (defaults to hoomd.variant.Ramp(1e-5, 1e-6, 0, 30)). alpha scales the corrections to x each iteration. Larger values of alpha lead to larger changes while a alpha of 0 leads to no change in x at all.

  • kappa (numpy.ndarray of float, optional) – A NumPy array of floats which are weight applied to the last \(N\) of the gradients to add to the current gradient as well, where \(N\) is the size of the array (defaults to (0.33, 0.165)).

  • tol (float, optional) – The absolute tolerance for convergence of y (defaults to 1e-5).

  • max_delta (float, optional) – The maximum iteration step allowed (defaults to None which does not limit step size).

Note

Given the stocasticity of TPS, a non none kappa is recommended.

Tip

For better convergence choose an alpha in the range of 0.01 divided by the expected order of magnitude of the TPS. The default value assumes a TPS in the thousands.

Tip

When using the hoomd.tune.solve.GradientDescent, optimization is improved by starting at lower buffer values, as this has the steepest gradient.

classmethod with_grid(trigger: Trigger | int, nlist: NeighborList, maximum_buffer: float, minimum_buffer: float = 0.0, n_bins: int = 5, n_rounds: int = 1)#

Create a NeighborListBuffer with a hoomd.tune.GridOptimizer.

Parameters:
  • trigger (hoomd.trigger.trigger_like) – Trigger to determine when to run the tuner.

  • nlist (hoomd.md.nlist.NeighborList) – Neighbor list buffer to maximize TPS.

  • maximum_buffer (float) – The largest buffer value to allow.

  • minimum_buffer (float, optional) – The smallest buffer value to allow (defaults to 0).

  • n_bins (int, optional) – The number of bins in the range to test (defaults to 2).

  • n_rounds (int, optional) – The number of rounds to perform the optimization over (defaults to 1).

Note

Using this method adds another attribue final_bin which gives the final bin boundaries after tuning for n_rounds.

md.update#

Overview

ActiveRotationalDiffusion

Updater to introduce rotational diffusion with an active force.

ReversePerturbationFlow

Reverse Perturbation method to establish shear flow.

ZeroMomentum

Zeroes system momentum.

Details

MD updaters.

class hoomd.md.update.ActiveRotationalDiffusion(trigger, active_force, rotational_diffusion)#

Bases: Updater

Updater to introduce rotational diffusion with an active force.

Parameters:

ActiveRotationalDiffusion works directly with hoomd.md.force.Active or hoomd.md.force.ActiveOnManifold to apply rotational diffusion to the particle quaternions \(\mathbf{q}_i\) in simulations with active forces. The persistence length of an active particle’s path is \(v_0 / D_r\).

In 2D, the diffusion follows \(\delta \theta / \delta t = \Gamma \sqrt{2 D_r / \delta t}\), where \(D_r\) is the rotational diffusion constant and the \(\Gamma\) unit-variance random variable.

In 3D, \(\hat{p}_i\) is a unit vector in 3D space, and the diffusion follows \(\delta \hat{p}_i / \delta t = \Gamma \sqrt{2 D_r / \delta t} (\hat{p}_i (\cos \theta - 1) + \hat{p}_r \sin \theta)\), where \(\hat{p}_r\) is an uncorrelated random unit vector.

When used with hoomd.md.force.ActiveOnManifold, rotational diffusion is performed in the tangent plane of the manifold.

trigger#

Select the timesteps to update rotational diffusion.

Type:

hoomd.trigger.Trigger

active_force#

The active force associated with the updater. This is not settable after construction.

Type:

hoomd.md.force.Active

rotational_diffusion#

The rotational diffusion as a function of time.

Type:

hoomd.variant.Variant

class hoomd.md.update.ReversePerturbationFlow(filter, flow_target, slab_direction, flow_direction, n_slabs, max_slab=-1, min_slab=-1)#

Bases: Updater

Reverse Perturbation method to establish shear flow.

“Florian Mueller-Plathe. Reversing the perturbation in nonequilibrium molecular dynamics: An easy way to calculate the shear viscosity of fluids. Phys. Rev. E, 59:4894-4898, May 1999.”

The simulation box is divided in a number of slabs. Two distinct slabs of those are chosen. The “max” slab searches for the maximum velocity component in flow direction while the “min” slab searches for the minimum velocity component. Afterward, both velocity components are swapped.

This introduces a momentum flow, which drives the flow. The strength of this flow is set through the flow_target argument, which defines a target value for the time-integrated momentum flux. The searching and swapping is repeated until the target is reached. Depending on the target sign, the “max” and “min” slab might be swapped.

Parameters:
  • filter (hoomd.filter.filter_like) – Subset of particles on which to apply this updater.

  • flow_target (hoomd.variant.variant_like) – Target value of the time-integrated momentum flux. \([\delta t \cdot \mathrm{mass} \cdot \mathrm{length} \cdot \mathrm{time}^{-1}]\) - where \(\delta t\) is the integrator step size.

  • slab_direction (str) – Direction perpendicular to the slabs. Can be “x”, “y”, or “z”

  • flow_direction (str) – Direction of the flow. Can be “x”, “y”, or “z”

  • n_slabs (int) – Number of slabs used to divide the simulation box along the shear gradient. Using too few slabs will lead to a larger volume being disturbed by the momentum exchange, while using too many slabs may mean that there are not enough particles to exchange the target momentum.

  • max_slab (int) – Id < n_slabs where the max velocity component is search for. If set < 0 the value is set to its default n_slabs/2.

  • min_slab (int) – Id < n_slabs where the min velocity component is search for. If set < 0 the value is set to its default 0.

Attention

  • This updater uses hoomd.trigger.Periodic(1) as a trigger, meaning it is applied every timestep.

  • This updater works currently only with orthorhombic boxes.

Note

The attributes of this updater are immutable once the updater is attached to a simulation.

Examples:

# const integrated flow with 0.1 slope for max 1e8 timesteps
ramp = hoomd.variant.Ramp(0.0, 0.1e8, 0, int(1e8))
# velocity gradient in z direction and shear flow in x direction.
mpf = hoomd.md.update.ReversePerturbationFlow(filter=hoomd.filter.All(),
                                              flow_target=ramp,
                                              slab_direction="Z",
                                              flow_direction="X",
                                              n_slabs=20)
filter#

Subset of particles on which to apply this updater.

Type:

hoomd.filter.filter_like

flow_target#

Target value of the time-integrated momentum flux.

Type:

hoomd.variant.Variant

slab_direction#

Direction perpendicular to the slabs.

Type:

str

flow_direction#

Direction of the flow.

Type:

str

n_slabs#

Number of slabs.

Type:

int

max_slab#

Id < n_slabs where the max velocity component is searched for.

Type:

int

min_slab#

Id < n_slabs where the min velocity component is searched for.

Type:

int

property summed_exchanged_momentum#

Returned the summed up exchanged velocity of the full simulation.

(Loggable: category=”scalar”)

class hoomd.md.update.ZeroMomentum(trigger)#

Bases: Updater

Zeroes system momentum.

Parameters:

trigger (hoomd.trigger.trigger_like) – Select the timesteps to zero momentum.

ZeroMomentum computes the center of mass linear momentum of the system:

\[\vec{p} = \frac{1}{N_\mathrm{free,central}} \sum_{i \in \mathrm{free,central}} m_i \vec{v}_i\]

and removes it:

\[\vec{v}_i' = \vec{v}_i - \frac{\vec{p}}{m_i}\]

where the index \(i\) includes only free and central particles (and excludes consitutent particles of rigid bodies).

Note

ZeroMomentum executes on the CPU even when using a GPU device.

Examples:

zero_momentum = hoomd.md.update.ZeroMomentum(
    hoomd.trigger.Periodic(100))

Documentation#

Notation#

The HOOMD-blue documentation uses the following mathematical notation.

General notation:

\(x\)

Scalar.

\(\vec{a}\)

Vector.

\(a\)

Magnitude of the vector \(\vec{a}\).

\(\hat{a}\)

Unit vector in the direction of \(\vec{a}\).

\(\mathbf{A}\)

Matrix.

\(\mathbf{b}\)

Quaternion.

\(\vert \mathbf{b} \vert\)

Magnitude of a quaternion.

\(i\), \(j\), \(k\)

Indices.

\(i\)

\(\sqrt{-1}\) in some contexts.

\(\mathrm{function}\)

A mathematical function.

a \([\mathrm{length}]^2\)

The quantity “a” has dimensions of \(\mathrm{length}^2\).

Symbol definitions:

\(\vec{v}_{ij}\)

\(\vec{v}_j - \vec{v}_j\)

\(\vec{r}\)

Position.

\(\vec{v}\)

Velocity.

\(\mathbf{q}\)

Orientation.

\(m\)

Mass.

\(\vec{p}\)

Momentum.

\(I\)

Moment of inertia.

\(q\)

Charge.

\(N\)

Number.

\(L\)

Length.

\(V\)

Volume.

\(P\)

Pressure.

\(\rho\)

Number density.

\(\vec{a}_1\), \(\vec{a}_2\), \(\vec{a}_3\)

Box unit cell vectors.

\(\vec{F}\)

Force.

\(\vec{\tau}\)

Torque.

\(U\)

Potential energy.

\(K\)

Kinetic energy.

\(E\)

Total energy.

\(T\)

Temperature.

\(k\)

Boltzmann’s constant in some contexts. Typically appears multiplying temperature: \(kT\).

\(k\)

Spring constant in some contexts.

\(\beta\)

\(\frac{1}{kT}\)

\(t\)

Time.

Units#

HOOMD-blue does not adopt a particular system of units, nor does it offer a variety of systems to choose from. Instead, it follows a self-consistent system of units where all derived units (e.g. force) are defined in terms of base units (e.g. energy / length). To adopt a system of units for your simulations, choose a set of base units (e.g. meters versus centimeters for length), and then determine what the derived units are.

Base Units#

The base units are:

  • \([\mathrm{energy}]\)

  • \([\mathrm{length}]\)

  • \([\mathrm{mass}]\)

Unit Conversion#

Example unit conversions between derived units and base units:

Derived units

Relation to base units

\([\mathrm{area}]\)

\([\mathrm{length}]^2\)

\([\mathrm{volume}]\)

\([\mathrm{length}]^3\)

\([\mathrm{time}]\)

\([\mathrm{energy}]^{-1/2} \cdot [\mathrm{length}] \cdot [\mathrm{mass}]^{1/2}\)

\([\mathrm{velocity}]\)

\([\mathrm{energy}]^{1/2} \cdot [\mathrm{mass}]^{-1/2}\)

\([\mathrm{force}]\)

\([\mathrm{energy}] \cdot [\mathrm{length}]^{-1}\)

\([\mathrm{pressure}]\)

\([\mathrm{energy}] \cdot [\mathrm{length}]^{-3}\)

\([\mathrm{charge}]\)

\(\left(4 \pi \epsilon_{0} \cdot [\mathrm{energy}] \cdot [\mathrm{length}] \right)^{1/2}\) - where \(\epsilon_{0}\) is permittivity of free space

Note

Most of the units on this page apply to MD simulations.

In HPMC, the primary unit is that of length. Mass is factored out of the partition function and does not enter into the simulation. In addition, the energy scale is irrelevant in athermal HPMC systems where overlapping energies are infinite and valid configurations have zero potential energy. However, energy does appear implicitly in derived units like \([\mathrm{pressure}] = [\mathrm{energy}] \cdot [\mathrm{length}]^{-3}\). In HPMC, \(kT\) is set to 1 \(\mathrm{energy}\).

Common unit systems#

Example base and derived units for common MD unit systems.

Note

All conversion factors given here are computed with Wolfram Alpha using the provided links.

Unit

AKMA

MD

\([\mathrm{energy}]\)

kcal/mol

kJ/mol

\([\mathrm{length}]\)

Å

nm

\([\mathrm{mass}]\)

atomic mass unit

atomic mass unit

\([\mathrm{area}]\)

\(\mathrm{Å}^2\)

\(\mathrm{nm}^2\)

\([\mathrm{volume}]\)

\(\mathrm{Å}^3\)

\(\mathrm{nm}^3\)

\([\mathrm{time}]\)

48.8882129 fs

1 ps

\([\mathrm{velocity}]\)

0.02045482828 Å/fs

1 nm/ps

\([\mathrm{force}]\)

kcal/mol/Å

kJ/mol/nm

\([\mathrm{pressure}]\)

68568.4230 atm

16.3882464 atm

\([\mathrm{charge}]\)

0.05487686461 e

0.0848385920 e

\(k\) (Boltzmann’s constant)

0.00198720426 kcal/mol/K

0.00831446262 kJ/mol/K

Changes#

Change Log#

4.x#
4.0.1 (2023-06-27)#

Fixed

  • Prevent ValueError: signal only works in main thread of the main interpreter when importing hoomd in a non-main thread (#1576).

  • The recommended conda install commands find the documented version (#1578).

  • CMake completes without error when HOOMD_GPU_PLATFORM=HIP (#1579).

  • Tests pass with GSD 3.0.0 installed (#1577).

  • Provide full CUDA error message when possible (#1581).

  • Notice level 4 gives additional GPU initialization details (#1581).

  • Show particle out of bounds error messages in exception description (#1581).

Changed

  • Package source in hoomd-x.y.z.tar.gz (previously hoomd-vx.y.z.tar.gz) (#1572).

4.0.0 (2023-06-06)#

Fixed

  • Fix error with MPI_Allreduce on OLCF Frontier (#1547).

  • Correct equations in virial pressure documentation (#1548).

  • Work around cases where Python’s garbage collector fails to collect Operation objects (#1457).

  • Incorrect behavior with hpmc.external.user.CPPExternalPotential in MPI domain decomposition simulations (#1562).

Added

  • hoomd.md.ConstantVolume integration method (#1419).

  • hoomd.md.ConstantPressure integration method, implementing the Langevin piston barostat (#1419).

  • Thermostats in hoomd.md.methods.thermostats that work with ConstantVolume and ConstantPressure, including the new Bussi-Donadio-Parrinello thermostat (#1419).

  • hoomd.md.external.wall.Gaussian (#1499).

  • hoomd.write.GSD.maximum_write_buffer_size - Set the maximum size of the GSD write buffer (#1541).

  • hoomd.write.GSD.flush - flush the write buffer of an open GSD file (#1541).

  • On importing hoomd, install a SIGTERM handler that calls sys.exit(1) (#1541).

  • More descriptive error messages when calling Simulation.run (#1552).

  • hoomd.Snapshot.from_gsd_frame - convert a gsd.hoomd.Frame object to hoomd.Snapshot (#1559).

  • hoomd.device.NoticeFile - a file-like object that writes to hoomd.device.Device.notice (#1449).

  • hoomd.write.Burst - selective high-frequency frame writing to GSD files (#1543).

  • Support LLVM 16 (#1568).

  • More detailed status message for found CUDA libraries (#1566).

Changed

  • hoomd.md.constrain.Rigid no longer takes diameters or charges as keys in the body parameters. create_bodies method now takes an optional charges argument to set charges (#1350).

  • Control the precision with the CMake options HOOMD_LONGREAL_SIZE (default: 64) and HOOMD_SHORTREAL_SIZE (default: 32) (#355).

  • [developers] ShortReal and LongReal types enable mixed precision implementations (#355).

  • hoomd.md.constrain.Rigid now updates constituent particle types each step (#1440).

  • Moved hoomd.mesh.Mesh.triangles to hoomd.mesh.Mesh.triangulation (#1464).

  • hoomd.write.GSD does not write particles/diameter by default (#1266).

  • Updated tutorials to use HOOMD-blue v4 API, work with up to date releases of freud, gsd, and signac. Also make general improvements to the tutorials.

  • Document changes needed to migrate from v3 to v4 in the migration guide.

  • More descriptive error messages when calling Simulation.run (#1552).

  • Increase performance of hoomd.write.GSD (#1538).

  • Increase performance of hoomd.State.get_snapshot in serial (#1538).

  • hoomd.write.GSD.dynamic now allows fine grained control over individual particle fields (#1538).

  • No longer test with GCC 7-8, Python 3.6-3.7, or Clang 6-9) (#1544).

  • Improved error messages with NVRTC compiled code (#1567).

Deprecated

Removed

  • fix_cudart_rpath CMake macro (#1383).

  • ENABLE_MPI_CUDA CMake option (#1401).

  • Berendsen, NPH, NPT, NVE, NVT MD integration methods (#1419).

  • hoomd.write.GSD.log (#1480).

  • CMake option and compiler definition SINGLE_PRECISION (#355).

  • charges key in hoomd.md.constrain.Rigid.body (#1496).

  • diameter key in hoomd.md.constrain.Rigid.body. (#1496).

  • hoomd.md.dihedral.Harmonic. (#1496).

  • hoomd.device.GPU.memory_traceback parameter. (#1496).

  • hoomd.md.pair.aniso.Dipole.mode parameter. (#1496).

  • hoomd.md.pair.aniso.ALJ.mode parameter (#1496).

  • hoomd.md.pair.Gauss (#1499).

  • hoomd.md.external.wall.Gauss (#1499).

  • msg_file property and argument in hoomd.device.Device. (#1499).

  • The sdf attribute of hoomd.hpmc.compute.SDF - use sdf_compression (#1523).

  • alpha parameter and attribute in Langevin, BD, and OverdampedViscous integration methods (#1266).

  • needsDiameter and setDiameter API in C++ potential evaluators (#1266).

v3.x#
v3.11.0 (2023-04-14)#

Added:

  • hoomd.md.Integrator.validate_groups verifies that MD integration methods are applied to distinct subsets of the system and that those subsets consist of integrable particles (automatically called when attached) (#1466).

Changed:

  • hoomd.hpmc.compute.SDF computes pressures for systems of concave and non-monotonic patch interactions (#1391).

  • Reorganize documentation contents to fit in the sidebar, including landing pages for tutorials and how-to guides (#1526).

Fixed:

  • Improved readability of images in the documentation (#1521).

  • hoomd.write.Table now raises a meaningful error when given incorrect logger categories (#1510).

  • Correctly document the 1/2 scaling factor in the pairwise virial computation (#1525).

  • thermalize_particle_momenta now sets 0 velocity and angular momentum for rigid constituent particles (#1472).

  • Reduce likelihood of data corruption when writing GSD files (#1531).

  • Clarify migration process for hoomd.md.pair.ExpandedLJ (#1501).

Deprecated:

  • The sdf attribute of hoomd.hpmc.compute.SDF - use sdf_compression (#1391).

v3.10.0 (2023-03-14)#

Added:

  • The message_filename property and argument to Device, CPU, and GPU to replace msg_file (#1497).

  • hoomd.md.pair.Gaussian to replace hoomd.md.pair.Gauss (#1497).

  • hoomd.md.pair.ExpandedGaussian - the expanded Gaussian pair force (#1493).

  • Guide: How to apply arbitrary pair potentials in HPMC (#1505).

Changed:

  • Use furo style for HTML documentation (#1498).

Fixed:

  • The hoomd.md.pair potentials ExpandedLJ, ExpandedMie, LJGauss, and TWF now shift V(r_cut) to 0 properly when mode == 'shift' (#1504).

  • Corrected errors in the pair potential documentation (#1504).

  • Note that the 'body' exclusion should be used with hoomd.md.constrain.Rigid (#1465).

  • Correctly identify the 'xyz' mode in hoomd.md.methods.NPH (#1509).

Deprecated:

  • The msg_file property and argument to Device, CPU, and GPU.

  • hoomd.md.pair.Gauss.

v3.9.0 (2023-02-15)#

Added:

  • GPU code path for hoomd.update.BoxResize (#1462).

  • logger keyword argument and property to hoomd.write.GSD (#1481).

Changed:

  • Issue FutureWarning warnings when using deprecated APIs (#1485).

  • Reformat the list of deprecated features. (#1490).

  • In simulations with rigid bodies, remove D degrees of freedom when the system is momentum conserving (#1467).

Fixed:

  • Compile without errors using hipcc and ROCM 5.1.0 (#1478).

  • Document that hoomd.md.force.Force can be added to Operations.computes (#1489).

  • hoomd.md.constrain.Rigid.create_bodies completes without segmentation faults when particle body tags are not -1 (#1476).

  • hoomd.hpmc.compute.FreeVolume computes the free area correctly in 2D simulations (#1473).

Deprecated:

  • Deprecate write.GSD log keyword argument and property in favor of logger (#1481).

v3.8.1 (2023-01-27)#

Fixed:

  • #1468: Conserve linear momentum in simulations using hoomd.md.constrain.Rigid on more than 1 MPI rank.

v3.8.0 (2023-01-12)#

Added

  • Support Python 3.11.

  • Support CUDA 11.8.

  • Support CUDA 12.0.0 final.

Fixed

  • Improve numerical stability of orientation quaternions when using hoomd.md.update.ActiveRotationalDiffusion

  • Reduced memory usage and fix spurious failures in test_nlist.py.

  • Avoid triggering TypeError("expected x and y to have same length") in hoomd.hpmc.compute.SDF.betaP.

Deprecated

  • The following integration methods are deprecated. Starting in v4.0.0, the same functionalities will be available via hoomd.md.methods.ConstantVolume/ hoomd.md.methods.ConstantPressure with an appropriately chosen thermostat argument.

    • hoomd.md.methods.NVE

    • hoomd.md.methods.NVT

    • hoomd.md.methods.Berendsen

    • hoomd.md.methods.NPH

    • hoomd.md.methods.NPT

Removed

  • Support for CUDA 10.

v3.7.0 (2022-11-29)#

Added

  • Neighborlist.r_cut sets the base cutoff radius for neighbor search - for use when the neighbor list is used for analysis or custom Python code.

  • Neighborlist.cpu_local_nlist_arrays provides zero-copy access to the computed neighbor list.

  • Neighborlist.gpu_local_nlist_arrays provides zero-copy access to the computed neighbor list.

  • Neighborlist.local_pair_list provides the rank local pair list by index.

  • Neighborlist.pair_list provides the global pair list by tag on rank 0.

  • hoomd.md.dihedral.Periodic - a new name for the previous Harmonic potential.

  • default_gamma and default_gamma_r arguments to the hoomd.md.methods: Brownian, Langevin, and OverdampedViscous.

  • reservoir_energy loggable in hoomd.md.methods.Langevin.

  • hoomd.md.force.Constant applies constant forces and torques to particles.

Changed

  • [plugin developers] Refactored the LocalDataAccess C++ classes to add flexibility.

Fixed

  • hoomd.hpmc.nec integrators compute non-infinite virial pressures for 2D simulations.

  • Raise an exception when attempting to get the shape specification of shapes with 0 elements.

  • Box conversion error message now names hoomd.Box.

Deprecated

  • hoomd.md.dihedral.Harmonic - use the functionally equivalent hoomd.md.dihedral.Periodic.

  • charges key in hoomd.md.constrain.Rigid.body.

  • diameters key in hoomd.md.constrain.Rigid.body.

v3.6.0 (2022-10-25)#

Changed

  • In hoomd.md.pair.aniso.ALJ, shape.rounding_radii now defaults to (0.0, 0.0, 0.0).

  • Revise hoomd.md.pair.aniso.ALJ documentation.

  • hoomd.md.force.Force instances can now be added to the Operations list allowing users to compute force, torque, energy, and virials of forces that are not included in the dynamics of the system.

  • [developers]: Removed internal methods _remove and _add from the data model.

Fixed

  • Increase the performance of md.pair.Table on the CPU.

  • Improve accuracy of hoomd.hpmc.update.BoxMC when used with patch potentials.

  • Provide an accurate warning message when creating the state with many bond/angle/… types.

  • Add missing documentation for hoomd.md.methods.Berendsen.

  • CVE-2007-4559

v3.5.0 (2022-09-14)#

Added

  • Example plugin that demonstrates how to add a MD pair potential.

  • Support a large number of particle and bond types (subject to available GPU memory and user patience) for the Cell neighbor list, MD pair potentials, MD bond potentials, Brownian, and Langevin integration methods.

Changed

  • Raise an error when initializing with duplicate types.

  • hpmc.compute.SDF now computes pressures of systems with patch interactions.

  • Raise descriptive error messages when the shared memory request exceeds that available on the GPU.

Fixed

  • Include all Neighborlist attributes in the documentation.

  • Memory allocation errors in C++ now result in MemoryError exceptions in Python.

  • Add missing Autotuned.h header file.

  • External components build correctly when ENABLE_MPI=on or ENABLE_GPU=on.

  • Type parameter validation when items contain numpy.ndarray elements.

  • Compile with CUDA 12.0.

Deprecated

  • Device.memory_traceback attribute. This attribute has no effect.

v3.4.0 (2022-08-15)#

Added

  • The new HOOMD-blue logo is now available in the documentation.

  • hoomd.md.methods.DisplacementCapped class for relaxing configurations with overlaps.

  • hoomd.md.methods.rattle.DisplacementCapped class for relaxing configurations with overlaps.

  • hoomd.device.Device.notice - print user-defined messages to the configured message output stream.

  • Tutorial: Modelling Rigid Bodies.

  • AutotunedObject class that provides an interface to read and write tuned kernel parameters, query whether tuning is complete, and start tuning again at the object level.

  • is_tuning_complete method to Operations. Check whether kernel parameter tuning is complete for all operations.

  • tune_kernel_parameters methods to Operations and many other classes. Start tuning kernel parameters in all operations.

  • hoomd.md.HalfStepHook - extensible hook class called between step 1 and 2 of MD integration.

  • hoomd.md.Integrator.half_step_hook - property to get/set the half step hook.

Fixed

  • Active forces on manifolds now attach to the Simulation correctly.

  • hoomd.update.FilterUpdater now accepts hoomd.filter.CustomFilter subclasses.

  • Correct error message is given when a sequence like parameter is not given to a type parameter.

  • Fix non-axis-aligned Cylinder walls in MD.

  • hoomd.md.constrain.Constraint now has hoomd.md.force.Force as a base class.

  • Provide a warning instead of an error when passing an out of range seed to the Simulation constructor.

  • Compile with current versions of HIP and ROCm.

  • Compilation errors with CUDA >=11.8.

v3.3.0 (2022-07-08)#

Added

  • A decorator that modifies the namespace of operation and custom action classes hoomd.logging.modify_namespace.

  • Tuner for the neighbor list buffer size hoomd.md.tune.NeighborListBuffer.

  • Solver infrastructure for optimization problems.

  • Simulation.initial_timestep: the timestep on which the last call to run started.

  • variant_like, trigger_like, and filter_like typing objects for documentation.

Changed

  • Removed "__main__" from some user custom action logging namespaces.

Fixed

  • Improve documentation.

  • Non-default loggables can now be explicitly specified with Logger.add.

  • Iteration of Logger instances.

  • The logging category of hoomd.md.Integrate.linear_momentum

v3.2.0 (2022-05-18)#

Added

  • hoomd.md.nlist.Neighborlist.num_builds property - The number of neighbor list builds since the last call to Simulation.run.

  • hoomd.md.nlist.Cell.dimensions property - The dimensions of the cell list.

  • hoomd.md.nlist.Cell.allocated_particles_per_cell property - The number of particle slots allocated per cell.

  • hoomd.mesh.Mesh - Triangular mesh data structure.

  • hoomd.md.mesh.bond - Bond potentials on mesh edges.

  • Support gcc 12.

  • Support clang 14.

  • Set ENABLE_LLVM=on in conda binary builds.

Fixed

  • Clarify documentation.

  • Box.dimension reports the correct value when reading in 2D boxes from GSD files generated in HOOMD v2.

  • Improve performance of run time compiled HPMC potentials on the CPU.

  • Pressing Ctrl-C or interrupting the kernel in Jupyter stops the run at the end of the current timestep.

v3.1.0 (2022-04-27)#

Added

  • Support LLVM 13 when ENABLE_LLVM=on.

  • hoomd.md.pair.LJGauss - Lennard-Jones-Gaussian pair potential.

  • hoomd.md.alchemy.methods.NVT - Alchemical molecular dynamics integration method.

  • hoomd.md.alchemy.pair.LJGauss - Lennard-Jones-Gaussian pair potential with alchemical degrees of freedom.

  • hoomd.hpmc.update.Shape - Alchemical hard particle Monte Carlo through shape change moves.

  • hoomd.hpmc.shape_move.Elastic - Shape move with elastic potential energy penalty.

  • hoomd.hpmc.shape_move.ShapeSpace - Moves in a user defined shape space.

  • hoomd.hpmc.shape_move.Vertex - Translate shape vertices.

Changed

  • HPMC fugacity is now a per-type quantity.

  • Improved documentation.

  • [developers] Reduced the time needed for incremental builds.

  • [developers] Reduced memory needed to compile HOOMD.

Fixed

  • ALJ unit test passes in Debug builds.

  • Add quotes to conda-forge gpu package installation example.

  • hoomd.md.force.Custom zeroes forces, torques, energies, and virials before calling set_forces.

  • Point tarball download link to https://github.com/glotzerlab/hoomd-blue/releases.

Deprecated

  • hoomd.md.pair.aniso.ALJ.mode - parameter has no effect.

  • hoomd.md.pair.aniso.Dipole.mode - parameter has no effect.

v3.0.1 (2022-04-08)#

Fixed

  • Display status of trunk-patch branch in the GitHub actions badge.

  • Add EvaluatorPairTable.h to installation directory.

  • Add hoomd.filter.Rigid to the documentation.

  • Prevent TypeError: 'bool' object is not iterable errors when comparing Tag filters with different lengths arrays.

  • Simulation.tps and Simulation.walltime update every step of the run.

v3.0.0 (2022-03-22)#

Overview

HOOMD-blue v3.0.0 is the first production release with the new API that has been developed and implemented over more than 2 years. Those still using v2.x will need to make changes to their scripts to use v3. See the Migrating to the latest version page for an overview and individual class and method documentation for more information. To summarize, the new API is object oriented, allows HOOMD-blue to work effectively as a Python package, and provides more hooks for Python code to directly interface with the simulation.

New features in v3 since v2.9.7:

  • Zero-copy data access through numpy and cupy.

  • Triggers determine what timesteps operations execute on.

  • User-defined operations, triggers, particle filters, variants, and forces.

  • Logging subsystem supports array quantities.

  • Implicit depletants for 2D shapes in HPMC.

  • Harmonically mapped averaging for MD thermodynamic quantities of crystals.

  • TWF and OPP pair potentials.

  • Tether bond potential.

  • Manifold constraints for MD integration methods (using RATTLE) and active forces.

  • Document code architecture in ARCHITECTURE.md.

  • Overdamped viscous MD integration method.

  • User-defined pair potentials work with HPMC on the GPU.

  • Long range tail correction for Lennard-Jones potential.

  • Anisotropic Lennard-Jones-like pair potential for polyhedra and ellipsoids.

  • Newtownian event chain Monte Carlo for spheres and convex polyhedra.

See the full change log below for all v3 beta releases.

Changes from v3.0.0-beta.14:

Added

  • hoomd.hpmc.tune.BoxMCMoveSize - Tune BoxMC move sizes to meet target acceptance ratios.

  • hoomd.hpmc.nec.integrate.Sphere - Newtonian event chain Monte Carlo for hard spheres.

  • hoomd.hpmc.nec.integrate.ConvexPolyhedron - Newtonian event chain Monte Carlo for hard convex polyhedra.

  • hoomd.hpmc.nec.tune.ChainTime - Tune chain times in newtonian event chain Monte Carlo method.

Changed

  • Improve documentation.

  • [breaking] Renamed the hoomd.md.bond.Table energy parameter from V to U.

  • [breaking] Renamed the hoomd.md.pair.Table energy parameter from V to U.

  • [breaking] Renamed the hoomd.md.angle.Table energy parameter from V to U.

  • [breaking] Renamed the hoomd.md.dihedral.Table energy parameter from V to U.

  • [breaking] Renamed hoomd.md.nlist.Nlist to hoomd.md.nlist.NeighborList.

  • [developer] Updater and Analyzer in C++ have a m_trigger member now.

  • [developer] _TriggeredOperation has been moved to TriggeredOperation and custom trigger setting and getting logic removed.

Fixed

  • FIRE.converged may be queried before calling Simulation.run.

  • Bug where using __iadd__ to certain attributes would fail with an exception.

  • Bug where hoomd.md.pair.LJ.additional_energy is NaN when tail_correction is enabled and some pairs have r_cut=0.

  • Compile error with CUDA 11.7.

  • Compile errors on native ubuntu 20.04 systems.

  • Compile errors with ENABLE_GPU=on and clang as a host compiler.

Removed

  • [developers] Removed IntegratorData class. It is replaced by structs that are defined in the integrator classes.

  • get_ordered_vertices from hoomd.md.pair.aniso.ALJ.

  • Removed optional coxeter dependency.

  • The limit parameter from hoomd.md.methods.NVE.

  • The limit parameter from hoomd.md.methods.rattle.NVE.

  • The diameter_shift parameter from hoomd.md.nlist.NeighborList.

  • The max_diameter parameter from hoomd.md.nlist.NeighborList.

v3.0.0-beta.14 (2022-02-18)#

Added

  • hoomd.hpmc.external.field.Harmonic - harmonic potential of particles to specific sites in the simulation box and orientations.

  • Support cereal 1.3.1

  • Guide on how to model molecular systems.

  • version.floating_point_precision - Floating point width in bits for the particle properties and local calculations.

  • hoomd.md.pair.LJ.tail_correction - Option to enable the isotropic integrated long range tail correction.

  • hoomd.md.Integrator.linear_momentum - Compute the total system linear momentum. Loggable.

  • hoomd.md.bond.Table - Tabulated bond potential.

  • hoomd.md.angle.Table - Tabulated angle potential.

  • hoomd.md.dihedral.Table - Tabulated dihedral potential.

  • hoomd.md.improper.Harmonic - Compute the harmonic improper potential and forces.

  • Tutorial on Organizing and executing simulations.

  • C++ and build system overview in ARCHITECTURE.md.

  • hoomd.hpmc.external.wall - Overlap checks between particles and wall surfaces.

  • hoomd.md.pair.ansio.ALJ - an anisotropic Lennard-Jones-like pair potential for polyhedra and ellipsoids.

  • New optional dependency: coxeter, needed for some ALJ methods.

Changed

  • Support variant translational and rotational spring constants in hoomd.hpmc.external.field.Harmonic.

  • [breaking] Renamed hoomd.md.angle.Cosinesq to hoomd.md.angle.CosineSquared.

  • [breaking] hoomd.Box no longer has a matrix property use to_matrix and from_matrix.

Fixed

  • Compilation errors on FreeBSD.

  • TypeError when instantiating special pair forces.

  • Inconsistent state when using the walls setter of a hoomd.md.external.wall.WallPotential.

Removed

  • [breaking] Removed hoomd.md.pair.SLJ potential and wall. Use hoomd.md.pair.ExpandedLJ.

  • [breaking] hoomd.Box.lattice_vectors property no longer exists.

v3.0.0-beta.13 (2022-01-18)#

Added

  • md.pair.ExpandedLJ - A Lennard-Jones potential where r is replaced with r-delta.

  • Support nested modification of operation parameters.

  • wall - Define wall surfaces in the simulation box.

  • md.external.wall - Pair interactions between particles and wall surfaces.

  • Communicator.walltime - the wall clock time since creating the Communicator.

  • md.force.Custom - user defined forces in Python.

Changed

  • Call update_group_dof implicitly in set_snapshot, when changing integrators or integration methods, and on steps where FilterUpdater acts on the system.

  • [breaking] update_group_dof defers counting the degrees of freedom until the next timestep or the next call to Simulation.run.

  • [breaking] Renamed md.bond.FENE to md.bond.FENEWCA.

  • md.bond.FENEWCA takes a user provided delta parameter and ignores the particle diameters.

  • [breaking] md.pair.DLVO takes user provided a1 and a2 parameters and ignores the particle diameters.

  • Removed invalid linker options when using gcc on Apple systems.

  • Removed the r_on attribute and default_r_on constructor argument from pair potentials that do not use it.

  • Building from source requires a C++17 compatible compiler.

Fixed

  • Compile error with Apple clang clang-1300.0.29.30.

  • Incorrect OPLS dihedral forces when compiled with Apple clang clang-1300.0.29.30.

Deprecated

  • md.pair.SLJ - Replaced with md.pair.ExpandedLJ.

Removed

  • Leftover state logging category.

v3.0.0-beta.12 (2021-12-14)#

Added

  • Support simulations with arbitrarily large or small scales (within the limits of the floating point representation).

Changed

  • Report full error details in the exception message.

  • Improved documentation.

  • [breaking]: buffer is now a required argument when constructing a neighbor list.

  • [breaking]: force_tol, angmom_tol, and energy_tol are now required arguments to md.minimize.FIRE

Fixed

  • Allow neighbor lists to store more than 2**32-1 total neighbors.

  • Return expected parameter values instead of NaN when potential parameters are set to 0.

v3.0.0-beta.11 (2021-11-18)#

Added

  • Support Python 3.10.

  • Support clang 13.

Changed

  • [developers] Place all all HOOMD C++ classes in the hoomd and nested namespaces.

  • [developers] Use official pre-commit clang-format repository.

v3.0.0-beta.10 (2021-10-25)#

Added

  • md.minimize.FIRE - MD integrator that minimizes the system’s potential energy.

  • Include example AKMA and MD unit conversion factors in the documentation.

  • BUILD_LLVM CMake option (defaults off) to enable features that require LLVM.

  • hpmc.pair.user.CPPPotential - user-defined pair potentials between particles in HPMC.

  • hpmc.pair.user.CPPPotentialUnion - user-defined site-site pair potentials between shapes in HPMC.

  • hpmc.external.user.CPPExternalPotential - user-defined external potentials in HPMC.

  • Support user-defined pair potentials in HPMC on the GPU.

Changed

  • Improved documentation.

  • Improved error messages when setting operation parameters.

  • Noted some dependencies of dependencies for building documentation.

  • [developers] Removed m_comm from most classes. Use m_sysdef->isDomainDecomposed() instead.

  • Add support for LLVM 12

  • ENABLE_LLVM=on requires the clang development libraries.

  • [breaking] Renamed the Integrator attribute aniso to integrate_rotational_dof and removed the 'auto' option. Users must now explicitly choose integrate_rotational_dof=True to integrate the rotational degrees of freedom in the system.

Fixed

  • Calling Operations.__len__ no longer raises a RecursionError.

  • RATTLE integration methods execute on the GPU.

  • Include EvaluatorPairDLVO.h in the installation for plugins.

  • Bug in setting zero sized ManagedArrays.

  • Kernel launch errors when one process uses different GPU devices.

  • Race condition that lead to incorrect simulations with md.pair.Table.

  • Bug where some particle filers would have 0 rotational degrees of freedom.

Removed

  • The BUILD_JIT CMake option.

  • Support for LLVM <= 9.

v3.0.0-beta.9 (2021-09-08)#

Added

  • Communicator.num_partitions - the number of partitions in the communicator.

  • domain_decomposition argument to State factory methods - set the parameters of the MPI domain decomposition

  • State.domain_decomposition - number of domains in the x, y, and z directions in the domain decomposition.

  • State.domain_decomposition_split_fractions - the fractional positions of the split planes in the domain decomposition.

  • hoomd.update.FilterUpdater - an updater that evaluates the particles associated with a hoomd.filter.ParticleFilter instance.

  • hoomd.update.RemoveDrift - Remove the average drift from a system restrained on a lattice.

  • Developer documentation for HOOMD-blue’s Python object data model in ARCHITECTURE.md.

  • Autocomplete support for interactive notebooks.

  • hoomd.md.methods.OverdampedViscous - Overdamped integrator with a drag force but no random force .

  • MutabilityError exception when setting read-only operation parameters.

Changed

  • Improved documentation.

  • [breaking] Moved manifold_constrant to separate integration method classes in hoomd.md.methods.rattle.

  • [breaking] Moved trigger to first argument position in hoomd.update.BoxResize, hoomd.write.DCD, and hoomd.write.GSD.

  • [breaking] hoomd.data.LocalSnapshot particle data API now matches Snapshot. Changes to angular momentum, moment of intertia, and rigid body id attributes.

  • hoomd.write.CustomWriter now exposes action through the writer attribute.

  • [breaking] Active force rotational diffusion is managed by hoomd.md.update.ActiveRotationalDiffusion.

Fixed

  • TypeParameter can set multiple parameters after calling hoomd.Simulation.run.

  • tune.LoadBalancer can be used in a simulation.

  • hoomd.md.pair.Pair r_cut type parameter can be set to 0.

  • MD integration methods can be removed from the integrator’s method list.

  • Neighborlist exclusions update when the number of bonds change.

  • Errors related to equality checks between HOOMD operations.

  • The integrator can be removed from a simulation after running.

  • hoomd.md.constrain.Rigid.create_bodies method correctly assigns the body attribute.

  • Setting rigid attribute of a MD integrator to None is allowed.

Deprecated

Removed

  • Snapshot.exists - use snapshot.communicator.rank == 0

  • State.snapshot - use get_snapshot and set_snapshot

  • The State.box property setter - use State.set_box

v3.0.0-beta.8 (2021-08-03)#

Added

  • Consistent documentation of parameter dimensions and units reference documentation.

  • md.update.ReversePerturbationFlow - implementation of mueller_plathe_flow from v2.

  • md.pair.ExpandedMie - Mie potential where r is replaced with r - delta.

  • md.pair.Table - Pair potential evaluated using the given tabulated values.

  • md.constrain.Distance - fix distances between pairs of particles.

  • hpmc.compute.SDF - compute the pressure of convex hard particle systems.

  • Snapshot.wrap() - wrap snapshot particles back into the box.

  • Support gcc11.

  • md.bond.Tether - A bond with minimum and maximum lengths.

  • State.get_snapshot and State.set_snapshot - methods to access the global snapshot.

  • State.set_box set a new simulation box without modifying particle properties.

  • md.long_range.pppm.make_pppm_coulomb_forces - Long range electrostatics evaluated by PPPM.

  • md.long_range.pppm.Coulomb - The reciprocal part of PPPM electrostatics.

  • md.force.ActiveOnManifold - Active forces constrained to manifolds.

Changed

  • Improved documentation.

  • [breaking] Constructor arguments that set a default value per type or pair of types now have default in their name (e.g. r_cut to default_r_cut for pair potentials and a to default_a for HPMC integrators).

  • [developer] Support git worktree checkouts.

  • [breaking] Rename nrank to ranks_per_partition in Communicator.

  • rowan is now an optional dependency when running unit tests.

  • Snapshot and Box methods that make in-place modifications return the object.

Fixed

  • Bug where ThermdynamicQuantities.volume returned 0 in 2D simulations.

  • Update neighbor list exclusions after the number of particles changes.

  • Test failures with the CMake option BUILD_MD=off.

  • write.Table can now display MD pressures.

Deprecated

  • State.snapshot - use get_snapshot and set_snapshot.

  • The ability to set boxes with the property State.box - use set_box.

Removed

  • [breaking] Simulation.write_debug_data.

  • [breaking] shared_msg_file option to Device. msg_file now has the same behavior as shared_msg_file.

  • [developers] C++ and Python implementations of constraint_ellipsoid, from hoomd.md.update and sphere and oneD from hoomd.md.constrain.

  • [developers] Doxygen configuration files.

v3.0.0-beta.7 (2021-06-16)#

Added

  • md.constrain.Rigid - Rigid body constraints.

  • dem_built, hpmc_built, md_built, and mpcd_built to hoomd.version - flags that indicate when optional submodules have been built.

  • GPU.compute_capability property.

  • [developers] pre-commit enforced style guidelines for the codebase.

  • [developers] Validation tests for MD Lennard-Jones simulations.

  • [developers] Unit tests for bond, angle, and dihedral potentials.

Changed

  • Improved documentation on compiling HOOMD.

  • Operations raise a DataAccessError when accessing properties that are not available because Simulation.run has not been called.

  • TypeConversionError is now in the hoomd.error package.

  • from_gsd_snapshot only accesses the GSD snapshot on MPI rank 0.

Fixed

  • Some broken references in the documentation.

  • Missing documentation for md.pair.TWF.

  • Inconsistent documentation in md.pair.

  • Correctly identify GPUs by ID in GPU.devices.

  • Don’t initialize contexts on extra GPUs on MPI ranks.

  • Support 2D inputs in from_gsd_snapshot.

Deprecated

  • Snapshot.exists - use Snapshot.communicator.rank == 0 instead.

Removed

  • [developers] C++ implementations of rescale_temp and enforce2d.

  • [developers] Unused methods of Integrator.

v3.0.0-beta.6 (2021-05-17)#

Added

  • md.pair.LJ0804 - 8,4 Lennard-Jones pair potential.

  • md.nlist.Stencil - Stencil algorithm to generate neighbor lists.

  • md.nlist.Tree - BVH algorithm to generate neighbor lists.

  • hoomd.md.Force, hoomd.md.Operation, and hoomd.md.Operations objects are now picklable.

  • Manifold constraints using RATTLE with md.methods.NVE, md.methods.Langevin and md.methods.Brownian - Supporting sphere, ellipsoid, plane, cylinder, gyroid, diamond, and primitive manifolds.

  • md.compute.HarmonicAveragedThermodynamicQuantities - More accurate thermodynamic quantities for crystals

Changed

  • Raise an exception when initializing systems with invalid particle type ids.

Fixed

  • Setting the operations attribute in Simulation objects in specific circumstances.

  • Misc documentation updates.

  • 'sim' is not defined error when using md.dihedral potentials.

Removed

  • C++ implemtation of v2 logging infrastructure.

v3.0.0-beta.5 (2021-03-23)#

Added

  • filter parameter to update.BoxResize - A ParticleFilter that identifies the particles to scale with the box.

  • Simulation.seed - one place to set random number seeds for all operations.

  • net_force, net_torque, and net_energy per-particle arrays in local snapshots.

  • Support hpmc.update.Clusters on the GPU.

  • hpmc.update.MuVT - Gibbs ensemble simulations with HPMC.

  • md.update.ZeroMomentum - Remove linear momentum from the system.

  • hpmc.compute.FreeVolume - Compute free volume available to test particles.

  • Custom action tutorials.

Changed

  • [breaking] Removed the parameter scale_particles in update.BoxResize

  • [internal] Modified signature of data.typeconverter.OnlyTypes

  • Remove use of deprecated numpy APIs.

  • Added more details to the migration guide.

  • Support timestep values in the range [0,2**64-1].

  • [breaking] Removed seed argument from State.thermalize_particle_momenta

  • [breaking] Removed seed argument from md.methods.NVT.thermalize_thermostat_dof

  • [breaking] Removed seed argument from md.methods.NPT.thermalize_thermostat_and_barostat_dof

  • [breaking] Removed seed argument from md.methods.NPH.thermalize_barostat_dof

  • [breaking] Removed seed argument from md.methods.Langevin

  • [breaking] Removed seed argument from md.methods.Brownian

  • [breaking] Removed seed argument from md.force.Active

  • [breaking] Removed seed argument from md.pair.DPD

  • [breaking] Removed seed argument from md.pair.DPDLJ

  • [breaking] Removed seed argument from all HPMC integrators.

  • [breaking] Removed seed argument from hpmc.update.Clusters

  • [breaking] Removed seed argument from hpmc.update.BoxMC

  • [breaking] Removed seed argument from hpmc.update.QuickCompress

  • Use latest version of getar library.

  • Improve documentation.

  • Improve performance of md.pair.Mie.

  • [breaking] hpmc.update.Clusters re-implemented with a rejection free, but not ergodic, algorithm for anisotropic particles. The new algorithm does not run in parallel over MPI ranks.

  • [breaking] HPMC depletion algorithm rewritten.

  • [breaking, temporary] HPMC depletant fugacity is now set for type pairs. This change will be reverted in a future release.

  • Tutorials require fresnel 0.13.

  • Support TBB 2021.

Fixed

  • Install ParticleFilter header files for external plugins.

  • md.force.Active keeps floating point values set for active_force and active_torque.

  • create_state_from_snapshot accepts gsd.hoomd.Snapshot objects without error.

  • HOOMD compiles on Apple silicon macOS systems.

  • Memory leak in PPPM force compute.

  • Segmentation fault that occurred when dumping GSD shapes for spheropolygons and spheropolyhedra with 0 vertices.

  • Incorrect MD neighbor lists in MPI simulations with more than 1 rank.

  • md.bond.FENE accepts parameters.

Removed

  • Testing with CUDA 9, GCC 4.8, GCC 5.x, GCC 6.x, clang 5

v3.0.0-beta.4 (2021-02-16)#

Added

  • hoomd.write.DCD - DCD trajectory writer.

  • hoomd.md.many_body - RevCross, SquareDensity, and Tersoff triplet potentials.

  • hoomd.md.methods.Berendsen - Berendsen integration method.

  • hoomd.md.methods.NPH - Constant pressure constant enthalpy integration method.

  • hoomd.md.pair.TWF - Potential for modeling globular proteins by Pieter Rein ten Wolde and Daan Frenkel.

  • Custom particle filters in Python via hoomd.filter.CustomFilter.

Changed

  • Documentation improvements.

Fixed

  • Correctly determine the maximum r_cut in simulations with more than one pair potential and more than one type.

v3.0.0-beta.3 (2021-01-11)#

Added

  • hoomd.variant.Variant objects are picklable.

  • hoomd.filter.ParticleFilter objects are picklable.

  • hoomd.trigger.Trigger objects are picklable.

  • hoomd.Snapshot.from_gsd_snapshot - Convert GSD snapshots to HOOMD.

  • hoomd.md.pair.aniso.GayBerne - Uniaxial ellipsoid pair potential.

  • hoomd.md.pair.aniso.Dipole - Dipole pair potential.

  • hoomd.md.pair.OPP - Oscillating pair potential.

Changed

  • Improved compilation docs.

  • Box equality checking now returns NotImplemented for non-hoomd.Box objects.

  • Simulation.create_state_from_snapshot now accepts gsd.hoomd.Snapshot objects.

  • Attempting to run in a local snapshot context manager will now raise a RuntimeError.

  • Attempting to set the state to a new snapshot in a local snapshot context manager will now raise a RuntimeError.

Fixed

  • hoomd.variant.Power objects now have a t_ramp attribute as documented.

  • Enable memory buffers larger than 2-4 GiB.

  • Correctly write large image flags to GSD files.

  • Support more than 26 default type names.

  • Correctly represent fractional degrees of freedom.

  • Compute the minimum image in double precision.

v3.0.0-beta.2 (2020-12-15)#

Added

  • Support pybind11 2.6.0

  • Exclusive creation file mode for write.GSD.

  • hpmc.update.BoxMC.

  • walltime and final_timestep loggable properties in Simulation.

  • Null particle filter.

  • Logging tutorial.

Changed

  • [breaking] Replace write.GSD argument overwrite with mode.

  • [breaking] Rename flags to categories in Logger

  • hoomd.snapshot.ConfigurationData.dimensions is not settable and is determined by the snapshot box. If box.Lz == 0, the dimensions are 2 otherwise 3.

  • Building from source requires a C++14 compatible compiler.

  • Improved documentation.

  • hpmc.integrate.FacetedEllipsoid’s shape specification now has a default origin of (0, 0, 0).

  • Document loggable quantities in property docstrings.

  • Skip GPU tests when no GPU is present.

  • write.Table writes integers with integer formatting.

Fixed

  • Simulation.run now ends with a KeyboardInterrupt exception when Jupyter interrupts the kernel.

  • Logging the state of specific objects with nested attributes.

  • Broken relative RPATHs.

  • Add missing documentation for version.version

  • Error when removing specific operations from a simulation’s operations attribute.

  • Find CUDA libraries on additional Linux distributions.

  • hpmc.update.Clusters now works with all HPMC integrators.

  • Simulation.timestep reports the correct value when analyzers are called.

  • Logger names quantities with the documented namespace name.

v3.0.0-beta.1 (2020-10-15)#

Overview

v3 has a completely new Python API. See the tutorials, migration guide and new API documentation learn about it. The API documentation serves as the complete list of all features currently implemented in v3.0.0-beta.1. Not all features in v2 have been ported in v3.0.0-beta.1. Future beta releases will add additional functionality.

Added

  • Zero-copy data access through numpy (CPU) and cupy (GPU).

  • User-defined operations in Python.

  • User-defined triggers determine what time steps operations execute on.

  • New logging subsystem supports array quantities and binary log files.

  • Implicit depletants are now supported by any hpmc integrator through mc.set_fugacity('type', fugacity).

  • Enable implicit depletants for two-dimensional shapes in hpmc.

  • jit.patch.user() and jit.patch.user_union() now support GPUs via NVRTC.

  • Add harmonically mapped averaging.

  • Add Visual Studio Code workspace

Changed

  • The run method has minimal overhead

  • All loggable quantities are directly accessible as object properties.

  • Operation parameters are always synchronized.

  • Operations can be instantiated without a device or MPI communicator.

  • Writers write output for step+1 at the bottom of the run loop.

  • HOOMD writes minimal output to stdout/stderr by default.

  • CMake >=3.9, cereal, eigen, and pybind11 are required to compile HOOMD.

  • Plugins must be updated to build against v3.

  • By default, HOOMD installs to the site-packages directory associated with the python executable given, which may be inside a virtual environment.

  • Refactored CMake code.

  • git submodule update no longer runs when during CMake configuration.

  • Use random123 library for implicit depletants in hpmc.

  • HOOMD requires a GPU that supports concurrent managed memory access (Pascal or newer).

Bug fixes

  • Improved accuracy of DLVO potential on the GPU.

  • Improved performance of HPMC simulations on the CPU in non-cubic boxes.

Removed

  • HOOMD-blue no longer parses command line options.

  • Type swap moves in hpmc.update.muvt() are no longer supported (transfer_ratio option to muvt.set_params())

  • The option implicit=True to hpmc.integrate.* is no longer available (use set_fugacity).

  • static parameter in dump.gsd

  • util.quiet_status and util.unquiet_status.

  • deprecated.analyze.msd.

  • deprecated.dump.xml.

  • deprecated.dump.pos.

  • deprecated.init.read_xml.

  • deprecated.init.create_random.

  • deprecated.init.create_random_polymers.

  • hpmc ignore_overlaps parameter.

  • hpmc sphere_union::max_members parameter.

  • hpmc convex_polyhedron_union.

  • hpmc setup_pos_writer method.

  • hpmc depletant_mode='circumsphere'.

  • hpmc max_verts parameter.

  • hpmc depletant_mode parameter.

  • hpmc ntrial parameter.

  • hpmc implicit boolean parameter.

  • group parameter to md.integrate.mode_minimize_fire

  • cgcmm.angle.cgcmm

  • cgcmm.pair.cgcmm

  • COPY_HEADERS CMake option.

  • Many other python modules have been removed or re-implemented with new names. See the migration guide and new API documentation for a complete list.

  • Support for NVIDIA GPUS with compute capability < 6.0.

v2.x#
v2.9.7 (2021-08-03)#

Bug fixes

  • Support CUDA 11.5. A bug in CUDA 11.4 may result in the error __global__ function call is not configured when running HOOMD.

v2.9.6 (2021-03-16)#

Bug fixes

  • Support TBB 2021.

v2.9.5 (2021-03-15)#

Bug fixes

  • Support macos-arm64.

  • Support TBB 2021.

  • Fix memory leak in PPPM.

v2.9.4 (2021-02-05)#

Bug fixes

  • Support thrust 1.10

  • Support LLVM11

  • Fix Python syntax warnings

  • Fix compile errors with gcc 10

v2.9.3 (2020-08-05)#

Bug fixes

  • Fix a compile error with CUDA 11

v2.9.2 (2020-06-26)#

Bug fixes

  • Fix a bug where repeatedly using objects with period=None would use significant amounts of memory.

  • Support CUDA 11.

  • Reccomend citing the 2020 Computational Materials Science paper 10.1016/j.commatsci.2019.109363.

v2.9.1 (2020-05-28)#

Bug fixes

  • Fixed a minor bug where the variable period timestep would be off by one when the timestep got sufficiently large.

  • Updated collections API to hide DeprecationWarning.

  • Fix scaling of cutoff in Gay-Berne potential to scale the current maximum distance based on the orientations of the particles, ensuring ellipsoidal energy isocontours.

  • Misc documentation fixes.

v2.9.0 (2020-02-03)#

New features

  • General

    • Read and write GSD 2.0 files.

      • HOOMD >=2.9 can read and write GSD files created by HOOMD <= 2.8 or GSD 1.x. HOOMD <= 2.8 cannot read GSD files created by HOOMD >=2.9 or GSD >= 2.0.

      • OVITO >=3.0.0-dev652 reads GSD 2.0 files.

      • A future release of the gsd-vmd plugin will read GSD 2.0 files.

  • HPMC

    • User-settable parameters in jit.patch.

    • 2D system support in muVT updater.

    • Fix bug in HPMC where overlaps were not checked after adding new particle types.

  • MD

    • The performance of nlist.tree has been drastically improved for a variety of systems.

v2.8.2 (2019-12-20)#

Bug fixes

  • Fix randomization of barostat and thermostat velocities with randomize_velocities() for non-unit temperatures.

  • Improve MPCD documentation.

  • Fix uninitialized memory in some locations which could have led to unreproducible results with HPMC in MPI, in particular with ALWAYS_USE_MANAGED_MEMORY=ON.

  • Fix calculation of cell widths in HPMC (GPU) and nlist.cell() with MPI.

  • Fix potential memory-management issue in MPI for migrating MPCD particles and cell energy.

  • Fix bug where exclusions were sometimes ignored when charge.pppm() is the only potential using the neighbor list.

  • Fix bug where exclusions were not accounted for properly in the pppm_energy log quantity.

  • Fix a bug where MD simulations with MPI start off without a ghost layer, leading to crashes or dangerous builds shortly after run().

  • hpmc.update.remove_drift now communicates particle positions after updating them.

v2.8.1 (2019-11-26)#

Bug fixes

  • Fix a rare divide-by-zero in the collide.srd thermostat.

  • Improve performance of first frame written by dump.gsd.

  • Support Python 3.8.

  • Fix an error triggering migration of embedded particles for MPCD with MPI + GPU configurations.

v2.8.0 (2019-10-30)#

New Features

  • MD:

    • hoomd.md.dihedral.harmonic now accepts phase offsets, phi_0, for CHARMM-style periodic dihedrals.

    • Enable per-type shape information for anisotropic pair potentials that complements the existing pair parameters struct.

  • HPMC:

    • Enable the use of an array with adjustable parameters within the user defined pair potential.

    • Add muVT updater for 2D systems.

Bug fixes

  • Fix missing header in external plugin builds.

  • Enable couple='none' option to md.integrate.npt() when randomly initializing velocities.

  • Documentation improvements.

  • Skip gsd shape unit test when required modules are not compiled.

  • Fix default particle properties when new particles are added to the system (e.g., via the muVT updater).

  • Fix charge.pppm() execution on multiple GPUs.

  • Enable with SimulationContext() as c.

  • Fix a bug for mpcd.collide.at with embedded particles, which may have given incorrect results or simulation crashes.

v2.7.0 (2019-10-01)#

New features

  • General:

    • Allow components to use Logger at the C++ level.

    • Drop support for python 2.7.

    • User-defined log quantities in dump.gsd.

    • Add hoomd.dump.gsd.dump_shape to save particle shape information in GSD files.

  • HPMC:

    • Add get_type_shapes to ellipsoid.

  • MPCD:

    • mpcd.stream.slit_pore allows for simulations through parallel-plate (lamellar) pores.

    • mpcd.integrate supports integration of MD (solute) particles with bounce-back rules in MPCD streaming geometries.

Bug fixes

  • hoomd.hdf5.log.query works with matrix quantities.

  • test_group_rigid.py is run out of the md module.

  • Fix a bug in md.integrate.langevin() and md.integrate.bd() where on the GPU the value of gamma would be ignored.

  • Fix documentation about interoperability between md.mode_minimize_fire() and MPI.

  • Clarify dump.gsd documentation.

  • Improve documentation of lattice_field and frenkel_ladd_energy classes.

  • Clarify singularity image download documentation.

  • Correctly document the functional form of the Buckingham pair potential.

  • Correct typos in HPMC example snippets.

  • Support compilation in WSL.

v2.6.0 (2019-05-28)#

New features

  • General:

    • Enable HPMC plugins.

    • Fix plug-in builds when ENABLE_TBB or ALWAYS_USE_MANAGED_MEMORY CMake parameters are set.

    • Remove support for compute 3.0 GPUs.

    • Report detailed CUDA errors on initialization.

    • Document upcoming feature removals and API changes.

  • MD:

    • Exclude neighbors that belong to the same floppy molecule.

    • Add fourier potential.

  • HPMC:

    • New shape class: hpmc.integrate.faceted_ellipsoid_union().

    • Store the orientable shape state.

  • MPCD:

    • mpcd.stream.slit allows for simulations in parallel-plate channels. Users can implement other geometries as a plugin.

    • MPCD supports virtual particle filling in bounded geometries through the set_filler method of mpcd.stream classes.

    • mpcd.stream includes an external mpcd.force acting on the MPCD particles. A block force, a constant force, and a sine force are implemented.

Bug fixes

  • Fix compile errors with LLVM 8 and -DBUILD_JIT=on.

  • Allow simulations with 0 bonds to specify bond potentials.

  • Fix a problem where HOOMD could not be imported in mpi4py jobs.

  • Validate snapshot input in restore_snapshot.

  • Fix a bug where rigid body energy and pressure deviated on the first time step after run().

  • Fix a bug which could lead to invalid MPI simulations with nlist.cell() and nlist.stencil().

C++ API changes

  • Refactor handling of MPI_Comm inside library

  • Use random123 for random number generation

  • CMake version 2.8.10.1 is now a minimum requirement for compiling from source

v2.5.2 (2019-04-30)#

Bug fixes

  • Support LLVM 9 in jit

  • Fix error when importing jit before hpmc

  • HPMC integrators raise errors when restore_state=True and state information is missing

  • Send messages to replaced sys.stdout and sys.stderr streams

  • Add hpmc.update.clusters to documentation index

  • Fix a bug in the MPCD Gaussian random number generator that could lead to NaN values

  • Fix issue where an initially cubic box can become non-cubic with integrate.npt() and randomize_velocities()

  • Fix illegal memory access in NeighborListGPU with -DALWAYS_USE_MANAGED_MEMORY=ON on single GPUs

  • Improve pair.table performance with multi-GPU execution

  • Improve charge.pppm performance with multi-GPU execution

  • Improve rigid body performance with multi-GPU execution

  • Display correct cell list statistics with the -DALWAYS_USE_MANAGED_MEMORY=ON compile option

  • Fix a sporadic data corruption / bus error issue when data structures are dynamically resized in simulations that use unified memory (multi-GPU, or with -DALWAYS_USE_MANAGED_MEMORY=ON compile time option)

  • Improve integrate.nve and integrate.npt performance with multi-GPU execution

  • Improve some angular degrees of freedom integrators with multi-GPU execution

  • Improve rigid body pressure calculation performance with multi-GPU execution

v2.5.1 (2019-03-14)#

Bug fixes

  • fix out-of-range memory access in hpmc.integrate.convex_polyheron

  • Remove support for clang3.8 and 4.0

  • Documentation improvements

  • Fix a segfault when using SLURM_LOCALID

v2.5.0 (2019-02-05)#

New features

  • General:

    • Fix BondedGroupData and CommunicatorGPU compile errors in certain build configurations

  • MD:

    • Generalize md.integrate.brownian and md.integrate.langevin to support anisotropic friction coefficients for rotational Brownian motion.

    • Improve NVLINK performance with rigid bodies

    • randomize_velocities now chooses random values for the internal integrator thermostat and barostat variables.

    • get_net_force returns the net force on a group of particles due to a specific force compute

  • HPMC:

    • Fix a bug where external fields were ignored with the HPMC implicit integrator unless a patch potential was also in use.

  • JIT:

    • Add jit.external.user to specify user-defined external fields in HPMC.

    • Use -DHOOMD_LLVMJIT_BUILD now instead of -DHOOMD_NOPYTHON

v2.4.2 (2018-12-20)#

Bug fixes

  • Miscellaneous documentation updates

  • Fix compile error with with -DALWAYS_USE_MANAGED_MEMORY=ON

  • Fix MuellerPlatheFlow, cast input parameter to int to avoid C++ constructor type mismatch

  • Improve startup time with multi-GPU simulations

  • Correctly assign GPUs to MPI processes on Summit when launching with more than one GPU per resource set

  • Optimize multi-GPU performance with NVLINK

  • Do not use mapped memory with MPI/GPU anymore

  • Fix some cases where a multi-GPU simulation fails with an alignment error

  • Eliminate remaining instance of unsafe __shfl

  • Hide CMake warnings regarding missing CPU math libraries

  • Hide CMake warning regarding missing MPI<->CUDA interoperability

  • Refactor memory management to fix linker errors with some compilers

C++ API Changes

  • May break some plug-ins which rely on GPUArray data type being returned from ParticleData and other classes (replace by GlobalArray)

v2.4.1 (2018-11-27)#

Bug fixes

  • Install WarpTools.cuh for use by plugins

  • Fix potential violation of detailed balance with anisotropic particles with hpmc.update.clusters in periodic boundary conditions

  • Support llvm 7.0

v2.4.0 (2018-11-07)#

New features

  • General:

    • Misc documentation updates

    • Accept mpi4py communicators in context.initialize.

    • CUDA 10 support and testing

    • Sphinx 1.8 support

    • Flush message output so that python -u is no longer required to obtain output on some batch job systems

    • Support multi-GPU execution on dense nodes using CUDA managed memory. Execute with --gpu=0,1,..,n-1 command line option to run on the first n GPUs (Pascal and above).

      • Node-local acceleration is implemented for a subset of kernels. Performance improvements may vary.

      • Improvements are only expected with NVLINK hardware. Use MPI when NVLINK is not available.

      • Combine the --gpu=.. command line option with mpirun to execute on many dense nodes

    • Bundle libgetar v0.7.0 and remove sqlite3 dependency

    • When building with ENABLE_CUDA=on, CUDA 8.0 is now a minimum requirement

  • MD:

    • no changes.

  • HPMC:

    • Add convex_spheropolyhedron_union shape class.

    • Correctly count acceptance rate when maximum particle move is is zero in hpmc.integrate.*.

    • Correctly count acceptance rate when maximum box move size is zero in hpmc.update.boxmc.

    • Fix a bug that may have led to overlaps between polygon soups with hpmc.integrate.polyhedron.

    • Improve performance in sphere trees used in hpmc.integrate.sphere_union.

    • Add test_overlap method to python API

  • API:

    • Allow external callers of HOOMD to set the MPI communicator

    • Removed all custom warp reduction and scan operations. These are now performed by CUB.

    • Separate compilation of pair potentials into multiple files.

    • Removed compute 2.0 workaround implementations. Compute 3.0 is now a hard minimum requirement to run HOOMD.

    • Support and enable compilation for sm70 with CUDA 9 and newer.

  • Deprecated:

    • HPMC: The implicit depletant mode circumsphere with ntrial > 0 does not support compute 7.0 (Volta) and newer GPUs and is now disabled by default. To enable this functionality, configure HOOMD with option the -DENABLE_HPMC_REINSERT=ON, which will not function properly on compute 7.0 (Volta) and newer GPUs.

    • HPMC: convex_polyhedron_union is replaced by convex_spheropolyhedron_union (when sweep_radii are 0 for all particles)

v2.3.5 (2018-10-07)#

Bug fixes

  • Document --single-mpi command line option.

  • HPMC: Fix a bug where hpmc.field.lattice_field did not resize 2D systems properly in combination with update.box_resize.

v2.3.4 (2018-07-30)#

Bug fixes

  • init.read_gsd no longer applies the time_step override when reading the restart file

  • HPMC: Add hpmc_patch_energy and hpmc_patch_rcut loggable quantities to the documentation

v2.3.3 (2018-07-03)#

Bug fixes

  • Fix libquickhull.so not found regression on Mac OS X

v2.3.2 (2018-06-29)#

Bug fixes

  • Fix a bug where gsd_snapshot would segfault when called without an execution context.

  • Compile warning free with gcc8.

  • Fix compile error when TBB include files are in non-system directory.

  • Fix libquickhull.so not found error on additional platforms.

  • HOOMD-blue is now available on conda-forge and the docker hub.

  • MPCD: Default value for kT parameter is removed for mpcd.collide.at. Scripts that are correctly running are not affected by this change.

  • MPCD: mpcd notifies the user of the appropriate citation.

  • MD: Correct force calculation between dipoles and point charge in pair.dipole

Deprecated

  • The anaconda channel glotzer will no longer be updated. Use conda-forge to upgrade to v2.3.2 and newer versions.

v2.3.1 (2018-05-25)#

Bug fixes

  • Fix doxygen documentation syntax errors

  • Fix libquickhull.so not found error on some platforms

  • HPMC: Fix bug that allowed particles to pas through walls

  • HPMC: Check spheropolyhedra with 0 vertices against walls correctly

  • HPMC: Fix plane wall/spheropolyhedra overlap test

  • HPMC: Restore detailed balance in implicit depletant integrator

  • HPMC: Correctly choose between volume and lnV moves in hpmc.update.boxmc

  • HPMC: Fix name of log quantity hpmc_clusters_pivot_acceptance

  • MD: Fix image list for tree neighbor lists in 2d

v2.3.0 (2018-04-25)#

New features

  • General:

    • Store BUILD_* CMake variables in the hoomd cmake cache for use in external plugins.

    • init.read_gsd and data.gsd_snapshot now accept negative frame indices to index from the end of the trajectory.

    • Faster reinitialization from snapshots when done frequently.

    • New command line option --single-mpi allows non-mpi builds of hoomd to launch within mpirun (i.e. for use with mpi4py managed pools of jobs)

    • For users of the University of Michigan Flux system: A --mode option is no longer required to run hoomd.

  • MD:

    • Improve performance with md.constrain.rigid in multi-GPU simulations.

    • New command integrator.randomize_velocities() sets a particle group’s linear and angular velocities to random values consistent with a given kinetic temperature.

    • md.force.constant() now supports setting the force per particle and inside a callback

  • HPMC:

    • Enabled simulations involving spherical walls and convex spheropolyhedral particle shapes.

    • Support patchy energetic interactions between particles (CPU only)

    • New command hpmc.update.clusters() supports geometric cluster moves with anisotropic particles and/or depletants and/or patch potentials. Supported move types: pivot and line reflection (geometric), and AB type swap.

  • JIT:

    • Add new experimental jit module that uses LLVM to compile and execute user provided C++ code at runtime. (CPU only)

    • Add jit.patch.user: Compute arbitrary patch energy between particles in HPMC (CPU only)

    • Add jit.patch.user_union: Compute arbitrary patch energy between rigid unions of points in HPMC (CPU only)

    • Patch energies operate with implicit depletant and normal HPMC integration modes.

    • jit.patch.user_union operates efficiently with additive contributions to the cutoff.

  • MPCD:

    • The mpcd component adds support for simulating hydrodynamics using the multiparticle collision dynamics method.

Beta feature

  • Node local parallelism (optional, build with ENABLE_TBB=on):

    • The Intel TBB library is required to enable this feature.

    • The command line option --nthreads limits the number of threads HOOMD will use. The default is all CPU cores in the system.

    • Only the following methods in HOOMD will take advantage of multiple threads:

      • hpmc.update.clusters()

      • HPMC integrators with implicit depletants enabled

      • jit.patch.user_union

Node local parallelism is still under development. It is not enabled in builds by default and only a few methods utilize multiple threads. In future versions, additional methods in HOOMD may support multiple threads.

To ensure future workflow compatibility as future versions enable threading in more components, explicitly set –nthreads=1.

Bug fixes

  • Fixed a problem with periodic boundary conditions and implicit depletants when depletant_mode=circumsphere

  • Fixed a rare segmentation fault with hpmc.integrate.*_union() and hpmc.integrate.polyhedron

  • md.force.active and md.force.dipole now record metadata properly.

  • Fixed a bug where HPMC restore state did not set ignore flags properly.

  • hpmc_boxmc_ln_volume_acceptance is now available for logging.

Other changes

  • Eigen is now provided as a submodule. Plugins that use Eigen headers need to update include paths.

  • HOOMD now builds with pybind 2.2. Minor changes to source and cmake scripts in plugins may be necessary. See the updated example plugin.

  • HOOMD now builds without compiler warnings on modern compilers (gcc6, gcc7, clang5, clang6).

  • HOOMD now uses pybind11 for numpy arrays instead of num_util.

  • HOOMD versions v2.3.x will be the last available on the anaconda channel glotzer.

v2.2.5 (2018-04-20)#

Bug fixes

  • Pin cuda compatible version in conda package to resolve libcu*.so not found errors in conda installations.

v2.2.4 (2018-03-05)#

Bug fixes

  • Fix a rare error in md.nlist.tree when particles are very close to each other.

  • Fix deadlock when `init.read_getar` is given different file names on different ranks.

  • Sample from the correct uniform distribution of depletants in a sphere cap with depletant_mode='overlap_regions' on the CPU

  • Fix a bug where ternary (or higher order) mixtures of small and large particles were not correctly handled with depletant_mode='overlap_regions' on the CPU

  • Improve acceptance rate in depletant simulations with depletant_mode='overlap_regions'

v2.2.3 (2018-01-25)#

Bug fixes

  • Write default values to gsd frames when non-default values are present in frame 0.

  • md.wall.force_shifted_lj now works.

  • Fix a bug in HPMC where run() would not start after restore_state unless shape parameters were also set from python.

  • Fix a bug in HPMC Box MC updater where moves were attempted with zero weight.

  • dump.gsd() now writes hpmc shape state correctly when there are multiple particle types.

  • hpmc.integrate.polyhedron() now produces correct results on the GPU.

  • Fix binary compatibility across python minor versions.

v2.2.2 (2017-12-04)#

Bug fixes

  • md.dihedral.table.set_from_file now works.

  • Fix a critical bug where forces in MPI simulations with rigid bodies or anisotropic particles were incorrectly calculated

  • Ensure that ghost particles are updated after load balancing.

  • meta.dump_metadata no longer reports an error when used with md.constrain.rigid

  • Miscellaneous documentation fixes

  • dump.gsd can now write GSD files with 0 particles in a frame

  • Explicitly report MPI synchronization delays due to load imbalance with profile=True

  • Correctly compute net torque of rigid bodies with anisotropic constituent particles in MPI execution on multiple ranks

  • Fix PotentialPairDPDThermoGPU.h for use in external plugins

  • Use correct ghost region with constrain.rigid in MPI execution on multiple ranks

  • hpmc.update.muvt() now works with depletant_mode='overlap_regions'

  • Fix the sampling of configurations with in hpmc.update.muvt with depletants

  • Fix simulation crash after modifying a snapshot and re-initializing from it

  • The pressure in simulations with rigid bodies (md.constrain.rigid()) and MPI on multiple ranks is now computed correctly

v2.2.1 (2017-10-04)#

Bug fixes

  • Add special pair headers to install target

  • Fix a bug where hpmc.integrate.convex_polyhedron, hpmc.integrate.convex_spheropolyhedron, hpmc.integrate.polyedron, hpmc.integrate.faceted_sphere, hpmc.integrate.sphere_union and hpmc.integrate.convex_polyhedron_union produced spurious overlaps on the GPU

v2.2.0 (2017-09-08)#

New features

  • General:

    • Add hoomd.hdf5.log to log quantities in hdf5 format. Matrix quantities can be logged.

    • dump.gsd can now save internal state to gsd files. Call dump_state(object) to save the state for a particular object. The following objects are supported:

      • HPMC integrators save shape and trial move size state.

    • Add dynamic argument to hoomd.dump.gsd to specify which quantity categories should be written every frame.

    • HOOMD now inter-operates with other python libraries that set the active CUDA device.

    • Add generic capability for bidirectional ghost communication, enabling multi body potentials in MPI simulation.

  • MD:

    • Added support for a 3 body potential that is harmonic in the local density.

    • force.constant and force.active can now apply torques.

    • quiet option to nlist.tune to quiet the output of the embedded run() commands.

    • Add special pairs as exclusions from neighbor lists.

    • Add cosine squared angle potential md.angle.cosinesq.

    • Add md.pair.DLVO() for evaluation of colloidal dispersion and electrostatic forces.

    • Add Lennard-Jones 12-8 pair potential.

    • Add Buckingham (exp-6) pair potential.

    • Add Coulomb 1-4 special_pair potential.

    • Check that composite body dimensions are consistent with minimum image convention and generate an error if they are not.

    • md.integrate.mode.minimize_fire() now supports anisotropic particles (i.e. composite bodies)

    • md.integrate.mode.minimize_fire() now supports flexible specification of integration methods

    • md.integrate.npt()/md.integrate.nph() now accept a friction parameter (gamma) for damping out box fluctuations during minimization runs

    • Add new command integrate.mode_standard.reset_methods() to clear NVT and NPT integrator variables

  • HPMC:

    • hpmc.integrate.sphere_union() takes new capacity parameter to optimize performance for different shape sizes

    • hpmc.integrate.polyhedron() takes new capacity parameter to optimize performance for different shape sizes

    • hpmc.integrate.convex_polyhedron and convex_spheropolyhedron now support arbitrary numbers of vertices, subject only to memory limitations (max_verts is now ignored).

    • HPMC integrators restore state from a gsd file read by init.read_gsd when the option restore_state is True.

    • Deterministic HPMC integration on the GPU (optional): mc.set_params(deterministic=True).

    • New hpmc.update.boxmc.ln_volume() move allows logarithmic volume moves for fast equilibration.

    • New shape: hpmc.integrate.convex_polyhedron_union performs simulations of unions of convex polyhedra.

    • hpmc.field.callback() now enables MC energy evaluation in a python function

    • The option depletant_mode='overlap_regions' for hpmc.integrate.* allows the selection of a new depletion algorithm that restores the diffusivity of dilute colloids in dense depletant baths

Deprecated

  • HPMC: hpmc.integrate.sphere_union() no longer needs the max_members parameter.

  • HPMC: hpmc.integrate.convex_polyhedron and convex_spheropolyhedron no longer needs the max_verts parameter.

  • The static argument to hoomd.dump.gsd should no longer be used. Use dynamic instead.

Bug fixes

  • HPMC:

    • hpmc.integrate.sphere_union() and hpmc.integrate.polyhedron() missed overlaps.

    • Fix alignment error when running implicit depletants on GPU with ntrial > 0.

    • HPMC integrators now behave correctly when the user provides different RNG seeds on different ranks.

    • Fix a bug where overlapping configurations were produced with hpmc.integrate.faceted_sphere()

  • MD:

    • charge.pppm() with order=7 now gives correct results

    • The PPPM energy for particles excluded as part of rigid bodies now correctly takes into account the periodic boundary conditions

  • EAM:

    • metal.pair.eam now produces correct results.

Other changes

  • Optimized performance of HPMC sphere union overlap check and polyhedron shape

  • Improved performance of rigid bodies in MPI simulations

  • Support triclinic boxes with rigid bodies

  • Raise an error when an updater is given a period of 0

  • Revised compilation instructions

  • Misc documentation improvements

  • Fully document constrain.rigid

  • -march=native is no longer set by default (this is now a suggestion in the documentation)

  • Compiler flags now default to CMake defaults

  • ENABLE_CUDA and ENABLE_MPI CMake options default OFF. User must explicitly choose to enable optional dependencies.

  • HOOMD now builds on powerpc+CUDA platforms (tested on summitdev)

  • Improve performance of GPU PPPM force calculation

  • Use sphere tree to further improve performance of hpmc.integrate.sphere_union()

v2.1.9 (2017-08-22)#

Bug fixes

  • Fix a bug where the log quantity momentum was incorrectly reported in MPI simulations.

  • Raise an error when the user provides inconsistent charge or diameter lists to md.constrain.rigid.

  • Fix a bug where pair.compute_energy() did not report correct results in MPI parallel simulations.

  • Fix a bug where make rigid bodies with anisotropic constituent particles did not work on the GPU.

  • Fix hoomd compilation after the rebase in the cub repository.

  • deprecated.dump.xml() now writes correct results when particles have been added or deleted from the simulation.

  • Fix a critical bug where charge.pppm() calculated invalid forces on the GPU

v2.1.8 (2017-07-19)#

Bug fixes

  • `init.read_getar` now correctly restores static quantities when given a particular frame.

  • Fix bug where many short calls to run() caused incorrect results when using md.integrate.langevin.

  • Fix a bug in the Saru pseudo-random number generator that caused some double-precision values to be drawn outside the valid range [0,1) by a small amount. Both floats and doubles are now drawn on [0,1).

  • Fix a bug where coefficients for multi-character unicode type names failed to process in Python 2.

Other changes

  • The Saru generator has been moved into hoomd/Saru.h, and plugins depending on Saru or SaruGPU will need to update their includes. The SaruGPU class has been removed. Use hoomd::detail::Saru instead for both CPU and GPU plugins.

v2.1.7 (2017-05-11)#

Bug fixes

  • Fix PPM exclusion handling on the CPU

  • Handle r_cut for special pairs correctly

  • Fix tauP reference in NPH documentation

  • Fixed constrain.rigid on compute 5.x.

  • Fixed random seg faults when using sqlite getar archives with LZ4 compression

  • Fixed XZ coupling with hoomd.md.integrate.npt integration

  • Fixed aspect ratio with non-cubic boxes in hoomd.hpmc.update.boxmc

v2.1.6 (2017-04-12)#

Bug fixes

  • Document hpmc.util.tune_npt

  • Fix dump.getar.writeJSON usage with MPI execution

  • Fix a bug where integrate.langevin and integrate.brownian correlated RNGs between ranks in multiple CPU execution

  • Bump CUB to version 1.6.4 for improved performance on Pascal architectures. CUB is now embedded using a git submodule. Users upgrading existing git repositories should reinitialize their git submodules with git submodule update --init

  • CMake no longer complains when it finds a partial MKL installation.

v2.1.5 (2017-03-09)#

Bug fixes

  • Fixed a compile error on Mac

v2.1.4 (2017-03-09)#

Bug fixes

  • Fixed a bug re-enabling disabled integration methods

  • Fixed a bug where adding particle types to the system failed for anisotropic pair potentials

  • scipy is no longer required to execute DEM component unit tests

  • Issue a warning when a subsequent call to context.initialize is given different arguments

  • DPD now uses the seed from rank 0 to avoid incorrect simulations when users provide different seeds on different ranks

  • Miscellaneous documentation updates

  • Defer initialization message until context.initialize

  • Fixed a problem where a momentary dip in TPS would cause walltime limited jobs to exit prematurely

  • HPMC and DEM components now correctly print citation notices

v2.1.3 (2017-02-07)#

Bug fixes

  • Fixed a bug where the WalltimeLimitReached was ignored

v2.1.2 (2017-01-11)#

Bug fixes

  • (HPMC) Implicit depletants with spheres and faceted spheres now produces correct ensembles

  • (HPMC) Implicit depletants with ntrial > 0 now produces correct ensembles

  • (HPMC) NPT ensemble in HPMC (hpmc.update.boxmc) now produces correct ensembles

  • Fix a bug where multiple nvt/npt integrators caused warnings from analyze.log.

  • update.balance() is properly ignored when only one rank is available

  • Add missing headers to plugin install build

  • Fix a bug where charge.pppm calculated an incorrect pressure

  • Other changes *

  • Drop support for compute 2.0 GPU devices

  • Support cusolver with CUDA 8.0

v2.1.1 (2016-10-23)#

Bug fixes

  • Fix force.active memory allocation bug

  • Quiet Python.h warnigns when building (python 2.7)

  • Allow multi-character particle types in HPMC (python 2.7)

  • Enable dump.getar.writeJSON in MPI

  • Allow the flow to change directions in md.update.mueller_plathe_flow

  • Fix critical bug in MPI communication when using HPMC integrators

v2.1.0 (2016-10-04)#

New features

  • enable/disable overlap checks between pairs of constituent particles for hpmc.integrate.sphere_union()

  • Support for non-additive mixtures in HPMC, overlap checks can now be enabled/disabled per type-pair

  • Add md.constrain.oned to constrain particles to move in one dimension

  • hpmc.integrate.sphere_union() now takes max_members as an optional argument, allowing to use GPU memory more efficiently

  • Add md.special_pair.lj() to support scaled 1-4 (or other) exclusions in all-atom force fields

  • md.update.mueller_plathe_flow(): Method to create shear flows in MD simulations

  • use_charge option for md.pair.reaction_field

  • md.charge.pppm() takes a Debye screening length as an optional parameter

  • md.charge.pppm() now computes the rigid body correction to the PPPM energy

Deprecated

  • HPMC: the ignore_overlaps flag is replaced by hpmc.integrate.interaction_matrix

Other changes

  • Optimized MPI simulations of mixed systems with rigid and non-rigid bodies

  • Removed dependency on all boost libraries. Boost is no longer needed to build hoomd

  • Intel compiler builds are no longer supported due to c++11 bugs

  • Shorter compile time for HPMC GPU kernels

  • Include symlinked external components in the build process

  • Add template for external components

  • Optimized dense depletant simulations with HPMC on CPU

Bug fixes

  • fix invalid mesh energy in non-neutral systems with md.charge.pppm()

  • Fix invalid forces in simulations with many bond types (on GPU)

  • fix rare cases where analyze.log() would report a wrong pressure

  • fix possible illegal memory access when using md.constrain.rigid() in GPU MPI simulations

  • fix a bug where the potential energy is misreported on the first step with md.constrain.rigid()

  • Fix a bug where the potential energy is misreported in MPI simulations with md.constrain.rigid()

  • Fix a bug where the potential energy is misreported on the first step with md.constrain.rigid()

  • md.charge.pppm() computed invalid forces

  • Fix a bug where PPPM interactions on CPU where not computed correctly

  • Match logged quantitites between MPI and non-MPI runs on first time step

  • Fix md.pair.dpd and md.pair.dpdlj set_params

  • Fix diameter handling in DEM shifted WCA potential

  • Correctly handle particle type names in lattice.unitcell

  • Validate md.group.tag_list is consistent across MPI ranks

v2.0.3 (2016-08-30)#
  • hpmc.util.tune now works with particle types as documented

  • Fix pressure computation with pair.dpd() on the GPU

  • Fix a bug where dump.dcd corrupted files on job restart

  • Fix a bug where HPMC walls did not work correctly with MPI

  • Fix a bug where stdout/stderr did not appear in MPI execution

  • HOOMD will now report an human readable error when users forget context.initialize()

  • Fix syntax errors in frenkel ladd field

v2.0.2 (2016-08-09)#
  • Support CUDA Toolkit 8.0

  • group.rigid()/nonrigid() did not work in MPI simulations

  • Fix builds with ENABLE_DOXYGEN=on

  • Always add -std=c++11 to the compiler command line arguments

  • Fix rare infinite loops when using hpmc.integrate.faceted_sphere

  • Fix hpmc.util.tune to work with more than one tunable

  • Fix a bug where dump.gsd() would write invalid data in simulations with changing number of particles

  • replicate() sometimes did not work when restarting a simulation

v2.0.1 (2016-07-15)#

Bug fixes

  • Fix acceptance criterion in mu-V-T simulations with implicit depletants (HPMC).

  • References to disabled analyzers, computes, updaters, etc. are properly freed from the simulation context.

  • Fix a bug where init.read_gsd ignored the restart argument.

  • Report an error when HPMC kernels run out of memory.

  • Fix ghost layer when using rigid constraints in MPI runs.

  • Clarify definition of the dihedral angle.

v2.0.0 (2016-06-22)#

HOOMD-blue v2.0 is released under a clean BSD 3-clause license.

New packages

  • dem - simulate faceted shapes with dynamics

  • hpmc - hard particle Monte Carlo of a variety of shape classes.

Bug fixes

  • Angles, dihedrals, and impropers no longer initialize with one default type.

  • Fixed a bug where integrate.brownian gave the same x,y, and z velocity components.

  • Data proxies verify input types and vector lengths.

  • dump.dcd no longer generates excessive metadata traffic on lustre file systems

New features

  • Distance constraints constrain.distance - constrain pairs of particles to a fixed separation distance

  • Rigid body constraints constrain.rigid - rigid bodies now have central particles, and support MPI and replication

  • Multi-GPU electrostatics charge.pppm - the long range electrostatic forces are now supported in MPI runs

  • context.initialize() can now be called multiple times - useful in jupyter notebooks

  • Manage multiple simulations in a single job script with SimulationContext as a python context manager.

  • util.quiet_status() / util.unquiet_status() allow users to control if line status messages are output.

  • Support executing hoomd in Jupyter (ipython) notebooks. Notice, warning, and error messages now show up in the notebook output blocks.

  • analyze.log can now register python callback functions as sources for logged quantities.

  • The GSD file format (http://gsd.readthedocs.io) is fully implemented in hoomd

    • dump.gsd writes GSD trajectories and restart files (use truncate=true for restarts).

    • init.read_gsd reads GSD file and initializes the system, and can start the simulation from any frame in the GSD file.

    • data.gsd_snapshot reads a GSD file into a snapshot which can be modified before system initialization with init.read_snapshot.

    • The GSD file format is capable of storing all particle and topology data fields in hoomd, either static at frame 0, or varying over the course of the trajectory. The number of particles, types, bonds, etc. can also vary over the trajectory.

  • force.active applies an active force (optionally with rotational diffusion) to a group of particles

  • update.constrain_ellipsoid constrains particles to an ellipsoid

  • integrate.langevin and integrate.brownian now apply rotational noise and damping to anisotropic particles

  • Support dynamically updating groups. group.force_update() forces the group to rebuild according to the original selection criteria. For example, this can be used to periodically update a cuboid group to include particles only in the specified region.

  • pair.reaction_field implements a pair force for a screened electrostatic interaction of a charge pair in a dielectric medium.

  • force.get_energy allows querying the potential energy of a particle group for a specific force

  • init.create_lattice initializes particles on a lattice.

    • lattice.unitcell provides a generic unit cell definition for create_lattice

    • Convenience functions for common lattices: sq, hex, sc, bcc, fcc.

  • Dump and initialize commands for the GTAR file format (http://libgetar.readthedocs.io).

    • GTAR can store trajectory data in zip, tar, sqlite, or bare directories

    • The current version stores system properties, later versions will be able to capture log, metadata, and other output to reduce the number of files that a job script produces.

  • integrate.npt can now apply a constant stress tensor to the simulation box.

  • Faceted shapes can now be simulated through the dem component.

Changes that require job script modifications

  • context.initialize() is now required before any other hoomd script command.

  • init.reset() no longer exists. Use context.initialize() or activate a SimulationContext.

  • Any scripts that relied on undocumented members of the globals module will fail. These variables have been moved to the context module and members of the currently active SimulationContext.

  • bonds, angles, dihedrals, and impropers no longer use the set_coeff syntax. Use bond_coeff.set, angle_coeff.set, dihedral_coeff.set, and improper_coeff.set instead.

  • hoomd_script no longer exists, python commands are now spread across hoomd, hoomd.md, and other sub packages.

  • integrate.\*_rigid() no longer exists. Use a standard integrator on group.rigid_center(), and define rigid bodies using constrain.rigid()

  • All neighbor lists must be explicitly created using nlist.\*, and each pair potential must be attached explicitly to a neighbor list. A default global neighbor list is no longer created.

  • Moved cgcmm into its own package.

  • Moved eam into the metal package.

  • Integrators now take kT arguments for temperature instead of T to avoid confusion on the units of temperature.

  • phase defaults to 0 for updaters and analyzers so that restartable jobs are more easily enabled by default.

  • dump.xml (deprecated) requires a particle group, and can dump subsets of particles.

Other changes

  • CMake minimum version is now 2.8

  • Convert particle type names to str to allow unicode type name input

  • __version__ is now available in the top level package

  • boost::iostreams is no longer a build dependency

  • boost::filesystem is no longer a build dependency

  • New concepts page explaining the different styles of neighbor lists

  • Default neighbor list buffer radius is more clearly shown to be r_buff = 0.4

  • Memory usage of nlist.stencil is significantly reduced

  • A C++11 compliant compiler is now required to build HOOMD-blue

Removed

  • Removed integrate.bdnvt: use integrate.langevin

  • Removed mtk=False option from integrate.nvt - The MTK NVT integrator is now the only implementation.

  • Removed integrate.\*_rigid(): rigid body functionality is now contained in the standard integration methods

  • Removed the global neighbor list, and thin wrappers to the neighbor list in nlist.

  • Removed PDB and MOL2 dump writers.

  • Removed init.create_empty

Deprecated

  • Deprecated analyze.msd.

  • Deprecated dump.xml.

  • Deprecated dump.pos.

  • Deprecated init.read_xml.

  • Deprecated init.create_random.

  • Deprecated init.create_random_polymers.

v1.x#
v1.3.3 (2016-03-06)#

Bug fixes

  • Fix problem incluing hoomd.h in plugins

  • Fix random memory errors when using walls

v1.3.2 (2016-02-08)#

Bug fixes

  • Fix wrong access to system.box

  • Fix kinetic energy logging in MPI

  • Fix particle out of box error if particles are initialized on the boundary in MPI

  • Add integrate.brownian to the documentation index

  • Fix misc doc typos

  • Fix runtime errors with boost 1.60.0

  • Fix corrupt metadata dumps in MPI runs

v1.3.1 (2016-1-14)#

Bug fixes

  • Fix invalid MPI communicator error with Intel MPI

  • Fix python 3.5.1 seg fault

v1.3.0 (2015-12-8)#

New features

  • Automatically load balanced domain decomposition simulations.

  • Anisotropic particle integrators.

  • Gay-Berne pair potential.

  • Dipole pair potential.

  • Brownian dynamics integrate.brownian

  • Langevin dynamics integrate.langevin (formerly bdnvt)

  • nlist.stencil to compute neighbor lists using stencilled cell lists.

  • Add single value scale, min_image, and make_fraction to data.boxdim

  • analyze.log can optionally not write a file and now supports querying current quantity values.

  • Rewritten wall potentials.

    • Walls are now sums of planar, cylindrical, and spherical half-spaces.

    • Walls are defined and can be modified in job scripts.

    • Walls execute on the GPU.

    • Walls support per type interaction parameters.

    • Implemented for: lj, gauss, slj, yukawa, morse, force_shifted_lj, and mie potentials.

  • External electric field potential: external.e_field

Bug fixes

  • Fixed a bug where NVT integration hung when there were 0 particles in some domains.

  • Check SLURM environment variables for local MPI rank identification

  • Fixed a typo in the box math documentation

  • Fixed a bug where exceptions weren’t properly passed up to the user script

  • Fixed a bug in the velocity initialization example

  • Fixed an openmpi fork() warning on some systems

  • Fixed segfaults in PPPM

  • Fixed a bug where compute.thermo failed after reinitializing a system

  • Support list and dict-like objects in init.create_random_polymers.

  • Fall back to global rank to assign GPUs if local rank is not available

Deprecated commands

  • integrate.bdnvt is deprecated. Use integrate.langevin instead.

  • dump.bin and init.bin are now removed. Use XML files for restartable jobs.

Changes that may break existing scripts

  • boxdim.wrap now returns the position and image in a tuple, where it used to return just the position.

  • wall.lj has a new API

  • dump.bin and init.bin have been removed.

v1.2.1 (2015-10-22)#

Bug fixes

  • Fix a crash when adding or removing particles and reinitializing

  • Fix a bug where simulations hung on sm 5.x GPUs with CUDA 7.5

  • Fix compile error with long tests enabled

  • Issue a warning instead of an error for memory allocations greater than 4 GiB.

  • Fix invalid RPATH when building inside zsh.

  • Fix incorrect simulations with integrate.npt_rigid

  • Label mie potential correctly in user documentation

v1.2.0 (2015-09-30)#

New features

  • Performance improvements for systems with large particle size disparity

  • Bounding volume hierarchy (tree) neighbor list computation

  • Neighbor lists have separate r_cut values for each pair of types

  • addInfo callback for dump.pos allows user specified information in pos files

Bug fixes

  • Fix test_pair_set_energy unit test, which failed on numpy < 1.9.0

  • Analyze.log now accepts unicode strings.

  • Fixed a bug where calling restore_snapshot() during a run zeroed potential parameters.

  • Fix segfault on exit with python 3.4

  • Add cite.save() to documentation

  • Fix a problem were bond forces are computed incorrectly in some MPI configurations

  • Fix bug in pair.zbl

  • Add pair.zbl to the documentation

  • Use HOOMD_PYTHON_LIBRARY to avoid problems with modified CMake builds that preset PYTHON_LIBRARY

v1.1.1 (2015-07-21)#

Bug fixes

  • dump.xml(restart=True) now works with MPI execution

  • Added missing documentation for meta.dump_metadata

  • Build all unit tests by default

  • Run all script unit tests through mpirun -n 1

v1.1.0 (2015-07-14)#

New features

  • Allow builds with ninja.

  • Allow K=0 FENE bonds.

  • Allow number of particles types to change after initialization.

    system.particles.types.add('newtype')
    
  • Allow number of particles to change after initialization.

    system.particles.add(‘A’)
    del system.particles[0]
    
  • OPLS dihedral

  • Add phase keyword to analyzers and dumps to make restartable jobs easier.

  • HOOMD_WALLTIME_STOP environment variable to stop simulation runs before they hit a wall clock limit.

  • init.read_xml() Now accepts an initialization and restart file.

  • dump.xml() can now write restart files.

  • Added documentation concepts page on writing restartable jobs.

  • New citation management infrastructure. cite.save() writes .bib files with a list of references to features actively used in the current job script.

  • Snapshots expose data as numpy arrays for high performance access to particle properties.

  • data.make_snapshot() makes a new empty snapshot.

  • analyze.callback() allows multiple python callbacks to operate at different periods.

  • comm.barrier()``and comm.barrier_all()``allow users to insert barriers into their scripts.

  • Mie pair potential.

  • meta.dump_metadata() writes job metadata information out to a json file.

  • context.initialize() initializes the execution context.

  • Restart option for dump.xml()

Bug fixes

  • Fix slow performance when initializing pair.slj()in MPI runs.

  • Properly update particle image when setting position from python.

  • PYTHON_SITEDIR hoomd shell launcher now calls the python interpreter used at build time.

  • Fix compile error on older gcc versions.

  • Fix a bug where rigid bodies had 0 velocity when restarting jobs.

  • Enable -march=native builds in OS X clang builds.

  • Fix group.rigid() and group.nonrigid().

  • Fix image access from the python data access proxies.

  • Gracefully exit when launching MPI jobs with mixed execution configurations.

Changes that may require updated job scripts

  • context.initialize() must be called before any comm method that queries the MPI rank. Call it as early as possible in your job script (right after importing hoomd_script) to avoid problems.

Deprecated

  • init.create_empty() is deprecated and will be removed in a future version. Use data.make_snapshot() and init.read_snapshot() instead.

  • Job scripts that do not call context.initialize() will result in a warning message. A future version of HOOMD will require that you call context.initialize().

Removed

  • Several option commands for controlling the execution configuration. Replaced with context.initialize.

v1.0.5 (2015-05-19)#

Bug fixes

  • Fix segfault when changing integrators

  • Fix system.box to indicate the correct number of dimensions

  • Fix syntax error in comm.get_rank with –nrank

  • Enable CUDA enabled builds with the intel compiler

  • Use CMake builtin FindCUDA on recent versions of CMake

  • GCC_ARCH env var sets the -march command line option to gcc at configure time

  • Auto-assign GPU-ids on non-compute exclusive systems even with –mode=gpu

  • Support python 3.5 alpha

  • Fix a bug where particle types were doubled with boost 1.58.0

  • Fix a bug where angle_z=true dcd output was inaccurate near 0 angles

  • Properly handle lj.wall potentials with epsilon=0.0 and particles on top of the walls

v1.0.4 (2015-04-07)#

Bug fixes

  • Fix invalid virials computed in rigid body simulations when multi-particle bodies crossed box boundaries

  • Fix invalid forces/torques for rigid body simulations caused by race conditions

  • Fix compile errors on Mac OS X 10.10

  • Fix invalid pair force computations caused by race conditions

  • Fix invalid neighbour list computations caused by race conditions on Fermi generation GPUs

Other

  • Extremely long running unit tests are now off by default. Enable with -DHOOMD_SKIP_LONG_TESTS=OFF

  • Add additional tests to detect race conditions and memory errors in kernels

v1.0.3 (2015-03-18)#

Bug fixes

  • Enable builds with intel MPI

  • Silence warnings coming from boost and python headers

v1.0.2 (2015-01-21)#

Bug fixes

  • Fixed a bug where linear_interp would not take a floating point value for zero

  • Provide more useful error messages when cuda drivers are not present

  • Assume device count is 0 when cudaGetDeviceCount() returns an error

  • Link to python statically when ENABLE_STATIC=on

  • Misc documentation updates

v1.0.1 (2014-09-09)#

Bug fixes

  1. Fixed bug where error messages were truncated and HOOMD exited with a segmentation fault instead (e.g. on Blue Waters)

  2. Fixed bug where plug-ins did not load on Blue Waters

  3. Fixed compile error with gcc4.4 and cuda5.0

  4. Fixed syntax error in read_snapshot()

  5. Fixed a bug where init.read_xml throwing an error (or any other command outside of run()) would hang in MPI runs

  6. Search the install path for hoomd_script - enable the hoomd executable to be outside of the install tree (useful with cray aprun)

  7. Fixed CMake 3.0 warnings

  8. Removed dependancy on tr1/random

  9. Fixed a bug where analyze.msd ignored images in the r0_file

  10. Fixed typos in pair.gauss documentation

  11. Fixed compile errors on Ubuntu 12.10

  12. Fix failure of integrate.nvt to reach target temperature in analyze.log. The fix is a new symplectic MTK integrate.nvt integrator. Simulation results in hoomd v1.0.0 are correct, just the temperature and velocity outputs are off slightly.

  13. Remove MPI from Mac OS X dmg build.

  14. Enable import hoomd_script as ...

Other changes

  1. Added default compile flag -march=native

  2. Support CUDA 6.5

  3. Binary builds for CentOS/RHEL 6, Fedora 20, Ubuntu 14.04 LTS, and Ubuntu 12.04 LTS.

Version 1.0.0 (2014-05-25)#

New features

  • Support for python 3

  • New NPT integrator capable of flexible coupling schemes

  • Triclinic unit cell support

  • MPI domain decomposition

  • Snapshot save/restore

  • Autotune block sizes at run time

  • Improve performance in small simulation boxes

  • Improve performance with smaller numbers of particles per GPU

  • Full double precision computations on the GPU (compile time option must be enabled, binary builds provided on the download page are single precision)

  • Tabulated bond potential bond.table

  • Tabulated angle potential angle.table

  • Tabulated dihedral potental dihedral.table

  • update.box_resize now accepts period=None to trigger an immediate update of the box without creating a periodic updater

  • update.box_resize now replaces None arguments with the current box parameters

  • init.create_random and init.create_random_polymers can now create random configurations in triclinc and 2D boxes

  • init.create_empty can now create triclinic boxes

  • particle, bond, angle, dihedral, and impropers types can now be named in init.create_empty

  • system.replicate command replicates the simulation box

Bug fixes

  • Fixed a bug where init.create_random_polymers failed when lx,ly,lz were not equal.

  • Fixed a bug in init.create_random_polymers and init.create_random where the separation radius was not accounted for correctly

  • Fixed a bug in bond.* where random crashes would occur when more than one bond type was defined

  • Fixed a bug where dump.dcd did not write the period to the file

Changes that may require updated job scripts

  • integrate.nph: A time scale tau_p for the relaxation of the barostat is now required instead of the barostat mass W of the previous release. The time scale is the relaxation time the barostat would have at an average temperature T_0 = 1, and it is related to the internally used (Andersen) Barostat mass W via W = d N T_0 tau_p^2, where d is the dimensionsality and N the number of particles.

  • sorter and nlist are now modules, not variables in the __main__ namespace.

  • Data proxies function correctly in MPI simulations, but are extremely slow. If you use init.create_empty, consider separating the generation step out to a single rank short execution that writes an XML file for the main run.

  • update.box_resize(Lx=...) no longer makes cubic box updates, instead it will keep the current Ly and Lz. Use the L=... shorthand for cubic box updates.

  • All init.* commands now take data.boxdim objects, instead of hoomd.boxdim (or 3-tuples). We strongly encourage the use of explicit argument names for data.boxdim(). In particular, if hoomd.boxdim(123) was previously used to create a cubic box, it is now required to use data.boxdim(L=123) (CORRECT) instead of data.boxdim(123) (INCORRECT), otherwise a box with unit dimensions along the y and z axes will be created.

  • system.dimensions can no longer be set after initialization. System dimensions are now set during initialization via the data.boxdim interface. The dimensionality of the system can now be queried through system.box.

  • system.box no longer accepts 3-tuples. It takes data.boxdim objects.

  • system.dimensions no longer exists. Query the dimensionality of the system from system.box. Set the dimensionality of the system by passing an appropriate data.boxdim to an init method.

  • init.create_empty no longer accepts n_*_types. Instead, it now takes a list of strings to name the types.

Deprecated

  • Support for G80, G200 GPUs.

  • dump.bin and read.bin. These will be removed in v1.1 and replaced with a new binary format.

Removed

  • OpenMP mult-core execution (replaced with MPI domain decomposition)

  • tune.find_optimal_block_size (replaced by Autotuner)

v0.x#
Version 0.11.3 (2013-05-10)#

Bug fixes

  • Fixed a bug where charge.pppm could not be used after init.reset()

  • Data proxies can now set body angular momentum before the first run()

  • Fixed a bug where PPPM forces were incorrect on the GPU

Version 0.11.2 (2012-12-19)#

New features

  • Block sizes tuned for K20

Bug fixes

  • Warn user that PPPM ignores rigid body exclusions

  • Document that proxy iterators need to be deleted before init.reset()

  • Fixed a bug where body angular momentum could not be set

  • Fixed a bug where analyze.log would report nan for the pressure tensor in nve and nvt simulations

Version 0.11.1 (2012-11-2)#

New features

  • Support for CUDA 5.0

  • Binary builds for Fedora 16 and OpenSUSE 12.1

  • Automatically specify /usr/bin/gcc to nvcc when the configured gcc is not supported

Bug fixes

  • Fixed a compile error with gcc 4.7

  • Fixed a bug where PPPM forces were incorrect with neighborlist exclusions

  • Fixed an issue where boost 1.50 and newer were not detected properly when BOOST_ROOT is set

  • Fixed a bug where accessing force data in python prevented init.reset() from working

  • Fixed a bug that prevented pair.external from logging energy

  • Fixed a unit test that failed randomly

Version 0.11.0 (2012-07-27)#

New features

  1. Support for Kepler GPUs (GTX 680)

  2. NPH integration (integrate.nph)

  3. Compute full pressure tensor

  4. Example plugin for new bond potentials

  5. New syntax for bond coefficients: bond.bond_coeff.set(‘type’, params)

  6. New external potential: external.periodic applies a periodic potential along one direction (uses include inducing lamellar phases in copolymer systems)

  7. Significant performance increases when running analyze.log, analyze.msd, update.box_resize, update.rescale_temp, or update.zero_momentum with a small period

  8. Command line options may now be overwritten by scripts, ex: options.set_gpu(2)

  9. Added –user command line option to allow user defined options to be passed into job scripts, ex: –user=“-N=5 -phi=0.56”

  10. Added table.set_from_file method to enable reading table based pair potentials from a file

  11. Added –notice-level command line option to control how much extra information is printed during a run. Set to 0 to disable, or any value up to 10. At 10, verbose debugging information is printed.

  12. Added –msg-file command line option which redirects the message output to a file

  13. New pair potential pair.force_shifted_lj : Implements http://dx.doi.org/10.1063/1.3558787

Bug fixes

  1. Fixed a bug where FENE bonds were sometimes computed incorrectly

  2. Fixed a bug where pressure was computed incorrectly when using pair.dpd or pair.dpdlj

  3. Fixed a bug where using OpenMP and CUDA at the same time caused invalid memory accesses

  4. Fixed a bug where RPM packages did not work on systems where the CUDA toolkit was not installed

  5. Fixed a bug where rigid body velocities were not set from python

  6. Disabled OpenMP builds on Mac OS X. HOOMD-blue w/ openmp enabled crashes due to bugs in Apple’s OpenMP implementation.

  7. Fixed a bug that allowed users to provide invalid rigid body data and cause a seg fault.

  8. Fixed a bug where using PPPM resulted in error messages on program exit.

API changes

  1. Bond potentials rewritten with template evaluators

  2. External potentials use template evaluators

  3. Complete rewrite of ParticleData - may break existing plugins

  4. Bond/Angle/Dihedral data structures rewritten

    • The GPU specific data structures are now generated on the GPU

  5. DPDThermo and DPDLJThermo are now processed by the same template class

  6. Headers that cannot be included by nvcc now throw an error when they are

  7. CUDA 4.0 is the new minimum requirement

  8. Rewrote BoxDim to internally handle minimum image conventions

  9. HOOMD now only compiles ptx code for the newest architecture, this halves the executable file size

  10. New Messenger class for global control of messages printed to the screen / directed to a file.

Testing changes

  1. Automated test suite now performs tests on OpenMPI + CUDA builds

  2. Valgrind tests added back into automated test suite

  3. Added CPU test in bd_ridid_updater_tests

  4. ctest -S scripts can now set parallel makes (with cmake > 2.8.2)

Version 0.10.1 (2012-02-10)#
  1. Add missing entries to credits page

  2. Add dist_check option to neighbor list. Can be used to force neighbor list builds at a specified frequency (useful in profiling runs with nvvp).

  3. Fix typos in ubuntu compile documentation

  4. Add missing header files to hoomd.h

  5. Add torque to the python particle data access API

  6. Support boost::filesystem API v3

  7. Expose name of executing gpu, n_cpu, hoomd version, git sha1, cuda version, and compiler version to python

  8. Fix a bug where multiple nvt_rigid or npt_rigid integrators didn’t work correctly

  9. Fix missing pages in developer documentation

Version 0.10.0 (2011-12-14)#

New features

  1. Added pair.dpdlj which uses the DPD thermostat and the Lennard-Jones potential. In previous versions, this could be accomplished by using two pair commands but at the cost of reduced performance.

  2. Additional example scripts are now present in the documentation. The example scripts are cross-linked to the commands that are used in them.

  3. Most dump commands now accept the form: dump.ext(filename=“filename.ext”) which immediately writes out filename.ext.

  4. Added vis parameter to dump.xml which enables output options commonly used in files written for the purposes of visulization. dump.xml also now accepts parameters on the instantiation line. Combined with the previous feature, dump.xml(filename=“file.xml”, vis=True) is now a convenient short hand for what was previously

    xml = dump.xml()
    xml.set_params(position = True, mass = True, diameter = True,
                          type = True, bond = True, angle = True,
                          dihedral = True, improper = True, charge = True)
    xml.write(filename="file.xml")
    
  5. Specify rigid bodies in XML input files

  6. Simulations that contain rigid body constraints applied to groups of particles in BDNVT, NVE, NVT, and NPT ensembles.

    • integrate.bdnvt_rigid

    • integrate.nve_rigid

    • integrate.nvt_rigid

    • integrate.npt_rigid

  7. Energy minimization of rigid bodies (integrate.mode_minimize_rigid_fire)

  8. Existing commands are now rigid-body aware

    • update.rescale_temp

    • update.box_resize

    • update.enforce2d

    • update.zero_momentum

  9. NVT integration using the Berendsen thermostat (integrate.berendsen)

  10. Bonds, angles, dihedrals, and impropers can now be created and deleted with the python data access API.

  11. Attribution clauses added to the HOOMD-blue license.

Changes that may break existing job scripts

  1. The wrap option to dump.dcd has been changed to unwrap_full and its meaning inverted. dump.dcd now offers two options for unwrapping particles, unwrap_full fully unwraps particles into their box image and unwrap_rigid unwraps particles in rigid bodies so that bodies are not broken up across a box boundary.

Bug/fixes small enhancements

  1. Fixed a bug where launching hoomd on mac os X 10.5 always resulted in a bus error.

  2. Fixed a bug where DCD output restricted to a group saved incorrect data.

  3. force.constant may now be applied to a group of particles, not just all particles

  4. Added C++ plugin example that demonstrates how to add a pair potential in a plugin

  5. Fixed a bug where box.resize would always transfer particle data even in a flat portion of the variant

  6. OpenMP builds re-enabled on Mac OS X

  7. Initial state of integrate.nvt and integrate.npt changed to decrease oscillations at startup.

  8. Fixed a bug where the polymer generator would fail to initialize very long polymers

  9. Fixed a bug where images were passed to python as unsigned ints.

  10. Fixed a bug where dump.pdb wrote coordinates in the wrong order.

  11. Fixed a rare problem where a file written by dump.xml would not be read by init.read_xml due to round-off errors.

  12. Increased the number of significant digits written out to dump.xml to make them more useful for ad-hoc restart files.

  13. Potential energy and pressure computations that slow performance are now only performed on those steps where the values are actually needed.

  14. Fixed a typo in the example C++ plugin

  15. Mac build instructions updated to work with the latest version of macports

  16. Fixed a bug where set_period on any dump was ineffective.

  17. print_status_line now handles multiple lines

  18. Fixed a bug where using bdnvt tally with per type gammas resulted in a race condition.

  19. Fix an issue where ENABLE_CUDA=off builds gave nonsense errors when –mode=gpu was requested.

  20. Fixed a bug where dumpl.xml could produce files that init.xml would not read

  21. Fixed a typo in the example plugin

  22. Fix example that uses hoomd as a library so that it compiles.

  23. Update maintainer lines

  24. Added message to nlist exclusions that notifies if diameter or body exclusions are set.

  25. HOOMD-blue is now hosted in a git repository

  26. Added bibtex bibliography to the user documentation

  27. Converted user documentation examples to use doxygen auto cross-referencing \example commands

  28. Fix a bug where particle data is not released in dump.binary

  29. ENABLE_OPENMP can now be set in the ctest builds

  30. Tuned block sizes for CUDA 4.0

  31. Removed unsupported GPUS from CUDA_ARCH_LIST

Version 0.9.2 (2011-04-04)#

Note: only major changes are listed here.

New features

  1. New exclusion option: Particles can now be excluded from the neighbor list based on diameter consistent with pair.slj.

  2. New pair coeff syntax: Coefficients for multiple type pairs can be specified conveniently on a single line.

    coeff.set(['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], epsilon=1.0)
    
  3. New documentation: HOOMD-blue’s system of units is now fully documented, and every coefficient in the documentation is labeled with the appropriate unit.

  4. Performance improvements: Performance has been significantly boosted for simulations of medium sized systems (5,000-20,000 particles). Smaller performance boosts were made to larger runs.

  5. CUDA 3.2 support: HOOMD-blue is now fully tested and performance tuned for use with CUDA 3.2.

  6. CUDA 4.0 support: HOOMD-blue compiles with CUDA 4.0 and passes initial tests.

  7. New command: tune.r_buff performs detailed auto-tuning of the r_buff neighborlist parameter.

  8. New installation method: RPM, DEB, and app bundle packages are now built for easier installation

  9. New command: charge.pppm computes the full long range electrostatic interaction using the PPPM method

Bug/fixes small enhancements

  1. Fixed a bug where the python library was linked statically.

  2. Added the PYTHON_SITEDIR setting to allow hoomd builds to install into the native python site directory.

  3. FIRE energy minimization convergence criteria changed to require both energy and force to converge

  4. Clarified that groups are static in the documentation

  5. Updated doc comments for compatibility with Doxygen#7.3

  6. system.particles.types now lists the particle types in the simulation

  7. Creating a group of a non-existant type is no longer an error

  8. Mention XML file format for walls in wall.lj documentation

  9. Analyzers now profile themselves

  10. Use \n for newlines in dump.xml - improves performance when writing many XML files on a NFS file system

  11. Fixed a bug where the neighbor list build could take an exceptionally long time (several seconds) to complete the first build.

  12. Fixed a bug where certain logged quantities always reported as 0 on the first step of the simulation.

  13. system.box can now be used to read and set the simulation box size from python

  14. Numerous internal API updates

  15. Fixed a bug the resulted in incorrect behavior when using integrate.npt on the GPU.

  16. Removed hoomd launcher shell script. In non-sitedir installs, ${HOOMD_ROOT}/bin/hoomd is now the executable itself

  17. Creating unions of groups of non-existent types no longer produces a seg fault

  18. hoomd now builds on all cuda architectures. Modify CUDA_ARCH_LIST in cmake to add or remove architectures from the build

  19. hoomd now builds with boost#46.0

  20. Updated hoomd icons to maize/blue color scheme

  21. hoomd xml file format bumped to#3, adds support for charge.

  22. FENE and harmonic bonds now handle 0 interaction parameters and 0 length bonds more gracefully

  23. The packaged plugin template now actually builds and installs into a recent build of hoomd

Version 0.9.1 (2010-10-08)#

Note: only major changes are listed here.

New features

  1. New constraint: constrain.sphere constrains a group of particles to the surface of a sphere

  2. New pair potential/thermostat: pair.dpd implements the standard DPD conservative, random, and dissipative forces

  3. New pair potential: pair.dpd_conservative applies just the conservative DPD potential

  4. New pair potential: pair.eam implements the Embedded Atom Method (EAM) and supports both alloy and FS type computations.

  5. Faster performance: Cell list and neighbor list code has been rewritten for performance.

    • In our benchmarks, performance increases ranged from 10-50% over HOOMD-blue 0.9.0. Simulations with shorter cutoffs tend to attain a higher performance boost than those with longer cutoffs.

    • We recommended that you re-tune r_buff values for optimal performance with 0.9.1.

    • Due to the nature of the changes, identical runs may produce different trajectories.

  6. Removed limitation: The limit on the number of neighbor list exclusions per particle has been removed. Any number of exclusions can now be added per particle. Expect reduced performance when adding excessive numbers of exclusions.

Bug/fixes small enhancements

  1. Pressure computation is now correct when constraints are applied.

  2. Removed missing files from hoomd.h

  3. pair.yukawa is no longer referred to by “gaussian” in the documentation

  4. Fermi GPUs are now prioritized over per-Fermi GPUs in systems where both are present

  5. HOOMD now compiles against CUDA 3.1

  6. Momentum conservation significantly improved on compute#x hardware

  7. hoomd plugins can now be installed into user specified directories

  8. Setting r_buff=0 no longer triggers exclusion list updates on every step

  9. CUDA 2.2 and older are no longer supported

  10. Workaround for compiler bug in 3.1 that produces extremely high register usage

  11. Disabled OpenMP compile checks on Mac OS X

  12. Support for compute 2.1 devices (such as the GTX 460)

Version 0.9.0 (2010-05-18)#

Note: only major changes are listed here.

New features

  1. New pair potential: Shifted LJ potential for particles of varying diameters (pair.slj)

  2. New pair potential: Tabulated pair potential (pair.table)

  3. New pair potential: Yukawa potential (pair.yukawa)

  4. Update to pair potentials: Most pair potentials can now accept different values of r_cut for different type pairs. The r_cut specified in the initial pair.*** command is now treated as the default r_cut, so no changes to scripts are necessary.

  5. Update to pair potentials: Default pair coeff values are now supported. The parameter alpha for lj now defaults to#0, so there is no longer a need to specify it for a majority of simulations.

  6. Update to pair potentials: The maximum r_cut needed for the neighbor list is now determined at the start of each run(). In simulations where r_cut may decrease over time, increased performance will result.

  7. Update to pair potentials: Pair potentials are now specified via template evaluator classes. Adding a new pair potential to hoomd now only requires a small amount of additional code.

  8. Plugin API : Advanced users/developers can now write, install, and use plugins for hoomd without needing to modify core hoomd source code

  9. Particle data access: User-level hoomd scripts can now directly access the particle data. For example, one can change all particles in the top half of the box to be type B:

    top = group.cuboid(name="top", zmin=0)
    for p in top:
        p.type = 'B'
    

    . All particle data including position, velocity, type, ‘’et cetera’’, can be read and written in this manner. Computed forces and energies can also be accessed in a similar way.

  10. New script command: init.create_empty() can be used in conjunction with the particle data access above to completely initialize a system within the hoomd script.

  11. New script command: dump.bin() writes full binary restart files with the entire system state, including the internal state of integrators.

    • File output can be gzip compressed (if zlib is available) to save space

    • Output can alternate between two different output files for safe crash recovery

  12. New script command: init.read_bin() reads restart files written by dump.bin()

  13. New option: run() now accepts a quiet option. When True, it eliminates the status information printouts that go to stdout.

  14. New example script: Example 6 demonstrates the use of the particle data access routines to initialize a system. It also demonstrates how to initialize velocities from a gaussian distribution

  15. New example script: Example 7 plots the pair.lj potential energy and force as evaluated by hoomd. It can trivially be modified to plot any potential in hoomd.

  16. New feature: Two dimensional simulations can now be run in hoomd: #259

  17. New pair potential: Morse potential for particles of varying diameters (pair.morse)

  18. New command: run_upto will run a simulation up to a given time step number (handy for breaking long simulations up into many independent jobs)

  19. New feature: HOOMD on the CPU is now accelerated with OpenMP.

  20. New feature: integrate.mode_minimize_fire performs energy minimization using the FIRE algorithm

  21. New feature: analyze.msd can now accept an xml file specifying the initial particle positions (for restarting jobs)

  22. Improved feature: analyze.imd now supports all IMD commands that VMD sends (pause, kill, change trate, etc.)

  23. New feature: Pair potentials can now be given names, allowing multiple potentials of the same type to be logged separately. Additionally, potentials that are disabled and not applied to the system dynamics can be optionally logged.

  24. Performance improvements: Simulation performance has been increased across the board, but especially when running systems with very low particle number densities.

  25. New hardware support: 0.9.0 and newer support Fermi GPUs

  26. Deprecated hardware support: 0.9.x might continue run on compute#1 GPUs but that hardware is no longer officially supported

  27. New script command: group.tag_list() takes a python list of particle tags and creates a group

  28. New script command: compute.thermo() computes thermodynamic properties of a group of particles for logging

  29. New feature: dump.dcd can now optionally write out only those particles that belong to a specified group

Changes that will break jobs scripts written for 0.8.x

  1. Integration routines have changed significantly to enable new use cases. Where scripts previously had commands like:

    integrate.nve(dt=0.005)
    

    they now need

    all = group.all()
    integrate.mode_standard(dt=0.005)
    integrate.nve(group=all)
    

    . Integrating only specific groups of particles enables simulations to fix certain particles in place or integrate different parts of the system at different temperatures, among many other possibilities.

  2. sorter.set_params no longer takes the ‘’bin_width’’ argument. It is replaced by a new ‘’grid’’ argument, see the documentation for details.

  3. conserved_quantity is no longer a quantity available for logging. Instead log the nvt reservoir energy and compute the total conserved quantity in post processing.

Bug/fixes small enhancements

  1. Fixed a bug where boost#38 is not found on some machines

  2. dump.xml now has an option to write particle accelerations

  3. Fixed a bug where periods like 1e6 were not accepted by updaters

  4. Fixed a bug where bond.fene forces were calculated incorrectly between particles of differing diameters

  5. Fixed a bug where bond.fene energies were computed incorrectly when running on the GPU

  6. Fixed a bug where comments in hoomd xml files were not ignored as they aught to be: #331

  7. It is now possible to prevent bond exclusions from ever being added to the neighbor list: #338

  8. init.create_random_polymers can now generate extremely dense systems and will warn the user about large memory usage

  9. variant.linear_interp now accepts a user-defined zero (handy for breaking long simulations up into many independent jobs)

  10. Improved installation and compilation documentation

  11. Integration methods now silently ignore when they are given an empty group

  12. Fixed a bug where disabling all forces resulted in some forces still being applied

  13. Integrators now behave in a reasonable way when given empty groups

  14. Analyzers now accept a floating point period

  15. run() now aborts immediately if limit_hours=0 is specified.

  16. Pair potentials that diverge at r=0 will no longer result in invalid simulations when the leading coefficients are set to zero.

  17. integrate.bdnvt can now tally the energy transferred into/out of the “reservoir”, allowing energy conservation to be monitored during bd simulation runs.

  18. Most potentials now prevent NaN results when computed for overlapping particles

  19. Stopping a simulation from a callback or time limit no longer produces invalid simulations when continued

  20. run() commands limited with limit_hours can now be set to only stop on given timestep multiples

  21. Worked around a compiler bug where pair.morse would crash on Fermi GPUs

  22. ULF stability improvements for G200 GPUs.

Version 0.8.2 (2009-09-10)#

Note: only major changes are listed here.

New features

  1. Quantities that vary over time can now be specified easily in scripts with the variant.linear_interp command.

  2. Box resizing updater (update.box_resize) command that uses the time varying quantity command to grow or shrink the simulation box.

  3. Individual run() commands can be limited by wall-clock time

  4. Angle forces can now be specified

  5. Dihedral forces can now be specified

  6. Improper forces can now be specified

  7. 1-3 and 1-4 exclusions from the cutoff pair force can now be chosen

  8. New command line option: –minimize-cpu-usage cuts the CPU usage of HOOMD down to 10% of one CPU core while only decreasing overall performance by 10%

  9. Major changes have been made in the way HOOMD chooses the device on which to run (all require CUDA 2.2 or newer)

    • there are now checks that an appropriate NVIDIA drivers is installed

    • running without any command line options will now correctly revert to running on the CPU if no capable GPUs are installed

    • when no gpu is explicitly specified, the default choice is now prioritized to choose the fastest GPU and one that is not attached to a display first

    • new command line option: –ignore-display-gpu will prevent HOOMD from executing on any GPU attached to a display

    • HOOMD now prints out a short description of the GPU(s) it is running on

    • on linux, devices can be set to compute-exclusive mode and HOOMD will then automatically choose the first free GPU (see the documentation for details)

  10. nlist.reset_exclusions command to control the particles that are excluded from the neighbor list

Bug/fixes small enhancements

  1. Default block size change to improve stability on compute#3 devices

  2. ULF workaround on GTX 280 now works with CUDA 2.2

  3. Standalone benchmark executables have been removed and replaced by in script benchmarking commands

  4. Block size tuning runs can now be performed automatically using the python API and results can be saved on the local machine

  5. Fixed a bug where GTX 280 bug workarounds were not properly applied in CUDA 2.2

  6. The time step read in from the XML file can now be optionally overwritten with a user-chosen one

  7. Added support for CUDA 2.2

  8. Fixed a bug where the WCA forces included in bond.fene had an improper cutoff

  9. Added support for a python callback to be executed periodically during a run()

  10. Removed demos from the hoomd downloads. These will be offered separately on the webpage now to keep the required download size small.

  11. documentation improvements

  12. Significantly increased performance of dual-GPU runs when build with CUDA 2.2 or newer

  13. Numerous stability and performance improvements

  14. Temperatures are now calculated based on 3N-3 degrees of freedom. See #283 for a more flexible system that is coming in the future.

  15. Emulation mode builds now work on systems without an NVIDIA card (CUDA 2.2 or newer)

  16. HOOMD now compiles with CUDA 2.3

  17. Fixed a bug where uninitialized memory was written to dcd files

  18. Fixed a bug that prevented the neighbor list on the CPU from working properly with non-cubic boxes

  19. There is now a compile time hack to allow for more than 4 exclusions per particle

  20. Documentation added to aid users in migrating from LAMMPS

  21. hoomd_script now has an internal version number useful for third party scripts interfacing with it

  22. VMD#8.7 is now found by the live demo scripts

  23. live demos now run in vista 64-bit

  24. init.create_random_polymers can now create polymers with more than one type of bond

Version 0.8.1 (2009-03-24)#

Note: only major changes are listed here.

New features

  1. Significant performance enhancements

  2. New build option for compiling on UMich CAC clusters: ENABLE_CAC_GPU_ID compiles HOOMD to read in the $CAC_GPU_ID environment variable and use it to determine which GPUs to execute on. No –gpu command line required in job scripts any more.

  3. Particles can now be assigned a non-unit mass

  4. init.reset() command added to allow for the creation of a looped series of simulations all in python

  5. dump.pdb() command for writing PDB files

  6. pair.lj now comes with an option to shift the potential energy to 0 at the cutoff

  7. pair.lj now comes with an opiton to smoothly switch both the potential and force to 0 at the cutoff with the XPLOR smoothing function

  8. Gaussian pair potential computation added (pair.gauss)

  9. update and analyze commands can now be given a function to determine a non-linear rate to run at

  10. analyze.log, and dump.dcd can now append to existing files

Changes that will break scripts from 0.8.0

  1. dump.mol2() has been changed to be more consistent with other dump commands. In order to get the same result as the previous behavior, replace

    dump.mol2(filename="file.mol2")
    

    with

    mol2 = dump.mol2()
    mol2.write(filename="file.mol2")
    
  2. Grouping commands have been moved to their own package for organizational purposes. group_all() must now be called as group.all() and similarly for tags and type.

Bug/fixes small enhancements

  1. Documentation updates

  2. DCD file writing no longer crashes HOOMD in windows

  3. !FindBoost.cmake is patched upstream. Use CMake 2.6.3 if you need BOOST_ROOT to work correctly

  4. Validation tests now run with –gpu_error_checking

  5. ULF bug workarounds are now enabled only on hardware where they are needed. This boosts performance on C1060 and newer GPUs.

  6. !FindPythonLibs now always finds the shared python libraries, if they exist

  7. “make package” now works fine on mac os x

  8. Fixed erroneously reported dangerous neighbor list builds when using –mode=cpu

  9. Small tweaks to the XML file format.

  10. Numerous performance enhancements

  11. Workaround for ULF on compute#1 devices in place

  12. dump.xml can now be given the option “all=true” to write all fields

  13. total momentum can now be logged by analyze.log

  14. HOOMD now compiles with boost#38 (and hopefully future versions)

  15. Updaters can now be given floating point periods such as 1e5

  16. Additional warnings are now printed when HOOMD is about to allocate a large amount of memory due to the specification of an extremely large box size

  17. run() now shows up in the documentation index

  18. Default sorter period is now 100 on CPUs to improve performance on chips with small caches

Version 0.8.0 (2008-12-22)#

Note: only major changes are listed here.

New features

  1. Addition of FENE bond potential

  2. Addition of update.zero_momentum command to zero a system’s linear momentum

  3. Brownian dynamics integration implemented

  4. Multi-GPU simulations

  5. Particle image flags are now tracked. analyze.msd command added to calculate the mean squared displacement.

Changes that will break scripts from 0.7.x

  1. analyze.log quantity names have changed

Bug/fixes small enhancements

  1. Performance of the neighbor list has been increased significantly on the GPU (overall performance improvements are approximately 10%)

  2. Profile option added to the run() command

  3. Warnings are now correctly printed when negative coefficients are given to bond forces

  4. Simulations no longer fail on G200 cards

  5. Mac OS X binaries will be provided for download: new documentation for installing on Mac OS x has been written

  6. Two new demos showcasing large systems

  7. Particles leaving the simulation box due to bad initial conditions now generate an error

  8. win64 installers will no longer attempt to install on win32 and vice-versa

  9. neighborlist check_period now defaults to 1

  10. The elapsed time counter in run() now continues counting time over multiple runs.

  11. init.create_random_polymers now throws an error if the bond length is too small given the specified separation radii

  12. Fixed a bug where a floating point value for the count field in init.create_random_polymers produced an error

  13. Additional error checking to test if particles go NaN

  14. Much improved status line printing for identifying hoomd_script commands

  15. Numerous documentation updates

  16. The VS redistributable package no longer needs to be installed to run HOOMD on windows (these files are distributed with HOOMD)

  17. Now using new features in doxygen#5.7 to build pdf user documentation for download.

  18. Performance enhancements of the Lennard-Jones pair force computation, thanks to David Tarjan

  19. A header prefix can be added to log files to make them more gnuplot friendly

  20. Log quantities completely revamped. Common quantities (i.e. kinetic energy, potential energy can now be logged in any simulation)

  21. Particle groups can now be created. Currently only analyze.msd makes use of them.

  22. The CUDA toolkit no longer needs to be installed to run a packaged HOOMD binary in windows.

  23. User documentation can now be downloaded as a pdf.

  24. Analyzers and updaters now count time 0 as being the time they were created, instead of time step 0.

  25. Added job test scripts to aid in validating HOOMD

  26. HOOMD will now build with default settings on a linux/unix-like OS where the boost static libraries are not installed, but the dynamic ones are.

Version 0.7.1 (2008-09-12)#
  1. Fixed bug where extremely large box dimensions resulted in an argument error - ticket:118

  2. Fixed bug where simulations ran incorrectly with extremely small box dimensions - ticket:138

Version 0.7.0 (2008-08-12)#

Note: only major changes are listed here.

  1. Stability and performance improvements.

  2. Cleaned up the hoomd_xml file format.

  3. Improved detection of errors in hoomd_xml files significantly.

  4. Users no longer need to manually specify HOOMD_ROOT, unless their installation is non-standard

  5. Particle charge can now be read in from a hoomd_xml file

  6. Consistency changes in the hoomd_xml file format: HOOMD 0.6.0 XML files are not compatible. No more compatibility breaking changes are planned after 0.7.0

  7. Enabled parallel builds in MSVC for faster compilation times on multicore systems

  8. Numerous small bug fixes

  9. New force compute for implementing walls

  10. Documentation updates

  11. Support for CUDA 2.0

  12. Bug fixed allowing simulations with no integrator

  13. Support for boost#35.0

  14. Cleaned up GPU code interface

  15. NVT integrator now uses tau (period) instead of Q (the mass of the extra degree of freedom).

  16. Added option to NVE integration to limit the distance a particle moves in a single time step

  17. Added code to dump system snapshots in the DCD file format

  18. Particle types can be named by strings

  19. A snapshot of the initial configuration can now be written in the .mol2 file format

  20. The default build settings now enable most of the optional features

  21. Separated the user and developer documentation

  22. Mixed polymer systems can now be generated inside HOOMD

  23. Support for CMake 2.6.0

  24. Wrote the user documentation

  25. GPU selection from the command line

  26. Implementation of the job scripting system

  27. GPU can now handle neighbor lists that overflow

  28. Energies are now calculated

  29. Added a logger for logging energies during a simulation run

  30. Code now actually compiles on Mac OS X

  31. Benchmark and demo scripts now use the new scripting system

  32. Consistent error message format that is more visible.

  33. Multiple types of bonds each with the own coefficients are now supported

  34. Added python scripts to convert from HOOMD’s XML file format to LAMMPS input and dump files

  35. Fixed a bug where empty xml nodes in input files resulted in an error message

  36. Fixed a bug where HOOMD seg faulted when a particle left the simulation , vis=True)* is now a convenient short hand for what was previously box now works fine on mac os x

  37. Fixed erroneously reported dangerous neighbor list builds when using –mode=cpu

  38. Small tweaks to the XML file format.

  39. Numerous performance enhancements

  40. Workaround for ULF on compute#1 devices in place

  41. dump.xml can now be given the option

Migrating to the latest version#

Migrating to HOOMD v4#
Breaking changes to existing functionalities#

For some functionalities, you will need to update your scripts to use a new API:

Removed functionalities#

HOOMD-blue v4 removes functionalities deprecated in v3.x releases:

  • hoomd.md.pair.aniso.ALJ.mode parameter

  • hoomd.md.pair.aniso.Dipole.mode parameter

  • hoomd.device.GPU.memory_traceback parameter

Compiling#
  • HOOMD-blue v4 no longer builds on macOS with ENABLE_GPU=on.

  • Use the CMake options HOOMD_LONGREAL_SIZE and HOOMD_SHORTREAL_SIZE to control the floating point precision of the calculations. These replace the SINGLE_PRECISION and HPMC_MIXED_PRECISION options from v3.

Components#
  • Remove fix_cudart_rpath(_${COMPONENT_NAME}) from your components CMakeLists.txt

  • Use LongReal and ShortReal types in new code. Scalar will be removed in a future release (v5 or later).

  • Replace any use of hpmc::OverlapReal with ShortReal.

  • Remove needsDiameter and setDiameter methods in potential evaluator classes.

Migrating to HOOMD v3#

HOOMD v3 introduces many breaking changes for both users and developers in order to provide a cleaner Python interface, enable new functionalities, and move away from unsupported tools. This guide highlights those changes.

Overview of API changes#

HOOMD v3 introduces a completely new API. All classes have been renamed to match PEP8 naming guidelines and have new or renamed parameters, methods, and properties. See the tutorials and the Python module documentation for full class-level details.

Here is a module level overview of features that have been moved or removed:

v2 module, class, or method

Replaced with

hoomd.analyze.log

hoomd.logging

hoomd.benchmark

Removed. Use Python standard libraries for timing.

hoomd.cite

Removed. See Citing HOOMD-blue.

hoomd.dump

hoomd.write

hoomd.compute.thermo

hoomd.md.compute.ThermodynamicQuantities

hoomd.context.initialize

hoomd.device.CPU and hoomd.device.GPU

hoomd.data

hoomd.State

hoomd.group

hoomd.filter

hoomd.init

hoomd.Simulation create_state_from_ factory methods

hoomd.lattice

Removed. Use an external tool.

hoomd.meta

hoomd.logging.Logger.

hoomd.option

Removed. Use Python standard libraries for option parsing.

hoomd.update

Some classes have been moved to hoomd.tune.

hoomd.util

Enable GPU profiling with hoomd.device.GPU.enable_profiling.

hoomd.hpmc.analyze.sdf

hoomd.hpmc.compute.SDF

hoomd.hpmc.data

hoomd.hpmc.integrate.HPMCIntegrator properties.

hoomd.hpmc.util

hoomd.hpmc.tune

hoomd.md.integrate.mode_standard

hoomd.md.Integrator

hoomd.md.update.rescale_temp

hoomd.State.thermalize_particle_momenta

hoomd.md.update.enforce2d

Removed. This is not needed.

hoomd.md.constrain.sphere

hoomd.md.manifold.Sphere

hoomd.md.constrain.oneD

Removed.

hoomd.md.update.constraint_ellipsoid

hoomd.md.manifold.Ellipsoid

hoomd.jit.patch

hoomd.hpmc.pair.user

hoomd.jit.external

hoomd.hpmc.external.user

Removed functionality#

HOOMD v3 removes old APIs, unused functionality, and features better served by other codes:

hoomd:

Feature

Replace with

Python 2.7

Python >= 3.6

Compute < 6.0 GPUs

Compute >= 6.0 GPUs

static parameter in hoomd.dump.gsd

dynamic parameter

set_params and other set_* methods

Parameters and type parameters accessed by properties.

context.initialize

device.CPU / device.GPU

util.quiet_status and util.unquiet_status

No longer needed.

hoomd.deprecated:

Feature

Replace with

deprecated.analyze.msd

Offline analysis: e.g. Freud’s msd module.

deprecated.dump.xml

hoomd.write.GSD

deprecated.dump.pos

hoomd.write.GSD with on-demand conversion to .pos.

deprecated.init.read_xml

Simulation.create_state_from_gsd

deprecated.init.create_random

mBuild, packmol, or user script.

deprecated.init.create_random_polymers

mBuild, packmol, or user script.

hoomd.hpmc:

Feature

Replace with

sphere_union::max_members parameter

no longer needed

convex_polyhedron_union

ConvexSpheropolyhedronUnion, sweep_radius=0

setup_pos_writer member

n/a

depletant_mode='circumsphere'

no longer needed

max_verts parameter

no longer needed

depletant_mode parameter

no longer needed

ntrial parameter

no longer needed

implicit boolean parameter

set fugacity non-zero

hoomd.md:

Feature

Replace with

group parameter to integrate.mode_minimize_fire

Pass group to integration method.

alpha parameter to pair.lj and related classes

n/a

f_list and t_list parameters to md.force.active

Per-type active_force and active_torque

md.pair.SLJ

md.pair.ExpandedLJ with hoomd.md.pair.Pair.r_cut set to r_cut(for delta=0) + delta

hoomd.cgcmm:

Feature

Replace with

cgcmm.angle.cgcmm

no longer needed

cgcmm.pair.cgcmm

no longer needed

hoomd.dem:

Feature

Replace with

DEM pair potentials

ALJ pair potential in hoomd.md.pair.aniso.

Not yet ported#

The following v2 functionalities have not yet been ported to the v3 API. They may be added in a future 3.x release:

  • HPMC box volume move size tuner.

These contributed functionalities rely on the community for support. Please contact the developers if you have an interest in porting these in a future release:

  • hoomd.hdf5

  • hoomd.metal

  • hoomd.mpcd

Compiling#
  • CMake 3.8 or newer is required to build HOOMD v3.0.

  • To compile with GPU support, use the option ENABLE_GPU=ON.

  • UPDATE_SUBMODULES no longer exists. Users and developers should use git clone --recursive, git submodule update and git submodule sync as appropriate.

  • COPY_HEADERS no longer exists. HOOMD will pull headers from the source directory when needed.

  • CMAKE_INSTALL_PREFIX is set to the Python site-packages directory (if not explicitly set by the user).

  • cereal, eigen, and pybind11 headers must be provided to build HOOMD. See Installing binaries for details.

  • BUILD_JIT is replaced with ENABLE_LLVM.

Components#
  • HOOMD now uses native CUDA support in CMake. Use CMAKE_CUDA_COMPILER to specify a specific nvcc or hipcc. Plugins will require updates to CMakeLists.txt to compile .cu files.

    • Remove CUDA_COMPILE.

    • Pass .cu sources directly to pybind11_add_module.

    • Add NVCC as a compile definition to .cu sources.

  • External components require additional updates to work with v3. See example_plugin for details:

    • Remove FindHOOMD.cmake.

    • Replace include(FindHOOMD.cmake) with find_package(HOOMD 3.Y REQUIRED) (where 3.Y is the minor version this plugin is compatible with).

    • Always force set CMAKE_INSTALL_PREFIX to ${HOOMD_INSTALL_PREFIX}.

    • Replace PYTHON_MODULE_BASE_DIR with PYTHON_SITE_INSTALL_DIR.

    • Replace all target_link_libraries and set_target_properties with target_link_libraries(_${COMPONENT_NAME} PUBLIC HOOMD::_hoomd) (can link HOOMD::_md, HOOMD::_hpmc, etc. if necessary).

  • Numerous C++ class APIs have changed, been removed, or renamed. Review the header files to see new class signatures. These changes may require you to update your component accordingly. Some of the more notable changes include:

    • Variant has been completely rewritten.

    • Trigger replaces periodic and variable period scheduling.

    • NeighborList has a addRCutMatrix method clients must use to specify the maximum cutoff radii per type pair.

    • timestep is now of type uint64_t.

    • Saru has been removed. Use RandomGenerator.

    • RandomGenerator is now constructed with a Seed and Counter object that support 64-bit timesteps.

    • m_seed is no longer present in individual operation objects. Use the global seed provided by SystemDefinition.

    • The HPMC integrators have been heavily refactored.

    • HPMC GPU kernels are now instantiated by template .cu files that are generated by CMake at configure time.

    • ParticleGroup instances are now constructed from immutable, reusable, and user-customizable ParticleFilter instances.

    • All GPU code is now written with HIP to support NVIDIA and AMD GPUs.

    • ActiveForceCompute always uses particle orientation in combination with per-type active forces and torques.

    • getProvidedLogQuantities and getLogQuantities have been removed. Provide loggable properties instead.

    • Removed the Sphere, Ellipsoid, and oneD constraints. Replaced with the more general RATTLE integration methods and Manifold classes.

    • Removed the Enforce2D and TempRescale Updaters. Enforce2D is not needed for 2D simulations, and TempRescale has been replaced by thermalize_ methods.

    • Removed Doxygen configuration scripts. View the document for classes in the source files.

    • Particle types may no longer be added after a Simulation is initialized. Classes no longer need to subscribe to the types added signal and reallocate data structures when the number of types changes.

Deprecated#

Features deprecated in HOOMD 4.x may be removed in a future 5.0.0 release.

HOOMD may issue FutureWarning messages to provide warnings for breaking changes in the next major release. Use Python’s warnings module to silence warnings which may not be correctable until the next major release. Use this filter: ignore::FutureWarning:hoomd. See Python’s warnings documentation for more information on warning filters.

4.x#

For developers#

Contributing#

Contributions are welcomed via pull requests on GitHub. Contact the HOOMD-blue developers before starting work to ensure it meshes well with the planned development direction and standards set for the project.

Features#
Implement functionality in a general and flexible fashion#

New features should be applicable to a variety of use-cases. The HOOMD-blue developers can assist you in designing flexible interfaces.

Maintain performance of existing code paths#

Expensive code paths should only execute when requested.

Optimize for the current GPU generation#

Write, test, and optimize your GPU kernels on the latest generation of GPUs.

Version control#
Base your work off the correct branch#
  • Base backwards compatible bug fixes on trunk-patch.

  • Base additional functionality on trunk-minor.

  • Base API incompatible changes on trunk-major.

Agree to the Contributor Agreement#

All contributors must agree to the Contributor Agreement before their pull request can be merged.

Source code#
Use a consistent style#

The Code style section of the documentation sets the style guidelines for HOOMD-blue code.

Document code with comments#

Use doxygen header comments for classes, functions, etc. Also comment complex sections of code so that other developers can understand them.

Compile without warnings#

Your changes should compile without warnings.

Tests#
Write unit tests#

Add unit tests for all new functionality.

Validity tests#

The developer should run research-scale simulations using the new functionality and ensure that it behaves as intended.

User documentation#
Write user documentation#

Document public-facing API with Python docstrings in Google style.

Document version status#

Add versionadded, versionchanged, and deprecated Sphinx directives to each user-facing Python class, method, etc., so that users will be aware of how functionality changes from version to version. Remove this when breaking APIs in major releases.

Add developer to the credits#

Update the credits documentation to list the name and affiliation of each individual that has contributed to the code.

Propose a change log entry#

Propose a short concise entry describing the change in the pull request description.

Code style#

All code in HOOMD-blue follows a consistent style to ensure readability. We provide configuration files for linters (specified below) so that developers can automatically validate and format files.

These tools are configured for use with pre-commit in .pre-commit-config.yaml. You can install pre-commit hooks to validate your code. Checks will run on pull requests. Run checks manually with:

pre-commit run --all-files
Python#

Python code in HOOMD-blue should follow PEP8 with the formatting performed by yapf (configuration in setup.cfg). Code should pass all flake8 tests and formatted by yapf.

Tools#
Documentation#

Python code should be documented with docstrings and added to the Sphinx documentation index in doc/. Docstrings should follow Google style formatting for use in Napoleon.

Simulation operations should unambiguously document what calculations they perform using formal mathematical notation and use a consistent set of symbols and across the whole codebase. HOOMD-blue documentation should follow standard physics and statistical mechanics notation with consistent use of symbols detailed in Notation.

When referencing classes, methods, and properties in documentation, use name to refer to names in the local scope (class method or property, or classes in the same module). For classes outside the module, use the fully qualified name (e.g. numpy.ndarray or hoomd.md.compute.ThermodynamicQuantities).

C++/CUDA#
  • Style is set by clang-format

    • Whitesmith’s indentation style.

    • 100 character line width.

    • Indent only with spaces.

    • 4 spaces per indent level.

    • See .clang-format for the full clang-format configuration.

  • Naming conventions:

    • Namespaces: All lowercase somenamespace

    • Class names: UpperCamelCase

    • Methods: lowerCamelCase

    • Member variables: m_ prefix followed by lowercase with words separated by underscores m_member_variable

    • Constants: all upper-case with words separated by underscores SOME_CONSTANT

    • Functions: lowerCamelCase

Tools#
Documentation#

Documentation comments should be in Javadoc format and precede the item they document for compatibility with many source code editors. Multi-line documentation comment blocks start with /** and single line ones start with ///.

/** Describe a class
 *
 *  Note the second * above makes this a documentation comment. Some
 *  editors like to add the additional *'s on each line. These may be
 * omitted
*/
class SomeClass
    {
    public:
        /// Single line doc comments should have three /'s
        Trigger() { }

        /** This is a brief description of a method

            This is a longer description.

            @param arg This is an argument.
            @returns This describes the return value
        */
        virtual bool method(int arg)
            {
            return false;
            }
    private:

        /// This is a member variable
        int m_var;
    };

See Trigger.h for a good example.

Other file types#

Use your best judgment and follow existing patterns when styling CMake, restructured text, markdown, and other files. The following general guidelines apply:

  • 100 character line width.

  • 4 spaces per indent level.

  • 4 space indent.

Editor configuration#

Visual Studio Code users: Open the provided workspace file (hoomd.code-workspace) which provides configuration settings for these style guidelines.

Testing#

All code in HOOMD must be tested to ensure that it operates correctly.

Unit tests check that basic functionality works, one class at a time. Unit tests assume internal knowledge about how classes work and may use unpublished APIs to stress test all possible input and outputs of a given class in order to exercise all code paths. For example, test that the box class properly wraps vectors back into the minimum image. Unit tests should complete in a fraction of a second.

System integration tests check that many classes work together to produce correct output. These tests are black box tests and should only use user-facing APIs to provide inputs and check for correct outputs. For example, test that the hard sphere HPMC simulation executes for several steps. System integration tests may take several seconds.

Long running tests check for correct behavior, but require up to a minute to execute. Mark long running tests with the validate label.

Validation tests rigorously check that simulations sample the correct statistical ensembles. These tests take hours to execute on many CPU cores or GPUs. Find HOOMD’s validation tests in the hoomd-validation repository.

Requirements#

The following Python packages are required to execute tests. Some tests will be skipped when optional requirements are missing.

  • gsd (optional)

  • mpi4py (optional)

  • pytest

  • rowan (optional)

  • CuPy (optional)

Running tests#

Change to the build directory and execute the following commands to run the tests:

  • ctest - Executes C++ tests

  • python3 -m pytest hoomd

pytest may be run outside the build directory by:

  • Passing a full path to the build: python3 -m pytest <build-directory>/hoomd

  • After installing to an environment: python3 -m pytest --pyargs hoomd

Note

python3 -m pytest --pyargs hoomd tests the hoomd installation it finds by import hoomd, which may not be the one you just built. You must also change to a directory outside the source, otherwise import hoomd attempts to import the uncompiled source.

See also

See the pytest documentation for information on how to control output, select specific tests, and more.

Running tests with MPI#

When ENABLE_MPI=ON, CTest will execute some tests with mpirun -n 1, some with -n 2 and some with -n 8. Make sure your test environment (e.g. interactive cluster job) is correctly configured before running ctest.

pytest tests may also be executed with MPI with 2 ranks. pytest does not natively support MPI. Execute it with the provided wrapper script in the build directory:

mpirun -n 2 build/hoomd/hoomd/pytest/pytest-openmpi.sh -v -x build/hoomd

The wrapper script displays the outout of rank 0 and redirects rank 1’s output to a file. Inspect this file when a test fails on rank 1. This will result in an MPI_ABORT on rank 0 (assuming the -x argument is passed):

cat pytest.out.1

Warning

Pass the -x option to prevent deadlocks when tests fail on only 1 rank.

Note

The provided wrapper script supports OpenMPI.

Executing long runing tests#

Longer running tests do not execute by default. Run these with the --validate command line option to pytest:

$ python3 -m pytest build/hoomd --validate -m validate
$ mpirun -n 2 hoomd/pytest/pytest-openmpi.sh build/hoomd -v -x -ra --validate -m validate

Note

The -m validate option selects only the long running tests.

Note

To run long running tests on an installed hoomd package, you need to specify additional options:

python3 -m pytest --pyargs hoomd -p hoomd.pytest_plugin_validate -m validate --validate
Implementing tests#

Most tests should be implemented in pytest. HOOMD’s test rig provides a device fixture that most tests should use to cache the execution device across multiple tests and reduce test execution time.

Important

Add any new test_*.py files to the list in the corresponding CMakeLists.txt file.

Only add C++ tests for classes that have no Python interface or otherwise require low level testing. If you are unsure, please check with the lead developers prior to adding new C++ tests. Add new validation tests to the hoomd-validation repository.

Components#

Extend HOOMD-blue with a component implemented in C++ for performance-critical tasks, such as pair potential evaluation. A component provides a number of related functionalities. For example, the hoomd.hpmc component enables hard particle Monte Carlo methods with HOOMD-blue.

Compile and install components built-in or as external components. The HOOMD-blue build process compiles all core and built-in components together, requiring one only one set of configure, make, and install commands. External components compile and link against a HOOMD-blue installation from a separate build directory with their own set of configure, make, and install commands. You may compile a component either way. When the end user is compiling HOOMD-blue and components from source, built-in components compile and install everything at once which minimizes chances for errors (e.g. building HOOMD-blue against python 3.6, but the component against python 3.7). External components provide more flexibility for packaging purposes.

The HOOMD-Blue source provides example component templates in the example_plugins subdirectory. updater_plugin demonstrates how to add a new update command with both CPU and GPU implementations, and pair_plugin shows how to add a new MD pair potential.

Built-in components#

You can fork HOOMD-blue and add your component directly, or you can create a separate source repository for your component. Create a symbolic link to the component in the hoomd source directory to compile it as a built-in component:

$ ln -s <path-to-component>/<component> hoomd-blue/hoomd/<component>

Note

Built-in components may be used directly from the build directory or installed.

External components#

To compile an external component, you must first install HOOMD-blue. Then, configure your component with CMake and install it into the hoomd python library. Point CMAKE_PREFIX_PATH at your virtual environment (if needed) so that cmake can find HOOMD-blue:

$ cmake -B build/<component> -S <path-to-component>
$ cmake --build build/<component>
$ cmake --install build/<component>

The component build environment, including the compiler, CUDA, MPI, python, and other libraries, must match exactly with those used to build HOOMD-blue.

Note

External components must be installed before use.

Open source#

License#

Copyright (c) 2009-2023 The Regents of the University of Michigan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Libraries#

HOOMD: HOOMD-blue is a continuation of the HOOMD project (http://www.ameslab.gov/hoomd/). The code from the original project is used under the following license:

Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
Source Software License
Copyright (c) 2008 Ames Laboratory Iowa State University
All rights reserved.

Redistribution and use of HOOMD, in source and binary forms, with or
without modification, are permitted, provided that the following
conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names HOOMD's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND
CONTRIBUTORS ``AS IS''  AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS  BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.

Additionally, HOOMD-blue links to or compiles in code from the following libraries:

Sockets code from VMD, used under the UIUC Open Source License.

Molfile plugin code from VMD, used under the UIUC Open Source License:

University of Illinois Open Source License
Copyright 2006 Theoretical and Computational Biophysics Group,
All rights reserved.

Developed by: Theoretical and Computational Biophysics Group
              University of Illinois at Urbana-Champaign
              http://www.ks.uiuc.edu/

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the Software), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to
do so, subject to the following conditions:

Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.

Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the documentation
and/or other materials provided with the distribution.

Neither the names of Theoretical and Computational Biophysics Group,
University of Illinois at Urbana-Champaign, nor the names of its contributors
may be used to endorse or promote products derived from this Software without
specific prior written permission.

THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS WITH THE SOFTWARE.

CUDA, used under the NVIDIA Software License Agreement.

kissFFT, used under the following license:

Copyright (c) 2003-2010 Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

* Neither the author nor the names of any contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

CUB, used under the following license:

Copyright (c) 2011, Duane Merrill.  All rights reserved.
Copyright (c) 2011-2016, NVIDIA CORPORATION.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the NVIDIA CORPORATION nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Eigen, used under the Mozilla Public License v.2.0 (http://mozilla.org/MPL/2.0/).

BVLSSolver, is embedded in HOOMD’s package and is made available under the following license:

Copyright (c) 2015, Michael P. Howard. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. Neither the name of the copyright holder nor the names of its
       contributors may be used to endorse or promote products derived from
       this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

pybind11, used under the following license:

Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

You are under no obligation whatsoever to provide any bug fixes, patches, or
upgrades to the features, functionality or performance of the source code
("Enhancements") to anyone; however, if you choose to make your Enhancements
available either publicly, or directly to the author of this software, without
imposing a separate written license agreement for such Enhancements, then you
hereby grant the following license: a non-exclusive, royalty-free perpetual
license to install, use, modify, prepare derivative works, incorporate into
other computer software, distribute, and sublicense such enhancements or
derivative works thereof, in binary and source code form.

cereal, used under the BSD license:

Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of cereal nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Random123, used under the following license:

Copyright 2010-2012, D. E. Shaw Research.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions, and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions, and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

* Neither the name of D. E. Shaw Research nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

A CUDA neighbor search library, used under the following license:

Copyright (c) 2018-2019, Michael P. Howard. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

LLVM, used under the Apache 2.0 license.

nano-signal-slot, used under the following license:

Copyright (c) 2012-2015 ApEk, NoAvailableAlias, Nano-signal-slot Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

hipper, used under the following license:

Copyright (c) 2020, Michael P. Howard. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

HIP is included under the following license:

Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

hipCUB, used under the following license:

Copyright (c) 2010-2011, Duane Merrill.  All rights reserved.
Copyright (c) 2011-2018, NVIDIA CORPORATION.  All rights reserved.
Modifications Copyright (c) 2019, Advanced Micro Devices, Inc.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
   *  Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
   *  Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
   *  Neither the name of the NVIDIA CORPORATION nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

rocPRIM, used under the following license:

Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

rocThrust, used under the Apache 2.0 license

rocFFT, used under the following license:

Copyright (c) 2016 Advanced Micro Devices, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

HOOMD-blue uses headers from jitify under the following license:

BSD 3-Clause License

Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name of NVIDIA CORPORATION nor the names of its
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

HOOMD uses the ECL code for connected components under the following license:

ECL-CC code: ECL-CC is a connected components algorithm. The CUDA
implementation thereof is very fast. It operates on graphs stored in
binary CSR format.

Copyright (c) 2017, Texas State University. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted for academic, research, experimental, or personal use provided
that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice,
     this list of conditions, and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions, and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the name of Texas State University nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

For all other uses, please contact the Office for Commercialization and Industry
Relations at Texas State University <http://www.txstate.edu/ocir/>.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Authors: Jayadharini Jaiganesh and Martin Burtscher

Python, Used under the Python license

Other Attributions#

HOOMD’s synced collection infrastructure is inspired from and in part derived from signac’s GitHub SyncedCollection implementation under the following license:

BSD 3-Clause License for the software signac.

Copyright (c) 2016, The Regents of the University of Michigan
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1.  Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.

2.  Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

3.  Neither the name of the copyright holder nor the names of its contributors may
    be used to endorse or promote products derived from this software without
    specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

Credits#

The following people have contributed to the to HOOMD-blue:

  • Aaron Keys, University of Michigan

  • Adrien Chen, University of Florida

  • Alain Kadar, University of Michigan

  • Alex Travesset, Iowa State University and Ames Laboratory

  • Alex Yang, Vanderbilt University

  • Alexander Hudson

  • Allen LaCour, University of Michigan

  • Alyssa Travitz, University of Michigan

  • Andrew Schultz, University at Buffalo

  • Andrew Mark, Max Planck Institute

  • Andrey Kazennov, Joint Institute for High Temperatures of RAS

  • Antonio Osorio, University of Michigan

  • Avisek Das, University of Michigan

  • Axel Kohlmeyer, Temple University

  • Ben Levine, Temple University

  • Ben Swerdlow, University of Michgan

  • Benjamin Schultz, University of Michgan

  • Bjørnar Jensen, University of Bergen

  • Bradley Dice, University of Michigan

  • Brandon Butler, University of Michigan

  • Brandon Denis Smith, University of Michigan

  • Bryan VanSaders, University of Michgan

  • Carl Simon Adorf, University of Michigan

  • Carolyn Phillips, University of Michigan

  • Charlie Slominski, Caltech

  • Chengyu Dai, University of Michigan

  • Chris Jones, Boise State University

  • Christoph Junghans

  • Christoph Klein, Vanderbilt University

  • Chrisy Du, University of Michigan

  • Cong Qiao, Brandeis University

  • Corwin Kerr, University of Michigan

  • Charlotte Zhao, University of Michigan

  • Dan Evans, University of Michigan

  • David LeBard, Temple University

  • Elizabeth R Chen, University of Michigan

  • Eric Harper, University of Michigan

  • Eric Irrgang, University of Michigan

  • Eric Jankowski, Boise State University

  • Erin Teich, University of Michigan

  • Fengyi Gao, University of Michigan

  • Gabrielle Jones, University of Michigan

  • Geert Kapteijns, University of Amsterdam

  • Greg van Anders, University of Michigan

  • Grey Garrett, University of Michigan

  • Ian Graham, University of Pennsylvania

  • Ignacio Blanco Varela, University of Michigan

  • Igor Morozov, Joint Institute for High Temperatures of RAS

  • Isaac Bruss, University of Michigan

  • Jakin B. Delony, University of South Florida

  • James Antonaglia, University of Michigan

  • James Proctor, University of Michigan

  • James W. Swan, Massachusetts Institute of Technology

  • Jen Bradley, University of Michigan

  • Jenny Fothergill, Boise State University

  • Jens Glaser, Oak Ridge National Laboratory

  • Joseph Berleant, University of Michigan

  • Joshua A. Anderson, University of Michigan

  • Kelly Wang, University of Michigan

  • Kevin Daly, Princeton University

  • Kevin Kohlstedt, University of Michigan

  • Kevin Silmore, Princeton University

  • Khalid Ahmed, University of Michigan

  • Kody Takada, University of Michigan

  • Kristi Pepa, University of Michigan

  • Kwanghwi Je, University of Michigan

  • Lin Yang, Iowa State University

  • Ludwig Schneider, Georg-August Univeristy Goettingen

  • Luis Y. Rivera-Rivera, University of Michigan

  • Malcolm Ramsay

  • Marco Klement, Friedrich-Alexander-Universität Erlangen-Nürnberg (FAU)

  • Martin Girard, Max-Planck-Institut für Polymerforschung

  • Matthew Spellings, University of Michgan

  • Melody Zhang, University of Michigan

  • Michael Howard, University of Texas

  • Mike Henry, Boise State University

  • Nathan Horst

  • Nipuli Gunaratne, University of Michigan

  • Pablo Zubieta, PME, The University of Chicago

  • Patrick Lawton, University of Michigan

  • Paul Dodd, University of Michigan

  • Pavani Medapuram Lakshmi Narasimha, University of Minnesota

  • Pengji Zhou, University of Michgan

  • Peter Palm, Leipzig University

  • Peter Schwendeman, University of Michigan

  • Philipp Mertmann, Ruhr University Bochum

  • Philipp Schönhöfer, University of Michigan

  • Praharsh Suryadevara, New York University

  • Rastko Sknepnek, Northwestern

  • Raymond Asare, University of Michigan

  • Richmond Newman, University of Michigan

  • Roman Bystryi, Joint Institute for High Temperatures of RAS

  • Ross Smith, University of Michigan

  • Ryan Marson, University of Michigan

  • Sam Nola, University of Michigan

  • Simone Ciarella, Eindhoven University of Technology

  • Shannon Moran, University of Michigan

  • Sophie YouJung Lee, University of Michigan

  • Stephen Thomas, Boise State University

  • Steve Barr, Princeton University

  • Sumedh R. Risbud, Massachusetts Institute of Technology

  • Thi Vo, University of Michigan

  • Tim Moore, University of Michigan

  • Tobias Dwyer, University of Michigan

  • Tommy Waltmann, University of Michigan

  • Trung Dac Nguyen, University of Michigan

  • Vyas Ramasubramani, University of Michigan

  • Wenbo Shen, University of Michigan

  • William Zygmunt, University of Michigan

  • Wouter Ellenbroek, Eindhoven University of Technology

  • Yuan Zhou, University of Michigan

  • Åsmund Ervik, SINTEF

  • Nathan Barrett, Pritzker School of Molecular Engineering

  • Domagoj Fijan, University of Michigan

Index#