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

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