Ejemplo n.º 1
0
    def parametrise(self, params=None, reparametrise=False):
        """
        Parametrises the whole protein system.

        Parameters
        ----------
        params : ProtoCaller.Parametrise.Params
            Force field parameters.
        reparametrise : bool
            Whether to reparametrise an already parametrised complex.
        """
        if self.complex_template is not None and not reparametrise:
            _logging.debug("Protein complex template %s is already parametrised." % self.name)
            return

        if params is None:
            params = _parametrise.Params()

        with self.workdir:
            _logging.info("Parametrising original crystal system...")
            # extract non-protein residues from pdb file and save them as separate pdb files
            hetatm_files, hetatm_types = self._pdb_obj.writeHetatms()
            filter = "type in ['amino_acid', 'amino_acid_modified']"
            non_protein_residues = self._pdb_obj.filter(filter)
            self._pdb_obj.purgeResidues(non_protein_residues, "keep")
            self._pdb_obj.reNumberResidues()
            self._pdb_obj.writePDB(self.pdb)

            # create a merged parmed object with all parametrised molecules and save to top/gro which is then read by
            # BioSimSpace
            # we can't use a direct BioSimSpace object because it throws an error if the file contains single ions
            system = _parametrise.parametriseAndLoadPmd(params=params, filename=self.pdb, molecule_type="protein",
                                                        disulfide_bonds=self._pdb_obj.disulfide_bonds)

            # add ligands to the system
            for ligand in self.ligands:
                ligand.parametrise(params, reparametrise=reparametrise, molecule_type="ligand")
                system += _pmdwrap.openFilesAsParmed(ligand.parametrised_files)

            # add cofactors to the system
            for cofactor in self.cofactors:
                id = _re.search(r"^([^_\W]+)_([^_\W]+)_([^_\W])_([^_\W]+)", cofactor.name).group(2)
                cofactor.parametrise(params, reparametrise=reparametrise, molecule_type="cofactor", id=id)
                system += _pmdwrap.openFilesAsParmed(cofactor.parametrised_files)

            # add all other HETATMS to the system
            for filename, type in zip(hetatm_files, hetatm_types):
                system += _parametrise.parametriseAndLoadPmd(params=params, filename=filename, molecule_type=type)

            _GROMACS.saveAsGromacs("complex_template", system)
            if _PC.BIOSIMSPACE:
                self.complex_template = _BSS.IO.readMolecules(["complex_template.top", "complex_template.gro"])
            else:
                self.complex_template = system
Ejemplo n.º 2
0
    def pdb(self, value):
        with self.workdir:
            self._pdb = "{}.pdb".format(self.name)
            if isinstance(value, _BSS._SireWrappers.System):
                _BSS.IO.saveMolecules(self.name, value, "pdb")
            elif isinstance(value, _BSS._SireWrappers.Molecule):
                _BSS.IO.saveMolecules(self.name, _BSS._SireWrappers.System(value), "pdb")
            elif isinstance(value, _pmd.Structure):
                _pmdwrap.saveFilesFromParmed(value, self._pdb)
            else:
                self._pdb = None
                if value is not None:
                    value = _fileio.checkFileExists(value)
                if value:
                    try:
                        try:
                            self._pdb = value
                            self._pdb_obj = _PDB.PDB(self.pdb)
                        except:
                            obj = _pmdwrap.openFilesAsParmed(value)
                            self._pdb = "{}.pdb".format(self.name)
                            _pmdwrap.saveFilesFromParmed(obj, self._pdb)
                            self._pdb_obj = _PDB.PDB(self.pdb)
                        self._checkfasta()
                    except:
                        self._pdb = None

            if not self._pdb:
                self._pdb_obj = _PDB.PDB(self.pdb) if self.pdb else None
Ejemplo n.º 3
0
def parametriseAndLoadPmd(params, *args, **kwargs):
    """
    Calls parametriseFile and loads the files into ParmEd.

    Parameters
    ----------
    params : ProtoCaller.Parametrise.Params
        Force field parameters.
    args
        Positional arguments to be passed to parametriseFile.
    kwargs
        Keyword arguments to be passed to parametriseFile.

    Returns
    -------
    system : parmed.structure.Structure
        The loaded parametrised files as a ParmEd Structure.
    """
    files = parametriseFile(params, *args, **kwargs)
    return _pmdwrap.openFilesAsParmed(files)
Ejemplo n.º 4
0
 def complex_template(self, input):
     if not input:
         self._complex_template = None
     elif isinstance(input, _BSS._SireWrappers.System):
         self._complex_template = input
     elif isinstance(input, _BSS._SireWrappers.Molecule):
         self._complex_template = _BSS._SireWrappers.System(input)
     elif isinstance(input, _pmd.Structure):
         if _PC.BIOSIMSPACE:
             tempfiles = ["temp.gro", "temp.top"]
             _pmdwrap.saveFilesFromParmed(input, tempfiles)
             self._complex_template = _BSS.IO.readMolecules(tempfiles)
             for tempfile in tempfiles:
                 _os.remove(tempfile)
         else:
             self._complex_template = input
     else:
         if _PC.BIOSIMSPACE:
             self._complex_template = _BSS.IO.readMolecules(input)
         else:
             self._complex_template = _pmdwrap.openFilesAsParmed(input)
Ejemplo n.º 5
0
def solvate(complex,
            params=None,
            box_length=8,
            shell=0,
            neutralise=True,
            ion_conc=0.154,
            centre=True,
            work_dir=None,
            filebase="complex"):
    """
    Uses gmx solvate and gmx genion to solvate the system and (optionally) add NaCl ions. This function preserves the
    crystal water molecules.

    Parameters
    ----------
    complex : BioSimSpace.System or parmed.structure.Structure
        The input unsolvated system.
    params : ProtoCaller.Parametrise.Params
        The input force field parameters.
    box_length : float, iterable
        Size of the box in nm.
    shell : float
        Places a layer of water of the specified thickness in nm around the solute.
    neutralise : bool
        Whether to add counterions to neutralise the system.
    ion_conc : float
        Ion concentration of NaCl in mol/L.
    centre : bool
        Whether to centre the system.
    work_dir : str
        Work directory. Default: current directory.
    filebase : str
        Output base name of the file.

    Returns
    -------
    complex : BioSimSpace.System or parmed.structure.Structure
        The solvated system.
    """
    if params is None:
        params = _parametrise.Params()

    if isinstance(complex, _pmd.Structure):
        centrefunc = _pmdwrap.centre
        chargefunc = lambda x: round(sum([atom.charge for atom in x.atoms]))
        readfunc = _pmdwrap.openFilesAsParmed
    elif _PC.BIOSIMSPACE and isinstance(complex,
                                        (_BSS._SireWrappers._molecule.Molecule,
                                         _BSS._SireWrappers._system.System)):
        if isinstance(complex, _BSS._SireWrappers._molecule.Molecule):
            complex = complex.toSystem()
        centrefunc = _BSSwrap.centre
        chargefunc = lambda x: round(x.charge().magnitude())
        readfunc = _BSS.IO.readMolecules
    else:
        raise TypeError("Cannot solvate object of type %s" % type(complex))

    if not isinstance(box_length, _Iterable):
        box_length = 3 * [box_length]

    if work_dir is None:
        work_dir = _os.path.basename(_tempfile.TemporaryDirectory().name)
        temp = True
    else:
        temp = False

    with _fileio.Dir(dirname=work_dir, temp=temp):
        # centre
        if centre:
            complex, box_length, _ = centrefunc(complex, box_length)

        # solvate with gmx solvate and load unparametrised waters into memory
        files = _PC.IO.GROMACS.saveAsGromacs(filebase, complex)
        # reloading the complex fixes some problems with ParmEd
        if isinstance(complex, _pmd.Structure):
            complex = _pmdwrap.openFilesAsParmed(files)
        new_gro = filebase + "_solvated.gro"
        command = "{0} solvate -shell {1} -box {2[0]} {2[1]} {2[2]} -cp \"{3}\" -o \"{4}\"".format(
            _PC.GROMACSEXE, shell, box_length, files[1], new_gro)
        if params.water_points == 4:
            command += " -cs tip4p.gro"
        _runexternal.runExternal(command, procname="gmx solvate")
        complex_solvated = _pmd.load_file(new_gro, skip_bonds=True)
        waters = complex_solvated[":SOL"]

        # prepare waters for tleap and parametrise
        for residue in waters.residues:
            residue.name = "WAT"
        for i, atom in enumerate(waters.atoms):
            if "H" in atom.name:
                atom.name = atom.name[0] + atom.name[2]
            elif "O" in atom.name:
                atom.name = "O"
            else:
                atom.name = "EPW"

        # here we only parametrise a single water molecule in order to gain performance
        waters_prep_filenames = [
            filebase + "_waters.top", filebase + "_waters.gro"
        ]
        waters[":1"].save(filebase + "_single_wat.pdb")
        water = _parametrise.parametriseAndLoadPmd(
            params, filebase + "_single_wat.pdb", "water")
        _pmdwrap.saveFilesFromParmed(waters, [waters_prep_filenames[1]],
                                     combine="all")
        _pmdwrap.saveFilesFromParmed(water, [waters_prep_filenames[0]])
        for line in _fileinput.input(waters_prep_filenames[0], inplace=True):
            line_new = line.split()
            if len(line_new) == 2 and line_new == ["WAT", "1"]:
                line = line.replace(
                    "1",
                    "{}".format(len(waters.positions) // params.water_points))
            print(line, end="")
        waters_prep = _pmdwrap.openFilesAsParmed(waters_prep_filenames)

        waters_prep.box = _pmd.load_file(files[1], skip_bonds=True).box
        if any([neutralise, ion_conc, shell]):
            for residue in waters_prep.residues:
                residue.name = "SOL"
        _pmdwrap.saveFilesFromParmed(waters_prep, waters_prep_filenames)

        # add ions
        if any([neutralise, ion_conc, shell]):
            # write an MDP file
            _protocol.Protocol(use_preset="default").write("GROMACS", "ions")

            # neutralise if needed
            charge = chargefunc(complex) if neutralise else 0
            volume = box_length[0] * box_length[1] * box_length[2] * 10**-24
            n_Na, n_Cl = [
                int(volume * 6.022 * 10**23 * ion_conc) - abs(charge) // 2
            ] * 2
            if neutralise:
                if charge < 0:
                    n_Na -= charge
                else:
                    n_Cl += charge

            # add ions with gmx genion
            ions_prep_filenames = [
                filebase + "_ions.top", filebase + "_ions.gro"
            ]
            command = "{0} grompp -f ions.mdp -p {1} -c {2} -o \"{3}_solvated.tpr\"".format(
                _PC.GROMACSEXE, *waters_prep_filenames, filebase)
            _runexternal.runExternal(command, procname="gmx grompp")

            command = "{{ echo 2; }} | {0} genion -s \"{1}_solvated.tpr\" -o \"{2}\" -nn {3} -np {4}".format(
                _PC.GROMACSEXE, filebase, ions_prep_filenames[1], n_Cl, n_Na)
            _runexternal.runExternal(command, procname="gmx genion")

            # prepare waters for tleap
            ions = _pmd.load_file(ions_prep_filenames[1], skip_bonds=True)
            for residue in ions.residues:
                if residue.name == "SOL":
                    residue.name = "WAT"

            # here we only parametrise single ions to gain performance
            ion = ions[":WAT"][":1"] + ions[":NA"][":1"] + ions[":CL"][":1"]
            max_len = len(ion.residues)
            ion.save(filebase + "_single_ion.pdb")
            ion = _parametrise.parametriseAndLoadPmd(
                params, filebase + "_single_ion.pdb", "water")
            _pmdwrap.saveFilesFromParmed(ions, [ions_prep_filenames[1]],
                                         combine="all")
            _pmdwrap.saveFilesFromParmed(ion, [ions_prep_filenames[0]])
            mol_dict = {}
            for line in _fileinput.input(ions_prep_filenames[0], inplace=True):
                line_new = line.split()
                if len(line_new) == 2 and line_new[0] in [
                        "WAT", "NA", "CL"
                ] and line_new[1] == "1":
                    n_mols = len(ions[":{}".format(line_new[0])].positions)
                    if line_new[0] == "WAT":
                        n_mols //= params.water_points
                    line = line.replace("1", "{}".format(n_mols))
                    mol_dict[line_new[0]] = line
                    # preserve the order of water, sodium and chloride
                    if len(mol_dict) == max_len:
                        for x in ["WAT", "NA", "CL"]:
                            if x in mol_dict.keys():
                                print(mol_dict[x], end="")
                        mol_dict = {}
                else:
                    print(line, end="")

            return complex + readfunc(ions_prep_filenames)
        else:
            complex + readfunc(waters_prep_filenames)
Ejemplo n.º 6
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)
Ejemplo n.º 7
0
from ProtoCaller.Utils.fileio import Dir
from ProtoCaller.Ensemble import Ligand
from ProtoCaller.Solvate import solvate
from ProtoCaller.IO.GROMACS import saveAsGromacs
from ProtoCaller.Parametrise import Params
from ProtoCaller.Wrappers.parmedwrapper import openFilesAsParmed, resize

with Dir("Absolute_Solvation", overwrite=True):
    with Dir("Ligands"):
        # create two ligands from SMILES strings and name them
        toluene = Ligand("C1=CC=CC=C1C", name="toluene", workdir="Ligands")
        benzene = Ligand("C1=CC=CC=C1", name="benzene", workdir="Ligands")

        # protonate parametrise the ligands at pH 7 with GAFF2
        for ligand in [toluene, benzene]:
            ligand.protonate(babel_parameters={"pH": 7.0})
            ligand.parametrise(Params(ligand_ff="gaff2"))

    for ligand in [toluene, benzene]:
        with Dir(ligand.name):
            # open the parametrised ligand as a ParmEd object
            lig_vac = openFilesAsParmed(ligand.parametrised_files)
            # give a dummy box length of e.g. 10 nm
            lig_vac = resize(lig_vac, 10)
            # save the vacuum leg as .gro and .top files
            saveAsGromacs(ligand.name + "_vac", lig_vac)

            # solvate and save the solvated leg
            lig_solv = solvate(lig_vac, Params(water_ff="tip3p"), box_length=4, ion_conc=0.154)
            saveAsGromacs(ligand.name + "_solv", lig_solv)