예제 #1
0
    def alignToEachOther(self, output_filename=None, realign=False, **kwargs):
        """
        Aligns the second ligand to the first ligand.

        Parameters
        ----------
        output_filename : str
            The name of the output file. None uses the default value.
        realign : bool
            Whether to realign an already aligned ligand.
        kwargs
            Keyword arguments to pass to ProtoCaller.Wrappers.rdkitwrapper.alignTwoMolecules.

        Returns
        -------
        morph : BioSimSpace.System
            The mixed topology object.
        mcs : [tuple]
            The maximum common substructure of the two molecules.
        """
        if self.current_ref in self._morph.keys() and not realign:
            _logging.info("Morph %s is already aligned to a reference" % self.name)
            return

        if output_filename is None:
            _stdio.stdout_stderr()(self.ligand1.parametrise)(reparametrise=False)
            _stdio.stdout_stderr()(self.ligand2.parametrise)(reparametrise=False)
            output_filename = "{}_aligned_{}.{}".format(self.ligand2.name, self.name,
                                                        self.ligand2.parametrised_files[1].split(".")[-1])
        if "two_way_matching" not in kwargs.keys():
            kwargs["two_way_matching"] = True

        if self.current_ref is None:
            self._ligand1_molecule[None] = self.ligand1.molecule
            self._ligand1_coords[None] = self.ligand1.parametrised_files[1]

        lig1_temp = self._ligand1_molecule[self.current_ref]
        lig2_temp = _copy.deepcopy(self.ligand2.molecule)
        self._ligand2_molecule[self.current_ref], mcs = _rdkit.alignTwoMolecules(lig1_temp, lig2_temp, **kwargs)
        self._ligand2_coords[self.current_ref] = _os.path.abspath(
            _rdkit.saveFromRdkit(self._ligand2_molecule[self.current_ref], output_filename))

        # load the shifted ligands into BioSimSpace
        ligand1_BSS = _BSS.IO.readMolecules(self.parametrised_files1).getMolecules()[0]
        ligand2_BSS = _BSS.IO.readMolecules(self.parametrised_files2).getMolecules()[0]

        # translate RDKit mapping into BioSimSpace mapping
        mapping = {}
        indices_1 = [atom.index() for atom in ligand1_BSS._sire_object.edit().atoms()]
        indices_2 = [atom.index() for atom in ligand2_BSS._sire_object.edit().atoms()]
        for idx1, idx2 in mcs:
            mapping[indices_1[idx1]] = indices_2[idx2]

        # finally create morph
        self._morph[self.current_ref] = _BSS.Align.merge(
            ligand1_BSS, ligand2_BSS, mapping=mapping, allow_ring_breaking=True)

        return self._morph[self.current_ref], mcs
예제 #2
0
    def alignToReference(self, ref, output_filename=None, realign=False, **kwargs):
        """
        Aligns the first ligand to a reference ligand.

        Parameters
        ----------
        ref : ProtoCaller.Ensemble.Ligand.Ligand
            The reference ligand.
        output_filename : str
            The name of the output file. None uses the default value.
        realign : bool
            Whether to realign an already aligned ligand.
        kwargs
            Keyword arguments to pass to ProtoCaller.Wrappers.rdkitwrapper.alignTwoMolecules.

        Returns
        -------
        mcs : [tuple]
            The maximum common substructure of the two molecules.
        """
        self.current_ref = ref
        if ref in self._ligand1_molecule.keys() and ref in self._ligand1_coords.keys() and not realign:
            _logging.info("Morph %s is already aligned to a reference" % self.name)
            return

        if output_filename is None:
            _stdio.stdout_stderr()(self.ligand1.parametrise)(reparametrise=False)
            output_filename = "{}_aligned_{}.{}".format(self.ligand1.name, self.name,
                                                        self.ligand1.parametrised_files[1].split(".")[-1])
        if "two_way_matching" not in kwargs.keys():
            kwargs["two_way_matching"] = False

        lig_temp = _copy.deepcopy(self.ligand1.molecule)
        self._ligand1_molecule[ref], mcs = _rdkit.alignTwoMolecules(ref.molecule, lig_temp, **kwargs)
        self._ligand1_coords[ref] = _rdkit.saveFromRdkit(self._ligand1_molecule[ref], output_filename)

        return mcs
예제 #3
0
    def prepareComplexes(self, replica_temps=None, scale_dummy_bonds=1,
                         dummy_bond_smarts="[*]~[*]", intermediate_files=False,
                         store_complexes=False, output_files=True):
        """
        Batch prepares all complexes with an option to output files for REST(2).

        Parameters
        ----------
        replica_temps : [float] or None
            A list of replica temperatures. Everything is normalised with respect to the lowest temperature. None
            means only output the normal files.
        scale_dummy_bonds : float
            Sets the dummy bond length distance as a fraction of the real bond length distance.
        dummy_bond_smarts : str
            SMARTS string which indicates which dummy bonds are to be affected by scale_dummy_bonds.
        intermediate_files : bool
            Whether to store all intermediate files.
        store_complexes : bool
            Whether to store the final complexes as a dictionary of BioSimSpace System objects.
        output_files : bool
            Whether to write output files immediately or later via saveSystems.
        """
        # make sure the proteins / ligands are parametrised before proceeding
        with self.workdir:
            _stdio.stdout_stderr()(self.protein.parametrise)(params=self.params, reparametrise=False)
            for morph in self.morphs:
                _stdio.stdout_stderr()(morph.ligand1.parametrise)(params=self.params, reparametrise=False)
                _stdio.stdout_stderr()(morph.ligand2.parametrise)(params=self.params, reparametrise=False)

            # take care of the replicas if there are any
            if replica_temps is None or len(replica_temps) == 1:
                scales = [1]
            else:
                sorted_list = sorted(replica_temps)
                if sorted_list != replica_temps:
                    _warnings.warn("Input replica temperatures were not in ascending order. Sorting...")
                    replica_temps = sorted_list
                scales = [replica_temps[0] / elem for elem in replica_temps]

            for i, morph in enumerate(self.morphs):
                if intermediate_files:
                    curdir = _fileio.Dir(morph.name, overwrite=True)
                else:
                    name = _os.path.basename(_tempfile.TemporaryDirectory().name)
                    curdir = _fileio.Dir(name, overwrite=True, temp=True)

                with curdir:
                    _logging.info("Creating morph %s..." % morph.name)
                    morph_BSS, mcs = _stdio.stdout_stderr()(
                        morph.alignAndCreateMorph)(self.protein.ligand_ref)
                    morph_BSS = _BSS._SireWrappers.System(morph_BSS)
                    box = self.protein.complex_template._sire_object.property(
                        "space")
                    morph_BSS._sire_object.setProperty("space", box)

                    # here we scale the equilibrium bond lengths if needed
                    if scale_dummy_bonds != 1:
                        n1 = morph.ligand1.molecule.GetNumAtoms()
                        n2 = morph.ligand2.molecule.GetNumAtoms()
                        inv_map = {y: x for x, y in mcs}
                        du2 = [i for i in range(n2) if i not in inv_map.keys()]
                        inv_map = {**{x: n1 + y
                                      for x, y in zip(du2, range(n2 - n1))},
                                   **inv_map}
                        mcs_smarts = _Chem.MolFromSmarts(dummy_bond_smarts)
                        matches_lig1 = morph.ligand1.molecule.\
                            GetSubstructMatches(mcs_smarts)
                        matches_lig2 = morph.ligand2.molecule.\
                            GetSubstructMatches(mcs_smarts)

                        # here we take care of the index transformation
                        matches_lig2 = [(inv_map[x[0]], inv_map[x[1]])
                                        for x in matches_lig2
                                        if set(x).issubset(inv_map.keys())]
                        matches_total = [*matches_lig1, *matches_lig2]
                        morph_BSS = _BSSwrap.rescaleBondedDummies(
                            morph_BSS, scale_dummy_bonds,
                            {"Merged_Molecule": matches_total}
                        )

                    complexes = [self.protein.complex_template + morph_BSS]

                    # solvate and save the prepared complex and morph with the appropriate box size
                    _logging.info("Solvating...")
                    complexes = [_solvate.solvate(complexes[0], self.params, box_length=self.box_length_complex,
                                                  shell=self.shell, neutralise=self.neutralise, ion_conc=self.ion_conc,
                                                  centre=self.centre, work_dir=curdir.path, filebase="complex")]
                    morph_sol = _solvate.solvate(morph_BSS, self.params,
                                                 box_length=self.box_length_morph, shell=self.shell,
                                                 neutralise=self.neutralise, ion_conc=self.ion_conc, centre=self.centre,
                                                 work_dir=curdir.path, filebase="morph")

                    # rescale complexes for replica exchange if needed
                    if len(scales) != 1:
                        _logging.info("Creating replicas...")
                        complexes = [_BSSwrap.rescaleSystemParams(complexes[0], scale, includelist=["Merged_Molecule"])
                                     for scale in scales]

                    if store_complexes:
                        self.systems_prep[morph.name] = (morph_sol, complexes)

                if output_files:
                    self.saveSystems({morph.name: (morph_sol, complexes)})
예제 #4
0
def amberWrapper(params,
                 filename,
                 molecule_type,
                 id=None,
                 charge=None,
                 *args,
                 **kwargs):
    """
    Parametrises an input file according to AMBER force field.

    Parameters
    ----------
    params : ProtoCaller.Parametrise.Params
        Force field parameters.
    filename : str
        Name of the input file.
    molecule_type : str
        The type of the molecule. One of: "protein", "ligand", "cofactor", "water", "simple_anion", "complex_anion",
        "simple_cation", "complex_cation".
    id : str
        The name of the molecule. Default: equal to molecule_type.
    charge : bool
        The net charge of the molecule. Default: automatic detection by antechamber.
    args
        Positional arguments to be passed to the relevant wrapper.
    kwargs
        Keyword arguments to be passed to the relevant wrapper.

    Returns
    -------
    files : [str]
        The output parametrised file(s). If there is more than one file, the first one is always the topology file and
        the second one - the coordinate file.
    """
    if id is None: id = molecule_type
    force_fields, files, param_files = [], [filename], []

    if molecule_type == "protein":
        force_fields = [params.protein_ff, params.water_ff]
    elif molecule_type in ["water", "simple_anion", "simple_cation"]:
        force_fields = [params.water_ff]
    elif molecule_type == "complex_anion":
        _warnings.warn(
            "AMBER parametrisation failed: polyatomic anions not supported")
        return
    elif molecule_type == "complex_cation":
        _warnings.warn(
            "AMBER parametrisation failed: transition metals not supported")
        return
    elif molecule_type == "cofactor":
        if params.water_ff != "tip3p" or params.protein_ff != "ff99SB":
            _warnings.warn("All cofactors have been parametrised for use with "
                           "the ff99SB protein force field and the TIP3P "
                           "water model. Be careful when using these "
                           "parameters with %s" % params.water_ff.upper())
        files = []
        force_fields = [params.protein_ff, params.ligand_ff]
        param_files = _glob.glob("%s/shared/amber-parameters/cofactors/%s.*" %
                                 (_PC.HOMEDIR, id))

        # here we override the default parametrisation behaviour for cofactors
        parametrised_files = runTleap(force_fields=force_fields,
                                      files=files,
                                      param_files=param_files,
                                      id=id,
                                      *args,
                                      **kwargs)
        filebase = _os.path.splitext(filename)[0]
        topol = "{}.prmtop".format(filebase)
        _os.rename(parametrised_files[0], topol)
        parametrised_files[0] = topol

        # convert the parametrised file into PDB and load in RDKit
        ref = _rdkit.openAsRdkit(filename, removeHs=False)
        mol = _pmd.openFilesAsParmed(parametrised_files)
        pdb_file = _pmd.saveFilesFromParmed(mol, [filename], overwrite=True)[0]
        mol = _rdkit.openAsRdkit(pdb_file, removeHs=False)

        # align the parametrised file to the molecule and overwrite
        # previous coordinates
        mol, mcs = _stdio.stdout_stderr()(_rdkit.alignTwoMolecules) \
            (ref, mol, two_way_matching=True,
             mcs_parameters=dict(atomCompare="elements"))
        if min(mol.GetNumAtoms(), ref.GetNumAtoms()) != len(mcs):
            _warnings.warn("The cofactor {} does not perfectly match the "
                           "AMBER parameter file. Please check your "
                           "molecule.".format(id))
        _os.remove(parametrised_files[1])
        coord = "{}.inpcrd".format(filebase)
        parametrised_files[1] = _rdkit.saveFromRdkit(mol, coord)
        return parametrised_files
    elif molecule_type == "ligand":
        force_fields = [params.ligand_ff]
        files = [runAntechamber(params.ligand_ff, filename, charge=charge)]
        param_files = [runParmchk(params.ligand_ff, files[0])]
    else:
        raise ValueError("Value %s for molecule_type not supported " %
                         molecule_type)

    return runTleap(force_fields=force_fields,
                    files=files,
                    param_files=param_files,
                    id=id,
                    *args,
                    **kwargs)