Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for writing rigid bodies when converting to HOOMD formats. #850

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3a27d99
add rigid_body field to atom, populate in from_mbuild
chrisjonesBSU Sep 17, 2024
bbb65c3
move rigid_id property to abstract_site from atom, write out rigid_id…
chrisjonesBSU Sep 17, 2024
92534db
add rigid types and typeids
chrisjonesBSU Sep 17, 2024
62edfeb
Merge branch 'fix/molecule' into rigid-bodies
chrisjonesBSU Sep 18, 2024
ab00493
add test for rigid_id assignment
chrisjonesBSU Sep 18, 2024
3d28187
Merge branch 'main' of github.com:mosdef-hub/gmso into rigid-bodies
chrisjonesBSU Sep 19, 2024
f6480bc
write out rigid xyz, com, tags
chrisjonesBSU Sep 23, 2024
ad603fa
add if statement before writing rigid tags
chrisjonesBSU Sep 23, 2024
fdba315
add basic rigid body snapshot test
chrisjonesBSU Sep 23, 2024
3a06f24
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 23, 2024
60e3538
Merge branch 'main' of github.com:mosdef-hub/gmso into rigid-bodies
chrisjonesBSU Sep 24, 2024
8842973
remove rigid id from convert mbuild, remove rigid id prop from abstra…
chrisjonesBSU Sep 25, 2024
6a383c6
parse rigid sites from site.molecule, update test
chrisjonesBSU Sep 26, 2024
7c65624
remove un-needed var
chrisjonesBSU Sep 30, 2024
a732661
Merge branch 'main' into rigid-bodies
chrisjonesBSU Oct 14, 2024
8da6fe5
update tests
chrisjonesBSU Oct 16, 2024
e9de935
Merge branch 'main' of github.com:mosdef-hub/gmso into rigid-bodies
chrisjonesBSU Oct 16, 2024
75289bb
fix charge array in np.concatenate call
chrisjonesBSU Oct 17, 2024
0d6e7d2
adjust snapshot groups by num rigid bodies
chrisjonesBSU Oct 17, 2024
a72d898
update tests
chrisjonesBSU Oct 17, 2024
5e8635f
fix _parse_pairs
chrisjonesBSU Oct 17, 2024
b96a83c
use unyt_arrays for charges and mass instead of lists
chrisjonesBSU Oct 18, 2024
937f913
Merge branch 'main' into rigid-bodies
chrisjonesBSU Oct 22, 2024
ffe639c
handle mix of rigid and non rigid
chrisjonesBSU Oct 30, 2024
4eaf697
remove if statement to filter -1 ids
chrisjonesBSU Oct 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 101 additions & 41 deletions gmso/external/convert_hoomd.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
NotYetImplementedWarning,
)

_parse_particle_information(
n_rigid = _parse_particle_information(
gsd_snapshot,
top,
base_units,
Expand All @@ -135,15 +135,15 @@
u.unyt_array([lx, ly, lz]),
)
if parse_special_pairs:
_parse_pairs_information(gsd_snapshot, top)
_parse_pairs_information(gsd_snapshot, top, n_rigid)
if top.n_bonds > 0:
_parse_bond_information(gsd_snapshot, top)
_parse_bond_information(gsd_snapshot, top, n_rigid)
if top.n_angles > 0:
_parse_angle_information(gsd_snapshot, top)
_parse_angle_information(gsd_snapshot, top, n_rigid)
if top.n_dihedrals > 0:
_parse_dihedral_information(gsd_snapshot, top)
_parse_dihedral_information(gsd_snapshot, top, n_rigid)
if top.n_impropers > 0:
_parse_improper_information(gsd_snapshot, top)
_parse_improper_information(gsd_snapshot, top, n_rigid)

return gsd_snapshot, base_units

Expand Down Expand Up @@ -224,7 +224,7 @@
NotYetImplementedWarning,
)

_parse_particle_information(
n_rigid = _parse_particle_information(
hoomd_snapshot,
top,
base_units,
Expand All @@ -233,15 +233,15 @@
u.unyt_array([lx, ly, lz]),
)
if parse_special_pairs:
_parse_pairs_information(hoomd_snapshot, top)
_parse_pairs_information(hoomd_snapshot, top, n_rigid)
if top.n_bonds > 0:
_parse_bond_information(hoomd_snapshot, top)
_parse_bond_information(hoomd_snapshot, top, n_rigid)
if top.n_angles > 0:
_parse_angle_information(hoomd_snapshot, top)
_parse_angle_information(hoomd_snapshot, top, n_rigid)
if top.n_dihedrals > 0:
_parse_dihedral_information(hoomd_snapshot, top)
_parse_dihedral_information(hoomd_snapshot, top, n_rigid)
if top.n_impropers > 0:
_parse_improper_information(hoomd_snapshot, top)
_parse_improper_information(hoomd_snapshot, top, n_rigid)

Check warning on line 244 in gmso/external/convert_hoomd.py

View check run for this annotation

Codecov / codecov/patch

gmso/external/convert_hoomd.py#L244

Added line #L244 was not covered by tests

hoomd_snapshot.wrap()
return hoomd_snapshot, base_units
Expand Down Expand Up @@ -284,17 +284,53 @@
site.name if site.atom_type is None else site.atom_type.name
for site in top.sites
]
unique_types = sorted(list(set(types)))
typeids = np.array([unique_types.index(t) for t in types])
masses = list()
charges = list()
for site in top.sites:
masses.append(
masses = u.unyt_array(
[
site.mass.to_value(base_units["mass"])
if site.mass
else 1 * base_units["mass"]
)
charges.append(site.charge if site.charge else 0 * u.elementary_charge)
for site in top.sites
]
)
charges = u.unyt_array(
[site.charge if site.charge else 0 * u.elementary_charge for site in top.sites]
)

unique_types = sorted(list(set(types)))
typeids = np.array([unique_types.index(t) for t in types])
# Check for rigid molecules
rigid_mols = any([site.molecule.isrigid for site in top.sites])
if rigid_mols:
rigid_ids = [
site.molecule.number if site.molecule.isrigid else -1 for site in top.sites
]
rigid_ids_set = set([i for i in rigid_ids if i != -1])
n_rigid = len(rigid_ids_set)
rigid_charges = np.zeros(n_rigid) * charges.units
rigid_masses = np.zeros(n_rigid) * masses.units
rigid_xyz = np.zeros((n_rigid, 3)) * xyz.units
# Rigid particle type defaults to "R"; add to front of list
# TODO: Can we always use "R" here? What if an atom_type is "R"?
unique_types = ["R"] + unique_types
# Rigid particles get type ID 0, move all others up by 1
typeids = np.concatenate((np.array([0] * n_rigid), typeids + 1))
# Update mass list and position list of Frame
for idx, _id in enumerate(rigid_ids_set):
group_indices = np.where(np.array(rigid_ids) == _id)[0]
group_positions = xyz[group_indices]
group_masses = masses[group_indices]
com_xyz = np.sum(group_positions.T * group_masses, axis=1) / sum(
group_masses
)
rigid_masses[idx] = sum(group_masses)
rigid_xyz[idx] = com_xyz
# Append rigid center mass and xyz to front
masses = np.concatenate((rigid_masses, masses))
xyz = np.concatenate((rigid_xyz, xyz))
charges = np.concatenate((rigid_charges, charges))
rigid_id_tags = np.concatenate((np.arange(n_rigid), rigid_ids))
else:
n_rigid = 0

"""
Permittivity of free space = 2.39725e-4 e^2/((kcal/mol)(angstrom)),
Expand All @@ -309,31 +345,40 @@
) ** 0.5

if isinstance(snapshot, hoomd.Snapshot):
snapshot.particles.N = top.n_sites
snapshot.particles.N = top.n_sites + n_rigid
snapshot.particles.types = unique_types
snapshot.particles.position[0:] = xyz
snapshot.particles.typeid[0:] = typeids
snapshot.particles.mass[0:] = masses
snapshot.particles.charge[0:] = charges / charge_factor
if n_rigid:
snapshot.particles.body[0:] = rigid_id_tags

Check warning on line 355 in gmso/external/convert_hoomd.py

View check run for this annotation

Codecov / codecov/patch

gmso/external/convert_hoomd.py#L355

Added line #L355 was not covered by tests
elif isinstance(snapshot, gsd.hoomd.Frame):
snapshot.particles.N = top.n_sites
snapshot.particles.N = top.n_sites + n_rigid
snapshot.particles.types = unique_types
snapshot.particles.position = xyz
snapshot.particles.typeid = typeids
snapshot.particles.mass = masses
snapshot.particles.charge = charges / charge_factor
if rigid_bodies:
warnings.warn(
"Rigid bodies detected, but not yet implemented for GSD",
NotYetImplementedWarning,
)
if n_rigid:
snapshot.particles.body = rigid_id_tags
return n_rigid


def _parse_pairs_information(
snapshot,
top,
):
"""Parse scaled pair types."""
def _parse_pairs_information(snapshot, top, n_rigid=0):
"""Parse sacled pair types.

Parameters
----------
snapshot : gsd.hoomd.Frame or hoomd.Snapshot
The target Snapshot object.
top : gmso.Topology
Topology object holding system information
n_rigid : int
The number of rigid bodies found in `_parse_particle_information()`
Used to adjust pair group indices.

"""
pair_types = list()
pair_typeids = list()
pairs = list()
Expand All @@ -353,7 +398,9 @@
if pair_type not in pair_types:
pair_types.append(pair_type)
pair_typeids.append(pair_types.index(pair_type))
pairs.append((top.get_index(pair[0]), top.get_index(pair[1])))
pairs.append(
(top.get_index(pair[0]) + n_rigid, top.get_index(pair[1]) + n_rigid)
)

if isinstance(snapshot, hoomd.Snapshot):
snapshot.pairs.N = len(pairs)
Expand All @@ -367,7 +414,7 @@
snapshot.pairs.typeid = pair_typeids


def _parse_bond_information(snapshot, top):
def _parse_bond_information(snapshot, top, n_rigid=0):
"""Parse bonds information from topology.

Parameters
Expand All @@ -376,6 +423,9 @@
The target Snapshot object.
top : gmso.Topology
Topology object holding system information
n_rigid : int
The number of rigid bodies found in `_parse_particle_information()`
Used to adjust bond group indices.

"""
snapshot.bonds.N = top.n_bonds
Expand All @@ -396,7 +446,7 @@

bond_types.append(bond_type)
bond_groups.append(
sorted(tuple(top.get_index(site) for site in connection_members))
sorted(tuple(top.get_index(site) + n_rigid for site in connection_members))
)

unique_bond_types = list(set(bond_types))
Expand All @@ -414,7 +464,7 @@
warnings.warn(f"{len(unique_bond_types)} unique bond types detected")


def _parse_angle_information(snapshot, top):
def _parse_angle_information(snapshot, top, n_rigid=0):
"""Parse angles information from topology.

Parameters
Expand All @@ -423,6 +473,9 @@
The target Snapshot object.
top : gmso.Topology
Topology object holding system information
n_rigid : int
The number of rigid bodies found in `_parse_particle_information()`
Used to adjust angle group indices.

"""
snapshot.angles.N = top.n_angles
Expand All @@ -442,7 +495,9 @@
angle_type = "-".join([site.name for site in connection_members])

angle_types.append(angle_type)
angle_groups.append(tuple(top.get_index(site) for site in connection_members))
angle_groups.append(
tuple(top.get_index(site) + n_rigid for site in connection_members)
)

unique_angle_types = list(set(angle_types))
angle_typeids = [unique_angle_types.index(i) for i in angle_types]
Expand All @@ -460,7 +515,7 @@
warnings.warn(f"{len(unique_angle_types)} unique angle types detected")


def _parse_dihedral_information(snapshot, top):
def _parse_dihedral_information(snapshot, top, n_rigid=0):
"""Parse dihedral information from topology.

Parameters
Expand All @@ -469,6 +524,9 @@
The target Snapshot object.
top : gmso.Topology
Topology object holding system information
n_rigid : int
The number of rigid bodies found in `_parse_particle_information()`
Used to adjust dihedral group indices.

"""
snapshot.dihedrals.N = top.n_dihedrals
Expand All @@ -487,7 +545,7 @@

dihedral_types.append(dihedral_type)
dihedral_groups.append(
tuple(top.get_index(site) for site in connection_members)
tuple(top.get_index(site) + n_rigid for site in connection_members)
)

unique_dihedral_types = list(set(dihedral_types))
Expand All @@ -506,7 +564,7 @@
warnings.warn(f"{len(unique_dihedral_types)} unique dihedral types detected")


def _parse_improper_information(snapshot, top):
def _parse_improper_information(snapshot, top, n_rigid=0):
"""Parse impropers information from topology.

Parameters
Expand All @@ -515,6 +573,8 @@
The target Snapshot object.
top : gmso.Topology
Topology object holding system information
n_rigid : int
The number of rigid bodies found in `_parse_particle_information()`

"""
snapshot.impropers.N = top.n_impropers
Expand All @@ -533,7 +593,7 @@

improper_types.append(improper_type)
improper_groups.append(
tuple(top.get_index(site) for site in connection_members)
tuple(top.get_index(site) + n_rigid for site in connection_members)
)

unique_improper_types = list(set(improper_types))
Expand Down
Loading
Loading