#!/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