import sys from PyQt5.QtWidgets import QWidget, QMainWindow, QApplication, QVBoxLayout, QHBoxLayout, QGroupBox, QComboBox, \ QGridLayout, QLabel, QPushButton, QSpinBox from PyQt5.QtCore import QCoreApplication, Qt from PyQt5.QtGui import QStandardItemModel import numpy as np from itertools import combinations import matplotlib.pyplot as plt from matplotlib.colors import LogNorm, BoundaryNorm, CSS4_COLORS from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolBar import Translation.constant_string as cs from View.checkable_combobox import CheckableComboBox import settings as stg from Model.acoustic_inversion_method_high_concentration import AcousticInversionMethodHighConcentration _translate = QCoreApplication.translate class AcousticInversionTab(QWidget): ''' This class generates the Acoustic Inversion Tab ''' def __init__(self, widget_tab): super().__init__() self.inv_hc = AcousticInversionMethodHighConcentration() ### --- General layout of widgets --- self.verticalLayoutMain = QVBoxLayout(widget_tab) self.horizontalLayoutTop = QHBoxLayout() self.verticalLayoutMain.addLayout(self.horizontalLayoutTop, 4) # 1O units is 100% , 1 units is 10% self.horizontalLayoutBottom = QHBoxLayout() self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 6) ### --- Layout of groupbox in the Top horizontal layout box # Acoustic inversion Options | Acoustic inversion method Settings parameter self.groupbox_acoustic_inversion_options = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_inversion_options, 3) self.groupbox_acoustic_inversion_settings_parameter = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_inversion_settings_parameter, 7) ### --- Layout of groupbox in the Bottom horizontal layout box # Plot SSC 2D field | Plot SSC graph sample vs inversion self.groupbox_SSC_2D_field = QGroupBox() self.horizontalLayoutBottom.addWidget(self.groupbox_SSC_2D_field, 6) self.groupbox_SSC_sample_vs_inversion = QGroupBox() self.horizontalLayoutBottom.addWidget(self.groupbox_SSC_sample_vs_inversion, 4) # ===================================================== # TOP HORIZONTAL BOX LAYOUT # ===================================================== # +++++++++++++++++++++++++++++++++++++++++++++++ # | Group box Acoustic inversion options | # +++++++++++++++++++++++++++++++++++++++++++++++ self.gridLayout_groupbox_acoustic_inversion_options = QGridLayout(self.groupbox_acoustic_inversion_options) self.groupbox_acoustic_inversion_options.setTitle("Acoustic inversion option") self.label_acoustic_inversion_method_choice = QLabel() self.gridLayout_groupbox_acoustic_inversion_options.addWidget( self.label_acoustic_inversion_method_choice, 0, 0, 1, 1) self.label_acoustic_inversion_method_choice.setText("Acoustic inversion method : ") self.combobox_acoustic_inversion_method_choice = QComboBox() self.gridLayout_groupbox_acoustic_inversion_options.addWidget( self.combobox_acoustic_inversion_method_choice, 0, 1, 1, 1) self.combobox_acoustic_inversion_method_choice.addItems([" ", "Acoustic inversion method 1"]) self.combobox_acoustic_inversion_method_choice.currentIndexChanged.connect( self.acoustic_inversion_method_choice) self.label_sample_choice = QLabel() self.gridLayout_groupbox_acoustic_inversion_options.addWidget(self.label_sample_choice, 1, 0, 1, 1) self.label_sample_choice.setText("Calibration samples : ") self.combobox_calibration_samples = CheckableComboBox() self.gridLayout_groupbox_acoustic_inversion_options.addWidget(self.combobox_calibration_samples, 1, 1, 1, 1) self.combobox_calibration_samples.currentIndexChanged.connect(self.sample_choice) # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # | Group box Acoustic inversion method settings parameter | # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ self.gridLayout_groupbox_acoustic_inversion_settings_parameter \ = QGridLayout(self.groupbox_acoustic_inversion_settings_parameter) self.groupbox_acoustic_inversion_settings_parameter.setTitle("Acoustic inversion method settings parameter") self.label_temperature = QLabel() self.label_temperature.setText("Temperature : ") self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.label_temperature, 0, 0, 1, 1) self.spinbox_temperature = QSpinBox() self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.spinbox_temperature, 0, 1, 1, 1) self.spinbox_temperature.valueChanged.connect(self.temperature_value) self.label_frequencies_pairs_to_compute_VBI = QLabel() self.label_frequencies_pairs_to_compute_VBI.setText("frequencies for VBI : ") self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget( self.label_frequencies_pairs_to_compute_VBI, 1, 0, 1, 1) self.combobox_frequencies_VBI = CheckableComboBox() self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget( self.combobox_frequencies_VBI, 1, 1, 1, 1) self.combobox_frequencies_VBI.currentIndexChanged.connect(self.frequencies_pair_choice_to_compute_VBI) self.label_frequency_to_compute_SSC = QLabel() self.label_frequency_to_compute_SSC.setText("frequencies for SSC : ") self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget( self.label_frequency_to_compute_SSC, 2, 0, 1, 1) self.combobox_frequency_SSC = CheckableComboBox() self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget( self.combobox_frequency_SSC, 2, 1, 1, 1) self.combobox_frequency_SSC.currentIndexChanged.connect(self.frequency_choice_to_compute_SSC) self.pushbutton_run = QPushButton() self.pushbutton_run.setText("RUN") self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.pushbutton_run, 3, 0, 1, 1) self.pushbutton_run.clicked.connect(self.compute_acoustic_inversion_method_high_concentration) self.pushbutton_plot = QPushButton() self.pushbutton_plot.setText("PLOT") self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.pushbutton_plot, 3, 1, 1, 1) self.pushbutton_plot.clicked.connect(self.plot_SSC_2D_fields) self.pushbutton_plot.clicked.connect(self.plot_SSC_inverse_VS_measured) # ===================================================== # BOTTOM HORIZONTAL BOX LAYOUT # ===================================================== # +++++++++++++++++++++++++++++++++++++++++++++++ # | Group box SSC 2D field | # +++++++++++++++++++++++++++++++++++++++++++++++ self.verticalLayout_groupbox_SSC_2D_field = QVBoxLayout(self.groupbox_SSC_2D_field) self.groupbox_SSC_2D_field.setTitle("Suspended Sediment Concentration 2D plot") self.canvas_SSC_2D_field = None # +++++++++++++++++++++++++++++++++++++++++++++++ # | Group box plot samples vs inversion | # +++++++++++++++++++++++++++++++++++++++++++++++ self.verticalLayout_groupbox_SSC_sample_vs_inversion = QVBoxLayout(self.groupbox_SSC_sample_vs_inversion) self.groupbox_SSC_sample_vs_inversion.setTitle("Suspended Sediment Concentration : sample vs inversion") self.canvas_SSC_sample_vs_inversion = None # # self.verticalLayout_groupbox_sediment_concentration_2Dplot = QVBoxLayout(self.groupbox_sediment_concentration_2Dplot) # # self.figure_SSC_2Dplot, self.axis_SSC_2Dplot = plt.subplots(nrows=2, ncols=1) # self.canvas_sediments2DPlot = FigureCanvas(self.figure_SSC_2Dplot) # self.toolbar_concentration_2Dplot = NavigationToolBar(self.canvas_sediments2DPlot, self) # self.plot_SSC_fine() # self.plot_SSC_sand() # # self.verticalLayout_groupbox_sediment_concentration_2Dplot.addWidget(self.toolbar_concentration_2Dplot) # self.verticalLayout_groupbox_sediment_concentration_2Dplot.addWidget(self.canvas_sediments2DPlot) # # # self.horizontalLayout_Bottom_acousticInversionTab.addWidget(self.canvas_sediments2DPlot) # self.horizontalLayout_Bottom_acousticInversionTab.addWidget(self.groupbox_sediment_concentration_2Dplot, 7) # # # # self.groupbox_sediment_concentration_sample_vs_measurement.setTitle( # # "Suspended sediment concentration plot : acoustic inversion theory VS measurements") # # self.verticalLayout_groupbox_sediment_concentration_sample_vs_measurement = QVBoxLayout( # self.groupbox_sediment_concentration_sample_vs_measurement) # # self.figure_inverseSSC_vs_measuredSSC, self.axis_inverseSSC_vs_measuredSSC = plt.subplots(nrows=1, ncols=1) # self.canvas_InverseSSC_vs_MeasuredSSC = FigureCanvas(self.figure_inverseSSC_vs_measuredSSC) # self.toolbar_InverseSSC_vs_MeasuredSSC = NavigationToolBar(self.canvas_InverseSSC_vs_MeasuredSSC, self) # # self.verticalLayout_groupbox_sediment_concentration_sample_vs_measurement.addWidget( # # self.toolbar_InverseSSC_vs_MeasuredSSC) # self.verticalLayout_groupbox_sediment_concentration_sample_vs_measurement.addWidget( # self.canvas_InverseSSC_vs_MeasuredSSC, 3) # # self.horizontalLayout_Bottom_acousticInversionTab.addWidget(self.canvas_InverseSSC_vs_MeasuredSSC) # # self.horizontalLayout_Bottom_acousticInversionTab.addWidget( # self.groupbox_sediment_concentration_sample_vs_measurement) # # self.verticalLayout_acoustic_inversion_tab.addLayout(self.horizontalLayout_Bottom_acousticInversionTab, 6) # # self.retranslate_acoustic_inversion_tab() # ---------------------------------------------------------------------------------------------------------------- # -------------------- Functions -------------------- # def retranslate_acoustic_inversion_tab(self): # # self.groupbox_AcousticInversionOption.setTitle(_translate("CONSTANT_STRING", cs.ACOUSTIC_INVERSION_OPTIONS)) # self.groupbox_sediment_concentration_2Dplot.setTitle(_translate("CONSTANT_STRING", cs.FINE_AND_SAND_SEDIMENTS_CONCENTRATION_2D_FIELD)) # self.groupbox_sediment_concentration_sample_vs_measurement.setTitle(_translate("CONSTANT_STRING", cs.SUSPENDED_SEDIMENT_CONCENTRATION_PLOT)) def acoustic_inversion_method_choice(self): if self.combobox_acoustic_inversion_method_choice.currentIndex() == 1: # --- add items in combobox of samples to calibrate acoustic inversion method --- samples_vertical_line = np.split(stg.samples, np.where(np.diff(stg.sample_time) != 0)[0]+1) for s in samples_vertical_line: self.combobox_calibration_samples.addItem(" - ".join([i for i in s])) for i in range(len(samples_vertical_line)): self.combobox_calibration_samples.setItemChecked(i, False) # --- add items in combobox of frequencies for VBI computation --- for k in combinations(stg.freq_text, 2): self.combobox_frequencies_VBI.addItem(k[0] + " - " + k[1]) # print(k) for i in range(len(list(combinations(stg.freq_text, 2)))): self.combobox_frequencies_VBI.setItemChecked(i, False) def sample_choice(self): sample_position = [] for i in range(self.combobox_calibration_samples.count()): if self.combobox_calibration_samples.itemChecked(i): sample_position.append(i) elif (i in sample_position) and (not self.combobox_calibration_samples.itemChecked(i)): sample_position.remove(i) def frequencies_pair_choice_to_compute_VBI(self): freq_combination = list(combinations(stg.freq, 2)) frequencies_position = [] for i in range(self.combobox_frequencies_VBI.count()): if self.combobox_frequencies_VBI.itemChecked(i): frequencies_position.append(i) elif (i in frequencies_position) and (not self.combobox_frequencies_VBI.itemChecked(i)): frequencies_position.remove(i) if len(frequencies_position) != 0: # print(frequencies_position) # print(freq_combination[frequencies_position[0]][0], freq_combination[frequencies_position[0]][1]) stg.frequencies_pair = ( np.array([[int(np.where(stg.freq == freq_combination[frequencies_position[0]][0])[0][0]), freq_combination[frequencies_position[0]][0]], [int(np.where(stg.freq == freq_combination[frequencies_position[0]][1])[0][0]), freq_combination[frequencies_position[0]][1]]])) # print(type(stg.frequencies_pair)) # print(stg.frequencies_pair) # print(stg.frequencies_pair[1, 0]) # print(type(stg.frequencies_pair[0]), stg.frequencies_pair[0], # np.where(stg.freq == stg.frequencies_pair[0])[0][0]) # print(type(stg.frequencies_pair[1]), stg.frequencies_pair[1], # np.where(stg.freq == stg.frequencies_pair[1])[0][0]) # --- add items in combobox of frequency for SSC computation --- for k in range(stg.frequencies_pair.shape[0]): self.combobox_frequency_SSC.addItem(str(1e-6*stg.frequencies_pair[k, 1]) + " MHz") for i in range(stg.frequencies_pair.shape[0]): self.combobox_frequency_SSC.setItemChecked(i, False) def frequency_choice_to_compute_SSC(self, index): # print(self.combobox_frequency_SSC.currentText()) # print(self.combobox_frequency_SSC.currentIndex()) # print(self.combobox_frequency_SSC.itemChecked(index)) if self.combobox_frequency_SSC.itemChecked(index): # # itemChecked(index)): # currentIndex() == 0) or (self.combobox_frequency_SSC.currentIndex() == 1): # print(self.combobox_frequency_SSC.currentText()) # print(stg.freq_text) # print(np.where(np.array(stg.freq_text) == self.combobox_frequency_SSC.currentText())) stg.frequency_to_compute_SSC \ = np.array([int(np.where(np.array(stg.freq_text) == self.combobox_frequency_SSC.currentText())[0][0]), stg.freq[int(np.where(np.array(stg.freq_text) == self.combobox_frequency_SSC.currentText())[0][0])]]) # print("stg.frequency_to_compute_SSC ", stg.frequency_to_compute_SSC) def temperature_value(self): stg.temperature = self.spinbox_temperature.value() # print(stg.temperature) def compute_acoustic_inversion_method_high_concentration(self): stg.water_attenuation = self.inv_hc.water_attenuation(stg.frequencies_pair[0, 1], stg.frequencies_pair[1, 1], stg.temperature) # print("water attenuation ", stg.water_attenuation) stg.water_velocity = self.inv_hc.water_velocity(stg.temperature) # print("water velocity ", stg.water_velocity) stg.kt_corrected = self.inv_hc.kt_corrected(stg.r, stg.water_velocity, stg.gain_rx[[int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])]], stg.gain_tx[[int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])]], stg.kt[[int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])]]) # print("kt ", stg.kt_corrected) # print("kt shape ", stg.kt_corrected.shape) stg.kt_corrected_2D = np.repeat(stg.kt_corrected, stg.r.shape[0], axis=0) # print("kt 2D ", stg.kt_corrected_2D) # print("kt 2D shape ", stg.kt_corrected_2D.shape) stg.kt_corrected_3D = np.zeros((stg.kt_corrected_2D.shape[1], stg.kt_corrected_2D.shape[0], stg.t.shape[0])) # print("stg.t.shape ", stg.t.shape) # print("kt corrected 3D zeros shape ", stg.kt_corrected_3D.shape) for k in range(stg.kt_corrected_2D.shape[1]): stg.kt_corrected_3D[k, :, :] = np.repeat(stg.kt_corrected_2D, stg.t.shape[0], axis=1)[:, k*stg.t.shape[0]:(k+1)*stg.t.shape[0]] print("kt 3D ", stg.kt_corrected_3D) print("kt 3D shape ", stg.kt_corrected_3D.shape) # print("kt 2D", np.repeat(stg.kt_corrected[:, :, np.newaxis], stg.t.shape[0], axis=2)) stg.J_cross_section = self.inv_hc.j_cross_section(stg.BS_data[:, [int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[0, 0])], :], stg.r_2D, stg.kt_corrected_3D) print("J ", stg.J_cross_section) print("J sahpe ", stg.J_cross_section.shape) stg.X_exponent = self.inv_hc.X_exponent(self.combobox_frequencies_VBI.currentIndex()) print("X ", stg.X_exponent) stg.zeta = self.inv_hc.zeta(int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])) print("zeta ", stg.zeta) # print("stg.frequencies_pair ", stg.frequencies_pair) # print("stg.frequencies_pair[0, 0]", int(stg.frequencies_pair[0, 0])) # print("int(stg.frequencies_pair[1, 0]", int(stg.frequencies_pair[1, 0])) stg.ks = self.inv_hc.ks(int(stg.frequency_to_compute_SSC[0])) print("ks ", stg.ks) stg.VBI_cross_section = self.inv_hc.VBI_cross_section(stg.frequencies_pair[0, 1], stg.frequencies_pair[1, 1], stg.zeta[0], # zeta is already limited to the frequencies pairs so that we just need to select indices 0 and 1 stg.zeta[1], stg.J_cross_section[0, :, :], stg.J_cross_section[1, :, :], stg.r_2D, stg.water_attenuation[0], stg.water_attenuation[1], stg.X_exponent) # print("VBI shape ", stg.VBI_cross_section.shape) # print(int(self.combobox_frequency_SSC.currentIndex())) # print(stg.zeta[int(self.combobox_frequency_SSC.currentIndex())]) stg.SSC_fine = self.inv_hc.SSC_fine(stg.zeta[int(self.combobox_frequency_SSC.currentIndex())], stg.r_2D, stg.VBI_cross_section, stg.frequency_to_compute_SSC[1], stg.X_exponent, stg.J_cross_section[self.combobox_frequency_SSC.currentIndex(), :, :]) # print("SSC fine shape ", stg.SSC_fine.shape) stg.SSC_sand = self.inv_hc.SSC_sand(stg.VBI_cross_section, stg.frequency_to_compute_SSC[1], stg.X_exponent, stg.ks) # print("SSC sand shape ", stg.SSC_sand.shape) def plot_SSC_2D_fields(self): if self.canvas_SSC_2D_field == None: self.figure_SSC_2D_field, self.axis_SSC_2D_field = plt.subplots(nrows=2, ncols=1, layout="constrained") self.canvas_SSC_2D_field = FigureCanvas(self.figure_SSC_2D_field) self.verticalLayout_groupbox_SSC_2D_field.addWidget(self.canvas_SSC_2D_field) self.plot_SSC_fine() self.plot_SSC_sand() def plot_SSC_fine(self): val_min = 1e-2 #np.nanmin(self.model.SSC_fine[:, :]) # val_max = 15 #np.nanmax(self.model.SSC_fine[:, :]) # # print('val_min=', val_min) # print('val_max=', val_max) # if val_min == 0: # val_min = 0.5 # print('val_min update =', val_min) pcm_SSC_fine = self.axis_SSC_2D_field[0].pcolormesh(stg.t, -stg.r, stg.J_cross_section[0, :, :], cmap='rainbow', # norm=LogNorm(vmin=val_min, vmax=val_max), shading='gouraud') self.axis_SSC_2D_field[0].plot(stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid") self.figure_SSC_2D_field.supxlabel("Time (sec)", fontsize=10) self.figure_SSC_2D_field.supylabel("Depth (m)", fontsize=10) cbar_SSC_fine = self.figure_SSC_2D_field.colorbar(pcm_SSC_fine, ax=self.axis_SSC_2D_field[0], shrink=1, location='right') cbar_SSC_fine.set_label(label='Fine SSC (g/L', rotation=270, labelpad=15) self.figure_SSC_2D_field.canvas.draw_idle() def plot_SSC_sand(self): val_min = np.nanmin(stg.VBI_cross_section) #1e-2 #np.nanmin(self.model.SSC_fine[:, :]) # val_max = np.nanmax(stg.VBI_cross_section) #15 #np.nanmax(self.model.SSC_fine[:, :]) # # print('val_min=', val_min) # print('val_max=', val_max) # if val_min == 0: # val_min = 0.5 # print('val_min update =', val_min) pcm_SSC_sand = self.axis_SSC_2D_field[1].pcolormesh(stg.t, -stg.r, stg.J_cross_section[1, :, :], cmap='rainbow', # vmin=val_min, vmax=val_max, # norm=LogNorm(vmin=val_min, vmax=val_max), shading='gouraud') self.axis_SSC_2D_field[1].plot(stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid") self.figure_SSC_2D_field.supxlabel("Time (sec)", fontsize=10) self.figure_SSC_2D_field.supylabel("Depth (m)", fontsize=10) cbar_SSC_sand = self.figure_SSC_2D_field.colorbar(pcm_SSC_sand, ax=self.axis_SSC_2D_field[1], shrink=1, location='right') cbar_SSC_sand.set_label(label='Sand SSC (g/L', rotation=270, labelpad=15) self.figure_SSC_2D_field.canvas.draw_idle() def plot_SSC_inverse_VS_measured(self): sample_depth_position = [] for i in range(stg.sample_depth.shape[0]): sample_depth_position.append( np.where(np.abs(stg.r + stg.sample_depth[i]) == np.min(np.abs(stg.r + stg.sample_depth[i])))[0][0]) sample_time_position = [] for j in range(stg.sample_time.shape[0]): sample_time_position.append( np.where(np.abs(stg.t - stg.sample_time[j]) == np.min(np.abs(stg.t - stg.sample_time[j])))[0][0]) if self.canvas_SSC_sample_vs_inversion == None: self.figure_SSC_sample_vs_inversion, self.axis_SSC_sample_vs_inversion = plt.subplots(nrows=1, ncols=1, layout="constrained") self.canvas_SSC_sample_vs_inversion = FigureCanvas(self.figure_SSC_sample_vs_inversion) self.verticalLayout_groupbox_SSC_sample_vs_inversion.addWidget(self.canvas_SSC_sample_vs_inversion) self.axis_SSC_sample_vs_inversion.plot(stg.Ctot_fine, stg.SSC_fine[sample_depth_position, sample_time_position], ls=" ", marker='v', color='black', label='Fine SSC') self.axis_SSC_sample_vs_inversion.plot(stg.Ctot_sand, stg.SSC_sand[sample_depth_position, sample_time_position], ls=" ", marker='x', color='black', label='Sand SSC') self.axis_SSC_sample_vs_inversion.set_xscale('log') self.axis_SSC_sample_vs_inversion.set_yscale('log') self.axis_SSC_sample_vs_inversion.plot([0.5e-2, 20], [0.5e-2, 20], color='black', lw=1) self.axis_SSC_sample_vs_inversion.set_xlabel('Measured SSC (g/l)', weight='bold') self.axis_SSC_sample_vs_inversion.set_ylabel('Inverse SSC (g/l)', weight='bold') self.axis_SSC_sample_vs_inversion.legend()