Esempio n. 1
0
def _versionString():
    """Return a nicely formatted string that describes the current Sire version"""
    import Sire.Base as Base

    return """Sire %s [%s|%s, %s]""" % \
              (Base.getReleaseVersion(),
               Base.getRepositoryBranch(),
               Config.sire_repository_version[0:7],
               ["unclean", "clean"][Base.getRepositoryVersionIsClean()])
Esempio n. 2
0
def help(name):
    """Print the help message for the named node.

       Parameters
       ----------

       name : str
           The name of the node.
    """

    if type(name) is not str:
        raise TypeError("'name' must be of type 'str'.")

    # Apped the node directory name.
    full_name = _node_dir + "/" + name

    # Make sure the node exists.
    if not _os.path.isfile(full_name):
        if not _os.path.isfile(full_name + ".py"):
            raise ValueError("Cannot find node: '%s'. " % name +
                             "Run 'Node.list()' to see available nodes!")
        else:
            full_name += ".py"

    # Create the command.
    command = "%s/python %s --help" % (_SireBase.getBinDir(), full_name)

    # Run the node as a subprocess.
    proc = _subprocess.run(command, shell=True)
Esempio n. 3
0
def saveMolecules(filebase, system, fileformat, property_map={}):
    """Save a molecular system to file.

       Parameters
       ----------

       filebase : str
           The base name of the output file.

       system : :class:`System <BioSimSpace._SireWrappers.System>`, \
                :class:`Molecule< BioSimSpace._SireWrappers.Molecule>` \
                :class:`Molecule< BioSimSpace._SireWrappers.Molecules>`
           The molecular system.

       fileformat : str, [str]
           The file format (or formats) to save to.

       property_map : dict
           A dictionary that maps system "properties" to their user
           defined values. This allows the user to refer to properties
           with their own naming scheme, e.g. { "charge" : "my-charge" }

       Returns
       -------

       files : [str]
           The list of files that were generated.

       Examples
       --------

       Load a molecular system from AMBER coordinate and topology files then
       try to save it to all supported file formats.

       >>> import BioSimSpace as BSS
       >>> system = BSS.IO.readMolecules(["ala.rst7", "ala.prm7"])
       >>> for format in BSS.IO.fileFormats():
       ...     try:
       ...         BSS.IO.saveMolecules("test", system, format)
       ...     except:
       ...         print("Could not convert to format: '%s'" % format)

       Load a molecular system from AMBER coordinate and topology files then
       try to save it to GROMACS format, mapping and un-mapping the charge
       property along the way.

       >>> import BioSimSpace as BSS
       >>> system = BSS.IO.readMolecules(["ala.rst7", "ala.prm7"], property_map={"charge" : "my-charge"})
       >>> BSS.IO.saveMolecules("test", system, ["gro87", "grotop"], property_map={"charge" : "my-charge"})
    """

    global _has_gmx_warned
    if _gromacs_path is None and not _has_gmx_warned:
        _warn(
            "BioSimSpace.IO: Please install GROMACS (http://www.gromacs.org) "
            "for GROMACS topology file support.")
        _has_gmx_warned = True

    # Check that the filebase is a string.
    if type(filebase) is not str:
        raise TypeError("'filebase' must be of type 'str'")

    # Check that that the system is of the correct type.

    # A System object.
    if type(system) is _System:
        pass
    # A Molecule object.
    elif type(system) is _Molecule:
        system = _System(system)
    elif type(system) is _Molecules:
        system = system.toSystem()
    # A list of Molecule objects.
    elif type(system) is list and all(
            isinstance(x, _Molecule) for x in system):
        system = _System(system)
    # Invalid type.
    else:
        raise TypeError(
            "'system' must be of type 'BioSimSpace.SireWrappers.System', "
            "'BioSimSpace._SireWrappers.Molecule, 'BioSimSpace._SireWrappers.Molecules' "
            "or a list of 'BiSimSpace._SireWrappers.Molecule' types.")

    # Check that fileformat argument is of the correct type.

    # Convert to a list if a single string is passed.
    # We split on ',' since the user might pass system.fileFormats() as the argument.
    if type(fileformat) is str:
        fileformat = fileformat.split(",")
    # Lists and tuples are okay!
    elif type(fileformat) is list:
        pass
    elif type(fileformat) is tuple:
        pass
    # Invalid.
    else:
        raise TypeError(
            "'fileformat' must be a 'str' or a 'list' of 'str' types.")

    # Make sure all items in list or tuple are strings.
    if not all(isinstance(x, str) for x in fileformat):
        raise TypeError(
            "'fileformat' must be a 'str' or a 'list' of 'str' types.")

    # Make a list of the matched file formats.
    formats = []

    # Make sure that all of the formats are valid.
    for format in fileformat:
        try:
            f = _formats_dict[format.replace(" ", "").upper()][0]
            formats.append(f)
        except KeyError:
            raise ValueError("Unsupported file format '%s'. Supported formats "
                             "are: %s." % (format, str(_formats)))

    # Validate the map.
    if type(property_map) is not dict:
        raise TypeError("'property_map' must be of type 'dict'")

    # Copy the map.
    _property_map = property_map.copy()

    # Add the GROMACS topology file path.
    if _gromacs_path is not None and ("GROMACS_PATH" not in _property_map):
        _property_map["GROMACS_PATH"] = _gromacs_path

    # Get the directory name.
    dirname = _os.path.dirname(filebase)

    # If the user has passed a directory, make sure that is exists.
    if _os.path.basename(filebase) != filebase:
        # Create the directory if it doesn't already exist.
        if not _os.path.isdir(dirname):
            _os.makedirs(dirname, exist_ok=True)

    # Store the current working directory.
    dir = _os.getcwd()

    # Change to the working directory for the process.
    # This avoid problems with relative paths.
    if dirname != "":
        _os.chdir(dirname)

    # A list of the files that have been written.
    files = []

    # Save the system using each file format.
    for format in formats:
        # Add the file format to the property map.
        _property_map["fileformat"] = _SireBase.wrap(format)

        # Write the file.
        try:
            file = _SireIO.MoleculeParser.save(system._getSireObject(),
                                               filebase, _property_map)
            files += file
        except Exception as e:
            if dirname != "":
                _os.chdir(dir)
            msg = "Failed to save system to format: '%s'" % format
            if _isVerbose():
                raise IOError(msg) from e
            else:
                raise IOError(msg) from None

    # Change back to the original directory.
    if dirname != "":
        _os.chdir(dir)

    # Return the list of files.
    return files
Esempio n. 4
0
from Sire import Maths as _SireMaths
from Sire import Mol as _SireMol
from Sire import Units as _SireUnits

from BioSimSpace import _isVerbose
from BioSimSpace._Exceptions import AlignmentError as _AlignmentError
from BioSimSpace._Exceptions import MissingSoftwareError as _MissingSoftwareError
from BioSimSpace._SireWrappers import Molecule as _Molecule

from BioSimSpace import IO as _IO
from BioSimSpace import Units as _Units
from BioSimSpace import _Utils as _Utils

# Try to find the FKCOMBU program from KCOMBU: http://strcomp.protein.osaka-u.ac.jp/kcombu
try:
    _fkcombu_exe = _SireBase.findExe("fkcombu").absoluteFilePath()
except:
    _fkcombu_exe = None


def matchAtoms(molecule0,
               molecule1,
               scoring_function="rmsd_align",
               matches=1,
               return_scores=False,
               prematch={},
               timeout=5 * _Units.Time.second,
               property_map0={},
               property_map1={}):
    """Find mappings between atom indices in molecule0 to those in molecule1.
       Molecules are aligned using a Maximum Common Substructure (MCS) search.
Esempio n. 5
0
def _solvate(molecule,
             box,
             shell,
             model,
             num_point,
             ion_conc,
             is_neutral,
             work_dir=None,
             property_map={}):
    """Internal function to add solvent using 'gmx solvate'.

       Parameters
       ----------

       molecule : :class:`Molecule <BioSimSpace._SireWrappers.Molecule>`, \
                  :class:`System <BioSimSpace._SireWrappers.System>`
           A molecule, or system of molecules.

       box : [:class:`Length <BioSimSpace.Types.Length>`]
           A list containing the box size in each dimension.

       shell : :class:`Length` <BioSimSpace.Types.Length>`
           Thickness of the water shell around the solute.

       model : str
           The name of the water model.

       num_point : int
           The number of atoms in the water model.

       ion_conc : float
           The ion concentration in (mol per litre).

       is_neutral : bool
           Whether to neutralise the system.

       work_dir : str
           The working directory for the process.

       property_map : dict
           A dictionary that maps system "properties" to their user defined
           values. This allows the user to refer to properties with their
           own naming scheme, e.g. { "charge" : "my-charge" }


       Returns
       -------

       system : :class:`System <BioSimSpace._SireWrappers.System>`
           The solvated system.
    """

    if molecule is not None:
        # Store the centre of the molecule.
        center = molecule._getAABox(property_map).center()

        # Work out the vector from the centre of the molecule to the centre of the
        # water box, converting the distance in each direction to Angstroms.
        vec = []
        for x, y in zip(box, center):
            vec.append(0.5 * x.angstroms().magnitude() - y)

        # Translate the molecule. This allows us to create a water box
        # around the molecule.
        molecule.translate(vec, property_map)

        if type(molecule) is _System:

            # Reformat all of the water molecules so that they match the
            # expected GROMACS topology template.
            waters = _SireIO.setGromacsWater(
                molecule._sire_object.search("water"), model)

            # Convert to a BioSimSpace molecules container.
            waters = _Molecules(waters.toMolecules())

            # Remove the old water molecules then add those with the updated topology.
            molecule.removeWaterMolecules()
            molecule.addMolecules(waters)

    # Create a temporary working directory and store the directory name.
    if work_dir is None:
        tmp_dir = _tempfile.TemporaryDirectory()
        work_dir = tmp_dir.name

    # Run the solvation in the working directory.
    with _Utils.cd(work_dir):

        # Create the gmx command.
        if num_point == 3:
            mod = "spc216"
        else:
            mod = model
        command = "%s solvate -cs %s" % (_gmx_exe, mod)

        if molecule is not None:
            # Write the molecule/system to a GRO files.
            _IO.saveMolecules("input", molecule, "gro87")
            _os.rename("input.gro87", "input.gro")

            # Update the command.
            command += " -cp input.gro"

            # Add the box information.
            if box is not None:
                command += " -box %f %f %f" % (box[0].nanometers().magnitude(),
                                               box[1].nanometers().magnitude(),
                                               box[2].nanometers().magnitude())

            # Add the shell information.
            if shell is not None:
                command += " -shell %f" % shell.nanometers().magnitude()

        # Just add box information.
        else:
            command += " -box %f %f %f" % (box[0].nanometers().magnitude(),
                                           box[1].nanometers().magnitude(),
                                           box[2].nanometers().magnitude())

        # Add the output file.
        command += " -o output.gro"

        with open("README.txt", "w") as file:
            # Write the command to file.
            file.write("# gmx solvate was run with the following command:\n")
            file.write("%s\n" % command)

        # Create files for stdout/stderr.
        stdout = open("solvate.out", "w")
        stderr = open("solvate.err", "w")

        # Run gmx solvate as a subprocess.
        proc = _subprocess.run(command,
                               shell=True,
                               stdout=stdout,
                               stderr=stderr)
        stdout.close()
        stderr.close()

        # gmx doesn't return sensible error codes, so we need to check that
        # the expected output was generated.
        if not _os.path.isfile("output.gro"):
            raise RuntimeError("'gmx solvate failed to generate output!")

        # Extract the water lines from the GRO file.
        water_lines = []
        with open("output.gro", "r") as file:
            for line in file:
                if _re.search("SOL", line):
                    # Store the SOL atom record.
                    water_lines.append(line)

            # Add any box information. This is the last line in the GRO file.
            water_lines.append(line)

        # Write a GRO file that contains only the water atoms.
        if len(water_lines) - 1 > 0:
            with open("water.gro", "w") as file:
                file.write("BioSimSpace %s water box\n" % model.upper())
                file.write("%d\n" % (len(water_lines) - 1))

                for line in water_lines:
                    file.write("%s" % line)
        else:
            raise ValueError(
                "No water molecules were generated. Try increasing "
                "the 'box' size or 'shell' thickness.")

        # Create a TOP file for the water model. By default we use the Amber03
        # force field to generate a dummy topology for the water model.
        with open("water_ions.top", "w") as file:
            file.write("#define FLEXIBLE 1\n\n")
            file.write("; Include AmberO3 force field\n")
            file.write('#include "amber03.ff/forcefield.itp"\n\n')
            file.write("; Include %s water topology\n" % model.upper())
            file.write('#include "amber03.ff/%s.itp"\n\n' % model)
            file.write("; Include ions\n")
            file.write('#include "amber03.ff/ions.itp"\n\n')
            file.write("[ system ] \n")
            file.write("BioSimSpace %s water box\n\n" % model.upper())
            file.write("[ molecules ] \n")
            file.write(";molecule name    nr.\n")
            file.write("SOL               %d\n" %
                       ((len(water_lines) - 1) / num_point))

        # Load the water box.
        water = _IO.readMolecules(["water.gro", "water_ions.top"])

        # Create a new system by adding the water to the original molecule.
        if molecule is not None:
            # Translate the molecule and water back to the original position.
            vec = [-x for x in vec]
            molecule.translate(vec, property_map)
            water.translate(vec)

            if type(molecule) is _System:
                # Extract the non-water molecules from the original system.
                non_waters = _Molecules(
                    molecule.search("not water")._sire_object.toMolecules())

                # Create a system by adding these to the water molecules from
                # gmx solvate, which will include the original waters.
                system = non_waters.toSystem() + water

            else:
                system = molecule.toSystem() + water

            # Add all of the water box properties to the new system.
            for prop in water._sire_object.propertyKeys():
                prop = property_map.get(prop, prop)

                # Add the space property from the water system.
                system._sire_object.setProperty(
                    prop, water._sire_object.property(prop))
        else:
            system = water

        # Now we add ions to the system and neutralise the charge.
        if ion_conc > 0 or is_neutral:

            # Write the molecule + water system to file.
            _IO.saveMolecules("solvated", system, "gro87")
            _IO.saveMolecules("solvated", system, "grotop")
            _os.rename("solvated.gro87", "solvated.gro")
            _os.rename("solvated.grotop", "solvated.top")

            # First write an mdp file.
            with open("ions.mdp", "w") as file:
                file.write("; Neighbour searching\n")
                file.write("cutoff-scheme           = Verlet\n")
                file.write("rlist                   = 1.1\n")
                file.write("pbc                     = xyz\n")
                file.write("verlet-buffer-tolerance = -1\n")
                file.write("\n; Electrostatics\n")
                file.write("coulombtype             = cut-off\n")
                file.write("\n; VdW\n")
                file.write("rvdw                    = 1.0\n")

            # Create the grompp command.
            command = "%s grompp -f ions.mdp -po ions.out.mdp -c solvated.gro -p solvated.top -o ions.tpr" % _gmx_exe

            with open("README.txt", "a") as file:
                # Write the command to file.
                file.write(
                    "\n# gmx grompp was run with the following command:\n")
                file.write("%s\n" % command)

            # Create files for stdout/stderr.
            stdout = open("grommp.out", "w")
            stderr = open("grommp.err", "w")

            # Run grompp as a subprocess.
            proc = _subprocess.run(command,
                                   shell=True,
                                   stdout=stdout,
                                   stderr=stderr)
            stdout.close()
            stderr.close()

            # Flag whether to break out of the ion adding stage.
            is_break = False

            # Check for the tpr output file.
            if not _os.path.isfile("ions.tpr"):
                if shell is None:
                    raise RuntimeError(
                        "'gmx grommp' failed to generate output! "
                        "Perhaps your box is too small?")
                else:
                    is_break = True
                    _warnings.warn(
                        "Unable to achieve target ion concentration, try using "
                        "'box' option instead of 'shell'.")

            # Only continue if grommp was successful. This allows us to skip the remainder
            # of the code if the ion addition failed when the 'shell' option was chosen, i.e.
            # because the estimated simulation box was too small.
            if not is_break:
                is_break = False

                # The ion concentration is unset.
                if ion_conc == 0:
                    # Get the current molecular charge.
                    charge = system.charge()

                    # Round to the nearest integer value.
                    charge = round(charge.magnitude())

                    # Create the genion command.
                    command = "echo SOL | %s genion -s ions.tpr -o solvated_ions.gro -p solvated.top -neutral" % _gmx_exe

                    # Add enough counter ions to neutralise the charge.
                    if charge > 0:
                        command += " -nn %d" % abs(charge)
                    else:
                        command += " -np %d" % abs(charge)
                else:
                    # Create the genion command.
                    command = "echo SOL | %s genion -s ions.tpr -o solvated_ions.gro -p solvated.top -%s -conc %f" \
                        % (_gmx_exe, "neutral" if is_neutral else "noneutral", ion_conc)

                with open("README.txt", "a") as file:
                    # Write the command to file.
                    file.write(
                        "\n# gmx genion was run with the following command:\n")
                    file.write("%s\n" % command)

                # Create files for stdout/stderr.
                stdout = open("genion.out", "w")
                stderr = open("genion.err", "w")

                # Run genion as a subprocess.
                proc = _subprocess.run(command,
                                       shell=True,
                                       stdout=stdout,
                                       stderr=stderr)
                stdout.close()
                stderr.close()

                # Check for the output GRO file.
                if not _os.path.isfile("solvated_ions.gro"):
                    if shell is None:
                        raise RuntimeError(
                            "'gmx genion' failed to add ions! Perhaps your box is too small?"
                        )
                    else:
                        is_break = True
                        _warnings.warn(
                            "Unable to achieve target ion concentration, try using "
                            "'box' option instead of 'shell'.")

                if not is_break:
                    # Counters for the number of SOL, NA, and CL atoms.
                    num_sol = 0
                    num_na = 0
                    num_cl = 0

                    # We now need to loop through the GRO file to extract the lines
                    # corresponding to water or ion atoms.
                    water_ion_lines = []

                    with open("solvated_ions.gro", "r") as file:
                        for line in file:
                            # This is a Sodium atom.
                            if _re.search("NA", line):
                                water_ion_lines.append(line)
                                num_na += 1

                            # This is a Chlorine atom.
                            if _re.search("CL", line):
                                water_ion_lines.append(line)
                                num_cl += 1

                            # This is a water atom.
                            elif _re.search("SOL", line):
                                water_ion_lines.append(line)
                                num_sol += 1

                    # Add any box information. This is the last line in the GRO file.
                    water_ion_lines.append(line)

                    # Write a GRO file that contains only the water and ion atoms.
                    if len(water_ion_lines) - 1 > 0:
                        with open("water_ions.gro", "w") as file:
                            file.write("BioSimSpace %s water box\n" %
                                       model.upper())
                            file.write("%d\n" % (len(water_ion_lines) - 1))

                            for line in water_ion_lines:
                                file.write("%s" % line)

                    # Ions have been added. Update the TOP file fo the water model
                    # with the new atom counts.
                    if num_na > 0 or num_cl > 0:
                        with open("water_ions.top", "w") as file:
                            file.write("#define FLEXIBLE 1\n\n")
                            file.write("; Include AmberO3 force field\n")
                            file.write(
                                '#include "amber03.ff/forcefield.itp"\n\n')
                            file.write("; Include %s water topology\n" %
                                       model.upper())
                            file.write('#include "amber03.ff/%s.itp"\n\n' %
                                       model)
                            file.write("; Include ions\n")
                            file.write('#include "amber03.ff/ions.itp"\n\n')
                            file.write("[ system ] \n")
                            file.write("BioSimSpace %s water box\n\n" %
                                       model.upper())
                            file.write("[ molecules ] \n")
                            file.write(";molecule name    nr.\n")
                            file.write("SOL               %d\n" %
                                       (num_sol / num_point))
                            if num_na > 0:
                                file.write("NA                %d\n" % num_na)
                            if num_cl > 0:
                                file.write("CL                %d\n" % num_cl)

                    # Load the water/ion box.
                    water_ions = _IO.readMolecules(
                        ["water_ions.gro", "water_ions.top"])

                    # Create a new system by adding the water to the original molecule.
                    if molecule is not None:

                        if type(molecule) is _System:
                            # Extract the non-water molecules from the original system.
                            non_waters = _Molecules(
                                molecule.search(
                                    "not water")._sire_object.toMolecules())

                            # Create a system by adding these to the water and ion
                            # molecules from gmx solvate, which will include the
                            # original waters.
                            system = non_waters.toSystem() + water_ions
                        else:
                            system = molecule.toSystem() + water_ions

                        # Add all of the water molecules' properties to the new system.
                        for prop in water_ions._sire_object.propertyKeys():
                            prop = property_map.get(prop, prop)

                            # Add the space property from the water system.
                            system._sire_object.setProperty(
                                prop, water_ions._sire_object.property(prop))
                    else:
                        system = water_ions

        # Store the name of the water model as a system property.
        system._sire_object.setProperty("water_model", _SireBase.wrap(model))

    return system
Esempio n. 6
0
    def __init__(self,
                 system,
                 protocol,
                 exe=None,
                 name="somd",
                 platform="CPU",
                 work_dir=None,
                 seed=None,
                 property_map={}):
        """Constructor.

           Parameters
           ----------

           system : :class:`System <BioSimSpace._SireWrappers.System>`
               The molecular system.

           protocol : :class:`Protocol <BioSimSpace.Protocol>`
               The protocol for the SOMD process.

           exe : str
               The full path to the SOMD executable.

           name : str
               The name of the process.

           platform : str
               The platform for the simulation: "CPU", "CUDA", or "OPENCL".

           work_dir :
               The working directory for the process.

           seed : int
               A random number seed.

           property_map : dict
               A dictionary that maps system "properties" to their user defined
               values. This allows the user to refer to properties with their
               own naming scheme, e.g. { "charge" : "my-charge" }
        """

        # Call the base class constructor.
        super().__init__(system, protocol, name, work_dir, seed, property_map)

        # Set the package name.
        self._package_name = "SOMD"

        # This process can generate trajectory data.
        self._has_trajectory = True

        if type(platform) is not str:
            raise TypeError("'platform' must be of type 'str'.")
        else:
            # Strip all whitespace and convert to upper case.
            platform = platform.replace(" ", "").upper()

            # Check for platform support.
            if platform not in self._platforms:
                raise ValueError("Supported platforms are: %s" %
                                 self._platforms.keys())
            else:
                self._platform = self._platforms[platform]

        # If the path to the executable wasn't specified, then use the bundled SOMD
        # executable.
        if exe is None:
            # Generate the name of the SOMD exe.
            if _sys.platform != "win32":
                somd_path = _SireBase.getBinDir()
                somd_suffix = ""
            else:
                somd_path = _os.path.join(
                    _os.path.normpath(_SireBase.getShareDir()), "scripts")
                somd_interpreter = _os.path.join(
                    _os.path.normpath(_SireBase.getBinDir()),
                    "sire_python.exe")
                somd_suffix = ".py"
            if type(self._protocol) is _Protocol.FreeEnergy:
                somd_exe = "somd-freenrg"
            else:
                somd_exe = "somd"
            somd_exe = _os.path.join(somd_path, somd_exe) + somd_suffix
            if not _os.path.isfile(somd_exe):
                raise _MissingSoftwareError(
                    "'Cannot find SOMD executable in expected location: '%s'" %
                    somd_exe)
            if _sys.platform != "win32":
                self._exe = somd_exe
            else:
                self._exe = somd_interpreter
                self._script = somd_exe
        else:
            # Make sure executable exists.
            if _os.path.isfile(exe):
                self._exe = exe
            else:
                raise IOError("SOMD executable doesn't exist: '%s'" % exe)

        # The names of the input files.
        self._rst_file = "%s/%s.rst7" % (self._work_dir, name)
        self._top_file = "%s/%s.prm7" % (self._work_dir, name)

        # The name of the trajectory file.
        self._traj_file = "%s/traj000000001.dcd" % self._work_dir

        # The name of the binary restart file.
        self._restart_file = "%s/latest.rst" % self._work_dir

        # Set the path for the SOMD configuration file.
        self._config_file = "%s/%s.cfg" % (self._work_dir, name)

        # Set the path for the perturbation file.
        self._pert_file = "%s/%s.pert" % (self._work_dir, name)

        # Set the path for the gradient file and create the gradient list.
        self._gradient_file = "%s/gradients.dat" % self._work_dir
        self._gradients = []

        # Create the list of input files.
        self._input_files = [self._config_file, self._rst_file, self._top_file]

        # Initalise the number of moves per cycle.
        self._num_moves = 10000

        # Initialise the buffering frequency.
        self._buffer_freq = 0

        # Now set up the working directory for the process.
        self._setup()
Esempio n. 7
0
def run(name, args={}):
    """Run a node.

       Parameters
       ----------

       name : str
           The name of the node.

       args : dict
           A dictionary of arguments to be passed to the node.

       Returns
       -------

       output : dict
           A dictionary containing the output of the node.
    """

    # Validate the input.

    if type(name) is not str:
        raise TypeError("'name' must be of type 'str'.")

    if type(args) is not dict:
        raise TypeError("'args' must be of type 'dict'.")

    # Apped the node directory name.
    full_name = _node_dir + "/" + name

    # Make sure the node exists.
    if not _os.path.isfile(full_name):
        if not _os.path.isfile(full_name + ".py"):
            raise ValueError("Cannot find node: '%s'. " % name +
                             "Run 'Node.list()' to see available nodes!")
        else:
            full_name += ".py"

    # Write a YAML configuration file for the BioSimSpace node.
    if len(args) > 0:
        with open("input.yaml", "w") as file:
            _yaml.dump(args, file, default_flow_style=False)

        # Create the command.
        command = "%s/python %s --config input.yaml" % (_SireBase.getBinDir(),
                                                        full_name)

    # No arguments.
    else:
        command = "%s/python %s" % (_SireBase.getBinDir(), full_name)

    # Run the node as a subprocess.
    proc = _subprocess.run(command, shell=True)

    if proc.returncode == 0:
        # Read the output YAML file into a dictionary.
        with open("output.yaml", "r") as file:
            output = _yaml.safe_load(file)

        # Delete the redundant YAML files.
        _os.remove("input.yaml")
        _os.remove("output.yaml")

        return output
Esempio n. 8
0
# Check to see if AMBERHOME is set.
if "AMBERHOME" in _environ:
    _amber_home = _environ.get("AMBERHOME")
else:
    _amber_home = None

# Check to see if GROMACS is installed.
import Sire.Base as _SireBase
from os import path as _path

# First, let the user tell us where to find GROMACS. This
# assumes that gromacs is installed in $GROMACSHOME/bin/gmx.
_gmx_exe = None
if "GROMACSHOME" in _environ:
    try:
        _gmx_exe = _SireBase.findExe("%s/bin/gmx" % _environ.get("GROMACSHOME")) \
                            .absoluteFilePath()
    except:
        try:
            _gmx_exe = _SireBase.findExe("%s/bin/gmx_mpi" % _environ.get("GROMACSHOME")) \
                                .absoluteFilePath()
        except:
            pass

if _gmx_exe is None:
    # The user has not told us where it is, so need to look in $PATH.
    try:
        _gmx_exe = _SireBase.findExe("gmx").absoluteFilePath()
    except:
        try:
            _gmx_exe = _SireBase.findExe("gmx_mpi").absoluteFilePath()
        except:
Esempio n. 9
0
def _find_md_package(system, protocol, gpu_support=False):
    """Find a molecular dynamics package on the system and return
       a handle to it as a MDPackage object.

       Parameters
       ----------

       system : :class:`System <BioSimSpace._SireWrappers.System>`
           The molecular system.

       protocol : :class:`Protocol <BioSimSpace.Protocol>`
           The simulation protocol.

       gpu_support : bool
           Whether to use package must have GPU support.

       Returns
       -------

       (package, exe) : (str, str)
           The name of the MD package and a path to its executable.
    """

    # The input has already been validated in the run method, so no need
    # to re-validate here.

    # Get the file format of the molecular system.
    fileformat = system.fileFormat()

    # Make sure that this format is supported.
    if not fileformat in _file_extensions:
        raise ValueError("Cannot find an MD package that supports format: %s" %
                         fileformat)
    else:
        packages = _file_extensions[fileformat]

    # Is this a free energy protocol.
    if type(protocol) is _Protocol.FreeEnergy:
        is_free_energy = True
    else:
        is_free_energy = False

    # Loop over each package that supports the file format.
    for package in packages:
        # If this is free energy protocol, then check that the package has support.
        if not is_free_energy or _free_energy[package]:
            # Check whether this package exists on the system and has the desired
            # GPU support.
            for exe, gpu in _md_packages[package].items():
                # If the user has requested GPU support make sure the package
                # supports it.
                if not gpu_support or gpu:
                    # AMBER
                    if package == "AMBER":
                        # Search AMBERHOME, if set.
                        if _amber_home is not None:
                            _exe = "%s/bin/%s" % (_amber_home, exe)
                            if _os.path.isfile(_exe):
                                return (package, _exe)
                        # Search system PATH.
                        else:
                            try:
                                exe = _SireBase.findExe(exe).absoluteFilePath()
                                return (package, exe)
                            except:
                                pass
                    # GROMACS
                    elif package == "GROMACS":
                        if _gmx_exe is not None:
                            return (package, _gmx_exe)
                    # SOMD
                    elif package == "SOMD":
                        return (package, _SireBase.getBinDir() + "/somd")
                    # Search system PATH.
                    else:
                        try:
                            exe = _SireBase.findExe(exe).absoluteFilePath()
                            return (package, exe)
                        except:
                            pass

    # If we get this far, then no package was found.
    raise _MissingSoftwareError("Couldn't find package to support format: %s" %
                                fileformat)