Esempio n. 1
0
    def _via_helper_water(cls, **kwargs):
        """
        Helper function for via_rdkit or via_openeye

        Returns
        ------------------
        system_pmd : parmed.structure
            The parameterised system as parmed object
        """
        from pdbfixer import PDBFixer  # for solvating

        fixer = PDBFixer(cls.pdb_filename)
        if "padding" not in kwargs:
            fixer.addSolvent(padding=cls.default_padding)
        else:
            fixer.addSolvent(padding=float(kwargs["padding"]))

        tmp_dir = tempfile.mkdtemp()
        cls.pdb_filename = tempfile.mktemp(suffix=".pdb", dir=tmp_dir)
        with open(cls.pdb_filename, "w") as f:
            PDBFile.writeFile(fixer.topology, fixer.positions, f)
        complex = parmed.load_file(cls.pdb_filename)

        solvent = complex["(:HOH)"]
        num_solvent = len(solvent.residues)

        solvent_pmd = cls.solvent_pmd * num_solvent
        solvent_pmd.positions = solvent.positions

        cls.system_pmd = cls.ligand_pmd + solvent_pmd
        cls.system_pmd.box_vectors = complex.box_vectors

        try:
            shutil.rmtree("/".join(cls.pdb_filename.split("/")[:-1]))
            del cls.ligand_pmd
        except:
            pass

        cls.system_pmd.title = cls.smiles
        return cls.system_pmd
Esempio n. 2
0
def add_solvent(pdb_filepath: str,
                ani_input: dict,
                pdb_output_filepath: str,
                box_length: unit.quantity.Quantity = (2.5 * unit.nanometer)):

    assert (type(box_length) == unit.Quantity)

    pdb = PDBFixer(filename=pdb_filepath)
    # Step 0: put the ligand in the center
    #pdb.positions = np.array(pdb.positions.value_in_unit(unit.nanometer)) + box_length/2
    # add water
    l = box_length.value_in_unit(unit.nanometer)
    pdb.addSolvent(boxVectors=(Vec3(l, 0.0, 0.0), Vec3(0.0, l, 0.0),
                               Vec3(0.0, 0.0, l)))
    # Step 1: convert coordinates from standard cartesian coordinate to unit
    # cell coordinates
    #inv_cell = 1/box_length
    #coordinates_cell = np.array(pdb.positions.value_in_unit(unit.nanometer)) * inv_cell
    # Step 2: wrap cell coordinates into [0, 1)
    #coordinates_cell -= np.floor(coordinates_cell)
    # Step 3: convert back to coordinates
    #coordinates_cell = (coordinates_cell * box_length) * unit.nanometer
    #pdb.positions = coordinates_cell
    from simtk.openmm.app import PDBFile
    PDBFile.writeFile(pdb.topology, pdb.positions,
                      open(pdb_output_filepath, 'w'))

    atom_list = []
    coord_list = []
    for atom, coor in zip(pdb.topology.atoms(), pdb.positions):
        if atom.residue.name != 'HOH':
            continue
        atom_list.append(atom.element.symbol)
        coor = coor.value_in_unit(unit.angstrom)
        coord_list.append([coor[0], coor[1], coor[2]])

    ani_input['solvent_atoms'] = ''.join(atom_list)
    ani_input['solvent_coords'] = np.array(coord_list) * unit.angstrom
    ani_input['box_length'] = box_length
Esempio n. 3
0
print('Adding missing atoms...')
fixer.findMissingAtoms()
fixer.addMissingAtoms()

# Remove heterogens.
print('Removing heterogens...')
fixer.removeHeterogens(keepWater=keepWater)

# Add missing hydrogens.
print('Adding missing hydrogens appropriate for pH %s' % pH)
fixer.addMissingHydrogens(pH)

if nonbondedMethod in [app.PME, app.CutoffPeriodic, app.Ewald]:
    # Add solvent.
    print('Adding solvent...')
    fixer.addSolvent(padding=padding)

# Write PDB file.
output_filename = '%s-pdbfixer.pdb' % pdbid
print('Writing PDB file to "%s"...' % output_filename)
app.PDBFile.writeFile(fixer.topology, fixer.positions, open(output_filename, 'w'))

# Create OpenMM System.
print('Creating OpenMM system...')
system = forcefield.createSystem(fixer.topology, nonbondedMethod=nonbondedMethod, constraints=constraints, rigidWater=True, removeCMMotion=False)

# Minimimze to update positions.
print('Minimizing...')
integrator = openmm.VerletIntegrator(1.0 * unit.femtosecond)
context = openmm.Context(system, integrator)
context.setPositions(fixer.positions)
Esempio n. 4
0
    def add_droplet(
        self,
        topology: md.Topology,
        coordinates: unit.quantity.Quantity,
        diameter: unit.quantity.Quantity = (30.0 * unit.angstrom),
        restrain_hydrogen_bonds: bool = True,
        restrain_hydrogen_angles: bool = False,
        top_file: str = "",
    ) -> md.Trajectory:
        """
        Adding a droplet with a given diameter around a small molecule.

        Parameters
        ----------
        topology: md.Topology
            topology of the molecule
        coordinates: np.array, unit'd
        diameter: float, unit'd
        top_file: str
            if top_file is provided the final droplet pdb is either kept and can be reused or if
            top_file already exists it will be used to create the same droplet.
        Returns
        ----------
        A mdtraj.Trajectory object with the ligand centered in the solvent for inspection.
        """

        assert type(diameter) == unit.Quantity
        assert type(topology) == md.Topology
        assert type(coordinates) == unit.Quantity
        if restrain_hydrogen_bonds:
            logger.debug("Hydrogen bonds are restraint.")

        if restrain_hydrogen_angles:
            logger.warning("HOH angles are restraint.")

        # get topology from mdtraj to PDBfixer via pdb file
        radius = diameter.value_in_unit(unit.angstrom) / 2
        center = np.array([radius, radius, radius])

        # if no solvated pdb file is provided generate one
        if top_file:
            # read in the file with the defined droplet
            pdb_filepath = top_file
        else:
            # generage a one time droplet
            pdb_filepath = f"tmp{random.randint(1,10000000)}.pdb"

        if not os.path.exists(pdb_filepath):
            logger.info(f"Generating droplet for {pdb_filepath}...")

            # mdtraj works with nanomter
            md.Trajectory(coordinates.value_in_unit(unit.nanometer),
                          topology).save_pdb(pdb_filepath)
            pdb = PDBFixer(filename=pdb_filepath)
            os.remove(pdb_filepath)

            # put the ligand in the center
            l_in_nanometer = diameter.value_in_unit(unit.nanometer)
            pdb.positions = np.array(
                pdb.positions.value_in_unit(
                    unit.nanometer)) + (l_in_nanometer / 2)
            # add water
            pdb.addSolvent(boxVectors=(
                Vec3(l_in_nanometer, 0.0, 0.0),
                Vec3(0.0, l_in_nanometer, 0.0),
                Vec3(0.0, 0.0, l_in_nanometer),
            ))
            # get topology from PDBFixer to mdtraj # NOTE: a second tmpfile - not happy about this
            from simtk.openmm.app import PDBFile

            PDBFile.writeFile(pdb.topology, pdb.positions,
                              open(pdb_filepath, "w"))
            # load pdb in parmed
            logger.debug("Load with parmed ...")
            structure = pm.load_file(pdb_filepath)
            os.remove(pdb_filepath)

            # search for residues that are outside of the cutoff and delete them
            to_delete = []
            logger.debug("Flag residues ...")

            for residue in structure.residues:
                for atom in residue:
                    p1 = np.array([atom.xx, atom.xy, atom.xz])
                    p2 = center
                    squared_dist = np.sum((p1 - p2)**2, axis=0)
                    dist = np.sqrt(squared_dist)
                    if (
                            dist > radius + 1
                    ):  # NOTE: distance must be greater than radius + 1 Angstrom
                        to_delete.append(residue)

            # only delete water molecules
            for residue in list(set(to_delete)):
                if residue.name == "HOH":
                    logger.debug(f"Remove: {residue}")
                    structure.residues.remove(residue)
                else:
                    logger.warning(
                        f"Residue {residue} reaches outside the droplet")
                    print(f"Residue {residue} reaches outside the droplet")

            structure.write_pdb(pdb_filepath)

        # load pdb with mdtraj
        traj = md.load(pdb_filepath)
        if not top_file:
            os.remove(pdb_filepath)

        # set coordinates #NOTE: note the xyz[0]
        self._ligand_in_water_coordinates = traj.xyz[0] * unit.nanometer

        # generate atom string
        atom_list = []
        for atom in traj.topology.atoms:
            atom_list.append(atom.element.symbol)

        # set atom string
        self.ligand_in_water_atoms = "".join(atom_list)
        # set mdtraj topology
        self.ligand_in_water_topology = traj.topology

        # set FlattBottomRestraintToCenter on each oxygen
        self.solvent_restraints = []
        for residue in traj.topology.residues:
            if residue.is_water:
                for atom in residue.atoms:
                    if str(atom.element.symbol) == "O":
                        self.solvent_restraints.append(
                            CenterFlatBottomRestraint(
                                sigma=0.1 * unit.angstrom,
                                point=center * unit.angstrom,
                                radius=(diameter / 2),
                                atom_idx=atom.index,
                                active_at=-1,
                            ))
                        logger.debug("Adding restraint to center to {}".format(
                            atom.index))

        if restrain_hydrogen_bonds or restrain_hydrogen_angles:
            for residue in traj.topology.residues:
                if residue.is_water:
                    oxygen_idx = -1
                    hydrogen_idxs = []
                    for atom in residue.atoms:
                        if str(atom.element.symbol) == "O":
                            oxygen_idx = atom.index
                        elif str(atom.element.symbol) == "H":
                            hydrogen_idxs.append(atom.index)
                        else:
                            raise RuntimeError(
                                "Water should only consist of O and H atoms.")
                    if restrain_hydrogen_bonds:
                        self.solvent_restraints.append(
                            BondFlatBottomRestraint(
                                sigma=0.2 * unit.angstrom,
                                atom_i_idx=oxygen_idx,
                                atom_j_idx=hydrogen_idxs[0],
                                atoms=self.ligand_in_water_atoms,
                            ))
                        self.solvent_restraints.append(
                            BondFlatBottomRestraint(
                                sigma=0.2 * unit.angstrom,
                                atom_i_idx=oxygen_idx,
                                atom_j_idx=hydrogen_idxs[1],
                                atoms=self.ligand_in_water_atoms,
                            ))
                    if restrain_hydrogen_angles:
                        self.solvent_restraints.append(
                            AngleHarmonicRestraint(
                                sigma=0.1 * unit.radian,
                                atom_i_idx=hydrogen_idxs[0],
                                atom_j_idx=oxygen_idx,
                                atom_k_idx=hydrogen_idxs[1],
                            ))
        # return a mdtraj object for visual check
        return md.Trajectory(
            self._ligand_in_water_coordinates.value_in_unit(unit.nanometer),
            self.ligand_in_water_topology,
        )
Esempio n. 5
0
print('Adding missing atoms...')
fixer.findMissingAtoms()
fixer.addMissingAtoms()

# Remove heterogens.
print('Removing heterogens...')
fixer.removeHeterogens(keepWater=keepWater)

# Add missing hydrogens.
print('Adding missing hydrogens appropriate for pH %s' % pH)
fixer.addMissingHydrogens(pH)

if nonbondedMethod in [app.PME, app.CutoffPeriodic, app.Ewald]:
    # Add solvent.
    print('Adding solvent...')
    fixer.addSolvent(padding=padding)

# Write PDB file.
output_filename = '%s-pdbfixer.pdb' % pdbid
print('Writing PDB file to "%s"...' % output_filename)
app.PDBFile.writeFile(fixer.topology, fixer.positions,
                      open(output_filename, 'w'))

# Create OpenMM System.
print('Creating OpenMM system...')
system = forcefield.createSystem(fixer.topology,
                                 nonbondedMethod=nonbondedMethod,
                                 constraints=constraints,
                                 rigidWater=True,
                                 removeCMMotion=False)
Esempio n. 6
0
def hydrate(system, opt):
    """
    This function solvates the system by using PDBFixer

    Parameters:
    -----------
    system: OEMol molecule
        The system to solvate
    opt: python dictionary
        The parameters used to solvate the system

    Return:
    -------
    oe_mol: OEMol
        The solvated system
    """
    def BoundingBox(molecule):
        """
        This function calculates the Bounding Box of the passed
        molecule

        molecule: OEMol

        return: bb (numpy array)
            the calculated bounding box is returned as numpy array:
            [(xmin,ymin,zmin), (xmax,ymax,zmax)]
        """
        coords = [v for k, v in molecule.GetCoords().items()]
        np_coords = np.array(coords)
        min_coord = np_coords.min(axis=0)
        max_coord = np_coords.max(axis=0)
        bb = np.array([min_coord, max_coord])
        return bb

    # Create a system copy
    sol_system = system.CreateCopy()

    # Calculate system BoundingBox (Angstrom units)
    BB = BoundingBox(sol_system)

    # Estimation of the box cube length in A
    box_edge = 2.0 * opt['solvent_padding'] + np.max(BB[1] - BB[0])

    # BB center
    xc = (BB[0][0]+BB[1][0])/2.
    yc = (BB[0][1]+BB[1][1])/2.
    zc = (BB[0][2]+BB[1][2])/2.

    delta = np.array([box_edge/2., box_edge/2., box_edge/2.]) - np.array([xc, yc, zc])

    sys_coord_dic = {k: (v+delta) for k, v in sol_system.GetCoords().items()}

    sol_system.SetCoords(sys_coord_dic)

    # Load a fake system to initialize PDBfixer
    filename = resource_filename('pdbfixer', 'tests/data/test.pdb')
    fixer = PDBFixer(filename=filename)

    # Convert between OE and OpenMM topology
    omm_top, omm_pos = oeommutils.oemol_to_openmmTop(sol_system)

    chain_names = []

    for chain in omm_top.chains():
        chain_names.append(chain.id)

    # Set the correct topology to the fake system
    fixer.topology = omm_top
    fixer.positions = omm_pos

    # Solvate the system
    fixer.addSolvent(padding=unit.Quantity(opt['solvent_padding'], unit.angstroms),
                     ionicStrength=unit.Quantity(opt['salt_concentration'], unit.millimolar))

    # The OpenMM topology produced by the solvation fixer has missing bond
    # orders and aromaticity. The following section is creating a new openmm
    # topology made of just water molecules and ions. The new topology is then
    # converted in an OEMol and added to the passed molecule to produce the
    # solvated system

    wat_ion_top = app.Topology()

    # Atom dictionary between the the PDBfixer topology and the water_ion topology
    fixer_atom_to_wat_ion_atom = {}

    for chain in fixer.topology.chains():
        if chain.id not in chain_names:
            n_chain = wat_ion_top.addChain(chain.id)
            for res in chain.residues():
                n_res = wat_ion_top.addResidue(res.name, n_chain)
                for at in res.atoms():
                    n_at = wat_ion_top.addAtom(at.name, at.element, n_res)
                    fixer_atom_to_wat_ion_atom[at] = n_at

    for bond in fixer.topology.bonds():
        at0 = bond[0]
        at1 = bond[1]
        try:
            wat_ion_top.addBond(fixer_atom_to_wat_ion_atom[at0],
                                fixer_atom_to_wat_ion_atom[at1], type=None, order=1)
        except:
            pass

    wat_ion_pos = fixer.positions[len(omm_pos):]

    oe_mol = oeommutils.openmmTop_to_oemol(wat_ion_top, wat_ion_pos)

    # Setting the box vectors
    omm_box_vectors = fixer.topology.getPeriodicBoxVectors()
    box_vectors = utils.PackageOEMol.encodePyObj(omm_box_vectors)
    oe_mol.SetData(oechem.OEGetTag('box_vectors'), box_vectors)

    oechem.OEAddMols(oe_mol, sol_system)

    return oe_mol
Esempio n. 7
0
def solvate(system, opt):
    """
    This function solvates the system by using PDBFixer

    Parameters:
    -----------
    system: OEMol molecule
        The system to solvate
    opt: python dictionary
        The parameters used to solvate the system

    Return:
    -------
    oe_mol: OEMol
        The solvated system
    """

    # Load a fake system to initialize PDBfixer
    filename = resource_filename('pdbfixer', 'tests/data/test.pdb')
    fixer = PDBFixer(filename=filename)

    # Convert between OE and OpenMM topology
    omm_top, omm_pos = oeommutils.oemol_to_openmmTop(system)

    chain_names = []

    for chain in omm_top.chains():
        chain_names.append(chain.id)

    # Set the correct topology to the fake system
    fixer.topology = omm_top
    fixer.positions = omm_pos

    # Solvate the system
    fixer.addSolvent(padding=unit.Quantity(opt['solvent_padding'], unit.angstroms),
                     ionicStrength=unit.Quantity(opt['salt_concentration'], unit.millimolar))

    # The OpenMM topology produced by the solvation fixer has missing bond
    # orders and aromaticity. The following section is creating a new openmm
    # topology made of just water molecules and ions. The new topology is then
    # converted in an OEMol and added to the passed molecule to produce the
    # solvated system

    wat_ion_top = app.Topology()

    # Atom dictionary between the the PDBfixer topology and the water_ion topology
    fixer_atom_to_wat_ion_atom = {}

    for chain in fixer.topology.chains():
        if chain.id not in chain_names:
            n_chain = wat_ion_top.addChain(chain.id)
            for res in chain.residues():
                n_res = wat_ion_top.addResidue(res.name, n_chain)
                for at in res.atoms():
                    n_at = wat_ion_top.addAtom(at.name, at.element, n_res)
                    fixer_atom_to_wat_ion_atom[at] = n_at

    for bond in fixer.topology.bonds():
        at0 = bond[0]
        at1 = bond[1]
        try:
            wat_ion_top.addBond(fixer_atom_to_wat_ion_atom[at0],
                                fixer_atom_to_wat_ion_atom[at1], type=None, order=1)
        except:
            pass

    wat_ion_pos = fixer.positions[len(omm_pos):]

    oe_mol = oeommutils.openmmTop_to_oemol(wat_ion_top, wat_ion_pos)

    # Setting the box vectors
    omm_box_vectors = fixer.topology.getPeriodicBoxVectors()
    box_vectors = utils.PackageOEMol.encodePyObj(omm_box_vectors)
    oe_mol.SetData(oechem.OEGetTag('box_vectors'), box_vectors)

    oechem.OEAddMols(oe_mol, system)

    return oe_mol
Esempio n. 8
0
import pdbfixer
from pdbfixer import PDBFixer
from simtk import unit
from simtk.openmm.app import PDBFile
output_file = 't_h.pdb'
fixer = PDBFixer(filename='VER_apo.pdb')
fixer.findMissingResidues()
fixer.findMissingAtoms()
fixer.addMissingAtoms()
fixer.addMissingHydrogens(pH=7.5)
fixer.addSolvent(padding=11*unit.angstrom, ionicStrength=0.050*unit.molar)
#PDBFile.writeHeader(fixer.topology, open(output_file, 'w'))                     
PDBFile.writeFile(fixer.topology, fixer.positions, open(output_file, 'w'))
#PDBFile.writeFooter(fixer.topology, open(output_file, 'a'))      



Esempio n. 9
0
def prepare_pdb(pdb,
                chains='A',
                ff=('amber99sbildn.xml', 'tip3p.xml'),
                ph=7,
                pad=10 * unit.angstroms,
                nbonded=app.PME,
                constraints=app.HBonds,
                crystal_water=True):
    """
    Fetch, solvate and minimize a protein PDB structure.

    Parameters
    ----------
    pdb : str
        PDB Id.
    chains : str or list
        Chain(s) to keep in the system.
    ff : tuple of xml ff files.
        Forcefields for parametrization.
    ph : float
        pH value for adding missing hydrogens.
    pad: Quantity object
        Padding around macromolecule for filling box with water.
    nbonded : object
        The method to use for nonbonded interactions.  Allowed values are
        NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
    constraints : object
        Specifies which bonds and angles should be implemented with
        constraints. Allowed values are None, HBonds, AllBonds, or HAngles.
    crystal_water : bool
        Keep crystal water.

    """

    # Load forcefield.
    logger.info('Retrieving %s from PDB...', pdb)
    ff = app.ForceField(*ff)

    # Retrieve structure from PDB.
    fixer = PDBFixer(pdbid=pdb)

    # Remove unselected chains.
    logger.info('Removing all chains but %s', chains)
    all_chains = [c.id for c in fixer.topology.chains()]
    fixer.removeChains(chainIds=set(all_chains) - set(chains))

    # Find missing residues.
    logger.info('Finding missing residues...')
    fixer.findMissingResidues()

    # Replace nonstandard residues.
    logger.info('Replacing nonstandard residues...')
    fixer.findNonstandardResidues()
    fixer.replaceNonstandardResidues()

    # Add missing atoms.
    logger.info('Adding missing atoms...')
    fixer.findMissingAtoms()
    fixer.addMissingAtoms()

    # Remove heterogens.
    logger.info('Removing heterogens...')
    fixer.removeHeterogens(keepWater=crystal_water)

    # Add missing hydrogens.
    logger.info('Adding missing hydrogens appropriate for pH %s', ph)
    fixer.addMissingHydrogens(ph)

    if nbonded in [app.PME, app.CutoffPeriodic, app.Ewald]:
        # Add solvent.
        logger.info('Adding solvent...')
        fixer.addSolvent(padding=pad)

    # Write PDB file.
    logger.info('Writing PDB file to "%s"...', '%s-pdbfixer.pdb' % pdb)
    app.PDBFile.writeFile(fixer.topology, fixer.positions,
                          open('%s-pdbfixer.pdb' % pdb, 'w'))

    # Create OpenMM System.
    logger.info('Creating OpenMM system...')
    system = ff.createSystem(fixer.topology,
                             nonbondedMethod=nbonded,
                             constraints=constraints,
                             rigidWater=True,
                             removeCMMotion=False)

    # Minimimze to update positions.
    logger.info('Minimizing...')
    integrator = mm.VerletIntegrator(1.0 * unit.femtosecond)
    context = mm.Context(system, integrator)
    context.setPositions(fixer.positions)
    mm.LocalEnergyMinimizer.minimize(context)
    # pylint: disable=unexpected-keyword-arg, no-value-for-parameter
    state = context.getState(getPositions=True)
    fixer.positions = state.getPositions()

    # Write final coordinates.
    logger.info('Writing PDB file to "%s"...', '%s-minimized.pdb' % pdb)
    with open('%s-minimized.pdb' % pdb, 'w') as fp:
        app.PDBFile.writeFile(fixer.topology, fixer.positions, fp)

    # Serialize final coordinates.
    logger.info('Serializing to XML...')
    serialize_system(context, system, integrator)