def __init__(self, N, alfa, quad="GL", neumann=False): # Prepare LU Helmholtz solver for velocity self.N = N self.alfa = alfa self.neumann = neumann M = (N - 4) / 2 if neumann else (N - 3) / 2 if hasattr(alfa, "__len__"): Ny, Nz = alfa.shape self.u0 = zeros((2, M + 1, Ny, Nz), float) # Diagonal entries of U self.u1 = zeros((2, M, Ny, Nz), float) # Diagonal+1 entries of U self.u2 = zeros((2, M - 1, Ny, Nz), float) # Diagonal+2 entries of U self.L = zeros((2, M, Ny, Nz), float) # The single nonzero row of L self.s = slice(1, N - 2) if neumann else slice(0, N - 2) SFTc.LU_Helmholtz_3D(N, neumann, quad == "GL", self.alfa, self.u0, self.u1, self.u2, self.L) else: self.u0 = zeros((2, M + 1), float) # Diagonal entries of U self.u1 = zeros((2, M), float) # Diagonal+1 entries of U self.u2 = zeros((2, M - 1), float) # Diagonal+2 entries of U self.L = zeros((2, M), float) # The single nonzero row of L self.s = slice(1, N - 2) if neumann else slice(0, N - 2) SFTc.LU_Helmholtz_1D(N, neumann, quad == "GL", self.alfa, self.u0, self.u1, self.u2, self.L)
def Divu(U, U_hat, c): c[:] = 0 SFTc.Mult_Div_3D(N[0], K[1, 0], K[2, 0], U_hat[0, u_slice], U_hat[1, u_slice], U_hat[2, u_slice], c[p_slice]) c[p_slice] = SFTc.TDMA_3D(a0N, b0N, bcN, c0N, c[p_slice]) return c
def ComputeRHS(dU, jj): # Add convection to rhs if jj == 0: #conv0[:] = divergenceConvection(conv0) conv0[:] = standardConvection(conv0) # Compute diffusion diff0[:] = 0 SFTc.Mult_Helmholtz_3D_complex(N[0], ST.quad == "GL", -1, alfa, U_hat0[0], diff0[0]) SFTc.Mult_Helmholtz_3D_complex(N[0], ST.quad == "GL", -1, alfa, U_hat0[1], diff0[1]) SFTc.Mult_Helmholtz_3D_complex(N[0], ST.quad == "GL", -1, alfa, U_hat0[2], diff0[2]) dU[:3] = 1.5 * conv0 - 0.5 * conv1 dU[:3] *= dealias # Add pressure gradient and body force dU = pressuregrad(P_hat, dU) dU = body_force(Sk, dU) # Scale by 2/nu factor dU[:3] *= 2. / nu dU[:3] += diff0 return dU
def __call__(self, u): N = u.shape[0] if self.a0 is None: self.init(N) if len(u.shape) == 3: SFTc.TDMA_3D(self.a0, self.b0, self.bc, self.c0, u[self.s]) elif len(u.shape) == 1: SFTc.TDMA_1D(self.a0, self.b0, self.bc, self.c0, u[self.s]) else: raise NotImplementedError return u
def __call__(self, u): N = u.shape[0] if self.B is None: self.init(N) if len(u.shape) == 3: SFTc.PDMA_Symsolve3D(self.d0, self.d1, self.d2, u[:-4]) elif len(u.shape) == 1: SFTc.PDMA_Symsolve(self.d0, self.d1, self.d2, u[:-4]) else: raise NotImplementedError return u
def __call__(self, u, b): if self.dim=="1": if self.Neumann: SFTc.UTDMA_1D_Neumann(self.bk, u, b) else: SFTc.UTDMA_1D(self.ak, self.bk, u, b) elif self.dim=="3": if self.Neumann: SFTc.UTDMA_Neumann(self.bk, u, b) else: SFTc.UTDMA(self.ak, self.bk, u, b) return b
def chebDerivative_3D(self, fj, fd): fk = fj.copy() fk = self.fct(fj, fk) fkd = fk.copy() fkd = SFTc.chebDerivativeCoefficients_3D(fk, fkd) fd = self.ifct(fkd, fd) return fd
def solve(fk): N = len(fk) + 2 k = ST.wavenumbers(N) if solver == "banded": A = np.zeros((N - 2, N - 2)) A[-1, :] = -2 * np.pi * (k + 1) * (k + 2) for i in range(2, N - 2, 2): A[-i - 1, i:] = -4 * np.pi * (k[:-i] + 1) uk_hat = solve_banded((0, N - 3), A, fk) elif solver == "sparse": aij = [-2 * np.pi * (k + 1) * (k + 2)] for i in range(2, N - 2, 2): aij.append(np.array(-4 * np.pi * (k[:-i] + 1))) A = diags(aij, range(0, N - 2, 2)) uk_hat = la.spsolve(A, fk) elif solver == "bs": fc = fk.copy() uk_hat = np.zeros(N - 2) uk_hat = SFTc.BackSubstitution_1D(uk_hat, fc) #for i in range(N-3, -1, -1): #for l in range(i+2, N-2, 2): #fc[i] += (4*np.pi*(i+1)uk_hat[l]) #uk_hat[i] = -fc[i] / (2*np.pi*(i+1)*(i+2)) return uk_hat
def chebDerivative_3D(self, fj, fd): fk = work[(fj, 0)] fkd = work[(fj, 1)] fk = self.fct(fj, fk) fkd = SFTc.chebDerivativeCoefficients_3D(fk, fkd) fd = self.ifct(fkd, fd) return fd
def __call__(self, u, b): if len(u.shape) > 1: SFTc.Solve_Helmholtz_3D_n(self.N, self.neumann, b[self.s], u[self.s], self.u0, self.u1, self.u2, self.L) else: if u.dtype == complex128: SFTc.Solve_Helmholtz_1D(self.N, self.neumann, b[self.s].real, u[self.s].real, self.u0, self.u1, self.u2, self.L) SFTc.Solve_Helmholtz_1D(self.N, self.neumann, b[self.s].imag, u[self.s].imag, self.u0, self.u1, self.u2, self.L) else: SFTc.Solve_Helmholtz_1D(self.N, self.neumann, b[self.s], u[self.s], self.u0, self.u1, self.u2, self.L) return u
def solvePressure(P_hat, U_hat): global F_tmp, F_tmp2 U_tmp4[:] = 0 U_tmp3[:] = 0 F_tmp2[:] = 0 Ni = F_tmp2 # dudx = 0 from continuity equation. Use Shen Dirichlet basis # Use regular Chebyshev basis for dvdx and dwdx F_tmp[0] = Cm.matvec(U_hat[0]) F_tmp[0, u_slice] = SFTc.TDMA_3D(a0, b0, bc, c0, F_tmp[0, u_slice]) dudx = U_tmp4[0] = ifst(F_tmp[0], U_tmp4[0], ST) SFTc.Mult_DPhidT_3D(N[0], U_hat[1], U_hat[2], F_tmp[1], F_tmp[2]) dvdx = U_tmp4[1] = ifct(F_tmp[1], U_tmp4[1]) dwdx = U_tmp4[2] = ifct(F_tmp[2], U_tmp4[2]) dudy_h = 1j * K[1] * U_hat[0] dudy = U_tmp3[0] = ifst(dudy_h, U_tmp3[0], ST) dudz_h = 1j * K[2] * U_hat[0] dudz = U_tmp3[1] = ifst(dudz_h, U_tmp3[1], ST) Ni[0] = fst(U0[0] * dudx + U0[1] * dudy + U0[2] * dudz, Ni[0], ST) U_tmp3[:] = 0 dvdy_h = 1j * K[1] * U_hat[1] dvdy = U_tmp3[0] = ifst(dvdy_h, U_tmp3[0], ST) dvdz_h = 1j * K[2] * U_hat[1] dvdz = U_tmp3[1] = ifst(dvdz_h, U_tmp3[1], ST) Ni[1] = fst(U0[0] * dvdx + U0[1] * dvdy + U0[2] * dvdz, Ni[1], ST) U_tmp3[:] = 0 dwdy_h = 1j * K[1] * U_hat[2] dwdy = U_tmp3[0] = ifst(dwdy_h, U_tmp3[0], ST) dwdz_h = 1j * K[2] * U_hat[2] dwdz = U_tmp3[1] = ifst(dwdz_h, U_tmp3[1], ST) Ni[2] = fst(U0[0] * dwdx + U0[1] * dwdy + U0[2] * dwdz, Ni[2], ST) F_tmp[0] = 0 SFTc.Mult_Div_3D(N[0], K[1, 0], K[2, 0], Ni[0, u_slice], Ni[1, u_slice], Ni[2, u_slice], F_tmp[0, p_slice]) SFTc.Solve_Helmholtz_3D_complex(N[0], 1, F_tmp[0, p_slice], P_hat[p_slice], u0N, u1N, u2N, LN) return P_hat
def standardConvection(c): c[:] = 0 U_tmp4[:] = 0 U_tmp3[:] = 0 # dudx = 0 from continuity equation. Use Shen Dirichlet basis # Use regular Chebyshev basis for dvdx and dwdx F_tmp[0] = Cm.matvec(U_hat0[0]) F_tmp[0, u_slice] = SFTc.TDMA_3D(a0, b0, bc, c0, F_tmp[0, u_slice]) dudx = U_tmp4[0] = ifst(F_tmp[0], U_tmp4[0], ST) SFTc.Mult_DPhidT_3D(N[0], U_hat0[1], U_hat0[2], F_tmp[1], F_tmp[2]) dvdx = U_tmp4[1] = ifct(F_tmp[1], U_tmp4[1]) dwdx = U_tmp4[2] = ifct(F_tmp[2], U_tmp4[2]) #dudx = U_tmp4[0] = chebDerivative_3D(U0[0], U_tmp4[0]) #dvdx = U_tmp4[1] = chebDerivative_3D0(U0[1], U_tmp4[1]) #dwdx = U_tmp4[2] = chebDerivative_3D0(U0[2], U_tmp4[2]) dudy_h = 1j * K[1] * U_hat0[0] dudy = U_tmp3[0] = ifst(dudy_h, U_tmp3[0], ST) dudz_h = 1j * K[2] * U_hat0[0] dudz = U_tmp3[1] = ifst(dudz_h, U_tmp3[1], ST) c[0] = fss(U0[0] * dudx + U0[1] * dudy + U0[2] * dudz, c[0], ST) U_tmp3[:] = 0 dvdy_h = 1j * K[1] * U_hat0[1] dvdy = U_tmp3[0] = ifst(dvdy_h, U_tmp3[0], ST) dvdz_h = 1j * K[2] * U_hat0[1] dvdz = U_tmp3[1] = ifst(dvdz_h, U_tmp3[1], ST) c[1] = fss(U0[0] * dvdx + U0[1] * dvdy + U0[2] * dvdz, c[1], ST) U_tmp3[:] = 0 dwdy_h = 1j * K[1] * U_hat0[2] dwdy = U_tmp3[0] = ifst(dwdy_h, U_tmp3[0], ST) dwdz_h = 1j * K[2] * U_hat0[2] dwdz = U_tmp3[1] = ifst(dwdz_h, U_tmp3[1], ST) c[2] = fss(U0[0] * dwdx + U0[1] * dwdy + U0[2] * dwdz, c[2], ST) c *= -1 return c
def fst(self, fj, fk): """Fast Shen transform for general BC. """ fk = self.fastShenScalar(fj, fk) N = fj.shape[0] k = self.wavenumbers(N) k1 = self.wavenumbers(N + 1) ak, bk = self.shenCoefficients(k, self.BC) ak1, bk1 = self.shenCoefficients(k1, self.BC) if self.quad == "GC": ck = ones(N - 2) ck[0] = 2 elif self.quad == "GL": ck = ones(N - 2) ck[0] = 2 ck[-1] = 2 a = (pi / 2) * (ck + ak**2 + bk**2) b = ones(N - 3) * (pi / 2) * (ak[:-1] + ak1[1:-1] * bk[:-1]) c = ones(N - 4) * (pi / 2) * bk[:-2] if len(fk.shape) == 3: if self.BC[0] == 0 and self.BC[1] == 1 and self.BC[ 2] == 0 and self.BC[3] == 0 and self.BC[ 4] == 1 and self.BC[5] == 0: fk[1:-2] = SFTc.PDMA_3D_complex(a[1:], b[1:], c[1:], fk[1:-2]) else: fk[:-2] = SFTc.PDMA_3D_complex(a, b, c, fk[:-2]) elif len(fk.shape) == 1: if self.BC[0] == 0 and self.BC[1] == 1 and self.BC[ 2] == 0 and self.BC[3] == 0 and self.BC[ 4] == 1 and self.BC[5] == 0: fk[1:-2] = SFTc.PDMA_1D(a[1:], b[1:], c[1:], fk[1:-2]) else: fk[:-2] = SFTc.PDMA_1D(a, b, c, fk[:-2]) return fk
def __call__(self, u, b): if len(u.shape) == 3: Ny, Nz = u.shape[1:] if self.solver == "scipy": for i in range(Ny): for j in range(Nz): u[:-4:2, i, j] = lu_solve(self.Le[i][j], b[:-4:2, i, j]) u[1:-4:2, i, j] = lu_solve(self.Lo[i][j], b[1:-4:2, i, j]) else: SFTc.Solve_Biharmonic_3D_n(b, u, self.u0, self.u1, self.u2, self.l0, self.l1, self.ak, self.bk, self.a0) else: if self.solver == "scipy": u[:-4:2] = lu_solve(self.Le, b[:-4:2]) u[1:-4:2] = lu_solve(self.Lo, b[1:-4:2]) else: SFTc.Solve_Biharmonic_1D(b, u, self.u0, self.u1, self.u2, self.l0, self.l1, self.ak, self.bk, self.a0) return u
def Curl(u0, uh, c): #c[2] = chebDerivative_3D(u0[1], c[2]) SFTc.Mult_DPhidT_3D(N[0], uh[1], uh[2], F_tmp[1], F_tmp[2]) c[2] = ifct(F_tmp[1], c[2]) Uc[:] = ifst(1j * K[1, :Nu] * uh[0, :Nu], Uc, ST) c[2] -= Uc #F_tmp[0] = -Cm.matvec(uh[2]) #F_tmp[0, u_slice] = SFTc.TDMA_3D(a0, b0, bc, c0, F_tmp[0, u_slice]) #c[1] = ifst(F_tmp[0], c[1], ST) c[1] = ifct(F_tmp[2], c[1]) Uc[:] = ifst(1j * K[2] * uh[0, :Nu], Uc, ST) c[1] += Uc c[0] = ifst(1j * (K[1] * uh[2] - K[2] * uh[1]), c[0], ST) return c
def chebDerivativeCoefficients(self, fk, fj): SFTc.chebDerivativeCoefficients(fk, fj) return fj
def __call__(self, u, b): if self.dim=="1": SFTc.PDMA_1D(self.a0, self.b0, self.c0, self.d0, self.e0, u, b) elif self.dim=="3": SFTc.PDMA(self.a0, self.b0, self.c0, self.d0, self.e0, u, b) return b
ck = ones(N[0] - 3) if SN.quad == "GL": ck[-1] = 2 a0N = ones(N[0] - 5) * (-pi / 2) * (kk[1:-2] / (kk[1:-2] + 2))**2 b0N = pi / 2 * (1 + ck * (kk[1:] / (kk[1:] + 2))**4) c0N = a0N.copy() bcN = b0N.copy() # Prepare LU Helmholtz solver for velocity M = (N[0] - 3) / 2 u0 = zeros((2, M + 1, U_hat.shape[2], U_hat.shape[3])) # Diagonal entries of U u1 = zeros((2, M, U_hat.shape[2], U_hat.shape[3])) # Diagonal+1 entries of U u2 = zeros( (2, M - 1, U_hat.shape[2], U_hat.shape[3])) # Diagonal+2 entries of U L0 = zeros( (2, M, U_hat.shape[2], U_hat.shape[3])) # The single nonzero row of L SFTc.LU_Helmholtz_3D(N[0], 0, ST.quad == "GL", alfa1, u0, u1, u2, L0) # Prepare LU Helmholtz solver Neumann for pressure MN = (N[0] - 4) / 2 u0N = zeros( (2, MN + 1, U_hat.shape[2], U_hat.shape[3])) # Diagonal entries of U u1N = zeros((2, MN, U_hat.shape[2], U_hat.shape[3])) # Diagonal+1 entries of U u2N = zeros( (2, MN - 1, U_hat.shape[2], U_hat.shape[3])) # Diagonal+2 entries of U LN = zeros( (2, MN, U_hat.shape[2], U_hat.shape[3])) # The single nonzero row of L SFTc.LU_Helmholtz_3D(N[0], 1, SN.quad == "GL", alfa2, u0N, u1N, u2N, LN) def solvePressure(P_hat, U_hat): global F_tmp, F_tmp2
def chebDerivative_3D0(fj, u0): UT[0] = fct0(fj, UT[0]) UT[1] = SFTc.chebDerivativeCoefficients_3D(UT[0], UT[1]) u0[:] = ifct0(UT[1], u0) return u0
def __init__(self, N, a0, alfa, beta, quad="GL", solver="scipy"): self.quad = quad self.solver = solver k = arange(N) self.S = S = SBBmat(k) self.B = B = BBBmat(k, self.quad) self.A = A = ABBmat(k) self.a0 = a0 self.alfa = alfa self.beta = beta if not solver == "scipy": sii, siu, siuu = S.dd, S.ud[0], S.ud[1] ail, aii, aiu = A.ld, A.dd, A.ud bill, bil, bii, biu, biuu = B.lld, B.ld, B.dd, B.ud, B.uud M = sii[::2].shape[0] if hasattr(beta, "__len__"): Ny, Nz = beta.shape if solver == "scipy": self.Le = Le = [] self.Lo = Lo = [] for i in range(Ny): Lej = [] Loj = [] for j in range(Nz): AA = a0 * S.diags().toarray() + alfa[i, j] * A.diags( ).toarray() + beta[i, j] * B.diags().toarray() Ae = AA[::2, ::2] Ao = AA[1::2, 1::2] Lej.append(lu_factor(Ae)) Loj.append(lu_factor(Ao)) Le.append(Lej) Lo.append(Loj) else: self.u0 = zeros((2, M, Ny, Nz)) self.u1 = zeros((2, M, Ny, Nz)) self.u2 = zeros((2, M, Ny, Nz)) self.l0 = zeros((2, M, Ny, Nz)) self.l1 = zeros((2, M, Ny, Nz)) self.ak = zeros((2, M, Ny, Nz)) self.bk = zeros((2, M, Ny, Nz)) SFTc.LU_Biharmonic_3D(a0, alfa, beta, sii, siu, siuu, ail, aii, aiu, bill, bil, bii, biu, biuu, self.u0, self.u1, self.u2, self.l0, self.l1) SFTc.Biharmonic_factor_pr_3D(self.ak, self.bk, self.l0, self.l1) else: if solver == "scipy": AA = a0 * S.diags().toarray() + alfa * A.diags().toarray( ) + beta * B.diags().toarray() Ae = AA[::2, ::2] Ao = AA[1::2, 1::2] self.Le = lu_factor(Ae) self.Lo = lu_factor(Ao) else: self.u0 = zeros((2, M)) self.u1 = zeros((2, M)) self.u2 = zeros((2, M)) self.l0 = zeros((2, M)) self.l1 = zeros((2, M)) self.ak = zeros((2, M)) self.bk = zeros((2, M)) SFTc.LU_Biharmonic_1D(a0, alfa, beta, sii, siu, siuu, ail, aii, aiu, bill, bil, bii, biu, biuu, self.u0, self.u1, self.u2, self.l0, self.l1) SFTc.Biharmonic_factor_pr(self.ak, self.bk, self.l0, self.l1)
def init(self, N): self.B = BBBmat(arange(N).astype(float), self.quad) self.d0, self.d1, self.d2 = self.B.dd.copy(), self.B.ud.copy( ), self.B.uud.copy() SFTc.PDMA_SymLU(self.d0, self.d1, self.d2)
def steps(): global t, tstep, e0, dU, U_hat, P_hat, Pcorr, U_hat1, U_hat0, P while t < T - 1e-8: #plt.pause(2) t += dt tstep += 1 #print "tstep ", tstep # Tentative momentum solve for jj in range(velocity_pressure_iters): dU[:] = 0 dU = ComputeRHS(dU, jj) SFTc.Solve_Helmholtz_3D_complex(N[0], 0, dU[0, u_slice], U_hat[0, u_slice], u0, u1, u2, L0) SFTc.Solve_Helmholtz_3D_complex(N[0], 0, dU[1, u_slice], U_hat[1, u_slice], u0, u1, u2, L0) SFTc.Solve_Helmholtz_3D_complex(N[0], 0, dU[2, u_slice], U_hat[2, u_slice], u0, u1, u2, L0) #SFTc.Solve_Helmholtz_3Dall_complex(N[0], 0, dU[:, u_slice], U_hat[:, u_slice], u0, u1, u2, L0) # Pressure correction dU[3] = pressurerhs(U_hat, dU[3]) SFTc.Solve_Helmholtz_3D_complex(N[0], 1, dU[3, p_slice], Pcorr[p_slice], u0N, u1N, u2N, LN) # Update pressure #dU[3] *= (-dt) # Get div(u) in dU[3] #dU[3, p_slice] = SFTc.TDMA_3D_complex(a0N, b0N, bcN, c0N, dU[3, p_slice]) #P_hat[p_slice] += (Pcorr[p_slice] - nu*dU[3, p_slice]) P_hat[p_slice] += Pcorr[p_slice] #if jj == 0: #print " Divergence error" #print " Pressure correction norm %2.6e" %(linalg.norm(Pcorr)) # Update velocity dU[:] = 0 pressuregrad(Pcorr, dU) dU[0, u_slice] = SFTc.TDMA_3D(a0, b0, bc, c0, dU[0, u_slice]) dU[1, u_slice] = SFTc.TDMA_3D(a0, b0, bc, c0, dU[1, u_slice]) dU[2, u_slice] = SFTc.TDMA_3D(a0, b0, bc, c0, dU[2, u_slice]) U_hat[:3, u_slice] += dt * dU[:3, u_slice] # + since pressuregrad computes negative pressure gradient for i in range(3): U[i] = ifst(U_hat[i], U[i], ST) # Rotate velocities U_hat1[:] = U_hat0 U_hat0[:] = U_hat U0[:] = U P = ifst(P_hat, P, SN) conv1[:] = conv0 timer() if tstep % check_step == 0: if case == "OS": pert = (U[1] - (1 - X[0]**2))**2 + U[0]**2 e1 = 0.5 * energy(pert) exact = exp(2 * imag(OS.eigval) * t) if rank == 0: print "Time %2.5f Norms %2.12e %2.12e %2.12e" % ( t, e1 / e0, exact, e1 / e0 - exact) elif case == "MKK": e0 = energy(U0[0]**2) e1 = energy(U0[2]**2) if rank == 0: print "Time %2.5f Energy %2.12e %2.12e " % (t, e0, e1) #if tstep == 100: #Source[2, :] = 0 #Sk[2] = fss(Source[2], Sk[2], ST) if tstep % plot_step == 0 and enable_plotting: if case == "OS": im1.ax.clear() im1.ax.contourf(X[1, :, :, 0], X[0, :, :, 0], U[1, :, :, 0] - (1 - X[0, :, :, 0]**2), 100) im1.autoscale() im2.ax.clear() im2.ax.contourf(X[1, :, :, 0], X[0, :, :, 0], U[0, :, :, 0], 100) im2.autoscale() im3.ax.clear() im3.ax.contourf(X[1, :, :, 0], X[0, :, :, 0], P[:, :, 0], 100) im3.autoscale() im4.set_UVC(U[1, :, :, 0] - (1 - X[0, :, :, 0]**2), U[0, :, :, 0]) elif case == "MKK": im1.ax.clear() im1.ax.contourf(X[1, :, :, 0], X[0, :, :, 0], U[1, :, :, 0], 100) im1.autoscale() im2.ax.clear() im2.ax.contourf(X[1, :, :, 0], X[0, :, :, 0], U[0, :, :, 0], 100) im2.autoscale() im3.ax.clear() im3.ax.contourf(X[1, :, :, 0], X[0, :, :, 0], P[:, :, 0], 100) im3.autoscale() plt.pause(1e-6)
def pressurerhs(U_hat, dU): dU[:] = 0. SFTc.Mult_Div_3D(N[0], K[1, 0], K[2, 0], U_hat[0, u_slice], U_hat[1, u_slice], U_hat[2, u_slice], dU[p_slice]) dU[p_slice] *= -1. / dt return dU
def chebDerivative_3D(fj, u0): Uc_hat2[:] = fct(fj, Uc_hat2) Uc_hat[:] = SFTc.chebDerivativeCoefficients_3D(Uc_hat2, Uc_hat) u0[:] = ifct(Uc_hat, u0) return u0