Beispiel #1
0
    def _initialize_from_topology(self):
        """
        Initializes a SolventWrapper object using a peleffy's
        molecular Topology.
        """
        logger = Logger()
        logger.info(' - Generating solvent parameters')

        from peleffy.utils.toolkits import OpenForceFieldToolkitWrapper

        off_toolkit = OpenForceFieldToolkitWrapper()
        GBSA_handler = off_toolkit.get_parameter_handler_from_forcefield(
            'GBSA', self._ff_file)

        self._solvent_dielectric = GBSA_handler.solvent_dielectric
        self._solute_dielectric = GBSA_handler.solute_dielectric
        self._surface_area_penalty = GBSA_handler.surface_area_penalty
        self._solvent_radius = GBSA_handler.solvent_radius

        from peleffy.forcefield import OpenForceField

        forcefield = OpenForceField(self._ff_file)

        for idx, topology in enumerate(self.topologies):
            parameters = forcefield.parameterize(topology.molecule,
                                                 charge_method='dummy')
            self._radii[idx] = parameters['GBSA_radii']
            self._scales[idx] = parameters['GBSA_scales']
Beispiel #2
0
 def calculate(self):
     """
     Calculate conformation library from the BCE output.
     """
     logger = Logger()
     logger.info(' - Calculating conformation library')
     self._calculate_all_conformations()
Beispiel #3
0
    def _initialize_from_smiles(self, smiles):
        """
        It initializes a molecule from a SMILES tag.

        Parameters
        ----------
        smiles : str
            The SMILES tag to construct the molecule structure with
        """
        logger = Logger()
        logger.info(' - Initializing molecule from a SMILES tag')
        self._initialize()

        logger.info('   - Loading molecule from RDKit')
        rdkit_toolkit = RDKitToolkitWrapper()
        self._rdkit_molecule = \
            rdkit_toolkit.from_smiles(smiles, self.hydrogens_are_explicit)

        # TODO not sure if stereochemistry assignment from 3D is still necessary
        # RDKit must generate stereochemistry specifically from 3D coords
        # rdkit_toolkit.assign_stereochemistry_from_3D(self)

        # Set molecule name according to the SMILES tag
        if self.name == '':
            logger.info('   - Setting molecule name to \'{}\''.format(smiles))
            self.set_name(smiles)

        logger.info('   - Representing molecule with the Open Force Field ' +
                    'Toolkit')
        openforcefield_toolkit = OpenForceFieldToolkitWrapper()
        self._off_molecule = \
            openforcefield_toolkit.from_rdkit(self,
                                              self.hydrogens_are_explicit)
Beispiel #4
0
    def get_by_name(self, forcefield_name):
        """
        Given a forcefield name, it returns the corresponding
        force field class.

        Parameters
        ----------
        forcefield_name : str
            The name of the requested forcefield

        Returns
        -------
        forcefield : a peleffy.forcefield.forcefield.ForceField
            The force field that corresponds to the supplied name

        Raises
        ------
        ValueError
            If the supplied forcefield_name is unknown

        Examples
        --------

        Use the force field selector to select a force field by name

        >>> from peleffy.forcefield import ForceFieldSelector

        >>> selector = ForceFieldSelector()
        >>> openff = selector.get_by_name('openff_unconstrained-1.2.1.offxml')

        """
        from peleffy.utils import Logger

        log = Logger()
        log.info(' - Loading \'{}\''.format(forcefield_name))

        from .forcefield import (OpenForceField, OPLS2005ForceField)

        if forcefield_name.upper() in self._FF_TYPES['OPLS2005']:
            return OPLS2005ForceField()
        elif forcefield_name in self._FF_TYPES['OpenFF']:
            return OpenForceField(forcefield_name=forcefield_name)
        else:
            raise ValueError('Invalid force field name')
Beispiel #5
0
    def _build_rotamers(self):
        """It builds the rotamers of the molecule."""
        logger = Logger()
        if self.off_molecule and self.rdkit_molecule:
            logger.info(' - Generating rotamer library')

            if len(self.core_constraints) != 0:
                self._graph = MolecularGraphWithConstrainedCore(
                    self, self.core_constraints)
                if len(self.core_constraints) == 1:
                    logger.info('   - Core forced to contain atom: ' +
                                self._graph.constraint_names[0])
                else:
                    logger.info(
                        '   - Core forced to contain atoms: ' + ', '.join(
                            atom_name.strip()
                            for atom_name in self._graph.constraint_names))
            else:
                self._graph = MolecularGraph(self)
                logger.info('   - Core set to the center of the molecule')

            self._rotamers = self._graph.get_rotamers()
Beispiel #6
0
def run_peleffy(pdb_file,
                forcefield_name=DEFAULT_OFF_FORCEFIELD,
                resolution=DEFAULT_RESOLUTION,
                charge_method=DEFAULT_CHARGE_METHOD,
                charges_from_file=None,
                chain=None,
                exclude_terminal_rotamers=True,
                output=None,
                with_solvent=False,
                as_datalocal=False,
                conformation_path=None):
    """
    It runs peleffy.

    Parameters
    ----------
    pdb_file : str
        The path to the pdb_file to parameterize with peleffy
    forcefield_name : str
        The name of an OpenForceField's forcefield
    resolution : float
        The resolution in degrees for the rotamer library. Default is 30
    charge_method : str
        The name of the method to use to compute partial charges. Default
        is 'am1bcc'
    charges_from_file : str
        The file containing the partial charges to assign to the
        molecule. Default is None
    chain : str
        Chain to the molecule if the PDB contains multiple molecules.
    exclude_terminal_rotamers : bool
        Whether to exclude terminal rotamers or not
    output : str
        Path where output files will be saved
    with_solvent : bool
        Whether to generate and save the solvent parameters for the input
        molecule or not
    as_datalocal : bool
        Whether to save output files following PELE's DataLocal hierarchy or
        not
    conformation_path: str
        Path to the BCE server outupt to use to extract dihedral angles
    dihedral_mode: str
        Select what kind of dihedrals to extract (all or only flexible)
    """
    if charges_from_file is not None:
        charge_method_str = 'file\n' \
            + '   - Charge file: {}'.format(charges_from_file)
        charge_method = 'dummy'
    else:
        charge_method_str = charge_method

    log = Logger()
    log.info('-' * 60)
    log.info('Open Force Field parameterizer for PELE', peleffy.__version__)
    log.info('-' * 60)
    log.info(' - General:')
    log.info('   - Input PDB:', pdb_file)
    log.info('   - Output path:', output)
    log.info('   - Write solvent parameters:', with_solvent)
    log.info('   - DataLocal-like output:', as_datalocal)
    log.info(' - Parameterization:')
    log.info('   - Force field:', forcefield_name)
    log.info('   - Charge method:', charge_method_str)
    log.info(' - Rotamer library:')
    log.info('   - Resolution:', resolution)
    log.info('   - Exclude terminal rotamers:', exclude_terminal_rotamers)
    log.info('-' * 60)

    from peleffy.topology import Molecule, BCEConformations
    from peleffy.template import Impact
    from peleffy.solvent import OBC2
    from peleffy.forcefield import ForceFieldSelector
    from peleffy.topology import Topology
    from peleffy.utils import parse_charges_from_mae
    from peleffy.utils.input import PDBFile

    if not output:
        output = os.getcwd()

    # Initialize molecule
    if chain is not None:
        PDBreader = PDBFile(pdb_file)
        molecule = PDBreader.get_molecules_from_chain(
            selected_chain=chain,
            rotamer_resolution=resolution,
            exclude_terminal_rotamers=exclude_terminal_rotamers)
    else:
        molecule = Molecule(
            pdb_file,
            rotamer_resolution=resolution,
            exclude_terminal_rotamers=exclude_terminal_rotamers)

    # Initialize force field
    ff_selector = ForceFieldSelector()
    forcefield = ff_selector.get_by_name(forcefield_name)

    output_handler = OutputPathHandler(molecule,
                                       forcefield,
                                       output_path=output,
                                       as_datalocal=as_datalocal)

    # if conformation_path is set, we don't want a rotamer library
    if conformation_path is None:
        rotamer_library = peleffy.topology.RotamerLibrary(molecule)
        rotamer_library.to_file(output_handler.get_rotamer_library_path())

    # Parameterize molecule with the selected force field
    log.info(' - Parameterizing molecule')
    parameters = forcefield.parameterize(molecule, charge_method=charge_method)

    # Update charge parameters from the MAE file
    if charges_from_file is not None:
        parameters = parse_charges_from_mae(charges_from_file, parameters)

    # Generate the molecular topology
    topology = Topology(molecule, parameters)
    log.info(' - Parameters were built successfully:')
    log.info('   - {} atoms'.format(len(topology.atoms)))
    log.info('   - {} bonds'.format(len(topology.bonds)))
    log.info('   - {} torsions'.format(len(topology.angles)))
    log.info('   - {} propers'.format(len(topology.propers)))
    log.info('   - {} impropers'.format(len(topology.impropers)))

    # Generate the impact template
    impact = Impact(topology)
    impact.to_file(output_handler.get_impact_template_path())

    # Generate the solvent template
    if with_solvent:
        solvent = OBC2(topology)
        solvent.to_file(output_handler.get_solvent_template_path())

    if conformation_path is not None:
        conformations = BCEConformations(topology, conformation_path)
        conformations.calculate()
        conformations.save(output_handler.get_conformation_library_path())

    log.info(' - All files were generated successfully:')
    if conformation_path is None:
        log.info('   - {}'.format(output_handler.get_rotamer_library_path()))
    log.info('   - {}'.format(output_handler.get_impact_template_path()))
    if conformation_path is not None:
        log.info('   - {}'.format(
            output_handler.get_conformation_library_path()))
    if with_solvent:
        log.info('   - {}'.format(output_handler.get_solvent_template_path()))

    log.info('-' * 60)
Beispiel #7
0
    def from_openff(openff_molecule,
                    rotamer_resolution=30,
                    exclude_terminal_rotamers=True,
                    name='',
                    tag='UNK',
                    connectivity_template=None,
                    core_constraints=[],
                    allow_undefined_stereo=False,
                    hydrogens_are_explicit=True):
        """
        It initializes and returns a peleffy Molecule representation
        from an OpenForceField molecular representation.

        Parameters
        ----------
        openff_molecule : an openforcefield.topology.Molecule object
            The OpenForceField's Molecule to use to initialize a peleffy
            Molecule object
        rotamer_resolution : float
            The resolution in degrees to discretize the rotamer's
            conformational space. Default is 30
        exclude_terminal_rotamers : bool
            Whether to exclude terminal rotamers when generating the
            rotamers library  or not
        name : str
            The molecule name
        tag : str
            The molecule tag. It must be a 3-character string
        connectivity_template : an rdkit.Chem.rdchem.Mol object
            A molecule represented with RDKit to use when assigning the
            connectivity of this Molecule object
        core_constraints : list[int or str]
            It defines the list of atoms to constrain in the core, thus,
            the core will be forced to contain them. Atoms can be specified
            through integers that match the atom index or strings that
            match with the atom PDB name
        allow_undefined_stereo : bool
            Whether to allow a molecule with undefined stereochemistry
            to be defined or try to assign the stereochemistry and
            raise a complaint if not possible. Default is False
        hydrogens_are_explicit : bool
            Whether the input molecule has explicit information about
            hydrogen atoms or not. Otherwise, they will be added when
            the molecule is built. Default is True

        Returns
        -------
        molecule : an peleffy.topology.Molecule
            The resulting peleffy's Molecule object

        Examples
        --------

        Load a molecule from an RDKit molecular representation

        >>> from rdkit import Chem

        >>> rdkit_molecule = Chem.MolFromPDBFile(pdb_path)

        >>> from peleffy.topology import Molecule

        >>> molecule = Molecule.from_rdkit(rdkit_molecule)

        """
        if name == '':
            name = openff_molecule.name

        molecule = Molecule(
            rotamer_resolution=30,
            exclude_terminal_rotamers=exclude_terminal_rotamers,
            name=name,
            tag=tag,
            connectivity_template=connectivity_template,
            core_constraints=core_constraints,
            allow_undefined_stereo=allow_undefined_stereo,
            hydrogens_are_explicit=hydrogens_are_explicit)

        logger = Logger()

        logger.info(' - Initializing molecule from an OpenFF ' +
                    'molecular representation')
        molecule._initialize()
        molecule._off_molecule = openff_molecule

        logger.info('   - Generating RDKit molecular representation with ' +
                    'the Open Force Field Toolkit')
        molecule._rdkit_molecule = openff_molecule.to_rdkit()

        molecule._build_rotamers()

        return molecule
Beispiel #8
0
    def _initialize_from_pdb_block(self, pdb_block):
        """
        It initializes a molecule with the molecule structure fetch in a PDB
        block.

        Parameters
        ----------
        pdb_block : str
            PDB block with the molecule structure
        """
        logger = Logger()
        logger.info(' - Initializing molecule from PDB')
        self._initialize()

        logger.info('   - Loading molecule from RDKit')
        rdkit_toolkit = RDKitToolkitWrapper()
        self._rdkit_molecule = \
            rdkit_toolkit.from_pdb_block(pdb_block,
                                         self.hydrogens_are_explicit)

        # Use RDKit template, if any, to assign the connectivity to
        # the current Molecule object
        if self.connectivity_template is not None:
            logger.info('   - Assigning connectivity from template')
            rdkit_toolkit.assign_connectivity_from_template(self)

        if not self.allow_undefined_stereo:
            # RDKit must generate stereochemistry specifically from 3D coords
            logger.info('   - Assigning stereochemistry from 3D coordinates')
            rdkit_toolkit.assign_stereochemistry_from_3D(self)

        # Set molecule tag according to PDB's residue name
        if self.tag == 'UNK':
            tag = rdkit_toolkit.get_residue_name(self)
            logger.info('   - Setting molecule tag to \'{}\''.format(tag))
            self.set_tag(tag)

        logger.info('   - Representing molecule with the Open Force Field ' +
                    'Toolkit')
        openforcefield_toolkit = OpenForceFieldToolkitWrapper()
        self._off_molecule = \
            openforcefield_toolkit.from_rdkit(self,
                                              self.hydrogens_are_explicit)
Beispiel #9
0
    def _initialize_from_pdb(self, path):
        """
        It initializes a molecule with the molecule structure read from
        a PDB file.

        Parameters
        ----------
        path : str
            The path to a PDB with the molecule structure
        """
        logger = Logger()
        logger.info(' - Initializing molecule from PDB')
        self._initialize()

        # Validate PDB
        self._pdb_checkup(path)

        # Read and fix PDB
        pdb_block = self._read_and_fix_pdb(path)

        logger.info('   - Loading molecule from RDKit')
        rdkit_toolkit = RDKitToolkitWrapper()
        self._rdkit_molecule = \
            rdkit_toolkit.from_pdb_block(pdb_block,
                                         self.hydrogens_are_explicit)

        # Use RDKit template, if any, to assign the connectivity to
        # the current Molecule object
        if self.connectivity_template is not None:
            logger.info('   - Assigning connectivity from template')
            rdkit_toolkit.assign_connectivity_from_template(self)

        if not self.allow_undefined_stereo:
            # RDKit must generate stereochemistry specifically from 3D coords
            logger.info('   - Assigning stereochemistry from 3D coordinates')
            rdkit_toolkit.assign_stereochemistry_from_3D(self)

        # Set molecule name according to PDB name
        if self.name == '':
            from pathlib import Path
            name = Path(path).stem
            logger.info('   - Setting molecule name to \'{}\''.format(name))
            self.set_name(name)

        # Set molecule tag according to PDB's residue name
        if self.tag == 'UNK':
            tag = rdkit_toolkit.get_residue_name(self)
            logger.info('   - Setting molecule tag to \'{}\''.format(tag))
            self.set_tag(tag)

        logger.info('   - Representing molecule with the Open Force Field ' +
                    'Toolkit')
        openforcefield_toolkit = OpenForceFieldToolkitWrapper()
        self._off_molecule = \
            openforcefield_toolkit.from_rdkit(self,
                                              self.hydrogens_are_explicit)