ff.x, ff.y, ff.velocityField[i, :, :, j].T, ":", ":", format(ff.z[j], '.2f'), ff.Re, "-", "-", str(j), ff.velocityField[m, :, :, j].T, ff.velocityField[p, :, :, j].T, "x", "y", velName, vl_max, vl_min, args.Quiver, contour_levels, printFullTitle, args.Small, args.Type) #===================================================================# #### If Co-Ordinate given #### #===================================================================# printFullTitle = True if args.Coordinate: if n == 0: coords = Tests.indices(ff.x, lambda m: m > float(args.Coordinate)) x_coord = coords[0] x_directory = ut.make_Folder(images_directory, "x", False) ut.plot_Contour(x_directory, str(args.File[:-3]), ff.z, ff.y, ff.velocityField[i, x_coord, :, :], format(ff.x[x_coord], '.2f'), ":", ":", ff.Re, str(x_coord), "-", "-", ff.velocityField[m, x_coord, :, :], ff.velocityField[p, x_coord, :, :], "z", "y", velName, vl_max, vl_min, args.Quiver, contour_levels, printFullTitle, args.Small, args.Type) elif n == 1: coords = Tests.indices(ff.y, lambda m: m > float(args.Coordinate)) y_coord = coords[-1]
def main(File, Details, VelComponent, SpatialComponent, Coordinate, Full, SpatiallyAveraged, Quiver, Levels): #===================================================================# #### Format current directory path #### #===================================================================# pwd = ut.format_Directory_Path(os.getcwd()) #===================================================================# #### Read file and details file #### #===================================================================# file_info, original_attrs = ut.read_H5(File) details = ut.read_Details(Details) #===================================================================# #### Make output directory for images and change into it #### #===================================================================# images_directory = ut.make_Folder(pwd, "images_" + str(File)[:-3], False) os.chdir(images_directory) #===================================================================# #### Initialise flow field class with given file #### #===================================================================# ff = ffClass.FlowFieldChannelFlow( file_info['Nd'], file_info['Nx'], file_info['Ny'], file_info['Nz'], file_info['Lx'], file_info['Lz'], file_info['alpha'], file_info['beta'], details['c'], details['bf'], details['Re'], file_info['ff'], "pp") #===================================================================# #### Set velocity and spatial components #### #===================================================================# i = VelComponent n = SpatialComponent m=n+1; p=n-1 if m==3: m=0 if p==-1: p=2 velName = "" if i==0: velName = "u" elif i==1: velName = "v" elif i==2: velName = "w" #===================================================================# #### Start plotting #### #===================================================================# print("Plotting...") vl_max = np.amax(ff.velocityField[i, :, :, :]) vl_min = np.amin(ff.velocityField[i, :, :, :]) printFullTitle = True if Levels: contour_levels = Levels else: contour_levels = 20 #===================================================================# #### If Full selected #### #===================================================================# if Full: if n == 0: x_directory = ut.make_Folder(images_directory, "x", False) for j in range(0, ff.Nx): ut.plot_Contour(x_directory, str(File[:-3]), ff.z, ff.y, ff.velocityField[i, j, :, :], format(ff.x[j], '.2f'), ":", ":", ff.Re, str(j), "-", "-", ff.velocityField[m, j, :, :], ff.velocityField[p, j, :, :], "z", "y", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) elif n == 1: y_directory = ut.make_Folder(images_directory, "y", False) for j in range(0, ff.Ny): ut.plot_Contour(y_directory, str(File[:-3]), ff.z, ff.x, ff.velocityField[i, :, j, :], ":", format(ff.y[j], '.2f'), ":", ff.Re, "-", str(j), "-", ff.velocityField[m, :, j, :], ff.velocityField[p, :, j, :], "z", "x", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) elif n == 2: z_directory = ut.make_Folder(images_directory, "z", False) for j in range(0, ff.Nz): ut.plot_Contour(z_directory, str(File[:-3]), ff.x, ff.y, ff.velocityField[i, :, :, j].T, ":", ":", format(ff.z[j], '.2f'), ff.Re, "-", "-", str(j), ff.velocityField[m, :, :, j].T, ff.velocityField[p, :, :, j].T, "x", "y", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) #===================================================================# #### If Co-Ordinate given #### #===================================================================# printFullTitle = True if Coordinate: if n == 0: coords = Tests.indices(ff.x, lambda m: m > float(Coordinate)) x_coord = coords[0] x_directory = ut.make_Folder(images_directory, "x", False) ut.plot_Contour(x_directory, str(File[:-3]), ff.z, ff.y, ff.velocityField[i, x_coord, :, :], format(ff.x[x_coord], '.2f'), ":", ":", ff.Re, str(x_coord), "-", "-", ff.velocityField[m, x_coord, :, :], ff.velocityField[p, x_coord, :, :], "z", "y", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) elif n == 1: coords = Tests.indices(ff.y, lambda m: m > float(Coordinate)) y_coord = coords[-1] y_directory = ut.make_Folder(images_directory, "y", False) ut.plot_Contour(y_directory, str(File[:-3]), ff.z, ff.x, ff.velocityField[i, :, y_coord, :], ":", format(ff.y[y_coord], '.2f'), ":", ff.Re, "-", str(y_coord), "-", ff.velocityField[m, :, y_coord, :], ff.velocityField[p, :, y_coord, :], "z", "x", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) elif n == 2: coords = Tests.indices(ff.z, lambda m: m > float(Coordinate)) z_coord = coords[0] z_directory = ut.make_Folder(images_directory, "z", False) ut.plot_Contour(z_directory, str(File[:-3]), ff.x, ff.y, ff.velocityField[i, :, :, z_coord].T, ":", ":", format(ff.z[z_coord], '.2f'), ff.Re, "-", "-", str(z_coord), ff.velocityField[m, :, :, z_coord].T, ff.velocityField[p, :, :, z_coord].T, "x", "y", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) #===================================================================# #### If Spatially averaging selected #### #===================================================================# printFullTitle = False if SpatiallyAveraged: if n == 0: # Average the flow field in teh streamwise direction. x_averaged_ff = np.zeros((ff.Nd, ff.Ny, ff.Nz)) for nd in range(0, ff.Nd): for nx in range(0, ff.Nx): x_averaged_ff[nd, :, :] += ff.velocityField[nd, nx, :, :] x_averaged_ff *= (1.0 / ff.Nx) vl_max = np.amax(x_averaged_ff[i, :, :]) vl_min = np.amin(x_averaged_ff[i, :, :]) fileName = str(File)[:-3] + "_x_avgd_" ut.plot_Contour(images_directory, fileName, ff.z, ff.y, x_averaged_ff[i, :, :], "avg", ":", ":", ff.Re, "x-avg", "-", "-", x_averaged_ff[m, :, :], x_averaged_ff[p, :, :], "z", "y", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) elif n == 1: # Average the flow field in teh streamwise direction. y_averaged_ff = np.zeros((ff.Nd, ff.Nx, ff.Nz)) for nd in range(0, ff.Nd): for ny in range(0, ff.Ny): y_averaged_ff[nd, :, :] += ff.velocityField[nd, :, ny, :] y_averaged_ff *= (1.0 / ff.Ny) vl_max = np.amax(y_averaged_ff[i, :, :]) vl_min = np.amin(y_averaged_ff[i, :, :]) fileName = str(File)[:-3] + "_y_avgd_" ut.plot_Contour(images_directory, fileName, ff.z, ff.x, y_averaged_ff[i, :, :], ":", "avg", ":", ff.Re, "-", "y-avg", "-", y_averaged_ff[m, :, :], y_averaged_ff[p, :, :], "z", "x", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) elif n == 2: # Average the flow field in teh streamwise direction. z_averaged_ff = np.zeros((ff.Nd, ff.Nx, ff.Ny)) for nd in range(0, ff.Nd): for nz in range(0, ff.Nz): z_averaged_ff[nd, :, :] += ff.velocityField[nd, :, :, nz] z_averaged_ff *= (1.0 / ff.Nz) vl_max = np.amax(z_averaged_ff[i, :, :]) vl_min = np.amin(z_averaged_ff[i, :, :]) fileName = str(File)[:-3] + "_z_avgd_" ut.plot_Contour(images_directory, fileName, ff.x, ff.y, z_averaged_ff[i, :, :].T, ":", ":", "avg", ff.Re, "-", "-", "z-avg", z_averaged_ff[m, :, :].T, z_averaged_ff[p, :, :].T, "x", "y", velName, vl_max, vl_min, Quiver, contour_levels, printFullTitle) ut.print_EndMessage()
def test_deconstruct_field(original_ff_spectral, kx_array, kz_array, Nm, y, c, Re, baseflow, mean_profile, sparse): #===============================================================# #### Store the resolvent modes and amplitude coefficients #### # at each Fourier mode pair # #===============================================================# resolvent_modes_array = np.zeros((len(kx_array), len(kz_array), 3*Nm, 3*Nm), dtype=np.complex128) forcing_modes_array = np.zeros((len(kx_array), len(kz_array), 3*Nm, 3*Nm), dtype=np.complex128) coefficients_array = np.zeros((len(kx_array), len(kz_array), 3*Nm), dtype=np.complex128) sing_vals_array = np.zeros((len(kx_array), len(kz_array), 3*Nm), dtype=np.float64) #================================================================ #### Loop through wavenumbers #================================================================ chebyshev_differentiation, mean_flow_derivatives = ps.calculate_derivatives(Nm+2, mean_profile, baseflow) #================================================================ #### FFT mean profile #================================================================ spectral_deviation_profile = np.zeros((3*Nm),dtype=complex) if len(mean_profile) == 0: spectral_deviation_profile = original_ff_spectral[0,:,0] else: # Remove baseflow from turbulent mean profile baseflow_profile = [] if baseflow == "lam": # Laminary base flow baseflow_profile = 1.0 - y**2.0 elif baseflow == "cou": # Couette base flow baseflow_profile = y # Remove baseflow from mean to get turbulent deviation profile vel_profile = mean_profile - np.asarray(baseflow_profile) deviation_profile_sp = np.fft.fft(vel_profile) spectral_deviation_profile[1:Nm] = deviation_profile_sp[1:Nm] #================================================================ #### Loop through wavenumbers #================================================================ startTime = datetime.now() for mx in range(0, len(kx_array)): kx = kx_array[mx] print('\n\nkx:'+ str(kx)) for mz in range(0, len(kz_array)): kz = kz_array[mz] sys.stdout.write(".") sys.stdout.flush() if kx == 0 and kz == 0: # Zeroth Fourier modes resolvent_modes_array[mx, mz, :, 0] = spectral_deviation_profile continue # Start the loop again #-------------------------------------------------------- #### Calculate the state vectors #-------------------------------------------------------- omega = kx * c wegihted_transfer_function, w = ps.calculate_transfer_function(kx, kz, Re, Nm, omega, chebyshev_differentiation, mean_flow_derivatives) #-------------------------------------------------------- #### Perform SVD #-------------------------------------------------------- if sparse: weighted_resolvent_modes, singular_values, weighted_forcing_modes = svd(wegihted_transfer_function, full_matrices=False) else: weighted_resolvent_modes, singular_values, weighted_forcing_modes = svd(wegihted_transfer_function) #-------------------------------------------------------- #### Test: SVD #-------------------------------------------------------- Tests.SVD(weighted_resolvent_modes, singular_values, weighted_forcing_modes, wegihted_transfer_function, sparse) #-------------------------------------------------------- #### Test: Orthogonality #-------------------------------------------------------- Tests.orthogonality(weighted_resolvent_modes) Tests.orthogonality(weighted_forcing_modes) #-------------------------------------------------------- #### Test: Invertibility #-------------------------------------------------------- Tests.invertible(np.diag(singular_values)) #-------------------------------------------------------- #### Retrieve non-grid-weighted (physical) modes #-------------------------------------------------------- weighted_resolvent_modes = np.asmatrix(weighted_resolvent_modes) weighted_forcing_modes = np.asmatrix(weighted_forcing_modes) resolvent_modes = np.linalg.solve(w, weighted_resolvent_modes) forcing_modes = np.linalg.solve(w, weighted_forcing_modes) #-------------------------------------------------------- #### Check that the continuity condition is satisfied #-------------------------------------------------------- Tests.continuity(resolvent_modes, np.diag(singular_values), kx, kz, Nm, chebyshev_differentiation['D1']) #-------------------------------------------------------- #### Fix phase of resolvent modes based on critical layer or centreline #-------------------------------------------------------- phase_shift = np.zeros((resolvent_modes.shape[1], resolvent_modes.shape[1]), dtype=np.complex128) ind0 = Nm/2 + 1 # Use centreline, unless if c < 1.0: inds = Tests.indices(mean_flow_derivatives['U'].diagonal(), lambda x: x > c) if len(inds) > 0: ind0 = inds[0] np.fill_diagonal(phase_shift, np.exp(-1j * np.angle(resolvent_modes[ind0,:]))) resolvent_modes *= phase_shift #-------------------------------------------------------- #### Project resolvent modes to get amplitude coefficients #-------------------------------------------------------- # Initialize amplitude coefficients vector ampl_coeffs = np.zeros((3*Nm, 1), dtype=np.complex128) # Projection ampl_coeffs = inv(np.diag(singular_values)) * resolvent_modes.H * w.H * w * np.asmatrix(original_ff_spectral[mx, :, mz]).T Tests.projection(ampl_coeffs, np.diag(singular_values), resolvent_modes, np.asmatrix(original_ff_spectral[mx, :, mz]).T, 1e-10) # phase_test = False # norm_test = False # xi_norm = np.linalg.norm(xi) # if kz == 2.0 or kz == -2.0: # #xi_norm >= 1e-10: # # Phase test # if phase_test: # print("\nApplying phase shift at: " + str(kz) + "\n ") # # shift the field by pi/3 # xi += 1.0j*(np.pi/3.0) # # # Norm test # if norm_test: # print("\nApplying norm doubling.") # # Double the energy of the field # xi *= np.sqrt(2.0) + 1.0j*np.sqrt(2.0) # # # Fix xi to see if same coefficients are retrieved from projection # if fixXi: # xi[0] = 1.0 # xi[1] = 0.0 # print("\nXI:") # print("norm: " + str(xi_norm)) # print(xi) # print("") # print(xi) #-------------------------------------------------------- #### Store resolvent modes, singular values and amplitude coeffs. #-------------------------------------------------------- resolvent_modes_array[mx, mz, :, :] = resolvent_modes forcing_modes_array[mx, mz, :, :] = forcing_modes coefficients_array[mx, mz, :] = np.squeeze(np.asarray(ampl_coeffs)) sing_vals_array[mx, mz, :] = singular_values calcTime = datetime.now() - startTime print("\n\n\n") print(calcTime) print("\n\n\n") deconstructed_dict = {} deconstructed_dict['resolvent_modes'] = resolvent_modes_array deconstructed_dict['forcing_modes'] = forcing_modes_array deconstructed_dict['singular_values'] = sing_vals_array deconstructed_dict['coefficients'] = coefficients_array return deconstructed_dict
def resolvent_formulation(ff): #===============================================================# #### Initialize 3D array to store approximated velocity field ### #===============================================================# # Velocity field is stacked in the wall-normal direction. tmp = np.zeros((ff.Nx, ff.Nd*ff.Nm, ff.Nz), dtype=complex) # Note that the number of gridpoints in the wall-normal direction # are equal to the number of interior Chebyshev nodes. This is # becasue when reshaped, the velocity field is missing its # wall-boundaries, i.e. top and bottom xz-planes. #===============================================================# #### Calculate differentiation matrices and mean flow derivatives #===============================================================# chebyshev_differentiation, mean_flow_derivatives = ps.calculate_derivatives(ff.Ny, [], ff.baseflow) #===============================================================# #### Loop through Wavepacket #### #===============================================================# for triplet in range(0, len(ff.kx)): #===========================================================# #### Get fundamental wavenumbers from Wavepacket #### #===========================================================# fund_alpha = ff.kx[triplet] fund_beta = ff.kz[triplet] amplitude = ff.chi_tilde[triplet] #===========================================================# #### Calculate first Fourier modes #### #===========================================================# kx_array = fund_alpha * ff.Mx kz_array = fund_beta * ff.Mz #===========================================================# #### Loop through the Fourier modes #### #===========================================================# for mx in range(0, len(kx_array)): kx = kx_array[mx] # Streamwise Fourier mode for mz in range(0, len(kz_array)): kz = kz_array[mz] # Spanwise Fourier mode if kx == 0 or kz == 0: continue print('kx:\t'+ str(kx) + "\tkz:\t" + str(kz)) #---------------------------------------------------- #### Calculate the state vectors - #---------------------------------------------------- omega = kx * ff.c wegihted_transfer_function, w = ps.calculate_transfer_function(kx, kz, ff.Re, ff.Nm, omega, chebyshev_differentiation, mean_flow_derivatives) #---------------------------------------------------- #### Perform SVD - #---------------------------------------------------- weighted_resolvent_modes, singular_values, weighted_forcing_modes = svd(wegihted_transfer_function) #---------------------------------------------------- #### Test: SVD - #---------------------------------------------------- Tests.SVD(weighted_resolvent_modes, singular_values, weighted_forcing_modes, wegihted_transfer_function, False) #---------------------------------------------------- #### Test: Orthogonality - #---------------------------------------------------- Tests.orthogonality(weighted_resolvent_modes) Tests.orthogonality(weighted_forcing_modes) #---------------------------------------------------- #### Test: Invertibility - #---------------------------------------------------- Tests.invertible(np.diag(singular_values)) #---------------------------------------------------- #### Retrieve non-grid-weighted (physical) modes - #---------------------------------------------------- weighted_resolvent_modes = np.asmatrix(weighted_resolvent_modes) weighted_forcing_modes = np.asmatrix(weighted_forcing_modes) resolvent_modes = np.linalg.solve(w, weighted_resolvent_modes) forcing_modes = np.linalg.solve(w, weighted_forcing_modes) #---------------------------------------------------- #### Test: Continuity condition - #---------------------------------------------------- Tests.continuity(resolvent_modes, np.diag(singular_values), kx, kz, ff.Nm, chebyshev_differentiation['D1']) #---------------------------------------------------- #### Fix phase of resolvent modes - # based on critical layer or centreline - #---------------------------------------------------- phase_shift = np.zeros((resolvent_modes.shape[1], resolvent_modes.shape[1]), dtype=np.complex128) ind0 = ff.Nm/2 + 1 # Use centreline, unless if ff.c < 1.0: inds = Tests.indices(mean_flow_derivatives['U'].diagonal(), lambda x: x > ff.c) if len(inds) > 0: ind0 = inds[0] np.fill_diagonal(phase_shift, np.exp(-1j * np.angle(resolvent_modes[ind0,:]))) resolvent_modes *= phase_shift # Alternative Method: # # Non-weighted forcing modes (physical forcing modes) # unweighted_forcing_modes = np.linalg.solve(state_vecs['w'], forcing_modes_h.conjugate().T) # unweighted_forcing_modes *= phase_shift # unweighted_H = np.linalg.inv(state_vecs['w']) * state_vecs['H'] * state_vecs['w'] # unweighted_vel_modes = unweighted_H * unweighted_forcing_modes * np.diag(1.0/singular_values) # delta_r = unweighted_vel_modes.real - resolvent_modes.real # delta_i = unweighted_vel_modes.imag - resolvent_modes.imag #---------------------------------------------------- #### Calculate spectral velocity vector - # u_tilde = psi * sigma * xi - # u_tilde = psi * chi - #---------------------------------------------------- u_tilde = resolvent_modes[:, 0] * amplitude # Rank 1 #---------------------------------------------------- # Inverse fourier transform - #---------------------------------------------------- u_tilde = np.asmatrix(u_tilde) physical_ff = np.zeros((ff.Nx, ff.Nd*ff.Nm, ff.Nz), dtype=complex) physical_ff = ps.my_ifft(u_tilde, kx, kz, ff) tmp += physical_ff return tmp
def deconstruct_field(original_ff_spectral, kx_array, kz_array, Nm, y, c, Re, baseflow, mean_profile, sparse): ''' Deconstruct given flow field and return the resolvent modes, forcing modes, singular values and amplitude coefficients needed to reconstruct it. ================================================================= INPUTS: ================================================================= original_ff_spectral: 3D array of flow field to approximate in xz spectral form with Chebyshev nodes in wall-normal direction (Chebyshev spacing). Stacked in wall-normal direction: dimensions: (Nx, Nd*Ny, Nz). kx_array: 1D array of streamwise Fourier modes. kz_array: 1D array of spanwise Fourier modes. Nm: Number of interior Chebyshev nodes, i.e. Ny - 2 (endpoints removed). y: Grid points in the wall-normal direction. c: Wavespeed. Re: Reynolds number based on laminar baseflow centreline velocity, i.e. Re = 1 / nu. baseflow: Base flow type: [laminar, Couette], laminar means Plane Poiseuille. mean_profile: 1D array of streamwise velocity profile of the turbulent mean in wall-normal direction, (endpoints included). sparse: Boolean that determines whether to use sparse or full SVD algorithm. ================================================================= OUTPUTS: ================================================================= A dictionary named 'deconstructed_dict' which contains: resolvent_modes: 4D array of resolvent modes at each Fourier mode combination: resolvent_modes[mx, mz, :, :] gives column vectors of given rank, i.e. rank = resolvent_modes.shape[3]. forcing_modes: 4D array of forcing modes at each Fourier mode combination:= resolvent_modes[mx, mz, :, :] gives column vectors of given rank, i.e. rank = resolvent_modes.shape[3]. singular_values: 3D array of singular values at each Fourier mode combination: singular_values[mx, mz, :] gives 1D array of singular values, where rank = len(singular_values[mx, mz, :]). coefficients: 3D array of complex amplitude coefficients at each Fourier mode combination: coefficients[mx, mz, :] gives 1D array of coefficients, where rank = len(coefficients[mx, mz, :]). ''' #===============================================================# #### Store the resolvent modes and amplitude coefficients #### # at each Fourier mode pair # #===============================================================# resolvent_modes_array = np.zeros((len(kx_array), len(kz_array), 3*Nm, 3*Nm), dtype=complex) forcing_modes_array = np.zeros((len(kx_array), len(kz_array), 3*Nm, 3*Nm), dtype=complex) coefficients_array = np.zeros((len(kx_array), len(kz_array), 3*Nm), dtype=complex) sing_vals_array = np.zeros((len(kx_array), len(kz_array), 3*Nm), dtype=float) #===============================================================# #### Calculate differentiation matrices and mean flow derivatives #===============================================================# chebyshev_differentiation, mean_flow_derivatives = ps.calculate_derivatives(Nm+2, mean_profile, baseflow) #===============================================================# #### Loop through wavenumbers #### #===============================================================# startTime = datetime.now() for mx in range(0, len(kx_array)): kx = kx_array[mx] # print('\nkx:'+ str(kx)) for mz in range(0, len(kz_array)): kz = kz_array[mz] # sys.stdout.write(".") # sys.stdout.flush() if kx == 0 and kz == 0: # Zeroth Fourier modes resolvent_modes_array[mx, mz, :, 0] = original_ff_spectral[mx, :, mz] continue # Start the loop again #-------------------------------------------------------- #### Calculate the state vectors - #-------------------------------------------------------- omega = kx * c wegihted_transfer_function, w = ps.calculate_transfer_function(kx, kz, Re, Nm, omega, chebyshev_differentiation, mean_flow_derivatives) #-------------------------------------------------------- #### Perform SVD - #-------------------------------------------------------- if sparse: weighted_resolvent_modes, singular_values, weighted_forcing_modes = svd(wegihted_transfer_function, full_matrices=False) else: weighted_resolvent_modes, singular_values, weighted_forcing_modes = svd(wegihted_transfer_function) #-------------------------------------------------------- #### Test: SVD - #-------------------------------------------------------- Tests.SVD(weighted_resolvent_modes, singular_values, weighted_forcing_modes, wegihted_transfer_function, sparse) #-------------------------------------------------------- #### Test: Orthogonality - #-------------------------------------------------------- Tests.orthogonality(weighted_resolvent_modes) Tests.orthogonality(weighted_forcing_modes) #-------------------------------------------------------- #### Test: Invertibility - #-------------------------------------------------------- Tests.invertible(np.diag(singular_values)) #-------------------------------------------------------- #### Retrieve non-grid-weighted (physical) modes - #-------------------------------------------------------- weighted_resolvent_modes = np.asmatrix(weighted_resolvent_modes) weighted_forcing_modes = np.asmatrix(weighted_forcing_modes) resolvent_modes = np.linalg.solve(w, weighted_resolvent_modes) forcing_modes = np.linalg.solve(w, weighted_forcing_modes) #-------------------------------------------------------- #### Tests: Continuity condition - #-------------------------------------------------------- Tests.continuity(resolvent_modes, np.diag(singular_values), kx, kz, Nm, chebyshev_differentiation['D1']) #-------------------------------------------------------- #### Fix phase of resolvent modes - # based on critical layer or centreline - #-------------------------------------------------------- phase_shift = np.zeros((resolvent_modes.shape[1], resolvent_modes.shape[1]), dtype=np.complex128) ind0 = Nm/2 + 1 # Use centreline, unless if c < 1.0: inds = Tests.indices(mean_flow_derivatives['U'].diagonal(), lambda x: x > c) if len(inds) > 0: ind0 = inds[0] np.fill_diagonal(phase_shift, np.exp(-1j * np.angle(resolvent_modes[ind0,:]))) resolvent_modes *= phase_shift #-------------------------------------------------------- #### Project resolvent modes to get coefficients - #-------------------------------------------------------- # Initialize amplitude coefficients vector xi = np.zeros((3*Nm, 1), dtype=complex) # Projection xi = inv(np.diag(singular_values)) * resolvent_modes.H * w.H * w * np.asmatrix(original_ff_spectral[mx, :, mz]).T Tests.projection(xi, np.diag(singular_values), resolvent_modes, np.asmatrix(original_ff_spectral[mx, :, mz]).T, 1e-10) #-------------------------------------------------------- #### Store resolvent modes, singular values and coeffs. - #-------------------------------------------------------- resolvent_modes_array[mx, mz, :, :] = resolvent_modes forcing_modes_array[mx, mz, :, :] = forcing_modes coefficients_array[mx, mz, :] = np.squeeze(np.asarray(xi)) sing_vals_array[mx, mz, :] = singular_values calcTime = datetime.now() - startTime # print("\n\n\n") # print(calcTime) # print("\n\n\n") deconstructed_dict = {} deconstructed_dict['resolvent_modes'] = resolvent_modes_array deconstructed_dict['forcing_modes'] = forcing_modes_array deconstructed_dict['singular_values'] = sing_vals_array deconstructed_dict['coefficients'] = coefficients_array return deconstructed_dict