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

root/raw2proc/trunk/raw2proc/proc_cr1000_ctd_v1.py

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

update both proc_cr1000_ctd and proc_sbe37_ctd to recover more data for b2

Line 
1 #!/usr/bin/env python
2 # Last modified:  Time-stamp: <2012-04-23 14:12:55 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     
151     # calculate depth, salinity and density   
152     import seawater.csiro
153     import seawater.constants
154
155     # seawater.constants.C3515 is units of mS/cm
156     # data['cond'] is units of S/m
157     # You have: mS cm-1
158     # You want: S m-1
159     #     <S m-1> = <mS cm-1>*0.1
160     #     <S m-1> = <mS cm-1>/10
161
162     data['depth'] = -1*seawater.csiro.depth(data['press'], platform_info['lat']) # meters
163     data['salin'] = seawater.csiro.salt(10*data['cond']/seawater.constants.C3515, data['wtemp'], data['press']) # psu
164     data['density'] = seawater.csiro.dens(data['salin'], data['wtemp'], data['press']) # kg/m^3
165
166     return data
167
168 def creator(platform_info, sensor_info, data):
169     #
170     #
171     # subset data only to month being processed (see raw2proc.process())
172     i = data['in']
173    
174     title_str = sensor_info['description']+' at '+ platform_info['location']
175     global_atts = {
176         'title' : title_str,
177         'institution' : platform_info['institution'],
178         'institution_url' : platform_info['institution_url'],
179         'institution_dods_url' : platform_info['institution_dods_url'],
180         'metadata_url' : platform_info['metadata_url'],
181         'references' : platform_info['references'],
182         'contact' : platform_info['contact'],
183         #
184         'source' : platform_info['source']+' '+sensor_info['source'],
185         'history' : 'raw2proc using ' + sensor_info['process_module'],
186         'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(),
187         # conventions
188         'Conventions' : platform_info['conventions'],
189         # SEACOOS CDL codes
190         'format_category_code' : platform_info['format_category_code'],
191         'institution_code' : platform_info['institution_code'],
192         'platform_code' : platform_info['id'],
193         'package_code' : sensor_info['id'],
194         # institution specific
195         'project' : platform_info['project'],
196         'project_url' : platform_info['project_url'],
197         # timeframe of data contained in file yyyy-mm-dd HH:MM:SS
198         # first date in monthly file
199         'start_date' : data['dt'][i][0].strftime("%Y-%m-%d %H:%M:%S"),
200         # last date in monthly file
201         'end_date' : data['dt'][i][-1].strftime("%Y-%m-%d %H:%M:%S"),
202         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
203         #
204         'creation_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
205         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
206         'process_level' : 'level1',
207         #
208         # must type match to data (e.g. fillvalue is real if data is real)
209         '_FillValue' : -99999.,
210         }
211
212     var_atts = {
213         # coordinate variables
214         'time' : {'short_name': 'time',
215                   'long_name': 'Time',
216                   'standard_name': 'time',
217                   'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC
218                   'axis': 'T',
219                   },
220         'lat' : {'short_name': 'lat',
221              'long_name': 'Latitude',
222              'standard_name': 'latitude',
223              'reference':'geographic coordinates',
224              'units': 'degrees_north',
225              'valid_range':(-90.,90.),
226              'axis': 'Y',
227              },
228         'lon' : {'short_name': 'lon',
229                  'long_name': 'Longitude',
230                  'standard_name': 'longitude',
231                  'reference':'geographic coordinates',
232                  'units': 'degrees_east',
233                  'valid_range':(-180.,180.),
234                  'axis': 'Y',
235                  },
236         'z' : {'short_name': 'z',
237                'long_name': 'Depth',
238                'standard_name': 'depth',
239                'reference':'zero at sea-surface',
240                'positive' : 'up',
241                'units': 'm',
242                'axis': 'Z',
243                },
244         # data variables
245         'wtemp': {'short_name': 'wtemp',
246                   'long_name': 'Water Temperature',
247                   'standard_name': 'water_temperature',                         
248                   'units': 'degrees_Celsius',
249                   },
250         'cond': {'short_name': 'cond',
251                  'long_name': 'Conductivity',
252                  'standard_name': 'conductivity',                         
253                  'units': 'S m-1',
254                  },
255         'press': {'short_name': 'press',
256                  'long_name': 'Pressure',
257                  'standard_name': 'water_pressure',                         
258                  'units': 'decibar',
259                  },
260         'depth': {'short_name': 'depth',
261                   'long_name': 'Depth',
262                   'standard_name': 'depth',                         
263                   'reference':'zero at sea-surface',
264                   'positive' : 'up',
265                   'units': 'm',
266                   'comment': 'Derived using seawater.csiro.depth(press,lat)',
267                  },
268         'salin': {'short_name': 'salin',
269                   'long_name': 'Salinity',
270                   'standard_name': 'salinity',
271                   'units': 'psu',
272                   'comment': 'Derived using seawater.csiro.salt(cond/C3515,wtemp,press)',
273                  },
274         'density': {'short_name': 'density',
275                     'long_name': 'Density',
276                     'standard_name': 'density',
277                     'units': 'kg m-3',
278                     'comment': 'Derived using seawater.csiro.dens0(salin,wtemp,press)',
279                  },
280         }
281
282     # dimension names use tuple so order of initialization is maintained
283     dim_inits = (
284         ('ntime', NC.UNLIMITED),
285         ('nlat', 1),
286         ('nlon', 1),
287         ('nz', 1),
288         )
289    
290     # using tuple of tuples so order of initialization is maintained
291     # using dict for attributes order of init not important
292     # use dimension names not values
293     # (varName, varType, (dimName1, [dimName2], ...))
294     var_inits = (
295         # coordinate variables
296         ('time', NC.INT, ('ntime',)),
297         ('lat', NC.FLOAT, ('nlat',)),
298         ('lon', NC.FLOAT, ('nlon',)),
299         ('z',  NC.FLOAT, ('nz',)),
300         # data variables
301         ('wtemp', NC.FLOAT, ('ntime',)),
302         ('cond', NC.FLOAT, ('ntime',)),
303         ('press', NC.FLOAT, ('ntime',)),
304         # derived variables
305         ('depth', NC.FLOAT, ('ntime',)),
306         ('salin', NC.FLOAT, ('ntime',)),
307         ('density', NC.FLOAT, ('ntime',)),
308         )
309
310     # var data
311     var_data = (
312         ('lat',  platform_info['lat']),
313         ('lon', platform_info['lon']),
314         ('z', sensor_info['nominal_depth']),
315         #
316         ('time', data['time'][i]),
317         #
318         ('wtemp', data['wtemp'][i]),
319         ('cond', data['cond'][i]),
320         ('press', data['press'][i]),
321         # derived variables
322         ('depth', data['depth'][i]),
323         ('salin',  data['salin'][i]),
324         ('density', data['density'][i]),
325         )
326
327     return (global_atts, var_atts, dim_inits, var_inits, var_data)
328
329 def updater(platform_info, sensor_info, data):
330     #
331
332     # subset data only to month being processed (see raw2proc.process())
333     i = data['in']
334
335     global_atts = {
336         # update times of data contained in file (yyyy-mm-dd HH:MM:SS)
337         # last date in monthly file
338         'end_date' : data['dt'][i][-1].strftime("%Y-%m-%d %H:%M:%S"),
339         'release_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
340         #
341         'modification_date' : now_dt.strftime("%Y-%m-%d %H:%M:%S"),
342         }
343
344     # data variables
345     # update any variable attributes like range, min, max
346     var_atts = {}
347     # var_atts = {
348     #    'wtemp': {'max': max(data.u),
349     #          'min': min(data.v),
350     #          },
351     #    'cond': {'max': max(data.u),
352     #          'min': min(data.v),
353     #          },
354     #    }
355     
356     # data
357     var_data = (
358         ('time', data['time'][i]),
359         ('wtemp', data['wtemp'][i]),
360         ('cond', data['cond'][i]),
361         ('press', data['press'][i]),
362         # derived variables
363         ('depth', data['depth'][i]),
364         ('salin',  data['salin'][i]),
365         ('density', data['density'][i]),
366         )
367
368     return (global_atts, var_atts, var_data)
369 #
370
Note: See TracBrowser for help on using the browser.