Example #1
0
File: cgs.py Project: cfd-hust/PyNS
def cgs(a, phi, b, tol, verbose=False, max_iter=-1):
    # -----------------------------------------------------------------------------
    """
    Args:
      a: ...... Object of the type "Matrix", holding the system matrix.
      phi: .... Object of the type "Unknown" to be solved.
      b: ...... Three-dimensional array holding the source term.
      tol: .... Absolute solver tolerance
      verbose:  Logical variable setting if solver will be verbose (print
                info on Python console) or not.
      max_iter: Maxiumum number of iterations.
      
    Returns:
      x: Three-dimensional array with solution.
    """

    if verbose is True:
        write.at(__name__)

    # Helping variable
    x = phi.val

    # Intitilize arrays
    p = zeros(x.shape)
    p_hat = Unknown("vec_p_hat",
                    phi.pos,
                    x.shape,
                    -1,
                    per=phi.per,
                    verbose=False)
    q = zeros(x.shape)
    r = zeros(x.shape)
    r_tilda = zeros(x.shape)
    u = zeros(x.shape)
    u_hat = Unknown("vec_u_hat",
                    phi.pos,
                    x.shape,
                    -1,
                    per=phi.per,
                    verbose=False)
    v_hat = zeros(x.shape)

    # r = b - A * x
    r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi)

    # Chose r~
    r_tilda[:, :, :] = r[:, :, :]

    # ---------------
    # Iteration loop
    # ---------------
    if max_iter == -1:
        max_iter = prod(phi.val.shape)

    for i in range(1, max_iter):

        if verbose is True:
            print("  iteration: %3d:" % (i), end="")

        # rho = r~ * r
        rho = vec_vec(r_tilda, r)

        # If rho == 0 method fails
        if abs(rho) < TINY * TINY:
            if verbose is True == True:
                write.at(__name__)
                print("  Fails becuase rho = %12.5e" % rho)
            return x

        if i == 1:
            # u = r
            u[:, :, :] = r[:, :, :]

            # p = u
            p[:, :, :] = u[:, :, :]

        else:
            # beta = rho / rho_old
            beta = rho / rho_old

            # u = r + beta q
            u[:, :, :] = r[:, :, :] + beta * q[:, :, :]

            # p = u + beta (q + beta p)
            p[:, :, :] = u[:, :, :] + beta * (q[:, :, :] + beta * p[:, :, :])

        # Solve M p_hat = p
        p_hat.val[:, :, :] = p[:, :, :] / a.C[:, :, :]

        # v^ = A * p^
        v_hat[:, :, :] = mat_vec_bnd(a, p_hat)

        # alfa = rho / (r~ * v^)
        alfa = rho / vec_vec(r_tilda, v_hat)

        # q = u - alfa v^
        q[:, :, :] = u[:, :, :] - alfa * v_hat[:, :, :]

        # Solve M u^ = u + q
        u_hat.val[:, :, :] = (u[:, :, :] + q[:, :, :]) / a.C[:, :, :]

        # x = x + alfa u^
        x[:, :, :] += alfa * u_hat.val[:, :, :]

        # q^ = A u^
        q_hat = mat_vec_bnd(a, u_hat)

        # r = r - alfa q^
        r[:, :, :] -= alfa * q_hat[:, :, :]

        # Compute residual
        res = norm(r)

        if verbose is True:
            print("%12.5e" % res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return x

        # Prepare for next iteration
        rho_old = rho

    return x  # end of function
Example #2
0
def main(show_plot=True, time_steps=12, plot_freq=1):

    # =============================================================================
    #
    # Define problem
    #
    # =============================================================================

    xn = nodes(0, 1, 64, 1.0 / 256, 1.0 / 256)
    yn = nodes(0, 1, 64, 1.0 / 256, 1.0 / 256)
    zn = nodes(0, 0.1, 5)

    # Cell dimensions
    nx, ny, nz, dx, dy, dz, rc, ru, rv, rw = cartesian_grid(xn, yn, zn)

    # Set physical properties
    grashof = 1.4105E+06
    prandtl = 0.7058
    rho = zeros(rc)
    mu = zeros(rc)
    kappa = zeros(rc)
    cap = zeros(rc)
    rho[:, :, :] = 1.0
    mu[:, :, :] = 1.0 / sqrt(grashof)
    kappa[:, :, :] = 1.0 / (prandtl * sqrt(grashof))
    cap[:, :, :] = 1.0

    # Time-stepping parameters
    dt = 2  # time step
    ndt = time_steps  # number of time steps

    # Create unknowns; names, positions and sizes
    uf = Unknown("face-u-vel", X, ru, DIRICHLET)
    vf = Unknown("face-v-vel", Y, rv, DIRICHLET)
    wf = Unknown("face-w-vel", Z, rw, DIRICHLET)
    t = Unknown("temperature", C, rc, NEUMANN)
    p = Unknown("pressure", C, rc, NEUMANN)
    p_tot = Unknown("total-pressure", C, rc, NEUMANN)

    # This is a new test
    t.bnd[W].typ[:] = DIRICHLET
    t.bnd[W].val[:] = -0.5

    t.bnd[E].typ[:] = DIRICHLET
    t.bnd[E].val[:] = +0.5

    for j in (B, T):
        uf.bnd[j].typ[:] = NEUMANN
        vf.bnd[j].typ[:] = NEUMANN
        wf.bnd[j].typ[:] = NEUMANN


# =============================================================================
#
# Solution algorithm
#
# =============================================================================

# ----------
#
# Time loop
#
# ----------
    for ts in range(1, ndt + 1):

        write.time_step(ts)

        # -----------------
        # Store old values
        # -----------------
        t.old[:] = t.val[:]
        uf.old[:] = uf.val[:]
        vf.old[:] = vf.val[:]
        wf.old[:] = wf.val[:]

        # ---------------------------
        # Start inner iteration loop
        # ---------------------------

        # Allocate space for results from previous iteration
        t_prev = zeros(rc)
        u_prev = zeros(ru)
        v_prev = zeros(rv)
        w_prev = zeros(rw)

        for inner in range(1, 33):

            write.iteration(inner)

            # Store results from previous iteration
            t_prev[:] = t.val[:]
            u_prev[:] = uf.val[:]
            v_prev[:] = vf.val[:]
            w_prev[:] = wf.val[:]

            # Temperature (enthalpy)
            calc_t(t, (uf, vf, wf), (rho * cap),
                   kappa,
                   dt, (dx, dy, dz),
                   advection_scheme="upwind",
                   under_relaxation=0.75)

            # Momentum conservation
            ext_f = zeros(ru), avg(Y, t.val), zeros(rw)

            calc_uvw((uf, vf, wf), (uf, vf, wf),
                     rho,
                     mu,
                     dt, (dx, dy, dz),
                     pressure=p_tot,
                     force=ext_f,
                     advection_scheme="upwind",
                     under_relaxation=0.75)

            # Pressure
            calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), verbose=False)

            p_tot.val += 0.25 * p.val

            # Velocity correction
            corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), verbose=False)

            # Print differences in results between two iterations
            t_diff = abs(t.val[:] - t_prev)
            u_diff = abs(uf.val[:] - u_prev)
            v_diff = abs(vf.val[:] - v_prev)
            w_diff = abs(wf.val[:] - w_prev)
            print("t_diff = ", norm(t_diff))
            print("u_diff = ", norm(u_diff))
            print("v_diff = ", norm(v_diff))
            print("w_diff = ", norm(w_diff))

        # --------------------------------------------------
        # Check the CFL number at the end of iteration loop
        # --------------------------------------------------
        cfl = cfl_max((uf, vf, wf), dt, (dx, dy, dz))

        # =============================================================================
        #
        # Visualisation
        #
        # =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                plot.isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z)
                plot.gmv("tdc-staggered-%6.6d" % ts, (xn, yn, zn),
                         (uf, vf, wf, t))
Example #3
0
def jacobi(a, phi, b, tol, verbose=False, max_iter=-1):
    # -----------------------------------------------------------------------------
    """
    Args:
      a: ...... Object of the type "Matrix", holding the system matrix.
      phi: .... Object of the type "Unknown" to be solved.
      b: ...... Three-dimensional array holding the source term.
      tol: .... Absolute solver tolerance
      verbose:  Logical variable setting if solver will be verbose (print
                info on Python console) or not.
      max_iter: Maxiumum number of iterations.

    Returns:
      phi.val: Three-dimensional array with solution.
    """

    if verbose is True:
        write.at(__name__)

    sum = zeros(phi.val.shape)
    r = zeros(phi.val.shape)

    if max_iter == -1:
        max_iter = prod(phi.val.shape)

    # Under-relaxation factor
    alfa = 0.9

    # Main iteration loop
    for iter in range(0, max_iter):

        if verbose is True:
            print("  iteration: %3d:" % (iter), end="")

        # Add source term
        sum[:] = b[:]

        # Add contribution from west and east
        sum[:1, :, :] += a.W[:1, :, :] * phi.bnd[W].val[:1, :, :]
        sum[-1:, :, :] += a.E[-1:, :, :] * phi.bnd[E].val[:1, :, :]

        # Add up west and east neighbors from the inside
        sum[1:, :, :] += a.W[1:, :, :] * phi.val[:-1, :, :]
        sum[:-1, :, :] += a.E[:-1, :, :] * phi.val[1:, :, :]

        # Add contribution from south and north
        sum[:, :1, :] += a.S[:, :1, :] * phi.bnd[S].val[:, :1, :]
        sum[:, -1:, :] += a.N[:, -1:, :] * phi.bnd[N].val[:, :1, :]

        # Add up south and north neighbors from the inside
        sum[:, 1:, :] += a.S[:, 1:, :] * phi.val[:, :-1, :]
        sum[:, :-1, :] += a.N[:, :-1, :] * phi.val[:, 1:, :]

        # Add contribution from bottom and top
        sum[:, :, :1] += a.B[:, :, :1] * phi.bnd[B].val[:, :, :1]
        sum[:, :, -1:] += a.T[:, :, -1:] * phi.bnd[T].val[:, :, :1]

        # Add up south and north neighbors from the inside
        sum[:, :, 1:] += a.B[:, :, 1:] * phi.val[:, :, :-1]
        sum[:, :, :-1] += a.T[:, :, :-1] * phi.val[:, :, 1:]

        phi.val[:,:,:] = (1.0 - alfa) * phi.val[:,:,:]   \
                       +        alfa  * sum[:,:,:] / a.C[:,:,:]
        phi.exchange()

        # r = b - A * x
        r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi)

        # Compute residual
        res = norm(r)

        if verbose is True:
            print("%12.5e" % res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return phi.val

    return phi.val  # end of function
Example #4
0
File: bicgstab.py Project: pya/PyNS
def bicgstab(a, phi, b, tol, ver):
# -----------------------------------------------------------------------------
    """
    Args:
      a:   System matrix in PyNS format (which ssentially means storing a
           bundle of non-zero diagonals in compas directions)
      phi: Unknown to be solved (from "create_unknown" function)
      b:   Three-dimensional matrix holding the source term.
      tol: Absolute solver tolerance
      ver: Logical variable setting if solver will be verbatim (print
           info on Python console) or not.

    Returns:
      x: Three-dimensional matrix with solution.

    Note:
      One should also consider implementing periodic boundary conditions
      in this version of the solver.
    """

    if ver:
        print("Solver: BiCGStab")

    # Helping variables
    x = phi.val
    n = prod(x.shape)

    # Intitilize arrays
    p       = zeros(x.shape)
    p_hat   = zeros(x.shape)
    r       = zeros(x.shape)
    r_tilda = zeros(x.shape)
    s       = zeros(x.shape)
    s_hat   = zeros(x.shape)
    v       = zeros(x.shape)

    # r = b - A * x
    r[:,:,:] = b[:,:,:] - mat_vec_bnd(a, phi)

    # Chose r~
    r_tilda[:,:,:] = r[:,:,:]

    # ---------------
    # Iteration loop
    # ---------------
    for i in range(1,n):

        if ver:
            print("  iteration: %3d:" % (i), end = "" )

        # rho = r~ * r
        rho = vec_vec(r_tilda, r)

        # If rho == 0 method fails
        if abs(rho) < TINY * TINY:
            print("bicgstab fails becuase rho = %12.5e" % rho)
            return x

        if i == 1:
            # p = r
            p[:,:,:] = r[:,:,:]

        else:
            # beta = (rho / rho_old)(alfa/omega)
            beta = rho / rho_old * alfa / omega

            # p = r + beta (p - omega v)
            p[:,:,:] = r[:,:,:] + beta * (p[:,:,:] - omega * v[:,:,:])

        # Solve M p_hat = p
        p_hat[:,:,:] = p[:,:,:] / a.P[:,:,:]

        # v = A * p^
        v[:,:,:] = mat_vec(a, p_hat)

        # alfa = rho / (r~ * v)
        alfa = rho / vec_vec(r_tilda, v)

        # s = r - alfa v
        s[:,:,:] = r[:,:,:] - alfa * v[:,:,:]

        # Check norm of s, if small enough set x = x + alfa p_hat and stop
        res = norm(s)
        if res < tol:
            if ver:
                print("%12.5e" %res)
            x[:,:,:] += alfa * p_hat[:,:,:]
            return x

        # Solve M s^ = s
        s_hat[:,:,:] = s[:,:,:] / a.P[:,:,:]

        # t = A s^
        t = mat_vec(a, s_hat)

        # omega = (t * s) / (t * t)
        omega = vec_vec(t, s) / vec_vec(t, t)

        # x = x + alfa p^ + omega * s^
        x[:,:,:] += alfa * p_hat[:,:,:] + omega * s_hat[:,:,:]

        # r = s - omega q^
        r[:,:,:] = s[:,:,:] - omega * t[:,:,:]

        # Compute residual
        res = norm(r)

        if ver:
            print("%12.5e" %res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return x

        # Prepare for next iteration
        rho_old = rho

    return x  # end of function
Example #5
0
def cgs(a, phi, b, tol, ver):
    # -----------------------------------------------------------------------------
    """
    Args:
      a:   System matrix in PyNS format (which ssentially means storing a
           bundle of non-zero diagonals in compas directions)
      phi: Unknown to be solved (from "create_unknown" function)
      b:   Three-dimensional matrix holding the source term.
      tol: Absolute solver tolerance
      ver: Logical variable setting if solver will be verbatim (print
           info on Python console) or not.

    Returns:
      x: Three-dimensional matrix with solution.

    Note:
      One should also consider implementing periodic boundary conditions
      in this version of the solver.
    """

    if ver:
        print("Solver: CGS")

    # Helping variables
    x = phi.val
    n = prod(x.shape)

    # Intitilize arrays
    p = zeros(x.shape)
    p_hat = zeros(x.shape)
    q = zeros(x.shape)
    r = zeros(x.shape)
    r_tilda = zeros(x.shape)
    u = zeros(x.shape)
    u_hat = zeros(x.shape)
    v_hat = zeros(x.shape)

    # r = b - A * x
    r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi)

    # Chose r~
    r_tilda[:, :, :] = r[:, :, :]

    # ---------------
    # Iteration loop
    # ---------------
    for i in range(1, n):

        if ver:
            print("  iteration: %3d:" % (i), end="")

        # rho = r~ * r
        rho = vec_vec(r_tilda, r)

        # If rho == 0 method fails
        if abs(rho) < TINY * TINY:
            print("cgs fails becuase rho = %12.5e" % rho)
            return x

        if i == 1:
            # u = r
            u[:, :, :] = r[:, :, :]

            # p = u
            p[:, :, :] = u[:, :, :]

        else:
            # beta = rho / rho_old
            beta = rho / rho_old

            # u = r + beta q
            u[:, :, :] = r[:, :, :] + beta * q[:, :, :]

            # p = u + beta (q + beta p)
            p[:, :, :] = u[:, :, :] + beta * (q[:, :, :] + beta * p[:, :, :])

        # Solve M p_hat = p
        p_hat[:, :, :] = p[:, :, :] / a.P[:, :, :]

        # v^ = A * p^
        v_hat[:, :, :] = mat_vec(a, p_hat)

        # alfa = rho / (r~ * v^)
        alfa = rho / vec_vec(r_tilda, v_hat)

        # q = u - alfa v^
        q[:, :, :] = u[:, :, :] - alfa * v_hat[:, :, :]

        # Solve M u^ = u + q
        u_hat[:, :, :] = (u[:, :, :] + q[:, :, :]) / a.P[:, :, :]

        # x = x + alfa u^
        x[:, :, :] += alfa * u_hat[:, :, :]

        # q^ = A u^
        q_hat = mat_vec(a, u_hat)

        # r = r - alfa q^
        r[:, :, :] -= alfa * q_hat[:, :, :]

        # Compute residual
        res = norm(r)

        if ver:
            print("%12.5e" % res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return x

        # Prepare for next iteration
        rho_old = rho

    return x  # end of function
Example #6
0
def bicgstab(a, phi, b, tol, verbose=False, max_iter=-1):
    # -----------------------------------------------------------------------------
    """
    Args:
      a: ...... Object of the type "Matrix", holding the system matrix.
      phi: .... Object of the type "Unknown" to be solved.
      b: ...... Three-dimensional array holding the source term.
      tol: .... Absolute solver tolerance
      verbose:  Logical variable setting if solver will be verbose (print
                info on Python console) or not.
      max_iter: Maxiumum number of iterations.

    Returns:
      x: Three-dimensional array with solution.
    """

    if verbose is True:
        write.at(__name__)

    # Helping variable
    x = phi.val

    # Intitilize arrays
    p = zeros(x.shape)
    p_hat = Unknown("vec_p_hat",
                    phi.pos,
                    x.shape,
                    -1,
                    per=phi.per,
                    verbose=False)
    r = zeros(x.shape)
    r_tilda = zeros(x.shape)
    s = zeros(x.shape)
    s_hat = Unknown("vec_s_hat",
                    phi.pos,
                    x.shape,
                    -1,
                    per=phi.per,
                    verbose=False)
    v = zeros(x.shape)

    # r = b - A * x
    r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi)

    # Chose r~
    r_tilda[:, :, :] = r[:, :, :]

    # ---------------
    # Iteration loop
    # ---------------
    if max_iter == -1:
        max_iter = prod(phi.val.shape)

    for i in range(1, max_iter):

        if verbose is True:
            print("  iteration: %3d:" % (i), end="")

        # rho = r~ * r
        rho = vec_vec(r_tilda, r)

        # If rho == 0 method fails
        if abs(rho) < TINY * TINY:
            write.at(__name__)
            print("  Fails becuase rho = %12.5e" % rho)
            return x

        if i == 1:
            # p = r
            p[:, :, :] = r[:, :, :]

        else:
            # beta = (rho / rho_old)(alfa/omega)
            beta = rho / rho_old * alfa / omega

            # p = r + beta (p - omega v)
            p[:, :, :] = r[:, :, :] + beta * (p[:, :, :] - omega * v[:, :, :])

        # Solve M p_hat = p
        p_hat.val[:, :, :] = p[:, :, :] / a.C[:, :, :]

        # v = A * p^
        v[:, :, :] = mat_vec_bnd(a, p_hat)

        # alfa = rho / (r~ * v)
        alfa = rho / vec_vec(r_tilda, v)

        # s = r - alfa v
        s[:, :, :] = r[:, :, :] - alfa * v[:, :, :]

        # Check norm of s, if small enough set x = x + alfa p_hat and stop
        res = norm(s)
        if res < tol:
            if verbose is True == True:
                write.at(__name__)
                print("  Fails becuase rho = %12.5e" % rho)
            x[:, :, :] += alfa * p_hat.val[:, :, :]
            return x

        # Solve M s^ = s
        s_hat.val[:, :, :] = s[:, :, :] / a.C[:, :, :]

        # t = A s^
        t = mat_vec_bnd(a, s_hat)

        # omega = (t * s) / (t * t)
        omega = vec_vec(t, s) / vec_vec(t, t)

        # x = x + alfa p^ + omega * s^
        x[:, :, :] += alfa * p_hat.val[:, :, :] + omega * s_hat.val[:, :, :]

        # r = s - omega q^
        r[:, :, :] = s[:, :, :] - omega * t[:, :, :]

        # Compute residual
        res = norm(r)

        if verbose is True:
            print("%12.5e" % res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return x

        # Prepare for next iteration
        rho_old = rho

    return x  # end of function
Example #7
0
def cg(a, phi, b, tol, ver):
    # -----------------------------------------------------------------------------
    """
    Args:
      a:   System matrix in PyNS format (which ssentially means storing a
           bundle of non-zero diagonals in compas directions)
      phi: Unknown to be solved (from "create_unknown" function)
      b:   Three-dimensional matrix holding the source term.
      tol: Absolute solver tolerance
      ver: Logical variable setting if solver will be verbatim (print
           info on Python console) or not.

    Returns:
      x: Three-dimensional matrix with solution.

    Note:
      One should also consider implementing periodic boundary conditions
      in this version of the solver.
    """

    if ver:
        print("Solver: CG")

    # Helping variables
    x = phi.val
    n = prod(x.shape)

    # Intitilize arrays
    p = zeros(x.shape)
    q = zeros(x.shape)
    r = zeros(x.shape)
    z = zeros(x.shape)

    # r = b - A * x
    r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi)

    # ---------------
    # Iteration loop
    # ---------------
    for i in range(1, n):

        if ver:
            print("  iteration: %3d:" % (i), end="")

        # Solve M z = r
        z[:, :, :] = r[:, :, :] / a.P[:, :, :]

        # rho = r * z
        rho = vec_vec(r, z)

        if i == 1:
            # p = z
            p[:, :, :] = z[:, :, :]

        else:
            # beta = rho / rho_old
            beta = rho / rho_old

            # p = z + beta p
            p[:, :, :] = z[:, :, :] + beta * p[:, :, :]

        # q = A * p
        q[:, :, :] = mat_vec(a, p)

        # alfa = rho / (p * q)
        alfa = rho / vec_vec(p, q)

        # x = x + alfa p
        x[:, :, :] += alfa * p[:, :, :]

        # r = r - alfa q
        r[:, :, :] -= alfa * q[:, :, :]

        # Compute residual
        res = norm(r)

        if ver:
            print("%12.5e" % res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return x

        # Prepare for next iteration
        rho_old = rho

    return x  # end of function
Example #8
0
def gamg_v_cycle(a, phi, b, tol, verbose=False, max_cycles=8, max_smooth=4):
    # -----------------------------------------------------------------------------
    """
    Args:
      a: ..... Object of the type "Matrix", holding the system matrix.
      phi: ... Object of the type "Unknown" to be solved.
      b: ..... Three-dimensional array holding the source term.
      tol: ... Absolute solver tolerance
      verbose: Logical variable setting if solver will be verbose (print
               info on Python console) or not.

    Returns:
      x: Three-dimensional array with solution.
    """

    if verbose is True:
        write.at(__name__)

    # ------------------
    #
    # Get system levels
    #
    # ------------------
    n_, shape_, a_, i_, d_, phi_, b_, r_ = gamg_coarsen_system(a, phi, b)

    # Set a couple of parameters for the solver
    n_steps = n_ - 1  # number of steps down the "V" cycle

    # -----------------------------------------------------
    #
    # Solve a bit on the finest level and compute residual
    #
    # -----------------------------------------------------
    grid = 0  # finest level
    phi_[grid].val = jacobi(a_[grid],
                            phi_[grid],
                            b_[grid],
                            TOL,
                            verbose=True,
                            max_iter=4)
    # r = b - A * x
    r_[grid].val[:] = b_[grid][:] - mat_vec_bnd(a_[grid], phi_[grid])
    if verbose is True:
        print("  residual at level %d" % grid, norm(r_[grid].val))

    # =========================================================================
    #
    # Start the V-cycle
    #
    # =========================================================================
    for cycle in range(0, max_cycles):

        if verbose is True:
            write.cycle(cycle)

        # --------------------
        #
        # Go down a few steps
        #
        # --------------------
        for level in range(1, n_steps + 1):
            grid = grid + 1

            # Compute ratio between grid levels
            rx = shape_[grid - 1][X] // shape_[grid][X]
            ry = shape_[grid - 1][Y] // shape_[grid][Y]
            rz = shape_[grid - 1][Z] // shape_[grid][Z]

            # Lower bounds for browsing through grid levels
            wl = 0
            el = 1
            sl = 0
            nl = 1
            bl = 0
            tl = 1

            if rx < 2:
                el = 0
            if ry < 2:
                nl = 0
            if rz < 2:
                tl = 0

            # -------------------------------------
            # Restrict
            #
            # Computes r.h.s. on the coarser level
            # from residual on the finer level.
            # -------------------------------------
            b_[grid][:] = r_[grid - 1].val[wl::rx, sl::ry, bl::rz]
            b_[grid][:] += r_[grid - 1].val[wl::rx, nl::ry, bl::rz]
            b_[grid][:] += r_[grid - 1].val[wl::rx, sl::ry, tl::rz]
            b_[grid][:] += r_[grid - 1].val[wl::rx, nl::ry, tl::rz]
            b_[grid][:] += r_[grid - 1].val[el::rx, sl::ry, bl::rz]
            b_[grid][:] += r_[grid - 1].val[el::rx, nl::ry, bl::rz]
            b_[grid][:] += r_[grid - 1].val[el::rx, sl::ry, tl::rz]
            b_[grid][:] += r_[grid - 1].val[el::rx, nl::ry, tl::rz]
            b_[grid][:] = b_[grid][:] / ((3 - rx) * (3 - ry) * (3 - rz))

            # ------------------------------------------------
            # Solve on the coarser level and compute residual
            # ------------------------------------------------
            phi_[grid].val[:] = 0  # nulify to forget previous corrections
            phi_[grid].val = jacobi(a_[grid],
                                    phi_[grid],
                                    b_[grid],
                                    TOL,
                                    verbose=False,
                                    max_iter=max_smooth)
            # r = b - A * x
            r_[grid].val[:] = b_[grid][:] - mat_vec_bnd(a_[grid], phi_[grid])
            if verbose is True:
                print("  residual at level %d" % grid, norm(r_[grid].val))

        # ==================================
        #
        # This is the bottom of the V-cycle
        #
        # ==================================

        # ------------------
        #
        # Go up a few steps
        #
        # ------------------
        for level in range(1, n_steps + 1):
            grid = grid - 1

            # Compute ratio between grid levels
            rx = shape_[grid][X] // shape_[grid + 1][X]
            ry = shape_[grid][Y] // shape_[grid + 1][Y]
            rz = shape_[grid][Z] // shape_[grid + 1][Z]

            # Lower bounds for browsing through grid levels
            wl = 0
            el = 1
            sl = 0
            nl = 1
            bl = 0
            tl = 1

            if rx < 2:
                el = 0
            if ry < 2:
                nl = 0
            if rz < 2:
                tl = 0

            # -------------------------------------------
            # Prolongation
            #
            # Interpolates the solution from the coarser
            # level as the correction to the current.
            # It also smoooths it out a little bit.
            # -------------------------------------------
            r_[grid].val[:] = 0

            # First copy in each available cell on fine level
            r_[grid].val[wl::rx, sl::ry, bl::rz] = phi_[grid + 1].val[:]

            # Then spread arond
            r_[grid].val[el::rx, sl::ry, bl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]
            r_[grid].val[wl::rx, nl::ry, bl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]
            r_[grid].val[el::rx, nl::ry, bl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]

            r_[grid].val[wl::rx, sl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]
            r_[grid].val[el::rx, sl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]
            r_[grid].val[wl::rx, nl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]
            r_[grid].val[el::rx, nl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry,
                                                                bl::rz]

            # Then smooth them out a little bit
            for smooth in range(0, max_smooth):
                r_[grid].exchange()
                summ = zeros((shape_[grid]))
                summ[:] += cat_x((r_[grid].bnd[W].val,
                                  r_[grid].val[:-1, :, :])) * a_[grid].W
                summ[:] += cat_x(
                    (r_[grid].val[1:, :, :], r_[grid].bnd[E].val)) * a_[grid].E
                summ[:] += cat_y((r_[grid].bnd[S].val,
                                  r_[grid].val[:, :-1, :])) * a_[grid].S
                summ[:] += cat_y(
                    (r_[grid].val[:, 1:, :], r_[grid].bnd[N].val)) * a_[grid].N
                summ[:] += cat_z((r_[grid].bnd[B].val,
                                  r_[grid].val[:, :, :-1])) * a_[grid].B
                summ[:] += cat_z(
                    (r_[grid].val[:, :, 1:], r_[grid].bnd[T].val)) * a_[grid].T
                r_[grid].val[:] = summ[:] / d_[grid][:]

            # -----------------------------------------------
            # Correction on the finer level, followed by a
            # bit of smoothing and computation of residuals.
            # -----------------------------------------------
            phi_[grid].val[:] += r_[grid].val[:]
            phi_[grid].val = jacobi(a_[grid],
                                    phi_[grid],
                                    b_[grid],
                                    TOL,
                                    verbose=False,
                                    max_iter=max_smooth)
            # r = b - A * x
            r_[grid].val[:] = b_[grid][:]  \
                                - mat_vec_bnd(a_[grid], phi_[grid])
            print("  residual at level %d" % grid, norm(r_[grid].val))

    return phi_[0].val  # end of function
Example #9
0
def cg(a, phi, b, tol, verbose=False, max_iter=-1):
    # -----------------------------------------------------------------------------
    """
    Args:
      a: ...... Object of the type "Matrix", holding the system matrix.
      phi: .... Object of the type "Unknown" to be solved.
      b: ...... Three-dimensional array holding the source term.
      tol: .... Absolute solver tolerance
      verbose:  Logical variable setting if solver will be verbose (print
                info on Python console) or not.
      max_iter: Maxiumum number of iterations.

    Returns:
      x: Three-dimensional array with solution.
    """

    if verbose is True:
        write.at(__name__)

    # Helping variable
    x = phi.val

    # Intitilize arrays
    p = Unknown("vec_p", phi.pos, x.shape, -1, per=phi.per, verbose=False)
    q = zeros(x.shape)
    r = zeros(x.shape)
    z = zeros(x.shape)

    # r = b - A * x
    r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi)

    # ---------------
    # Iteration loop
    # ---------------
    if max_iter == -1:
        max_iter = prod(phi.val.shape)

    for i in range(1, max_iter):

        if verbose is True:
            print("  iteration: %3d:" % (i), end="")

        # Solve M z = r
        z[:, :, :] = r[:, :, :] / a.C[:, :, :]

        # rho = r * z
        rho = vec_vec(r, z)

        if i == 1:
            # p = z
            p.val[:, :, :] = z[:, :, :]

        else:
            # beta = rho / rho_old
            beta = rho / rho_old

            # p = z + beta p
            p.val[:, :, :] = z[:, :, :] + beta * p.val[:, :, :]

        # q = A * p
        q[:, :, :] = mat_vec_bnd(a, p)

        # alfa = rho / (p * q)
        alfa = rho / vec_vec(p.val, q)

        # x = x + alfa p
        x[:, :, :] += alfa * p.val[:, :, :]

        # r = r - alfa q
        r[:, :, :] -= alfa * q[:, :, :]

        # Compute residual
        res = norm(r)

        if verbose is True:
            print("%12.5e" % res)

        # If tolerance has been reached, get out of here
        if res < tol:
            return x

        # Prepare for next iteration
        rho_old = rho

    return x  # end of function