#!/usr/bin/env python # Last modified: Time-stamp: <2007-12-27 15:16:33 haines> """ how to parse data, and assert what data and info goes into creating and updating monthly netcdf files RDI/Wavesmon processed adcp current profile data parser : sample date and time, ensemble number, currents and wave summary output from WavesMon software nc_creator : nc_updator : Examples -------- >> (parse, create, update) = load_processors('proc_rdi_logdata') >> data = parse(lines) >> create(platform_info, sensor_info, data) >> update(platform_info, sensor_info, data) """ def parser(lines): """ parse and assign currents data from RDI ADCP Log Data """ i = 0 for line in lines: # split line and parse float and integers rdi = [] sw = re.split(',', line) for s in sw: m = re.search(REAL_RE_STR, s) if m: rdi.append(float(m.groups()[0])) # assign specific fields n = len(rdi) burst_num = int(rdi[0]) # Ensemble Number # get sample datetime from data sample_str = '%02d-%02d-%02d %02d:%02d:%02d' % tuple(rdi[1:7]) sample_dt = datetime(*strptime(sample_str, "%y-%m-%d %H:%M:%S")[0:6]) # get sample datetime from filename # compare with datetime from filename sig_wave_ht = rdi[8] # Significant Wave Height (Hs, meters) peak_wave_period = rdi[9] # Peak Wave Period (Tp, sec) peak_wave_dir = rdi[10] # Peak Wave Direction (deg N) max_wave_ht = rdi[12] # Maximum Wave Height (Hmax, meters) max_wave_period = rdi[13] # Maximum Wave Period (Tmax, sec) water_depth = rdi[11]/1000 # Water Depth (meters) (based on ADCP backscatter or input config??) nbins = int(rdi[14]) # Number of bins current_spd = numpy.array(rdi[15::2]) # starting at idx=15 skip=2 to end current_dir = numpy.array(rdi[16::2]) # starting at idx=16 skip=2 to end if nbins!=sensor_info['adcp']['nbins']: print 'Number of bins reported in data ('+ \ str(nbins)+') does not match config number ('+ \ str(sensor_info['adcp']['nbins'])+')' if len(current_spd)!=nbins or len(current_dir)!=nbins: print 'Data length does not match number of bins in data' ibad = (current_spd==-32768) | (current_dir==-32768) current_spd[ibad] = numpy.nan current_dir[ibad] = numpy.nan # these items can also be teased out of raw adcp but for now get from config file th = sensor_info['adcp']['transducer_ht'] # Transducer height above bottom (meters) bh = sensor_info['adcp']['blanking_ht'] # Blanking height above Transducer (meters) bin_size = sensor_info['adcp']['bin_size'] # Bin Size (meters) # compute height for each bin above the bottom bins = numpy.arange(1,nbins+1) bin_habs = (bins*bin_size+bin_size/2)+th+bh # compute water mask # Using George Voulgaris' method based on water depth # minus half of the significant wave height (Hs) # and computed habs # if positive is up, what's less than zero depth? bin_depths = bin_habs-(water_depth-sig_wave_ht/2) iwater = bin_depths+bin_size/2 < 0 z = bin_habs # check that length of bin_depths is equal to nbins u = numpy.ones(nbins)*numpy.nan v = numpy.ones(nbins)*numpy.nan u[iwater] = current_spd[iwater]*numpy.sin(current_dir[iwater]*numpy.pi/180) v[iwater] = current_spd[iwater]*numpy.cos(current_dir[iwater]*numpy.pi/180) # set up dict of data if first line if i==0: data = { 'en' : numpy.array(numpy.ones((len(lines),), dtype=float)*numpy.nan), 'dt' : numpy.array(numpy.ones((len(lines),), dtype=object)*numpy.nan), 'nbins' : numpy.array(numpy.zeros((len(lines),), dtype=int)), 'z' : numpy.array(numpy.ones((len(lines),nbins), dtype=float)*numpy.nan), 'u' : numpy.array(numpy.ones((len(lines),nbins), dtype=float)*numpy.nan), 'v' : numpy.array(numpy.ones((len(lines),nbins), dtype=float)*numpy.nan), } data['en'][i] = burst_num data['dt'][i] = sample_dt data['nbins'][i] = nbins data['z'][i] = z data['u'][i] = u data['v'][i] = v i = i+1 return data def creator(platform_info, sensor_info, data): # # title_str = sensor_info['description']+' at '+ platform_info['location'] global_atts = { 'title' : title_str, 'institution' : 'Unversity of North Carolina at Chapel Hill (UNC-CH)', 'institution_url' : 'http://nccoos.unc.edu', 'institution_dods_url' : 'http://nccoos.unc.edu', 'metadata_url' : 'http://nccoos.unc.edu', 'references' : 'http://nccoos.unc.edu', 'contact' : 'Sara Haines (haines@email.unc.edu)', # 'source' : 'fixed-profiler (acoustic doppler) observation', 'history' : 'Data processed by NCCOOS', 'comment' : 'File created using pycdf'+pycdfVersion()+' and numpy '+pycdfArrayPkg(), # conventions 'Conventions' : 'CF-1.0; SEACOOS-CDL-v2.0', # SEACOOS CDL codes 'format_category_code' : 'fixed-profiler', 'institution_code' : platform_info['instituion'], 'platform_code' : platform_info['id'], 'package_code' : sensor_info['id'], # institution specific 'project' : 'North Carolina Coastal Ocean Observing System (NCCOOS)', 'project_url' : 'http://nccoos.unc.edu', # timeframe of data contained in file yyyy-mm-dd HH:MM:SS 'start_date' : data['sample_dt'].strftime("%Y-%m-%d %H:%M:%S"), 'end_date' : data['sample_dt'].strftime("%Y-%m-%d %H:%M:%S"), 'release_date' : now.strftime("%Y-%m-%d %H:%M:%S"), # 'creation_date' : now.strftime("%Y-%m-%d %H:%M:%S"), 'modification_date' : now.strftime("%Y-%m-%d %H:%M:%S"), 'process_level' : 'level1', # # must type match to data (e.g. fillvalue is real if data is real) '_FillValue' : -99999., } var_atts = { # coordinate variables 'time' : {'short_name': 'time', 'long_name': 'Time', 'standard_name': 'time', 'units': 'seconds since 1970-1-1 00:00:00 -0', # UTC 'axis': 'T', }, 'lat' : {'short_name': 'lat', 'long_name': 'Latitude', 'standard_name': 'latitude', 'reference':'geographic coordinates', 'units': 'degrees_north', 'valid_range':(-90.,90.), 'axis': 'Y', }, 'lon' : {'short_name': 'lon', 'long_name': 'Longtitude', 'standard_name': 'longtitude', 'reference':'geographic coordinates', 'units': 'degrees_east', 'valid_range':(-180.,180.), 'axis': 'Y', }, 'z' : {'short_name': 'z', 'long_name': 'Height', 'standard_name': 'height', 'reference':'zero at sea-surface', 'units': 'm', 'axis': 'Z', }, # data variables 'u': {'long_name': 'East/West Component of Current', 'standard_name': 'eastward_current', 'units': 'm s-1', 'reference': 'clockwise from True East', }, 'v': {'long_name': 'North/South Component of Current', 'standard_name': 'northward_current', 'units': 'm s-1', 'reference': 'clockwise from True North', }, 'w': {'long_name': 'Upward/Downward Component of Current', 'standard_name': 'upward_current', 'units': 'm s-1', 'positive': 'up', }, 'back_scatter':{'long_name': 'Backscatter', 'standard_name': 'back_scatter', 'units': 'decibels', }, 'wtemp': {'long_name': 'Water Temperature', 'standard_name': 'water_temperature', 'units': 'degrees Celsius', }, } # integer values ntime=NC.UNLIMITED nlat=1 nlon=1 nz=sensor_info['nbins'] # dimension names use tuple so order of initialization is maintained dimensions = ('ntime', 'nlat', 'nlon', 'nz') # using tuple of tuples so order of initialization is maintained # using dict for attributes order of init not important # use dimension names not values # (varName, varType, (dimName1, [dimName2], ...)) var_inits = ( # coordinate variables ('time', NC.INT, ('ntime',)), ('lat', NC.FLOAT, ('nlat',)), ('lon', NC.FLOAT, ('nlon',)), ('z', NC.FLOAT, ('nz',)), # data variables ('u', NC.FLOAT, ('ntime', 'nz')), ('v', NC.FLOAT, ('ntime', 'nz')), ('w', NC.FLOAT, ('ntime', 'nz')), ('back_scatter', NC.FLOAT, ('ntime', 'nz')), ('wtemp', NC.FLOAT, ('ntime',)), ) # var data var_data = ( ('lat', platform_info['lat']), ('lon', platform_info['lon']), ('z', []), ('u', []), ('v', []), ('w', []), ('back_scatter', []), ('wtemp', []), ) return (global_atts, dimensions, var_inits, var_data) def updater(platform_info, sensor_info, data): # global_atts = { # timeframe of data contained in file yyyy-mm-dd HH:MM:SS 'end_date' : data['sample_dt'].strftime("%Y-%m-%d %H:%M:%S"), 'release_date' : now.strftime("%Y-%m-%d %H:%M:%S"), # 'creation_date' : now.strftime("%Y-%m-%d %H:%M:%S"), 'modification_date' : now.strftime("%Y-%m-%d %H:%M:%S"), } # var data var_data = ( ('u', data['u']), ('v', data['v']), ('w', data['w']), ('back_scatter', data['back_scatter']), ('wtemp', data['wtemp']), ) return (global_atts, var_data) #