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

root/raw2proc/trunk/raw2proc/proc_nortek_wpa_adcp.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:13:37 haines>
3 """
4 how to parse data, and assert what data and info goes into
5 creating and updating monthly netcdf files
6
7 RDI/Wavesmon processed adcp current profile data
8
9 parser : sample date and time, currents, water temperature, pressure and water_depth
10
11 creator : lat, lon, z, time, ens, u, v, w, water_depth, water_temp (at tranducer depth), pressure
12 updator : time, ens, u, v, w, water_depth, water_temp (at tranducer depth), pressure
13
14
15 Examples
16 --------
17
18 >> (parse, create, update) = load_processors('proc_rdi_logdata_adcp')
19 or
20 >> si = get_config(cn+'.sensor_info')
21 >> (parse, create, update) = load_processors(si['adcp']['proc_module'])
22
23 >> lines = load_data(filename)
24 >> data = parse(platform_info, sensor_info, lines)
25 >> create(platform_info, sensor_info, data) or
26 >> update(platform_info, sensor_info, data)
27
28 """
29
30
31 from raw2proc import *
32 from procutil import *
33 from ncutil import *
34
35 import seawater
36
37 now_dt = datetime.utcnow()
38 now_dt.replace(microsecond=0)
39
40 def parser(platform_info, sensor_info, lines):
41     """
42     parse and assign ocean profile current data from Nortek AWAC ADCP Data
43
44     Notes
45     -----
46     1. This parser requires date/time be parsed from .wap for each to
47     get sig_wave_ht for determining depth of each bin and surface mask
48     and check time same as in .wpa file.
49
50     2. multiple profiles in one file separated by header w/time,
51        pitch, roll, heading, ducer pressure, bottom temp, top bin#
52        bottom bin# (??).  The profile data is several lines one for
53        each bin.
54     
55     MM DD YYYY HH MM SS  ERR STATUS BATT SNDSPD HDG  PITCH  ROLL  PRESS   WTEMP    ??  ?? TBIN BBIN
56     07 31 2008 23 54 00    0   48  18.2 1525.8 270.1  -2.4   0.2  10.503  21.64     0     0 3  34
57        1    0.9    0.071   24.04    0.029    0.065   -0.058 123 126 124
58        2    1.4    0.089  342.38   -0.027    0.085   -0.057 110 111 113
59        3    1.9    0.065  310.03   -0.050    0.042   -0.063 102 104 104
60        4    2.4    0.063   46.93    0.046    0.043   -0.045  93  95  99
61        5    2.9    0.049  355.33   -0.004    0.049   -0.047  87  89  92
62          ...
63      NBIN  DEPTH   SPEED    DIR       U         V       W    E1? E2? E3?
64        32   16.4    0.184  331.76   -0.087    0.162   -0.162  26  25  27
65        33   16.9    0.137  288.70   -0.130    0.044   -0.181  26  24  26
66        34   17.4    0.070   32.78    0.038    0.059   -0.248  25  25  26
67
68     3. not sure if depth column is hab or down from surface?
69
70
71     """
72
73     # get sample datetime from filename
74     fn = sensor_info['fn']
75     sample_dt_start = filt_datetime(fn)
76
77     nbins = sensor_info['nbins'# Number of bins in data
78     nbursts = len(lines)/(nbins+1)
79
80     data = {
81         'dt' : numpy.array(numpy.ones((nbursts,), dtype=object)*numpy.nan),
82         'time' : numpy.array(numpy.ones((nbursts,), dtype=long)*numpy.nan),
83         'z' : numpy.array(numpy.ones((nbins,), dtype=float)*numpy.nan),
84         'u' : numpy.array(numpy.ones((nbursts,nbins), dtype=float)*numpy.nan),
85         'v' : numpy.array(numpy.ones((nbursts,nbins), dtype=float)*numpy.nan),
86         'w' : numpy.array(numpy.ones((nbursts,nbins), dtype=float)*numpy.nan),
87         'e1' : numpy.array(numpy.ones((nbursts,nbins), dtype=int)*numpy.nan),
88         'e2' : numpy.array(numpy.ones((nbursts,nbins), dtype=int)*numpy.nan),
89         'e3' : numpy.array(numpy.ones((nbursts,nbins), dtype=int)*numpy.nan),
90         'wd' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
91         'wl' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
92         'water_temp' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
93         'pressure' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
94         }
95
96     # these items can also be teased out of raw adcp but for now get from config file
97     th = sensor_info['transducer_ht'# Transducer height above bottom (meters)
98     bh = sensor_info['blanking_ht']    # Blanking height above Transducer (meters)
99     bin_size = sensor_info['bin_size'] # Bin Size (meters)
100     
101     # compute height for each bin above the bottom
102     bins = numpy.arange(1,nbins+1)
103     # bin_habs = (bins*bin_size+bin_size/2)+th+bh
104     bin_habs = (bins*bin_size+bin_size/2)+th+bh
105
106     # added by SH -- 15 Oct 2008
107     # raw2proc:ticket:27 adjust bin_habs along beam to nadir
108     # Nortek awac beam angle is fixed at 25 deg
109     # adjustment is cos(25 deg) (which is  approx .90*height)
110     # -------------------
111     # bin_habs =  (bin_habs*numpy.cos(25.*numpy.pi/180))
112     # -------------------
113     # commented out by SH -- 18 Aug 2010
114     # This does not apply to habs provided in .wpa.  They
115     # are adjusted for beam angle in ascii output.
116     iaboveblank = bin_habs > th+bh+(bin_size)
117
118     # current profile count
119     i = 0
120
121     wpa = []
122     for line in lines:
123         wpa = []
124         # split line and parse float and integers
125         sw = re.split(' ', line)
126         for s in sw:
127             m = re.search(REAL_RE_STR, s)
128             if m:
129                 wpa.append(float(m.groups()[0]))
130
131         if len(wpa)==19:                                                                             
132             # get sample datetime from data
133             sample_str = '%02d-%02d-%4d %02d:%02d:%02d' % tuple(wpa[0:6])
134             if  sensor_info['utc_offset']:
135                 sample_dt = scanf_datetime(sample_str, fmt='%m-%d-%Y %H:%M:%S') + \
136                             timedelta(hours=sensor_info['utc_offset'])
137             else:
138                 sample_dt = scanf_datetime(sample_str, fmt='%m-%d-%Y %H:%M:%S')
139            
140             # these items can also be teased out of raw adcp but for now get from config file
141             # th = sensor_info['transducer_ht']  # Transducer height above bottom (meters)
142             
143             error_code = int(wpa[6])
144             status_code = int(wpa[7])
145             battery_voltage = wpa[8] # volts
146             sound_speed = wpa[9]     # m/s
147             heading = wpa[10]        # deg
148             pitch = wpa[11]          # deg
149             roll = wpa[12]           # deg
150             
151             pressure = wpa[13]       # dbar
152             # pressure (dbar) converted to water depth
153             wd = th + seawater.depth(pressure, platform_info['lat']) # m
154             temperature = wpa[14]       # deg C
155
156             start_bin = int(wpa[17])     # first good bin from transducer (?)
157             wpa_nbins = int(wpa[18])     # Number of bins
158             # check this is same as in sensor_info
159
160             # initialize for new profile
161             hab = numpy.ones(nbins)*numpy.nan
162             spd = numpy.ones(nbins)*numpy.nan
163             dir = numpy.ones(nbins)*numpy.nan
164             u = numpy.ones(nbins)*numpy.nan
165             v = numpy.ones(nbins)*numpy.nan
166             w = numpy.ones(nbins)*numpy.nan
167             e1 = numpy.array(numpy.ones((nbins), dtype=int)*numpy.nan)
168             e2 = numpy.array(numpy.ones((nbins), dtype=int)*numpy.nan)
169             e3 = numpy.array(numpy.ones((nbins), dtype=int)*numpy.nan)
170
171         elif len(wpa)==10:
172             # current profile data at  each bin
173             bin_number = wpa[0]
174             j = wpa[0]-1
175             # print j
176             hab[j] = wpa[1]
177            
178             spd[j] = wpa[2] # m/s
179             dir[j] = wpa[3] # deg N
180
181             u[j] = wpa[4] # m/s
182             v[j] = wpa[5] # m/s
183             w[j] = wpa[6] # m/s
184
185             e1[j] = int(wpa[7]) # echo dB ??
186             e2[j] = int(wpa[8]) #
187             e3[j] = int(wpa[9]) #
188
189             # ibad = (current_spd==-32768) | (current_dir==-32768)
190             # current_spd[ibad] = numpy.nan
191             # current_dir[ibad] = numpy.nan
192
193             # if done reading profile, just read data for last bin
194             if bin_number==nbins:
195                 # compute water mask
196                 # if positive is up, in water is less than zero depth
197                 bin_depths =  (bin_habs)-(wd)
198                 iwater = bin_depths+bin_size/2 < 0
199                 iwater = iwater*iaboveblank
200                
201                 # use nominal water depth (MSL) averaged from full pressure record
202                 #  this should be checked/recalulated every so often
203                 z = bin_habs+platform_info['mean_water_depth']
204                
205                 data['dt'][i] = sample_dt # sample datetime
206                 data['time'][i] = dt2es(sample_dt) # sample time in epoch seconds
207                 data['z'] =  z
208                 data['wd'][i] = -1*wd
209                 data['wl'][i] = platform_info['mean_water_depth'] - (-1*wd)
210                 data['water_temp'][i] = temperature
211                 data['pressure'][i] = pressure
212                
213                 data['u'][i][iwater] =  u[iwater]
214                 data['v'][i][iwater] =  v[iwater]
215                 data['w'][i][iwater] =  w[iwater]
216
217                 data['e1'][i] =  e1
218                 data['e2'][i] =  e2
219                 data['e3'][i] =  e3
220
221                 # ready for next burst
222                 i = i+1
223             # if j+1==nbins
224         # if len(wpa)==19 elif ==10
225     # for line
226
227     return data
228  
229
230 def creator(platform_info, sensor_info, data):
231     #
232     #
233     title_str = sensor_info['description']+' at '+ platform_info['location']
234
235     if 'mean_water_depth' in platform_info.keys():
236         msl_str = platform_info['mean_water_depth']
237     else:
238         msl_str = 'None'
239     if 'mean_water_depth_time_period' in platform_info.keys():
240         msl_tp_str = platform_info['mean_water_depth_time_period']
241     else:
242         msl_tp_str = 'None'
243
244     global_atts = {
245         'title' : title_str,
246         'institution' : 'University of North Carolina at Chapel Hill (UNC-CH)',
247         'institution_url' : 'http://nccoos.unc.edu',
248         'institution_dods_url' : 'http://nccoos.unc.edu',
249         'metadata_url' : 'http://nccoos.unc.edu',
250         'references' : 'http://nccoos.unc.edu',
251         'contact' : 'Sara Haines (haines@email.unc.edu)',
252         #
253         'source' : 'fixed-profiler (acoustic doppler) observation',
254         'history' : 'raw2proc using ' + sensor_info['process_module'],
255         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
256         # conventions
257         'Conventions' : 'CF-1.0; SEACOOS-CDL-v2.0',
258         # SEACOOS CDL codes
259         'format_category_code' : 'fixed-profiler',
260         'institution_code' : platform_info['institution'],
261         'platform_code' : platform_info['id'],
262         'package_code' : sensor_info['id'],
263         # institution specific
264         'project' : 'North Carolina Coastal Ocean Observing System (NCCOOS)',
265         'project_url' : 'http://nccoos.unc.edu',
266         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
267         # first date in monthly file
268         'start_date' : data['dt'][0].strftime("%Y-%m-%d %H:%M:%S"),
269         # last date in monthly file
270         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
271         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
272         #
273         'mean_water_depth' : msl_str,
274         'mean_water_depth_time_period' : msl_tp_str,
275         #
276         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
277         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
278         'process_level' : 'level1',
279         #
280         # must type match to data (e.g. fillvalue is real if data is real)
281         '_FillValue' : numpy.nan,
282         }
283
284     var_atts = {
285         # coordinate variables
286         'time' : {'short_name': 'time',
287                   'long_name': 'Time',
288                   'standard_name': 'time',
289                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
290                   'axis': 'T',
291                   },
292         'lat' : {'short_name': 'lat',
293              'long_name': 'Latitude',
294              'standard_name': 'latitude',
295              'reference':'geographic coordinates',
296              'units': 'degrees_north',
297              'valid_range':(-90.,90.),
298              'axis': 'Y',
299              },
300         'lon' : {'short_name': 'lon',
301                  'long_name': 'Longitude',
302                  'standard_name': 'longitude',
303                  'reference':'geographic coordinates',
304                  'units': 'degrees_east',
305                  'valid_range':(-180.,180.),
306                  'axis': 'Y',
307                  },
308         'z' : {'short_name': 'z',
309                'long_name': 'Height',
310                'standard_name': 'height',
311                'reference':'zero at mean-sea-level',
312                'positive' : 'up',
313                'units': 'm',
314                'axis': 'Z',
315                },
316         # data variables
317         'u': {'short_name' : 'u',
318               'long_name': 'East/West Component of Current',
319               'standard_name': 'eastward_current',
320               'units': 'm s-1',
321               'reference': 'clockwise from True East',
322               },
323         'v': {'short_name' : 'v',
324               'long_name': 'North/South Component of Current',
325               'standard_name': 'northward_current',                         
326               'units': 'm s-1',
327               'reference': 'clockwise from True North',
328               },
329         'w': {'short_name' : 'w',
330               'long_name': 'Vertical Component of Current',
331               'standard_name': 'upward_current',                         
332               'units': 'm s-1',
333               'reference': 'clockwise from True North',
334               },
335         'e1': {'short_name' : 'e1',
336               'long_name': 'Echo Beam 1 (??)',
337               'standard_name': 'beam_echo',
338               'units': 'dB',
339               },
340         'e2': {'short_name' : 'e2',
341               'long_name': 'Echo Beam 2 (??)',
342               'standard_name': 'beam_echo',
343               'units': 'dB',
344               },
345         'e3': {'short_name' : 'e3',
346               'long_name': 'Echo Beam 3 (??)',
347               'standard_name': 'beam_echo',
348               'units': 'dB',
349               },
350         'wd': {'short_name': 'wd',
351                'long_name': 'Water Depth',
352                'standard_name': 'water_depth',                         
353                'reference':'zero at surface',
354                'positive' : 'up',
355                'units': 'm',
356                },
357         'wl': {'short_name': 'wl',
358                'long_name': 'Water Level',
359                'standard_name': 'water_level',                         
360                'reference':'MSL',
361                'reference_to_MSL' : 0.,
362                'reference_MSL_datum' : platform_info['mean_water_depth'],
363                'reference_MSL_datum_time_period' : platform_info['mean_water_depth_time_period'],
364                'positive' : 'up',
365                'z' : 0.,
366                'units': 'm',
367                },
368         'pressure': {'short_name': 'p',
369                      'long_name': 'Pressure',
370                      'standard_name': 'pressure',                         
371                      'units': 'dbar',
372                      },
373         'water_temp': {'short_name': 'wtemp',
374                         'long_name': 'Water Temperature at Transducer',
375                         'standard_name': 'water_temperature',                         
376                         'units': 'deg_C',
377                         },
378         }
379
380
381     # dimension names use tuple so order of initialization is maintained
382     dim_inits = (
383         ('ntime', NC.UNLIMITED),
384         ('nlat', 1),
385         ('nlon', 1),
386         ('nz', sensor_info['nbins'])
387         )
388    
389     # using tuple of tuples so order of initialization is maintained
390     # using dict for attributes order of init not important
391     # use dimension names not values
392     # (varName, varType, (dimName1, [dimName2], ...))
393     var_inits = (
394         # coordinate variables
395         ('time', NC.INT, ('ntime',)),
396         ('lat', NC.FLOAT, ('nlat',)),
397         ('lon', NC.FLOAT, ('nlon',)),
398         ('z',  NC.FLOAT, ('nz',)),
399         # data variables
400         ('u', NC.FLOAT, ('ntime', 'nz')),
401         ('v', NC.FLOAT, ('ntime', 'nz')),
402         ('w', NC.FLOAT, ('ntime', 'nz')),
403         ('e1', NC.INT, ('ntime', 'nz')),
404         ('e2', NC.INT, ('ntime', 'nz')),
405         ('e3', NC.INT, ('ntime', 'nz')),
406         ('wd', NC.FLOAT, ('ntime',)),
407         ('wl', NC.FLOAT, ('ntime',)),
408         ('pressure', NC.FLOAT, ('ntime',)),
409         ('water_temp', NC.FLOAT, ('ntime',)),
410         )
411
412     # subset data only to month being processed (see raw2proc.process())
413     i = data['in']
414    
415     # var data
416     var_data = (
417         ('lat',  platform_info['lat']),
418         ('lon', platform_info['lon']),
419         ('z', data['z']),
420         #
421         ('time', data['time'][i]),
422         ('u', data['u'][i]),
423         ('v', data['v'][i]),
424         ('w', data['w'][i]),
425         ('e1', data['e1'][i]),
426         ('e2', data['e2'][i]),
427         ('e3', data['e3'][i]),
428         ('wd', data['wd'][i]),
429         ('wl', data['wl'][i]),
430         ('pressure', data['pressure'][i]),
431         ('water_temp', data['water_temp'][i]),
432         )
433
434     return (global_atts, var_atts, dim_inits, var_inits, var_data)
435
436 def updater(platform_info, sensor_info, data):
437     #
438     global_atts = {
439         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
440         # last date in monthly file
441         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
442         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
443         #
444         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
445         }
446
447     # data variables
448     # update any variable attributes like range, min, max
449     var_atts = {}
450     # var_atts = {
451     #    'u': {'max': max(data.u),
452     #          'min': min(data.v),
453     #          },
454     #    'v': {'max': max(data.u),
455     #          'min': min(data.v),
456     #          },
457     #    }
458     
459     # subset data only to month being processed (see raw2proc.process())
460     i = data['in']
461
462     # data
463     var_data = (
464         ('time', data['time'][i]),
465         ('u', data['u'][i]),
466         ('v', data['v'][i]),
467         ('w', data['w'][i]),
468         ('e1', data['e1'][i]),
469         ('e2', data['e2'][i]),
470         ('e3', data['e3'][i]),
471         ('wd', data['wd'][i]),
472         ('wl', data['wl'][i]),
473         ('pressure', data['pressure'][i]),
474         ('water_temp', data['water_temp'][i]),
475         )
476
477     return (global_atts, var_atts, var_data)
478 #
479
Note: See TracBrowser for help on using the browser.