def figure_fstress(qmod_all, vh_all, name_inv, path_im, name_river, fig_opt = {}): """ This function creates the figures for Fstress, notably the suitability index as a function of discharge for all rivers :param qmod_all: the modelled discharge for each river :param vh_all: the suitability indoex for each invertebrate species for each river :param name_inv: The four letter code of each selected invetebrate :param path_im: the path where to save the figure :param name_river: the name of the river :param fig_opt: the figure option in a dictionnary """ if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() plt.rcParams['figure.figsize'] = fig_opt['width'], fig_opt['height'] plt.rcParams['font.size'] = fig_opt['font_size'] plt.rcParams['lines.linewidth'] = fig_opt['line_width'] format = int(fig_opt['format']) plt.rcParams['axes.grid'] = fig_opt['grid'] mpl.rcParams['pdf.fonttype'] = 42 name_fig = 'test_fig' i = 0 for r in name_river: qmod = qmod_all[i] j = vh_all[i].T fig = plt.figure() ax = plt.subplot(111) for e in range(0, len(name_inv)): plt.plot(qmod, j[e, :], '-', label=name_inv[e]) plt.xlabel('Q [m$^{3}$/sec]') plt.ylabel('Index J [ ]') if fig_opt['language'] == 0: plt.title('Suitability index J - River: ' + r) elif fig_opt['language'] == 1: plt.title('Index de suitabilité J - Rivère: ' + r) else: plt.title('Suitability index J - River: ' + r) box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.7, box.height]) lgd = plt.legend(bbox_to_anchor=(1.60, 1), loc='upper right', ncol=1) if format == 0 or format == 1: name_fig = os.path.join(path_im, 'Fstress_' + r + "_suitability_index" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.png') if format == 0 or format == 3: name_fig = os.path.join(path_im, 'Fstress_' + r + "_suitability_index" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.pdf') if format == 2: name_fig = os.path.join(path_im, 'Fstress_' + r + "_suitability_index" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.jpg') fig.savefig(os.path.join(path_im, name_fig), bbox_extra_artists=(lgd,), bbox_inches='tight', dpi=fig_opt['resolution'], transparent=True) i += 1
def fstress_test(qmod_all, vh_all, name_inv, name_river, path_rre, fig_opt={}): """ This functions compares the output of the C programm of FStress and the output of this script. it is not used by HABBY, but it is practical to debug. :param qmod_all: the modelled discharge for each river :param vh_all: the suitability indoex for each invertebrate species for each river :param name_inv: The four letter code of each selected invetebrate :param name_river: the name of the river :param path_rre: the path to the C output """ if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() plt.rcParams['figure.figsize'] = fig_opt['width'], fig_opt['height'] plt.rcParams['font.size'] = fig_opt['font_size'] plt.rcParams['lines.linewidth'] = fig_opt['line_width'] format1 = int(fig_opt['format']) plt.rcParams['axes.grid'] = fig_opt['grid'] mpl.rcParams['pdf.fonttype'] = 42 i = 0 for r in name_river: # get the C data for this river namefile = os.path.join(path_rre, r + 'rre.txt') c_data = np.loadtxt(namefile) namefile = os.path.join(path_rre, r + 'rrd.txt') dis_data = np.loadtxt(namefile) # modelled by python data qmod = qmod_all[i] j = vh_all[i].T # plot for this river fig = plt.figure() ax = plt.subplot(111) dis_c = np.exp(dis_data[:,0]) for e in range(0, min(len(name_inv),5)): plt.plot(qmod, j[e, :], '-', label=name_inv[e] + '_Python') plt.plot(dis_c, c_data[:,e], 'x', label=name_inv[e]+ '_C') plt.xlabel('Q [m$^{3}$/sec]') plt.ylabel('Index J [ ]') plt.title('Suitability index J - FStress') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) lgd = plt.legend(bbox_to_anchor=(1.4, 1), loc='upper right', ncol=1) i += 1
def main(): """ Used to test the module on the biological preference """ # test to load the pref from PRF # path = r'D:\Diane_work\pref_curve\EVHA\CourbesPref1\PREF-part1-Multispe1998' # path = r'D:\Diane_work\pref_curve\EVHA\CourbesPref1\PREF-part2-Lamourouxetal1999' # filenames = load_hdf5.get_all_filename(path, '.PRF') # for i in range(0, len(filenames)): # [height, vel, sub, code_fish, name_fish, stade, descri] = load_evha_curve(filenames[i], path) # figure_pref(height, vel, sub, code_fish, name_fish, stade) # plt.show() # test to load the pref from xml # path = r'C:\Users\diane.von-gunten\HABBY\biology' # filenames = load_hdf5.get_all_filename(path, '.xml') # for i in range(0,len(filenames)): # filename = os.path.join(path, filenames[i]) # [height, vel, sub, code_fish, name_fish, stages] = read_pref(filename) # figure_pref(height, vel, sub, code_fish, name_fish, stages) # plt.show() # test comparison # path_xml = r'C:\Users\diane.von-gunten\HABBY\biology' # path_evha = r'D:\Diane_work\pref_curve\EVHA\CourbesPref1\PREF_ALL' # test_evah_xml_pref(path_xml, path_evha) # test for pdf report path_bio = r'C:\Users\diane.von-gunten\HABBY\biology' path_bio_im = r"C:\Users\diane.von-gunten\HABBY\biology\figure_pref" path_out = r'C:\Users\diane.von-gunten\HABBY\biology' xmlfiles = ['ABL01.xml', 'ABL01.xml', 'BAM01.xml'] stages = ['adult', 'juvenile', 'fry'] fig_opt = output_fig_GUI.create_default_figoption() fig_opt['language'] = 1 create_pdf(xmlfiles, stages, path_bio, '', path_out, fig_opt)
def fig_substrate(coord_p, ikle, sub_pg, sub_dom, path_im, fig_opt={}, xtxt=[-99], ytxt=[-99], subtxt=[-99], reach_num=-99): """ The function to plot the substrate data, which was loaded before. This function will only work if the substrate data is given using the cemagref code. :param coord_p: the coordinate of the point :param ikle: the connectivity table :param sub_pg: the information on subtrate by element for the "coarser part" :param sub_dom: the information on subtrate by element for the "dominant part" :param fig_opt: the figure option as a doctionnary :param xtxt: if the data was given in txt form, the orignal x data :param ytxt: if the data was given in txt form, the orignal y data :param subtxt: if the data was given in txt form, the orignal sub data :param path_im: the path where to save the figure :param reach_num: If we plot more than one reach, this is the reach number """ if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() plt.rcParams['figure.figsize'] = fig_opt['width'], fig_opt['height'] plt.rcParams['font.size'] = fig_opt['font_size'] plt.rcParams['lines.linewidth'] = fig_opt['line_width'] format = int(fig_opt['format']) plt.rcParams['axes.grid'] = fig_opt['grid'] mpl.rcParams['pdf.fonttype'] = 42 erase1 = fig_opt['erase_id'] if erase1 == 'True': # xml in text erase1 = True else: erase1 = False sub_dom = np.array(sub_dom) sub_pg = np.array(sub_pg) if len(sub_dom) == 0 or len(sub_pg) == 0: print('no data found to plot.') return # prepare grid (to optimize) xlist = [] ylist = [] coord_p = np.array(coord_p) for i in range(0, len(ikle)): pi = 0 while pi < len( ikle[i]) - 1: # we have all sort of xells, max eight sides p = int(ikle[i] [pi]) # we start at 0 in python, careful about -1 or not p2 = int(ikle[i][pi + 1]) xlist.extend([coord_p[p, 0], coord_p[p2, 0]]) xlist.append(None) ylist.extend([coord_p[p, 1], coord_p[p2, 1]]) ylist.append(None) pi += 1 p = int(ikle[i][pi]) p2 = int(ikle[i][0]) xlist.extend([coord_p[p, 0], coord_p[p2, 0]]) xlist.append(None) ylist.extend([coord_p[p, 1], coord_p[p2, 1]]) ylist.append(None) # substrate coarser fig = plt.figure() sub1 = fig.add_subplot(211) patches = [] cmap = plt.get_cmap(fig_opt['color_map1']) colors_val = np.array( sub_pg) # convert nfloors to colors that we can use later (cemagref) # Set norm to correspond to the data for which # the colorbar will be used. norm = mpl.colors.Normalize(vmin=1, vmax=8) n = len(sub_pg) for i in range(0, n): verts = [] for j in range(0, len(ikle[i])): verts_j = coord_p[int(ikle[i][j]), :] verts.append(verts_j) polygon = Polygon(verts, closed=True, edgecolor='w') patches.append(polygon) collection = PatchCollection(patches, linewidth=0.0, cmap=cmap, norm=norm) sub1.add_collection(collection) #collection.set_color(colors) collection.set_array(colors_val) sub1.autoscale_view() #sub1.plot(xlist, ylist, c='b', linewidth=0.2) plt.xlabel('x coord []') plt.ylabel('y coord []') if reach_num == -99: if fig_opt['language'] == 0: plt.title('Substrate Grid - Coarser Data') elif fig_opt['language'] == 1: plt.title('Maillage Substrat - Plus Gros') else: plt.title('Substrate Grid - Coarser Data') else: if fig_opt['language'] == 0: plt.title('Substrate Grid - Coarser Data - Reach ' + str(reach_num)) elif fig_opt['language'] == 1: plt.title('Maillage Substrat - Plus Gros - Bief ' + str(reach_num)) else: plt.title('Substrate Grid - Coarser Data - Reach ' + str(reach_num)) # substrate dominant sub2 = fig.add_subplot(212) patches = [] colors_val = np.array( sub_dom) # convert nfloors to colors that we can use later # Set norm to correspond to the data for which # the colorbar will be used. norm = mpl.colors.Normalize(vmin=1, vmax=8) n = len(sub_dom) for i in range(0, n): verts = [] for j in range(0, len(ikle[i])): verts_j = coord_p[int(ikle[i][j]), :] verts.append(verts_j) polygon = Polygon(verts, closed=True) patches.append(polygon) collection = PatchCollection(patches, linewidth=0.0, cmap=cmap, norm=norm) sub2.add_collection(collection) collection.set_array(colors_val) sub2.autoscale_view() # cbar = plt.colorbar() # cbar.ax.set_ylabel('Substrate') #sub2.plot(xlist, ylist, c='b', linewidth=0.2) plt.xlabel('x coord []') plt.ylabel('y coord []') if reach_num == -99: if fig_opt['language'] == 0: plt.title('Substrate Grid - Dominant') elif fig_opt['language'] == 1: plt.title('Maillage Substrat - Dominant') else: plt.title('Substrate Grid - Dominant') else: if fig_opt['language'] == 0: plt.title('Substrate Grid - Dominant - Reach ' + str(reach_num)) elif fig_opt['language'] == 1: plt.title('Maillage Substrat - Dominant - Reach ' + str(reach_num)) else: plt.title('Substrate Grid - Dominant - Reach ' + str(reach_num)) # colorbar ax1 = fig.add_axes([0.92, 0.2, 0.015, 0.7]) # posistion x2, sizex2, 1= top of the figure # ColorbarBase derives from ScalarMappable and puts a colorbar # in a specified axes, so it has everything needed for a # standalone colorbar. There are many more kwargs, but the # following gives a basic continuous colorbar with ticks # and labels. cb1 = mpl.colorbar.ColorbarBase(ax1, cmap=cmap, norm=norm, orientation='vertical') cb1.set_label('Code Cemagref') #plt.tight_layout() # save the figure if not erase1: if format == 0 or format == 1: plt.savefig(os.path.join( path_im, "substrate_dom" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.png'), dpi=fig_opt['resolution'], transparent=True) if format == 0 or format == 3: plt.savefig(os.path.join( path_im, "substrate_dom" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.pdf'), dpi=fig_opt['resolution'], transparent=True) if format == 2: plt.savefig(os.path.join( path_im, "substrate_dom" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.jpg'), dpi=fig_opt['resolution'], transparent=True) else: test = calcul_hab.remove_image("substrate_dom", path_im, format) if not test: return if format == 0 or format == 1: plt.savefig(os.path.join(path_im, "substrate_dom.png"), dpi=fig_opt['resolution'], transparent=True) if format == 0 or format == 3: plt.savefig(os.path.join(path_im, "substrate_dom.pdf"), dpi=fig_opt['resolution'], transparent=True) if format == 2: plt.savefig(os.path.join(path_im, "substrate_dom.jpg"), dpi=fig_opt['resolution'], transparent=True) # if we start with txt data, plot the original data # not done usually, but we let it here to debug if xtxt != [-99]: plt.figure() subtxt = list(map(float, subtxt)) # size of the marker (to avoid having to pale, unclear figure) # this is a rough estimation, no need for precise number here d1 = 0.5 * np.sqrt((xtxt[1] - xtxt[0])**2 + (ytxt[1] - xtxt[1])**2) # dist in coordinate dist_data = np.mean( [np.max(xtxt) - np.min(xtxt), np.max(ytxt) - np.min(ytxt)]) f_len = 5 * 72 # point is 1/72 inch, figure is 5 inch large transf = f_len / dist_data s1 = 3.1 * (d1 * transf)**2 / 2 # markersize is given as an area cm = plt.cm.get_cmap('gist_rainbow') sc = plt.scatter(xtxt, ytxt, c=subtxt, vmin=np.nanmin(subtxt), vmax=np.nanmax(subtxt), s=34, cmap=cm, edgecolors='none') plt.xlabel('x coord []') plt.ylabel('y coord []') if fig_opt['language'] == 0: plt.title('Original Substrate Data (x,y)') elif fig_opt['language'] == 1: plt.title('Données Substrat Original (x,y)') else: plt.title('Original Substrate Data (x,y)') if not erase1: plt.savefig(os.path.join( path_im, "substrate_txtdata" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.png'), fig_opt['resolution'], transparent=True) plt.savefig(os.path.join( path_im, "substrate_txtdata" + time.strftime("%d_%m_%Y_at_%H_%M_%S") + '.pdf'), fig_opt['resolution'], transparent=True) else: test = calcul_hab.remove_image("substrate_txtdata", path_im, format) if not test: return plt.savefig(os.path.join(path_im, "substrate_txtdata.png"), fig_opt['resolution'], transparent=True) plt.savefig(os.path.join(path_im, "substrate_txtdata.pdf"), fig_opt['resolution'], transparent=True)
def load_hec_ras_2d_and_cut_grid(name_hdf5, filename, path, name_prj, path_prj, model_type, nb_dim, path_hdf5, q=[], print_cmd=False, fig_opt={}): """ This function calls load_hec_ras_2d and the cut_2d_grid function. Hence, it loads the data, pass it from cell to node (as data output in hec-ras is by cells) and it cut the grid to get only the wetted area. This was done before in the HEC_RAS2D Class in hydro_gui_2.py, but it was necessary to create a separate function to called this task in a second thread to avoid freezing the GUI. :param name_hdf5: the base name of the created hdf5 (string) :param filename: the name of the file containg the results of HEC-RAS in 2D. (string) :param path: the path where the file is (string) :param name_prj: the name of the project (string) :param path_prj: the path of the project :param model_type: the name of the model such as Rubar, hec-ras, etc. (string) :param nb_dim: the number of dimension (model, 1D, 1,5D, 2D) in a float :param path_hdf5: A string which gives the adress to the folder in which to save the hdf5 :param q: used by the second thread to get the error back to the GUI at the end of the thread :param print_cmd: If True will print the error and warning to the cmd. If False, send it to the GUI. :param fig_opt: the figure option, used here to get the minimum water height to have a wet node (can be > 0) ** Technical comments** This function redirect the sys.stdout. The point of doing this is because this function will be call by the GUI or by the cmd. If it is called by the GUI, we want the output to be redirected to the windoows for the log under HABBY. If it is called by the cmd, we want the print function to be sent to the command line. """ # minimum water height if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() minwh = fig_opt['min_height_hyd'] # create the empy output inter_vel_all_t = [] inter_h_all_t = [] # load hec-ras data if not print_cmd: sys.stdout = mystdout = StringIO() [vel_cell, height_cell, elev_min, coord_p, coord_c, ikle, timesteps] = load_hec_ras2d(filename, path) if isinstance(vel_cell[0], int): if vel_cell == [-99]: print("Error: HEC-RAS2D data could not be loaded.") if q: sys.stdout = sys.__stdout__ q.put(mystdout) return else: return # mimic the "whole" profile for 1D model (t=0) point_all_t = [coord_p] point_c_all_t = [coord_c] ikle_all_t = [ikle] inter_h_all_t.append([]) inter_vel_all_t.append([]) # cut the data and pass it to node warn1 = True for t in range(0, len(vel_cell)): # cell to node data if t == 0: [v_node, h_node, vtx_all, wts_all] = manage_grid_8.pass_grid_cell_to_node_lin( point_all_t[0], point_c_all_t[0], vel_cell[t], height_cell[t], warn1) else: [v_node, h_node, vtx_all, wts_all] = manage_grid_8.pass_grid_cell_to_node_lin( point_all_t[0], point_c_all_t[0], vel_cell[t], height_cell[t], warn1, vtx_all, wts_all) # to study the difference in average, do no forget to comment sys.stdout = mystdout = StringIO() # other wise you get zero for all. warn1 = False ikle_f = [] point_f = [] v_f = [] h_f = [] for f in range(0, len(ikle_all_t[0])): # by reach (or water area) # cut grid to wet area [ikle2, point_all, water_height, velocity] = manage_grid_8.cut_2d_grid(ikle_all_t[0][f], point_all_t[0][f], h_node[f], v_node[f], minwh) ikle_f.append(ikle2) point_f.append(point_all) h_f.append(water_height) v_f.append(velocity) inter_h_all_t.append(h_f) inter_vel_all_t.append(v_f) point_all_t.append(point_f) point_c_all_t.append([[]]) ikle_all_t.append(ikle_f) # save data load_hdf5.save_hdf5(name_hdf5, name_prj, path_prj, model_type, nb_dim, path_hdf5, ikle_all_t, point_all_t, point_c_all_t, inter_vel_all_t, inter_h_all_t, sim_name=timesteps) if not print_cmd: sys.stdout = sys.__stdout__ if q: q.put(mystdout) return else: return
def estimhab(qmes, width, height, q50, qrange, substrat, path_bio, fish_xml, path_im, pict=False, fig_opt={}, path_txt=[], fish_name=''): """ This the function which forms the Estimhab model in HABBY. It is a reproduction in python of the excel file which forms the original Estimhab model.. Unit in meter amd m^3/sec :param qmes: the two measured discharge :param width: the two measured width :param height: the two measured height :param q50: the natural median discharge :param qrange: the range of discharge :param substrat: mean height of substrat :param path_im: the path where the image should be saved :param path_bio: the path to the xml file with the information on the fishes :param fish_xml: the name of the xml file to be analyzed :param pict: if true the figure is shown. If false, the figure is not shown :param fig_opt: a dictionnary with the figure option :param path_txt: the path where to send the text data :param fish_name: the name fo the fish to be analysed (if not there, use the xml name) :return: habitat value and useful surface (VH and SPU) as a function of discharge **Technical comments and walk-through** First, we get all the discharges on which we want to calculate the SPU (surface ponderée utile), using the inputs from the user. Next we use hydrological rating curves (info on google if needed) to get the height and the width of the river for all discharge. The calculation is based on the width and height of the river measured at two discharges (given by the user). Next, we get other parameters which are used in the preference curves such as the Froude number of the mean discharge or the Reynolds number. Next, we load the fish data contains in the xml files in the biology folder. Careful, this is not the xml project file. This are the xml files described above in the “Class EstimhabW” section. There are one xml file per fish and they described the preference curves. For the argumentation on the form of the relationship, report yourself to the documentation of Estimhab (one pdf file should in the folder “doc “ in HABBY). Then, we calculate the habitat values (VH and SPU). Finally, we plot the results in a figure and we save it as a text file. """ if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() if pict: plt.rcParams['figure.figsize'] = fig_opt['width'], fig_opt['height'] plt.rcParams['font.size'] = fig_opt['font_size'] plt.rcParams['lines.linewidth'] = fig_opt['line_width'] format1 = int(fig_opt['format']) plt.rcParams['axes.grid'] = fig_opt['grid'] if fig_opt['font_size'] > 7: plt.rcParams['legend.fontsize'] = fig_opt['font_size'] - 2 plt.rcParams['legend.loc'] = 'best' erase1 = fig_opt['erase_id'] if erase1 == 'True': # xml in text erase1 = True else: erase1 = False if not fish_name: fish_name = fish_xml # Q nb_q = 20 # number of calculated q if qrange[1] > qrange[0]: diff = (qrange[1] - qrange[0]) / nb_q if qrange[0] == 0: qrange[0] = 10**-10 # if exactly zero, you cannot divide anymore q_all = np.arange(qrange[0], qrange[1]+diff, diff) else: print('Error: The mininum discharge is higher or equal than the maximum') return [-99], [-99] # height slope = (np.log(height[1]) - np.log(height[0])) / (np.log(qmes[1]) - np.log(qmes[0])) exp_cte = np.exp(np.log(height[0]) - slope*np.log(qmes[0])) h_all = exp_cte * q_all**slope h50 = exp_cte * q50**slope # width slope = (np.log(width[1]) - np.log(width[0])) / (np.log(qmes[1]) - np.log(qmes[0])) exp_cte = np.exp(np.log(width[0]) - slope*np.log(qmes[0])) w_all = exp_cte * q_all**slope l50 = exp_cte * q50**slope # velocity vel = (q_all/h_all)/w_all v50 = (q50/h50)/l50 re = q_all/(10 * w_all) re50 = q50/(10*l50) # extra-data related to q50 fr50 = q50 / (9.81**0.5 * h50**1.5*l50) dh50 = substrat / h50 q50_data = [q50, h50, l50, v50, re50, fr50, dh50, np.exp(dh50)] # prepare figure if pict: c = ['b', 'm', 'r', 'c', '#9932CC', '#800000', 'k', 'g', 'y', '#9F81F7', '#BDBDBD', '#F7819F', 'b', 'm', 'r', 'c', '#9932CC', '#800000', 'k', 'g', 'y', '#810D0D', '#810D0D', '#9F81F7'] plt.figure() plt.suptitle("ESTIMHAB - HABBY") mpl.rcParams['pdf.fonttype'] = 42 # get fish data VH = [] SPU = [] for f in range(0, len(fish_xml)): # load xml file filename = os.path.join(path_bio, fish_xml[f]) if os.path.isfile(filename): doc = ET.parse(filename) root = doc.getroot() else: print('Error: the xml file for the file '+fish_xml[f]+" does not exist") return [-99], [-99] # get data try: coeff_q = pass_to_float_estimhab(".//coeff_q", root) func_q = pass_to_float_estimhab(".//func_q", root) coeff_const = pass_to_float_estimhab(".//coeff_const", root) var_const = pass_to_float_estimhab(".//var_const", root) except ValueError: print('Error: Some data can not be read or are not number. Check the xml file '+ fish_name[f]) return [-99], [-99] # calculate VH if func_q[0] == 0.: part_q = re**coeff_q[0]*np.exp(coeff_q[1] * re) elif func_q[0] == 1.: part_q = 1 + coeff_q[0]*np.exp(coeff_q[1] * re) else: print('Error: no function defined for Q') const = coeff_const[0] for i in range(0, len(var_const)): const += coeff_const[i+1] * np.log(q50_data[int(var_const[i])]) VH_f = const*part_q SPU_f = VH_f*w_all*100 if pict: if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() plt.subplot(2, 1, 1) plt.grid(True) plt.plot(q_all, VH_f, color=c[f]) if fig_opt['language'] == 0: plt.xlabel('Discharge [m$^{3}$/sec]') plt.ylabel('Habitat Value[]') elif fig_opt['language'] == 1: plt.xlabel('Débit [m$^{3}$/sec]') plt.ylabel('Valeur habitat []') else: plt.xlabel('Discharge [m$^{3}$/sec]') plt.ylabel('Habitat Value[]') plt.legend(fish_name, fancybox=True, framealpha=0.5) plt.ylim(0, 1) plt.subplot(2, 1, 2) plt.grid(True) plt.plot(q_all, SPU_f, color=c[f]) if fig_opt['language'] == 0: plt.xlabel('Discharge [m$^{3}$/sec]') plt.ylabel('WUA by 100 m') elif fig_opt['language'] == 1: plt.xlabel('Débit [m$^{3}$/sec]') plt.ylabel('SPU par 100 m') else: plt.xlabel('Discharge [m$^{3}$/sec]') plt.ylabel('WUA by 100 m') VH.append(VH_f) SPU.append(SPU_f) if pict: # name with date and time if not erase1: name_pict = "Estimhab_" + time.strftime("%d_%m_%Y_at_%H_%M_%S") name_input = "Estimhab_input_" + time.strftime("%d_%m_%Y_at_%H_%M_%S") # name without data and time, erase old files else: name_pict = "Estimhab" name_input = "Estimhab_input" if os.path.isfile(name_pict + '.png'): os.remove(name_pict + '.png') if os.path.isfile(name_pict + '.pdf'): os.remove(name_pict + '.pdf') if os.path.isfile(name_pict + '.jpg'): os.remove(name_pict + '.jpg') if os.path.isfile(name_pict + '.txt'): os.remove(name_pict + '.txt') if os.path.isfile(name_input + '.txt'): os.remove(name_input + '.txt') # save image if format1 == 0 or format1 == 1: plt.savefig(os.path.join(path_im, name_pict + '.png'), dpi=fig_opt['resolution'], transparent=True) if format1 == 0 or format1 == 3: plt.savefig(os.path.join(path_im, name_pict + '.pdf'), dpi=fig_opt['resolution'], transparent=True) if format1 == 2: plt.savefig(os.path.join(path_im, name_pict + '.jpg'), dpi=fig_opt['resolution'], transparent=True) # plt.show() # text files output txt_header = 'Q ' data = q_all for f in range(0, len(fish_name)): txt_header += '\tVH_' + fish_name[f] + '\tSPU_' + fish_name[f] data = np.vstack((data, VH[f])) data = np.vstack((data, SPU[f])) txt_header += '\n[m3/sec]' for f in range(0, len(fish_name)): txt_header += '\t[-]\t[m2/100m]' np.savetxt(os.path.join(path_txt, name_pict+'.txt'), data.T, newline=os.linesep, header=txt_header, delimiter='\t') # text file input txtin = 'Discharge [m3/sec]:\t' + str(qmes[0]) + '\t' + str(qmes[1]) + '\n' txtin += 'Width [m]:\t' + str(width[0]) + '\t' + str(width[1]) + '\n' txtin += 'Height [m]:\t' + str(height[0]) + '\t' + str(height[1]) + '\n' txtin += 'Median discharge [m3/sec]:\t' + str(q50) + '\n' txtin += 'Mean substrate size [m]:\t' + str(substrat)+ '\n' txtin += 'Minimum and maximum discharge [m3/sec]:\t' + str(qrange[0]) + '\t' + str(qrange[1]) + '\n' txtin += 'Fish chosen:\t' for n in fish_name: txtin += n + '\t' txtin = txtin[:-1] txtin += '\n' txtin += 'Output file:\t' + name_pict+'.txt\n' with open(os.path.join(path_txt,name_input + '.txt'), 'wt') as f: f.write(txtin) del fish_name return VH, SPU
def figure_pref(height, vel, sub, code_fish, name_fish, stade, get_fig=False, fig_opt={}): """ This function is used to plot the preference curves. :param height: the height preference data (list of list) :param vel: the height preference data (list of list) :param sub: the height preference data (list of list) :param code_fish: the three letter code which indiate which fish species is analyzed :param name_fish: the name of the fish analyzed :param stade: the name of the stade analyzed (ADU, JUV, ...) :param get_fig: usually False, If True return the figure (to modfied it more) """ mpl.rcParams['pdf.fonttype'] = 42 if not get_fig: if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() plt.rcParams['figure.figsize'] = fig_opt['width'], fig_opt['height'] plt.rcParams['font.size'] = fig_opt['font_size'] if fig_opt['font_size'] > 7: plt.rcParams['legend.fontsize'] = fig_opt['font_size'] - 2 plt.rcParams['legend.loc'] = 'best' plt.rcParams['lines.linewidth'] = fig_opt['line_width'] plt.rcParams['axes.grid'] = fig_opt['grid'] if fig_opt['marker'] == 'True': mar = 'o' else: mar = None if name_fish == '-99': # failed before return if len( stade ) > 1: # if you take this out, the commande axarr[x,x] does not work as axarr is only 1D f, axarr = plt.subplots(len(stade), 3, sharey='row') if fig_opt['language'] == 0: plt.suptitle('Suitability curve of ' + name_fish + ' (' + code_fish + ') ') else: plt.suptitle('Courbe de préférence pour ' + name_fish + ' (' + code_fish + ') ') for s in range(0, len(stade)): axarr[s, 0].plot(height[s][0], height[s][1], '-b', marker=mar) if fig_opt['language'] == 0: axarr[s, 0].set_xlabel('Water height [m]') axarr[s, 0].set_ylabel('Coeff. pref. ' + stade[s]) else: axarr[s, 0].set_xlabel("Hauteur d'eau [m]") axarr[s, 0].set_ylabel('Coeff. pref. ' + stade[s]) axarr[s, 0].set_ylim([0, 1.1]) axarr[s, 1].plot(vel[s][0], vel[s][1], '-r', marker=mar) if fig_opt['language'] == 0: axarr[s, 1].set_xlabel('Velocity [m/sec]') else: axarr[s, 1].set_xlabel('Vitesse [m/sec]') axarr[s, 1].set_ylabel('Coeff. pref. ' + stade[s]) axarr[s, 1].set_ylim([0, 1.1]) if len( sub[0][0] ) > 2: # if substrate is accounted, it is accounted for all stages axarr[s, 2].bar(sub[s][0], sub[s][1], facecolor='c', align='center') if fig_opt['language'] == 0: axarr[s, 2].set_xlabel('Substrate []') else: axarr[s, 2].set_xlabel('Substrat []') axarr[s, 2].set_ylabel('Coeff. pref. ' + stade[s]) axarr[s, 2].set_ylim([0, 1.1]) axarr[s, 2].set_xlim([0.4, 8.6]) else: f, axarr = plt.subplots(3, 1, sharey='row') if fig_opt['language'] == 0: plt.suptitle('Suitability curve of ' + name_fish + ' (' + code_fish + ') ') else: plt.suptitle('Courbe de préférence pour ' + name_fish + ' (' + code_fish + ') ') axarr[0].plot(height[0][0], height[0][1], '-b', marker=mar) if fig_opt['language'] == 0: axarr[0].set_xlabel('Water height [m]') axarr[0].set_ylabel('Coeff. pref. ') else: axarr[0].set_xlabel("Hauteur d'eau [m]") axarr[0].set_ylabel('Coeff. pref. ') axarr[0].set_ylim([0, 1.1]) axarr[1].plot(vel[0][0], vel[0][1], '-r', marker=mar) if fig_opt['language'] == 0: axarr[1].set_xlabel('Velocity [m/sec]') else: axarr[1].set_xlabel('Vitesse [m/sec]') axarr[1].set_ylabel('Coeff. pref. ') axarr[1].set_ylim([0, 1.1]) if len(sub[0][0]) > 2: axarr[2].bar(sub[0][0], sub[0][1], facecolor='c', align='center') if fig_opt['language'] == 0: axarr[2].set_xlabel('Substrate []') else: axarr[2].set_xlabel('Substrat []') axarr[2].set_ylabel('Coeff. pref. ') axarr[2].set_ylim([0, 1.1]) axarr[2].set_xlim([0.4, 8.6]) plt.tight_layout(rect=[0, 0, 1, 0.95]) if get_fig: return f, axarr
def load_sw2d_and_modify_grid(name_hdf5, geom_sw2d_file, result_sw2d_file, path_geo, path_res, path_im, name_prj, path_prj, model_type, nb_dim, path_hdf5, q=[], print_cmd=False, fig_opt={}): """ This function loads the sw2d file, using the function below. Then, it changes the mesh which has triangle and quadrilater toward a triangle mesh and it passes the data from cell-centric data to node data using a linear interpolation. Finally it saves the data in one hdf5. TODO See if we could improve the interpolation or study its effect in more details. :param name_hdf5: the base name of the created hdf5 (string) :param geom_sw2d_file: the name of the .geo gile (string) :param result_sw2d_file: the name of the result file (string) :param path_geo: path to the geo file (string) :param path_res: path to the result file which contains the outputs (string) :param path_im: the path where to save the figure (string) :param name_prj: the name of the project (string) :param path_prj: the path of the project (string) :param model_type: the name of the model such as Rubar, hec-ras, etc. (string) :param nb_dim: the number of dimension (model, 1D, 1,5D, 2D) in a float :param path_hdf5: A string which gives the adress to the folder in which to save the hdf5 :param q: used by the second thread to get the error back to the GUI at the end of the thread :param print_cmd: If True will print the error and warning to the cmd. If False, send it to the GUI. :param fig_opt: the figure option, used here to get the minimum water height to have a wet node (can be > 0) :return: none """ # get minimum water height if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() minwh = fig_opt['min_height_hyd'] # find where we should send the error (cmd or GUI) if not print_cmd: sys.stdout = mystdout = StringIO() # create the empy output inter_vel_all_t = [] inter_h_all_t = [] ikle_all_t = [] point_all_t = [] point_c_all_t = [] # load swd data [baryXY, timesteps, height_cell, vel_cell] = read_result_sw2d(result_sw2d_file, path_res) if isinstance(baryXY[0], int): if baryXY == [-99]: print("Error: the SW2D result file could not be loaded.") if q: sys.stdout = sys.__stdout__ q.put(mystdout) return else: return [noNodElem, listNoNodElem, nodesXYZ] = read_mesh_sw2d(geom_sw2d_file, path_geo) if isinstance(noNodElem[0], int): if noNodElem == [-99]: print("Error: the SW2D geometry file could not be loaded.") if q: sys.stdout = sys.__stdout__ q.put(mystdout) return else: return # get triangular nodes from quadrilateral [ikle_base, coord_c, coord_p, height_cell, vel_cell] = rubar.get_triangular_grid(listNoNodElem, baryXY, \ nodesXYZ[:,:2], height_cell, \ vel_cell) # remove non connected nodes triangles = np.asarray(ikle_base) nodes = coord_p nbnode = nodes.shape[0] nbtriangle = triangles.shape[0] connect = np.zeros(nbnode, dtype=np.int) connect[np.ravel(triangles)] = 1 pointer = np.zeros(nbnode, dtype=np.int) k = 0 for i in range(nbnode): if connect[i]: pointer[i] = k k = k + 1 nds = [nodes[i,] for i in range(nbnode) if connect[i]] coord_p = np.asarray(nds) tria1 = np.ravel(triangles[:,0]) tria2 = np.ravel(triangles[:,1]) tria3 = np.ravel(triangles[:,2]) trs1 = [pointer[tria1[i]] for i in range(nbtriangle)] trs2 = [pointer[tria2[i]] for i in range(nbtriangle)] trs3 = [pointer[tria3[i]] for i in range(nbtriangle)] trs = trs1 + trs2 + trs3 trs = np.asarray(trs) trs = trs.reshape(3, nbtriangle) ikle_base = np.transpose(trs) ikle_base = ikle_base.tolist() # create grid # first, the grid for the whole profile (no velocity or height data) # because we have a "whole" grid for 1D model before the actual time step inter_h_all_t.append([[]]) inter_vel_all_t.append([[]]) point_all_t.append([coord_p]) point_c_all_t.append([coord_c]) ikle_all_t.append([ikle_base]) # the grid data for each time step warn1 = False for t in range(0, len(vel_cell)): # get data no the node (and not on the cells) by linear interpolation if t == 0: [vel_node, height_node, vtx_all, wts_all] = manage_grid_8.pass_grid_cell_to_node_lin([coord_p], [coord_c], vel_cell[t], height_cell[t], warn1) else: [vel_node, height_node, vtx_all, wts_all] = manage_grid_8.pass_grid_cell_to_node_lin([coord_p], [coord_c], vel_cell[t], height_cell[t], warn1, vtx_all, wts_all) # cut the grid to the water limit [ikle, point_all, water_height, velocity] = manage_grid_8.cut_2d_grid(ikle_base, coord_p, height_node[0], vel_node[0], minwh) inter_h_all_t.append([water_height]) inter_vel_all_t.append([velocity]) point_all_t.append([point_all]) point_c_all_t.append([[]]) ikle_all_t.append([ikle]) warn1 = False # save data timestep_str = list(map(str, timesteps)) load_hdf5.save_hdf5(name_hdf5, name_prj, path_prj, model_type, nb_dim, path_hdf5, ikle_all_t, point_all_t, point_c_all_t, inter_vel_all_t, inter_h_all_t, sim_name=timestep_str) if not print_cmd: sys.stdout = sys.__stdout__ if q: q.put(mystdout) else: return
def load_lammi(facies_path, transect_path, path_im, new_dir, fig_opt, savefig1d, transect_name, facies_name): """ This function loads the data from the LAMMI model. A description of the LAMMI model is available in the documentation folder (LAMMIGuideMetho.pdf). :param transect_path: the path to the transect.txt path :param facies_path: the path the facies.txt file :param path_im: the path where to save the image :param fig_opt: the figure option :param savefig1d: create and save the figure related to the loading of the data (profile and so on) :param new_dir: if necessary, the path to the resultat file (.prn file). Be default, use the one in transect.txt :param transect_name: the name of the transect file, usually 'Transect.txt' :param facies_name: the name of the facies file, usually 'Facies.txt' :return: **Technical Comments** LAMMI is organised aroung group of transects. Transect are river profile which describe the river geometry. In LAMMI, there are four way of grouping transect. The facies is the a group a transect which is considered by HABBY to form a reach. The facies can then begroup in station. HABBY do not considered station directly, but it is possible to use the function "load_station" to get the station info if needed. The group Secteur are used in case where water is brought to the river. To load LAMMI data, we first load the facies file, which gives which transect are in which facies. Then, we use the transect file to know the length of each transect (length between transects along the river) and the name of the file containing the transect precise data. The name of the file is an absolute path to the file. This can be annoying if one want to move the files. Hence, we add the variable new_dir which correct the transect file in case the files containing the transect data have been moved (they should however all be in the same directory). This is done by the function get_transect_name(). Then it uses the function load_transect_data to read all this data , file by file. Consequentely, we have the data in memory but no(x,y) coordinate. In addition, this data is is in the different form than in the other hydraulic model. To obtain the coordainte of the river and to put the data is the form usually needed by HABBY for 1.5D model (coord_pro, vh_pro, nb_pro_reach), we use the coord_lammi() function. There is also an optionnal check to control that the conversion between lammi and cemagref code is as normal. This check is only done if HABBY can find the habitat.txt file where the conversion can be modified by the user. Otherwise we assume that the normal conversion is used. Obviously, this check should be modifed if the edf to cemagref conversion is modified. """ failload = [-99], [-99], [-99], [-99], [-99], [-99] if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() # get the filename of the transect by facies [length_all, fac_filename_all] = get_transect_filename(facies_path, facies_name, transect_path, transect_name, new_dir) if len(length_all) == 1: if length_all[0] == -99: return failload # load the transect data [dist_all, vel_all, height_all, sub_all, q_step] = load_transect_data(fac_filename_all) if len(dist_all) == 1: if dist_all[0] == -99: return failload # check if habitat.txt exist. # This is a lammi file which can be used to change the passage from lammi code to # cemagref code. This is very very rarely done and the info can not be transfered to HABBY. # Hence we just test if this habitat file and we refuse to execute if the code is not the right one. # If we do not find habitat.txt, we carry on code_ok = check_code_change(facies_path) if not code_ok: print('Error: The conversion from the EDF code to the Cemagref code given in habitat.txt was not the one' ' known by HABBY. Could not execute. \n') return failload # get the (not realistic) coordinates of the rivers and the coordinate of the substrate [coord_pro, vh_pro, nb_pro_reach, sub_pro, div] = coord_lammi(dist_all, vel_all, height_all, sub_all, length_all) # create the figure if savefig1d: fig_lammi(vh_pro, coord_pro, nb_pro_reach, [0, 1, 2], 0, fig_opt, path_im) # plt.show() plt.close() # avoid problem with matplotlib return coord_pro, vh_pro, nb_pro_reach, sub_pro, div, q_step
def load_river2d_and_cut_grid(name_hdf5,namefiles, paths, name_prj, path_prj, model_type, nb_dim, path_hdf5, q=[], print_cmd=False, fig_opt={}): """ This function loads the river2d data and cut the grid to the wet area. Originally, this function was in the class River2D() in hydro_GUI_2. This function was added as it was practical to have a second thread to avoid freezing the GUI. :param name_hdf5: the base name of the created hdf5 (string) :param namefiles: the names of all the cdg file (list of string) :param paths: the path to the files (list of string). :param name_prj: the name of the project (string) :param path_prj: the path of the project :param model_type: the name of the model such as Rubar, hec-ras, etc. (string) :param nb_dim: the number of dimension (model, 1D, 1,5D, 2D) in a float :param path_hdf5: A string which gives the adress to the folder in which to save the hdf5 :param q: used to send the error back from the second thread (can be used to send other variable too) :param print_cmd: if True the print command is directed in the cmd, False if directed to the GUI :param fig_opt: the figure option, used here to get the minimum water height to have a wet node (can be > 0) """ # minimum water height if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() minwh = fig_opt['min_height_hyd'] # creation of array xyzhv = [] ikle_all_t = [] point_c_all_t = [] point_all_t = [] inter_h_all_t = [] inter_vel_all_t = [] # for all time step if not print_cmd: sys.stdout = mystdout = StringIO() for i in range(0, len(namefiles)): # load river 2d data [xyzhv_i, ikle_i, coord_c] = load_river2d_cdg(namefiles[i], paths[i]) if isinstance(xyzhv_i[0], int): if xyzhv_i[0] == -99: print('Error: River2D data could not be loaded') if q: sys.stdout = sys.__stdout__ q.put(mystdout) return else: return # cut grid to wet area [ikle_i, point_all, water_height, velocity] = manage_grid_8.cut_2d_grid(ikle_i, xyzhv_i[:, :2],xyzhv_i[:, 3], xyzhv_i[:, 4], minwh) #mimic empty grid for t = 0 for 1 D model if i == 0: point_all_t.append([point_all]) ikle_all_t.append([ikle_i]) point_c_all_t.append([coord_c]) inter_h_all_t.append([]) inter_vel_all_t.append([]) point_all_t.append([point_all]) ikle_all_t.append([ikle_i]) point_c_all_t.append([[]]) inter_h_all_t.append([water_height]) inter_vel_all_t.append([velocity]) # save data namefiles2 = [x[:-4] for x in namefiles] # no need of the .cdg to name the time step load_hdf5.save_hdf5(name_hdf5, name_prj, path_prj, model_type, nb_dim, path_hdf5, ikle_all_t, point_all_t, point_c_all_t, inter_vel_all_t, inter_h_all_t, sim_name=namefiles2) if not print_cmd: sys.stdout = sys.__stdout__ if q: q.put(mystdout) return else: return
def load_telemac_and_cut_grid(name_hdf5, namefilet, pathfilet, name_prj, path_prj, model_type, nb_dim, path_hdf5, q=[], print_cmd=False, fig_opt={}): """ This function calls the function load_telemac and call the function cut_2d_grid(). Orginally, this function was part of the TELEMAC class in Hydro_GUI_2.py but it was separated to be able to have a second thread, which is useful to avoid freezing the GUI. :param name_hdf5: the base name of the created hdf5 (string) :param namefilet: the name of the selafin file (string) :param pathfilet: the path to this file (string) :param name_prj: the name of the project (string) :param path_prj: the path of the project :param model_type: the name of the model such as Rubar, hec-ras, etc. (string) :param nb_dim: the number of dimension (model, 1D, 1,5D, 2D) in a float :param path_hdf5: A string which gives the adress to the folder in which to save the hdf5 :param q: used by the second thread to get the error back to the GUI at the end of the thread :param print_cmd: if True the print command is directed in the cmd, False if directed to the GUI :param fig_opt: the figure option, used here to get the minimum water height to have a wet node (can be > 0) """ if not print_cmd: sys.stdout = mystdout = StringIO() # minimum water height if not fig_opt: fig_opt = output_fig_GUI.create_default_figoption() minwh = fig_opt['min_height_hyd'] # load data [v, h, coord_p, ikle, coord_c, timestep] = load_telemac(namefilet, pathfilet) if isinstance(v, int) and v == [-99]: print('Error: Telemac data not loaded.') if q: sys.stdout = sys.__stdout__ q.put(mystdout) return else: return # cut the grid to have the precise wet area and put data in new form point_all_t = [[coord_p]] ikle_all_t = [[ikle]] point_c_all_t = [[coord_c]] inter_h_all_t = [[]] inter_vel_all_t = [[]] for t in range(0, len(v)): [ikle2, point_all, water_height, velocity] = manage_grid_8.cut_2d_grid(ikle, coord_p, h[t], v[t], minwh) point_all_t.append([point_all]) # only one reach ikle_all_t.append([ikle2]) point_c_all_t.append([[]]) inter_vel_all_t.append([velocity]) inter_h_all_t.append([water_height]) # save data timestep_str = list(map(str, timestep)) load_hdf5.save_hdf5(name_hdf5, name_prj, path_prj, model_type, nb_dim, path_hdf5, ikle_all_t, point_all_t, point_c_all_t, inter_vel_all_t, inter_h_all_t, sim_name=timestep_str) if not print_cmd: sys.stdout = sys.__stdout__ if q and not print_cmd: q.put(mystdout) return else: return