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
12 NO plotting options are included
13 NO FortFlex is included for simplicity
15 Warning: Version 9 and Version 8 reagdrig are the same
25 from pflexible
import _shout
32 """ Read grid using BinaryFile class"""
34 skip =
lambda n = 8 : f2.seek(n, 1)
35 getbin =
lambda dtype, n = 1 : f2.read(dtype, (n,))
38 def getdump(n, fmt='f'):
39 """ function to get the dump values for the sparse format """
53 cmd =
"global %s; %s = D['%s'];" % (key, key, key)
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 """
60 if len(grd.shape) == 5:
66 print 'CNT_R: ' + str(cnt_r)
67 print 'DMP_R: ' + str(dmp_r)
68 print 'TYPE DMP_R: ' + str(type(dmp_r))
70 for ir
in range(cnt_r):
73 if dmp_r[ir] * fact > 0:
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])
92 if dmp_r[ir] * fact > 0:
99 ix = n - H.numxgrid * jy
100 grd[ix, jy, k, nage] = abs(dmp_r[ir])
107 from sdspflexcy
import dumpdatagrid, dumpdepogrid
108 print 'using pflexcy'
115 dumpdatagrid = _dumpgrid
116 dumpdepogrid = _dumpgrid
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)
131 for na
in range(nage):
133 for ks
in range(H.numpointspec):
137 dmp_i = getdump(cnt_i,
'i')
140 dmp_r = getdump(cnt_r)
143 wetgrid = dumpdepogrid(dmp_i, cnt_r, dmp_r, wetgrid, ks, na, H.numxgrid, H.numygrid)
148 dmp_i = getdump(cnt_i,
'i')
151 dmp_r = getdump(cnt_r)
154 drygrid = dumpdepogrid(dmp_i, cnt_r, dmp_r, drygrid, ks, na, H.numxgrid, H.numygrid)
159 dmp_i = getdump(cnt_i,
'i')
162 dmp_r = getdump(cnt_r)
168 datagrid = dumpdatagrid(dmp_i, cnt_r, dmp_r, datagrid, ks, na, H.numxgrid, H.numygrid)
173 return datagrid, wetgrid, drygrid, itime
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.
183 Requires FortFlex.so module compiled using f2py. See FortFlex.f for more details.
187 > FLEXDATA = read_grid(H,**kwargs)
191 A grid dictionary key by tuples with (species,available_dates), where species is
192 and integer. See grid.keys()
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']
207 .. tabularcolumns:: |l|L|
209 ============= ========================================
210 keyword Description [default]
211 ============= ========================================
212 date which yyyymmddhhmmss from available_dates
214 time_ret index to time
215 unit 'conc', 'pptv', ['time'], 'footprint'
217 pspec_ret index to ???
218 age_ret index to ageclass
219 nested obtained from H['nested']
220 BinaryFile Use BinaryFile vs. FortFlex [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
229 version A string 'V8' or 'V6', ['V8']
230 ============= ========================================
234 most arguments are able to be extracted fro the header "H"
238 if H.version ==
'V9':
239 return readgridV9(H, **kwargs)
240 if H.version ==
'V8':
242 if H.version ==
'V6':
245 raise IOError(
"No version attribute defined for Header.")
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.
253 See the :func:`read_grid` for more information on keyword arguments
255 This is the 'V8' version of the function.
264 OPS.npspec_int =
False
270 OPS.decayconstant = 9e6
274 OPS.BinaryFile =
False
288 if H[
'loutstep'] > 0:
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."
305 if OPS.time_ret
is not None:
307 time_ret = OPS.time_ret
308 if isinstance(time_ret, int) ==
True:
309 time_ret = [time_ret]
314 time_ret = np.arange(len(H.available_dates))
319 get_dates.append(H.available_dates[t])
325 if time_ret
is not None:
326 Warning(
"overwriting time_ret variable, date was requested")
328 if not isinstance(date, list):
329 date = date.strip().split(
',')
332 get_dates.append(H.available_dates[H.available_dates.index(d)])
335 _shout(
"Cannot find date: %s in H['available_dates']\n" % d)
337 if get_dates
is None:
338 raise ValueError(
"Must provide either time_ret or date value.")
341 fd.grid_dates = get_dates[:]
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'
353 units = [
'conc',
'pptv',
'time',
'footprint',
'footprint_total']
354 unit_i = units.index(unit)
358 readgrid = _readgridBF
359 OPS.BinaryFile =
True
369 fd.options.update(OPS)
375 for date_i
in range(len(get_dates)):
376 datestring = get_dates[date_i]
381 spec_fid =
'_' + str(s + 1).zfill(3)
384 filename = os.path.join(H[
'pathname'], \
385 prefix[(unit_i) + (H.nested * 5)] + datestring + spec_fid)
390 print "Total footprint"
391 filename = os.path.join(H[
'pathname'], \
392 prefix[(unit_i) + (H.nested * 5)] + spec_fid)
395 if os.path.exists(filename):
396 H.filename = filename
400 inputvars = [
'filename',
'numxgrid',
'numygrid',
401 'zdims',
'numpoint',
'nageclass', \
402 'scaledepo',
'scaleconc',
403 'decayconstant',
'numpointspec']
405 print v,
" ==> ", H[v]
410 gridT, wetgrid, drygrid, itime =
_readgridBF(H, filename)
414 if OPS.npspec_int
is not False:
415 npspec_int = OPS.npspec_int
419 numpointspec = H.numpointspec
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)
427 wet = wetgrid.squeeze()
429 dry = drygrid.squeeze()
431 zplot = gridT[:, :, :, :, 0]
433 zplot = gridT[:, :, :, :, 0]
437 zplot = sumgrid(zplot, gridT, \
442 if H.direction ==
'forward':
458 FLEXDATA[(s, datestring)][
'grid'] = D
460 FLEXDATA[(s, datestring)][
'itime'] = itime
462 FLEXDATA[(s, datestring)][
'shape'] = zplot.shape
464 FLEXDATA[(s, datestring)][
'max'] = zplot.max()
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
473 FLEXDATA[(s, datestring)][
'wet'] = wet
475 FLEXDATA[(s, datestring)][
'wet'] =
None
478 FLEXDATA[(s, datestring)][
'dry'] = dry
480 FLEXDATA[(s, datestring)][
'dry'] =
None
483 _shout(
'***ERROR: file %s not found! \n' % filename)
486 fd.set_with_dict(FLEXDATA)
490 qind = (nspec_ret[0], fd.grid_dates[0])
491 fd.grid = fd[qind][fd[qind].keys()[0]].grid
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.
504 See the :func:`read_grid` for more information on keyword arguments
506 This is the 'V6' version of the function.
518 OPS.decayconstant = 9e6
522 OPS.BinaryFile =
False
532 fd.options.update(OPS)
536 if H[
'loutstep'] > 0:
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."
552 if OPS.time_ret
is not None:
554 time_ret = OPS.time_ret
555 if isinstance(time_ret, int) ==
True:
556 time_ret = [time_ret]
561 time_ret = np.arange(len(H.available_dates))
563 raise ValueError(
"Must enter a positive time_ret for forward runs")
566 get_dates.append(H.available_dates[t])
572 if time_ret
is not None:
573 Warning(
"overwriting time_ret variable, date was requested")
575 if not isinstance(date, list):
576 date = date.strip().split(
',')
579 get_dates.append(H.available_dates[H.available_dates.index(d)])
582 _shout(
"Cannot find date: %s in H['available_dates']\n" % d)
584 if get_dates
is None:
585 raise ValueError(
"Must provide either time_ret or date value.")
588 fd.grid_dates = get_dates[:]
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'
600 units = [
'conc',
'pptv',
'time',
'footprint',
'footprint_total']
601 unit_i = units.index(unit)
605 readgrid = _readgridBF
606 OPS.BinaryFile =
True
638 for date_i
in range(len(get_dates)):
639 datestring = get_dates[date_i]
641 FLEXDATA[datestring] = {}
643 total_footprint =
False
648 filename = os.path.join(H[
'pathname'], \
649 prefix[(unit_i) + (H.nested * 5)] + datestring)
654 print "Total footprint"
655 total_footprint =
True
656 filename = os.path.join(H[
'pathname'], \
657 prefix[(unit_i) + (H.nested * 5)])
660 if os.path.exists(filename):
661 H.filename = filename
665 inputvars = [
'filename',
'numxgrid',
'numygrid',
666 'zdims',
'numpoint',
'nageclass', \
667 'scaledepo',
'scaleconc',
668 'decayconstant',
'numpointspec']
670 print v,
" ==> ", H[v]
675 gridT, wetgrid, drygrid, itime =
_readgridBF(H, filename)
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)
684 zplot = gridT[:, :, :, :, 0]
686 zplot = gridT[:, :, :, :, 0]
692 zplot = sumgrid(zplot, gridT, \
697 if H.direction ==
'forward':
712 FLEXDATA[(s, datestring)][
'grid'] = D
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
725 _shout(
'***ERROR: file %s not found! \n' % filename)
727 fd.set_with_dict(FLEXDATA)
732 qind = (0, fd.grid_dates[0])
733 fd.grid = fd[qind][fd[qind].keys()[0]].grid
746 BinaryFile: A class for accessing data to/from large binary files
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
755 This class is seeking capable.
757 :Author: Francesc Alted
758 :Contact: faltet@pytables.org
760 :Acknowledgment: Funding for the development of this code is provided
761 through the Norwegian Research Council VAUUAV project #184724, 2010
769 'i1':
'b',
'i2':
'h',
'i4':
'i',
770 'f4':
'f',
'f8':
'd',
773 def __init__(self, filename, mode="r", order="fortran"):
774 """Open the `filename` for write/read binary files.
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.
782 `order` specifies whether the file is is written in 'fortran'
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'."
791 """The order for file ('c' or 'fortran')."""
796 def read(self, dtype, shape=(1,)):
797 """Read an array of `dtype` and `shape` from current position.
799 `shape` must be any tuple made of integers or even () for scalars.
801 The current position will be updated to point to the end of
804 if not isinstance(dtype, np.dtype):
805 dtype = np.dtype(dtype)
806 if type(shape) is int:
808 if type(shape) is not tuple:
809 raise ValueError, "shape must be a tuple"
810 length = dtype.itemsize
815 length *= np.array(shape).prod()
817 # Correct the shape in case dtype is multi-dimensional
819 shape = shape + dtype.shape
824 if shape in (1, (1,)):
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."
835 # Convert read string into a regular array, or scalar
836 dts = dtype.base.str[1:]
840 elif dts in self.structtypes:
841 data = struct.unpack(self.structtypes[dts], data)[0]
843 data = np.ndarray(shape=shape, buffer=data, dtype=dtype.base)
845 # Retrieve the scalar out of the 0-dim array
849 # If original data file is in fortran mode, reverse the
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
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:
866 def write(self, arr):
867 """Write an `arr` to current position.
869 The current position will be updated to point to the end of
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)
879 def seek(self, offset, whence=0):
880 """Move to new file position.
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.
891 self.file.seek(offset, whence)
895 "Returns current file position, an integer (may be a long integer)."
896 return self.file.tell()
900 "Flush buffers to file."
905 "End access to file."
909 def closest(num, numlist):
910 """ returns the index of the *closest* value in a list """
911 # check if we're using datetimes
913 if isinstance(num, datetime.datetime):
917 assert isinstance(numlist[0], datetime.datetime), \
918 "num is date, numlist must be a list of dates"
919 numlist = date2num(numlist)
921 return (np.abs(numlist - num)).argmin()
925 class Structure(dict, object):
926 """ A 'fancy' dictionary that provides 'MatLab' structure-like
930 may be replaced with a pure dict in future release.
933 def __getattr__(self, attr):
934 # Fake a __getstate__ method that returns None
935 if attr == "__getstate__":
939 def __setattr__(self, attr, value):
943 """ necessary for Ipython tab-completion """
946 def set_with_dict(self, D):
947 """ set attributes with a dict """
949 self.__setattr__(k, D[k])
952 def data_range(data, min='median'):
954 return a data range for flexpart data
956 optional keyword min = ['median', 'mean', 'min']
958 dmax = np.nanmax(data)
963 dmin = np.mean(data[data.nonzero()])
964 elif min == 'median':
965 dmin = np.median(data[data.nonzero()])
967 dmin = np.nanmin(data[data.nonzero()])
974 #### Below for use from command line ##########################################
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'})
984 if __name__ == '__main__':
HELPER FUNCTIONS ##########.