From f3bfd82e315e9046a11865c03812edc99c606129 Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Tue, 4 Jun 2024 12:08:45 -0500 Subject: [PATCH 01/11] Update to flow fields --- src/CMakeLists.txt | 2 + src/ConstantFlow.h | 82 ++++++++++++++++++++ src/FlowFields.h | 153 -------------------------------------- src/ParabolicFlow.h | 84 +++++++++++++++++++++ src/__init__.py | 2 +- src/flow.py | 34 +++++++++ src/module.cc | 5 ++ src/pytest/CMakeLists.txt | 1 + src/pytest/test_flow.py | 36 +++++++++ 9 files changed, 245 insertions(+), 154 deletions(-) create mode 100644 src/ConstantFlow.h delete mode 100644 src/FlowFields.h create mode 100644 src/ParabolicFlow.h create mode 100644 src/flow.py create mode 100644 src/pytest/test_flow.py diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e194f6dc..95b7e193 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,8 @@ set(_${COMPONENT_NAME}_cu_sources # TODO: List all Python modules in python_files. set(python_files __init__.py + bond.py + flow.py pair.py ) diff --git a/src/ConstantFlow.h b/src/ConstantFlow.h new file mode 100644 index 00000000..3b426d80 --- /dev/null +++ b/src/ConstantFlow.h @@ -0,0 +1,82 @@ + +#ifndef AZPLUGINS_CONSTANT_FLOW_H_ +#define AZPLUGINS_CONSTANT_FLOW_H_ + +#include "hoomd/HOOMDMath.h" + +#ifdef __HIPCC__ +#define HOSTDEVICE __host__ __device__ +#else +#define HOSTDEVICE +#include +#endif +namespace hoomd + { +namespace azplugins + { + +//! Position-independent flow along a vector +class ConstantFlow + { + public: + //! Constructor + /*! + *\param U_ Flow field + */ + ConstantFlow(Scalar3 U_): + U(U_){ } + //! Evaluate the flow field + /*! + * \param r position to evaluate flow + * + * This is just a constant, independent of \a r. + */ + HOSTDEVICE Scalar3 operator()(const Scalar3& r) const + { + return U; + } + + HOSTDEVICE Scalar3 getVelocity() const + { + return U; + } + + HOSTDEVICE void setVelocity(const Scalar3& U_) + { + U = U_; + } + + private: + Scalar3 U; //!< Flow field + }; + +namespace detail + { + void export_ConstantFlow(pybind11::module& m) + { + namespace py = pybind11; + py::class_>(m, "ConstantFlow") + .def(py::init()) + .def_property( + "mean_velocity", + [](const ConstantFlow& U) + { + const auto field = U.getVelocity(); + return pybind11::make_tuple(field.x, field.y, field.z); + }, + [](ConstantFlow& U, const pybind11::tuple& field) + { + U.setVelocity(make_scalar3(pybind11::cast(field[0]), + pybind11::cast(field[1]), + pybind11::cast(field[2]))); + }); + } + } //end namespace detail + + } // end of azplugins + } + + +#undef HOSTDEVICE + +#endif // AZPLUGINS_CONSTANT_FLOW_H_ \ No newline at end of file diff --git a/src/FlowFields.h b/src/FlowFields.h deleted file mode 100644 index d5432438..00000000 --- a/src/FlowFields.h +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2018-2020, Michael P. Howard -// Copyright (c) 2021-2024, Auburn University -// Part of azplugins, released under the BSD 3-Clause License. - -/*! - * \file ParabolicFlow.h - * \brief Declaration of ParabolicFlow - */ - -#ifndef AZPLUGINS_PARABOLIC_FLOW_H_ -#define AZPLUGINS_PARABOLIC_FLOW_H_ - -#ifdef NVCC -#define HOSTDEVICE __host__ __device__ -#else -#define HOSTDEVICE -#include "hoomd/extern/pybind/include/pybind11/pybind11.h" -#endif - -namespace azplugins - { - -//! Quiescent (motionless) fluid flow field -class QuiescentFluid - { - public: - //! Construct quiescent fluid - QuiescentFluid() { } - - //! Evaluate the flow field - /*! - * \param r position to evaluate flow - */ - HOSTDEVICE Scalar3 operator()(const Scalar3& r) const - { - return make_scalar3(0.0, 0.0, 0.0); - } - }; - -//! Position-independent flow along a vector -class ConstantFlow - { - public: - //! Constructor - /*! - *\param U_ Flow field - */ - ConstantFlow(Scalar3 U_) : U(U_) { } - - //! Evaluate the flow field - /*! - * \param r position to evaluate flow - * - * This is just a constant, independent of \a r. - */ - HOSTDEVICE Scalar3 operator()(const Scalar3& r) const - { - return U; - } - - private: - Scalar3 U; //!< Flow field - }; - -//! Unidirectional parabolic flow field -/*! - * 1d flow along the \a x axis. The geometry is a parallel plate channel with - * the plates centered around \f$ z = 0 \f$ and positioned at \f$ \pm L \f$. - * The \a y axis is the vorticity direction and periodic. The flow profile in - * this geometry is then - * - * \f[ - * u_x(z) = \frac{3}{2} U \left[1 - \left(\frac{z}{L}\right)^2 \right] - * \f] - * - * Here, \f$ U \f$ is the mean velocity, which is related to the pressure drop - * and viscosity. - * - * \note The user must properly establish no flux of particles through the channel - * walls through an appropriate wall potential. - */ -class ParabolicFlow - { - public: - //! Construct parabolic flow profile - /*! - * \param U_ Mean velocity - * \param L_ Channel half width - */ - ParabolicFlow(Scalar U_, Scalar L_) : Umax(Scalar(1.5) * U_), L(L_) { } - - //! Evaluate the flow field - /*! - * \param r position to evaluate flow - */ - HOSTDEVICE Scalar3 operator()(const Scalar3& r) const - { - const Scalar zr = (r.z / L); - return make_scalar3(Umax * (1. - zr * zr), 0.0, 0.0); - } - - private: - Scalar Umax; //>(m, "QuiescentFluid") - .def(py::init<>()) - .def("__call__", &QuiescentFluid::operator()); - } - -//! Export ConstantFlow to python -/*! - * \param m Python module to export to - */ -void export_ConstantFlow(pybind11::module& m) - { - namespace py = pybind11; - py::class_>(m, "ConstantFlow") - .def(py::init()) - .def("__call__", &ConstantFlow::operator()); - } - -//! Export ParabolicFlow to python -/*! - * \param m Python module to export to - */ -void export_ParabolicFlow(pybind11::module& m) - { - namespace py = pybind11; - py::class_>(m, "ParabolicFlow") - .def(py::init()) - .def("__call__", &ParabolicFlow::operator()); - } - } // end namespace detail -#endif // NVCC - - } // end namespace azplugins - -#undef HOSTDEVICE - -#endif // AZPLUGINS_PARABOLIC_FLOW_H_ diff --git a/src/ParabolicFlow.h b/src/ParabolicFlow.h new file mode 100644 index 00000000..5866011f --- /dev/null +++ b/src/ParabolicFlow.h @@ -0,0 +1,84 @@ +// Copyright (c) 2018-2020, Michael P. Howard +// Copyright (c) 2021-2024, Auburn University +// Part of azplugins, released under the BSD 3-Clause License. + +/*! + * \file ParabolicFlow.h + * \brief Declaration of ParabolicFlow + */ + +#ifndef AZPLUGINS_PARABOLIC_FLOW_H_ +#define AZPLUGINS_PARABOLIC_FLOW_H_ + +#include "hoomd/HOOMDMath.h" + +#ifdef __HIPCC__ +#define HOSTDEVICE __host__ __device__ +#else +#define HOSTDEVICE +#include +#endif +namespace hoomd + { +namespace azplugins + { +class ParabolicFlow + { + public: + //! Construct parabolic flow profile + /*! + * \param U_ Mean velocity + * \param L_ Separation + */ + ParabolicFlow(Scalar U_, Scalar L_) : Umax(Scalar(1.5) * U_), L(Scalar(0.5) * L_) { } + + //! Evaluate the flow field + /*! + * \param r position to evaluate flow + */ + HOSTDEVICE Scalar3 operator()(const Scalar3& r) const + { + const Scalar zr = (r.z / L); + return make_scalar3(Umax * (1. - zr * zr), 0.0, 0.0); + } + + HOSTDEVICE Scalar getVelocity() const + { + return Scalar(0.6666666667) * Umax; + } + + HOSTDEVICE void setVelocity(const Scalar& U) + { + Umax = Scalar(1.5) * U; + } + + HOSTDEVICE Scalar getLength() const + { + return Scalar(2.0) * L; + } + + HOSTDEVICE void setLength(const Scalar& L_) + { + L = Scalar(0.5) * L_; + } + private: + Scalar Umax; //>(m, "ParabolicFlow") + .def(py::init()) + .def_property("mean_velocity", &ParabolicFlow::getVelocity, &ParabolicFlow::setVelocity) + .def_property("separation", &ParabolicFlow::getLength, &ParabolicFlow::setLength); + } + } + }// end of azplugins + } +#undef HOSTDEVICE + +#endif // AZPLUGINS_PARABOLIC_FLOW_H_ diff --git a/src/__init__.py b/src/__init__.py index 7a19c75d..386e8c10 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -4,6 +4,6 @@ """azplugins.""" -from hoomd.azplugins import bond, pair +from hoomd.azplugins import bond, pair, flow __version__ = '1.0.0' diff --git a/src/flow.py b/src/flow.py new file mode 100644 index 00000000..d88aa441 --- /dev/null +++ b/src/flow.py @@ -0,0 +1,34 @@ +import hoomd +from hoomd import _hoomd +from hoomd.data.parameterdicts import ParameterDict +from hoomd.operation import _HOOMDBaseObject +from . import _azplugins + + + +class FlowField(_HOOMDBaseObject): + pass + +class ConstantFlow(FlowField): + def __init__(self, mean_velocity): + super().__init__() + param_dict = ParameterDict(mean_velocity=(float, float, float)) + param_dict["mean_velocity"] = mean_velocity + self._param_dict.update(param_dict) + + def _attach_hook(self): + self._cpp_obj = _azplugins.ConstantFlow(_hoomd.make_scalar3(self.mean_velocity[0], self.mean_velocity[1], self.mean_velocity[2])) + super()._attach_hook() + +class ParabolicFlow(FlowField): + def __init__(self, mean_velocity, separation): + super().__init__() + + param_dict = ParameterDict( + mean_velocity=float(mean_velocity),separation=float(separation)) + + self._param_dict.update(param_dict) + + def _attach_hook(self): + self._cpp_obj = _azplugins.ParabolicFlow(self.mean_velocity, self.separation) + super()._attach_hook() diff --git a/src/module.cc b/src/module.cc index 1e5d92ef..ffd8905f 100644 --- a/src/module.cc +++ b/src/module.cc @@ -2,6 +2,8 @@ // Copyright (c) 2021-2024, Auburn University // Part of azplugins, released under the BSD 3-Clause License. +#include "ConstantFlow.h" +#include "ParabolicFlow.h" #include namespace hoomd @@ -49,6 +51,7 @@ namespace azplugins { namespace detail { + } // namespace detail } // namespace azplugins } // namespace hoomd @@ -57,4 +60,6 @@ namespace detail PYBIND11_MODULE(_azplugins, m) { using namespace hoomd::azplugins::detail; + export_ConstantFlow(m); + export_ParabolicFlow(m); } diff --git a/src/pytest/CMakeLists.txt b/src/pytest/CMakeLists.txt index 2e72f523..b4088268 100644 --- a/src/pytest/CMakeLists.txt +++ b/src/pytest/CMakeLists.txt @@ -2,6 +2,7 @@ set(test_files __init__.py test_bond.py + test_flow.py test_pair.py ) diff --git a/src/pytest/test_flow.py b/src/pytest/test_flow.py new file mode 100644 index 00000000..fd8ceff8 --- /dev/null +++ b/src/pytest/test_flow.py @@ -0,0 +1,36 @@ +import collections + +import hoomd +import numpy +import pytest +from hoomd.conftest import pickling_check +import hoomd.azplugins + +def test_constant_flow_field(simulation_factory): + # make the force + U = hoomd.azplugins.flow.ConstantFlow(mean_velocity= (1,0,0)) + numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 0, 0)) + pickling_check(U) + + U.mean_velocity= (1,1,1) + numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 1, 1)) + + sim = simulation_factory() + U._attach(sim) + numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 1, 1)) + + +def test_parabolic_flow_field(simulation_factory): + + U = hoomd.azplugins.flow.ParabolicFlow(mean_velocity= 4, separation= 10) + assert U.mean_velocity == 4 + assert U.separation == 10 + pickling_check(U) + + U.mean_velocity = 10 + U.separation = 20 + numpy.testing.assert_array_almost_equal((U.mean_velocity, U.separation), (10, 20)) + + sim = simulation_factory() + U._attach(sim) + numpy.testing.assert_array_almost_equal((U.mean_velocity, U.separation), (10, 20)) From f232a1edb9cd5169a235f6a68d10cdc3f40b161d Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Tue, 4 Jun 2024 12:19:48 -0500 Subject: [PATCH 02/11] Formatting changes --- src/ConstantFlow.h | 65 +++++++++++++++++++++-------------------- src/ParabolicFlow.h | 21 ++++++------- src/flow.py | 24 ++++++++++----- src/pytest/test_flow.py | 24 ++++++++------- 4 files changed, 75 insertions(+), 59 deletions(-) diff --git a/src/ConstantFlow.h b/src/ConstantFlow.h index 3b426d80..f54e0779 100644 --- a/src/ConstantFlow.h +++ b/src/ConstantFlow.h @@ -1,3 +1,6 @@ +// Copyright (c) 2018-2020, Michael P. Howard +// Copyright (c) 2021-2024, Auburn University +// Part of azplugins, released under the BSD 3-Clause License. #ifndef AZPLUGINS_CONSTANT_FLOW_H_ #define AZPLUGINS_CONSTANT_FLOW_H_ @@ -23,8 +26,7 @@ class ConstantFlow /*! *\param U_ Flow field */ - ConstantFlow(Scalar3 U_): - U(U_){ } + ConstantFlow(Scalar3 U_) : U(U_) { } //! Evaluate the flow field /*! * \param r position to evaluate flow @@ -34,49 +36,48 @@ class ConstantFlow HOSTDEVICE Scalar3 operator()(const Scalar3& r) const { return U; - } - + } + HOSTDEVICE Scalar3 getVelocity() const { return U; } - + HOSTDEVICE void setVelocity(const Scalar3& U_) { U = U_; - } - + } + private: Scalar3 U; //!< Flow field }; namespace detail { - void export_ConstantFlow(pybind11::module& m) - { - namespace py = pybind11; - py::class_>(m, "ConstantFlow") - .def(py::init()) - .def_property( - "mean_velocity", - [](const ConstantFlow& U) - { - const auto field = U.getVelocity(); - return pybind11::make_tuple(field.x, field.y, field.z); - }, - [](ConstantFlow& U, const pybind11::tuple& field) - { - U.setVelocity(make_scalar3(pybind11::cast(field[0]), - pybind11::cast(field[1]), - pybind11::cast(field[2]))); - }); - } - } //end namespace detail - - } // end of azplugins - } - +void export_ConstantFlow(pybind11::module& m) + { + namespace py = pybind11; + py::class_>(m, "ConstantFlow") + .def(py::init()) + .def_property( + "mean_velocity", + [](const ConstantFlow& U) + { + const auto field = U.getVelocity(); + return pybind11::make_tuple(field.x, field.y, field.z); + }, + [](ConstantFlow& U, const pybind11::tuple& field) + { + U.setVelocity(make_scalar3(pybind11::cast(field[0]), + pybind11::cast(field[1]), + pybind11::cast(field[2]))); + }); + } + } // end namespace detail + + } // namespace azplugins + } // namespace hoomd #undef HOSTDEVICE -#endif // AZPLUGINS_CONSTANT_FLOW_H_ \ No newline at end of file +#endif // AZPLUGINS_CONSTANT_FLOW_H_ diff --git a/src/ParabolicFlow.h b/src/ParabolicFlow.h index 5866011f..8d1dfe68 100644 --- a/src/ParabolicFlow.h +++ b/src/ParabolicFlow.h @@ -28,7 +28,7 @@ class ParabolicFlow //! Construct parabolic flow profile /*! * \param U_ Mean velocity - * \param L_ Separation + * \param L_ Separation */ ParabolicFlow(Scalar U_, Scalar L_) : Umax(Scalar(1.5) * U_), L(Scalar(0.5) * L_) { } @@ -41,7 +41,7 @@ class ParabolicFlow const Scalar zr = (r.z / L); return make_scalar3(Umax * (1. - zr * zr), 0.0, 0.0); } - + HOSTDEVICE Scalar getVelocity() const { return Scalar(0.6666666667) * Umax; @@ -61,24 +61,25 @@ class ParabolicFlow { L = Scalar(0.5) * L_; } + private: Scalar Umax; //>(m, "ParabolicFlow") +void export_ParabolicFlow(pybind11::module& m) + { + namespace py = pybind11; + py::class_>(m, "ParabolicFlow") .def(py::init()) .def_property("mean_velocity", &ParabolicFlow::getVelocity, &ParabolicFlow::setVelocity) .def_property("separation", &ParabolicFlow::getLength, &ParabolicFlow::setLength); - } - } - }// end of azplugins } + } // namespace detail + } // namespace azplugins + } // namespace hoomd #undef HOSTDEVICE #endif // AZPLUGINS_PARABOLIC_FLOW_H_ diff --git a/src/flow.py b/src/flow.py index d88aa441..1ea56df9 100644 --- a/src/flow.py +++ b/src/flow.py @@ -1,3 +1,7 @@ +# Copyright (c) 2018-2020, Michael P. Howard +# Copyright (c) 2021-2024, Auburn University +# Part of azplugins, released under the BSD 3-Clause License. + import hoomd from hoomd import _hoomd from hoomd.data.parameterdicts import ParameterDict @@ -5,28 +9,34 @@ from . import _azplugins - class FlowField(_HOOMDBaseObject): pass - + + class ConstantFlow(FlowField): def __init__(self, mean_velocity): super().__init__() param_dict = ParameterDict(mean_velocity=(float, float, float)) - param_dict["mean_velocity"] = mean_velocity + param_dict['mean_velocity'] = mean_velocity self._param_dict.update(param_dict) - + def _attach_hook(self): - self._cpp_obj = _azplugins.ConstantFlow(_hoomd.make_scalar3(self.mean_velocity[0], self.mean_velocity[1], self.mean_velocity[2])) + self._cpp_obj = _azplugins.ConstantFlow( + _hoomd.make_scalar3( + self.mean_velocity[0], self.mean_velocity[1], self.mean_velocity[2] + ) + ) super()._attach_hook() + class ParabolicFlow(FlowField): def __init__(self, mean_velocity, separation): super().__init__() param_dict = ParameterDict( - mean_velocity=float(mean_velocity),separation=float(separation)) - + mean_velocity=float(mean_velocity), separation=float(separation) + ) + self._param_dict.update(param_dict) def _attach_hook(self): diff --git a/src/pytest/test_flow.py b/src/pytest/test_flow.py index fd8ceff8..17d9a223 100644 --- a/src/pytest/test_flow.py +++ b/src/pytest/test_flow.py @@ -1,3 +1,7 @@ +# Copyright (c) 2018-2020, Michael P. Howard +# Copyright (c) 2021-2024, Auburn University +# Part of azplugins, released under the BSD 3-Clause License. + import collections import hoomd @@ -6,31 +10,31 @@ from hoomd.conftest import pickling_check import hoomd.azplugins + def test_constant_flow_field(simulation_factory): # make the force - U = hoomd.azplugins.flow.ConstantFlow(mean_velocity= (1,0,0)) + U = hoomd.azplugins.flow.ConstantFlow(mean_velocity=(1, 0, 0)) numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 0, 0)) pickling_check(U) - - U.mean_velocity= (1,1,1) + + U.mean_velocity = (1, 1, 1) numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 1, 1)) - + sim = simulation_factory() U._attach(sim) numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 1, 1)) - - -def test_parabolic_flow_field(simulation_factory): - U = hoomd.azplugins.flow.ParabolicFlow(mean_velocity= 4, separation= 10) + +def test_parabolic_flow_field(simulation_factory): + U = hoomd.azplugins.flow.ParabolicFlow(mean_velocity=4, separation=10) assert U.mean_velocity == 4 assert U.separation == 10 pickling_check(U) - + U.mean_velocity = 10 U.separation = 20 numpy.testing.assert_array_almost_equal((U.mean_velocity, U.separation), (10, 20)) - + sim = simulation_factory() U._attach(sim) numpy.testing.assert_array_almost_equal((U.mean_velocity, U.separation), (10, 20)) From caef0072ac2b669e8bb409d5897bc8c8be4c8819 Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Tue, 4 Jun 2024 16:33:28 -0500 Subject: [PATCH 03/11] Update two step BD and Langevin flow class --- src/TwoStepBrownianFlow.h | 66 +++++++++++------------------------- src/TwoStepLangevinFlow.h | 71 ++++++++++----------------------------- src/module.cc | 18 +++++----- 3 files changed, 47 insertions(+), 108 deletions(-) diff --git a/src/TwoStepBrownianFlow.h b/src/TwoStepBrownianFlow.h index c9f12f54..f7136330 100644 --- a/src/TwoStepBrownianFlow.h +++ b/src/TwoStepBrownianFlow.h @@ -10,16 +10,17 @@ #ifndef AZPLUGINS_TWO_STEP_BROWNIAN_FLOW_H_ #define AZPLUGINS_TWO_STEP_BROWNIAN_FLOW_H_ -#ifdef NVCC +#ifdef __HIPCC__ #error This header cannot be compiled by nvcc #endif #include "hoomd/RandomNumbers.h" -#include "hoomd/extern/pybind/include/pybind11/pybind11.h" +#include #include "hoomd/md/TwoStepLangevinBase.h" #include "RNGIdentifiers.h" - +namespace hoomd + { namespace azplugins { @@ -27,7 +28,8 @@ namespace azplugins /*! * \note Only translational motion is supported by this integrator. */ -template class PYBIND11_EXPORT TwoStepBrownianFlow : public TwoStepLangevinBase +template +class PYBIND11_EXPORT TwoStepBrownianFlow : public md::TwoStepLangevinBase { public: //! Constructor @@ -35,17 +37,13 @@ template class PYBIND11_EXPORT TwoStepBrownianFlow : public Two std::shared_ptr group, std::shared_ptr T, std::shared_ptr flow_field, - unsigned int seed, - bool use_lambda, - Scalar lambda, bool noiseless) - : TwoStepLangevinBase(sysdef, group, T, seed, use_lambda, lambda), m_flow_field(flow_field), + : md::TwoStepLangevinBase(sysdef, group, T), m_flow_field(flow_field), m_noiseless(noiseless) { m_exec_conf->msg->notice(5) << "Constructing TwoStepBrownianFlow" << std::endl; if (m_sysdef->getNDimensions() < 3) { - m_exec_conf->msg->error() << "flow.brownian is only supported in 3D" << std::endl; throw std::runtime_error("Brownian dynamics in flow is only supported in 3D"); } } @@ -75,10 +73,6 @@ template class PYBIND11_EXPORT TwoStepBrownianFlow : public Two /*! * \param flow_field New flow field to apply */ - void setFlowField(std::shared_ptr flow_field) - { - m_flow_field = flow_field; - } //! Get the flag for if noise is applied to the motion bool getNoiseless() const @@ -90,10 +84,6 @@ template class PYBIND11_EXPORT TwoStepBrownianFlow : public Two /*! * \param noiseless If true, do not apply a random diffusive force */ - void setNoiseless(bool noiseless) - { - m_noiseless = noiseless; - } protected: std::shared_ptr m_flow_field; //!< Flow field functor @@ -105,13 +95,8 @@ void TwoStepBrownianFlow::integrateStepOne(unsigned int timestep) { if (m_aniso) { - m_exec_conf->msg->error() << "azplugins.integrate: anisotropic particles are not supported " - "with brownian flow integrators." - << std::endl; throw std::runtime_error("Anisotropic integration not supported with brownian flow"); } - if (m_prof) - m_prof->push("Brownian step"); ArrayHandle h_pos(m_pdata->getPositions(), access_location::host, @@ -121,16 +106,15 @@ void TwoStepBrownianFlow::integrateStepOne(unsigned int timestep) ArrayHandle h_net_force(m_pdata->getNetForce(), access_location::host, access_mode::read); - ArrayHandle h_diameter(m_pdata->getDiameters(), - access_location::host, - access_mode::read); ArrayHandle h_gamma(m_gamma, access_location::host, access_mode::read); - const Scalar currentTemp = m_T->getValue(timestep); + const Scalar currentTemp = (*m_T)(timestep); const FlowField& flow_field = *m_flow_field; const BoxDim& box = m_pdata->getBox(); + uint16_t seed = m_sysdef->getSeed(); + // perform the first half step of velocity verlet unsigned int group_size = m_group->getNumMembers(); for (unsigned int group_idx = 0; group_idx < group_size; group_idx++) @@ -141,13 +125,7 @@ void TwoStepBrownianFlow::integrateStepOne(unsigned int timestep) const Scalar4 postype = h_pos.data[idx]; Scalar3 pos = make_scalar3(postype.x, postype.y, postype.z); const unsigned int type = __scalar_as_int(postype.w); - Scalar gamma; - if (m_use_lambda) - gamma = m_lambda * h_diameter.data[idx]; - else - { - gamma = h_gamma.data[type]; - } + const Scalar gamma = h_gamma.data[type]; // get the flow velocity at the current position const Scalar3 flow_vel = flow_field(pos); @@ -158,10 +136,10 @@ void TwoStepBrownianFlow::integrateStepOne(unsigned int timestep) coeff = Scalar(0.0); // draw random force - hoomd::RandomGenerator rng(azplugins::RNGIdentifier::TwoStepBrownianFlow, - m_seed, - h_tag.data[idx], - timestep); + hoomd::RandomGenerator rng(hoomd::Seed(hoomd::azplugins::detail::RNGIdentifier::TwoStepBrownianFlow, + timestep, + seed), + hoomd::Counter(h_tag.data[idx])); hoomd::UniformDistribution uniform(-coeff, coeff); const Scalar3 random_force = make_scalar3(uniform(rng), uniform(rng), uniform(rng)); @@ -176,9 +154,6 @@ void TwoStepBrownianFlow::integrateStepOne(unsigned int timestep) // write out the position h_pos.data[idx] = make_scalar4(pos.x, pos.y, pos.z, type); } - - if (m_prof) - m_prof->pop(); } namespace detail @@ -192,19 +167,16 @@ void export_TwoStepBrownianFlow(pybind11::module& m, const std::string& name) py::class_>(m, name.c_str(), - py::base()) + py::base()) .def(py::init, std::shared_ptr, std::shared_ptr, std::shared_ptr, - unsigned int, - bool, - Scalar, bool>()) - .def("setFlowField", &BrownianFlow::setFlowField) - .def("setNoiseless", &BrownianFlow::setNoiseless); + .def("getFlowField", &BrownianFlow::getFlowField) + .def("getNoiseless", &BrownianFlow::getNoiseless); } } // end namespace detail } // end namespace azplugins - + } // end namespace hoomd #endif // AZPLUGINS_TWO_STEP_BROWNIAN_FLOW_H_ diff --git a/src/TwoStepLangevinFlow.h b/src/TwoStepLangevinFlow.h index d0cd9764..2a68cd07 100644 --- a/src/TwoStepLangevinFlow.h +++ b/src/TwoStepLangevinFlow.h @@ -10,16 +10,17 @@ #ifndef AZPLUGINS_TWO_STEP_LANGEVIN_FLOW_H_ #define AZPLUGINS_TWO_STEP_LANGEVIN_FLOW_H_ -#ifdef NVCC +#ifdef __HIPCC__ #error This header cannot be compiled by nvcc #endif #include "hoomd/RandomNumbers.h" -#include "hoomd/extern/pybind/include/pybind11/pybind11.h" +#include #include "hoomd/md/TwoStepLangevinBase.h" #include "RNGIdentifiers.h" - +namespace hoomd + { namespace azplugins { @@ -27,7 +28,7 @@ namespace azplugins /*! * \note Only translational motion is supported by this integrator. */ -template class PYBIND11_EXPORT TwoStepLangevinFlow : public TwoStepLangevinBase +template class PYBIND11_EXPORT TwoStepLangevinFlow : public md::TwoStepLangevinBase { public: //! Constructor @@ -35,17 +36,13 @@ template class PYBIND11_EXPORT TwoStepLangevinFlow : public Two std::shared_ptr group, std::shared_ptr T, std::shared_ptr flow_field, - unsigned int seed, - bool use_lambda, - Scalar lambda, bool noiseless) - : TwoStepLangevinBase(sysdef, group, T, seed, use_lambda, lambda), m_flow_field(flow_field), + : TwoStepLangevinBase(sysdef, group, T), m_flow_field(flow_field), m_noiseless(noiseless) { m_exec_conf->msg->notice(5) << "Constructing TwoStepLangevinFlow" << std::endl; if (m_sysdef->getNDimensions() < 3) { - m_exec_conf->msg->error() << "flow.langevin is only supported in 3D" << std::endl; throw std::runtime_error("Langevin dynamics in flow is only supported in 3D"); } } @@ -72,10 +69,6 @@ template class PYBIND11_EXPORT TwoStepLangevinFlow : public Two /*! * \param flow_field New flow field to apply */ - void setFlowField(std::shared_ptr flow_field) - { - m_flow_field = flow_field; - } //! Get the flag for if noise is applied to the motion bool getNoiseless() const @@ -87,10 +80,6 @@ template class PYBIND11_EXPORT TwoStepLangevinFlow : public Two /*! * \param noiseless If true, do not apply a random diffusive force */ - void setNoiseless(bool noiseless) - { - m_noiseless = noiseless; - } protected: std::shared_ptr m_flow_field; //!< Flow field functor @@ -102,13 +91,8 @@ void TwoStepLangevinFlow::integrateStepOne(unsigned int timestep) { if (m_aniso) { - m_exec_conf->msg->error() << "azplugins.integrate: anisotropic particles are not supported " - "with langevin flow integrators." - << std::endl; throw std::runtime_error("Anisotropic integration not supported with langevin flow"); } - if (m_prof) - m_prof->push("Langevin step 1"); ArrayHandle h_pos(m_pdata->getPositions(), access_location::host, @@ -151,9 +135,6 @@ void TwoStepLangevinFlow::integrateStepOne(unsigned int timestep) h_pos.data[idx] = make_scalar4(pos.x, pos.y, pos.z, __int_as_scalar(type)); h_vel.data[idx] = make_scalar4(vel.x, vel.y, vel.z, mass); } - - if (m_prof) - m_prof->pop(); } template @@ -166,8 +147,6 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) << std::endl; throw std::runtime_error("Anisotropic integration not supported with langevin flow"); } - if (m_prof) - m_prof->push("Langevin step 2"); ArrayHandle h_vel(m_pdata->getVelocities(), access_location::host, @@ -179,33 +158,23 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) ArrayHandle h_pos(m_pdata->getPositions(), access_location::host, access_mode::read); ArrayHandle h_tag(m_pdata->getTags(), access_location::host, access_mode::read); ArrayHandle h_net_force(m_pdata->getNetForce(), - access_location::host, - access_mode::read); - ArrayHandle h_diameter(m_pdata->getDiameters(), access_location::host, access_mode::read); ArrayHandle h_gamma(m_gamma, access_location::host, access_mode::read); - const Scalar currentTemp = m_T->getValue(timestep); + const Scalar currentTemp = (*m_T)(timestep); const FlowField& flow_field = *m_flow_field; + uint16_t seed = m_sysdef->getSeed(); // second step of velocity verlet while modifying accelerations unsigned int group_size = m_group->getNumMembers(); for (unsigned int group_idx = 0; group_idx < group_size; group_idx++) { unsigned int idx = m_group->getMemberIndex(group_idx); - // get the friction coefficient const Scalar4 postype = h_pos.data[idx]; - Scalar gamma; - if (m_use_lambda) - gamma = m_lambda * h_diameter.data[idx]; - else - { - unsigned int type = __scalar_as_int(postype.w); - gamma = h_gamma.data[type]; - } - + unsigned int type = __scalar_as_int(postype.w); + const Scalar gamma = h_gamma.data[type]; // get the flow velocity at the current position const Scalar3 flow_vel = flow_field(make_scalar3(postype.x, postype.y, postype.z)); @@ -213,10 +182,10 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) Scalar coeff = fast::sqrt(Scalar(6.0) * gamma * currentTemp / m_deltaT); if (m_noiseless) coeff = Scalar(0.0); - hoomd::RandomGenerator rng(azplugins::RNGIdentifier::TwoStepLangevinFlow, - m_seed, - h_tag.data[idx], - timestep); + hoomd::RandomGenerator rng(hoomd::Seed(hoomd::azplugins::detail::RNGIdentifier::TwoStepBrownianFlow, + timestep, + seed), + hoomd::Counter(h_tag.data[idx])); hoomd::UniformDistribution uniform(-coeff, coeff); const Scalar3 random = make_scalar3(uniform(rng), uniform(rng), uniform(rng)); @@ -244,8 +213,6 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) h_accel.data[idx] = accel; } - if (m_prof) - m_prof->pop(); } namespace detail @@ -259,19 +226,17 @@ void export_TwoStepLangevinFlow(pybind11::module& m, const std::string& name) py::class_>(m, name.c_str(), - py::base()) + py::base()) .def(py::init, std::shared_ptr, std::shared_ptr, std::shared_ptr, - unsigned int, - bool, - Scalar, bool>()) - .def("setFlowField", &LangevinFlow::setFlowField) - .def("setNoiseless", &LangevinFlow::setNoiseless); + .def("getFlowField", &LangevinFlow::getFlowField) + .def("getNoiseless", &LangevinFlow::getNoiseless); } } // end namespace detail } // end namespace azplugins + } // end namespace hoomd #endif // AZPLUGINS_TWO_STEP_LANGEVIN_FLOW_H_ diff --git a/src/module.cc b/src/module.cc index 7a17faad..c620ec21 100644 --- a/src/module.cc +++ b/src/module.cc @@ -5,7 +5,8 @@ #include "ConstantFlow.h" #include "ParabolicFlow.h" #include - +#include "TwoStepBrownianFlow.h" +#include "TwoStepLangevinFlow.h" namespace hoomd { //! Plugins for soft matter @@ -53,12 +54,9 @@ namespace detail { void export_PotentialPairHertz(pybind11::module&); - #ifdef ENABLE_HIP void export_PotentialPairHertzGPU(pybind11::module&); #endif // ENABLE_HIP - - } // namespace detail } // namespace azplugins } // namespace hoomd @@ -67,13 +65,17 @@ void export_PotentialPairHertzGPU(pybind11::module&); PYBIND11_MODULE(_azplugins, m) { using namespace hoomd::azplugins::detail; - + export_PotentialPairHertz(m); + export_ConstantFlow(m); export_ParabolicFlow(m); - - export_PotentialPairHertz(m); - + export_TwoStepBrownianFlow(m, "BrownianConstantFlow"); + export_TwoStepBrownianFlow(m, "BrownianParabolicFlow"); + export_TwoStepLangevinFlow(m, "LangevinConstantFlow"); + export_TwoStepLangevinFlow(m, "LangevinParabolicFlow"); #ifdef ENABLE_HIP export_PotentialPairHertzGPU(m); #endif // ENABLE_HIP } + + \ No newline at end of file From 969feb1308e1cb05bcf67f121a5056f697c7cf72 Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Tue, 4 Jun 2024 16:33:56 -0500 Subject: [PATCH 04/11] Update random number generator --- src/RNGIdentifiers.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/RNGIdentifiers.h b/src/RNGIdentifiers.h index 8e2c7c1f..dd28d486 100644 --- a/src/RNGIdentifiers.h +++ b/src/RNGIdentifiers.h @@ -10,18 +10,23 @@ #ifndef AZPLUGINS_RNG_IDENTIFIERS_H_ #define AZPLUGINS_RNG_IDENTIFIERS_H_ +#include + +namespace hoomd + { namespace azplugins { - +namespace detail + { struct RNGIdentifier { - // hoomd's identifiers, changed by +/- 1 - static const uint32_t DPDEvaluatorGeneralWeight = 0x4a84f5d1; - static const uint32_t TwoStepBrownianFlow = 0x431287fe; - static const uint32_t TwoStepLangevinFlow = 0x89abcdee; - static const uint32_t ParticleEvaporator = 0x3eb8536f; + static const uint8_t DPDEvaluatorGeneralWeight = 200; + static const uint8_t TwoStepBrownianFlow = 201; + static const uint8_t TwoStepLangevinFlow = 202; + static const uint8_t ParticleEvaporator = 203; }; - + } // end namespace detail } // end namespace azplugins + } // end namespace hoomd #endif // AZPLUGINS_RNG_IDENTIFIERS_H_ From 2c825027750a1112b08e64960cbea5bba8c5c941 Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Wed, 5 Jun 2024 10:26:30 -0500 Subject: [PATCH 05/11] Add cpp files for Parabolic and Constant flow class --- .ruff.toml | 2 ++ src/CMakeLists.txt | 2 ++ src/ConstantFlow.cc | 34 +++++++++++++++++++++++ src/ConstantFlow.h | 33 +++++------------------ src/ParabolicFlow.cc | 23 ++++++++++++++++ src/ParabolicFlow.h | 40 ++++++++++++++++----------- src/__init__.py | 2 +- src/flow.py | 60 ++++++++++++++++++++++++++++++++++++----- src/module.cc | 10 +++---- src/pytest/test_flow.py | 27 ++++++++++++------- 10 files changed, 168 insertions(+), 65 deletions(-) create mode 100644 src/ConstantFlow.cc create mode 100644 src/ParabolicFlow.cc diff --git a/.ruff.toml b/.ruff.toml index 3a8f2a73..faef7fa0 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -32,6 +32,8 @@ ignore = [ "__init__.py" = ["F401", # __init__.py import submodules for use by the package importer. ] +"*/pytest/*.py" = ["PLR2004", # allow "magic numbers" in tests +] [lint.pydocstyle] convention = "google" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4c4bb97..b02ec7e4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,8 +3,10 @@ set(COMPONENT_NAME azplugins) # TODO: List all host C++ source code files in _${COMPONENT_NAME}_sources. set(_${COMPONENT_NAME}_sources + ConstantFlow.cc GroupVelocityCompute.cc module.cc + ParabolicFlow.cc ) # TODO: List all GPU C++ source code files in _${COMPONENT_NAME}_cu_sources. diff --git a/src/ConstantFlow.cc b/src/ConstantFlow.cc new file mode 100644 index 00000000..dea4527c --- /dev/null +++ b/src/ConstantFlow.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2018-2020, Michael P. Howard +// Copyright (c) 2021-2024, Auburn University +// Part of azplugins, released under the BSD 3-Clause License. + +#include "ConstantFlow.h" + +namespace hoomd + { +namespace azplugins + { +namespace detail + { +void export_ConstantFlow(pybind11::module& m) + { + namespace py = pybind11; + py::class_>(m, "ConstantFlow") + .def(py::init()) + .def_property( + "velocity", + [](const ConstantFlow& U) + { + const auto field = U.getVelocity(); + return pybind11::make_tuple(field.x, field.y, field.z); + }, + [](ConstantFlow& U, const pybind11::tuple& field) + { + U.setVelocity(make_scalar3(pybind11::cast(field[0]), + pybind11::cast(field[1]), + pybind11::cast(field[2]))); + }); + } + } // end namespace detail + } // end namespace azplugins + } // end namespace hoomd diff --git a/src/ConstantFlow.h b/src/ConstantFlow.h index f54e0779..6949e023 100644 --- a/src/ConstantFlow.h +++ b/src/ConstantFlow.h @@ -5,14 +5,18 @@ #ifndef AZPLUGINS_CONSTANT_FLOW_H_ #define AZPLUGINS_CONSTANT_FLOW_H_ +#ifndef __HIPCC__ +#include +#endif + #include "hoomd/HOOMDMath.h" -#ifdef __HIPCC__ +#ifndef __HIPCC__ #define HOSTDEVICE __host__ __device__ #else #define HOSTDEVICE -#include -#endif +#endif // __HIPCC__ + namespace hoomd { namespace azplugins @@ -52,29 +56,6 @@ class ConstantFlow Scalar3 U; //!< Flow field }; -namespace detail - { -void export_ConstantFlow(pybind11::module& m) - { - namespace py = pybind11; - py::class_>(m, "ConstantFlow") - .def(py::init()) - .def_property( - "mean_velocity", - [](const ConstantFlow& U) - { - const auto field = U.getVelocity(); - return pybind11::make_tuple(field.x, field.y, field.z); - }, - [](ConstantFlow& U, const pybind11::tuple& field) - { - U.setVelocity(make_scalar3(pybind11::cast(field[0]), - pybind11::cast(field[1]), - pybind11::cast(field[2]))); - }); - } - } // end namespace detail - } // namespace azplugins } // namespace hoomd diff --git a/src/ParabolicFlow.cc b/src/ParabolicFlow.cc new file mode 100644 index 00000000..a281b560 --- /dev/null +++ b/src/ParabolicFlow.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2018-2020, Michael P. Howard +// Copyright (c) 2021-2024, Auburn University +// Part of azplugins, released under the BSD 3-Clause License. + +#include "ParabolicFlow.h" + +namespace hoomd + { +namespace azplugins + { +namespace detail + { +void export_ParabolicFlow(pybind11::module& m) + { + namespace py = pybind11; + py::class_>(m, "ParabolicFlow") + .def(py::init()) + .def_property("mean_velocity", &ParabolicFlow::getVelocity, &ParabolicFlow::setVelocity) + .def_property("separation", &ParabolicFlow::getLength, &ParabolicFlow::setLength); + } + } // namespace detail + } // namespace azplugins + } // namespace hoomd diff --git a/src/ParabolicFlow.h b/src/ParabolicFlow.h index 8d1dfe68..d7d1bf2f 100644 --- a/src/ParabolicFlow.h +++ b/src/ParabolicFlow.h @@ -10,18 +10,39 @@ #ifndef AZPLUGINS_PARABOLIC_FLOW_H_ #define AZPLUGINS_PARABOLIC_FLOW_H_ +#ifndef __HIPCC__ +#include +#endif + #include "hoomd/HOOMDMath.h" -#ifdef __HIPCC__ +#ifndef __HIPCC__ #define HOSTDEVICE __host__ __device__ #else #define HOSTDEVICE -#include -#endif +#endif // __HIPCC__ + namespace hoomd { namespace azplugins { +//! Unidirectional parabolic flow field +/*! + * 1d flow along the \a x axis. The geometry is a parallel plate channel with + * the plates centered around \f$ z = 0 \f$ and positioned at \f$ \pm L \f$. + * The \a y axis is the vorticity direction and periodic. The flow profile in + * this geometry is then + * + * \f[ + * u_x(z) = \frac{3}{2} U \left[1 - \left(\frac{z}{L}\right)^2 \right] + * \f] + * + * Here, \f$ U \f$ is the mean velocity, which is related to the pressure drop + * and viscosity. + * + * \note The user must properly establish no flux of particles through the channel + * walls through an appropriate wall potential. + */ class ParabolicFlow { public: @@ -44,7 +65,7 @@ class ParabolicFlow HOSTDEVICE Scalar getVelocity() const { - return Scalar(0.6666666667) * Umax; + return Umax / Scalar(1.5); } HOSTDEVICE void setVelocity(const Scalar& U) @@ -67,17 +88,6 @@ class ParabolicFlow Scalar L; //!< Full width }; -namespace detail - { -void export_ParabolicFlow(pybind11::module& m) - { - namespace py = pybind11; - py::class_>(m, "ParabolicFlow") - .def(py::init()) - .def_property("mean_velocity", &ParabolicFlow::getVelocity, &ParabolicFlow::setVelocity) - .def_property("separation", &ParabolicFlow::getLength, &ParabolicFlow::setLength); - } - } // namespace detail } // namespace azplugins } // namespace hoomd #undef HOSTDEVICE diff --git a/src/__init__.py b/src/__init__.py index 386e8c10..740d46fe 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -4,6 +4,6 @@ """azplugins.""" -from hoomd.azplugins import bond, pair, flow +from hoomd.azplugins import bond, flow, pair __version__ = '1.0.0' diff --git a/src/flow.py b/src/flow.py index 1ea56df9..21c640b1 100644 --- a/src/flow.py +++ b/src/flow.py @@ -2,34 +2,80 @@ # Copyright (c) 2021-2024, Auburn University # Part of azplugins, released under the BSD 3-Clause License. +"""Flow fields.""" + import hoomd -from hoomd import _hoomd +from hoomd.azplugins import _azplugins from hoomd.data.parameterdicts import ParameterDict from hoomd.operation import _HOOMDBaseObject -from . import _azplugins class FlowField(_HOOMDBaseObject): + """Base flow field.""" + pass +# hoomd.azplugins.flow.constant class ConstantFlow(FlowField): - def __init__(self, mean_velocity): + r"""Constant flow profile. + + Args: + U (tuple): Flow field. + + This flow corresponds to a constant vector field, e.g., a constant + backflow in bulk or a plug flow in a channel. The flow field is + independent of the position it is evaluated at. + + Example:: + + u = azplugins.flow.constant(velocity=(1,0,0)) + + """ + + def __init__(self, velocity): super().__init__() - param_dict = ParameterDict(mean_velocity=(float, float, float)) - param_dict['mean_velocity'] = mean_velocity + param_dict = ParameterDict(velocity=(float, float, float)) + param_dict['velocity'] = velocity self._param_dict.update(param_dict) def _attach_hook(self): self._cpp_obj = _azplugins.ConstantFlow( - _hoomd.make_scalar3( - self.mean_velocity[0], self.mean_velocity[1], self.mean_velocity[2] + hoomd._hoomd.make_scalar3( + self.velocity[0], self.velocity[1], self.velocity[2] ) ) super()._attach_hook() class ParabolicFlow(FlowField): + r"""Parabolic flow profile between parallel plates. + + Args: + U (float): Mean velocity + H (float): Channel half-width + + This flow field generates the parabolic flow profile in a slit geomtry: + + .. math:: + + u_x(z) = \frac{3}{2}U \left[1 - \left(\frac{z}{H}\right)^2 \right] + + The flow is along *x* with the gradient in *z*. The distance between the + two plates is :math:`2H`, and the channel is centered around :math:`z=0`. + The mean flow velocity is *U*. + + Example:: + + u = hoomd.azplugins.flow.parabolic(mean_velocity = 2.0, separation = 0.5) + + Note: + Creating a flow profile does **not** imply anything about the simulation + box boundaries. It is the responsibility of the user to construct + appropriate bounding walls commensurate with the flow profile geometry. + + """ + def __init__(self, mean_velocity, separation): super().__init__() diff --git a/src/module.cc b/src/module.cc index 7a17faad..24aae5da 100644 --- a/src/module.cc +++ b/src/module.cc @@ -2,10 +2,7 @@ // Copyright (c) 2021-2024, Auburn University // Part of azplugins, released under the BSD 3-Clause License. -#include "ConstantFlow.h" -#include "ParabolicFlow.h" #include - namespace hoomd { //! Plugins for soft matter @@ -51,14 +48,13 @@ namespace azplugins { namespace detail { - +void export_ConstantFlow(pybind11::module&); +void export_ParabolicFlow(pybind11::module&); void export_PotentialPairHertz(pybind11::module&); - #ifdef ENABLE_HIP void export_PotentialPairHertzGPU(pybind11::module&); #endif // ENABLE_HIP - } // namespace detail } // namespace azplugins } // namespace hoomd @@ -67,7 +63,7 @@ void export_PotentialPairHertzGPU(pybind11::module&); PYBIND11_MODULE(_azplugins, m) { using namespace hoomd::azplugins::detail; - + export_ConstantFlow(m); export_ParabolicFlow(m); diff --git a/src/pytest/test_flow.py b/src/pytest/test_flow.py index 17d9a223..4bfa3ee2 100644 --- a/src/pytest/test_flow.py +++ b/src/pytest/test_flow.py @@ -2,39 +2,48 @@ # Copyright (c) 2021-2024, Auburn University # Part of azplugins, released under the BSD 3-Clause License. -import collections +"""Test flow fields.""" import hoomd import numpy -import pytest from hoomd.conftest import pickling_check -import hoomd.azplugins def test_constant_flow_field(simulation_factory): - # make the force - U = hoomd.azplugins.flow.ConstantFlow(mean_velocity=(1, 0, 0)) - numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 0, 0)) + """Test constant flow field.""" + # make the flow field + U = hoomd.azplugins.flow.ConstantFlow(velocity=(1, 0, 0)) + numpy.testing.assert_array_almost_equal(U.velocity, (1, 0, 0)) pickling_check(U) - U.mean_velocity = (1, 1, 1) - numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 1, 1)) + # set velocity + U.velocity = (1, 2, 3) + numpy.testing.assert_array_almost_equal(U.velocity, (1, 2, 3)) + pickling_check(U) + # get and set velocity sim = simulation_factory() U._attach(sim) - numpy.testing.assert_array_almost_equal(U.mean_velocity, (1, 1, 1)) + numpy.testing.assert_array_almost_equal(U.velocity, (1, 2, 3)) + pickling_check(U) def test_parabolic_flow_field(simulation_factory): + """Test parabolic flow field.""" + # make the flow field U = hoomd.azplugins.flow.ParabolicFlow(mean_velocity=4, separation=10) assert U.mean_velocity == 4 assert U.separation == 10 pickling_check(U) + # set velocity and separation U.mean_velocity = 10 U.separation = 20 numpy.testing.assert_array_almost_equal((U.mean_velocity, U.separation), (10, 20)) + pickling_check(U) + # get and set velocity and separation sim = simulation_factory() U._attach(sim) numpy.testing.assert_array_almost_equal((U.mean_velocity, U.separation), (10, 20)) + pickling_check(U) From ce4d81f8651e151ecf9d9c9f7244f448de2d41bb Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Wed, 5 Jun 2024 13:44:02 -0500 Subject: [PATCH 06/11] Revise parabolic flow coordinate system --- src/ConstantFlow.h | 6 +++++- src/ParabolicFlow.cc | 6 ++++-- src/ParabolicFlow.h | 25 +++++++++++++++---------- src/flow.py | 18 +++++++++--------- src/module.cc | 1 + 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/ConstantFlow.h b/src/ConstantFlow.h index 6949e023..47b3c114 100644 --- a/src/ConstantFlow.h +++ b/src/ConstantFlow.h @@ -30,7 +30,11 @@ class ConstantFlow /*! *\param U_ Flow field */ - ConstantFlow(Scalar3 U_) : U(U_) { } + ConstantFlow(Scalar3 velocity) + { + setVelocity(velocity); + } + //! Evaluate the flow field /*! * \param r position to evaluate flow diff --git a/src/ParabolicFlow.cc b/src/ParabolicFlow.cc index a281b560..5a7be438 100644 --- a/src/ParabolicFlow.cc +++ b/src/ParabolicFlow.cc @@ -15,8 +15,10 @@ void export_ParabolicFlow(pybind11::module& m) namespace py = pybind11; py::class_>(m, "ParabolicFlow") .def(py::init()) - .def_property("mean_velocity", &ParabolicFlow::getVelocity, &ParabolicFlow::setVelocity) - .def_property("separation", &ParabolicFlow::getLength, &ParabolicFlow::setLength); + .def_property("mean_velocity", + &ParabolicFlow::getMeanVelocity, + &ParabolicFlow::setMeanVelocity) + .def_property("separation", &ParabolicFlow::getSeparation, &ParabolicFlow::setSeparation); } } // namespace detail } // namespace azplugins diff --git a/src/ParabolicFlow.h b/src/ParabolicFlow.h index d7d1bf2f..e6e042e5 100644 --- a/src/ParabolicFlow.h +++ b/src/ParabolicFlow.h @@ -26,18 +26,19 @@ namespace hoomd { namespace azplugins { + //! Unidirectional parabolic flow field /*! * 1d flow along the \a x axis. The geometry is a parallel plate channel with - * the plates centered around \f$ z = 0 \f$ and positioned at \f$ \pm L \f$. + * the plates centered around \f$ y = 0 \f$ and positioned at \f$ \pm L \f$. * The \a y axis is the vorticity direction and periodic. The flow profile in * this geometry is then * * \f[ - * u_x(z) = \frac{3}{2} U \left[1 - \left(\frac{z}{L}\right)^2 \right] + * u_x(y) = \frac{3}{2} U \left[1 - \left(\frac{y}{L}\right)^2 \right] * \f] * - * Here, \f$ U \f$ is the mean velocity, which is related to the pressure drop + * Here, \f$ mean_velocity \f$ is the mean velocity, which is related to the pressure drop * and viscosity. * * \note The user must properly establish no flux of particles through the channel @@ -51,7 +52,11 @@ class ParabolicFlow * \param U_ Mean velocity * \param L_ Separation */ - ParabolicFlow(Scalar U_, Scalar L_) : Umax(Scalar(1.5) * U_), L(Scalar(0.5) * L_) { } + ParabolicFlow(Scalar mean_velocity, Scalar separation) + { + setMeanVelocity(mean_velocity); + setSeparation(separation); + } //! Evaluate the flow field /*! @@ -59,26 +64,26 @@ class ParabolicFlow */ HOSTDEVICE Scalar3 operator()(const Scalar3& r) const { - const Scalar zr = (r.z / L); - return make_scalar3(Umax * (1. - zr * zr), 0.0, 0.0); + const Scalar yr = (r.y / L); + return make_scalar3(Umax * (1. - yr * yr), 0.0, 0.0); } - HOSTDEVICE Scalar getVelocity() const + HOSTDEVICE Scalar getMeanVelocity() const { return Umax / Scalar(1.5); } - HOSTDEVICE void setVelocity(const Scalar& U) + HOSTDEVICE void setMeanVelocity(const Scalar& U) { Umax = Scalar(1.5) * U; } - HOSTDEVICE Scalar getLength() const + HOSTDEVICE Scalar getSeparation() const { return Scalar(2.0) * L; } - HOSTDEVICE void setLength(const Scalar& L_) + HOSTDEVICE void setSeparation(const Scalar& L_) { L = Scalar(0.5) * L_; } diff --git a/src/flow.py b/src/flow.py index 21c640b1..d6fb1e14 100644 --- a/src/flow.py +++ b/src/flow.py @@ -21,7 +21,7 @@ class ConstantFlow(FlowField): r"""Constant flow profile. Args: - U (tuple): Flow field. + velocity (tuple): Flow field. This flow corresponds to a constant vector field, e.g., a constant backflow in bulk or a plug flow in a channel. The flow field is @@ -29,7 +29,7 @@ class ConstantFlow(FlowField): Example:: - u = azplugins.flow.constant(velocity=(1,0,0)) + u = hoomd.azplugins.flow.ConstantFlow(velocity=(1,0,0)) """ @@ -52,22 +52,22 @@ class ParabolicFlow(FlowField): r"""Parabolic flow profile between parallel plates. Args: - U (float): Mean velocity - H (float): Channel half-width + mean_velocity (float): Mean velocity. + separation (float): Separation between parallel plates defining the flow field. This flow field generates the parabolic flow profile in a slit geomtry: .. math:: - u_x(z) = \frac{3}{2}U \left[1 - \left(\frac{z}{H}\right)^2 \right] + u_x(y) = \frac{3}{2}U \left[1 - \left(\frac{y}{H}\right)^2 \right] - The flow is along *x* with the gradient in *z*. The distance between the - two plates is :math:`2H`, and the channel is centered around :math:`z=0`. - The mean flow velocity is *U*. + The flow is along *x* with the gradient in *y*. The ``separation`` between the + two plates is :math:`2H`, and the channel is centered around :math:`y=0`. + The ``mean_velocity`` is *U*. Example:: - u = hoomd.azplugins.flow.parabolic(mean_velocity = 2.0, separation = 0.5) + u = hoomd.azplugins.flow.ParabolicFlow(mean_velocity=2.0, separation=0.5) Note: Creating a flow profile does **not** imply anything about the simulation diff --git a/src/module.cc b/src/module.cc index d25c6e01..1c86d6bb 100644 --- a/src/module.cc +++ b/src/module.cc @@ -50,6 +50,7 @@ namespace detail { void export_ConstantFlow(pybind11::module&); void export_ParabolicFlow(pybind11::module&); + void export_PotentialPairHertz(pybind11::module&); void export_PotentialPairPerturbedLennardJones(pybind11::module&); From 8f121b7378d55f777212fe3042d54cf4ceba1818 Mon Sep 17 00:00:00 2001 From: Michael Howard Date: Wed, 5 Jun 2024 14:02:17 -0500 Subject: [PATCH 07/11] Fix pybind11 visbility --- src/ConstantFlow.h | 7 ++++++- src/ParabolicFlow.h | 8 +++++++- src/module.cc | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ConstantFlow.h b/src/ConstantFlow.h index 47b3c114..bff9340a 100644 --- a/src/ConstantFlow.h +++ b/src/ConstantFlow.h @@ -17,13 +17,17 @@ #define HOSTDEVICE #endif // __HIPCC__ +#ifndef PYBIND11_EXPORT +#define PYBIND11_EXPORT __attribute__((visibility("default"))) +#endif + namespace hoomd { namespace azplugins { //! Position-independent flow along a vector -class ConstantFlow +class PYBIND11_EXPORT ConstantFlow { public: //! Constructor @@ -64,5 +68,6 @@ class ConstantFlow } // namespace hoomd #undef HOSTDEVICE +#undef PYBIND11_EXPORT #endif // AZPLUGINS_CONSTANT_FLOW_H_ diff --git a/src/ParabolicFlow.h b/src/ParabolicFlow.h index e6e042e5..b925bf01 100644 --- a/src/ParabolicFlow.h +++ b/src/ParabolicFlow.h @@ -22,6 +22,10 @@ #define HOSTDEVICE #endif // __HIPCC__ +#ifndef PYBIND11_EXPORT +#define PYBIND11_EXPORT __attribute__((visibility("default"))) +#endif + namespace hoomd { namespace azplugins @@ -44,7 +48,7 @@ namespace azplugins * \note The user must properly establish no flux of particles through the channel * walls through an appropriate wall potential. */ -class ParabolicFlow +class PYBIND11_EXPORT ParabolicFlow { public: //! Construct parabolic flow profile @@ -95,6 +99,8 @@ class ParabolicFlow } // namespace azplugins } // namespace hoomd + #undef HOSTDEVICE +#undef PYBIND11_EXPORT #endif // AZPLUGINS_PARABOLIC_FLOW_H_ diff --git a/src/module.cc b/src/module.cc index 6005b386..32d9d97e 100644 --- a/src/module.cc +++ b/src/module.cc @@ -3,6 +3,7 @@ // Part of azplugins, released under the BSD 3-Clause License. #include + namespace hoomd { //! Plugins for soft matter @@ -72,7 +73,6 @@ PYBIND11_MODULE(_azplugins, m) { using namespace hoomd::azplugins::detail; - export_ConstantFlow(m); export_ParabolicFlow(m); From 5541e45ba76666d4614eaf9f565f861901358412 Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Wed, 5 Jun 2024 14:06:48 -0500 Subject: [PATCH 08/11] Apply set method for noiseless in TwoStepBD class --- src/TwoStepBrownianFlow.h | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/TwoStepBrownianFlow.h b/src/TwoStepBrownianFlow.h index f7136330..adaaac26 100644 --- a/src/TwoStepBrownianFlow.h +++ b/src/TwoStepBrownianFlow.h @@ -15,8 +15,8 @@ #endif #include "hoomd/RandomNumbers.h" -#include #include "hoomd/md/TwoStepLangevinBase.h" +#include #include "RNGIdentifiers.h" namespace hoomd @@ -28,8 +28,7 @@ namespace azplugins /*! * \note Only translational motion is supported by this integrator. */ -template -class PYBIND11_EXPORT TwoStepBrownianFlow : public md::TwoStepLangevinBase +template class PYBIND11_EXPORT TwoStepBrownianFlow : public md::TwoStepLangevinBase { public: //! Constructor @@ -84,6 +83,10 @@ class PYBIND11_EXPORT TwoStepBrownianFlow : public md::TwoStepLangevinBase /*! * \param noiseless If true, do not apply a random diffusive force */ + void setNoiseless(bool noiseless) + { + m_noiseless = noiseless; + } protected: std::shared_ptr m_flow_field; //!< Flow field functor @@ -136,10 +139,11 @@ void TwoStepBrownianFlow::integrateStepOne(unsigned int timestep) coeff = Scalar(0.0); // draw random force - hoomd::RandomGenerator rng(hoomd::Seed(hoomd::azplugins::detail::RNGIdentifier::TwoStepBrownianFlow, - timestep, - seed), - hoomd::Counter(h_tag.data[idx])); + hoomd::RandomGenerator rng( + hoomd::Seed(hoomd::azplugins::detail::RNGIdentifier::TwoStepBrownianFlow, + timestep, + seed), + hoomd::Counter(h_tag.data[idx])); hoomd::UniformDistribution uniform(-coeff, coeff); const Scalar3 random_force = make_scalar3(uniform(rng), uniform(rng), uniform(rng)); @@ -165,18 +169,19 @@ void export_TwoStepBrownianFlow(pybind11::module& m, const std::string& name) namespace py = pybind11; typedef TwoStepBrownianFlow BrownianFlow; - py::class_>(m, - name.c_str(), - py::base()) + py::class_>( + m, + name.c_str(), + py::base()) .def(py::init, std::shared_ptr, std::shared_ptr, std::shared_ptr, bool>()) - .def("getFlowField", &BrownianFlow::getFlowField) - .def("getNoiseless", &BrownianFlow::getNoiseless); + .def_property_readonly("flow_field", &BrownianFlow::getFlowField) + .def_property("noiseless", &BrownianFlow::getNoiseless, &BrownianFlow::setNoiseless); } - } // end namespace detail - } // end namespace azplugins - } // end namespace hoomd + } // end namespace detail + } // end namespace azplugins + } // end namespace hoomd #endif // AZPLUGINS_TWO_STEP_BROWNIAN_FLOW_H_ From ba528563bb625c3cce42276427bb76028b2e3b0a Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Thu, 6 Jun 2024 12:13:32 -0500 Subject: [PATCH 09/11] Add constant and parabolic flow header files to module.cc --- src/module.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/module.cc b/src/module.cc index baf5c7fd..e29412b3 100644 --- a/src/module.cc +++ b/src/module.cc @@ -4,6 +4,8 @@ #include +#include "ConstantFlow.h" +#include "ParabolicFlow.h" #include "TwoStepBrownianFlow.h" #include "TwoStepLangevinFlow.h" From 3f37110c2e9a9a8c9143b546e5397f1981c35d1b Mon Sep 17 00:00:00 2001 From: Mayukh Kundu Date: Thu, 6 Jun 2024 12:25:01 -0500 Subject: [PATCH 10/11] Add set noiseless method to LangevinFlow.h --- src/TwoStepLangevinFlow.h | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/TwoStepLangevinFlow.h b/src/TwoStepLangevinFlow.h index 2a68cd07..7fdcb015 100644 --- a/src/TwoStepLangevinFlow.h +++ b/src/TwoStepLangevinFlow.h @@ -15,8 +15,8 @@ #endif #include "hoomd/RandomNumbers.h" -#include #include "hoomd/md/TwoStepLangevinBase.h" +#include #include "RNGIdentifiers.h" namespace hoomd @@ -28,7 +28,8 @@ namespace azplugins /*! * \note Only translational motion is supported by this integrator. */ -template class PYBIND11_EXPORT TwoStepLangevinFlow : public md::TwoStepLangevinBase +template +class PYBIND11_EXPORT TwoStepLangevinFlow : public hoomd::md::TwoStepLangevinBase { public: //! Constructor @@ -37,8 +38,7 @@ template class PYBIND11_EXPORT TwoStepLangevinFlow : public md: std::shared_ptr T, std::shared_ptr flow_field, bool noiseless) - : TwoStepLangevinBase(sysdef, group, T), m_flow_field(flow_field), - m_noiseless(noiseless) + : TwoStepLangevinBase(sysdef, group, T), m_flow_field(flow_field), m_noiseless(noiseless) { m_exec_conf->msg->notice(5) << "Constructing TwoStepLangevinFlow" << std::endl; if (m_sysdef->getNDimensions() < 3) @@ -80,6 +80,10 @@ template class PYBIND11_EXPORT TwoStepLangevinFlow : public md: /*! * \param noiseless If true, do not apply a random diffusive force */ + void setNoiseless(bool noiseless) + { + m_noiseless = noiseless; + } protected: std::shared_ptr m_flow_field; //!< Flow field functor @@ -158,8 +162,8 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) ArrayHandle h_pos(m_pdata->getPositions(), access_location::host, access_mode::read); ArrayHandle h_tag(m_pdata->getTags(), access_location::host, access_mode::read); ArrayHandle h_net_force(m_pdata->getNetForce(), - access_location::host, - access_mode::read); + access_location::host, + access_mode::read); ArrayHandle h_gamma(m_gamma, access_location::host, access_mode::read); const Scalar currentTemp = (*m_T)(timestep); @@ -182,10 +186,11 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) Scalar coeff = fast::sqrt(Scalar(6.0) * gamma * currentTemp / m_deltaT); if (m_noiseless) coeff = Scalar(0.0); - hoomd::RandomGenerator rng(hoomd::Seed(hoomd::azplugins::detail::RNGIdentifier::TwoStepBrownianFlow, - timestep, - seed), - hoomd::Counter(h_tag.data[idx])); + hoomd::RandomGenerator rng( + hoomd::Seed(hoomd::azplugins::detail::RNGIdentifier::TwoStepBrownianFlow, + timestep, + seed), + hoomd::Counter(h_tag.data[idx])); hoomd::UniformDistribution uniform(-coeff, coeff); const Scalar3 random = make_scalar3(uniform(rng), uniform(rng), uniform(rng)); @@ -212,7 +217,6 @@ void TwoStepLangevinFlow::integrateStepTwo(unsigned int timestep) h_vel.data[idx] = make_scalar4(vel.x, vel.y, vel.z, mass); h_accel.data[idx] = accel; } - } namespace detail @@ -224,16 +228,17 @@ void export_TwoStepLangevinFlow(pybind11::module& m, const std::string& name) namespace py = pybind11; typedef TwoStepLangevinFlow LangevinFlow; - py::class_>(m, - name.c_str(), - py::base()) + py::class_>( + m, + name.c_str(), + py::base()) .def(py::init, std::shared_ptr, std::shared_ptr, std::shared_ptr, bool>()) - .def("getFlowField", &LangevinFlow::getFlowField) - .def("getNoiseless", &LangevinFlow::getNoiseless); + .def_property_readonly("flow_field", &LangevinFlow::getFlowField) + .def_property("noiseless", &LangevinFlow::getNoiseless, &LangevinFlow::setNoiseless); } } // end namespace detail } // end namespace azplugins From 163f8cf7dfdb034d960292dfd6499b3c322b6d8b Mon Sep 17 00:00:00 2001 From: Michael Howard Date: Thu, 6 Jun 2024 16:53:33 -0500 Subject: [PATCH 11/11] Fix pybind11 error --- src/ConstantFlow.h | 8 +++++--- src/ParabolicFlow.h | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ConstantFlow.h b/src/ConstantFlow.h index bff9340a..4c484bea 100644 --- a/src/ConstantFlow.h +++ b/src/ConstantFlow.h @@ -18,7 +18,9 @@ #endif // __HIPCC__ #ifndef PYBIND11_EXPORT -#define PYBIND11_EXPORT __attribute__((visibility("default"))) +#define _PYBIND11_EXPORT __attribute__((visibility("default"))) +#else +#define _PYBIND11_EXPORT PYBIND11_EXPORT #endif namespace hoomd @@ -27,7 +29,7 @@ namespace azplugins { //! Position-independent flow along a vector -class PYBIND11_EXPORT ConstantFlow +class _PYBIND11_EXPORT ConstantFlow { public: //! Constructor @@ -68,6 +70,6 @@ class PYBIND11_EXPORT ConstantFlow } // namespace hoomd #undef HOSTDEVICE -#undef PYBIND11_EXPORT +#undef _PYBIND11_EXPORT #endif // AZPLUGINS_CONSTANT_FLOW_H_ diff --git a/src/ParabolicFlow.h b/src/ParabolicFlow.h index b925bf01..47c741d2 100644 --- a/src/ParabolicFlow.h +++ b/src/ParabolicFlow.h @@ -23,7 +23,9 @@ #endif // __HIPCC__ #ifndef PYBIND11_EXPORT -#define PYBIND11_EXPORT __attribute__((visibility("default"))) +#define _PYBIND11_EXPORT __attribute__((visibility("default"))) +#else +#define _PYBIND11_EXPORT PYBIND11_EXPORT #endif namespace hoomd @@ -48,7 +50,7 @@ namespace azplugins * \note The user must properly establish no flux of particles through the channel * walls through an appropriate wall potential. */ -class PYBIND11_EXPORT ParabolicFlow +class _PYBIND11_EXPORT ParabolicFlow { public: //! Construct parabolic flow profile @@ -101,6 +103,6 @@ class PYBIND11_EXPORT ParabolicFlow } // namespace hoomd #undef HOSTDEVICE -#undef PYBIND11_EXPORT +#undef _PYBIND11_EXPORT #endif // AZPLUGINS_PARABOLIC_FLOW_H_