def __init__(self, topo, quad, X, dX, dt, grav): self.topo = topo self.quad = quad self.X = X self.dX = dX self.dt = dt self.grav = grav self.linear = False self.topo_q = Topo(topo.nx, quad.n) # 1 form matrix inverse self.M1 = Pmat(topo, quad, dX).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad, dX).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.E10 = BoundaryMat(topo).M self.E01 = -1.0 * self.E10.transpose() self.PtQ = PtQmat(topo, quad, dX).M self.PtQT = PtQmat(topo, quad, dX).M.transpose() self.UtQ = UtQmat(topo, quad, dX).M self.UtQT = UtQmat(topo, quad, dX).M.transpose() # helmholtz operator GRAD = 0.5 * self.grav * self.dt * self.E01 * self.M1 DIV = 0.5 * self.dt * self.M1 * self.E10 HELM = self.M1 - DIV * self.M0inv * GRAD self.HELMinv = la.inv(HELM) self.DM0inv = DIV self.M0invG = self.M0inv * GRAD
def __init__(self, topo, quad, topo_q, lx, g, H): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.g = g self.H = H det = 0.5 * lx / topo.nx self.detInv = 1.0 / det # 1 form matrix inverse self.M1 = Pmat(topo, quad).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.D10 = BoundaryMat(topo).M self.D01 = self.D10.transpose() # 0 form to 1 from gradient operator self.A = self.detInv * self.D10 # 1 form to 0 form gradient operator self.B = -1.0 * self.detInv * self.M0inv * self.D01 * self.M1
def __init__(self, topo, quad, topo_q, lx, ly, f, g, apvm, hb): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.g = g self.apvm = apvm det = 0.5 * lx / topo.nx self.detInv = 1.0 / det self.hb = hb # 1 form matrix inverse M1 = Umat(topo, quad).M self.M1inv = la.inv(M1) # 2 form matrix inverse M2 = Wmat(topo, quad).M self.M2inv = la.inv(M2) # 0 form matrix inverse self.M0 = Pmat(topo, quad).M M0inv = la.inv(self.M0) D10 = BoundaryMat10(topo).M D01 = D10.transpose() self.D01M1 = self.detInv * D01 * M1 self.D10 = self.detInv * D10 self.M0inv = M0inv # 2 form gradient matrix self.D21 = BoundaryMat(topo).M self.D12 = -1.0 * self.D21.transpose() self.D12M2 = self.detInv * self.D12 * M2 # 0 form coriolis vector Mxto0 = Xto0(topo, quad).M fx = f * np.ones( (topo_q.n * topo_q.n * topo.nx * topo.ny), dtype=np.float64) self.f = Mxto0 * fx self.M0f = self.M0 * self.f self.Uh = Uhmat(topo, quad) self.WU = WtQUmat(topo, quad) self.PU = PtQUmat(topo, quad) self.Rq = RotationalMat(topo, quad) self.q = np.zeros((self.M0f.shape[0]), dtype=np.float64) self.hvec = Phvec(topo, quad)
def __init__(self,topo,quad,topo_q,lx,R,cp,eta_f,eta_h,Aeta,Beta,po,ps): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.edge = LagrangeEdge(topo.n) self.R = R self.cp = cp self.eta_f = eta_f # mass based vertical height at full levels self.eta_h = eta_h # mass based vertical height at half levels self.Aeta = Aeta # self.Beta = Beta det = 0.5*lx/topo.nx self.detInv = 1.0/det self.po = po # reference pressure (constant) self.ps = ps # surface pressure # layer thickness with respect to the generalised vertical coordiante, eta self.dEta = np.zeros((self.eta_h.shape[0]),dtype=np.float64) for k in np.arange(self.eta_h.shape[0]): self.dEta[k] = self.eta_f[k+1] - self.eta_f[k]; # pseudo-density (vertical pressure gradient) within the layer self.pi = np.zeros((self.eta_h.shape[0],topo.nx*topo.n),dtype=np.float64) # 1 form matrix inverse self.M1 = Pmat(topo,quad).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo,quad).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.D10 = BoundaryMat(topo).M self.D01 = self.D10.transpose() # 0 form to 1 from gradient operator #self.A = self.detInv*self.D10 # 1 form to 0 form gradient operator #self.B = -1.0*self.detInv*self.M0inv*self.D01*self.M1 self.B = -1.0*self.M0inv*self.D01*self.M1
class WaveEqn_EEC: def __init__(self, topo, quad, topo_q, lx, g, H, dt): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.g = g self.H = H self.dt = dt det = 0.5 * lx / topo.nx self.detInv = 1.0 / det # 1 form matrix inverse self.M1 = Pmat(topo, quad).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.D10 = BoundaryMat(topo).M self.D01 = self.D10.transpose() # 0 form to 1 from gradient operator self.A = self.detInv * self.D10 # 1 form to 0 form gradient operator self.B = -1.0 * self.detInv * self.M0inv * self.D01 * self.M1 # Identity matrix self.I = diags([1.0], [0], shape=(topo.nx * topo.n, topo.nx * topo.n)) # block system self.M = bmat( [[self.I, 0.5 * dt * H * self.A], [0.5 * dt * g * self.B, self.I]], format='csc', dtype=np.float64) self.Minv = la.inv(self.M) def solve(self, hi, ui): rhs = np.zeros(2 * self.topo.nx * self.topo.n, dtype=np.float64) rhs[:self.topo.nx * self.topo.n] = hi - 0.5 * self.dt * self.H * self.A * ui rhs[self.topo.nx * self.topo.n:] = ui - 0.5 * self.dt * self.g * self.B * hi ans = self.Minv * rhs hf = ans[:self.topo.nx * self.topo.n] uf = ans[self.topo.nx * self.topo.n:] return hf, uf
def __init__(self, topo, quad, topo_q, lx, g, H, dt): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.g = g self.H = H self.dt = dt det = 0.5 * lx / topo.nx self.detInv = 1.0 / det # 1 form matrix inverse self.M1 = Pmat(topo, quad).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.D10 = BoundaryMat(topo).M self.D01 = self.D10.transpose() # 0 form to 1 from gradient operator self.A = self.detInv * self.D10 # 1 form to 0 form gradient operator self.B = -1.0 * self.detInv * self.M0inv * self.D01 * self.M1 # Identity matrix self.I = diags([1.0], [0], shape=(topo.nx * topo.n, topo.nx * topo.n)) # block system self.M = bmat( [[self.I, 0.5 * dt * H * self.A], [0.5 * dt * g * self.B, self.I]], format='csc', dtype=np.float64) self.Minv = la.inv(self.M)
class SWEqn: def __init__(self, topo, quad, topo_q, lx, ly, f, g, apvm, hb): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.g = g self.apvm = apvm det = 0.5 * lx / topo.nx self.detInv = 1.0 / det self.hb = hb # 1 form matrix inverse M1 = Umat(topo, quad).M self.M1inv = la.inv(M1) # 2 form matrix inverse M2 = Wmat(topo, quad).M self.M2inv = la.inv(M2) # 0 form matrix inverse self.M0 = Pmat(topo, quad).M M0inv = la.inv(self.M0) D10 = BoundaryMat10(topo).M D01 = D10.transpose() self.D01M1 = self.detInv * D01 * M1 self.D10 = self.detInv * D10 self.M0inv = M0inv # 2 form gradient matrix self.D21 = BoundaryMat(topo).M self.D12 = -1.0 * self.D21.transpose() self.D12M2 = self.detInv * self.D12 * M2 # 0 form coriolis vector Mxto0 = Xto0(topo, quad).M fx = f * np.ones( (topo_q.n * topo_q.n * topo.nx * topo.ny), dtype=np.float64) self.f = Mxto0 * fx self.M0f = self.M0 * self.f self.Uh = Uhmat(topo, quad) self.WU = WtQUmat(topo, quad) self.PU = PtQUmat(topo, quad) self.Rq = RotationalMat(topo, quad) self.q = np.zeros((self.M0f.shape[0]), dtype=np.float64) self.hvec = Phvec(topo, quad) def diagnose_q(self, h, u): w = self.D01M1 * u #f = self.M0*self.f #M0h = Phmat(self.topo,self.quad,h).M #M0hinv = la.inv(M0h) #q = M0hinv*(w+f) hv = self.hvec.assemble(h) for ii in np.arange(hv.shape[0]): self.q[ii] = (w[ii] + self.M0f[ii]) / hv[ii] return self.q def diagnose_F(self, h, u): M1h = self.Uh.assemble(h) M1invM1h = self.M1inv * M1h F = M1invM1h * u return F def diagnose_K(self, u): WtQU = self.WU.assemble(u) K = self.M2inv * WtQU k = 0.5 * K * u return k def prognose_h(self, hi, F, dt): hf = hi - dt * self.detInv * self.D21 * F return hf def prognose_u(self, hi, ui, hd, ud, q, F, dt): # remove the anticipated potential vorticity from q if self.apvm > 0.0: dq = self.D10 * q PtQU = self.PU.assemble(dq) udq = self.M0inv * PtQU * ud q = q - self.apvm * udq R = self.Rq.assemble(q) qCrossF = R * F k = self.diagnose_K(ud) hBar = k + self.g * hd + self.g * self.hb gE = self.D12M2 * hBar uf = ui - dt * self.M1inv * (qCrossF + gE) return uf def solveEuler(self, hi, ui, hd, ud, dt): q = self.diagnose_q(hd, ud) F = self.diagnose_F(hd, ud) hf = self.prognose_h(hi, F, dt) uf = self.prognose_u(hi, ui, hd, ud, q, F, dt) return hf, uf def solveRK2(self, hi, ui, dt): hh, uh = self.solveEuler(hi, ui, hi, ui, 0.5 * dt) hf, uf = self.solveEuler(hi, ui, hh, uh, dt) return hf, uf
print 'testing boundary matrices...' dpx = np.zeros(2 * nxm * nym, dtype=np.float64) for ey in np.arange(ny): for ex in np.arange(nx): inds0 = topo_q.localToGlobal0(ex, ey) for jj in np.arange(mp1 * mp1): if jj % mp1 == m or jj / mp1 == m: continue i = inds0[jj] % nxm j = inds0[jj] / nxm dpx[inds0[jj]] = dpdx_func(x[i], y[j]) dpx[inds0[jj] + shiftQuad] = dpdy_func(x[i], y[j]) dpi = Mxto1 * dpx D21 = BoundaryMat(topo).M D12 = -1.0 * D21.transpose() dp = (2.0 * nx / lx) * D21 * dpi M1 = Umat(topo, quad).M M2 = Wmat(topo, quad).M M1inv = la.inv(M1) dh = (2.0 * nx / lx) * M1inv * D12 * M2 * hi for ey in np.arange(ny): for ex in np.arange(nx): inds0 = topo_q.localToGlobal0(ex, ey) inds1x = topo.localToGlobal1x(ex, ey) inds1y = topo.localToGlobal1y(ex, ey) inds2 = topo.localToGlobal2(ex, ey) for jj in np.arange(mp1 * mp1):
class WaveEqn: def __init__(self, topo, quad, topo_q, lx, g, H): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.g = g self.H = H det = 0.5 * lx / topo.nx self.detInv = 1.0 / det # 1 form matrix inverse self.M1 = Pmat(topo, quad).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.D10 = BoundaryMat(topo).M self.D01 = self.D10.transpose() # 0 form to 1 from gradient operator self.A = self.detInv * self.D10 # 1 form to 0 form gradient operator self.B = -1.0 * self.detInv * self.M0inv * self.D01 * self.M1 def prognose_h(self, hi, ud, dt): hf = hi - dt * self.H * self.A * ud return hf def prognose_u(self, hi, ui, hd, ud, dt): uf = ui - dt * self.g * self.B * hd return uf def solveEuler(self, hi, ui, hd, ud, dt): hf = self.prognose_h(hi, ud, dt) uf = self.prognose_u(hi, ui, hd, ud, dt) return hf, uf def solveRK2(self, hi, ui, dt): hh, uh = self.solveEuler(hi, ui, hi, ui, 0.5 * dt) hf, uf = self.solveEuler(hi, ui, hh, uh, dt) return hf, uf def solveRK2_SS(self, hi, ui, dt): Fui = self.g * self.B * hi Fhi = self.H * self.A * ui uj = ui - dt * Fui hj = hi - dt * Fhi Fuj = self.g * self.B * hj Fhj = self.H * self.A * uj uf = ui - 0.5 * dt * (Fui + Fuj) hf = hi - 0.5 * dt * (Fhi + Fhj) return hf, uf
class SWEqn: def __init__(self, topo, quad, X, dX, dt, grav): self.topo = topo self.quad = quad self.X = X self.dX = dX self.dt = dt self.grav = grav self.linear = False self.topo_q = Topo(topo.nx, quad.n) # 1 form matrix inverse self.M1 = Pmat(topo, quad, dX).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad, dX).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.E10 = BoundaryMat(topo).M self.E01 = -1.0 * self.E10.transpose() self.PtQ = PtQmat(topo, quad, dX).M self.PtQT = PtQmat(topo, quad, dX).M.transpose() self.UtQ = UtQmat(topo, quad, dX).M self.UtQT = UtQmat(topo, quad, dX).M.transpose() # helmholtz operator GRAD = 0.5 * self.grav * self.dt * self.E01 * self.M1 DIV = 0.5 * self.dt * self.M1 * self.E10 HELM = self.M1 - DIV * self.M0inv * GRAD self.HELMinv = la.inv(HELM) self.DM0inv = DIV self.M0invG = self.M0inv * GRAD #u,s,vt = la.svds(self.M0) #print('SVD: ') #print(u.shape) #print(s.shape) #print(vt.shape) #S = sparse.csc_matrix((s,(np.arange(len(s)),np.arange(len(s)))),shape=(len(s),len(s)),dtype=np.float64) #vs = vt.transpose() * S #ut = u.transpose() #print(vs.shape) #print(ut.shape) #self.M0inv_pseudo = np.matmul(vs,ut) #print(self.M0inv_pseudo.shape) def diagnose_F(self, u1, u2, h1, h2): #Mu1 = PtU_u(self.topo,self.quad,self.dX,u1).M.transpose() #Mu2 = PtU_u(self.topo,self.quad,self.dX,u2).M.transpose() u1q = plot_u(u1, self.X, self.topo, self.topo_q, self.dX) u2q = plot_u(u2, self.X, self.topo, self.topo_q, self.dX) Mu1 = PtU_u(self.topo, self.quad, self.dX, u1q).M.transpose() Mu2 = PtU_u(self.topo, self.quad, self.dX, u2q).M.transpose() if self.linear: u1h1 = self.M0 * u1 u1h2 = self.M0 * u1 u2h1 = self.M0 * u2 u2h2 = self.M0 * u2 else: u1h1 = Mu1 * h1 u1h2 = Mu1 * h2 u2h1 = Mu2 * h1 u2h2 = Mu2 * h2 rhs = 2.0 * u1h1 + u1h2 + u2h1 + 2.0 * u2h2 rhs = (1.0 / 6.0) * rhs F = self.M0inv * rhs return F def diagnose_Phi(self, u1, u2, h1, h2): #Mu1 = PtU_u(self.topo,self.quad,self.dX,u1).M #Mu2 = PtU_u(self.topo,self.quad,self.dX,u2).M u1q = plot_u(u1, self.X, self.topo, self.topo_q, self.dX) u2q = plot_u(u2, self.X, self.topo, self.topo_q, self.dX) Mu1 = PtU_u(self.topo, self.quad, self.dX, u1q).M Mu2 = PtU_u(self.topo, self.quad, self.dX, u2q).M u1u1 = Mu1 * u1 u1u2 = Mu1 * u2 u2u2 = Mu2 * u2 rhs = u1u1 + u1u2 + u2u2 rhs = (1.0 / 6.0) * rhs gh = 0.5 * self.grav * self.M1 * (h1 + h2) rhs = rhs + gh if self.linear: Phi = self.M1inv * gh else: Phi = self.M1inv * rhs return Phi def residual_u(self, u1, u2, h1, h2): Fu = self.M0 * (u2 - u1) Phi = self.diagnose_Phi(u1, u2, h1, h2) dPhi = self.E01 * self.M1 * Phi Fu = Fu + self.dt * dPhi return Fu def residual_h(self, u1, u2, h1, h2): Fh = self.M1 * (h2 - h1) F = self.diagnose_F(u1, u2, h1, h2) dF = self.E10 * F MdF = self.M1 * dF Fh = Fh + self.dt * MdF return Fh def energy(self, u, h): uq = plot_u(u, self.X, self.topo, self.topo_q, self.dX) Mu = PtU_u(self.topo, self.quad, self.dX, uq).M u2 = Mu * u K = 0.5 * np.dot(h, u2) Mh = self.M1 * h P = 0.5 * self.grav * np.dot(h, Mh) return K + P def plot_eig_vals(self, u): uq = plot_u(u, self.X, self.topo, self.topo_q, self.dX) Mu = PtU_u(self.topo, self.quad, self.dX, uq).M.transpose() L = self.M1 + 0.5 * self.dt * self.M1 * self.E10 * self.M0inv * Mu R = self.M1 - 0.5 * self.dt * self.M1 * self.E10 * self.M0inv * Mu Linv = la.inv(L) A = Linv * R w, v = la.eigs(A, k=len(u) - 2) xx = np.linspace(0.0, 1.0, 1000000) plt.plot(xx, np.sqrt(1.0 - xx * xx), c='k') plt.plot(xx, -np.sqrt(1.0 - xx * xx), c='k') plt.xlim([1.0 - 0.00003, 1.0 + 0.00001]) plt.ylim([-0.003, 0.003]) plt.plot(w.real, w.imag, 'o') plt.show() def solve(self, u1, h1): it = 0 u2 = np.zeros(self.topo.nx * self.topo.n) h2 = np.zeros(self.topo.nx * self.topo.n) u2[:] = u1[:] h2[:] = h1[:] # begin newton iteration done = False while not done: Fu = self.residual_u(u1, u2, h1, h2) Fh = self.residual_h(u1, u2, h1, h2) rhs = self.DM0inv * Fu - Fh dh = self.HELMinv * rhs du = -1.0 * (self.M0invG * dh + self.M0inv * Fu) h2 = h2 + dh u2 = u2 + du # check the error dusq = np.dot(du, du) usq = np.dot(u2, u2) err_u = np.sqrt(dusq / usq) dhsq = np.dot(dh, dh) hsq = np.dot(h2, h2) err_h = np.sqrt(dhsq / hsq) print( str(it) + '\t|du|/|u|: ' + str(err_u) + '\t|dh|/|h|: ' + str(err_h)) it = it + 1 if err_u < 1.0e-12 and err_h < 1.0e-12: done = True u1[:] = u2[:] h1[:] = h2[:] return def solve_rk2(self, u1, h1): F1 = self.diagnose_F(u1, u1, h1, h1) Phi1 = self.diagnose_Phi(u1, u1, h1, h1) uh = u1 - self.dt * self.M0inv * self.E01 * self.M1 * Phi1 hh = h1 - self.dt * self.E10 * F1 F2 = self.diagnose_F(u1, uh, h1, hh) Phi2 = self.diagnose_Phi(u1, uh, h1, hh) u2 = u1 - self.dt * self.M0inv * self.E01 * self.M1 * Phi2 h2 = h1 - self.dt * self.E10 * F2 u1[:] = u2[:] h1[:] = h2[:] return def solve_imex(self, u1, h1): u2 = np.zeros(self.topo.nx * self.topo.n) up = np.zeros(self.topo.nx * self.topo.n) h2 = np.zeros(self.topo.nx * self.topo.n) # compute the provisional velocity Phi1 = self.diagnose_Phi(u1, u1, h1, h1) up = u1 - self.dt * self.grav * self.M0inv * self.E01 * self.M1 * Phi1 # continuity rhs u1q = plot_u(u1, self.X, self.topo, self.topo_q, self.dX) upq = plot_u(up, self.X, self.topo, self.topo_q, self.dX) Mu1 = PtU_u(self.topo, self.quad, self.dX, u1q).M.transpose() Mup = PtU_u(self.topo, self.quad, self.dX, upq).M.transpose() u1h1 = Mu1 * h1 uph1 = Mup * h1 F1 = (1.0 / 6.0) * self.M0inv * (2.0 * u1h1 + uph1) rhs = self.M1 * (h1 - self.dt * self.E10 * F1) # continuity lhs Mu = PtU_u(self.topo, self.quad, self.dX, (1.0 / 6.0) * (2.0 * upq + u1q)).M.transpose() A = self.M1 + self.dt * self.M1 * self.E10 * self.M0inv * Mu Ainv = la.inv(A) h2 = Ainv * rhs #A1 = self.dt*self.M1*self.E10 #A2 = A1*self.M0inv_pseudo #A = self.M1 + A2*Mu #Ainv = np.linalg.inv(A) #h2 = np.matmul(Ainv,rhs).transpose() #print(h1.shape) #print(h2.shape) #print(Ainv.shape) # compute the final velocity Phi2 = self.diagnose_Phi(u1, up, h1, h2) u2 = u1 - self.dt * self.grav * self.M0inv * self.E01 * self.M1 * Phi2 # compute the constraint #F2 = self.diagnose_F(u1,up,h1,h2); #uc = self.M0*F2 #Mu1 = PtU_u(self.topo,self.quad,self.dX,u1q).M.transpose() #Mup = PtU_u(self.topo,self.quad,self.dX,upq).M.transpose() #uc = (1.0/6.0)*(2.0*Mu1*h1 + Mu1*h2 + Mup*h1 + 2.0*Mup*h2) #uo = np.zeros(self.topo.nx*self.topo.n) #J = self.dt*self.grav*self.E01*(Mu.transpose()) #u2 = self.gmres(self.M0,up,self.M0*u1-self.dt*self.grav*self.E01*self.M1*Phi2) #u2 = self.gmres_constrained(self.M0+J,up,self.M0*u1-self.dt*self.grav*self.E01*self.M1*Phi2+J*up,uc) #du = self.gmres_constrained(self.M0+J,uo,self.M0*(u1-up)-self.dt*self.grav*self.E01*self.M1*Phi2,uc) #du = self.gmres_constrained_2(self.M0+J,uo,self.M0*(u1-up)-self.dt*self.grav*self.E01*self.M1*Phi2,uc) #u2 = up + du u1[:] = u2[:] h1[:] = h2[:] return def solve_imex_2(self, u1, h1): u2 = np.zeros(self.topo.nx * self.topo.n) up = np.zeros(self.topo.nx * self.topo.n) h2 = np.zeros(self.topo.nx * self.topo.n) # compute the provisional velocity Phi1 = self.diagnose_Phi(u1, u1, h1, h1) up = u1 - self.dt * self.grav * self.M0inv * self.E01 * self.M1 * Phi1 # continuity equation u1q = plot_u(u1, self.X, self.topo, self.topo_q, self.dX) upq = plot_u(up, self.X, self.topo, self.topo_q, self.dX) Mu1 = PtU_u(self.topo, self.quad, self.dX, u1q).M.transpose() Mup = PtU_u(self.topo, self.quad, self.dX, upq).M.transpose() Fi = (1.0 / 6.0) * self.M0inv * (2.0 * Mu1 + Mup) * h1 A = self.M0 + (self.dt / 6.0) * (Mu1 + 2.0 * Mup) * self.E10 Ainv = la.inv(A) rhs = Mu1 * h1 + 2.0 * Mup * h1 - self.dt * (Mu1 * self.E10 * Fi + 2.0 * Mup * self.E10 * Fi) Fj = (1.0 / 6.0) * Ainv * rhs F2 = Fi + Fj h2 = h1 - self.dt * self.E10 * F2 Phi2 = self.diagnose_Phi(u1, up, h1, h2) u2 = u1 - self.dt * self.grav * self.M0inv * self.E01 * self.M1 * Phi2 u1[:] = u2[:] h1[:] = h2[:] return def gmres(self, A, x, b): max_size = 20 H = np.zeros((2, 1)) Q = np.zeros((max_size, len(x))) ro = b - A * x beta = np.linalg.norm(ro) Q[0, :] = ro / beta for kk in np.arange(max_size - 1) + 1: v = A * Q[kk - 1, :] for jj in np.arange(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] H[kk, kk - 1] = np.linalg.norm(v) Q[kk, :] = v / H[kk, kk - 1] # solve e = np.zeros(kk + 1) e[0] = beta y = np.linalg.lstsq(H, e, rcond=None)[0] res = np.matmul(H, y) - e err = np.linalg.norm(res) print(str(kk) + ':\terr: ' + str(err)) if err < 1.0e-16: break # resize the hessenberg Htmp = H H = np.zeros((kk + 2, kk + 1)) H[:kk + 1, :kk] = Htmp # build the solution return x + np.matmul(Q[:kk, :].transpose(), y) # constrained gmres iteration # A: linear operator # x: initial guess and solution # b: right hand side # c: constraint def gmres_constrained(self, A, x, b, c): max_size = 20 H = np.zeros((2, 1)) Q = np.zeros((max_size, len(x))) c2inv = 1.0 / np.dot(c, c) #print('c2inv: ' + str(c2inv)) ro = b - A * x # orthogonalise with respect to c #ro = ro - c2inv*np.dot(ro,c)*c #print('\torthoganalising w.r.t. c: ' + str(np.dot(ro,c))) beta = np.linalg.norm(ro) Q[0, :] = ro / beta for kk in np.arange(max_size - 1) + 1: v = A * Q[kk - 1, :] for jj in np.arange(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] # orthogonalise with respect to c #v = v - c2inv*np.dot(v,c)*c #print(str(kk) + '\torthoganalising w.r.t. c: ' + str(np.dot(v,c))) H[kk, kk - 1] = np.linalg.norm(v) Q[kk, :] = v / H[kk, kk - 1] #print(str(kk) + '\torthoganalising w.r.t. c: ' + str(np.dot(Q[kk,:],c))) #print('GMRES iteration: ' + str(kk)) #print(H) # solve e = np.zeros(kk + 1) e[0] = beta y = np.linalg.lstsq(H, e, rcond=None)[0] res = np.matmul(H, y) - e err = np.linalg.norm(res) print(str(kk) + ':\terr: ' + str(err)) if err < 1.0e-16: break # resize the hessenberg Htmp = H H = np.zeros((kk + 2, kk + 1)) H[:kk + 1, :kk] = Htmp # build the solution xi = np.matmul(Q[:kk, :].transpose(), y) xi = xi - c2inv * np.dot(xi, c) * c print(str(kk) + '\torthoganalising w.r.t. c: ' + str(np.dot(xi, c))) return x + xi def gmres_constrained_2(self, A, x, b, c): max_size = 20 H = np.zeros((2, 1)) Q = np.zeros((max_size, len(x))) du = np.zeros(len(x)) ro = b - A * x beta = np.linalg.norm(ro) Q[0, :] = ro / beta for kk in np.arange(max_size - 1) + 1: v = A * Q[kk - 1, :] for jj in np.arange(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] H[kk, kk - 1] = np.linalg.norm(v) Q[kk, :] = v / H[kk, kk - 1] # solve e = np.zeros(kk + 1) e[0] = beta #y = np.linalg.lstsq(H, e, rcond=None)[0] y = self.solve_lsq(H, Q, e, c, du) res = np.matmul(H, y) - e err = np.linalg.norm(res) print(str(kk) + ':\terr: ' + str(err)) du = np.matmul(Q[:kk, :].transpose(), y) if err < 1.0e-16: break # resize the hessenberg Htmp = H H = np.zeros((kk + 2, kk + 1)) H[:kk + 1, :kk] = Htmp # build the solution #y = self.solve_lsq(H, Q, e, c, du) #du = np.matmul(Q[:kk,:].transpose(),y) return x + du def solve_lsq(self, H, Q, e, V, du): kp1, kk = H.shape HT = H.transpose() HTH = np.matmul(HT, H) QV = np.matmul(Q[:kk, :], V) A = np.zeros((kp1, kp1)) A[:kk, :kk] = HTH A[kk, :kk] = QV A[:kk, kk] = QV b = np.zeros(kp1) b[:kk] = np.matmul(HT, e) b[kk] = -1.0 * np.dot(V, du) Ainv = np.linalg.inv(A) y = np.matmul(Ainv, b) return y[:kk]
class HPEqn: def __init__(self,topo,quad,topo_q,lx,R,cp,eta_f,eta_h,Aeta,Beta,po,ps): self.topo = topo self.quad = quad self.topo_q = topo_q # topology for the quadrature points as 0 forms self.edge = LagrangeEdge(topo.n) self.R = R self.cp = cp self.eta_f = eta_f # mass based vertical height at full levels self.eta_h = eta_h # mass based vertical height at half levels self.Aeta = Aeta # self.Beta = Beta det = 0.5*lx/topo.nx self.detInv = 1.0/det self.po = po # reference pressure (constant) self.ps = ps # surface pressure # layer thickness with respect to the generalised vertical coordiante, eta self.dEta = np.zeros((self.eta_h.shape[0]),dtype=np.float64) for k in np.arange(self.eta_h.shape[0]): self.dEta[k] = self.eta_f[k+1] - self.eta_f[k]; # pseudo-density (vertical pressure gradient) within the layer self.pi = np.zeros((self.eta_h.shape[0],topo.nx*topo.n),dtype=np.float64) # 1 form matrix inverse self.M1 = Pmat(topo,quad).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo,quad).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.D10 = BoundaryMat(topo).M self.D01 = self.D10.transpose() # 0 form to 1 from gradient operator #self.A = self.detInv*self.D10 # 1 form to 0 form gradient operator #self.B = -1.0*self.detInv*self.M0inv*self.D01*self.M1 self.B = -1.0*self.M0inv*self.D01*self.M1 # diagnose the layer density as the vertical derivative of the pressure def diag_pi(eta, pres): pi = np.zeros((pres.shape[0]-1,pres.shape[1]),dtype=np.float64) for k in np.arange(pres.shape[0] - 1): for i in np.arange(pres.shape[1]): pi[k,i] = (pres[k+1,i] - pres[k,i])/self.dEta[k] return pi # diagnose the mass flux field in each layer def diag_F(pi, vel): F = np.zeros(vel.shape,dtype=np.float64) for k in np.arange(pi.shape[0]): A = U_pi_mat(self.topo,self.quad,self.edge,pi[k,:]).M Af = np.dot(A,vel[k,:]) F[k,:] = np.dot(self.M0inv,Af) return F # diagnose the pressure via the surface pressure def diag_p(pi, vel, pres): F = self.diag_F(pi, vel) # compute the surface pressure time derivative dps = np.zeros((pi.shape[1]),dtype=np.float64) for k in np.arange(pi.shape[0]): dFk = self.D10*F[k,:] for i in np.arange(pi.shape[1]): dps[i] = dps[i] + dFk[i]*self.dEta[k] # update the surface pressure self.ps = self.ps + dps # compute the pressure (skipping over the top level where # a rigid lid has been imposed) # TODO: does this need to be done in the weak form? for k = np.arange(pres.shape[0] - 1) + 1 pres[k,:] = self.Aeta[k]*self.po + self.Beta[k]*ps[:]
class SWEqn: def __init__(self, topo, quad, X, dX, dt, grav): self.topo = topo self.quad = quad self.X = X self.dX = dX self.dt = dt self.grav = grav self.linear = False self.topo_q = Topo(topo.nx, quad.n) # 1 form matrix inverse self.M1 = Pmat(topo, quad, dX).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad, dX).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.E10 = BoundaryMat(topo).M self.E01 = -1.0 * self.E10.transpose() self.PtQ = PtQmat(topo, quad, dX).M self.PtQT = PtQmat(topo, quad, dX).M.transpose() self.UtQ = UtQmat(topo, quad, dX).M self.UtQT = UtQmat(topo, quad, dX).M.transpose() # helmholtz operator GRAD = 0.5 * self.grav * self.dt * self.E01 * self.M1 DIV = 0.5 * self.dt * self.M1 * self.E10 HELM = self.M1 - DIV * self.M0inv * GRAD self.HELMinv = la.inv(HELM) self.DM0inv = DIV self.M0invG = self.M0inv * GRAD def assemble_J(self, u, h): uq = plot_u(u, self.X, self.topo, self.topo_q, self.dX) hq = plot_h(h, self.X, self.topo, self.topo_q, self.dX) PtU = PtU_u(self.topo, self.quad, self.dX, uq).M UtP = PtU.transpose() M0h = Uhmat(self.topo, self.quad, self.dX, hq).M Juu = self.M0 + 0.5 * self.dt * self.E01 * PtU Juh = 0.5 * self.dt * self.grav * self.E01 * self.M1 Jhu = 0.5 * self.dt * self.M1 * self.E10 * self.M0inv * M0h Jhh = self.M1 + 0.5 * self.dt * self.E10 * self.M0inv * UtP J = bmat([[Juu, Juh], [Jhu, Jhh]]) return J def diagnose_F(self, u1, u2, h1, h2): u1q = plot_u(u1, self.X, self.topo, self.topo_q, self.dX) u2q = plot_u(u2, self.X, self.topo, self.topo_q, self.dX) Mu1 = PtU_u(self.topo, self.quad, self.dX, u1q).M.transpose() Mu2 = PtU_u(self.topo, self.quad, self.dX, u2q).M.transpose() if self.linear: u1h1 = self.M0 * u1 u1h2 = self.M0 * u1 u2h1 = self.M0 * u2 u2h2 = self.M0 * u2 else: u1h1 = Mu1 * h1 u1h2 = Mu1 * h2 u2h1 = Mu2 * h1 u2h2 = Mu2 * h2 rhs = 2.0 * u1h1 + u1h2 + u2h1 + 2.0 * u2h2 rhs = (1.0 / 6.0) * rhs F = self.M0inv * rhs return F def diagnose_Phi(self, u1, u2, h1, h2): u1q = plot_u(u1, self.X, self.topo, self.topo_q, self.dX) u2q = plot_u(u2, self.X, self.topo, self.topo_q, self.dX) Mu1 = PtU_u(self.topo, self.quad, self.dX, u1q).M Mu2 = PtU_u(self.topo, self.quad, self.dX, u2q).M u1u1 = Mu1 * u1 u1u2 = Mu1 * u2 u2u2 = Mu2 * u2 rhs = u1u1 + u1u2 + u2u2 rhs = (1.0 / 6.0) * rhs gh = 0.5 * self.grav * self.M1 * (h1 + h2) rhs = rhs + gh if self.linear: Phi = self.M1inv * gh else: Phi = self.M1inv * rhs return Phi def residual_u(self, u1, u2, h1, h2): Fu = self.M0 * (u2 - u1) Phi = self.diagnose_Phi(u1, u2, h1, h2) dPhi = self.E01 * self.M1 * Phi Fu = Fu + self.dt * dPhi return Fu def residual_h(self, u1, u2, h1, h2): Fh = self.M1 * (h2 - h1) F = self.diagnose_F(u1, u2, h1, h2) dF = self.E10 * F MdF = self.M1 * dF Fh = Fh + self.dt * MdF return Fh def energy(self, u, h): uq = plot_u(u, self.X, self.topo, self.topo_q, self.dX) Mu = PtU_u(self.topo, self.quad, self.dX, uq).M u2 = Mu * u K = 0.5 * np.dot(h, u2) Mh = self.M1 * h P = 0.5 * self.grav * np.dot(h, Mh) return K + P def solve(self, u1, h1): it = 0 u2 = np.zeros(self.topo.nx * self.topo.n) h2 = np.zeros(self.topo.nx * self.topo.n) F = np.zeros(len(u2) + len(h2)) u2[:] = u1[:] h2[:] = h1[:] # begin newton iteration done = False while not done: Fu = self.residual_u(u1, u2, h1, h2) Fh = self.residual_h(u1, u2, h1, h2) F[:len(u2)] = Fu F[len(u2):] = Fh J = self.assemble_J(u2, h2) #Jinv = la.inv(J) #dU = Jinv*F #dU,info = la.gmres(J,F,tol=1.0e-12) dU = self.gmres(J, F) du = dU[:len(u2)] dh = dU[len(u2):] u2 = u2 - du h2 = h2 - dh # check the error dusq = np.dot(du, du) usq = np.dot(u2, u2) err_u = np.sqrt(dusq / usq) dhsq = np.dot(dh, dh) hsq = np.dot(h2, h2) err_h = np.sqrt(dhsq / hsq) print( str(it) + '\t|du|/|u|: ' + str(err_u) + '\t|dh|/|h|: ' + str(err_h)) it = it + 1 if it == 3: done = True if err_u < 1.0e-12 and err_h < 1.0e-12: done = True u1[:] = u2[:] h1[:] = h2[:] return def solve_c(self, u1, h1): it = 0 u2 = np.zeros(self.topo.nx * self.topo.n) h2 = np.zeros(self.topo.nx * self.topo.n) F = np.zeros(len(u2) + len(h2)) u2[:] = u1[:] h2[:] = h1[:] # begin newton iteration done = False while not done: Fu = -1.0 * self.residual_u(u1, u2, h1, h2) Fh = -1.0 * self.residual_h(u1, u2, h1, h2) F[:len(u2)] = Fu F[len(u2):] = Fh J = self.assemble_J(u2, h2) if it == 2: dHu = self.diagnose_F(u1, u2, h1, h2) dHh = self.diagnose_Phi(u1, u2, h1, h2) MdH = np.zeros(len(F)) MdH[:len(u2)] = self.M0 * dHu MdH[len(u2):] = self.M1 * dHh dU = self.gmres_c(J, F, MdH) #a=np.dot(dU,MdH) #print('projection error: ' + str(a)) else: dU = self.gmres(J, F) du = dU[:len(u2)] dh = dU[len(u2):] u2 = u2 + du h2 = h2 + dh # check the error dusq = np.dot(du, du) usq = np.dot(u2, u2) err_u = np.sqrt(dusq / usq) dhsq = np.dot(dh, dh) hsq = np.dot(h2, h2) err_h = np.sqrt(dhsq / hsq) print( str(it) + '\t|du|/|u|: ' + str(err_u) + '\t|dh|/|h|: ' + str(err_h)) it = it + 1 if it == 3: done = True if err_u < 1.0e-12 and err_h < 1.0e-12: done = True u1[:] = u2[:] h1[:] = h2[:] return def gmres(self, A, b): max_size = 200 eps = 1.0e-12 H = np.zeros((max_size + 1, max_size)) Q = np.zeros((max_size + 1, len(b))) ro = b # - A*x beta = np.linalg.norm(ro, 2) Q[0, :] = ro / beta for kk in range(1, max_size + 1): v = A * Q[kk - 1, :] for jj in range(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] H[kk, kk - 1] = np.linalg.norm(v, 2) if H[kk, kk - 1] > eps: Q[kk, :] = v / H[kk, kk - 1] else: break # solve e = np.zeros(kk + 1) e[0] = beta H = H[:kk + 1, :kk] #y = np.linalg.lstsq(H, e, rcond=None)[0] y = np.linalg.lstsq(H, e)[0] res = np.matmul(H, y) - e err = np.linalg.norm(res, 2) # if err < 1.0e-16: # break # resize the hessenberg # Htmp = H # H = np.zeros((kk+2,kk+1)) # H[:kk+1,:kk] = Htmp # build the solution x = np.matmul(Q[:kk, :].transpose(), y) return x def gmres_c(self, A, b, c): max_size = 200 eps = 1.0e-12 H = np.zeros((max_size + 2, max_size)) Q = np.zeros((max_size + 2, len(b))) c_norm = c / np.linalg.norm(c, 2) c2inv = 1.0 / np.dot(c, c) ro = b beta = np.linalg.norm(ro, 2) #ro = ro - c2inv*np.dot(ro,c)*c #beta = np.linalg.norm(ro,2) Q[0, :] = ro / beta Q[0, :] = Q[0, :] - c2inv * np.dot(Q[0, :], c) * c for kk in range(1, max_size + 1): v = A * Q[kk - 1, :] #H[0,kk-1] = np.dot(c,v) #v = v - c2inv*H[0,kk-1]*c for jj in range(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] #H[jj+1,kk-1] = np.dot(Q[jj,:],v) #v = v - H[jj+1,kk-1]*Q[jj,:] #vc = np.dot(c,v) #v = v - vc*c #H[kk,kk-1] = np.dot(c,v) #v = v - c2inv*H[kk,kk-1]*c H[kk, kk - 1] = c2inv * np.dot(c, v) v = v - H[kk, kk - 1] * c H[kk + 1, kk - 1] = np.linalg.norm(v, 2) if H[kk + 1, kk - 1] > eps: Q[kk, :] = v / H[kk + 1, kk - 1] else: break # solve #print("gmres its: " + str(kk)) e = np.zeros(kk + 2) e[0] = beta H = H[:kk + 2, :kk] y = np.linalg.lstsq(H, e)[0] res = np.matmul(H, y) - e err = np.linalg.norm(res, 2) # build the solution x = np.matmul(Q[:kk, :].transpose(), y) #xc = c2inv*np.dot(x,c) #print('projection error: ' + str(xc)) return x # constrained gmres iteration # A: linear operator # x: initial guess and solution # b: right hand side # c: constraint def gmres_constrained(self, A, x, b, c): max_size = 20 H = np.zeros((2, 1)) Q = np.zeros((max_size, len(x))) c2inv = 1.0 / np.dot(c, c) #print('c2inv: ' + str(c2inv)) ro = b - A * x # orthogonalise with respect to c #ro = ro - c2inv*np.dot(ro,c)*c #print('\torthoganalising w.r.t. c: ' + str(np.dot(ro,c))) beta = np.linalg.norm(ro) Q[0, :] = ro / beta for kk in np.arange(max_size - 1) + 1: v = A * Q[kk - 1, :] for jj in np.arange(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] # orthogonalise with respect to c #v = v - c2inv*np.dot(v,c)*c #print(str(kk) + '\torthoganalising w.r.t. c: ' + str(np.dot(v,c))) H[kk, kk - 1] = np.linalg.norm(v) Q[kk, :] = v / H[kk, kk - 1] #print(str(kk) + '\torthoganalising w.r.t. c: ' + str(np.dot(Q[kk,:],c))) #print('GMRES iteration: ' + str(kk)) #print(H) # solve e = np.zeros(kk + 1) e[0] = beta y = np.linalg.lstsq(H, e, rcond=None)[0] res = np.matmul(H, y) - e err = np.linalg.norm(res) print(str(kk) + ':\terr: ' + str(err)) if err < 1.0e-16: break # resize the hessenberg Htmp = H H = np.zeros((kk + 2, kk + 1)) H[:kk + 1, :kk] = Htmp # build the solution xi = np.matmul(Q[:kk, :].transpose(), y) xi = xi - c2inv * np.dot(xi, c) * c print(str(kk) + '\torthoganalising w.r.t. c: ' + str(np.dot(xi, c))) return x + xi def gmres_constrained_2(self, A, x, b, c): max_size = 20 H = np.zeros((2, 1)) Q = np.zeros((max_size, len(x))) du = np.zeros(len(x)) ro = b - A * x beta = np.linalg.norm(ro) Q[0, :] = ro / beta for kk in np.arange(max_size - 1) + 1: v = A * Q[kk - 1, :] for jj in np.arange(kk): H[jj, kk - 1] = np.dot(Q[jj, :], v) v = v - H[jj, kk - 1] * Q[jj, :] H[kk, kk - 1] = np.linalg.norm(v) Q[kk, :] = v / H[kk, kk - 1] # solve e = np.zeros(kk + 1) e[0] = beta #y = np.linalg.lstsq(H, e, rcond=None)[0] y = self.solve_lsq(H, Q, e, c, du) res = np.matmul(H, y) - e err = np.linalg.norm(res) print(str(kk) + ':\terr: ' + str(err)) du = np.matmul(Q[:kk, :].transpose(), y) if err < 1.0e-16: break # resize the hessenberg Htmp = H H = np.zeros((kk + 2, kk + 1)) H[:kk + 1, :kk] = Htmp # build the solution #y = self.solve_lsq(H, Q, e, c, du) #du = np.matmul(Q[:kk,:].transpose(),y) return x + du def solve_lsq(self, H, Q, e, V, du): kp1, kk = H.shape HT = H.transpose() HTH = np.matmul(HT, H) QV = np.matmul(Q[:kk, :], V) A = np.zeros((kp1, kp1)) A[:kk, :kk] = HTH A[kk, :kk] = QV A[:kk, kk] = QV b = np.zeros(kp1) b[:kk] = np.matmul(HT, e) b[kk] = -1.0 * np.dot(V, du) Ainv = np.linalg.inv(A) y = np.matmul(Ainv, b) return y[:kk]
def __init__(self, topo, quad, dX, dt, vel): self.topo = topo self.quad = quad self.dX = dX self.dt = dt # 1 form matrix inverse self.M1 = Pmat(topo, quad, dX).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad, dX).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.E10 = BoundaryMat(topo).M self.E01 = self.E10.transpose() # <gamma,u.beta> self.M10 = PtU_u(topo, quad, dX, vel).M self.M01 = self.M10.transpose() # solution operators M1E10 = self.M1 * self.E10 M1E10M0inv = M1E10 * self.M0inv self.A = M1E10M0inv * self.M01 self.At = -1.0 * self.A.transpose() self.A2 = 0.5 * self.A + 0.5 * self.At # solution operators for the implicit solve self.L = self.M1 + 0.5 * dt * self.A2 self.R = self.M1 - 0.5 * dt * self.A2 self.Linv = la.inv(self.L) self.S = self.Linv * self.R # implicit solvers for the advective and material forms self.La = self.M1 + 0.5 * dt * self.A self.Ra = self.M1 - 0.5 * dt * self.A self.La_inv = la.inv(self.La) self.Sa = self.La_inv * self.Ra self.Lt = self.M1 + 0.5 * dt * self.At self.Rt = self.M1 - 0.5 * dt * self.At self.Lt_inv = la.inv(self.Lt) self.St = self.Lt_inv * self.Rt # upwinded form node = LagrangeNode(topo.n, quad.n) for i in np.arange(node.m + 1): for j in np.arange(node.n + 1): node.M_ij_u[i, j] = node.eval( node.quad.x[i] + dt * vel[0] * (2.0 / dX[0]), node.quad.x, j) node.M_ij_d[i, j] = node.eval( node.quad.x[i] - dt * vel[0] * (2.0 / dX[0]), node.quad.x, j) edge = LagrangeEdge(topo.n, quad.n) edge.M_ij_u = np.zeros((edge.m + 1, edge.n), dtype=np.float64) for i in np.arange(edge.m + 1): for j in np.arange(edge.n): for k in np.arange(j + 1): edge.M_ij_u[i, j] = edge.M_ij_u[i, j] - edge.node.eval_deriv( edge.node.quad.x[i] + dt * vel[0] * (2.0 / dX[0]), edge.node.quad.x, k) edge.M_ij_d[i, j] = edge.M_ij_u[i, j] - edge.node.eval_deriv( edge.node.quad.x[i] - dt * vel[0] * (2.0 / dX[0]), edge.node.quad.x, k) # flux form M1_c_c = Pmat_up(topo, quad, dX, edge.M_ij_c, edge.M_ij_c).M M0_u_c = Umat_up_2(topo, quad, dX, vel, node, dt).M M0_u_c_inv = la.inv(M0_u_c) M01_up2 = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, +1.0).M A_up2 = M1_c_c * self.E10 * M0_u_c_inv * M01_up2 # mass conserving # material form M0_d_c = Umat_up(topo, quad, dX, node.M_ij_d, node.M_ij_c).M M0_d_c_inv = la.inv(M0_d_c) M01_up2 = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, -1.0).M A_up2_T = M1_c_c * self.E10 * M0_d_c_inv * M01_up2 # mass conserving A_dep = -1.0 * A_up2_T.transpose() L = M1_c_c + 0.5 * dt * (A_dep) # smoother solution #L = M1_c_c + 0.25*dt*(A_dep - A_dep.transpose()) # energy conserving L_inv = la.inv(L) R = M1_c_c - 0.5 * dt * (A_dep) # smoother solution #R = M1_c_c - 0.25*dt*(A_dep - A_dep.transpose()) # energy conserving self.Q_up = L_inv * R L = M1_c_c + 0.5 * dt * (A_up2) # smoother solution #L = M1_c_c + 0.25*dt*(A_up2 - A_up2.transpose()) # energy conserving L_inv = la.inv(L) R = M1_c_c - 0.5 * dt * (A_up2) # smoother solution #R = M1_c_c - 0.25*dt*(A_up2 - A_up2.transpose()) # energy conserving self.Q_up_2 = L_inv * R self.A_upw = self.M1inv * A_up2 self.A_cen = self.M1inv * self.A self.A_up2 = self.M1inv * A_dep # for the convergence tests (F = qu) M1_c_c = Pmat_up(topo, quad, dX, edge.M_ij_c, edge.M_ij_c).M M1_c_u = Pmat_up(topo, quad, dX, edge.M_ij_c, edge.M_ij_u).M M0_c_c = Umat_up(topo, quad, dX, node.M_ij_c, node.M_ij_c).M M0_u_c = Umat_up_2(topo, quad, dX, vel, node, dt).M M0_c_u = Umat_up(topo, quad, dX, node.M_ij_c, node.M_ij_u).M M0_u_u = Umat_up(topo, quad, dX, node.M_ij_u, node.M_ij_u).M M0_c_c_inv = la.inv(M0_c_c) M0_u_c_inv = la.inv(M0_u_c) M0_c_u_inv = la.inv(M0_c_u) M0_u_u_inv = la.inv(M0_u_u) M01_arr = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, +0.0).M M01_up2 = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, +1.0).M self.B = M0_c_c_inv * M01_arr self.B_up2 = M0_u_c_inv * M01_up2 # for the convergence test (u.GRAD p) self.C = -1.0 * self.M1inv * (self.B.transpose()) * self.E01 * self.M1 M01_dwn = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, -1.0).M M01_dwn_T = M01_dwn.transpose() M0_d_c = Umat_up_2(topo, quad, dX, vel, node, -dt).M M0_d_c_T = M0_d_c.transpose() M0_d_c_T_inv = la.inv(M0_d_c_T) self.C_up2 = -1.0 * self.M1inv * M01_dwn_T * M0_d_c_T_inv * self.E01 * self.M1
class AdvEqn: def __init__(self, topo, quad, dX, dt, vel): self.topo = topo self.quad = quad self.dX = dX self.dt = dt # 1 form matrix inverse self.M1 = Pmat(topo, quad, dX).M self.M1inv = la.inv(self.M1) # 0 form matrix inverse self.M0 = Umat(topo, quad, dX).M self.M0inv = la.inv(self.M0) # 1 form gradient matrix self.E10 = BoundaryMat(topo).M self.E01 = self.E10.transpose() # <gamma,u.beta> self.M10 = PtU_u(topo, quad, dX, vel).M self.M01 = self.M10.transpose() # solution operators M1E10 = self.M1 * self.E10 M1E10M0inv = M1E10 * self.M0inv self.A = M1E10M0inv * self.M01 self.At = -1.0 * self.A.transpose() self.A2 = 0.5 * self.A + 0.5 * self.At # solution operators for the implicit solve self.L = self.M1 + 0.5 * dt * self.A2 self.R = self.M1 - 0.5 * dt * self.A2 self.Linv = la.inv(self.L) self.S = self.Linv * self.R # implicit solvers for the advective and material forms self.La = self.M1 + 0.5 * dt * self.A self.Ra = self.M1 - 0.5 * dt * self.A self.La_inv = la.inv(self.La) self.Sa = self.La_inv * self.Ra self.Lt = self.M1 + 0.5 * dt * self.At self.Rt = self.M1 - 0.5 * dt * self.At self.Lt_inv = la.inv(self.Lt) self.St = self.Lt_inv * self.Rt # upwinded form node = LagrangeNode(topo.n, quad.n) for i in np.arange(node.m + 1): for j in np.arange(node.n + 1): node.M_ij_u[i, j] = node.eval( node.quad.x[i] + dt * vel[0] * (2.0 / dX[0]), node.quad.x, j) node.M_ij_d[i, j] = node.eval( node.quad.x[i] - dt * vel[0] * (2.0 / dX[0]), node.quad.x, j) edge = LagrangeEdge(topo.n, quad.n) edge.M_ij_u = np.zeros((edge.m + 1, edge.n), dtype=np.float64) for i in np.arange(edge.m + 1): for j in np.arange(edge.n): for k in np.arange(j + 1): edge.M_ij_u[i, j] = edge.M_ij_u[i, j] - edge.node.eval_deriv( edge.node.quad.x[i] + dt * vel[0] * (2.0 / dX[0]), edge.node.quad.x, k) edge.M_ij_d[i, j] = edge.M_ij_u[i, j] - edge.node.eval_deriv( edge.node.quad.x[i] - dt * vel[0] * (2.0 / dX[0]), edge.node.quad.x, k) # flux form M1_c_c = Pmat_up(topo, quad, dX, edge.M_ij_c, edge.M_ij_c).M M0_u_c = Umat_up_2(topo, quad, dX, vel, node, dt).M M0_u_c_inv = la.inv(M0_u_c) M01_up2 = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, +1.0).M A_up2 = M1_c_c * self.E10 * M0_u_c_inv * M01_up2 # mass conserving # material form M0_d_c = Umat_up(topo, quad, dX, node.M_ij_d, node.M_ij_c).M M0_d_c_inv = la.inv(M0_d_c) M01_up2 = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, -1.0).M A_up2_T = M1_c_c * self.E10 * M0_d_c_inv * M01_up2 # mass conserving A_dep = -1.0 * A_up2_T.transpose() L = M1_c_c + 0.5 * dt * (A_dep) # smoother solution #L = M1_c_c + 0.25*dt*(A_dep - A_dep.transpose()) # energy conserving L_inv = la.inv(L) R = M1_c_c - 0.5 * dt * (A_dep) # smoother solution #R = M1_c_c - 0.25*dt*(A_dep - A_dep.transpose()) # energy conserving self.Q_up = L_inv * R L = M1_c_c + 0.5 * dt * (A_up2) # smoother solution #L = M1_c_c + 0.25*dt*(A_up2 - A_up2.transpose()) # energy conserving L_inv = la.inv(L) R = M1_c_c - 0.5 * dt * (A_up2) # smoother solution #R = M1_c_c - 0.25*dt*(A_up2 - A_up2.transpose()) # energy conserving self.Q_up_2 = L_inv * R self.A_upw = self.M1inv * A_up2 self.A_cen = self.M1inv * self.A self.A_up2 = self.M1inv * A_dep # for the convergence tests (F = qu) M1_c_c = Pmat_up(topo, quad, dX, edge.M_ij_c, edge.M_ij_c).M M1_c_u = Pmat_up(topo, quad, dX, edge.M_ij_c, edge.M_ij_u).M M0_c_c = Umat_up(topo, quad, dX, node.M_ij_c, node.M_ij_c).M M0_u_c = Umat_up_2(topo, quad, dX, vel, node, dt).M M0_c_u = Umat_up(topo, quad, dX, node.M_ij_c, node.M_ij_u).M M0_u_u = Umat_up(topo, quad, dX, node.M_ij_u, node.M_ij_u).M M0_c_c_inv = la.inv(M0_c_c) M0_u_c_inv = la.inv(M0_u_c) M0_c_u_inv = la.inv(M0_c_u) M0_u_u_inv = la.inv(M0_u_u) M01_arr = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, +0.0).M M01_up2 = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, +1.0).M self.B = M0_c_c_inv * M01_arr self.B_up2 = M0_u_c_inv * M01_up2 # for the convergence test (u.GRAD p) self.C = -1.0 * self.M1inv * (self.B.transpose()) * self.E01 * self.M1 M01_dwn = U_u_TP_up_2(topo, quad, dX, vel, node, edge, dt, -1.0).M M01_dwn_T = M01_dwn.transpose() M0_d_c = Umat_up_2(topo, quad, dX, vel, node, -dt).M M0_d_c_T = M0_d_c.transpose() M0_d_c_T_inv = la.inv(M0_d_c_T) self.C_up2 = -1.0 * self.M1inv * M01_dwn_T * M0_d_c_T_inv * self.E01 * self.M1 def solve_a(self, hi): #return self.St*hi return self.Sa * hi def solve_a_up(self, hi): #return self.Q_up*hi return self.Q_up_2 * hi def solve_2(self, hi): #return self.Q_up_2*hi return self.Q_up * hi def disp_rel(self, AA, do_real): quad = self.quad nx = len(self.dX) * quad.n x = np.zeros(nx) for ii in np.arange(len(self.dX)): x[ii * quad.n:ii * quad.n + quad.n] = ii * self.dX[0] + self.dX[0] * 0.5 * (quad.x[:quad.n] + 1) xx = 2.0 * np.pi * x kk = 1.0 * (np.arange(nx) - nx / 2 + 1) x2 = (2.0 * np.pi / nx) * np.arange(nx) F = np.zeros((nx, nx), dtype=np.complex128) for ii in np.arange(nx): for jj in np.arange(nx): F[ii, jj] = np.exp(1.0j * kk[jj] * xx[ii]) Finv = np.linalg.inv(F) node = LagrangeNode(self.topo.n, self.quad.n) edge = LagrangeEdge(self.topo.n, self.quad.n) QP = P_interp(self.topo, self.quad, self.dX, node, edge).M PQ = PtQmat(self.topo, self.quad, self.dX).M P2F = Finv * QP II = np.zeros((nx, nx), dtype=np.complex128) np.fill_diagonal(II, +1.0) vals, vecs = la.eigs(AA, M=II, k=nx - 2) if do_real: vr = vals.real vecr = vecs.real else: vr = vals.imag vecr = vecs.imag inds = np.argsort(vr)[::-1] vr2 = vr[inds] vecr2 = vecr[:, inds] ki = np.zeros((nx - 2, 8), dtype=np.int32) for ii in np.arange(nx - 2): vf = np.dot(P2F, vecr2[:, ii]) inds = np.argsort(np.abs(vf))[::-1] ki[ii] = np.abs(kk[inds[0]]) return ki, vr2