Пример #1
0
def runAntechamber(force_field, file, output_ext="mol2", charge=None):
    """
    A wrapper around antechamber.

    Parameters
    ----------
    force_field : str
        Which force field to use. Only "gaff" and "gaff2" are accepted.
    file : str
        Name of input file.
    output_ext : str
        Output extension.
    charge : int
        The net charge of the molecule. Default: automatic detection by antechamber.

    Returns
    -------
    output_name : str
        Absolute path of the output parametrised file.
    """
    input_base, input_ext = _os.path.splitext(file)[0], file.split(".")[-1]
    if input_ext.lower() in ["mol", "sdf"]:
        _babel.babelTransform(file, output_extension="mol2", pH=None)
        input_ext = "mol2"

    output_name = "%s_antechamber.%s" % (input_base, output_ext)

    commandstr = "antechamber -i '%s' -fi %s -o '%s' -fo %s -c bcc -at %s -s 2" % (
        file, input_ext, output_name, output_ext, force_field)
    if charge is not None:
        commandstr += " -nc {}".format(charge)

    _runexternal.runExternal(commandstr, procname="antechamber")

    return _os.path.abspath(output_name)
Пример #2
0
def runParmchk(force_field, file):
    """
    A wrapper around parmchk2.

    Parameters
    ----------
    force_field : str
        Which force field to use. Only "gaff" and "gaff2" are accepted.
    file : str
        Name of the file generated by antechamber.

    Returns
    -------
    filename_output : str
        Absolute path to the extra parameter file generated by parmchk2.
    """
    input_base, input_ext = _os.path.splitext(file)[0], file.split(".")[-1]
    commandstr = "parmchk2 -i '{0}.{1}' -f {1} -o '{0}.frcmod' -s %s".format(
        input_base, input_ext, force_field)
    _runexternal.runExternal(commandstr, procname="parmchk2")

    return _os.path.abspath(input_base + ".frcmod")
Пример #3
0
def babelTransform(input_filename,
                   output_extension="mol2",
                   pH=None,
                   generate_3D_coords=False):
    """
    A light wrapper of some of OpenBabel's file conversion capabilities.

    Parameters
    ----------
    input_filename : str
        Name of the input file.
    output_extension : str
        Type of output extension.
    pH : float or None
        Hydrogenate the molecule for a certain pH. None means no hydrogenation.
    generate_3D_coords : bool
        Whether to generate 3D coordinates for the molecule.

    Returns
    -------
    filename : str
        The absolute path to the output file.
    """
    if input_filename is None:
        return None

    input_filebase, input_extension = _os.path.splitext(
        input_filename)[0], input_filename.split(".")[-1]
    output_filename = _os.path.abspath(
        _os.path.basename(input_filebase) + "." + output_extension)
    command = "obabel -i{0} \"{1}\" -o{2} -O \"{3}\"".format(
        input_extension, input_filename, output_extension, output_filename)
    if pH is not None: command += " -p {}".format(pH)
    if generate_3D_coords: command += " --gen3d"
    _runexternal.runExternal(command, procname="OpenBabel")

    return _os.path.abspath(output_filename)
Пример #4
0
    def generateMBARData(self, n_cores=None, n_nodes=1, cont=True):
        """
        Manually generates input data for MBAR using gmx mdrun -rerun using N
        topologies and N trajectories generated from N simulations (N squared
        energy evaluations are needed). Doesn't work with constrained
        simulations. For most cases one should instead use the XVG files
        readily generated by GROMACS during the simulation.

        Parameters
        ----------
         n_cores : int or None, optional
            Number of cores used. Default: the same as the number of replicas.
        n_nodes : int, optional
            Number of nodes used.
        cont : bool, optional
            Whether to overwrite existing files or to continue from the last
            one.

        Returns
        -------
        mbar_data : numpy.ndarray
            Data which is to be passed to pymbar.
        """
        # GROMACS might generate a bunch of warnings when we apply a non-dummy Hamiltonian to a trajectory with dummies
        # due to clashes and backup too many structures. Here we suppress this backing up
        gmx_suppress_dump = _os.environ[
            "GMX_SUPPRESS_DUMP"] if "GMX_SUPPRESS_DUMP" in _os.environ.keys(
            ) else None
        _os.environ["GMX_SUPPRESS_DUMP"] = "1"
        self.mbar_data = []

        _logging.info("Generating Energy files...")
        with self._workdir:
            with _fileio.Dir("MBAR"):
                for i, file in enumerate(self.files):
                    self.mbar_data += [[]]
                    gro, top = file["gro"], file["top"]
                    for j, file in enumerate(self.files):
                        run = True
                        trr = file["trr"]
                        filebase = "Energy_%d_%d" % (i, j)
                        # we only overwrite the last generated energies, because they might be incomplete
                        if cont:
                            filebase_next = "Energy_%d_%d" % (
                                i + (j + 1) // len(self.files),
                                (j + 1) % len(self.files))
                            files_current = _glob.glob(
                                "%s/%s.xvg" % (_os.getcwd(), filebase))
                            files_next = _glob.glob(
                                "%s/%s.xvg" % (_os.getcwd(), filebase_next))
                            if len(files_current) and len(files_next):
                                run = False
                        if run:
                            # use the last protocol or create a default one
                            if len(self.protocols):
                                protocol = self.protocols[-1]
                            else:
                                protocol = _Protocol.Protocol(
                                    use_preset="default", **self.lambda_dict)
                            protocol.init_lambda_state = i
                            protocol.skip_positions = 0
                            protocol.skip_velocities = 0
                            protocol.skip_forces = 0
                            protocol.write_derivatives = False
                            protocol.random_velocities = False
                            protocol.constraint = "no"
                            protocol.__setattr__("continuation", "yes")
                            protocol.__setattr__("dhdl-print-energy",
                                                 "potential")
                            protocol.__setattr__("calc-lambda-neighbors", "0")
                            protocol.__setattr__("calc-lambda-neighbors", "0")

                            mdp = protocol.write("GROMACS", filebase=filebase)
                            tpr = filebase + ".tpr"

                            grompp_command = "%s grompp -maxwarn 10 -f '%s' -c '%s' -p '%s' -o '%s'" % (
                                _PC.GROMACSEXE, mdp, gro, top, tpr)
                            _runexternal.runExternal(grompp_command,
                                                     procname="gmx grompp")

                            if n_cores is None:
                                mdrun_command = "%s mdrun -s '%s' -rerun '%s' -deffnm '%s'" % (
                                    _PC.GROMACSEXE, tpr, trr, filebase)
                            else:
                                ppn = n_cores // n_nodes
                                mdrun_command = "{0} -np {1} --map-by ppr:{2}:node {3} mdrun -s '{4}' -rerun '{5}' " \
                                                "-deffnm {6}".format(_PC.MPIEXE, n_cores, ppn, _PC.GROMACSMPIEXE, tpr,
                                                                     trr, filebase)

                            _runexternal.runExternal(mdrun_command,
                                                     procname="gmx mdrun")

                        self.mbar_data[i] += list(
                            _MDAnalysis.auxiliary.XVG.XVGReader(
                                filebase + ".xvg")._auxdata_values[:, 1])

        # restore the original environment variable
        del _os.environ["GMX_SUPPRESS_DUMP"]
        if gmx_suppress_dump is not None:
            _os.environ["GMX_SUPPRESS_DUMP"] = gmx_suppress_dump

        return self.mbar_data
Пример #5
0
    def runSimulation(self,
                      name,
                      multi=False,
                      multidir=False,
                      single_lambda=None,
                      use_mpi=False,
                      mdrun_mpi=False,
                      gpu_id=None,
                      use_preset=None,
                      replex=None,
                      plumed_file=None,
                      n_cores_per_process=None,
                      n_nodes=1,
                      n_processes=None,
                      dlb=False,
                      gmx_kwargs=None,
                      **protocol_params):
        """
        Runs a simulation in GROMACS.

        Parameters
        ----------
        name : str
            The name of the simulation.
        multi : bool, optional
            Whether to run the simulations in parallel, using -multi.
        multidir : bool, optional
            Whether to run the simulations in parallel, using -multidir. Overrides multi.
        single_lambda : None, int, optional
            An integer runs a simulation at a single lambda value and overrides multi and replex.
            None runs all lambda values.
        use_mpi : bool, optional
            Whether to use ProtoCaller.GROMACSEXE or GROMACSMPIEXE.
        mdrun_mpi : bool, optional
            Whether to call mdrun as "mdrun" or as "mdrun_mpi".
        gpu_id : str, optional
            Which GPU id to be used, if applicable.
        use_preset : str, Protocaller.Protocol.Protocol, None
            Which default preset to use. One of: "minimisation", "equilibration_nvt", "equilibration_npt", "production"
            "vacuum". You can alternatively pass a custom protocol here, in which case **protocol_params will not be
            used.
        replex : int or None, optional
            Attempts replica exchange after replex number of steps using PLUMED. None means no replica exchange.
            Overrides use_mpi and multi if not None.
        plumed_file : str, optional
            If replex is True, it uses this file as a configuration for PLUMED, otherwise an empty file is used.
        n_cores_per_process : int or None, optional
            Number of cores used per process. Default: let GROMACS decide.
        n_nodes : int, optional
            Number of physical nodes used.
        n_processes : int, optional
            Number of processes. Default: the same as the number of simulation.
        dlb : bool
            Whether to enable dynamic load balancing. Default is False due to some possible instabilities with
            gmx_mpi mdrun in some cases.
        gmx_kwargs : dict
            Additional arguments to be passed to mdrun. The keys of the dictionary need to be the name of the option,
            e.g. "cpt" for checkpoint interval, while the values need to be the value of the option if it permits one
            or None if it doesn't. If the values contain "{}" while the user is running the lambda windows in serial,
            this will be replaced by the lambda number.
        protocol_params
            Keyword arguments passed to ProtoCaller.Protocol.Protocol.
        """
        # perform some checks and initialise some default values
        if n_processes is None:
            n_processes = 1 if single_lambda else self.lambda_size
        if n_nodes > 1 or multi or multidir:
            use_mpi = True
        if single_lambda is not None:
            replex, multi, multidir = None, False, False
        if replex is not None:
            use_mpi, multi = True, True

        if mdrun_mpi:
            MDRUNEXE = _os.path.dirname(_PC.GROMACSMPIEXE) + "/mdrun_mpi"
        elif use_mpi:
            MDRUNEXE = _PC.GROMACSMPIEXE + " mdrun"
        else:
            MDRUNEXE = _PC.GROMACSEXE + " mdrun"

        if use_mpi or mdrun_mpi:
            base_mdrun_command = f"{_PC.MPIEXE} -np {n_processes} --map-by ppr:{n_processes // n_nodes}:node {MDRUNEXE}"
        else:
            base_mdrun_command = MDRUNEXE

        gmx_kwargs = {} if gmx_kwargs is None else gmx_kwargs
        gmx_kwargs["dlb"] = "yes" if dlb else "no"
        if n_cores_per_process is not None:
            gmx_kwargs["ntomp"] = n_cores_per_process
        if gpu_id is not None:
            gmx_kwargs["gpu_id"] = gpu_id

        # this is due to incompatibility between GROMACS 2019+ and multi
        multidir = True if self._gmx_version(
            _PC.GROMACSMPIEXE) >= 2019 and multi else multidir

        # initialise the protocol
        if isinstance(use_preset, _Protocol.Protocol):
            protocol = use_preset
        else:
            protocol = _Protocol.Protocol(use_preset=use_preset,
                                          **protocol_params,
                                          **self.lambda_dict)
        self.protocols += [protocol]

        # run the simulations
        _logging.info(f"Running {name}...")
        with self._workdir:
            with _fileio.Dir(name, overwrite=False):
                # run single lambda if needed
                if single_lambda is not None:
                    it = [single_lambda]
                else:
                    it = range(self.lambda_size)

                # call grompp for each lambda
                for i in it:
                    filebase = name if multidir else f"{name}_{i}"
                    dirname = f"Lambda_{i}" if multidir else "."
                    with _fileio.Dir(dirname):
                        protocol.init_lambda_state = i
                        self.files[i]["mdp"] = _os.path.abspath(
                            protocol.write(engine="GROMACS",
                                           filebase=filebase))
                        grompp_args = {
                            "-f": "mdp",
                            "-c": "gro",
                            "-p": "top",
                            "-t": "cpt",
                        }

                        grompp_command = f"{_PC.GROMACSEXE} grompp -maxwarn 10 -o {filebase}.tpr"
                        for grompp_arg, filetype in grompp_args.items():
                            if filetype in self.files[i].keys():
                                grompp_command += f" {grompp_arg} '{self.files[i][filetype]}'"
                        _runexternal.runExternal(grompp_command,
                                                 procname="gmx grompp")

                # call the simulations consecutively for each lambda if multi is not specified
                if not (multi or multidir):
                    for i in it:
                        filebase = f"{name}_{i}"
                        gmx_kwargs["s"] = f"'{filebase}.tpr'"
                        gmx_kwargs["deffnm"] = f"'{filebase}'"

                        # run GROMACS
                        mdrun_command = self._dict_to_arguments(
                            base_mdrun_command, gmx_kwargs, i)
                        _runexternal.runExternal(mdrun_command,
                                                 procname="gmx mdrun")

                        # update files after the run
                        self._update_files(i, filebase)
                # alternatively, run all simulations in parallel
                else:
                    filebase = name if multidir else name + "_"
                    gmx_kwargs["s"] = f"'{filebase}.tpr'"
                    gmx_kwargs["deffnm"] = f"'{filebase}'"
                    if multidir:
                        gmx_kwargs["multidir"] = " ".join(f"Lambda_{i}"
                                                          for i in it)
                    else:
                        gmx_kwargs["multi"] = f"{self.lambda_size}"

                    # run replica exchange with PLUMED if needed
                    if replex is not None:
                        if plumed_file is None:
                            plumed_file = "plumed.dat"
                            open(plumed_file, "a").close()
                        gmx_kwargs["plumed"] = f"'{plumed_file}'"
                        gmx_kwargs["replex"] = replex
                        gmx_kwargs["hrex"] = None

                    # run GROMACS
                    mdrun_command = self._dict_to_arguments(
                        base_mdrun_command, gmx_kwargs, i)
                    _runexternal.runExternal(mdrun_command,
                                             procname="gmx mdrun")

                    # update files after the run
                    for i in it:
                        filebase = name if multidir else f"{name}_{i}"
                        dirname = f"Lambda_{i}" if multidir else "."
                        with _fileio.Dir(dirname):
                            self._update_files(i, filebase)
Пример #6
0
    def runSimulation(self, name, multi=False, single_lambda=None, use_mpi=False, use_preset=None, replex=None,
                      n_cores_per_process=None, n_nodes=1, n_processes=None, dlb=False, **protocol_params):
        """
        Runs a simulation in GROMACS.

        Parameters
        ----------
        name : str
            The name of the simulation.
        multi : bool, optional
            Whether to run the simulations in parallel, using -multi.
        single_lambda : None, int, optional
            An integer runs a simulation at a single lambda value and overrides multi and replex.
            None runs all lambda values.
        use_mpi : bool, optional
            Whether to use ProtoCaller.GROMACSEXE or GROMACSMPIEXE.
        use_preset : str, None
            Which default preset to use. One of: "minimisation", "equilibration_nvt", "equilibration_npt", "production"
            "vacuum".
        replex : int or None, optional
            Attempts replica exchange after replex number of steps using PLUMED. None means no replica exchange.
            Overrides use_mpi and multi if not None.
        n_cores_per_process : int or None, optional
            Number of cores used per process. Default: let GROMACS decide.
        n_nodes : int, optional
            Number of physical nodes used.
        n_processes : int, optional
            Number of processes. Default: the same as the number of simulation.
        dlb : bool
            Whether to enable dynamic load balancing. Default is False due to some possible instabilities with
            gmx_mpi mdrun in some cases.
        protocol_params
            Keyword arguments passed to ProtoCaller.Protocol.Protocol.
        """
        if n_processes is None:
            n_processes = 1 if single_lambda else self.lambda_size
        ppn = n_processes // n_nodes
        if n_nodes > 1:
            use_mpi = True
        if single_lambda is not None:
            replex = None
            multi = False
        if replex is not None:
            multi = True
            use_mpi = True
        dlb = "yes" if dlb else "no"

        protocol = _Protocol.Protocol(use_preset=use_preset, **protocol_params, **self.lambda_dict)
        self.protocols += [protocol]

        _logging.info("Running %s..." % name)
        with self._workdir:
            with _fileio.Dir(name, overwrite=True):
                # run single lambda if needed
                if single_lambda is not None:
                    it = [single_lambda]
                else:
                    it = range(self.lambda_size)

                # call grompp for every lambda
                for i in it:
                    filebase = "%s_%d" % (name, i)
                    protocol.init_lambda_state = i
                    self.files[i]["mdp"] = _os.path.abspath(protocol.write(engine="GROMACS", filebase=filebase))
                    grompp_args = {
                        "-f": "mdp",
                        "-c": "gro",
                        "-p": "top",
                        "-t": "cpt",
                    }

                    grompp_command = "%s grompp -maxwarn 10 -o %s.tpr" % (_PC.GROMACSEXE, filebase)
                    for grompp_arg, filetype in grompp_args.items():
                        if filetype in self.files[i].keys():
                            grompp_command += " %s '%s'" % (grompp_arg, self.files[i][filetype])
                    _runexternal.runExternal(grompp_command, procname="gmx grompp")

                    # call the simulation consecutively for every lambda if multi is not specified
                    if not multi:
                        if not use_mpi:
                            mdrun_command = "{0} mdrun -s '{1}.tpr' -deffnm {1} -dlb {2}".format(
                                _PC.GROMACSEXE, filebase, dlb)
                        else:
                            mdrun_command = "{0} -np {1} --map-by ppr:{2}:node {3} " \
                                            "mdrun -s '{4}.tpr' -deffnm {4} -dlb {5}".format(
                                _PC.MPIEXE, n_processes, ppn, _PC.GROMACSMPIEXE, filebase, dlb)

                        if n_cores_per_process:
                            mdrun_command += " -ntomp {}".format(n_cores_per_process)

                        _runexternal.runExternal(mdrun_command, procname="gmx mdrun")

                        # update files after the run
                        self.files[i] = {"top" : self.files[i]["top"],}
                        output_files = _glob.glob("%s.*" % filebase)
                        for output_file in output_files:
                            ext = output_file.split(".")[-1].lower()
                            if ext != "tpr":
                                self.files[i][ext] = _os.path.abspath(output_file)

                # alternatively, run all simulations in parallel
                if multi:
                    filebase = name + "_"
                    mdrun_command = "{0} -np {1} --map-by ppr:{2}:node {3} mdrun -multi {4} -s {5}.tpr " \
                                    "-deffnm {5} -dlb {6}".format(
                        _PC.MPIEXE, n_processes, ppn, _PC.GROMACSMPIEXE, self.lambda_size, filebase, dlb)

                    # run replica exchange with PLUMED if needed
                    if replex is not None:
                        open("plumed.dat", "a").close()
                        mdrun_command += " -plumed plumed.dat -replex {} -hrex".format(replex)

                    if n_cores_per_process:
                        mdrun_command += " -ntomp {}".format(n_cores_per_process)

                    _runexternal.runExternal(mdrun_command, procname="gmx mdrun")

                    # update files after the run
                    for i in range(self.lambda_size):
                        filebase = "%s_%d" % (name, i)
                        self.files[i] = {"top": self.files[i]["top"], }
                        output_files = _glob.glob("%s.*" % filebase)
                        for output_file in output_files:
                            ext = output_file.split(".")[-1].lower()
                            if ext != "tpr":
                                self.files[i][ext] = _os.path.abspath(output_file)
Пример #7
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)
Пример #8
0
def runTleap(force_fields=None,
             files=None,
             param_files=None,
             id=None,
             disulfide_bonds=None):
    """
    Writes and runs tleap scripts.

    Parameters
    ----------
    force_fields : [str]
        All force fields to be loaded in tleap.
    files : [str]
        All regular files to be loaded in tleap.
    param_files : [str]
        All parameter files to be loaded in tleap.
    id : str
        The name of the molecule. Default: equal to molecule_type.
    disulfide_bonds : [[ProtoCaller.IO.PDB.Residue, ProtoCaller.IO.PDB.Residue]]:
        Residues between which there is a disulfide bond.

    Returns
    -------
    filenames : [str]
        Absolute paths of the final parametrised files. The first file is a topology file and the second file is a
        coordinate file.
    """
    if id is None: id = "molecule"
    if disulfide_bonds is None: disulfide_bonds = []

    filename_tleap = "tleap_script_%s.in" % id
    filenames = [id + ".prmtop", id + ".inpcrd"]

    with open(filename_tleap, "w+") as out:
        for force_field in force_fields:
            out.write("source \"%s\"\n" % returnFFPath(force_field))
        if param_files is not None:
            for param_file in param_files:
                ext = param_file.split(".")[-1].lower()
                if ext in ["frcmod", "frcfld"]:
                    command = "loadamberparams"
                elif ext in ["off", "lib"]:
                    command = "loadoff"
                elif ext == "prep":
                    command = "loadamberprep"
                else:
                    _warnings.warn(
                        "%s is not a valid parameter file. Skipping value..." %
                        param_file)
                    continue
                out.write("%s \"%s\"\n" % (command, param_file))
        for file in files:
            ext = file.split(".")[-1]
            if ext == "pqr": ext = "pdb"
            out.write("MOL = load%s \"%s\"\n" % (ext, file))
        for disulfide_bond in disulfide_bonds:
            out.write("bond MOL.%d.SG MOL.%d.SG\n" %
                      (disulfide_bond[0].resSeq, disulfide_bond[1].resSeq))
        # add support for cofactors
        name = "MOL" if files else id
        out.write("check {}\n".format(name))
        out.write("saveAmberParm {0} {1} {2}\n".format(name, *filenames))
        out.write("quit\n")

    _runexternal.runExternal("tleap -f %s" % filename_tleap, procname="tleap")
    return [_os.path.abspath(f) for f in filenames]