def test_Biharmonic(quad): M = 128 SB = ShenBiharmonicBasis(M, quad=quad) x = Symbol("x") u = sin(6*pi*x)**2 a = 1.0 b = 1.0 f = -u.diff(x, 4) + a*u.diff(x, 2) + b*u ul = lambdify(x, u, 'numpy') fl = lambdify(x, f, 'numpy') points, _ = SB.points_and_weights(M) uj = ul(points) fj = fl(points) A = inner_product((SB, 0), (SB, 4)) B = inner_product((SB, 0), (SB, 0)) C = inner_product((SB, 0), (SB, 2)) AA = -A.diags() + C.diags() + B.diags() f_hat = np.zeros(M) f_hat = SB.scalar_product(fj, f_hat) u_hat = np.zeros(M) u_hat[:-4] = la.spsolve(AA, f_hat[:-4]) u1 = np.zeros(M) u1 = SB.backward(u_hat, u1) #from IPython import embed; embed() assert np.allclose(u1, uj)
def assemble(self): N = self.N SB = ShenBiharmonicBasis(N, quad=self.quad) SB.plan((N, N), 0, np.float, {}) x, w = self.x, self.w = SB.points_and_weights(N) V = SB.vandermonde(x) # Trial function P4 = SB.get_vandermonde_basis(V) # Second derivatives T2x = SB.get_vandermonde_basis_derivative(V, 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 interp(self, y, eigval=1, same_mesh=False, verbose=False): """Interpolate solution eigenvector and it's derivative onto y """ N = self.N nx, eigval = self.get_eigval(eigval, verbose) phi_hat = np.zeros(N, np.complex) phi_hat[:-4] = np.squeeze(self.eigvectors[:, nx]) if same_mesh: phi = np.zeros_like(phi_hat) dphidy = np.zeros_like(phi_hat) if self.SB is None: self.SB = ShenBiharmonicBasis(N, quad=self.quad, plan=True) self.SD = ShenDirichletBasis(N, quad=self.quad, plan=True) self.CDB = inner_product((self.SD, 0), (self.SB, 1)) phi = self.SB.ifst(phi_hat, phi) dphidy_hat = self.CDB.matvec(phi_hat) dphidy_hat = self.SD.apply_inverse_mass(dphidy_hat) dphidy = self.SD.backward(dphidy_hat, dphidy) else: # Recompute interpolation matrices if necessary if not len(self.P4) == len(y): SB = ShenBiharmonicBasis(N, quad=self.quad) V = self.V = SB.vandermonde(y) P4 = self.P4 = SB.get_vandermonde_basis(V) T4x = self.T4x = SB.get_vandermonde_basis_derivative(V, 1) phi = np.dot(self.P4, phi_hat) dphidy = np.dot(self.T4x, phi_hat) return phi, dphidy
def interp(self, y, eigvals, eigvectors, eigval=1, same_mesh=False, verbose=False): """Interpolate solution eigenvector and it's derivative onto y args: y Interpolation points eigvals All computed eigenvalues eigvectors All computed eigenvectors kwargs: eigval The chosen eigenvalue, ranked with descending imaginary part. The largest imaginary part is 1, the second largest is 2, etc. same_mesh Boolean. Whether or not to interpolate to the same quadrature points as used for computing the eigenvectors verbose Boolean. Print information or not """ N = self.N nx, eigval = self.get_eigval(eigval, eigvals, verbose) phi_hat = np.zeros(N, np.complex) phi_hat[:-4] = np.squeeze(eigvectors[:, nx]) if same_mesh: phi = np.zeros_like(phi_hat) dphidy = np.zeros_like(phi_hat) if self.SB is None: self.SB = ShenBiharmonicBasis(N, quad=self.quad, plan=True) self.SD = ShenDirichletBasis(N, quad=self.quad, plan=True) self.CDB = inner_product((self.SD, 0), (self.SB, 1)) phi = self.SB.ifst(phi_hat, phi) dphidy_hat = self.CDB.matvec(phi_hat) dphidy_hat = self.SD.apply_inverse_mass(dphidy_hat) dphidy = self.SD.backward(dphidy_hat, dphidy) else: # Recompute interpolation matrices if necessary if not len(self.P4) == len(y): SB = ShenBiharmonicBasis(N, quad=self.quad) V = SB.vandermonde(y) self.P4 = SB.get_vandermonde_basis(V) self.T4x = SB.get_vandermonde_basis_derivative(V, 1) phi = np.dot(self.P4, phi_hat) dphidy = np.dot(self.T4x, phi_hat) return eigval, phi, dphidy
class OrrSommerfeld(object): def __init__(self, **kwargs): self.par = {'alfa': 1., 'Re': 8000., 'N': 80, 'quad': 'GC'} self.par.update(**kwargs) for name, val in six.iteritems(self.par): setattr(self, name, val) self.P4 = np.zeros(0) self.T4x = np.zeros(0) self.SB, self.SD, self.CDB = (None, ) * 3 self.x, self.w = None, None def interp(self, y, eigvals, eigvectors, eigval=1, same_mesh=False, verbose=False): """Interpolate solution eigenvector and it's derivative onto y args: y Interpolation points eigvals All computed eigenvalues eigvectors All computed eigenvectors kwargs: eigval The chosen eigenvalue, ranked with descending imaginary part. The largest imaginary part is 1, the second largest is 2, etc. same_mesh Boolean. Whether or not to interpolate to the same quadrature points as used for computing the eigenvectors verbose Boolean. Print information or not """ N = self.N nx, eigval = self.get_eigval(eigval, eigvals, verbose) phi_hat = np.zeros(N, np.complex) phi_hat[:-4] = np.squeeze(eigvectors[:, nx]) if same_mesh: phi = np.zeros_like(phi_hat) dphidy = np.zeros_like(phi_hat) if self.SB is None: self.SB = ShenBiharmonicBasis(N, quad=self.quad, plan=True) self.SD = ShenDirichletBasis(N, quad=self.quad, plan=True) self.CDB = inner_product((self.SD, 0), (self.SB, 1)) phi = self.SB.ifst(phi_hat, phi) dphidy_hat = self.CDB.matvec(phi_hat) dphidy_hat = self.SD.apply_inverse_mass(dphidy_hat) dphidy = self.SD.backward(dphidy_hat, dphidy) else: # Recompute interpolation matrices if necessary if not len(self.P4) == len(y): SB = ShenBiharmonicBasis(N, quad=self.quad) V = SB.vandermonde(y) self.P4 = SB.get_vandermonde_basis(V) self.T4x = SB.get_vandermonde_basis_derivative(V, 1) phi = np.dot(self.P4, phi_hat) dphidy = np.dot(self.T4x, phi_hat) return eigval, phi, dphidy def assemble(self): N = self.N SB = ShenBiharmonicBasis(N, quad=self.quad) SB.plan((N, N), 0, np.float, {}) x, w = self.x, self.w = SB.points_and_weights(N) V = SB.vandermonde(x) # Trial function P4 = SB.get_vandermonde_basis(V) # Second derivatives T2x = SB.get_vandermonde_basis_derivative(V, 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 solve(self, verbose=False): """Solve the Orr-Sommerfeld eigenvalue problem """ if verbose: print('Solving the Orr-Sommerfeld eigenvalue problem...') print('Re = ' + str(self.par['Re']) + ' and alfa = ' + str(self.par['alfa'])) A, B = self.assemble() return eig(A[:-4, :-4], B[:-4, :-4]) # return eig(np.dot(inv(B[:-4, :-4]), A[:-4, :-4])) @staticmethod def get_eigval(nx, eigvals, verbose=False): """Get the chosen eigenvalue Args: nx The chosen eigenvalue. nx=1 corresponds to the one with the largest imaginary part, nx=2 the second largest etc. eigvals Computed eigenvalues verbose Print the value of the chosen eigenvalue """ indices = np.argsort(np.imag(eigvals)) indi = indices[-1 * np.array(nx)] eigval = eigvals[indi] if verbose: ev = list(eigval) if np.ndim(eigval) else [eigval] indi = list(indi) if np.ndim(indi) else [indi] for i, (e, v) in enumerate(zip(ev, indi)): print('Eigenvalue {} ({}) = {:2.16e}'.format(i + 1, v, e)) return indi, eigval
def get_context(): """Set up context for solver""" # Get points and weights for Chebyshev weighted integrals ST = ShenDirichletBasis(params.N[0], quad=params.Dquad) SB = ShenBiharmonicBasis(params.N[0], quad=params.Bquad) CT = Basis(params.N[0], quad=params.Dquad) ST0 = ShenDirichletBasis(params.N[0], quad=params.Dquad, plan=True) # For 1D problem K0 = C2CBasis(params.N[1], domain=(0, params.L[1])) K1 = R2CBasis(params.N[2], domain=(0, params.L[2])) #CT = ST.CT # Chebyshev transform FST = TensorProductSpace(comm, (ST, K0, K1), **{ 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) # Dirichlet FSB = TensorProductSpace(comm, (SB, K0, K1), **{ 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) # Biharmonic FCT = TensorProductSpace(comm, (CT, K0, K1), **{ 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) # Regular Chebyshev VFS = VectorTensorProductSpace([FSB, FST, FST]) # Padded STp = ShenDirichletBasis(params.N[0], quad=params.Dquad) SBp = ShenBiharmonicBasis(params.N[0], quad=params.Bquad) CTp = Basis(params.N[0], quad=params.Dquad) K0p = C2CBasis(params.N[1], padding_factor=1.5, domain=(0, params.L[1])) K1p = R2CBasis(params.N[2], padding_factor=1.5, domain=(0, params.L[2])) FSTp = TensorProductSpace( comm, (STp, K0p, K1p), **{ 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) FSBp = TensorProductSpace( comm, (SBp, K0p, K1p), **{ 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) FCTp = TensorProductSpace( comm, (CTp, K0p, K1p), **{ 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) VFSp = VectorTensorProductSpace([FSBp, FSTp, FSTp]) VFSp = VFS FCTp = FCT FSTp = FST FSBp = FSB Nu = params.N[0] - 2 # Number of velocity modes in Shen basis Nb = params.N[0] - 4 # Number of velocity modes in Shen biharmonic basis u_slice = slice(0, Nu) v_slice = slice(0, Nb) 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 U = Array(VFS, False) U0 = Array(VFS, False) U_hat = Array(VFS) U_hat0 = Array(VFS) g = Array(FST) # primary variable u = (U_hat, g) H_hat = Array(VFS) H_hat0 = Array(VFS) H_hat1 = Array(VFS) dU = Array(VFS) hv = Array(FST) hg = Array(FST) Source = Array(VFS, False) Sk = Array(VFS) K2 = K[1] * K[1] + K[2] * K[2] K_over_K2 = np.zeros((2, ) + g.shape) for i in range(2): K_over_K2[i] = K[i + 1] / np.where(K2 == 0, 1, K2) work = work_arrays() nu, dt, N = params.nu, params.dt, params.N K4 = K2**2 kx = K[0][:, 0, 0] alfa = K2[0] - 2.0 / nu / dt # Collect all matrices mat = config.AttributeDict( dict( CDD=inner_product((ST, 0), (ST, 1)), AB=HelmholtzCoeff(kx, -1.0, -alfa, ST.quad), AC=BiharmonicCoeff(kx, nu * dt / 2., (1. - nu * dt * K2[0]), -(K2[0] - nu * dt / 2. * K4[0]), quad=SB.quad), # Matrices for biharmonic equation CBD=inner_product((SB, 0), (ST, 1)), ABB=inner_product((SB, 0), (SB, 2)), BBB=inner_product((SB, 0), (SB, 0)), SBB=inner_product((SB, 0), (SB, 4)), # Matrices for Helmholtz equation ADD=inner_product((ST, 0), (ST, 2)), BDD=inner_product((ST, 0), (ST, 0)), BBD=inner_product((SB, 0), (ST, 0)), CDB=inner_product((ST, 0), (SB, 1)), ADD0=inner_product((ST0, 0), (ST0, 2)), BDD0=inner_product((ST0, 0), (ST0, 0)), )) # Collect all linear algebra solvers #la = config.AttributeDict(dict( #HelmholtzSolverG = Helmholtz(N[0], np.sqrt(K2[0]+2.0/nu/dt), ST), #BiharmonicSolverU = Biharmonic(N[0], -nu*dt/2., 1.+nu*dt*K2[0], #-(K2[0] + nu*dt/2.*K4[0]), quad=SB.quad, #solver="cython"), #HelmholtzSolverU0 = Helmholtz(N[0], np.sqrt(2./nu/dt), ST), #TDMASolverD = TDMA(inner_product((ST, 0), (ST, 0))) #) #) mat.ADD.axis = 0 mat.BDD.axis = 0 mat.SBB.axis = 0 la = config.AttributeDict( dict(HelmholtzSolverG=Helmholtz(mat.ADD, mat.BDD, -np.ones( (1, 1, 1)), (K2[0] + 2.0 / nu / dt)[np.newaxis, :, :]), BiharmonicSolverU=Biharmonic( mat.SBB, mat.ABB, mat.BBB, -nu * dt / 2. * np.ones( (1, 1, 1)), (1. + nu * dt * K2[0])[np.newaxis, :, :], (-(K2[0] + nu * dt / 2. * K4[0]))[np.newaxis, :, :]), HelmholtzSolverU0=old_Helmholtz(N[0], np.sqrt(2. / nu / dt), ST), TDMASolverD=TDMA(inner_product((ST, 0), (ST, 0))))) hdf5file = KMMWriter({ "U": U[0], "V": U[1], "W": U[2] }, chkpoint={ 'current': { 'U': U }, 'previous': { 'U': U0 } }, filename=params.solver + ".h5", mesh={ "x": x0, "y": x1, "z": x2 }) return config.AttributeDict(locals())
def get_context(): """Set up context for solver""" # Get points and weights for Chebyshev weighted integrals ST = ShenDirichletBasis(params.N[0], quad=params.Dquad) SB = ShenBiharmonicBasis(params.N[0], quad=params.Bquad) CT = ST.CT # Chebyshev transform Nu = params.N[0] - 2 # Number of velocity modes in Shen basis Nb = params.N[0] - 4 # Number of velocity modes in Shen biharmonic basis u_slice = slice(0, Nu) v_slice = slice(0, Nb) FST = SlabShen_R2C(params.N, params.L, comm, threads=params.threads, communication=params.communication, planner_effort=params.planner_effort, dealias_cheb=params.dealias_cheb) float, complex, mpitype = datatypes("double") ST.plan(FST.complex_shape(), 0, complex, { 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) SB.plan(FST.complex_shape(), 0, complex, { 'threads': params.threads, 'planner_effort': params.planner_effort["dct"] }) # Mesh variables X = FST.get_local_mesh(ST) x0, x1, x2 = FST.get_mesh_dims(ST) K = FST.get_local_wavenumbermesh(scaled=True) K2 = K[1] * K[1] + K[2] * K[2] K_over_K2 = zeros((2, ) + FST.complex_shape()) for i in range(2): K_over_K2[i] = K[i + 1] / np.where(K2 == 0, 1, K2) # Solution variables U = zeros((3, ) + FST.real_shape(), dtype=float) U0 = zeros((3, ) + FST.real_shape(), dtype=float) U_hat = zeros((3, ) + FST.complex_shape(), dtype=complex) U_hat0 = zeros((3, ) + FST.complex_shape(), dtype=complex) g = zeros(FST.complex_shape(), dtype=complex) # primary variable u = (U_hat, g) H_hat = zeros((3, ) + FST.complex_shape(), dtype=complex) H_hat0 = zeros((3, ) + FST.complex_shape(), dtype=complex) H_hat1 = zeros((3, ) + FST.complex_shape(), dtype=complex) dU = zeros((3, ) + FST.complex_shape(), dtype=complex) hv = zeros(FST.complex_shape(), dtype=complex) hg = zeros(FST.complex_shape(), dtype=complex) Source = zeros((3, ) + FST.real_shape(), dtype=float) Sk = zeros((3, ) + FST.complex_shape(), dtype=complex) work = work_arrays() nu, dt, N = params.nu, params.dt, params.N K4 = K2**2 kx = K[0][:, 0, 0] # Collect all linear algebra solvers la = config.AttributeDict( dict(HelmholtzSolverG=Helmholtz(N[0], np.sqrt(K2[0] + 2.0 / nu / dt), ST), BiharmonicSolverU=Biharmonic(N[0], -nu * dt / 2., 1. + nu * dt * K2[0], -(K2[0] + nu * dt / 2. * K4[0]), quad=SB.quad, solver="cython"), HelmholtzSolverU0=Helmholtz(N[0], np.sqrt(2. / nu / dt), ST), TDMASolverD=TDMA(inner_product((ST, 0), (ST, 0))))) alfa = K2[0] - 2.0 / nu / dt # Collect all matrices mat = config.AttributeDict( dict( CDD=inner_product((ST, 0), (ST, 1)), AB=HelmholtzCoeff(N[0], 1.0, -alfa, ST.quad), AC=BiharmonicCoeff(N[0], nu * dt / 2., (1. - nu * dt * K2[0]), -(K2[0] - nu * dt / 2. * K4[0]), quad=SB.quad), # Matrices for biharmonic equation CBD=inner_product((SB, 0), (ST, 1)), ABB=inner_product((SB, 0), (SB, 2)), BBB=inner_product((SB, 0), (SB, 0)), SBB=inner_product((SB, 0), (SB, 4)), # Matrices for Helmholtz equation ADD=inner_product((ST, 0), (ST, 2)), BDD=inner_product((ST, 0), (ST, 0)), BBD=inner_product((SB, 0), (ST, 0)), CDB=inner_product((ST, 0), (SB, 1)))) hdf5file = KMMWriter({ "U": U[0], "V": U[1], "W": U[2] }, chkpoint={ 'current': { 'U': U }, 'previous': { 'U': U0 } }, filename=params.solver + ".h5", mesh={ "x": x0, "y": x1, "z": x2 }) return config.AttributeDict(locals())
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