From b9a2293b363a7bf3a2ca48f4b8e547933933053c Mon Sep 17 00:00:00 2001 From: janbridley Date: Mon, 15 Jan 2024 12:17:47 -0500 Subject: [PATCH 01/13] Fixed typo --- hoomd/hpmc/ShapeMoves.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hoomd/hpmc/ShapeMoves.h b/hoomd/hpmc/ShapeMoves.h index a87d1f88eb..c44b29c836 100644 --- a/hoomd/hpmc/ShapeMoves.h +++ b/hoomd/hpmc/ShapeMoves.h @@ -212,8 +212,7 @@ template class PythonShapeMove : public ShapeMoveBase std::vector> m_params_backup; // tunable shape parameters to perform trial moves on std::vector> m_params; // tunable shape parameters to perform trial moves on - // callback that takes m_params as an argiment and returns a Python dictionary with the shape - // params. + // callback that takes m_params as an argument and returns a Python dictionary of shape params. pybind11::object m_python_callback; }; From dd71c0809b9ce39263892d8186ede6139783b23f Mon Sep 17 00:00:00 2001 From: janbridley Date: Mon, 15 Jan 2024 12:18:43 -0500 Subject: [PATCH 02/13] Expanded on test_python_callback_shape_move --- hoomd/hpmc/pytest/test_shape_updater.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index ad400bbff3..a60148b09d 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -234,12 +234,22 @@ def __call__(self, type_id, param_list): # - shape and params should change # - volume should remain unchanged move.param_move_probability = 1 - sim.run(10) - assert np.sum(updater.shape_moves) == 20 + sim.run(20) + assert np.sum(updater.shape_moves) == 40 + + # Check that the shape parameters have changed assert not np.allclose(mc.shape["A"]["a"], ellipsoid["a"]) assert not np.allclose(mc.shape["A"]["b"], ellipsoid["b"]) assert not np.allclose(mc.shape["A"]["c"], ellipsoid["c"]) assert not np.allclose(move.params["A"], [1]) + + # Check that the shape parameters map back to the correct geometry + assert np.allclose(move.params["A"], [ + mc.shape["A"]["a"] / mc.shape["A"]["b"], + mc.shape["A"]["a"] / mc.shape["A"]["c"] + ]) + + # Check that the callback is conserving volume properly assert np.allclose(updater.particle_volumes, 4 * np.pi / 3) From f2e7c4f2fed867c3cced8a09308436d0289ffcca Mon Sep 17 00:00:00 2001 From: janbridley Date: Mon, 15 Jan 2024 14:13:03 -0500 Subject: [PATCH 03/13] Added test_python_callback_shape_move_pyramid --- hoomd/hpmc/pytest/test_shape_updater.py | 88 ++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index a60148b09d..047fd74f89 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -173,8 +173,8 @@ def test_vertex_shape_move(simulation_factory, two_particle_snapshot_factory): assert np.isclose(updater.particle_volumes[0], 1) -def test_python_callback_shape_move(simulation_factory, - two_particle_snapshot_factory): +def test_python_callback_shape_move_ellipsoid(simulation_factory, + two_particle_snapshot_factory): """Test ShapeSpace with a toy class that randomly squashes spheres \ into oblate ellipsoids with constant volume.""" @@ -253,6 +253,90 @@ def __call__(self, type_id, param_list): assert np.allclose(updater.particle_volumes, 4 * np.pi / 3) +def test_python_callback_shape_move_pyramid(simulation_factory, + two_particle_snapshot_factory): + """Test ShapeSpace with a toy class that randomly stretches square \ + pyramids.""" + + def square_pyramid_factory(h): + """Generate a square pyramid with unit volume.""" + theta = np.arange(0, 2 * np.pi, np.pi / 2) + base_vertices = np.array( + [np.cos(theta), np.sin(theta), + np.zeros_like(theta)]).T * np.sqrt(3 / 2) + vertices = np.vstack([base_vertices, [0, 0, h]]) + return vertices / np.cbrt(h), base_vertices + + class ScalePyramid: + + def __init__(self, h=1.1): + _, self.base_vertices = square_pyramid_factory(h=1.1) + self.default_dict = dict(sweep_radius=0, ignore_statistics=True) + + def __call__(self, type_id, param_list): + h = param_list[0] + 0.1 # Prevent a 0-height pyramid + new_vertices = np.vstack([self.base_vertices, [0, 0, h]]) + new_vertices /= np.cbrt(h) # Rescale to unit volume + ret = dict(vertices=new_vertices, **self.default_dict) + return ret + + initial_pyramid, _ = square_pyramid_factory(h=1.1) + + move = ShapeSpace(callback=ScalePyramid(), default_step_size=0.2) + move.params["A"] = [1] + + updater = hpmc.update.Shape(trigger=1, shape_move=move, nsweeps=2) + updater.shape_move = move + + mc = hoomd.hpmc.integrate.ConvexPolyhedron() + mc.d["A"] = 0 + mc.a["A"] = 0 + mc.shape["A"] = dict(vertices=initial_pyramid) + + # create simulation & attach objects + sim = simulation_factory(two_particle_snapshot_factory(d=10)) + sim.operations.integrator = mc + sim.operations += updater + + # test attachmet before first run + assert not move._attached + assert not updater._attached + + sim.run(0) + + # test attachmet after first run + assert move._attached + assert updater._attached + + # run with 0 probability of performing a move: + # - shape and params should remain unchanged + # - all moves accepted + move.param_move_probability = 0 + sim.run(10) + assert np.allclose(mc.shape["A"]["vertices"], initial_pyramid) + assert np.allclose(move.params["A"], [1]) + assert np.allclose(updater.particle_volumes, 1) + + # always attempt a shape move: + # - shape and params should change + # - volume should remain unchanged + move.param_move_probability = 1 + sim.run(20) + assert np.sum(updater.shape_moves) == 40 + + # Check that the shape parameters have changed + current_h = move.params["A"][0] + assert not np.allclose(mc.shape["A"]["vertices"], initial_pyramid) + assert not np.isclose(current_h, 1) + + # Check that the shape parameters map back to the correct geometry + assert np.allclose( + square_pyramid_factory(current_h + 0.1)[0], mc.shape["A"]["vertices"]) + + # Check that the callback is conserving volume properly + assert np.allclose(updater.particle_volumes, 1) + + def test_elastic_shape_move(simulation_factory, two_particle_snapshot_factory): mc = hoomd.hpmc.integrate.ConvexPolyhedron() From c13f33f20fd1e93c2c8f7e5c5bf2a23ac750c2f7 Mon Sep 17 00:00:00 2001 From: janbridley Date: Mon, 15 Jan 2024 14:17:48 -0500 Subject: [PATCH 04/13] Applied fix --- hoomd/hpmc/UpdaterShape.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hoomd/hpmc/UpdaterShape.h b/hoomd/hpmc/UpdaterShape.h index 4f7f857079..b281310038 100644 --- a/hoomd/hpmc/UpdaterShape.h +++ b/hoomd/hpmc/UpdaterShape.h @@ -322,6 +322,7 @@ template void UpdaterShape::update(uint64_t timestep) m_exec_conf->msg->notice(5) << "UpdaterShape move rejected -- overlaps found" << std::endl; // revert shape parameter changes + m_move_function->retreat(timestep, typ_i); h_det.data[typ_i] = h_det_old.data[typ_i]; m_mc->setParam(typ_i, shape_param_old); } From 3aa5f41818e84826d75f5f7feadd4eff7b35ef42 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 17 Jan 2024 13:32:41 -0500 Subject: [PATCH 05/13] Move particles close enough to regularly experience overlaps --- hoomd/hpmc/pytest/test_shape_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index 047fd74f89..9d805d9e71 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -294,7 +294,7 @@ def __call__(self, type_id, param_list): mc.shape["A"] = dict(vertices=initial_pyramid) # create simulation & attach objects - sim = simulation_factory(two_particle_snapshot_factory(d=10)) + sim = simulation_factory(two_particle_snapshot_factory(d=3)) sim.operations.integrator = mc sim.operations += updater From 70f0472ad7840b4e28acc8e3859bbaf25b88640f Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 17 Jan 2024 14:30:58 -0500 Subject: [PATCH 06/13] Decreased test distances further --- hoomd/hpmc/pytest/test_shape_updater.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index 9d805d9e71..7ee0c33c9d 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -206,7 +206,7 @@ def __call__(self, type_id, param_list): mc.shape["A"] = ellipsoid # create simulation & attach objects - sim = simulation_factory(two_particle_snapshot_factory(d=10)) + sim = simulation_factory(two_particle_snapshot_factory(d=2.5)) sim.operations.integrator = mc sim.operations += updater @@ -294,7 +294,7 @@ def __call__(self, type_id, param_list): mc.shape["A"] = dict(vertices=initial_pyramid) # create simulation & attach objects - sim = simulation_factory(two_particle_snapshot_factory(d=3)) + sim = simulation_factory(two_particle_snapshot_factory(d=2.5)) sim.operations.integrator = mc sim.operations += updater From 802f05a90bd4c661fb032ddfbd9350512462e818 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 17 Jan 2024 15:23:07 -0500 Subject: [PATCH 07/13] Slightly increased runtime to avoid stochastic failures --- hoomd/hpmc/pytest/test_shape_updater.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index 7ee0c33c9d..53242fcf91 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -222,7 +222,7 @@ def __call__(self, type_id, param_list): # run with 0 probability of performing a move: # - shape and params should remain unchanged - # - all moves accepted + # - no shape moves proposed move.param_move_probability = 0 sim.run(10) assert np.allclose(mc.shape["A"]["a"], ellipsoid["a"]) @@ -234,8 +234,8 @@ def __call__(self, type_id, param_list): # - shape and params should change # - volume should remain unchanged move.param_move_probability = 1 - sim.run(20) - assert np.sum(updater.shape_moves) == 40 + sim.run(50) + assert np.sum(updater.shape_moves) == 100 # Check that the shape parameters have changed assert not np.allclose(mc.shape["A"]["a"], ellipsoid["a"]) @@ -321,8 +321,8 @@ def __call__(self, type_id, param_list): # - shape and params should change # - volume should remain unchanged move.param_move_probability = 1 - sim.run(20) - assert np.sum(updater.shape_moves) == 40 + sim.run(50) + assert np.sum(updater.shape_moves) == 100 # Check that the shape parameters have changed current_h = move.params["A"][0] From 5d3d9383d3140ce659ed86d988f94e64d49f2c4c Mon Sep 17 00:00:00 2001 From: janbridley Date: Tue, 23 Jan 2024 14:16:36 -0500 Subject: [PATCH 08/13] Increased ellipsoid test size to accommodate GPU/MPI testing --- hoomd/hpmc/pytest/test_shape_updater.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index 53242fcf91..203327739d 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -174,7 +174,7 @@ def test_vertex_shape_move(simulation_factory, two_particle_snapshot_factory): def test_python_callback_shape_move_ellipsoid(simulation_factory, - two_particle_snapshot_factory): + lattice_snapshot_factory): """Test ShapeSpace with a toy class that randomly squashes spheres \ into oblate ellipsoids with constant volume.""" @@ -206,7 +206,7 @@ def __call__(self, type_id, param_list): mc.shape["A"] = ellipsoid # create simulation & attach objects - sim = simulation_factory(two_particle_snapshot_factory(d=2.5)) + sim = simulation_factory(lattice_snapshot_factory(a=2.5, n=3)) sim.operations.integrator = mc sim.operations += updater From 0c9c9b07f99071a3ccbd7446a5ddc71b27575aab Mon Sep 17 00:00:00 2001 From: janbridley Date: Tue, 23 Jan 2024 14:43:14 -0500 Subject: [PATCH 09/13] Bumped simulation size further --- hoomd/hpmc/pytest/test_shape_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index 203327739d..c3d669a162 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -206,7 +206,7 @@ def __call__(self, type_id, param_list): mc.shape["A"] = ellipsoid # create simulation & attach objects - sim = simulation_factory(lattice_snapshot_factory(a=2.5, n=3)) + sim = simulation_factory(lattice_snapshot_factory(a=2.75, n=3)) sim.operations.integrator = mc sim.operations += updater From f66edf0eecd59804304dfe83798da745854b3958 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 24 Jan 2024 09:24:54 -0500 Subject: [PATCH 10/13] Bumped simulation size further --- hoomd/hpmc/pytest/test_shape_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/hpmc/pytest/test_shape_updater.py b/hoomd/hpmc/pytest/test_shape_updater.py index c3d669a162..87da571ac5 100644 --- a/hoomd/hpmc/pytest/test_shape_updater.py +++ b/hoomd/hpmc/pytest/test_shape_updater.py @@ -206,7 +206,7 @@ def __call__(self, type_id, param_list): mc.shape["A"] = ellipsoid # create simulation & attach objects - sim = simulation_factory(lattice_snapshot_factory(a=2.75, n=3)) + sim = simulation_factory(lattice_snapshot_factory(a=2.75, n=(3, 3, 5))) sim.operations.integrator = mc sim.operations += updater From 34f98eb6601572dbfbf1c187bf8acef16d5435e3 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 24 Jan 2024 10:52:47 -0500 Subject: [PATCH 11/13] Passed managed memory flag on GPU --- hoomd/hpmc/ShapeMoves.h | 15 ++++++++++----- hoomd/hpmc/UpdaterShape.h | 6 +++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hoomd/hpmc/ShapeMoves.h b/hoomd/hpmc/ShapeMoves.h index c44b29c836..cce7d0ce8a 100644 --- a/hoomd/hpmc/ShapeMoves.h +++ b/hoomd/hpmc/ShapeMoves.h @@ -40,7 +40,8 @@ template class ShapeMoveBase virtual void update_shape(uint64_t, const unsigned int&, typename Shape::param_type&, - hoomd::RandomGenerator&) + hoomd::RandomGenerator&, + bool managed) { } @@ -141,7 +142,8 @@ template class PythonShapeMove : public ShapeMoveBase void update_shape(uint64_t timestep, const unsigned int& type_id, typename Shape::param_type& shape, - hoomd::RandomGenerator& rng) + hoomd::RandomGenerator& rng, + bool managed) { for (unsigned int i = 0; i < m_params[type_id].size(); i++) { @@ -278,7 +280,8 @@ class ConvexPolyhedronVertexShapeMove : public ShapeMoveBase : public ElasticShapeMoveBase class ElasticShapeMove : public ElasticShapeMoveBase< void update_shape(uint64_t timestep, const unsigned int& type_id, param_type& param, - hoomd::RandomGenerator& rng) + hoomd::RandomGenerator& rng, + bool managed) { Scalar lnx = log(param.x / param.y); Scalar stepsize = this->m_step_size[type_id]; diff --git a/hoomd/hpmc/UpdaterShape.h b/hoomd/hpmc/UpdaterShape.h index b281310038..ed96ba2132 100644 --- a/hoomd/hpmc/UpdaterShape.h +++ b/hoomd/hpmc/UpdaterShape.h @@ -288,7 +288,11 @@ template void UpdaterShape::update(uint64_t timestep) hoomd::Counter(typ_i, 0, i_sweep)); // perform an in-place shape update on shape_param_new - m_move_function->update_shape(timestep, typ_i, shape_param_new, rng_i); + m_move_function->update_shape(timestep, + typ_i, + shape_param_new, + rng_i, + m_exec_conf->isCUDAEnabled()); // update det(I) detail::MassProperties mp(shape_param_new); From 9205c78cb2b6527a2daac37dd50b3cf2f1b44321 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 24 Jan 2024 12:20:30 -0500 Subject: [PATCH 12/13] Fixed managed memory flag --- hoomd/hpmc/ShapeMoves.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hoomd/hpmc/ShapeMoves.h b/hoomd/hpmc/ShapeMoves.h index cce7d0ce8a..45910bcbc0 100644 --- a/hoomd/hpmc/ShapeMoves.h +++ b/hoomd/hpmc/ShapeMoves.h @@ -167,7 +167,7 @@ template class PythonShapeMove : public ShapeMoveBase } pybind11::object d = m_python_callback(type_id, m_params[type_id]); pybind11::dict shape_dict = pybind11::cast(d); - shape = typename Shape::param_type(shape_dict); + shape = typename Shape::param_type(shape_dict, managed); } void retreat(uint64_t timestep, unsigned int type) @@ -589,8 +589,7 @@ template<> class ElasticShapeMove : public ElasticShapeMoveBase< void update_shape(uint64_t timestep, const unsigned int& type_id, param_type& param, - hoomd::RandomGenerator& rng, - bool managed) + hoomd::RandomGenerator& rng) { Scalar lnx = log(param.x / param.y); Scalar stepsize = this->m_step_size[type_id]; From 6947eab265ef7e257dca330df27ed86d5bc6a7d3 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 24 Jan 2024 12:39:26 -0500 Subject: [PATCH 13/13] Added final managed flag --- hoomd/hpmc/ShapeMoves.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hoomd/hpmc/ShapeMoves.h b/hoomd/hpmc/ShapeMoves.h index 45910bcbc0..990f0dd63b 100644 --- a/hoomd/hpmc/ShapeMoves.h +++ b/hoomd/hpmc/ShapeMoves.h @@ -589,7 +589,8 @@ template<> class ElasticShapeMove : public ElasticShapeMoveBase< void update_shape(uint64_t timestep, const unsigned int& type_id, param_type& param, - hoomd::RandomGenerator& rng) + hoomd::RandomGenerator& rng, + bool managed) { Scalar lnx = log(param.x / param.y); Scalar stepsize = this->m_step_size[type_id];