def assemble(self): N = self.N SB = Basis(N, 'C', bc='Biharmonic', quad=self.quad) SB.plan((N, N), 0, np.float, {}) x, _ = self.x, self.w = SB.points_and_weights(N) # Trial function P4 = SB.evaluate_basis_all(x=x) # Second derivatives T2x = SB.evaluate_basis_derivative_all(x=x, k=2) # (u'', v) K = np.zeros((N, N)) K[:-4, :-4] = inner_product((SB, 0), (SB, 2)).diags().toarray() # ((1-x**2)u, v) xx = np.broadcast_to((1 - x**2)[:, np.newaxis], (N, N)) #K1 = np.dot(w*P4.T, xx*P4) # Alternative: K1 = np.dot(w*P4.T, ((1-x**2)*P4.T).T) K1 = np.zeros((N, N)) K1 = SB.scalar_product(xx * P4, K1) K1 = extract_diagonal_matrix( K1).diags().toarray() # For improved roundoff # ((1-x**2)u'', v) K2 = np.zeros((N, N)) K2 = SB.scalar_product(xx * T2x, K2) K2 = extract_diagonal_matrix( K2).diags().toarray() # For improved roundoff # (u'''', v) Q = np.zeros((self.N, self.N)) Q[:-4, :-4] = inner_product((SB, 0), (SB, 4)).diags().toarray() # (u, v) M = np.zeros((self.N, self.N)) M[:-4, :-4] = inner_product((SB, 0), (SB, 0)).diags().toarray() Re = self.Re a = self.alfa B = -Re * a * 1j * (K - a**2 * M) A = Q - 2 * a**2 * K + a**4 * M - 2 * a * Re * 1j * M - 1j * a * Re * ( K2 - a**2 * K1) return A, B
def assemble(self): N = self.N SB = Basis(N, 'C', bc='Biharmonic', quad=self.quad) SB.plan((N, N), 0, np.float, {}) x, _ = self.x, self.w = SB.points_and_weights(N) # Trial function P4 = SB.evaluate_basis_all(x=x) # Second derivatives T2x = SB.evaluate_basis_derivative_all(x=x, k=2) # (u'', v) K = np.zeros((N, N)) K[:-4, :-4] = inner_product((SB, 0), (SB, 2)).diags().toarray() # ((1-x**2)u, v) xx = np.broadcast_to((1-x**2)[:, np.newaxis], (N, N)) #K1 = np.dot(w*P4.T, xx*P4) # Alternative: K1 = np.dot(w*P4.T, ((1-x**2)*P4.T).T) K1 = np.zeros((N, N)) K1 = SB.scalar_product(xx*P4, K1) K1 = extract_diagonal_matrix(K1).diags().toarray() # For improved roundoff # ((1-x**2)u'', v) K2 = np.zeros((N, N)) K2 = SB.scalar_product(xx*T2x, K2) K2 = extract_diagonal_matrix(K2).diags().toarray() # For improved roundoff # (u'''', v) Q = np.zeros((self.N, self.N)) Q[:-4, :-4] = inner_product((SB, 0), (SB, 4)).diags().toarray() # (u, v) M = np.zeros((self.N, self.N)) M[:-4, :-4] = inner_product((SB, 0), (SB, 0)).diags().toarray() Re = self.Re a = self.alfa B = -Re*a*1j*(K-a**2*M) A = Q-2*a**2*K+a**4*M - 2*a*Re*1j*M - 1j*a*Re*(K2-a**2*K1) return A, B
def test_PDMA(quad): SB = Basis(N, 'C', bc='Biharmonic', quad=quad, plan=True) u = TrialFunction(SB) v = TestFunction(SB) points, weights = SB.points_and_weights(N) fj = Array(SB, buffer=np.random.randn(N)) f_hat = Function(SB) f_hat = inner(v, fj, output_array=f_hat) A = inner(v, div(grad(u))) B = inner(v, u) s = SB.slice() H = A + B P = PDMA(A, B, A.scale, B.scale, solver='cython') u_hat = Function(SB) u_hat[s] = solve(H.diags().toarray()[s, s], f_hat[s]) u_hat2 = Function(SB) u_hat2 = P(u_hat2, f_hat) assert np.allclose(u_hat2, u_hat)
def main(N, dt=0.005, end_time=2, dealias_initial=True, plot_result=False): SD = Basis(N, 'F', dtype='D') X = SD.points_and_weights()[0] v = TestFunction(SD) U = Array(SD) dU = Function(SD) U_hat = Function(SD) U_hat0 = Function(SD) U_hat1 = Function(SD) w0 = Function(SD) a = [1./6., 1./3., 1./3., 1./6.] # Runge-Kutta parameter b = [0.5, 0.5, 1.] # Runge-Kutta parameter nu = 0.2 k = SD.wavenumbers().astype(float) # initialize U[:] = 3./(5.-4.*np.cos(X)) if not dealias_initial: U_hat = SD.forward(U, U_hat) else: U_hat[:] = 2**(-abs(k)) def compute_rhs(rhs, u_hat, w0): rhs.fill(0) w0.fill(0) rhs = inner(v, nu*div(grad(u_hat)), output_array=rhs) rhs -= inner(v, grad(u_hat), output_array=w0) return rhs # Integrate using a 4th order Rung-Kutta method t = 0.0 tstep = 0 if plot_result is True: im = plt.figure() ca = im.gca() ca.plot(X, U.real, 'b') plt.draw() plt.pause(1e-6) while t < end_time-1e-8: t += dt tstep += 1 U_hat1[:] = U_hat0[:] = U_hat for rk in range(4): dU = compute_rhs(dU, U_hat, w0) if rk < 3: U_hat[:] = U_hat0 + b[rk]*dt*dU U_hat1 += a[rk]*dt*dU U_hat[:] = U_hat1 if tstep % (200) == 0 and plot_result is True: ca.plot(X, U.real) plt.pause(1e-6) #plt.savefig('Ginzburg_Landau_pad_{}_real_{}.png'.format(N[0], int(np.round(t)))) U = SD.backward(U_hat, U) Ue = np.zeros_like(U) for k in range(-100, 101): Ue += 2**(-abs(k))*np.exp(1j*k*(X-t) - nu*k**2*t) err = np.sqrt(2*np.pi/N*np.linalg.norm(U-Ue.real)**2) return 1./N, err
f_hat = Array(SD) f_hat = inner(v, fj, output_array=f_hat) # Get left hand side of Poisson equation if family == 'chebyshev': A = inner(v, -div(grad(u))) B = inner(v, alfa * u) else: A = inner(grad(v), grad(u)) B = inner(v, alfa * u) H = Solver(A, B) u_hat = Function(SD) # Solution spectral space u_hat = H(u_hat, f_hat) uj = SD.backward(u_hat) # Compare with analytical solution ua = ul(X) if family == 'chebyshev': # Compute L2 error norm using Clenshaw-Curtis integration from shenfun import clenshaw_curtis1D error = clenshaw_curtis1D((uj - ua)**2, quad=SD.quad) print("Error=%2.16e" % (error)) else: x, w = SD.points_and_weights() print("Error=%2.16e" % (np.sqrt(np.sum((uj - ua)**2 * w)))) assert np.allclose(uj, ua)