#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Deployment Strategy definition (:mod:`hydrac.instruments.mod_deployment`)
=========================================================================
Derived class for acoustic data processing.
.. autoclass:: ModeDeployment
:members:
:private-members:
"""
# from .instruments import Instrument
from hydrac.calcul.resample import Resample
import numpy as np
from hydrac.util.parameters import Parameters
# from .calcul import Resample
[docs]class ModeDeployment(object):
"""
Deployment Strategy Class.
The ModeDeployment class changes the data configuration of the both
hydroacoustic data and environmental data. For instance, if the instrument
is deployed from the surface like an echosounder, the range variable
becomes the depth. To the difference, if an instrument is deployed in a
cast, the range variable is not to be considered as the depth. This
information is crucial to average HAC data or resample environmental data,
for example pass from a time series sapling at different depths to one
single depth average profile with no temporal information (see
:class: `hydrac.calcul.resample.Resample`). Among the
different possibilities :
1 - **Mooring** : The instrument is either fixed to the sea/riverbed and
records timeseries of HAC or environmental data.
2 - **Cast** : The instrument is cast down the water column and samples at
different depths. For HAC data, the orientation of the transducers is to be
horizontal. Also, for the case of HAC data, the user is
promted to indicate whether the current files consist on one profile each
or an continuous ensemble of multiple profiles that need to be split.
3 - **Survey** : The instrument is positioned at the air-water interface
and records spatial geolocalized HAC or environmental data (To do).
The class contains methods dedicated to HAC (:func: `acoustic_depl`) or
environmental (:func: `multiparam_depl`) data handling. The user will be
prompted to know whether and how he wishes to resample the data (HAC
data necessitate to be resampled most of the time to ensure incoherent
scattering and better converge towards a Rayleigh distribution of the
acoustic signal). If no reampling is needed, answering 0 does the trick.
For an example see
:func:`hydrac.instruments.acoustique.Acoustic.preproc_acoustic_data`
"""
def __init__(self, obj, mode_depl=None, force=None):
self.obj = obj
self.force = force
if self.check_depl(self.force) == 1:
return
if mode_depl is None:
self.mode_depl = input('Deployment Mod : ')
else:
self.mode_depl = mode_depl
self.obj.mode_depl = self.mode_depl
if self.obj.instr_type == 'acoustic':
self.obj = self.acoustic_depl()
elif self.obj.instr_type == 'param_phy':
self.obj = self.multiparam_depl()
def check_depl(self, force=None):
if hasattr(self.obj, 'mode_depl'):
ordre = 1
if force is None:
ordre = 1
print('Deployment strategy already assigned')
return ordre
else:
ordre = 0
print('Forcing new deployment strategy')
return ordre
else:
ordre = 0
return ordre
def acoustic_depl(self):
if self.mode_depl == 'Mooring':
self.obj.geo_xyz = ['T', '']
self.obj.binsize = float(input('Select a temporal window (in sec) for ' +
'averaging of moored acoustic ' +
'parameter instrument ' +
'(0 for no averaging): '))
vert_on = float(input('Select a vertical bin size (in m)' +
'for averaging of casted ' +
'physical parameter ' +
'instrument (0 for no ' +
'averaging): '))
Resample(self.obj, self.obj.binsize, vert_on=vert_on)
elif self.mode_depl == 'Cast':
self.obj.geo_xyz = ['Z', 'T']
self.cast_type = input('Cast Type : Continuous or Single ?')
self.obj.cast_type = self.cast_type
if self.cast_type == 'Single':
self.obj.binsize = float(input('Select a vertical bin size (in m)' +
'for averaging of casted ' +
'physical parameter ' +
'instrument (0 for no ' +
'averaging): '))
elif self.cast_type == 'Continuous':
self.lol = Parameters({})
for u in range(0, len(self.obj.param)):
if u == 0:
idx_s = 0
b1, b2, bx = self.detect_profiles(
self.obj.param['P' + str(u)])
tmp = self.obj.split_profiles(
self.obj.param['P' + str(u)], b1, b2, bx)
idx_e = idx_s + len(tmp)
[self.lol.update({"P"+str(u1): tmp[u1-idx_s]})
for u1 in range(idx_s, idx_e)]
idx_s = idx_s + len(tmp)
import copy
self.test = copy.deepcopy(self.obj.param)
self.obj.param = self.lol
del self.lol
self.obj.binsize = float(input('Select a vertical bin size' +
'(in m) for averaging of' +
'casted acoustic parameter ' +
'instrument (0 for no' +
'averaging): '))
Resample(self.obj, self.obj.binsize)
print("toto va a la plage : {}".format(np.shape(self.obj.param.P0.adepth)))
if self.obj.binsize > 0:
for i in range(0, len(self.obj.param)):
self.obj.param['P' + str(i)].at = np.zeros(np.shape(
self.obj.param['P' + str(i)].adepth)) +\
self.obj.param['P' + str(i)].time[max(np.where(
self.obj.param['P' + str(i)].depth ==
max(self.obj.param['P' + str(i)].depth)))[0]]
else:
for i in range(0, len(self.obj.param)):
dcor = np.correlate(self.obj.param['P' + str(i)].depth,
self.obj.param['P' + str(i)].adepth)
ind = int(np.where(dcor == np.max(dcor))[0])
target = self.obj.param['P' + str(i)].keys()
split_target =\
[x for x in self.obj.param['P' + str(i)].keys() if
[y for y in np.shape(self.obj.param['P' + str(i)][x])
if y == len(self.obj.param['P' + str(i)].time)]]
self.obj.param['P' + str(i)].at =\
self.obj.param['P' + str(i)
].time[ind: ind +
len(self.obj.param['P' + str(i)
].adepth)]
for uj in split_target:
if len(np.shape(self.obj.param['P' + str(i)][uj])) > 2:
self.obj.param['P' + str(i)][uj] = self.obj.param['P' + str(i)][uj][:,ind:ind+len(self.obj.param['P' + str(i)].adepth),:]
else:
self.obj.param['P' + str(i)][uj] = self.obj.param['P' + str(i)][uj][ind:ind+len(self.obj.param['P' + str(i)].adepth)]
return self.obj
def smooth(self, y, box_pts):
box = np.ones(box_pts) / box_pts
y_smooth = np.convolve(y, box, mode='same')
return y_smooth
def detect_profiles(self, B, box=None, thr=None, cnt=None):
if box is None:
box = 10 * B[self.obj.instr_name].AuxSampleRate
print('box ={}'.format(box))
if cnt is None:
cnt = 0
d_tmp = (B.depth - np.nanmean(B.depth)) / np.std(B.depth)
if np.max(d_tmp) > 3 * np.std(d_tmp):
d_tmp = self.smooth(d_tmp, int(box))
else:
return np.array([0]), np.array([len(d_tmp)]), [0, len(d_tmp)]
if thr is None:
thr = np.histogram(d_tmp,
bins=list(np.arange(0,
max(d_tmp),
(max(d_tmp) -
min(d_tmp)) / 100)))[1][4]
d_tmp[np.where(d_tmp >= thr)] = 1
d_tmp[np.where(d_tmp < thr)] = 0
b1 = np.where(np.diff(d_tmp) > 0)[0]
b2 = np.where(np.diff(d_tmp) < 0)[0]
while len(b1) != len(b2) and cnt < 10:
return self.detect_profiles(B, box=box+1, thr=None, cnt=cnt+1)
fox = []
[fox.append(x) for x in zip(b1, b2)]
fox2 = [item for sublist in fox for item in sublist]
print(fox2)
del fox2[0]
fox2[-1] = len(d_tmp)
bx = []
bx.append(0)
for u in range(0, int(len(fox2)), 2):
bx.append(int(np.floor(np.nanmean(fox2[u: u + 2]))))
return b1, b2, bx
def multiparam_depl(self):
if self.mode_depl == 'Mooring':
self.obj.geo_xyz = ['t', '']
self.obj.binsize = float(input('Select a temporal bin size (in ' +
's) for' +
'averaging of moored physical ' +
'parameter instrument ' +
'(0 for no averaging): '))
Resample(self.obj, self.obj.binsize)
elif self.mode_depl == 'Cast':
self.obj.geo_xyz = ['depth', 'time']
self.obj.binsize = float(input('Select a vertical bin size (m) ' +
'for averaging of casted ' +
'physical parameter instrument ' +
'(0 for no averaging): '))
while self.obj.binsize == 0:
self.obj.binsize = float(input('Select a vertical bin size ' +
'(in m) ' +
'for averaging of casted phy' +
'sical parameter instrument ' +
'(0 for no averaging): '))
Resample(self.obj, self.obj.binsize)
for i in range(0, len(self.obj.param)):
self.obj.param['P' + str(i)].at[:] = np.nanmean(
self.obj.param['P' + str(i)].at)
elif self.obj.mode_depl == 'Surface':
pass
else:
print('Please choose amongst the following propositions ' +
': 1-Mooring, 2-Cast, 3-Surface')
return
return self.obj