00001 """ Python APBS Generalized Born Implementation
00002
00003 This module uses APBS to parameterize the effective Born radii of the
00004 Generalized Born electrostatic model and calculate the electrostatic
00005 solvation energy.
00006
00007 Justin Xiang (jxiang@ccb.wustl.edu)
00008 Todd Dolinsky (todd@ccb.wustl.edu)
00009 Nathan Baker (baker@biochem.wustl.edu)
00010 Washington University in St. Louis
00011
00012 APBS -- Adaptive Poisson-Boltzmann Solver
00013
00014 Nathan A. Baker (baker@biochem.wustl.edu)
00015 Dept. Biochemistry and Molecular Biophysics
00016 Center for Computational Biology
00017 Washington University in St. Louis
00018
00019 Additional contributing authors listed in the code documentation.
00020
00021 Copyright (c) 2002-2010, Washington University in St. Louis.
00022 Portions Copyright (c) 2002-2010. Nathan A. Baker
00023 Portions Copyright (c) 1999-2002. The Regents of the University of California.
00024 Portions Copyright (c) 1995. Michael Holst
00025
00026 All rights reserved.
00027
00028 Redistribution and use in source and binary forms, with or without
00029 modification, are permitted provided that the following conditions are met:
00030
00031 * Redistributions of source code must retain the above copyright notice, this
00032 list of conditions and the following disclaimer.
00033
00034 * Redistributions in binary form must reproduce the above copyright notice,
00035 this list of conditions and the following disclaimer in the documentation
00036 and/or other materials provided with the distribution.
00037
00038 * Neither the name of Washington University in St. Louis nor the names of its
00039 contributors may be used to endorse or promote products derived from this
00040 software without specific prior written permission.
00041
00042 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00043 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00044 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00045 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00046 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00047 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00048 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00049 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00050 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00051 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00052 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00053 """
00054
00055 from apbslib import *
00056 import sys, time, getopt
00057 import string
00058 import math
00059 from sys import stdout, stderr
00060 from math import sqrt, pow, exp, pi
00061
00062 __author__ = "Justin Xiang, Todd Dolinsky, Nathan Baker, Yong Huang"
00063 __date__ = "September 2009"
00064
00065 Python_kb = 1.3806581e-23
00066 Python_Na = 6.0221367e+23
00067 Python_e0 = 8.85419e-12
00068 Python_C = 1.602117e-19
00069 NOSH_MAXMOL = 20
00070 NOSH_MAXCALC = 20
00071
00072 class APBSError(Exception):
00073 """ APBSError class
00074
00075 The APBSError class inherits off the Exception module and returns
00076 a string defining the nature of the error.
00077 """
00078
00079 def __init__(self, value):
00080 """
00081 Initialize with error message
00082
00083 Parameters
00084 value: Error Message (string)
00085 """
00086 self.value = value
00087
00088 def __str__(self):
00089 """
00090 Return the error message
00091 """
00092 return `self.value`
00093
00094 def getHeader():
00095 """ Get header information about APBS
00096 Returns (header)
00097 header: Information about APBS
00098 """
00099
00100 """ Get header information about APBS
00101 Returns (header)
00102 header: Information about APBS
00103 """
00104
00105 header = "\n\n\
00106 ----------------------------------------------------------------------\n\
00107 Adaptive Poisson-Boltzmann Solver (APBS)\n\
00108 Version 1.3\n\
00109 \n\
00110 APBS -- Adaptive Poisson-Boltzmann Solver\n\
00111 \n\
00112 Nathan A. Baker (baker@biochem.wustl.edu)\n\
00113 Dept. Biochemistry and Molecular Biophysics\n\
00114 Center for Computational Biology\n\
00115 Washington University in St. Louis\n\
00116 \n\
00117 Additional contributing authors listed in the code documentation.\n\
00118 \n\
00119 Copyright (c) 2002-2010, Washington University in St. Louis.\n\
00120 Portions Copyright (c) 2002-2010. Nathan A. Baker\n\
00121 Portions Copyright (c) 1999-2002. The Regents of the University of California.\n\
00122 Portions Copyright (c) 1995. Michael Holst\n\
00123 \n\
00124 All rights reserved.\n\
00125 \n\
00126 Redistribution and use in source and binary forms, with or without\n\
00127 modification, are permitted provided that the following conditions are met:\n\
00128 \n\
00129 * Redistributions of source code must retain the above copyright notice, this\n\
00130 list of conditions and the following disclaimer.\n\
00131 \n\
00132 * Redistributions in binary form must reproduce the above copyright notice,\n\
00133 this list of conditions and the following disclaimer in the documentation\n\
00134 and/or other materials provided with the distribution.\n\
00135 \n\
00136 * Neither the name of Washington University in St. Louis nor the names of its\n\
00137 contributors may be used to endorse or promote products derived from this\n\
00138 software without specific prior written permission.\n\
00139 \n\
00140 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\
00141 \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\
00142 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
00143 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n\
00144 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n\
00145 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n\
00146 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n\
00147 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n\
00148 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n\
00149 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n\
00150 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
00151 ----------------------------------------------------------------------\n\
00152 \n\n"
00153 return header
00154
00155 def getUsage():
00156 """ Get usage information about running APBS via Python
00157 Returns (usage)
00158 usage: Text about running APBS via Python
00159 """
00160
00161 usage = "\n\n\
00162 ----------------------------------------------------------------------\n\
00163 This driver program calculates electrostatic solvation energy with\n\
00164 Poission-Boltzmann parameterized Generailized Born model. \n\
00165 It is invoked as:\n\n\
00166 python runGB.py -i apbs.in\n\n\
00167 Optional arguments:\n\
00168 -o <output_parameter> specifies path to output GB parameter file\n\
00169 (default: GB-parameters)\n\
00170 this parameter file is compatible with\n\
00171 readGB.py module\n\
00172 -m <output_matrix> specifies path to output GB energy matrix\n\
00173 -h or --help prints this help text\n\n\
00174 Special input file requirements:\n\
00175 This program can only calculate solvation energy for 1 molecule. Also,\n\
00176 it is assumed that the first molecule read in from the input file is\n\
00177 the target molecule. Additional molecules can be included only for\n\
00178 other purposes, such as centering etc. The elec statments specifies\n\
00179 the conditions for computing self energies during the parameterization\n\
00180 step. \n\
00181 ----------------------------------------------------------------------\n\n"
00182
00183 return usage
00184
00185 def main():
00186 """ Main driver for testing. Runs APBS on given input file """
00187
00188
00189 startVio()
00190
00191
00192 com = Vcom_ctor(1)
00193 rank = Vcom_rank(com)
00194 size = Vcom_size(com)
00195 mgparm = MGparm()
00196 pbeparm = PBEparm()
00197 mem = Vmem_ctor("Main")
00198 pbe = new_pbelist(NOSH_MAXMOL)
00199 pmg = new_pmglist(NOSH_MAXMOL)
00200 pmgp = new_pmgplist(NOSH_MAXMOL)
00201 realCenter = double_array(3)
00202 totEnergy = []
00203 nforce = int_array(NOSH_MAXCALC)
00204 atomforce = new_atomforcelist(NOSH_MAXCALC)
00205 sdie = 0
00206
00207
00208
00209 main_timer_start = time.clock()
00210
00211
00212
00213 stdout.write(getHeader())
00214 try:
00215 opts, args = getopt.getopt(sys.argv[1:], "hi:o:m:", ["help"])
00216 except getopt.GetoptError:
00217 stdout.write("problem with input format\n")
00218 stdout.write(getUsage())
00219 sys.exit("Incorrect usage!\n")
00220
00221 output_param = "GB-parameters.dat"
00222 output_matrix = ""
00223 for o, a in opts:
00224 if o in ("-h", "--help"):
00225 stdout.write("Printing help text...\n")
00226 stdout.write(getUsage())
00227 sys.exit()
00228 if o == "-i":
00229 input_file = a
00230 if o == "-o":
00231 output_param = a
00232 if o == "-m":
00233 output_matrix = a
00234
00235
00236
00237 nosh = NOsh_ctor(rank, size)
00238 try: input_file
00239 except:
00240 stdout.write("input file not initiated - check input\n")
00241 stdout.write(getUsage())
00242 sys.exit("Incorrect usage!\n")
00243 stdout.write("Parsing input file %s...\n" % input_file)
00244 if NOsh_parseInputFile(nosh, input_file) != 1:
00245 stderr.write("main: Error while parsing input file.\n")
00246 raise APBSError, "Error while parsing input file!"
00247
00248
00249
00250 alist = new_valist(NOSH_MAXMOL)
00251
00252 if loadMolecules(nosh,None,alist) != 1:
00253 stderr.write("main: Error while loading molecules. \n")
00254 raise APBSError, "Error while loading molecules!"
00255
00256
00257
00258 numAtoms = get_Valist(alist,0).number
00259 stdout.write("Number of atoms loaded: %d\n" % numAtoms)
00260 reflist = []
00261 radlist = []
00262 position = [0 for i in range(numAtoms)]
00263 for iatom in xrange(numAtoms):
00264 reflist.append(Vatom_getCharge(Valist_getAtom(get_Valist(alist, 0), iatom)))
00265 radlist.append(Vatom_getRadius(Valist_getAtom(get_Valist(alist, 0), iatom)))
00266 position[iatom] = getAtomPosition(Valist_getAtom(get_Valist(alist, 0), iatom))
00267
00268
00269
00270 if NOsh_setupElecCalc(nosh, alist)!=1:
00271 stderr.write("main: Error while setting up calculations. \n")
00272 raise APBSError, "Error while setting up calculations. \n"
00273
00274
00275
00276 for i in xrange(nosh.ncalc): totEnergy.append(0.0)
00277 selfEnergy = []
00278
00279
00280
00281 dielXMap = new_gridlist(NOSH_MAXMOL)
00282 dielYMap = new_gridlist(NOSH_MAXMOL)
00283 dielZMap = new_gridlist(NOSH_MAXMOL)
00284 if loadDielMaps(nosh, dielXMap, dielYMap, dielZMap) != 1:
00285 stderr.write("Error reading dielectric maps!\n")
00286 raise APBSError, "Error reading dielectric maps!"
00287
00288 kappaMap = new_gridlist(NOSH_MAXMOL)
00289 if loadKappaMaps(nosh, kappaMap) != 1:
00290 stderr.write("Error reading kappa maps!\n")
00291 raise APBSError, "Error reading kappa maps!"
00292
00293
00294
00295 for iatom in range(numAtoms):
00296 Vatom_setCharge(Valist_getAtom(get_Valist(alist, 0), iatom),0.0)
00297
00298 stdout.write("-----------------------------\n")
00299 for iatom in range(numAtoms):
00300
00301
00302
00303 if iatom == 0:
00304 refCharge = reflist[iatom]
00305 Vatom_setCharge(Valist_getAtom(get_Valist(alist, 0), iatom),refCharge)
00306 else:
00307 refCharge = reflist[iatom]
00308 Vatom_setCharge(Valist_getAtom(get_Valist(alist, 0), iatom),refCharge)
00309 Vatom_setCharge(Valist_getAtom(get_Valist(alist, 0), iatom-1),0.0)
00310
00311
00312
00313 chargeMap = new_gridlist(NOSH_MAXMOL)
00314 if loadChargeMaps(nosh, chargeMap) != 1:
00315 stderr.write("Error reading charge maps!\n")
00316 raise APBSError, "Error reading charge maps!"
00317
00318
00319 stdout.write("Parameterizaing atom %d with %d PBE calculations\n" % ((iatom+1), nosh.ncalc))
00320 percentage = iatom*100*numAtoms**-1
00321 stdout.write("Roughly %f%% complete\n" % percentage)
00322
00323 energylist = [0.0 for i in range(nosh.ncalc)]
00324 energymatrix = []
00325
00326 for icalc in xrange(nosh.ncalc):
00327 stdout.write("Details of calculation %d:\n" % (icalc+1))
00328 calc = NOsh_getCalc(nosh, icalc)
00329 mgparm = calc.mgparm
00330 pbeparm = calc.pbeparm
00331
00332 if ((sdie == 0) & (pbeparm.sdie != 1)):
00333 sdie = pbeparm.sdie
00334
00335 if calc.calctype != 0:
00336 stderr.write("main: Only multigrid calculations supported!\n")
00337 raise APBSError, "Only multigrid calculations supported!"
00338
00339
00340
00341 if initMG(icalc, nosh, mgparm, pbeparm, realCenter, pbe,
00342 alist, dielXMap, dielYMap, dielZMap, kappaMap, chargeMap,
00343 pmgp, pmg) != 1:
00344 stderr.write("Error setting up MG calculation!\n")
00345 raise APBSError, "Error setting up MG calculation!"
00346
00347
00348
00349 thispmg = get_Vpmg(pmg,icalc)
00350
00351 if solveMG(nosh, thispmg, mgparm.type) != 1:
00352 stderr.write("Error solving PDE! \n")
00353 raise APBSError, "Error Solving PDE!"
00354
00355
00356
00357 if setPartMG(nosh, mgparm, thispmg) != 1:
00358 stderr.write("Error setting partition info!\n")
00359 raise APBSError, "Error setting partition info!"
00360
00361
00362
00363
00364 ret, totEnergy[icalc] = energyMG(nosh, icalc, thispmg, 0,
00365 totEnergy[icalc], 0.0, 0.0, 0.0)
00366
00367 energies = getEnergies(thispmg, get_Valist(alist, 0))
00368 energylist[icalc] = 0.5*energies[iatom]
00369
00370 stdout.write("\n")
00371
00372 for iprint in range(nosh.nprint):
00373 selfEnergy.append(returnEnergy(com, nosh, energylist, iprint))
00374
00375 stdout.write("Self energy value: %.6E kJ/mol for atom %d\n" % (selfEnergy[-1], (iatom+1)))
00376 stdout.write("-----------------------------\n")
00377
00378
00379 killEnergy()
00380 killMG(nosh, pbe, pmgp, pmg)
00381 killChargeMaps(nosh, chargeMap)
00382
00383
00384
00385 killKappaMaps(nosh, kappaMap)
00386 killDielMaps(nosh, dielXMap, dielYMap, dielZMap)
00387
00388
00389
00390 for i in xrange(numAtoms):
00391 reflist[i]=reflist[i]*Python_C
00392
00393
00394
00395 bradlist = []
00396 dij2 = [[0.0 for i in range(numAtoms)] for j in range(numAtoms)]
00397 fGB = [[0.0 for i in range(numAtoms)] for j in range(numAtoms)]
00398 for i in xrange(numAtoms):
00399 brad = -pow(reflist[i],2)*(1-1/sdie)*0.5*Python_Na/(4.0*pi*Python_e0*selfEnergy[i]*1e3)
00400 bradlist.append(brad)
00401
00402 FILE = open(output_param, "w")
00403 FILE.write(str(sdie)+"\n")
00404 FILE.write("radii\tenergy\n")
00405 parameters = zip(bradlist, selfEnergy)
00406 for i in parameters:
00407 print >> FILE, "\t".join(map(str,i))
00408 FILE.close()
00409 stdout.write("GB parameters ouput in %s\n" % output_param)
00410 stdout.write("(1st column, Born radii; 2nd column, self energy)\n")
00411
00412 for i in xrange(numAtoms):
00413 for j in xrange(i+1):
00414
00415 for coord in xrange(3):
00416 dij2[i][j] = dij2[i][j] + pow((position[i][coord]-position[j][coord])*1e-10,2)
00417
00418 d = dij2[i][j]
00419 bradi = bradlist[i]
00420 bradj = bradlist[j]
00421 fGB[i][j] = sqrt(d+bradi*bradj*exp(-d/(4.0*bradi*bradj)))
00422
00423
00424
00425 Gpol = 0.0
00426 for i in xrange(numAtoms):
00427 for j in xrange(numAtoms):
00428 if j <= i:
00429 Gpol = Gpol + reflist[i]*reflist[j]/fGB[i][j]
00430 else:
00431 Gpol = Gpol + reflist[i]*reflist[j]/fGB[j][i]
00432
00433 Gpol = -Gpol*(1-1/sdie)*0.5*1e-3*Python_Na/(4.0*pi*Python_e0)
00434
00435
00436
00437 stdout.write("\nGB Energy: %.10E kJ/mol\n" % Gpol)
00438
00439
00440
00441 if output_matrix != "":
00442 FILE = open(output_matrix, "w")
00443 term = 0.0
00444 for i in range(numAtoms):
00445 for j in range(numAtoms):
00446 if j<=i:
00447 term = reflist[i]*reflist[j]/fGB[i][j]
00448 term = -term*(1-1/sdie)*0.5*1e-3*Python_Na/(4*pi*Python_e0)
00449 FILE.write(str(term)+"\t")
00450 else:
00451 term = reflist[i]*reflist[j]/fGB[j][i]
00452 term = -term*(1-1/sdie)*0.5*1e-3*Python_Na/(4*pi*Python_e0)
00453 FILE.write(str(term)+"\t")
00454 FILE.write("\n")
00455 FILE.close()
00456 stdout.write("Energy matrix ouput in %s\n" % output_matrix)
00457
00458
00459
00460 killMolecules(nosh, alist)
00461
00462 delete_Nosh(nosh)
00463
00464
00465
00466 delete_double_array(realCenter)
00467 delete_int_array(nforce)
00468 delete_atomforcelist(atomforce)
00469 delete_valist(alist)
00470 delete_gridlist(dielXMap)
00471 delete_gridlist(dielYMap)
00472 delete_gridlist(dielZMap)
00473 delete_gridlist(kappaMap)
00474 delete_gridlist(chargeMap)
00475 delete_pmglist(pmg)
00476 delete_pmgplist(pmgp)
00477 delete_pbelist(pbe)
00478
00479
00480
00481 delete_Com(com)
00482 delete_Mem(mem)
00483 stdout.write("\n")
00484 stdout.write("Thanks for using APBS!\n\n")
00485
00486
00487 main_timer_stop = time.clock()
00488 stdout.write("Total execution time: %1.6e sec\n" % (main_timer_stop - main_timer_start))
00489
00490
00491 if __name__ == "__main__": main()