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

root/raw2proc/tags/raw2proc-1.0/proc_rdi_logdata_adcp.py

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

ncutil--added functions; proc2latest--moved to procutil; configs--added the computed mean_water_depth where measured and mean_water_depth_time_period

Line 
1 #!/usr/bin/env python
2 # Last modified:  Time-stamp: <2008-10-16 14:06:06 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, ensemble number, currents
10          and wave summary output from WavesMon software
11 creator : lat, lon, z, time, ens, u, v
12 updator : time, ens, u, v
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 now_dt = datetime.utcnow()
36 now_dt.replace(microsecond=0)
37
38 def parser(platform_info, sensor_info, lines):
39     """
40     parse and assign currents data from RDI ADCP Log Data
41
42     """
43  
44     i = 0
45    
46     for line in lines:
47         # split line and parse float and integers
48         rdi = []
49         sw = re.split(',', line)
50         for s in sw:
51             m = re.search(REAL_RE_STR, s)
52             if m:
53                 rdi.append(float(m.groups()[0]))
54
55         # assign specific fields
56         n = len(rdi)
57         burst_num = int(rdi[0]) # Ensemble Number
58
59         # get sample datetime from data
60         sample_str = '%02d-%02d-%02d %02d:%02d:%02d' % tuple(rdi[1:7])
61         if  sensor_info['utc_offset']:
62             sample_dt = scanf_datetime(sample_str, fmt='%y-%m-%d %H:%M:%S') + \
63                         timedelta(hours=sensor_info['utc_offset'])
64         else:
65             sample_dt = scanf_datetime(sample_str, fmt='%y-%m-%d %H:%M:%S')
66         #   datetime(*strptime(sample_str, "%y-%m-%d %H:%M:%S")[0:6])
67
68         # get sample datetime from filename
69         # compare with datetime from filename
70
71         sig_wave_ht = rdi[8]         # Significant Wave Height (Hs, meters)
72         peak_wave_period = rdi[9]    # Peak Wave Period (Tp, sec)
73         peak_wave_dir = rdi[10]      # Peak Wave Direction (deg N)
74         max_wave_ht = rdi[12]        # Maximum Wave Height (Hmax, meters)
75         max_wave_period = rdi[13]    # Maximum Wave Period (Tmax, sec)
76
77         wd = rdi[11]/1000   # Water Depth (meters) (based on ADCP backscatter or input config??)
78                             # This includes height of transducer
79         nbins = int(rdi[14])         # Number of bins
80
81         current_spd = numpy.array(rdi[15::2]) # starting at idx=15 skip=2 to end
82         current_dir = numpy.array(rdi[16::2]) # starting at idx=16 skip=2 to end
83
84         if nbins!=sensor_info['nbins']:
85             print 'Number of bins reported in data ('+ \
86                   str(nbins)+') does not match config number ('+ \
87                   str(sensor_info['nbins'])+')'
88
89         if len(current_spd)!=nbins or len(current_dir)!=nbins:
90             print 'Data length does not match number of bins in data'
91
92         ibad = (current_spd==-32768) | (current_dir==-32768)
93         current_spd[ibad] = numpy.nan
94         current_dir[ibad] = numpy.nan
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
105         # compute water mask
106         # Using George Voulgaris' method based on water depth
107         # minus half of the significant wave height (Hs)
108         # and computed habs
109         # if positive is up, what's less than zero depth?
110
111         # added by SH -- 15 Oct 2008
112         # raw2proc:ticket:27 adjust bin_habs along beam to nadir
113         # adjustment is cos(20 deg) (which is  approx .95*height) assuming fixed 20 deg
114         bin_habs =  bin_habs*numpy.cos(20.*numpy.pi/180)
115         bin_depths =  bin_habs-(wd)
116         iwater = bin_depths+bin_size/2 < 0
117
118         # use nominal water depth (MSL) averaged from full pressure record
119         #  this should be checked/recalulated every so often
120         z = bin_habs + platform_info['mean_water_depth']  # meters, (+) up, (-) down
121
122         # check that length of bin_depths is equal to nbins
123         u = numpy.ones(nbins)*numpy.nan
124         v = numpy.ones(nbins)*numpy.nan
125
126         u[iwater] = current_spd[iwater]*numpy.sin(current_dir[iwater]*numpy.pi/180)
127         v[iwater] = current_spd[iwater]*numpy.cos(current_dir[iwater]*numpy.pi/180)
128
129         # set up dict of data if first line
130         if i==0:
131             data = {
132                 'en' : numpy.array(numpy.ones((len(lines),), dtype=int)*numpy.nan),
133                 'dt' : numpy.array(numpy.ones((len(lines),), dtype=object)*numpy.nan),
134                 'time' : numpy.array(numpy.ones((len(lines),), dtype=long)*numpy.nan),
135                 'z' : numpy.array(numpy.ones((nbins,), dtype=float)*numpy.nan),
136                 'u' : numpy.array(numpy.ones((len(lines),nbins), dtype=float)*numpy.nan),
137                 'v' : numpy.array(numpy.ones((len(lines),nbins), dtype=float)*numpy.nan),
138                 'wd' : numpy.array(numpy.ones((len(lines)), dtype=float)*numpy.nan),
139                 'wl' : numpy.array(numpy.ones((len(lines)), dtype=float)*numpy.nan),
140                 }
141        
142         data['en'][i] = burst_num
143         data['dt'][i] = sample_dt # sample datetime
144         data['time'][i] = dt2es(sample_dt) # sample time in epoch seconds
145         data['z'] =  z
146         data['u'][i] =  u
147         data['v'][i] =  v
148         data['wd'][i] = -1*wd
149         data['wl'][i] = platform_info['mean_water_depth'] - (-1*wd) 
150         i = i+1
151
152     return data
153
154 def creator(platform_info, sensor_info, data):
155     #
156     #
157     title_str = sensor_info['description']+' at '+ platform_info['location']
158
159     if 'mean_water_depth' in platform_info.keys():
160         msl_str = platform_info['mean_water_depth']
161     else:
162         msl_str = 'None'
163     if 'mean_water_depth_time_period' in platform_info.keys():
164         msl_tp_str = platform_info['mean_water_depth_time_period']
165     else:
166         msl_tp_str = 'None'
167        
168     global_atts = {
169         'title' : title_str,
170         'institution' : 'University of North Carolina at Chapel Hill (UNC-CH)',
171         'institution_url' : 'http://nccoos.unc.edu',
172         'institution_dods_url' : 'http://nccoos.unc.edu',
173         'metadata_url' : 'http://nccoos.unc.edu',
174         'references' : 'http://nccoos.unc.edu',
175         'contact' : 'Sara Haines (haines@email.unc.edu)',
176         #
177         'source' : 'fixed-profiler (acoustic doppler) observation',
178         'history' : 'raw2proc using ' + sensor_info['process_module'],
179         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
180         # conventions
181         'Conventions' : 'CF-1.0; SEACOOS-CDL-v2.0',
182         # SEACOOS CDL codes
183         'format_category_code' : 'fixed-profiler',
184         'institution_code' : platform_info['institution'],
185         'platform_code' : platform_info['id'],
186         'package_code' : sensor_info['id'],
187         # institution specific
188         'project' : 'North Carolina Coastal Ocean Observing System (NCCOOS)',
189         'project_url' : 'http://nccoos.unc.edu',
190         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
191         # first date in monthly file
192         'start_date' : data['dt'][0].strftime("%Y-%m-%d %H:%M:%S"),
193         # last date in monthly file
194         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
195         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
196         #
197         'mean_water_depth' : msl_str,
198         'mean_water_depth_time_period' : msl_tp_str,
199         #
200         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
201         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
202         'process_level' : 'level1',
203         #
204         # must type match to data (e.g. fillvalue is real if data is real)
205         '_FillValue' : -99999.,
206         }
207
208     var_atts = {
209         # coordinate variables
210         'time' : {'short_name': 'time',
211                   'long_name': 'Time',
212                   'standard_name': 'time',
213                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
214                   'axis': 'T',
215                   },
216         'lat' : {'short_name': 'lat',
217              'long_name': 'Latitude',
218              'standard_name': 'latitude',
219              'reference':'geographic coordinates',
220              'units': 'degrees_north',
221              'valid_range':(-90.,90.),
222              'axis': 'Y',
223              },
224         'lon' : {'short_name': 'lon',
225                  'long_name': 'Longitude',
226                  'standard_name': 'longitude',
227                  'reference':'geographic coordinates',
228                  'units': 'degrees_east',
229                  'valid_range':(-180.,180.),
230                  'axis': 'Y',
231                  },
232         'z' : {'short_name': 'z',
233                'long_name': 'Height',
234                'standard_name': 'height',
235                'reference':'zero at sea-surface',
236                'units': 'm',
237                'axis': 'Z',
238                },
239         # data variables
240         'en' : {'short_name' : 'en',
241                 'long_name': 'Ensemble Number',
242                  'standard_name': 'ensemble_number',                         
243                  'units': 'None',
244                  },
245         'u': {'short_name' : 'u',
246               'long_name': 'East/West Component of Current',
247               'standard_name': 'eastward_current',
248               'units': 'm s-1',
249               'reference': 'clockwise from True East',
250               },
251         'v': {'short_name' : 'v',
252               'long_name': 'North/South Component of Current',
253               'standard_name': 'northward_current',                         
254               'units': 'm s-1',
255               'reference': 'clockwise from True North',
256               },
257         'wd': {'short_name': 'wd',
258                'long_name': 'Water Depth',
259                'standard_name': 'water_depth',                         
260                'reference':'zero at surface',
261                'positive' : 'up',
262                'units': 'm',
263                },
264         'wl': {'short_name': 'wl',
265                'long_name': 'Water Level',
266                'standard_name': 'water_level',                         
267                'reference':'MSL',
268                'reference_to_MSL' : 0.,
269                'reference_MSL_datum' : platform_info['mean_water_depth'],
270                'reference_MSL_datum_time_period' : platform_info['mean_water_depth_time_period'],
271                'positive' : 'up',
272                'z' : 0.,
273                'units': 'm',
274                },
275         }
276
277
278     # dimension names use tuple so order of initialization is maintained
279     dim_inits = (
280         ('ntime', NC.UNLIMITED),
281         ('nlat', 1),
282         ('nlon', 1),
283         ('nz', sensor_info['nbins'])
284         )
285    
286     # using tuple of tuples so order of initialization is maintained
287     # using dict for attributes order of init not important
288     # use dimension names not values
289     # (varName, varType, (dimName1, [dimName2], ...))
290     var_inits = (
291         # coordinate variables
292         ('time', NC.INT, ('ntime',)),
293         ('lat', NC.FLOAT, ('nlat',)),
294         ('lon', NC.FLOAT, ('nlon',)),
295         ('z',  NC.FLOAT, ('nz',)),
296         # data variables
297         ('en', NC.INT, ('ntime', )),
298         ('u', NC.FLOAT, ('ntime', 'nz')),
299         ('v', NC.FLOAT, ('ntime', 'nz')),
300         ('wd', NC.FLOAT, ('ntime',)),
301         ('wl', NC.FLOAT, ('ntime',)),
302         )
303
304     # subset data only to month being processed (see raw2proc.process())
305     i = data['in']
306    
307     # var data
308     var_data = (
309         ('lat',  platform_info['lat']),
310         ('lon', platform_info['lon']),
311         ('z', data['z']),
312         #
313         ('time', data['time'][i]),
314         ('en', data['en'][i]),
315         ('u', data['u'][i]),
316         ('v', data['v'][i]),
317         ('wd', data['wd'][i]),
318         ('wl', data['wl'][i]),
319         )
320
321     return (global_atts, var_atts, dim_inits, var_inits, var_data)
322
323 def updater(platform_info, sensor_info, data):
324     #
325     global_atts = {
326         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
327         # last date in monthly file
328         'end_date' : data['dt'][-1].strftime("%Y-%m-%d %H:%M:%S"),
329         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
330         #
331         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
332         }
333
334     # data variables
335     # update any variable attributes like range, min, max
336     var_atts = {}
337     # var_atts = {
338     #    'u': {'max': max(data.u),
339     #          'min': min(data.v),
340     #          },
341     #    'v': {'max': max(data.u),
342     #          'min': min(data.v),
343     #          },
344     #    }
345    
346     # subset data only to month being processed (see raw2proc.process())
347     i = data['in']
348
349     # data
350     var_data = (
351         ('time', data['time'][i]),
352         ('en', data['en'][i]),
353         ('u', data['u'][i]),
354         ('v', data['v'][i]),
355         ('wd', data['wd'][i]),
356         ('wl', data['wl'][i]),
357         )
358
359     return (global_atts, var_atts, var_data)
360 #
Note: See TracBrowser for help on using the browser.