Source code for hydrac.instruments.instruments

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Instrument (:mod:`hydrac.instruments.instruments`)
=======================================================


.. autoclass:: Instrument
   :members:
   :private-members:
"""

import numpy as np
from hydrac.util.display import Display
from hydrac.model.water import Water


[docs]class Instrument: """Instrument class for raw data interfacing. This class is made to handle hydroacoustic (defined in the :class:`hydrac.instruments.acoustique.Acoustic`) or multiparameters (defined in the :class:`hydrac.instruments.physicalparam.PhysicalParam`) instruments. The data are contained in the ``param`` attribute which is a Modified dictionnary (created with the class :class:`hydrac.util.parameters.AttrDict`). The hydroacoustic and physical data structures in ``param`` are harmonized to facilitate data manipulation. All the methods of the class are common to all instruments and enable data display through the :class:`hydrac.util.display.Display` class. It is also possible to export (:func:`nc_save_param`) /import back (:func:`nc_load`) processed acoustic data in netCDF format. """ def __init__(self): print('test')
[docs] def display_data(self, key, k, **kwargs): """Method returning a default display based on the data dimensions. The figure parameters are saved inside param. A deployment strategy has to be attached to the instrument to avoid ambiguities for diplaying the data Typical usage with an hydroacoustic object A (:mod:`hydrac.instruments.acoustique`):: # Display the Intensity varaible of the first profile in param and # save the figure in A.param.P0.d_0 >>>A.display('Intensity',0) # Adjust the colorbar >>>A.param.P0.d_0.c_lim(0,1) Parameters ---------- key : str, {'Intensity', 'asv', 'conc', ...} Attribute to be displayed. k : int Profile number """ if 'title' not in kwargs.keys(): title = [key] if len(list(self.find_all(key, 'Int'))) > 0 or\ len(list(self.find_all(key, 'as'))) > 0: x = 10 * np.log10(self.look_up_keys(key, k)) print('toto ici popo') else: x = self.look_up_keys(key, k) if x is None: raise AttributeError('No key found in current object...') shape = np.shape(x) shape_i = [a for a in shape if a != 1] _lim_elem_for_pcolor = 1e5 any_in = lambda a, b: bool(set(a).intersection(b)) if hasattr(self, 'mode_depl'): if self.mode_depl == 'Mooring': if self.instr_type == 'param_phy': x_0 = self.param['P' + str(k)].time y_0 = [] x_0_l = ['time (s)'] y_0_l = [''] x_1 = self.param['P' + str(k)].at y_1 = [] x_1_l = ['time (s)'] y_1_l = [''] else: x_0 = self.param['P' + str(k)].time y_0 = self.param['P' + str(k)].BinRange[:, 0] try: y_00 = self.param['P' + str(k)].BinRange_raw[:, 0] except AttributeError: y_00 = y_0 x_0_l = ['time (s)'] y_0_l = ['range (m)'] x_1 = self.param['P' + str(k)].at y_1 = self.param['P' + str(k)].BinRange[:, 0] try: y_11 = self.param['P' + str(k)].BinRange_raw[:, 0] except AttributeError: y_11 = y_1 x_1_l = ['time (s)'] y_1_l = ['range (m)'] elif self.mode_depl == 'Cast': if self.instr_type == 'param_phy': x_0 = self.param['P' + str(k)].time y_0 = [] x_0_l = ['time (s)'] y_0_l = [''] x_1 = self.param['P' + str(k)].adepth y_1 = [] x_1_l = ['depth (m)'] y_1_l = [''] else: x_0 = self.param['P' + str(k)].time y_0 = self.param['P' + str(k)].BinRange[:, 0] x_0_l = ['time (s)'] y_0_l = ['range (m)'] x_1 = self.param['P' + str(k)].adepth y_1 = self.param['P' + str(k)].BinRange[:, 0] x_1_l = ['depth (m)'] y_1_l = ['range (m)'] else: raise AttributeError('Please define a deployment strategy...') if any_in([np.size(x_0)], shape_i): print('No Averaging => {}'.format(np.shape(x_0))) x_n = x_0 y_n = y_0 x_n_l = x_0_l y_n_l = y_0_l if self.instr_type == 'acoustic': if any_in([np.size(y_0)], shape_i) is False and self.mode_depl == 'Mooring': y_n = y_00 else: x_n = x_1 y_n = y_1 x_n_l = x_1_l y_n_l = y_1_l if any_in([np.size(y_0)], shape_i) is False and self.mode_depl == 'Mooring': y_n = y_11 if hasattr(self, 'd_ind'): self.d_ind += 1 else: self.d_ind = 0 if len(shape_i) == 1 or (len(shape_i) == 2 and len(self.param['P' + str(k)].FrequencyRx) in shape_i): u_ind = np.max(shape_i) if self.instr_type != 'param_phy': ji = [] [ji.append(1) for lpl in np.isnan(self.param['P' + str(k)].sal) if lpl is True] if np.sum(ji) == len(x): raise ValueError("Can't display nan values only") if u_ind == len(self.param['P' + str(k)].BinRange[:, 0]): x_n = self.param['P' + str(k)].BinRange[:, 0] x_n_l = ['range(m)'] elif u_ind == len(x_1): pass else: x_n = np.arange(0, np.max(shape_i)) /\ np.unique(np.diff(self.param['P' + str(k)].time))[0] x_n_l = ['time (s)'] y_n_l = [key] try: self.param['P' + str(k)]['d_' + str(self.d_ind)] =\ Display(x_n, x, plt_type=['plot'], xlabel=x_n_l, ylabel=y_n_l, title=title) except TypeError or ValueError: self.param['P' + str(k)]['d_' + str(self.d_ind)] =\ Display(x_n, x.T, plt_type=['plot'], xlabel=x_n_l, ylabel=y_n_l, title=title) pass elif len(shape_i) == 2 and (len(self.param['P' + str(k)].FrequencyRx) not in shape_i): print('x_n={}'.format(len(x_n))) try: print('hibou') self.param['P' + str(k)]['d_' + str(self.d_ind)] =\ Display(y_n, x_n, x.T, plt_type=['imshow'], aspect=['auto'], cmap=['jet'], xlabel=y_n_l, ylabel=x_n_l, title=title) except TypeError: print('chouette') self.param['P' + str(k)]['d_' + str(self.d_ind)] =\ Display(y_n, x_n, x, plt_type=['imshow'], aspect=['auto'], cmap=['jet'], xlabel=y_n_l, ylabel=x_n_l, title=title) elif len(shape_i) == 3 and shape[2] == len(self.param['P' + str(k)].FrequencyRx): _str_subplot = '' _plt_type = '' _aspect = '' _cmap = '' _xlabel = '' _ylabel = '' _title = '' # for tutu in range(len(shape_i)+1): for tutu in range(shape[-1]): _str_subplot += ', x_n, y_n, np.squeeze(x[:, :, ' + str(tutu) +']).T' if shape[0]*shape[1] > _lim_elem_for_pcolor: _plt_type += ",'imshow'" else: _plt_type += ",'pcolor'" _aspect += ",'auto'" _cmap += ",'jet'" _title += ",'Sv " + str(self.param['P' + str(k)].FrequencyRx[tutu]/1e6) + " MHz'" _xlabel += ",'" + y_n_l[0] + "'" _ylabel += ",'" + x_n_l[0] + "'" exec("self.param['P' + str(k)]['d_' + str(self.d_ind)]=Display(" + _str_subplot[1:] + ",plt_type=[" + _plt_type[1:] + "],aspect=[" + _aspect[1:] + "],subplot=(" + str(shape[-1]) + ",1),cmap=[" + _cmap[1:] + "],xlabel=[" + _xlabel[1:] + "],ylabel=[" + _ylabel[1:] + "],title=[" + _title[1:] + "])") else: print('Ambiguity on how to display the data on a single plot...')
[docs] def look_up_keys(self, x, k, ini=None): """Looks throughout the param dictionnary of profile k to find the key x and returns the value h """ if ini is None: ini = self.param['P' + str(k)] else: pass pass if x in ini.keys(): h = ini[x] return h else: h = None for u in ini.keys(): if isinstance(ini[u], dict): h = self.look_up_keys(x, k, ini=ini[u]) if h is not None: break return h
[docs] def find_all(self, a_str, sub): """Finds all occurences of str sub in str a_str """ start = 0 while True: start = a_str.find(sub, start) if start == -1: return yield start start += len(sub)
[docs] def nc_save_param(self, file): """Saves HAC data in a netCDF file keeping the param structure. Note that the data have to be inverted before saving them. Typical usage with an hydroacoustic object A (:mod:`hydrac.instruments.acoustique`):: # Save the current object content in 'file_netcdf.nc' >>>A.nc_save_param('file_netcdf.nc') """ if hasattr(self, 'method_inv') is False: raise AttributeError('Data are not processed yet...') from netCDF4 import Dataset, stringtochar from hydrac.util.parameters import Parameters if file[-3:] == '.nc': f = Dataset(file, 'w') else: f = Dataset(file + '.nc', 'w') nchar1 = f.createDimension('nchar1', len(self.instr_name)) nchar2 = f.createDimension('nchar2', len(self.instr_type)) nchar3 = f.createDimension('nchar3', len(self.method_inv)) nchar4 = f.createDimension('nchar4', len(self.mode_depl)) nchar5 = f.createDimension('nchar5', len(self.tag_M)) instr_name = f.createVariable('instr_name', 'S1', ('nchar1')) instr_type = f.createVariable('instr_type', 'S1', ('nchar2')) method_inv = f.createVariable('method_inv', 'S1', ('nchar3')) mode_depl = f.createVariable('mode_depl', 'S1', ('nchar4')) tag_M = f.createVariable('tag_M', 'S1', ('nchar5')) instr_name[:] = stringtochar(np.array([self.instr_name], 'S' + str(len(self.instr_name)))) instr_type[:] = stringtochar(np.array([self.instr_type], 'S' + str(len(self.instr_type)))) method_inv[:] = stringtochar(np.array([self.method_inv], 'S' + str(len(self.method_inv)))) mode_depl[:] = stringtochar(np.array([self.mode_depl], 'S' + str(len(self.mode_depl)))) tag_M[:] = stringtochar(np.array([self.tag_M], 'S' + str(len(self.tag_M)))) for u in range(len(self.param)): filename = self.filepath[u].split('/')[-1] filepath = self.filepath[u][0:-len(filename)] fe = dict() fe.update({'f' + str(u) + '0': f.createGroup("P" + str(u) + "/HAC")}) fe.update({'f' + str(u) + '1': f.createGroup("P" + str(u) + "/Wat")}) fe.update({'f' + str(u) + '2': f.createGroup("P" + str(u) + "/Model")}) fe.update({'f' + str(u) + '3': f.createGroup("P" + str(u) + "/Inv")}) # Dimensions for HAC r = self.param['P' + str(u)].BinRange t_raw = self.param['P' + str(u)].time nf = self.param['P' + str(u)].FrequencyRx ad = self.look_up_keys('adepth', u) if ad is None: ad = self.look_up_keys('at', u) atime = self.look_up_keys('at', u) size_class = self.look_up_keys('a_UND', u) rg = fe['f' + str(u) + '0'].createDimension('rg', np.size(r, 0)) dpth_t = fe['f' + str(u) + '0'].createDimension('dpth_t', len(ad)) frq = fe['f' + str(u) + '0'].createDimension('frq', len(nf)) t = fe['f' + str(u) + '0'].createDimension('t', len(atime)) t_r = fe['f' + str(u) + '0'].createDimension('t_r', len(t_raw)) scalar = fe['f' + str(u) + '0'].createDimension('scalar', 1) ncharf = fe['f' + str(u) + '0' ].createDimension('ncharf', len(self.look_up_keys('FileName', u))) ncharf2 = fe['f' + str(u) + '0'].createDimension('ncharf2', len(filepath)) print('gygy{}, gugu {}, jojo {}'.format(np.size(r, 0), len(ad), len(nf))) # Variables for HAC L = Parameters({}) L.asv = fe['f' + str(u) + '0'].createVariable('asv', 'f8', ('rg', 'dpth_t', 'frq')) L.BinRange = fe['f' + str(u) + '0'].createVariable('BinRange', 'f4', ('rg', 'frq')) if self.look_up_keys('adepth', u) is not None: L.adepth = fe['f' + str(u) + '0'].createVariable('adepth', 'f4', ('dpth_t')) L.at = fe['f' + str(u) + '0'].createVariable('at', 'f8', ('t')) L.time = fe['f' + str(u) + '0'].createVariable('time', 'f8', ('t_r')) L.BurstTime = fe['f' + str(u) + '0'].createVariable('BurstTime', 'f4', ('scalar')) L.FrequencyRx = fe['f' + str(u) + '0'].createVariable('FrequencyRx', 'f4', ('frq') ) L.Frequency = fe['f' + str(u) + '0'].createVariable('Frequency', 'f4', ('frq')) L.NumAverage = fe['f' + str(u) + '0'].createVariable('NumAverage', 'f4', ('frq')) L.NumBins = fe['f' + str(u) + '0'].createVariable('NumBins', 'f4', ('frq')) L.NumChannels = fe['f' + str(u) + '0'].createVariable('NumChannels', 'f4', ('scalar')) L.NumPingsTot = fe['f' + str(u) + '0'].createVariable('NumPingsTot', 'f4', ('scalar')) L.NumProfilesSamples = fe['f' + str(u) + '0' ].createVariable('NumProfilesSamples', 'f4', ('frq')) L.NumSamples = fe['f' + str(u) + '0'].createVariable('NumSamples', 'f4', ('frq')) L.PingRate = fe['f' + str(u) + '0'].createVariable('PingRate', 'f4', ('scalar')) L.PulseLength = fe['f' + str(u) + '0'].createVariable('PulseLength', 'f4', ('frq')) L.SampleRate = fe['f' + str(u) + '0'].createVariable('SampleRate', 'f4',('frq')) L.StartBin = fe['f' + str(u) + '0'].createVariable('StartBin', 'f4',('frq')) L.TransducerAngle = fe['f' + str(u) + '0' ].createVariable('TransducerAngle', 'f4', ('frq')) L.TransducerBeamWidth = fe['f' + str(u) + '0' ].createVariable('TransducerBeamWidth', 'f4',('frq')) L.TransducerRadius = fe['f' + str(u) + '0' ].createVariable('TransducerRadius', 'f4', ('frq')) self._attrib_nc_keys(L, fe['f' + str(u) + '0'], u) L.FileName = fe['f' + str(u) + '0'].createVariable('FileName', 'S1', ('ncharf')) L.FileName[:] = stringtochar(np.array( [self.look_up_keys('FileName', u)], 'S' + str(len(self.look_up_keys('FileName', u))))) L.FilePath = fe['f' + str(u) + '0'].createVariable('FilePath', 'S1', ('ncharf2')) L.FileName[:] = stringtochar(np.array( [self.look_up_keys('FileName', u)], 'S' + str(len(self.look_up_keys('FileName', u))))) L.FilePath[:] = stringtochar(np.array(filepath, 'S' + str(len(filepath)))) # Dimensions for Wat celerity = np.array([self.param['P' + str(u)].w_obj.paramw.cw]) temperature = np.array([self.param['P' + str(u)].w_obj.paramw.T]) salinity = np.array([self.param['P' + str(u)].w_obj.paramw.S]) pressure = np.array([self.param['P' + str(u)].w_obj.paramw.P]) density = np.array([self.param['P' + str(u)].w_obj.paramw.rho]) cel = fe['f' + str(u) + '1'].createDimension('cel', len(celerity)) temp = fe['f' + str(u) + '1'].createDimension('temp', len(temperature)) sal = fe['f' + str(u) + '1'].createDimension('sal', len(salinity)) pres = fe['f' + str(u) + '1'].createDimension('pres', len(pressure)) dens = fe['f' + str(u) + '1'].createDimension('dens', len(density)) # Variables for Wat cw = fe['f' + str(u) + '1'].createVariable('cw', 'f4', ('cel')) T = fe['f' + str(u) + '1'].createVariable('T', 'f4', ('temp')) S = fe['f' + str(u) + '1'].createVariable('S', 'f4', ('sal')) P = fe['f' + str(u) + '1'].createVariable('P', 'f4', ('pres')) rho = fe['f' + str(u) + '1'].createVariable('rho', 'f4', ('dens')) # Pour variables for Wat cw[:] = celerity T[:] = temperature S[:] = salinity P[:] = pressure rho[:] = density # Dimensions for Model aHR = self.param['P' + str(u)].S.a_HR aUND = self.look_up_keys('a_UND', u) a_0 = self.look_up_keys('a0_HR', u) a_inf = fe['f' + str(u) + '2'].createDimension('a_inf', len(aHR)) if self.tag_M != 'mono': a_U = fe['f' + str(u) + '2'].createDimension('a_U', len(aUND)) size_class = fe['f' + str(u) + '2' ].createDimension('size_class', np.size(aUND)) if a_0 is not None: a00 = fe['f' + str(u) + '2'].createDimension('a00', len(a_0)) frq2 = fe['f' + str(u) + '2'].createDimension('frq2', len(np.unique(nf))) # Variables for Model f_infHR = fe['f' + str(u) + '2'].createVariable('f_infHR', 'f4', ('frq2', 'a_inf')) c_infHR = fe['f' + str(u) + '2'].createVariable('c_infHR', 'f4', ('frq2', 'a_inf')) a_HR = fe['f' + str(u) + '2'].createVariable('a_HR', 'f4', ('a_inf')) if a_0 is not None: f_0HR = fe['f' + str(u) + '2'].createVariable('f_0HR', 'f4', ('frq2', 'a00')) c_0HR = fe['f' + str(u) + '2'].createVariable('c_0HR', 'f4', ('frq2', 'a00')) a0_HR = fe['f' + str(u) + '2'].createVariable('a0_HR', 'f4', ('a00')) if self.tag_M != 'mono': a_UND = fe['f' + str(u) + '2'].createVariable('a_UND', 'f4', ('a_U')) f_infUND = fe['f' + str(u) + '2'].createVariable('f_infUND', 'f4', ('frq2', 'size_class') ) c_infUND = fe['f' + str(u) + '2'].createVariable('c_infUND', 'f4', ('frq2', 'size_class') ) aij = fe['f' + str(u) + '2'].createVariable('aij', 'f4', ('frq2', 'size_class')) # Pour variables for Model f_infHR[:, :] = self.look_up_keys('f_infHR', u) c_infHR[:, :] = self.look_up_keys('c_infHR', u) a_HR[:] = aHR if a_0 is not None: f_0HR[:, :] = self.look_up_keys('f_0HR', u) c_0HR[:, :] = self.look_up_keys('c_0HR', u) a0_HR[:] = a_0 if self.tag_M != 'mono': f_infUND[:, :] = self.look_up_keys('f_infUND', u) c_infUND[:, :] = self.look_up_keys('c_infUND', u) a_UND[:] = aUND aij[:] = self.look_up_keys('aij', u) L3 = Parameters({}) # Dimensions for HAC r = self.param['P' + str(u)].BinRange nf = self.param['P' + str(u)].FrequencyRx ad = self.look_up_keys('adepth', u) if ad is None: ad = self.look_up_keys('at', u) rg = fe['f' + str(u) + '3'].createDimension('rg', np.size(r, 0)) dpth_t = fe['f' + str(u) + '3'].createDimension('dpth_t', len(ad)) frq = fe['f' + str(u) + '3'].createDimension('frq', len(nf)) if self.look_up_keys('bv', u) is not None: size_class = fe['f' + str(u) + '3'].createDimension('size_class', np.size(aUND)) L3.conc = fe['f' + str(u) + '3'].createVariable('conc', 'f4', ('rg', 'dpth_t')) L3.bv = fe['f' + str(u) + '3'].createVariable('bv', 'f4', ('rg', 'dpth_t', 'size_class')) L3.conc_i = fe['f' + str(u) + '3'].createVariable('conc_i', 'f4', ('rg', 'dpth_t', 'size_class' ) ) L3.norm = fe['f' + str(u) + '3'].createVariable('norm', 'f4', ('rg', 'dpth_t', 'frq')) L3.rnorm = fe['f' + str(u) + '3'].createVariable('rnorm', 'f4', ('rg', 'dpth_t')) elif self.look_up_keys('a_mat', u) is not None: if self.tag_M != 'mono': L3.conc = fe['f' + str(u) + '3'].createVariable('conc', 'f4', ('rg', 'dpth_t')) else: L3.conc = fe['f' + str(u) + '3'].createVariable('conc', 'f4', ('rg', 'dpth_t', 'frq')) L3.a_mat = fe['f' + str(u) + '3'].createVariable('a_mat', 'f4', ('rg', 'dpth_t')) L3.zeta_mat = fe['f' + str(u) + '3'].createVariable('zeta_mat', 'f4', ('rg', 'dpth_t', 'frq')) self._attrib_nc_keys(L3, fe['f' + str(u) + '3'], u) f.close()
def _attrib_nc_keys(self, L, fe, u): f_keys = list(fe.variables.keys()) for mi in f_keys: if len(np.shape(self.look_up_keys(mi, u))) <= 1: print('mi = {}'.format(mi)) L[mi][:] = self.look_up_keys(mi, u) elif len(np.shape(self.look_up_keys(mi, u))) == 2: print('mi = {}'.format(mi)) L[mi][:, :] = self.look_up_keys(mi, u) elif len(np.shape(self.look_up_keys(mi, u))) == 3: print('mi = {}'.format(mi)) L[mi][:, :, :] = self.look_up_keys(mi, u) return
[docs] def nc_load(self, file): """Load HAC data from a netCDF file generated with :func:`nc_save_param` and reshaping the param allowing to the common data structure of hydrac Typical usage for an hydroacoustic object A (:mod:`hydrac.instruments.acoustique`):: # Create an empty Acoustic object >>>A=hydrac.instruments.acoustique.Acoustique() # Load the content of 'file_netcdf.nc' in A >>>A.nc_load('file_netcdf.nc') """ from netCDF4 import Dataset, chartostring from hydrac.util.parameters import Parameters if file[-3:] == '.nc': f = Dataset(file) else: f = Dataset(file + '.nc') numel = list(f.groups.keys()) self.instr_name = str(chartostring(f.variables['instr_name'][:])) self.instr_type = str(chartostring(f.variables['instr_type'][:])) self.method_inv = str(chartostring(f.variables['method_inv'][:])) self.mode_depl = str(chartostring(f.variables['mode_depl'][:])) self.tag_M = str(chartostring(f.variables['tag_M'][:])) self.param = Parameters({}) for u in range(len(numel)): self.param[numel[u]] = Parameters({}) self.param[numel[u]].update({'S': Parameters({}), 'inv': Parameters({}), 'w_obj': Water()}) self.param[numel[u]].w_obj.paramw = Parameters({}) f1 = f.groups[numel[u]]['HAC'] f1_keys = list(f1.variables.keys()) f2 = f.groups[numel[u]]['Wat'] f2_keys = list(f2.variables.keys()) f3 = f.groups[numel[u]]['Model'] f3_keys = list(f3.variables.keys()) f4 = f.groups[numel[u]]['Inv'] f4_keys = list(f4.variables.keys()) [self.param[numel[u]].update({tu: f1.variables[tu][:]}) for tu in f1_keys] [self.param[numel[u]].w_obj.paramw.update({tu: f2.variables[tu][:]} ) for tu in f2_keys] [self.param[numel[u]].S.update({tu: f3.variables[tu][:]}) for tu in f3_keys] [self.param[numel[u]].inv.update({tu: f4.variables[tu][:]}) for tu in f4_keys] if 'FileName' in f1_keys: print('hello') self.filepath = [] for u in range(len(numel)): fn = [io.decode('UTF-8') for io in self.param[numel[u]].FileName] fp = [io.decode('UTF-8') for io in self.param[numel[u]].FilePath] self.param[numel[u]].FileName = ''.join(fn) self.filepath.append(''.join(fp + fn)) self.filepath = tuple(self.filepath) return