1from __future__ import print_function 2 3# -------------------------------------------------------------------- 4 5from petsc4py import PETSc 6 7# -------------------------------------------------------------------- 8 9OptDB = PETSc.Options() 10 11INFO = OptDB.hasName('info') 12 13def LOG(arg): 14 if INFO: 15 print(arg) 16 17# -------------------------------------------------------------------- 18 19class Laplace1D(object): 20 21 def create(self, A): 22 LOG('Laplace1D.create()') 23 M, N = A.getSize() 24 assert M == N 25 26 def destroy(self, A): 27 LOG('Laplace1D.destroy()') 28 29 def view(self, A, vw): 30 LOG('Laplace1D.view()') 31 32 def setFromOptions(self, A): 33 LOG('Laplace1D.setFromOptions()') 34 35 def setUp(self, A): 36 LOG('Laplace1D.setUp()') 37 38 def assemblyBegin(self, A, flag): 39 LOG('Laplace1D.assemblyBegin()') 40 41 def assemblyEnd(self, A, flag): 42 LOG('Laplace1D.assemblyEnd()') 43 44 def getDiagonal(self, A, d): 45 LOG('Laplace1D.getDiagonal()') 46 M, N = A.getSize() 47 h = 1.0/(M-1) 48 d.set(2.0/h**2) 49 50 def mult(self, A, x, y): 51 LOG('Laplace1D.mult()') 52 M, N = A.getSize() 53 xx = x.getArray(readonly=1) # to numpy array 54 yy = y.getArray(readonly=0) # to numpy array 55 yy[0] = 2.0*xx[0] - xx[1] 56 yy[1:-1] = - xx[:-2] + 2.0*xx[1:-1] - xx[2:] 57 yy[-1] = - xx[-2] + 2.0*xx[-1] 58 h = 1.0/(M-1) 59 yy *= 1.0/h**2 60 61 def multTranspose(self, A, x, y): 62 LOG('Laplace1D.multTranspose()') 63 self.mult(A, x, y) 64 65 66# -------------------------------------------------------------------- 67 68class Jacobi(object): 69 70 def create(self, pc): 71 LOG('Jacobi.create()') 72 self.diag = None 73 74 def destroy(self, pc): 75 LOG('Jacobi.destroy()') 76 if self.diag: 77 self.diag.destroy() 78 79 def view(self, pc, vw): 80 LOG('Jacobi.view()') 81 82 def setFromOptions(self, pc): 83 LOG('Jacobi.setFromOptions()') 84 85 def setUp(self, pc): 86 LOG('Jacobi.setUp()') 87 A, B = pc.getOperators() 88 self.diag = B.getDiagonal(self.diag) 89 90 def apply(self, pc, x, y): 91 LOG('Jacobi.apply()') 92 y.pointwiseDivide(x, self.diag) 93 94 def applyTranspose(self, pc, x, y): 95 LOG('Jacobi.applyTranspose()') 96 self.apply(pc, x, y) 97 98# -------------------------------------------------------------------- 99 100class ConjGrad(object): 101 102 def create(self, ksp): 103 LOG('ConjGrad.create()') 104 self.work = [] 105 106 def destroy(self, ksp): 107 LOG('ConjGrad.destroy()') 108 for vec in self.work: 109 if vec: 110 vec.destroy() 111 self.work = [] 112 113 def view(self, ksp, viewer): 114 LOG('ConjGrad.view()') 115 116 def setUp(self, ksp): 117 LOG('ConjGrad.setUp()') 118 self.work[:] = ksp.getWorkVecs(right=3, left=None) 119 120 def solve(self, ksp, b, x): 121 LOG('ConjGrad.solve()') 122 A, P = get_op_pc(ksp, transpose=False) 123 pcg(ksp, A, P, b, x, *self.work) 124 125 def solveTranspose(self, ksp, b, x): 126 LOG('ConjGrad.solveTranspose()') 127 A, P = get_op_pc(ksp, transpose=True) 128 pcg(ksp, A, P, b, x, *self.work) 129 130def get_op_pc(ksp, transpose=False): 131 op, _ = ksp.getOperators() 132 pc = ksp.getPC() 133 if not transpose: 134 A = op.mult 135 P = pc.apply 136 else: 137 A = op.multTranspose 138 P = pc.applyTranspose 139 return A, P 140 141def do_loop(ksp, r): 142 its = ksp.getIterationNumber() 143 rnorm = r.norm() 144 ksp.setResidualNorm(rnorm) 145 ksp.logConvergenceHistory(rnorm) 146 ksp.monitor(its, rnorm) 147 reason = ksp.callConvergenceTest(its, rnorm) 148 if not reason: 149 ksp.setIterationNumber(its+1) 150 else: 151 ksp.setConvergedReason(reason) 152 return reason 153 154def pcg(ksp, A, P, b, x, r, z, p): 155 A(x, r) 156 r.aypx(-1, b) 157 P(r, z) 158 delta = r.dot(z) 159 z.copy(p) 160 while not do_loop(ksp, z): 161 A(p, z) 162 alpha = delta / z.dot(p) 163 x.axpy(+alpha, p) 164 r.axpy(-alpha, z) 165 P(r, z) 166 delta_old = delta 167 delta = r.dot(z) 168 beta = delta / delta_old 169 p.aypx(beta, z) 170 171def richardson(ksp, A, P, b, x, r, z): 172 A(x, r) 173 r.aypx(-1, b) 174 P(r, z) 175 x.axpy(1, z) 176 while not do_loop(ksp, z): 177 A(x, r) 178 r.aypx(-1, b) 179 P(r, z) 180 x.axpy(1, z) 181 182# -------------------------------------------------------------------- 183