From 71e49b25c75c1477f836bf3a44a8c39c4506b43b Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 10 Jun 2025 15:55:51 -0500 Subject: [PATCH 01/13] Rename body frame angular momentum variable --- hoomd/md/ForceComposite.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hoomd/md/ForceComposite.cc b/hoomd/md/ForceComposite.cc index 5045bdb915..e5c3b6bcef 100644 --- a/hoomd/md/ForceComposite.cc +++ b/hoomd/md/ForceComposite.cc @@ -997,8 +997,8 @@ void ForceComposite::updateCompositeParticles(uint64_t timestep) */ const quat angmom(h_angmom.data[central_idx]); const vec3 inertia(h_inertia.data[central_idx]); - const quat angvel_body_quat = Scalar(0.5) * conj(orientation) * angmom; - vec3 angvel_body = angvel_body_quat.v; + const quat angmom_body_quat = Scalar(0.5) * conj(orientation) * angmom; + vec3 angvel_body = angmom_body_quat.v; if (inertia.x != Scalar(0)) { angvel_body.x /= inertia.x; From 1ac264f0e4610ee23d0b80d20f0d811fd6df89e4 Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 10 Jun 2025 16:57:18 -0500 Subject: [PATCH 02/13] Add mass option for create_bodies --- hoomd/md/ForceComposite.cc | 37 +++++++++++++++++++++++++++++------ hoomd/md/ForceComposite.h | 5 +++-- hoomd/md/constrain.py | 9 +++++++-- hoomd/md/pytest/test_rigid.py | 29 +++++++++++++-------------- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/hoomd/md/ForceComposite.cc b/hoomd/md/ForceComposite.cc index e5c3b6bcef..b5edc2e225 100644 --- a/hoomd/md/ForceComposite.cc +++ b/hoomd/md/ForceComposite.cc @@ -428,15 +428,17 @@ void ForceComposite::validateRigidBodies() m_particles_added_removed = false; } -void ForceComposite::pyCreateRigidBodies(pybind11::dict charges) +void ForceComposite::pyCreateRigidBodies(pybind11::dict charges, pybind11::dict masses) { - if (pybind11::len(charges) == 0) + if (pybind11::len(charges) == 0 && pybind11::len(masses) == 0) { - createRigidBodies(std::unordered_map>()); + createRigidBodies(std::unordered_map>(), + std::unordered_map>()); return; } std::unordered_map> charges_map; + std::unordered_map> masses_map; { ArrayHandle h_body_len(m_body_len, access_location::host, access_mode::read); for (const auto& item : charges) @@ -458,13 +460,33 @@ void ForceComposite::pyCreateRigidBodies(pybind11::dict charges) } charges_map.insert({type, charges_vector}); } + for (const auto& item : masses) + { + const auto type = m_pdata->getTypeByName(item.first.cast()); + if (h_body_len.data[type] == 0) + { + throw std::runtime_error("Masses provided for non-central particle type."); + } + const auto masses_list = item.second.cast(); + if (pybind11::len(masses_list) != h_body_len.data[type]) + { + throw std::runtime_error("Masses provided not consistent with rigid body size."); + } + std::vector masses_vector; + for (auto& mass : masses_list) + { + masses_vector.emplace_back(mass.cast()); + } + masses_map.insert({type, masses_vector}); + } } - createRigidBodies(charges_map); + createRigidBodies(charges_map, masses_map); } void ForceComposite::createRigidBodies( - const std::unordered_map> charges) + const std::unordered_map> charges, + const std::unordered_map> masses) { SnapshotParticleData snap; const BoxDim& global_box = m_pdata->getGlobalBox(); @@ -567,7 +589,10 @@ void ForceComposite::createRigidBodies( snap.charge[constituent_particle_tag] = charges.at(body_type)[current_body_index]; } - + if (!masses.empty()) + { + snap.mass[constituent_particle_tag] = masses.at(body_type)[current_body_index]; + } // Set position and orientation of constituents vec3 body_position(snap.pos[particle_tag]); quat body_orientation(snap.orientation[particle_tag]); diff --git a/hoomd/md/ForceComposite.h b/hoomd/md/ForceComposite.h index ab9b0e95cd..513fb5ccd8 100644 --- a/hoomd/md/ForceComposite.h +++ b/hoomd/md/ForceComposite.h @@ -99,11 +99,12 @@ class PYBIND11_EXPORT ForceComposite : public MolecularForceCompute virtual void validateRigidBodies(); //! Create rigid body constituent particles - void pyCreateRigidBodies(pybind11::dict charges); + void pyCreateRigidBodies(pybind11::dict charges, pybind11::dict masses); //! Create rigid body constituent particles virtual void - createRigidBodies(const std::unordered_map> charges); + createRigidBodies(const std::unordered_map> charges, + const std::unordered_map> masses); /// Construct from a Python dictionary void setBody(std::string typ, pybind11::object v) diff --git a/hoomd/md/constrain.py b/hoomd/md/constrain.py index e222837812..6388a68c67 100644 --- a/hoomd/md/constrain.py +++ b/hoomd/md/constrain.py @@ -331,7 +331,7 @@ def __init__(self): self._add_typeparam(body) self.body.default = None - def create_bodies(self, state, charges=None): + def create_bodies(self, state, charges=None, masses=None): r"""Create rigid bodies from central particles in state. Args: @@ -339,6 +339,9 @@ def create_bodies(self, state, charges=None): 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. + masses (dict[str, list[float]]): (optional) The masses for each of + the constituent particles, defaults to ``None``. If ``None``, + all masses are unchanged. 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 @@ -347,7 +350,9 @@ def create_bodies(self, state, charges=None): if self._attached: raise RuntimeError("Cannot call create_bodies after running simulation.") super()._attach(state._simulation) - self._cpp_obj.createRigidBodies({} if charges is None else charges) + self._cpp_obj.createRigidBodies( + {} if charges is None else charges, {} if masses is None else masses + ) # Restore previous state self._detach() diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index 94933b0df0..5eaec96ae6 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -66,7 +66,7 @@ def test_body_setting(valid_body_definition): current_body_definition[key] = valid_body_definition[key] -def check_bodies(snapshot, definition, charges=None): +def check_bodies(snapshot, definition, charges=None, masses=None): """Non-general assumes a snapshot from two_particle_snapshot_factory. This is just to prevent duplication of code from test_create_bodies and @@ -86,6 +86,12 @@ def check_bodies(snapshot, definition, charges=None): assert snapshot.particles.charge[i + 2] == charges[i] assert snapshot.particles.charge[i + 6] == charges[i] + # check masses + if masses is not None: + for i in range(4): + assert snapshot.particles.mass[i + 2] == masses[i] + assert snapshot.particles.mass[i + 6] == masses[i] + particle_one = (snapshot.particles.position[0], snapshot.particles.orientation[0]) particle_two = (snapshot.particles.position[1], snapshot.particles.orientation[1]) @@ -146,10 +152,11 @@ def test_create_bodies( sim = simulation_factory(initial_snapshot) charges = [1.0, 2.0, 3.0, 4.0] - rigid.create_bodies(sim.state, charges={"A": charges}) + masses = [5.0, 6.0, 7.0, 8.0] + rigid.create_bodies(sim.state, charges={"A": charges}, masses={"A": masses}) snapshot = sim.state.get_snapshot() if snapshot.communicator.rank == 0: - check_bodies(snapshot, valid_body_definition, charges) + check_bodies(snapshot, valid_body_definition, charges, masses) sim.operations.integrator = hoomd.md.Integrator(dt=0.005, rigid=rigid) # Ensure validate bodies passes @@ -262,12 +269,13 @@ def test_running_simulation( sim.seed = 5 charges = [1.0, 2.0, 3.0, 4.0] - rigid.create_bodies(sim.state, charges={"A": charges}) + masses = [5.0, 6.0, 7.0, 8.0] + rigid.create_bodies(sim.state, charges={"A": charges}, masses={"A": masses}) sim.operations += integrator sim.run(5) snapshot = sim.state.get_snapshot() if sim.device.communicator.rank == 0: - check_bodies(snapshot, valid_body_definition, charges) + check_bodies(snapshot, valid_body_definition, charges, masses) autotuned_kernel_parameter_check(instance=rigid, activate=lambda: sim.run(1)) @@ -587,16 +595,7 @@ def test_velocity_constituents_constant_angmom( rigid = md.constrain.Rigid() rigid.body["A"] = body_definition - rigid.create_bodies(sim.state) - - intermed_snapshot = sim.state.get_snapshot() - if intermed_snapshot.communicator.rank == 0: - flags = ( - intermed_snapshot.particles.typeid - == intermed_snapshot.particles.types.index("B") - ) - intermed_snapshot.particles.mass[flags] = mass[flags] - sim.state.set_snapshot(intermed_snapshot) + rigid.create_bodies(sim.state, masses={"A": mass[1:]}) constvol = md.methods.ConstantVolume(filter=hoomd.filter.Rigid()) integrator = md.Integrator( From da35aaac186e5b158624190c61c2b54ca13c239f Mon Sep 17 00:00:00 2001 From: mzbush Date: Mon, 16 Jun 2025 14:22:27 -0500 Subject: [PATCH 03/13] Parametrize adding mass or charge in pytest --- hoomd/md/pytest/test_rigid.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index 5eaec96ae6..0e25fec6f9 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -137,11 +137,22 @@ def check_orientation( @skip_rowan +@pytest.mark.parametrize( + "create_bodies_args", + [ + {}, + {"charges": {"A": [1.0, 2.0, 3.0, 4.0]}}, + {"masses": {"A": [5.0, 6.0, 7.0, 8.0]}}, + {"charges": {"A": [1.0, 2.0, 3.0, 4.0]}, "masses": {"A": [5.0, 6.0, 7.0, 8.0]}}, + ], + ids=["Default", "optional-change", "optional-mass", "optional-charge-mass"], +) def test_create_bodies( simulation_factory, two_particle_snapshot_factory, lattice_snapshot_factory, valid_body_definition, + create_bodies_args, ): rigid = md.constrain.Rigid() rigid.body["A"] = valid_body_definition @@ -151,11 +162,19 @@ def test_create_bodies( initial_snapshot.particles.types = ["A", "B"] sim = simulation_factory(initial_snapshot) - charges = [1.0, 2.0, 3.0, 4.0] - masses = [5.0, 6.0, 7.0, 8.0] - rigid.create_bodies(sim.state, charges={"A": charges}, masses={"A": masses}) + rigid.create_bodies(sim.state, **create_bodies_args) snapshot = sim.state.get_snapshot() if snapshot.communicator.rank == 0: + charges = ( + create_bodies_args["charges"]["A"] + if "charges" in create_bodies_args.keys() + else None + ) + masses = ( + create_bodies_args["masses"]["A"] + if "masses" in create_bodies_args.keys() + else None + ) check_bodies(snapshot, valid_body_definition, charges, masses) sim.operations.integrator = hoomd.md.Integrator(dt=0.005, rigid=rigid) From dd54e82ea1e330c51df7225b9c95d1e64887fe3c Mon Sep 17 00:00:00 2001 From: mzbush Date: Mon, 16 Jun 2025 14:47:32 -0500 Subject: [PATCH 04/13] Remove unnecessary if in pyCreateRigidBodies --- hoomd/md/ForceComposite.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hoomd/md/ForceComposite.cc b/hoomd/md/ForceComposite.cc index b5edc2e225..2e894b5b0a 100644 --- a/hoomd/md/ForceComposite.cc +++ b/hoomd/md/ForceComposite.cc @@ -430,13 +430,6 @@ void ForceComposite::validateRigidBodies() void ForceComposite::pyCreateRigidBodies(pybind11::dict charges, pybind11::dict masses) { - if (pybind11::len(charges) == 0 && pybind11::len(masses) == 0) - { - createRigidBodies(std::unordered_map>(), - std::unordered_map>()); - return; - } - std::unordered_map> charges_map; std::unordered_map> masses_map; { From 4b1f78691950663241494c21207e047140204cba Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 17 Jun 2025 10:21:43 -0500 Subject: [PATCH 05/13] Revert typo change --- hoomd/md/ForceComposite.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hoomd/md/ForceComposite.cc b/hoomd/md/ForceComposite.cc index 2e894b5b0a..48bed25682 100644 --- a/hoomd/md/ForceComposite.cc +++ b/hoomd/md/ForceComposite.cc @@ -1015,8 +1015,8 @@ void ForceComposite::updateCompositeParticles(uint64_t timestep) */ const quat angmom(h_angmom.data[central_idx]); const vec3 inertia(h_inertia.data[central_idx]); - const quat angmom_body_quat = Scalar(0.5) * conj(orientation) * angmom; - vec3 angvel_body = angmom_body_quat.v; + const quat angvel_body_quat = Scalar(0.5) * conj(orientation) * angmom; + vec3 angvel_body = angvel_body_quat.v; if (inertia.x != Scalar(0)) { angvel_body.x /= inertia.x; From 891d93f1ad3cf58dfcff77bdbd033e2cdb5c96d7 Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 17 Jun 2025 10:44:15 -0500 Subject: [PATCH 06/13] Use boolean in parametrize --- hoomd/md/pytest/test_rigid.py | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index 0e25fec6f9..199748e47b 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -138,13 +138,8 @@ def check_orientation( @skip_rowan @pytest.mark.parametrize( - "create_bodies_args", - [ - {}, - {"charges": {"A": [1.0, 2.0, 3.0, 4.0]}}, - {"masses": {"A": [5.0, 6.0, 7.0, 8.0]}}, - {"charges": {"A": [1.0, 2.0, 3.0, 4.0]}, "masses": {"A": [5.0, 6.0, 7.0, 8.0]}}, - ], + "include_charge,include_mass", + [(False, False), (True, False), (False, True), (True, True)], ids=["Default", "optional-change", "optional-mass", "optional-charge-mass"], ) def test_create_bodies( @@ -152,7 +147,8 @@ def test_create_bodies( two_particle_snapshot_factory, lattice_snapshot_factory, valid_body_definition, - create_bodies_args, + include_charge, + include_mass, ): rigid = md.constrain.Rigid() rigid.body["A"] = valid_body_definition @@ -162,20 +158,24 @@ def test_create_bodies( initial_snapshot.particles.types = ["A", "B"] sim = simulation_factory(initial_snapshot) - rigid.create_bodies(sim.state, **create_bodies_args) + charges = [1.0, 2.0, 3.0, 4.0] + masses = [5.0, 6.0, 7.0, 8.0] + if include_charge and include_mass: + rigid.create_bodies(sim.state, charges={"A": charges}, masses={"A": masses}) + elif include_charge: + rigid.create_bodies(sim.state, charges={"A": charges}) + elif include_mass: + rigid.create_bodies(sim.state, masses={"A": masses}) + else: + rigid.create_bodies(sim.state) snapshot = sim.state.get_snapshot() if snapshot.communicator.rank == 0: - charges = ( - create_bodies_args["charges"]["A"] - if "charges" in create_bodies_args.keys() - else None - ) - masses = ( - create_bodies_args["masses"]["A"] - if "masses" in create_bodies_args.keys() - else None + check_bodies( + snapshot, + valid_body_definition, + charges if include_charge else None, + masses if include_mass else None, ) - check_bodies(snapshot, valid_body_definition, charges, masses) sim.operations.integrator = hoomd.md.Integrator(dt=0.005, rigid=rigid) # Ensure validate bodies passes From b1bdbf7dfab4af328d1a24689f2256f55c76bcb3 Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 17 Jun 2025 10:44:33 -0500 Subject: [PATCH 07/13] Give default value of mass --- hoomd/md/constrain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/md/constrain.py b/hoomd/md/constrain.py index 6388a68c67..53d11d8878 100644 --- a/hoomd/md/constrain.py +++ b/hoomd/md/constrain.py @@ -341,7 +341,7 @@ def create_bodies(self, state, charges=None, masses=None): all charges are zero. The keys should be the central particles. masses (dict[str, list[float]]): (optional) The masses for each of the constituent particles, defaults to ``None``. If ``None``, - all masses are unchanged. The keys should be the central particles. + all masses are one. 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 From 47f49feba14d5aca0c4965466215b37c2308a31b Mon Sep 17 00:00:00 2001 From: mzbush <107584654+mzbush@users.noreply.github.com> Date: Wed, 18 Jun 2025 15:30:28 -0500 Subject: [PATCH 08/13] Update hoomd/md/pytest/test_rigid.py Co-authored-by: Michael Howard --- hoomd/md/pytest/test_rigid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index 199748e47b..a7cc5535c1 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -140,7 +140,7 @@ def check_orientation( @pytest.mark.parametrize( "include_charge,include_mass", [(False, False), (True, False), (False, True), (True, True)], - ids=["Default", "optional-change", "optional-mass", "optional-charge-mass"], + ids=["default", "optional-change", "optional-mass", "optional-charge-mass"], ) def test_create_bodies( simulation_factory, From 0ebee107c7a13dee69c4c763fe74c93c1e1f4e9e Mon Sep 17 00:00:00 2001 From: mzbush <107584654+mzbush@users.noreply.github.com> Date: Wed, 18 Jun 2025 15:31:07 -0500 Subject: [PATCH 09/13] Update hoomd/md/pytest/test_rigid.py Co-authored-by: Michael Howard --- hoomd/md/pytest/test_rigid.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index a7cc5535c1..3f9a5b9ba2 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -158,7 +158,9 @@ def test_create_bodies( initial_snapshot.particles.types = ["A", "B"] sim = simulation_factory(initial_snapshot) - charges = [1.0, 2.0, 3.0, 4.0] + optional_kwargs = {} + if include_charge: + optional_kwargs["charges"] = {"A": [1.0, 2.0, 3.0, 4.0]} masses = [5.0, 6.0, 7.0, 8.0] if include_charge and include_mass: rigid.create_bodies(sim.state, charges={"A": charges}, masses={"A": masses}) From f36d93a7b438db5d69e447c070a82d225eaa5b52 Mon Sep 17 00:00:00 2001 From: mzbush <107584654+mzbush@users.noreply.github.com> Date: Wed, 18 Jun 2025 15:31:28 -0500 Subject: [PATCH 10/13] Update hoomd/md/pytest/test_rigid.py Co-authored-by: Michael Howard --- hoomd/md/pytest/test_rigid.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index 3f9a5b9ba2..a94eee727f 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -161,15 +161,9 @@ def test_create_bodies( optional_kwargs = {} if include_charge: optional_kwargs["charges"] = {"A": [1.0, 2.0, 3.0, 4.0]} - masses = [5.0, 6.0, 7.0, 8.0] - if include_charge and include_mass: - rigid.create_bodies(sim.state, charges={"A": charges}, masses={"A": masses}) - elif include_charge: - rigid.create_bodies(sim.state, charges={"A": charges}) - elif include_mass: - rigid.create_bodies(sim.state, masses={"A": masses}) - else: - rigid.create_bodies(sim.state) + if include_mass: + optional_kwargs["masses"] = {"A": [5.0, 6.0, 7.0, 8.0]} + rigid.create_bodies(sim.state, **optional_kwargs) snapshot = sim.state.get_snapshot() if snapshot.communicator.rank == 0: check_bodies( From 2a6e2b5962c45ee6682c5ebc6e94f1f8c013cc20 Mon Sep 17 00:00:00 2001 From: mzbush <107584654+mzbush@users.noreply.github.com> Date: Wed, 18 Jun 2025 15:31:37 -0500 Subject: [PATCH 11/13] Update hoomd/md/pytest/test_rigid.py Co-authored-by: Michael Howard --- hoomd/md/pytest/test_rigid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hoomd/md/pytest/test_rigid.py b/hoomd/md/pytest/test_rigid.py index a94eee727f..6d69f44d09 100644 --- a/hoomd/md/pytest/test_rigid.py +++ b/hoomd/md/pytest/test_rigid.py @@ -169,8 +169,8 @@ def test_create_bodies( check_bodies( snapshot, valid_body_definition, - charges if include_charge else None, - masses if include_mass else None, + optional_kwargs["charges"]["A"] if include_charge else None, + optional_kwargs["masses"]["A"] if include_mass else None, ) sim.operations.integrator = hoomd.md.Integrator(dt=0.005, rigid=rigid) From 4b7290896c1d70f1e2d110e43263478b5980d828 Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 11 Nov 2025 13:07:00 -0600 Subject: [PATCH 12/13] Simplify add mass to constituents in mpcd pytests --- hoomd/mpcd/pytest/test_collide.py | 64 ++++++++----------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/hoomd/mpcd/pytest/test_collide.py b/hoomd/mpcd/pytest/test_collide.py index d76cc452d0..3bc4852f9b 100644 --- a/hoomd/mpcd/pytest/test_collide.py +++ b/hoomd/mpcd/pytest/test_collide.py @@ -225,29 +225,18 @@ def test_rigid_collide( initial_snap.particles.velocity[:] = [velo_rigid] initial_snap.particles.angmom[:] = [angmom_rigid] + # place the mpcd particles on top of constituents + initial_snap.mpcd.N = N_mpcd + initial_snap.mpcd.types = ["C"] + initial_snap.mpcd.position[:] = def_rigid["positions"] + initial_snap.mpcd.velocity[:] = velo_mpcd + sim = simulation_factory(initial_snap) sim.seed = 5 rigid = hoomd.md.constrain.Rigid() rigid.body["A"] = def_rigid - rigid.create_bodies(sim.state) - - intermed_snap = sim.state.get_snapshot() - if intermed_snap.communicator.rank == 0: - # add mass of constituents - flags = ( - intermed_snap.particles.typeid - == intermed_snap.particles.types.index("B") - ) - intermed_snap.particles.mass[flags] = properties_rigid["mass"][flags] - intermed_snap.wrap() - - # place the mpcd particles on top of constituents - intermed_snap.mpcd.N = N_mpcd - intermed_snap.mpcd.types = ["C"] - intermed_snap.mpcd.position[:] = intermed_snap.particles.position[flags] - intermed_snap.mpcd.velocity[:] = velo_mpcd - sim.state.set_snapshot(intermed_snap) + rigid.create_bodies(sim.state, masses={"A": properties_rigid["mass"][1:]}) sim.operations.integrator = hoomd.mpcd.Integrator( dt=0, integrate_rotational_dof=True, rigid=rigid @@ -364,31 +353,18 @@ def test_rigid_collide_free( initial_snap.particles.angmom[:] = [[0, 0, 0, 0], [0, 0, 0, 0]] initial_snap.particles.typeid[:] = [0, 2] + # place the mpcd particles on top of constituents + initial_snap.mpcd.N = N_mpcd + initial_snap.mpcd.types = ["C"] + initial_snap.mpcd.position[:] = def_rigid["positions"] + initial_snap.mpcd.velocity[:] = velo_mpcd + sim = simulation_factory(initial_snap) sim.seed = 5 rigid = hoomd.md.constrain.Rigid() rigid.body["A"] = def_rigid - rigid.create_bodies(sim.state) - - intermed_snap = sim.state.get_snapshot() - if intermed_snap.communicator.rank == 0: - # add mass of constituents - flags = np.logical_or( - intermed_snap.particles.typeid - == intermed_snap.particles.types.index("B"), - intermed_snap.particles.typeid - == intermed_snap.particles.types.index("D"), - ) - intermed_snap.particles.mass[flags] = properties_rigid["mass"][1:] - intermed_snap.wrap() - - # place the mpcd particles on top of constituents - intermed_snap.mpcd.N = N_mpcd - intermed_snap.mpcd.types = ["C"] - intermed_snap.mpcd.position[:] = intermed_snap.particles.position[flags] - intermed_snap.mpcd.velocity[:] = velo_mpcd - sim.state.set_snapshot(intermed_snap) + rigid.create_bodies(sim.state, masses={"A": properties_rigid["mass"][1:]}) sim.operations.integrator = hoomd.mpcd.Integrator( dt=0, integrate_rotational_dof=True, rigid=rigid @@ -538,17 +514,7 @@ def test_rigid_mass_errors( rigid = hoomd.md.constrain.Rigid() rigid.body["A"] = def_rigid - rigid.create_bodies(sim.state) - - # add mass of constituents - intermed_snap = sim.state.get_snapshot() - if intermed_snap.communicator.rank == 0: - flags = intermed_snap.particles.typeid == intermed_snap.particles.types.index( - "B" - ) - intermed_snap.particles.mass[flags] = masses[1:] - intermed_snap.wrap() - sim.state.set_snapshot(intermed_snap) + rigid.create_bodies(sim.state, masses={"A": masses[1:]}) sim.operations.integrator = hoomd.mpcd.Integrator(dt=0, rigid=rigid) sim.operations.integrator.collision_method = ( From e98cff9daa743244d57d41b710cecd6bac400552 Mon Sep 17 00:00:00 2001 From: mzbush Date: Tue, 11 Nov 2025 15:38:13 -0600 Subject: [PATCH 13/13] Add change to CHANGELOG --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 674aa5e1db..8768e58eff 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,8 @@ Next release (`#2136 `__). * Add thermodynamically consistent frictional contact forces: ``hoomd.md.pair.friction`` (`#2116 `__). +* ``create_bodies`` method takes optional ``masses`` argument to set masses + (`#2169 `__). *Fixed*