def read_mode_info(dir_NM, option, i_clip=None): # Define directories and files. dir_processed = os.path.join(dir_NM, 'processed') # Load the mode identification information. path_ids = os.path.join(dir_processed, 'mode_ids_{:}.txt'.format(option)) i_mode, l, type_, shell = np.loadtxt(path_ids, dtype=np.int).T if i_clip is not None: i_mode = i_mode[:i_clip] l = l[:i_clip] type_ = type_[:i_clip] shell = shell[:i_clip] # Read the mode frequency. file_eigval_list = os.path.join(dir_processed, 'eigenvalue_list.txt') _, f = read_eigenvalues(file_eigval_list) ## Read coefficients. #coeffs = load_all_vsh_coefficients(dir_NM, i_mode) if i_clip is not None: f = f[:i_clip] return i_mode, f, l, type_, shell
def plot_sh_disp_animation(dir_NM, i_mode, i_radius_str, n_lat_grid, mode_real_or_complex, rotation_period_hrs, save = True): # Determine if the plot is 'quick' mode or 'full' mode. if i_radius_str is None: option = 'quick' else: option = 'full' if mode_real_or_complex == 'real': raise NotImplementedError elif mode_real_or_complex in ['complex_real_only', 'complex_imag_only']: print('Animation for complex mode requires both real and imaginary parts. Change flag from \'{:}\' to \'complex\' in input_plotting.txt'.format(mode_real_or_complex)) raise ValueError elif mode_real_or_complex == 'complex': # Plot the first frame, which is the real part. fig, ax_arr, handles, fields, contour_info = plot_sh_disp_wrapper(dir_NM, i_mode, n_lat_grid, 'complex_real_only', show = False, fmt = None, close = False, c_bar_label = 'Displacement', figsize = (3.5, 7.0)) # Identify the eigenvalue list file. # Load the frequency of the mode. dir_processed = os.path.join(dir_NM, 'processed') path_eigenvalues = os.path.join(dir_processed, 'eigenvalue_list.txt') freq_mHz = read_eigenvalues(path_eigenvalues, i_mode = i_mode) freq_Hz = 1.0E-3*freq_mHz time_str_fmt = 'Time = {:>6.2f} h,\n{:>.2f} mode cycles,\n{:>.2f} rotations' time_str = time_str_fmt.format(0.0, 0.0, 0.0) time_title = ax_arr[0].set_title(time_str) rotation_period_seconds = 60.0*60.0*rotation_period_hrs t_min = 0.0 t_max = 0.25*rotation_period_seconds n_t = 200 t = np.linspace(t_min, t_max, n_t) period_mode = 1.0/freq_Hz t_hours = t/3600.0 t_mode_cycles = t/period_mode t_rotations = t_hours/rotation_period_hrs omega = 2.0*np.pi*freq_Hz # Angular freq, radians per second. phase = omega*t cos_phase = np.cos(phase) sin_phase = np.sin(phase) Ur_real = (fields['U']['real']['r']*cos_phase[:, np.newaxis, np.newaxis]) - (fields['U']['imag']['r']*sin_phase[:, np.newaxis, np.newaxis]) Ur_imag = (fields['U']['real']['r']*sin_phase[:, np.newaxis, np.newaxis]) + (fields['U']['imag']['r']*cos_phase[:, np.newaxis, np.newaxis]) Ve_real = (fields['V']['real']['e']*cos_phase[:, np.newaxis, np.newaxis]) - (fields['V']['imag']['e']*sin_phase[:, np.newaxis, np.newaxis]) Ve_imag = (fields['V']['real']['e']*sin_phase[:, np.newaxis, np.newaxis]) + (fields['V']['imag']['e']*cos_phase[:, np.newaxis, np.newaxis]) Vn_real = (fields['V']['real']['n']*cos_phase[:, np.newaxis, np.newaxis]) - (fields['V']['imag']['n']*sin_phase[:, np.newaxis, np.newaxis]) Vn_imag = (fields['V']['real']['n']*sin_phase[:, np.newaxis, np.newaxis]) + (fields['V']['imag']['n']*cos_phase[:, np.newaxis, np.newaxis]) We_real = (fields['W']['real']['e']*cos_phase[:, np.newaxis, np.newaxis]) - (fields['W']['imag']['e']*sin_phase[:, np.newaxis, np.newaxis]) We_imag = (fields['W']['real']['e']*sin_phase[:, np.newaxis, np.newaxis]) + (fields['W']['imag']['e']*cos_phase[:, np.newaxis, np.newaxis]) Wn_real = (fields['W']['real']['n']*cos_phase[:, np.newaxis, np.newaxis]) - (fields['W']['imag']['n']*sin_phase[:, np.newaxis, np.newaxis]) Wn_imag = (fields['W']['real']['n']*sin_phase[:, np.newaxis, np.newaxis]) + (fields['W']['imag']['n']*cos_phase[:, np.newaxis, np.newaxis]) def animate(i): time_title.set_text(time_str_fmt.format(t_hours[i], t_mode_cycles[i], t_rotations[i])) ax = ax_arr[0] v_scalar = Ur_real[i, :, :] v_scalar, lon_grid = add_cyclic_point(v_scalar, contour_info['lon_grid']) ax.collections = [] ax.contourf( np.rad2deg(lon_grid), np.rad2deg(contour_info['lat_grid']), v_scalar, contour_info['c_levels'], transform = ccrs.PlateCarree(), norm = contour_info['norm'], cmap = contour_info['cmap']) ax = ax_arr[1] # slice_ controls the down-sampling of the data. slice_ = int(np.ceil(lon_grid.shape[0]/20)) v_e = Ve_real[i, :, :] v_n = Vn_real[i, :, :] v_scalar = np.sqrt((v_e**2.0) + (v_n**2.0)) v_scalar, lon_grid = add_cyclic_point(v_scalar, contour_info['lon_grid']) ax.collections = [] ax.contourf( np.rad2deg(lon_grid), np.rad2deg(contour_info['lat_grid']), v_scalar, contour_info['c_levels'], transform = ccrs.PlateCarree(), norm = contour_info['norm'], cmap = contour_info['cmap'], zorder = -1) #print(handles[2].__dict__) #handles[2]['U'] = v_e[::slice_, ::slice_] #handles[2]['V'] = v_n[::slice_, ::slice_] #handles[2].set_UVC( # v_e[::slice_, ::slice_], # v_n[::slice_, ::slice_],) slice_ = int(np.ceil(lon_grid.shape[0]/20)) arrows = ax.quiver( np.rad2deg(lon_grid[::slice_]), np.rad2deg(contour_info['lat_grid'][::slice_]), v_e[::slice_, ::slice_], v_n[::slice_, ::slice_], transform = ccrs.PlateCarree(), scale = 1.0E1, pivot = 'middle', color = 'mediumblue') ax = ax_arr[2] # slice_ controls the down-sampling of the data. slice_ = int(np.ceil(lon_grid.shape[0]/20)) v_e = We_real[i, :, :] v_n = Wn_real[i, :, :] v_scalar = np.sqrt((v_e**2.0) + (v_n**2.0)) v_scalar, lon_grid = add_cyclic_point(v_scalar, contour_info['lon_grid']) ax.collections = [] ax.contourf( np.rad2deg(lon_grid), np.rad2deg(contour_info['lat_grid']), v_scalar, contour_info['c_levels'], transform = ccrs.PlateCarree(), norm = contour_info['norm'], cmap = contour_info['cmap'], zorder = -1) #print(handles[2].__dict__) #handles[2]['U'] = v_e[::slice_, ::slice_] #handles[2]['V'] = v_n[::slice_, ::slice_] #handles[2].set_UVC( # v_e[::slice_, ::slice_], # v_n[::slice_, ::slice_],) slice_ = int(np.ceil(lon_grid.shape[0]/20)) arrows = ax.quiver( np.rad2deg(lon_grid[::slice_]), np.rad2deg(contour_info['lat_grid'][::slice_]), v_e[::slice_, ::slice_], v_n[::slice_, ::slice_], transform = ccrs.PlateCarree(), scale = 1.0E1, pivot = 'middle', color = 'mediumblue') anim = FuncAnimation( fig, animate, interval= 10, frames=len(t)-1) fmt = 'gif' if option == 'quick': name_anim = 'disp_anim_{:}_{:>05d}.{:}'.format(option, i_mode, fmt) else: name_anim = 'disp_anim_{:}_{:>05d}_{:>03d}.{:}'.format(option, i_mode, j_radius, fmt) if save: dir_plot = os.path.join(dir_processed, 'plots') path_anim = os.path.join(dir_plot, name_anim) print('Saving animation to {:}'.format(path_anim)) anim.save(path_anim, writer='imagemagick') plt.show() else: raise ValueError return
def plot_sh_disp_wrapper(dir_NM, i_mode, n_lat_grid, mode_real_or_complex, show = True, fmt = 'pdf', transparent = False, i_radius_str = None, close = True, c_bar_label = 'Default', figsize = None, path_outline = None): ''' Plots a vector field on the surface of a sphere in terms of the radial, consoidal and toroidal components. This is a wrapper for plot_sh_disp() which first loads the necessary arrays. Input: dir_NM, i_mode, n_lat_grid, fmt See 'Definitions of variables' in NMPostProcess/process.py. Output: None ''' # Set transparency. transparent = True # Define directories. dir_processed = os.path.join(dir_NM, 'processed') dir_spectral = os.path.join(dir_processed, 'spectral') dir_plot = os.path.join(dir_processed, 'plots') mkdir_if_not_exist(dir_plot) # Load outline data if specified. if path_outline is not None: outline_data = np.loadtxt(path_outline) else: outline_data = None # Determine if the plot is 'quick' mode or 'full' mode. if i_radius_str is None: option = 'quick' else: option = 'full' if mode_real_or_complex in ['real', 'complex_imag_only', 'complex_real_only']: if figsize is None: figsize = (3.5, 6.0) two_panel = False elif mode_real_or_complex == 'complex': if figsize is None: figsize = (7.0, 6.0) two_panel = True else: raise ValueError # Reconstruct the coordinate grid. n_lon_grid = (2*n_lat_grid) - 1 lon_grid = np.linspace(0.0, 2.0*np.pi, n_lon_grid + 1, endpoint = True)[:-1] lat_grid = np.linspace(-np.pi/2.0, np.pi/2.0, n_lat_grid, endpoint=True) if i_radius_str == 'all': _, header_info, _, _ = load_vsh_coefficients(dir_NM, i_mode, 0) n_samples = len(header_info['r_sample']) i_radius_list = list(range(n_samples)) elif i_radius_str is None: i_radius_list = [None] else: i_radius_list = [int(i_radius_str)] # Identify the eigenvalue list file. # Load the frequency of the mode. path_eigenvalues = os.path.join(dir_processed, 'eigenvalue_list.txt') freq_mHz = read_eigenvalues(path_eigenvalues, i_mode = i_mode) first_iteration = True for j_radius in i_radius_list: fig = plt.figure(figsize = figsize) # Load the VSH coefficients for the specified mode. coeffs, header_info, r_sample, i_sample = load_vsh_coefficients(dir_NM, i_mode, j_radius) if mode_real_or_complex == 'real': Ulm, Vlm, Wlm = coeffs else: Ulm_real, Vlm_real, Wlm_real, Ulm_imag, Vlm_imag, Wlm_imag = coeffs title_str_mode = 'Mode {:>4d}'.format(i_mode) title_str_freq = 'freq. {:>7.4f} mHz'.format(freq_mHz) title_str_sample = region_int_to_title(i_sample, r_sample, shell_name_path = os.path.join(dir_processed, 'shell_names.txt')) title_str_sample = title_str_sample[0].lower() + title_str_sample[1:] if two_panel: title = '{:} ({:}), sampled at {:}'.format(title_str_mode, title_str_freq, title_str_sample) else: title = '{:} ({:}),\nsampled at {:}'.format(title_str_mode, title_str_freq, title_str_sample) if first_iteration: # Infer the maximum l-value used. #n_coeffs = len(Ulm) n_coeffs = coeffs.shape[-1] l_max = (int((np.round(np.sqrt(8*n_coeffs + 1)) - 1))//2) - 1 # Re-construct the shtns calculator. m_max = l_max sh_calculator = shtns.sht(l_max, m_max) grid_type = shtns.sht_reg_fast \ | shtns.SHT_SOUTH_POLE_FIRST \ | shtns.SHT_PHI_CONTIGUOUS sh_calculator.set_grid(n_lat_grid, n_lon_grid, flags = grid_type) first_iteration = False n_c_levels_default = 20 # Expand the VSH into spatial components and plot. if mode_real_or_complex == 'real': U_r, V_e, V_n, W_e, W_n = project_from_spherical_harmonics(sh_calculator, Ulm, Vlm, Wlm) fig, ax_arr, handles, contour_info = plot_sh_disp_3_comp(lon_grid, lat_grid, U_r, V_e, V_n, W_e, W_n, fig = fig, ax_arr = None, show = False, title = title, n_c_levels = n_c_levels_default) fields = { 'U' : {'r' : U_r}, 'V' : {'e' : V_e, 'n' : V_n}, 'W' : {'e' : W_e, 'n' : W_n}} else: U_real_r, V_real_e, V_real_n, W_real_e, W_real_n = project_from_spherical_harmonics(sh_calculator, Ulm_real, Vlm_real, Wlm_real) U_imag_r, V_imag_e, V_imag_n, W_imag_e, W_imag_n = project_from_spherical_harmonics(sh_calculator, Ulm_imag, Vlm_imag, Wlm_imag) fields = { 'U' : { 'real' : { 'r' : U_real_r}, 'imag' : { 'r' : U_imag_r}}, 'V' : { 'real' : { 'n' : V_real_n, 'e' : V_real_e}, 'imag' : { 'n' : V_imag_n, 'e' : V_imag_e}}, 'W' : { 'real' : { 'n' : W_real_n, 'e' : W_real_e}, 'imag' : { 'n' : W_imag_n, 'e' : W_imag_e}}} #U_abs_r = np.sqrt((U_real_r**2.0) + (U_imag_r**2.0)) #V_abs_e = np.sqrt((V_real_e**2.0) + (V_imag_e**2.0)) #V_abs_n = np.sqrt((V_real_n**2.0) + (V_imag_n**2.0)) #W_abs_e = np.sqrt((W_real_e**2.0) + (W_imag_e**2.0)) #W_abs_n = np.sqrt((W_real_n**2.0) + (W_imag_n**2.0)) if c_bar_label == 'Default': c_bar_label_real = 'Real part' c_bar_label_imag = 'Imaginary part' else: c_bar_label_real = c_bar_label c_bar_label_imag = c_bar_label if mode_real_or_complex == 'complex': #plt.imshow(W_real_e) #plt.show() fig, ax_arr_real, handles_real, contour_info_real = plot_sh_disp_3_comp(lon_grid, lat_grid, U_real_r, V_real_e, V_real_n, W_real_e, W_real_n, fig = fig, axes_grid_int = 121, ax_arr = None, show = False, title = title, n_c_levels = n_c_levels_default, c_bar_label = c_bar_label_real, outline_data = outline_data) fig, ax_arr_imag, handles_imag, contour_info_imag = plot_sh_disp_3_comp(lon_grid, lat_grid, U_imag_r, V_imag_e, V_imag_n, W_imag_e, W_imag_n, fig = fig, axes_grid_int = 122, ax_arr = None, show = False, title = None, n_c_levels = n_c_levels_default, c_bar_label = c_bar_label_imag, outline_data = outline_data) contour_info = [contour_info_real, contour_info_imag] ax_arr = [ax_arr_real, ax_arr_imag] handles = [handles_real, handles_imag] elif mode_real_or_complex == 'complex_real_only': fig, ax_arr, handles, contour_info = plot_sh_disp_3_comp(lon_grid, lat_grid, U_real_r, V_real_e, V_real_n, W_real_e, W_real_n, fig = fig, ax_arr = None, show = False, title = title, n_c_levels = n_c_levels_default, c_bar_label = c_bar_label_real, outline_data = outline_data) elif mode_real_or_complex == 'complex_imag_only': fig, ax_arr, handles, contour_info = plot_sh_disp_3_comp(lon_grid, lat_grid, U_real_r, V_real_e, V_real_n, W_real_e, W_real_n, fig = fig, ax_arr = None, show = False, title = title, n_c_levels = n_c_levels_default, c_bar_label = c_bar_label_imag, outline_data = outline_data) else: raise ValueError # Save the plot. if fmt is not None: real_or_complex_str_dict = { 'real' : 'real', 'complex' : 'cplx', 'complex_real_only' : 'real_only', 'complex_imag_only' : 'imag_only'} real_or_complex_str = real_or_complex_str_dict[mode_real_or_complex] if option == 'quick': name_fig = 'displacement_{:}_{:}_{:>05d}.{:}'.format(option, real_or_complex_str, i_mode, fmt) else: name_fig = 'displacement_{:}_{:}_{:>05d}_{:>03d}.{:}'.format(option, real_or_complex_str, i_mode, j_radius, fmt) #plt.draw() path_fig = os.path.join(dir_plot, name_fig) print('Saving figure to {:}'.format(path_fig)) save_figure(path_fig, fmt, transparent = transparent) # Show the plot. if show: plt.show() # Close the plot. if close: plt.close() return fig, ax_arr, handles, fields, contour_info
def main(): # Read the NMPostProcess input file. dir_PM, dir_NM, option, l_max, i_mode_str, n_radii = read_input_NMPostProcess() # Load the mode identification information. dir_processed = os.path.join(dir_NM, 'processed') path_ids = os.path.join(dir_processed, 'mode_ids_{:}.txt'.format(option)) i_mode, l, type_, shell = np.loadtxt(path_ids, dtype = np.int).T # Read the mode frequency. file_eigval_list = os.path.join(dir_processed, 'eigenvalue_list.txt') _, f = read_eigenvalues(file_eigval_list) num_modes = len(f) # Read 3-D mode information. mode_info = mode_id_information_to_dict(type_, l, f, shell) # Find 1-D mode information. Ouroboros_input_file = '../Ouroboros/input_Magrathea.txt' Ouroboros_info = read_Ouroboros_input_file(Ouroboros_input_file) mode_types = list(mode_info.keys()) NormalModes_to_Ouroboros_T_layer_num_dict = {0 : 1, 2 : 0} paths_ref = dict() for mode_type in mode_types: if mode_type[0] == 'T': _, _, _, dir_type = get_Ouroboros_out_dirs(Ouroboros_info, 'T') layer_number_NormalModes = int(mode_type[1]) layer_number_Ouroboros = \ NormalModes_to_Ouroboros_T_layer_num_dict[layer_number_NormalModes] path_ref = os.path.join(dir_type, 'eigenvalues_{:>03d}.txt'.format(layer_number_Ouroboros)) else: _, _, _, dir_type = get_Ouroboros_out_dirs(Ouroboros_info, mode_type) path_ref = os.path.join(dir_type, 'eigenvalues.txt') paths_ref[mode_type] = path_ref # Read 1-D reference information. nlf_ref = reference_mode_info_to_dict(paths_ref) # For each mode, find best fitting reference mode. n = np.zeros(num_modes, dtype = np.int) f_ref = np.zeros(num_modes) ref_key_list = [] for i in range(num_modes): if type_[i] == 0: ref_key = 'R' elif type_[i] == 1: ref_key = 'S' elif type_[i] == 2: ref_key = 'T{:>1d}'.format(shell[i]) else: raise ValueError ref_key_list.append(ref_key) j_match = np.where(nlf_ref[ref_key]['l'] == l[i])[0] k_match = np.argmin(np.abs(nlf_ref[ref_key]['f'][j_match] - f[i])) i_match = j_match[k_match] n[i] = nlf_ref[ref_key]['n'][i_match] f_ref[i] = nlf_ref[ref_key]['f'][i_match] f_diff = f - f_ref format_string = '{:>5d} {:>1d} {:>4} {:>1d} {:>9.6f} {:>9.6f} {:>+10.6f}' print('{:>5} {:>1} {:>4} {:>1} {:>9} {:>9}'.format('Mode', 'n', 'type', 'l', 'f', 'f_ref', 'f_diff')) for i in range(num_modes): print(format_string.format(i_mode[i], n[i], ref_key_list[i], l[i], f[i], f_ref[i], f_diff[i])) return
def main(): # Read the NMPostProcess input file. _, dir_NM_1, _, _, _, _ = read_input_NMPostProcess() # Read the comparison input file. file_compare = 'input_compare.txt' with open(file_compare, 'r') as in_id: dir_NM_2 = in_id.readline().strip() # Read the mode frequencies. dir_processed_1 = os.path.join(dir_NM_1, 'processed') file_eigval_list_1 = os.path.join(dir_processed_1, 'eigenvalue_list.txt') _, f_1 = read_eigenvalues(file_eigval_list_1) # dir_processed_2 = os.path.join(dir_NM_2, 'processed') file_eigval_list_2 = os.path.join(dir_processed_2, 'eigenvalue_list.txt') _, f_2 = read_eigenvalues(file_eigval_list_2) # Read the comparison information. path_compare = os.path.join(dir_processed_1, 'comparison.txt') i_mode_1, i_mode_2 = np.loadtxt(path_compare, dtype=np.int).T # Load the mode identification information. path_ids_1 = os.path.join(dir_processed_1, 'mode_ids_quick.txt') _, l_1, _, _ = np.loadtxt(path_ids_1, dtype=np.int).T #i_mode, l, type_, shell = np.loadtxt(path_ids, dtype = np.int).T # Sort the frequencies of the comparison run to their best match in the # original run. f_2_reordered = f_2[i_mode_2] # Find minimum and maximum frequencies. f_min = np.min(np.concatenate([f_1, f_2])) f_max = np.max(np.concatenate([f_1, f_2])) # Find maximum frequency difference. f_diff = f_1 - f_2_reordered f_diff_frac = f_diff / (0.5 * (f_1 + f_2_reordered)) f_diff_max = np.max(np.abs(f_diff)) print('Maximum frequency difference: {:>12.6} muHz'.format(f_diff_max * 1.0E3)) #fig = plt.figure(figsize = (7.0, 7.0)) #ax = plt.gca() #ax.scatter(f_1, f_2_reordered) ## Plot guide line. #f_line_buff = 0.2 #f_min_line = f_min*(1.0 - f_line_buff) #f_max_line = f_max*(1.0 + f_line_buff) #ax.plot([f_min_line, f_max_line], [f_min_line, f_max_line]) ## Set axis limits. #f_lim_buff = 0.1 #f_min_lim = f_min*(1.0 - f_lim_buff) #f_max_lim = f_max*(1.0 + f_lim_buff) #ax.set_xlim([f_min_lim, f_max_lim]) #ax.set_ylim([f_min_lim, f_max_lim]) #font_size_label = 12 #ax.set_xlabel('Frequency (mHz) of mode in run 1', fontsize = font_size_label) #ax.set_ylabel('Frequency (mHz) of mode in run 2', fontsize = font_size_label) #ax.set_aspect(1.0) #plt.show() #fig = plt.figure() #ax = plt.gca() ##ax.plot(i_mode_1, f_diff*1.0E3, 'k.-') #ax.plot(i_mode_1, f_diff_frac*1.0E2, 'k.-') #font_size_label = 12 #ax.set_xlabel('Mode number', fontsize = font_size_label) ##ax.set_ylabel('Frequency difference ($\mu$Hz)', fontsize = font_size_label) #ax.set_ylabel('Frequency difference (%)', fontsize = font_size_label) #fig = plt.figure() #ax = plt.gca() #ax.scatter(f_1, f_diff*1.0E3, c = 'k', alpha = 0.5) ##ax.plot(i_mode_1, f_diff_frac*1.0E2, 'k.-') #font_size_label = 12 #ax.set_xlabel('Frequency', fontsize = font_size_label) #ax.set_ylabel('Frequency difference ($\mu$Hz)', fontsize = font_size_label) ##ax.set_ylabel('Frequency difference (%)', fontsize = font_size_label) fig = plt.figure() ax = plt.gca() ax.scatter(l_1, f_1, s=10 * 1.0E3 * np.abs(f_diff), c='k', alpha=0.5) #ax.plot(i_mode_1, f_diff_frac*1.0E2, 'k.-') ax.scatter([], [], c='k', s=10.0, label='1 $\mu Hz$') ax.scatter([], [], c='k', s=100.0, label='10 $\mu Hz$') ax.legend() font_size_label = 12 ax.set_xlabel('Angular order, $\ell$', fontsize=font_size_label) ax.set_ylabel('Frequency (mHz)', fontsize=font_size_label) #ax.set_ylabel('Frequency difference ($\mu$Hz)', fontsize = font_size_label) ##ax.set_ylabel('Frequency difference (%)', fontsize = font_size_label) plt.show()