/python/pyclaw/io/ascii.py

http://github.com/clawpack/clawpack-4.x · Python · 428 lines · 340 code · 27 blank · 61 comment · 56 complexity · 3b2ea60dfb0053668c41356e54b1d210 MD5 · raw file

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. r"""
  4. Routines for reading and writing an ascii output file
  5. :Authors:
  6. Kyle T. Mandli (2008-02-07) Initial version
  7. """
  8. # ============================================================================
  9. # Copyright (C) 2008 Kyle T. Mandli <mandli@amath.washington.edu>
  10. #
  11. # Distributed under the terms of the Berkeley Software Distribution (BSD)
  12. # license
  13. # http://www.opensource.org/licenses/
  14. # ============================================================================
  15. import os,sys
  16. import logging
  17. import numpy as np
  18. from pyclaw.util import read_data_line
  19. import pyclaw.solution
  20. logger = logging.getLogger('io')
  21. def write_ascii(solution,frame,path,file_prefix='fort',write_aux=False,
  22. options={}):
  23. r"""
  24. Write out ascii data file
  25. Write out an ascii file formatted identical to the fortran clawpack files
  26. including writing out fort.t, fort.q, and fort.aux if necessary. Note
  27. that there are some parameters that assumed to be the same for every grid
  28. in this format which is not necessarily true for the actual data objects.
  29. Make sure that if you use this output format that all of you grids share
  30. the appropriate values of ndim, meqn, maux, and t. Only supports up to
  31. 3 dimensions.
  32. :Input:
  33. - *solution* - (:class:`~pyclaw.solution.Solution`) Pyclaw object to be
  34. output.
  35. - *frame* - (int) Frame number
  36. - *path* - (string) Root path
  37. - *file_prefix* - (string) Prefix for the file name. ``default = 'fort'``
  38. - *write_aux* - (bool) Boolean controlling whether the associated
  39. auxiliary array should be written out. ``default = False``
  40. - *options* - (dict) Optional argument dictionary which in the case for
  41. ``ascii`` output contains nothing.
  42. """
  43. # Option parsing
  44. option_defaults = {}
  45. for (k,v) in option_defaults.iteritems():
  46. if options.has_key(k):
  47. exec("%s = options['%s']" % (k,k))
  48. else:
  49. exec('%s = v' % k)
  50. try:
  51. # Create file name
  52. file_name = '%s.t%s' % (file_prefix,str(frame).zfill(4))
  53. f = open(os.path.join(path,file_name),'w')
  54. # Header for fort.txxxx file
  55. f.write("%18.8e time\n" % solution.t)
  56. f.write("%5i meqn\n" % solution.meqn)
  57. f.write("%5i ngrids\n" % len(solution.grids))
  58. f.write("%5i maux\n" % solution.maux)
  59. f.write("%5i ndim\n" % solution.ndim)
  60. f.close()
  61. # Open fort.qxxxx for writing
  62. file_name = 'fort.q%s' % str(frame).zfill(4)
  63. q_file = open(os.path.join(path,file_name),'w')
  64. # If maux != 0 then we open up a file to write it out as well
  65. if solution.maux > 0 and write_aux:
  66. file_name = 'fort.a%s' % str(frame).zfill(4)
  67. aux_file = open(os.path.join(path,file_name),'w')
  68. # for i in range(0,len(solution.grids)):
  69. for grid in solution.grids:
  70. # Header for fort.qxxxx file
  71. q_file.write("%5i grid_number\n" % grid.gridno)
  72. q_file.write("%5i AMR_level\n" % grid.level)
  73. for dim in grid.dimensions:
  74. q_file.write("%5i m%s\n" % (dim.n,dim.name))
  75. for dim in grid.dimensions:
  76. q_file.write("%18.8e %slow\n" % (dim.lower,dim.name))
  77. for dim in grid.dimensions:
  78. q_file.write("%18.8e d%s\n" % (dim.d,dim.name))
  79. q_file.write("\n")
  80. # Write data from q
  81. q = grid.q
  82. dims = grid.dimensions
  83. if grid.ndim == 1:
  84. for k in xrange(dims[0].n):
  85. for m in xrange(solution.meqn):
  86. q_file.write("%16.8e" % q[k,m])
  87. q_file.write('\n')
  88. elif grid.ndim == 2:
  89. for j in xrange(dims[1].n):
  90. for k in xrange(dims[0].n):
  91. for m in xrange(solution.meqn):
  92. q_file.write("%16.8e" % q[k,j,m])
  93. q_file.write('\n')
  94. q_file.write('\n')
  95. elif grid.ndim == 3:
  96. for l in xrange(dims[2].n):
  97. for j in xrange(dims[1].n):
  98. for k in xrange(dims[0].n):
  99. for m in range(solution.meqn):
  100. q_file.write("%16.8e" % q[k,j,l,m])
  101. q_file.write('\n')
  102. q_file.write('\n')
  103. q_file.write('\n')
  104. else:
  105. raise Exception("Dimension Exception in writing fort file.")
  106. if grid.maux > 0 and write_aux:
  107. aux = grid.aux
  108. aux_file.write("%5i grid_number\n" % grid.gridno)
  109. aux_file.write("%5i AMR_level\n" % grid.level)
  110. for dim in grid.dimensions:
  111. aux_file.write("%5i m%s\n" % (dim.n,dim.name))
  112. for dim in grid.dimensions:
  113. aux_file.write("%18.8e %slow\n" % (dim.lower,dim.name))
  114. for dim in grid.dimensions:
  115. aux_file.write("%18.8e d%s\n" % (dim.d,dim.name))
  116. aux_file.write("\n")
  117. if grid.ndim == 1:
  118. for k in xrange(grid.dimensions[0]):
  119. for m in xrange(grid.maux):
  120. aux_file.write("%16.8e" % aux[k,m])
  121. aux_file.write('\n')
  122. elif grid.ndim == 2:
  123. for j in xrange(grid.dimensions[1].n):
  124. for k in xrange(grid.dimension[0].n):
  125. for m in xrange(grid.maux):
  126. aux_file.write("%16.8e" % aux[k,j,m])
  127. aux_file.write('\n')
  128. aux_file.write('\n')
  129. elif grid.ndim == 3:
  130. for l in xrange(grid.dimensions[2].n):
  131. for j in xrange(grid.dimensions[1].n):
  132. for k in xrange(grid.dimensions[0].n):
  133. for m in xrange(grid.maux):
  134. aux_file.write("%16.8e" % aux[k,j,l,m])
  135. aux_file.write('\n')
  136. aux_file.write('\n')
  137. aux_file.write('\n')
  138. q_file.close()
  139. if grid.maux > 0 and write_aux:
  140. aux_file.close()
  141. except IOError, (errno, strerror):
  142. logger.error("Error writing file: %s" % os.path.join(path,file_name))
  143. logger.error("I/O error(%s): %s" % (errno, strerror))
  144. raise
  145. except:
  146. logger.error("Unexpected error:", sys.exc_info()[0])
  147. raise
  148. def read_ascii(solution,frame,path='./',file_prefix='fort',read_aux=False,
  149. options={}):
  150. r"""
  151. Read in a set of ascii formatted files
  152. This routine reads the ascii formatted files corresponding to the classic
  153. clawpack format 'fort.txxxx', 'fort.qxxxx', and 'fort.axxxx' or 'fort.aux'
  154. Note that the fort prefix can be changed.
  155. :Input:
  156. - *solution* - (:class:`~pyclaw.solution.Solution`) Solution object to
  157. read the data into.
  158. - *frame* - (int) Frame number to be read in
  159. - *path* - (string) Path to the current directory of the file
  160. - *file_prefix* - (string) Prefix of the files to be read in.
  161. ``default = 'fort'``
  162. - *read_aux* (bool) Whether or not an auxillary file will try to be read
  163. in. ``default = False``
  164. - *options* - (dict) Dictionary of options particular to this format
  165. which in the case of ``ascii`` files is empty.
  166. """
  167. # Option parsing
  168. option_defaults = {}
  169. for (k,v) in option_defaults.iteritems():
  170. if options.has_key(k):
  171. exec("%s = options['%s']" % (k,k))
  172. else:
  173. exec('%s = v' % k)
  174. if frame < 0:
  175. # Don't construct file names with negative frameno values.
  176. raise IOError("Frame " + str(frame) + " does not exist ***")
  177. # Construct path names
  178. base_path = os.path.join(path,)
  179. # t_fname = os.path.join(base_path, '%s.t' % file_prefix) + str(frame).zfill(4)
  180. q_fname = os.path.join(base_path, '%s.q' % file_prefix) + str(frame).zfill(4)
  181. # Read in values from fort.t file:
  182. [t,meqn,ngrids,maux,ndim] = read_ascii_t(frame,path,file_prefix)
  183. # Read in values from fort.q file:
  184. try:
  185. f = open(q_fname,'r')
  186. # Loop through every grid setting the appropriate information
  187. # for ng in range(len(solution.grids)):
  188. for m in xrange(ngrids):
  189. # Read in base header for this grid
  190. gridno = read_data_line(f,type='int')
  191. level = read_data_line(f,type='int')
  192. n = np.zeros((ndim))
  193. lower = np.zeros((ndim))
  194. d = np.zeros((ndim))
  195. for i in xrange(ndim):
  196. n[i] = read_data_line(f,type='int')
  197. for i in xrange(ndim):
  198. lower[i] = read_data_line(f)
  199. for i in xrange(ndim):
  200. d[i] = read_data_line(f)
  201. blank = f.readline()
  202. # Construct the grid
  203. # Since we do not have names here, we will construct the grid with
  204. # the assumed dimensions x,y,z
  205. names = ['x','y','z']
  206. dimensions = []
  207. for i in xrange(ndim):
  208. dimensions.append(
  209. pyclaw.solution.Dimension(names[i],lower[i],lower[i] + n[i]*d[i],n[i]))
  210. grid = pyclaw.solution.Grid(dimensions)
  211. grid.t = t
  212. grid.meqn = meqn
  213. # RJL 1/8/10: Changed empty_aux to zeros_aux below so aux won't
  214. # be filled with random values if aux arrays not read in. Would
  215. # like to delete this and initialize grid.aux only if it will be
  216. # read in below, but for some reason that doesn't work.
  217. if maux > 0:
  218. grid.zeros_aux(maux)
  219. # Fill in q values
  220. grid.empty_q()
  221. if grid.ndim == 1:
  222. for i in xrange(grid.dimensions[0].n):
  223. l = []
  224. while len(l)<grid.meqn:
  225. line = f.readline()
  226. l = l + line.split()
  227. for m in xrange(grid.meqn):
  228. grid.q[i,m] = float(l[m])
  229. elif grid.ndim == 2:
  230. for j in xrange(grid.dimensions[1].n):
  231. for i in xrange(grid.dimensions[0].n):
  232. l = []
  233. while len(l)<grid.meqn:
  234. line = f.readline()
  235. l = l + line.split()
  236. for m in xrange(grid.meqn):
  237. grid.q[i,j,m] = float(l[m])
  238. blank = f.readline()
  239. elif grid.ndim == 3:
  240. raise NotImplementedError("3d still does not work!")
  241. for k in xrange(grid.dimensions[2].n):
  242. for j in xrange(grid.dimensions[1].n):
  243. for i in xrange(grid.dimensions[0].n):
  244. l=[]
  245. while len(l) < grid.meqn:
  246. line = f.readline()
  247. l = l + line.split()
  248. for m in xrange(grid.meqn):
  249. grid.q[i,j,k,m] = float(l[m])
  250. blank = f.readline()
  251. blank = f.readline()
  252. else:
  253. msg = "Read only supported up to 3d."
  254. logger.critical(msg)
  255. raise Exception(msg)
  256. # Add AMR attributes:
  257. grid.gridno = gridno
  258. grid.level = level
  259. # Add new grid to solution
  260. solution.grids.append(grid)
  261. except(IOError):
  262. raise
  263. except:
  264. logger.error("File %s was not able to be read." % q_fname)
  265. raise
  266. # Read auxillary file if available and requested
  267. if solution.grids[0].maux > 0 and read_aux:
  268. # Check for aux file
  269. fname1 = os.path.join(base_path,'%s.a' % file_prefix)+str(frame).zfill(4)
  270. fname2 = os.path.join(base_path,'%s.a' % file_prefix)
  271. if os.path.exists(fname1):
  272. fname = fname1
  273. elif os.path.exists(fname2):
  274. fname = fname2
  275. else:
  276. logger.info("Unable to open auxillary file %s or %s" % (fname1,fname2))
  277. return
  278. # Found a valid path, try to open and read it
  279. try:
  280. f = open(fname,'r')
  281. # Read in aux file
  282. for n in xrange(len(solution.grids)):
  283. # Fetch correct grid
  284. gridno = read_data_line(f,type='int')
  285. grid = solution.grids[gridno-1]
  286. # These should match this grid already, raise exception otherwise
  287. if not (grid.level == read_data_line(f,type='int')):
  288. raise IOError("Grid level in aux file header did not match grid no %s." % grid.gridno)
  289. for dim in grid.dimensions:
  290. if not (dim.n == read_data_line(f,type='int')):
  291. raise IOError("Dimension %s's n in aux file header did not match grid no %s." % (dim.name,grid.gridno))
  292. for dim in grid.dimensions:
  293. if not (dim.lower == read_data_line(f,type='float')):
  294. raise IOError("Dimension %s's lower in aux file header did not match grid no %s." % (dim.name,grid.gridno))
  295. for dim in grid.dimensions:
  296. if not (dim.d == read_data_line(f,type='float')):
  297. raise IOError("Dimension %s's d in aux file header did not match grid no %s." % (dim.name,grid.gridno))
  298. f.readline()
  299. # Read in auxillary array
  300. if grid.ndim == 1:
  301. for i in xrange(grid.dimensions[0].n):
  302. l = []
  303. while len(l)<grid.maux:
  304. line = f.readline()
  305. l = l + line.split()
  306. for m in xrange(grid.maux):
  307. grid.aux[i,m] = float(l[m])
  308. elif grid.ndim == 2:
  309. for j in xrange(grid.dimensions[1].n):
  310. for i in xrange(grid.dimensions[0].n):
  311. l = []
  312. while len(l)<grid.maux:
  313. line = f.readline()
  314. l = l + line.split()
  315. for m in xrange(grid.maux):
  316. grid.aux[i,j,m] = float(l[m])
  317. blank = f.readline()
  318. elif grid.ndim == 3:
  319. for k in xrange(grid.dimensions[2].n):
  320. for j in xrange(grid.dimensions[1].n):
  321. for i in xrange(grid.dimensions[0].n):
  322. l = []
  323. while len(l)<grid.maux:
  324. line = f.readline()
  325. l = l + line.split()
  326. for m in xrange(grid.maux):
  327. grid.aux[i,j,k,m] = float(l[m])
  328. blank = f.readline()
  329. blank = f.readline()
  330. else:
  331. logger.critical("Read aux only up to 3d is supported.")
  332. raise Exception("Read aux only up to 3d is supported.")
  333. except(IOError):
  334. raise
  335. except:
  336. logger.error("File %s was not able to be read." % q_fname)
  337. raise
  338. def read_ascii_t(frame,path='./',file_prefix='fort'):
  339. r"""Read only the fort.t file and return the data
  340. :Input:
  341. - *frame* - (int) Frame number to be read in
  342. - *path* - (string) Path to the current directory of the file
  343. - *file_prefix* - (string) Prefix of the files to be read in.
  344. ``default = 'fort'``
  345. :Output:
  346. - (list) List of output variables
  347. - *t* - (int) Time of frame
  348. - *meqn* - (int) Number of equations in the frame
  349. - *ngrids* - (int) Number of grids
  350. - *maux* - (int) Auxillary value in the frame
  351. - *ndim* - (int) Number of dimensions in q and aux
  352. """
  353. base_path = os.path.join(path,)
  354. path = os.path.join(base_path, '%s.t' % file_prefix) + str(frame).zfill(4)
  355. try:
  356. logger.debug("Opening %s file." % path)
  357. f = open(path,'r')
  358. t = read_data_line(f)
  359. meqn = read_data_line(f,type='int')
  360. ngrids = read_data_line(f,type='int')
  361. maux = read_data_line(f,type='int')
  362. ndim = read_data_line(f,type='int')
  363. f.close()
  364. except(IOError):
  365. raise
  366. except:
  367. logger.error("File " + t_fname + " should contain t, meqn, ngrids, maux, ndim")
  368. print "File " + t_fname + " should contain t, meqn, ngrids, maux, ndim"
  369. raise
  370. return t,meqn,ngrids,maux,ndim