Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
	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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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):
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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]
Ejemplo n.º 11
0
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[:]
Ejemplo n.º 12
0
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]
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
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