def test_cylinder(): T = get_function_space('cylinder') u = TrialFunction(T) du = div(grad(u)) assert du.tolatex() == '\\frac{\\partial^2 u}{\\partial x^2 }+\\frac{1}{x}\\frac{\\partial u}{\\partial x }+\\frac{1}{x^{2}}\\frac{\\partial^2 u}{\\partial y^2 }+\\frac{\\partial^2 u}{\\partial z^2 }' V = VectorSpace(T) u = TrialFunction(V) du = div(grad(u)) assert du.tolatex() == '\\left( \\frac{\\partial^2 u^{x}}{\\partial x^2 }+\\frac{1}{x}\\frac{\\partial u^{x}}{\\partial x }+\\frac{1}{x^{2}}\\frac{\\partial^2 u^{x}}{\\partial y^2 }- \\frac{2}{x}\\frac{\\partial u^{y}}{\\partial y }- \\frac{1}{x^{2}}u^{x}+\\frac{\\partial^2 u^{x}}{\\partial z^2 }\\right) \\mathbf{b}_{x} \\\\+\\left( \\frac{\\partial^2 u^{y}}{\\partial x^2 }+\\frac{3}{x}\\frac{\\partial u^{y}}{\\partial x }+\\frac{2}{x^{3}}\\frac{\\partial u^{x}}{\\partial y }+\\frac{1}{x^{2}}\\frac{\\partial^2 u^{y}}{\\partial y^2 }+\\frac{\\partial^2 u^{y}}{\\partial z^2 }\\right) \\mathbf{b}_{y} \\\\+\\left( \\frac{\\partial^2 u^{z}}{\\partial x^2 }+\\frac{1}{x}\\frac{\\partial u^{z}}{\\partial x }+\\frac{1}{x^{2}}\\frac{\\partial^2 u^{z}}{\\partial y^2 }+\\frac{\\partial^2 u^{z}}{\\partial z^2 }\\right) \\mathbf{b}_{z} \\\\'
def setup(self, dt): self.params['dt'] = dt u = TrialFunction(self.T) v = TestFunction(self.T) # Note that we are here assembling implicit left hand side matrices, # as well as matrices that can be used to assemble the right hande side # much faster through matrix-vector products a, b = self.a, self.b self.solver = [] for rk in range(3): mats = inner(v, u - ((a[rk]+b[rk])*dt/2)*self.LinearRHS(u)) if len(mats[0].naxes) == 1: self.solver.append(la.SolverGeneric1ND(mats)) elif len(mats[0].naxes) == 2: self.solver.append(la.SolverGeneric2ND(mats)) else: raise NotImplementedError self.rhs_mats = [] for rk in range(3): self.rhs_mats.append(inner(v, u + ((a[rk]+b[rk])*dt/2)*self.LinearRHS(u))) self.mass = inner(u, v)
def test_biharmonic2D(family, axis): la = lla if family == 'chebyshev': la = cla N = (16, 16) SD = Basis(N[axis], family=family, bc='Biharmonic') K1 = Basis(N[(axis + 1) % 2], family='F', dtype='d') subcomms = mpi4py_fft.pencil.Subcomm(MPI.COMM_WORLD, allaxes2D[axis]) bases = [K1] bases.insert(axis, SD) T = TensorProductSpace(subcomms, bases, axes=allaxes2D[axis]) u = TrialFunction(T) v = TestFunction(T) if family == 'chebyshev': mat = inner(v, div(grad(div(grad(u))))) else: mat = inner(div(grad(v)), div(grad(u))) H = la.Biharmonic(*mat) u = Function(T) u[:] = np.random.random(u.shape) + 1j * np.random.random(u.shape) f = Function(T) f = H.matvec(u, f) g0 = Function(T) g1 = Function(T) g2 = Function(T) M = {d.get_key(): d for d in mat} g0 = M['SBBmat'].matvec(u, g0) g1 = M['ABBmat'].matvec(u, g1) g2 = M['BBBmat'].matvec(u, g2) assert np.linalg.norm(f - (g0 + g1 + g2)) < 1e-8
def test_quasiGalerkin(basis): N = 40 T = FunctionSpace(N, 'C') S = FunctionSpace(N, 'C', basis=basis) u = TrialFunction(S) v = TestFunction(T) A = inner(v, div(grad(u))) B = inner(v, u) Q = chebyshev.quasi.QIGmat(N) A = Q*A B = Q*B M = B-A sol = la.Solve(M, S) f_hat = inner(v, Array(T, buffer=fe)) f_hat[:-2] = Q.diags('csc')*f_hat[:-2] u_hat = Function(S) u_hat = sol(f_hat, u_hat) uj = u_hat.backward() ua = Array(S, buffer=ue) bb = Q*np.ones(N) assert abs(np.sum(bb[:8])) < 1e-8 if S.boundary_condition().lower() == 'neumann': xj, wj = S.points_and_weights() ua -= np.sum(ua*wj)/np.pi # normalize uj -= np.sum(uj*wj)/np.pi # normalize assert np.sqrt(inner(1, (uj-ua)**2)) < 1e-5
def test_solve(quad): SD = Basis(N, 'C', bc=(0, 0), quad=quad, plan=True) u = TrialFunction(SD) v = TestFunction(SD) A = inner(div(grad(u)), v) b = np.ones(N) u_hat = Function(SD) u_hat = A.solve(b, u=u_hat) w_hat = Function(SD) B = SparseMatrix(dict(A), (N - 2, N - 2)) w_hat[:-2] = B.solve(b[:-2], w_hat[:-2]) assert np.all(abs(w_hat[:-2] - u_hat[:-2]) < 1e-8) ww = w_hat[:-2].repeat(N - 2).reshape((N - 2, N - 2)) bb = b[:-2].repeat(N - 2).reshape((N - 2, N - 2)) ww = B.solve(bb, ww, axis=0) assert np.all( abs(ww - u_hat[:-2].repeat(N - 2).reshape((N - 2, N - 2))) < 1e-8) bb = bb.transpose() ww = B.solve(bb, ww, axis=1) assert np.all( abs(ww - u_hat[:-2].repeat(N - 2).reshape( (N - 2, N - 2)).transpose()) < 1e-8)
def test_curl(typecode): K0 = Basis(N[0], 'F', dtype=typecode.upper()) K1 = Basis(N[1], 'F', dtype=typecode.upper()) K2 = Basis(N[2], 'F', dtype=typecode) T = TensorProductSpace(comm, (K0, K1, K2), dtype=typecode) X = T.local_mesh(True) K = T.local_wavenumbers() Tk = VectorTensorProductSpace(T) u = TrialFunction(Tk) v = TestFunction(Tk) U = Array(Tk) U_hat = Function(Tk) curl_hat = Function(Tk) curl_ = Array(Tk) # Initialize a Taylor Green vortex U[0] = np.sin(X[0]) * np.cos(X[1]) * np.cos(X[2]) U[1] = -np.cos(X[0]) * np.sin(X[1]) * np.cos(X[2]) U[2] = 0 U_hat = Tk.forward(U, U_hat) Uc = U_hat.copy() U = Tk.backward(U_hat, U) U_hat = Tk.forward(U, U_hat) assert allclose(U_hat, Uc) divu_hat = project(div(U_hat), T) divu = Array(T) divu = T.backward(divu_hat, divu) assert allclose(divu, 0) curl_hat[0] = 1j * (K[1] * U_hat[2] - K[2] * U_hat[1]) curl_hat[1] = 1j * (K[2] * U_hat[0] - K[0] * U_hat[2]) curl_hat[2] = 1j * (K[0] * U_hat[1] - K[1] * U_hat[0]) curl_ = Tk.backward(curl_hat, curl_) w_hat = Function(Tk) w_hat = inner(v, curl(U_hat), output_array=w_hat) A = inner(v, u) for i in range(3): w_hat[i] = A[i].solve(w_hat[i]) w = Array(Tk) w = Tk.backward(w_hat, w) #from IPython import embed; embed() assert allclose(w, curl_) u_hat = Function(Tk) u_hat = inner(v, U, output_array=u_hat) for i in range(3): u_hat[i] = A[i].solve(u_hat[i]) uu = Array(Tk) uu = Tk.backward(u_hat, uu) assert allclose(u_hat, U_hat)
def test_div2(basis, quad): B = basis(8, quad=quad) u = TrialFunction(B) v = TestFunction(B) m = inner(u, v) z = Function(B, val=1) c = m / z m2 = m.diags('csr') c2 = spsolve(m2, z[B.slice()]) assert np.allclose(c2, c[B.slice()])
def test_mul2(): mat = SparseMatrix({0: 1}, (3, 3)) v = np.ones(3) c = mat * v assert np.allclose(c, 1) mat = SparseMatrix({-2: 1, -1: 1, 0: 1, 1: 1, 2: 1}, (3, 3)) c = mat * v assert np.allclose(c, 3) SD = Basis(8, "L", bc=(0, 0), scaled=True) u = TrialFunction(SD) v = TestFunction(SD) mat = inner(grad(u), grad(v)) z = Function(SD, val=1) c = mat * z assert np.allclose(c[:6], 1)
def test_PDMA(quad): SB = FunctionSpace(N, 'C', bc=(0, 0, 0, 0), quad=quad) 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 test_TwoDMA(): N = 12 SD = FunctionSpace(N, 'C', basis='ShenDirichlet') HH = FunctionSpace(N, 'C', basis='Heinrichs') u = TrialFunction(HH) v = TestFunction(SD) points, weights = SD.points_and_weights(N) fj = Array(SD, buffer=np.random.randn(N)) f_hat = Function(SD) f_hat = inner(v, fj, output_array=f_hat) A = inner(v, div(grad(u))) sol = TwoDMA(A) u_hat = Function(HH) u_hat = sol(f_hat, u_hat) sol2 = la.Solve(A, HH) u_hat2 = Function(HH) u_hat2 = sol2(f_hat, u_hat2) assert np.allclose(u_hat2, u_hat)
def main(N, family, bci, bcj, plotting=False): global fe, ue BX = FunctionSpace(N, family=family, bc=bcx[bci], domain=xdomain) BY = FunctionSpace(N, family=family, bc=bcy[bcj], domain=ydomain) T = TensorProductSpace(comm, (BX, BY)) u = TrialFunction(T) v = TestFunction(T) # Get f on quad points fj = Array(T, buffer=fe) # Compare with analytical solution ua = Array(T, buffer=ue) if T.use_fixed_gauge: mean = dx(ua, weighted=True) / inner(1, Array(T, val=1)) # Compute right hand side of Poisson equation f_hat = Function(T) f_hat = inner(v, fj, output_array=f_hat) # Get left hand side of Poisson equation A = inner(v, -div(grad(u))) u_hat = Function(T) sol = la.Solver2D(A, fixed_gauge=mean if T.use_fixed_gauge else None) u_hat = sol(f_hat, u_hat) uj = u_hat.backward() assert np.allclose(uj, ua), np.linalg.norm(uj - ua) print("Error=%2.16e" % (np.sqrt(dx((uj - ua)**2)))) if 'pytest' not in os.environ and plotting is True: import matplotlib.pyplot as plt X, Y = T.local_mesh(True) plt.contourf(X, Y, uj, 100) plt.colorbar() plt.figure() plt.contourf(X, Y, ua, 100) plt.colorbar() plt.figure() plt.contourf(X, Y, ua - uj, 100) plt.colorbar()
def get_pressure(context, solver): FCT = context.FCT FST = context.FST U_hat = context.U_hat U_hat0 = context.U_hat0 Um = Function(context.FST) Um[:] = 0.5*(U_hat[0] + U_hat0[0]) U = U_hat.backward(context.U) U0 = U_hat0.backward(context.U0) dt = solver.params.dt Hx = Function(context.FST) Hx[:] = solver.get_convection(**context)[0] v = TestFunction(FCT) p = TrialFunction(FCT) rhs_hat = inner(context.nu*div(grad(Um)), v) Hx -= 1./dt*(U_hat[0]-U_hat0[0]) rhs_hat += inner(Hx, v) CT = inner(Dx(p, 0, 1), v) # Should implement fast solver. Just a backwards substitution # Apply integral constraint A = CT.mats[0] N = A.shape[0] A[-(N-1)] = 1 p_hat = Function(context.FCT) p_hat = CT.solve(rhs_hat, p_hat) p = Array(FCT) p = FCT.backward(p_hat, p) uu = 0. if params.convection == 'Vortex': uu = np.sum((0.5*(U+U0))**2, 0) uu *= 0.5 return p-uu
def get_pressure(context, solver): FCT = context.FCT FST = context.FST U = solver.get_velocity(**context) U0 = context.VFS.backward(context.U_hat0, context.U0) dt = solver.params.dt H_hat = solver.get_convection(**context) Hx = Array(FST) Hx = FST.backward(H_hat[0], Hx) v = TestFunction(FCT) p = TrialFunction(FCT) U = U.as_function() U0 = U0.as_function() rhs_hat = inner((0.5 * context.nu) * div(grad(U[0] + U0[0])), v) Hx -= 1. / dt * (U[0] - U0[0]) rhs_hat += inner(Hx, v) CT = inner(Dx(p, 0), v) # Should implement fast solver. Just a backwards substitution A = CT.diags().toarray() * CT.scale[0] A[-1, 0] = 1 a_i = np.linalg.inv(A) p_hat = Function(context.FCT) for j in range(p_hat.shape[1]): for k in range(p_hat.shape[2]): p_hat[:, j, k] = np.dot(a_i, rhs_hat[:, j, k]) p = Array(FCT) p = FCT.backward(p_hat, p) uu = np.sum((0.5 * (U + U0))**2, 0) uu *= 0.5 return p - uu + 3. / 16.
def main(N, family, bci): bc = bcs[bci] if bci == 0: SD = FunctionSpace(N, family=family, bc=bc, domain=domain, mean=mean[family.lower()]) else: SD = FunctionSpace(N, family=family, bc=bc, domain=domain) u = TrialFunction(SD) v = TestFunction(SD) # Get f on quad points fj = Array(SD, buffer=fe) # Compute right hand side of Poisson equation f_hat = Function(SD) f_hat = inner(v, fj, output_array=f_hat) # Get left hand side of Poisson equation A = inner(v, div(grad(u))) u_hat = Function(SD).set_boundary_dofs() if isinstance(A, list): bc_mat = extract_bc_matrices([A]) A = A[0] f_hat -= bc_mat[0].matvec(u_hat, Function(SD)) u_hat = A.solve(f_hat, u_hat) uj = u_hat.backward() uh = uj.forward() # Compare with analytical solution ua = Array(SD, buffer=ue) assert np.allclose(uj, ua), np.linalg.norm(uj - ua) if 'pytest' not in os.environ: print("Error=%2.16e" % (np.sqrt(dx((uj - ua)**2)))) import matplotlib.pyplot as plt plt.plot(SD.mesh(), uj, 'b', SD.mesh(), ua, 'r')
def test_helmholtz3D(family, axis): la = lla if family == 'chebyshev': la = cla N = (8, 9, 10) SD = Basis(N[allaxes3D[axis][0]], family=family, bc=(0, 0)) K1 = Basis(N[allaxes3D[axis][1]], family='F', dtype='D') K2 = Basis(N[allaxes3D[axis][2]], family='F', dtype='d') subcomms = mpi4py_fft.pencil.Subcomm(MPI.COMM_WORLD, [0, 1, 1]) bases = [0] * 3 bases[allaxes3D[axis][0]] = SD bases[allaxes3D[axis][1]] = K1 bases[allaxes3D[axis][2]] = K2 T = TensorProductSpace(subcomms, bases, axes=allaxes3D[axis]) u = TrialFunction(T) v = TestFunction(T) if family == 'chebyshev': mat = inner(v, div(grad(u))) else: mat = inner(grad(v), grad(u)) H = la.Helmholtz(*mat) u = Function(T) s = SD.sl[SD.slice()] u[s] = np.random.random(u[s].shape) + 1j * np.random.random(u[s].shape) f = Function(T) f = H.matvec(u, f) g0 = Function(T) g1 = Function(T) M = {d.get_key(): d for d in mat} g0 = M['ADDmat'].matvec(u, g0) g1 = M['BDDmat'].matvec(u, g1) assert np.linalg.norm(f - (g0 + g1)) < 1e-12, np.linalg.norm(f - (g0 + g1)) uc = Function(T) uc = H(uc, f) assert np.linalg.norm(uc - u) < 1e-12
def test_quasiTau(bc): N = 40 T = FunctionSpace(N, 'C') u = TrialFunction(T) v = TestFunction(T) A = inner(v, div(grad(u))) B = inner(v, u) Q = chebyshev.quasi.QITmat(N) A = Q*A B = Q*B bb = Q*np.ones(N) assert abs(np.sum(bb[:8])) < 1e-8 M = B-A M0 = M.diags().tolil() if bc == 'Dirichlet': M0[0] = np.ones(N) nn = np.ones(N) nn[1::2] = -1 M0[1] = nn elif bc == 'Neumann': nn = np.arange(N)**2 M0[0] = nn.copy() nn[1::2] *= -1 M0[1] = nn M0 = M0.tocsc() f_hat = inner(v, Array(T, buffer=fe)) gh = Q.diags('csc')*f_hat gh[:2] = 0 u_hat = Function(T) u_hat[:] = scp.linalg.spsolve(M0, gh) uj = u_hat.backward() ua = Array(T, buffer=ue) if bc == 'Neumann': xj, wj = T.points_and_weights() ua -= np.sum(ua*wj)/np.pi # normalize uj -= np.sum(uj*wj)/np.pi # normalize assert np.sqrt(inner(1, (uj-ua)**2)) < 1e-5
def test_vector_laplace(space): """Test that div(grad(u)) = grad(div(u)) - curl(curl(u)) """ T = get_function_space(space) V = VectorSpace(T) u = TrialFunction(V) v = _TestFunction(V) du = div(grad(u)) dv = grad(div(u)) - curl(curl(u)) u_hat = Function(V) u_hat[:] = np.random.random(u_hat.shape) + np.random.random(u_hat.shape)*1j A0 = inner(v, du) A1 = inner(v, dv) a0 = BlockMatrix(A0) a1 = BlockMatrix(A1) b0 = Function(V) b1 = Function(V) b0 = a0.matvec(u_hat, b0) b1 = a1.matvec(u_hat, b1) assert np.linalg.norm(b0-b1) < 1e-8
dt = 5e-5 c = -(k**2+nu*dt/2*k**4) b = 1.0+nu*dt*k**2 a = -nu*dt/2. fe = a*ue.diff(x, 4) + b*ue.diff(x, 2) + c*ue # Lambdify for faster evaluation ul = lambdify(x, ue, 'numpy') fl = lambdify(x, fe, 'numpy') # Size of discretization N = int(sys.argv[-2]) SD = Basis(N, family=family, bc='Biharmonic', domain=domain) X = SD.mesh() u = TrialFunction(SD) v = TestFunction(SD) # Get f on quad points fj = Array(SD, buffer=fl(X)) # Compute right hand side of biharmonic equation f_hat = inner(v, fj) # Get left hand side of biharmonic equation (no integration by parts) S = inner(v, a*Dx(u, 0, 4)) A = inner(v, b*Dx(u, 0, 2)) B = inner(v, c*u) # Create linear algebra solver H = Solver(S, A, B)
-ua[1].diff(x, 2) - ua[1].diff(y, 2)) neumann_condition_x = ua[0].diff(x).evalf(subs={x: -1}) neumann_condition_y = ua[1].diff(y).evalf(subs={y: 1}) FXX = FunctionSpace(20, family='legendre', bc=(None, 0)) FXY = FunctionSpace(20, family='legendre', bc=(0, 0)) FYX = FunctionSpace(20, family='legendre', bc=(0, 0)) FYY = FunctionSpace(20, family='legendre', bc=(0, None)) TX = TensorProductSpace(comm, (FXX, FXY)) TY = TensorProductSpace(comm, (FYX, FYY)) V = VectorSpace([TX, TY]) u = TrialFunction(V) v = TestFunction(V) mat = inner(grad(u), grad(v)) fj = Array(V, buffer=f) rhs = inner(v, fj) # boundary integrals # x - component v_bndry_x = TestFunction(FXY) gn_x = Array(FXY, buffer=neumann_condition_x) evaluate_bndry_x = FXX.evaluate_basis_all(-1) project_gn_x = inner(gn_x, v_bndry_x) bndry_integral_x = -np.outer(evaluate_bndry_x, project_gn_x) # y - component v_bndry_y = TestFunction(FYX) gn_y = Array(FYX, buffer=neumann_condition_y)
Array, Function, FunctionSpace assert len(sys.argv) == 2, 'Call with one command-line argument' assert isinstance(int(sys.argv[-1]), int) # Use sympy to compute a rhs, given an analytical solution x = symbols("x", real=True) #ue = sin(4*x)*exp(-x**2) ue = hermite(4, x) * exp(-x**2 / 2) fe = ue.diff(x, 2) # Size of discretization N = int(sys.argv[-1]) SD = FunctionSpace(N, 'Hermite') u = TrialFunction(SD) v = TestFunction(SD) # Get f on quad points fj = Array(SD, buffer=fe) # Compute right hand side of Poisson equation f_hat = Function(SD) f_hat = inner(v, -fj, output_array=f_hat) # Get left hand side of Poisson equation A = inner(grad(v), grad(u)) f_hat = A / f_hat uj = f_hat.backward() uh = uj.forward()
import numpy as np from shenfun import inner, grad, TestFunction, TrialFunction, Basis, Function, \ Array # Use sympy to compute a rhs, given an analytical solution x = Symbol("x") ue = cos(4 * x) + 1j * sin(6 * x) #ue = cos(4*x) fe = ue.diff(x, 2) # Size of discretization N = 40 dtype = {True: np.complex, False: np.float}[ue.has(1j)] ST = Basis(N, dtype=dtype, domain=(-2 * np.pi, 2 * np.pi)) u = TrialFunction(ST) v = TestFunction(ST) X = ST.mesh() # Get f on quad points and exact solution fj = Array(ST, buffer=fe) uj = Array(ST, buffer=ue) # Compute right hand side f_hat = Function(ST) f_hat = inner(v, fj, output_array=f_hat) # Solve Poisson equation A = inner(grad(v), grad(u)) u_hat = Function(ST)
from shenfun.chebyshev.bases import ShenBiharmonicBasis, Basis from shenfun.fourier.bases import R2CBasis, C2CBasis from shenfun.chebyshev.la import Biharmonic as Solver from shenfun import inner, div, grad, TestFunction, TrialFunction, project, Dx from shenfun import Function, TensorProductSpace from mpi4py import MPI import numpy as np comm = MPI.COMM_WORLD N = (32, 33, 34) K0 = ShenBiharmonicBasis(N[0]) K1 = C2CBasis(N[1]) K2 = R2CBasis(N[2]) W = TensorProductSpace(comm, (K0, K1, K2)) u = TrialFunction(W) v = TestFunction(W) matrices = inner(v, div(grad(div(grad(u))))) fj = Function(W, False) fj[:] = np.random.random(fj.shape) f_hat = inner(v, fj) # Some right hand side B = Solver(**matrices) # Solve and transform to real space u_hat = Function(W) # Solution spectral space u_hat = B(u_hat, f_hat) # Solve u = Function(W, False) u = W.backward(u_hat, u) # compute dudx of the solution
(y + 0.04) / a) + 1)))) + 0.5 v0 = 0.25 * (0.5 * (erf((x - 0.04) / a) + 1) - 0.5 * (erf( (x + 0.04) / a) + 1)) * (0.5 * (erf((y - 0.04) / a) + 1) - 0.5 * (erf( (y + 0.04) / a) + 1)) ul = lambdify((x, y), u0, modules=['numpy', {'erf': scipy.special.erf}]) vl = lambdify((x, y), v0, modules=['numpy', {'erf': scipy.special.erf}]) # Size of discretization N = (200, 200) K0 = Basis(N[0], 'F', dtype='D', domain=(-1., 1.)) K1 = Basis(N[1], 'F', dtype='d', domain=(-1., 1.)) T = TensorProductSpace(comm, (K0, K1)) X = T.local_mesh(True) u = TrialFunction(T) v = TestFunction(T) # For nonlinear term we can use the 3/2-rule with padding Tp = T.get_dealiased((1.5, 1.5)) # Turn on padding by commenting #Tp = T # Create vector spaces and a test function for the regular vector space TV = VectorTensorProductSpace(T) TVp = VectorTensorProductSpace(Tp) vv = TestFunction(TV) uu = TrialFunction(TV) # Declare solution arrays and work arrays
x, y = symbols("x,y") ue = (sin(2 * np.pi * x) * sin(4 * np.pi * y)) * (1 - x**2) * (1 - y**2) fe = ue.diff(x, 4) + ue.diff(y, 4) + 2 * ue.diff(x, 2, y, 2) # Lambdify for faster evaluation ul = lambdify((x, y), ue, 'numpy') fl = lambdify((x, y), fe, 'numpy') # Size of discretization N = (36, 36) S0 = Basis(N[0], family=family, bc='Biharmonic') S1 = Basis(N[1], family=family, bc='Biharmonic') T = TensorProductSpace(comm, (S0, S1), axes=(0, 1)) X = T.local_mesh(True) u = TrialFunction(T) v = TestFunction(T) # Get f on quad points fj = Array(T, buffer=fl(*X)) # Compute right hand side of biharmonic equation f_hat = inner(v, fj) # Get left hand side of biharmonic equation if family == 'chebyshev': # No integration by parts due to weights matrices = inner(v, div(grad(div(grad(u))))) else: # Use form with integration by parts. matrices = inner(div(grad(v)), div(grad(u))) # Create linear algebra solver
def get_context(): """Set up context for solver""" # Get points and weights for Chebyshev weighted integrals assert params.Dquad == params.Bquad collapse_fourier = False if params.dealias == '3/2-rule' else True ST = Basis(params.N[0], 'C', bc=(0, 0), quad=params.Dquad) CT = Basis(params.N[0], 'C', quad=params.Dquad) CP = Basis(params.N[0], 'C', quad=params.Dquad) K0 = Basis(params.N[1], 'F', domain=(0, params.L[1]), dtype='D') K1 = Basis(params.N[2], 'F', domain=(0, params.L[2]), dtype='d') CP.slice = lambda: slice(0, CT.N) kw0 = {'threads': params.threads, 'planner_effort': params.planner_effort["dct"], 'slab': (params.decomposition == 'slab'), 'collapse_fourier': collapse_fourier} FST = TensorProductSpace(comm, (ST, K0, K1), **kw0) # Dirichlet FCT = TensorProductSpace(comm, (CT, K0, K1), **kw0) # Regular Chebyshev N FCP = TensorProductSpace(comm, (CP, K0, K1), **kw0) # Regular Chebyshev N-2 VFS = VectorTensorProductSpace(FST) VCT = VectorTensorProductSpace(FCT) VQ = MixedTensorProductSpace([VFS, FCP]) mask = FST.get_mask_nyquist() if params.mask_nyquist else None # Padded kw = {'padding_factor': 1.5 if params.dealias == '3/2-rule' else 1, 'dealias_direct': params.dealias == '2/3-rule'} if params.dealias == '3/2-rule': # Requires new bases due to planning and transforms on different size arrays STp = Basis(params.N[0], 'C', bc=(0, 0), quad=params.Dquad) CTp = Basis(params.N[0], 'C', quad=params.Dquad) else: STp, CTp = ST, CT K0p = Basis(params.N[1], 'F', dtype='D', domain=(0, params.L[1]), **kw) K1p = Basis(params.N[2], 'F', dtype='d', domain=(0, params.L[2]), **kw) FSTp = TensorProductSpace(comm, (STp, K0p, K1p), **kw0) FCTp = TensorProductSpace(comm, (CTp, K0p, K1p), **kw0) VFSp = VectorTensorProductSpace(FSTp) VCp = MixedTensorProductSpace([FSTp, FCTp, FCTp]) float, complex, mpitype = datatypes("double") constraints = ((3, 0, 0), (3, params.N[0]-1, 0)) # Mesh variables X = FST.local_mesh(True) x0, x1, x2 = FST.mesh() K = FST.local_wavenumbers(scaled=True) # Solution variables UP_hat = Function(VQ) UP_hat0 = Function(VQ) U_hat, P_hat = UP_hat U_hat0, P_hat0 = UP_hat0 UP = Array(VQ) UP0 = Array(VQ) U, P = UP U0, P0 = UP0 # primary variable u = UP_hat H_hat = Function(VFS) H_hat0 = Function(VFS) H_hat1 = Function(VFS) dU = Function(VQ) Source = Array(VFS) # Note - not using VQ. Only used for constant pressure gradient Sk = Function(VFS) K2 = K[1]*K[1]+K[2]*K[2] for i in range(3): K[i] = K[i].astype(float) work = work_arrays() u_dealias = Array(VFSp) curl_hat = Function(VCp) curl_dealias = Array(VCp) nu, dt, N = params.nu, params.dt, params.N up = TrialFunction(VQ) vq = TestFunction(VQ) ut, pt = up vt, qt = vq alfa = 2./nu/dt a0 = inner(vt, (2./nu/dt)*ut-div(grad(ut))) a1 = inner(vt, (2./nu)*grad(pt)) a2 = inner(qt, (2./nu)*div(ut)) M = BlockMatrix(a0+a1+a2) # Collect all matrices mat = config.AttributeDict( dict(CDD=inner_product((ST, 0), (ST, 1)), AB=HelmholtzCoeff(N[0], 1., alfa-K2, 0, ST.quad),)) la = None hdf5file = CoupledFile(config.params.solver, checkpoint={'space': VQ, 'data': {'0': {'UP': [UP_hat]}, '1': {'UP': [UP_hat0]}}}, results={'space': VFS, 'data': {'U': [U]}}) return config.AttributeDict(locals())
import shenfun from shenfun import inner, TestFunction, TrialFunction, div, grad import numpy as np N = 8 B = shenfun.chebyshev.bases.ShenDirichletBasis(N, plan=True) #B = FFT = shenfun.fourier.bases.R2CBasis(N, plan=True) u = TrialFunction(B) v = TestFunction(B) mass = inner(u, v) # spectral matrix, i.e. a dict print(type(mass)) print(mass) # linear and bilinear form K = inner(v, div(grad(u))) # solves Ku=b fj = np.random.random(N) bhat = inner(v, fj) # transform of fj, same as B.forward(fj) #bhat2 = B.forward(fj) print(type(mass)) arint(type(mass)) uhat = np.zeros_like(bhat) uhat = K.solve(bhat, uhat) # solution in spectral space u = B.backward(uhat) # back to physical space # on a three dimensional cube, t # the matrix solve is applied along the first dimension since this is the default behaviour.
### #err += " & {:2.2e} ".format(errb/M) err += " & {:2.2e} & {:2.2e} ".format(errb / M, errs / M) err += " \\\ " print(err) print("\hline") for z in Z: err = str(z) for n in N: errh = 0 vh = zeros(n) sh = zeros(n) alfa = sqrt(z**2 + 2.0 / nu / dt) basis = chebyshev.bases.ShenDirichletBasis(n, plan=True, quad='GC') u = TrialFunction(basis) v = TestFunction(basis) A = inner(v, div(grad(u))) A.axis = 0 B = inner(v, u) B.axis = 0 HS = chebyshev.la.Helmholtz(A, B, array([1.]), array([alfa])) for m in range(M): u = random.randn(n) u[-2:] = 0 vh = HS.matvec(u, vh) sh = HS(sh, vh) errh += max(abs(sh - u)) / max(abs(u)) err += " & {:2.2e} ".format(errh / M) err += " \\\ " print(err)
def get_context(): """Set up context for solver""" collapse_fourier = False if params.dealias == '3/2-rule' else True family = 'C' ST = FunctionSpace(params.N[0], family, bc=(0, 0), quad=params.Dquad) CT = FunctionSpace(params.N[0], family, quad=params.Dquad) CP = FunctionSpace(params.N[0], family, quad=params.Dquad) K0 = FunctionSpace(params.N[1], 'F', domain=(0, params.L[1]), dtype='D') K1 = FunctionSpace(params.N[2], 'F', domain=(0, params.L[2]), dtype='d') #CP.slice = lambda: slice(0, CP.N-2) constraints = ((3, 0, 0), (3, params.N[0] - 1, 0)) kw0 = { 'threads': params.threads, 'planner_effort': params.planner_effort["dct"], 'slab': (params.decomposition == 'slab'), 'collapse_fourier': collapse_fourier } FST = TensorProductSpace(comm, (ST, K0, K1), **kw0) # Dirichlet FCT = TensorProductSpace(comm, (CT, K0, K1), **kw0) # Regular Chebyshev N FCP = TensorProductSpace(comm, (CP, K0, K1), **kw0) # Regular Chebyshev N-2 VFS = VectorSpace(FST) VCT = VectorSpace(FCT) VQ = CompositeSpace([VFS, FCP]) mask = FST.get_mask_nyquist() if params.mask_nyquist else None # Padded kw = { 'padding_factor': 1.5 if params.dealias == '3/2-rule' else 1, 'dealias_direct': params.dealias == '2/3-rule' } if params.dealias == '3/2-rule': # Requires new bases due to planning and transforms on different size arrays STp = FunctionSpace(params.N[0], family, bc=(0, 0), quad=params.Dquad) CTp = FunctionSpace(params.N[0], family, quad=params.Dquad) else: STp, CTp = ST, CT K0p = FunctionSpace(params.N[1], 'F', dtype='D', domain=(0, params.L[1]), **kw) K1p = FunctionSpace(params.N[2], 'F', dtype='d', domain=(0, params.L[2]), **kw) FSTp = TensorProductSpace(comm, (STp, K0p, K1p), **kw0) FCTp = TensorProductSpace(comm, (CTp, K0p, K1p), **kw0) VFSp = VectorSpace(FSTp) VCp = CompositeSpace([FSTp, FCTp, FCTp]) float, complex, mpitype = datatypes("double") # Mesh variables X = FST.local_mesh(True) x0, x1, x2 = FST.mesh() K = FST.local_wavenumbers(scaled=True) # Solution variables UP_hat = Function(VQ) UP_hat0 = Function(VQ) U_hat, P_hat = UP_hat U_hat0, P_hat0 = UP_hat0 UP = Array(VQ) UP0 = Array(VQ) U, P = UP U0, P0 = UP0 # RK parameters a = (8. / 15., 5. / 12., 3. / 4.) b = (0.0, -17. / 60., -5. / 12.) # primary variable u = UP_hat H_hat = Function(VFS) dU = Function(VQ) hv = np.zeros((2, ) + H_hat.shape, dtype=np.complex) Source = Array( VFS) # Note - not using VQ. Only used for constant pressure gradient Sk = Function(VFS) K2 = K[1] * K[1] + K[2] * K[2] for i in range(3): K[i] = K[i].astype(float) work = work_arrays() u_dealias = Array(VFSp) curl_hat = Function(VCp) curl_dealias = Array(VCp) nu, dt, N = params.nu, params.dt, params.N up = TrialFunction(VQ) vq = TestFunction(VQ) ut, pt = up vt, qt = vq M = [] for rk in range(3): a0 = inner(vt, (2. / nu / dt / (a[rk] + b[rk])) * ut - div(grad(ut))) a1 = inner(vt, (2. / nu / (a[rk] + b[rk])) * grad(pt)) a2 = inner(qt, (2. / nu / (a[rk] + b[rk])) * div(ut)) M.append(BlockMatrix(a0 + a1 + a2)) # Collect all matrices if ST.family() == 'chebyshev': mat = config.AttributeDict( dict(AB=[ HelmholtzCoeff(N[0], 1., -(K2 - 2. / nu / dt / (a[rk] + b[rk])), 0, ST.quad) for rk in range(3) ], )) else: mat = config.AttributeDict( dict(ADD=inner_product((ST, 0), (ST, 2)), BDD=inner_product((ST, 0), (ST, 0)))) la = None hdf5file = CoupledRK3File(config.params.solver, checkpoint={ 'space': VQ, 'data': { '0': { 'UP': [UP_hat] } } }, results={ 'space': VFS, 'data': { 'U': [U] } }) del rk return config.AttributeDict(locals())
def initialize(solver, context): # Initialize with pertubation ala perturbU (https://github.com/wyldckat/perturbU) for openfoam U = context.U X = context.X U_hat = context.U_hat params = config.params Y = np.where(X[0] < 0, 1+X[0], 1-X[0]) utau = params.nu*params.Re_tau Um = 46.9091*utau # For Re_tau=180 #Um = 56.*utau Xplus = Y*params.Re_tau Yplus = X[1]*params.Re_tau Zplus = X[2]*params.Re_tau duplus = Um*0.2/utau #Um*0.25/utau alfaplus = params.L[1]/200. # May have to adjust these two for different Re betaplus = params.L[2]/100. # sigma = 0.00055 # 0.00055 epsilon = Um/200. #Um/200. U[:] = 0 U[1] = Um*(Y-0.5*Y**2) dev = 1+0.0000001*np.random.randn(Y.shape[0], Y.shape[1], Y.shape[2]) #dev = np.fromfile('dev.dat').reshape((64, 64, 64)) dd = utau*duplus/2.0*Xplus/40.*np.exp(-sigma*Xplus**2+0.5)*np.cos(betaplus*Zplus)*dev[:, slice(0, 1), :] U[1] += dd U[2] += epsilon*np.sin(alfaplus*Yplus)*Xplus*np.exp(-sigma*Xplus**2)*dev[:, :, slice(0, 1)] U_hat = U.forward(U_hat) U = U_hat.backward(U) U_hat = U.forward(U_hat) if "KMM" in params.solver: context.g[:] = 1j*context.K[1]*U_hat[2] - 1j*context.K[2]*U_hat[1] # Set the flux #flux[0] = context.FST.dx(U[1], context.ST.quad) #solver.comm.Bcast(flux) # project to zero divergence div_u = solver.get_divergence(**context) print('div0 ', dx(div_u**2, context.FST)) u = TrialFunction(context.FST) v = TestFunction(context.FST) A = inner(v, div(grad(u))) b = inner(v, div(U_hat)) from shenfun.chebyshev.la import Helmholtz sol = Helmholtz(*A) phi = Function(context.FST) phi = sol(phi, b) U_hat -= project(grad(phi), context.VFS) U = U_hat.backward(U) div_u = solver.get_divergence(**context) print('div1 ', dx(div_u**2, context.FST)) if solver.rank == 0: print("Flux {}".format(flux[0])) if not 'KMM' in params.solver: P_hat = solver.compute_pressure(**context) P = P_hat.backward(context.P) if not 'RK3' in params.solver: context.U_hat0[:] = context.U_hat[:] context.H_hat1[:] = solver.get_convection(**context)