# ============================================================================== # # 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 . # # by Brahim MOUDJED # # ============================================================================== # # -*- coding: utf-8 -*- import os import gc import time import logging import numpy as np 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): data_id = self.combobox_acoustic_data_choice.currentIndex() 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[data_id][0], j_cross_section_freq2=stg.J_cross_section[data_id][1], r2D=stg.depth_2D[data_id][ stg.frequency_for_inversion[1] ], 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.depth_2D[data_id][stg.frequencies_for_calibration[0][1]], 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=np.full( shape=stg.depth_2D[data_id][ stg.frequencies_for_calibration[0][1] ].shape, fill_value=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.depth_2D[data_id][stg.frequency_for_inversion[1]], 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[data_id][1], alpha_w=np.full( shape=stg.depth_2D[data_id][ stg.frequency_for_inversion[1] ].shape, fill_value=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( time_data[data_id][stg.frequency_for_inversion[1]], -depth_data[data_id][stg.frequency_for_inversion[1]], 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( time_data[data_id][stg.frequency_for_inversion[1]], -stg.depth_bottom[data_id], color='black', linewidth=1, linestyle="solid" ) self.pcm_SSC_fine_vertical_line, = self.axis_SSC_fine.plot( time_data[data_id][stg.frequency_for_inversion[1], self.slider_fine.value() - 1] * np.ones( depth_data[data_id][ stg.frequency_for_inversion[1] ].shape ), -depth_data[data_id][stg.frequency_for_inversion[1]], 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], -depth_data[data_id][stg.frequency_for_inversion[1]], linestyle="solid", linewidth=1, color="k" ) self.pcm_SSC_fine_vertical_line.set_data( time_data[data_id][ stg.frequency_for_inversion[1], self.slider_fine.value() - 1 ] * np.ones( depth_data[data_id][ stg.frequency_for_inversion[1] ].shape ), -depth_data[data_id][ stg.frequency_for_inversion[1] ] ) self.figure_SSC_fine.canvas.draw_idle() self.axis_vertical_profile_SSC_fine.set_ylim( [ -np.nanmax( depth_data[data_id][stg.frequency_for_inversion[1]] ), -np.nanmin( depth_data[data_id][stg.frequency_for_inversion[1]] ) ] ) 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], -depth_data[data_id][stg.frequency_for_inversion[1]], linestyle="solid", linewidth=1, color="k" ) self.pcm_SSC_fine_vertical_line.set_data( time_data[data_id][stg.frequency_for_inversion[1], self.slider_fine.value() - 1] * np.ones(depth_data[data_id][ stg.frequency_for_inversion[1] ].shape), -depth_data[data_id][stg.frequency_for_inversion[1]] ) self.figure_SSC_fine.canvas.draw_idle() self.axis_vertical_profile_SSC_fine.set_ylim( [ -np.nanmax( depth_data[data_id][stg.frequency_for_inversion[1]] ), -np.nanmin( depth_data[data_id][stg.frequency_for_inversion[1]] ) ] ) 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( time_data[data_id][stg.frequency_for_inversion[1]], -depth_data[data_id][stg.frequency_for_inversion[1]], 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( time_data[data_id][stg.frequency_for_inversion[1]], -stg.depth_bottom[data_id], color='black', linewidth=1, linestyle="solid" ) self.pcm_SSC_sand_vertical_line, = self.axis_SSC_sand.plot( time_data[data_id][stg.frequency_for_inversion[1], self.slider_sand.value() - 1] * np.ones( depth_data[data_id][stg.frequency_for_inversion[1]].shape ), -depth_data[data_id][stg.frequency_for_inversion[1]], 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): if self.combobox_acoustic_data_choice.count() > 0: if stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()].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[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): self.slider_sand.setMaximum(stg.SSC_fine[self.combobox_acoustic_data_choice.currentIndex()].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[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): self.plot_sand , = self.axis_vertical_profile_SSC_sand.plot( stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][:, self.slider_sand.value() -1], -stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]], linestyle="solid", linewidth=1, color="k") self.pcm_SSC_sand_vertical_line.set_data( stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1], self.slider_sand.value() - 1] * np.ones(stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]].shape), -stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ 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[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]]), -np.nanmin(stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]])]) else: self.plot_sand , = self.axis_vertical_profile_SSC_sand.plot( stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][:, self.slider_sand.value() -1], -stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]], linestyle="solid", linewidth=1, color="k") self.pcm_SSC_sand_vertical_line.set_data( stg.time[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1], self.slider_sand.value() - 1] * np.ones(stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]].shape), -stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]]) self.figure_SSC_sand.canvas.draw_idle() self.axis_vertical_profile_SSC_sand.set_ylim( [-np.nanmax(stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]]), -np.nanmin(stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ 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): if stg.filename_BS_noise_data != []: if stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): self.axis_vertical_profile_SSC_sand.cla() if stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): self.axis_vertical_profile_SSC_sand.plot( stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][:, self.slider_sand.value() - 1], -stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]], linestyle="solid", linewidth=1, color="k") self.pcm_SSC_sand_vertical_line.set_data( stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1], self.slider_sand.value() - 1] * np.ones(stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]].shape), -stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ 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[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]]), -np.nanmin(stg.depth_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]])]) else: self.axis_vertical_profile_SSC_sand.plot( stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][:, self.slider_sand.value() - 1], -stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]], linestyle="solid", linewidth=1, color="k") self.pcm_SSC_sand_vertical_line.set_data( stg.time[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1], self.slider_sand.value() - 1] * np.ones(stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]].shape), -stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]]) self.figure_SSC_sand.canvas.draw_idle() self.axis_vertical_profile_SSC_sand.set_ylim( [-np.nanmax(stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]]), -np.nanmin(stg.depth[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]])]) if stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()].shape != (0,): time_sand_calibration = ( np.where(np.abs(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]] - stg.time_sand[ stg.sand_sample_target[0][1]]) == np.nanmin( np.abs(stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]] - stg.time_sand[ stg.sand_sample_target[0][1]])))[0][0] ) if (stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1], int(self.slider_sand.value())] == stg.time_cross_section[self.combobox_acoustic_data_choice.currentIndex()][ 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[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]] - stg.time_sand[ stg.sand_sample_target[0][1]]) == np.nanmin(np.abs(stg.time[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1]] - stg.time_sand[ stg.sand_sample_target[0][1]])))[0][0] ) if (stg.time[self.combobox_acoustic_data_choice.currentIndex()][ stg.frequency_for_inversion[1], int(self.slider_sand.value())] == stg.time[self.combobox_acoustic_data_choice.currentIndex()][ 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: for k in range(self.combobox_acoustic_data_choice.count()): if stg.time_cross_section[k].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time if stg.depth_cross_section[k].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth t = np.repeat( time_data[k][stg.frequency_for_inversion[1]], depth_data[k].shape[1] ) r = np.zeros( depth_data[k].shape[1] * time_data[k].shape[1] ) for i in range(time_data[k].shape[1]): for j in range(depth_data[k].shape[1]): r_id = i * depth_data[k].shape[1] + j r[r_id] = depth_data[k][ int(stg.frequency_for_inversion[1]), j ] 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]) result = pd.DataFrame( { 'Time (sec)': list(t), 'Depth (m)': list(r), 'SSC_fine (g/L)': list( stg.SSC_fine[k].reshape(t.shape[0]) ), 'SSC_sand (g/L)': list( stg.SSC_sand[k].reshape(t.shape[0]) ), } ) gc.collect() # Force garbade collection result.to_excel( writer, index=False, na_rep='NA', sheet_name=stg.data_preprocessed[k], ) 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) # 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. ''' # Retrieve the time stamps and vertical positions: if stg.time_cross_section[k].shape != (0,): time_data = stg.time_cross_section else: time_data = stg.time if stg.depth_cross_section[k].shape != (0,): depth_data = stg.depth_cross_section else: depth_data = stg.depth # Form the 1D arrays of time stamps and vertical positions # for the k-th dataset: time_shape = time_data[k].shape[1] depth_shape = depth_data[k].shape[1] 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][stg.frequency_for_inversion[1]], 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][ int(stg.frequency_for_inversion[1]), j ] ) # 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 )