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

root/raw2proc/trunk/raw2proc/proc_cr1000_ctd_v1.py

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

--

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