示例#1
0
def test_parameter_round_trip(method, tmpdir):
    """
    Check we can parametrise a molecule then write out the same parameters.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.sdf"))
        method(mol)
        # write out params
        mol.write_parameters(name="test")

        # make a second mol
        mol2 = Ligand.from_file(get_data("acetone.sdf"))
        XML(mol2, "test.xml")

        assert mol.AtomTypes == mol2.AtomTypes
        for bond in mol.HarmonicBondForce.keys():
            assert mol.HarmonicBondForce[bond] == pytest.approx(
                mol2.HarmonicBondForce[bond], abs=1e-6
            )
        for angle in mol.HarmonicAngleForce.keys():
            assert mol.HarmonicAngleForce[angle] == pytest.approx(
                mol2.HarmonicAngleForce[angle], abs=1e-6
            )
        for atom in range(mol.n_atoms):
            assert (
                pytest.approx(mol.NonbondedForce[atom], abs=1e-6)
                == mol2.NonbondedForce[atom]
            )
        for dihedral, terms in mol.PeriodicTorsionForce.items():
            try:
                other_dih = mol2.PeriodicTorsionForce[dihedral]
            except KeyError:
                other_dih = mol2.PeriodicTorsionForce[tuple(reversed(dihedral))]
            assert np.allclose(terms[:4], other_dih[:4])
示例#2
0
def test_protein_params(tmpdir):
    """
    Load up the small protein and make sure it is parametrised with the general qube forcefield.
    """
    with tmpdir.as_cwd():
        pro = Protein.from_file(file_name=get_data("capped_leu.pdb"))
        shutil.copy(get_data("capped_leu.pdb"), "capped_leu.pdb")
        XMLProtein(protein=pro)
示例#3
0
def test_add_conformers(file_name):
    """
    Load up the bace pdb and then add conformers to it from other file types.
    """
    mol = Ligand.from_file(file_name=get_data("bace0.pdb"))
    mol.coordinates = None
    mol.add_conformer(file_name=get_data(file_name))
    assert mol.coordinates.shape == (mol.n_atoms, 3)
示例#4
0
def test_to_topology(molecule):
    """
    Make sure that a topology generated using qubekit matches an openff one.
    """
    mol = Ligand.from_file(file_name=get_data(molecule))
    offmol = OFFMolecule.from_file(file_path=get_data(molecule))
    assert (
        nx.algorithms.isomorphism.is_isomorphic(mol.to_topology(), offmol.to_networkx())
        is True
    )
示例#5
0
def test_xml_with_sites(tmpdir):
    """
    Make sure that virtual sites are saved into the ligand if they are found in the input file.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("pyridine.pdb"))
        XML(mol, input_file=get_data("pyridine.xml"))

        assert mol.extra_sites is not None
        assert len(mol.extra_sites) == 1
        # make sure that charge we extracted
        assert mol.extra_sites[0].charge == -0.180000
示例#6
0
def test_parametrise_all(parameter_engine, tmpdir):
    """
    For each parameter engine make sure the molecule is correctly parameterised.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("pyridine.sdf"))
        mol.parameter_engine = parameter_engine
        if parameter_engine == "xml":
            shutil.copy(get_data("pyridine.xml"), "pyridine.xml")
        param_mol = Execute.parametrise(molecule=mol, verbose=False)
        # make sure parameters have been found
        for i in range(param_mol.n_atoms):
            assert param_mol.NonbondedForce[i] != [0, 0, 0]
示例#7
0
def test_no_rotatable_bonds():
    """
    If there are no dihedrals in the molecule make sure we return None.
    """
    mol = Ligand.from_file(file_name=get_data("water.pdb"))
    assert mol.rotatable_bonds is None
    assert mol.n_rotatable_bonds == 0
示例#8
0
def test_to_rdkit(molecule):
    """
    Make sure we can convert to rdkit.
    We test on bace which has a chiral center and 12-dichloroethene which has a stereo bond.
    """
    from rdkit import Chem

    mol = Ligand.from_file(file_name=get_data(molecule))
    rd_mol = mol.to_rdkit()
    # make sure the atom and bond stereo match
    for atom in rd_mol.GetAtoms():
        qb_atom = mol.atoms[atom.GetIdx()]
        assert atom.GetIsAromatic() is qb_atom.aromatic
        if qb_atom.stereochemistry is not None:
            if qb_atom.stereochemistry == "S":
                assert atom.GetChiralTag() == Chem.CHI_TETRAHEDRAL_CCW
            else:
                assert atom.GetChiralTag() == Chem.CHI_TETRAHEDRAL_CW
    for bond in rd_mol.GetBonds():
        qb_bond = mol.bonds[bond.GetIdx()]
        assert qb_bond.aromatic is bond.GetIsAromatic()
        assert qb_bond.bond_order == bond.GetBondTypeAsDouble()
        if qb_bond.stereochemistry is not None:
            if qb_bond.stereochemistry == "E":
                assert bond.GetStereo() == Chem.BondStereo.STEREOE
            else:
                assert bond.GetStereo() == Chem.BondStereo.STEREOZ
示例#9
0
def test_no_impropers():
    """
    Make sure we return None when no impropers are found in the molecule.
    """
    mol = Ligand.from_file(file_name=get_data("water.pdb"))
    assert mol.improper_torsions is None
    assert mol.n_improper_torsions == 0
示例#10
0
def test_no_dihedrals():
    """
    Make sure we return None when no dihedrals are found in the molecule.
    """
    mol = Ligand.from_file(file_name=get_data("water.pdb"))
    assert mol.dihedrals is None
    assert mol.n_dihedrals == 0
示例#11
0
def test_from_pdb():
    """
    Make sure we can make a protein from a pdb file.
    """
    pro = Protein.from_file(file_name=get_data("capped_leu.pdb"))
    assert pro.n_atoms == 31
    assert pro.coordinates.shape == (pro.n_atoms, 3)
示例#12
0
def test_xml_sites_roundtrip(tmpdir):
    """
    If we load in an xml with sites make sure we can write it back out.
    """

    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("pyridine.pdb"))
        XML(mol, input_file=get_data("pyridine.xml"))

        mol.write_parameters(name="test")

        mol2 = Ligand.from_file(get_data("pyridine.pdb"))
        XML(mol2, input_file="test.xml")

        assert mol.AtomTypes == mol2.AtomTypes
        for bond in mol.HarmonicBondForce.keys():
            assert (
                pytest.approx(mol.HarmonicBondForce[bond], abs=1e-6)
                == mol2.HarmonicBondForce[bond]
            )
        for angle in mol.HarmonicAngleForce.keys():
            assert (
                pytest.approx(mol.HarmonicAngleForce[angle], abs=1e-6)
                == mol2.HarmonicAngleForce[angle]
            )
        for atom in range(mol.n_atoms):
            assert (
                pytest.approx(mol.NonbondedForce[atom], abs=1e-6)
                == mol2.NonbondedForce[atom]
            )
        # make sure the virtual site was round tripped
        mol_site = mol.extra_sites[0]
        mol2_site = mol2.extra_sites[0]
        assert mol_site.charge == mol2_site.charge
        assert mol_site.parent_index == mol2_site.parent_index
        assert mol_site.closest_a_index == mol2_site.closest_a_index
        assert mol_site.closest_b_index == mol2_site.closest_b_index
        assert mol_site.p1 == mol2_site.p1
        assert mol_site.p2 == mol2_site.p2
        assert mol_site.p3 == mol2_site.p3

        for dihedral, terms in mol.PeriodicTorsionForce.items():
            try:
                other_dih = mol2.PeriodicTorsionForce[dihedral]
            except KeyError:
                other_dih = mol2.PeriodicTorsionForce[tuple(reversed(dihedral))]
            assert np.allclose(terms[:4], other_dih[:4])
示例#13
0
def test_make_unique_names():
    """
    After loading a molecule with non unique atom names make sure a unique set is automatically generated.
    """
    # load the molecule with missing names
    mol = Ligand.from_file(get_data("missing_names.pdb"))
    # make sure they have been converted
    assert mol.has_unique_atom_names is True
示例#14
0
def test_to_mapped_smiles():
    """
    Make sure the the mapped smiles flag is respected.
    """
    mol = Ligand.from_file(file_name=get_data("bace0.sdf"))
    no_map = mol.to_smiles(isomeric=True, explicit_hydrogens=True, mapped=False)
    mapped = mol.to_smiles(isomeric=True, explicit_hydrogens=True, mapped=True)
    assert no_map != mapped
示例#15
0
def test_ligand_from_file(file_name):
    """
    For the given file type make sure rdkit can parse it and return the molecule.
    """
    mol = Ligand.from_file(file_name=get_data(file_name))
    assert mol.n_atoms > 1
    assert mol.n_bonds > 1
    assert mol.name is not None
示例#16
0
def test_rotatable_bonds():
    """
    Make sure we can find true rotatable bonds for a molecule.
    """
    mol = Ligand.from_file(file_name=get_data("biphenyl.pdb"))
    assert mol.rotatable_bonds == [
        (3, 4),
    ]
    assert mol.n_rotatable_bonds == 1
示例#17
0
def test_to_smiles_isomeric():
    """
    Make sure we can write out smiles strings with the correct settings.
    """
    # use bace as it has a chiral center
    mol = Ligand.from_file(file_name=get_data("bace0.sdf"))
    smiles = mol.to_smiles(isomeric=True, explicit_hydrogens=False, mapped=False)
    assert "@@" in smiles
    smiles = mol.to_smiles(isomeric=False, explicit_hydrogens=False, mapped=False)
    assert "@" not in smiles
示例#18
0
def test_parametrise_missing_file(tmpdir):
    """
    If a missing file is provided make sure an error is raised.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.pdb"))
        mol.home = os.getcwd()
        mol.parameter_engine = "xml"
        with pytest.raises(FileNotFoundError):
            _ = Execute.parametrise(molecule=mol, verbose=False)
示例#19
0
def test_parametrise_none(tmpdir):
    """
    If no engine is passed make sure we init the parameter holders but store nothing.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.pdb"))
        mol.parameter_engine = "none"
        param_mol = Execute.parametrise(molecule=mol, verbose=False)
        for i in range(param_mol.n_atoms):
            assert param_mol.NonbondedForce[i] == [0, 0, 0]
示例#20
0
def test_mod_sem_no_symmetry(tmpdir):
    """
    A simple regression test for the modified seminario method.
    # TODO expand these tests
    """
    with tmpdir.as_cwd():
        # the sdf file is at the qm geometry
        mol = Ligand.from_file(file_name=get_data("ethane.sdf"))
        hessian = np.loadtxt(fname=get_data("ethane_hessian.txt"))
        mol.hessian = hessian
        mod_sem = ModSeminario(molecule=mol)
        mod_sem.modified_seminario_method()
        # now check the values
        assert mol.HarmonicBondForce[(
            0, 1)][0] == pytest.approx(0.15344171531887932)
        assert mol.HarmonicBondForce[(
            0, 1)][1] == pytest.approx(192462.76956156612)
        assert mol.HarmonicBondForce[(
            0, 2)][0] == pytest.approx(0.10954907576059233)
        assert mol.HarmonicBondForce[(
            0, 2)][1] == pytest.approx(295645.6124892813)

        assert mol.HarmonicAngleForce[(
            1, 0, 2)][0] == pytest.approx(1.9423960113296368)
        assert mol.HarmonicAngleForce[(
            1, 0, 2)][1] == pytest.approx(374.76469990519263)
        assert mol.HarmonicAngleForce[(
            1, 0, 3)][0] == pytest.approx(1.9422108316309619)
        assert mol.HarmonicAngleForce[(
            1, 0, 3)][1] == pytest.approx(401.56353614024914)
        assert mol.HarmonicAngleForce[(
            1, 0, 4)][0] == pytest.approx(1.9416241741805782)
        assert mol.HarmonicAngleForce[(
            1, 0, 4)][1] == pytest.approx(371.0717571027322)
        assert mol.HarmonicAngleForce[(
            2, 0, 3)][0] == pytest.approx(1.8787818480998344)
        assert mol.HarmonicAngleForce[(
            2, 0, 3)][1] == pytest.approx(314.5677633711689)
        assert mol.HarmonicAngleForce[(
            0, 1, 6)][0] == pytest.approx(1.9423960113296368)
        assert mol.HarmonicAngleForce[(
            0, 1, 6)][1] == pytest.approx(399.59297576081184)
示例#21
0
def test_from_rdkit():
    """
    Make sure we can create a molecule directly from an rdkit object.
    """
    # load a molecule with openff
    offmol = OFFMolecule.from_file(file_path=get_data("bace0.sdf"))
    # make a ligand from the openff object
    mol = Ligand.from_rdkit(rdkit_mol=offmol.to_rdkit())
    # make sure we have the same molecule
    mol2 = Ligand.from_file(get_data("bace0.sdf"))
    for i in range(mol.n_atoms):
        atom1 = mol.atoms[i]
        atom2 = mol2.atoms[i]
        assert atom1.dict() == atom2.dict()
    for i in range(mol.n_bonds):
        bond1 = mol.bonds[i]
        bon2 = mol2.bonds[i]
        assert bond1.dict() == bon2.dict()

    assert np.allclose(mol.coordinates, mol2.coordinates)
示例#22
0
def test_openff_skeleton(tmpdir):
    """
    Make sure the skeleton method in openff works when we have missing coverage in the openff forcefield.
    This will add generic parameters to the forcefield which should match any missing terms, no charges are generated this way.
    """
    with tmpdir.as_cwd():
        # load a molecule with b
        mol = Ligand.from_file(get_data("132-Benzodioxaborole.pdb"))
        OpenFF(mol)

        # no charges should be generated
        for i in range(mol.n_atoms):
            assert mol.NonbondedForce[i][0] == 0
示例#23
0
def test_write_xyz_multiple_conformer(tmpdir):
    """
    Make sure we can write multiple conformer xyz files for a molecule.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(file_name=get_data("butane.pdb"))
        # fake a set of conformers
        coords = [mol.coordinates, np.random.random((mol.n_atoms, 3))]
        mol.to_multiconformer_file(file_name="butane.xyz", positions=coords)

        # now read in the file again
        with open("butane.xyz") as xyz:
            lines = xyz.readlines()
            assert len(lines) == 2 * mol.n_atoms + 4
示例#24
0
def test_mod_sem_symmetry(tmpdir):
    """
    A simple regression test for modified seminario method with symmetry.
    """
    with tmpdir.as_cwd():
        # the sdf file is at the qm geometry
        mol = Ligand.from_file(file_name=get_data("ethane.sdf"))
        hessian = np.loadtxt(fname=get_data("ethane_hessian.txt"))
        mol.hessian = hessian
        mod_sem = ModSeminario(molecule=mol)
        mod_sem.modified_seminario_method()
        mod_sem.symmetrise_bonded_parameters()
        # make sure symmetry groups are the same
        for bonds in mol.bond_types.values():
            values = set()
            for bond in bonds:
                values.add(tuple(mol.HarmonicBondForce[bond]))
            assert len(values) == 1
        for angles in mol.angle_types.values():
            values = set()
            for angle in angles:
                values.add(tuple(mol.HarmonicAngleForce[angle]))
                assert len(values) == 1
示例#25
0
def test_parameter_prep():
    """Test that the base parameter class preps a molecule to store prameters."""
    mol = Ligand.from_file(get_data("acetone.sdf"))
    assert mol.AtomTypes is None
    assert mol.HarmonicBondForce is None
    assert mol.HarmonicAngleForce is None
    assert mol.PeriodicTorsionForce is None
    assert mol.NonbondedForce is None

    # now use the base class to prep the molecule
    Parametrisation(mol)
    assert mol.AtomTypes == {}
    assert len(mol.HarmonicBondForce) == mol.n_bonds
    assert len(mol.HarmonicAngleForce) == mol.n_angles
    assert len(mol.NonbondedForce) == mol.n_atoms
示例#26
0
def test_smarts_matches(acetone):
    """
    Make sure we can find the same environment matches as openff.
    """
    matches = acetone.get_smarts_matches(smirks="[#6:1](=[#8:2])-[#6]")
    # make sure the atoms are in the correct order
    assert len(matches) == 1
    match = matches[0]
    assert acetone.atoms[match[0]].atomic_symbol == "C"
    assert acetone.atoms[match[1]].atomic_symbol == "O"
    # make sure these atoms are bonded
    _ = acetone.get_bond_between(*match)
    off = OFFMolecule.from_file(file_path=get_data("acetone.sdf"))
    off_matches = off.chemical_environment_matches(query="[#6:1](=[#8:2])-[#6]")
    # check we match the same bonds
    assert set(off_matches) == set(matches)
示例#27
0
def test_parameter_engines(tmpdir, parameter_engine):
    """
    Make sure we can parametrise a molecule using antechamber
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.sdf"))
        parameter_engine(mol)

        # loop over the parameters and make sure they not defaults
        for bond in mol.bonds:
            assert mol.HarmonicBondForce[(bond.atom1_index, bond.atom2_index)] != [0, 0]
        for angle in mol.angles:
            assert mol.HarmonicAngleForce[angle] != [0, 0]
        assert (
            len(mol.PeriodicTorsionForce) == mol.n_dihedrals + mol.n_improper_torsions
        )
        for i in range(mol.n_atoms):
            assert mol.NonbondedForce[i] != [0, 0, 0]
示例#28
0
def test_pdb_round_trip(tmpdir):
    """
    Make sure we can round trip a protein to pdb.
    """
    with tmpdir.as_cwd():
        pro = Protein.from_file(file_name=get_data("capped_leu.pdb"))
        pro.write_pdb(name="test")

        pro2 = Protein.from_file("test.pdb")

        assert pro.n_atoms == pro2.n_atoms
        assert pro.n_bonds == pro.n_bonds
        for bond in pro.bonds:
            assert bond in pro2.bonds
        for angle in pro.angles:
            assert angle in pro2.angles
        for central_bond, torsions in pro.dihedrals.items():
            for d in torsions:
                assert d in pro2.dihedrals[central_bond]
示例#29
0
def test_charge(molecule, charge):
    """
    Make sure that the charge is correctly identified.
    """
    mol = Ligand.from_file(file_name=get_data(molecule))
    assert mol.charge == charge
示例#30
0
def mol():
    """
    Initialise the Ligand molecule object with data for Chloromethane
    """
    molecule = Ligand.from_file(file_name=get_data("chloromethane.pdb"))
    molecule.ddec_data = {
        0: CustomNamespace(
            a_i=72461.2438863321,
            atomic_symbol="C",
            b_i=36.09781017184126,
            charge=-0.220088,
            r_aim=1.9933297947778903,
            volume=30.276517,
        ),
        1: CustomNamespace(
            a_i=153692.84134145387,
            atomic_symbol="Cl",
            b_i=101.44341268889193,
            charge=1.815899,
            r_aim=1.9020122149415648,
            volume=67.413573,
        ),
        2: CustomNamespace(
            a_i=149.1117208173859,
            atomic_symbol="H",
            b_i=1.247688109065071,
            charge=0.13473,
            r_aim=1.2455924332095252,
            volume=3.329737,
        ),
        3: CustomNamespace(
            a_i=149.1117208173859,
            atomic_symbol="H",
            b_i=1.247688109065071,
            charge=0.13473,
            r_aim=1.2455924332095252,
            volume=3.329737,
        ),
        4: CustomNamespace(
            a_i=149.1117208173859,
            atomic_symbol="H",
            b_i=1.247688109065071,
            charge=0.134729,
            r_aim=1.2455924332095252,
            volume=3.329737,
        ),
    }
    molecule.dipole_moment_data = {
        0: CustomNamespace(x_dipole=0.109154, y_dipole=0.006347, z_dipole=-0.000885),
        1: CustomNamespace(x_dipole=-0.139599, y_dipole=-0.006372, z_dipole=0.000994),
        2: CustomNamespace(x_dipole=-0.005778, y_dipole=-0.018142, z_dipole=-0.029462),
        3: CustomNamespace(x_dipole=-0.00516, y_dipole=-0.016898, z_dipole=0.030335),
        4: CustomNamespace(x_dipole=-0.00839, y_dipole=0.035106, z_dipole=-0.000628),
    }

    molecule.quadrupole_moment_data = {
        0: CustomNamespace(
            q_3z2_r2=-0.150042,
            q_x2_y2=0.148149,
            q_xy=0.007494,
            q_xz=-0.001301,
            q_yz=-0.000128,
        ),
        1: CustomNamespace(
            q_3z2_r2=-1.074695,
            q_x2_y2=1.070914,
            q_xy=0.052325,
            q_xz=-0.006765,
            q_yz=-0.000286,
        ),
        2: CustomNamespace(
            q_3z2_r2=0.013971,
            q_x2_y2=0.011282,
            q_xy=0.001128,
            q_xz=0.000274,
            q_yz=0.011593,
        ),
        3: CustomNamespace(
            q_3z2_r2=0.01544,
            q_x2_y2=0.011683,
            q_xy=0.001125,
            q_xz=-0.000412,
            q_yz=-0.01131,
        ),
        4: CustomNamespace(
            q_3z2_r2=-0.043386,
            q_x2_y2=-0.007519,
            q_xy=-0.001058,
            q_xz=-5.4e-05,
            q_yz=-0.000249,
        ),
    }

    molecule.cloud_pen_data = {
        0: CustomNamespace(a=2.102843, atomic_symbol="C", b=2.40575),
        1: CustomNamespace(a=7.939831, atomic_symbol="Cl", b=3.395079),
        2: CustomNamespace(a=0.1242, atomic_symbol="H", b=2.533532),
        3: CustomNamespace(a=0.123448, atomic_symbol="H", b=2.533309),
        4: CustomNamespace(a=0.120282, atomic_symbol="H", b=2.533191),
    }
    print(f"mol coords: {molecule.coordinates}")
    return molecule