Changeset 3883
- Timestamp:
- Aug 8, 2025, 7:50:27 PM (19 hours ago)
- Location:
- trunk/LMDZ.COMMON/libf/evolution
- Files:
-
- 1 added
- 1 deleted
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LMDZ.COMMON/libf/evolution/changelog.txt
r3869 r3883 766 766 == 28/07/2025 == JBC 767 767 Bug correction to detect the job time limit with PBS/TORQUE. Making it more robust and automatic for the launching script and the Fortran code. 768 769 == 08/08/2025 == JBC 770 - Replacing the Bash script "concat_diagpem.sh" by a Python script "concat_pem.py" which is much faster. 771 - Corrections and updates for "visu_evol_layering.py". -
trunk/LMDZ.COMMON/libf/evolution/deftank/README
r3861 r3883 103 103 Bash script file to set the orbital parameters of a file "startfi.nc" from Laskar's data contained in "obl_ecc_lsp.asc" according to the initial date 'year_earth_bp_ini' defined in "run_PEM.def". See also "modify_startfi_orbit.sh". 104 104 105 # concat_ diagpem.sh:106 Bash script file to concatenate along the variable 'Time' all the "diagpem.nc" files of the PEM into one NetCDF file. 'Time' is re-indexed with the numbering of Martian years simulated by the PEM run.105 # concat_pem.py: 106 Python script file to concatenate the NetCDF files of the PEM along the dimension 'Time' into one NetCDF file. 'Time' is re-indexed by increment. 107 107 108 108 # clean.sh: -
trunk/LMDZ.COMMON/libf/evolution/deftank/visu_evol_layering.py
r3860 r3883 509 509 output_folder, f"layering_evolution_ig{ig+1}_is{isl+1}.png" 510 510 ) 511 fig.savefig(fname, dpi=1 50)511 fig.savefig(fname, dpi=1200, bbox_inches='tight') 512 512 513 513 … … 577 577 rgb = np.ones((nz, ntime, 3), dtype=float) 578 578 579 frac_all = np. zeros((nz, ntime, 3), dtype=float) # store fH2O, fCO2, fDust579 frac_all = np.full((nz, ntime, 3), np.nan, dtype=float) # store fH2O, fCO2, fDust 580 580 for t in range(ntime): 581 581 depth = ti[ig, t, isl] … … 598 598 display_frac = frac_all[elevation_mask, :, :] 599 599 600 display_rgb = rgb[elevation_mask, :, :]601 602 600 # Compute edges for pcolormesh 603 601 dt = date_time[1] - date_time[0] if len(date_time) > 1 else 1 … … 609 607 # Create figure with legend 610 608 fig, (ax_main, ax_leg) = plt.subplots( 611 1, 2, figsize=(8, 4), dpi= 200,609 1, 2, figsize=(8, 4), dpi=150, 612 610 gridspec_kw={'width_ratios': [5, 1]} 613 611 ) … … 630 628 i = np.searchsorted(x_edges, x) - 1 631 629 j = np.searchsorted(y_edges, y) - 1 632 i = np.clip(i, 0, display_rgb.shape[1] -1)633 j = np.clip(j, 0, display_rgb.shape[0] -1)630 i = np.clip(i, 0, display_rgb.shape[1] - 1) 631 j = np.clip(j, 0, display_rgb.shape[0] - 1) 634 632 # get fractions 635 633 fH2O, fCO2, fDust = display_frac[j, i] 636 return f"Time={x:.2f}, Elev={y:.2f}, H2O={fH2O:. 2f}, CO2={fCO2:.2f}, Dust={fDust:.2f}"634 return f"Time={x:.2f}, Elev={y:.2f}, H2O={fH2O:.4f}, CO2={fCO2:.4f}, Dust={fDust:.4f}" 637 635 ax_main.format_coord = main_format 638 636 ax_main.set_facecolor('white') … … 684 682 plt.tight_layout() 685 683 fname = os.path.join(output_folder, f"layering_rgb_evolution_ig{ig+1}_is{isl+1}.png") 686 fig.savefig(fname, dpi=1 50, bbox_inches='tight')684 fig.savefig(fname, dpi=1200, bbox_inches='tight') 687 685 688 686 … … 722 720 vmin, vmax = -2, 1 723 721 epsilon = 1e-6 724 722 725 723 # Loop over grids and slopes 726 724 for ig in range(ngrid): 727 725 for isl in range(nslope): 728 726 ti = top_index[ig, :, isl].copy().astype(int) 729 for t in range(1, ntime):730 if ti[t] <= 0:731 ti[t] = ti[t-1]732 727 733 728 # Compute log10(dust/ice) profile at each time step 734 729 log_ratio_array = np.full((nz, ntime), np.nan, dtype=np.float32) 735 730 for t in range(ntime): 731 if ti[t] <= 0: 732 ti[t] = ti[t-1] 736 733 zmax = ti[t] 737 734 if zmax <= 0: 738 735 continue 739 736 740 h2o_profile = np.clip(h2o[ig, t, isl, :zmax], 0, None) 741 dust_profile = np.clip(dust[ig, t, isl, :zmax], 0, None) 737 cH2O = np.clip(h2o[ig, t, isl, :zmax], 0, None) 738 cCO2 = np.clip(co2[ig, t, isl, :zmax], 0, None) 739 cDust = np.clip(dust[ig, t, isl, :zmax], 0, None) 742 740 743 741 with np.errstate(divide='ignore', invalid='ignore'): 744 ratio _profile= np.where(745 h2o_profile> 0,746 dust_profile / h2o_profile,742 ratio = np.where( 743 cH2O > 0, 744 cDust / cH2O, 747 745 10**(vmax + 1) 748 746 ) 749 log_ratio = np.log10(ratio _profile+ epsilon)747 log_ratio = np.log10(ratio + epsilon) 750 748 log_ratio = np.clip(log_ratio, vmin, vmax) 751 749 752 750 log_ratio_array[:zmax, t] = log_ratio 753 751 754 # Convert back to linear ratio and apply elevation mask752 # Mask and prepare for display 755 753 ratio_array = 10**log_ratio_array 756 754 ratio_display = ratio_array[elevation_mask, :] 755 x_edges = np.concatenate([date_time, [date_time[-1] + (date_time[-1] - date_time[-2])]]) 756 y_edges = np.concatenate([elev, [elev[-1] + (elev[-1] - elev[-2])]]) 757 757 758 758 # Plot … … 766 766 norm=LogNorm(vmin=10**vmin, vmax=10**vmax), 767 767 ) 768 x_edges = np.concatenate([date_time, [date_time[-1] + (date_time[-1]-date_time[-2])]]) 769 attach_format_coord(ax, ratio_display, x_edges, np.concatenate([elev, [elev[-1] + (elev[-1]-elev[-2])]]), is_pcolormesh=True) 768 attach_format_coord(ax, ratio_display, x_edges, y_edges, is_pcolormesh=True) 770 769 ax.set_title(f"Dust-to-Ice ratio over time (Grid point {ig+1}, Slope {isl+1})", fontweight='bold') 771 770 ax.set_xlabel('Time (Mars years)') 772 771 ax.set_ylabel('Elevation (m)') 773 772 774 # Add colorbar with simplified ratio labels775 cbar = fig.colorbar(im, ax=ax, orientation='vertical' )773 # Add colorbar 774 cbar = fig.colorbar(im, ax=ax, orientation='vertical', pad=0.15) 776 775 cbar.set_label('Dust / H₂O ice (ratio)') 777 778 # Define custom ticks and labels 779 ticks = [1e-2, 1e-1, 1, 1e1] 780 labels = ['1:100', '1:10', '1:1', '10:1'] 781 cbar.set_ticks(ticks) 782 cbar.set_ticklabels(labels) 776 cbar.set_ticks([1e-2, 1e-1, 1, 1e1]) 777 cbar.set_ticklabels(['1:100', '1:10', '1:1', '10:1']) 783 778 784 779 # Save figure 785 780 plt.tight_layout() 786 fname = os.path.join(781 outname = os.path.join( 787 782 output_folder, 788 783 f"dust_to_ice_ratio_grid{ig+1}_slope{isl+1}.png" 789 784 ) 790 fig.savefig( fname, dpi=150)785 fig.savefig(outname, dpi=1200, bbox_inches='tight') 791 786 792 787 … … 1060 1055 elev = ref_grid 1061 1056 1062 # Custom colormap: blue (ice) to orange (dust)1063 blue = np.array([0, 0, 255] ) / 2551064 orange = np.array([255, 165, 0] ) / 2551057 # Define custom blue-to-orange colormap 1058 blue = np.array([0, 0, 255], dtype=float) / 255 1059 orange = np.array([255, 165, 0], dtype=float) / 255 1065 1060 custom_cmap = LinearSegmentedColormap.from_list('BlueOrange', [blue, orange], N=256) 1066 1061 … … 1072 1067 for ig in range(ngrid): 1073 1068 for isl in range(nslope): 1069 # Prepare fraction and ratio arrays 1074 1070 ti = top_index[ig, :, isl].copy().astype(int) 1075 frac_all = np.zeros((nz, ntime, 3), dtype=float) # store fH2O, fCO2, fDust 1076 for t in range(1, ntime): 1071 log_ratio_array = np.full((nz, ntime), np.nan, dtype=np.float32) 1072 frac_all = np.full((nz, ntime, 3), np.nan, dtype=float) # store fH2O, fCO2, fDust 1073 for t in range(ntime): 1077 1074 if ti[t] <= 0: 1078 1075 ti[t] = ti[t-1] 1079 1080 # Compute log10(dust/ice) profile at each time step1081 log_ratio_array = np.full((nz, ntime), np.nan, dtype=np.float32)1082 for t in range(ntime):1083 1076 zmax = ti[t] 1084 1077 if zmax <= 0: 1085 1078 continue 1079 1086 1080 cH2O = np.clip(h2o[ig, t, isl, :zmax], 0, None) 1087 1081 cCO2 = np.clip(co2[ig, t, isl, :zmax], 0, None) … … 1094 1088 frac_all[:zmax, t, :] = np.stack([fH2O, fCO2, fDust], axis=1) 1095 1089 1096 h2o_profile = np.clip(h2o[ig, t, isl, :zmax], 0, None)1097 dust_profile = np.clip(dust[ig, t, isl, :zmax], 0, None)1098 1099 1090 with np.errstate(divide='ignore', invalid='ignore'): 1100 ratio _profile= np.where(1101 h2o_profile> 0,1102 dust_profile / h2o_profile,1091 ratio = np.where( 1092 cH2O > 0, 1093 cDust / cH2O, 1103 1094 10**(vmax + 1) 1104 1095 ) 1105 log_ratio = np.log10(ratio _profile+ epsilon)1096 log_ratio = np.log10(ratio + epsilon) 1106 1097 log_ratio = np.clip(log_ratio, vmin, vmax) 1107 1098 1108 1099 log_ratio_array[:zmax, t] = log_ratio 1109 1100 1110 # Convert back to linear ratio and mask1101 # Mask elevation 1111 1102 ratio_array = 10**log_ratio_array 1112 1103 ratio_display = ratio_array[elevation_mask, :] 1113 1104 display_frac = frac_all[elevation_mask, :, :] 1114 1105 1106 # Compute edges for pcolormesh 1107 dt = date_time[1] - date_time[0] if len(date_time) > 1 else 1 1108 x_edges = np.concatenate([date_time, [date_time[-1] + dt]]) 1109 d_e = np.diff(elev) 1110 last_e = elev[-1] + (d_e[-1] if len(d_e)>0 else 1) 1111 y_edges = np.concatenate([elev, [last_e]]) 1112 1115 1113 # Plot 1116 1114 fig, ax = plt.subplots(figsize=(8, 6), dpi=150) 1117 1115 im = ax.pcolormesh( 1118 date_time,1119 elev,1116 x_edges, 1117 y_edges, 1120 1118 ratio_display, 1121 1119 shading='auto', … … 1123 1121 norm=LogNorm(vmin=10**vmin, vmax=10**vmax), 1124 1122 ) 1125 x_edges = np.concatenate([date_time, [date_time[-1] + (date_time[-1]-date_time[-2])]]) 1126 y_edges = np.concatenate([elev, [elev[-1] + (elev[-1]-elev[-2])]]) 1127 def format_coord_all(x, y): 1123 1124 def format_coord_custom(x_input, y_input): 1125 # map onto the main axis 1126 if plt.gca() is ax2: 1127 x_pix, y_pix = ax2.transData.transform((x_input, y_input)) 1128 x, y = ax.transData.inverted().transform((x_pix, y_pix)) 1129 else: 1130 x, y = x_input, y_input 1128 1131 # check bounds 1129 1132 if x < x_edges[0] or x > x_edges[-1] or y < y_edges[0] or y > y_edges[-1]: … … 1132 1135 i = np.searchsorted(x_edges, x) - 1 1133 1136 j = np.searchsorted(y_edges, y) - 1 1134 i = np.clip(i, 0, display_frac.shape[1]-1) 1135 j = np.clip(j, 0, display_frac.shape[0]-1) 1136 # get fractions 1137 fH2O = display_frac[j, i, 0] 1138 fDust = display_frac[j, i, 2] 1137 i = np.clip(i, 0, ratio_display.shape[1] - 1) 1138 j = np.clip(j, 0, ratio_display.shape[0] - 1) 1139 # get fractions and obliquity 1140 fH2O, fCO2, fDust = display_frac[j, i] 1139 1141 obl = np.interp(x, date_time, obliquity) 1140 return f"Time={x:.2f}, Elev={y:.2f}, H2O={fH2O:.2f}, Dust={fDust:.2f}, Obl={obl:.2f}°" 1141 1142 ax.format_coord = format_coord_all 1142 return f"Time={x:.2f}, Elev={y:.2f}, H2O={fH2O:.4f}, Dust={fDust:.4f}, Obl={obl:.2f}°" 1143 1143 1144 ax.set_title(f"Dust-to-Ice ratio over time (Grid point {ig+1}, Slope {isl+1})", fontweight='bold') 1144 1145 ax.set_xlabel('Time (Mars years)') … … 1161 1162 linewidth=1.5 1162 1163 ) 1163 ax2.format_coord = format_coord_ all1164 ax2.format_coord = format_coord_custom 1164 1165 ax2.set_ylabel('Obliquity (°)') 1165 1166 ax2.tick_params(axis='y') 1166 1167 ax2.grid(False) 1167 1168 1168 # Save 1169 os.makedirs(output_folder, exist_ok=True)1169 # Save figure 1170 plt.tight_layout() 1170 1171 outname = os.path.join( 1171 1172 output_folder, 1172 1173 f'dust_ice_obliquity_grid{ig+1}_slope{isl+1}.png' 1173 1174 ) 1174 plt.tight_layout() 1175 fig.savefig(outname, dpi=150) 1175 fig.savefig(outname, dpi=1200, bbox_inches='tight') 1176 1176 1177 1177
Note: See TracChangeset
for help on using the changeset viewer.