def SolveProblem(order=order, refines=refines): # load mesh from file for i in range(refines): t0 = timeit.time() mesh = MakeStructured2DMesh(quads=False, nx=8 * 2**i, ny=8 * 2**i) t1 = timeit.time() # C0-HDG FESpaces VT = H1(mesh, order=order + 1, dirichlet=".*") if bc == "clamped": # clamped bc VF = TangentialFacetFESpace(mesh, order=order - 1, dirichlet=".*") # with bdry condition else: VF = TangentialFacetFESpace(mesh, order=order - 1) # no bdry condition V = FESpace([VT, VF]) gfu = GridFunction(V) (xi, uhat), (zeta, vhat) = V.TnT() n = specialcf.normal(2) h = specialcf.mesh_size def tang(v): return v - (v * n) * n u = CoefficientFunction((grad(xi)[1], -grad(xi)[0])) v = CoefficientFunction((grad(zeta)[1], -grad(zeta)[0])) hess_zeta = zeta.Operator("hesse") # gradient by row gradv = CoefficientFunction( ((hess_zeta[1], hess_zeta[3]), (-hess_zeta[0], -hess_zeta[1])), dims=(2, 2)) hess_xi = xi.Operator("hesse") gradu = CoefficientFunction( ((hess_xi[1], hess_xi[3]), (-hess_xi[0], -hess_xi[1])), dims=(2, 2)) f = LinearForm(V) f += zeta * dx a = BilinearForm(V, condense=True, symmetric=True) lap = tau * u * v bilap = InnerProduct(gradu, gradv) bilap_BND = -(gradu * n * tang(v - vhat) + gradv * n * tang(u - uhat) - 4 * (order + 1)**2 / h * tang(u - uhat) * tang(v - vhat)) ir = IntegrationRule(SEGM, 2 * order - 1) a += (lap + bilap) * dx a += bilap_BND * dx(element_boundary=True, intrules={SEGM: ir}) ########### ASP 1: C0--> HDiv ########### ASP 1: C0--> HDiv ########### ASP 1: C0--> HDiv # two grid (Hdiv-HDG) VT1 = HDiv(mesh, order=order, hodivfree=True, dirichlet='.*') V1 = FESpace([VT1, VF]) (u1, uhat1), (v1, vhat1) = V1.TnT() # Mapping HDiv--> H1 mixmass = BilinearForm(trialspace=V1, testspace=V) # tangential part mixmass += u1 * v * dx # construct Pi-hat xiT, zetaT = VT.TnT() uT = CoefficientFunction((grad(xiT)[1], -grad(xiT)[0])) vT = CoefficientFunction((grad(zetaT)[1], -grad(zetaT)[0])) uhatT, vhatT = VF.TnT() # tangential part massfX = BilinearForm(VT, symmetric=True) massfX += uT * vT * dx massfY = BilinearForm(trialspace=VT, testspace=VF) massfY += -tang(uT) * tang(vhatT) * dx(element_boundary=True) massfZ = BilinearForm(VF) massfZ += tang(uhatT) * tang(vhatT) * dx(element_boundary=True) ############### DOFS splits for PROJECTOR embU = Embedding(V.ndof, V.Range(0)) embV = Embedding(V.ndof, V.Range(1)) a1 = BilinearForm(V1, condense=True) lap1 = tau * u1 * v1 gradu1 = Grad(u1) gradv1 = Grad(v1) bilap1 = InnerProduct(gradu1, gradv1) jmp_u1 = tang(u1 - uhat1) jmp_v1 = tang(v1 - vhat1) bilap_BND1 = -(gradu1 * n * jmp_v1 + gradv1 * n * jmp_u1 - 4 * (order + 1)**2 / h * jmp_u1 * jmp_v1) a1 += (lap1 + bilap1) * dx a1 += bilap_BND1 * dx(element_boundary=True, intrules={SEGM: ir}) ########### ASP 2: HDiv--> H1 ########### FIXME: weakly impose bdry condition if bc == "clamped": V0 = VectorH1(mesh, dirichlet=".*") else: V0 = VectorH1(mesh, dirichletx="left|right", dirichlety="top|bottom") u0, v0 = V0.TnT() a0 = BilinearForm(V0) a0 += (InnerProduct(Grad(u0), Grad(v0)) + tau * u0 * v0) * dx # Projection operator H1--> M mixmass0 = BilinearForm(trialspace=V0, testspace=V1) # tangential part mixmass0 += tang(u0) * tang(vhat1) * dx(element_boundary=True) mixmass0 += (u0 * n) * (v1 * n) * dx(element_boundary=True) massf0 = BilinearForm(V1) # tangential part massf0 += tang(uhat1) * tang(vhat1) * dx(element_boundary=True) massf0 += (u1 * n) * (v1 * n) * dx(element_boundary=True) def edgePatchBlocks(mesh, fes): blocks = [] freedofs = fes.FreeDofs(True) for e in mesh.edges: edofs = set() # get ALL dofs connected to the edge for el in mesh[e].elements: edofs |= set(d for d in fes.GetDofNrs(el) if freedofs[d]) blocks.append(edofs) return blocks eBlocks = edgePatchBlocks(mesh, V1) class SymmetricGS(BaseMatrix): def __init__(self, smoother): super(SymmetricGS, self).__init__() self.smoother = smoother def Mult(self, x, y): y[:] = 0.0 self.smoother.Smooth(y, x) self.smoother.SmoothBack(y, x) def Height(self): return self.smoother.height def Width(self): return self.smoother.height with TaskManager(): f.Assemble() a.Assemble() ######## ASP 1 mixmass.Assemble() massfX.Assemble() massfY.Assemble() massfZ.Assemble() ####### RK: PROJECTION (sparse cholesky factorization) imX = massfX.mat.Inverse(VT.FreeDofs(True), inverse="sparsecholesky") imZ = massfZ.mat.CreateSmoother(VF.FreeDofs(True)) m_inv = embU @ imX @ embU.T + embV @ imZ @embV.T \ - embV @ imZ @ massfY.mat @ imX @ embU.T m_invT = embU @ imX @ embU.T + embV @ imZ @embV.T \ - embU @ imX @ massfY.mat.T @ imZ @ embV.T E = m_inv @ mixmass.mat ET = mixmass.mat.T @ m_invT a1.Assemble() ## ASP 2 bjac = a1.mat.CreateBlockSmoother(eBlocks) bgs = SymmetricGS(bjac) mixmass0.Assemble() massf0.Assemble() m_inv0 = massf0.mat.CreateSmoother(V1.FreeDofs(True)) a0.Assemble() pm0 = ngs_petsc.PETScMatrix(a0.mat, V0.FreeDofs()) inva0 = ngs_petsc.PETSc2NGsPrecond( pm0, petsc_options={"pc_type": "hypre"}) E0 = m_inv0 @ mixmass0.mat # ASP for rd system pc_a1 = bgs + E0 @ inva0 @ E0.T # Direct solver for rd system pc_a2 = a1.mat.Inverse(V1.FreeDofs(True), inverse="sparsecholesky") pre1 = E @ pc_a1 @ ET pre2 = E @ pc_a2 @ ET inv1 = CGSolver(a.mat, pre1, maxsteps=5000, precision=1e-10, printrates=True) inv2 = CGSolver(a.mat, pre2, maxsteps=5000, precision=1e-10, printrates=True) f.vec.data += a.harmonic_extension_trans * f.vec # solver gfu.vec.data = inv1 * f.vec gfu.vec.data = inv2 * f.vec gfu.vec.data += a.harmonic_extension * gfu.vec gfu.vec.data += a.inner_solve * f.vec print("bc:%s tau0:%.0e tau1 %.0e ASP:%i EXA: %i" % (bc, tau0, tau1, inv1.GetSteps(), inv2.GetSteps()))
# # 2D Poisson, high order, using AMG + BDDC # from ngsolve import * import ngs_amg from ngsolve.krylovspace import CGSolver from amg_utils import * comm = mpi_world geo, mesh = gen_square(maxh=0.05, nref=0, comm=mpi_world) V, a, f = setup_poisson(mesh, order=4, diri="right") gfu = GridFunction(V) # Here we use the BDDC precodnitioner, and tell it to plug the coarse level matrix into AMG. pc_opts = {"ngs_amg_max_coarse_size": 5} c = Preconditioner(a, "bddc", coarsetype="ngs_amg.h1_scal", **pc_opts) with TaskManager(): a.Assemble() f.Assemble() cb = None if comm.rank != 0 else lambda k, x: print( "it =", k, ", err =", x) cg = CGSolver(mat=a.mat, pre=c, callback=cb, maxsteps=100, tol=1e-12) cg.Solve(sol=gfu.vec, rhs=f.vec) print("nits", cg.iterations)
def SolveProblem(order=order, refines=refines, condense=True, symmetric=False): for i in range(refines): t0 = timeit.time() mesh = MakeStructured3DMesh(hexes=False, nx=8 * 2**i, ny=8 * 2**i, nz=8 * 2**i) t1 = timeit.time() print("\nElasped:%.2e MESHING " % (t1 - t0)) # Div-HDG spaces V = HDiv(mesh, order=order, dirichlet=".*") if freeBC == True: M = TangentialFacetFESpace(mesh, order=order, highest_order_dc=True) # aux H1 space V0 = VectorH1(mesh, order=1, dirichlety="left|right", dirichletx="front|back", dirichletz="top|bottom") else: # dir bc M = TangentialFacetFESpace(mesh, order=order, highest_order_dc=True, dirichlet=".*") # aux H1 space V0 = VectorH1(mesh, order=1, dirichlet=".*") fes = FESpace([V, M]) gfu = GridFunction(fes) (u, uhat), (v, vhat) = fes.TnT() (u0, v0) = V0.TnT() # gradients gradv, gradu = Grad(v), Grad(u) # RHS (constant) f = LinearForm(fes) f += (v[0] + v[1] + v[2]) * dx # normal direction and mesh size n = specialcf.normal(mesh.dim) h = specialcf.mesh_size # stability parameter #alpha = 8*order**2/h alpha = 8 * order**2 / h # tangential component def tang(v): return v - (v * n) * n ########### HDG operator ah a = BilinearForm(fes, symmetric=True, condense=True) # volume term a += (D * InnerProduct(gradu, gradv) + tau * u * v) * dx # bdry terms a += D * (-gradu * n * tang(v - vhat) - gradv * n * tang(u - uhat) + alpha * tang(u - uhat) * tang(v - vhat)) * dx( element_boundary=True) ######## face path blocks for smoother def facePatchBlocks(mesh, fes): blocks = [] freedofs = fes.FreeDofs(True) for e in mesh.faces: edofs = set() # get ALL dofs connected to the face for el in mesh[e].elements: edofs |= set(d for d in fes.GetDofNrs(el) if freedofs[d]) blocks.append(edofs) return blocks def faceBlocks(mesh, fes): blocks = [] freedofs = fes.FreeDofs(True) for e in mesh.faces: edofs = set(d for d in fes.GetDofNrs(e) if freedofs[d]) blocks.append(edofs) return blocks ######## THIS IS MOST TIME CONSUMING PART fBlocks = facePatchBlocks(mesh, fes) fBlocks0 = faceBlocks(mesh, fes) t0 = timeit.time() # number of DOFS ntotal = fes.ndof nglobal = sum(fes.FreeDofs(True)) print("Elasped:%.2e BLOCKING Total DOFs: %.2e Global DOFs: %.2e " % (t0 - t1, ntotal, nglobal)) class SymmetricGS(BaseMatrix): def __init__(self, smoother): super(SymmetricGS, self).__init__() self.smoother = smoother def Mult(self, x, y): y[:] = 0.0 self.smoother.Smooth(y, x) self.smoother.SmoothBack(y, x) def Height(self): return self.smoother.height def Width(self): return self.smoother.height ########### ASP operator ah0 a0 = BilinearForm(V0, symmetric=True) a0 += (D * InnerProduct(Grad(u0), Grad(v0)) + tau * u0 * v0) * dx # Projection operator V0--> fes # We set up a mixed mass matrix for V0 -> fes and then solving with the mass matrix in M mixmass = BilinearForm(trialspace=V0, testspace=fes) # tangential part mixmass += tang(u0) * tang(vhat) * dx(element_boundary=True) # normal part mixmass += (u0 * n) * (v * n) * dx(element_boundary=True) massf = BilinearForm(fes) massf += tang(uhat) * tang(vhat) * dx(element_boundary=True) massf += (u * n) * (v * n) * dx(element_boundary=True) with TaskManager(): f.Assemble() a.Assemble() t1 = timeit.time() print("Elasped:%.2e ASSEMBLE " % (t1 - t0)) ######### smoother (use edge blocks) # smoother jac = a.mat.CreateSmoother(fes.FreeDofs(True)) bjac = a.mat.CreateBlockSmoother(fBlocks) ######## ASP a0.Assemble() pm = ngs_petsc.PETScMatrix(a0.mat, V0.FreeDofs()) inva0 = ngs_petsc.PETSc2NGsPrecond( pm, petsc_options={"pc_type": "hypre"}) massf.Assemble() mixmass.Assemble() # massf is block-diagonal in 3D!!!!!!!!! m_inv = massf.mat.CreateBlockSmoother(fBlocks0) E = m_inv @ mixmass.mat ET = mixmass.mat.T @ m_inv pre_twogrid = E @ inva0 @ ET # jacobi smoother pre1 = jac + pre_twogrid # block gs smoother pre2 = SymmetricGS(bjac) + pre_twogrid t2 = timeit.time() print("Elasped:%.2e PREC " % (t2 - t1)) inv1 = CGSolver(a.mat, pre1, maxsteps=10000, precision=1e-10, printrates=True) inv2 = CGSolver(a.mat, pre2, maxsteps=10000, precision=1e-10, printrates=True) f.vec.data += a.harmonic_extension_trans * f.vec # solver gfu.vec.data = inv1 * f.vec gfu.vec.data = inv2 * f.vec gfu.vec.data += a.harmonic_extension * gfu.vec gfu.vec.data += a.inner_solve * f.vec t3 = timeit.time() print("Elasped:%.2e SOLVE " % (t3 - t2)) print("JAC:%i BGS: %i" % (inv1.GetSteps(), inv2.GetSteps())) print("*****************************************************") print("*****************************************************") print("*****************************************************")
ngmesh = unit_cube.GenerateMesh(maxh=0.1).Distribute(comm) else: ngmesh = netgen.meshing.Mesh.Receive(comm) for l in range(0): ngmesh.Refine() mesh = Mesh(ngmesh) fes = H1(mesh, order=1) u, v = fes.TnT() a = BilinearForm(grad(u) * grad(v) * dx + u * v * ds).Assemble() f = LinearForm(x * v * dx).Assemble() gfu = GridFunction(fes) inv = CGSolver(a.mat, freedofs=fes.FreeDofs(), printing=False, maxsteps=400, tol=1e-8) gfu.vec.data = inv * f.vec masterprint("ngs-dot =", InnerProduct(gfu.vec, f.vec)) pardofs = fes.ParallelDofs() globnums, nglob = pardofs.EnumerateGlobally() locmat = a.mat.local_mat val, col, ind = locmat.CSR() ind = np.array(ind, dtype='int32') apsc_loc = psc.Mat().createAIJ(size=(locmat.height, locmat.width), csr=(ind, col, val), comm=MPI.COMM_SELF)