diff --git a/README.md b/README.md index 423c670..7f65a92 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# HOOMD-blue component template +# HOOMD-blue component template for HPMC shapes -`hoomd-component-template` provides a framework to develop components that extend -[**HOOMD-blue**](https://glotzerlab.engin.umich.edu/hoomd-blue/). It includes template C++ and -Python modules, an example unit test, CMake scripts to build the component, and GitHub Actions -workflows. +`hoomd-hpmc-shape-template` provides a framework to develop components that extend +[**HOOMD-blue**](https://glotzerlab.engin.umich.edu/hoomd-blue/) with new hard shapes. +It includes template C++ and Python modules, an example unit test, CMake scripts to +build the component, and GitHub Actions workflows. ## Building the component @@ -12,19 +12,19 @@ To build this component: 1. Build and install **HOOMD-blue** from source. 2. Obtain the component's source. ``` - $ git clone https://github.com/glotzerlab/hoomd-component-template + $ git clone https://github.com/glotzerlab/hoomd-hpmc-shape-template ``` 3. Configure. ``` - $ cmake -B build/hoomd-component-template -S hoomd-component-template + $ cmake -B build/hoomd-hpmc-shape-template -S hoomd-hpmc-shape-template ``` 4. Build the component. ``` - $ cmake --build build/hoomd-component-template + $ cmake --build build/hoomd-hpmc-shape-template ``` 5. Install the component. ``` - $ cmake --install build/hoomd-component-template + $ cmake --install build/hoomd-hpmc-shape-template ``` Once installed, the template is available for import via: @@ -37,7 +37,7 @@ import hoomd.template To create a new component: -1. Fork [hoomd-component-template](https://github.com/glotzerlab/hoomd-component-template/). +1. Fork [hoomd-hpmc-shape-template](https://github.com/glotzerlab/hoomd-hpmc-shape-template/). 2. Address all **TODO** comments (including those in `.github/`) 3. Add C++ and Python files to `src/`. 4. Add unit tests in `src/pytest`. @@ -57,7 +57,7 @@ new GitHub release with automatically generated release notes. ## Maintaining your component The HOOMD-blue developers will periodically update -[hoomd-component-template](https://github.com/glotzerlab/hoomd-component-template/), including +[hoomd-hpmc-shape-template](https://github.com/glotzerlab/hoomd-hpmc-shape-template/), including updates to the GitHub Actions workflow, pre-commit configuration, and CMake scripts. Merge these changes into your fork to support the latest version of HOOMD-blue. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2cad425..acc12ec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,11 +8,13 @@ set(_${COMPONENT_NAME}_sources # TODO: List all GPU C++ source code files in _${COMPONENT_NAME}_cu_sources. set(_${COMPONENT_NAME}_cu_sources + kernels.cu ) # TODO: List all Python modules in python_files. set(python_files __init__.py + integrate.py version.py ) @@ -34,7 +36,7 @@ endif() # libraries) as needed. target_link_libraries(_${COMPONENT_NAME} PUBLIC HOOMD::_hoomd - PUBLIC HOOMD::_md + PUBLIC HOOMD::_hpmc ) # Install the library. diff --git a/src/ShapeMySphere.h b/src/ShapeMySphere.h new file mode 100644 index 0000000..af0a9fb --- /dev/null +++ b/src/ShapeMySphere.h @@ -0,0 +1,175 @@ +// Copyright (c) 2009-2024 The Regents of the University of Michigan. +// Part of HOOMD-blue, released under the BSD 3-Clause License. + +#pragma once + +#include "hoomd/AABB.h" +#include "hoomd/BoxDim.h" +#include "hoomd/HOOMDMath.h" +#include "hoomd/VectorMath.h" +#include "hoomd/hpmc/HPMCMiscFunctions.h" +#include "hoomd/hpmc/Moves.h" +#include "hoomd/hpmc/OBB.h" +#include "hoomd/hpmc/ShapeSphere.h" + +#include + +#include + +#ifdef __HIPCC__ +#define DEVICE __device__ +#define HOSTDEVICE __host__ __device__ +#else +#define DEVICE +#define HOSTDEVICE +#include +#endif + +namespace hoomd + { +namespace hpmc + { + +struct MySphereParams : ShapeParams + { + /// The radius of the sphere + ShortReal radius; + + /// True when move statistics should not be counted + bool ignore; + + /// True when the shape may be oriented + bool isOriented; + +#ifdef ENABLE_HIP + /// Set CUDA memory hints + void set_memory_hint() const { } +#endif + +#ifndef __HIPCC__ + + /// Default constructor + MySphereParams() { } + + /// Construct from a Python dictionary + MySphereParams(pybind11::dict v, bool managed = false) + { + ignore = v["ignore_statistics"].cast(); + radius = v["radius"].cast(); + isOriented = v["orientable"].cast(); + } + + /// Convert parameters to a python dictionary + pybind11::dict asDict() + { + pybind11::dict v; + v["radius"] = radius; + v["orientable"] = isOriented; + v["ignore_statistics"] = ignore; + return v; + } + +#endif + } __attribute__((aligned(32))); + +struct ShapeMySphere + { + /// Define the parameter type + typedef MySphereParams param_type; + + /// Construct a shape at a given orientation + DEVICE ShapeMySphere(const quat& _orientation, const param_type& _params) + : orientation(_orientation), params(_params) + { + } + + /// Check if the shape may be rotated + DEVICE bool hasOrientation() const + { + return params.isOriented; + } + + /// Check if this shape should be ignored in the move statistics + DEVICE bool ignoreStatistics() const + { + return params.ignore; + } + + /// Get the circumsphere diameter of the shape + DEVICE ShortReal getCircumsphereDiameter() const + { + return params.radius * ShortReal(2.0); + } + + /// Get the in-sphere radius of the shape + DEVICE ShortReal getInsphereRadius() const + { + return params.radius; + } + + /// Return the bounding box of the shape in world coordinates + DEVICE hoomd::detail::AABB getAABB(const vec3& pos) const + { + return hoomd::detail::AABB(pos, params.radius); + } + + /// Return a tight fitting OBB around the shape + DEVICE detail::OBB getOBB(const vec3& pos) const + { + return detail::OBB(pos, params.radius); + } + + /// Returns true if this shape splits the overlap check over several threads of a warp using + /// threadIdx.x + HOSTDEVICE static bool isParallel() + { + return false; + } + + /// Returns true if the overlap check supports sweeping both shapes by a sphere of given radius + HOSTDEVICE static bool supportsSweepRadius() + { + return true; + } + + quat orientation; //!< Orientation of the sphere (unused) + + /// MySphere parameters + const MySphereParams& params; + }; + +//! MySphere-MySphere overlap +/*! \param r_ab Vector defining the position of shape b relative to shape a (r_b - r_a) + \param a first shape + \param b second shape + \param err in/out variable incremented when error conditions occur in the overlap test + \returns true when *a* and *b* overlap, and false when they are disjoint + + \ingroup shape +*/ +template<> +DEVICE inline bool test_overlap(const vec3& r_ab, + const ShapeMySphere& a, + const ShapeMySphere& b, + unsigned int& err) + { + vec3 dr(r_ab); + + ShortReal rsq = dot(dr, dr); + + ShortReal RaRb = a.params.radius + b.params.radius; + if (rsq < RaRb * RaRb) + { + return true; + } + else + { + return false; + } + } + + } // end namespace hpmc + } // end namespace hoomd + +#undef DEVICE +#undef HOSTDEVICE diff --git a/src/__init__.py b/src/__init__.py index b4942b8..43097f5 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -6,3 +6,4 @@ # TODO: Import all Python modules in your component. from . import version +from .integrate import MySphere diff --git a/src/integrate.py b/src/integrate.py new file mode 100644 index 0000000..093d34e --- /dev/null +++ b/src/integrate.py @@ -0,0 +1,44 @@ +# Copyright (c) 2009-2024 The Regents of the University of Michigan. +# Part of HOOMD-blue, released under the BSD 3-Clause License. + +"""Example Shape Integrator.""" + +# Import the C++ module +import hoomd + +from . import _template + + +class MySphere(hoomd.hpmc.integrate.HPMCIntegrator): + """Example shape integrator.""" + + # set static class data + _ext_module = _template + _cpp_cls = 'IntegratorHPMCMonoMySphere' + + def __init__( + self, + default_d=0.1, + default_a=0.1, + translation_move_probability=0.5, + nselect=4, + kT=1.0, + ): + # initialize base class + super().__init__( + default_d, default_a, translation_move_probability, nselect, kT + ) + + typeparam_shape = hoomd.data.typeparam.TypeParameter( + 'shape', + type_kind='particle_types', + param_dict=hoomd.data.parameterdicts.TypeParameterDict( + radius=float, ignore_statistics=False, orientable=False, len_keys=1 + ), + ) + self._add_typeparam(typeparam_shape) + + @hoomd.logging.log(category='object', requires_run=True) + def type_shapes(self): + """list[dict]: Description of shapes in ``type_shapes`` format.""" + return super()._return_type_shapes() diff --git a/src/kernels.cu b/src/kernels.cu new file mode 100644 index 0000000..3798bce --- /dev/null +++ b/src/kernels.cu @@ -0,0 +1,39 @@ +// Copyright (c) 2009-2024 The Regents of the University of Michigan. +// Part of HOOMD-blue, released under the BSD 3-Clause License. + +#include "ShapeMySphere.h" +#include "hoomd/hpmc/ComputeFreeVolumeGPU.cuh" +#include "hoomd/hpmc/IntegratorHPMCMonoGPU.cuh" +#include "hoomd/hpmc/IntegratorHPMCMonoGPUMoves.cuh" +#include "hoomd/hpmc/UpdaterGCAGPU.cuh" + +namespace hoomd + { +namespace hpmc + { +namespace detail + { +template hipError_t +gpu_hpmc_free_volume(const hpmc_free_volume_args_t& args, + const typename ShapeMySphere::param_type* d_params); + } +namespace gpu + { +template void hpmc_gen_moves(const hpmc_args_t& args, + const ShapeMySphere::param_type* params); + +template void hpmc_narrow_phase(const hpmc_args_t& args, + const ShapeMySphere::param_type* params); + +template void hpmc_update_pdata(const hpmc_update_args_t& args, + const ShapeMySphere::param_type* params); + +template void hpmc_cluster_overlaps(const cluster_args_t& args, + const ShapeMySphere::param_type* params); + +template void transform_particles(const clusters_transform_args_t& args, + const ShapeMySphere::param_type* params); + } // namespace gpu + + } // end namespace hpmc + } // end namespace hoomd diff --git a/src/module.cc b/src/module.cc index b3f4d48..9c7407d 100644 --- a/src/module.cc +++ b/src/module.cc @@ -3,24 +3,60 @@ // TODO: Include the header files of classes that will be exported to Python. +#include "hoomd/hpmc/ComputeFreeVolume.h" +#include "hoomd/hpmc/IntegratorHPMC.h" +#include "hoomd/hpmc/IntegratorHPMCMono.h" #include +#include "hoomd/hpmc/ComputeSDF.h" +#include "hoomd/hpmc/ShapeUnion.h" + +#include "hoomd/hpmc/ExternalFieldHarmonic.h" +#include "hoomd/hpmc/ExternalFieldWall.h" + +#include "hoomd/hpmc/UpdaterGCA.h" +#include "hoomd/hpmc/UpdaterMuVT.h" + +#include "ShapeMySphere.h" + +#ifdef ENABLE_HIP +#include "hoomd/hpmc/ComputeFreeVolumeGPU.h" +#include "hoomd/hpmc/IntegratorHPMCMonoGPU.h" +#include "hoomd/hpmc/UpdaterGCAGPU.h" +#endif + +using namespace hoomd::hpmc::detail; + namespace hoomd { -namespace md +namespace hpmc { // TODO: Set the name of the python module to match ${COMPONENT_NAME} (set in // CMakeLists.txt), prefixed with an underscore. PYBIND11_MODULE(_template, m) { - // TODO: Call export_Class(m) for each C++ class to be exported to Python. + // TODO: Call export_Class(m) for each C++ class to be exported to Python. + export_IntegratorHPMCMono(m, "IntegratorHPMCMonoMySphere"); + export_ComputeFreeVolume(m, "ComputeFreeVolumeMySphere"); + export_ComputeSDF(m, "ComputeSDFMySphere"); + export_UpdaterMuVT(m, "UpdaterMuVTMySphere"); + export_UpdaterGCA(m, "UpdaterGCAMySphere"); + + export_ExternalFieldWall(m, "WallMySphere"); + + pybind11::class_>(m, "MySphereParams") + .def(pybind11::init()) + .def("asDict", &MySphereParams::asDict); #ifdef ENABLE_HIP - // TODO: Call export_ClassGPU(m) for each GPU enabled C++ class to be exported - // to Python. + // TODO: Call export_ClassGPU(m) for each GPU enabled C++ class to be exported + // to Python. + export_IntegratorHPMCMonoGPU(m, "IntegratorHPMCMonoMySphereGPU"); + export_ComputeFreeVolumeGPU(m, "ComputeFreeVolumeMySphereGPU"); + export_UpdaterGCAGPU(m, "UpdaterGCAMySphereGPU"); #endif } - } // end namespace md + } // namespace hpmc } // end namespace hoomd diff --git a/src/pytest/CMakeLists.txt b/src/pytest/CMakeLists.txt index 8f2d47e..0e9c95e 100644 --- a/src/pytest/CMakeLists.txt +++ b/src/pytest/CMakeLists.txt @@ -1,6 +1,6 @@ # TODO: List all pytest files in test_files. set(test_files __init__.py - test_version.py + test_mysphere.py ) # Copy tests to the install directory. diff --git a/src/pytest/test_mysphere.py b/src/pytest/test_mysphere.py new file mode 100644 index 0000000..993ae2c --- /dev/null +++ b/src/pytest/test_mysphere.py @@ -0,0 +1,20 @@ +# Copyright (c) 2009-2024 The Regents of the University of Michigan. +# Part of HOOMD-blue, released under the BSD 3-Clause License. + +"""Test the shape.""" + +import hoomd.template + +# TODO: rewrite the unit tests to verify that your shape functions correctly. + + +def test_attach(simulation_factory, two_particle_snapshot_factory): + """Ensure that an integrator can be created with the shape.""" + mc = hoomd.template.MySphere() + mc.shape['A'] = dict(radius=0.5) + mc.d['A'] = 0.1 + mc.a['A'] = 0.1 + sim = simulation_factory(two_particle_snapshot_factory()) + sim.operations.integrator = mc + + sim.run(0) diff --git a/src/pytest/test_version.py b/src/pytest/test_version.py deleted file mode 100644 index c367953..0000000 --- a/src/pytest/test_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2009-2024 The Regents of the University of Michigan. -# Part of HOOMD-blue, released under the BSD 3-Clause License. - -"""Test the version module.""" - -import hoomd.template - - -def test_version(): - """Test the version attribute.""" - assert hoomd.template.version.version == '0.0.0'