From 1b0fcb8379daeb2234becb5ddcc14837befb1e0d Mon Sep 17 00:00:00 2001 From: chrisjonesBSU Date: Mon, 28 Oct 2024 11:31:45 -0600 Subject: [PATCH] remove rigid from conversion.py, update tests --- mbuild/conversion.py | 22 -- mbuild/tests/test_compound.py | 6 +- mbuild/tests/test_hoomd.py | 427 ---------------------------------- 3 files changed, 3 insertions(+), 452 deletions(-) delete mode 100644 mbuild/tests/test_hoomd.py diff --git a/mbuild/conversion.py b/mbuild/conversion.py index 6d42091ab..7cb168017 100644 --- a/mbuild/conversion.py +++ b/mbuild/conversion.py @@ -36,7 +36,6 @@ def load( relative_to_module=None, compound=None, coords_only=False, - rigid=False, smiles=False, infer_hierarchy=True, backend=None, @@ -68,8 +67,6 @@ def load( will be added to the existing compound as a sub compound. coords_only : bool, optional, default=False Only load the coordinates into an existing compound. - rigid : bool, optional, default=False - Treat the compound as a rigid body backend : str, optional, default=None Backend used to load structure from file or string. If not specified, a default backend (extension specific) will be used. @@ -103,7 +100,6 @@ def load( obj=filename_or_object, compound=compound, coords_only=coords_only, - rigid=rigid, infer_hierarchy=infer_hierarchy, **kwargs, ) @@ -126,7 +122,6 @@ def load( relative_to_module=relative_to_module, compound=compound, coords_only=coords_only, - rigid=rigid, backend=backend, infer_hierarchy=infer_hierarchy, **kwargs, @@ -137,7 +132,6 @@ def load_object( obj, compound=None, coords_only=False, - rigid=False, infer_hierarchy=True, **kwargs, ): @@ -156,8 +150,6 @@ def load_object( The host mbuild Compound coords_only : bool, optional, default=False Only load the coordinates into existing compound. - rigid : bool, optional, default=False - Treat the compound as a rigid body infer_hierarchy : bool, optional, default=True If True, infer hiereachy from chains and residues **kwargs : keyword arguments @@ -200,8 +192,6 @@ def load_object( infer_hierarchy=infer_hierarchy, **kwargs, ) - if rigid: - compound.label_rigid_bodies() return compound # If nothing is return raise an error @@ -323,7 +313,6 @@ def load_file( relative_to_module=None, compound=None, coords_only=False, - rigid=False, backend=None, infer_hierarchy=True, **kwargs, @@ -348,8 +337,6 @@ def load_file( will be added to the existing compound as a sub compound. coords_only : bool, optional, default=False Only load the coordinates into an existing compound. - rigid : bool, optional, default=False - Treat the compound as a rigid body backend : str, optional, default=None Backend used to load structure from file. If not specified, a default backend (extension specific) will be used. @@ -462,8 +449,6 @@ def load_file( ) # Note: 'Input not supported' error will be handled # by the corresponding backend - if rigid: - compound.label_rigid_bodies() return compound @@ -1199,7 +1184,6 @@ def to_hoomdsnapshot( identify_connections=True, ref_distance=1.0, ref_mass=1.0, - rigid_bodies=None, shift_coords=True, write_special_pairs=True, **kwargs, @@ -1216,11 +1200,6 @@ def to_hoomdsnapshot( Reference distance for conversion to reduced units ref_mass : float, optional, default=1.0 Reference mass for conversion to reduced units - rigid_bodies : list of int, optional, default=None - List of rigid body information. An integer value is required for each - atom corresponding to the index of the rigid body the particle is to be - associated with. A value of None indicates the atom is not part of a - rigid body. shift_coords : bool, optional, default=True Shift coordinates from (0, L) to (-L/2, L/2) if necessary. write_special_pairs : bool, optional, default=True @@ -1249,7 +1228,6 @@ def to_hoomdsnapshot( snapshot, refs = to_gsd_snapshot( top=gmso_top, base_units=base_units, - rigid_bodies=rigid_bodies, shift_coords=shift_coords, parse_special_pairs=write_special_pairs, auto_scale=False, diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index 376f1eb6f..ab86c1ac6 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -2560,9 +2560,9 @@ def test_elements_from_smiles(self, backend): for particle in mol.particles(): assert particle.element is not None - def test_mins_maxs(self, rigid_benzene): - assert np.allclose(rigid_benzene.mins, [-0.2267, -0.15422, 0.0]) - assert np.allclose(rigid_benzene.maxs, [0.20318, 0.34207, 0.0]) + def test_mins_maxs(self, ethane): + assert np.allclose(ethane.mins, [-0.10699999, -0.21690001, -0.0993]) + assert np.allclose(ethane.maxs, [0.10699999, 0.07690001, 0.0653]) def test_periodicity_raises(self): with pytest.raises(ValueError): diff --git a/mbuild/tests/test_hoomd.py b/mbuild/tests/test_hoomd.py deleted file mode 100644 index 88439aa14..000000000 --- a/mbuild/tests/test_hoomd.py +++ /dev/null @@ -1,427 +0,0 @@ -import xml.etree.ElementTree - -import numpy as np -import packaging.version -import pytest - -import mbuild as mb -from mbuild.tests.base_test import BaseTest -from mbuild.utils.io import get_fn, has_foyer, has_gsd, has_hoomd, import_ - -if has_hoomd: - import hoomd - - if "version" in dir(hoomd): - hoomd_version = packaging.version.parse(hoomd.version.version) - else: - hoomd_version = packaging.version.parse(hoomd.__version__) - - -@pytest.mark.skipif(not has_hoomd, reason="HOOMD is not installed") -class TestHoomdAny(BaseTest): - def test_empty_initial_snapshot(self): - import hoomd - - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - part = mb.Compound(name="Ar") - box = mb.Box(lengths=[5, 5, 5], angles=[90, 90, 90]) - system = mb.fill_box(part, n_compounds=10, box=box) - - if hoomd_version.major == 2: - hoomd.context.initialize("") - init_snap = hoomd.data.make_snapshot( - N=0, box=hoomd.data.boxdim(L=10) - ) - else: - init_snap = hoomd.Snapshot() - init_snap.configuration.box = hoomd.Box.cube(L=10) - - with pytest.raises(RuntimeError): - snap, _ = to_hoomdsnapshot(system, hoomd_snapshot=init_snap) - - def test_compound_from_snapshot(self, ethane): - from mbuild.formats.hoomd_snapshot import ( - from_snapshot, - to_hoomdsnapshot, - ) - - lengths = [5, 5, 5] - filled = mb.fill_box(ethane, n_compounds=5, box=mb.Box(lengths)) - snap, _ = to_hoomdsnapshot(filled) - new_filled = from_snapshot(snap, scale=0.1) - - assert filled.n_bonds == new_filled.n_bonds - assert filled.n_particles == new_filled.n_particles - - assert np.array_equal(filled.box.angles, new_filled.box.angles) - assert np.array_equal(filled.box.lengths, new_filled.box.lengths) - - for i in range(filled.n_particles): - assert np.allclose(filled[i].pos, new_filled[i].pos) - - @pytest.mark.skipif(not has_gsd, reason="gsd is not installed") - def test_compound_from_gsdsnapshot(self, ethane): - import gsd.hoomd - - from mbuild.formats.hoomd_snapshot import ( - from_snapshot, - to_hoomdsnapshot, - ) - - lengths = [5, 5, 5] - filled = mb.fill_box(ethane, n_compounds=5, box=mb.Box(lengths)) - snap, _ = to_hoomdsnapshot(filled) - - # copy attributes from the snapshot to a gsd snapshot - gsd_snap = gsd.hoomd.Frame() - gsd_snap.particles.N = snap.particles.N - gsd_snap.particles.types = snap.particles.types - gsd_snap.particles.typeid = snap.particles.typeid - gsd_snap.particles.position = snap.particles.position - if hoomd_version.major == 2: - gsd_snap.configuration.box = np.array( - [ - snap.box.Lx, - snap.box.Ly, - snap.box.Lz, - snap.box.xy, - snap.box.xy, - snap.box.yz, - ] - ) - else: - gsd_snap.configuration.box = snap.configuration.box - - gsd_snap.bonds.N = snap.bonds.N - gsd_snap.bonds.group = snap.bonds.group - gsd_snap.particles.charge = snap.particles.charge - gsd_snap.validate() - - new_filled = from_snapshot(gsd_snap, scale=0.1) - - assert filled.n_bonds == new_filled.n_bonds - assert filled.n_particles == new_filled.n_particles - - assert np.array_equal(filled.box.angles, new_filled.box.angles) - assert np.array_equal(filled.box.lengths, new_filled.box.lengths) - - for i in range(filled.n_particles): - assert np.allclose(filled[i].pos, new_filled[i].pos) - - def test_compound_to_snapshot(self, ethane): - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - snap, _ = to_hoomdsnapshot(ethane) - - assert snap.particles.N == 8 - assert snap.bonds.N == 7 - assert snap.angles.N == 0 - - def test_particles_to_snapshot(self): - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - part = mb.Compound(name="Ar") - box = mb.Box(lengths=[5, 5, 5], angles=[90, 90, 90]) - system = mb.fill_box(part, n_compounds=10, box=box) - snap, _ = to_hoomdsnapshot(system) - - assert snap.particles.N == 10 - assert snap.bonds.N == 0 - assert snap.angles.N == 0 - - def test_snapshot_from_initial(self): - import hoomd - - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - part = mb.Compound(name="Ar") - box = mb.Box(lengths=[5, 5, 5], angles=[90, 90, 90]) - system = mb.fill_box(part, n_compounds=10, box=box) - if hoomd_version.major == 2: - hoomd.context.initialize("") - init_snap = hoomd.data.make_snapshot( - N=10, box=hoomd.data.boxdim(L=10) - ) - else: - init_snap = hoomd.Snapshot() - init_snap.particles.N = 10 - init_snap.configuration.box = hoomd.Box.cube(L=10) - - snap, _ = to_hoomdsnapshot(system, hoomd_snapshot=init_snap) - - assert snap.particles.N == 20 - assert snap.bonds.N == 0 - assert snap.angles.N == 0 - if hoomd_version.major == 2: - assert (snap.box.Lx, snap.box.Ly, snap.box.Lz) == (50, 50, 50) - assert (snap.box.xy, snap.box.xz, snap.box.yz) == (0, 0, 0) - else: - np.testing.assert_allclose( - snap.configuration.box, [50, 50, 50, 0, 0, 0] - ) - - def test_bad_input_to_snapshot(self): - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - with pytest.raises(ValueError): - to_hoomdsnapshot("fake_object") - - def test_non_param_struc_to_snapshot(self, ethane): - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - structure = ethane.to_parmed() - snap, _ = to_hoomdsnapshot(structure) - - assert snap.particles.N == 8 - assert snap.bonds.N == 7 - assert snap.angles.N == 0 - - @pytest.mark.skipif(not has_foyer, reason="Foyer is not installed") - def test_param_structure_to_snapshot(self, ethane): - from foyer.forcefield import Forcefield - - from mbuild.formats.hoomd_snapshot import to_hoomdsnapshot - - ff = Forcefield(name="oplsaa") - structure = ff.apply(ethane) - snap, _ = to_hoomdsnapshot(structure) - - assert snap.particles.N == 8 - assert snap.bonds.N == 7 - assert snap.angles.N == 12 - assert snap.dihedrals.N == 9 - assert snap.pairs.N == 9 - - -@pytest.mark.skipif( - not has_hoomd or hoomd_version.major != 2, - reason="HOOMD is not installed or is the wrong version", -) -class TestHoomdSimulation(BaseTest): - def test_bad_input_to_hoomdsimulation(self): - from mbuild.formats.hoomd_simulation import create_hoomd_simulation - - with pytest.raises(ValueError): - create_hoomd_simulation("fake_object", 2) - - def test_compound_to_hoomdsimulation(self, ethane): - from mbuild.formats.hoomd_simulation import create_hoomd_simulation - - with pytest.raises(ValueError): - create_hoomd_simulation(ethane, 2.5) - - @pytest.mark.skipif(not has_foyer, reason="Foyer is not installed") - def test_structure_to_hoomdsimulation(self, ethane): - import hoomd - from foyer.forcefield import Forcefield - - from mbuild.formats.hoomd_simulation import create_hoomd_simulation - - ff = Forcefield(name="oplsaa") - structure = ff.apply(ethane) - sim = hoomd.context.SimulationContext() - with sim: - create_hoomd_simulation(structure, 2.5) - - sim_forces = hoomd.context.current.forces - pair_force = import_("hoomd.md.pair") - charge_force = import_("hoomd.md.charge") - special_pair_force = import_("hoomd.md.special_pair") - bond_force = import_("hoomd.md.bond") - angle_force = import_("hoomd.md.angle") - dihedral_force = import_("hoomd.md.dihedral") - - assert isinstance(sim_forces[0], pair_force.lj) - assert isinstance(sim_forces[1], charge_force.pppm) - assert isinstance(sim_forces[2], pair_force.ewald) - assert isinstance(sim_forces[3], special_pair_force.lj) - assert isinstance(sim_forces[4], special_pair_force.coulomb) - assert isinstance(sim_forces[5], bond_force.harmonic) - assert isinstance(sim_forces[6], angle_force.harmonic) - assert isinstance(sim_forces[7], dihedral_force.opls) - - @pytest.mark.skipif(not has_foyer, reason="Foyer is not installed") - def test_lj_to_hoomdsimulation(self): - import hoomd - from foyer.forcefield import Forcefield - - from mbuild.formats.hoomd_simulation import create_hoomd_simulation - - box = mb.Compound() - box.add(mb.Compound(name="Ar", pos=[1, 1, 1])) - box.add(mb.Compound(name="Ar", pos=[1, 1, 1])) - ff = Forcefield(forcefield_files=get_fn("lj.xml")) - structure = ff.apply(box) - structure.box = [10, 10, 10, 90, 90, 90] - sim = hoomd.context.SimulationContext() - with sim: - create_hoomd_simulation(structure, 2.5) - sim_forces = hoomd.context.current.forces - pair_force = import_("hoomd.md.pair") - - assert isinstance(sim_forces[0], pair_force.lj) - - @pytest.mark.skipif(not has_foyer, reason="Foyer is not installed") - @pytest.mark.skipif(not has_gsd, reason="GSD is not installed") - def test_hoomdsimulation_restart(self): - import gsd.hoomd - import hoomd - from foyer.forcefield import Forcefield - - from mbuild.formats.hoomd_simulation import create_hoomd_simulation - - box = mb.Compound() - box.add(mb.Compound(name="Ar", pos=[1, 1, 1])) - box.add(mb.Compound(name="Ar", pos=[1, 1, 1])) - ff = Forcefield(forcefield_files=get_fn("lj.xml")) - structure = ff.apply(box) - structure.box = [10, 10, 10, 90, 90, 90] - sim = hoomd.context.SimulationContext() - with sim: - hoomd_obj, ref_vals = create_hoomd_simulation( - structure, 2.5, restart=get_fn("restart.gsd") - ) - sim_forces = hoomd.context.current.forces - pair_force = import_("hoomd.md.pair") - - assert isinstance(sim_forces[0], pair_force.lj) - - snap = hoomd_obj[0] - with gsd.hoomd.open(get_fn("restart.gsd")) as f: - rsnap = f[0] - assert np.array_equal(snap.particles.position, rsnap.particles.position) - - def test_hoomdsimulation_nlist(self, ethane): - hoomd_simulation = import_("mbuild.formats.hoomd_simulation") - hoomd = import_("hoomd") - hoomd.md = import_("hoomd.md") - - with pytest.raises(ValueError): - hoomd_simulation.create_hoomd_simulation( - ethane, 2.5, nlist=hoomd.md.nlist.tree - ) - - -@pytest.mark.skipif( - not has_hoomd or hoomd_version.major < 3, - reason="HOOMD is not installed or is the wrong version", -) -class TestHoomdForcefield(BaseTest): - def test_bad_input_to_hoomd_forcefield(self): - from mbuild.formats.hoomd_forcefield import create_hoomd_forcefield - - with pytest.raises(ValueError): - create_hoomd_forcefield("fake_object", 2.5) - - def test_compound_to_hoomd_forcefield(self, ethane): - from mbuild.formats.hoomd_forcefield import create_hoomd_forcefield - - with pytest.raises(ValueError): - create_hoomd_forcefield(ethane, 2.5) - - @pytest.mark.skipif(not has_foyer, reason="Foyer is not installed") - def test_structure_to_hoomd_forcefield(self, ethane): - import hoomd - from foyer.forcefield import Forcefield - - from mbuild.formats.hoomd_forcefield import create_hoomd_forcefield - - ff = Forcefield(name="oplsaa") - structure = ff.apply(ethane) - - snapshot, forces, ref_values = create_hoomd_forcefield(structure, 2.5) - - assert isinstance(forces[0], hoomd.md.pair.LJ) - assert isinstance(forces[1], hoomd.md.pair.Ewald) - assert isinstance(forces[2], hoomd.md.long_range.pppm.Coulomb) - assert isinstance(forces[3], hoomd.md.special_pair.LJ) - assert isinstance(forces[4], hoomd.md.special_pair.Coulomb) - assert isinstance(forces[5], hoomd.md.bond.Harmonic) - assert isinstance(forces[6], hoomd.md.angle.Harmonic) - assert isinstance(forces[7], hoomd.md.dihedral.OPLS) - - @pytest.mark.skipif(not has_foyer, reason="Foyer is not installed") - def test_lj_to_hoomd_forcefield(self): - import hoomd - from foyer.forcefield import Forcefield - - from mbuild.formats.hoomd_forcefield import create_hoomd_forcefield - - box = mb.Compound() - box.add(mb.Compound(name="Ar", pos=[1, 1, 1])) - box.add(mb.Compound(name="Ar", pos=[1, 1, 1])) - ff = Forcefield(forcefield_files=get_fn("lj.xml")) - structure = ff.apply(box) - structure.box = [10, 10, 10, 90, 90, 90] - - snapshot, forces, ref_values = create_hoomd_forcefield(structure, 2.5) - - assert isinstance(forces[0], hoomd.md.pair.LJ) - - -class TestHoomdXML(BaseTest): - def test_save(self, ethane): - ethane.save(filename="ethane.hoomdxml") - - @pytest.mark.skipif(not has_foyer, reason="Foyer package not installed") - def test_save_forcefield(self, ethane): - ethane.save(filename="ethane-opls.hoomdxml", forcefield_name="oplsaa") - - def test_save_box(self, ethane): - box = mb.box.Box(lengths=[2.0, 2.0, 2.0], angles=[90, 90, 90]) - ethane.save(filename="ethane-box.hoomdxml", box=box) - - def test_save_triclinic_box_(self, ethane): - box = mb.Box(lengths=np.array([2.0, 2.0, 2.0]), angles=[60, 70, 80]) - ethane.save(filename="triclinic-box.hoomdxml", box=box) - - @pytest.mark.skipif(not has_foyer, reason="Foyer package not installed") - def test_number_in_each_section(self, box_of_benzenes): - box_of_benzenes.save( - filename="benzene.hoomdxml", forcefield_name="oplsaa" - ) - xml_file = xml.etree.ElementTree.parse("benzene.hoomdxml").getroot() - for attribute in ["position", "type", "mass", "charge"]: - body_text = xml_file[0].find(attribute).text - list_of_things = [x for x in body_text.split("\n") if x] - assert len(list_of_things) == 12 * 10 - for attribute, number in [ - ("bond", 12), - ("angle", 18), - ("dihedral", 24), - ]: - body_text = xml_file[0].find(attribute).text - list_of_things = [x for x in body_text.split("\n") if x] - assert len(list_of_things) == number * 10 - - def test_box_dimensions(self, benzene): - n_benzenes = 10 - filled = mb.fill_box( - benzene, n_compounds=n_benzenes, box=[0, 0, 0, 4, 4, 4] - ) - filled.save(filename="benzene.hoomdxml") - for atom in mb.load("benzene.hoomdxml"): - assert atom.pos.max() < 20 - assert atom.pos.min() > -20 - - @pytest.mark.skipif(not has_foyer, reason="Foyer package not installed") - def test_auto_scale_forcefield(self, ethane): - ethane.save( - filename="ethane-opls.hoomdxml", - forcefield_name="oplsaa", - auto_scale=True, - ) - xml_file = xml.etree.ElementTree.parse("ethane-opls.hoomdxml").getroot() - masses = xml_file[0].find("mass").text.splitlines() - # We use 1 and 5 since the first element of masses is empty - assert masses[1] == "1.0" - assert masses[5] == "1.0" - pair_coeffs = [ - _.split("\t") - for _ in xml_file[0].find("pair_coeffs").text.splitlines() - ] - # The first element is empty, the next element should be - # ['opls_135', '1.0000', '1.0000'] - assert pair_coeffs[1][1] == "1.0000" - assert pair_coeffs[1][2] == "1.0000"