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

root/raw2proc/trunk/raw2proc/proc_nortek_wpa_adcp.py

Revision 211 (checked in by haines, 16 years ago)

corrected lon to negative for (longitude W) in config files; corrected misspelled field in all proc_*.py

Line 
1 #!/usr/bin/env python
2 # Last modified:  Time-stamp: <2008-10-01 12:47:16 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)[0]
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         'water_depth' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
91         'water_temp' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
92         'pressure' : numpy.array(numpy.ones((nbursts), dtype=float)*numpy.nan),
93         }
94
95     # these items can also be teased out of raw adcp but for now get from config file
96     th = sensor_info['transducer_ht'# Transducer height above bottom (meters)
97     bh = sensor_info['blanking_ht']    # Blanking height above Transducer (meters)
98     bin_size = sensor_info['bin_size'] # Bin Size (meters)
99     
100     # compute height for each bin above the bottom
101     bins = numpy.arange(1,nbins+1)
102     # bin_habs = (bins*bin_size+bin_size/2)+th+bh
103     bin_habs = (bins*bin_size+bin_size/2)
104     iaboveblank = bin_habs > th+bh+(bin_size)
105
106     # current profile count
107     i = 0
108
109     wpa = []
110     for line in lines:
111         wpa = []
112         # split line and parse float and integers
113         sw = re.split(' ', line)
114         for s in sw:
115             m = re.search(REAL_RE_STR, s)
116             if m:
117                 wpa.append(float(m.groups()[0]))
118
119         if len(wpa)==19:                                                                             
120             # get sample datetime from data
121             sample_str = '%02d-%02d-%4d %02d:%02d:%02d' % tuple(wpa[0:6])
122             if  sensor_info['utc_offset']:
123                 sample_dt = scanf_datetime(sample_str, fmt='%m-%d-%Y %H:%M:%S') + \
124                             timedelta(hours=sensor_info['utc_offset'])
125             else:
126                 sample_dt = scanf_datetime(sample_str, fmt='%m-%d-%Y %H:%M:%S')
127            
128             # these items can also be teased out of raw adcp but for now get from config file
129             # th = sensor_info['transducer_ht']  # Transducer height above bottom (meters)
130             
131             error_code = int(wpa[6])
132             status_code = int(wpa[7])
133             battery_voltage = wpa[8] # volts
134             sound_speed = wpa[9]     # m/s
135             heading = wpa[10]        # deg
136             pitch = wpa[11]          # deg
137             roll = wpa[12]           # deg
138             
139             pressure = wpa[13]       # dbar
140             # pressure (dbar) converted to water depth
141             water_depth = th + seawater.depth(pressure, platform_info['lat']) # m
142             temperature = wpa[14]       # deg C
143
144             start_bin = int(wpa[17])     # first good bin from transducer (?)
145             wpa_nbins = int(wpa[18])     # Number of bins
146             # check this is same as in sensor_info
147
148             # initialize for new profile
149             bin_hab = numpy.ones(nbins)*numpy.nan
150             spd = numpy.ones(nbins)*numpy.nan
151             dir = numpy.ones(nbins)*numpy.nan
152             u = numpy.ones(nbins)*numpy.nan
153             v = numpy.ones(nbins)*numpy.nan
154             w = numpy.ones(nbins)*numpy.nan
155             e1 = numpy.array(numpy.ones((nbins), dtype=int)*numpy.nan)
156             e2 = numpy.array(numpy.ones((nbins), dtype=int)*numpy.nan)
157             e3 = numpy.array(numpy.ones((nbins), dtype=int)*numpy.nan)
158
159         elif len(wpa)==10:
160             # current profile data at  each bin
161             bin_number = wpa[0]
162             j = wpa[0]-1
163             bin_hab[j] = wpa[1]
164            
165             spd[j] = wpa[2] # m/s
166             dir[j] = wpa[3] # deg N
167
168             u[j] = wpa[4] # m/s
169             v[j] = wpa[5] # m/s
170             w[j] = wpa[6] # m/s
171
172             e1[j] = int(wpa[7]) # echo dB ??
173             e2[j] = int(wpa[8]) #
174             e3[j] = int(wpa[9]) #
175
176             # ibad = (current_spd==-32768) | (current_dir==-32768)
177             # current_spd[ibad] = numpy.nan
178             # current_dir[ibad] = numpy.nan
179
180             # if done reading profile, just read data for last bin
181             if bin_number==nbins:
182                 # compute water mask
183                 # Using George Voulgaris' method based on water depth
184                 # minus half of the significant wave height (Hs)
185                 # and computed habs
186                 # if positive is up, what's less than zero depth?
187                 bin_depths =  bin_habs-(water_depth)
188                 iwater = bin_depths+bin_size/2 < 0
189                 iwater = iwater*iaboveblank
190                
191                 # alternatively use nominal water depth (MSL) averaged from full pressure record
192                 #  this should be checked/recalulated every so often
193                 # MSL = sensor_info['mean_sea_level']  # Mean sea level at station (meters) or nominal water depth
194                 # MSL = 12. # **** first guess is 12 meters for jpier
195                 # z = bin_habs-MSL
196                 z = bin_habs
197                
198                 data['dt'][i] = sample_dt # sample datetime
199                 data['time'][i] = dt2es(sample_dt) # sample time in epoch seconds
200                 data['z'] =  z
201                 data['water_depth'][i] = water_depth
202                 data['water_temp'][i] = temperature
203                 data['pressure'][i] = pressure
204                
205                 data['u'][i][iwater] =  u[iwater]
206                 data['v'][i][iwater] =  v[iwater]
207                 data['w'][i][iwater] =  w[iwater]
208
209                 data['e1'][i] =  e1
210                 data['e2'][i] =  e2
211                 data['e3'][i] =  e3
212
213                 # ready for next burst
214                 i = i+1
215             # if j+1==nbins
216         # if len(wpa)==19 elif ==10
217     # for line
218
219     return data
220  
221
222 def creator(platform_info, sensor_info, data):
223     #
224     #
225     title_str = sensor_info['description']+' at '+ platform_info['location']
226     global_atts = {
227         'title' : title_str,
228         'institution' : 'University of North Carolina at Chapel Hill (UNC-CH)',
229         'institution_url' : 'http://nccoos.unc.edu',
230         'institution_dods_url' : 'http://nccoos.unc.edu',
231         'metadata_url' : 'http://nccoos.unc.edu',
232         'references' : 'http://nccoos.unc.edu',
233         'contact' : 'Sara Haines (haines@email.unc.edu)',
234         #
235         'source' : 'fixed-profiler (acoustic doppler) observation',
236         'history' : 'raw2proc using ' + sensor_info['process_module'],
237         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
238         # conventions
239         'Conventions' : 'CF-1.0; SEACOOS-CDL-v2.0',
240         # SEACOOS CDL codes
241         'format_category_code' : 'fixed-profiler',
242         'institution_code' : platform_info['institution'],
243         'platform_code' : platform_info['id'],
244         'package_code' : sensor_info['id'],
245         # institution specific
246         'project' : 'North Carolina Coastal Ocean Observing System (NCCOOS)',
247         'project_url' : 'http://nccoos.unc.edu',
248         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
249         # first date in monthly file
250         'start_date' : data['dt'][0].strftime("%Y-%m-%d %H:%M:%S"),
251         # last date in monthly file
252         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
253         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
254         #
255         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
256         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
257         'process_level' : 'level1',
258         #
259         # must type match to data (e.g. fillvalue is real if data is real)
260         '_FillValue' : -99999.,
261         }
262
263     var_atts = {
264         # coordinate variables
265         'time' : {'short_name': 'time',
266                   'long_name': 'Time',
267                   'standard_name': 'time',
268                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
269                   'axis': 'T',
270                   },
271         'lat' : {'short_name': 'lat',
272              'long_name': 'Latitude',
273              'standard_name': 'latitude',
274              'reference':'geographic coordinates',
275              'units': 'degrees_north',
276              'valid_range':(-90.,90.),
277              'axis': 'Y',
278              },
279         'lon' : {'short_name': 'lon',
280                  'long_name': 'Longitude',
281                  'standard_name': 'longitude',
282                  'reference':'geographic coordinates',
283                  'units': 'degrees_east',
284                  'valid_range':(-180.,180.),
285                  'axis': 'Y',
286                  },
287         'z' : {'short_name': 'z',
288                'long_name': 'Height',
289                'standard_name': 'height',
290                'reference':'zero at sea-surface',
291                'positive' : 'up',
292                'units': 'm',
293                'axis': 'Z',
294                },
295         # data variables
296         'u': {'short_name' : 'u',
297               'long_name': 'East/West Component of Current',
298               'standard_name': 'eastward_current',
299               'units': 'm s-1',
300               'reference': 'clockwise from True East',
301               },
302         'v': {'short_name' : 'v',
303               'long_name': 'North/South Component of Current',
304               'standard_name': 'northward_current',                         
305               'units': 'm s-1',
306               'reference': 'clockwise from True North',
307               },
308         'w': {'short_name' : 'w',
309               'long_name': 'Vertical Component of Current',
310               'standard_name': 'upward_current',                         
311               'units': 'm s-1',
312               'reference': 'clockwise from True North',
313               },
314         'e1': {'short_name' : 'e1',
315               'long_name': 'Echo Beam 1 (??)',
316               'standard_name': 'beam_echo',
317               'units': 'dB',
318               },
319         'e2': {'short_name' : 'e2',
320               'long_name': 'Echo Beam 2 (??)',
321               'standard_name': 'beam_echo',
322               'units': 'dB',
323               },
324         'e3': {'short_name' : 'e3',
325               'long_name': 'Echo Beam 3 (??)',
326               'standard_name': 'beam_echo',
327               'units': 'dB',
328               },
329         'water_depth': {'short_name': 'wd',
330                         'long_name': 'Water Depth',
331                         'standard_name': 'water_depth',                         
332                         'units': 'm',
333                         },
334         'pressure': {'short_name': 'p',
335                         'long_name': 'Pressure',
336                         'standard_name': 'pressure',                         
337                         'units': 'dbar',
338                         },
339         'water_temp': {'short_name': 'wtemp',
340                         'long_name': 'Water Temperature at Transducer',
341                         'standard_name': 'water_temperature',                         
342                         'units': 'deg C',
343                         },
344         }
345
346
347     # dimension names use tuple so order of initialization is maintained
348     dim_inits = (
349         ('ntime', NC.UNLIMITED),
350         ('nlat', 1),
351         ('nlon', 1),
352         ('nz', sensor_info['nbins'])
353         )
354    
355     # using tuple of tuples so order of initialization is maintained
356     # using dict for attributes order of init not important
357     # use dimension names not values
358     # (varName, varType, (dimName1, [dimName2], ...))
359     var_inits = (
360         # coordinate variables
361         ('time', NC.INT, ('ntime',)),
362         ('lat', NC.FLOAT, ('nlat',)),
363         ('lon', NC.FLOAT, ('nlon',)),
364         ('z',  NC.FLOAT, ('nz',)),
365         # data variables
366         ('u', NC.FLOAT, ('ntime', 'nz')),
367         ('v', NC.FLOAT, ('ntime', 'nz')),
368         ('w', NC.FLOAT, ('ntime', 'nz')),
369         ('e1', NC.INT, ('ntime', 'nz')),
370         ('e2', NC.INT, ('ntime', 'nz')),
371         ('e3', NC.INT, ('ntime', 'nz')),
372         ('water_depth', NC.FLOAT, ('ntime',)),
373         ('pressure', NC.FLOAT, ('ntime',)),
374         ('water_temp', NC.FLOAT, ('ntime',)),
375         )
376
377     # subset data only to month being processed (see raw2proc.process())
378     i = data['in']
379    
380     # var data
381     var_data = (
382         ('lat',  platform_info['lat']),
383         ('lon', platform_info['lon']),
384         ('z', data['z']),
385         #
386         ('time', data['time'][i]),
387         ('u', data['u'][i]),
388         ('v', data['v'][i]),
389         ('w', data['w'][i]),
390         ('e1', data['e1'][i]),
391         ('e2', data['e2'][i]),
392         ('e3', data['e3'][i]),
393         ('water_depth', data['water_depth'][i]),
394         ('pressure', data['pressure'][i]),
395         ('water_temp', data['water_temp'][i]),
396         )
397
398     return (global_atts, var_atts, dim_inits, var_inits, var_data)
399
400 def updater(platform_info, sensor_info, data):
401     #
402     global_atts = {
403         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
404         # last date in monthly file
405         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
406         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
407         #
408         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
409         }
410
411     # data variables
412     # update any variable attributes like range, min, max
413     var_atts = {}
414     # var_atts = {
415     #    'u': {'max': max(data.u),
416     #          'min': min(data.v),
417     #          },
418     #    'v': {'max': max(data.u),
419     #          'min': min(data.v),
420     #          },
421     #    }
422     
423     # subset data only to month being processed (see raw2proc.process())
424     i = data['in']
425
426     # data
427     var_data = (
428         ('time', data['time'][i]),
429         ('u', data['u'][i]),
430         ('v', data['v'][i]),
431         ('w', data['w'][i]),
432         ('e1', data['e1'][i]),
433         ('e2', data['e2'][i]),
434         ('e3', data['e3'][i]),
435         ('water_depth', data['water_depth'][i]),
436         ('pressure', data['pressure'][i]),
437         ('water_temp', data['water_temp'][i]),
438         )
439
440     return (global_atts, var_atts, var_data)
441 #
442
Note: See TracBrowser for help on using the browser.