NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/raw2proc/trunk/raw2proc/proc_cr1000_flow.py

Revision 448 (checked in by cbc, 13 years ago)

Add new Billy Mitchell configs.

Line 
1 #!/usr/bin/env python
2 # Last modified:  Time-stamp: <2010-12-09 16:14:55 haines>
3 """
4 how to parse data, and assert what data and info goes into
5 creating and updating monthly netcdf files
6
7 parse data water level and flow data (sontek argonaut and pressure
8 sensor) collected on Campbell Scientific DataLogger (loggernet) (csi)
9
10 parser : sample date and time, water_depth and flow from sontek and pressure
11
12 creator : lat, lon, z, time, sontek_wl, sontek_flow, press_wl, press_flow
13 updator : time, sontek_wl, sontek_flow, press_wl, press_flow
14
15
16 Examples
17 --------
18
19 >> (parse, create, update) = load_processors('proc_csi_adcp_v2')
20 or
21 >> si = get_config(cn+'.sensor_info')
22 >> (parse, create, update) = load_processors(si['adcp']['proc_module'])
23
24 >> lines = load_data(filename)
25 >> data = parse(platform_info, sensor_info, lines)
26 >> create(platform_info, sensor_info, data) or
27 >> update(platform_info, sensor_info, data)
28
29 """
30
31
32 from raw2proc import *
33 from procutil import *
34 from ncutil import *
35
36 now_dt = datetime.utcnow()
37 now_dt.replace(microsecond=0)
38
39 def parser(platform_info, sensor_info, lines):
40     """
41     From FSL (CSI datalogger program files):
42    
43     Example data: NO Sontek
44
45     TOA5,CR1000_CBC,CR1000,5498,CR1000.Std.11,CPU:UNC_CrowBranch.CR1,1554,Data15Min
46     TIMESTAMP,RECORD,RainIn_Tot,WaterLevelFt,Flow
47     TS,RN,,,
48     ,,Tot,Smp,Smp
49     2009-01-22 15:30:00,0,0,0,0
50     2009-01-22 15:45:00,1,0,0,0
51     2009-01-22 16:00:00,2,0.01,0,0
52     2009-01-22 16:15:00,3,0,0,0
53
54     Example data: with Sontek
55
56     """
57
58     import numpy
59     from datetime import datetime
60     from time import strptime
61
62     # get sample datetime from filename
63     fn = sensor_info['fn']
64     sample_dt_start = filt_datetime(fn)
65
66     # how many samples (don't count header 4 lines)
67     nsamp = len(lines[4:])
68
69     N = nsamp
70     data = {
71         'dt' : numpy.array(numpy.ones((N,), dtype=object)*numpy.nan),
72         'time' : numpy.array(numpy.ones((N,), dtype=long)*numpy.nan),
73         'rain' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
74         'sontek_wl' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
75         'sontek_flow' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
76         'press' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
77         'press_wl' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
78         'press_flow' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
79         'press_csi_ft' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
80         'press_csi_cfs' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
81         }
82
83     # sample count
84     i = 0
85
86     for line in lines[4:]:
87         csi = []
88         # split line
89         sw = re.split(',', line)
90         if len(sw)<=0:
91             print ' ... skipping line %d ' % (i,)
92             continue
93
94         # replace any "NAN" text with a number
95         for index, s in enumerate(sw):
96             m = re.search(NAN_RE_STR, s)
97             if m:
98                 sw[index] = '-99999'
99
100         # parse date-time, and all other float and integers
101         for s in sw[1:]:
102             m = re.search(REAL_RE_STR, s)
103             if m:
104                 csi.append(float(m.groups()[0]))
105
106         if  sensor_info['utc_offset']:
107             sample_dt = scanf_datetime(sw[0], fmt='"%Y-%m-%d %H:%M:%S"') + \
108                         timedelta(hours=sensor_info['utc_offset'])
109         else:
110             sample_dt = scanf_datetime(sw[0], fmt='"%Y-%m-%d %H:%M:%S"')
111
112         data['dt'][i] = sample_dt # sample datetime
113         data['time'][i] = dt2es(sample_dt) # sample time in epoch seconds
114        
115         # SMH -- 2009-12-05 modification
116         # press_csi water level and flow conversion on the data logger is not correct
117         # this will be reverted to original pressure reading and wl and flow recomputed.
118         if len(csi)==6:
119             # MOW has all six fields but no sontek now
120             data['rain'][i] =  csi[1] # 15 min rain count (inches)
121             # data['sontek_wl'][i] = csi[2] # sontek water level (ft)
122             # data['sontek_flow'][i] = csi[3] # sontek flow (cfs)
123             data['press_csi_ft'][i] = csi[4] # csi reported pressure water level (ft)
124             data['press_csi_cfs'][i] = csi[5] # csi reported flow (cfs)
125             i=i+1
126         elif len(csi)==4:
127             # CBC is not reporting pressure level and flow -- no pressure sensor!
128             data['rain'][i] =  csi[1] # 15 min rain count (inches)
129             data['sontek_wl'][i] = csi[2] # sontek water level (ft)
130             data['sontek_flow'][i] = csi[3] # sontek flow (cfs)
131             i=i+1
132         else:
133             print ' ... skipping line %d -- %s ' % (i,line)
134             continue
135
136         # if re.search
137     # for line
138
139     # revert  press_csi_ft back  to raw  pressure  reading (eventually
140     # want csi to just report the  raw pressure reading so we can just
141     # do this ourselves.
142     data['press'] = (data['press_csi_ft']+1.5)/27.6778 # raw pressure (psi)
143     # convert psi to height of water column based on hydrostatic eqn
144     data['press_wl'] = data['press']*2.3059+sensor_info['press_offset'] # (feet)
145    
146     # flow based on parameter as computed by data logger
147     # data['press_flow'] = data['press_csi_cfs']
148                                
149     # flow based on calculation from data logger but applied to offset calibration
150     # SMH does not know what equation is based on or how these values are derived
151     data['press_flow'] = ((data['press_wl']*12))*10.81 - 8.81 # cfs
152
153     # check that no data[dt] is set to Nan or anything but datetime
154     # keep only data that has a resolved datetime
155     keep = numpy.array([type(datetime(1970,1,1)) == type(dt) for dt in data['dt'][:]])
156     if keep.any():
157         for param in data.keys():
158             data[param] = data[param][keep]
159
160     return data
161  
162
163 def creator(platform_info, sensor_info, data):
164     #
165     #
166     title_str = sensor_info['description']+' at '+ platform_info['location']
167     global_atts = {
168         'title' : title_str,
169         'institution' : 'Unversity of North Carolina at Chapel Hill (UNC-CH)',
170         'institution_url' : 'http://nccoos.unc.edu',
171         'institution_dods_url' : 'http://nccoos.unc.edu',
172         'metadata_url' : 'http://nccoos.unc.edu',
173         'references' : 'http://nccoos.unc.edu',
174         'contact' : 'Sara Haines (haines@email.unc.edu)',
175         'station_owner' : 'Environment, Health, and Safety Office',
176         'station_contact' : 'Sharon Myers (samyers@ehs.unc.edu)',
177         #
178         'source' : 'fixed-observation',
179         'history' : 'raw2proc using ' + sensor_info['process_module'],
180         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
181         # conventions
182         'Conventions' : 'CF-1.0; SEACOOS-CDL-v2.0',
183         # SEACOOS CDL codes
184         'format_category_code' : 'fixed-point',
185         'institution_code' : platform_info['institution'],
186         'platform_code' : platform_info['id'],
187         'package_code' : sensor_info['id'],
188         # institution specific
189         'project' : 'Environment, Health, and Safety (EHS)',
190         'project_url' : 'http://ehs.unc.edu/environment/water_quality',
191         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
192         # first date in monthly file
193         'start_date' : data['dt'][0].strftime("%Y-%m-%d %H:%M:%S"),
194         # last date in monthly file
195         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
196         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
197         #
198         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
199         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
200         'process_level' : 'level1',
201         #
202         # must type match to data (e.g. fillvalue is real if data is real)
203         '_FillValue' : -99999.,
204         }
205
206     var_atts = {
207         # coordinate variables
208         'time' : {'short_name': 'time',
209                   'long_name': 'Time',
210                   'standard_name': 'time',
211                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
212                   'axis': 'T',
213                   },
214         'lat' : {'short_name': 'lat',
215              'long_name': 'Latitude',
216              'standard_name': 'latitude',
217              'reference':'geographic coordinates',
218              'units': 'degrees_north',
219              'valid_range':(-90.,90.),
220              'axis': 'Y',
221              },
222         'lon' : {'short_name': 'lon',
223                  'long_name': 'Longitude',
224                  'standard_name': 'longitude',
225                  'reference':'geographic coordinates',
226                  'units': 'degrees_east',
227                  'valid_range':(-180.,180.),
228                  'axis': 'Y',
229                  },
230         'z' : {'short_name': 'z',
231                'long_name': 'Altitude',
232                'standard_name': 'altitude',
233                'reference':'zero at mean sea level',
234                'positive' : 'up',
235                'units': 'm',
236                'axis': 'Z',
237                },
238         # data variables
239         'rain': {'short_name': 'rain',
240                  'long_name': '15-Minute Rain',
241                  'standard_name': 'rain',                         
242                  'units': 'inches',
243                   },
244         'sontek_wl': {'short_name': 'sontek_wl',
245                   'long_name': 'Sontek Water Level',
246                   'standard_name': 'water_level',                         
247                   'units': 'feet',
248                   'reference':'zero at station altitude',
249                   'positive' : 'up',
250                   },
251         'sontek_flow': {'short_name': 'flow',
252                         'long_name': 'Sontek Stream Flow',
253                         'standard_name': 'water_flux',                         
254                         'units': 'cfs',
255                         },
256         'press_wl': { 'short_name': 'press_wl',
257                   'long_name': 'Pressure Water Level',
258                   'standard_name': 'water_level',                         
259                   'units': 'feet',
260                   'reference':'zero at station altitude',
261                   'positive' : 'up',
262                   },
263         'press_flow': { 'short_name': 'flow',
264                         'long_name': 'Pressure Stream Flow',
265                         'standard_name': 'water_flux',                         
266                         'units': 'cfs',
267                         },
268         }
269
270     # dimension names use tuple so order of initialization is maintained
271     dim_inits = (
272         ('ntime', NC.UNLIMITED),
273         ('nlat', 1),
274         ('nlon', 1),
275         ('nz', 1),
276         )
277    
278     # using tuple of tuples so order of initialization is maintained
279     # using dict for attributes order of init not important
280     # use dimension names not values
281     # (varName, varType, (dimName1, [dimName2], ...))
282     var_inits = (
283         # coordinate variables
284         ('time', NC.INT, ('ntime',)),
285         ('lat', NC.FLOAT, ('nlat',)),
286         ('lon', NC.FLOAT, ('nlon',)),
287         ('z',  NC.FLOAT, ('nz',)),
288         # data variables
289         ('rain', NC.FLOAT, ('ntime',)),
290         ('sontek_wl', NC.FLOAT, ('ntime',)),
291         ('sontek_flow', NC.FLOAT, ('ntime',)),
292         ('press_wl', NC.FLOAT, ('ntime',)),
293         ('press_flow', NC.FLOAT, ('ntime',)),
294         )
295
296     # subset data only to month being processed (see raw2proc.process())
297     i = data['in']
298    
299     # var data
300     var_data = (
301         ('lat',  platform_info['lat']),
302         ('lon', platform_info['lon']),
303         ('z', platform_info['altitude']),
304         #
305         ('time', data['time'][i]),
306         #
307         ('rain', data['rain'][i]),
308         ('sontek_wl', data['sontek_wl'][i]),
309         ('sontek_flow', data['sontek_flow'][i]),
310         ('press_wl', data['press_wl'][i]),
311         ('press_flow', data['press_flow'][i]),
312         )
313
314     return (global_atts, var_atts, dim_inits, var_inits, var_data)
315
316 def updater(platform_info, sensor_info, data):
317     #
318     global_atts = {
319         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
320         # last date in monthly file
321         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
322         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
323         #
324         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
325         }
326
327     # data variables
328     # update any variable attributes like range, min, max
329     var_atts = {}
330     # var_atts = {
331     #    'wtemp': {'max': max(data.u),
332     #          'min': min(data.v),
333     #          },
334     #    'cond': {'max': max(data.u),
335     #          'min': min(data.v),
336     #          },
337     #    }
338    
339     # subset data only to month being processed (see raw2proc.process())
340     i = data['in']
341
342     # data
343     var_data = (
344         ('time', data['time'][i]),
345         #
346         ('rain', data['rain'][i]),
347         ('sontek_wl', data['sontek_wl'][i]),
348         ('sontek_flow', data['sontek_flow'][i]),
349         ('press_wl', data['press_wl'][i]),
350         ('press_flow', data['press_flow'][i]),
351         )
352
353     return (global_atts, var_atts, var_data)
354 #
Note: See TracBrowser for help on using the browser.