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

root/raw2proc/trunk/raw2proc/proc_cr1000_wind.py

Revision 494 (checked in by haines, 12 years ago)

Processing mods for buoy data

Line 
1 #!/usr/bin/env python
2 # Last modified:  Time-stamp: <2012-06-27 09:00:17 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 met data collected on Campbell Scientific DataLogger (loggernet) (csi)
8
9 parser : sample date and time,
10
11 creator : lat, lon, z, time,
12 updator : time,
13
14
15 Examples
16 --------
17
18 >> (parse, create, update) = load_processors('proc_csi_adcp_v2')
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     Example wind data
41
42     Stats (avg, std, and max) for wind sampled every second for one minute DURING a 6 minute time period.  Stats are NOT over 6 minutes, as
43     the time stamp would have you believe.
44     
45     "TOA5","CR1000_B1","CR1000","37541","CR1000.Std.21","CPU:NCWIND_12_Buoy_All.CR1","58723","AWind_6Min"
46     "TIMESTAMP","RECORD","W1_SpeedAvg","W1_DirAvg","W1_SpeedMax","W1_SpeedStd","W2_SpeedAvg","W2_DirAvg","W2_SpeedMax","W2_SpeedStd"
47     "TS","RN","","Deg","","","","Deg","",""
48     "","","WVc","WVc","Max","Std","WVc","WVc","Max","Std"
49     "2011-12-01 00:01:59",6507,8.32,319.1,10.09,0.781,8.15,310.9,10.09,0.832
50     "2011-12-01 00:07:59",6508,9.43,323.3,11.27,1.094,9.11,315.8,10.68,1.015
51     "2011-12-01 00:13:59",6509,9.94,308.6,12.35,1.077,9.74,301.3,11.96,1.027
52     "2011-12-01 00:19:59",6510,8.86,304.5,10.98,1.003,8.8,296.4,11.27,1.066
53     "2011-12-01 00:25:59",6511,9.02,310.8,10.98,1.023,8.95,302.4,10.78,0.964
54     "2011-12-01 00:31:59",6512,9.58,304.9,11.76,1.156,9.39,296.7,11.76,1.167
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         'wspd1' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
74         'wspd1_std' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
75         'wgust1' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
76         'wdir1' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
77         'wspd2' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
78         'wspd2_std' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
79         'wgust2' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
80         'wdir2' : 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         if len(csi)==9:
116             #
117             # data['samplenum'][i] = csi[0] # sample number assigned by datalogger in table
118             data['wspd1'][i] = csi[1] #
119             data['wdir1'][i] = csi[2] #
120             data['wgust1'][i] = csi[3] # relative humidity std
121             data['wspd1_std'][i] = csi[4] # air temperature avg (deg C)
122             data['wspd2'][i] = csi[5] # air temperature std (deg C)
123             data['wdir2'][i] = csi[6] # precip gauge cummulative
124             data['wgust2'][i] = csi[7] # PSP avg
125             data['wspd2_std'][i] = csi[8] # PSP std
126             i=i+1
127         else:
128             print ' ... skipping line %d -- %s ' % (i,line)
129             continue
130
131         # if re.search
132     # for line
133
134     # cannot figure out how to combine the two operations
135     # for some reason, this one liner does not work
136     bad = data['wdir1']==0    # print ' ... ... Number of zero wdir1 = %d' % numpy.sum(bad)
137     data['wdir1'][bad] = numpy.nan
138     bad = data['wdir2']==0    # print ' ... ... Number of zero wdir1 = %d' % numpy.sum(bad)
139     data['wdir2'][bad] = numpy.nan
140                                    
141     # check that no data[dt] is set to Nan or anything but datetime
142     # keep only data that has a resolved datetime
143     keep = numpy.array([type(datetime(1970,1,1)) == type(dt) for dt in data['dt'][:]])
144     if keep.any():
145         for param in data.keys():
146             data[param] = data[param][keep]
147
148     return data
149  
150
151 def creator(platform_info, sensor_info, data):
152     #
153     #
154     # subset data only to month being processed (see raw2proc.process())
155     i = data['in']
156
157     title_str = sensor_info['description']+' at '+ platform_info['location']
158     global_atts = {
159         'title' : title_str,
160         'institution' : platform_info['institution'],
161         'institution_url' : platform_info['institution_url'],
162         'institution_dods_url' : platform_info['institution_dods_url'],
163         'metadata_url' : platform_info['metadata_url'],
164         'references' : platform_info['references'],
165         'contact' : platform_info['contact'],
166         #
167         'source' : platform_info['source']+' '+sensor_info['source'],
168         'history' : 'raw2proc using ' + sensor_info['process_module'],
169         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
170         # conventions
171         'Conventions' : platform_info['conventions'],
172         # SEACOOS CDL codes
173         'format_category_code' : platform_info['format_category_code'],
174         'institution_code' : platform_info['institution_code'],
175         'platform_code' : platform_info['id'],
176         'package_code' : sensor_info['id'],
177         # institution specific
178         'project' : platform_info['project'],
179         'project_url' : platform_info['project_url'],
180         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
181         # first date in monthly file
182         'start_date' : data['dt'][i][0].strftime("%Y-%m-%d %H:%M:%S"),
183         # last date in monthly file
184         'end_date' : data['dt'][i][-1].strftime("%Y-%m-%d %H:%M:%S"),
185         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
186         #
187         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
188         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
189         'process_level' : 'level1',
190         #
191         # must type match to data (e.g. fillvalue is real if data is real)
192         '_FillValue' : -99999.,
193         }
194
195
196     var_atts = {
197         # coordinate variables
198         'time' : {'short_name': 'time',
199                   'long_name': 'Time',
200                   'standard_name': 'time',
201                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
202                   'axis': 'T',
203                   },
204         'lat' : {'short_name': 'lat',
205                  'long_name': 'Latitude',
206                  'standard_name': 'latitude',
207                  'reference':'geographic coordinates',
208                  'units': 'degrees_north',
209                  'valid_range':(-90.,90.),
210                  'axis': 'Y',
211                  },
212         'lon' : {'short_name': 'lon',
213                  'long_name': 'Longitude',
214                  'standard_name': 'longitude',
215                  'reference':'geographic coordinates',
216                  'units': 'degrees_east',
217                  'valid_range':(-180.,180.),
218                  'axis': 'Y',
219                  },
220         'z' : {'short_name': 'z',
221                'long_name': 'Altitude',
222                'standard_name': 'altitude',
223                'reference':'zero at mean sea level',
224                'positive' : 'up',
225                'units': 'm',
226                'axis': 'Z',
227                },
228         # data variables
229         'wspd1' : {'short_name': 'wspd',
230                   'long_name': 'Wind Speed',
231                   'standard_name': 'wind_speed',
232                   'units': 'm s-1',
233                   'can_be_normalized': 'no',
234                   'z' : sensor_info['anemometer1_height'],
235                   'z_units' : 'meter',
236                   },
237         'wdir1' : {'short_name': 'wdir',
238                   'long_name': 'Wind Direction from',
239                   'standard_name': 'wind_from_direction',
240                   'reference': 'clockwise from Magnetic North',
241                   'valid_range': (0., 360),
242                   'units': 'degrees',
243                   'z' : sensor_info['anemometer1_height'],
244                   'z_units' : 'meter',
245                   },
246         'wgust1' : {'short_name': 'wgust',
247                   'long_name': 'Wind Gust',
248                   'standard_name': 'wind_gust',
249                   'units': 'm s-1',
250                   'can_be_normalized': 'no',
251                   'z' : sensor_info['anemometer1_height'],
252                   'z_units' : 'meter',
253                   },
254         'wspd1_std' : {'short_name': 'wspd std',
255                   'long_name': 'Standard Deviation of Wind Speed ',
256                   'standard_name': 'wind_speed standard_deviation',
257                   'units': 'm s-1',
258                   'can_be_normalized': 'no',
259                   'z' : sensor_info['anemometer1_height'],
260                   'z_units' : 'meter',
261                   },
262         # Second anemometer
263         'wspd2' : {'short_name': 'wspd',
264                   'long_name': 'Wind Speed',
265                   'standard_name': 'wind_speed',
266                   'units': 'm s-1',
267                   'can_be_normalized': 'no',
268                   'z' : sensor_info['anemometer2_height'],
269                   'z_units' : 'meter',
270                   },
271         'wdir2' : {'short_name': 'wdir',
272                   'long_name': 'Wind Direction from',
273                   'standard_name': 'wind_from_direction',
274                   'reference': 'clockwise from Magnetic North',
275                   'valid_range': (0., 360),
276                   'units': 'degrees',
277                   'z' : sensor_info['anemometer2_height'],
278                   'z_units' : 'meter',
279                   },
280         'wgust2' : {'short_name': 'wgust',
281                   'long_name': 'Wind Gust',
282                   'standard_name': 'wind_gust',
283                   'units': 'm s-1',
284                   'can_be_normalized': 'no',
285                   'z' : sensor_info['anemometer2_height'],
286                   'z_units' : 'meter',
287                   },
288         'wspd2_std' : {'short_name': 'wspd std',
289                   'long_name': 'Standard Deviation of Wind Speed ',
290                   'standard_name': 'wind_speed standard_deviation',
291                   'units': 'm s-1',
292                   'can_be_normalized': 'no',
293                   'z' : sensor_info['anemometer2_height'],
294                   'z_units' : 'meter',
295                   },
296         }
297
298     # dimension names use tuple so order of initialization is maintained
299     dim_inits = (
300         ('ntime', NC.UNLIMITED),
301         ('nlat', 1),
302         ('nlon', 1),
303         ('nz', 1),
304         )
305    
306     # using tuple of tuples so order of initialization is maintained
307     # using dict for attributes order of init not important
308     # use dimension names not values
309     # (varName, varType, (dimName1, [dimName2], ...))
310     var_inits = (
311         # coordinate variables
312         ('time', NC.INT, ('ntime',)),
313         ('lat', NC.FLOAT, ('nlat',)),
314         ('lon', NC.FLOAT, ('nlon',)),
315         ('z',  NC.FLOAT, ('nz',)),
316         # data variables
317         ('wspd1', NC.FLOAT, ('ntime',)),
318         ('wdir1', NC.FLOAT, ('ntime',)),
319         ('wgust1', NC.FLOAT, ('ntime',)),
320         ('wspd1_std', NC.FLOAT, ('ntime',)),
321         ('wspd2', NC.FLOAT, ('ntime',)),
322         ('wdir2', NC.FLOAT, ('ntime',)),
323         ('wgust2', NC.FLOAT, ('ntime',)),
324         ('wspd2_std', NC.FLOAT, ('ntime',)),
325         )
326
327     # var data
328     var_data = (
329         ('lat',  platform_info['lat']),
330         ('lon', platform_info['lon']),
331         ('z', platform_info['altitude']),
332         #
333         ('time', data['time'][i]),
334         #
335         ('wspd1', data['wspd1'][i]),
336         ('wdir1', data['wdir1'][i]),
337         ('wgust1', data['wgust1'][i]),
338         ('wspd1_std', data['wspd1_std'][i]),
339         ('wspd2', data['wspd2'][i]),
340         ('wdir2', data['wdir2'][i]),
341         ('wgust2', data['wgust2'][i]),
342         ('wspd2_std', data['wspd2_std'][i]),
343         )
344
345     return (global_atts, var_atts, dim_inits, var_inits, var_data)
346
347 def updater(platform_info, sensor_info, data):
348     #
349     # subset data only to month being processed (see raw2proc.process())
350     i = data['in']
351
352     global_atts = {
353         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
354         # last date in monthly file
355         'end_date' : data['dt'][i][-1].strftime("%Y-%m-%d %H:%M:%S"),
356         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
357         #
358         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
359         }
360
361     # data variables
362     # update any variable attributes like range, min, max
363     var_atts = {}
364     # var_atts = {
365     #    'wtemp': {'max': max(data.u),
366     #          'min': min(data.v),
367     #          },
368     #    'cond': {'max': max(data.u),
369     #          'min': min(data.v),
370     #          },
371     #    }
372     
373     # data
374     var_data = (
375         ('time', data['time'][i]),
376         #
377         ('wspd1', data['wspd1'][i]),
378         ('wdir1', data['wdir1'][i]),
379         ('wgust1', data['wgust1'][i]),
380         ('wspd1_std', data['wspd1_std'][i]),
381         ('wspd2', data['wspd2'][i]),
382         ('wdir2', data['wdir2'][i]),
383         ('wgust2', data['wgust2'][i]),
384         ('wspd2_std', data['wspd2_std'][i]),
385         )
386
387     return (global_atts, var_atts, var_data)
388 #
389
Note: See TracBrowser for help on using the browser.