def test_chemical_environments_matches_OE(self): """Test Topology.chemical_environment_matches""" from simtk.openmm import app toolkit_wrapper = OpenEyeToolkitWrapper() pdbfile = app.PDBFile( get_data_file_path( "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb")) # toolkit_wrapper = RDKitToolkitWrapper() molecules = [ Molecule.from_file(get_data_file_path(name)) for name in ("molecules/ethanol.mol2", "molecules/cyclohexane.mol2") ] topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules) # Test for substructure match matches = topology.chemical_environment_matches( "[C:1]-[C:2]-[O:3]", toolkit_registry=toolkit_wrapper) assert len(matches) == 143 assert matches[0].topology_atom_indices == (1728, 1729, 1730) # Test for whole-molecule match matches = topology.chemical_environment_matches( "[H][C:1]([H])([H])-[C:2]([H])([H])-[O:3][H]", toolkit_registry=toolkit_wrapper, ) assert (len(matches) == 1716 ) # 143 * 12 (there are 12 possible hydrogen mappings) assert matches[0].topology_atom_indices == (1728, 1729, 1730) # Search for a substructure that isn't there matches = topology.chemical_environment_matches( "[C][C:1]-[C:2]-[O:3]", toolkit_registry=toolkit_wrapper) assert len(matches) == 0
def test_reference(constrained, mol): """Minimal regression test comparing molecule energies to energies computed by version 0.8.0 of the toolkit""" # TODO: Also test periodic vs. vacuum with open(get_data_file_path("reference_energies/reference_0.8.0.json"), "r") as fi: reference = json.loads(fi.read()) name = mol + "_" if not constrained: name += "un" name += "constrained" reference_energy = reference[name] omm_sys, positions, off_top = _build_system( mol=mol, constrained=constrained, ) simulation = _build_simulation(omm_sys=omm_sys, off_top=off_top) derived_energy = _get_energy(simulation=simulation, positions=positions) np.testing.assert_almost_equal( actual=derived_energy / unit.kilojoule_per_mole, desired=reference_energy, decimal=5, )
def test_to_file_vsites(self): """ Checks that Topology.to_file() doesn't write vsites """ from tempfile import NamedTemporaryFile from openff.toolkit.topology import Molecule, Topology mol = Molecule.from_pdb_and_smiles( get_data_file_path("systems/test_systems/1_ethanol.pdb"), "CCO") carbons = [atom for atom in mol.atoms if atom.atomic_number == 6] positions = mol.conformers[0] mol.add_bond_charge_virtual_site( (carbons[0], carbons[1]), 0.1 * unit.angstrom, charge_increments=[0.1, 0.05] * unit.elementary_charge, ) topology = Topology() topology.add_molecule(mol) count = 0 # The file should be printed out with 9 atoms and 0 virtualsites, so we check to ensure that thtere are only 9 HETATM entries with NamedTemporaryFile(suffix=".pdb") as iofile: topology.to_file(iofile.name, positions) data = open(iofile.name).readlines() for line in data: if line.startswith("HETATM"): count = count + 1 assert count == 9
def _build_system(mol, constrained): if constrained: parsley = ForceField("openff-1.0.0.offxml") else: parsley = ForceField("openff_unconstrained-1.0.0.offxml") mol = Molecule.from_file(get_data_file_path("molecules/" + mol), file_format="sdf") if type(mol) == Molecule: off_top = mol.to_topology() positions = mol.conformers[0] elif type(mol) == list: # methane_multiconformer case is a list of two mols off_top = Topology() for mol_i in mol: off_top.add_molecule(mol_i) positions = (np.vstack([mol[0].conformers[0], mol[1].conformers[0]]) * unit.angstrom) from openff.toolkit.utils.toolkits import ( AmberToolsToolkitWrapper, RDKitToolkitWrapper, ToolkitRegistry, ) toolkit_registry = ToolkitRegistry( toolkit_precedence=[RDKitToolkitWrapper, AmberToolsToolkitWrapper]) omm_sys = parsley.create_openmm_system(off_top, toolkit_registry=toolkit_registry) return omm_sys, positions, off_top
def test_from_openmm_duplicate_unique_mol(self): """Check that a DuplicateUniqueMoleculeError is raised if we try to pass in two indistinguishably unique mols""" from simtk.openmm import app pdbfile = app.PDBFile( get_data_file_path( "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb")) molecules = [ Molecule.from_file(get_data_file_path(name)) for name in ( "molecules/ethanol.mol2", "molecules/ethanol_reordered.mol2", "molecules/cyclohexane.mol2", ) ] with self.assertRaises(DuplicateUniqueMoleculeError) as context: topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules)
def test_catch_bond_order_interpolation_bonds(self): from openff.toolkit.tests.test_forcefield import xml_ff_bo forcefield = ForceField( get_data_file_path("test_forcefields/test_forcefield.offxml"), xml_ff_bo, ) top = Molecule.from_smiles("CCO").to_topology() with pytest.raises(SMIRNOFFParameterAttributeNotImplementedError, match="length_bondorder"): Interchange.from_smirnoff(force_field=forcefield, topology=top)
def test_unsupported_mixing_rule(): molecules = [create_ethanol()] pdbfile = app.PDBFile(get_data_file_path("systems/test_systems/1_ethanol.pdb")) topology = OFFBioTop.from_openmm(pdbfile.topology, unique_molecules=molecules) topology.mdtop = md.Topology.from_openmm(topology.to_openmm()) forcefield = ForceField("test_forcefields/test_forcefield.offxml") openff_sys = Interchange.from_smirnoff(force_field=forcefield, topology=topology) openff_sys["vdW"].mixing_rule = "geometric" with pytest.raises(UnsupportedExportError, match="default NonbondedForce"): openff_sys.to_openmm(combine_nonbonded_forces=True)
def test_to_file_units_check(self): """ Checks whether writing pdb with unitless positions, Angstrom positions, nanometer positions, result in the same output """ from tempfile import NamedTemporaryFile from simtk.unit import nanometer from openff.toolkit.topology import Molecule, Topology topology = Topology() mol = Molecule.from_pdb_and_smiles( get_data_file_path("systems/test_systems/1_ethanol.pdb"), "CCO") topology.add_molecule(mol) positions_angstrom = mol.conformers[0] count = 1 # Write the molecule to PDB and ensure that the X coordinate of the first atom is 10.172 with NamedTemporaryFile(suffix=".pdb") as iofile: topology.to_file(iofile.name, positions_angstrom) data = open(iofile.name).readlines() for line in data: if line.startswith("HETATM") and count == 1: count = count + 1 coord = line.split()[-6] assert coord == "10.172" # Do the same check, but feed in equivalent positions measured in nanometers and ensure the PDB is still the same count = 1 coord = None with NamedTemporaryFile(suffix=".pdb") as iofile: positions_nanometer = positions_angstrom.in_units_of(nanometer) topology.to_file(iofile.name, positions_nanometer) data = open(iofile.name).readlines() for line in data: if line.startswith("HETATM") and count == 1: count = count + 1 coord = line.split()[-6] assert coord == "10.172" count = 1 coord = "abc" with NamedTemporaryFile(suffix=".pdb") as iofile: positions_unitless = positions_angstrom._value topology.to_file(iofile.name, positions_unitless) data = open(iofile.name).readlines() for line in data: if line.startswith("HETATM") and count == 1: count = count + 1 coord = line.split()[-6] assert coord == "10.172"
def test_to_file_multi_molecule_different_order(self): """ Checks for the following if Topology.to_write maintains the order of atoms for the same molecule with different indexing """ from tempfile import NamedTemporaryFile from openff.toolkit.tests.test_forcefield import ( create_ethanol, create_reversed_ethanol, ) from openff.toolkit.topology import Molecule, Topology topology = Topology() topology.add_molecule(create_ethanol()) topology.add_molecule(create_reversed_ethanol()) mol = Molecule.from_pdb_and_smiles( get_data_file_path("systems/test_systems/1_ethanol.pdb"), "CCO") positions = mol.conformers[0] # Make up coordinates for the second ethanol by translating the first by 10 angstroms # (note that this will still be a gibberish conformation, since the atom order in the second molecule is different) positions = np.concatenate( [positions, positions + 10.0 * unit.angstrom]) element_order = [] with NamedTemporaryFile(suffix=".pdb") as iofile: topology.to_file(iofile.name, positions) data = open(iofile.name).readlines() for line in data: if line.startswith("HETATM"): element_order.append(line.strip()[-1]) assert element_order == [ "C", "C", "O", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "O", "C", "C", ]
def test_catch_virtual_sites(self): from openff.toolkit.tests.test_forcefield import TestForceFieldVirtualSites forcefield = ForceField( get_data_file_path("test_forcefields/test_forcefield.offxml"), TestForceFieldVirtualSites. xml_ff_virtual_sites_monovalent_match_once, ) top = Molecule.from_smiles("CCO").to_topology() with pytest.raises(SMIRNOFFHandlersNotImplementedError, match="VirtualSites"): Interchange.from_smirnoff(force_field=forcefield, topology=top)
def test_from_openmm_missing_reference(self): """Test creation of an OpenFF Topology object from an OpenMM Topology when missing a unique molecule""" from simtk.openmm import app pdbfile = app.PDBFile( get_data_file_path( "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb")) molecules = [create_ethanol()] with pytest.raises( ValueError, match="No match found for molecule C6H12") as excinfo: topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules)
def test_to_file_fileformat_invalid(self): """ Checks for invalid file format """ from openff.toolkit.topology import Molecule, Topology topology = Topology() mol = Molecule.from_pdb_and_smiles( get_data_file_path("systems/test_systems/1_ethanol.pdb"), "CCO") topology.add_molecule(mol) positions = mol.conformers[0] fname = "ethanol_file.pdb" with pytest.raises(NotImplementedError): topology.to_file(fname, positions, file_format="AbC")
def test_openmm_nonbonded_methods(inputs): """See test_nonbonded_method_resolution in openff/toolkit/tests/test_forcefield.py""" vdw_method = inputs["vdw_method"] electrostatics_method = inputs["electrostatics_method"] periodic = inputs["periodic"] result = inputs["result"] molecules = [create_ethanol()] forcefield = ForceField("test_forcefields/test_forcefield.offxml") pdbfile = app.PDBFile(get_data_file_path("systems/test_systems/1_ethanol.pdb")) topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules) if not periodic: topology.box_vectors = None if type(result) == int: nonbonded_method = result # The method is validated and may raise an exception if it's not supported. forcefield.get_parameter_handler("vdW", {}).method = vdw_method forcefield.get_parameter_handler( "Electrostatics", {} ).method = electrostatics_method openff_interchange = Interchange.from_smirnoff( force_field=forcefield, topology=topology ) openmm_system = openff_interchange.to_openmm(combine_nonbonded_forces=True) for force in openmm_system.getForces(): if isinstance(force, openmm.NonbondedForce): assert force.getNonbondedMethod() == nonbonded_method break else: raise Exception elif issubclass(result, (BaseException, Exception)): exception = result forcefield.get_parameter_handler("vdW", {}).method = vdw_method forcefield.get_parameter_handler( "Electrostatics", {} ).method = electrostatics_method openff_interchange = Interchange.from_smirnoff( force_field=forcefield, topology=topology ) with pytest.raises(exception): openff_interchange.to_openmm(combine_nonbonded_forces=True) else: raise Exception("uh oh")
def test_from_openmm(self): """Test creation of an OpenFF Topology object from an OpenMM Topology and component molecules""" from simtk.openmm import app pdbfile = app.PDBFile( get_data_file_path( "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb")) with pytest.raises(MissingUniqueMoleculesError, match="requires a list of Molecule objects"): Topology.from_openmm(pdbfile.topology) molecules = [create_ethanol(), create_cyclohexane()] topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules) assert topology.n_reference_molecules == 2 assert topology.n_topology_molecules == 239
def test_from_mdtraj(self): """Test construction of an OpenFF Topology from an MDTraj Topology object""" import mdtraj as md pdb_path = get_data_file_path( "systems/test_systems/1_cyclohexane_1_ethanol.pdb") trj = md.load(pdb_path) with pytest.raises(MissingUniqueMoleculesError, match="requires a list of Molecule objects"): Topology.from_mdtraj(trj.top) unique_molecules = [ Molecule.from_smiles(mol_name) for mol_name in ["C1CCCCC1", "CCO"] ] top = Topology.from_mdtraj(trj.top, unique_molecules=unique_molecules) assert top.n_topology_molecules == 2 assert top.n_topology_bonds == 26
def test_to_file_fileformat_lettercase(self): """ Checks if fileformat specifier is indpendent of upper/lowercase """ from tempfile import NamedTemporaryFile from openff.toolkit.topology import Molecule, Topology topology = Topology() mol = Molecule.from_pdb_and_smiles( get_data_file_path("systems/test_systems/1_ethanol.pdb"), "CCO") topology.add_molecule(mol) positions = mol.conformers[0] count = 1 with NamedTemporaryFile(suffix=".pdb") as iofile: topology.to_file(iofile.name, positions, file_format="pDb") data = open(iofile.name).readlines() for line in data: if line.startswith("HETATM") and count == 1: count = count + 1 coord = line.split()[-6] assert coord == "10.172"
def test_from_openmm_missing_conect(self): """ Test creation of an OpenFF Topology object from an OpenMM Topology when the origin PDB lacks CONECT records """ from simtk.openmm import app pdbfile = app.PDBFile( get_data_file_path("systems/test_systems/1_ethanol_no_conect.pdb")) molecules = [] molecules.append(Molecule.from_smiles("CCO")) with pytest.raises( ValueError, match="No match found for molecule C. This would be a " "very unusual molecule to try and parameterize, " "and it is likely that the data source it was " "read from does not contain connectivity " "information. If this molecule is coming from " "PDB, please ensure that the file contains CONECT " "records.", ) as excinfo: topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules)
def setUp(self): self.empty_molecule = Molecule() self.ethane_from_smiles = Molecule.from_smiles("CC") self.ethene_from_smiles = Molecule.from_smiles("C=C") self.propane_from_smiles = Molecule.from_smiles("CCC") filename = get_data_file_path("molecules/toluene.sdf") self.toluene_from_sdf = Molecule.from_file(filename) if OpenEyeToolkitWrapper.is_available(): filename = get_data_file_path("molecules/toluene_charged.mol2") # TODO: This will require openeye to load self.toluene_from_charged_mol2 = Molecule.from_file(filename) self.charged_methylamine_from_smiles = Molecule.from_smiles( "[H]C([H])([H])[N+]([H])([H])[H]") molecule = Molecule.from_smiles("CC") carbons = [atom for atom in molecule.atoms if atom.atomic_number == 6] c0_hydrogens = [ atom for atom in carbons[0].bonded_atoms if atom.atomic_number == 1 ] molecule.add_bond_charge_virtual_site( (carbons[0], carbons[1]), 0.1 * unit.angstrom, charge_increments=[0.1, 0.05] * unit.elementary_charge, ) molecule.add_monovalent_lone_pair_virtual_site( (c0_hydrogens[0], carbons[0], carbons[1]), 0.2 * unit.angstrom, 20 * unit.degree, 25 * unit.degree, charge_increments=[0.01, 0.02, 0.03] * unit.elementary_charge, ) self.ethane_from_smiles_w_vsites = Molecule(molecule) # Make a propane with virtual sites molecule = Molecule.from_smiles("CCC") carbons = [atom for atom in molecule.atoms if atom.atomic_number == 6] c0_hydrogens = [ atom for atom in carbons[0].bonded_atoms if atom.atomic_number == 1 ] # This will add *two* particles (symmetric=True), *one* virtual site molecule.add_monovalent_lone_pair_virtual_site( (c0_hydrogens[0], carbons[0], carbons[1]), 0.2 * unit.angstrom, 20 * unit.degree, 25 * unit.degree, charge_increments=[0.01, 0.02, 0.03] * unit.elementary_charge, symmetric=True, ) # This will add *one* particle (symmetric=False), *one* virtual site molecule.add_bond_charge_virtual_site( (carbons[0], carbons[1]), 0.1 * unit.angstrom, charge_increments=[0.1, 0.05] * unit.elementary_charge, symmetric=False, ) self.propane_from_smiles_w_vsites = Molecule(molecule) # Make a TIP5 water molecule = Molecule.from_smiles("[H][O][H]") O1 = [atom for atom in molecule.atoms if atom.atomic_number == 8][0] H1, H2 = [atom for atom in O1.bonded_atoms if atom.atomic_number == 1] molecule.add_divalent_lone_pair_virtual_site( (H1, O1, H2), 0.7 * unit.angstrom, 54.71384225 * unit.degree, charge_increments=[0.1205, 0.00, 0.1205] * unit.elementary_charge, symmetric=True, ) self.tip5_water = Molecule(molecule)
versus energies from AMBER .prmtop and .crd files (parm@frosst params). """ import os import glob # datapath = './AlkEthOH_tripos/AlkEthOH_chain_filt1' # datapath = './AlkEthOH_tripos/AlkEthOH_rings_filt1' datapath = './AlkEthOH_tripos/AlkEthOH_test_filt1' # Check if we have this data file; if not we have to extract the archive. if not os.path.isdir(datapath): print("Extracting archived molecule files.") # Extract the AlkEthOH dataset shipped with the toolkit in data/molecules/ in the working directory. from openff.toolkit.tests.utils import get_data_file_path tarfile_path = os.path.join(get_data_file_path('molecules'), 'AlkEthOH_tripos.tar.gz') import tarfile with tarfile.open(tarfile_path, 'r:gz') as tar: tar.extractall() #Obtain list of molecules mol_filepaths = glob.glob(datapath + '/*tripos.mol2') mol_filepaths = [fnm for fnm in mol_filepaths if not 'c1302' in fnm] # Skip water. print('Found {} files to test'.format(len(mol_filepaths))) # Load force field from openff.toolkit.typing.engines.smirnoff import ForceField forcefield = ForceField('test_forcefields/Frosst_AlkEthOH_parmAtFrosst.offxml')