Ejemplo n.º 1
0
    def prepare(self):
        """
        """
        mrec = self.com.rec()
        mlig = self.com.lig()

        m = mrec.concat(mlig)

        if self.protonate:
            if self.verbose:
                self.log.add('\nRe-building hydrogen atoms...')

            tempdir = self.tempdir
            if tempdir:
                tempdir += '/0_reduce'

            r = Reduce(m,
                       tempdir=tempdir,
                       log=self.log,
                       autocap=False,
                       debug=self.debug,
                       verbose=self.verbose)
            m = r.run()

        if self.addcharge:
            if self.verbose:
                self.log.add('\nAssigning charges from Amber topologies...')

            ac = AtomCharger(log=self.log, verbose=self.verbose)
            ac.charge(m)

        mrec = m.takeChains(range(mrec.lenChains()))
        mlig = m.takeChains(range(mrec.lenChains(), m.lenChains()))

        self.delphicom = Complex(mrec, mlig)
Ejemplo n.º 2
0
    def prepare( self ):
        """
        """
        mrec = self.com.rec()
        mlig = self.com.lig()
        
        m = mrec.concat( mlig )

        if self.protonate:
            if self.verbose:
                self.log.add( '\nRe-building hydrogen atoms...' )
            
            tempdir = self.tempdir
            if tempdir:
                tempdir += '/0_reduce'
                
            r = Reduce( m, tempdir=tempdir, log=self.log,
                        autocap=False,
                        debug=self.debug, verbose=self.verbose )
            m = r.run()
            
        if self.addcharge:
            if self.verbose:
                self.log.add( '\nAssigning charges from Amber topologies...')
                    
            ac = AtomCharger( log=self.log, verbose=self.verbose )
            ac.charge( m )
            
        mrec = m.takeChains( range( mrec.lenChains() ) )
        mlig = m.takeChains( range( mrec.lenChains(), m.lenChains() ) )
            
        self.delphicom = Complex( mrec, mlig )
Ejemplo n.º 3
0
    def test_errorcase1(self):
        """bindinEnergyDelphi test (error case 01)"""
        self.m = PDBModel(T.testRoot() + '/delphi/case01.pdb')
        rec = self.m.takeChains([0, 1])
        lig = self.m.takeChains([2])
        self.com = Complex(rec, lig)

        self.dG = DelphiBindingEnergy(self.com,
                                      log=self.log,
                                      scale=0.5,
                                      verbose=self.local)
        self.r = self.dG.run()

        if self.local:
            self.log.add('\nFinal result: dG = %3.2f kcal/mol' %
                         self.r['dG_kcal'])
Ejemplo n.º 4
0
def inputComplex(options):
    if 'c' in options:
        return T.load(T.absfile(options['c']))

    m = PDBModel(T.absfile(options['i']))

    ## extract rec and lig chains
    rec_chains = T.toIntList(options['r'])
    lig_chains = T.toIntList(options['l'])

    rec = m.takeChains(rec_chains)
    lig = m.takeChains(lig_chains)

    ## create Protein complex
    com = Complex(rec, lig)
    return com
Ejemplo n.º 5
0
    def processTrajs( self ):
        """
        Extract reference model and member trajectories from rec, lig, and
        com trajectories. Identify outlier member trajectories, if requested.
        """
        ## free rec
        self.ref_frec = self.nameRef( self.rec )

        t, self.ex_frec, self.members_frec = self.loadTraj(
            self.rec, self.ex_frec, self.ref_frec )

        n_rec_members = t.n_members
        self.cr       = self.cr or range( t.ref.lenChains( breaks=0 ) )
        del t

        ## free lig
        self.ref_flig = self.nameRef( self.lig )

        t, self.ex_flig, self.members_flig = self.loadTraj(
            self.lig, self.ex_flig, self.ref_flig )

        n_lig_members = t.n_members
        del t

        ## complex
        fname = T.stripSuffix( T.absfile( self.com, resolveLinks=0 ) )
        self.ref_com = fname + '_ref.complex'
        self.ref_blig= fname + '_blig.model'
        self.ref_brec= fname + '_brec.model'

        t, self.ex_com, self.members_com = self.loadTraj(
            self.com, self.ex_com  )

        n_com_members = t.n_members

        self.cl = self.cl or MU.difference( range(t.ref.lenChains()), self.cr)
        rec = t.ref.takeChains( self.cr, breaks=0 )
        lig = t.ref.takeChains( self.cl, breaks=0 )

        del t
        self.dumpMissing( Complex( rec, lig ), self.ref_com )
        self.dumpMissing( rec, self.ref_brec )
        self.dumpMissing( lig, self.ref_blig )

        self.equalizeMemberCount( n_rec_members, n_lig_members, n_com_members )

        if self.jack:  self.prepareJackknife()
Ejemplo n.º 6
0
class DelphiBindingEnergy(object):
    """
    Determine the electrostatic component of the free energy of binding using
    several rounds of Delphi calculations. DelphiBindingEnergy accepts a 
    binary complex (L{Biskit.Dock.Complex}) as input, performs several house
    keeping tasks (optional capping of free terminals, h-bond optimization and
    protonation with the reduce program, assignment of Amber partial atomic 
    charges) and then calls Delphi six times:

    1 - 3: one run each for complex, receptor, and ligand with zero ionic 
           strength
    4 - 6: one run each for complex, receptor, and ligand with custom salt
           concentration (default: physiological 0.15 M).
           
    The grid position and dimensions are determined once for the complex and
    then kept constant between all runs so that receptor, ligand and complex
    calculations can indeed be compared to each other.
           
    The free energy of binding is calculated as described in the Delphi
    documentation -- see: delphi2004/examples/binding.html -- according to the
    energy partioning scheme:
    
    dG = dG(coulomb) + ddG(solvation) + ddG(ions)
    Please have a look at the source code of DelphiBindingEnergy.bindingEnergy() 
    for a detailed breakup of these terms.
    
    Use:
    ====
    
    >>> com = Biskit.Complex( 'myrec.pdb', 'mylig.pdb' )
    >>> dg = DelphiBindingEnergy( com, verbose=True )
    >>> r = dg.run()

    Variable r will then receive a dictionary with the free energy of binding
    and its three components:
    
         {'dG_kt': free E. in units of kT, 
          'dG_kcal': free E. in units of kcal / mol, 
          'dG_kJ': free E. in units of kJ / mol,
          'coul': coulomb contribution in kT , 
          'solv': solvation contribution in kT, 
          'ions': salt or ionic contribution in kT }
          
    The modified complex used for the calculation (with hydrogens added and
    many other small changes) can be recovered from the DelphiBindingEnergy
    instance:
    
    >>> modified_com = dg.delphicom
    
    The run() method assigns the result dictionary to the info record
    of both the original and the modified complex. That means:
    
    >>> r1 = com.info['dG_delphi']
    >>> r2 = modified_com.info['dG_delphi']
    >>> r1 == r2
    True
    
    The result of the original DelPhi calculations (with and without salt for
    receptor, ligand and complex) are assigned to the info dictionaries of the
    complex' receptor and ligand model as well as to the complex itself:
    
    com.info['delphi_0.15salt'] ...delphi run with 0.15M salt on complex
    com.info['delphi_0salt']    ...delphi run without salt on complex

    com.lig().info['delphi_0.15salt'] ...delphi run with 0.15M salt on ligand
    com.lig().info['delphi_0salt']    ...delphi run without salt on ligand
    com.rec().info['delphi_0.15salt'] ...delphi run with 0.15M salt on receptor
    com.rec().info['delphi_0salt']    ...delphi run without salt on receptor
    
    From there the individual values for solvation, ionic and couloumb
    contributions can be recovered. See L{Biskit.Delphi} for a description of
    this result dictionary.
     
    Customization:
    ==============
    
    The most important Delphi parameters (dielectric, salt concentration, 
    grid scales, ion and probe radius) can be adjusted by passing parameters
    to the constructor (see documentation of __init__). The default parameters
    should be reasonable. By default,
    we create a grid that covers every linear dimension to at least 60% 
    (perfil=60) and has a density of 2.3 points per Angstroem (scale=2.3). 
    Such high densities come at much larger computational cost. It is
    recommended to test different values and average results.
    
    Note: Any parameters that are not recognized by 
    DelphiBindingEnergy() will be passed on to the Biskit.Delphi instance
    of each Delphi run and, from there, passed on to Biskit.Executor.
    
    The internal pipeline of DelphiBindingEnergy consists of:
    
    * adding hydrogens and capping of protein chain breaks and terminals with
      Biskit.Reduce( autocap=True ). The capping is performed by 
      L{Biskit.PDBCleaner} called from within Reduce.
    
    * mapping Amber partial atomic charges into the structure with 
      Biskit.AtomCharger()
      
    * setting up the various delphi runs with L{Biskit.Delphi}.
    
    A point worth looking at is the automatic capping of protein chain
    breaks and premature terminals with ACE and NME residues. This should
    generally be a good idea but the automatic discovery of premature C-termini
    or N-termini is guess work at best. See L{Biskit.PDBCleaner} for a more
    detailed discussion. You can override the default behaviour by setting
    autocap=False (no capping at all, this is now the default) and you can 
    then provide a complex structure that is already pre-treated by 
    L{Biskit.Reduce}.
    For example:
    
    >>> m = PDBModel('mycomplex.pdb')
    >>> m = Reduce( m, capN=[0], capC=[2] )
    >>> com = Biskit.Complex( m.takeChains([0]), m.takeChains([1,2]) )
    >>> dg = DelphiBindingEnergy( com, protonate=False )
    
    In this case, the original structure would receive a ACE N-terminal
    capping of the first chain and the second chain would receive a C-terminal
    NME capping residue. The first chain is considered receptor and the second
    and third chain are considered ligand.
    
    @see: L{Biskit.PDBCleaner}
    @see: L{Biskit.Reduce}
    @see: L{Biskit.AtomCharger}
    @see: L{Biskit.Delphi}
    """
    def __init__(self,
                 com,
                 protonate=True,
                 addcharge=True,
                 indi=4.0,
                 exdi=80.0,
                 salt=0.15,
                 ionrad=2,
                 prbrad=1.4,
                 bndcon=4,
                 scale=2.3,
                 perfil=60,
                 template=None,
                 topologies=None,
                 f_charges=None,
                 verbose=True,
                 debug=False,
                 log=None,
                 tempdir=None,
                 cwd=None,
                 **kw):
        """
        @param com: complex to analyze
        @type  com: Biskit.Complex
        @param protonate: (re-)build hydrogen atoms with reduce program (True)
                          see L{Biskit.Reduce}
        @type  protonate: bool
        @param addcharge: Assign partial charges from Amber topologies (True)
        @type  addcharge: bool
        @param indi: interior dilectric (4.0)
        @param exdi: exterior dielectric (80.0)
        @param salt: salt conc. in M (0.15)
        @param ionrad: ion radius (2)
        @param prbrad: probe radius (1.4) 
        @param bndcon: boundary condition (4, delphi default is 2)
        @param scale:  grid spacing (2.3)
        @param perfil: grid fill factor in % (for automatic grid, 60) 
        
        @param template: delphi command file template [None=use default]
        @type  template: str
        @param f_radii: alternative delphi atom radii file [None=use default]
        @type  f_radii: str
        @param topologies: alternative list of residue charge/topology files
                           [default: amber/residues/all*]
        @type  topologies: [ str ]
        @param f_charges: alternative delphi charge file 
                          [default: create custom]
        @type  f_charges: str

        @param kw: additional key=value parameters for Delphi or Executor:
        @type  kw: key=value pairs
        ::
          debug    - 0|1, keep all temporary files (default: 0)
          verbose  - 0|1, print progress messages to log (log != STDOUT)
          node     - str, host for calculation (None->local) NOT TESTED
                          (default: None)
          nice     - int, nice level (default: 0)
          log      - Biskit.LogFile, program log (None->STOUT) (default: None)
        """
        self.com = com
        self.delphicom = None

        self.protonate = protonate
        self.addcharge = addcharge
        ## DELPHI run parameters
        self.indi = indi  # interior dilectric(4.0)
        self.exdi = exdi  # exterior dielectric(80.0)
        self.salt = salt  # salt conc. in M (0.15)
        self.ionrad = ionrad  # ion radius (2)
        self.prbrad = prbrad  # probe radius (1.4)
        self.bndcon = bndcon  # boundary condition (4, delphi default is 2)

        ## DELPHI parameters for custom grid
        self.scale = scale  # grid spacing (1.2 / A)
        self.perfil = perfil  # grid fill factor in % (for automatic grid, 60)

        ## DELPHI parameter file and Amber residue definitions or charge file
        self.template = template
        self.topologies = topologies
        self.f_charges = f_charges

        ## pump everything else into name space, too
        self.__dict__.update(kw)

        ## prepare globally valid grid
        self.grid = None

        self.verbose = verbose
        self.log = log or StdLog()
        self.debug = debug
        self.tempdir = tempdir
        self.cwd = cwd

        self.ezero = self.esalt = None  # raw results assigned by run()

    def prepare(self):
        """
        """
        mrec = self.com.rec()
        mlig = self.com.lig()

        m = mrec.concat(mlig)

        if self.protonate:
            if self.verbose:
                self.log.add('\nRe-building hydrogen atoms...')

            tempdir = self.tempdir
            if tempdir:
                tempdir += '/0_reduce'

            r = Reduce(m,
                       tempdir=tempdir,
                       log=self.log,
                       autocap=False,
                       debug=self.debug,
                       verbose=self.verbose)
            m = r.run()

        if self.addcharge:
            if self.verbose:
                self.log.add('\nAssigning charges from Amber topologies...')

            ac = AtomCharger(log=self.log, verbose=self.verbose)
            ac.charge(m)

        mrec = m.takeChains(range(mrec.lenChains()))
        mlig = m.takeChains(range(mrec.lenChains(), m.lenChains()))

        self.delphicom = Complex(mrec, mlig)

    def setupDelphi(self, model, grid={}, **kw):
        """
        """
        params = copy.copy(self.__dict__)
        params.update(kw)
        params['protonate'] = False  # run reduce once for complex only
        params['addcharge'] = False  # run AtomCharger once for complex only

        d = Delphi(model, **params)
        d.setGrid(**grid)

        return d

    def processThreesome(self, **kw):
        """
        Calculate Delphi energies for rec, lig and complex
        @return: result dictionaries for com, rec, lig
        @rtype: ( dict, dict, dict )
        """
        dcom = self.setupDelphi(self.delphicom.model(), **kw)
        grid = dcom.getGrid()

        drec = self.setupDelphi(self.delphicom.rec(), grid=grid, **kw)
        dlig = self.setupDelphi(self.delphicom.lig(), grid=grid, **kw)

        if self.verbose:
            self.log.add('\nrunning Delphi for complex...')
        r_com = dcom.run()

        if self.verbose:
            self.log.add('\nrunning Delphi for receptor...')
        r_rec = drec.run()

        if self.verbose:
            self.log.add('\nrunning Delphi for ligand...')
        r_lig = dlig.run()

        return r_com, r_rec, r_lig

    def processSixsome(self, **kw):
        """
        Calculate Delphi energies for rec, lig and complex with and without
        salt.
        @return: com, rec, lig delphi calculations with and without ions
        @rtype: ( {}, {} )
        """
        ## with ions
        if self.verbose:
            self.log.add('\nDelphi calculations with %1.3f M salt' % self.salt)
            self.log.add('=======================================')
        ri_com, ri_rec, ri_lig = self.processThreesome(salt=self.salt, **kw)

        ## w/o ions
        if self.verbose:
            self.log.add('\nDelphi calculations with zero ionic strenght')
            self.log.add('==============================================')
        r_com, r_rec, r_lig = self.processThreesome(salt=0.0, **kw)

        rsalt = {'com': ri_com, 'rec': ri_rec, 'lig': ri_lig}
        rzero = {'com': r_com, 'rec': r_rec, 'lig': r_lig}

        if self.verbose:
            self.log.add('\nRaw results')
            self.log.add('============')
            self.log.add('zero ionic strength: \n' + str(rzero))
            self.log.add('\nwith salt: \n' + str(rsalt))

        return rzero, rsalt

    def bindingEnergy(self, ezero, esalt):
        """
        Calculate electrostatic component of the free energy of binding 
        according to energy partitioning formula.
        @param ezero: delphi energies calculated at zero ionic strength
        @type  ezero: {'com':{}, 'rec':{}, 'lig':{} }
        @param esalt: delphi energies calculated with ions (see salt=)
        @type  esalt: {'com':{}, 'rec':{}, 'lig':{} }
        @return: {'dG_kt': free E. in units of kT, 
                  'dG_kcal': free E. in units of kcal / mol, 
                  'dG_kJ': free E. in units of kJ / mol,
                  'coul': coulomb contribution in kT , 
                  'solv': solvation contribution in kT, 
                  'ions': salt or ionic contribution in kT }
        @rtype: dict { str : float }
        """
        delta_0 = {}
        delta_i = {}
        for k, v in ezero['com'].items():
            delta_0[k] = ezero['com'][k] - ezero['rec'][k] - ezero['lig'][k]
            delta_i[k] = esalt['com'][k] - esalt['rec'][k] - esalt['lig'][k]

        dG_coul = delta_0['ecoul']
        ddG_rxn = delta_0['erxn']
        ddG_ions = delta_i['egrid'] - delta_0['egrid']

        dG = dG_coul + ddG_rxn + ddG_ions  # in units of kT
        dG_kcal = round(dG * 0.593, 3)  # kcal / mol
        dG_kJ = round(dG * 2.479, 3)  # kJ / mol

        r = {
            'dG_kt': dG,
            'dG_kcal': dG_kcal,
            'dG_kJ': dG_kJ,
            'coul': dG_coul,
            'solv': ddG_rxn,
            'ions': ddG_ions
        }
        return r

    def run(self):
        """
        Prepare structures and perform Delphi calculations for complex, 
        receptor and ligand, each with and without ions (salt). Calculate
        free energy of binding according to energy partitioning.
        Detailed delphi results are saved into object fields 'ezero' and
        'esalt' for calculations without and with ions, respectively.
        
        @return: {'dG_kt': free E. in units of kT, 
                  'dG_kcal': free E. in units of kcal / mol, 
                  'dG_kJ': free E. in units of kJ / mol,
                  'coul': coulomb contribution in kT , 
                  'solv': solvation contribution in kT, 
                  'ions': salt or ionic contribution in kT }
        @rtype: dict { str : float }
        """
        self.prepare()
        self.ezero, self.esalt = self.processSixsome()
        self.result = self.bindingEnergy(self.ezero, self.esalt)

        self.delphicom.info['dG_delphi'] = self.result
        self.com.info['dG_delphi'] = self.result

        for com in [self.delphicom, self.com]:
            key = 'delphi_%4.2fsalt' % self.salt
            com.rec_model.info[key] = self.esalt['rec']
            com.lig_model.info[key] = self.esalt['lig']
            com.lig_model.lig_transformed = None
            key = 'delphi_0salt'
            com.rec_model.info[key] = self.ezero['rec']
            com.lig_model.info[key] = self.ezero['lig']
            com.lig_model.lig_transformed = None  # reset Complex.lig() cache
            com.info[key] = self.ezero['com']

        return self.result
Ejemplo n.º 7
0
class DelphiBindingEnergy( object ):
    """
    Determine the electrostatic component of the free energy of binding using
    several rounds of Delphi calculations. DelphiBindingEnergy accepts a 
    binary complex (L{Biskit.Dock.Complex}) as input, performs several house
    keeping tasks (optional capping of free terminals, h-bond optimization and
    protonation with the reduce program, assignment of Amber partial atomic 
    charges) and then calls Delphi six times:

    1 - 3: one run each for complex, receptor, and ligand with zero ionic 
           strength
    4 - 6: one run each for complex, receptor, and ligand with custom salt
           concentration (default: physiological 0.15 M).
           
    The grid position and dimensions are determined once for the complex and
    then kept constant between all runs so that receptor, ligand and complex
    calculations can indeed be compared to each other.
           
    The free energy of binding is calculated as described in the Delphi
    documentation -- see: delphi2004/examples/binding.html -- according to the
    energy partioning scheme:
    
    dG = dG(coulomb) + ddG(solvation) + ddG(ions)
    Please have a look at the source code of DelphiBindingEnergy.bindingEnergy() 
    for a detailed breakup of these terms.
    
    Use:
    ====
    
    >>> com = Biskit.Complex( 'myrec.pdb', 'mylig.pdb' )
    >>> dg = DelphiBindingEnergy( com, verbose=True )
    >>> r = dg.run()

    Variable r will then receive a dictionary with the free energy of binding
    and its three components:
    
         {'dG_kt': free E. in units of kT, 
          'dG_kcal': free E. in units of kcal / mol, 
          'dG_kJ': free E. in units of kJ / mol,
          'coul': coulomb contribution in kT , 
          'solv': solvation contribution in kT, 
          'ions': salt or ionic contribution in kT }
          
    The modified complex used for the calculation (with hydrogens added and
    many other small changes) can be recovered from the DelphiBindingEnergy
    instance:
    
    >>> modified_com = dg.delphicom
    
    The run() method assigns the result dictionary to the info record
    of both the original and the modified complex. That means:
    
    >>> r1 = com.info['dG_delphi']
    >>> r2 = modified_com.info['dG_delphi']
    >>> r1 == r2
    True
    
    The result of the original DelPhi calculations (with and without salt for
    receptor, ligand and complex) are assigned to the info dictionaries of the
    complex' receptor and ligand model as well as to the complex itself:
    
    com.info['delphi_0.15salt'] ...delphi run with 0.15M salt on complex
    com.info['delphi_0salt']    ...delphi run without salt on complex

    com.lig().info['delphi_0.15salt'] ...delphi run with 0.15M salt on ligand
    com.lig().info['delphi_0salt']    ...delphi run without salt on ligand
    com.rec().info['delphi_0.15salt'] ...delphi run with 0.15M salt on receptor
    com.rec().info['delphi_0salt']    ...delphi run without salt on receptor
    
    From there the individual values for solvation, ionic and couloumb
    contributions can be recovered. See L{Biskit.Delphi} for a description of
    this result dictionary.
     
    Customization:
    ==============
    
    The most important Delphi parameters (dielectric, salt concentration, 
    grid scales, ion and probe radius) can be adjusted by passing parameters
    to the constructor (see documentation of __init__). The default parameters
    should be reasonable. By default,
    we create a grid that covers every linear dimension to at least 60% 
    (perfil=60) and has a density of 2.3 points per Angstroem (scale=2.3). 
    Such high densities come at much larger computational cost. It is
    recommended to test different values and average results.
    
    Note: Any parameters that are not recognized by 
    DelphiBindingEnergy() will be passed on to the Biskit.Delphi instance
    of each Delphi run and, from there, passed on to Biskit.Executor.
    
    The internal pipeline of DelphiBindingEnergy consists of:
    
    * adding hydrogens and capping of protein chain breaks and terminals with
      Biskit.Reduce( autocap=True ). The capping is performed by 
      L{Biskit.PDBCleaner} called from within Reduce.
    
    * mapping Amber partial atomic charges into the structure with 
      Biskit.AtomCharger()
      
    * setting up the various delphi runs with L{Biskit.Delphi}.
    
    A point worth looking at is the automatic capping of protein chain
    breaks and premature terminals with ACE and NME residues. This should
    generally be a good idea but the automatic discovery of premature C-termini
    or N-termini is guess work at best. See L{Biskit.PDBCleaner} for a more
    detailed discussion. You can override the default behaviour by setting
    autocap=False (no capping at all, this is now the default) and you can 
    then provide a complex structure that is already pre-treated by 
    L{Biskit.Reduce}.
    For example:
    
    >>> m = PDBModel('mycomplex.pdb')
    >>> m = Reduce( m, capN=[0], capC=[2] )
    >>> com = Biskit.Complex( m.takeChains([0]), m.takeChains([1,2]) )
    >>> dg = DelphiBindingEnergy( com, protonate=False )
    
    In this case, the original structure would receive a ACE N-terminal
    capping of the first chain and the second chain would receive a C-terminal
    NME capping residue. The first chain is considered receptor and the second
    and third chain are considered ligand.
    
    @see: L{Biskit.PDBCleaner}
    @see: L{Biskit.Reduce}
    @see: L{Biskit.AtomCharger}
    @see: L{Biskit.Delphi}
    """
    
    def __init__(self, com, 
                 protonate=True, addcharge=True,
                 indi=4.0, exdi=80.0, salt=0.15, ionrad=2, prbrad=1.4, 
                 bndcon=4, scale=2.3, perfil=60, 
                 template=None, topologies=None,
                 f_charges=None,
                 verbose=True, debug=False, log=None, tempdir=None, cwd=None,
                 **kw ):
        """
        @param com: complex to analyze
        @type  com: Biskit.Complex
        @param protonate: (re-)build hydrogen atoms with reduce program (True)
                          see L{Biskit.Reduce}
        @type  protonate: bool
        @param addcharge: Assign partial charges from Amber topologies (True)
        @type  addcharge: bool
        @param indi: interior dilectric (4.0)
        @param exdi: exterior dielectric (80.0)
        @param salt: salt conc. in M (0.15)
        @param ionrad: ion radius (2)
        @param prbrad: probe radius (1.4) 
        @param bndcon: boundary condition (4, delphi default is 2)
        @param scale:  grid spacing (2.3)
        @param perfil: grid fill factor in % (for automatic grid, 60) 
        
        @param template: delphi command file template [None=use default]
        @type  template: str
        @param f_radii: alternative delphi atom radii file [None=use default]
        @type  f_radii: str
        @param topologies: alternative list of residue charge/topology files
                           [default: amber/residues/all*]
        @type  topologies: [ str ]
        @param f_charges: alternative delphi charge file 
                          [default: create custom]
        @type  f_charges: str

        @param kw: additional key=value parameters for Delphi or Executor:
        @type  kw: key=value pairs
        ::
          debug    - 0|1, keep all temporary files (default: 0)
          verbose  - 0|1, print progress messages to log (log != STDOUT)
          node     - str, host for calculation (None->local) NOT TESTED
                          (default: None)
          nice     - int, nice level (default: 0)
          log      - Biskit.LogFile, program log (None->STOUT) (default: None)
        """
        self.com = com
        self.delphicom = None
        
        self.protonate = protonate
        self.addcharge = addcharge
        ## DELPHI run parameters
        self.indi=indi  # interior dilectric(4.0)
        self.exdi=exdi  # exterior dielectric(80.0)
        self.salt=salt  # salt conc. in M (0.15)
        self.ionrad=ionrad # ion radius (2)
        self.prbrad=prbrad # probe radius (1.4) 
        self.bndcon=bndcon # boundary condition (4, delphi default is 2)
        
        ## DELPHI parameters for custom grid
        self.scale=scale   # grid spacing (1.2 / A)
        self.perfil=perfil # grid fill factor in % (for automatic grid, 60)
        
        ## DELPHI parameter file and Amber residue definitions or charge file
        self.template = template
        self.topologies = topologies
        self.f_charges = f_charges
        
        ## pump everything else into name space, too
        self.__dict__.update( kw )
        
        ## prepare globally valid grid
        self.grid = None
        
        self.verbose = verbose
        self.log = log or StdLog()
        self.debug = debug
        self.tempdir = tempdir
        self.cwd = cwd
        
        self.ezero = self.esalt = None # raw results assigned by run()

    def prepare( self ):
        """
        """
        mrec = self.com.rec()
        mlig = self.com.lig()
        
        m = mrec.concat( mlig )

        if self.protonate:
            if self.verbose:
                self.log.add( '\nRe-building hydrogen atoms...' )
            
            tempdir = self.tempdir
            if tempdir:
                tempdir += '/0_reduce'
                
            r = Reduce( m, tempdir=tempdir, log=self.log,
                        autocap=False,
                        debug=self.debug, verbose=self.verbose )
            m = r.run()
            
        if self.addcharge:
            if self.verbose:
                self.log.add( '\nAssigning charges from Amber topologies...')
                    
            ac = AtomCharger( log=self.log, verbose=self.verbose )
            ac.charge( m )
            
        mrec = m.takeChains( range( mrec.lenChains() ) )
        mlig = m.takeChains( range( mrec.lenChains(), m.lenChains() ) )
            
        self.delphicom = Complex( mrec, mlig )


    def setupDelphi( self, model, grid={}, **kw ):
        """
        """
        params = copy.copy( self.__dict__ )
        params.update( kw )
        params['protonate'] = False   # run reduce once for complex only
        params['addcharge'] = False   # run AtomCharger once for complex only
        
        d = Delphi( model, **params )
        d.setGrid( **grid )
        
        return d
    
    def processThreesome( self, **kw ):
        """
        Calculate Delphi energies for rec, lig and complex
        @return: result dictionaries for com, rec, lig
        @rtype: ( dict, dict, dict )
        """
        dcom = self.setupDelphi( self.delphicom.model(), **kw )
        grid = dcom.getGrid()
        
        drec = self.setupDelphi( self.delphicom.rec(), grid=grid, **kw )
        dlig = self.setupDelphi( self.delphicom.lig(), grid=grid, **kw )
        
        if self.verbose:
            self.log.add('\nrunning Delphi for complex...')
        r_com = dcom.run()

        if self.verbose:
            self.log.add('\nrunning Delphi for receptor...')
        r_rec = drec.run()
        
        if self.verbose:
            self.log.add('\nrunning Delphi for ligand...')
        r_lig = dlig.run()
        
        return r_com, r_rec, r_lig
    
    def processSixsome( self, **kw ):
        """
        Calculate Delphi energies for rec, lig and complex with and without
        salt.
        @return: com, rec, lig delphi calculations with and without ions
        @rtype: ( {}, {} )
        """
        ## with ions
        if self.verbose:
            self.log.add('\nDelphi calculations with %1.3f M salt' % self.salt)
            self.log.add('=======================================')
        ri_com, ri_rec, ri_lig = self.processThreesome( salt=self.salt, **kw )

        ## w/o ions
        if self.verbose:
            self.log.add('\nDelphi calculations with zero ionic strenght')
            self.log.add('==============================================')
        r_com, r_rec, r_lig = self.processThreesome( salt=0.0, **kw )
        
        rsalt = { 'com':ri_com, 'rec':ri_rec, 'lig':ri_lig }
        rzero = { 'com':r_com, 'rec':r_rec, 'lig':r_lig }
        
        if self.verbose:
            self.log.add('\nRaw results')
            self.log.add('============')
            self.log.add('zero ionic strength: \n' + str(rzero) )
            self.log.add('\nwith salt: \n' + str(rsalt) )
    
        return rzero, rsalt
    
    def bindingEnergy( self, ezero, esalt ):
        """
        Calculate electrostatic component of the free energy of binding 
        according to energy partitioning formula.
        @param ezero: delphi energies calculated at zero ionic strength
        @type  ezero: {'com':{}, 'rec':{}, 'lig':{} }
        @param esalt: delphi energies calculated with ions (see salt=)
        @type  esalt: {'com':{}, 'rec':{}, 'lig':{} }
        @return: {'dG_kt': free E. in units of kT, 
                  'dG_kcal': free E. in units of kcal / mol, 
                  'dG_kJ': free E. in units of kJ / mol,
                  'coul': coulomb contribution in kT , 
                  'solv': solvation contribution in kT, 
                  'ions': salt or ionic contribution in kT }
        @rtype: dict { str : float }
        """
        delta_0 = {}
        delta_i = {}
        for k, v in ezero['com'].items():
            delta_0[ k ] = ezero['com'][k] - ezero['rec'][k] - ezero['lig'][k]
            delta_i[ k ] = esalt['com'][k] - esalt['rec'][k] - esalt['lig'][k]
        
        dG_coul = delta_0['ecoul']
        ddG_rxn = delta_0['erxn']
        ddG_ions= delta_i['egrid'] - delta_0['egrid']
        
        dG = dG_coul + ddG_rxn + ddG_ions  # in units of kT
        dG_kcal = round( dG * 0.593, 3)  # kcal / mol
        dG_kJ = round( dG * 2.479, 3)    # kJ / mol
        
        r = {'dG_kt':dG, 'dG_kcal':dG_kcal, 'dG_kJ':dG_kJ,
             'coul':dG_coul, 'solv':ddG_rxn, 'ions':ddG_ions}
        return r
    
    def run( self ):
        """
        Prepare structures and perform Delphi calculations for complex, 
        receptor and ligand, each with and without ions (salt). Calculate
        free energy of binding according to energy partitioning.
        Detailed delphi results are saved into object fields 'ezero' and
        'esalt' for calculations without and with ions, respectively.
        
        @return: {'dG_kt': free E. in units of kT, 
                  'dG_kcal': free E. in units of kcal / mol, 
                  'dG_kJ': free E. in units of kJ / mol,
                  'coul': coulomb contribution in kT , 
                  'solv': solvation contribution in kT, 
                  'ions': salt or ionic contribution in kT }
        @rtype: dict { str : float }
        """
        self.prepare()
        self.ezero, self.esalt = self.processSixsome()
        self.result = self.bindingEnergy( self.ezero, self.esalt )
        
        self.delphicom.info['dG_delphi'] = self.result
        self.com.info['dG_delphi'] = self.result
        
        for com in [self.delphicom, self.com]:
            key = 'delphi_%4.2fsalt' % self.salt
            com.rec_model.info[key] = self.esalt['rec']
            com.lig_model.info[key] = self.esalt['lig']
            com.lig_model.lig_transformed = None
            key = 'delphi_0salt'
            com.rec_model.info[key] = self.ezero['rec']
            com.lig_model.info[key] = self.ezero['lig']
            com.lig_model.lig_transformed = None  # reset Complex.lig() cache
            com.info[key] = self.ezero['com']
        
        return self.result
Ejemplo n.º 8
0
    def nextComplex(self):
        """
        Take list of lines, extract all Hex info about one complex
        (Solution number, hex energy,..) also extract 16 numbers of
        the transformation matrix and put them into 4 by 4 numeric
        array.

        @return: Complex created from the output from Hex
        @rtype: Complex
        """
        ## get set of lines describing next complex:
        lines = self._nextBlock()
        if lines == None:
            ## EOF
            return None
        ## skip incomplete records
        if len(lines) < 13:
            lines = self._nextBlock()

        ## fill info dictionary
        i = {}
        matrix = None
        for l in lines:
            try:
                ## labels has to be in the same order as in hex.out
                m = self.ex_line.search(l)
                if m != None:
                    m = m.groups()

                    if m[0] == 'Orientation':
                        i['hex_clst'] = int(m[1])
                    elif m[0] == 'Solution':
                        i['soln'] = int(m[1])
                    elif m[0] == 'ReceptorModel':
                        if self.forceModel:
                            i['model1'] = self.forceModel[0]
                        else:
                            i['model1'] = int(m[1])
                    elif m[0] == 'LigandModel':
                        if self.forceModel:
                            i['model2'] = self.forceModel[1]
                        else:
                            i['model2'] = int(m[1])
                    elif m[0] == 'Bumps':
                        if int(m[1]) != -1:
                            i['bumps'] = int(m[1])
                    elif m[0] == 'ReferenceRMS':
                        i['rms'] = float(m[1])
                    elif m[0] == 'Vshape':
                        if float(m[1]) != 0.0:
                            i['hex_Vshape'] = float(m[1])
                    elif m[0] == 'Vclash':
                        if float(m[1]) != 0.0:
                            i['hex_Vclash'] = float(m[1])
                    elif m[0] == 'Etotal':
                        i['hex_etotal'] = float(m[1])
                    elif m[0] == 'Eshape':
                        i['hex_eshape'] = float(m[1])
                    elif m[0] == 'LigandMatrix':
                        ## get all numbers of matrix as list of strings
                        strings = self.ex_matrix.findall(l)
                        ## convert that to list of floats
                        numbers = []
                        for each in strings:
                            numbers += [float(each)]
                        ## convert that to list of lists of 4 floats each
                        matrix = []
                        for j in range(0, 4):
                            matrix.append(numbers[4 * j:4 * (j + 1)])
                        ## create 4 by 4 Numeric array from 4 by 4 list
                        matrix = Numeric.array(matrix, Numeric.Float32)
            except AttributeError:
                print "HexParser.nextComplex(): ", t.lastError()

        ## Create new complex taking PCR models from dictionary
        c = Complex(self.rec_models[i['model1']], self.lig_models[i['model2']],
                    matrix, i)
        return c
Ejemplo n.º 9
0
    lig = m_com.takeChains([1])

    ## add molecular surface to components
    doper = PDBDope(rec)
    doper.addSurfaceRacer(probe=1.4)
    surf_rec = rec.profile2mask('MS', 0.0001, 101)

    doper = PDBDope(lig)
    doper.addSurfaceRacer(probe=1.4)
    surf_lig = lig.profile2mask('MS', 0.0001, 101)

    ## kick out non-surface
    rec = rec.compress(surf_rec)
    lig = lig.compress(surf_lig)

    com = Complex(rec, lig)

    ## get interface patch
    cont = com.atomContacts(cutoff=6.0)
    rec_if = N0.sum(cont, 1)
    lig_if = N0.sum(cont, 0)

    ## center distance
    c2c = N0.sqrt(N0.sum((rec.center() - lig.center())**2, 0))
    print "Center2Center: ", c2c

    ## get patches and put them into Pymoler for display
    print "Patching"
    excl = N0.compress(N0.ones(len(rec_if)), rec_if)
    pm = test(rec, c2c, nAtoms=len(N0.nonzero(rec_if)), exclude=rec_if)
Ejemplo n.º 10
0
    from Biskit import PDBDope
    from Biskit.tools import *
    from Biskit.Dock import Complex

    print "Loading"
##     m_com = load( testRoot() + '/com_wet/dry_com.model' )
    m_com = load( testRoot() + '/com/ref.complex').model()
    m_com._resIndex = None   ## HACK, something wrong with legacy _resIndex
    
    doper = PDBDope( m_com )
    doper.addSurfaceRacer()
    
    mask = m_com.profile2mask( 'relAS', 5, 101 )
    m = m_com.compress( mask )

    ## get patches and put them into Pymoler for display
    print "Patching"
    pm = test( m )

    ## show real interface patch
    com = Complex( m_com.takeChains([0]), m_com.takeChains([1]))
    cont = com.atomContacts()
    rec_i = N.flatnonzero( N.sum( cont, 1 ) )
    lig_i = N.flatnonzero( N.sum( cont, 0 ) )

    pm.addPdb( m_com.take( rec_i ), 'rec_interface' )
    pm.addPdb( m_com.takeChains([1]).take( lig_i ), 'lig_interface' )

    ## show everything
    pm.show()
Ejemplo n.º 11
0
    lig = m_com.takeChains([1])

    ## add molecular surface to components
    doper = PDBDope( rec )
    doper.addSurfaceRacer( probe=1.4 )
    surf_rec = rec.profile2mask( 'MS', 0.0001, 101 )

    doper = PDBDope( lig )
    doper.addSurfaceRacer( probe=1.4 )
    surf_lig = lig.profile2mask( 'MS', 0.0001, 101 )

    ## kick out non-surface
    rec = rec.compress( surf_rec )
    lig = lig.compress( surf_lig )

    com = Complex( rec, lig )

    ## get interface patch
    cont = com.atomContacts( cutoff=6.0 )
    rec_if = N0.sum( cont, 1 )
    lig_if = N0.sum( cont, 0 )

    ## center distance
    c2c = N0.sqrt( N0.sum( (rec.center() - lig.center())**2, 0 ) )
    print "Center2Center: ", c2c

    ## get patches and put them into Pymoler for display
    print "Patching"
    excl = N0.compress( N0.ones( len( rec_if ) ), rec_if )
    pm = test( rec, c2c, nAtoms=len(N0.nonzero(rec_if)), exclude=rec_if )
Ejemplo n.º 12
0
#

# separate DNA and protein

mask_dna = [ name in ['A','C','T','G']
             for name in m['residue_name'] ]

dna = m.compress( mask_dna )
dna.writePdb( 'dna_only.pdb' )

prot = m.compress( m.maskProtein() )

## Contact analysis with Complex
from Biskit.Dock import Complex

com = Complex( prot, dna )

## what is Complex??
dir( com )
print com.atomContacts.__doc__

cont = com.atomContacts( cutoff=10 )
print cont

G.scatter( zip( *N.nonzero( cont ) ) )
# --------------------------
##
## Visualization
##

# how many contacs has each protein residue?