def __init__(self, cfg, **kwargs): super().__init__(cfg, **kwargs) # number of quadrature points inside each element self._Nq = self._K # the Gauss-Lobatto quadrature on standard interval self._z, self._w = zwglj(self._Nq, 0., 0.) # define the lagrange nodal basis self._B = nodal_basis_at(self._K, self._z, self._z).T # define the mass matrix # since the basis is identity, this just have weights on diagonal self._M = np.einsum("mq,q,lq->ml", self._B, self._w, self._B) self._invM = np.linalg.inv(self._M) # Forward transform operator self._fwdTransMat = self._B # identity # interpolation operator Nqr = self.cfg.lookupint(basissect, 'Nqr') #zr = np.linspace(-1., 1., Nqr) # the reconstruction points zr, _ = zwglj(Nqr, 0., 0.) # the reconstruction points Br = nodal_basis_at(self._K, self._z, zr).T # at "recons" points #self._interpMat = np.einsum('kr,kq->rq', Br, self._fwdTransMat) self._interpMat = Br # the H tensor (see J. Comput. Phys. 378, 178-208, 2019) H = np.einsum("mq,aq,bq,q->mab", self._B, self._B, self._B, self._w) invM_H = np.einsum("ml,mab->lab", self._invM, H) invM_H = H # svd decomposition # defines the U, V matrices, and identifies the significant modes U, V, sigModes = [0] * self._K, [0] * self._K, [0] * self._K for m in range(self._K): u, s, v = np.linalg.svd(invM_H[m, :, :]) U[m], V[m] = u, np.dot(np.diag(s), v) U[m], V[m] = map(filter_tol, (U[m], V[m])) nnzUm = np.where(np.sum(U[m], axis=0) != 0)[0] nnzVm = np.where(np.sum(V[m], axis=1) != 0)[0] sigModes[m] = np.intersect1d(nnzUm, nnzVm) self._U, self._V, self._sigModes = U, V, sigModes # define the {K-1} order derivative matrix D = jac_nodal_basis_at(self._K, self._z, self._z)[0] self._Sx = np.matmul(self._M, D.T).T self._derivMat = self._Sx.T # define the operator for reconstructing solution at faces self._Nqf = 2 # number of points used in reconstruction at faces zqf, _ = zwglj(self._Nqf, 0., 0.) self._Bqf = nodal_basis_at(self._K, self._z, zqf).T # define the correction functions at the left and right boundaries self._gLD = self._Bqf[:, 0] #/self._w[0] self._gRD = self._Bqf[:, -1] #/self._w[-1] #gLD, gRD = invM[0,:], invM[-1,:] # prepare kernels # since B is identity, (fwdTrans, bwdTrans) just copy data self._fwdTransKern = get_mm_kernel(self._fwdTransMat) self._bwdTransKern = get_mm_kernel(self._B.T) self._bwdTransFaceKern = get_mm_kernel(self._Bqf.T) self._derivKern = get_mm_kernel(self._Sx.T) self._invMKern = get_mm_kernel(self._invM.T) # U, V operator kernels for m in range(self._K): self._uTransKerns[m] = get_mm_kernel(self._U[m].T) self._vTransKerns[m] = get_mm_kernel(self._V[m]) # operators for limiting V = ortho_basis_at(self._K, self._z).T invV = np.linalg.inv(V) computeCellAvgOp = V.copy() computeCellAvgOp[:, 1:] = 0 computeCellAvgOp = np.matmul(computeCellAvgOp, invV) extractLinOp = V.copy() extractLinOp[:, 2:] = 0 extractLinOp = np.matmul(extractLinOp, invV) extractDrLinOp = np.matmul(D.T, extractLinOp) self.computeCellAvgKern, self.extractDrLinKern = map( get_mm_kernel, (computeCellAvgOp, extractDrLinOp))
def __init__(self, cfg, **kwargs): super().__init__(cfg, **kwargs) # number of quadrature points inside each element self._Nq = self.cfg.lookupordefault(basissect, 'Nq', np.int(np.ceil(1.5 * self._K))) # define the orthonormal basis # the Gauss quadrature on standard interval self._z, self._w = zwgrjm(self._Nq, 0., 0.) # define the modified basis (see Karniadakis, page 64) self._B = self.modified_basis_at(self._K, self._z) # define the mass matrix self._M = np.einsum("mq,q,lq->ml", self._B, self._w, self._B) self._invM = np.linalg.inv(self._M) # Forward transform operator self._fwdTransMat = np.einsum("ml,lq,q->mq", self._invM, self._B, self._w) # interpolation operator Nqr = self.cfg.lookupint(basissect, 'Nqr') zr = np.linspace(-1, 1, Nqr) # the reconstruction points Br = self.modified_basis_at(self._K, zr) # basis at reconst points self._interpMat = Br # the H tensor (see J. Comput. Phys. 378, 178-208, 2019) H = np.einsum("mq,aq,bq,q->mab", self._B, self._B, self._B, self._w) invM_H = np.einsum("ml,mab->lab", self._invM, H) # svd decomposition # defines the U, V matrices, and identifies the significant modes U, V, sigModes = [0] * self._K, [0] * self._K, [0] * self._K for m in range(self._K): u, s, v = np.linalg.svd(H[m, :, :]) U[m], V[m] = u, np.dot(np.diag(s), v) U[m], V[m] = map(filter_tol, (U[m], V[m])) nnzUm = np.where(np.sum(U[m], axis=0) != 0)[0] nnzVm = np.where(np.sum(V[m], axis=1) != 0)[0] sigModes[m] = np.intersect1d(nnzUm, nnzVm) self._U, self._V, self._sigModes = U, V, sigModes # define the {K-1} order derivative matrix D = self.jac_modified_basis_at(self._K, self._z) self._Sx = np.einsum("lq,q,mq->ml", self._B, self._w, D) #self._Sx = np.einsum("ml,mn->ln", self._invM, self._Sx) #self._Sx = np.einsum("lm,mn->ln", self._invM, self._Sx) # define the operator for reconstructing solution at faces self._Nqf = 2 # number of points used in reconstruction at faces zqf, _ = zwglj(self._Nqf, 0., 0.) self._Bqf = self.modified_basis_at(self._K, zqf) #self._gBqf = np.einsum("ml,mn->ln", self._invM, self._Bqf) # define the correction functions at the left and right boundaries #self._gLD, self._gRD = self._gBqf[:,0], self._gBqf[:,-1] self._gLD, self._gRD = self._Bqf[:, 0], self._Bqf[:, -1] # prepare kernels self._fwdTransKern = get_mm_kernel(self._fwdTransMat) self._bwdTransKern = get_mm_kernel(self._B.T) self._bwdTransFaceKern = get_mm_kernel(self._Bqf.T) self._derivKern = get_mm_kernel(self._Sx.T) self._invMKern = get_mm_kernel(self._invM.T) # U, V operator kernels for m in range(self._K): self._uTransKerns[m] = get_mm_kernel(self._U[m].T) self._vTransKerns[m] = get_mm_kernel(self._V[m])