def test_atom_ordering(self): """Test that atom indices in bonds are ordered consistently between the slot map and topology""" import foyer from openff.interchange.components.interchange import Interchange from openff.interchange.drivers import ( get_gromacs_energies, get_lammps_energies, get_openmm_energies, ) oplsaa = foyer.forcefields.load_OPLSAA() benzene = Molecule.from_file(get_test_file_path("benzene.sdf")) benzene.name = "BENZ" biotop = OFFBioTop.from_molecules(benzene) biotop.mdtop = md.Topology.from_openmm(biotop.to_openmm()) out = Interchange.from_foyer(force_field=oplsaa, topology=biotop) out.box = [4, 4, 4] out.positions = benzene.conformers[0] # Violates OPLS-AA, but the point here is just to make sure everything runs out["vdW"].mixing_rule = "lorentz-berthelot" get_gromacs_energies(out) get_openmm_energies(out) get_lammps_energies(out)
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 = OFFBioTop.from_openmm(pdbfile.topology, unique_molecules=[mol]) top.mdtop = md.Topology.from_openmm(top.to_openmm()) box = pdbfile.topology.getPeriodicBoxVectors() box = box.value_in_unit(nm) * unit.nanometer out = Interchange.from_smirnoff(argon_ff, 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_residues(): pdb = app.PDBFile(get_test_file_path("ALA_GLY/ALA_GLY.pdb")) traj = md.load(get_test_file_path("ALA_GLY/ALA_GLY.pdb")) mol = Molecule(get_test_file_path("ALA_GLY/ALA_GLY.sdf"), file_format="sdf") top = OFFBioTop.from_openmm(pdb.topology, unique_molecules=[mol]) top.mdtop = traj.top assert top.n_topology_atoms == 29 assert top.mdtop.n_residues == 4 assert [r.name for r in top.mdtop.residues] == ["ACE", "ALA", "GLY", "NME"] ff = ForceField("openff-1.3.0.offxml") off_sys = Interchange.from_smirnoff(ff, top) # Assign positions and box vectors in order to run MM off_sys.positions = pdb.positions off_sys.box = [4.8, 4.8, 4.8] # Just ensure that a single-point energy can be obtained without error get_openmm_energies(off_sys) assert len(top.mdtop.select("resname ALA")) == 10 assert [*off_sys.topology.mdtop.residues][-1].n_atoms == 6
def test_rb_torsions(self, ethanol_with_rb_torsions): omm = get_openmm_energies(ethanol_with_rb_torsions, round_positions=3).energies[ "Torsion" ] gmx = get_gromacs_energies(ethanol_with_rb_torsions, decimal=3).energies[ "Torsion" ] assert (gmx - omm).m_as(kj_mol) < 1e-6
def test_to_lammps_single_mols(mol, n_mols): """ Test that Interchange.to_openmm Interchange.to_lammps report sufficiently similar energies. TODO: Tighten tolerances TODO: Test periodic and non-periodic """ parsley = ForceField("openff_unconstrained-1.0.0.offxml") mol = Molecule.from_smiles(mol) mol.generate_conformers(n_conformers=1) top = OFFBioTop.from_molecules(n_mols * [mol]) top.mdtop = md.Topology.from_openmm(top.to_openmm()) mol.conformers[0] -= np.min(mol.conformers) * omm_unit.angstrom top.box_vectors = np.eye(3) * np.asarray([10, 10, 10]) * omm_unit.nanometer if n_mols == 1: positions = mol.conformers[0] elif n_mols == 2: positions = np.vstack( [mol.conformers[0], mol.conformers[0] + 3 * omm_unit.nanometer]) positions = positions * omm_unit.angstrom openff_sys = Interchange.from_smirnoff(parsley, top) openff_sys.positions = positions.value_in_unit(omm_unit.nanometer) openff_sys.box = top.box_vectors reference = get_openmm_energies( off_sys=openff_sys, round_positions=3, ) lmp_energies = get_lammps_energies( off_sys=openff_sys, round_positions=3, ) _write_lammps_input( off_sys=openff_sys, file_name="tmp.in", ) lmp_energies.compare( reference, custom_tolerances={ "Nonbonded": 100 * omm_unit.kilojoule_per_mole, "Electrostatics": 100 * omm_unit.kilojoule_per_mole, "vdW": 100 * omm_unit.kilojoule_per_mole, "Torsion": 3e-5 * omm_unit.kilojoule_per_mole, }, )
def test_basic_combination(self, parsley_unconstrained): """Test basic use of Interchange.__add__() based on the README example""" mol = Molecule.from_smiles("C") mol.generate_conformers(n_conformers=1) top = OFFBioTop.from_molecules([mol]) top.mdtop = md.Topology.from_openmm(top.to_openmm()) openff_sys = Interchange.from_smirnoff(parsley_unconstrained, top) openff_sys.box = [4, 4, 4] * np.eye(3) openff_sys.positions = mol.conformers[0]._value / 10.0 # Copy and translate atoms by [1, 1, 1] other = Interchange() other._inner_data = deepcopy(openff_sys._inner_data) other.positions += 1.0 * unit.nanometer combined = openff_sys + other # Just see if it can be converted into OpenMM and run get_openmm_energies(combined)
def test_argon_buck(self): """Test that Buckingham potentials are supported and can be exported""" from openff.interchange.components.smirnoff import SMIRNOFFElectrostaticsHandler mol = Molecule.from_smiles("[#18]") top = OFFBioTop.from_molecules([mol, mol]) top.mdtop = md.Topology.from_openmm(top.to_openmm()) # http://www.sklogwiki.org/SklogWiki/index.php/Argon#Buckingham_potential erg_mol = unit.erg / unit.mol * float(unit.avogadro_number) A = 1.69e-8 * erg_mol B = 1 / (0.273 * unit.angstrom) C = 102e-12 * erg_mol * unit.angstrom**6 r = 0.3 * unit.nanometer buck = BuckinghamvdWHandler() coul = SMIRNOFFElectrostaticsHandler(method="pme") pot_key = PotentialKey(id="[#18]") pot = Potential(parameters={"A": A, "B": B, "C": C}) for atom in top.mdtop.atoms: top_key = TopologyKey(atom_indices=(atom.index, )) buck.slot_map.update({top_key: pot_key}) coul.slot_map.update({top_key: pot_key}) coul.potentials.update({ pot_key: Potential(parameters={"charge": 0 * unit.elementary_charge}) }) buck.potentials[pot_key] = pot out = Interchange() out.handlers["Buckingham-6"] = buck out.handlers["Electrostatics"] = coul out.topology = top out.box = [10, 10, 10] * unit.nanometer out.positions = [[0, 0, 0], [0.3, 0, 0]] * unit.nanometer out.to_gro("out.gro", writer="internal") out.to_top("out.top", writer="internal") omm_energies = get_openmm_energies(out) by_hand = A * exp(-B * r) - C * r**-6 resid = omm_energies.energies["Nonbonded"] - by_hand assert resid < 1e-5 * unit.kilojoule / unit.mol # TODO: Add back comparison to GROMACS energies once GROMACS 2020+ # supports Buckingham potentials with pytest.raises(GMXMdrunError): get_gromacs_energies(out, mdp="cutoff_buck")
def test_from_toolkit_packmol_boxes(self, pdb_path, unique_molecules): """ Test loading some pre-prepared PACKMOL-generated systems. These use PDB files already prepared in the toolkit because PDB files are a pain. """ ff = ForceField("openff-1.0.0.offxml") pdb_file_path = get_data_file_path("systems/packmol_boxes/" + pdb_path) pdbfile = openmm.app.PDBFile(pdb_file_path) top = OFFBioTop.from_openmm( pdbfile.topology, unique_molecules=unique_molecules, ) top.mdtop = md.Topology.from_openmm(top.to_openmm()) box = pdbfile.topology.getPeriodicBoxVectors() box = box.value_in_unit(nm) * unit.nanometer out = Interchange.from_smirnoff(ff, 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, combine_nonbonded_forces=True, ).compare( _get_openmm_energies( omm_sys=ff.create_openmm_system(top), box_vectors=pdbfile.topology.getPeriodicBoxVectors(), positions=pdbfile.getPositions(), hard_cutoff=True, ) )
def test_ethanol_energies(self, oplsaa_interchange_ethanol): from openff.interchange.tests.energy_tests.test_energies import ( get_gromacs_energies, ) gmx_energies = get_gromacs_energies(oplsaa_interchange_ethanol) omm_energies = get_openmm_energies(oplsaa_interchange_ethanol) gmx_energies.compare( omm_energies, custom_tolerances={ "vdW": 12.0 * unit.kilojoule / unit.mole, "Electrostatics": 12.0 * unit.kilojoule / unit.mole, }, )