def test_from_openmm_pdbfile(self, argon_ff, argon_top): pdb_file_path = get_test_file_path("10-argons.pdb") pdbfile = openmm.app.PDBFile(pdb_file_path) mol = Molecule.from_smiles("[#18]") top = Topology.from_openmm(pdbfile.topology, unique_molecules=[mol]) box = pdbfile.topology.getPeriodicBoxVectors() box = box.value_in_unit(nm) * unit.nanometer out = argon_ff.create_openff_system(top) out.box = box out.positions = pdbfile.getPositions() assert np.allclose( out.positions.to(unit.nanometer).magnitude, pdbfile.getPositions().value_in_unit(nm), ) get_openmm_energies(out, hard_cutoff=True).compare( _get_openmm_energies( omm_sys=argon_ff.create_openmm_system(top), box_vectors=pdbfile.topology.getPeriodicBoxVectors(), positions=pdbfile.getPositions(), hard_cutoff=True, ))
def test_from_openmm_single_mols(mol, n_mols): """ Test that ForceField.create_openmm_system and System.to_openmm produce objects with similar energies TODO: Tighten tolerances TODO: Test periodic and non-periodic """ parsley = ForceField(get_test_file_path("parsley.offxml")) mol = Molecule.from_smiles(mol) mol.generate_conformers(n_conformers=1) top = Topology.from_molecules(n_mols * [mol]) mol.conformers[0] -= np.min(mol.conformers) * unit.angstrom top.box_vectors = np.eye(3) * np.asarray([10, 10, 10]) * unit.nanometer if n_mols == 1: positions = mol.conformers[0] elif n_mols == 2: positions = np.vstack( [mol.conformers[0], mol.conformers[0] + 3 * unit.nanometer]) positions = positions * unit.angstrom toolkit_system = parsley.create_openmm_system(top) native_system = parsley.create_openff_system(topology=top).to_openmm() compare_system_energies( system1=toolkit_system, system2=native_system, positions=positions, box_vectors=top.box_vectors, )
def test_to_force_field_to_system_parameters(self, parsley, ethanol_top, handler_name, n_ff_terms, n_sys_terms): import jax from openff.system.stubs import ForceField handler = parsley[handler_name].create_potential(topology=ethanol_top) p = handler.get_force_field_parameters() assert isinstance(p, jax.interpreters.xla.DeviceArray) assert np.prod(p.shape) == n_ff_terms q = handler.get_system_parameters() assert isinstance(q, jax.interpreters.xla.DeviceArray) assert np.prod(q.shape) == n_sys_terms assert jax.numpy.allclose(q, handler.parametrize(p)) param_matrix = handler.get_param_matrix() ref_file = get_test_file_path( f"ethanol_param_{handler_name.lower()}.npy") ref = jax.numpy.load(ref_file) assert jax.numpy.allclose(ref, param_matrix) # TODO: Update with other handlers that can safely be assumed to follow 1:1 slot:smirks mapping if handler_name in ["vdW", "Bonds", "Angles"]: assert np.allclose(np.sum(param_matrix, axis=1), np.ones(param_matrix.shape[0]))
def get_mdp_file(key: str) -> Path: mapping = { "default": "default.mdp", "cutoff": "cutoff.mdp", "cutoff_hbonds": "cutoff_hbonds.mdp", "cutoff_buck": "cutoff_buck.mdp", } return get_test_file_path(f"mdp/{mapping[key]}")
def test_from_openmm_pdbfile(self, argon_ff, argon_top): # TODO: Host files like this here instead of grabbing from the toolkit pdb_file_path = get_test_file_path("10-argons.pdb") pdbfile = openmm.app.PDBFile(pdb_file_path) System( topology=argon_top, forcefield=argon_ff, positions=pdbfile.positions, box=pdbfile.topology.getPeriodicBoxVectors(), )
def test_parmed_roundtrip(self): original = pmd.load_file(get_test_file_path("ALA_GLY/ALA_GLY.top")) gro = pmd.load_file(get_test_file_path("ALA_GLY/ALA_GLY.gro")) original.box = gro.box original.positions = gro.positions openff_sys = from_parmed(original) roundtrip = openff_sys.to_parmed() roundtrip.save("conv.gro", overwrite=True) roundtrip.save("conv.top", overwrite=True) original_energy = run_gmx_energy( top_file=get_test_file_path("ALA_GLY/ALA_GLY.top"), gro_file=get_test_file_path("ALA_GLY/ALA_GLY.gro"), mdp_file=get_mdp_file("cutoff_hbonds"), ) internal_energy = get_gromacs_energies(openff_sys, mdp="cutoff_hbonds") roundtrip_energy = run_gmx_energy( top_file="conv.top", gro_file="conv.gro", mdp_file=get_mdp_file("cutoff_hbonds"), ) # Differences in bond energies appear to be related to ParmEd's rounding # of the force constant and equilibrium bond length original_energy.compare(internal_energy) internal_energy.compare( roundtrip_energy, custom_tolerances={ "Bond": 0.02 * omm_unit.kilojoule_per_mole, }, ) original_energy.compare( roundtrip_energy, custom_tolerances={ "Bond": 0.02 * omm_unit.kilojoule_per_mole, }, )
def test_water_dimer(): from openff.system.utils import get_test_file_path tip3p = ForceField(get_test_file_path("tip3p.offxml")) water = Molecule.from_smiles("O") top = Topology.from_molecules(2 * [water]) pdbfile = openmm.app.PDBFile(get_test_file_path("water-dimer.pdb")) positions = np.array(pdbfile.positions / omm_unit.nanometer) * unit.nanometer openff_sys = tip3p.create_openff_system(top) openff_sys.positions = positions openff_sys.box = [10, 10, 10] * unit.nanometer omm_energies = get_openmm_energies( openff_sys, hard_cutoff=True, electrostatics=False, ) toolkit_energies = _get_openmm_energies( tip3p.create_openmm_system(top), openff_sys.box, openff_sys.positions, hard_cutoff=True, electrostatics=False, ) omm_energies.compare(toolkit_energies) # TODO: Fix GROMACS energies by handling SETTLE constraints # gmx_energies, _ = get_gromacs_energies(openff_sys) # compare_gromacs_openmm(omm_energies=omm_energies, gmx_energies=gmx_energies) lmp_energies = get_lammps_energies(openff_sys, electrostatics=False) lmp_energies.compare(omm_energies)
def test_water_dimer(): """Test that a water dimer can be written and the files can be grommp'd""" from openff.system.utils import get_test_file_path tip3p = ForceField(get_test_file_path("tip3p.offxml")) water = Molecule.from_smiles("O") top = Topology.from_molecules(2 * [water]) from simtk import openmm from simtk import unit as omm_unit pdbfile = openmm.app.PDBFile(get_test_file_path("water-dimer.pdb")) positions = np.array( pdbfile.positions / omm_unit.nanometer) * unit.nanometer openff_sys = tip3p.create_openff_system(top) openff_sys.positions = positions openff_sys.box = [10, 10, 10] * unit.nanometer gmx_energies = get_gromacs_energies(openff_sys, writer="internal") assert gmx_energies is not None
def test_argon(n_mol): from openff.system.utils import get_test_file_path ar_ff = ForceField(get_test_file_path("argon.offxml")) mol = Molecule.from_smiles("[#18]") mol.add_conformer(np.array([[0, 0, 0]]) * omm_unit.angstrom) mol.name = "FOO" top = Topology.from_molecules(n_mol * [mol]) off_sys = ar_ff.create_openff_system(top) mol.to_file("out.xyz", file_format="xyz") compound: mb.Compound = mb.load("out.xyz") packed_box: mb.Compound = mb.fill_box( compound=compound, n_compounds=[n_mol], box=mb.Box([4, 4, 4]), ) positions = packed_box.xyz * unit.nanometer positions = np.round(positions, 3) off_sys.positions = positions box = np.asarray(packed_box.box.lengths) * unit.nanometer off_sys.box = box omm_energies = get_openmm_energies( off_sys, round_positions=8, hard_cutoff=True, electrostatics=False ) gmx_energies = get_gromacs_energies( off_sys, writer="internal", electrostatics=False ) lmp_energies = get_lammps_energies(off_sys) omm_energies.compare(lmp_energies) omm_energies.compare( gmx_energies, custom_tolerances={ "Nonbonded": 2e-5 * omm_unit.kilojoule_per_mole, }, )
def ammonia_ff(self): """Fixture that loads an SMIRNOFF XML for ammonia""" return ForceField(get_test_file_path("ammonia.offxml"))
def argon_ff(self): """Fixture that loads an SMIRNOFF XML for argon""" return ForceField(get_test_file_path("argon.offxml"))