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

root/raw2proc/trunk/raw2proc/proc_cr1000_ctd_v2.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-28 14:47:52 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 Examples
15 --------
16
17 >> (parse, create, update) = load_processors('proc_csi_adcp_v2')
18 or
19 >> si = get_config(cn+'.sensor_info')
20 >> (parse, create, update) = load_processors(si['adcp']['proc_module'])
21
22 >> lines = load_data(filename)
23 >> data = parse(platform_info, sensor_info, lines)
24 >> create(platform_info, sensor_info, data) or
25 >> update(platform_info, sensor_info, data)
26
27 """
28
29
30 from raw2proc import *
31 from procutil import *
32 from ncutil import *
33
34 now_dt = datetime.utcnow()
35 now_dt.replace(microsecond=0)
36
37 def parser(platform_info, sensor_info, lines):
38     """
39     "TOA5","CR1000_B1","CR1000","37541","CR1000.Std.21","CPU:NCWIND_12_Buoy_All.CR1","58723","CTD1_6Min"
40     "TIMESTAMP","RECORD","ID","Temp","Cond","Depth","SampleDate","SampleTime","SampleNum"
41     "TS","RN","","","","","","",""
42     "","","Smp","Smp","Smp","Smp","Smp","Smp","Smp"
43     "2011-12-01 00:02:09",4449,3585,16.1596,4.15704,3.413," 30 Nov 2011"," 23:58:44","   4406 "
44     "2011-12-01 00:08:09",4450,3585,16.1783,4.15878,3.745," 01 Dec 2011"," 00:04:44","   4407 "
45     "2011-12-01 00:14:09",4451,3585,16.1638,4.15794,3.545," 01 Dec 2011"," 00:10:44","   4408 "
46     "2011-12-01 00:20:09",4452,3585,16.1632,4.15769,3.254," 01 Dec 2011"," 00:16:44","   4409 "
47     "2011-12-01 00:26:09",4453,3585,16.1524,4.15665,3.649," 01 Dec 2011"," 00:22:44","   4410 "
48     "2011-12-01 00:32:09",4454,3585,16.1661,4.1582,3.277," 01 Dec 2011"," 00:28:44","   4411 "
49     """
50
51     import numpy
52     from datetime import datetime
53     from time import strptime
54
55     # get sample datetime from filename
56     fn = sensor_info['fn']
57     sample_dt_start = filt_datetime(fn)
58
59     # how many samples (don't count header 4 lines)
60     nsamp = len(lines[4:])
61
62     N = nsamp
63     data = {
64         'dt' : numpy.array(numpy.ones((N,), dtype=object)*numpy.nan),
65         'time' : numpy.array(numpy.ones((N,), dtype=long)*numpy.nan),
66         'wtemp' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
67         'cond' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
68         'press' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
69         'salin' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
70         'density' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
71         'depth' : numpy.array(numpy.ones((N,), dtype=float)*numpy.nan),
72         }
73
74     # sample count
75     i = 0
76
77     for line in lines[4:]:
78         csi = []
79         # split line
80         sw = re.split(',', line)
81         if len(sw)<=0:
82             print ' ... skipping line %d -- %s' % (i,line)
83             continue
84
85         # replace "NAN"
86         for index, s in enumerate(sw):
87             m = re.search(NAN_RE_STR, s)
88             if m:
89                 sw[index] = '-99999'
90
91         # parse date-time, and all other float and integers
92         for s in sw[1:6]:
93             m = re.search(REAL_RE_STR, s)
94             if m:
95                 csi.append(float(m.groups()[0]))
96
97         if len(sw)>=9:
98             dstr = re.sub('"', '', sw[6]+' '+sw[7])
99             # print dstr
100             m = re.search('\s*(\d{2})\s*(\w{2,3})\s*(\d{4})\s*(\d{2}):(\d{2}):(\d{2})', dstr)
101         else:
102             print ' ... skipping line %d -- %s ' % (i,line)
103             continue           
104
105         if m:
106             dstr = '%s %s %s %s:%s:%s' % m.groups()
107         else:
108             print ' ... skipping line %d -- %s ' % (i,line)
109             continue           
110
111         if  sensor_info['utc_offset']:
112             sample_dt = scanf_datetime(dstr, fmt='%d %b %Y %H:%M:%S') + \
113                         timedelta(hours=sensor_info['utc_offset'])
114         else:
115             sample_dt = scanf_datetime(dstr, fmt='%d %b %Y %H:%M:%S')
116
117         # ***** TO DO: need to adjust any drift of offset in CTD sample time to CR1000 clock
118         data['dt'][i] = sample_dt # sample datetime
119         data['time'][i] = dt2es(sample_dt) # sample time in epoch seconds
120
121         if len(csi)==5:
122             #
123             # (pg 31 SBE IMP Microcat User Manual)
124             # "#iiFORMAT=1 (default) Output converted to data
125             # date format dd mmm yyyy,
126             # conductivity = S/m,
127             # temperature precedes conductivity"
128             sn = csi[1] # ctd serial number == check against platform configuration
129             data['wtemp'][i] =  csi[2] # water temperature (C)
130             data['cond'][i] = csi[3] # specific conductivity (S/m)
131             data['press'][i] = csi[4]   # pressure decibars
132             i=i+1
133         else:
134             print ' ... skipping line %d -- %s ' % (i,line)
135             continue           
136            
137         # if re.search
138     # for line
139
140     # check that no data[dt] is set to Nan or anything but datetime
141     # keep only data that has a resolved datetime
142     keep = numpy.array([type(datetime(1970,1,1)) == type(dt) for dt in data['dt'][:]])
143     if keep.any():
144         for param in data.keys():
145             data[param] = data[param][keep]
146
147     # Quality Control steps for temp, depth, and cond
148     # (1) within range
149     # (2) if not pumped
150     # (2) if not pumped
151     good = (5<data['wtemp']) & (data['wtemp']<30)
152     bad = ~good
153     data['wtemp'][bad] = numpy.nan
154    
155     good = (2<data['cond']) & (data['cond']<7)
156     bad = ~good
157     data['cond'][bad] = numpy.nan
158    
159     # calculate depth, salinity and density   
160     import seawater.csiro
161     import seawater.constants
162
163     # seawater.constants.C3515 is units of mS/cm
164     # data['cond'] is units of S/m
165     # You have: mS cm-1
166     # You want: S m-1
167     #     <S m-1> = <mS cm-1>*0.1
168     #     <S m-1> = <mS cm-1>/10
169
170     data['depth'] = -1*seawater.csiro.depth(data['press'], platform_info['lat']) # meters
171     data['salin'] = seawater.csiro.salt(10*data['cond']/seawater.constants.C3515, data['wtemp'], data['press']) # psu
172     data['density'] = seawater.csiro.dens(data['salin'], data['wtemp'], data['press']) # kg/m^3
173
174     return data
175
176 def creator(platform_info, sensor_info, data):
177     #
178     #
179     # subset data only to month being processed (see raw2proc.process())
180     i = data['in']
181    
182     title_str = sensor_info['description']+' at '+ platform_info['location']
183     global_atts = {
184         'title' : title_str,
185         'institution' : platform_info['institution'],
186         'institution_url' : platform_info['institution_url'],
187         'institution_dods_url' : platform_info['institution_dods_url'],
188         'metadata_url' : platform_info['metadata_url'],
189         'references' : platform_info['references'],
190         'contact' : platform_info['contact'],
191         #
192         'source' : platform_info['source']+' '+sensor_info['source'],
193         'history' : 'raw2proc using ' + sensor_info['process_module'],
194         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
195         # conventions
196         'Conventions' : platform_info['conventions'],
197         # SEACOOS CDL codes
198         'format_category_code' : platform_info['format_category_code'],
199         'institution_code' : platform_info['institution_code'],
200         'platform_code' : platform_info['id'],
201         'package_code' : sensor_info['id'],
202         # institution specific
203         'project' : platform_info['project'],
204         'project_url' : platform_info['project_url'],
205         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
206         # first date in monthly file
207         'start_date' : data['dt'][i][0].strftime("%Y-%m-%d %H:%M:%S"),
208         # last date in monthly file
209         'end_date' : data['dt'][i][-1].strftime("%Y-%m-%d %H:%M:%S"),
210         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
211         #
212         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
213         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
214         'process_level' : 'level1',
215         #
216         # must type match to data (e.g. fillvalue is real if data is real)
217         '_FillValue' : -99999.,
218         }
219
220     var_atts = {
221         # coordinate variables
222         'time' : {'short_name': 'time',
223                   'long_name': 'Time',
224                   'standard_name': 'time',
225                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
226                   'axis': 'T',
227                   },
228         'lat' : {'short_name': 'lat',
229              'long_name': 'Latitude',
230              'standard_name': 'latitude',
231              'reference':'geographic coordinates',
232              'units': 'degrees_north',
233              'valid_range':(-90.,90.),
234              'axis': 'Y',
235              },
236         'lon' : {'short_name': 'lon',
237                  'long_name': 'Longitude',
238                  'standard_name': 'longitude',
239                  'reference':'geographic coordinates',
240                  'units': 'degrees_east',
241                  'valid_range':(-180.,180.),
242                  'axis': 'Y',
243                  },
244         'z' : {'short_name': 'z',
245                'long_name': 'Depth',
246                'standard_name': 'depth',
247                'reference':'zero at sea-surface',
248                'positive' : 'up',
249                'units': 'm',
250                'axis': 'Z',
251                },
252         # data variables
253         'wtemp': {'short_name': 'wtemp',
254                   'long_name': 'Water Temperature',
255                   'standard_name': 'water_temperature',                         
256                   'units': 'degrees_Celsius',
257                   },
258         'cond': {'short_name': 'cond',
259                  'long_name': 'Conductivity',
260                  'standard_name': 'conductivity',                         
261                  'units': 'S m-1',
262                  },
263         'press': {'short_name': 'press',
264                  'long_name': 'Pressure',
265                  'standard_name': 'water_pressure',                         
266                  'units': 'decibar',
267                  },
268         'depth': {'short_name': 'depth',
269                   'long_name': 'Depth',
270                   'standard_name': 'depth',                         
271                   'reference':'zero at sea-surface',
272                   'positive' : 'up',
273                   'units': 'm',
274                   'comment': 'Derived using seawater.csiro.depth(press,lat)',
275                  },
276         'salin': {'short_name': 'salin',
277                   'long_name': 'Salinity',
278                   'standard_name': 'salinity',
279                   'units': 'psu',
280                   'comment': 'Derived using seawater.csiro.salt(cond/C3515,wtemp,press)',
281                  },
282         'density': {'short_name': 'density',
283                     'long_name': 'Density',
284                     'standard_name': 'density',
285                     'units': 'kg m-3',
286                     'comment': 'Derived using seawater.csiro.dens0(salin,wtemp,press)',
287                  },
288         }
289
290     # dimension names use tuple so order of initialization is maintained
291     dim_inits = (
292         ('ntime', NC.UNLIMITED),
293         ('nlat', 1),
294         ('nlon', 1),
295         ('nz', 1),
296         )
297    
298     # using tuple of tuples so order of initialization is maintained
299     # using dict for attributes order of init not important
300     # use dimension names not values
301     # (varName, varType, (dimName1, [dimName2], ...))
302     var_inits = (
303         # coordinate variables
304         ('time', NC.INT, ('ntime',)),
305         ('lat', NC.FLOAT, ('nlat',)),
306         ('lon', NC.FLOAT, ('nlon',)),
307         ('z',  NC.FLOAT, ('nz',)),
308         # data variables
309         ('wtemp', NC.FLOAT, ('ntime',)),
310         ('cond', NC.FLOAT, ('ntime',)),
311         ('press', NC.FLOAT, ('ntime',)),
312         # derived variables
313         ('depth', NC.FLOAT, ('ntime',)),
314         ('salin', NC.FLOAT, ('ntime',)),
315         ('density', NC.FLOAT, ('ntime',)),
316         )
317
318     # var data
319     var_data = (
320         ('lat',  platform_info['lat']),
321         ('lon', platform_info['lon']),
322         ('z', sensor_info['nominal_depth']),
323         #
324         ('time', data['time'][i]),
325         #
326         ('wtemp', data['wtemp'][i]),
327         ('cond', data['cond'][i]),
328         ('press', data['press'][i]),
329         # derived variables
330         ('depth', data['depth'][i]),
331         ('salin',  data['salin'][i]),
332         ('density', data['density'][i]),
333         )
334
335     return (global_atts, var_atts, dim_inits, var_inits, var_data)
336
337 def updater(platform_info, sensor_info, data):
338     #
339
340     # subset data only to month being processed (see raw2proc.process())
341     i = data['in']
342
343     global_atts = {
344         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
345         # last date in monthly file
346         'end_date' : data['dt'][i][-1].strftime("%Y-%m-%d %H:%M:%S"),
347         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
348         #
349         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
350         }
351
352     # data variables
353     # update any variable attributes like range, min, max
354     var_atts = {}
355     # var_atts = {
356     #    'wtemp': {'max': max(data.u),
357     #          'min': min(data.v),
358     #          },
359     #    'cond': {'max': max(data.u),
360     #          'min': min(data.v),
361     #          },
362     #    }
363     
364     # data
365     var_data = (
366         ('time', data['time'][i]),
367         ('wtemp', data['wtemp'][i]),
368         ('cond', data['cond'][i]),
369         ('press', data['press'][i]),
370         # derived variables
371         ('depth', data['depth'][i]),
372         ('salin',  data['salin'][i]),
373         ('density', data['density'][i]),
374         )
375
376     return (global_atts, var_atts, var_data)
377 #
378
Note: See TracBrowser for help on using the browser.