• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

tools/python/noinput.py

00001 #!/usr/bin/python
00002 """ Python APBS No Input Driver File
00003     
00004     This module allows a user to run APBS through Python. Use this module if
00005     you wish to include APBS in a Python-based application.  This specific
00006     version allows a user to read in data from the Python level without
00007     using the command line - thus enabling the ability to link seamlessly
00008     with other Python programs.  Here the 'INPUT and 'PQR' variables are
00009     predetermined global strings, but can (and *should*) be dynamically created
00010     as desired - that's one of the main advantages of using Python!
00011 
00012     It is strongly recommended that you edit out any part of this script that
00013     you do not need - many different options are included, but this makes the
00014     code much harder to read.  I
00015 
00016     The module mimics the main.c driver that is used in the C version of APBS.
00017     The functions which are called are located in apbslib.py, which is 
00018     automatically generated by SWIG to wrap each APBS function.  See the APBS
00019     documentation for more information about each function.
00020 
00021     To access energy, potential, or force vectors for further use, see the
00022     appropriate printResults() function at the top of this script.  This is
00023     merely an example - instead of printing the forces and energies you'll
00024     simply want to pass the arrays to other Python functions.
00025 
00026     NOTE:  You ***MUST*** use
00027 
00028         calcforce comps
00029 
00030     in the input file for each calculation that you wish to obtain a force
00031     vector - otherwise the vector will NOT be calculated.
00032 
00033     Todd Dolinsky (todd@ccb.wustl.edu)
00034     Nathan Baker (baker@biochem.wustl.edu)
00035     Washington University in St. Louis
00036 
00037            APBS -- Adaptive Poisson-Boltzmann Solver
00038 
00039              Nathan A. Baker (baker@biochem.wustl.edu)
00040              Dept. Biochemistry and Molecular Biophysics
00041              Center for Computational Biology
00042              Washington University in St. Louis
00043 
00044              Additional contributing authors listed in the code documentation.
00045 
00046            Copyright (c) 2002-2010, Washington University in St. Louis.
00047            Portions Copyright (c) 2002-2010.  Nathan A. Baker
00048            Portions Copyright (c) 1999-2002.  The Regents of the University of California.
00049            Portions Copyright (c) 1995.  Michael Holst
00050 
00051            All rights reserved.
00052 
00053            Redistribution and use in source and binary forms, with or without
00054            modification, are permitted provided that the following conditions are met: 
00055 
00056            * Redistributions of source code must retain the above copyright notice, this
00057            list of conditions and the following disclaimer.  
00058 
00059            * Redistributions in binary form must reproduce the above copyright notice,
00060            this list of conditions and the following disclaimer in the documentation
00061            and/or other materials provided with the distribution.
00062 
00063            * Neither the name of Washington University in St. Louis nor the names of its
00064            contributors may be used to endorse or promote products derived from this
00065            software without specific prior written permission.
00066 
00067            THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00068            "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00069            LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00070            A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00071            CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00072            EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00073            PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00074            PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00075            LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00076            NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00077            SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00078 """    
00079 
00080 from apbslib import *
00081 import sys, time
00082 import string
00083 import re
00084 from sys import stdout, stderr
00085 
00086 __author__ = "Todd Dolinsky, Nathan Baker"
00087 __date__ = "July 2007"
00088 
00089 INPUT = """read
00090     mol pqr ion.pqr
00091 end
00092 elec name solvated
00093     mg-manual
00094     dime 65 65 65
00095     nlev 4
00096     grid 0.33 0.33 0.33
00097     gcent mol 1
00098     chgm spl2
00099     mol 1
00100     lpbe
00101     bcfl mdh
00102     ion 1 0.000 2.0
00103     ion -1 0.000 2.0
00104     pdie 1.0
00105     sdie 78.54
00106     chgm spl2
00107     srfm spl2
00108     sdens 10.0
00109     srad 1.4
00110     swin 0.3
00111     temp 298.15
00112     gamma 0.105
00113     calcenergy total
00114     calcforce comps
00115 end
00116 elec name reference
00117     mg-manual
00118     dime 65 65 65
00119     nlev 4
00120     grid 0.33 0.33 0.33
00121     gcent mol 1
00122     mol 1
00123     lpbe
00124     bcfl mdh
00125     ion 1 0.000 2.0
00126     ion -1 0.000 2.0
00127     pdie 1.0
00128     sdie 1.0
00129     chgm spl2
00130     srfm spl2
00131     sdens 10.0
00132     srad 1.4
00133     swin 0.3
00134     temp 298.15
00135     gamma 0.105
00136     calcenergy total
00137     calcforce comps
00138 end
00139  
00140 print energy 1 - 2 end
00141  
00142 quit
00143 """
00144  
00145 PQR = "ATOM      1  I   ION     1       0.000   0.000  0.000  1.00  3.00"
00146 
00147 Python_kb = 1.3806581e-23
00148 Python_Na = 6.0221367e+23
00149 NOSH_MAXMOL = 20
00150 NOSH_MAXCALC = 20
00151 
00152 class APBSError(Exception):
00153     """ APBSError class
00154 
00155         The APBSError class inherits off the Exception module and returns
00156         a string defining the nature of the error. 
00157     """
00158     
00159     def __init__(self, value):
00160         """
00161             Initialize with error message
00162 
00163             Parameters
00164                 value:  Error Message (string)
00165         """
00166         self.value = value
00167         
00168     def __str__(self):
00169         """
00170             Return the error message
00171         """
00172         return `self.value`
00173 
00174 def getUnitConversion():
00175     """
00176         Get the unit conversion from kT to kJ/mol
00177 
00178         Returns
00179             factor: The conversion factor (float)
00180     """
00181     temp = 298.15
00182     factor = Python_kb/1000.0 * temp * Python_Na
00183     return factor
00184 
00185 def getHeader():
00186     """ Get header information about APBS
00187         Returns (header)
00188             header: Information about APBS
00189     """
00190 
00191     """ Get header information about APBS
00192         Returns (header)
00193             header: Information about APBS
00194     """
00195 
00196     header = "\n\n\
00197     ----------------------------------------------------------------------\n\
00198     Adaptive Poisson-Boltzmann Solver (APBS)\n\
00199     Version 1.3\n\
00200     \n\
00201     APBS -- Adaptive Poisson-Boltzmann Solver\n\
00202     \n\
00203     Nathan A. Baker (baker@biochem.wustl.edu)\n\
00204     Dept. Biochemistry and Molecular Biophysics\n\
00205     Center for Computational Biology\n\
00206     Washington University in St. Louis\n\
00207     \n\
00208     Additional contributing authors listed in the code documentation.\n\
00209     \n\
00210     Copyright (c) 2002-2010, Washington University in St. Louis.\n\
00211     Portions Copyright (c) 2002-2010.  Nathan A. Baker\n\
00212     Portions Copyright (c) 1999-2002.  The Regents of the University of California.\n\
00213     Portions Copyright (c) 1995.  Michael Holst\n\
00214     \n\
00215     All rights reserved.\n\
00216     \n\
00217     Redistribution and use in source and binary forms, with or without\n\
00218     modification, are permitted provided that the following conditions are met:\n\
00219     \n\
00220     * Redistributions of source code must retain the above copyright notice, this\n\
00221       list of conditions and the following disclaimer.\n\
00222     \n\
00223     * Redistributions in binary form must reproduce the above copyright notice,\n\
00224       this list of conditions and the following disclaimer in the documentation\n\
00225       and/or other materials provided with the distribution.\n\
00226     \n\
00227     * Neither the name of Washington University in St. Louis nor the names of its\n\
00228       contributors may be used to endorse or promote products derived from this\n\
00229       software without specific prior written permission.\n\
00230     \n\
00231     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\
00232     \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\
00233     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
00234     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n\
00235     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n\
00236     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n\
00237     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n\
00238     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n\
00239     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n\
00240     NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n\
00241     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
00242     ----------------------------------------------------------------------\n\
00243     \n\n"
00244     return header
00245 
00246 def getUsage():
00247     """ Get usage information about running APBS via Python
00248         Returns (usage)
00249             usage: Text about running APBS via Python
00250     """
00251     
00252     usage = "\n\n\
00253     ----------------------------------------------------------------------\n\
00254     This driver program calculates electrostatic potentials, energies,\n\
00255     and forces using both multigrid methods.\n\
00256     It is invoked as:\n\n\
00257       python noinput.py\n\
00258     ----------------------------------------------------------------------\n\n"
00259 
00260     return usage
00261 
00262 
00263 def printResults(energyList, potList, forceList):
00264     """
00265         Print the results stored in the energy, potential and force lists to
00266         stdout. The arrays are accessed as follows:
00267 
00268         energyList[calc #][atom #]: Per-atom energy for a specific calc #
00269 
00270         potList[calc #][atom #]  :  Per-atom potential for a specific calc #
00271 
00272         forceList is a little more difficult, as it is a list of dictionaries
00273         of lists:
00274 
00275         forceList[calc #]['force type'][atom #][x=0/y=1/z=2 direction ]
00276 
00277         So to access the qf x-component force from the first APBS elec
00278         calculation for the 2nd (atom id 1) atom, you can access
00279 
00280         forceList[0]['qf'][1][0]
00281 
00282         If you plan on using these lists extensively it would be wise to
00283         convert them into Python objects - this format is the cleanest for
00284         getting information back out from C, but not for dealing between
00285         Python functions.  
00286     """
00287     # Print the per-atom energies
00288     #    Each list corresponds to a calculation, having len(atoms) entries
00289 
00290     factor = getUnitConversion()
00291 
00292     for i in range(len(potList)):
00293         list = potList[i]
00294         print "\nPer-atom potentials from calculation %i" % i
00295         for j in range(len(list)):
00296             atom = list[j]
00297             print "\t%i\t%.4f kT/e" % (j, (float(atom)))     
00298     
00299     for i in range(len(energyList)):
00300         list = energyList[i]
00301         print "\nPer-atom energies from calculation %i" % i
00302         for j in range(len(list)):
00303             atom = list[j]
00304             print "\t%i\t%.4f kJ/mol" % (j, (float(atom) * factor * 0.5))     
00305 
00306     # Print the per-atom forces
00307 
00308     for i in range(len(forceList)):
00309         qflist = forceList[i]["qf"]
00310         iblist = forceList[i]["ib"]
00311         dblist = forceList[i]["db"]
00312         
00313         print "\nPer-atom forces from calculation %i" % i
00314         for j in range(len(qflist)):
00315             qf = "%.3E %.3E %.3E" % (qflist[j][0]*factor, qflist[j][1]*factor, qflist[j][2]*factor)
00316             ib = "%.3E %.3E %.3E" % (iblist[j][0]*factor, iblist[j][1]*factor, iblist[j][2]*factor)
00317             db = "%.3E %.3E %.3E" % (dblist[j][0]*factor, dblist[j][1]*factor, dblist[j][2]*factor)
00318             print "\t%i\t%s (qf)" % (j, qf)
00319             print "\t%i\t%s (ib)" % (j, ib)
00320             print "\t%i\t%s (db)" % (j, db)
00321 
00322 
00323 def runAPBS(PQR, INPUT):
00324     """ Main driver for testing.  Runs APBS on given input file """
00325     
00326     # Initialize variables, arrays
00327     com = Vcom_ctor(1)
00328     rank = Vcom_rank(com)
00329     size = Vcom_size(com)
00330     mgparm = MGparm()
00331     pbeparm = PBEparm()
00332     mem = Vmem_ctor("Main")
00333     pbe = new_pbelist(NOSH_MAXMOL)
00334     pmg = new_pmglist(NOSH_MAXMOL)
00335     pmgp = new_pmgplist(NOSH_MAXMOL)
00336     realCenter = double_array(3)
00337     totEnergy = []
00338     x = []
00339     y = []
00340     z = []
00341     chg = []
00342     rad = []
00343     nforce = int_array(NOSH_MAXCALC)
00344     atomforce = new_atomforcelist(NOSH_MAXCALC)
00345 
00346     # Start the main timer
00347     main_timer_start = time.clock()
00348 
00349     # Parse the input file
00350     nosh = NOsh_ctor(rank, size)
00351 
00352     # Instead of having an input file, we have a string!
00353 
00354     if not parseInputFromString(nosh, INPUT):
00355         stderr.write("main:  Error while parsing input file.\n")
00356         raise APBSError, "Error occurred!"
00357    
00358     # Load the molecules using Valist_load routine, thereby
00359     # loading atoms directly into the valist object, removing
00360     # the need for an actual PQR file from stdin
00361 
00362     alist = new_valist(NOSH_MAXMOL)
00363     atoms = string.split(PQR,"\n")
00364     for i in range(len(atoms)):
00365         atom = atoms[i]
00366         if not (atom.startswith("ATOM") or atom.startswith("HETATM")): continue
00367         if atom == "": continue
00368 
00369         # Try matching to see if a chain ID is present
00370         haschain = 0
00371         if re.compile("( [A-Z]{3} [A-Z]{1} *\d+)").findall(atom) != []:
00372             haschain = 1
00373 
00374         params = string.split(atom)
00375         x.append(float(params[5+haschain]))
00376         y.append(float(params[6+haschain]))
00377         z.append(float(params[7+haschain]))
00378         chg.append(float(params[8+haschain]))
00379         rad.append(float(params[9+haschain]))
00380     
00381     # If there are more than one PQR file, make multiple Valist
00382     # objects.  Make sure to get the actual length of the
00383     # coordinate since atoms may contain non ATOM lines.
00384 
00385     myAlist = make_Valist(alist,0)
00386     Valist_load(myAlist, len(x), x,y,z,chg,rad)  
00387 
00388     if not NOsh_setupElecCalc(nosh, alist):
00389         stderr.write("main: Error setting up calculation.\n")
00390         raise APBSError, "Error setting up calculations!"
00391 
00392 
00393     for i in range(nosh.ncalc): totEnergy.append(0.0)
00394 
00395     # Initialize the Python holders
00396     energyList = []
00397     potList = []
00398     forceList = []
00399 
00400     # Load the various maps - since this example shows how to eliminate
00401     # inputs from the command line, this will probably not be used
00402   
00403     dielXMap = new_gridlist(NOSH_MAXMOL)
00404     dielYMap = new_gridlist(NOSH_MAXMOL)
00405     dielZMap = new_gridlist(NOSH_MAXMOL)
00406     if loadDielMaps(nosh, dielXMap, dielYMap, dielZMap) != 1:
00407         stderr.write("Error reading dielectric maps!\n")
00408         raise APBSError, "Error reading dielectric maps!"
00409 
00410     kappaMap = new_gridlist(NOSH_MAXMOL)
00411     if loadKappaMaps(nosh, kappaMap) != 1:
00412         stderr.write("Error reading kappa maps!\n")
00413         raise APBSError, "Error reading kappa maps!"
00414 
00415     chargeMap = new_gridlist(NOSH_MAXMOL)
00416     if loadChargeMaps(nosh, chargeMap) != 1:
00417         stderr.write("Error reading charge maps!\n")
00418         raise APBSError, "Error reading charge maps!"
00419 
00420     # Do the calculations
00421 
00422     stdout.write("Preparing to run %d PBE calculations. \n" % nosh.ncalc)
00423 
00424     for icalc in xrange(nosh.ncalc):
00425         stdout.write("---------------------------------------------\n")
00426         calc = NOsh_getCalc(nosh, icalc)
00427         mgparm = calc.mgparm
00428         pbeparm = calc.pbeparm
00429         if calc.calctype != 0:
00430             stderr.write("main:  Only multigrid calculations supported!\n")
00431             raise APBSError, "Only multigrid calculations supported!"
00432 
00433         for k in range(0, nosh.nelec):
00434             if NOsh_elec2calc(nosh,k) >= icalc:
00435                 break
00436 
00437         name = NOsh_elecname(nosh, k)
00438         if name == "":
00439             stdout.write("CALCULATION #%d:  MULTIGRID\n" % (icalc+1))
00440         else:
00441             stdout.write("CALCULATION #%d (%s): MULTIGRID\n" % ((icalc+1),name))
00442         stdout.write("Setting up problem...\n")
00443            
00444         # Routine initMG
00445         
00446         if initMG(icalc, nosh, mgparm, pbeparm, realCenter, pbe, 
00447               alist, dielXMap, dielYMap, dielZMap, kappaMap, chargeMap, 
00448               pmgp, pmg) != 1:
00449             stderr.write("Error setting up MG calculation!\n")
00450             raise APBSError, "Error setting up MG calculation!"
00451            
00452         # Print problem parameters if desired (comment out if you want
00453         # to minimize output to stdout)
00454            
00455         printMGPARM(mgparm, realCenter)
00456         printPBEPARM(pbeparm)
00457       
00458         # Solve the problem : Routine solveMG
00459            
00460         thispmg = get_Vpmg(pmg,icalc)
00461 
00462         if solveMG(nosh, thispmg, mgparm.type) != 1:
00463             stderr.write("Error solving PDE! \n")
00464             raise APBSError, "Error Solving PDE!"
00465 
00466         # Set partition information : Routine setPartMG
00467 
00468         if setPartMG(nosh, mgparm, thispmg) != 1:
00469             stderr.write("Error setting partition info!\n")
00470             raise APBSError, "Error setting partition info!"
00471            
00472         # Get the energies - the energy for this calculation
00473         # (calculation number icalc) will be stored in the totEnergy array
00474         ret, totEnergy[icalc] = energyMG(nosh, icalc, thispmg, 0, 0.0, 0.0, 0.0, 0.0)
00475 
00476         # Calculate forces - doforce will be > 0 if anything other than
00477         # "calcforce no" is specified
00478         
00479         aforce = get_AtomForce(atomforce, icalc)
00480         doforce = wrap_forceMG(mem, nosh, pbeparm, mgparm, thispmg, aforce, alist, nforce, icalc)
00481       
00482         # Write out data from MG calculations : Routine writedataMG          
00483         writedataMG(rank, nosh, pbeparm, thispmg)
00484            
00485         # Write out matrix from MG calculations        
00486         writematMG(rank, nosh, pbeparm, thispmg)
00487 
00488         # Get the per-atom potentials and energies from this calculation.
00489 
00490         potentials = getPotentials(nosh, pbeparm, thispmg, myAlist)
00491         potList.append(potentials)
00492                
00493         energies = getEnergies(thispmg, myAlist)
00494         energyList.append(energies)
00495 
00496         # Get the forces from this calculation and store the result in
00497         # forceList.  For information on how to use this array see
00498         # printResults()
00499 
00500         if doforce:
00501             forceList.append(getForces(aforce, myAlist))
00502     
00503     # Handle print statements - comment out if limiting output to stdout
00504 
00505     if nosh.nprint > 0:
00506         stdout.write("---------------------------------------------\n")
00507         stdout.write("PRINT STATEMENTS\n")
00508     for iprint in xrange(nosh.nprint):
00509         if NOsh_printWhat(nosh, iprint) == NPT_ENERGY:
00510             printEnergy(com, nosh, totEnergy, iprint)
00511         elif NOsh_printWhat(nosh, iprint) == NPT_FORCE:
00512             printForce(com, nosh, nforce, atomforce, iprint)
00513         else:
00514             stdout.write("Undefined PRINT keyword!\n")
00515             break
00516                 
00517     stdout.write("----------------------------------------\n")
00518     stdout.write("CLEANING UP AND SHUTTING DOWN...\n")
00519 
00520     # Clean up APBS structures
00521     killForce(mem, nosh, nforce, atomforce)
00522     killEnergy()
00523     killMG(nosh, pbe, pmgp, pmg)
00524     killChargeMaps(nosh, chargeMap)
00525     killKappaMaps(nosh, kappaMap)
00526     killDielMaps(nosh, dielXMap, dielYMap, dielZMap)
00527     killMolecules(nosh, alist)
00528     #delete_Nosh(nosh)
00529     
00530     # Clean up Python structures
00531 
00532     delete_double_array(realCenter)
00533     delete_int_array(nforce)
00534     delete_atomforcelist(atomforce)
00535     delete_valist(alist)
00536     delete_gridlist(dielXMap)
00537     delete_gridlist(dielYMap)
00538     delete_gridlist(dielZMap)
00539     delete_gridlist(kappaMap)
00540     delete_gridlist(chargeMap)
00541     delete_pmglist(pmg)
00542     delete_pmgplist(pmgp)
00543     delete_pbelist(pbe)
00544         
00545     # Clean up MALOC structures
00546     #delete_Com(com)
00547     #delete_Mem(mem)
00548     stdout.write("\n")
00549     stdout.write("Thanks for using APBS!\n\n")
00550 
00551     # Stop the main timer
00552     main_timer_stop = time.clock()
00553     stdout.write("Total execution time:  %1.6e sec\n" % (main_timer_stop - main_timer_start))
00554 
00555     return energyList, potList, forceList
00556 
00557 if __name__ == "__main__":
00558     
00559     # Check invocation
00560     stdout.write(getHeader())
00561     if len(sys.argv) != 1:
00562         stderr.write("main:  Called with %d arguments!\n" % len(sys.argv))
00563         stderr.write(getUsage())
00564         raise APBSError, "Incorrect Usage!"
00565 
00566     energyList, potList, forceList = runAPBS(PQR, INPUT)
00567 
00568     # As an example, print the resulting information
00569 
00570     printResults(energyList, potList, forceList)

Generated on Wed Oct 20 2010 11:12:21 for APBS by  doxygen 1.7.2