FLEXPART Testing Environment CTBTO WO8
 All Classes Namespaces Files Functions Variables Pages
read_grid.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 """
3 D. Arnold
4 D. Morton
5 
6 This is taken from a version of pflexible from Don Morton.
7 For original pflexible contact J. Bukhardt.
8 It is adapted so that we only have the reading of the header
9 for FLEXPART version 6.X, 8.X and further. Some other things have
10 been modified. Classes and helper functions also from pflexible
11 
12 NO plotting options are included
13 NO FortFlex is included for simplicity
14 
15 Warning: Version 9 and Version 8 reagdrig are the same
16 """
17 
18 # Imported modules
19 import os
20 import struct
21 import traceback
22 import datetime
23 import traceback
24 
25 from pflexible import _shout
26 
27 #Dependencies:
28 # Numpy
29 import numpy as np
30 
31 def _readgridBF(H, filename):
32  """ Read grid using BinaryFile class"""
33  # Utility functions
34  skip = lambda n = 8 : f2.seek(n, 1)
35  getbin = lambda dtype, n = 1 : f2.read(dtype, (n,))
36 
37 
38  def getdump(n, fmt='f'):
39  """ function to get the dump values for the sparse format """
40  skip()
41  # Dfmt=[fmt]*n
42 # a=[struct.unpack(ft,f.read(struct.calcsize(ft))) for ft in Dfmt]
43  a = f2.read(fmt, n)
44  ### DJM HACK - 2013-09-02 - without the following, 'a' ends up being
45  ### a float rather than a numpy array
46  if n==1:
47  a = np.array([a])
48 # dumplist=[a[j][0] for j in range(len(a))]
49  # dumplist=[a[j] for j in range(len(a))]
50  return a # dumplist
51 
52  def key2var(D, key):
53  cmd = "global %s; %s = D['%s'];" % (key, key, key)
54  exec(cmd)
55 
56  def _dumpgrid(dmp_i, cnt_r, dmp_r, grd, k, nage, nx, ny):
57  """ function to dump sparse elements into grid, fall back method if
58  pflexcy.so module (cython) not available -- it is SLOW """
59  conc = False
60  if len(grd.shape) == 5:
61  conc = True
62  ii = 0
63  fact = 1
64  pos = 0
65  '''
66  print 'CNT_R: ' + str(cnt_r)
67  print 'DMP_R: ' + str(dmp_r)
68  print 'TYPE DMP_R: ' + str(type(dmp_r))
69  '''
70  for ir in range(cnt_r):
71 
72  if conc:
73  if dmp_r[ir] * fact > 0:
74  n = dmp_i[ii]
75  ii = ii + 1
76  fact = fact * -1.
77  else:
78  n = n + 1
79 
80  kz = n / (H.numxgrid * H.numygrid)
81  jy = (n - kz * H.numxgrid * H.numygrid) / H.numxgrid
82  ix = n - H.numxgrid * H.numygrid * kz - H.numxgrid * jy
83  grd[ix, jy, kz - 1, k, nage] = abs(dmp_r[ir])
84 
85 #
86 # print "n ==> ix,jy,kz,k,nage"
87 # print "%s ==> %s,%s,%s,%s,%s" % (n,ix,jy,kz,k,nage)
88 # print grd.shape
89 # print grd[0,0,0,0,0]
90 
91  else:
92  if dmp_r[ir] * fact > 0:
93  n = dmp_i[ii]
94  ii = ii + 1
95  fact = fact * -1.
96  else:
97  n = n + 1
98  jy = n / H.numxgrid
99  ix = n - H.numxgrid * jy
100  grd[ix, jy, k, nage] = abs(dmp_r[ir])
101 
102  return grd # flipud(grd.transpose())
103 
104  # # Import pflexcy.so (cython compiled version of dumpgrid)
105  try:
106 
107  from sdspflexcy import dumpdatagrid, dumpdepogrid
108  print 'using pflexcy'
109  except:
110  #print """WARNING: Using PURE Python to readgrid, execution will be slow.
111  # Try compiling the FortFlex module or the pflexcy module
112  # for your machine. For more information see the
113  # pflexible/f2py_build directory or use cython with pflexcy.pyx
114  #"""
115  dumpdatagrid = _dumpgrid
116  dumpdepogrid = _dumpgrid
117 
118  dat_cnt = 0
119  nage = 1
120  # #datagrid=np.zeros((numxgrid,numygrid,numzgrid[nspec-1],nspec,nageclass),np.float)
121  wetgrid = np.zeros((H.numxgrid, H.numygrid, H.numpointspec, 1), np.float)
122  drygrid = np.zeros((H.numxgrid, H.numygrid, H.numpointspec, 1), np.float)
123  datagrid = np.zeros((H.numxgrid, H.numygrid, H.numzgrid, H.numpointspec, nage), np.float)
124  # f = file(filename,'rb')
125  # print filename
126  f2 = BinaryFile(filename, order='fortran')
127  # read data:
128  skip(4)
129  itime = getbin('i')
130 
131  for na in range(nage):
132 
133  for ks in range(H.numpointspec):
134  # Read Wet Depostion
135  skip()
136  cnt_i = getbin('i')
137  dmp_i = getdump(cnt_i, 'i')
138  skip()
139  cnt_r = getbin('i')
140  dmp_r = getdump(cnt_r)
141  if dmp_r.any():
142  # print dmp_r, dmp_i
143  wetgrid = dumpdepogrid(dmp_i, cnt_r, dmp_r, wetgrid, ks, na, H.numxgrid, H.numygrid)
144 
145  # Read Dry Deposition
146  skip()
147  cnt_i = getbin('i')
148  dmp_i = getdump(cnt_i, 'i')
149  skip()
150  cnt_r = getbin('i')
151  dmp_r = getdump(cnt_r)
152  if dmp_r.any():
153  # print dmp_r, dmp_i
154  drygrid = dumpdepogrid(dmp_i, cnt_r, dmp_r, drygrid, ks, na, H.numxgrid, H.numygrid)
155 
156  # Read Concentrations
157  skip()
158  cnt_i = getbin('i')
159  dmp_i = getdump(cnt_i, 'i')
160  skip()
161  cnt_r = getbin('i')
162  dmp_r = getdump(cnt_r)
163  # print len(dmp_r),len(dmp_i)
164  # print cnt_r,cnt_i
165  # print dmp_i
166  # print type(dmp_i),type(cnt_r),type(dmp_r),type(datagrid),type(ks),type(na)
167  # print type(H.numxgrid),type(H.numygrid)
168  datagrid = dumpdatagrid(dmp_i, cnt_r, dmp_r, datagrid, ks, na, H.numxgrid, H.numygrid)
169 
170  # G[H['ibtime']].append(concgrid)
171  f2.close()
172 
173  return datagrid, wetgrid, drygrid, itime
174 
175 def read_grid(H, **kwargs):
176  """
177  Accepts a header object as input, returns dictionary of Grid values
178  keyed by species and datestring from H['available_dates']. A grid instance from this
179  dictionary may be passed to the get_slabs function to return a dictionary of slabs
180  suitable for plotting with the plotting routines. See below for more information.
181 
182  **DEPENDENCY**
183  Requires FortFlex.so module compiled using f2py. See FortFlex.f for more details.
184 
185  Usage::
186 
187  > FLEXDATA = read_grid(H,**kwargs)
188 
189  Returns:
190 
191  A grid dictionary key by tuples with (species,available_dates), where species is
192  and integer. See grid.keys()
193 
194  FLEXDATA[(s,datestring)]['grid']
195  FLEXDATA[(s,datestring)]['itime']
196  FLEXDATA[(s,datestring)]['shape']
197  FLEXDATA[(s,datestring)]['max']
198  FLEXDATA[(s,datestring)]['min']
199  FLEXDATA[(s,datestring)]['timestamp']
200  FLEXDATA[(s,datestring)]['species']
201  FLEXDATA[(s,datestring)]['gridfile']
202  FLEXDATA[(s,datestring)]['rel_i']
203  FLEXDATA[(s,datestring)]['spec_i']
204 
205  Arguments
206 
207  .. tabularcolumns:: |l|L|
208 
209  ============= ========================================
210  keyword Description [default]
211  ============= ========================================
212  date which yyyymmddhhmmss from available_dates
213  or use (time_ret)
214  time_ret index to time
215  unit 'conc', 'pptv', ['time'], 'footprint'
216  nspec_ret numspecies
217  pspec_ret index to ???
218  age_ret index to ageclass
219  nested obtained from H['nested']
220  BinaryFile Use BinaryFile vs. FortFlex [False]
221  getwet True, [False]
222  getdry True, [False]
223  scaledepo A float value to scale deposition [1.0]
224  scaleconc A float value to scale conc [1.0]
225  decayconstant A float for decay const. [9e6]
226  calcfoot Will cause footprint to be calculated
227  [False]
228  verbose more output
229  version A string 'V8' or 'V6', ['V8']
230  ============= ========================================
231 
232 
233  .. note::
234  most arguments are able to be extracted fro the header "H"
235 
236  """
237 
238  if H.version == 'V9':
239  return readgridV9(H, **kwargs)
240  if H.version == 'V8':
241  return readgridV8(H, **kwargs)
242  if H.version == 'V6':
243  return readgridV6(H, **kwargs)
244  else:
245  raise IOError("No version attribute defined for Header.")
246 
247 def readgridV8(H, **kwargs):
248 
249  """
250  Accepts a header object as input, and selects appropriate readgrid function
251  to use for reading in data from the flexpart binary Fortran files.
252 
253  See the :func:`read_grid` for more information on keyword arguments
254 
255  This is the 'V8' version of the function.
256 
257  """
258  # # OPS is the options Structure, sets defaults, then update w/ kwargs
259  OPS = Structure()
260  OPS.unit = H.unit
261  OPS.getwet = False
262  OPS.getdry = False
263  OPS.nspec_ret = 0
264  OPS.npspec_int = False # allows to select an index of npsec when calling readgrid
265  OPS.pspec_ret = 0
266  OPS.age_ret = 0
267  OPS.time_ret = 0
268  OPS.scaledepo = 1.0
269  OPS.scaleconc = 1.0
270  OPS.decayconstant = 9e6
271  OPS.date = None
272  OPS.calcfoot = False
273  OPS.verbose = False
274  OPS.BinaryFile = False
275  OPS.version = 'V8'
276  # # add keyword overides and options to header
277  OPS.update(kwargs)
278  # H.update(OPS)
279 
280  # # set up the return dictionary (FLEXDATA updates fd, fd is returned)
281  FLEXDATA = {}
282  fd = Structure()
283  fd.options = Structure()
284 
285  # # What direction is the run?
286  unit = OPS.unit
287 
288  if H['loutstep'] > 0:
289  forward = True
290  if unit == 'time':
291  # # default forward unit
292  unit = 'conc'
293  OPS.unit = unit
294  else:
295  forward = False
296 
297  # # What species to return?
298  nspec_ret = OPS.nspec_ret
299  if isinstance(nspec_ret, int):
300  nspec_ret = [nspec_ret]
301  assert iter(nspec_ret), "nspec_ret must be iterable."
302 
303  # # get times to return
304  get_dates = None
305  if OPS.time_ret is not None:
306  get_dates = []
307  time_ret = OPS.time_ret
308  if isinstance(time_ret, int) == True:
309  time_ret = [time_ret]
310 
311  if time_ret[0] < 0:
312  #if forward == False:
313  # # get all dates for calculating footprint.
314  time_ret = np.arange(len(H.available_dates))
315  #else:
316  # raise ValueError("Must enter a positive time_ret for forward runs")
317 
318  for t in time_ret:
319  get_dates.append(H.available_dates[t])
320 
321 
322  # # define what dates to extract if user has explicitly defined a 'date'
323  if OPS.date != None:
324  date = OPS.date
325  if time_ret is not None:
326  Warning("overwriting time_ret variable, date was requested")
327  get_dates = []
328  if not isinstance(date, list):
329  date = date.strip().split(',')
330  for d in date:
331  try:
332  get_dates.append(H.available_dates[H.available_dates.index(d)])
333  time_ret = None
334  except:
335  _shout("Cannot find date: %s in H['available_dates']\n" % d)
336 
337  if get_dates is None:
338  raise ValueError("Must provide either time_ret or date value.")
339  else:
340  # # assign grid dates for indexing fd
341  fd.grid_dates = get_dates[:]
342 
343  #print 'getting grid for: ', get_dates
344  # Some predifinitions
345  fail = 0
346  # set filename prefix
347  prefix = ['grid_conc_', 'grid_pptv_', \
348  'grid_time_', 'footprint_', 'footprint_total', \
349  'grid_conc_nest_', 'grid_pptv_nest_', \
350  'grid_time_nest_', 'footprint_nest_', 'footprint_total_nest'
351  ]
352 
353  units = ['conc', 'pptv', 'time', 'footprint', 'footprint_total']
354  unit_i = units.index(unit)
355 
356  useFortFlex = False
357  if not useFortFlex:
358  readgrid = _readgridBF
359  OPS.BinaryFile = True
360 
361 
362  # reserve output fields
363  #print H.numxgrid, H.numygrid, H.numzgrid, OPS.nspec_ret, OPS.pspec_ret, OPS.age_ret, len(get_dates), H.numpoint
364 
365  # -------------------------------------------------
366 
367  # # add the requests to the fd object to be returned
368  OPS.unit = unit
369  fd.options.update(OPS)
370 
371  #--------------------------------------------------
372  # Loop over all times, given in field H['available_dates']
373  #--------------------------------------------------
374 
375  for date_i in range(len(get_dates)):
376  datestring = get_dates[date_i]
377  #print datestring
378  for s in nspec_ret: # range(OPS.nspec_ret,OPS.nspec_ret+1):A
379 
380  FLEXDATA[(s, datestring)] = Structure()
381  spec_fid = '_' + str(s + 1).zfill(3)
382 
383  if unit_i != 4:
384  filename = os.path.join(H['pathname'], \
385  prefix[(unit_i) + (H.nested * 5)] + datestring + spec_fid)
386  H.zdims = H.numzgrid
387 
388  else:
389  # grid total footprint
390  print "Total footprint"
391  filename = os.path.join(H['pathname'], \
392  prefix[(unit_i) + (H.nested * 5)] + spec_fid)
393  H.zdims = 1
394 
395  if os.path.exists(filename):
396  H.filename = filename
397  # print 'reading: ' + filename
398  if OPS.verbose:
399  print 'with values:'
400  inputvars = ['filename', 'numxgrid', 'numygrid',
401  'zdims', 'numpoint', 'nageclass', \
402  'scaledepo', 'scaleconc',
403  'decayconstant', 'numpointspec']
404  for v in inputvars:
405  print v, " ==> ", H[v]
406 
407 
408  if OPS.BinaryFile:
409  #print("Reading {0} with BinaryFile".format(filename))
410  gridT, wetgrid, drygrid, itime = _readgridBF(H, filename)
411  else:
412  # # Quick fix for Sabine's Ship releases, added nspec_int so that only one
413  # # field of the nspec dimension is actually read
414  if OPS.npspec_int is not False:
415  npspec_int = OPS.npspec_int
416  numpointspec = 1
417  else:
418  npspec_int = 0
419  numpointspec = H.numpointspec
420 
421  gridT, wetgrid, drygrid, itime = readgrid(filename, \
422  H.numxgrid, H.numygrid,
423  H.zdims, numpointspec, H.nageclass, \
424  OPS.scaledepo, OPS.scaleconc, H.decayconstant, npspec_int)
425 
426  if OPS.getwet:
427  wet = wetgrid.squeeze()
428  if OPS.getdry:
429  dry = drygrid.squeeze()
430  if forward:
431  zplot = gridT[:, :, :, :, 0]
432  else:
433  zplot = gridT[:, :, :, :, 0]
434 
435  if OPS.calcfoot:
436 
437  zplot = sumgrid(zplot, gridT, \
438  H.area, H.Heightnn)
439 
440 
441  # # get the total column and prep the grid
442  if H.direction == 'forward':
443  # not trying to do anything here... must be done
444  # after retrieving the grid
445  # D = get_slabs(H,np.squeeze(zplot))
446  rel_i = 0 #H.available_dates.index(datestring)
447  D = zplot
448 
449  else:
450  D = zplot
451  rel_i = 'k'
452 
453  # # NOTE:
454  # # If you're changing things here, you might want to change
455  # # them in fill_backward as well, yes I know... something is
456  # # poorly designed ;(
457 
458  FLEXDATA[(s, datestring)]['grid'] = D # zplot
459 
460  FLEXDATA[(s, datestring)]['itime'] = itime
461 
462  FLEXDATA[(s, datestring)]['shape'] = zplot.shape
463 
464  FLEXDATA[(s, datestring)]['max'] = zplot.max()
465 
466  FLEXDATA[(s, datestring)]['min'] = zplot.min()
467  FLEXDATA[(s, datestring)]['timestamp'] = datetime.datetime.strptime(datestring, '%Y%m%d%H%M%S')
468  FLEXDATA[(s, datestring)]['species'] = H['species'][s]
469  FLEXDATA[(s, datestring)]['gridfile'] = filename
470  FLEXDATA[(s, datestring)]['rel_i'] = rel_i
471  FLEXDATA[(s, datestring)]['spec_i'] = s
472  if OPS.getwet:
473  FLEXDATA[(s, datestring)]['wet'] = wet
474  else:
475  FLEXDATA[(s, datestring)]['wet'] = None
476 
477  if OPS.getdry:
478  FLEXDATA[(s, datestring)]['dry'] = dry
479  else:
480  FLEXDATA[(s, datestring)]['dry'] = None
481 
482  else:
483  _shout('***ERROR: file %s not found! \n' % filename)
484  fail = 1
485 
486  fd.set_with_dict(FLEXDATA)
487  try:
488  # just for testing, set the first available grid as a shortcut
489  # this will be removed.
490  qind = (nspec_ret[0], fd.grid_dates[0])
491  fd.grid = fd[qind][fd[qind].keys()[0]].grid
492  except:
493  pass
494 
495 
496  return fd
497 
498 def readgridV6(H, **kwargs):
499 
500  """
501  Accepts a header object as input, and selects appropriate readgrid function
502  to use for reading in data from the flexpart binary Fortran files.
503 
504  See the :func:`read_grid` for more information on keyword arguments
505 
506  This is the 'V6' version of the function.
507 
508  """
509  # # OPS is the options Structure, sets defaults, then update w/ kwargs
510  OPS = Structure()
511  OPS.unit = 'time'
512  OPS.nspec_ret = 0
513  OPS.pspec_ret = 0
514  OPS.age_ret = 0
515  OPS.time_ret = 0
516  OPS.scaledepo = 1.0
517  OPS.scaleconc = 1.0
518  OPS.decayconstant = 9e6
519  OPS.date = None
520  OPS.calcfoot = False
521  OPS.verbose = False
522  OPS.BinaryFile = False
523  # # add keyword overides and options to header
524  OPS.update(kwargs)
525  # H.update(OPS)
526 
527  # # set up the return dictionary (FLEXDATA updates fd, fd is returned)
528  FLEXDATA = {}
529  fd = Structure()
530  fd.options = Structure()
531  # # add the requests to the fd object to be returned
532  fd.options.update(OPS)
533 
534  # # What direction is the run?
535  unit = OPS.unit
536  if H['loutstep'] > 0:
537  forward = True
538  if unit == 'time':
539  # # default forward unit
540  unit = 'conc'
541  else:
542  forward = False
543 
544  # # What species to return?
545  nspec_ret = OPS.nspec_ret
546  if isinstance(nspec_ret, int):
547  nspec_ret = [nspec_ret]
548  assert iter(nspec_ret), "nspec_ret must be iterable."
549 
550  # # get times to return
551  get_dates = None
552  if OPS.time_ret is not None:
553  get_dates = []
554  time_ret = OPS.time_ret
555  if isinstance(time_ret, int) == True:
556  time_ret = [time_ret]
557 
558  if time_ret[0] < 0:
559  if forward == False:
560  # # get all dates for calculating footprint.
561  time_ret = np.arange(len(H.available_dates))
562  else:
563  raise ValueError("Must enter a positive time_ret for forward runs")
564 
565  for t in time_ret:
566  get_dates.append(H.available_dates[t])
567 
568 
569  # # define what dates to extract if user has explicitly defined a 'date'
570  if OPS.date != None:
571  date = OPS.date
572  if time_ret is not None:
573  Warning("overwriting time_ret variable, date was requested")
574  get_dates = []
575  if not isinstance(date, list):
576  date = date.strip().split(',')
577  for d in date:
578  try:
579  get_dates.append(H.available_dates[H.available_dates.index(d)])
580  time_ret = None
581  except:
582  _shout("Cannot find date: %s in H['available_dates']\n" % d)
583 
584  if get_dates is None:
585  raise ValueError("Must provide either time_ret or date value.")
586  else:
587  # # assign grid dates for indexing fd
588  fd.grid_dates = get_dates[:]
589 
590  #print 'getting grid for: ', get_dates
591  # Some predifinitions
592  fail = 0
593  # set filename prefix
594  prefix = ['grid_conc_', 'grid_pptv_', \
595  'grid_time_', 'footprint_', 'footprint_total', \
596  'grid_conc_nest_', 'grid_pptv_nest_', \
597  'grid_time_nest_', 'footprint_nest_', 'footprint_total_nest'
598  ]
599 
600  units = ['conc', 'pptv', 'time', 'footprint', 'footprint_total']
601  unit_i = units.index(unit)
602 
603  useFortFlex = False
604  if not useFortFlex:
605  readgrid = _readgridBF
606  OPS.BinaryFile = True
607 
608  # cheat: use key2var function to get values from header dict, H
609  # need to change this to using H.xxxxx
610  # headervars = ['nested','nspec','numxgrid','numygrid','numzgrid','nageclass',\
611  # 'dates','pathname','decayconstant','numpoint','numpointspec',
612  # 'area','Heightnn','lage']
613  # for k in headervars:
614  # key2var(H,k)
615 
616 
617 
618  # reserve output fields
619  #print H.numxgrid, H.numygrid, H.numzgrid, OPS.nspec_ret, OPS.pspec_ret, OPS.age_ret, len(get_dates), H.numpoint
620 
621  # -------------------------------------------------
622 
623  # if forward:
624  # numpointspec = 1
625  # else:
626  # numpointspec = numpoint
627  # numpointspec = H['numpointspec']
628  # if unit_i == 4:
629  # grid=np.empty((numxgrid,numygrid,1,nspec_ret,pspec_ret,age_ret,len(get_dates)))
630  # else:
631  # grid=np.empty((numxgrid,numygrid,numzgrid,nspec_ret,pspec_ret,age_ret,len(get_dates)))
632  # zplot=np.empty((numxgrid,numygrid,numzgrid,numpointspec))
633 
634  #--------------------------------------------------
635  # Loop over all times, given in field H['available_dates']
636  #--------------------------------------------------
637 
638  for date_i in range(len(get_dates)):
639  datestring = get_dates[date_i]
640  #print datestring
641  FLEXDATA[datestring] = {}
642  for s in nspec_ret: # range(OPS.nspec_ret,OPS.nspec_ret+1):
643  total_footprint = False
644  FLEXDATA[(s, datestring)] = Structure()
645  # spec_fid = '_'+str(s+1).zfill(3)
646 
647  if unit_i != 4:
648  filename = os.path.join(H['pathname'], \
649  prefix[(unit_i) + (H.nested * 5)] + datestring)
650  H.zdims = H.numzgrid
651 
652  else:
653  # grid total footprint
654  print "Total footprint"
655  total_footprint = True
656  filename = os.path.join(H['pathname'], \
657  prefix[(unit_i) + (H.nested * 5)])
658  H.zdims = 1
659 
660  if os.path.exists(filename):
661  H.filename = filename
662  # print 'reading: ' + filename
663  if OPS.verbose:
664  print 'with values:'
665  inputvars = ['filename', 'numxgrid', 'numygrid',
666  'zdims', 'numpoint', 'nageclass', \
667  'scaledepo', 'scaleconc',
668  'decayconstant', 'numpointspec']
669  for v in inputvars:
670  print v, " ==> ", H[v]
671 
672 
673  if OPS.BinaryFile:
674  # print 'Using BinaryFile'
675  gridT, wetgrid, drygrid, itime = _readgridBF(H, filename)
676  else:
677  gridT, wetgrid, drygrid, itime = readgrid(filename, \
678  H.numxgrid, H.numygrid,
679  H.zdims, H.numpointspec, H.nageclass, \
680  OPS.scaledepo, OPS.scaleconc, H.decayconstant)
681 
682 
683  if forward:
684  zplot = gridT[:, :, :, :, 0]
685  else:
686  zplot = gridT[:, :, :, :, 0]
687 
688  # if total_footprint:
689  # zplot = np.squeeze(gridT)
690 
691  if OPS.calcfoot:
692  zplot = sumgrid(zplot, gridT, \
693  H.area, H.Heightnn)
694 
695 
696  # # get the total column and prep the grid
697  if H.direction == 'forward':
698  # not trying to do anything here... must be done
699  # after retrieving the grid
700  # D = get_slabs(H,np.squeeze(zplot))
701  # rel_i = H.available_dates.index(datestring)
702  D = zplot
703  rel_i = 'k'
704  else:
705  D = zplot
706  rel_i = 'k'
707 
708  # # NOTE:
709  # # If you're changing things here, you might want to change
710  # # them in fill_backward as well, yes I know... something is
711  # # poorly designed ;(
712  FLEXDATA[(s, datestring)]['grid'] = D # zplot
713  FLEXDATA[(s, datestring)]['itime'] = itime
714  FLEXDATA[(s, datestring)]['shape'] = zplot.shape
715  FLEXDATA[(s, datestring)]['max'] = zplot.max()
716  FLEXDATA[(s, datestring)]['min'] = zplot.min()
717  FLEXDATA[(s, datestring)]['timestamp'] = datetime.datetime.strptime(datestring, '%Y%m%d%H%M%S')
718  FLEXDATA[(s, datestring)]['species'] = H['species'][s]
719  FLEXDATA[(s, datestring)]['gridfile'] = filename
720  FLEXDATA[(s, datestring)]['rel_i'] = rel_i
721  FLEXDATA[(s, datestring)]['spec_i'] = s
722 
723 
724  else:
725  _shout('***ERROR: file %s not found! \n' % filename)
726  fail = 1
727  fd.set_with_dict(FLEXDATA)
728 
729  try:
730  # just for testing, set the first available grid as a shortcut
731  # this will be removed.
732  qind = (0, fd.grid_dates[0])
733  fd.grid = fd[qind][fd[qind].keys()[0]].grid
734  except:
735  pass
736 
737 
738  return fd
739 
740 
741 ########### HELPER FUNCTIONS ##########
742 class BinaryFile(object):
743 
744  """
745 
746  BinaryFile: A class for accessing data to/from large binary files
747 
748 
749  The data is meant to be read/write sequentially from/to a binary file.
750  One can request to read a piece of data with a specific type and shape
751  from it. Also, it supports the notion of Fortran and C ordered data,
752  so that the returned data is always well-behaved (C-contiguous and
753  aligned).
754 
755  This class is seeking capable.
756 
757  :Author: Francesc Alted
758  :Contact: faltet@pytables.org
759  :Created: 2010-03-18
760  :Acknowledgment: Funding for the development of this code is provided
761  through the Norwegian Research Council VAUUAV project #184724, 2010
762 
763  """
764 
765 
766  # Common types whose conversion can be accelerated via the struct
767  # module
768  structtypes = {
769  'i1': 'b', 'i2': 'h', 'i4': 'i',
770  'f4': 'f', 'f8': 'd',
771  }
772 
773  def __init__(self, filename, mode="r", order="fortran"):
774  """Open the `filename` for write/read binary files.
775 
776  The `mode` can be 'r', 'w' or 'a' for reading (default),
777  writing or appending. The file will be created if it doesn't
778  exist when opened for writing or appending; it will be
779  truncated when opened for writing. Add a '+' to the mode to
780  allow simultaneous reading and writing.
781 
782  `order` specifies whether the file is is written in 'fortran'
783  or 'c' order.
784  """
785  self.mode = mode + "b"
786  self.file = open(filename, mode=self.mode, buffering=1)
787  """The file handler."""
788  if order not in ['fortran', 'c']:
789  raise ValueError, "order should be either 'fortran' or 'c'."
790  self.order = order
791  """The order for file ('c' or 'fortran')."""
792 
793 
794 
795 
796  def read(self, dtype, shape=(1,)):
797  """Read an array of `dtype` and `shape` from current position.
798 
799  `shape` must be any tuple made of integers or even () for scalars.
800 
801  The current position will be updated to point to the end of
802  read data.
803  """
804  if not isinstance(dtype, np.dtype):
805  dtype = np.dtype(dtype)
806  if type(shape) is int:
807  shape = (shape,)
808  if type(shape) is not tuple:
809  raise ValueError, "shape must be a tuple"
810  length = dtype.itemsize
811  rank = len(shape)
812  if rank == 1:
813  length *= shape[0]
814  elif rank > 1:
815  length *= np.array(shape).prod()
816 
817  # Correct the shape in case dtype is multi-dimensional
818  if shape != (1,):
819  shape = shape + dtype.shape
820  else:
821  shape = dtype.shape
822  rank = len(shape)
823 
824  if shape in (1, (1,)):
825  order = "c"
826  else:
827  order = self.order
828 
829  # Read the data from file
830  data = self.file.read(length)
831  if len(data) < length:
832  raise EOFError, "Asking for more data than available in file."
833 
834 
835  # Convert read string into a regular array, or scalar
836  dts = dtype.base.str[1:]
837  if rank == 0:
838  if dts[1] == "S":
839  data = str(data)
840  elif dts in self.structtypes:
841  data = struct.unpack(self.structtypes[dts], data)[0]
842  else:
843  data = np.ndarray(shape=shape, buffer=data, dtype=dtype.base)
844  if rank == 0:
845  # Retrieve the scalar out of the 0-dim array
846  data = data[()]
847 
848  if rank > 1:
849  # If original data file is in fortran mode, reverse the
850  # shape first
851  if order == "fortran":
852  shape = [i for i in shape[::-1]]
853  data = data.reshape(shape)
854  # If original data file is in fortran mode, do a transpose.
855  # As the shape was reversed previously, we get the original
856  # shape again.
857  if self.order == "fortran":
858  data = data.transpose().copy()
859  # Do an additional copy just in case the array is not
860  # well-behaved (i.e., it is not aligned or not contiguous).
861  elif not data.flags.behaved:
862  data = data.copy()
863  return data
864 
865 
866  def write(self, arr):
867  """Write an `arr` to current position.
868 
869  The current position will be updated to point to the end of
870  written data.
871  """
872  # Transpose data if case we need to
873  if (self.order == "fortran") != (arr.flags.fortran):
874  arr = arr.transpose().copy()
875  # Write the data to file
876  self.file.write(arr.data)
877 
878 
879  def seek(self, offset, whence=0):
880  """Move to new file position.
881 
882  Argument offset is a byte count. Optional argument whence
883  defaults to 0 (offset from start of file, offset should be >=
884  0); other values are 1 (move relative to current position,
885  positive or negative), and 2 (move relative to end of file,
886  usually negative, although many platforms allow seeking beyond
887  the end of a file). If the file is opened in text mode, only
888  offsets returned by tell() are legal. Use of other offsets
889  causes undefined behavior.
890  """
891  self.file.seek(offset, whence)
892 
893 
894  def tell(self):
895  "Returns current file position, an integer (may be a long integer)."
896  return self.file.tell()
897 
898 
899  def flush(self):
900  "Flush buffers to file."
901  self.file.flush()
902 
903 
904  def close(self):
905  "End access to file."
906  self.file.close()
907 
908 
909 def closest(num, numlist):
910  """ returns the index of the *closest* value in a list """
911  # check if we're using datetimes
912  dates = False
913  if isinstance(num, datetime.datetime):
914  dates = True
915  if dates:
916  num = date2num(num)
917  assert isinstance(numlist[0], datetime.datetime), \
918  "num is date, numlist must be a list of dates"
919  numlist = date2num(numlist)
920 
921  return (np.abs(numlist - num)).argmin()
922 
923 
924 
925 class Structure(dict, object):
926  """ A 'fancy' dictionary that provides 'MatLab' structure-like
927  referencing.
928 
929  .. warning::
930  may be replaced with a pure dict in future release.
931 
932  """
933  def __getattr__(self, attr):
934  # Fake a __getstate__ method that returns None
935  if attr == "__getstate__":
936  return lambda: None
937  return self[attr]
938 
939  def __setattr__(self, attr, value):
940  self[attr] = value
941 
942  def __dir__(self):
943  """ necessary for Ipython tab-completion """
944  return self.keys()
945 
946  def set_with_dict(self, D):
947  """ set attributes with a dict """
948  for k in D.keys():
949  self.__setattr__(k, D[k])
950 
951 
952 def data_range(data, min='median'):
953  """
954  return a data range for flexpart data
955 
956  optional keyword min = ['median', 'mean', 'min']
957  """
958  dmax = np.nanmax(data)
959  if np.isnan(dmax):
960  dmax = 1e5
961 
962  if min == 'mean':
963  dmin = np.mean(data[data.nonzero()])
964  elif min == 'median':
965  dmin = np.median(data[data.nonzero()])
966  else:
967  dmin = np.nanmin(data[data.nonzero()])
968 
969  if np.isnan(dmin):
970  dmin = 1e-5
971 
972  return [dmin, dmax]
973 
974 #### Below for use from command line ##########################################
975 
976 def main ():
977 
978  global options, args
979  here = os.path.curdir
980  dataDir = options.pathname
981  H = read_header(dataDir, **{'readp':1}) # readheader and release pointspiu
982  G = readgridV8(H, **{'unit':'time'})
983 
984 if __name__ == '__main__':
985  print H
986  print G
HELPER FUNCTIONS ##########.
Definition: read_grid.py:742