Beispiel #1
0
 def __init__(self, mat, blocks1, blocks2):
     super(FastInv, self).__init__()
     self.parmat = mat
     self.spmat = self.parmat if mpi_world.size == 1 else self.parmat.local_mat
     self.inv1 = self.spmat.CreateBlockSmoother(blocks1)
     self.inv2 = self.spmat.CreateBlockSmoother(
         blocks2) if blocks2 is not None else None
     self.res = self.spmat.CreateColVector()
     self.ty = self.spmat.CreateColVector()
     self.tmult = Timer("FastInv")
Beispiel #2
0
def solve_with_bramble_pasciak_cg(a_matrix, b_matrix, pre_a, pre_schur_complement, gfu, gfp, f, g, tolerance, max_steps):
    sol = BlockVector([gfu, gfp])
    bramble_pasciak_cg_timer = Timer("BramblePasciakCG")
    bramble_pasciak_cg_timer.Start()
    (solution, errors) = bramble_pasciak_cg(a_matrix, b_matrix, None, pre_a, pre_schur_complement, f, g, sol,
                                            tolerance=tolerance, max_steps=max_steps)
    bramble_pasciak_cg_timer.Stop()
    print("Bramble Pasciak CG took",
          bramble_pasciak_cg_timer.time, "seconds")
    return (solution, errors, bramble_pasciak_cg_timer.time)
def orthonormalize(basis, tries=3):
    orthonormalize_timer = Timer("orthonormalization")
    orthonormalize_timer.Start()
    for tries in range(tries):
        for j in range(len(basis)):
            for i in range(j):
                basis[j].data -= InnerProduct(basis[i], basis[j]) / \
                    InnerProduct(basis[i], basis[i]) * basis[i]
            basis[j].data = 1 / Norm(basis[j]) * basis[j]
    orthonormalize_timer.Stop()

    return basis
Beispiel #4
0
def solve_with_min_res(a, b, preA, preS, gfu, gfp, f, g, tolerance, max_steps):
    K = BlockMatrix([[a, b.T], [b, None]])
    C = BlockMatrix([[preA, None], [None, preS]])
    rhs = BlockVector([f, g])
    sol = BlockVector([gfu, gfp])

    min_res_timer = Timer("MinRes")
    min_res_timer.Start()
    (solution, errors) = MinRes(mat=K, pre=C, rhs=rhs, sol=sol, initialize=False,
                                tol=tolerance, maxsteps=max_steps)
    min_res_timer.Stop()
    print("MinRes took", min_res_timer.time, "seconds")
    return (solution, errors, min_res_timer.time)
Beispiel #5
0
class FastInv(BaseMatrix):
    def __init__(self, mat, blocks1, blocks2):
        super(FastInv, self).__init__()
        self.parmat = mat
        self.spmat = self.parmat if mpi_world.size == 1 else self.parmat.local_mat
        self.inv1 = self.spmat.CreateBlockSmoother(blocks1)
        self.inv2 = self.spmat.CreateBlockSmoother(
            blocks2) if blocks2 is not None else None
        self.res = self.spmat.CreateColVector()
        self.ty = self.spmat.CreateColVector()
        self.tmult = Timer("FastInv")

    def Height(self):
        return self.parmat.height

    def Width(self):
        return self.parmat.width

    def CreateRowVector(self):
        return self.spmat.CreateRowVector()

    def CreateColVector(self):
        return self.spmat.CreateColVector()

    def MultAdd(self, scal, x, y):
        self.ty[:] = 0
        self.Mult(x, self.ty)
        y.local_vec.data += scal * self.ty

    def Mult(self, x, y):
        self.tmult.Start()
        y.local_vec.data = self.inv1 * x.local_vec
        # self.res.data = x - self.spmat * y
        # y.local_vec.data += self.inv2 * self.res
        self.tmult.Stop()

    def MultTransAdd(self, scal, x, y):
        self.ty[:] = 0
        self.MultTrans(x, self.ty)
        y.local_vec.data += scal * self.ty

    def MultTrans(self, x, y):
        self.tmult.Start()
        # y.local_vec.data = self.inv2.T * x.local_vec
        # self.res.data = x - self.spmat.T * y
        # y.local_vec.data += self.inv1.T * self.res
        y.local_vec.data = self.inv1.T * x.local_vec
        self.tmult.Stop()

    def IsComplex(self):
        return False
Beispiel #6
0
def TimeFunction(func, name=None):
    name = name or func.__qualname__
    timer = Timer(name)
    def retfunc(*args,**kwargs):
        with timer:
            ret = func(*args, **kwargs)
        return ret
    return retfunc
Beispiel #7
0
def solve_hcurldiv(mesh, discretization, solver_factory):
    V, S, Q = discretization(
        mesh, velocity_dirichlet='wall|inlet|cyl', velocity_neumann='outlet')

    X = FESpace([V, S, Q])
    (u, sigma, p), (v, tau, q) = X.TnT()

    n = specialcf.normal(mesh.dim)

    a = BilinearForm(X, symmetric=True)
    a += SymbolicBFI(InnerProduct(sigma, tau))
    a += SymbolicBFI(div(sigma) * v + div(tau) * u)
    a += SymbolicBFI(-(sigma * n) * n * (v * n) - (tau * n) *
                     n * (u * n), element_boundary=True)
    a += SymbolicBFI(div(u) * q + div(v) * p)

    a.Assemble()

    f = LinearForm(X)
    f += SymbolicLFI(CoefficientFunction((0, x - 0.5)) * v)
    f.Assemble()

    grid_function = GridFunction(X)
    uin = CoefficientFunction((1.5 * 4 * y * (0.41 - y) / (0.41 * 0.41), 0))
    grid_function.components[0].Set(uin, definedon=mesh.Boundaries("inlet"))

    direct_timer = Timer("Direct Solver")
    direct_timer.Start()
    res = grid_function.vec.CreateVector()
    res.data = f.vec - a.mat * grid_function.vec
    inv = a.mat.Inverse(freedofs=X.FreeDofs(), inverse="umfpack")
    grid_function.vec.data += inv * res
    direct_timer.Stop()

    velocity = CoefficientFunction(grid_function.components[0])
    pressure = CoefficientFunction(grid_function.components[2])

    Draw(velocity, mesh, "velocity")
    Draw(pressure, mesh, "pressure")
    ndofs = X.ndof
    return (velocity, pressure, [], direct_timer.time, ndofs)
def bramble_pasciak_cg(a_matrix,
                       b_matrix,
                       c_matrix,
                       pre_a,
                       pre_schur_complement,
                       upper_rhs,
                       lower_rhs,
                       solution=None,
                       tolerance=1e-12,
                       max_steps=1000,
                       print_rates=True):
    ev_timer = Timer("eigenvalues")
    ev_timer.Start()
    eigenvalues = EigenValues_Preconditioner(mat=a_matrix, pre=pre_a)
    k = 1 / min(eigenvalues) + 1e-3
    ev_timer.Stop()
    print("scale factor: ", k)
    print("condition number: ", max(eigenvalues) / min(eigenvalues))
    scaled_pre_a = ScaledPreconditioner(k, a_matrix, pre_a)

    original_matrix = BlockMatrix([[a_matrix, b_matrix.T],
                                   [b_matrix, c_matrix]])
    full_pre_a = BlockMatrix([[scaled_pre_a, None],
                              [None, IdentityMatrix(b_matrix.height)]])
    full_b = BlockMatrix([[IdentityMatrix(a_matrix.width), None],
                          [b_matrix, -IdentityMatrix(b_matrix.height)]])
    a_b_block_matrix = MatrixAB(a_matrix, b_matrix)
    full_pre_schur_complement = BlockMatrix(
        [[IdentityMatrix(a_matrix.width), None], [None, pre_schur_complement]])

    rhs = BlockVector([upper_rhs, lower_rhs])
    if not solution:
        solution = rhs.CreateVector()
        solution[:] = 0

    residuum = rhs.CreateVector()
    temp_1 = rhs.CreateVector()
    full_preconditioned_residuum = rhs.CreateVector()
    a_preconditioned_residuum = rhs.CreateVector()
    temp_2 = rhs.CreateVector()

    temp_2.data = rhs - original_matrix * solution
    a_preconditioned_residuum.data = full_pre_a * temp_2
    residuum.data = a_b_block_matrix * a_preconditioned_residuum \
        - rhs + original_matrix * solution
    temp_1.data = full_pre_schur_complement @ full_b * a_preconditioned_residuum
    full_preconditioned_residuum.data = temp_1

    current_residual_error_squared = InnerProduct(temp_1, residuum)

    err0 = sqrt(abs(current_residual_error_squared))
    errors = []

    for iteration in range(max_steps):
        iteration_timer = Timer("Bramble Pasciak CG Iteration " +
                                str(iteration))
        iteration_timer.Start()

        err = sqrt(abs(current_residual_error_squared))
        if print_rates:
            print("\rit =",
                  iteration,
                  "rel err =",
                  err / err0,
                  "abs err =",
                  err,
                  " " * 20,
                  end="")
        errors.append(err / err0)
        if err < tolerance * err0:
            iteration_timer.Stop()
            break

        previous_residual_error_squared = current_residual_error_squared

        temp_1.data = -original_matrix * full_preconditioned_residuum
        temp_2.data = -full_pre_a * temp_1
        temp_1.data += a_b_block_matrix * temp_2

        alpha = previous_residual_error_squared / \
            InnerProduct(full_preconditioned_residuum, temp_1)
        solution.data += alpha * full_preconditioned_residuum
        residuum.data += (-alpha) * temp_1
        a_preconditioned_residuum.data += (-alpha) * temp_2

        temp_1.data = full_pre_schur_complement @ full_b * a_preconditioned_residuum

        current_residual_error_squared = InnerProduct(temp_1, residuum)
        beta = current_residual_error_squared / previous_residual_error_squared

        full_preconditioned_residuum *= beta
        full_preconditioned_residuum.data += temp_1

        iteration_timer.Stop()
    else:
        print("\nWarning: CG did not converge to TOL")

    print("")
    return (solution, errors)
Beispiel #9
0
def CG(mat,
       rhs,
       pre=None,
       sol=None,
       tol=1e-12,
       maxsteps=100,
       printrates=True,
       initialize=True,
       conjugate=False):
    """preconditioned conjugate gradient method


    Parameters
    ----------

    mat : Matrix
      The left hand side of the equation to solve. The matrix has to be spd or hermitsch.

    rhs : Vector
      The right hand side of the equation.

    pre : Preconditioner
      If provided the preconditioner is used.

    sol : Vector
      Start vector for CG method, if initialize is set False. Gets overwritten by the solution vector. If sol = None then a new vector is created.

    tol : double
      Tolerance of the residuum. CG stops if tolerance is reached.

    maxsteps : int
      Number of maximal steps for CG. If the maximal number is reached before the tolerance is reached CG stops.

    printrates : bool
      If set to True then the error of the iterations is displayed.

    initialize : bool
      If set to True then the initial guess for the CG method is set to zero. Otherwise the values of the vector sol, if provided, is used.

    conjugate : bool
      If set to True, then the complex inner product is used.


    Returns
    -------
    (vector)
      Solution vector of the CG method.

    """

    timer = Timer("CG-Solver")
    timer.Start()
    u = sol if sol else rhs.CreateVector()
    d = rhs.CreateVector()
    w = rhs.CreateVector()
    s = rhs.CreateVector()

    if initialize: u[:] = 0.0
    d.data = rhs - mat * u
    w.data = pre * d if pre else d
    err0 = sqrt(abs(InnerProduct(d, w)))
    s.data = w
    # wdn = InnerProduct (w,d)
    wdn = w.InnerProduct(d, conjugate=conjugate)

    if wdn == 0:
        return u

    for it in range(maxsteps):
        w.data = mat * s
        wd = wdn
        # as_s = InnerProduct (s, w)
        as_s = s.InnerProduct(w, conjugate=conjugate)
        alpha = wd / as_s
        u.data += alpha * s
        d.data += (-alpha) * w

        w.data = pre * d if pre else d

        # wdn = InnerProduct (w, d)
        wdn = w.InnerProduct(d, conjugate=conjugate)
        beta = wdn / wd

        s *= beta
        s.data += w

        err = sqrt(abs(wd))
        if printrates:
            print("it = ", it, " err = ", err)
        if err < tol * err0: break
    else:
        print("Warning: CG did not converge to TOL")

    timer.Stop()
    return u
Beispiel #10
0
def solve(initial_temperature, end_time, time_step):
    mesh = Mesh(unit_square.GenerateMesh(maxh=0.1))
    Draw(mesh)

    space = H1(mesh, order=10, dirichlet='bottom|right|top|left')

    print(space)

    Draw(initial_temperature, mesh, "initial_temperature")

    trial_function = space.TrialFunction()
    test_function = space.TestFunction()

    diffusion_term = grad(trial_function) * grad(test_function)
    diffusion = BilinearForm(space)
    diffusion += diffusion_term * dx

    mass_term = trial_function * test_function
    mass = BilinearForm(space)
    mass += mass_term * dx

    heat = BilinearForm(space)
    heat += mass_term * dx + time_step * diffusion_term * dx

    source_term = 0 * test_function
    source = LinearForm(space)
    source += source_term * dx

    diffusion.Assemble()
    mass.Assemble()
    heat.Assemble()
    source.Assemble()

    temperature = GridFunction(space, "temperature")
    temperature.Set(initial_temperature)
    for i in range(space.ndof):
        if not space.FreeDofs()[i]:
            temperature.vec[i] = 0

    Draw(temperature)

    residual = temperature.vec.CreateVector()
    heat_inverse = heat.mat.Inverse(space.FreeDofs())

    subspace_dimension = 5
    dt = time_step / subspace_dimension
    runge_kutta_weights = ImplicitRungeKuttaMethodWeights(10)
    time = 0
    print(f"time={time}")

    with (TaskManager()):
        while time < end_time:
            time += time_step

            print(f"time={time}")
            timer = Timer("exponential integrators timer")
            timer.Start()
            subspace_basis = [temperature.vec.Copy()]

            initial_condition_norm = Norm(temperature.vec)

            subspace_basis_assembling_timer = Timer(
                "subspace basis assembling")
            subspace_basis_assembling_timer.Start()

            for i in range(1, subspace_dimension):
                residual.data = diffusion.mat * temperature.vec
                temperature.vec.data -= dt * heat_inverse * residual
                subspace_basis.append(temperature.vec.Copy())

            subspace_basis = orthonormalize(subspace_basis)
            subspace_basis_assembling_timer.Stop()

            subspace_matrix_assembling_timer = Timer(
                "subspace matrix assembling")
            subspace_matrix_assembling_timer.Start()
            subspace_diffusion = Matrix(subspace_dimension, subspace_dimension)
            subspace_mass = Matrix(subspace_dimension, subspace_dimension)

            for col in range(subspace_dimension):
                residual.data = diffusion.mat * subspace_basis[col]
                for row in range(subspace_dimension):
                    subspace_diffusion[row, col] = InnerProduct(
                        subspace_basis[row], residual)

                residual.data = mass.mat * subspace_basis[col]
                for row in range(subspace_dimension):
                    subspace_mass[row,
                                  col] = InnerProduct(subspace_basis[row],
                                                      residual)

            subspace_mass_inverse = Matrix(subspace_dimension,
                                           subspace_dimension)
            subspace_mass.Inverse(subspace_mass_inverse)

            evolution_matrix = -subspace_mass_inverse * subspace_diffusion

            subspace_matrix_assembling_timer.Stop()

            large_timestep_timer = Timer("large timestep")
            large_timestep_timer.Start()

            subspace_temperature = Vector(subspace_dimension)
            subspace_temperature[:] = 0
            subspace_temperature[0] = initial_condition_norm

            next_temperature = linear_implicit_runge_kutta_step(
                runge_kutta_weights, evolution_matrix, subspace_temperature,
                time_step)

            temperature.vec[:] = 0
            for i, basis_vector in enumerate(subspace_basis):
                temperature.vec.data += next_temperature[i] * basis_vector

            large_timestep_timer.Stop()
            timer.Stop()
            Redraw()

        return (temperature, mesh, time)
Beispiel #11
0
def BramblePasciakCG(blfA,
                     blfB,
                     matC,
                     f,
                     g,
                     preA_unscaled,
                     preM,
                     sol=None,
                     tol=1e-6,
                     maxsteps=100,
                     printrates=True,
                     initialize=True,
                     rel_err=True):
    """preconditioned bramble pasciak conjugate gradient method


    Parameters
    ----------

    matA : Matrix
      The left upper matrix of the saddle point matrix. The matrix has to be spd.

    matB : Matrix
      The B of the saddle point matrix. The matrix has to be spd.

    matC : Matrix
      The lower right of the saddle point matrix. The matrix has to be spd.

    f : Vector
      The first component right hand side of the equation.

    g : Vector
      The second component right hand side of the equation.

    preA_unscaled :
      Preconditioner of matA, preferedly BDDC.

    preA_unscaled :
      Preconditioner of matB, arbitrary (i.e. Jacobi).

    sol : Vector
      Start vector for CG method, if initialize is set False. Gets overwritten by the solution vector. If sol = None then a new vector is created.

    tol : double
      Tolerance of the residuum. BPCG stops if tolerance is reached.

    maxsteps : int
      Number of maximal steps for BPCG. If the maximal number is reached before the tolerance is reached CG stops.

    printrates : bool
      If set to True then the error of the iterations is displayed.

    initialize : bool
      If set to True then the initial guess for the BPCG method is set to zero. Otherwise the values of the vector sol, if provided, is used.

    conjugate : bool
      If set to True, then the complex inner product is used.

    rel_err : bool
      Whether to use the tolerance relative to the the initial error or not.

    Returns
    -------
    (vector - call by reference)
      Solution vector of the BPCG method.

    (int)
      Number of iterations the BCGP took

    """
    class myAmatrix(BaseMatrix):
        def __init__(self, blfA):
            super(myAmatrix, self).__init__()
            self.blfA = blfA
            self.mat = (IdentityMatrix() - blfA.harmonic_extension_trans) @ (
                blfA.mat + blfA.inner_matrix) @ (IdentityMatrix() -
                                                 blfA.harmonic_extension)

        def Mult(self, x, y):
            y.data = self.mat * x

        def Height(self):
            return self.blfA.mat.height

        def Width(self):
            return self.blfA.mat.width

        def CreateColVector(self):
            return self.blfA.mat.CreateColVector()

        def CreateVector(self):
            return self.blfA.mat.CreateColVector()

    if blfA.condense:
        matA = myAmatrix(blfA)
    else:
        matA = blfA.mat
    matB = blfB.mat

    timer_prep = Timer("BPCG-Preparation")
    timer_prep.Start()
    timer_prepev = Timer("BPCG-Preparation-EV")
    timer_prepev.Start()
    lams = EigenValues_Preconditioner(mat=matA, pre=preA_unscaled, tol=1e-3)
    timer_prepev.Stop()
    # print("min", min(lams), "max", max(lams))
    k = 1. / min(lams) + 1e-3

    print("condition", max(lams) / min(lams))
    # print("scale factor", k)
    preA = k * preA_unscaled

    f_new = matA.CreateColVector()

    # tmp0.data = preA * f
    #tmp0 = harmonic_extension(f, blfA, preA)
    tmp0 = f.CreateVector()
    harmonic_extension(f, blfA, preA, result=tmp0)
    f_new.data = matA * tmp0 - f

    g_new = matB.CreateColVector()
    g_new.data = matB * tmp0 - g

    rhs = BlockVector([f_new, g_new])

    u = sol if sol else rhs.CreateVector()
    if initialize:
        u[:] = 0.0

    d = rhs.CreateVector()
    w = rhs.CreateVector()
    v = rhs.CreateVector()
    z = rhs.CreateVector()
    z_old = rhs.CreateVector()
    s = rhs.CreateVector()

    # MatOp = BP_Matrices(preA, matA, matB, preM)

    # MatOp.update(u)
    tmp0 = blfA.mat.CreateColVector()
    #tmp1 = preA.CreateColVector()
    tmp1 = blfA.mat.CreateColVector()
    tmp2 = blfA.mat.CreateColVector()
    tmp3 = matB.CreateColVector()
    tmp4 = tmp1.CreateVector()
    matA_s0 = blfA.mat.CreateColVector()
    matB_s1 = matB.CreateRowVector()

    tmp0.data = matA * u[0] + matB.T * u[1]
    # tmp1.data = preA * tmp0
    harmonic_extension(tmp0, blfA, preA, tmp1)
    tmp2.data = matA * tmp1

    tmp4.data = tmp1 - u[0]
    tmp3.data = matB * tmp4

    # d.data = rhs - MatOp.K * u
    d[0].data = rhs[0] - (tmp2 - tmp0)
    d[1].data = rhs[1] - tmp3

    pr = rhs.CreateVector()
    harmonic_extension(f, blfA, preA, pr[0])
    # pr[0].data = preA * f

    tmp5 = matB.CreateColVector()
    tmp5.data = matB * pr[0] - g

    pr[1].data = preM * tmp5

    # w.data = pr - MatOp.Cinv_K * u
    w[0].data = pr[0] - tmp1
    w[1].data = pr[1] - preM * tmp3

    wdn = InnerProduct(w, d)

    err0 = sqrt(abs(wdn))
    print("err0", err0)
    s.data = w

    if wdn == 0:
        return u

    timer_prep.Stop()
    timer_its = Timer("BPCG-Iterations")
    timer_its.Start()

    matB_tranposed = matB.CreateTranspose()

    for it in range(maxsteps):
        if it == 0:
            matA_s0.data = matA * s[0]
            z[0].data = matA_s0  # A*w_0_0
        else:
            matA_s0.data = beta * matA_s0 + z_old[0] - alpha * tmp2
        matB_s1.data = matB_tranposed * s[1]
        tmp0.data = matA_s0 + matB_s1
        # tmp1.data = preA * tmp0
        harmonic_extension(f=tmp0, blfA=blfA, inverse=preA, result=tmp1)
        tmp2.data = matA * tmp1

        tmp4.data = tmp1 - s[0]
        tmp3.data = matB * tmp4

        z_old[0].data = z[0]

        # w.data = MatOp.K * s
        v[0].data = tmp2 - tmp0
        v[1].data = tmp3

        wd = wdn
        as_s = InnerProduct(s, v)
        # giving one (A,B) to the other side of the dot product
        # as_s = InnerProduct(matA_s0, tmp1) - InnerProduct(s[0], tmp0) + InnerProduct(matB_s1, tmp4)

        alpha = wd / as_s

        u.data += alpha * s
        d.data += (-alpha) * v

        # w.data = w_old + (-alpha) * MatOp.Cinv_K * s
        w[0].data = w[0] + (-alpha) * tmp1
        w[1].data = w[1] + (-alpha) * preM * tmp3

        wdn = InnerProduct(w, d)
        beta = wdn / wd

        z[0].data -= alpha * tmp2

        s *= beta
        s.data += w

        err = sqrt(abs(wd))
        if printrates:
            print("it = ", it, " err = ", err, " " * 20)
        if err < tol * (err0 if rel_err else 1):
            break
    else:
        print("Warning: BPCG did not converge to TOL")

    timer_its.Stop()
    print("\n")
    return (it, timer_its.time)