def test_parser_boundaries(verbose=False): """ Here we add the value B to the boundary without setting it in the system. This should return a NameError """ # Create system system = System(grid, variables='f', eigenvalue='sigma') # Add the first (and only) equation system.add_equation("sigma*z*f = dz(dz(f))") system.add_boundary('f', 'Dirichlet', 'B*f = 0') solver = Solver(grid, system) with pytest.raises(NameError) as e_info: # The error is found when the solve method is called solver.solve() if verbose: print(str(e_info.value))
def test_solver_methods(verbose=False): """Show how the solver class methods can be called directly, using the MTI as an example. This can be useful when setting up a new problem. """ import numpy as np from psecas import Solver, ChebyshevExtremaGrid from psecas.systems.mti import MagnetoThermalInstability from scipy.linalg import eig grid = ChebyshevExtremaGrid(N=64, zmin=0, zmax=1) system = MagnetoThermalInstability(grid, beta=1e5, Kn0=200, kx=4 * np.pi) solver = Solver(grid, system) solver.get_matrix1(verbose=verbose) solver.get_matrix2(verbose=verbose) E, V = eig(solver.mat1.toarray(), solver.mat2.toarray()) # Sort the eigenvalues E, index = solver.sorting_strategy(E) mode = 0 # Choose the eigenvalue mode value only sigma = E[index[mode]] v = V[:, index[mode]] np.testing.assert_allclose(1.7814514515967603, sigma, atol=1e-8) # Compare with solve without using OPinv solver.solve(useOPinv=False, saveall=True) np.testing.assert_allclose(solver.E[mode], sigma, atol=1e-8)
Berlok, T. & Pfrommer, C. (2019). *On the Kelvin-Helmholtz instability with smooth initial conditions – Linear theory and simulations*, MNRAS, 485, 908 Another reference for the KHI with anisotropic viscosity is Suzuki, K., Ogawa, T., Matsumoto, Y., & Matsumoto, R. (2013). Magnetohydrodynamic simulations of the formation of cold fronts in clusters of galaxies: Effects of anisotropic viscosity. Astrophysical Journal, 768(2). https://doi.org/10.1088/0004-637X/768/2/175 """ directory = './data/' kx_global = np.linspace(3, 4, 5) kx_local = kx_global[comm.rank :: comm.size] grid = FourierGrid(N=64, zmin=0, zmax=2) system = KelvinHelmholtzUniform(grid, beta=1e4, nu=1e-2, kx=0) io = IO(system, directory, __file__, len(kx_global)) solver = Solver(grid, system) for i in range(len(kx_local)): t1 = time.time() system.kx = kx_local[i] omega, v = solver.solve() io.save_system(i) io.log(i, time.time() - t1, 'kx = {:1.4e}'.format(system.kx)) io.finished()
# Set large values to zero, as they are presumably numerical artifact # and unphysical. E[np.abs(E.real) > 20.0] = 0 E[np.abs(E.imag) > 20.0] = 0 # Sort from largest to smallest eigenvalue index = np.argsort(np.real(E))[::-1] return (E, index) # Overwrite the standard sorting strategy with the function defined above solver.sorting_strategy = sorting_strategy # Solve the full matrix problem keeping all eigenvalues and vectors # results are stored in solver.E (a 1D array with the eigenvalues) and solver.v # (a 2D array of the eigenvectors). solver.solve(saveall=True) """ The approximation to the physical eigenvalue problem is a matrix eigenvalue problem. The matrix has size d times N (where d is the number of linearized equations and N is the number of grid points). There are thus d times N eigenvalues. Obviously, the number of physical eigenvalues cannot depend on the number of grid points. Some of the solutions found above are therefore not physical (see e.g. the book by Boyd). The solutions were also calculated at fixed number of grid points, N. Convergent solutions are found by increasing N and discarding the eigenvalues that are not present at higher N. This would normally be done by manually increasing N, calling solve, looking at the eigenvalues, increasing N, calling solve, comparing with previous iteration and so on. This procedure is tedious. The solver class in Psecas contains a different method, iterate_solver,
hydrodynamics, MNRAS, 455(4), 4274–4288. https://doi.org/10.1093/mnras/stv2564 """ # Plot omega vs kx if True: grid = FourierGrid(N=64, zmin=0.0, zmax=2.0) system = KelvinHelmholtzHydroOnly(grid, u0=1.0, delta=1.0, kx=0) solver = Solver(grid, system) omega_vec = [] kx_vec = np.linspace(0.1, 8, 15) for kx in kx_vec: t1 = time.time() system.kx = kx (omega, v) = solver.solve() omega_vec.append(omega) print(kx, omega) t2 = time.time() print("Solver took {} seconds".format(t2 - t1)) omega_vec = np.array(omega_vec) plt.figure(1) # plt.clf() plt.plot(kx_vec, omega_vec.real) plt.xlabel(r"$k_x$") plt.ylabel(r"$\omega$") plt.show() # Find the kx that gives maximum growth if False:
drhodz_sym = sym.diff(rho_sym, z) domgdz_sym = sym.diff(Omg_sym, z) zg = self.grid.zg self.rho = np.ones_like(zg) * lambdify(z, rho_sym)(zg) self.Omg = np.ones_like(zg) * lambdify(z, Omg_sym)(zg) self.shr = np.ones_like(zg) * lambdify(z, shr_sym)(zg) self.drhodz = np.ones_like(zg) * lambdify(z, drhodz_sym)(zg) self.domgdz = np.ones_like(zg) * lambdify(z, domgdz_sym)(zg) # Create a grid grid = ChebyshevRationalGrid(N=200, C=0.2) # grid = ChebyshevExtremaGrid(N=199, zmin=-5, zmax=5) # Create the system system = VerticalShearInstability(grid, variables=['rh', 'wx', 'wy', 'wz'], eigenvalue='sigma') # The linearized equations system.add_equation("-sigma*rh = - 1j*kx*wx - 1/h*dz(wz) - 1/h*drhodz/rho*wz") system.add_equation("-sigma*wx = + 2*Omg*wy - 1j*kx*(h/O0)**2*rh") system.add_equation("-sigma*wy = - (2*Omg + shr)*wx - 1/h*domgdz*wz") system.add_equation("-sigma*wz = - h/O0**2*dz(rh)", boundary=True) solver = Solver(grid, system, do_gen_evp=True) omega, vec = solver.solve(mode=0, verbose=True) plot_solution(system)