# ============================================================================== # # acoustic_data_tab.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 . # # by Brahim MOUDJED # # ============================================================================== # # -*- coding: utf-8 -*- import os import logging from scipy.stats import linregress import numpy as np import pandas as pd from math import isinf 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, QGridLayout, QLabel, QPushButton, QSlider, QLineEdit, QFileDialog, QMessageBox, QFrame ) from PyQt5.QtCore import Qt, QPropertyAnimation, QSize from PyQt5.QtGui import QIcon, QPixmap, QFont import settings as stg from View.checkable_combobox import CheckableComboBox from Model.acoustic_inversion_method_high_concentration import AcousticInversionMethodHighConcentration from tools import trace logger = logging.getLogger("acoused") class SedimentCalibrationTab(QWidget): ''' This class generates the Sediment Calibration Tab ''' def __init__(self, widget_tab): super().__init__() self._widget_tab = widget_tab self.inv_hc = AcousticInversionMethodHighConcentration() self._setup_icons() self._setup_attrs() self._setup_widgets() 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")) self.icon_approved = QIcon(self._path_icon("approved.png")) self.icon_no_approved = QIcon(self._path_icon("no_approved.png")) def _setup_attrs(self): self.fig_BS = None self.fig_Mfine = None self.fig_FCB = None def _setup_widgets(self): self.verticalLayoutMain = QVBoxLayout(self._widget_tab) # 1O units is 100% , 1 units is 10% 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.groupbox_acoustic_data = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_data, 6) self.groupbox_Mfine_profile = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_Mfine_profile, 4) self._setup_widgets_acoustic_data() self._setup_widgets_concentration() self._setup_widgets_calibration() self._setup_widgets_fcb() self._setup_connections() def _setup_widgets_acoustic_data(self): self.groupbox_acoustic_data.setTitle( "Step 1 : acoustic and sample data choice" ) self.horizontalLayout_groupbox_acoustic_data = QHBoxLayout(self.groupbox_acoustic_data) self.groupbox_data_choice = QGroupBox() self.horizontalLayout_groupbox_acoustic_data.addWidget(self.groupbox_data_choice, 3) self.groupbox_data_plot = QGroupBox() self.horizontalLayout_groupbox_acoustic_data.addWidget(self.groupbox_data_plot, 7) # --- Groupbox data choice --- self.verticalLayout_groupbox_data_choice = QVBoxLayout(self.groupbox_data_choice) self._setup_widgets_acoustic_data_1() self._setup_widgets_acoustic_data_2() self._setup_widgets_acoustic_data_3() self._setup_widgets_acoustic_data_plot() def _setup_widgets_acoustic_data_1(self): self.groupbox_acoustic_recording = QGroupBox() self.groupbox_acoustic_recording.setTitle("➊") self.verticalLayout_groupbox_data_choice.addWidget( self.groupbox_acoustic_recording ) self.gridLayout_groupbox_acoustic_recording = QGridLayout( self.groupbox_acoustic_recording ) self.pushbutton_update_acoustic_file = QPushButton() self.pushbutton_update_acoustic_file.setIcon(self.icon_update) self.gridLayout_groupbox_acoustic_recording.addWidget( self.pushbutton_update_acoustic_file, 0, 0, 1, 2 ) self.label_acoustic_data_choice = QLabel() self.label_acoustic_data_choice.setText("Acoustic data") self.gridLayout_groupbox_acoustic_recording.addWidget( self.label_acoustic_data_choice, 1, 0, 1, 1 ) self.combobox_acoustic_data_choice = QComboBox() self.gridLayout_groupbox_acoustic_recording.addWidget( self.combobox_acoustic_data_choice, 1, 1, 1, 1 ) def _setup_widgets_acoustic_data_2(self): self.groupbox_frequency = QGroupBox() self.groupbox_frequency.setTitle("➋") self.verticalLayout_groupbox_data_choice.addWidget( self.groupbox_frequency ) self.gridLayout_groupbox_frequency = QGridLayout( self.groupbox_frequency ) self.label_freq1_choice = QLabel() self.label_freq1_choice.setText("Frequency 1") self.gridLayout_groupbox_frequency.addWidget( self.label_freq1_choice, 0, 0, 1, 1 ) self.combobox_freq1 = QComboBox() self.gridLayout_groupbox_frequency.addWidget( self.combobox_freq1, 0, 1, 1, 1 ) self.label_freq2_choice = QLabel() self.label_freq2_choice.setText("Frequency 2") self.gridLayout_groupbox_frequency.addWidget( self.label_freq2_choice, 1, 0, 1, 1 ) self.combobox_freq2 = QComboBox() self.gridLayout_groupbox_frequency.addWidget( self.combobox_freq2, 1, 1, 1, 1 ) def _setup_widgets_acoustic_data_3(self): self.groupbox_sample = QGroupBox() self.groupbox_sample.setTitle("➌") self.verticalLayout_groupbox_data_choice.addWidget( self.groupbox_sample ) self.gridLayout_groupbox_sample = QGridLayout( self.groupbox_sample ) self.label_fine_profile = QLabel() self.label_fine_profile.setText("Fine profile") self.gridLayout_groupbox_sample.addWidget( self.label_fine_profile, 0, 0, 1, 1 ) self.combobox_fine_sample_choice = CheckableComboBox() self.gridLayout_groupbox_sample.addWidget( self.combobox_fine_sample_choice, 0, 1, 1, 1 ) self.label_sand_target = QLabel() self.label_sand_target.setText("Sand target") self.gridLayout_groupbox_sample.addWidget( self.label_sand_target, 1, 0, 1, 1 ) self.combobox_sand_sample_choice = QComboBox() self.gridLayout_groupbox_sample.addWidget( self.combobox_sand_sample_choice, 1, 1, 1, 1 ) self.pushbutton_plot_sample = QPushButton() self.pushbutton_plot_sample.setText("Plot sample") self.gridLayout_groupbox_sample.addWidget( self.pushbutton_plot_sample, 2, 0, 1, 2 ) def _setup_widgets_acoustic_data_plot(self): self.verticalLayout_groupbox_data_plot = QVBoxLayout( self.groupbox_data_plot ) self.canvas_BS = FigureCanvas() self.toolbar_BS = NavigationToolBar(self.canvas_BS, self) # self.verticalLayout_groupbox_acoustic_data.addWidget(self.canvas_BS) self.verticalLayout_groupbox_data_plot.addWidget(self.toolbar_BS) self.verticalLayout_groupbox_data_plot.addWidget(self.canvas_BS) def _setup_widgets_concentration(self): self.groupbox_Mfine_profile.setTitle( "Step 2 : profile of the fine sediment concentration" ) self.horizontalLayout_groupbox_Mfine_profile = QHBoxLayout( self.groupbox_Mfine_profile ) self.groupbox_interpolate_info = QGroupBox() self.horizontalLayout_groupbox_Mfine_profile.addWidget( self.groupbox_interpolate_info, 4 ) self.groupbox_interpolate_plot = QGroupBox() self.horizontalLayout_groupbox_Mfine_profile.addWidget( self.groupbox_interpolate_plot, 6 ) self._setup_widgets_concentration_interpolate() self._setup_widgets_concentration_interpolate_plot() def _setup_widgets_concentration_interpolate(self): self.gridLayout_groupbox_interpolate_info = QGridLayout( self.groupbox_interpolate_info ) self.pushbutton_interpolate_Mfine_profile = QPushButton() self.pushbutton_interpolate_Mfine_profile.setText("Interpolate") self.gridLayout_groupbox_interpolate_info.addWidget( self.pushbutton_interpolate_Mfine_profile, 0, 0, 1, 4, Qt.AlignCenter ) self.label_sample_fine = QLabel() self.label_sample_fine.setText("Sample") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_sample_fine, 1, 0, 1, 1, Qt.AlignCenter ) self.label_depth_fine = QLabel() self.label_depth_fine.setText("Depth (m)") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_depth_fine, 1, 1, 1, 1, Qt.AlignCenter ) self.label_time_fine = QLabel() self.label_time_fine.setText("time") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_time_fine, 1, 2, 1, 1, Qt.AlignCenter ) self.label_concentration_fine = QLabel() self.label_concentration_fine.setText("Cfine (g/L)") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_concentration_fine, 1, 3, 1, 1, Qt.AlignCenter ) self.double_horizontal_line = QFrame() self.double_horizontal_line.setFrameShape(QFrame.HLine) self.double_horizontal_line.setFrameShadow(QFrame.Sunken) self.double_horizontal_line.setLineWidth(1) self.double_horizontal_line.setMidLineWidth(3) self.gridLayout_groupbox_interpolate_info.addWidget( self.double_horizontal_line, 4, 0, 1, 4, Qt.AlignCenter ) self.label_sample_sand = QLabel() self.label_sample_sand.setText("Sample") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_sample_sand, 5, 0, 1, 1, Qt.AlignCenter ) self.label_depth_sand = QLabel() self.label_depth_sand.setText("Depth (m)") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_depth_sand, 5, 1, 1, 1, Qt.AlignCenter ) self.label_time_sand = QLabel() self.label_time_sand.setText("time") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_time_sand, 5, 2, 1, 1, Qt.AlignCenter ) self.label_concentration_sand = QLabel() self.label_concentration_sand.setText("Csand (g/L)") self.gridLayout_groupbox_interpolate_info.addWidget( self.label_concentration_sand, 5, 3, 1, 1, Qt.AlignCenter ) def _setup_widgets_concentration_interpolate_plot(self): self.verticalLayout_groupbox_interpolate_plot = QVBoxLayout( self.groupbox_interpolate_plot ) self.canvas_Mfine = FigureCanvas() self.toolbar_Mfine = NavigationToolBar(self.canvas_Mfine, self) self.verticalLayout_groupbox_interpolate_plot\ .addWidget(self.toolbar_Mfine) self.verticalLayout_groupbox_interpolate_plot\ .addWidget(self.canvas_Mfine) def _setup_widgets_calibration(self): self.groupbox_sediment_calibration = QGroupBox() self.horizontalLayoutBottom.addWidget(self.groupbox_sediment_calibration, 4) self.groupbox_FCB = QGroupBox() self.horizontalLayoutBottom.addWidget(self.groupbox_FCB, 6) # +++++++++++++++++++++++++++++++++++++ # +++ Groupbox sediment calibration +++ self.groupbox_sediment_calibration\ .setTitle("Step 3 : Compute Calibration") self.verticalLayout_groupbox_sediment_calibration = QVBoxLayout( self.groupbox_sediment_calibration ) self.horizontalLayout_groupboxes_Import_Compute_Calibration = QHBoxLayout() self.verticalLayout_groupbox_sediment_calibration.addLayout( self.horizontalLayout_groupboxes_Import_Compute_Calibration ) self._setup_widgets_calibration_import_file() self._setup_widgets_calibration_compute() self._setup_widgets_calibration_parameters() def _setup_widgets_calibration_import_file(self): self.groupbox_sediment_calibration_import = QGroupBox() self.groupbox_sediment_calibration_import.setTitle( "Import sediment calibration file" ) self.groupbox_sediment_calibration_import.setCheckable(True) self.groupbox_sediment_calibration_import.setChecked(True) self.horizontalLayout_groupboxes_Import_Compute_Calibration.addWidget( self.groupbox_sediment_calibration_import ) self.gridLayout_groupbox_sediment_calibration_import = QGridLayout( self.groupbox_sediment_calibration_import ) self.pushbutton_import_calibration = QPushButton() self.pushbutton_import_calibration.setText('Import calibration') self.gridLayout_groupbox_sediment_calibration_import.addWidget( self.pushbutton_import_calibration, 0, 0, 1, 1 ) self.lineEdit_import_calibration = QLineEdit() self.gridLayout_groupbox_sediment_calibration_import.addWidget( self.lineEdit_import_calibration, 0, 1, 1, 2 ) def _setup_widgets_calibration_compute(self): self.groupbox_sediment_calibration_compute = QGroupBox() self.groupbox_sediment_calibration_compute.setTitle( "Compute sediment calibration" ) self.groupbox_sediment_calibration_compute.setCheckable(True) self.groupbox_sediment_calibration_compute.setChecked(False) self.horizontalLayout_groupboxes_Import_Compute_Calibration\ .addWidget(self.groupbox_sediment_calibration_compute) self.gridLayout_groupbox_sediment_calibration_compute = QGridLayout( self.groupbox_sediment_calibration_compute ) self.pushbutton_compute_calibration = QPushButton() self.pushbutton_compute_calibration.setText( "Compute Calibration" ) self.pushbutton_compute_calibration.setToolTip( "Calibration is computed at abscissa 'sand target'" ) self.gridLayout_groupbox_sediment_calibration_compute\ .addWidget(self.pushbutton_compute_calibration, 0, 0, 1, 3) def _setup_widgets_calibration_parameters(self): self.groupbox_sediment_calibration_parameter = QGroupBox() self.gridLayout_groupbox_sediment_calibration_parameter = \ QGridLayout(self.groupbox_sediment_calibration_parameter) self.verticalLayout_groupbox_sediment_calibration\ .addWidget(self.groupbox_sediment_calibration_parameter) self.label_temperature = QLabel() self.label_temperature.setText("T = 0.00 °C") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_temperature, 0, 0, 1, 1) self.label_freq1 = QLabel("Frequency 1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_freq1, 1, 1, 1, 2, Qt.AlignCenter) self.label_freq2 = QLabel("Frequency 2") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_freq2, 1, 3, 1, 2, Qt.AlignCenter) self.label_kt = QLabel() self.label_kt.setText("kt") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_kt, 2, 0, 1, 1, Qt.AlignCenter) self.label_kt_freq1 = QLabel() self.label_kt_freq1.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_kt_freq1, 2, 1, 1, 1, Qt.AlignRight) self.label_kt_freq1_unit = QLabel() self.label_kt_freq1_unit.setText("V.m1.5") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_kt_freq1_unit, 2, 2, 1, 1, Qt.AlignLeft) self.label_kt_freq2 = QLabel() self.label_kt_freq2.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_kt_freq2, 2, 3, 1, 1, Qt.AlignRight) self.label_kt_freq2_unit = QLabel() self.label_kt_freq2_unit.setText("V.m1.5") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_kt_freq2_unit, 2, 4, 1, 1, Qt.AlignLeft) self.horizontalLine = QFrame() self.horizontalLine.setFrameShape(QFrame.HLine) self.horizontalLine.setFrameShadow(QFrame.Sunken) self.horizontalLine.setLineWidth(1) self.horizontalLine.setMidLineWidth(0) self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.horizontalLine, 3, 0, 1, 6) self.label_ks = QLabel() self.label_ks.setText("ks") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_ks, 4, 0, 1, 1, Qt.AlignCenter) self.lineEdit_ks_freq1 = QLineEdit() self.lineEdit_ks_freq1.setMaximumWidth(100) self.lineEdit_ks_freq1.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_ks_freq1, 4, 1, 1, 1) self.label_ks_freq1_unit = QLabel() self.label_ks_freq1_unit.setText("m.kg-0.5") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_ks_freq1_unit, 4, 2, 1, 1, Qt.AlignLeft) self.lineEdit_ks_freq2 = QLineEdit() self.lineEdit_ks_freq2.setMaximumWidth(100) self.lineEdit_ks_freq2.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_ks_freq2, 4, 3, 1, 1) self.label_ks_freq2_unit = QLabel() self.label_ks_freq2_unit.setText("m.kg-0.5") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_ks_freq2_unit, 4, 4, 1, 1, Qt.AlignLeft) self.label_sv = QLabel() self.label_sv.setText("sv") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_sv, 5, 0, 1, 1, Qt.AlignCenter) self.lineEdit_sv_freq1 = QLineEdit() self.lineEdit_sv_freq1.setMaximumWidth(100) self.lineEdit_sv_freq1.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_sv_freq1, 5, 1, 1, 1) self.label_sv_freq1_unit = QLabel() self.label_sv_freq1_unit.setText("m-1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_sv_freq1_unit, 5, 2, 1, 1) self.lineEdit_sv_freq2 = QLineEdit() self.lineEdit_sv_freq2.setMaximumWidth(100) self.lineEdit_sv_freq2.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_sv_freq2, 5, 3, 1, 1) self.label_sv_freq2_unit = QLabel() self.label_sv_freq2_unit.setText("m-1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_sv_freq2_unit, 5, 4, 1, 1) self.label_X = QLabel() self.label_X.setText("X") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_X, 6, 0, 1, 1, Qt.AlignCenter) self.lineEdit_X = QLineEdit() self.lineEdit_X.setMaximumWidth(100) self.lineEdit_X.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_X, 6, 2, 1, 1, Qt.AlignCenter) self.label_alphas = QLabel() self.label_alphas.setText("\u03B1s") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_alphas, 7, 0, 1, 1, Qt.AlignCenter) self.lineEdit_alphas_freq1 = QLineEdit() self.lineEdit_alphas_freq1.setMaximumWidth(100) self.lineEdit_alphas_freq1.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_alphas_freq1, 7, 1, 1, 1) self.label_alphas_freq1_unit = QLabel() self.label_alphas_freq1_unit.setText("m-1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_alphas_freq1_unit, 7, 2, 1, 1, Qt.AlignLeft) self.lineEdit_alphas_freq2 = QLineEdit() self.lineEdit_alphas_freq2.setMaximumWidth(100) self.lineEdit_alphas_freq2.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_alphas_freq2, 7, 3, 1, 1) self.label_alphas_freq2_unit = QLabel() self.label_alphas_freq2_unit.setText("m-1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_alphas_freq2_unit, 7, 4, 1, 1, Qt.AlignLeft) self.label_zeta = QLabel() self.label_zeta.setText("\u03B6") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_zeta, 8, 0, 1, 1, Qt.AlignCenter) self.lineEdit_zeta_freq1 = QLineEdit() self.lineEdit_zeta_freq1.setMaximumWidth(100) self.lineEdit_zeta_freq1.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_zeta_freq1, 8, 1, 1, 1) self.label_zeta_freq1_unit = QLabel() self.label_zeta_freq1_unit.setText("m-1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_zeta_freq1_unit, 8, 2, 1, 1, Qt.AlignLeft) self.lineEdit_zeta_freq2 = QLineEdit() self.lineEdit_zeta_freq2.setMaximumWidth(100) self.lineEdit_zeta_freq2.setText("0.00") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.lineEdit_zeta_freq2, 8, 3, 1, 1) self.label_zeta_freq2_unit = QLabel() self.label_zeta_freq2_unit.setText("m-1") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.label_zeta_freq2_unit, 8, 4, 1, 1, Qt.AlignLeft) self.pushbutton_save_calibration = QPushButton() self.pushbutton_save_calibration.setText("Save calibration") self.gridLayout_groupbox_sediment_calibration_parameter\ .addWidget(self.pushbutton_save_calibration,9, 5, 1, 1) def _setup_widgets_fcb(self): self.groupbox_FCB.setTitle( "Step 3 (for information) : Fluid Corrected Backscatter" ) self.horizontalLayout_groupbox_FCB = QHBoxLayout(self.groupbox_FCB) self.groupbox_FCB.setCheckable(True) self.groupbox_FCB.setChecked(False) self._setup_widgets_fcb_options() self._setup_widgets_fcb_plot() def _setup_widgets_fcb_options(self): self.groupbox_FCB_option = QGroupBox() self.verticalLayout_groupbox_FCB_option = QVBoxLayout(self.groupbox_FCB_option) self.horizontalLayout_groupbox_FCB\ .addWidget(self.groupbox_FCB_option, 4) self.groupbox_FCB_text = QGroupBox() self.verticalLayout_groupbox_FCB_text = QVBoxLayout(self.groupbox_FCB_text) self.verticalLayout_groupbox_FCB_option\ .addWidget(self.groupbox_FCB_text) self.label_FCB_explanation = QLabel() self.label_FCB_explanation.setText( "When fine sediments concentration is constant \n " "and effect on sound attenuation on sand is negligible, \n " "this sediment attenuation alphas can be compared \n " "to the obtained by the sediment calibration computation." ) self.verticalLayout_groupbox_FCB_text\ .addWidget(self.label_FCB_explanation) self.gridLayout_groupbox_FCB_text_alphas = QGridLayout() self.verticalLayout_groupbox_FCB_text\ .addLayout(self.gridLayout_groupbox_FCB_text_alphas) self.label_FCB_explanation_alphas_positive_icon = QLabel() self.label_FCB_explanation_alphas_positive_icon.setPixmap( QPixmap(self._path_icon("approved.png")).scaledToHeight( 16, Qt.SmoothTransformation ) ) self.gridLayout_groupbox_FCB_text_alphas.addWidget( self.label_FCB_explanation_alphas_positive_icon, 0, 0, 1, 1, Qt.AlignCenter ) self.label_FCB_explanation_alphas_positive = QLabel() self.label_FCB_explanation_alphas_positive.setText( "αs FCB > 0 : comparison with calibration" ) self.label_FCB_explanation_alphas_positive.setFont(QFont('DejaVu Sans', 12)) self.gridLayout_groupbox_FCB_text_alphas.addWidget( self.label_FCB_explanation_alphas_positive, 0, 1, 1, 1, Qt.AlignLeft ) self.label_FCB_explanation_alphas_negative_icon = QLabel() self.label_FCB_explanation_alphas_negative_icon.setPixmap( QPixmap(self._path_icon("no_approved.png")).scaledToHeight( 16, Qt.SmoothTransformation ) ) self.gridLayout_groupbox_FCB_text_alphas.addWidget( self.label_FCB_explanation_alphas_negative_icon, 1, 0, 1, 1, Qt.AlignCenter ) self.label_FCB_explanation_alphas_negative = QLabel() self.label_FCB_explanation_alphas_negative.setText( "αs FCB < 0 : do not compare with calibration" ) self.label_FCB_explanation_alphas_negative.setFont(QFont('DejaVu Sans', 12)) self.gridLayout_groupbox_FCB_text_alphas.addWidget( self.label_FCB_explanation_alphas_negative, 1, 1, 1, 1, Qt.AlignLeft ) self.groupbox_FCB_compute = QGroupBox() self.gridLayout_groupbox_FCB_compute = QGridLayout(self.groupbox_FCB_compute) self.verticalLayout_groupbox_FCB_option.addWidget(self.groupbox_FCB_compute) self.label_frequency_FCB = QLabel() self.label_frequency_FCB.setText("Frequency ") self.gridLayout_groupbox_FCB_compute.addWidget( self.label_frequency_FCB, 0, 0, 1, 3, Qt.AlignCenter ) self.combobox_frequency_FCB = QComboBox() self.gridLayout_groupbox_FCB_compute.addWidget( self.combobox_frequency_FCB, 0, 3, 1, 3, Qt.AlignCenter ) self.label_from = QLabel() self.label_from.setText("From ") self.gridLayout_groupbox_FCB_compute.addWidget( self.label_from, 1, 0, 1, 1, Qt.AlignCenter ) self.lineEdit_FCB_from = QLineEdit() self.lineEdit_FCB_from.setMaximumWidth(100) self.gridLayout_groupbox_FCB_compute.addWidget( self.lineEdit_FCB_from, 1, 1, 1, 1, Qt.AlignCenter ) self.label_FCB_from_unit = QLabel() self.label_FCB_from_unit.setText("m") self.gridLayout_groupbox_FCB_compute.addWidget( self.label_FCB_from_unit, 1, 2, 1, 1, Qt.AlignLeft ) self.label_to = QLabel() self.label_to.setText("to ") self.gridLayout_groupbox_FCB_compute.addWidget( self.label_to, 1, 3, 1, 1, Qt.AlignCenter ) self.lineEdit_FCB_to = QLineEdit() self.lineEdit_FCB_to.setMaximumWidth(100) self.gridLayout_groupbox_FCB_compute.addWidget( self.lineEdit_FCB_to, 1, 4, 1, 1, Qt.AlignCenter ) self.label_FCB_to_unit = QLabel() self.label_FCB_to_unit.setText("m") self.gridLayout_groupbox_FCB_compute.addWidget( self.label_FCB_to_unit, 1, 5, 1, 1, Qt.AlignLeft ) self.pushbutton_FCB_fit = QPushButton() self.pushbutton_FCB_fit.setText("Compute and Plot Linear regression") self.gridLayout_groupbox_FCB_compute.addWidget( self.pushbutton_FCB_fit, 2, 0, 1, 3, Qt.AlignCenter ) self.label_alphaS_FCB = QLabel() self.label_alphaS_FCB.setText( "αs = " + "0.0" + "dB/m" ) self.label_alphaS_FCB.setFont(QFont("DejaVu Sans", 14, QFont.Normal)) self.gridLayout_groupbox_FCB_compute.addWidget( self.label_alphaS_FCB, 2, 4, 1, 2 ) def _setup_widgets_fcb_plot(self): self.verticalLayout_groupbox_FCB_plot_and_slider_FCB = QVBoxLayout() self.horizontalLayout_groupbox_FCB.addLayout( self.verticalLayout_groupbox_FCB_plot_and_slider_FCB, 8 ) self.groupbox_FCB_plot = QGroupBox() self.verticalLayout_groupbox_FCB_plot = QVBoxLayout(self.groupbox_FCB_plot) self.verticalLayout_groupbox_FCB_plot_and_slider_FCB\ .addWidget(self.groupbox_FCB_plot) self.canvas_FCB = FigureCanvas() self.toolbar_FCB = NavigationToolBar(self.canvas_FCB, self) self.verticalLayout_groupbox_FCB_plot.addWidget(self.toolbar_FCB) self.verticalLayout_groupbox_FCB_plot.addWidget(self.canvas_FCB) self.horizontalLayout_slider_FCB = QHBoxLayout() self.verticalLayout_groupbox_FCB_plot_and_slider_FCB\ .addLayout(self.horizontalLayout_slider_FCB) self.pushbutton_left_to_begin_FCB = QPushButton() self.pushbutton_left_to_begin_FCB.setIcon( self.icon_triangle_left_to_begin ) self.horizontalLayout_slider_FCB.addWidget( self.pushbutton_left_to_begin_FCB ) self.pushbutton_left_FCB = QPushButton() self.pushbutton_left_FCB.setIcon(self.icon_triangle_left) self.horizontalLayout_slider_FCB.addWidget(self.pushbutton_left_FCB) self.lineEdit_slider_FCB = QLineEdit() self.lineEdit_slider_FCB.setText("1") self.lineEdit_slider_FCB.setFixedWidth(50) self.horizontalLayout_slider_FCB.addWidget(self.lineEdit_slider_FCB) self.pushbutton_right_FCB = QPushButton() self.pushbutton_right_FCB.setIcon(self.icon_triangle_right) self.horizontalLayout_slider_FCB.addWidget(self.pushbutton_right_FCB) self.pushbutton_right_to_end_FCB = QPushButton() self.pushbutton_right_to_end_FCB.setIcon( self.icon_triangle_right_to_end ) self.horizontalLayout_slider_FCB.addWidget( self.pushbutton_right_to_end_FCB ) self.slider_FCB = QSlider() self.horizontalLayout_slider_FCB.addWidget(self.slider_FCB) self.slider_FCB.setOrientation(Qt.Horizontal) self.slider_FCB.setCursor(Qt.OpenHandCursor) self.slider_FCB.setMinimum(1) self.slider_FCB.setMaximum(10) self.slider_FCB.setTickInterval(1) self.slider_FCB.setValue(1) def _setup_connections(self): self.pushbutton_update_acoustic_file\ .clicked.connect( self.function_pushbutton_update_acoustic_file ) self.pushbutton_plot_sample\ .clicked.connect( self.function_pushbutton_plot_sample ) self.pushbutton_interpolate_Mfine_profile\ .clicked.connect(self.interpolate_Mfine_profile) self.groupbox_sediment_calibration_import\ .toggled.connect(self.groupbox_calibration_import_toggle) self.groupbox_sediment_calibration_import\ .toggled.connect(self.groupbox_calibration_import_size_change) self.pushbutton_import_calibration\ .clicked.connect(self.import_calibration_file) self.groupbox_sediment_calibration_compute\ .toggled.connect(self.groupbox_calibration_compute_toggle) self.groupbox_sediment_calibration_compute\ .toggled.connect(self.groupbox_calibration_compute_size_change) self.pushbutton_compute_calibration\ .clicked.connect(self.function_pushbutton_compute_calibration) self.pushbutton_save_calibration\ .clicked.connect(self.save_calibration) self.pushbutton_left_to_begin_FCB\ .clicked.connect(self.slider_profile_number_to_begin_FCB) self.pushbutton_left_FCB\ .clicked.connect(self.slider_profile_number_to_left_FCB) self.pushbutton_right_FCB\ .clicked.connect(self.slider_profile_number_to_right_FCB) self.pushbutton_right_to_end_FCB\ .clicked.connect(self.slider_profile_number_to_end_FCB) self.lineEdit_slider_FCB\ .returnPressed.connect(self.profile_number_on_lineEdit_FCB) self.slider_FCB\ .valueChanged.connect(self.update_lineEdit_by_moving_slider_FCB) self.pushbutton_FCB_fit\ .clicked.connect( self.fit_FCB_profile_with_linear_regression_and_compute_alphaS ) def full_update(self): logger.debug(f"{__name__}: Update") self.blockSignals(True) self.function_pushbutton_update_acoustic_file() self._update_calibration_parameters() self._update_calibration() self.function_pushbutton_plot_sample() self.compute_depth_2D() self.compute_kt2D_kt3D() self.compute_J_cross_section() self.blockSignals(False) def _update_calibration_parameters(self): if stg.calib_acoustic_data == -1: return self.combobox_acoustic_data_choice.blockSignals(True) self.combobox_freq1.blockSignals(True) self.combobox_freq2.blockSignals(True) self.combobox_fine_sample_choice.blockSignals(True) self.combobox_sand_sample_choice.blockSignals(True) self.combobox_acoustic_data_choice\ .setCurrentIndex(stg.calib_acoustic_data) self.combobox_freq1.setCurrentIndex(stg.calib_freq_1) self.combobox_freq2.setCurrentIndex(stg.calib_freq_2) self.combobox_fine_sample_choice\ .setCurrentIndexes(stg.calib_fine_profiles) self.combobox_sand_sample_choice\ .setCurrentIndex(stg.calib_sand_target) self.update_label_freq1_for_calibration() self.update_label_freq2_for_calibration() self.update_label_kt_value_for_calibration() self.combobox_sand_sample_choice.blockSignals(False) self.combobox_fine_sample_choice.blockSignals(False) self.combobox_freq2.blockSignals(False) self.combobox_freq1.blockSignals(False) self.combobox_acoustic_data_choice.blockSignals(False) def _update_calibration(self): self.groupbox_sediment_calibration_compute.blockSignals(True) if stg.filename_calibration_file == "": self.groupbox_sediment_calibration_compute\ .setChecked(True) self.groupbox_sediment_calibration_import\ .setChecked(False) self.lineEdit_ks_freq1.setText(f"{stg.ks[0]:.5f}") self.lineEdit_ks_freq2.setText(f"{stg.ks[1]:.5f}") self.lineEdit_sv_freq1.setText(f"{stg.sv[0]:.5f}") self.lineEdit_sv_freq2.setText(f"{stg.sv[1]:.5f}") self.lineEdit_X.setText(f"{stg.X_exponent[0]:.2f}") self.lineEdit_alphas_freq1.setText(f"{stg.alpha_s[0]:.5f}") self.lineEdit_alphas_freq2.setText(f"{stg.alpha_s[1]:.5f}") self.lineEdit_zeta_freq1.setText(f"{stg.zeta[0]:.5f}") self.lineEdit_zeta_freq2.setText(f"{stg.zeta[1]:.5f}") self.groupbox_sediment_calibration_compute.blockSignals(False) def function_pushbutton_update_acoustic_file(self): if len(stg.data_preprocessed) == 0: return if (len(stg.sample_fine) == 0 or len(stg.sample_sand) == 0): return self.update_acoustic_data() self.compute_depth_2D() def update_acoustic_data(self): self.combobox_acoustic_data_choice.clear() self.combobox_acoustic_data_choice.addItems(stg.data_preprocessed) self.combobox_acoustic_data_choice\ .currentIndexChanged.connect(self.plot_acoustic_recording) self.combobox_freq1.clear() self.combobox_freq1.addItems( stg.freq_text[self.combobox_acoustic_data_choice.currentIndex()] ) self.combobox_freq1.currentIndexChanged\ .connect(self.update_label_freq1_for_calibration) self.combobox_freq1.currentIndexChanged\ .connect(self.update_label_kt_value_for_calibration) self.combobox_freq2.clear() self.combobox_freq2.addItems( stg.freq_text[self.combobox_acoustic_data_choice.currentIndex()] ) self.combobox_freq2.currentIndexChanged\ .connect(self.update_label_freq2_for_calibration) self.combobox_freq2.currentIndexChanged\ .connect(self.update_label_kt_value_for_calibration) self.combobox_freq2.currentIndexChanged\ .connect(self.plot_acoustic_recording) self.combobox_fine_sample_choice.clear() self.combobox_fine_sample_choice.addItems( [f[0] for f in stg.sample_fine] ) self.combobox_sand_sample_choice.clear() self.combobox_sand_sample_choice.addItems( [s[0] for s in stg.sample_sand] ) self.label_temperature.clear() self.label_temperature.setText("T = " + str(stg.temperature) + " °C") self.update_label_freq1_for_calibration() self.update_label_freq2_for_calibration() self.update_label_kt_value_for_calibration() def function_pushbutton_plot_sample(self): if (self.combobox_acoustic_data_choice.currentIndex() == -1): return self.sample_choice_for_calibration() self.plot_acoustic_recording() self.summary_samples_choices() self.plot_profile_of_concentration_fine() self.compute_FCB() def plot_acoustic_recording(self): data_id = self.combobox_acoustic_data_choice.currentIndex() # --- Record frequencies for calibration --- stg.calib_acoustic_data = data_id freq1 = self.combobox_freq1.currentIndex() freq2 = self.combobox_freq2.currentIndex() stg.frequencies_for_calibration.clear() stg.frequencies_for_calibration.append( ( stg.freq[data_id][freq1], freq1 ) ) stg.calib_freq_1 = freq1 stg.frequencies_for_calibration.append( ( stg.freq[data_id][freq2], freq2 ) ) stg.calib_freq_2 = freq2 stg.frequency_for_inversion = tuple() stg.frequency_for_inversion = ( stg.freq[data_id][freq2], freq2 ) # --- Plot acoustic data recording --- self.verticalLayout_groupbox_data_plot.removeWidget(self.toolbar_BS) self.verticalLayout_groupbox_data_plot.removeWidget(self.canvas_BS) if self.fig_BS is not None: self.fig_BS.clear() plt.close(self.fig_BS) self.fig_BS, self.axis_BS = plt.subplots( nrows=1, ncols=1, sharex=True, sharey=False, layout='constrained' ) self.canvas_BS = FigureCanvas(self.fig_BS) self.toolbar_BS = NavigationToolBar(self.canvas_BS, self) self.verticalLayout_groupbox_data_plot.addWidget(self.toolbar_BS) self.verticalLayout_groupbox_data_plot.addWidget(self.canvas_BS) BS_data = None time_data = None depth_data = None if stg.BS_stream_bed_pre_process_average[data_id].shape != (0,): BS_data = stg.BS_stream_bed_pre_process_average elif stg.BS_stream_bed_pre_process_SNR[data_id].shape != (0,): BS_data = stg.BS_stream_bed_pre_process_SNR elif stg.BS_stream_bed[data_id].shape != (0,): BS_data = stg.BS_stream_bed elif stg.BS_cross_section_pre_process_average[data_id].shape != (0,): BS_data = stg.BS_cross_section_pre_process_average elif stg.BS_cross_section_pre_process_SNR[data_id].shape != (0,): BS_data = stg.BS_cross_section_pre_process_SNR elif stg.BS_raw_data_pre_process_average[data_id].shape != (0,): BS_data = stg.BS_raw_data_pre_process_average elif stg.BS_raw_data_pre_process_SNR[data_id].shape != (0,): BS_data = stg.BS_raw_data_pre_process_SNR elif stg.BS_raw_data[data_id].shape != (0,): BS_data = stg.BS_raw_data 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_date = stg.depth val_min = np.nanmin( BS_data[data_id][freq2, :, :] ) val_max = np.nanmax( BS_data[data_id][freq2, :, :] ) if val_min == 0: val_min = 1e-5 self.axis_BS.pcolormesh( time_data[data_id][freq2, :], -depth_data[data_id][freq2, :], BS_data[data_id][freq2, :, :], norm=LogNorm(vmin=val_min, vmax=val_max), cmap='viridis' ) self.plot_acoustic_recording_samples() def plot_acoustic_recording_samples(self): data_id = self.combobox_acoustic_data_choice.currentIndex() freq1 = self.combobox_freq1.currentIndex() freq2 = self.combobox_freq2.currentIndex() if (stg.fine_sample_profile) or (stg.sand_sample_target): self.axis_BS.scatter( [stg.time_fine[f[1]] for f in stg.fine_sample_profile], [stg.depth_fine[f[1]] for f in stg.fine_sample_profile], marker='o', s=20, facecolor="k", edgecolor="None" ) self.axis_BS.scatter( [stg.time_sand[s[1]] for s in stg.sand_sample_target], [stg.depth_sand[s[1]] for s in stg.sand_sample_target], marker='o', s=50, facecolor="None", edgecolor="k" ) for i in stg.fine_sample_profile: self.axis_BS.text( stg.time_fine[i[1]] + 5, stg.depth_fine[i[1]] - .2, i[0], fontstyle="normal", fontweight="light", fontsize=8 ) for j in stg.sand_sample_target: self.axis_BS.text( stg.time_sand[j[1]] - 12, stg.depth_sand[j[1]] - .2, j[0], fontstyle="normal", fontweight="light", fontsize=8 ) elif (stg.sample_fine) or (stg.sample_sand): self.axis_BS.scatter( stg.time_fine, stg.depth_fine, marker='o', s=20, facecolor="k", edgecolor="None" ) self.axis_BS.scatter( stg.time_sand, stg.depth_sand, marker='o', s=50, facecolor="None", edgecolor="k" ) for i in stg.sample_fine: self.axis_BS.text( stg.time_fine[i[1]] + 5, stg.depth_fine[i[1]] - .2, i[0], fontstyle="normal", fontweight="light", fontsize=8 ) for j in stg.sample_sand: self.axis_BS.text( stg.time_sand[j[1]] - 12, stg.depth_sand[j[1]] - .2, j[0], fontstyle="normal", fontweight="light", fontsize=8 ) # --- Plot vertical red line for position of FCB profile --- if stg.sand_sample_target_indice: if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth if stg.time_cross_section[data_id].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time self.red_line_plot_return, = ( self.axis_BS.plot( time_data[data_id][ freq2, stg.sand_sample_target_indice[0][1] ] * np.ones(depth_data[data_id].shape[1]), -depth_data[data_id][freq2, :], color='red', linestyle="solid", linewidth=2 ) ) self.axis_BS.set_xlabel("Time (sec)") self.axis_BS.set_ylabel("Depth (m)") self.fig_BS.canvas.draw_idle() def sample_choice_for_calibration(self): fine_id = self.combobox_fine_sample_choice.currentIndexes() fine_data = self.combobox_fine_sample_choice.currentData() sand_id = self.combobox_sand_sample_choice.currentIndex() sand_data = self.combobox_sand_sample_choice.currentData() sand_text = self.combobox_sand_sample_choice.currentText() # --- List selected fine samples --- stg.fine_sample_profile = [ (f, int(f[1:]) - 1) for f in fine_data ] stg.calib_fine_profiles = fine_id # --- List selected sand samples --- stg.sand_sample_target = [(sand_text, sand_id)] stg.calib_sand_target = sand_id t1, t2 = self.sample_choice_for_calibration_times() d1, d2 = self.sample_choice_for_calibration_depths() stg.sand_sample_target_indice = [(d1, t1), (d2, t2)] def sample_choice_for_calibration_times(self): data_id = self.combobox_acoustic_data_choice.currentIndex() freq1_id = self.combobox_freq1.currentIndex() freq2_id = self.combobox_freq1.currentIndex() # --- Find index in time (along acoustic recording) of sand sample target --- if stg.time_cross_section[data_id].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time t1 = ( np.where( np.abs( time_data[data_id][freq1_id] - stg.time_sand[stg.sand_sample_target[0][1]] ) == np.nanmin( np.abs( time_data[data_id][freq1_id] - stg.time_sand[stg.sand_sample_target[0][1]] ) ) )[0][0] ) t2 = ( np.where( np.abs( time_data[data_id][freq2_id] - stg.time_sand[stg.sand_sample_target[0][1]] ) == np.nanmin( np.abs( time_data[data_id][freq2_id] - stg.time_sand[stg.sand_sample_target[0][1]] ) ) )[0][0] ) return (t1, t2) def sample_choice_for_calibration_depths(self): data_id = self.combobox_acoustic_data_choice.currentIndex() freq1_id = self.combobox_freq1.currentIndex() freq2_id = self.combobox_freq2.currentIndex() # --- Find index in depth (along acoustic recording) of sand sample target --- if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth d1 = ( np.where( np.abs( depth_data[data_id][freq1_id] - (-stg.depth_sand[stg.sand_sample_target[0][1]]) ) == np.nanmin( np.abs( depth_data[data_id][freq1_id] - (-stg.depth_sand[stg.sand_sample_target[0][1]]) ) ) )[0][0] ) d2 = ( np.where( np.abs( depth_data[data_id][freq2_id] - (-stg.depth_sand[stg.sand_sample_target[0][1]]) ) == np.nanmin( np.abs( depth_data[data_id][freq2_id] - (-stg.depth_sand[stg.sand_sample_target[0][1]]) ) ) )[0][0] ) return (d1, d2) def summary_samples_choices(self): self.pushbutton_compute_calibration\ .setToolTip( "Calibration is computed at abscissa " + str(self.combobox_sand_sample_choice.currentText()) ) for i in reversed(range(self.gridLayout_groupbox_interpolate_info.count())): self.gridLayout_groupbox_interpolate_info\ .itemAt(i)\ .widget()\ .setParent(None) self.gridLayout_groupbox_interpolate_info\ .addWidget( self.pushbutton_interpolate_Mfine_profile, 0, 0, 1, 4, Qt.AlignCenter ) self.summary_samples_choices_fine() self.summary_samples_choices_sand() def summary_samples_choices_fine(self): fine_head = ["Sample", "Depth (m)", "time", "Cfine (g/L)"] fine_label = [ self.label_sample_fine, self.label_depth_fine, self.label_time_fine, self.label_concentration_fine ] for j in range(len(fine_head)): fine_label[j] = QLabel() fine_label[j].setText(fine_head[j]) self.gridLayout_groupbox_interpolate_info\ .addWidget( fine_label[j], 1, j, 1, 1, Qt.AlignCenter ) self.gridLayout_groupbox_interpolate_info\ .addWidget( fine_label[j], 1, j, 1, 1, Qt.AlignCenter ) fine_data = [] for k in range(len(stg.fine_sample_profile)): fine_data.append( [ stg.fine_sample_profile[k][0], str(stg.depth_fine[k]), str(stg.time_fine[k]), str(stg.Ctot_fine[k]) ] ) for p in range(len(fine_data)): for q in range(len(fine_data[0])): self.gridLayout_groupbox_interpolate_info\ .addWidget( QLabel(fine_data[p][q]), 2 + p, q, 1, 1, Qt.AlignCenter ) self.gridLayout_groupbox_interpolate_info\ .addWidget( self.double_horizontal_line, 2 + len(fine_data), 0, 1, 4, Qt.AlignCenter ) def summary_samples_choices_sand(self): sand_head = ["Sample", "Depth (m)", "time", "Csand (g/L)"] sand_label = [ self.label_sample_sand, self.label_depth_sand, self.label_time_sand, self.label_concentration_sand ] fine_data = [] for k in range(len(stg.fine_sample_profile)): fine_data.append( [ stg.fine_sample_profile[k][0], str(stg.depth_fine[k]), str(stg.time_fine[k]), str(stg.Ctot_fine[k]) ] ) for s in range(len(sand_head)): sand_label[s] = QLabel() sand_label[s].setText(sand_head[s]) self.gridLayout_groupbox_interpolate_info\ .addWidget( sand_label[s], 3 + len(fine_data), s, 1, 1, Qt.AlignCenter ) sand_data = [ stg.sand_sample_target[0][0], str(stg.depth_sand[stg.sand_sample_target[0][1]]), str(stg.time_sand[stg.sand_sample_target[0][1]]), str(stg.Ctot_sand[stg.sand_sample_target[0][1]]) ] for t in range(len(sand_data)): self.gridLayout_groupbox_interpolate_info\ .addWidget( QLabel(sand_data[t]), 4 + len(fine_data), t, 1, 1, Qt.AlignCenter ) def plot_profile_of_concentration_fine(self): # --- Plot profile of the concentration of the fine sediments --- self.verticalLayout_groupbox_interpolate_plot.removeWidget(self.canvas_Mfine) self.verticalLayout_groupbox_interpolate_plot.removeWidget(self.toolbar_Mfine) if self.fig_Mfine is not None: self.fig_Mfine.clear() plt.close(self.fig_Mfine) self.fig_Mfine, self.ax_Mfine = plt.subplots(1, 1, layout="constrained") self.canvas_Mfine = FigureCanvas(self.fig_Mfine) self.toolbar_Mfine = NavigationToolBar(self.canvas_Mfine, self) self.verticalLayout_groupbox_interpolate_plot.addWidget(self.toolbar_Mfine) self.verticalLayout_groupbox_interpolate_plot.addWidget(self.canvas_Mfine) for t, c in stg.fine_sample_profile: self.ax_Mfine.plot(stg.Ctot_fine[c], stg.depth_fine[c], marker="o", mfc="k", mec="k", ms=10, ls="None") self.ax_Mfine.text(stg.Ctot_fine[c] + 0.05 * stg.Ctot_fine[c], stg.depth_fine[c], t, fontstyle="normal", fontweight="light", fontsize=12) self.ax_Mfine.set_xlabel("Concentration fine sediments (g/L)") self.ax_Mfine.set_ylabel("Depth (m)") if stg.M_profile_fine.any(): self.ax_Mfine.plot(stg.M_profile_fine, -stg.range_lin_interp, marker="*", mfc="b", mec="b", ms=8, ls="None") def interpolate_Mfine_profile(self): # Variable 'stg.sand_sample_target_indice' is set only at # 'plot sample' button click if len(stg.sand_sample_target_indice) == 0: self._data_validity_message_box() return if len(stg.fine_sample_profile) == 0: self._data_validity_message_box() return data_choice = self.combobox_acoustic_data_choice\ .currentIndex() if stg.depth_cross_section[data_choice].shape != (0,): depth_data = stg.depth_cross_section if stg.time_cross_section[data_choice].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time else: depth_data = stg.depth if stg.time_cross_section[data_choice].shape != (0,): time_data = stg.time_cross_sectino else: time_data = stg.time self.interpolate_Mfine_profile_compute( data_choice, depth_data, time_data ) def interpolate_Mfine_profile_compute(self, data_choice, depth_data, time_data): range_cells=depth_data[data_choice][ self.combobox_freq2.currentIndex(), : ] sample_depth = [ -stg.depth_fine[k[1]] for k in stg.fine_sample_profile ] M_profile = [ stg.Ctot_fine[k[1]] for k in stg.fine_sample_profile ] r_bottom = [stg.depth_bottom[data_choice][ np.where( np.abs( time_data[data_choice][ self.combobox_freq2.currentIndex(), : ] - stg.time_fine[stg.fine_sample_profile[-1][1]] ) == np.nanmin( np.abs( time_data[data_choice][ self.combobox_freq2.currentIndex(), : ] - stg.time_fine[stg.fine_sample_profile[-1][1]]) ) )[0][0] ] if len(stg.depth_bottom[data_choice])!=0 else np.array([])][0] logger.debug( "call 'inv_hc.M_profile_SCC_fine_interpolated' params:" ) logger.debug(f"sample_depth = {sample_depth}") logger.debug(f"M_profile = {M_profile}") logger.debug(f"range_cells = {range_cells}") logger.debug(f"r_bottom = {r_bottom}") stg.range_lin_interp, stg.M_profile_fine = ( self.inv_hc.M_profile_SCC_fine_interpolated( sample_depth=sample_depth, M_profile=M_profile, range_cells=range_cells, r_bottom=r_bottom ) ) stg.range_lin_interp = stg.range_lin_interp stg.M_profile_fine = stg.M_profile_fine stg.M_profile_fine = stg.M_profile_fine[ :stg.range_lin_interp.shape[0] ] self.plot_profile_of_concentration_fine() def _data_validity_message_box(self): msgBox = QMessageBox() msgBox.setWindowTitle("Interpolate (step 2)") msgBox.setIconPixmap( QPixmap( self._path_icon("no_approved.png") ) .scaledToHeight(32, Qt.SmoothTransformation) ) msgBox.setText( "Please select and valid the find and sand" + "sample data with click on 'sample plot' button" ) msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() # ------------------------------------------------------------------ # --------------- Functions for sediment calibration --------------- # ------------------------------------------------------------------ def groupbox_calibration_import_toggle(self): if self.groupbox_sediment_calibration_import.isChecked() == True: self.groupbox_sediment_calibration_compute.setChecked(False) elif self.groupbox_sediment_calibration_import.isChecked() == True: self.groupbox_sediment_calibration_compute.setChecked(False) def groupbox_calibration_import_size_change(self): duration = 500 self.animaiton_groupbox_import = QPropertyAnimation(self.groupbox_sediment_calibration_import, b"size") self.animaiton_groupbox_import.setDuration(duration) self.animaiton_groupbox_import.setStartValue(QSize(self.groupbox_sediment_calibration_import.width(), self.groupbox_sediment_calibration_import.height())) if self.groupbox_sediment_calibration_import.isChecked(): self.animaiton_groupbox_import.setEndValue( QSize(self.groupbox_sediment_calibration_import.width(), self.groupbox_sediment_calibration_import.sizeHint().height())) else: self.animaiton_groupbox_import.setEndValue(QSize(self.groupbox_sediment_calibration_import.width(), 25)) self.animaiton_groupbox_import.start() def groupbox_calibration_compute_toggle(self): if self.groupbox_sediment_calibration_compute.isChecked() == True: self.groupbox_sediment_calibration_import.setChecked(False) elif self.groupbox_sediment_calibration_compute.isChecked() == True: self.groupbox_sediment_calibration_import.setChecked(False) def groupbox_calibration_compute_size_change(self): duration = 500 self.animaiton_groupbox_compute = QPropertyAnimation(self.groupbox_sediment_calibration_compute, b"size") self.animaiton_groupbox_compute.setDuration(duration) self.animaiton_groupbox_compute.setStartValue(QSize(self.groupbox_sediment_calibration_compute.width(), self.groupbox_sediment_calibration_compute.height())) if self.groupbox_sediment_calibration_compute.isChecked(): self.animaiton_groupbox_compute.setEndValue( QSize(self.groupbox_sediment_calibration_compute.width(), self.groupbox_sediment_calibration_compute.sizeHint().height())) else: self.animaiton_groupbox_compute.setEndValue(QSize(self.groupbox_sediment_calibration_compute.width(), 25)) self.animaiton_groupbox_compute.start() def import_calibration_file(self): if self.combobox_acoustic_data_choice.count() == 0: msgBox = QMessageBox() msgBox.setWindowTitle("Calibration import error") msgBox.setIconPixmap( QPixmap( self._path_icon("no_approved.png") ).scaledToHeight(32, Qt.SmoothTransformation) ) msgBox.setText("Update data before importing calibration") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() return path = "" if stg.path_calibration_file: path = stg.path_calibration_file elif self.combobox_acoustic_data_choice.count() > 0: path = stg.path_BS_raw_data[-1] file_type = { "Calibration Files (*.csv *.ods *.xls *.xlsx)": self.read_calibration_dispatch, "CSV Files (*.csv)": self.read_calibration_csv, "Excel Files (*.xlsx *.xls)": self.read_calibration_excel, "LibreOffice Calc Files (*.ods)": self.read_calibration_ods, } filename, ftype = QFileDialog.getOpenFileName( self, "Open calibration file", path, ";;".join(file_type), options=QFileDialog.DontUseNativeDialog ) if filename == '': return dir_name = os.path.dirname(filename) name = os.path.basename(filename) stg.path_calibration_file = dir_name stg.filename_calibration_file = name self.lineEdit_import_calibration.clear() self.lineEdit_import_calibration.setText(name) self.lineEdit_import_calibration.setToolTip(dir_name) self.compute_depth_2D() try: parser = file_type[ftype] data = parser(filename) self.fill_calibration_select_frequencies(data) self.fill_calibration_parameters(data) except Exception as e: logger.warning(f"read calibration failed: {str(e)}") def read_calibration_dispatch(self, filename): if ".csv" in filename: return self.read_calibration_csv(filename) elif ".ods" in filename: return self.read_calibration_ods(filename) else: return self.read_calibration_excel(filename) def read_calibration_csv(self, filename): data = pd.read_csv( filename, header=0, index_col=0, ) logger.debug(f"Calibration data: {data}") return data def read_calibration_ods(self, filename): data = pd.read_excel( filename, header=0, index_col=0, engine="odf" ) logger.debug(f"Calibration data: {data}") return data def read_calibration_excel(self, filename): data = pd.read_excel( filename, header=0, index_col=0, ) logger.debug(f"Calibration data: {data}") return data def update_label_freq1_for_calibration(self): self.label_freq1.clear() self.label_freq1.setText( str(self.combobox_freq1.currentText()) ) def update_label_freq2_for_calibration(self): self.label_freq2.clear() self.label_freq2.setText( self.combobox_freq2.currentText() ) def update_label_kt_value_for_calibration(self): freq_1 = self.combobox_freq1.currentIndex() freq_2 = self.combobox_freq2.currentIndex() self.label_kt_freq1.clear() if stg.kt_corrected[freq_1] != stg.kt_read[freq_1]: self.label_kt_freq1.setText( str('%.4f' % stg.kt_corrected[freq_1]) ) else: self.label_kt_freq1.setText( str('%.4f' % stg.kt_read[freq_1]) ) self.label_kt_freq2.clear() if stg.kt_corrected[freq_2] != stg.kt_read[freq_2]: self.label_kt_freq2.setText( str('%.4f' % stg.kt_corrected[freq_2]) ) else: self.label_kt_freq2.setText( str('%.4f' % stg.kt_read[freq_2]) ) def fill_calibration_select_frequencies(self, data): if stg.filename_calibration_file == "": return # --- Fill spinboxes of calibration parameter --- self.label_temperature.clear() self.label_temperature.setText( "T = " + str(stg.temperature) + " °C" ) data_id = self.combobox_acoustic_data_choice.currentIndex() stg.calib_acoustic_data = data_id stg.frequencies_for_calibration.clear() for label, column in [ (self.label_freq1, 0), (self.label_freq2, 1) ]: label.clear() label.setText(data.columns[0]) index = next( map( lambda e: e[0], filter( lambda e: e[1] == data.columns[column], enumerate(stg.freq_text[data_id]) ) ) ) stg.frequencies_for_calibration.append( ( stg.freq[data_id][index], index ) ) logger.debug(f"Select freq {index}: {stg.freq_text[data_id][index]}") stg.calib_freq_1 = stg.frequencies_for_calibration[0][1] stg.calib_freq_2 = stg.frequencies_for_calibration[1][1] def fill_calibration_parameters(self, data): self.lineEdit_ks_freq1.clear() self.lineEdit_ks_freq1.setText( str("%.5f" % float(data.iloc[0][0])) ) self.lineEdit_ks_freq2.clear() self.lineEdit_ks_freq2.setText( str("%.5f" % float(data.iloc[0][1])) ) stg.ks.clear() stg.ks = [ float(self.lineEdit_ks_freq1.text()), float(self.lineEdit_ks_freq2.text()) ] self.lineEdit_sv_freq1.clear() self.lineEdit_sv_freq1.setText( str("%.5f" % float(data.iloc[1][0])) ) self.lineEdit_sv_freq2.clear() self.lineEdit_sv_freq2.setText( str("%.5f" % float(data.iloc[1][1])) ) stg.sv.clear() stg.sv = [ float(self.lineEdit_sv_freq1.text()), float(self.lineEdit_sv_freq2.text()) ] self.lineEdit_X.clear() self.lineEdit_X.setText( str("%.2f" % float(data.iloc[2][0])) ) stg.X_exponent.clear() stg.X_exponent.append(float(self.lineEdit_X.text())) self.lineEdit_alphas_freq1.clear() self.lineEdit_alphas_freq1.setText( str("%.5f" % float(data.iloc[3][0])) ) self.lineEdit_alphas_freq2.clear() self.lineEdit_alphas_freq2.setText( str("%.5f" % float(data.iloc[3][1])) ) stg.alpha_s.clear() stg.alpha_s = [ float(self.lineEdit_alphas_freq1.text()), float(self.lineEdit_alphas_freq2.text()) ] self.lineEdit_zeta_freq1.clear() self.lineEdit_zeta_freq1.setText( str("%.5f" % float(data.iloc[4][0])) ) self.lineEdit_zeta_freq2.clear() self.lineEdit_zeta_freq2.setText( str("%.5f" % float(data.iloc[4][1])) ) stg.zeta.clear() stg.zeta = [ float(self.lineEdit_zeta_freq1.text()), float(self.lineEdit_zeta_freq2.text()) ] self.compute_kt2D_kt3D() self.compute_J_cross_section() def compute_depth_2D(self): freq = self.combobox_freq1.currentIndex() for k in range(self.combobox_acoustic_data_choice.count()): while len(stg.depth_2D) <= k: stg.depth_2D.append(np.array([])) if stg.depth_cross_section[k].shape != (0,): depth_data = stg.depth_cross_section elif stg.depth[k].shape != (0,): depth_data = stg.depth if stg.time_cross_section[k].shape != (0,): time_data = stg.time_cross_section elif stg.time[k].shape != (0,): time_data = stg.time stg.depth_2D[k] = ( np.zeros(( stg.freq[k].shape[0], depth_data[k].shape[1], time_data[k].shape[1] )) ) for f, _ in enumerate(stg.freq[k]): stg.depth_2D[k][f, :, :] = ( np.repeat( np.transpose( depth_data[k][freq] )[:, np.newaxis], time_data[k].shape[1], axis=1 ) ) def function_pushbutton_compute_calibration(self): if self.combobox_acoustic_data_choice.count() == 0: msgBox = QMessageBox() msgBox.setWindowTitle("Calibration computation error") msgBox.setIconPixmap( QPixmap( self._path_icon("no_approved.png") ).scaledToHeight(32, Qt.SmoothTransformation) ) msgBox.setText("Update data before importing calibration") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() else: self.label_temperature.clear() self.label_temperature.setText("T = " + str(stg.temperature) + " °C") self.compute_depth_2D() self.compute_ks() self.compute_sv() self.compute_X() self.compute_kt2D_kt3D() self.compute_J_cross_section() self.compute_alpha_s() self.compute_zeta() def compute_ks(self): data_id = self.combobox_acoustic_data_choice.currentIndex() psd_number_of_particles = ( self.inv_hc.compute_particle_size_distribution_in_number_of_particles( num_sample=stg.sand_sample_target[0][1], r_grain=stg.radius_grain_sand, frac_vol_cumul=stg.frac_vol_sand_cumul ) ) ks_freq1 = self.inv_hc.ks( proba_num=psd_number_of_particles, freq=stg.freq[data_id][self.combobox_freq1.currentIndex()], C=stg.water_velocity ) ks_freq2 = self.inv_hc.ks( proba_num=psd_number_of_particles, freq=stg.freq[data_id][self.combobox_freq2.currentIndex()], C=stg.water_velocity ) stg.ks = [ks_freq1, ks_freq2] logger.debug( "ks for frequency of " + f"{stg.freq[data_id][self.combobox_freq1.currentIndex()]} : " + f"{ks_freq1} m/kg^0.5 \n" ) logger.debug( "ks for frequency of " + f"{stg.freq[data_id][self.combobox_freq2.currentIndex()]} : " + f"{ks_freq2} m/kg^0.5" ) self.lineEdit_ks_freq1.clear() self.lineEdit_ks_freq1.setText(str("%.5f" % ks_freq1)) self.lineEdit_ks_freq2.clear() self.lineEdit_ks_freq2.setText(str("%.5f" % ks_freq2)) def compute_sv(self): data_id = self.combobox_acoustic_data_choice.currentIndex() sv_freq1 = self.inv_hc.sv(ks=stg.ks[0], M_sand=stg.Ctot_sand[stg.sand_sample_target[0][1]]) sv_freq2 = self.inv_hc.sv(ks=stg.ks[1], M_sand=stg.Ctot_sand[stg.sand_sample_target[0][1]]) stg.sv = [sv_freq1, sv_freq2] logger.debug( f"sv for frequency of {stg.freq[data_id][self.combobox_freq1.currentIndex()]}" + f" : {sv_freq1:.8f} /m \n" ) logger.debug( f"sv for frequency of {stg.freq[data_id][self.combobox_freq2.currentIndex()]}" + f" : {sv_freq2:.8f} /m" ) self.lineEdit_sv_freq1.clear() self.lineEdit_sv_freq1.setText(str("%.5f" % sv_freq1)) self.lineEdit_sv_freq2.clear() self.lineEdit_sv_freq2.setText(str("%.5f" % sv_freq2)) def compute_X(self): data_id = self.combobox_acoustic_data_choice.currentIndex() X_exponent = self.inv_hc.X_exponent( freq1=stg.freq[data_id][self.combobox_freq1.currentIndex()], freq2=stg.freq[data_id][self.combobox_freq2.currentIndex()], sv_freq1=stg.sv[0], sv_freq2=stg.sv[1] ) stg.X_exponent.clear() stg.X_exponent.append(X_exponent) logger.debug(f"Exponent X = {X_exponent:.2f}\n") self.lineEdit_X.setText(str("%.2f" % X_exponent)) def compute_kt2D_kt3D(self): for i in range(self.combobox_acoustic_data_choice.count()): if stg.depth_cross_section[i].shape != (0,): depth_data = stg.depth_cross_section elif stg.depth[i].shape != (0,): depth_data = stg.depth else: continue if stg.time_cross_section[i].shape != (0,): time_data = stg.time_cross_section elif stg.time[i].shape != (0,): time_data = stg.time else: continue if stg.kt_corrected != stg.kt_read: kt_data = stg.kt_corrected else: kt_data = stg.kt_read stg.kt2D[i] = np.repeat( np.array([kt_data]).transpose(), time_data[i].shape[1], axis=1 ) stg.kt3D[i] = np.repeat( stg.kt2D[i][:, np.newaxis, :], depth_data[i].shape[1], axis=1 ) def compute_J_cross_section(self): lst_bs_data = [ stg.BS_stream_bed_pre_process_average, stg.BS_stream_bed_pre_process_SNR, stg.BS_stream_bed, stg.BS_cross_section_pre_process_average, stg.BS_cross_section_pre_process_SNR, stg.BS_cross_section, stg.BS_raw_data_pre_process_average, stg.BS_raw_data_pre_process_SNR, stg.BS_raw_data ] for i in range(self.combobox_acoustic_data_choice.count()): J_cross_section_freq1 = np.array([]) J_cross_section_freq2 = np.array([]) for data in lst_bs_data: if data[i].shape != (0,): bs_data = data break J_cross_section_freq1 = self.inv_hc.j_cross_section( BS = bs_data[i][ stg.frequencies_for_calibration[0][1], :, : ], r2D = stg.depth_2D[i][ stg.frequencies_for_calibration[0][1], :, : ], kt = stg.kt3D[i][ stg.frequencies_for_calibration[0][1], :, : ] ) J_cross_section_freq2 = self.inv_hc.j_cross_section( BS = bs_data[i][ stg.frequencies_for_calibration[1][1], :, : ], r2D = stg.depth_2D[i][ stg.frequencies_for_calibration[1][1], :, : ], kt = stg.kt3D[i][ stg.frequencies_for_calibration[1][1], :, : ] ) stg.J_cross_section[i][0] = J_cross_section_freq1 stg.J_cross_section[i][1] = J_cross_section_freq2 def compute_alpha_s(self): data_id = self.combobox_acoustic_data_choice.currentIndex() freq_1 = self.combobox_freq1.currentIndex() freq_2 = self.combobox_freq2.currentIndex() depth_data = stg.depth if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section alpha_s_freq1 = self.inv_hc.alpha_s( sv=stg.sv[0], j_cross_section=stg.J_cross_section[data_id][0][ stg.sand_sample_target_indice[0][0], stg.sand_sample_target_indice[0][1] ], depth=depth_data[data_id][ freq_1, stg.sand_sample_target_indice[0][0] ], alpha_w=stg.water_attenuation[data_id][freq_1] ) alpha_s_freq2 = self.inv_hc.alpha_s( sv=stg.sv[1], j_cross_section=stg.J_cross_section[data_id][1][ stg.sand_sample_target_indice[1][0], stg.sand_sample_target_indice[1][1] ], depth=depth_data[data_id][ freq_2, stg.sand_sample_target_indice[1][0] ], alpha_w=stg.water_attenuation[data_id][freq_2] ) stg.alpha_s = [alpha_s_freq1, alpha_s_freq2] logger.debug( f"\u03B1s for frequency of freq1 : {alpha_s_freq1:.2f} / m" ) logger.debug( f"\u03B1s for frequency of freq2 : {alpha_s_freq2:.2f} / m" ) self.lineEdit_alphas_freq1.clear() self.lineEdit_alphas_freq1.setText(f"{alpha_s_freq1:.5f}") self.lineEdit_alphas_freq2.clear() self.lineEdit_alphas_freq2.setText(f"{alpha_s_freq2:.5f}") title = "Alpha computation error" icon = self._path_icon("no_approved.png") if (alpha_s_freq1 < 0) or (alpha_s_freq2 < 0): text = "Sediment sound attenuation is negative !" elif isinf(alpha_s_freq1) or isinf(alpha_s_freq2): text = "Sediment sound attenuation is infinite !" else: title = "Alpha computation validation" icon = self._path_icon("approved.png") text = "Sediment sound attenuation is positive." msgBox = QMessageBox() msgBox.setWindowTitle(title) msgBox.setIconPixmap( QPixmap(icon).scaledToHeight( 32, Qt.SmoothTransformation ) ) msgBox.setText(text) msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() def compute_zeta(self): if stg.M_profile_fine.shape == (0,): msgBox = QMessageBox() msgBox.setWindowTitle("Zeta computation error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Please interpolate fine profile") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() return data_id = self.combobox_acoustic_data_choice.currentIndex() freq_1 = self.combobox_freq1.currentIndex() freq_2 = self.combobox_freq2.currentIndex() if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth zeta_freq1 = self.inv_hc.zeta( alpha_s = stg.alpha_s[0], r = depth_data[data_id][freq_1, :], M_profile_fine = stg.M_profile_fine ) zeta_freq2 = self.inv_hc.zeta( alpha_s = stg.alpha_s[1], r = depth_data[data_id][freq_2, :], M_profile_fine = stg.M_profile_fine ) stg.zeta = [zeta_freq1, zeta_freq2] logger.debug( f"\u03B6 for frequency of freq1 : {zeta_freq1:.3f} / m" ) logger.debug( f"\u03B6 for frequency of freq2 : {zeta_freq2:.3f} / m" ) self.lineEdit_zeta_freq1.clear() self.lineEdit_zeta_freq1.setText(f"{zeta_freq1:.5f}") self.lineEdit_zeta_freq2.clear() self.lineEdit_zeta_freq2.setText(f"{zeta_freq2:.5f}") def save_calibration(self): data_id = self.combobox_acoustic_data_choice.currentIndex() freq1 = stg.frequencies_for_calibration[0][1] freq2 = stg.frequencies_for_calibration[1][1] if stg.alpha_s: directory = "" if stg.path_calibration_file != "": directory = stg.path_calibration_file elif self.combobox_acoustic_data_choice.count() > 0: directory = stg.path_BS_raw_data[-1] dir_save_cal = QFileDialog.getExistingDirectory( caption="Save calibration", directory=directory, options=QFileDialog.DontUseNativeDialog ) if dir_save_cal: stg.path_calibration_file = os.path.dirname(dir_save_cal) cal_array = [ [ ' ', stg.freq_text[data_id][freq1], stg.freq_text[data_id][freq2] ], ['ks', stg.ks[0], stg.ks[1]], ['sv', stg.sv[0], stg.sv[1]], ['X', stg.X_exponent[0], 0], ['alphas', stg.alpha_s[0], stg.alpha_s[1]], ['zeta', stg.zeta[0], stg.zeta[1]] ] np.savetxt( f"{dir_save_cal}/Sediment_calibration_" + f"{stg.filename_BS_raw_data[data_id][:-4]}.csv", cal_array, delimiter=',', fmt ='% s' ) else: msgBox = QMessageBox() msgBox.setWindowTitle("Save Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Please compute calibration before saving") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() # --- Compute FCB --- # ------------ Computing real cell size ------------ # def range_cells_function(self): """ Computing the real cell size, that depends on the temperature """ data_id = self.combobox_acoustic_data_choice.currentIndex() aquascat_cell_size = [] tau = [] real_cell_size = [] if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth stg.depth_real = np.zeros(depth_data[data_id].shape) for f in range(stg.freq[data_id].shape[0]): # defaut Aquascat cell size aquascat_cell_size.append( depth_data[data_id][f, 1] - depth_data[data_id][f, 0] ) # Pulse duration: figure 2.9 1500 vitesse du son entrée # pour le paramètrage des mesures aquascat tau.append(aquascat_cell_size[f] * 2 / 1500) # voir fig 2.9 real_cell_size.append(stg.water_velocity * tau[f] / 2) # Converting to real cell profile stg.depth_real[f, :] = ( depth_data[data_id][f, :] / aquascat_cell_size[f] * real_cell_size[f] ) if stg.time_cross_section[data_id].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time stg.depth_real = np.repeat( stg.depth_real[:, :, np.newaxis], time_data[data_id].shape[1], axis=2 ) def compute_FCB(self): data_id = self.combobox_acoustic_data_choice.currentIndex() fcb_id = self.combobox_frequency_FCB.currentIndex() self.combobox_frequency_FCB.clear() self.combobox_frequency_FCB.addItems(stg.freq_text[data_id]) self.range_cells_function() BS_data = stg.BS_raw_data if stg.BS_stream_bed_pre_process_average[data_id].shape != (0,): BS_data = stg.BS_stream_bed_pre_process_average elif stg.BS_stream_bed_pre_process_SNR[data_id].shape != (0,): BS_data = stg.BS_stream_bed_pre_process_SNR elif stg.BS_stream_bed[data_id].shape != (0,): BS_data = stg.BS_stream_bed elif stg.BS_cross_section_pre_process_average[data_id].shape != (0,): BS_data = stg.BS_cross_section_pre_process_average elif stg.BS_cross_section_pre_process_SNR[data_id].shape != (0,): BS_data = stg.BS_cross_section_pre_process_SNR elif stg.BS_cross_section[data_id].shape != (0,): BS_data = stg.BS_cross_section elif stg.BS_raw_data_pre_process_average[data_id].shape != (0,): BS_data = stg.BS_raw_data_pre_process_average elif stg.BS_raw_data_pre_process_SNR[data_id].shape != (0,): BS_data = stg.BS_raw_data_pre_process_SNR stg.FCB = ( np.log(BS_data[data_id]) + np.log(stg.depth_real) + 2 * stg.water_attenuation[data_id][fcb_id] * stg.depth_real ) self.plot_FCB() def plot_FCB(self): data_id = self.combobox_acoustic_data_choice.currentIndex() fcb_id = self.combobox_frequency_FCB.currentIndex() if stg.FCB.shape == (0,): return if stg.time_cross_section[data_id].shape != (0,): self.slider_FCB.setMaximum( stg.time_cross_section[data_id].shape[1] ) else: self.slider_FCB.setMaximum(stg.time[data_id].shape[1]) self.slider_FCB.setValue(stg.sand_sample_target_indice[0][1]) self.verticalLayout_groupbox_FCB_plot.removeWidget(self.canvas_FCB) self.verticalLayout_groupbox_FCB_plot.removeWidget(self.toolbar_FCB) if self.fig_FCB is not None: self.fig_FCB.clear() plt.close(self.fig_FCB) self.fig_FCB, self.axis_FCB = plt.subplots( nrows=1, ncols=1, layout="constrained" ) self.canvas_FCB = FigureCanvas(self.fig_FCB) self.toolbar_FCB = NavigationToolBar(self.canvas_FCB, self) self.verticalLayout_groupbox_FCB_plot.addWidget(self.toolbar_FCB) self.verticalLayout_groupbox_FCB_plot.addWidget(self.canvas_FCB) if stg.depth_cross_section[data_id].shape != (0,): self.axis_FCB.plot( stg.depth_cross_section[data_id][fcb_id], stg.FCB[fcb_id, :, self.slider_FCB.value() - 1], linestyle="solid", linewidth=1, color="k" ) else: self.axis_FCB.plot( stg.depth[data_id][fcb_id], stg.FCB[fcb_id, :, self.slider_FCB.value() - 1], linestyle="solid", linewidth=1, color="k" ) self.axis_FCB.text( .95, .05, stg.freq_text[data_id][fcb_id], fontsize=10, fontweight='bold', fontname="DejaVu Sans", fontstyle="normal", c="black", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_FCB.transAxes ) self.fig_FCB.supxlabel("Depth (m)") self.fig_FCB.supylabel("FCB") self.fig_FCB.canvas.draw_idle() self.slider_FCB.valueChanged.connect(self.update_plot_FCB) self.combobox_frequency_FCB.currentIndexChanged\ .connect(self.update_plot_FCB) def update_plot_FCB(self): data_id = self.combobox_acoustic_data_choice.currentIndex() fcb_id = self.combobox_frequency_FCB.currentIndex() freq1_id = self.combobox_freq1.currentIndex() freq2_id = self.combobox_freq2.currentIndex() if stg.FCB.shape != (0,): self.axis_FCB.cla() if stg.depth_cross_section[data_id].shape != (0,): self.axis_FCB.plot( stg.depth_cross_section[data_id][fcb_id], stg.FCB[fcb_id, :, self.slider_FCB.value() - 1], linestyle="solid", linewidth=1, color="k" ) else: self.axis_FCB.plot( stg.depth[data_id][fcb_id], stg.FCB[fcb_id, :, self.slider_FCB.value() - 1], linestyle="solid", linewidth=1, color="k" ) self.axis_FCB.text( .95, .05, stg.freq_text[data_id][fcb_id], fontsize=10, fontweight='bold', fontname="DejaVu Sans", fontstyle="normal", c="black", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_FCB.transAxes ) self.fig_FCB.canvas.draw_idle() # --- Update red line on acoustic record plot --- if stg.sand_sample_target_indice: if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth if stg.time_cross_section[data_id].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time self.red_line_plot_return.set_data( time_data[data_id][freq2_id, self.slider_FCB.value() -1] * np.ones( depth_data[data_id].shape[1] ), -depth_data[data_id][freq2_id, :] ) self.fig_BS.canvas.draw_idle() def fit_FCB_profile_with_linear_regression_and_compute_alphaS(self): data_id = self.combobox_acoustic_data_choice.currentIndex() fcb_id = self.combobox_frequency_FCB.currentIndex() if (self.lineEdit_FCB_from.text() == '' or self.lineEdit_FCB_to.text() == ''): return self.update_plot_FCB() if stg.FCB.shape == (0,): return # --- Identify FCB profile where value are not NaN --- y0 = stg.FCB[fcb_id, :, self.slider_FCB.value() - 1] y = y0[np.where(np.isnan(y0) == False)] if stg.depth_cross_section[data_id].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth # --- Select depth corresponding to the FCB profile where value are not NaN --- x0 = depth_data[data_id][fcb_id, :] x = x0[np.where(np.isnan(y0) == False)] # --- Find the indices of the values between which the linear regression is fitted --- value1 = np.where( np.round( np.abs( x - float( self.lineEdit_FCB_from.text().replace(',','.') ) ), 2 ) == np.min( np.round( np.abs( x - float( self.lineEdit_FCB_from.text().replace(',','.')) ), 2 ) ) )[0][0] value2 = np.where( np.round( np.abs( x - float( self.lineEdit_FCB_to.text().replace(',', '.') ) ), 2 ) == np.min( np.round( np.abs( x - float( self.lineEdit_FCB_to.text().replace(',', '.') ) ), 2 ) ) )[0][0] lin_reg_compute = linregress(x[value1:value2], y[value1:value2]) stg.lin_reg.clear() stg.lin_reg = [lin_reg_compute.slope, lin_reg_compute.intercept] # --- Plot result of linear regression --- self.axis_FCB.plot( depth_data[data_id][fcb_id, value1:value2], stg.lin_reg[0] * depth_data[data_id][fcb_id, value1:value2] + stg.lin_reg[1], linestyle="dashed", linewidth=1, color="b" ) self.fig_FCB.canvas.draw_idle() # --- Display the value of alphaS compute with FCB --- self.label_alphaS_FCB.clear() self.label_alphaS_FCB.setText( f"αs = {-0.5*stg.lin_reg[0]:.4f} dB/m" ) def slider_profile_number_to_begin_FCB(self): self.slider_FCB.setValue(int(self.slider_FCB.minimum())) self.update_lineEdit_by_moving_slider_FCB() def slider_profile_number_to_right_FCB(self): self.slider_FCB.setValue(int(self.slider_FCB.value()) + 1) self.update_lineEdit_by_moving_slider_FCB() def slider_profile_number_to_left_FCB(self): self.slider_FCB.setValue(int(self.slider_FCB.value()) - 1) self.update_lineEdit_by_moving_slider_FCB() def slider_profile_number_to_end_FCB(self): self.slider_FCB.setValue(int(self.slider_FCB.maximum())) self.update_lineEdit_by_moving_slider_FCB() def profile_number_on_lineEdit_FCB(self): if stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): self.slider_FCB.setValue( int(np.where( np.abs(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ self.combobox_frequency_FCB.currentIndex()] - float(self.lineEdit_slider_FCB.text().replace(",", "."))) == np.nanmin( np.abs(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ self.combobox_frequency_FCB.currentIndex()] - float(self.lineEdit_slider_FCB.text().replace(",", ".")))))[0][0])) else: self.slider_FCB.setValue( int(np.where( np.abs(stg.time[self.combobox_acoustic_data_choice.currentIndex()][ self.combobox_frequency_FCB.currentIndex()] - float(self.lineEdit_slider_FCB.text().replace(",", "."))) == np.nanmin( np.abs(stg.time[self.combobox_acoustic_data_choice.currentIndex()][ self.combobox_frequency_FCB.currentIndex()] - float(self.lineEdit_slider_FCB.text().replace(",", ".")))))[0][0])) def update_lineEdit_by_moving_slider_FCB(self): if stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): self.lineEdit_slider_FCB.setText( str(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ self.combobox_frequency_FCB.currentIndex(), self.slider_FCB.value()-1])) else: self.lineEdit_slider_FCB.setText( str(stg.time[self.combobox_acoustic_data_choice.currentIndex()][ self.combobox_frequency_FCB.currentIndex(), self.slider_FCB.value()-1]))