def test_heat_1d_periodic(x_basis_class, Nx, timestepper, dtype): # Bases c = coords.Coordinate('x') d = distributor.Distributor((c, )) xb = basis.ComplexFourier(c, size=Nx, bounds=(0, 2 * np.pi)) x = xb.local_grid(1) # Fields u = field.Field(name='u', dist=d, bases=(xb, ), dtype=dtype) F = field.Field(name='F', dist=d, bases=(xb, ), dtype=dtype) F['g'] = -np.sin(x) # Problem dx = lambda A: operators.Differentiate(A, c) dt = operators.TimeDerivative problem = problems.IVP([u]) problem.add_equation((-dt(u) + dx(dx(u)), F)) # Solver solver = solvers.InitialValueSolver(problem, timestepper) dt = 1e-5 iter = 10 for i in range(iter): solver.step(dt) # Check solution amp = 1 - np.exp(-solver.sim_time) u_true = amp * np.sin(x) assert np.allclose(u['g'], u_true)
def test_waves_1d(x_basis_class, Nx, dtype): # Bases c = coords.Coordinate('x') d = distributor.Distributor((c, )) xb = x_basis_class(c, size=Nx, bounds=(0, np.pi)) x = xb.local_grid(1) # Fields u = field.Field(name='u', dist=d, bases=(xb, ), dtype=dtype) a = field.Field(name='a', dist=d, dtype=dtype) τ1 = field.Field(name='τ1', dist=d, dtype=dtype) τ2 = field.Field(name='τ2', dist=d, dtype=dtype) # Problem dx = lambda A: operators.Differentiate(A, c) xb2 = dx(dx(u)).domain.bases[0] P1 = field.Field(name='P1', dist=d, bases=(xb2, ), dtype=dtype) P2 = field.Field(name='P2', dist=d, bases=(xb2, ), dtype=dtype) P1['c'][-1] = 1 P2['c'][-2] = 1 problem = problems.EVP([u, τ1, τ2], a) problem.add_equation((a * u + dx(dx(u)) + P1 * τ1 + P2 * τ2, 0)) problem.add_equation((u(x=0), 0)) problem.add_equation((u(x=np.pi), 0)) # Solver solver = solvers.EigenvalueSolver(problem, matrix_coupling=[True]) solver.solve_dense(solver.subproblems[0]) i_sort = np.argsort(solver.eigenvalues) sorted_eigenvalues = solver.eigenvalues[i_sort] # Check solution Nmodes = Nx // 4 k = np.arange(Nmodes) + 1 assert np.allclose(sorted_eigenvalues[:Nmodes], k**2)
def test_waves_1d_first_order(x_basis_class, Nx, dtype): # Bases c = coords.Coordinate('x') d = distributor.Distributor((c, )) xb = x_basis_class(c, size=Nx, bounds=(0, np.pi)) x = xb.local_grid(1) # Fields u = field.Field(name='u', dist=d, bases=(xb, ), dtype=dtype) ux = field.Field(name='ux', dist=d, bases=(xb, ), dtype=dtype) a = field.Field(name='a', dist=d, dtype=dtype) τ1 = field.Field(name='τ1', dist=d, dtype=dtype) τ2 = field.Field(name='τ2', dist=d, dtype=dtype) # Problem dx = lambda A: operators.Differentiate(A, c) xb1 = dx(u).domain.bases[0] P1 = field.Field(name='P1', dist=d, bases=(xb1, ), dtype=dtype) P2 = field.Field(name='P2', dist=d, bases=(xb1, ), dtype=dtype) P1['c'][-1] = 1 P2['c'][-1] = 1 problem = problems.EVP([u, ux, τ1, τ2], a) problem.add_equation((a * u + dx(ux) + P1 * τ1, 0)) problem.add_equation((ux - dx(u) + P2 * τ2, 0)) problem.add_equation((u(x=0), 0)) problem.add_equation((u(x=np.pi), 0)) # Solver solver = solvers.EigenvalueSolver(problem, matrix_coupling=[True]) solver.solve_dense(solver.subproblems[0]) i_sort = np.argsort(solver.eigenvalues) solver.eigenvalues = solver.eigenvalues[i_sort] solver.eigenvectors = solver.eigenvectors[:, i_sort] # Check solution solver.set_state(0, solver.subproblems[0].subsystems[0]) eigenfunction = u['g'] / np.max(u['g']) sol = np.sin(x) / np.max(np.sin(x)) assert np.allclose(eigenfunction, sol)
def test_sin_nlbvp(Nx, dtype, dealias, basis_class): ncc_cutoff = 1e-10 tolerance = 1e-10 # Bases c = coords.Coordinate('x') d = distributor.Distributor((c,)) xb = basis_class(c, size=Nx, bounds=(0, 1), dealias=dealias) x = xb.local_grid(1) # Fields u = field.Field(name='u', dist=d, bases=(xb,), dtype=dtype) τ = field.Field(name='τ', dist=d, dtype=dtype) xb1 = xb.clone_with(a=xb.a+1, b=xb.b+1) P = field.Field(name='P', dist=d, bases=(xb1,), dtype=dtype) P['c'][-1] = 1 # Problem dx = lambda A: operators.Differentiate(A, c) problem = problems.NLBVP([u, τ]) problem.add_equation((dx(u) + τ*P, np.sqrt(1-u*u))) problem.add_equation((u(x=0), 0)) # Solver solver = solvers.NonlinearBoundaryValueSolver(problem, ncc_cutoff=ncc_cutoff) # Initial guess u['g'] = x # Iterations def error(perts): return np.sum([np.sum(np.abs(pert['c'])) for pert in perts]) err = np.inf while err > tolerance: solver.newton_iteration() err = error(solver.perturbations) # Check solution u_true = np.sin(x) u.change_scales(1) assert np.allclose(u['g'], u_true)
def test_jacobi_differentiate(N, a, b, k, dtype): c = coords.Coordinate('x') d = distributor.Distributor((c,)) b = basis.Jacobi(c, size=N, a0=a, b0=b, a=a+k, b=b+k, bounds=(0, 1)) x = b.local_grid(1) f = field.Field(dist=d, bases=(b,), dtype=dtype) f['g'] = x**5 fx = operators.Differentiate(f, c).evaluate() assert np.allclose(fx['g'], 5*x**4)
def test_jacobi_convert_explicit(N, a, b, k, dtype, layout): c = coords.Coordinate('x') d = distributor.Distributor((c,)) b = basis.Jacobi(c, size=N, a0=a, b0=b, a=a+k, b=b+k, bounds=(0, 1)) x = b.local_grid(1) f = field.Field(dist=d, bases=(b,), dtype=dtype) f['g'] = x**5 fx = operators.Differentiate(f, c) f[layout] g = operators.convert(f, fx.domain.bases).evaluate() assert np.allclose(g['g'], f['g'])
def test_fourier_differentiate(N, bounds, dtype): c = coords.Coordinate('x') d = distributor.Distributor((c, )) if dtype == np.float64: b = basis.RealFourier(c, size=N, bounds=bounds) elif dtype == np.complex128: b = basis.ComplexFourier(c, size=N, bounds=bounds) x = b.local_grid(1) f = field.Field(dist=d, bases=(b, ), dtype=dtype) k = 4 * np.pi / (bounds[1] - bounds[0]) f['g'] = 1 + np.sin(k * x + 0.1) fx = operators.Differentiate(f, c).evaluate() assert np.allclose(fx['g'], k * np.cos(k * x + 0.1))
def test_jacobi_convert_implicit(N, a, b, k, dtype): c = coords.Coordinate('x') d = distributor.Distributor((c,)) b = basis.Jacobi(c, size=N, a0=a, b0=b, a=a+k, b=b+k, bounds=(0, 1)) x = b.local_grid(1) f = field.Field(dist=d, bases=(b,), dtype=dtype) f['g'] = x**5 fx = operators.Differentiate(f, c).evaluate() g = field.Field(dist=d, bases=(b,), dtype=dtype) problem = problems.LBVP([g]) problem.add_equation((g, fx)) solver = solvers.LinearBoundaryValueSolver(problem) solver.solve() assert np.allclose(g['g'], fx['g'])
def test_heat_1d_periodic(x_basis_class, Nx, dtype): # Bases c = coords.Coordinate('x') d = distributor.Distributor((c, )) xb = x_basis_class(c, size=Nx, bounds=(0, 2 * np.pi)) x = xb.local_grid(1) # Fields u = field.Field(name='u', dist=d, bases=(xb, ), dtype=dtype) a = field.Field(name='a', dist=d, dtype=dtype) # Problem dx = lambda A: operators.Differentiate(A, c) problem = problems.EVP([u], a) problem.add_equation((a * u + dx(dx(u)), 0)) # Solver solver = solvers.EigenvalueSolver(problem, matrix_coupling=[True]) solver.solve_dense(solver.subproblems[0]) # Check solution k = xb.wavenumbers if x_basis_class is basis.RealFourier: k = k[1:] # Drop one k=0 for msin assert np.allclose(solver.eigenvalues, k**2)
def __init__(self, Nx, Ny, Lx, Ly, dtype, **kw): self.Nx = Nx self.Ny = Ny self.Lx = Lx self.Ly = Ly self.dtype = dtype self.N = Nx * Ny self.R = 2 * Nx + 2 * Ny self.M = self.N + self.R # Bases self.c = c = coords.CartesianCoordinates('x', 'y') self.d = d = distributor.Distributor((c, )) self.xb = xb = basis.ChebyshevT(c.coords[0], Nx, bounds=(0, Lx)) self.yb = yb = basis.ChebyshevT(c.coords[1], Ny, bounds=(0, Ly)) self.x = x = xb.local_grid(1) self.y = y = yb.local_grid(1) xb2 = xb._new_a_b(1.5, 1.5) yb2 = yb._new_a_b(1.5, 1.5) # Forcing self.f = f = field.Field(name='f', dist=d, bases=(xb2, yb2), dtype=dtype) # Boundary conditions self.uL = uL = field.Field(name='f', dist=d, bases=(yb, ), dtype=dtype) self.uR = uR = field.Field(name='f', dist=d, bases=(yb, ), dtype=dtype) self.uT = uT = field.Field(name='f', dist=d, bases=(xb, ), dtype=dtype) self.uB = uB = field.Field(name='f', dist=d, bases=(xb, ), dtype=dtype) # Fields self.u = u = field.Field(name='u', dist=d, bases=(xb, yb), dtype=dtype) self.tx1 = tx1 = field.Field(name='tx1', dist=d, bases=(xb2, ), dtype=dtype) self.tx2 = tx2 = field.Field(name='tx2', dist=d, bases=(xb2, ), dtype=dtype) self.ty1 = ty1 = field.Field(name='ty1', dist=d, bases=(yb2, ), dtype=dtype) self.ty2 = ty2 = field.Field(name='ty2', dist=d, bases=(yb2, ), dtype=dtype) # Problem Lap = lambda A: operators.Laplacian(A, c) self.problem = problem = problems.LBVP([u, tx1, tx2, ty1, ty2]) problem.add_equation((Lap(u), f)) problem.add_equation((u(y=Ly), uT)) problem.add_equation((u(x=Lx), uR)) problem.add_equation((u(y=0), uB)) problem.add_equation((u(x=0), uL)) # Solver self.solver = solver = solvers.LinearBoundaryValueSolver( problem, bc_top=False, tau_left=False, store_expanded_matrices=False, **kw) # Tau entries L = solver.subproblems[0].L_min.tolil() # Taus for nx in range(Nx): L[Ny - 1 + nx * Ny, Nx * Ny + 0 * Nx + nx] = 1 # tx1 * Py1 L[Ny - 2 + nx * Ny, Nx * Ny + 1 * Nx + nx] = 1 # tx2 * Py2 for ny in range(Ny - 2): L[(Nx - 1) * Ny + ny, Nx * Ny + 2 * Nx + 0 * Ny + ny] = 1 # ty1 * Px1 L[(Nx - 2) * Ny + ny, Nx * Ny + 2 * Nx + 1 * Ny + ny] = 1 # ty2 * Px2 # BC taus not resolution safe if Nx != Ny: raise ValueError("Current implementation requires Nx == Ny.") else: # Remember L is left preconditoined but not right preconditioned L[-7, Nx * Ny + 2 * Nx + 0 * Ny + Ny - 2] = 1 # Right -2 L[-5, Nx * Ny + 2 * Nx + 0 * Ny + Ny - 1] = 1 # Right -1 L[-3, Nx * Ny + 2 * Nx + 1 * Ny + Ny - 2] = 1 # Left -2 L[-1, Nx * Ny + 2 * Nx + 1 * Ny + Ny - 1] = 1 # Left -1 solver.subproblems[0].L_min = L.tocsr() # Neumann operators ux = operators.Differentiate(u, c.coords[0]) uy = operators.Differentiate(u, c.coords[1]) self.duL = -ux(x='left') self.duR = ux(x='right') self.duT = uy(y='right') self.duB = -uy(y='left') # Neumann matrix duT_mat = self.duT.expression_matrices(solver.subproblems[0], vars=[u])[u] duR_mat = self.duR.expression_matrices(solver.subproblems[0], vars=[u])[u] duB_mat = self.duB.expression_matrices(solver.subproblems[0], vars=[u])[u] duL_mat = self.duL.expression_matrices(solver.subproblems[0], vars=[u])[u] self.interior_to_neumann_matrix = sp.vstack( [duT_mat, duR_mat, duB_mat, duL_mat], format='csr')
c = coords.CartesianCoordinates('x', 'z') d = distributor.Distributor((c,)) if dtype == np.complex128: xb = basis.ComplexFourier(c.coords[0], size=Nx, bounds=(0, 2*np.pi), dealias=3/2) elif dtype == np.float64: xb = basis.RealFourier(c.coords[0], size=Nx, bounds=(0, 2*np.pi), dealias=3/2) zb = basis.ChebyshevT(c.coords[1], size=Nz, bounds=(0, Lz),dealias=3/2) x = xb.local_grid(1) z = zb.local_grid(1) zb1 = basis.ChebyshevU(c.coords[1], size=Nz, bounds=(0, Lz), alpha0=0) t1 = field.Field(name='t1', dist=d, bases=(xb,), dtype=dtype) t2 = field.Field(name='t2', dist=d, bases=(xb,), dtype=dtype) P1 = field.Field(name='P1', dist=d, bases=(zb1,), dtype=dtype) if rank == 0: P1['c'][0,-1] = 1 dz = lambda A: operators.Differentiate(A, c.coords[1]) P2 = dz(P1).evaluate() # Fields u = field.Field(name='u', dist=d, bases=(xb,zb), dtype=dtype) F = field.Field(name='F', dist=d, bases=(xb,zb), dtype=dtype) u_true = 0 for n in np.arange(1,Nz//8): u_current_n = 0 for m in np.arange(Nx//4): u_current_m = np.sin(n*z)*np.cos(m*x) u_current_n += u_current_m F['g'] += -m**2*u_current_m u_true += u_current_n F['g'] += -n**2*u_current_n # Problem
# Fields u = field.Field(dist=d, bases=(zb, b), tensorsig=(c,),dtype=dtype) w = field.Field(dist=d, bases=(zb, b), dtype=dtype) p = field.Field(dist=d, bases=(zb, b), dtype=dtype) tau_u = field.Field(dist=d, bases=(cb,), tensorsig=(c,), dtype=dtype) tau_w = field.Field(dist=d, bases=(cb,), dtype=dtype) # Parameters and operators lap = lambda A: operators.Laplacian(A, c) div = lambda A: operators.Divergence(A) grad = lambda A: operators.Gradient(A, c) curl = lambda A: operators.Curl(A) dot = lambda A,B: arithmetic.DotProduct(A, B) cross = lambda A,B: arithmetic.CrossProduct(A, B) dt = lambda A: operators.TimeDerivative(A) dz = lambda A: operators.Differentiate(A, zc) # Problem def eq_eval(eq_str): return [eval(expr) for expr in split_equation(eq_str)] problem = problems.IVP([u, w, p, tau_u, tau_w]) problem.add_equation(eq_eval("dt(u) - nu*(lap(u) + dz(dz(u))) - grad(p) = 0."), condition='nphi != 0') problem.add_equation(eq_eval("dt(w) - nu*(lap(w) + dz(dz(w))) - dz(p) = 0."), condition='nphi != 0') problem.add_equation(eq_eval("u = 0"), condition='nphi == 0') problem.add_equation(eq_eval("w = 0"), condition='nphi == 0') problem.add_equation(eq_eval("div(u) + dz(w) = 0"), condition='nphi != 0') problem.add_equation(eq_eval("p = 0"), condition='nphi == 0') problem.add_equation(eq_eval("u(r=1) = 0"), condition='nphi != 0') problem.add_equation(eq_eval("tau_u = 0"), condition='nphi == 0') problem.add_equation(eq_eval("w(r=1) = 0"), condition='nphi != 0')
def main(N, alpha, method, tau): # Bases c = coords.Coordinate('x') d = distributor.Distributor((c,)) xb = basis.ChebyshevT(c, size=N, bounds=(-1, 1)) x = xb.local_grid(1) # Fields u = field.Field(name='u', dist=d, bases=(xb,), dtype=np.float64) ux = field.Field(name='ux', dist=d, bases=(xb,), dtype=np.float64) f = field.Field(name='f', dist=d, bases=(xb,), dtype=np.float64) t1 = field.Field(name='t1', dist=d, dtype=np.float64) t2 = field.Field(name='t2', dist=d, dtype=np.float64) pi, sin, cos = np.pi, np.sin, np.cos f['g'] = 64*pi**3*(4*pi*sin(4*pi*x)**2*sin(4*pi*cos(4*pi*x)) + cos(4*pi*x)*cos(4*pi*cos(4*pi*x))) + alpha*sin(4*pi*cos(4*pi*x)) # Tau polynomials xb1 = xb._new_a_b(xb.a+1, xb.b+1) xb2 = xb._new_a_b(xb.a+2, xb.b+2) if tau == 0: # First-order classical Chebyshev tau: T[-1], dx(T[-1]) p1 = field.Field(name='p1', dist=d, bases=(xb,), dtype=np.float64) p2 = field.Field(name='p2', dist=d, bases=(xb,), dtype=np.float64) p1['c'][-1] = 1 p2['c'][-1] = 1 elif tau == 1: # First-order ultraspherical tau: U[-1], dx(U[-1]) p1 = field.Field(name='p1', dist=d, bases=(xb1,), dtype=np.float64) p2 = field.Field(name='p2', dist=d, bases=(xb1,), dtype=np.float64) p1['c'][-1] = 1 p2['c'][-1] = 1 # Problem dx = lambda A: operators.Differentiate(A, c) problem = problems.LBVP([u, ux, t1, t2]) problem.add_equation((alpha*u - dx(ux) + t1*p1, f)) problem.add_equation((ux - dx(u) + t2*p2, 0)) problem.add_equation((u(x=-1), 0)) problem.add_equation((u(x=+1), 0)) solver = solvers.LinearBoundaryValueSolver(problem) # Methods if method == 0: # Condition number L_exp = solver.subproblems[0].L_exp result = np.linalg.cond(L_exp.A) elif method == 1: # Roundtrip roundoff with uniform u A = solver.subproblems[0].L_exp v = np.random.rand(A.shape[1]) f = A * v u = solver.subproblem_matsolvers[solver.subproblems[0]].solve(f) result = np.max(np.abs(u-v)) elif method == 2: # Manufactured solution from mpi4py_fft import fftw as mpi4py_fftw solver.solve() ue = np.sin(4*np.pi*np.cos(4*np.pi*x)) d = mpi4py_fftw.aligned(N, fill=0) k = 2*(1 + np.arange((N-1)//2)) d[::2] = (2./N)/np.hstack((1., 1.-k*k)) w = mpi4py_fftw.aligned_like(d) dct = mpi4py_fftw.dctn(w, axes=(0,), type=3) weights = dct(d, w) result = np.sqrt(np.sum(weights*(u['g']-ue)**2)) elif method == 3: # Roundtrip roundoff with uniform f A = solver.subproblems[0].L_exp g = np.random.rand(A.shape[0]) v = solver.subproblem_matsolvers[solver.subproblems[0]].solve(g) f = A * v u = solver.subproblem_matsolvers[solver.subproblems[0]].solve(f) result = np.max(np.abs(u-v)) return result