diff --git a/main.py b/main.py index 52d150f889e289c85f14d7e559778048d26fdf4e..5dfa0e4c5a4f46e8aa928e4f4a146763af094151 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,5 @@ +import copy + import pandas as pd import open_functions as of from Classes.Measurement import Measurement @@ -15,7 +17,7 @@ class Qrame: def __init__(self): self.data_brm = None self.root = tk.Tk() - self.root.geometry('250x535') + self.root.geometry('250x585') self.root.resizable(0, 1) self.root.title('QRAME') # QRevint ADCP Massive Extraction self.root.wm_iconbitmap(r'QRAME.ico') @@ -27,6 +29,8 @@ class Qrame: self.choice3 = tk.BooleanVar(value=True) self.choice3b = tk.BooleanVar(value=True) default_text3 = "Code station HYDRO" + self.text1b = tk.StringVar(value=1) + self.text1c = tk.StringVar(value=0) self.text3 = tk.StringVar(value=default_text3) self.nav_menu4 = tk.StringVar(self.root) self.extrap_menu5 = tk.StringVar(self.root) @@ -52,6 +56,16 @@ class Qrame: padx=50, pady=4, height=1, width=10) self.brm_button.pack() + self.label1b = tk.Label(self.root, text="Time delta in hours (integer)", justify='left') + self.label1b.pack(side=tk.TOP, anchor=tk.W, padx=15) + self.Entry_1b = tk.Entry(self.root, textvariable=self.text1b) + self.Entry_1b.pack(anchor=tk.W, padx=35, ipadx=35) + + self.label1c = tk.Label(self.root, text="Time difference with Bareme (integer)", justify='left') + self.label1c.pack(side=tk.TOP, anchor=tk.W, padx=15) + self.Entry_1c = tk.Entry(self.root, textvariable=self.text1c) + self.Entry_1c.pack(anchor=tk.W, padx=35, ipadx=35) + # .dat data with entry box for Bareme station's name def some_callback(event): if self.text3.get() == default_text3: @@ -90,22 +104,19 @@ class Qrame: # Chose extrap self.label5 = tk.Label(self.root, text="Extrapolation law") self.label5.pack(side=tk.TOP, anchor=tk.W, padx=15) - self.extrap_menu5.set("Default") # default value + # Chose exp value self.Entry_5 = tk.Entry(self.root, textvariable=self.text5) + # Chose if personnalize exp self.Checkbutton_5 = tk.Checkbutton(self.root, text='Personnalize exp.', variable=self.choice5, command=lambda e=[self.Entry_5], v=self.choice5: self.naccheck(e, v)) - + # Chose law self.Option_extrap5 = tk.OptionMenu(self.root, self.extrap_menu5, "Default", "Power", "CNS", "3-points", command=lambda e=self.Checkbutton_5, v=self.extrap_menu5: self.nanmenu(e, v)) self.Option_extrap5.pack(anchor=tk.W, padx=35, ipadx=35) - self.Checkbutton_5.pack(side=tk.TOP, anchor=tk.W, ipadx=15) self.Entry_5.pack(anchor=tk.W, padx=35, ipadx=35) - # Lock by default - self.Checkbutton_5["state"] = "disabled" - self.Entry_5.configure(state='disabled') # No moving-bed detected self.Checkbutton_6 = tk.Checkbutton(self.root, text='No moving-bed detected', variable=self.choice6) @@ -164,25 +175,38 @@ class Qrame: self.naccheck([self.Entry_5], self.choice5) def import_data(self): - path_folder, path_meas, type_meas, name_meas = of.select_directory() + self.import_button["state"] = "disabled" + self.run_button["state"] = "disabled" + path_folder, path_meas, type_meas, name_meas, no_adcp = of.select_directory() if type_meas is not None: if len(type_meas) == 0: tk.messagebox.showerror(title='Wrong folder', message='Invalid folder selected.') + self.import_button["state"] = "normal" return else: + if len(no_adcp) > 0: + print('errors in folders') + no_adcp_str = ', '.join(no_adcp) + tk.messagebox.showwarning(title='No ADCP measurement', + message=f'No ADCP measure file found in the folders : {no_adcp_str}') + self.disable_all(way=False) self.path_folder = path_folder self.path_meas = path_meas self.type_meas = type_meas self.name_meas = name_meas self.name_folder = self.path_folder.split('\\')[-1] + self.label0.config(wraplength=self.root.winfo_width()) self.label0.config(text=f'ADCP folder: {self.name_folder}') self.label0.config(wraplength=self.label0.winfo_width()) + self.run_button["state"] = "normal" + self.import_button["state"] = "normal" def get_brm_export(self): self.data_brm = None # Select a file path path_brm = of.select_file() + print(path_brm) if path_brm: try: with open(path_brm) as f: @@ -213,12 +237,18 @@ class Qrame: range(len(data_brm['time_start']))] self.data_brm = data_brm name_brm = path_brm.split('/')[-1] + self.label1.config(wraplength=self.root.winfo_width()) self.label1.config(text=f'HYDRO2 file: {name_brm}') self.label1.config(wraplength=self.label1.winfo_width()) + self.Entry_1b.configure(state='normal') + self.Entry_1c.configure(state='normal') except: tk.messagebox.showerror(title='Invalid Barème import', message='Please enter a valid Barème import.') else: - self.brm_button.config(text=f'Import HYDRO2 : ***') + self.data_brm = None + self.Entry_1b.configure(state='disabled') + self.Entry_1c.configure(state='disabled') + self.label1.config(text="HYDRO2 file: ***") def disable_all(self, way=True, import_data=True): # Able/Disable button @@ -228,6 +258,8 @@ class Qrame: self.Checkbutton_3["state"] = "disabled" self.Entry_3.configure(state='disabled') self.brm_button["state"] = "disabled" + self.Entry_1b.configure(state="disabled") + self.Entry_1c.configure(state="disabled") self.Checkbutton_1["state"] = "disabled" self.Checkbutton_2["state"] = "disabled" self.Checkbutton_3b["state"] = "disabled" @@ -244,6 +276,9 @@ class Qrame: self.Checkbutton_3["state"] = "normal" self.naccheck([self.Entry_3], self.choice3) self.brm_button["state"] = "normal" + if self.data_brm is not None: + self.Entry_1b.configure(state='normal') + self.Entry_1c.configure(state='normal') self.Checkbutton_1["state"] = "normal" self.Checkbutton_2["state"] = "normal" self.Checkbutton_3b["state"] = "normal" @@ -255,7 +290,11 @@ class Qrame: self.close_button["state"] = "normal" def run(self): + print(self.run_button["state"]) + if self.run_button["state"] == "disabled": + return self.disable_all(way=True) + # Default value nav_ref = None fit_method = 'Automatic' @@ -270,9 +309,23 @@ class Qrame: # Get input save_as_dat = self.choice3.get() name_station = self.text3.get() + try: + delta_time = int(self.text1b.get()) + except ValueError: + tk.messagebox.showerror(title='Invalid time delta', message='Please enter correct time delta as integer.') + self.disable_all(way=False) + return + try: + lag_time = int(self.text1c.get()) + except ValueError: + tk.messagebox.showerror(title='Invalid lag time', + message='Please enter correct time difference as integer.') + self.disable_all(way=False) + return + save_as_csv = self.choice1.get() save_as_bad = self.choice2.get() - save_general = self.choice3b.get() + # save_general = self.choice3b.get() input_nav = self.nav_menu4.get() input_extrap_type = self.extrap_menu5.get() input_extrap_mode = self.choice5.get() @@ -309,7 +362,7 @@ class Qrame: if save_as_dat and self.data_brm is None: res = tk.messagebox.askquestion('No Barème import', 'You didn\'t select a Barème import, stages will be set ' - 'at -999. Do you want to continue ?') + 'at -999m or -32m. Do you want to continue ?') if res != 'yes': self.disable_all(way=False) return @@ -350,13 +403,15 @@ class Qrame: default_checked = [] current_checked = [] error_meas = [] + for id_meas in range(len(self.path_meas)): + print(f"==================== {id_meas} ====================") print(self.path_meas[id_meas]) print(self.type_meas[id_meas]) self.pb['value'] = 100 * (id_meas + 1) / len(self.path_meas) self.pb.update_idletasks() self.value_label['text'] = self.update_progress_label() - + valid_meas = False try: # Open measurement meas, checked_transect, navigation_reference = of.open_measurement(self.path_meas[id_meas], @@ -364,6 +419,11 @@ class Qrame: use_weighted=True, navigation_reference=nav_ref, run_oursin=True) + valid_meas = True + except: + error_meas.append(self.name_meas[id_meas]) + + if valid_meas: default_checked.append(str(len(checked_transect))) # Remove transect with Delta Q > 40% discharge = meas.mean_discharges(meas) @@ -372,7 +432,7 @@ class Qrame: for transect_id in checked_transect: per_diff = np.abs(((meas.discharge[transect_id].total - discharge['total_mean']) / discharge['total_mean']) * 100) - if per_diff > 40 and len(checked_transect) >= 4: + if per_diff > 40 and len(checked_transect) > 4: remove.append(checked_transect.index(transect_id)) if remove: @@ -392,32 +452,29 @@ class Qrame: if no_bt and meas.current_settings()['NavRef'] == 'bt_vel': meas.observed_no_moving_bed = True meas.oursin.compute_oursin(meas) - except: - error_meas.append(self.name_meas[id_meas]) - # Date data - date_value = meas.transects[checked_transect[0]].date_time.start_serial_time - date_list.append(datetime.datetime.strftime(datetime.datetime.utcfromtimestamp(date_value), - '%Y-%m-%d %H:%M')) - date_day_list.append(datetime.datetime.strftime(datetime.datetime.utcfromtimestamp(date_value), - '%Y%m%d')) - date_hour_start.append(datetime.datetime.strftime(datetime.datetime.utcfromtimestamp(date_value), - '%H:%M')) - - date_hour_end.append( - datetime.datetime.strftime(datetime.datetime.utcfromtimestamp( - meas.transects[checked_transect[-1]].date_time.end_serial_time), '%H:%M')) - - # Cross-section width and area - trans_prop = Measurement.compute_measurement_properties(meas) - n_transects = len(meas.transects) - width_list.append(trans_prop['width'][n_transects]) - area_list.append(trans_prop['area'][n_transects]) - - # Discharge data - uh_list.append(0) - q_list.append(meas.mean_discharges(meas)['total_mean']) - uq_list.append(meas.oursin.u_measurement['total_95'][0]) + # Date data + date_value = meas.transects[checked_transect[0]].date_time.start_serial_time + date_lag = datetime.datetime.utcfromtimestamp(date_value) + datetime.timedelta(hours=lag_time) + date_list.append(datetime.datetime.strftime(date_lag, '%Y-%m-%d %H:%M')) + date_day_list.append(datetime.datetime.strftime(date_lag, '%Y%m%d')) + date_hour_start.append(datetime.datetime.strftime(date_lag, '%H:%M')) + + date_hour_end.append( + datetime.datetime.strftime(datetime.datetime.utcfromtimestamp( + meas.transects[checked_transect[-1]].date_time.end_serial_time) + + datetime.timedelta(hours=lag_time), '%H:%M')) + + # Cross-section width and area + trans_prop = Measurement.compute_measurement_properties(meas) + n_transects = len(meas.transects) + width_list.append(trans_prop['width'][n_transects]) + area_list.append(trans_prop['area'][n_transects]) + + # Discharge data + uh_list.append(0) + q_list.append(meas.mean_discharges(meas)['total_mean']) + uq_list.append(meas.oursin.u_measurement['total_95'][0]) # Add height with closest date if Bareme import if data_brm is not None: @@ -436,7 +493,8 @@ class Qrame: for date in date_mid: closest_date.append(min(data_brm['time_mid'], key=lambda x: abs(x - date))) time_diff.append(abs(closest_date[-1] - date)) - id_delta = [i for i in range(len(time_diff)) if time_diff[i] > datetime.timedelta(hours=1)] + id_delta = [i for i in range(len(time_diff)) if time_diff[i] > + datetime.timedelta(hours=max(1, abs(delta_time)))] for index in id_delta: closest_date[index] = None # Find if duplicate in selected date @@ -466,8 +524,9 @@ class Qrame: if closest_date[i] is None: h_csv.append(-999) else: - h_csv.append(float(data_brm.loc[ - data_brm['time_mid'] == closest_date[i], 'cote'].values[0])/1000) + h_csv.append(float(data_brm.loc[ + data_brm['time_mid'] == closest_date[i], 'cote'].values[ + 0]) / 1000) else: h_csv = [-999] * len(q_list) csv_q = [np.round(i, 2) for i in q_list] @@ -487,7 +546,8 @@ class Qrame: h_bad.append(-999) else: h_bad.append(float(data_brm.loc[ - data_brm['time_mid'] == closest_date[i], 'cote'].values[0])/1000) + data_brm['time_mid'] == closest_date[i], 'cote'].values[ + 0]) / 1000) else: h_bad = [-999] * len(q_list) # Absolute uncertainty 68% @@ -506,7 +566,7 @@ class Qrame: if data_brm is not None: j = -1 mean_vel = [a / b for a, b in zip(q_list, area_list)] - q_list_brm = [1000 * i for i in np.round(q_list, 2)] + q_list_brm = [np.round(1000 * i) for i in np.round(q_list, 2)] # Update Barème import for i in range(len(closest_date)): if closest_date[i] is not None: @@ -520,8 +580,8 @@ class Qrame: f'Extrap {extrap_str}{exp_str}]' data_brm.loc[data_brm['time_mid'] == closest_date[i], - ['debit', 'incertitude', 'sect_mouillee', 'larg_miroir', - 'vitesse_moyenne', 'commentaire']] = \ + ['debit', 'incertitude', 'sect_mouillee', 'larg_miroir', + 'vitesse_moyenne', 'commentaire']] = \ [q_list_brm[i], np.round(uq_list[i], 2), np.round(area_list[i], 2), np.round(width_list[i], 2), np.round(mean_vel[i], 2), comment] @@ -529,11 +589,11 @@ class Qrame: comment = f'QRAME add [Transect {current_checked[i]}/{default_checked[i]}, ' \ f'Extrap {extrap_str}{exp_str}]' data_brm.loc[j] = ['C', 'JGG', name_station, -999, date_day_list[i], - date_hour_start[i], date_hour_end[i], -320000, '', '', '', - q_list_brm[i], np.round(uq_list[i], 2), '', - np.round(area_list[i], 2), '', np.round(width_list[i], 2), - np.round(mean_vel[i], 2), '', '', '', comment, 'PC', '', '', - ''] + date_hour_start[i], date_hour_end[i], -32000, '', '', '', + q_list_brm[i], np.round(uq_list[i], 2), '', + np.round(area_list[i], 2), '', np.round(width_list[i], 2), + np.round(mean_vel[i], 2), '', '', '', comment, 'PC', '', '', + ''] j -= 1 # Update num for new gauging @@ -547,34 +607,15 @@ class Qrame: unmatch_row.index = unmatch_index data_brm.loc[unmatch_index] = unmatch_row - - # data_brm_by_date = data_brm.sort_values(by=['date', 'start']) - # data_brm_by_date = data_brm_by_date.rename_axis('sort_date').reset_index() - - # data_brm = data_brm.sort_values(by=['date', 'start']) - # data_brm = data_brm.rename_axis('sort_date').reset_index() - # unmatch_index = data_brm.index[data_brm['num'] == -999].tolist() - # len_max_str = len(str(unmatch_index[-1])) - # zero = '0' - # list_unmatch = [f'Q{zero*(len_max_str-len(str(i)))}{i}' for i in range(1, len(unmatch_index)+1)] - # data_brm.loc[unmatch_index, 'num'] = list_unmatch - # data_brm = data_brm.sort_values(by=['sort_date']) - # data_brm = data_brm.reset_index(drop=True) - - # gaps = [[s, e] for s, e in zip(unmatch_index, unmatch_index[1:]) if s + 1 < e] - # edges = iter(unmatch_index[:1] + sum(gaps, []) + unmatch_index[-1:]) - # unmatch = list(zip(edges, edges)) - # for start, end in unmatch: - # if start == 0: - # val_before = '0' - # else: - # val_before = data_brm.loc[[start - 1], 'num'].values[0] - # list_num = [f'{val_before} QRAME{i}' for i in range(end - start + 1)] - # data_brm.loc[start:end, 'num'] = list_num - # Delete time columns data_brm.drop(['time_start', 'time_end', 'time_mid'], axis=1, inplace=True) + # self.width_list = width_list + # self.area_list = area_list + # + # self.q_list = q_list + # self.uq_list = uq_list + if j < -1: tk.messagebox.showinfo(title='New gauging added', message='Some gaugings were not in the database, they have been ' @@ -584,15 +625,17 @@ class Qrame: length = len(q_list) range_length = [f'QRAME{i}' for i in np.arange(1, length + 1)] mean_vel = [a / b for a, b in zip(q_list, area_list)] - q_list_brm = [1000 * i for i in np.round(q_list, 2)] + q_list_brm = [np.round(1000 * i) for i in np.round(q_list, 2)] comment = [] for i in range(len(q_list_brm)): comment.append(f'QRAME add [Transect {current_checked[i]}/{default_checked[i]}, ' \ f'Extrap {extrap_str}{exp_str}]') + self.comment = comment + data_brm = pd.DataFrame( {'C': ['C'] * length, 'JGG': ['JGG'] * length, 'station_name': [self.name_folder] * length, 'num': [''] * length, 'date': date_day_list, 'date_start': date_hour_start, - 'date_end': date_hour_end, 'cote': [-320000] * length, 'cote_start': [''] * length, + 'date_end': date_hour_end, 'cote': [-32000] * length, 'cote_start': [''] * length, 'cote_end': [''] * length, 'code_station': [''] * length, 'debit': q_list_brm, 'incertitude': np.round(uq_list, 2), 'distance_station': [''] * length, 'sect_mouillee': np.round(area_list, 2), @@ -605,9 +648,8 @@ class Qrame: data_brm = data_brm.reset_index(drop=True) data_brm['num'] = range_length - # data_brm = data_brm.sort_values(by=['num']) - # data_brm = data_brm.reset_index(drop=True) length = len(data_brm) + print(f"AREA : {np.round(area_list, 2)}") df = data_brm.to_csv(header=None, index=False, sep=';').strip('\r\n').split('\n') df_str = [i.strip('\r') for i in df] df_bareme = ';\n'.join(df_str) @@ -638,11 +680,12 @@ class Qrame: except Exception as e: tk.messagebox.showerror(title='Extraction error', - message=f'An error has occured, please contact blaise.calmel@inrae.fr\n' - f'Message error : {e}') + message=f'An error has occured, please contact blaise.calmel@inrae.fr\n' + f'Message error : {e}') print('exception') # Enable button self.disable_all(way=False) + return if __name__ == '__main__':