00001
00002
00003 """
00004 mergedx.py - Python script for merging dx files
00005
00006 Written by Todd Dolinsky (todd@ccb.wustl.edu)
00007 Washington University in St. Louis
00008 """
00009
00010 __date__ = "January 2005"
00011 __author__ = "Todd Dolinsky"
00012
00013 VSMALL = 1.0e-9
00014 OUT = "mergedgrid.dx"
00015 HEADER = "\n\n\
00016 ----------------------------------------------------------------------\n\
00017 Adaptive Poisson-Boltzmann Solver (APBS)\n\
00018 Version 1.3 (November 2009)\n\
00019 \n\
00020 Nathan A. Baker (baker@biochem.wustl.edu)\n\
00021 Dept. of Biochemistry and Molecular Biophysics\n\
00022 Center for Computational Biology\n\
00023 Washington University in St. Louis\n\
00024 Additional contributing authors listed in the code documentation.\n\n\
00025 Copyright (c) 2002-2010. Washington University in St. Louis\n\
00026 All Rights Reserved.\n\n\
00027 Portions copyright (c) 1999-2002. University of California.\n\
00028 Portions copyright (c) 1995. Michael Holst.\n\n\
00029 Permission to use, copy, modify, and distribute this software and its\n\
00030 documentation for educational, research, and not-for-profit purposes,\n\
00031 without fee and without a signed licensing agreement, is hereby granted,\n\
00032 provided that the above copyright notice, this paragraph and the\n\
00033 following two paragraphs appear in all copies, modifications, and\n\
00034 distributions.\n\n\
00035 IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT,\n\
00036 INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST\n\
00037 PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,\n\
00038 EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH\n\
00039 DAMAGE.\n\n\
00040 THE AUTHORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT\n\
00041 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n\
00042 PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF\n\
00043 ANY, PROVIDED HEREUNDER IS PROVIDED \"AS IS\". THE AUTHORS HAVE NO\n\
00044 OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n\
00045 MODIFICATIONS.\n\
00046 ----------------------------------------------------------------------\n\
00047 \n\n"
00048
00049 import string
00050 import sys
00051 import getopt
00052 from vgrid import *
00053
00054 def IJK(nx, ny, nz, i, j, k):
00055 """
00056 Translate a three dimensional point to
00057 a one dimensional list
00058
00059 Parameters
00060 nx: No. of total gridpoints in x direction (int)
00061 ny: No. of total gridpoints in y direction (int)
00062 nz: No. of total gridpoints in z direction (int)
00063 i: Specific gridpoint in x direction (int)
00064 j: Specific gridpoint in y direction (int)
00065 k: Specific gridpoint in z direction (int)
00066
00067 Returns
00068 value: The one dimensional value matching the
00069 three dimensional point
00070 """
00071 value = (k*nx*ny + j*nx + i)
00072 return value
00073
00074 def createGrid(inputpath, root):
00075 """
00076 Create the merged grid by use of an APBS input file and
00077 the multiple dx files.
00078
00079 Parameters
00080 inputpath: The path to the APBS input file (string)
00081 root: The root of the name of the multiple dx files,
00082 to be completed with <int>.dx (string)
00083 Returns
00084 mygrid: The merged grid object (Vgrid)
00085 """
00086
00087
00088
00089 myaccess = []
00090 ofrac = [0,0,0]
00091 pdime = [0,0,0]
00092 dime = [0,0,0]
00093 fglen = [0,0,0]
00094 glob = [0,0,0]
00095 mygrid = None
00096 mydata = None
00097
00098
00099
00100 inputfile = open(inputpath)
00101 while 1:
00102 line = inputfile.readline()
00103 if line == "": break
00104 words = string.split(line)
00105 if len(words) == 0: continue
00106 if words[0] == "ofrac":
00107 ofrac[0] = float(words[1])
00108 ofrac[1] = float(words[1])
00109 ofrac[2] = float(words[1])
00110 elif words[0] == "pdime":
00111 pdime[0] = int(words[1])
00112 pdime[1] = int(words[2])
00113 pdime[2] = int(words[3])
00114 elif words[0] == "dime":
00115 dime[0] = int(words[1])
00116 dime[1] = int(words[2])
00117 dime[2] = int(words[3])
00118 elif words[0] == "fglen":
00119 fglen[0] = float(words[1])
00120 fglen[1] = float(words[2])
00121 fglen[2] = float(words[3])
00122
00123 inputfile.close()
00124
00125 if pdime[0] == 1: ofrac[0] = 0
00126 if pdime[1] == 1: ofrac[1] = 0
00127 if pdime[2] == 1: ofrac[2] = 0
00128
00129 glob[0] = pdime[0]*int(round(dime[0]/(1 + 2*ofrac[0])))
00130 glob[1] = pdime[1]*int(round(dime[1]/(1 + 2*ofrac[1])))
00131 glob[2] = pdime[2]*int(round(dime[2]/(1 + 2*ofrac[2])))
00132
00133 size = pdime[0] * pdime[1] * pdime[2]
00134
00135 myxmin = None
00136 myymin = None
00137 myzmin = None
00138 myhx = None
00139 myhy = None
00140 myhz = None
00141 mydata = []
00142
00143
00144
00145 for i in range(size):
00146 mins = []
00147 for j in range(3): mins.append(None)
00148 kp = int(i/(pdime[0]*pdime[1]))
00149 jp = int((i - kp*pdime[0]*pdime[1])/pdime[0])
00150 ip = i - kp*pdime[0]*pdime[1] - jp*pdime[0]
00151 mins[0] = ip*glob[0]/pdime[0]
00152 mins[1] = jp*glob[1]/pdime[1]
00153 mins[2] = kp*glob[2]/pdime[2]
00154
00155
00156 filename = "%s%i.dx" % (root, i)
00157 try:
00158 file = open(filename)
00159 file.close()
00160 except IOError:
00161 print "Unable to find file %s!" % filename
00162 sys.exit()
00163
00164 data = []
00165 grid = Vgrid_ctor(0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, data)
00166
00167 print "Reading dx file %s..." % filename
00168 Vgrid_readDX(grid, "FILE", "ASC", "", filename)
00169 grid.xmax = grid.xmin + grid.hx*(grid.nx - 1)
00170 grid.ymax = grid.ymin + grid.hy*(grid.ny - 1)
00171 grid.zmax = grid.zmin + grid.hzed*(grid.nz - 1)
00172
00173 print "\tGrid dimensions: %i %i %i" % (grid.nx, grid.ny, grid.nz)
00174 print "\tGrid spacing: %.5f %.5f %.5f" % (grid.hx, grid.hy, grid.hzed)
00175 print "\tGrid lower corner: %.2f %.2f %.2f" % (grid.xmin, grid.ymin, grid.zmin)
00176 print "\tGrid upper corner: %.2f %.2f %.2f" % (grid.xmax, grid.ymax, grid.zmax)
00177 print "\tGlobal Gridpoint Minima: %i %i %i\n" % (mins[0], mins[1], mins[2])
00178
00179
00180
00181 if i == 0:
00182 myhx = fglen[0]/(glob[0] - 1)
00183 myhy = fglen[1]/(glob[1] - 1)
00184 myhzed = fglen[2]/(glob[2] - 1)
00185 myxmin = grid.xmin
00186 myymin = grid.ymin
00187 myzmin = grid.zmin
00188 for j in range(glob[0]*glob[1]*glob[2]):
00189 mydata.append(0.0)
00190 myaccess.append(0)
00191
00192
00193
00194 if ip == (pdime[0] - 1):
00195 if glob[0] != (mins[0] + grid.nx):
00196 print "Error occurred - This grid does not line up globally!"
00197 print "Global x-dim gridpoint size: %i" % glob[0]
00198 print "This grid's maximum gridpoint: %i" % (mins[0] + grid.nx)
00199 sys.exit()
00200 if jp == (pdime[1] - 1):
00201 if glob[1] != (mins[1] + grid.ny):
00202 print "Error occurred - This grid does not line up globally!"
00203 print "Global x-dim gridpoint size: %i" % glob[1]
00204 print "This grid's maximum gridpoint: %i" % (mins[1] + grid.ny)
00205 sys.exit()
00206 if kp == (pdime[2] - 1):
00207 if glob[2] != (mins[2] + grid.nz):
00208 print "Error occurred - This grid does not line up globally!"
00209 print "Global x-dim gridpoint size: %i" % glob[2]
00210 print "This grid's maximum gridpoint: %i" % (mins[2] + grid.nz)
00211 sys.exit()
00212
00213
00214
00215 for x in range(grid.nx):
00216 ival = grid.xmin + x*grid.hx
00217 for y in range(grid.ny):
00218 jval = grid.ymin + y*grid.hy
00219 for z in range(grid.nz):
00220 kval = grid.zmin + z*grid.hzed
00221 inval = 0.0
00222 pt = [ival, jval, kval]
00223 ret, value = Vgrid_value(grid, pt, inval)
00224 if ret:
00225 location = IJK(glob[0], glob[1], glob[2], (x+mins[0]), (y+mins[1]), (z+mins[2]))
00226 myaccess[location] += 1
00227 mydata[location] = value
00228 else:
00229 print ival, jval, kval
00230 print "Could not find gridpoint %i %i %i in grid %s!" % (x,y,z, filename)
00231 sys.exit()
00232
00233
00234
00235 delete_vgrid(grid)
00236
00237
00238
00239 print "Ensuring all grid points were merged..."
00240 for i in range(glob[0]):
00241 for j in range(glob[1]):
00242 for k in range(glob[2]):
00243 location = IJK(glob[0], glob[1], glob[2], i, j, k)
00244 if myaccess[location] == 0:
00245 print "Error: Found unaccessed gridpoint at %i %i %i!" % (i,j,k)
00246 sys.exit()
00247 elif myaccess[location] > 1:
00248 print "Error: Multiple grids attempted to access gridpoint %i %i %i in the global grid!" % (i,j,k)
00249 sys.exit()
00250
00251
00252
00253
00254 mygrid = Vgrid_ctor(glob[0], glob[1], glob[2], myhx, myhy, myhzed,
00255 myxmin, myymin, myzmin, mydata)
00256
00257 return mygrid
00258
00259 def resampleGrid(grid, nx, ny, nz):
00260 """
00261 Resample the grid to a smaller (less-defined) resolution
00262
00263 Parameters
00264 grid: The merged grid (Vgrid)
00265 nx: The number of gridpoints in the x dir (int)
00266 nx: The number of gridpoints in the x dir (int)
00267 nx: The number of gridpoints in the x dir (int)
00268
00269 Retrurns
00270 newgrid: The resampleed merged grid (Vgrid)
00271 """
00272
00273 print "Resampling the grid..."
00274
00275
00276
00277 if (nx > grid.nx or ny > grid.ny or nz > grid.nz):
00278 print "Error: User specified grid size (%i %i %i) is larger than " % (nx, ny, nz)
00279 print "merged grid size (%i %i %i)!" % (grid.nx, grid.ny, grid.nz)
00280 sys.exit()
00281
00282
00283
00284 xmin = grid.xmin
00285 ymin = grid.ymin
00286 zmin = grid.zmin
00287 xmax = grid.xmin + grid.hx*(grid.nx - 1)
00288 ymax = grid.ymin + grid.hy*(grid.ny - 1)
00289 zmax = grid.zmin + grid.hzed*(grid.nz - 1)
00290 hxnew = (xmax - xmin)/(nx - 1)
00291 hynew = (ymax - ymin)/(ny - 1)
00292 hznew = (zmax - zmin)/(nz - 1)
00293 mydata = []
00294 for i in range(nx*ny*nz): mydata.append(0.0)
00295
00296
00297
00298 for x in range(nx):
00299 ival = xmin + x*hxnew
00300 for y in range(ny):
00301 jval = ymin + y*hynew
00302 for z in range(nz):
00303 kval = zmin + z*hznew
00304 pt = [ival, jval, kval]
00305 inval = 0.0
00306 ret, value = Vgrid_value(grid, pt, inval)
00307 if ret:
00308 location = IJK(nx, ny, nz, x,y,z)
00309 if (value < VSMALL and value > 0): value = 0.0
00310 mydata[location] = value
00311 else:
00312 print "Could not find gridpoint %i %i %i in grid %s!" % (x,y,z, filename)
00313 sys.exit()
00314
00315
00316 delete_vgrid(grid)
00317
00318
00319 newgrid = Vgrid_ctor(nx, ny, nz, hxnew, hynew, hznew,
00320 xmin, ymin, zmin, mydata)
00321 return newgrid
00322
00323 def printGrid(mygrid, outpath):
00324 """
00325 Print the merged grid using the Vgrid_writeDX command
00326
00327 Parameters
00328 mygrid: The merged grid (Vgrid)
00329 outpath: The output path for the new .dx file (string)
00330 """
00331 print "Writing output to %s..." % outpath
00332 title = "Merged Grid from mergedx.py"
00333 Vgrid_writeDX(mygrid, "FILE", "ASC", "", outpath,title, null_array());
00334
00335 def usage():
00336 """
00337 Print usage information
00338 """
00339 str = "%s" % HEADER
00340 str = str + "mergedx.py\n"
00341 str = str + "\n"
00342 str = str + "This module merges multiple dx files generated from parallel\n"
00343 str = str + "APBS runs into one merged dx file. Users may also resample the\n"
00344 str = str + "grid size if desired. Default output is written to mergedgrid.dx\n"
00345 str = str + "\n"
00346 str = str + "Usage: mergedx.py [options] <input-file> <dx-stem>\n"
00347 str = str + "\n"
00348 str = str + " Required Arguments:\n"
00349 str = str + " <input-file> : The path to an APBS input file used to\n"
00350 str = str + " generate the dx file. If the APBS run was\n"
00351 str = str + " asynchronous, any of the input files may be used\n"
00352 str = str + " <dx-stem> : The stem of the dx filenames. This script will\n"
00353 str = str + " add the digit and the .dx extension - note that\n"
00354 str = str + " the dx files MUST be trailed by the form *.dx\n"
00355 str = str + "\n"
00356 str = str + " Example: given dx files 2PHKB-PE0.dx and 2PHKB-PE1.dx,\n"
00357 str = str + " the stem would be 2PHKB-PE\n"
00358 str = str + "\n"
00359 str = str + " Optional Arguments:\n"
00360 str = str + " --help (-h) : Display the usage information\n"
00361 str = str + " --out=<outpath>: Save merged dx file into filename <outpath>\n"
00362 str = str + " --nx=<xsize> : Resample to the <xsize> gridpoints in the x direction\n"
00363 str = str + " --ny=<ysize> : Resample to the <ysize> gridpoints in the z direction\n"
00364 str = str + " --nz=<zsize> : Resample to the <zsize> gridpoints in the z direction\n"
00365 str = str + " Note: If resampling, nx, ny, and nz all must be specified.\n"
00366 str = str + "\n"
00367 sys.stderr.write(str)
00368 sys.exit()
00369
00370 def main():
00371 """
00372 The main driver for the mergedx script
00373 """
00374 shortOptlist = "h"
00375 longOptlist = ["help","out=","nx=","ny=","nz="]
00376 try: opts, args = getopt.getopt(sys.argv[1:], shortOptlist, longOptlist)
00377 except getopt.GetoptError, details:
00378 sys.stderr.write("GetoptError: %s\n" % details)
00379 usage()
00380
00381 outpath = OUT
00382 nx = None
00383 ny = None
00384 nz = None
00385 resample = 0
00386 for o,a in opts:
00387 if o in ("-h","--help"):
00388 usage()
00389 sys.exit()
00390 elif o == "--out":
00391 outpath = a
00392 elif o == "--nx":
00393 nx = int(a)
00394 elif o == "--ny":
00395 ny = int(a)
00396 elif o == "--nz":
00397 nz = int(a)
00398
00399 if (nx != None and ny != None and nz != None):
00400 resample = 1
00401 elif (nx == None and ny == None and nz == None):
00402 pass
00403 else:
00404 print "\nYou must enter either none or all values for nx, ny, and nz!"
00405 usage()
00406 sys.exit()
00407
00408 argid = 1
00409 if outpath != OUT: argid += 1
00410 if resample == 1: argid += 3
00411
00412 try:
00413 inputpath = sys.argv[argid]
00414 root = sys.argv[argid + 1]
00415 except IndexError:
00416 print "\nImproper number of arguments!"
00417 usage()
00418 sys.exit()
00419
00420 startVio()
00421
00422 mygrid = createGrid(inputpath, root)
00423 if resample:
00424 mygrid = resampleGrid(mygrid,nx,ny,nz)
00425 printGrid(mygrid, outpath)
00426
00427
00428 delete_vgrid(mygrid)
00429
00430 if __name__ == "__main__": main()