def mfem_smoother(name, **kwargs): prc = kwargs.pop('prc') blockname = kwargs.pop('blockname') row = prc.get_row_by_name(blockname) col = prc.get_col_by_name(blockname) mat = prc.get_operator_block(row, col) if isinstance(mat, mfem.ComplexOperator): conv = mat.GetConvention() blockOffsets = mfem.intArray() blockOffsets.SetSize(3) blockOffsets[0] = 0 blockOffsets[1] = mat.Height() // 2 blockOffsets[2] = mat.Height() // 2 blockOffsets.PartialSum() smoother = mfem.BlockDiagonalPreconditioner(blockOffsets) m_r = mat._real_operator #m_i = mat._imag_operator pc_r = _create_smoother(name, m_r) pc_i = mfem.ScaledOperator( pc_r, 1 if conv == mfem.ComplexOperator.HERMITIAN else -1) smoother.SetDiagonalBlock(0, pc_r) smoother.SetDiagonalBlock(1, pc_i) smoother._smoothers = (pc_r, pc_i) else: smoother = _create_smoother(name, mat) return smoother
# [ S0^{-1} 0 ] # [ 0 Shat^{-1} ] Shat = (Bhat^T Sinv Bhat) # # corresponding to the primal (x0) and interfacial (xhat) unknowns. # Since the Shat operator is equivalent to an H(div) matrix reduced to # the interfacial skeleton, we approximate its inverse with one V-cycle # of the ADS preconditioner from the hypre library (in 2D we use AMS for # the rotated H(curl) problem). S0inv = mfem.HypreBoomerAMG(matS0) S0inv.SetPrintLevel(0) Shat = mfem.RAP(matSinv, matBhat) if (dim == 2): Shatinv = mfem.HypreAMS(Shat, xhat_space) else: Shatinv = mfem.HypreADS(Shat, xhat_space) P = mfem.BlockDiagonalPreconditioner(true_offsets) P.SetDiagonalBlock(0, S0inv) P.SetDiagonalBlock(1, Shatinv) # 12. Solve the normal equation system using the PCG iterative solver. # Check the weighted norm of residual for the DPG least square problem. # Wrap the primal variable in a GridFunction for visualization purposes. pcg = mfem.CGSolver(MPI.COMM_WORLD) pcg.SetOperator(A) pcg.SetPreconditioner(P) pcg.SetRelTol(1e-6) pcg.SetMaxIter(200) pcg.SetPrintLevel(1) pcg.Mult(b, x) LSres = mfem.HypreParVector(test_space)
#M2 = M.Transpose() #M3 = M2.Transpose() MinvBt = B.Transpose() Md = mfem.HypreParVector(MPI.COMM_WORLD, M.GetGlobalNumRows(), M.GetRowStarts()) M.GetDiag(Md) MinvBt.InvScaleRows(Md) S = mfem.hypre.ParMult(B, MinvBt) invM = mfem.HypreDiagScale(M) invS = mfem.HypreBoomerAMG(S) invM.iterative_mode = False invS.iterative_mode = False darcyPr = mfem.BlockDiagonalPreconditioner(block_trueOffsets) darcyPr.SetDiagonalBlock(0, invM) darcyPr.SetDiagonalBlock(1, invS) maxIter = 500 rtol = 1e-6 atol = 1e-10 import time stime = time.clock() solver = mfem.MINRESSolver(MPI.COMM_WORLD) solver.SetAbsTol(atol) solver.SetRelTol(rtol) solver.SetMaxIter(maxIter) solver.SetOperator(darcyOp)
def genearate_smoother(engine, level, blk_opr): from petram.engine import ParallelEngine assert not isinstance( engine, ParallelEngine), "Parallel is not supported" engine.access_idx = 0 P = None diags = [] cols = [0] ess_tdofs = [] A, _X, _RHS, _Ae, _B, _M, _dep_vars = engine.assembled_blocks widths = A.get_local_col_widths() use_complex_opr = A.complex and (A.shape[0] == blk_opr.NumRowBlocks()) for dep_var in engine.r_dep_vars: offset = engine.r_dep_var_offset(dep_var) tmp_cols = [] tmp_diags = [] if engine.r_isFESvar(dep_var): ess_tdof = mfem.intArray(engine.ess_tdofs[dep_var]) ess_tdofs.append(ess_tdofs) opr = A[offset, offset] if use_complex_opr: mat = blk_opr._linked_op[(offset, offset)] conv = mat.GetConvention() conv == 1 if mfem.ComplexOperator.HERMITIAN else -1 mat1 = mat._real_operator mat2 = mat._imag_operator else: conv = 1 if A.complex: mat1 = blk_opr.GetBlock(offset*2, offset*2) mat2 = blk_opr.GetBlock(offset*2 + 1, offset*2 + 1) else: mat1 = blk_opr.GetBlock(offset, offset) if A.complex: dd = opr.diagonal() diag = mfem.Vector(list(dd.real)) print("real", dd.real) rsmoother = mfem.OperatorChebyshevSmoother(mat1, diag, ess_tdof, 2) dd = opr.diagonal()*conv diag = mfem.Vector(list(dd.real)) print("imag", dd.imag) ismoother = mfem.OperatorChebyshevSmoother(mat1, diag, ess_tdof, 2) tmp_cols.append(opr.shape[0]) tmp_cols.append(opr.shape[0]) tmp_diags.append(rsmoother) tmp_diags.append(ismoother) else: dd = opr.diagonal() diag = mfem.Vector(list(dd)) smoother = mfem.OperatorChebyshevSmoother(mat1, diag, ess_tdof, 2) tmp_diags.append(smoother) tmp_cols.append(opr.shape[0]) else: print("Non FESvar", dep_var, offset) tmp_cols.append(widths[offset]) tmp_diags.append(mfem.IdentityOperator(widths[offset])) if A.complex: tmp_cols.append(widths[offset]) oo = mfem.IdentityOperator(widths[offset]) if conv == -1: oo2 = mfem.ScaleOperator(oo, -1) oo2._opr = oo tmp_diags.append(oo2) else: tmp_diags.append(oo) if use_complex_opr: tmp_cols = [0] + tmp_cols blockOffsets = mfem.intArray(tmp_cols) blockOffsets.PartialSum() smoother = mfem.BlockDiagonalPreconditioner(blockOffsets) smoother.SetDiagonalBlock(0, tmp_diags[0]) smoother.SetDiagonalBlock(1, tmp_diags[1]) smoother._smoother = tmp_diags cols.append(tmp_cols[1]*2) diags.append(smoother) else: cols.extend(tmp_cols) diags.extend(tmp_diags) co = mfem.intArray(cols) co.PartialSum() P = mfem.BlockDiagonalPreconditioner(co) for i, d in enumerate(diags): P.SetDiagonalBlock(i, d) P._diags = diags P._ess_tdofs = ess_tdofs return P
def solve_serial(self, A, b, x=None): def get_block(Op, i, j): try: return Op._linked_op[(i, j)] except KeyError: return None offset = A.RowOffsets() rows = A.NumRowBlocks() cols = A.NumColBlocks() if self.gui.write_mat: for i in range(cols): for j in range(rows): m = get_block(A, i, j) if m is None: continue m.Print('matrix_' + str(i) + '_' + str(j)) for i, bb in enumerate(b): for j in range(rows): v = bb.GetBlock(j) v.Print('rhs_' + str(i) + '_' + str(j)) M = mfem.BlockDiagonalPreconditioner(offset) prcs = dict(self.gui.preconditioners) name = self.Aname assert not self.gui.parent.is_complex(), "can not solve complex" if self.gui.parent.is_converted_from_complex(): name = sum([[n, n] for n in name], []) ''' this if block does a generalized version of this... M1 = mfem.GSSmoother(get_block(A, 0, 0)) M1.iterative_mode = False M.SetDiagonalBlock(0, M1) ''' for k, n in enumerate(name): prc = prcs[n][0] if prc == "None": continue name = "".join([tmp for tmp in prc if not tmp.isdigit()]) A0 = get_block(A, k, k) cls = SparseSmootherCls[name][0] arg = SparseSmootherCls[name][1] if name == 'MUMPS': invA0 = cls(A0, gui=self.gui[prc], engine=self.engine) else: invA0 = cls(A0, arg) invA0.iterative_mode = False M.SetDiagonalBlock(k, invA0) ''' We should support Shur complement type preconditioner if offset.Size() > 2: B = get_block(A, 1, 0) MinvBt = get_block(A, 0, 1) Md = mfem.Vector(get_block(A, 0, 0).Height()) get_block(A, 0, 0).GetDiag(Md) for i in range(Md.Size()): if Md[i] != 0.: MinvBt.ScaleRow(i, 1/Md[i]) else: assert False, "diagnal element of matrix is zero" S = mfem.Mult(B, MinvBt) S.iterative_mode = False SS = mfem.DSmoother(S) SS.iterative_mode = False M.SetDiagonalBlock(1, SS) ''' ''' int GMRES(const Operator &A, Vector &x, const Vector &b, Solver &M, int &max_iter, int m, double &tol, double atol, int printit) ''' maxiter = int(self.maxiter) atol = self.abstol rtol = self.reltol kdim = int(self.kdim) printit = 1 sol = [] solver = mfem.GMRESSolver() solver.SetKDim(kdim) #solver = mfem.MINRESSolver() solver.SetAbsTol(atol) solver.SetRelTol(rtol) solver.SetMaxIter(maxiter) solver.SetOperator(A) solver.SetPreconditioner(M) solver.SetPrintLevel(1) for bb in b: if x is None: xx = mfem.Vector(bb.Size()) xx.Assign(0.0) else: xx = x #for j in range(cols): # print x.GetBlock(j).Size() # print x.GetBlock(j).GetDataArray() #assert False, "must implement this" solver.Mult(bb, xx) sol.append(xx.GetDataArray().copy()) sol = np.transpose(np.vstack(sol)) return sol
def solve_parallel(self, A, b, x=None): from mpi4py import MPI myid = MPI.COMM_WORLD.rank nproc = MPI.COMM_WORLD.size from petram.helper.mpi_recipes import gather_vector def get_block(Op, i, j): try: return Op._linked_op[(i, j)] except KeyError: return None offset = A.RowOffsets() rows = A.NumRowBlocks() cols = A.NumColBlocks() if self.gui.write_mat: for i in range(cols): for j in range(rows): m = get_block(A, i, j) if m is None: continue m.Print('matrix_' + str(i) + '_' + str(j)) for i, bb in enumerate(b): for j in range(rows): v = bb.GetBlock(j) v.Print('rhs_' + str(i) + '_' + str(j) + '.' + smyid) if x is not None: for j in range(rows): xx = x.GetBlock(j) xx.Print('x_' + str(i) + '_' + str(j) + '.' + smyid) M = mfem.BlockDiagonalPreconditioner(offset) prcs = dict(self.gui.preconditioners) name = self.Aname assert not self.gui.parent.is_complex(), "can not solve complex" if self.gui.parent.is_converted_from_complex(): name = sum([[n, n] for n in name], []) for k, n in enumerate(name): prc = prcs[n][1] if prc == "None": continue name = "".join([tmp for tmp in prc if not tmp.isdigit()]) A0 = get_block(A, k, k) if A0 is None and not name.startswith('schur'): continue if hasattr(mfem.HypreSmoother, prc): invA0 = mfem.HypreSmoother(A0) invA0.SetType(getattr(mfem.HypreSmoother, prc)) elif prc == 'ams': depvar = self.engine.r_dep_vars[k] dprint1("setting up AMS for ", depvar) prec_fespace = self.engine.fespaces[depvar] invA0 = mfem.HypreAMS(A0, prec_fespace) invA0.SetSingularProblem() elif name == 'MUMPS': cls = SparseSmootherCls[name][0] invA0 = cls(A0, gui=self.gui[prc], engine=self.engine) elif name.startswith('schur'): args = name.split("(")[-1].split(")")[0].split(",") dprint1("setting up schur for ", args) if len(args) > 1: assert False, "not yet supported" for arg in args: r1 = self.engine.dep_var_offset(arg.strip()) c1 = self.engine.r_dep_var_offset(arg.strip()) B = get_block(A, k, c1) Bt = get_block(A, r1, k).Transpose() Bt = Bt.Transpose() B0 = get_block(A, r1, c1) Md = mfem.HypreParVector(MPI.COMM_WORLD, B0.GetGlobalNumRows(), B0.GetColStarts()) B0.GetDiag(Md) Bt.InvScaleRows(Md) S = mfem.ParMult(B, Bt) invA0 = mfem.HypreBoomerAMG(S) invA0.iterative_mode = False else: cls = SparseSmootherCls[name][0] invA0 = cls(A0, gui=self.gui[prc]) invA0.iterative_mode = False M.SetDiagonalBlock(k, invA0) ''' We should support Shur complement type preconditioner if offset.Size() > 2: B = get_block(A, 1, 0) MinvBt = get_block(A, 0, 1) #Md = mfem.HypreParVector(MPI.COMM_WORLD, # A0.GetGlobalNumRows(), # A0.GetRowStarts()) Md = mfem.Vector() A0.GetDiag(Md) MinvBt.InvScaleRows(Md) S = mfem.ParMult(B, MinvBt) invS = mfem.HypreBoomerAMG(S) invS.iterative_mode = False M.SetDiagonalBlock(1, invS) ''' maxiter = int(self.maxiter) atol = self.abstol rtol = self.reltol kdim = int(self.kdim) printit = 1 sol = [] solver = mfem.GMRESSolver(MPI.COMM_WORLD) solver.SetKDim(kdim) #solver = mfem.MINRESSolver(MPI.COMM_WORLD) #solver.SetOperator(A) #solver = mfem.CGSolver(MPI.COMM_WORLD) solver.SetOperator(A) solver.SetAbsTol(atol) solver.SetRelTol(rtol) solver.SetMaxIter(maxiter) solver.SetPreconditioner(M) solver.SetPrintLevel(1) # solve the problem and gather solution to head node... # may not be the best approach for bb in b: rows = MPI.COMM_WORLD.allgather(np.int32(bb.Size())) rowstarts = np.hstack((0, np.cumsum(rows))) dprint1("rowstarts/offser", rowstarts, offset.ToList()) if x is None: xx = mfem.BlockVector(offset) xx.Assign(0.0) else: xx = x #for j in range(cols): # dprint1(x.GetBlock(j).Size()) # dprint1(x.GetBlock(j).GetDataArray()) #assert False, "must implement this" solver.Mult(bb, xx) s = [] for i in range(offset.Size() - 1): v = xx.GetBlock(i).GetDataArray() vv = gather_vector(v) if myid == 0: s.append(vv) else: pass if myid == 0: sol.append(np.hstack(s)) if myid == 0: sol = np.transpose(np.vstack(sol)) return sol else: return None
def __call__(self, *args, **kwargs): offset = self.opr.RowOffsets() D = mfem.BlockDiagonalPreconditioner(offset) if self.func is not None: self.func(D, self, *args, **kwargs) return D