acoused/View/acoustic_inversion_tab.py

1929 lines
81 KiB
Python

# ============================================================================== #
# acoustic_inversion.py - AcouSed #
# Copyright (C) 2024 INRAE #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# by Brahim MOUDJED #
# ============================================================================== #
# -*- coding: utf-8 -*-
import os
import gc
import time
import logging
import numpy as np
import scipy as sp
import pandas as pd
from math import isinf
from copy import deepcopy
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolBar
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QComboBox,
QLabel, QPushButton, QSpacerItem, QSlider, QLineEdit,
QMessageBox, QFileDialog
)
from PyQt5.QtCore import QCoreApplication, Qt
from PyQt5.QtGui import QIcon, QPixmap
from View.checkable_combobox import CheckableComboBox
import settings as stg
from Model.acoustic_inversion_method_high_concentration import AcousticInversionMethodHighConcentration
from tools import trace
_translate = QCoreApplication.translate
logger = logging.getLogger("acoused")
class AcousticInversionTab(QWidget):
''' This class generates the Acoustic Inversion Tab '''
def __init__(self, widget_tab):
super().__init__()
self.inv_hc = AcousticInversionMethodHighConcentration()
self._setup_icons()
self._setup_attrs()
self._setup_general_layout(widget_tab)
self._setup_connections()
def _path_icon(self, icon):
return os.path.join(
os.path.dirname(__file__), "..", "icons", icon
)
def _setup_icons(self):
self.icon_folder = QIcon(self._path_icon("folder.png"))
self.icon_triangle_left = QIcon(self._path_icon("triangle_left.png"))
self.icon_triangle_left_to_begin = QIcon(
self._path_icon("triangle_left_to_begin.png")
)
self.icon_triangle_right = QIcon(
self._path_icon("triangle_right.png")
)
self.icon_triangle_right_to_end = QIcon(
self._path_icon("triangle_right_to_end.png")
)
self.icon_update = QIcon(self._path_icon("update.png"))
def _setup_general_layout(self, widget_tab):
self.verticalLayoutMain = QVBoxLayout(widget_tab)
self.horizontalLayout_Run_Inversion = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayout_Run_Inversion)
self.horizontalLayoutTop = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayoutTop, 5) # 1O units is 100% , 1 units is 10%
self.horizontalLayoutBottom = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 5)
self._setup_acoustic_data()
self._setup_top_layout()
self._setup_bottom_layout()
self._setup_SSC_fine()
self._setup_measured_SSC_fine()
self._setup_SSC_sand()
self._setup_measured_SSC_sand()
def _setup_acoustic_data(self):
### --- Combobox acoustic data choice + pushbutton Run Inversion ---
self.pushbutton_update_acoustic_data_choice = QPushButton()
self.pushbutton_update_acoustic_data_choice.setIcon(self.icon_update)
self.pushbutton_update_acoustic_data_choice.setMaximumWidth(50)
self.horizontalLayout_Run_Inversion.addWidget(
self.pushbutton_update_acoustic_data_choice
)
self.combobox_acoustic_data_choice = QComboBox()
self.combobox_acoustic_data_choice.setMaximumWidth(300)
self.horizontalLayout_Run_Inversion.addWidget(
self.combobox_acoustic_data_choice
)
self.pushbutton_run_inversion = QPushButton()
self.pushbutton_run_inversion.setText("RUN INVERSION")
self.pushbutton_run_inversion.setMaximumWidth(110)
self.horizontalLayout_Run_Inversion\
.addWidget(self.pushbutton_run_inversion)
self.spacerItem_RunInversion = QSpacerItem(1000, 10)#, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_Run_Inversion.addSpacerItem(
self.spacerItem_RunInversion
)
self.pushbutton_save_result = QPushButton()
self.pushbutton_save_result.setText("Save Results")
self.pushbutton_save_result.setMaximumWidth(110)
self.horizontalLayout_Run_Inversion.addWidget(self.pushbutton_save_result)
def _setup_top_layout(self):
# Plot SSC 2D field | SSC vertical profile | Plot SSC graph sample vs inversion ===>>> FINE
self.groupbox_plot_SSC_fine = QGroupBox()
self.horizontalLayoutTop.addWidget(self.groupbox_plot_SSC_fine, 6)
self.groupbox_plot_SSC_fine_vertical_profile = QGroupBox()
self.verticalLayout_groupbox_plot_SSC_fine_profile_and_slider = QVBoxLayout()
self.horizontalLayoutTop.addLayout(
self.verticalLayout_groupbox_plot_SSC_fine_profile_and_slider, 3
)
self.groupbox_plot_measured_vs_inverted_SSC_fine = QGroupBox()
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine_and_combobox = QVBoxLayout()
self.horizontalLayoutTop.addLayout(
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine_and_combobox, 3
)
def _setup_bottom_layout(self):
# Plot SSC 2D field | SSC vertical profile | Plot SSC graph sample vs inversion ===>>> SAND
self.groupbox_plot_SSC_sand = QGroupBox()
self.horizontalLayoutBottom.addWidget(self.groupbox_plot_SSC_sand, 6)
self.groupbox_plot_SSC_sand_vertical_profile = QGroupBox()
self.verticalLayout_groupbox_plot_SSC_sand_profile_and_slider = QVBoxLayout()
self.horizontalLayoutBottom.addLayout(
self.verticalLayout_groupbox_plot_SSC_sand_profile_and_slider, 3
)
self.groupbox_plot_measured_vs_inverted_SSC_sand = QGroupBox()
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand_and_combobox = QVBoxLayout()
self.horizontalLayoutBottom.addLayout(
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand_and_combobox,
3
)
def _setup_SSC_fine(self):
self.verticalLayout_groupbox_plot_SSC_fine = QVBoxLayout(
self.groupbox_plot_SSC_fine
)
self.canvas_SSC_fine = FigureCanvas()
self.toolbar_SSC_fine = NavigationToolBar(self.canvas_SSC_fine, self)
self.verticalLayout_groupbox_plot_SSC_fine\
.addWidget(self.toolbar_SSC_fine)
self.verticalLayout_groupbox_plot_SSC_fine\
.addWidget(self.canvas_SSC_fine)
self.verticalLayout_groupbox_plot_SSC_fine_profile_and_slider\
.addWidget(self.groupbox_plot_SSC_fine_vertical_profile)
self.verticalLayout_groupbox_plot_vertical_profile_fine = QVBoxLayout(
self.groupbox_plot_SSC_fine_vertical_profile)
self.canvas_profile_fine = FigureCanvas()
self.toolbar_profile_fine = NavigationToolBar(
self.canvas_profile_fine, self
)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.addWidget(self.toolbar_profile_fine)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.addWidget(self.canvas_profile_fine)
self.horizontalLayout_slider_fine = QHBoxLayout()
self.verticalLayout_groupbox_plot_SSC_fine_profile_and_slider\
.addLayout(self.horizontalLayout_slider_fine)
self.pushbutton_left_to_begin_fine = QPushButton()
self.pushbutton_left_to_begin_fine\
.setIcon(self.icon_triangle_left_to_begin)
self.horizontalLayout_slider_fine\
.addWidget(self.pushbutton_left_to_begin_fine)
self.pushbutton_left_fine = QPushButton()
self.pushbutton_left_fine.setIcon(self.icon_triangle_left)
self.horizontalLayout_slider_fine.addWidget(self.pushbutton_left_fine)
self.lineEdit_slider_fine = QLineEdit()
self.lineEdit_slider_fine.setText("1")
self.lineEdit_slider_fine.setFixedWidth(50)
self.horizontalLayout_slider_fine.addWidget(self.lineEdit_slider_fine)
self.pushbutton_right_fine = QPushButton()
self.pushbutton_right_fine.setIcon(self.icon_triangle_right)
self.horizontalLayout_slider_fine.addWidget(self.pushbutton_right_fine)
self.pushbutton_right_to_end_fine = QPushButton()
self.pushbutton_right_to_end_fine\
.setIcon(self.icon_triangle_right_to_end)
self.horizontalLayout_slider_fine\
.addWidget(self.pushbutton_right_to_end_fine)
self.slider_fine = QSlider()
self.horizontalLayout_slider_fine.addWidget(self.slider_fine)
self.slider_fine.setOrientation(Qt.Horizontal)
self.slider_fine.setCursor(Qt.OpenHandCursor)
self.slider_fine.setMinimum(1)
self.slider_fine.setMaximum(10)
self.slider_fine.setTickInterval(1)
self.slider_fine.setValue(1)
def _setup_measured_SSC_fine(self):
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine_and_combobox\
.addWidget(
self.groupbox_plot_measured_vs_inverted_SSC_fine
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine = QVBoxLayout(
self.groupbox_plot_measured_vs_inverted_SSC_fine)
self.canvas_inverted_vs_measured_SSC_fine = FigureCanvas()
self.toolbar_inverted_vs_measured_SSC_fine = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_fine, self
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine.addWidget(
self.toolbar_inverted_vs_measured_SSC_fine
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine.addWidget(
self.canvas_inverted_vs_measured_SSC_fine
)
self.horizontalLayout_combobox_fine_sample_choice = QHBoxLayout()
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine_and_combobox\
.addLayout(
self.horizontalLayout_combobox_fine_sample_choice
)
self.label_fine_sample_choice = QLabel()
self.label_fine_sample_choice.setText("Fine sample choice : ")
self.horizontalLayout_combobox_fine_sample_choice\
.addWidget(self.label_fine_sample_choice)
self.combobox_fine_sample_choice = CheckableComboBox()
self.horizontalLayout_combobox_fine_sample_choice\
.addWidget(self.combobox_fine_sample_choice)
self.pushbutton_plot_fine_sample_choice = QPushButton()
self.pushbutton_plot_fine_sample_choice.setIcon(self.icon_update)
self.pushbutton_plot_fine_sample_choice.setMaximumWidth(50)
self.horizontalLayout_combobox_fine_sample_choice\
.addWidget(self.pushbutton_plot_fine_sample_choice)
self.fine_sample_to_plot = []
def _setup_SSC_sand(self):
self.verticalLayout_groupbox_plot_SSC_sand = QVBoxLayout(
self.groupbox_plot_SSC_sand
)
self.canvas_SSC_sand = FigureCanvas()
self.toolbar_SSC_sand = NavigationToolBar(self.canvas_SSC_sand, self)
self.verticalLayout_groupbox_plot_SSC_sand\
.addWidget(self.toolbar_SSC_sand)
self.verticalLayout_groupbox_plot_SSC_sand\
.addWidget(self.canvas_SSC_sand)
self.verticalLayout_groupbox_plot_SSC_sand_profile_and_slider.addWidget(
self.groupbox_plot_SSC_sand_vertical_profile)
self.verticalLayout_groupbox_plot_vertical_profile_sand = QVBoxLayout(
self.groupbox_plot_SSC_sand_vertical_profile)
self.canvas_profile_sand = FigureCanvas()
self.toolbar_profile_sand = NavigationToolBar(
self.canvas_profile_sand, self
)
self.verticalLayout_groupbox_plot_vertical_profile_sand\
.addWidget(self.toolbar_profile_sand)
self.verticalLayout_groupbox_plot_vertical_profile_sand\
.addWidget(self.canvas_profile_sand)
self.horizontalLayout_slider_sand = QHBoxLayout()
self.verticalLayout_groupbox_plot_SSC_sand_profile_and_slider\
.addLayout(self.horizontalLayout_slider_sand)
self.pushbutton_left_to_begin_sand = QPushButton()
self.pushbutton_left_to_begin_sand\
.setIcon(self.icon_triangle_left_to_begin)
self.horizontalLayout_slider_sand\
.addWidget(self.pushbutton_left_to_begin_sand)
self.pushbutton_left_sand = QPushButton()
self.pushbutton_left_sand.setIcon(self.icon_triangle_left)
self.horizontalLayout_slider_sand.addWidget(self.pushbutton_left_sand)
self.lineEdit_slider_sand = QLineEdit()
self.lineEdit_slider_sand.setText("1")
self.lineEdit_slider_sand.setFixedWidth(50)
self.horizontalLayout_slider_sand.addWidget(self.lineEdit_slider_sand)
self.pushbutton_right_sand = QPushButton()
self.pushbutton_right_sand.setIcon(self.icon_triangle_right)
self.horizontalLayout_slider_sand.addWidget(self.pushbutton_right_sand)
self.pushbutton_right_to_end_sand = QPushButton()
self.pushbutton_right_to_end_sand\
.setIcon(self.icon_triangle_right_to_end)
self.horizontalLayout_slider_sand\
.addWidget(self.pushbutton_right_to_end_sand)
self.slider_sand = QSlider()
self.horizontalLayout_slider_sand.addWidget(self.slider_sand)
self.slider_sand.setOrientation(Qt.Horizontal)
self.slider_sand.setCursor(Qt.OpenHandCursor)
self.slider_sand.setMinimum(1)
self.slider_sand.setMaximum(10)
self.slider_sand.setTickInterval(1)
self.slider_sand.setValue(1)
def _setup_measured_SSC_sand(self):
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand_and_combobox\
.addWidget(
self.groupbox_plot_measured_vs_inverted_SSC_sand
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand = QVBoxLayout(
self.groupbox_plot_measured_vs_inverted_SSC_sand
)
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas()
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_sand, self
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.addWidget(
self.toolbar_inverted_vs_measured_SSC_sand
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.addWidget(
self.canvas_inverted_vs_measured_SSC_sand
)
self.horizontalLayout_combobox_sand_sample_choice = QHBoxLayout()
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand_and_combobox\
.addLayout(
self.horizontalLayout_combobox_sand_sample_choice
)
self.label_sand_sample_choice = QLabel()
self.label_sand_sample_choice.setText("Sand sample choice : ")
self.horizontalLayout_combobox_sand_sample_choice\
.addWidget(self.label_sand_sample_choice)
self.combobox_sand_sample_choice = CheckableComboBox()
self.horizontalLayout_combobox_sand_sample_choice\
.addWidget(self.combobox_sand_sample_choice)
self.pushbutton_plot_sand_sample_choice = QPushButton()
self.pushbutton_plot_sand_sample_choice.setIcon(self.icon_update)
self.pushbutton_plot_sand_sample_choice.setMaximumWidth(50)
self.horizontalLayout_combobox_sand_sample_choice\
.addWidget(self.pushbutton_plot_sand_sample_choice)
def _setup_connections(self):
self.pushbutton_update_acoustic_data_choice\
.clicked.connect(self.update_acoustic_data_choice)
self.pushbutton_run_inversion\
.clicked.connect(self.function_run_inversion)
self.pushbutton_save_result\
.clicked.connect(self.save_result)
self.pushbutton_left_to_begin_fine\
.clicked.connect(self.slider_profile_number_to_begin_fine)
self.pushbutton_left_fine\
.clicked.connect(self.slider_profile_number_to_left_fine)
self.pushbutton_right_fine\
.clicked.connect(self.slider_profile_number_to_right_fine)
self.pushbutton_right_to_end_fine\
.clicked.connect(self.slider_profile_number_to_end_fine)
self.lineEdit_slider_fine\
.returnPressed.connect(self.profile_number_on_lineEdit_fine)
self.slider_fine.valueChanged\
.connect(self.update_lineEdit_by_moving_slider_fine)
self.slider_fine.valueChanged\
.connect(self.update_plot_SSC_fine_vertical_profile)
self.pushbutton_plot_fine_sample_choice\
.clicked\
.connect(self.plot_measured_vs_inverted_SSC_fine)
self.pushbutton_left_to_begin_sand\
.clicked.connect(self.slider_profile_number_to_begin_sand)
self.pushbutton_left_sand\
.clicked.connect(self.slider_profile_number_to_left_sand)
self.pushbutton_right_sand\
.clicked.connect(self.slider_profile_number_to_right_sand)
self.pushbutton_right_to_end_sand\
.clicked.connect(self.slider_profile_number_to_end_sand)
self.lineEdit_slider_sand\
.returnPressed.connect(self.profile_number_on_lineEdit_sand)
self.slider_sand.valueChanged\
.connect(self.update_lineEdit_by_moving_slider_sand)
self.slider_sand.valueChanged\
.connect(self.update_plot_SSC_sand_vertical_profile)
self.pushbutton_plot_sand_sample_choice\
.clicked.connect(self.plot_measured_vs_inverted_SSC_sand)
def _setup_attrs(self):
self.figure_SSC_fine = None
self.figure_SSC_sand = None
self.figure_vertical_profile_SSC_fine = None
self.figure_vertical_profile_SSC_sand = None
self.figure_measured_vs_inverted_fine = None
self.figure_measured_vs_inverted_sand = None
def full_update(self):
logger.debug(f"{__name__}: Update")
self.blockSignals(True)
self.update_acoustic_data_choice()
self.function_run_inversion()
self.blockSignals(False)
def update_acoustic_data_choice(self):
self.combobox_acoustic_data_choice.clear()
for i in range(len(stg.filename_BS_raw_data)):
self.combobox_acoustic_data_choice.addItem(stg.data_preprocessed[i])
self.combobox_acoustic_data_choice\
.currentIndexChanged\
.connect(self.combobox_acoustic_data_choice_currentIndexChanged)
def combobox_acoustic_data_choice_currentIndexChanged(self):
self.compute_VBI()
self.compute_SSC_fine()
self.compute_SSC_sand()
self.fill_combobox_fine_sample()
self.plot_SSC_fine()
self.plot_SSC_fine_vertical_profile()
self.plot_measured_vs_inverted_SSC_fine()
self.fill_combobox_sand_sample()
self.plot_SSC_sand()
self.plot_SSC_sand_vertical_profile()
self.plot_measured_vs_inverted_SSC_sand()
def function_run_inversion(self):
if (stg.alpha_s[0] < 0) or (stg.alpha_s[1] < 0):
msgBox = QMessageBox()
msgBox.setWindowTitle("Alpha computation error")
msgBox.setIconPixmap(
QPixmap(
self._path_icon("no_approved.png")
).scaledToHeight(32, Qt.SmoothTransformation)
)
msgBox.setText("Sediment sound attenuation is negative !")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
elif isinf(stg.alpha_s[0]) or isinf(stg.alpha_s[1]):
msgBox = QMessageBox()
msgBox.setWindowTitle("Alpha computation error")
msgBox.setIconPixmap(
QPixmap(
self._path_icon("no_approved.png")
).scaledToHeight(32, Qt.SmoothTransformation)
)
msgBox.setText("Sediment sound attenuation is infinite !")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
else:
self.compute_VBI()
self.compute_SSC_fine()
self.compute_SSC_sand()
self.fill_combobox_fine_sample()
self.plot_SSC_fine()
self.plot_SSC_fine_vertical_profile()
self.plot_measured_vs_inverted_SSC_fine()
self.fill_combobox_sand_sample()
self.plot_SSC_sand()
self.plot_SSC_sand_vertical_profile()
self.plot_measured_vs_inverted_SSC_sand()
def compute_VBI(self):
'''
Compute the VBI (Volume Backscatter Index) for the selected dataset in the combobox.
If the data has been recorded by an Ubertone UB SediFlow, the data for the two
calibration frequencies is first interpolated on the same spatial and temporal
grids.
'''
# Get the dataset ID (integer relating the dataset selected in the combobox
# to the corresponding dataset loaded into AcouSed):
data_id = self.combobox_acoustic_data_choice.currentIndex()
# Get the spatial and temporal grids for the two selected frequencies, and create common
# grids to be used for the VBI and SSC computations (reminder: the grids have
# the same number of points, but the intervals are different). Here, we assume that the
# time delay between the channels (i.e., frequencies) is negligible, so that the i-th
# time stamp is taken as the average between the i-th time stamp of the first frequency
# and the i-th time stamp of the second frequency:
rGrid_freq1 = stg.depth_2D[data_id][ stg.frequencies_for_calibration[0][1] ]
rGrid_freq2 = stg.depth_2D[data_id][ stg.frequencies_for_calibration[1][1] ]
rVect_freq1 = rGrid_freq1[:,0] #Vector of vertical coordinates (m) for the first frequency
rVect_freq2 = rGrid_freq2[:,0] #Vector of vertical coordinates (m) for the second frequency
tVect_freq1 = stg.time[data_id][ stg.frequencies_for_calibration[0][1] ]
tVect_freq2 = stg.time[data_id][ stg.frequencies_for_calibration[1][1] ]
rMin = np.min( np.array( [ np.min(rVect_freq1), np.min(rVect_freq2) ] ) ) #Minimum vertical position (m)
rMax = np.max( np.array( [ np.max(rVect_freq1), np.max(rVect_freq2) ] ) ) #Maximum vertical position (m)
rVect_interp = np.linspace( rMin, rMax, rVect_freq1.shape[0] ) #Vector of vertical coordinates (m) used for interpolation
tVect_interp = ( tVect_freq1 + tVect_freq2 ) / 2 #Vector of time stamps (s) used for interpolation
rGrid_interp = np.zeros( ( rVect_interp.shape[0], rGrid_freq1.shape[1] ) )
tGrid_interp = np.zeros( rGrid_interp.shape )
for j in range( rGrid_interp.shape[1] ):
rGrid_interp[:, j] = rVect_interp
tGrid_interp[:, j] = tVect_interp[j] * np.ones( rGrid_interp.shape[0] )
stg.r2D_interp[data_id] = rGrid_interp
stg.t2D_interp[data_id] = tGrid_interp
# Interpolate on the same grid the quantity 'J' that has been previously
# computed for both frequencies:
j_interpolator_freq1 = sp.interpolate.RegularGridInterpolator( ( rVect_freq1, tVect_interp ),
stg.J_cross_section[data_id][0],
method="linear", fill_value=np.nan )
j_interpolator_freq2 = sp.interpolate.RegularGridInterpolator( ( rVect_freq2, tVect_interp ),
stg.J_cross_section[data_id][1],
method="linear", fill_value=np.nan )
j_interp_freq1 = j_interpolator_freq1( ( stg.r2D_interp[data_id], stg.t2D_interp[data_id] ) )
j_interp_freq2 = j_interpolator_freq2( ( stg.r2D_interp[data_id], stg.t2D_interp[data_id] ) )
stg.J_cross_section_interp[data_id] = [ j_interp_freq1, j_interp_freq2 ]
# Compute the Volume Backscatter Index (VBI) on the common grid:
stg.VBI_cross_section[data_id] = np.array([])
stg.VBI_cross_section[data_id] = self.inv_hc.VBI_cross_section(
freq1=stg.frequencies_for_calibration[0][0],
freq2=stg.frequencies_for_calibration[1][0],
zeta_freq1=stg.zeta[0], zeta_freq2=stg.zeta[1],
j_cross_section_freq1=stg.J_cross_section_interp[data_id][0],
j_cross_section_freq2=stg.J_cross_section_interp[data_id][1],
r2D=stg.r2D_interp[data_id],
water_attenuation_freq1=stg.alpha_s[0],
water_attenuation_freq2=stg.alpha_s[1],
X=stg.X_exponent[0]
)
def compute_SSC_fine(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
stg.SSC_fine[data_id] = np.array([])
'''
stg.SSC_fine[data_id] = self.inv_hc.SSC_fine(
zeta=stg.zeta[0],
r2D=stg.r2D_interp[data_id],
VBI=stg.VBI_cross_section[data_id],
freq=stg.frequencies_for_calibration[0][0],
X=stg.X_exponent[0],
j_cross_section=stg.J_cross_section[data_id][0],
alpha_w=stg.water_attenuation[data_id][ stg.frequencies_for_calibration[0][1] ]
) #Inversion using the first frequency
'''
stg.SSC_fine[data_id] = self.inv_hc.SSC_fine(
zeta=stg.zeta[1],
r2D=stg.r2D_interp[data_id],
VBI=stg.VBI_cross_section[data_id],
freq=stg.frequencies_for_calibration[1][0],
X=stg.X_exponent[0],
j_cross_section=stg.J_cross_section_interp[data_id][1],
alpha_w=stg.water_attenuation[data_id][ stg.frequency_for_inversion[1] ]
) #Inversion using the second frequency
def compute_SSC_sand(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
stg.SSC_sand[data_id] = np.array([])
'''
stg.SSC_sand[data_id] = self.inv_hc.SSC_sand(
VBI=stg.VBI_cross_section[data_id],
freq=stg.frequencies_for_calibration[0][0],
X=stg.X_exponent,
ks=stg.ks[0]
) #Inversion using the first frequency
'''
stg.SSC_sand[data_id] = self.inv_hc.SSC_sand(
VBI=stg.VBI_cross_section[data_id],
freq=stg.frequencies_for_calibration[1][0],
X=stg.X_exponent,
ks=stg.ks[1]
) #Inversion using the second frequency
def plot_SSC_fine(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if self.combobox_acoustic_data_choice.count() <= 0:
return
if stg.SSC_fine[data_id].shape == (0,):
self.verticalLayout_groupbox_plot_SSC_fine.removeWidget(self.toolbar_SSC_fine)
self.verticalLayout_groupbox_plot_SSC_fine.removeWidget(self.canvas_SSC_fine)
self.canvas_SSC_fine = FigureCanvas()
self.toolbar_SSC_fine = NavigationToolBar(self.canvas_SSC_fine, self)
self.verticalLayout_groupbox_plot_SSC_fine.addWidget(self.toolbar_SSC_fine)
self.verticalLayout_groupbox_plot_SSC_fine.addWidget(self.canvas_SSC_fine)
elif stg.SSC_fine[data_id].shape != (0,):
self.verticalLayout_groupbox_plot_SSC_fine.removeWidget(self.toolbar_SSC_fine)
self.verticalLayout_groupbox_plot_SSC_fine.removeWidget(self.canvas_SSC_fine)
if self.figure_SSC_fine is not None:
self.figure_SSC_fine.clear()
plt.close(fig=self.figure_SSC_fine)
self.figure_SSC_fine, self.axis_SSC_fine = plt.subplots(
nrows=1, ncols=1, layout="constrained"
)
self.canvas_SSC_fine = FigureCanvas(self.figure_SSC_fine)
self.toolbar_SSC_fine = NavigationToolBar(self.canvas_SSC_fine, self)
self.verticalLayout_groupbox_plot_SSC_fine.addWidget(self.toolbar_SSC_fine)
self.verticalLayout_groupbox_plot_SSC_fine.addWidget(self.canvas_SSC_fine)
val_min = np.nanmin(stg.SSC_fine[data_id])
val_max = np.nanmax(stg.SSC_fine[data_id])
if stg.time_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
else:
time_data = stg.time
depth_data = stg.depth
pcm_SSC_fine = self.axis_SSC_fine.pcolormesh(
stg.t2D_interp[data_id], -stg.r2D_interp[data_id],
stg.SSC_fine[data_id],
cmap='rainbow', norm=LogNorm(vmin=1e0, vmax=15),
shading='gouraud'
)
if stg.depth_bottom[data_id].shape != (0,):
self.axis_SSC_fine.plot(
stg.t2D_interp[data_id][0,:],
-stg.depth_bottom[data_id],
color='black', linewidth=1, linestyle="solid"
)
self.pcm_SSC_fine_vertical_line, = self.axis_SSC_fine.plot(
stg.t2D_interp[data_id][0, self.slider_fine.value() - 1]
* np.ones( ( stg.r2D_interp[data_id].shape[0], 1 ) ),
- stg.r2D_interp[data_id][:,0], linestyle="solid", color='r', linewidth=2
)
# --- Plot samples of fine sediments ---
time_fine_temp = deepcopy(stg.time_fine)
depth_fine_temp = deepcopy(stg.depth_fine)
for s in stg.fine_sample_profile:
time_fine_temp.remove(stg.time_fine[s[1]])
depth_fine_temp.remove(stg.depth_fine[s[1]])
self.pcm_SSC_fine_meas_vs_inv, = self.axis_SSC_fine.plot(
time_fine_temp, depth_fine_temp,
ls=" ", marker="o", ms=5, mec="k", mfc="k"
)
time_fine_temp = deepcopy(stg.time_fine)
depth_fine_temp = deepcopy(stg.depth_fine)
sample_fine_temp = deepcopy(stg.sample_fine)
for s in stg.fine_sample_profile:
sample_fine_temp.remove(s)
time_fine_temp.remove(stg.time_fine[s[1]])
depth_fine_temp.remove(stg.depth_fine[s[1]])
for i in range(len(sample_fine_temp)):
self.pcm_SSC_fine_meas_vs_inv_text = self.axis_SSC_fine.text(
time_fine_temp[i],
depth_fine_temp[i], sample_fine_temp[i][0]
)
time_fine_temp, depth_fine_temp = stg.time_fine, stg.depth_fine
self.pcm_SSC_fine_meas_vs_inv_sample_calibration, = self.axis_SSC_fine.plot(
[time_fine_temp[s[1]] for s in stg.fine_sample_profile],
[depth_fine_temp[s[1]] for s in stg.fine_sample_profile],
ls=" ", marker="*", ms=12, mec="r", mfc="r"
)
time_fine_temp, depth_fine_temp = stg.time_fine, stg.depth_fine
for i, j in stg.fine_sample_profile:
self.pcm_SSC_fine_meas_vs_inv_sample_calibration_text = self.axis_SSC_fine.text(
time_fine_temp[j]+5, depth_fine_temp[j]+0.05, i,
color='r', fontweight='bold'
)
cbar_SSC_fine = self.figure_SSC_fine.colorbar(
pcm_SSC_fine, ax=self.axis_SSC_fine, shrink=1,
location='right'
)
cbar_SSC_fine.set_label(label='Fine SSC (g/L)', rotation=270, labelpad=15)
self.figure_SSC_fine.supxlabel("Time (sec)", fontsize=10)
self.figure_SSC_fine.supylabel("Depth (m)", fontsize=10)
self.figure_SSC_fine.canvas.draw_idle()
def plot_SSC_fine_vertical_profile(self):
if self.combobox_acoustic_data_choice.count() <= 0:
return
data_id = self.combobox_acoustic_data_choice.currentIndex()
if stg.SSC_fine[data_id].shape == (0,):
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.removeWidget(self.toolbar_profile_fine)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.removeWidget(self.canvas_profile_fine)
self.canvas_profile_fine = FigureCanvas()
self.toolbar_profile_fine = NavigationToolBar(self.canvas_profile_fine, self)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.addWidget(self.toolbar_profile_fine)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.addWidget(self.canvas_profile_fine)
if stg.SSC_fine[data_id].shape != (0,):
self.slider_fine.setMaximum(
stg.SSC_fine[data_id].shape[1]
)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.removeWidget(self.toolbar_profile_fine)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.removeWidget(self.canvas_profile_fine)
if self.figure_vertical_profile_SSC_fine is not None:
self.figure_vertical_profile_SSC_fine.clear()
plt.close(fig=self.figure_vertical_profile_SSC_fine)
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.figure_vertical_profile_SSC_fine = fig
self.axis_vertical_profile_SSC_fine = ax
self.canvas_profile_fine = FigureCanvas(self.figure_vertical_profile_SSC_fine)
self.toolbar_profile_fine = NavigationToolBar(self.canvas_profile_fine, self)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.addWidget(self.toolbar_profile_fine)
self.verticalLayout_groupbox_plot_vertical_profile_fine\
.addWidget(self.canvas_profile_fine)
if stg.depth_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
else:
time_data = stg.time
depth_data = stg.depth
self.plot_fine , = self.axis_vertical_profile_SSC_fine.plot(
stg.SSC_fine[data_id][:, self.slider_fine.value() -1],
-stg.r2D_interp[data_id][:,0],
linestyle="solid", linewidth=1, color="k"
)
self.pcm_SSC_fine_vertical_line.set_data(
stg.t2D_interp[data_id][0, self.slider_fine.value() - 1]
* np.ones( ( stg.r2D_interp[data_id].shape[0], 1 ) ),
-stg.r2D_interp[data_id][:,0] )
self.figure_SSC_fine.canvas.draw_idle()
self.axis_vertical_profile_SSC_fine.set_ylim(
[ - np.nanmax( stg.r2D_interp[data_id][:,0] ), -np.nanmin( stg.r2D_interp[data_id][:,0] ) ] )
self.axis_vertical_profile_SSC_fine.set_xlim(0, 10)
self.axis_vertical_profile_SSC_fine.set_xlabel("Inverted Fine SSC (g/L)")
self.axis_vertical_profile_SSC_fine.set_ylabel("Depth (m)")
self.figure_vertical_profile_SSC_fine.canvas.draw_idle()
def update_plot_SSC_fine_vertical_profile(self):
if len(stg.filename_BS_noise_data) == 0:
return
data_id = self.combobox_acoustic_data_choice.currentIndex()
if stg.SSC_fine[data_id].shape == (0,):
return
self.axis_vertical_profile_SSC_fine.cla()
if stg.depth_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
else:
time_data = stg.time
depth_data = stg.depth
self.axis_vertical_profile_SSC_fine.plot(
stg.SSC_fine[data_id][:, self.slider_fine.value() - 1],
-stg.r2D_interp[data_id][:,0],
linestyle="solid", linewidth=1, color="k"
)
self.pcm_SSC_fine_vertical_line.set_data(
stg.t2D_interp[data_id][0, self.slider_fine.value() - 1]
* np.ones( ( stg.r2D_interp[data_id].shape[0], 1 ) ),
-stg.r2D_interp[data_id][:,0]
)
self.figure_SSC_fine.canvas.draw_idle()
self.axis_vertical_profile_SSC_fine.set_ylim(
[ - np.nanmax( stg.r2D_interp[data_id][:,0] ), -np.nanmin( stg.r2D_interp[data_id][:,0] ) ] )
for f in stg.fine_sample_profile:
time_fine_calibration = (
np.where(
np.abs(
time_data[data_id][stg.frequency_for_inversion[1]]
- stg.time_fine[f[1]]
) == np.nanmin(
np.abs(
time_data[data_id][
stg.frequency_for_inversion[1]
]
- stg.time_fine[f[1]]
)
)
)[0][0]
)
if (time_data[data_id][
stg.frequency_for_inversion[1],
int(self.slider_fine.value())
] == time_data[data_id][
stg.frequency_for_inversion[1],
int(time_fine_calibration)
]):
self.axis_vertical_profile_SSC_fine.scatter(
stg.Ctot_fine[f[1]], stg.depth_fine[f[1]],
marker='*', s=48, c='r', edgecolors='r'
)
self.axis_vertical_profile_SSC_fine.text(
stg.Ctot_fine[f[1]],
stg.depth_fine[f[1]], f[0]
)
self.axis_vertical_profile_SSC_fine.set_xlim(0, 10)
self.axis_vertical_profile_SSC_fine\
.set_xlabel("Inverted Fine SSC (g/L)")
self.axis_vertical_profile_SSC_fine\
.set_ylabel("Depth (m)")
self.figure_vertical_profile_SSC_fine.canvas.draw_idle()
def slider_profile_number_to_begin_fine(self):
self.slider_fine.setValue(int(self.slider_fine.minimum()))
self.update_lineEdit_by_moving_slider_fine()
def slider_profile_number_to_right_fine(self):
self.slider_fine.setValue(int(self.slider_fine.value()) + 1)
self.update_lineEdit_by_moving_slider_fine()
def slider_profile_number_to_left_fine(self):
self.slider_fine.setValue(int(self.slider_fine.value()) - 1)
self.update_lineEdit_by_moving_slider_fine()
def slider_profile_number_to_end_fine(self):
self.slider_fine.setValue(int(self.slider_fine.maximum()))
self.update_lineEdit_by_moving_slider_fine()
def profile_number_on_lineEdit_fine(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if stg.time_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
else:
time_data = stg.time
slider_value = float(
self.lineEdit_slider_fine.text().replace(",", ".")
)
self.slider_fine.setValue(
int(
np.where(
np.abs(
time_data[data_id][
stg.frequency_for_inversion[1]
] - slider_value
) == np.nanmin(
np.abs(
time_data[data_id][
stg.frequency_for_inversion[1]
] - slider_value
)
)
)[0][0]
)
)
def update_lineEdit_by_moving_slider_fine(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if stg.time_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
else:
time_data = stg.time
self.lineEdit_slider_fine.setText(
str(
time_data[data_id][
stg.frequency_for_inversion[1],
self.slider_fine.value()
]
)
)
def fill_combobox_fine_sample(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
self.combobox_fine_sample_choice.clear()
self.combobox_fine_sample_choice.addItems(
[f for f, _ in stg.sample_fine]
)
# --- Get position (index, value) of sample in acoustic measurement space ---
if ((stg.time_cross_section[data_id].shape != (0,))
and (stg.depth_cross_section[data_id].shape != (0,))):
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
elif ((stg.time_cross_section[data_id].shape != (0,))
and (stg.depth[data_id].shape != (0,))):
time_data = stg.time_cross_section
depth_data = stg.depth
elif ((stg.time[data_id].shape != (0,))
and (stg.depth_cross_section[data_id].shape != (0,))):
time_data = stg.time
depth_data = stg.depth_cross_section
elif ((stg.time[data_id].shape != (0,))
and (stg.depth[data_id].shape != (0,))):
time_data = stg.time
depth_data = stg.depth
for j in range(len(stg.time_fine)):
stg.fine_sample_position\
.append(
(
np.where(
np.abs(
time_data[data_id][
stg.frequency_for_inversion[1]
] - stg.time_fine[j]
) == np.nanmin(
np.abs(
time_data[data_id][
stg.frequency_for_inversion[1]
] - stg.time_fine[j]
)
)
)[0][0],
np.where(
np.abs(
depth_data[data_id][
stg.frequency_for_inversion[1]
] - (-stg.depth_fine[j]))
== np.nanmin(
np.abs(
depth_data[data_id][
stg.frequency_for_inversion[1]
] - (-stg.depth_fine[j])
)
)
)[0][0]
)
)
def plot_measured_vs_inverted_SSC_fine(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if self.combobox_acoustic_data_choice.count() <= 0:
return
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine\
.removeWidget(self.toolbar_inverted_vs_measured_SSC_fine)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine\
.removeWidget(self.canvas_inverted_vs_measured_SSC_fine)
if stg.SSC_fine[data_id].shape == (0,):
self.canvas_inverted_vs_measured_SSC_fine = FigureCanvas()
self.toolbar_inverted_vs_measured_SSC_fine = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_fine, self
)
else:
if self.figure_measured_vs_inverted_fine is not None:
self.figure_measured_vs_inverted_fine.clear()
plt.close(fig=self.figure_measured_vs_inverted_fine)
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.figure_measured_vs_inverted_fine = fig
self.axis_measured_vs_inverted_fine = ax
self.canvas_inverted_vs_measured_SSC_fine = FigureCanvas(
self.figure_measured_vs_inverted_fine
)
self.toolbar_inverted_vs_measured_SSC_fine = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_fine, self
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine\
.addWidget(self.toolbar_inverted_vs_measured_SSC_fine)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine\
.addWidget(self.canvas_inverted_vs_measured_SSC_fine)
if stg.SSC_fine[data_id].shape != (0,):
fine_id = self.combobox_fine_sample_choice.currentData()
self.fine_sample_to_plot = [
int(f[1:]) - 1 for f in fine_id
]
if self.fine_sample_to_plot:
fine_range = lambda : self.fine_sample_to_plot
else:
fine_range = lambda : range(len(stg.sample_fine))
self.axis_measured_vs_inverted_fine.plot(
[stg.Ctot_fine[k] for k in fine_range()],
[
stg.SSC_fine[data_id][
stg.fine_sample_position[k][1],
stg.fine_sample_position[k][0]
] for k in fine_range()
],
ls=" ", marker='o', ms=5, mec='black', mfc="black"
)
self.axis_measured_vs_inverted_fine.plot(
[
0, np.nanmax(
[
np.nanmax(
[stg.Ctot_fine[c] for c in fine_range()]
),
np.nanmax(
[
stg.SSC_fine[data_id][
stg.fine_sample_position[i][1],
stg.fine_sample_position[i][0]
] for i in fine_range()
]
)
]
) + 1
],
[
0, np.nanmax(
[
np.nanmax(
[stg.Ctot_fine[c] for c in fine_range()]
),
np.nanmax(
[
stg.SSC_fine[data_id][
stg.fine_sample_position[i][1],
stg.fine_sample_position[i][0]
] for i in fine_range()
]
)
]
) + 1
],
ls="solid", linewidth=1, color="k"
)
# --- Display sample label on plot ---
for i in fine_range():
self.axis_measured_vs_inverted_fine.text(
stg.Ctot_fine[i],
stg.SSC_fine[data_id][
stg.fine_sample_position[i][1],
stg.fine_sample_position[i][0]
],
stg.sample_fine[i][0],
fontstyle="normal", fontweight="light", fontsize=10
)
self.axis_measured_vs_inverted_fine\
.set_xlabel("Measured SSC fine (g/L)")
self.axis_measured_vs_inverted_fine\
.set_ylabel("Inverted SSC fine (g/L)")
self.figure_measured_vs_inverted_fine.canvas.draw_idle()
def update_plot_sample_position_on_concentration_field(self):
# --- Plot sample position on concentration field ---
self.pcm_SSC_fine_meas_vs_inv.set_data(
[[stg.time_fine.remove(s) for s in stg.fine_sample_profile[1]][i] for i in self.fine_sample_to_plot] ,
[[stg.depth_fine.remove(s) for s in stg.fine_sample_profile[1]][j] for j in self.fine_sample_to_plot],
ls=" ", marker="o", ms=5, mec="k", mfc="k"
)
self.pcm_SSC_fine_meas_vs_inv_sample_calibration.set_data(
[[stg.time_fine[s] for s in stg.fine_sample_profile[1]][i] for i in self.fine_sample_to_plot] ,
[[stg.depth_fine[s] for s in stg.fine_sample_profile[1]][j] for j in self.fine_sample_to_plot],
ls=" ", marker="*", ms=5, mec="r", mfc="r"
)
for i in self.fine_sample_to_plot:
for t in stg.fine_sample_profile[0]:
if i == t:
self.pcm_SSC_fine_meas_vs_inv_sample_calibration_text\
.set_text(stg.sample_fine[i][0])
self.pcm_SSC_fine_meas_vs_inv_sample_calibration_text\
.set_position(stg.time_fine[i], stg.depth_fine[i])
else:
self.pcm_SSC_fine_meas_vs_inv_text\
.set_text(stg.sample_fine[i][0])
self.pcm_SSC_fine_meas_vs_inv_text\
.set_position(stg.time_fine[i], stg.depth_fine[i])
self.figure_SSC_fine.canvas.draw_idle()
def plot_SSC_sand(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if self.combobox_acoustic_data_choice.count() <= 0:
return
self.verticalLayout_groupbox_plot_SSC_sand.removeWidget(self.toolbar_SSC_sand)
self.verticalLayout_groupbox_plot_SSC_sand.removeWidget(self.canvas_SSC_sand)
if stg.SSC_sand[data_id].shape == (0,):
self.canvas_SSC_sand = FigureCanvas()
self.toolbar_SSC_sand = NavigationToolBar(self.canvas_SSC_sand, self)
else:
if self.figure_SSC_sand is not None:
self.figure_SSC_sand.clear()
plt.close(fig=self.figure_SSC_sand)
self.figure_SSC_sand, self.axis_SSC_sand = plt.subplots(
nrows=1, ncols=1, layout="constrained"
)
self.canvas_SSC_sand = FigureCanvas(self.figure_SSC_sand)
self.toolbar_SSC_sand = NavigationToolBar(self.canvas_SSC_sand, self)
self.verticalLayout_groupbox_plot_SSC_sand.addWidget(self.toolbar_SSC_sand)
self.verticalLayout_groupbox_plot_SSC_sand.addWidget(self.canvas_SSC_sand)
if stg.SSC_sand[data_id].shape != (0,):
val_min = np.nanmin(stg.SSC_sand[data_id])
val_max = np.nanmax(stg.SSC_sand[data_id])
if stg.time_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
else:
time_data = stg.time
depth_data = stg.depth
pcm_SSC_sand = self.axis_SSC_sand.pcolormesh(
stg.t2D_interp[data_id], -stg.r2D_interp[data_id],
stg.SSC_sand[data_id],
cmap='rainbow', norm=LogNorm(vmin=1e0, vmax=10),
shading='gouraud'
)
if stg.depth_bottom[data_id].shape != (0,):
self.axis_SSC_sand.plot(
stg.t2D_interp[data_id][0,:],
-stg.depth_bottom[data_id],
color='black', linewidth=1, linestyle="solid"
)
self.pcm_SSC_sand_vertical_line, = self.axis_SSC_sand.plot(
stg.t2D_interp[data_id][0, self.slider_sand.value() - 1]
* np.ones( ( stg.r2D_interp[data_id].shape[0], 1 ) ),
-stg.r2D_interp[data_id][:,0],
linestyle="solid", color='r', linewidth=2
)
self.plot_SSC_sand_fig, = self.axis_SSC_sand.plot(
stg.time_sand, stg.depth_sand,
ls=" ", marker="o", ms=5, mec="k", mfc="k"
)
# --- Plot samples of fine sediments ---
time_sand_temp = deepcopy(stg.time_sand)
depth_sand_temp = deepcopy(stg.depth_sand)
for s in stg.sand_sample_target:
time_sand_temp.remove(stg.time_sand[s[1]])
depth_sand_temp.remove(stg.depth_sand[s[1]])
self.pcm_SSC_sand_meas_vs_inv, = self.axis_SSC_sand.plot(
time_sand_temp, depth_sand_temp,
ls=" ", marker="o", ms=5, mec="k", mfc="k"
)
time_sand_temp = deepcopy(stg.time_sand)
depth_sand_temp = deepcopy(stg.depth_sand)
sample_sand_temp = deepcopy(stg.sample_sand)
for s in stg.sand_sample_target:
sample_sand_temp.remove(s)
time_sand_temp.remove(stg.time_sand[s[1]])
depth_sand_temp.remove(stg.depth_sand[s[1]])
for i in range(len(sample_sand_temp)):
self.axis_SSC_sand.text(
time_sand_temp[i],
depth_sand_temp[i],
sample_sand_temp[i][0]
)
time_sand_temp, depth_sand_temp = stg.time_sand, stg.depth_sand
self.axis_SSC_sand.plot(
[time_sand_temp[s[1]] for s in stg.sand_sample_target],
[depth_sand_temp[s[1]] for s in stg.sand_sample_target],
ls=" ", marker="*", ms=12, mec="r", mfc="r"
)
time_sand_temp, depth_sand_temp = stg.time_sand, stg.depth_sand
for i, j in stg.sand_sample_target:
self.axis_SSC_sand.text(
time_sand_temp[j] + 5, depth_sand_temp[j] + 0.05, i,
color='r', fontweight='bold'
)
cbar_SSC_sand = self.figure_SSC_sand.colorbar(
pcm_SSC_sand, ax=self.axis_SSC_sand, shrink=1,
location='right'
)
cbar_SSC_sand.set_label(label='Sand SSC (g/L)', rotation=270, labelpad=15)
self.figure_SSC_sand.supxlabel("Time (sec)", fontsize=10)
self.figure_SSC_sand.supylabel("Depth (m)", fontsize=10)
self.figure_SSC_sand.canvas.draw_idle()
def plot_SSC_sand_vertical_profile(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if self.combobox_acoustic_data_choice.count() > 0:
if stg.SSC_sand[data_id].shape == (0,):
self.verticalLayout_groupbox_plot_vertical_profile_sand.removeWidget(self.toolbar_profile_sand)
self.verticalLayout_groupbox_plot_vertical_profile_sand.removeWidget(self.canvas_profile_sand)
self.canvas_profile_sand = FigureCanvas()
self.toolbar_profile_sand = NavigationToolBar(self.canvas_profile_sand, self)
self.verticalLayout_groupbox_plot_vertical_profile_sand.addWidget(self.toolbar_profile_sand)
self.verticalLayout_groupbox_plot_vertical_profile_sand.addWidget(self.canvas_profile_sand)
if stg.SSC_sand[data_id].shape != (0,):
self.slider_sand.setMaximum(stg.SSC_fine[data_id].shape[1])
self.verticalLayout_groupbox_plot_vertical_profile_sand.removeWidget(self.toolbar_profile_sand)
self.verticalLayout_groupbox_plot_vertical_profile_sand.removeWidget(self.canvas_profile_sand)
if self.figure_vertical_profile_SSC_sand is not None:
self.figure_vertical_profile_SSC_sand.clear()
plt.close(fig=self.figure_vertical_profile_SSC_sand)
fig, ax = plt.subplots(
nrows=1, ncols=1, layout="constrained"
)
self.figure_vertical_profile_SSC_sand = fig
self.axis_vertical_profile_SSC_sand = ax
self.canvas_profile_sand = FigureCanvas(self.figure_vertical_profile_SSC_sand)
self.toolbar_profile_sand = NavigationToolBar(self.canvas_profile_sand, self)
self.verticalLayout_groupbox_plot_vertical_profile_sand.addWidget(self.toolbar_profile_sand)
self.verticalLayout_groupbox_plot_vertical_profile_sand.addWidget(self.canvas_profile_sand)
if stg.depth_cross_section[data_id].shape != (0,):
self.plot_sand , = self.axis_vertical_profile_SSC_sand.plot(
stg.SSC_sand[data_id][:, self.slider_sand.value() -1],
-stg.r2D_interp[data_id][:,0],
linestyle="solid", linewidth=1, color="k")
self.pcm_SSC_sand_vertical_line.set_data(
stg.t2D_interp[data_id][0, self.slider_sand.value() - 1]
* np.ones( ( stg.r2D_interp[data_id].shape[0], 1 ) ),
-stg.r2D_interp[data_id][:, 0] )
self.figure_SSC_sand.canvas.draw_idle()
self.axis_vertical_profile_SSC_sand.set_ylim(
[ -np.nanmax( stg.r2D_interp[data_id][:,0] ), -np.nanmin( stg.r2D_interp[data_id][:,0] ) ] )
else:
self.plot_sand , = self.axis_vertical_profile_SSC_sand.plot(
stg.SSC_sand[data_id][:, self.slider_sand.value() -1],
-stg.depth[data_id][stg.frequency_for_inversion[1].shape],
linestyle="solid", linewidth=1, color="k")
self.pcm_SSC_sand_vertical_line.set_data(
stg.t2D_interp[data_id][0, self.slider_sand.value() - 1]
* np.ones( stg.depth[data_id][stg.frequency_for_inversion[1]].shape ),
-stg.depth[data_id][ stg.frequency_for_inversion[1] ] )
self.figure_SSC_sand.canvas.draw_idle()
self.axis_vertical_profile_SSC_sand.set_ylim(
[-np.nanmax(stg.depth[data_id][
stg.frequency_for_inversion[1]]),
-np.nanmin(stg.depth[data_id][
stg.frequency_for_inversion[1]])])
# self.axis_SSC_fine.plot([], [], )
self.axis_vertical_profile_SSC_sand.set_xlim(0, 10)
self.axis_vertical_profile_SSC_sand.set_xlabel("Inverted Sand SSC (g/L)")
self.axis_vertical_profile_SSC_sand.set_ylabel("Depth (m)")
self.figure_vertical_profile_SSC_sand.canvas.draw_idle()
def update_plot_SSC_sand_vertical_profile(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if stg.filename_BS_noise_data != []:
if stg.SSC_sand[data_id].shape != (0,):
self.axis_vertical_profile_SSC_sand.cla()
if stg.depth_cross_section[data_id].shape != (0,):
self.axis_vertical_profile_SSC_sand.plot(
stg.SSC_sand[data_id][:, self.slider_sand.value() - 1],
-stg.r2D_interp[data_id][:, 0],
linestyle="solid", linewidth=1, color="k")
self.pcm_SSC_sand_vertical_line.set_data(
stg.time_cross_section[data_id][
stg.frequency_for_inversion[1],
self.slider_sand.value() - 1] *
np.ones(stg.depth_cross_section[data_id][
stg.frequency_for_inversion[1]].shape),
-stg.depth_cross_section[data_id][
stg.frequency_for_inversion[1]])
self.figure_SSC_sand.canvas.draw_idle()
self.axis_vertical_profile_SSC_sand.set_ylim(
[-np.nanmax(stg.depth_cross_section[data_id][
stg.frequency_for_inversion[1]]),
-np.nanmin(stg.depth_cross_section[data_id][
stg.frequency_for_inversion[1]])])
else:
self.axis_vertical_profile_SSC_sand.plot(
stg.SSC_sand[data_id][:, self.slider_sand.value() - 1],
-stg.r2D_interp[data_id][:, 0],
linestyle="solid", linewidth=1, color="k")
self.pcm_SSC_sand_vertical_line.set_data(
stg.time[data_id][
stg.frequency_for_inversion[1], self.slider_sand.value() - 1] *
np.ones(stg.depth[data_id][
stg.frequency_for_inversion[1]].shape),
-stg.depth[data_id][
stg.frequency_for_inversion[1]])
self.figure_SSC_sand.canvas.draw_idle()
self.axis_vertical_profile_SSC_sand.set_ylim(
[-np.nanmax(stg.depth[data_id][
stg.frequency_for_inversion[1]]),
-np.nanmin(stg.depth[data_id][
stg.frequency_for_inversion[1]])])
if stg.time_cross_section[data_id].shape != (0,):
time_sand_calibration = (
np.where(np.abs(stg.time_cross_section[data_id][
stg.frequency_for_inversion[1]] - stg.time_sand[
stg.sand_sample_target[0][1]]) ==
np.nanmin(
np.abs(stg.time_cross_section[data_id][
stg.frequency_for_inversion[1]] - stg.time_sand[
stg.sand_sample_target[0][1]])))[0][0]
)
if (stg.time_cross_section[data_id][
stg.frequency_for_inversion[1], int(self.slider_sand.value())] ==
stg.time_cross_section[data_id][
stg.frequency_for_inversion[1], int(time_sand_calibration)]):
self.axis_vertical_profile_SSC_sand.scatter(stg.Ctot_sand[stg.sand_sample_target[0][1]],
stg.depth_sand[stg.sand_sample_target[0][1]],
marker='*', s=48, c='r', edgecolors='r')
self.axis_vertical_profile_SSC_sand.text(
stg.Ctot_sand[stg.sand_sample_target[0][1]],
stg.depth_sand[stg.sand_sample_target[0][1]],
stg.sand_sample_target[0][0])
else:
time_sand_calibration = (
np.where(np.abs(stg.time[data_id][
stg.frequency_for_inversion[1]] - stg.time_sand[
stg.sand_sample_target[0][1]]) ==
np.nanmin(np.abs(stg.time[data_id][
stg.frequency_for_inversion[1]] - stg.time_sand[
stg.sand_sample_target[0][1]])))[0][0]
)
if (stg.time[data_id][
stg.frequency_for_inversion[1], int(self.slider_sand.value())] ==
stg.time[data_id][
stg.frequency_for_inversion[1], int(time_sand_calibration)]):
self.axis_vertical_profile_SSC_sand.scatter(stg.Ctot_fine[stg.sand_sample_target[0][1]],
stg.depth_fine[stg.sand_sample_target[0][1]],
marker='*', s=48, c='r', edgecolors='r')
self.axis_vertical_profile_SSC_sand.text(
stg.Ctot_fine[stg.sand_sample_target[0][1]],
stg.depth_fine[stg.sand_sample_target[0][1]],
stg.sand_sample_target[0][0])
self.axis_vertical_profile_SSC_sand.set_xlim(0, 10)
self.axis_vertical_profile_SSC_sand.set_xlabel("Inverted Sand SSC (g/L)")
self.axis_vertical_profile_SSC_sand.set_ylabel("Depth (m)")
self.figure_vertical_profile_SSC_sand.canvas.draw_idle()
def slider_profile_number_to_begin_sand(self):
self.slider_sand.setValue(int(self.slider_sand.minimum()))
self.update_lineEdit_by_moving_slider_sand()
def slider_profile_number_to_right_sand(self):
self.slider_sand.setValue(int(self.slider_sand.value()) + 1)
self.update_lineEdit_by_moving_slider_sand()
def slider_profile_number_to_left_sand(self):
self.slider_sand.setValue(int(self.slider_sand.value()) - 1)
self.update_lineEdit_by_moving_slider_sand()
def slider_profile_number_to_end_sand(self):
self.slider_sand.setValue(int(self.slider_sand.maximum()))
self.update_lineEdit_by_moving_slider_sand()
def profile_number_on_lineEdit_sand(self):
if stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,):
self.slider_sand.setValue(
int(np.where(
np.abs(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][
stg.frequency_for_inversion[1]] -
float(self.lineEdit_slider_sand.text().replace(",", "."))) ==
np.nanmin(
np.abs(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][
stg.frequency_for_inversion[1]] -
float(self.lineEdit_slider_sand.text().replace(",", ".")))))[0][0]))
else:
self.slider_sand.setValue(
int(np.where(
np.abs(stg.time[self.combobox_acoustic_data_choice.currentIndex()][
stg.frequency_for_inversion[1]] -
float(self.lineEdit_slider_sand.text().replace(",", "."))) ==
np.nanmin(
np.abs(stg.time[self.combobox_acoustic_data_choice.currentIndex()][
stg.frequency_for_inversion[1]] -
float(self.lineEdit_slider_sand.text().replace(",", ".")))))[0][0]))
def update_lineEdit_by_moving_slider_sand(self):
if stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,):
self.lineEdit_slider_sand.setText(
str(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][
stg.frequency_for_inversion[1], self.slider_sand.value()-1]))
else:
self.lineEdit_slider_sand.setText(
str(stg.time[self.combobox_acoustic_data_choice.currentIndex()][
stg.frequency_for_inversion[1], self.slider_sand.value()-1]))
# --- Plot sand SSC : measured vs inverted ---
def fill_combobox_sand_sample(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
self.combobox_sand_sample_choice.clear()
self.combobox_sand_sample_choice.addItems(
[f for f, _ in stg.sample_sand]
)
# --- Get position (index, value) of sample in acoustic measurement space ---
if stg.time_cross_section[data_id].shape != (0,):
time_data = stg.time_cross_section
else:
time_data = stg.time
if stg.depth_cross_section[data_id].shape != (0,):
depth_data = stg.depth_cross_section
else:
depth_data = stg.depth
freq = stg.frequency_for_inversion[1]
for j in range(len(stg.time_sand)):
time_diff = np.abs(time_data[data_id][freq] - stg.time_sand[j])
depth_diff = np.abs(depth_data[data_id][freq] - (-stg.depth_sand[j]))
stg.sand_sample_position.append(
(
np.where(
time_diff == np.nanmin(time_diff)
)[0][0],
np.where(
depth_diff == np.nanmin(depth_diff)
)[0][0]
)
)
def plot_measured_vs_inverted_SSC_sand(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if self.combobox_acoustic_data_choice.count() <= 0:
return
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.removeWidget(self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.removeWidget(self.canvas_inverted_vs_measured_SSC_sand)
if stg.SSC_sand[data_id].shape == (0,):
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas()
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_sand, self
)
else:
if self.figure_measured_vs_inverted_sand is not None:
self.figure_measured_vs_inverted_sand.clear()
plt.close(fig=self.figure_measured_vs_inverted_sand)
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.figure_measured_vs_inverted_sand = fig
self.axis_measured_vs_inverted_sand = ax
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas(
self.figure_measured_vs_inverted_sand
)
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_sand, self
)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.addWidget(self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.addWidget(self.canvas_inverted_vs_measured_SSC_sand)
if stg.SSC_sand[data_id].shape != (0,):
sand_id = self.combobox_sand_sample_choice.currentData()
self.sand_sample_to_plot = [
int(f[1:]) - 1 for f in sand_id
]
if self.sand_sample_to_plot:
sand_range = lambda : self.sand_sample_to_plot
else:
sand_range = lambda : range(len(stg.sample_sand))
self.axis_measured_vs_inverted_sand.plot(
[stg.Ctot_sand[k] for k in sand_range()],
[
stg.SSC_sand[data_id][
stg.sand_sample_position[k][1],
stg.sand_sample_position[k][0]
] for k in sand_range()
],
ls=" ", marker='o', ms=5, mec='black', mfc="black"
)
self.axis_measured_vs_inverted_sand.plot(
[
0, np.nanmax(
[
np.nanmax(
[stg.Ctot_sand[c] for c in sand_range()]
),
np.nanmax(
[
stg.SSC_sand[data_id][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]
] for i in sand_range()
]
)
]
) + 1
],
[
0, np.nanmax(
[
np.nanmax(
[stg.Ctot_sand[c] for c in sand_range()]
),
np.nanmax(
[
stg.SSC_sand[data_id][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]
] for i in sand_range()
]
)
]
) + 1
],
ls="solid", linewidth=1, color="k"
)
# --- Display sample label on plot ---
for i in sand_range():
self.axis_measured_vs_inverted_sand.text(
stg.Ctot_sand[i],
stg.SSC_sand[data_id][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]
],
stg.sample_sand[i][0],
fontstyle="normal", fontweight="light", fontsize=10
)
self.axis_measured_vs_inverted_sand\
.set_xlabel("Measured SSC sand (g/L)")
self.axis_measured_vs_inverted_sand\
.set_ylabel("Inverted SSC sand (g/L)")
self.figure_measured_vs_inverted_sand.canvas.draw_idle()
def save_result(self):
if self.combobox_acoustic_data_choice.count() <= 0:
return
file_type = {
"CSV Files (*.csv)": (self.save_result_in_csv_file, ".csv"),
"Excel Files (*.xlsx)": (self.save_result_in_excel_file, ".xlsx"),
# "LibreOffice Calc Files (*.ods)": (self.save_result_in_excel_file, ".ods"),
}
name, type_ext = QFileDialog.getSaveFileName(
caption="Save As - Inversion results",
directory="",
filter=";;".join(file_type),
options=QFileDialog.DontUseNativeDialog
)
if name == '':
return
dirname = os.path.dirname(name)
filename = os.path.basename(name)
_, ext = os.path.splitext(filename)
os.chdir(dirname)
fun, t_ext = file_type[type_ext]
if t_ext not in filename:
filename += t_ext
t = time.time()
logger.info(f"Export results to {os.path.join(dirname, filename)}")
fun(dirname, filename)
logger.info(f"... export done in {time.time() - t:.4f} sec")
def save_result_in_excel_file(self, dirname, filename):
if ".ods" in filename:
engine = "odf"
else:
engine = "xlsxwriter"
with pd.ExcelWriter(
os.path.join(dirname, filename),
engine=engine
) as writer:
time_data = stg.t2D_interp
depth_data = stg.r2D_interp
for k in range(self.combobox_acoustic_data_choice.count()):
dataset_name = self.combobox_acoustic_data_choice.itemText(k)
time_shape = time_data[k].shape[1]
depth_shape = depth_data[k].shape[0]
t = np.repeat( time_data[k][0,:], depth_shape )
r = np.zeros( time_shape * depth_shape )
for i in range(time_shape):
for j in range(depth_shape):
r_id = i * depth_shape + j
r[r_id] = depth_data[k][j, 0]
# If no SSC has been computed, fill
if stg.SSC_fine[k].shape == (0,):
stg.SSC_fine[k] = np.zeros(r.shape[0])
if stg.SSC_sand[k].shape == (0,):
stg.SSC_sand[k] = np.zeros(r.shape[0])
# Flatten the fine and sand SSC arrays in a column-major order (i.e., "the first index
# runs the fastest"):
ssc_fine = np.reshape( stg.SSC_fine[k], r.shape[0], 'F' ).tolist()
ssc_sand = np.reshape( stg.SSC_sand[k], r.shape[0], 'F' ).tolist()
result = pd.DataFrame(
{
'Time (sec)': t.tolist(),
'Depth (m)': r.tolist(),
'SSC_fine (g/L)': ssc_fine,
'SSC_sand (g/L)': ssc_sand,
}
)
gc.collect() # Force garbage collection
result.to_excel( writer, index=False, na_rep='NA', engine=engine,
sheet_name=dataset_name )
def save_result_in_csv_file(self, dirname, filename):
'''
Comments by Bjarne VINCENT
This function exports the acoustic inversion results to a separate .csv
file. In AcouSed, the SSC fields computed for each dataset are stored
as 2D arrays of size M*P, where 'M' is the number of vertical positions and
'P' is the number of time stamps. The idea is to flatten these arrays (i.e.,
convert them to 1D arrays) in order to export the data as a table.
'''
# Define & initialize the lists of 1D arrays to be written to the .csv
# file. Each of these lists shall form one column in the written .csv
# file. Each list is of length N, where 'N' stands for the number of
# datasets loaded into AcouSed:
d_id = [] #List of the datasets' ID (integers ranging from 0 to N-1)
t = [] #List of time stamps (s)
r = [] #List of vertical positions (m)
ssc_fine = [] #List of flattened fine SSC arrays (g/L)
ssc_sand = [] #List of flattened sand SSC arrays (g/L)
time_data = stg.t2D_interp
depth_data = stg.r2D_interp
# Loop over all datasets loaded into AcouSed:
for k in range(self.combobox_acoustic_data_choice.count()):
'''
Comments by Bjarne VINCENT
Array-flattening convention: the index spanning the number of vertical
positions runs the fastest, followed by the index spanning the number of
time stamps, followed by the index spanning the number of datasets.
Example of file output:
data_id | time (s) | Depth(m)
0 0.0 0.1
0 0.0 0.2
. . .
. . .
. . .
0 0.0 1.0
0 0.1 0.1
0 0.1 0.2
. . .
. . .
. . .
0 5.0 1.0
1 0.0 0.1
1 0.0 0.2
. . .
. . .
. . .
etc.
'''
# Form the 1D arrays of time stamps and vertical positions
# for the k-th dataset:
time_shape = time_data[k].shape[1] #Number of time stamps
depth_shape = depth_data[k].shape[0] #Number of vertical coordinates
d_id += np.repeat(k, depth_shape * time_shape).tolist() #Flattened array of the current dataset's index
tmp_t = np.repeat(time_data[k][0,:], depth_shape) #Flattened array of time stamps
tmp_r = np.zeros(depth_shape * time_shape) #Initialise the flattened array of vertical positions
# Fill the flattened array of vertical positions:
for i in range(time_shape):
for j in range(depth_shape):
r_id = i * depth_shape + j
tmp_r[r_id] = depth_data[k][j, 0]
# Add the flattened arrays of time stamps and vertical positions to their respective
# lists:
t += tmp_t.tolist()
r += tmp_r.tolist()
# If no fine or sand SSC concentrations have been computed, create empty 2D arrays:
if stg.SSC_fine[k].shape == (0,):
stg.SSC_fine[k] = np.zeros(tmp_r.shape[0])
if stg.SSC_sand[k].shape == (0,):
stg.SSC_sand[k] = np.zeros(tmp_r.shape[0])
# Flatten the fine and sand SSC arrays in a column-major order (i.e., "the first index
# runs the fastest"):
ssc_fine += np.reshape( stg.SSC_fine[k], tmp_r.shape[0], 'F' ).tolist()
ssc_sand += np.reshape( stg.SSC_sand[k], tmp_r.shape[0], 'F' ).tolist()
# Finally, create a Pandas 'DataFrame' with all lists, and write that DataFrame to a .csv file:
results = pd.DataFrame(
{
'acoustic data': d_id,
'Time (sec)': t,
'Depth (m)': r,
'SSC_fine (g/L)': ssc_fine,
'SSC_sand (g/L)': ssc_sand,
}
)
results.to_csv(
os.path.join(dirname, filename),
index=False
)