def pcg(A, f, P, w0, eps=1e-4, maxiter=100): # for most quantities in PCG (except zeta) only the most recent # values needs to be kept in memory w = ForgetfulVector(1) rho = ForgetfulVector(1) s = ForgetfulVector(1) v = ForgetfulVector(1) z = ForgetfulVector(1) alpha = ForgetfulVector(1) zeta = ForgetfulVector(2) w[0] = w0 rho[0] = f - A * w[0] s[0] = P * rho[0] v[0] = s[0] zeta[0] = inner(rho[0], s[0]) for i in xrange(1, maxiter): logger.info("pcg iter: %s -> zeta=%s, rho^2=%s" % (i, zeta[i - 1], inner(rho[i - 1], rho[i - 1]))) if zeta[i - 1] < 0: for mu in rho[i - 1].active_indices(): print i, mu, inner(rho[i - 1][mu], s[i - 1][mu]) raise Exception("Preconditioner for PCG is not positive definite (%s)" % zeta[i - 1]) if zeta[i - 1] <= eps ** 2: return (w[i - 1], zeta[i - 1], i) z[i - 1] = A * v[i - 1] alpha[i - 1] = inner(z[i - 1], v[i - 1]) if alpha[i - 1] == 0: raise Exception("Matrix for PCG is singular (%s)" % alpha[i - 1]) elif alpha[i - 1] < 0: raise Exception("Matrix for PCG is not positive definite (%s)" % alpha[i - 1]) w[i] = w[i - 1] + zeta[i - 1] / alpha[i - 1] * v[i - 1] rho[i] = rho[i - 1] - zeta[i - 1] / alpha[i - 1] * z[i - 1] s[i] = P * rho[i] zeta[i] = inner(rho[i], s[i]) v[i] = s[i] + zeta[i] / zeta[i - 1] * v[i - 1] raise Exception("PCG did not converge")
#coeff_field = CoefficientField(a, rvs) a0 = Constant("1.0") a = (Expression('A*cos(pi*I*x[0])*cos(pi*I*x[1])', A=1 / i ** 2, I=i, degree=2) for i in count(1)) rvs = (UniformRV() for _ in count()) coeff_field = ParametricCoefficientField(func_func=a, rv_func=rvs, mean_func=a0) pde = FEMPoisson() A = MultiOperator(coeff_field, pde.assemble_operator) mis = [Multiindex([0]), Multiindex([1]), Multiindex([0, 1]), Multiindex([0, 2])] mesh = UnitSquare(4, 4) fs = FunctionSpace(mesh, "CG", 1) F = [interpolate(Expression("*".join(["x[0]"] * i)), fs) for i in range(1, 5)] vecs = [FEniCSVector(f) for f in F] w = MultiVectorWithProjection() for mi, vec in zip(mis, vecs): w[mi] = vec v = A * w #P = MultiplicationOperator(1, vecs[0].basis) P = PreconditioningOperator(a0, pde.assemble_solve_operator) w2, zeta, numit = pcg(A, v, P, 0 * v) print print zeta, numit print inner(w - w2, w - w2) / inner(w, w) v2 = A * w2 print inner(v - v2, v - v2) / inner(v, v)
def __inner__(self, other): assert isinstance(other, MultiVector) s = 0.0 for mi in self.keys(): s += inner(self[mi], other[mi]) return s
def norm(v): return math.sqrt(inner(v, v))