Ejemplo n.º 1
1
def pdb_fix_pdbfixer(pdbid, file_pathway, ph, chains_to_remove):
    """

    Args:
        pdbid: 4 letter string specifying the PDB ID of the file yoou want to fix
        file_pathway: a string containing the pathway specifying how you want to organize the PDB files once written
        ph: the pH at which hydrogens will be determined and added
        chains_to_remove: dictionary containing pdbs with chains to remove
    Returns: nothing, but it does right PDB files

    """
    print(pdbid)

    # Download the topology from rcsb based on pdbod
    fixer = PDBFixer(pdbid=pdbid)

    # Remove chains based on hand curated .csv file
    if pdbid in chains_to_remove['pdbid']:
        chains = chains_to_remove['chain_to_remove'][chain_to_remove['pdbid'].index(pdbid)]
        chains_list = chains.split()
        fixer.removeChains(chainIds=chains_list)

    # Determine the first and last residue resolved in chain 0
    chains = [chain for chain in fixer.topology.chains()]
    resindices = [residue.index for residue in chains[0].residues()]
    resindices = natsorted(resindices)
    first_resindex = resindices[0]
    last_resindex = resindices[-1]

    # Find Missing residues and determine if they are C or N terminal fragments (which will be removed)

    fixer.findMissingResidues()
    if len(fixer.missingResidues) > 0:
        if sorted(fixer.missingResidues.keys())[0][-1] <= first_resindex:
            fixer.missingResidues.pop((sorted(fixer.missingResidues.keys())[0]))

        if sorted(fixer.missingResidues.keys())[-1][-1] >= last_resindex:
            fixer.missingResidues.pop((sorted(fixer.missingResidues.keys())[-1]))

    fixer.findNonstandardResidues()
    fixer.replaceNonstandardResidues()
    fixer.findMissingAtoms()
    fixer.addMissingAtoms()
    fixer.addMissingHydrogens(ph)
    # Write fixed PDB file, with all of the waters and ligands
    PDBFile.writeFile(fixer.topology, fixer.positions, open(os.path.join(file_pathway,
                                                                         '%s_fixed_ph%s.pdb' % (pdbid, ph)), 'w'),
                      keepIds=keepNumbers)

    # Remove the ligand and write a pdb file
    fixer.removeHeterogens(True)
    PDBFile.writeFile(fixer.topology, fixer.positions, open(os.path.join(file_pathway,
                                                                         '%s_fixed_ph%s_apo.pdb' % (pdbid, ph)), 'w'),
                      keepIds=keepNumbers)
    # Remove the waters and write a pdb file
    fixer.removeHeterogens(False)
    PDBFile.writeFile(fixer.topology, fixer.positions, open(os.path.join(file_pathway,
                                                                         '%s_fixed_ph%s_apo_nowater.pdb' % (pdbid, ph)),
                                                            'w'), keepIds=keepNumbers)
Ejemplo n.º 2
0
    def __init__(self, file):
        """Load a prmtop file."""
        top = Topology()
        ## The Topology read from the prmtop file
        self.topology = top

        # Load the prmtop file

        prmtop = amber_file_parser.PrmtopLoader(file)
        self._prmtop = prmtop

        # Add atoms to the topology

        PDBFile._loadNameReplacementTables()
        lastResidue = None
        c = top.addChain()
        for index in range(prmtop.getNumAtoms()):
            resNumber = prmtop.getResidueNumber(index)
            if resNumber != lastResidue:
                lastResidue = resNumber
                resName = prmtop.getResidueLabel(iAtom=index).strip()
                if resName in PDBFile._residueNameReplacements:
                    resName = PDBFile._residueNameReplacements[resName]
                r = top.addResidue(resName, c)
                if resName in PDBFile._atomNameReplacements:
                    atomReplacements = PDBFile._atomNameReplacements[resName]
                else:
                    atomReplacements = {}
            atomName = prmtop.getAtomName(index).strip()
            if atomName in atomReplacements:
                atomName = atomReplacements[atomName]

            # Try to guess the element.

            upper = atomName.upper()
            if upper.startswith('CL'):
                element = elem.chlorine
            elif upper.startswith('NA'):
                element = elem.sodium
            elif upper.startswith('MG'):
                element = elem.magnesium
            else:
                try:
                    element = elem.get_by_symbol(atomName[0])
                except KeyError:
                    element = None
            top.addAtom(atomName, element, r)

        # Add bonds to the topology

        atoms = list(top.atoms())
        for bond in prmtop.getBondsWithH():
            top.addBond(atoms[bond[0]], atoms[bond[1]])
        for bond in prmtop.getBondsNoH():
            top.addBond(atoms[bond[0]], atoms[bond[1]])

        # Set the periodic box size.

        if prmtop.getIfBox():
            top.setUnitCellDimensions(tuple(x.value_in_unit(unit.nanometer) for x in prmtop.getBoxBetaAndDimensions()[1:4])*unit.nanometer)
Ejemplo n.º 3
0
def fix_pdb(pdb_id, pdb_file, pdb_group):
    chains_to_retain = get_required_chains(pdb_group)
    chains_to_remove = []

    for chain in PDBParser().get_structure(pdb_id, pdb_file)[0]:
        if chain.get_id() not in chains_to_retain:
            chains_to_remove.append(chain.get_id())

    fixer = PDBFixer(filename=pdb_file)

    fixer.removeChains(chainIds=chains_to_remove)

    fixer.findMissingResidues()
    fixer.findMissingAtoms()
    fixer.addMissingAtoms()
    fixer.removeHeterogens(True)

    # KeepIds flag is critical here, otherwise we loose all information binding
    pdb_file = dirname(pdb_file) + '/' + pdb_id + '.pdb'
    PDBFile.writeFile(fixer.topology,
                      fixer.positions,
                      open(pdb_file, 'w'),
                      keepIds=True)

    return pdb_file
Ejemplo n.º 4
0
def write_trajectory_dcd(netcdf_filename, topology, pdb_trajectory_filename, dcd_trajectory_filename):
    """
    Write trajectory.

    Parameters
    ----------
    netcdf_filename : str
        NetCDF filename.
    topology : Topology
        Topology object
    pdb_trajectory_filename : str
        PDB trajectory output filename
    dcd_trajectory_filename : str
        Output trajectory filename.

    """
    ncfile = netCDF4.Dataset(netcdf_filename, 'r')
    [nsamples, nstates] = ncfile.variables['logZ'].shape

    # Write reference.pdb file
    from simtk.openmm.app import PDBFile
    outfile = open(pdb_trajectory_filename, 'w')
    positions = unit.Quantity(ncfile.variables['positions'][0,:,:], unit.nanometers)
    PDBFile.writeFile(topology, positions, file=outfile)
    outfile.close()

    # TODO: Export as DCD trajectory with MDTraj
    from mdtraj.formats import DCDTrajectoryFile
    with DCDTrajectoryFile(dcd_trajectory_filename, 'w') as f:
        f.write(ncfile.variables['positions'][:,:,:] * 10.0) # angstroms
Ejemplo n.º 5
0
    def __init__(self, **kwargs):
        super(AlanineDipeptideExplicitSimulatedTempering,
              self).__init__(**kwargs)
        self.description = 'Alanine dipeptide in explicit solvent simulated tempering simulation'

        # Create topology, positions, and system.
        from openmmtools.testsystems import AlanineDipeptideExplicit
        testsystem = AlanineDipeptideExplicit(
            nonbondedMethod=app.CutoffPeriodic)
        self.topology = testsystem.topology
        self.positions = testsystem.positions
        self.system = testsystem.system

        # DEBUG: Write PDB
        from simtk.openmm.app import PDBFile
        outfile = open('initial.pdb', 'w')
        PDBFile.writeFile(self.topology, self.positions, outfile)
        outfile.close()

        # Add a MonteCarloBarostat
        temperature = 270 * unit.kelvin  # will be replaced as thermodynamic state is updated
        pressure = 1.0 * unit.atmospheres
        barostat = openmm.MonteCarloBarostat(pressure, temperature)
        self.system.addForce(barostat)

        # Create thermodynamic states.
        Tmin = 270 * unit.kelvin
        Tmax = 600 * unit.kelvin
        ntemps = 256  # number of temperatures
        from sams import ThermodynamicState
        temperatures = unit.Quantity(
            np.logspace(np.log10(Tmin / unit.kelvin),
                        np.log10(Tmax / unit.kelvin), ntemps), unit.kelvin)
        self.thermodynamic_states = [
            ThermodynamicState(system=self.system,
                               temperature=temperature,
                               pressure=pressure)
            for temperature in temperatures
        ]

        # Create SAMS samplers
        from sams.samplers import SamplerState, MCMCSampler, ExpandedEnsembleSampler, SAMSSampler
        thermodynamic_state_index = 0  # initial thermodynamic state index
        thermodynamic_state = self.thermodynamic_states[
            thermodynamic_state_index]
        sampler_state = SamplerState(positions=self.positions)
        self.mcmc_sampler = MCMCSampler(
            sampler_state=sampler_state,
            thermodynamic_state=thermodynamic_state,
            ncfile=self.ncfile)
        #self.mcmc_sampler.pdbfile = open('output.pdb', 'w')
        self.mcmc_sampler.topology = self.topology
        self.mcmc_sampler.nsteps = 500
        self.mcmc_sampler.timestep = 2.0 * unit.femtoseconds
        self.mcmc_sampler.verbose = True
        self.exen_sampler = ExpandedEnsembleSampler(self.mcmc_sampler,
                                                    self.thermodynamic_states)
        self.exen_sampler.verbose = True
        self.sams_sampler = SAMSSampler(self.exen_sampler)
        self.sams_sampler.verbose = True
Ejemplo n.º 6
0
    def _geometry_forward(self, topology_proposal, old_sampler_state):
        """
        Run geometry engine to propose new positions and compute logP

        Parameters
        ----------
        topology_proposal : TopologyProposal
            Contains old/new Topology and System objects and atom mappings.
        old_sampler_state : openmmtools.states.SamplerState
            Configurational properties of the old system atoms.

        Returns
        -------
        new_sampler_state : openmmtools.states.SamplerState
            Configurational properties of new atoms proposed by geometry engine calculation.
        geometry_logp_propose : float
            The log probability of the forward-only proposal
        """
        if self.verbose: print("Geometry engine proposal...")
        # Generate coordinates for new atoms and compute probability ratio of old and new probabilities.
        initial_time = time.time()
        new_positions, geometry_logp_propose = self.geometry_engine.propose(topology_proposal, old_sampler_state.positions, self.sampler.thermodynamic_state.beta)
        if self.verbose: print('proposal took %.3f s' % (time.time() - initial_time))

        if self.geometry_pdbfile is not None:
            print("Writing proposed geometry...")
            from simtk.openmm.app import PDBFile
            PDBFile.writeFile(topology_proposal.new_topology, new_positions, file=self.geometry_pdbfile)
            self.geometry_pdbfile.flush()

        new_sampler_state = SamplerState(new_positions, box_vectors=old_sampler_state.box_vectors)

        return new_sampler_state, geometry_logp_propose
Ejemplo n.º 7
0
def pdb2xyz(inputfile, outputPrefix, keepIntermediate=False):
    """pdb2xyz: Transform a pdb file to a goccs compatible xyz file with number of atoms, elements and coordinates into an ouputfile, prefixed with outputPrefix.xyz. If you set keepIntermediate to true then the pdb file written by PDBFixer will be kept in the output folder. """

    pdbfixedfilename = outputPrefix + "_fixed.pdb"
    xyzoutfilename = outputPrefix + ".xyz"
    fixer = pdbfixer.PDBFixer(inputfile)
    fixer.removeHeterogens(False)
    PDBFile.writeFile(fixer.topology, fixer.positions,
                      open(pdbfixedfilename, 'w'))

    parser = PDB.PDBParser()
    #parser = PDB.MMCIFParser() #in case it's a cif file

    structure = parser.get_structure("input", pdbfixedfilename)

    #print(dir(structure))

    natoms = sum(1 for _ in structure.get_atoms())

    #print("Writing output")
    outputhandle = open(xyzoutfilename, "w")
    outputhandle.write("""%d
    empty line\n""" % (natoms))

    for atom in structure.get_atoms():
        element = atom.element
        coords = atom.get_coord()
        outputhandle.write("%s     %.3f     %.3f     %.3f\n" %
                           (element, coords[0], coords[1], coords[2]))
    outputhandle.close()
    if not keepIntermediate:
        os.remove(pdbfixedfilename)
Ejemplo n.º 8
0
    def _geometry_forward(self, topology_proposal, old_sampler_state):
        """
        Run geometry engine to propose new positions and compute logP

        Parameters
        ----------
        topology_proposal : TopologyProposal
            Contains old/new Topology and System objects and atom mappings.
        old_sampler_state : openmmtools.states.SamplerState
            Configurational properties of the old system atoms.

        Returns
        -------
        new_sampler_state : openmmtools.states.SamplerState
            Configurational properties of new atoms proposed by geometry engine calculation.
        geometry_logp_propose : float
            The log probability of the forward-only proposal
        """
        if self.verbose: print("Geometry engine proposal...")
        # Generate coordinates for new atoms and compute probability ratio of old and new probabilities.
        initial_time = time.time()
        new_positions, geometry_logp_propose = self.geometry_engine.propose(topology_proposal, old_sampler_state.positions, self.sampler.thermodynamic_state.beta)
        if self.verbose: print('proposal took %.3f s' % (time.time() - initial_time))

        if self.geometry_pdbfile is not None:
            print("Writing proposed geometry...")
            from simtk.openmm.app import PDBFile
            PDBFile.writeFile(topology_proposal.new_topology, new_positions, file=self.geometry_pdbfile)
            self.geometry_pdbfile.flush()

        new_sampler_state = SamplerState(new_positions, box_vectors=old_sampler_state.box_vectors)  

        return new_sampler_state, geometry_logp_propose
Ejemplo n.º 9
0
def add_missing_atoms(session, m, minimization_steps = 0, keep_waters = False):
    fname = m.filename
    from pdbfixer import PDBFixer
    pf = PDBFixer(filename = fname)
    pf.findMissingResidues()
    pf.findNonstandardResidues()
    pf.replaceNonstandardResidues()
    pf.findMissingAtoms()
    pf.addMissingAtoms()
    pf.removeHeterogens(keep_waters)
    pf.addMissingHydrogens(7.0)
    if minimization_steps > 0:
        minimize(pf, minimization_steps)
    from os.path import splitext
    fout = splitext(fname)[0] + '-pdbfixer.pdb'
    out = open(fout, 'w')
    from simtk.openmm.app import PDBFile
    PDBFile.writeFile(pf.topology, pf.positions, out)
    out.close()
    mfix = session.models.open([fout])[0]
    mfix.atoms.displays = True
    mfix.residues.ribbon_displays = False
    m.display = False
    log = session.logger
    log.info('Wrote %s' % fout)
Ejemplo n.º 10
0
def add_hydrogens_to_mol(mol):
    """
  Add hydrogens to a molecule object
  TODO (LESWING) see if there are more flags to add here for default
  :param mol: Rdkit Mol
  :return: Rdkit Mol
  """
    molecule_file = None
    try:
        pdbblock = Chem.MolToPDBBlock(mol)
        pdb_stringio = StringIO()
        pdb_stringio.write(pdbblock)
        pdb_stringio.seek(0)
        fixer = PDBFixer(pdbfile=pdb_stringio)
        fixer.addMissingHydrogens(7.4)

        hydrogenated_io = StringIO()
        PDBFile.writeFile(fixer.topology, fixer.positions, hydrogenated_io)
        hydrogenated_io.seek(0)
        return Chem.MolFromPDBBlock(hydrogenated_io.read(),
                                    sanitize=False,
                                    removeHs=False)
    except ValueError as e:
        logging.warning("Unable to add hydrogens", e)
        raise MoleculeLoadException(e)
    finally:
        try:
            os.remove(molecule_file)
        except (OSError, TypeError):
            pass
Ejemplo n.º 11
0
    def from_pdb(cls, path, forcefield=None, **kwargs):
        """
        Loads topology, positions and, potentially, velocities and vectors,
        from a PDB file

        Parameters
        ----------
        path : str
            Path to PDB file
        forcefields : list of str
            Paths to FFXML and/or FRCMOD forcefields. REQUIRED.

        Returns
        -------
        pdb : SystemHandler
            SystemHandler with topology, positions, and, potentially, velocities and
            box vectors. Forcefields are embedded in the `master` attribute.
        """
        pdb = PDBFile(path)
        box = kwargs.pop('box', pdb.topology.getPeriodicBoxVectors())
        positions = kwargs.pop('positions', pdb.positions)
        velocities = kwargs.pop('velocities', getattr(pdb, 'velocities', None))

        if not forcefield:
            from .md import FORCEFIELDS as forcefield
            print('INFO: Forcefields for PDB not specified. Using default:\n ',
                  ', '.join(forcefield))
        pdb.forcefield = ForceField(*list(process_forcefield(*forcefield)))

        return cls(master=pdb, topology=pdb.topology, positions=positions,
                   velocities=velocities, box=box, path=path, **kwargs)
Ejemplo n.º 12
0
def write_trajectory_dcd(netcdf_filename, topology, pdb_trajectory_filename, dcd_trajectory_filename):
    """
    Write trajectory.

    Parameters
    ----------
    netcdf_filename : str
        NetCDF filename.
    topology : Topology
        Topology object
    pdb_trajectory_filename : str
        PDB trajectory output filename
    dcd_trajectory_filename : str
        Output trajectory filename.

    """
    ncfile = netCDF4.Dataset(netcdf_filename, 'r')
    [nsamples, nstates] = ncfile.variables['logZ'].shape

    # Write reference.pdb file
    from simtk.openmm.app import PDBFile
    outfile = open(pdb_trajectory_filename, 'w')
    positions = unit.Quantity(ncfile.variables['positions'][0,:,:], unit.angstroms)
    PDBFile.writeFile(topology, positions, file=outfile)
    outfile.close()

    # TODO: Export as DCD trajectory with MDTraj
    from mdtraj.formats import DCDTrajectoryFile
    with DCDTrajectoryFile(dcd_trajectory_filename, 'w') as f:
        f.write(ncfile.variables['positions'][:,:,:])
Ejemplo n.º 13
0
def add_hydrogens_to_mol(mol):
  """
  Add hydrogens to a molecule object
  TODO (LESWING) see if there are more flags to add here for default
  :param mol: Rdkit Mol
  :return: Rdkit Mol
  """
  molecule_file = None
  try:
    pdbblock = Chem.MolToPDBBlock(mol)
    pdb_stringio = StringIO()
    pdb_stringio.write(pdbblock)
    pdb_stringio.seek(0)
    fixer = PDBFixer(pdbfile=pdb_stringio)
    fixer.addMissingHydrogens(7.4)

    hydrogenated_io = StringIO()
    PDBFile.writeFile(fixer.topology, fixer.positions, hydrogenated_io)
    hydrogenated_io.seek(0)
    return Chem.MolFromPDBBlock(
        hydrogenated_io.read(), sanitize=False, removeHs=False)
  except ValueError as e:
    logging.warning("Unable to add hydrogens", e)
    raise MoleculeLoadException(e)
  finally:
    try:
      os.remove(molecule_file)
    except (OSError, TypeError):
      pass
Ejemplo n.º 14
0
 def write_pdb(self, path):
     """
     Outputs a PDB file with the current contents of the system
     """
     if self.master is None and self.positions is None:
         raise ValueError('Topology and positions are needed to write output files.')
     with open(path, 'w') as f:
         PDBFile.writeFile(self.topology, self.positions, f)
Ejemplo n.º 15
0
 def write_pdb(self, path):
     """
     Outputs a PDB file with the current contents of the system
     """
     if self.master is None and self.positions is None:
         raise ValueError(
             'Topology and positions are needed to write output files.')
     with open(path, 'w') as f:
         PDBFile.writeFile(self.topology, self.positions, f)
Ejemplo n.º 16
0
 def _create_chain_pdb(self, topology_pdb, positions):
     dirname = os.path.dirname(__file__)
     filename = "{}.pdb".format(self.sequence_str)
     if self.forceField_str == 'OPLS-AA':
         filename = "{}_aa.pdb".format(self.sequence_str)
     file_path = os.path.join(dirname, "data/{}".format(filename))
     if not os.path.isfile(file_path) or self.overwrite_pdb:
         self.overwrite_pdb = False
         PDBFile.writeFile(topology_pdb, positions, open(file_path, 'w'))
Ejemplo n.º 17
0
 def write_header(self):
     """
     Confusingly this initializes writer as well because 
     """
     outfile = open(self.out_filepath, 'w')
     self.outfile = outfile
     cpdb = app.PDBFile(self.pdb_str)
     PDBFile.writeHeader(cpdb.topology, self.outfile)
     self.topology = cpdb.topology
     self.frame_idx = 0
Ejemplo n.º 18
0
def fix_pdb(pdb_file):
    fixer = PDBFixer(filename=pdb_file)
    fixer.findMissingResidues()
    fixer.findNonstandardResidues()
    fixer.replaceNonstandardResidues()
    fixer.removeHeterogens(True)
    fixer.findMissingAtoms()
    fixer.addMissingAtoms()
    fixer.addMissingHydrogens(7.0)
    PDBFile.writeFile(fixer.topology, fixer.positions, open(pdb_file, 'w'))
Ejemplo n.º 19
0
    def writePDBFixed(self):

        'Write the fixed (initial) structure to a pdb file.'

        from simtk.openmm.app import PDBFile

        PDBFile.writeFile(self._topology,
                          self._positions,
                          open(self.getTitle()[:-8] + 'fixed.pdb', 'w'),
                          keepIds=True)
Ejemplo n.º 20
0
    def update(self):
        """
        Update the sampler with one step of sampling.
        """
        if not self._initialized:
            self._initialize()

        if self.verbose:
            print("." * 80)
            print("MCMC sampler iteration %d" % self.iteration)

        initial_time = time.time()

        # Reset statistics
        if hasattr(self.integrator, 'setGlobalVariableByName'):
            self.integrator.setGlobalVariableByName('naccept', 0)

        # Take some steps
        self.integrator.step(self.nsteps)

        # Get new sampler state.
        self.sampler_state = SamplerState.createFromContext(self.context)

        # Report statistics
        if hasattr(self.integrator, 'getGlobalVariableByName'):
            naccept = self.integrator.getGlobalVariableByName('naccept')
            fraction_accepted = float(naccept) / float(self.nsteps)
            if self.verbose: print("Accepted %d / %d GHMC steps (%.2f%%)." % (naccept, self.nsteps, fraction_accepted * 100))

        final_time = time.time()
        elapsed_time = final_time - initial_time
        self._timing['sample positions'] = elapsed_time

        if self.verbose:
            final_energy = self.context.getState(getEnergy=True).getPotentialEnergy() * self.thermodynamic_state.beta
            print('Final energy is %12.3f kT' % (final_energy))
            print('elapsed time %8.3f s' % elapsed_time)

        if self.ncfile:
            self.ncfile.variables['positions'][self.iteration,:,:] = self.sampler_state.positions[:,:] / unit.nanometers
            for k in range(3):
                self.ncfile.variables['box_vectors'][self.iteration,k,:] = self.sampler_state.box_vectors[k,:] / unit.nanometers
            self.ncfile.variables['potential'][self.iteration] = self.thermodynamic_state.beta * self.context.getState(getEnergy=True).getPotentialEnergy()
            self.ncfile.variables['sample_positions_time'][self.iteration] = elapsed_time

        # Increment iteration count
        self.iteration += 1

        if self.verbose:
            print("." * 80)
        if self.pdbfile is not None:
            print("Writing frame...")
            from simtk.openmm.app import PDBFile
            PDBFile.writeModel(self.topology, self.sampler_state.positions, self.pdbfile, self.iteration)
            self.pdbfile.flush()
Ejemplo n.º 21
0
def save_frames_pdb(pdb, start=0, stop=0, step=1, where='./', name='frame-%s'):
    isfname = isinstance(pdb, PDBFile)
    nformat = name if not isfname else pdb.split('.pdb') + name
    nformat = (nformat if '%' in nformat else nformat + '%s') + '.pdb'
    pdbfile = pdb if isfname else PDBFile(pdb)
    topology = pdbfile.getTopology()
    stop = stop if stop else pdbfile.getNumFrames()
    for idx in range(start, stop, step):
        positions = pdbfile.getPositions(frame=stop)
        filepath = normpath(where + '/' + nformat % step)
        PDBFile.writeFile(topology, positions, filepath)
Ejemplo n.º 22
0
 def fix_pdb(self, infile, out=None, pH=7):
     with open(infile, 'r') as f:
         fixer = PDBFixer(pdbfile=f)
     fixer.findMissingResidues()
     fixer.findMissingAtoms()
     fixer.addMissingAtoms()
     fixer.addMissingHydrogens(pH=pH)
     if out is None:
         out = '{0[0]}{1}{0[1]}'.format(os.path.splitext(infile), '_fixed')
     with open(out, 'w') as f:
         PDBFile.writeFile(fixer.topology, fixer.positions, f)
Ejemplo n.º 23
0
def minimize_energy(pdb: PDBFile, simulation: Simulation, args: ListOfArgs):
    if args.MINIMIZE:
        print('Energy minimizing...')
        simulation.minimizeEnergy(tolerance=0.01 * simtk.unit.kilojoules_per_mole)
        if not args.MINIMIZED_FILE:
            base, _ = os.path.splitext(args.INITIAL_STRUCTURE_PATH)
            minimized_file_name = f'{base}_min.pdb'
        else:
            minimized_file_name = args.MINIMIZED_FILE  # TODO: Nasty fix
        print(f'  Saving minimized structure in {minimized_file_name}')
        state = simulation.context.getState(getPositions=True)
        PDBFile.writeFile(pdb.topology, state.getPositions(), open(minimized_file_name, 'w'))
Ejemplo n.º 24
0
 def add_hydrogens_by_openmm(self):
     from simtk.openmm.app import ForceField, Modeller, PDBFile
     from pdbfixer import PDBFixer
     fixer = PDBFixer(self.name)
     field = ForceField('amber99sb.xml', 'tip3p.xml')
     fixer.findMissingResidues()
     fixer.findMissingAtoms()
     fixer.addMissingAtoms()
     fixer.addMissingHydrogens(7.0)
     modeller = Modeller(fixer.topology, fixer.positions)
     modeller.addHydrogens(forcefield=field)
     modeller.deleteWater()
     PDBFile.writeModel(modeller.topology, modeller.positions, open(self.shotname+'_h.pdb', 'w'))
Ejemplo n.º 25
0
    def report(self, simulation, state):
        """Generate a report.

        Parameters:
         - simulation (Simulation) The Simulation to generate a report for
         - state (State) The current state of the simulation
        """
        if self._nextModel == 0:
            PDBFile.writeHeader(simulation.topology, self._out)
            self._topology = simulation.topology
            self._nextModel += 1
        PDBFile.writeModel(simulation.topology, state.getPositions(), self._out, self._nextModel)
        self._nextModel += 1
Ejemplo n.º 26
0
    def write_frame(self, x):
        """
        Write a coordinate frame

        Parameters
        ----------
        x: np.ndarray
            coordinates in units of angstroms

        """
        # if self.outfile is None:
        # raise ValueError("remember to call write_header first")
        self.frame_idx += 1
        PDBFile.writeModel(self.topology, x, self.out_handle, self.frame_idx)
Ejemplo n.º 27
0
    def report(self, simulation, state):
        """Generate a report.

        Parameters:
         - simulation (Simulation) The Simulation to generate a report for
         - state (State) The current state of the simulation
        """
        if self._nextModel == 0:
            PDBFile.writeHeader(simulation.topology, self._out)
            self._topology = simulation.topology
            self._nextModel += 1
        PDBFile.writeModel(simulation.topology, state.getPositions(),
                           self._out, self._nextModel)
        self._nextModel += 1
Ejemplo n.º 28
0
def pdbfixerTransform(filename, replace_nonstandard_residues,
                      add_missing_residues, add_missing_atoms):
    """
    Adds missing residues and/or missing atoms to a PDB file.

    Parameters
    ----------
    filename : str
        Name of the input PDB file.
    replace_nonstandard_residues : bool
        Whether to replace nonstandard residues with their standard equivalents.
    add_missing_residues : bool
        Whether to add missing residues.
    add_missing_atoms : bool
        Whether to add missing atoms.

    Returns
    -------
    filename_output : str
        Absolute path to the modified file.
    """
    if not replace_nonstandard_residues and not add_missing_atoms \
            and not add_missing_residues:
        return _os.path.abspath(filename)

    fix = _pdbfix.PDBFixer(filename=filename)

    if replace_nonstandard_residues:
        fix.findNonstandardResidues()
        fix.replaceNonstandardResidues()

    if add_missing_residues:
        fix.findMissingResidues()
    else:
        fix.missingResidues = []

    if add_missing_atoms:
        fix.findMissingAtoms()
    else:
        fix.missingAtoms = []
        fix.missingTerminals = []

    fix.addMissingAtoms()

    filename_output = _os.path.splitext(filename)[0] + "_pdbfixer.pdb"
    _PDBFile.writeFile(fix.topology, fix.positions, open(filename_output, "w"))

    return fixPDBFixerPDB(filename_output, filename,
                          replace_nonstandard_residues, add_missing_residues,
                          add_missing_atoms, filename_output)
Ejemplo n.º 29
0
def cleanPdb(pdb_list, chain=None, fromFolder=None, toFolder="cleaned_pdbs"):
    os.system(f"mkdir -p {toFolder}")
    for pdb_id in pdb_list:
        # print(chain)
        pdb = f"{pdb_id.lower()[:4]}"
        pdbFile = pdb + ".pdb"
        if fromFolder is None:
            fromFile = os.path.join("original_pdbs", pdbFile)
        elif fromFolder[:4] == ".pdb":
            fromFile = fromFolder
        else:
            fromFile = os.path.join(fromFolder, pdbFile)
        if chain is None:  # None mean deafult is chain A unless specified.
            if len(pdb_id) == 5:
                Chosen_chain = pdb_id[4].upper()
            else:
                assert (len(pdb_id) == 4)
                Chosen_chain = "A"
        elif chain == "-1" or chain == -1:
            Chosen_chain = getAllChains(fromFile)
        else:
            Chosen_chain = chain
        # clean pdb
        fixer = PDBFixer(filename=fromFile)
        # remove unwanted chains
        chains = list(fixer.topology.chains())
        chains_to_remove = [
            i for i, x in enumerate(chains) if x.id not in Chosen_chain
        ]
        fixer.removeChains(chains_to_remove)

        fixer.findMissingResidues()
        # add missing residues in the middle of a chain, not ones at the start or end of the chain.
        chains = list(fixer.topology.chains())
        keys = fixer.missingResidues.keys()
        # print(keys)
        for key in list(keys):
            chain_tmp = chains[key[0]]
            if key[1] == 0 or key[1] == len(list(chain_tmp.residues())):
                del fixer.missingResidues[key]

        fixer.findNonstandardResidues()
        fixer.replaceNonstandardResidues()
        fixer.removeHeterogens(keepWater=False)
        fixer.findMissingAtoms()
        fixer.addMissingAtoms()
        fixer.addMissingHydrogens(7.0)
        PDBFile.writeFile(fixer.topology, fixer.positions,
                          open(os.path.join(toFolder, pdbFile), 'w'))
Ejemplo n.º 30
0
def test_gaffResidueTemplateGenerator():
    """
    Test the GAFF residue template generator.
    """

    #
    # Test where we generate parameters for only a ligand.
    #

    # Load the PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator
    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    # Check potential is finite.
    check_potential_is_finite(system, pdb.positions)
    # Check energy matches prmtop route.
    check_energy_components_vs_prmtop(
        prmtop=utils.get_data_filename('chemicals/imatinib/imatinib.prmtop'),
        inpcrd=utils.get_data_filename('chemicals/imatinib/imatinib.inpcrd'),
        system=system)

    #
    # Test where we generate parameters for only a ligand in a protein.
    #

    # Load the PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = utils.get_data_filename(
        "chemicals/proteins/T4-lysozyme-L99A-p-xylene-implicit.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField('amber99sb.xml', gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator
    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    # Check potential is finite.
    check_potential_is_finite(system, pdb.positions)
Ejemplo n.º 31
0
    def deserialize_input(self, content):
        """Retreive the state and topology from the message content

        The message protocol tries not to pass 'data' around within the
        messages, but instead pass paths to data. So far we're only sending
        paths on the local filesystem, but we might could generalize this to
        HTTP or S3 or something later.

        The assumption that data can be passed around on the local filesystem
        shouldn't be built deep into the code at all
        """
        # todo: better name for this function?

        if content.starting_state.protocol == 'localfs':
            with open(content.starting_state.path) as f:
                self.log.info('Opening state file: %s',
                              content.starting_state.path)
                state = XmlSerializer.deserialize(f.read())
        else:
            raise ValueError('Unknown protocol')

        if content.topology_pdb.protocol == 'localfs':
            topology = PDBFile(content.topology_pdb.path).topology
        else:
            raise ValueError('Unknown protocol')

        return state, topology
def test_membraneModeller():
    # pdb file containing a solvated single lipid molecule
    pdb = PDBFile('solvated-lipid.pdb')
    modeller = Modeller(pdb.topology,pdb.positions)
    modeller.modifyTopology()
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    modeller.addHydrogens(forcefield=forcefield)

    system = forcefield.createSystem(modeller.topology,
                                     nonbondedMethod=app.PME,
                                     rigidWater=True,
                                     nonbondedCutoff=1*unit.nanometer)
    integrator = mm.VerletIntegrator(0.5*unit.femtoseconds)
    platform = mm.Platform.getPlatformByName('Reference')
    simulation = app.Simulation(modeller.topology, system, integrator, platform)
    simulation.context.setPositions(modeller.positions)
    simulation.context.setVelocitiesToTemperature(300*unit.kelvin)
    # Minimize the system after adding hydrogens
    tolerance = 0.1*unit.kilojoules_per_mole/unit.angstroms
    simulation.minimizeEnergy(tolerance=tolerance,maxIterations=200)
    simulation.reporters.append(app.StateDataReporter('relax-hydrogens.log',
                                                       1000,
                                                       step=True,
                                                       potentialEnergy=True))
    simulation.step(1000)
Ejemplo n.º 33
0
def test_membrane_modeller():
    """Test the addition of hydrogens to a solvated DPPC molecule"""
    # pdb file corresponding to a solvated lipid molecule
    pdb = PDBFile(os.path.join(os.path.dirname(__file__), '../data/dppc/solvated-dppc.pdb'))
    modeller = MembraneModeller(pdb.topology,pdb.positions)
    modeller.modify_topology()
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    modeller.addHydrogens(forcefield=forcefield)

    system = forcefield.createSystem(modeller.topology,
                                     nonbondedMethod=app.PME,
                                     rigidWater=True,
                                     nonbondedCutoff=1*unit.nanometer)
    integrator = mm.VerletIntegrator(0.5*unit.femtoseconds)
    platform = mm.Platform.getPlatformByName('Reference')
    simulation = app.Simulation(modeller.topology, system, integrator, platform)
    simulation.context.setPositions(modeller.positions)
    simulation.context.setVelocitiesToTemperature(300*unit.kelvin)
    # Minimize the system after adding hydrogens
    simulation.minimizeEnergy(maxIterations=200)
    # Run a few MD steps to check the system has no overlaps
    simulation.step(1000)
    state = simulation.context.getState(getEnergy=True)
    pe = state.getPotentialEnergy()._value
    assert pe < 0.0
Ejemplo n.º 34
0
def create_pdb_object(solute_file_path):
    file_extension = solute_file_path.split(".")[-1]
    if file_extension == "pdb":
        pdb = PDBFile(solute_file_path)
        return pdb
    else:
        raise ValueError('Unrecognised file extension: %s  -> A PDB must be given' % file_extension)
Ejemplo n.º 35
0
def test_porin_membrane_system():
    """Test the addition of a ligand to a solvated porin"""
    # pdb file corresponding to a solvated porin
    pdb = PDBFile(
        os.path.join(os.path.dirname(__file__),
                     '../data/porin/solvated-porin.pdb'))
    modeller = app.Modeller(pdb.topology, pdb.positions)
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    platform = mm.Platform.getPlatformByName('CPU')
    modeller.addHydrogens(forcefield=forcefield)
    # rigidWater False is required for ParMed to access water paramters
    system_md = forcefield.createSystem(modeller.topology,
                                        nonbondedMethod=app.PME,
                                        rigidWater=False,
                                        nonbondedCutoff=1 * unit.nanometer)
    ligand_system = PorinMembraneSystem('comp7',
                                        system_md,
                                        modeller.topology,
                                        modeller.positions,
                                        platform,
                                        tolerance=1 * unit.kilojoule /
                                        unit.mole,
                                        max_iterations=200)
    integrator = mm.LangevinIntegrator(300 * unit.kelvin,
                                       1.0 / unit.picoseconds,
                                       2 * unit.femtosecond)
    simulation = app.Simulation(ligand_system.structure.topology,
                                ligand_system.system, integrator, platform)
    simulation.context.setPositions(ligand_system.structure.positions)
    state = simulation.context.getState(getEnergy=True)
    pe = state.getPotentialEnergy()._value
    assert pe < 0.0
Ejemplo n.º 36
0
def test_build_docked_coordinates_protocol():
    """Tests docking a methanol molecule into alpha-Cyclodextrin."""

    if not has_openeye():
        pytest.skip("The `BuildDockedCoordinates` protocol requires OpenEye.")

    ligand_substance = Substance()
    ligand_substance.add_component(
        Component("CO", role=Component.Role.Ligand),
        ExactAmount(1),
    )

    # TODO: This test could likely be made substantially faster
    #       by storing the binary prepared receptor. Would this
    #       be in breach of any oe license terms?
    with tempfile.TemporaryDirectory() as temporary_directory:

        build_docked_coordinates = BuildDockedCoordinates("build_methanol")
        build_docked_coordinates.ligand_substance = ligand_substance
        build_docked_coordinates.number_of_ligand_conformers = 5
        build_docked_coordinates.receptor_coordinate_file = get_data_filename(
            "test/molecules/acd.mol2")
        build_docked_coordinates.execute(temporary_directory,
                                         ComputeResources())

        docked_pdb = PDBFile(
            build_docked_coordinates.docked_complex_coordinate_path)
        assert docked_pdb.topology.getNumResidues() == 2
Ejemplo n.º 37
0
def test_solvate_existing_structure_protocol():
    """Tests solvating a single methanol molecule in water."""

    methanol_substance = Substance()
    methanol_substance.add_component(Substance.Component('CO'),
                                     Substance.ExactAmount(1))

    water_substance = Substance()
    water_substance.add_component(Substance.Component('O'),
                                  Substance.MoleFraction(1.0))

    with tempfile.TemporaryDirectory() as temporary_directory:

        build_methanol_coordinates = BuildCoordinatesPackmol('build_methanol')
        build_methanol_coordinates.max_molecules = 1
        build_methanol_coordinates.substance = methanol_substance
        build_methanol_coordinates.execute(temporary_directory,
                                           ComputeResources())

        solvate_coordinates = SolvateExistingStructure('solvate_methanol')
        solvate_coordinates.max_molecules = 9
        solvate_coordinates.substance = water_substance
        solvate_coordinates.solute_coordinate_file = build_methanol_coordinates.coordinate_file_path
        solvate_coordinates.execute(temporary_directory, ComputeResources())
        solvated_pdb = PDBFile(solvate_coordinates.coordinate_file_path)

        assert solvated_pdb.topology.getNumResidues() == 10
Ejemplo n.º 38
0
    def _off_handler(cls, molecule, **kwargs):
        forcefield = cls._get_forcefield(**kwargs)
        topology = Topology.from_molecules(molecule)
        openmm_system = forcefield.create_openmm_system(
            topology, charge_from_molecules=[molecule])

        # ligand_pmd.title = cls.smiles

        # for i in ligand_pmd.residues:
        #     i.name = 'LIG' #XXX no longer needed when using omm_top to create parmed structure

        tmp_dir = tempfile.mkdtemp()
        # We need all molecules as both pdb files (as packmol input)
        # and mdtraj.Trajectory for restoring bonds later.
        pdb_filename = tempfile.mktemp(suffix=".pdb", dir=tmp_dir)

        # XXX legacy code for save a pdb copy for simulation box creation
        # Chem.MolToPDBFile(mol, pdb_filename)
        # from openeye import oechem # OpenEye Python toolkits
        # oechem.OEWriteMolecule( oechem.oemolostream( pdb_filename ), mol)

        # XXX swtich to off save pdb
        # ligand_pmd.save(pdb_filename, overwrite=True)
        molecule.to_file(pdb_filename, "pdb")
        omm_top = PDBFile(pdb_filename).topology
        # ligand_pmd = parmed.openmm.topsystem.load_topology(topology.to_openmm(), openmm_system, molecule._conformers[0]) #XXX off topology does not keep atom names and resnames, use omm topology instead
        ligand_pmd = parmed.openmm.topsystem.load_topology(
            omm_top, openmm_system, molecule._conformers[0])

        return pdb_filename, ligand_pmd
Ejemplo n.º 39
0
    def __init__(self, **kwargs):
        super(AlanineDipeptideExplicitSimulatedTempering, self).__init__(**kwargs)
        self.description = 'Alanine dipeptide in explicit solvent simulated tempering simulation'

        # Create topology, positions, and system.
        from openmmtools.testsystems import AlanineDipeptideExplicit
        testsystem = AlanineDipeptideExplicit(nonbondedMethod=app.CutoffPeriodic)
        self.topology = testsystem.topology
        self.positions = testsystem.positions
        self.system = testsystem.system

        # DEBUG: Write PDB
        from simtk.openmm.app import PDBFile
        outfile = open('initial.pdb', 'w')
        PDBFile.writeFile(self.topology, self.positions, outfile)
        outfile.close()

        # Add a MonteCarloBarostat
        temperature = 270 * unit.kelvin # will be replaced as thermodynamic state is updated
        pressure = 1.0 * unit.atmospheres
        barostat = openmm.MonteCarloBarostat(pressure, temperature)
        self.system.addForce(barostat)

        # Create thermodynamic states.
        Tmin = 270 * unit.kelvin
        Tmax = 600 * unit.kelvin
        ntemps = 256 # number of temperatures
        from sams import ThermodynamicState
        temperatures = unit.Quantity(np.logspace(np.log10(Tmin / unit.kelvin), np.log10(Tmax / unit.kelvin), ntemps), unit.kelvin)
        self.thermodynamic_states = [ ThermodynamicState(system=self.system, temperature=temperature, pressure=pressure) for temperature in temperatures ]

        # Create SAMS samplers
        from sams.samplers import SamplerState, MCMCSampler, ExpandedEnsembleSampler, SAMSSampler
        thermodynamic_state_index = 0 # initial thermodynamic state index
        thermodynamic_state = self.thermodynamic_states[thermodynamic_state_index]
        sampler_state = SamplerState(positions=self.positions)
        self.mcmc_sampler = MCMCSampler(sampler_state=sampler_state, thermodynamic_state=thermodynamic_state, ncfile=self.ncfile)
        #self.mcmc_sampler.pdbfile = open('output.pdb', 'w')
        self.mcmc_sampler.topology = self.topology
        self.mcmc_sampler.nsteps = 500
        self.mcmc_sampler.timestep = 2.0 * unit.femtoseconds
        self.mcmc_sampler.verbose = True
        self.exen_sampler = ExpandedEnsembleSampler(self.mcmc_sampler, self.thermodynamic_states)
        self.exen_sampler.verbose = True
        self.sams_sampler = SAMSSampler(self.exen_sampler)
        self.sams_sampler.verbose = True
Ejemplo n.º 40
0
def download_pdb(pdbid, file_pathway):
    """

    Args:
        pdbid: 4 letter string specifying the PDB ID of the file yoou want to fix
        file_pathway: a string containing the pathway specifying how you want to organize the PDB files once written

    Returns: nothing, but it does write the PDB file

    ***Note: this function does NOT fix any mistakes with the PDB file

    """

    if not os.path.exists(file_pathway):
        os.makedirs(file_pathway)
    fixer = PDBFixer(pdbid=pdbid)
    PDBFile.writeFile(fixer.topology, fixer.positions, open(os.path.join(file_pathway, '%s.pdb' % pdbid), 'w'))
Ejemplo n.º 41
0
def check_hydrogens(molecule, ID):
    # Check that Hydrogens are in structure
    if len(molecule.top.select("name == H")) == 0:
        # If absent, then add Hydrogens using the Amber99sb force-field
        try:
            from simtk.openmm.app import PDBFile, Modeller, ForceField
            pdb = PDBFile(ID + ".pdb")
            modeller = Modeller(pdb.topology, pdb.positions)
            forcefield = ForceField('amber99sb.xml','tip3p.xml')
            modeller.addHydrogens(forcefield)
            PDBFile.writeFile(modeller.topology, modeller.positions, open(ID + ".pdb", 'w'))
            molecule = md.load(ID + ".pdb").remove_solvent()
        except:
            warnings.warn("""PDB topology missing Hydrogens. Either manually add
            or install OpenMM through SIMTK to automatically correct.""")
            pass
    return molecule
Ejemplo n.º 42
0
    def report(self, simulation, state):
        """Generate a report.

        Parameters
        ----------
        simulation : Simulation
            The Simulation to generate a report for
        state : State
            The current state of the simulation
        """
        if self._nextModel == 0:
            PDBFile.writeHeader(simulation.topology, self._out)
            self._topology = simulation.topology
            self._nextModel += 1
        PDBFile.writeModel(simulation.topology, state.getPositions(), self._out, self._nextModel)
        self._nextModel += 1
        if hasattr(self._out, 'flush') and callable(self._out.flush):
            self._out.flush()
Ejemplo n.º 43
0
    def update(self):
        """
        Update the sampler with one step of sampling.
        """
        if self.verbose:
            print("-" * 80)
            print("Expanded Ensemble sampler iteration %8d" % self.iteration)
        self.update_positions()
        self.update_state()
        self.iteration += 1
        if self.verbose:
            print("-" * 80)

        if self.pdbfile is not None:
            print("Writing frame...")
            from simtk.openmm.app import PDBFile
            PDBFile.writeModel(self.topology, self.sampler.sampler_state.positions, self.pdbfile, self.iteration)
            self.pdbfile.flush()
Ejemplo n.º 44
0
    def report(self, simulation, _):
        """Generate a report.

        Parameters
        ----------
        simulation : Simulation
            The Simulation to generate a report for
        _ : State
            The current state of the simulation
        """
        state = simulation.context.getState(getPositions=True, enforcePeriodicBox=self._enforcePeriodicBox)
        if self._nextModel == 0:
            PDBFile.writeHeader(simulation.topology, self._out)
            self._topology = simulation.topology
            self._nextModel += 1
        PDBFile.writeModel(simulation.topology, state.getPositions(), self._out, self._nextModel)
        self._nextModel += 1
        if hasattr(self._out, 'flush') and callable(self._out.flush):
            self._out.flush()
Ejemplo n.º 45
0
def fix_pdb(pdb_id, pdb_file, pdb_group):
    chains_to_retain = get_required_chains(pdb_group)
    chains_to_remove = []

    for chain in PDBParser().get_structure(pdb_id, pdb_file)[0]:
        if chain.get_id() not in chains_to_retain:
            chains_to_remove.append(chain.get_id())

    fixer = PDBFixer(filename=pdb_file)

    fixer.removeChains(chainIds=chains_to_remove)

    fixer.findMissingResidues()
    fixer.findMissingAtoms()
    fixer.addMissingAtoms()
    fixer.removeHeterogens(True)

    # KeepIds flag is critical here, otherwise we loose all information binding
    pdb_file = dirname(pdb_file) + '/' + pdb_id + '.pdb'
    PDBFile.writeFile(fixer.topology, fixer.positions, open(pdb_file, 'w'), keepIds=True)

    return pdb_file
Ejemplo n.º 46
0
mcmc_sampler = MCMCSampler(sampler_state=sampler_state, thermodynamic_state=thermodynamic_state, ncfile=ncfile, platform=platform)
mcmc_sampler.timestep = timestep
mcmc_sampler.nsteps = 500
#mcmc_sampler.pdbfile = open('output.pdb', 'w') # uncomment this if you want to write a PDB trajectory as you simulate; WARNING: LARGE!
mcmc_sampler.topology = topology
mcmc_sampler.verbose = True
exen_sampler = ExpandedEnsembleSampler(mcmc_sampler, thermodynamic_states)
exen_sampler.verbose = True
sams_sampler = SAMSSampler(exen_sampler)
sams_sampler.verbose = True

# DEBUG: Write PDB of initial frame
print("Writing initial frame to 'initial.pdb'...")
from simtk.openmm.app import PDBFile
outfile = open('initial.pdb', 'w')
PDBFile.writeFile(topology, positions, outfile)
outfile.close()

# Run the simulation
print('Running simulation...')
#exen_sampler.update_scheme = 'restricted-range' # scheme for deciding which alchemical state to jump to
exen_sampler.update_scheme = 'global-jump' # scheme for deciding which alchemical state to jump to
#exen_sampler.locality = thermodynamic_state_neighbors # neighbors to examine for each state
sams_sampler.update_method = 'rao-blackwellized' # scheme for updating free energy estimates
niterations = 20000 # number of iterations to run
sams_sampler.run(niterations) # run sampler
ncfile.close()

# Analyze
from sams import analysis
# States
Ejemplo n.º 47
0
    def __init__(self, file):
        """Load a prmtop file."""
        ## The Topology read from the prmtop file
        self.topology = top = Topology()
        self.elements = []

        # Load the prmtop file

        prmtop = amber_file_parser.PrmtopLoader(file)
        self._prmtop = prmtop

        # Add atoms to the topology

        PDBFile._loadNameReplacementTables()
        lastResidue = None
        c = top.addChain()
        for index in range(prmtop.getNumAtoms()):
            resNumber = prmtop.getResidueNumber(index)
            if resNumber != lastResidue:
                lastResidue = resNumber
                resName = prmtop.getResidueLabel(iAtom=index).strip()
                if resName in PDBFile._residueNameReplacements:
                    resName = PDBFile._residueNameReplacements[resName]
                r = top.addResidue(resName, c)
                if resName in PDBFile._atomNameReplacements:
                    atomReplacements = PDBFile._atomNameReplacements[resName]
                else:
                    atomReplacements = {}
            atomName = prmtop.getAtomName(index).strip()
            if atomName in atomReplacements:
                atomName = atomReplacements[atomName]

            # Get the element from the prmtop file if available
            if prmtop.has_atomic_number:
                try:
                    element = elem.Element.getByAtomicNumber(int(prmtop._raw_data['ATOMIC_NUMBER'][index]))
                except KeyError:
                    element = None
            else:
                # Try to guess the element from the atom name.

                upper = atomName.upper()
                if upper.startswith('CL'):
                    element = elem.chlorine
                elif upper.startswith('NA'):
                    element = elem.sodium
                elif upper.startswith('MG'):
                    element = elem.magnesium
                elif upper.startswith('ZN'):
                    element = elem.zinc
                else:
                    try:
                        element = elem.get_by_symbol(atomName[0])
                    except KeyError:
                        element = None

            top.addAtom(atomName, element, r)
            self.elements.append(element)

        # Add bonds to the topology

        atoms = list(top.atoms())
        for bond in prmtop.getBondsWithH():
            top.addBond(atoms[bond[0]], atoms[bond[1]])
        for bond in prmtop.getBondsNoH():
            top.addBond(atoms[bond[0]], atoms[bond[1]])

        # Set the periodic box size.

        if prmtop.getIfBox():
            box = prmtop.getBoxBetaAndDimensions()
            top.setPeriodicBoxVectors(computePeriodicBoxVectors(*(box[1:4] + box[0:1]*3)))
Ejemplo n.º 48
0
fixer.findMissingResidues()
# only add missing residues in the middle of the chain, do not add terminal ones
chains = list(fixer.topology.chains())
keys = fixer.missingResidues.keys()
missingResidues = dict()
for key in keys:
    chain = chains[key[0]]
    if not (key[1] == 0 or key[1] == len(list(chain.residues()))):
        missingResidues[key] = fixer.missingResidues[key]
fixer.missingResidues = missingResidues

fixer.findMissingAtoms()
fixer.addMissingAtoms()

PDBFile.writeFile(fixer.topology, fixer.positions, open('4h12_fixed.pdb', 'w'))

# keep only protein and zinc ions
traj = md.load('4h12_fixed.pdb')
traj = traj.atom_slice(traj.top.select('(protein and not resname SAH) or resname ZN'))

# implement changes necessary for the use of the dummy atom Zn2+ model
# change residue name of the zincs from ZN to ZNB, and atom names from ZN to Zn
for residue in traj.top.chain(1).residues:
    residue.name = 'ZNB'
for atom in traj.top.chain(1).atoms:
    atom.name = 'Zn'
    
# change name of cysteines coordinating zincs to CYM (deprotonated cysteine)
for residue in traj.top.chain(0).residues:
    if residue.index in [86, 92, 82, 69, 54, 52, 73, 184, 233, 238, 231]:
Ejemplo n.º 49
0
    def addSolvent(self, forcefield, model='tip3p', boxSize=None, padding=None, positiveIon='Na+', negativeIon='Cl-', ionicStrength=0*molar):
        """Add solvent (both water and ions) to the model to fill a rectangular box.

        The algorithm works as follows:
        1. Water molecules are added to fill the box.
        2. Water molecules are removed if their distance to any solute atom is less than the sum of their van der Waals radii.
        3. If the solute is charged, enough positive or negative ions are added to neutralize it.  Each ion is added by
           randomly selecting a water molecule and replacing it with the ion.
        4. Ion pairs are added to give the requested total ionic strength.

        The box size can be specified in three ways.  First, you can explicitly give a box size to use.  Alternatively, you can
        give a padding distance.  The largest dimension of the solute (along the x, y, or z axis) is determined, and a cubic
        box of size (largest dimension)+2*padding is used.  Finally, if neither a box size nor a padding distance is specified,
        the existing Topology's unit cell dimensions are used.

        Parameters:
         - forcefield (ForceField) the ForceField to use for determining van der Waals radii and atomic charges
         - model (string='tip3p') the water model to use.  Supported values are 'tip3p', 'spce', 'tip4pew', and 'tip5p'.
         - boxSize (Vec3=None) the size of the box to fill with water
         - padding (distance=None) the padding distance to use
         - positiveIon (string='Na+') the type of positive ion to add.  Allowed values are 'Cs+', 'K+', 'Li+', 'Na+', and 'Rb+'
         - negativeIon (string='Cl-') the type of negative ion to add.  Allowed values are 'Cl-', 'Br-', 'F-', and 'I-'. Be aware
           that not all force fields support all ion types.
         - ionicString (concentration=0*molar) the total concentration of ions (both positive and negative) to add.  This
           does not include ions that are added to neutralize the system.
        """
        # Pick a unit cell size.

        if boxSize is not None:
            if is_quantity(boxSize):
                boxSize = boxSize.value_in_unit(nanometer)
            box = Vec3(boxSize[0], boxSize[1], boxSize[2])*nanometer
        elif padding is not None:
            maxSize = max(max((pos[i] for pos in self.positions))-min((pos[i] for pos in self.positions)) for i in range(3))
            box = (maxSize+2*padding)*Vec3(1, 1, 1)
        else:
            box = self.topology.getUnitCellDimensions()
            if box is None:
                raise ValueError('Neither the box size nor padding was specified, and the Topology does not define unit cell dimensions')
        box = box.value_in_unit(nanometer)
        invBox = Vec3(1.0/box[0], 1.0/box[1], 1.0/box[2])

        # Identify the ion types.

        posIonElements = {'Cs+':elem.cesium, 'K+':elem.potassium, 'Li+':elem.lithium, 'Na+':elem.sodium, 'Rb+':elem.rubidium}
        negIonElements = {'Cl-':elem.chlorine, 'Br-':elem.bromine, 'F-':elem.fluorine, 'I-':elem.iodine}
        if positiveIon not in posIonElements:
            raise ValueError('Illegal value for positive ion: %s' % positiveIon)
        if negativeIon not in negIonElements:
            raise ValueError('Illegal value for negative ion: %s' % negativeIon)
        positiveElement = posIonElements[positiveIon]
        negativeElement = negIonElements[negativeIon]

        # Load the pre-equilibrated water box.

        vdwRadiusPerSigma = 0.5612310241546864907
        if model == 'tip3p':
            waterRadius = 0.31507524065751241*vdwRadiusPerSigma
        elif model == 'spce':
            waterRadius = 0.31657195050398818*vdwRadiusPerSigma
        elif model == 'tip4pew':
            waterRadius = 0.315365*vdwRadiusPerSigma
        elif model == 'tip5p':
            waterRadius = 0.312*vdwRadiusPerSigma
        else:
            raise ValueError('Unknown water model: %s' % model)
        pdb = PDBFile(os.path.join(os.path.dirname(__file__), 'data', model+'.pdb'))
        pdbTopology = pdb.getTopology()
        pdbPositions = pdb.getPositions().value_in_unit(nanometer)
        pdbResidues = list(pdbTopology.residues())
        pdbBoxSize = pdbTopology.getUnitCellDimensions().value_in_unit(nanometer)

        # Have the ForceField build a System for the solute from which we can determine van der Waals radii.

        system = forcefield.createSystem(self.topology)
        nonbonded = None
        for i in range(system.getNumForces()):
            if isinstance(system.getForce(i), NonbondedForce):
                nonbonded = system.getForce(i)
        if nonbonded is None:
            raise ValueError('The ForceField does not specify a NonbondedForce')
        cutoff = [nonbonded.getParticleParameters(i)[1].value_in_unit(nanometer)*vdwRadiusPerSigma+waterRadius for i in range(system.getNumParticles())]
        waterCutoff = waterRadius
        if len(cutoff) == 0:
            maxCutoff = waterCutoff
        else:
            maxCutoff = max(waterCutoff, max(cutoff))

        # Copy the solute over.

        newTopology = Topology()
        newTopology.setUnitCellDimensions(box)
        newAtoms = {}
        newPositions = []*nanometer
        for chain in self.topology.chains():
            newChain = newTopology.addChain()
            for residue in chain.residues():
                newResidue = newTopology.addResidue(residue.name, newChain)
                for atom in residue.atoms():
                    newAtom = newTopology.addAtom(atom.name, atom.element, newResidue)
                    newAtoms[atom] = newAtom
                    newPositions.append(deepcopy(self.positions[atom.index]))
        for bond in self.topology.bonds():
            newTopology.addBond(newAtoms[bond[0]], newAtoms[bond[1]])

        # Sort the solute atoms into cells for fast lookup.

        if len(self.positions) == 0:
            positions = []
        else:
            positions = self.positions.value_in_unit(nanometer)
        cells = {}
        numCells = tuple((max(1, int(floor(box[i]/maxCutoff))) for i in range(3)))
        cellSize = tuple((box[i]/numCells[i] for i in range(3)))
        for i in range(len(positions)):
            cell = tuple((int(floor(positions[i][j]/cellSize[j]))%numCells[j] for j in range(3)))
            if cell in cells:
                cells[cell].append(i)
            else:
                cells[cell] = [i]

        # Create a generator that loops over atoms close to a position.

        def neighbors(pos):
            centralCell = tuple((int(floor(pos[i]/cellSize[i])) for i in range(3)))
            offsets = (-1, 0, 1)
            for i in offsets:
                for j in offsets:
                    for k in offsets:
                        cell = ((centralCell[0]+i+numCells[0])%numCells[0], (centralCell[1]+j+numCells[1])%numCells[1], (centralCell[2]+k+numCells[2])%numCells[2])
                        if cell in cells:
                            for atom in cells[cell]:
                                yield atom

        # Define a function to compute the distance between two points, taking periodic boundary conditions into account.

        def periodicDistance(pos1, pos2):
            delta = pos1-pos2
            delta = [delta[i]-floor(delta[i]*invBox[i]+0.5)*box[i] for i in range(3)]
            return norm(delta)

        # Find the list of water molecules to add.

        newChain = newTopology.addChain()
        if len(positions) == 0:
            center = Vec3(0, 0, 0)
        else:
            center = [(max((pos[i] for pos in positions))+min((pos[i] for pos in positions)))/2 for i in range(3)]
            center = Vec3(center[0], center[1], center[2])
        numBoxes = [int(ceil(box[i]/pdbBoxSize[i])) for i in range(3)]
        addedWaters = []
        for boxx in range(numBoxes[0]):
            for boxy in range(numBoxes[1]):
                for boxz in range(numBoxes[2]):
                    offset = Vec3(boxx*pdbBoxSize[0], boxy*pdbBoxSize[1], boxz*pdbBoxSize[2])
                    for residue in pdbResidues:
                        oxygen = [atom for atom in residue.atoms() if atom.element == elem.oxygen][0]
                        atomPos = pdbPositions[oxygen.index]+offset
                        if not any((atomPos[i] > box[i] for i in range(3))):
                            # This molecule is inside the box, so see how close to it is to the solute.

                            atomPos += center-box/2
                            for i in neighbors(atomPos):
                                if periodicDistance(atomPos, positions[i]) < cutoff[i]:
                                    break
                            else:
                                # Record this water molecule as one to add.

                                addedWaters.append((residue.index, atomPos))

        # There could be clashes between water molecules at the box edges.  Find ones to remove.

        upperCutoff = center+box/2-Vec3(waterCutoff, waterCutoff, waterCutoff)
        lowerCutoff = center-box/2+Vec3(waterCutoff, waterCutoff, waterCutoff)
        lowerSkinPositions = [pos for index, pos in addedWaters if pos[0] < lowerCutoff[0] or pos[1] < lowerCutoff[1] or pos[2] < lowerCutoff[2]]
        filteredWaters = []
        cells = {}
        for i in range(len(lowerSkinPositions)):
            cell = tuple((int(floor(lowerSkinPositions[i][j]/cellSize[j]))%numCells[j] for j in range(3)))
            if cell in cells:
                cells[cell].append(i)
            else:
                cells[cell] = [i]
        for entry in addedWaters:
            pos = entry[1]
            if pos[0] < upperCutoff[0] and pos[1] < upperCutoff[1] and pos[2] < upperCutoff[2]:
                filteredWaters.append(entry)
            else:
                if not any((periodicDistance(lowerSkinPositions[i], pos) < waterCutoff and norm(lowerSkinPositions[i]-pos) > waterCutoff for i in neighbors(pos))):
                    filteredWaters.append(entry)
        addedWaters = filteredWaters

        # Add ions to neutralize the system.

        totalCharge = int(floor(0.5+sum((nonbonded.getParticleParameters(i)[0].value_in_unit(elementary_charge) for i in range(system.getNumParticles())))))
        if abs(totalCharge) > len(addedWaters):
            raise Exception('Cannot neutralize the system because the charge is greater than the number of available positions for ions')
        def addIon(element):
            # Replace a water by an ion.
            index = random.randint(0, len(addedWaters)-1)
            newResidue = newTopology.addResidue(element.symbol.upper(), newChain)
            newTopology.addAtom(element.symbol, element, newResidue)
            newPositions.append(addedWaters[index][1]*nanometer)
            del addedWaters[index]
        for i in range(abs(totalCharge)):
            addIon(positiveElement if totalCharge < 0 else negativeElement)

        # Add ions based on the desired ionic strength.

        numIons = len(addedWaters)*ionicStrength/(55.4*molar) # Pure water is about 55.4 molar (depending on temperature)
        numPairs = int(floor(numIons/2+0.5))
        for i in range(numPairs):
            addIon(positiveElement)
        for i in range(numPairs):
            addIon(negativeElement)

        # Add the water molecules.

        for index, pos in addedWaters:
            newResidue = newTopology.addResidue(residue.name, newChain)
            residue = pdbResidues[index]
            oxygen = [atom for atom in residue.atoms() if atom.element == elem.oxygen][0]
            oPos = pdbPositions[oxygen.index]
            molAtoms = []
            for atom in residue.atoms():
                molAtoms.append(newTopology.addAtom(atom.name, atom.element, newResidue))
                newPositions.append((pos+pdbPositions[atom.index]-oPos)*nanometer)
            for atom1 in molAtoms:
                if atom1.element == elem.oxygen:
                    for atom2 in molAtoms:
                        if atom2.element == elem.hydrogen:
                            newTopology.addBond(atom1, atom2)
        newTopology.setUnitCellDimensions(deepcopy(box)*nanometer)
        self.topology = newTopology
        self.positions = newPositions
Ejemplo n.º 50
0
def run(options):
        fixer = PDBFixer(options['pdb'])
        fixer.addMissingHydrogens(7.0)
        fixer.addSolvent(boxSize=Vec3(2.62,2.62,2.62)*nanometers, padding=None, 
                    positiveIon='Na+', negativeIon='Cl-', ionicStrength=0.0*molar)
        PDBFile.writeFile(fixer.topology, fixer.positions, open(options['outfile'], 'w'))
Ejemplo n.º 51
0
 def __del__(self):
     if self._topology is not None:
         PDBFile.writeFooter(self._topology, self._out)
     self._out.close()
Ejemplo n.º 52
0
    def __init__(self, file, periodicBoxVectors=None, unitCellDimensions=None, includeDir=None, defines=None):
        """Load a top file.

        Parameters
        ----------
        file : str
            the name of the file to load
        periodicBoxVectors : tuple of Vec3=None
            the vectors defining the periodic box
        unitCellDimensions : Vec3=None
            the dimensions of the crystallographic unit cell.  For
            non-rectangular unit cells, specify periodicBoxVectors instead.
        includeDir : string=None
            A directory in which to look for other files included from the
            top file. If not specified, we will attempt to locate a gromacs
            installation on your system. When gromacs is installed in
            /usr/local, this will resolve to /usr/local/gromacs/share/gromacs/top
        defines : dict={}
            preprocessor definitions that should be predefined when parsing the file
         """
        if includeDir is None:
            includeDir = _defaultGromacsIncludeDir()
        self._includeDirs = (os.path.dirname(file), includeDir)
        # Most of the gromacs water itp files for different forcefields,
        # unless the preprocessor #define FLEXIBLE is given, don't define
        # bonds between the water hydrogen and oxygens, but only give the
        # constraint distances and exclusions.
        self._defines = OrderedDict()
        self._defines['FLEXIBLE'] = True
        self._genpairs = True
        if defines is not None:
            for define, value in defines.iteritems():
                self._defines[define] = value

        # Parse the file.

        self._currentCategory = None
        self._ifStack = []
        self._elseStack = []
        self._moleculeTypes = {}
        self._molecules = []
        self._currentMoleculeType = None
        self._atomTypes = {}
        self._bondTypes= {}
        self._angleTypes = {}
        self._dihedralTypes = {}
        self._implicitTypes = {}
        self._pairTypes = {}
        self._cmapTypes = {}
        self._processFile(file)

        # Create the Topology from it.

        top = Topology()
        ## The Topology read from the prmtop file
        self.topology = top
        if periodicBoxVectors is not None:
            if unitCellDimensions is not None:
                raise ValueError("specify either periodicBoxVectors or unitCellDimensions, but not both")
            top.setPeriodicBoxVectors(periodicBoxVectors)
        else:
            top.setUnitCellDimensions(unitCellDimensions)
        PDBFile._loadNameReplacementTables()
        for moleculeName, moleculeCount in self._molecules:
            if moleculeName not in self._moleculeTypes:
                raise ValueError("Unknown molecule type: "+moleculeName)
            moleculeType = self._moleculeTypes[moleculeName]
            if moleculeCount > 0 and moleculeType.has_virtual_sites:
                raise ValueError('Virtual sites not yet supported by Gromacs parsers')

            # Create the specified number of molecules of this type.

            for i in range(moleculeCount):
                atoms = []
                lastResidue = None
                c = top.addChain()
                for index, fields in enumerate(moleculeType.atoms):
                    resNumber = fields[2]
                    if resNumber != lastResidue:
                        lastResidue = resNumber
                        resName = fields[3]
                        if resName in PDBFile._residueNameReplacements:
                            resName = PDBFile._residueNameReplacements[resName]
                        r = top.addResidue(resName, c)
                        if resName in PDBFile._atomNameReplacements:
                            atomReplacements = PDBFile._atomNameReplacements[resName]
                        else:
                            atomReplacements = {}
                    atomName = fields[4]
                    if atomName in atomReplacements:
                        atomName = atomReplacements[atomName]

                    # Try to guess the element.

                    upper = atomName.upper()
                    if upper.startswith('CL'):
                        element = elem.chlorine
                    elif upper.startswith('NA'):
                        element = elem.sodium
                    elif upper.startswith('MG'):
                        element = elem.magnesium
                    else:
                        try:
                            element = elem.get_by_symbol(atomName[0])
                        except KeyError:
                            element = None
                    atoms.append(top.addAtom(atomName, element, r))

                # Add bonds to the topology

                for fields in moleculeType.bonds:
                    top.addBond(atoms[int(fields[0])-1], atoms[int(fields[1])-1])
Ejemplo n.º 53
0
    def __init__(self, **kwargs):
        super(LoopSoftening, self).__init__(**kwargs)
        self.description = 'Alchemical Loop Softening script'

        padding = 9.0*unit.angstrom
        explicit_solvent_model = 'tip3p'
        setup_path = 'data/mtor'

        # Create topology, positions, and system.
        from pkg_resources import resource_filename
        gaff_xml_filename = resource_filename('sams', 'data/gaff.xml')
        system_generators = dict()
        ffxmls = [gaff_xml_filename, 'amber99sbildn.xml', 'tip3p.xml']
        forcefield_kwargs={ 'nonbondedMethod' : app.CutoffPeriodic, 'nonbondedCutoff' : 9.0 * unit.angstrom, 'implicitSolvent' : None, 'constraints' : app.HBonds, 'rigidWater' : True }

        # Load topologies and positions for all components
        print('Creating mTOR test system...')
        forcefield = app.ForceField(*ffxmls)
        from simtk.openmm.app import PDBFile, Modeller
        pdb_filename = resource_filename('sams', os.path.join(setup_path, 'mtor_pdbfixer_apo.pdb'))

        pdbfile = PDBFile(pdb_filename)
        modeller = app.Modeller(pdbfile.topology, pdbfile.positions)
        print('Adding solvent...')
        modeller.addSolvent(forcefield, model=explicit_solvent_model, padding=padding)
        self.topology = modeller.getTopology()
        self.positions = modeller.getPositions()
        print('Creating system...')
        self.system = forcefield.createSystem(self.topology, **forcefield_kwargs)

        # DEBUG: Write PDB
        outfile = open('initial.pdb', 'w')
        PDBFile.writeFile(self.topology, self.positions, outfile)
        outfile.close()

        # Atom Selection using MDtraj
        res_pairs = [[403, 483], [1052, 1109]]
        t = md.load(pdb_filename)
        alchemical_atoms = set()
        for x in res_pairs:
            start = min(t.top.select('residue %s' % min(x)))
            end = max(t.top.select('residue %s' % max(x))) + 1
            alchemical_atoms.union(set(range(start, end)))


        # Create thermodynamic states.
        print('Creating alchemically-modified system...')
        temperature = 300 * unit.kelvin
        pressure = 1.0 * unit.atmospheres

        from alchemy import AbsoluteAlchemicalFactory
        factory = AbsoluteAlchemicalFactory(self.system, ligand_atoms=alchemical_atoms, annihilate_electrostatics=True,
                                            alchemical_torsions=True, annihilate_sterics=True,
                                            softcore_beta=0.0)  # turn off softcore electrostatics
        self.system = factory.createPerturbedSystem()
        print('Setting up alchemical intermediates...')
        from sams import ThermodynamicState
        self.thermodynamic_states = list()
        for state in range(26):
            parameters = {'lambda_sterics' : 1.0, 'lambda_electrostatics' : (1.0 - float(state)/25.0) }
            self.thermodynamic_states.append( ThermodynamicState(system=self.system, temperature=temperature,
                                                                 parameters=parameters) )
        for state in range(1,26):
            parameters = {'lambda_sterics' : (1.0 - float(state)/25.0), 'lambda_electrostatics' : 0.0 }
            self.thermodynamic_states.append( ThermodynamicState(system=self.system, temperature=temperature,
                                                                 parameters=parameters) )

        #minimize(self.system, self.positions)
        minimize(self.system)

        # Create SAMS samplers
        print('Setting up samplers...')
        from sams.samplers import SamplerState, MCMCSampler, ExpandedEnsembleSampler, SAMSSampler
        thermodynamic_state_index = 0  # initial thermodynamic state index
        thermodynamic_state = self.thermodynamic_states[thermodynamic_state_index]
        sampler_state = SamplerState(positions=self.system.positions)
        self.mcmc_sampler = MCMCSampler(sampler_state=sampler_state, thermodynamic_state=thermodynamic_state,
                                        ncfile=self.ncfile)
        self.mcmc_sampler.pdbfile = open('output.pdb', 'w')
        self.mcmc_sampler.topology = self.topology
        self.mcmc_sampler.verbose = True
        self.exen_sampler = ExpandedEnsembleSampler(self.mcmc_sampler, self.thermodynamic_states)
        self.exen_sampler.verbose = True
        self.sams_sampler = SAMSSampler(self.exen_sampler)
        self.sams_sampler.verbose = True
Ejemplo n.º 54
0
nsteps = 5 # number of timesteps per iteration
niterations = 500 # number of iterations
mctrials = 10 # number of Monte Carlo trials per iteration
nsalt = 0 # current number of salt pairs
tol = 1e-6 # constraint tolerance

# Determine number of molecules
nmolecules = 0
for residue in topology.residues():
    nmolecules += 1
print('system originally has %d water molecules' % nmolecules)

# Open PDB file for writing.
from simtk.openmm.app import PDBFile
pdbfile = open('output.pdb', 'w')
PDBFile.writeHeader(topology, file=pdbfile)
PDBFile.writeModel(topology, positions, file=pdbfile, modelIndex=0)

# Simulate
for iteration in range(niterations):
    print('iteration %5d / %5d' % (iteration, niterations))

    # Create a simulation
    from openmmtools.integrators import VelocityVerletIntegrator
    integrator = VelocityVerletIntegrator(timestep)
    integrator.setConstraintTolerance(tol)
    context = openmm.Context(system, integrator)
    context.setPositions(positions)

    # Propagate dynamics at constant counterion number.
    print('propagating dynamics for %d steps...' % nsteps)
Ejemplo n.º 55
0
    def __init__(self, alchemical_protocol='two-phase', nlambda=50, **kwargs):
        """
        Create an alchemical free energy calculation SAMS test system from the provided system.

        Parameters
        ----------
        alchemical_protocol : str, optional, default='two-phase'
            Alchemical protocol scheme to use. ['two-phase', 'fused']
        nlambda : int, optional, default=50
            Number of alchemical states.

        """
        super(AlchemicalSAMSTestSystem, self).__init__(**kwargs)
        self.description = 'Alchemical SAMS test system'
        self.alchemical_protocol = alchemical_protocol

        if not (hasattr(self, 'topology') and hasattr(self, 'system') and hasattr(self, 'positions') and hasattr(self, 'alchemical_atoms')):
            raise Exception("%s: 'topology', 'system', 'positions', and 'alchemical_atoms' properties must be defined!" % self.__class__.__name__)
        if not hasattr(self, 'temperature'):
            self.temperature = 300 * unit.kelvin
        if not hasattr(self, 'temperature'):
            self.temperature = 300 * unit.kelvin
        if not hasattr(self, 'pressure'):
            self.pressure = None

        # Add a MonteCarloBarostat if system does not have one
        has_barostat = False
        for force in self.system.getForces():
            if force.__class__.__name__ in ['MonteCarloBarostat', 'MonteCarloAnisotropicBarostat']:
                has_barostat = True
        if (self.pressure is not None) and (not has_barostat):
            barostat = openmm.MonteCarloBarostat(self.pressure, self.temperature)
            self.system.addForce(barostat)

        # Create alchemically-modified system and populate thermodynamic states.
        from alchemy import AbsoluteAlchemicalFactory
        from sams import ThermodynamicState
        self.thermodynamic_states = list()
        if alchemical_protocol == 'fused':
            factory = AbsoluteAlchemicalFactory(self.system, ligand_atoms=self.alchemical_atoms, annihilate_electrostatics=True, annihilate_sterics=False)
            self.system = factory.createPerturbedSystem()
            from sams import ThermodynamicState
            alchemical_lambdas = np.linspace(1.0, 0.0, nlambda)
            for alchemical_lambda in alchemical_lambdas:
                parameters = {'lambda_sterics' : alchemical_lambda, 'lambda_electrostatics' : alchemical_lambda}
                self.thermodynamic_states.append( ThermodynamicState(system=self.system, temperature=self.temperature, pressure=self.pressure, parameters=parameters) )
        elif alchemical_protocol == 'two-phase':
            factory = AbsoluteAlchemicalFactory(self.system, ligand_atoms=self.alchemical_atoms, annihilate_electrostatics=True, annihilate_sterics=False, softcore_beta=0.0) # turn off softcore electrostatics
            self.system = factory.createPerturbedSystem()
            nelec = int(nlambda/2.0)
            nvdw = nlambda - nelec
            for state in range(nelec+1):
                parameters = {'lambda_sterics' : 1.0, 'lambda_electrostatics' : (1.0 - float(state)/float(nelec)) }
                self.thermodynamic_states.append( ThermodynamicState(system=self.system, temperature=self.temperature, pressure=self.pressure, parameters=parameters) )
            for state in range(1,nvdw+1):
                parameters = {'lambda_sterics' : (1.0 - float(state)/float(nvdw)), 'lambda_electrostatics' : 0.0 }
                self.thermodynamic_states.append( ThermodynamicState(system=self.system, temperature=self.temperature, pressure=self.pressure, parameters=parameters) )
        else:
            raise Exception("'alchemical_protocol' must be one of ['two-phase', 'fused']; scheme '%s' unknown." % alchemical_protocol)

        # Create SAMS samplers
        print('Setting up samplers...')
        from sams.samplers import SamplerState, MCMCSampler, ExpandedEnsembleSampler, SAMSSampler
        thermodynamic_state_index = 0 # initial thermodynamic state index
        thermodynamic_state = self.thermodynamic_states[thermodynamic_state_index]
        sampler_state = SamplerState(positions=self.positions)
        self.mcmc_sampler = MCMCSampler(sampler_state=sampler_state, thermodynamic_state=thermodynamic_state, ncfile=self.ncfile)
        self.mcmc_sampler.timestep = 2.0 * unit.femtoseconds
        self.mcmc_sampler.nsteps = 500
        #self.mcmc_sampler.pdbfile = open('output.pdb', 'w')
        self.mcmc_sampler.topology = self.topology
        self.mcmc_sampler.verbose = True
        self.exen_sampler = ExpandedEnsembleSampler(self.mcmc_sampler, self.thermodynamic_states)
        self.exen_sampler.verbose = True
        self.sams_sampler = SAMSSampler(self.exen_sampler)
        self.sams_sampler.verbose = True

        # DEBUG: Write PDB of initial frame
        from simtk.openmm.app import PDBFile
        outfile = open('initial.pdb', 'w')
        PDBFile.writeFile(self.topology, self.positions, outfile)
        outfile.close()
Ejemplo n.º 56
0
    return

#
# TEST HARNESS
#

if __name__ == '__main__':

    # Read OpenMM System and coordinates.
    from simtk import openmm
    from simtk import unit
    system = openmm.XmlSerializer.deserialize(_readFileContents('explicit-system.xml'))
    state = openmm.XmlSerializer.deserialize(_readFileContents('explicit-state.xml'))

    # Read explicitly solvated PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = 'explicit-refined.pdb'
    pdbfile = PDBFile(pdb_filename)
    topology = pdbfile.getTopology()

    # Create AMBER input files.
    prmtop_filename = 'amber.prmtop'
    inpcrd_filename = 'amber.crd'
    openmm_forcefields_to_use = ['amber99sbildn.xml', 'tip3p.xml']
    amber_forcefield_to_use = '/mnt/b/projects/sciteam/jn6/GIT/amber-gnu/dat/leap/cmd/oldff/leaprc.ff99SBildn'
    createAmberInputFiles(topology, system, state, openmm_forcefields_to_use, amber_forcefield_to_use, prmtop_filename, inpcrd_filename, verbose=True)

    # Run dynamics.
    ntimesteps = 5000
    run_pmemd_cuda(ntimesteps, verbose=True)
Ejemplo n.º 57
0
    def __init__(self, file, unitCellDimensions=None, includeDir='/usr/local/gromacs/share/gromacs/top', defines={}):
        """Load a top file.

        Parameters:
         - file (string) the name of the file to load
         - unitCellDimensions (Vec3=None) the dimensions of the crystallographic unit cell
         - includeDir (string=/usr/local/gromacs/share/gromacs/top) a directory in which to look for other files
           included from the top file
         - defines (map={}) preprocessor definitions that should be predefined when parsing the file
         """
        self._includeDirs = (os.path.dirname(file), includeDir)
        self._defines = defines

        # Parse the file.

        self._currentCategory = None
        self._ifStack = []
        self._moleculeTypes = {}
        self._molecules = []
        self._currentMoleculeType = None
        self._atomTypes = {}
        self._bondTypes= {}
        self._angleTypes = {}
        self._dihedralTypes = {}
        self._implicitTypes = {}
        self._pairTypes = {}
        self._cmapTypes = {}
        self._processFile(file)

        # Create the Topology from it.

        top = Topology()
        ## The Topology read from the prmtop file
        self.topology = top
        top.setUnitCellDimensions(unitCellDimensions)
        PDBFile._loadNameReplacementTables()
        for moleculeName, moleculeCount in self._molecules:
            if moleculeName not in self._moleculeTypes:
                raise ValueError("Unknown molecule type: "+moleculeName)
            moleculeType = self._moleculeTypes[moleculeName]

            # Create the specified number of molecules of this type.

            for i in range(moleculeCount):
                atoms = []
                lastResidue = None
                c = top.addChain()
                for index, fields in enumerate(moleculeType.atoms):
                    resNumber = fields[2]
                    if resNumber != lastResidue:
                        lastResidue = resNumber
                        resName = fields[3]
                        if resName in PDBFile._residueNameReplacements:
                            resName = PDBFile._residueNameReplacements[resName]
                        r = top.addResidue(resName, c)
                        if resName in PDBFile._atomNameReplacements:
                            atomReplacements = PDBFile._atomNameReplacements[resName]
                        else:
                            atomReplacements = {}
                    atomName = fields[4]
                    if atomName in atomReplacements:
                        atomName = atomReplacements[atomName]

                    # Try to guess the element.

                    upper = atomName.upper()
                    if upper.startswith('CL'):
                        element = elem.chlorine
                    elif upper.startswith('NA'):
                        element = elem.sodium
                    elif upper.startswith('MG'):
                        element = elem.magnesium
                    else:
                        try:
                            element = elem.get_by_symbol(atomName[0])
                        except KeyError:
                            element = None
                    atoms.append(top.addAtom(atomName, element, r))

                # Add bonds to the topology

                for fields in moleculeType.bonds:
                    top.addBond(atoms[int(fields[0])-1], atoms[int(fields[1])-1])
Ejemplo n.º 58
0
 def __del__(self):
     PDBFile.writeFooter(self._topology, self._out)
     self._out.close()
Ejemplo n.º 59
0
    def integrate(self, topology_proposal, initial_positions, direction='insert', platform=None):
        """
        Performs NCMC switching to either delete or insert atoms according to the provided `topology_proposal`.

        For `delete`, the system is first modified from fully interacting to alchemically modified, and then NCMC switching is used to eliminate atoms.
        For `insert`, the system begins with eliminated atoms in an alchemically noninteracting form and NCMC switching is used to turn atoms on, followed by making system real.
        The contribution of transforming the real system to/from an alchemical system is included.

        Parameters
        ----------
        topology_proposal : TopologyProposal
            Contains old/new Topology and System objects and atom mappings.
        initial_positions : simtk.unit.Quantity with dimension [natoms, 3] with units of distance.
            Positions of the atoms at the beginning of the NCMC switching.
        direction : str, optional, default='insert'
            Direction of alchemical switching:
                'insert' causes lambda to switch from 0 to 1 over nsteps steps of integration
                'delete' causes lambda to switch from 1 to 0 over nsteps steps of integration
        platform : simtk.openmm.Platform, optional, default=None
            If not None, this platform is used for integration.

        Returns
        -------
        final_positions : simtk.unit.Quantity of dimensions [nparticles,3] with units compatible with angstroms
            The final positions after `nsteps` steps of alchemical switching
        logP : float
            The log acceptance probability of the switch
        potential : simtk.unit.Quantity with units compatible with kilocalories_per_mole
            For `delete`, the potential energy of the final (alchemically eliminated) conformation.
            For `insert`, the potential energy of the initial (alchemically eliminated) conformation.

        """
        if direction not in ['insert', 'delete']:
            raise Exception("'direction' must be one of ['insert', 'delete']; was '%s' instead" % direction)

        if (self.nsteps == 0):
            # Special case of instantaneous insertion/deletion.
            logP = 0.0
            final_positions = copy.deepcopy(initial_positions)
            from perses.tests.utils import compute_potential
            if direction == 'delete':
                potential = self.beta * compute_potential(topology_proposal.old_system, initial_positions, platform=self.platform)
            elif direction == 'insert':
                potential = self.beta * compute_potential(topology_proposal.new_system, initial_positions, platform=self.platform)
            return [final_positions, logP, potential]

        # Create alchemical system.
        [unmodified_system, alchemical_system] = self.make_alchemical_system(topology_proposal, direction=direction)

        # DEBUG: Compute initial potential of unmodified system and alchemical system to make sure finite.
        from perses.tests.utils import compute_potential
        #print(compute_potential(unmodified_system, initial_positions, platform=self.platform))
        #print(compute_potential(alchemical_system, initial_positions, platform=self.platform))

        # Select subset of switching functions based on which alchemical parameters are present in the system.
        available_parameters = self._getAvailableParameters(alchemical_system)
        functions = { parameter_name : self.functions[parameter_name] for parameter_name in self.functions if (parameter_name in available_parameters) }

        # Create an NCMC velocity Verlet integrator.
        integrator = NCMCAlchemicalIntegrator(self.temperature, alchemical_system, functions, nsteps=self.nsteps, timestep=self.timestep, direction=direction)
        # Set the constraint tolerance if specified.
        if self.constraint_tolerance is not None:
            integrator.setConstraintTolerance(self.constraint_tolerance)
        # Create a context on the specified platform.
        if self.platform is not None:
            context = openmm.Context(alchemical_system, integrator, self.platform)
        else:
            context = openmm.Context(alchemical_system, integrator)
        context.setPositions(initial_positions)
        context.applyConstraints(integrator.getConstraintTolerance())
        # Set velocities to temperature and apply velocity constraints.
        context.setVelocitiesToTemperature(self.temperature)
        context.applyVelocityConstraints(integrator.getConstraintTolerance())

        # Set initial context parameters.
        if direction == 'insert':
            for parameter_name in available_parameters:
                context.setParameter(parameter_name, 0)
        elif direction == 'delete':
            for parameter_name in available_parameters:
                context.setParameter(parameter_name, 1)

        # Compute initial potential of alchemical state.
        initial_potential = self.beta * context.getState(getEnergy=True).getPotentialEnergy()
        if np.isnan(initial_potential):
            raise NaNException("Initial potential of 'insert' operation is NaN (unmodified potential was %.3f kT, alchemical potential was %.3f kT before changing lambda)" % (unmodified_potential, alchemical_potential))
        from perses.tests.utils import compute_potential_components
        #print("initial potential before '%s' : %f kT" % (direction, initial_potential))
        #print("initial potential components:   %s" % str(compute_potential_components(context))) # DEBUG

        # Take a single integrator step since all switching steps are unrolled in NCMCAlchemicalIntegrator.
        try:
            # Write PDB file if requested.
            if self.write_pdb_interval:
                if direction == 'insert':
                    topology = topology_proposal.new_topology
                    indices = topology_proposal.unique_new_atoms
                else:
                    topology = topology_proposal.old_topology
                    indices = topology_proposal.unique_old_atoms

                # Write atom indices that are changing
                import pickle
                filename = 'ncmc-%s-%d-atomindices.pkl' % (direction, self.nattempted)
                outfile = open(filename, 'wb')
                pickle.dump(indices, outfile)
                outfile.close()

                from simtk.openmm.app import PDBFile
                filename = 'ncmc-%s-%d.pdb' % (direction, self.nattempted)
                outfile = open(filename, 'w')
                PDBFile.writeHeader(topology, file=outfile)
                modelIndex = 0
                PDBFile.writeModel(topology, context.getState(getPositions=True).getPositions(asNumpy=True), file=outfile, modelIndex=modelIndex)
                try:
                    for step in range(self.nsteps):
                        integrator.step(1)
                        if (step+1)%self.write_pdb_interval == 0:
                            modelIndex += 1
                            PDBFile.writeModel(topology, context.getState(getPositions=True).getPositions(asNumpy=True), file=outfile, modelIndex=modelIndex)
                except ValueError as e:
                    # System is exploding and coordinates won't fit in PDB ATOM fields
                    print(e)

                PDBFile.writeFooter(topology, file=outfile)
                outfile.close()
            else:
                integrator.step(self.nsteps)

        except Exception as e:
            # Trap NaNs as a special exception (allowing us to reject later, if desired)
            if str(e) == "Particle coordinate is nan":
                raise NaNException(str(e))
            else:
                raise e

        # Set final context parameters.
        if direction == 'insert':
            for parameter_name in available_parameters:
                context.setParameter(parameter_name, 1)
        elif direction == 'delete':
            for parameter_name in available_parameters:
                context.setParameter(parameter_name, 0)

        # Compute final potential of alchemical state.
        final_potential = self.beta * context.getState(getEnergy=True).getPotentialEnergy()
        if np.isnan(final_potential):
            raise NaNException("Final potential of 'delete' operation is NaN")
        #print("final potential before '%s' : %f kT" % (direction, final_potential))
        #print("final potential components: %s" % str(compute_potential_components(context))) # DEBUG
        #print('')

        # Store final positions and log acceptance probability.
        final_positions = context.getState(getPositions=True).getPositions(asNumpy=True)
        logP_NCMC = integrator.getLogAcceptanceProbability(context)
        # DEBUG
        logging.debug("NCMC logP %+10.1f | initial_total_energy %+10.1f kT | final_total_energy %+10.1f kT." % (logP_NCMC, integrator.getGlobalVariableByName('initial_total_energy'), integrator.getGlobalVariableByName('final_total_energy')))
        # Clean up NCMC switching integrator.
        del context, integrator

        # Compute contribution from transforming real system to/from alchemical system.
        logP_alchemical_correction = self._computeAlchemicalCorrection(unmodified_system, alchemical_system, initial_positions, final_positions, direction=direction)

        # Compute total logP
        logP = logP_NCMC + logP_alchemical_correction

        # Clean up alchemical system.
        del alchemical_system

        # Select whether to return initial or final potential.
        if direction == 'insert':
            potential = initial_potential
        elif direction == 'delete':
            potential = final_potential

        # Keep track of statistics.
        self.nattempted += 1

        # Return
        return [final_positions, logP, potential]