Пример #1
0
def corr_uvw(uvw, p, rho, dt, dxyz, obstacle=None, verbose=True):
    # -----------------------------------------------------------------------------
    """
    Args:
      uvw: .... Tuple with three staggered or centered velocity components.
                (Each component is object of type "Unknown").
      p: ...... Unknown holding the pressure correction.
      rho: .... Three-dimensional array holding density for all cells.
      dt: ..... Time step
      dxyz: ... Tuple holding cell dimensions in "x", "y" and "z" directions.
                Each cell dimension is a three-dimensional array.
      obstacle: Obstacle, three-dimensional array with zeros and ones.
                It is zero in fluid, one in solid.

    Returns:
      None, but input argument uvw is modified.
    """

    # Unpack received tuples
    dx, dy, dz = dxyz

    # Compute pressure correction gradients
    p_x = dif_x(p.val) / avg_x(dx)
    p_y = dif_y(p.val) / avg_y(dy)
    p_z = dif_z(p.val) / avg_z(dz)

    # Set to zero in obst
    if obstacle is not None:
        p_x = obst_zero_val(X, p_x, obstacle)
        p_y = obst_zero_val(Y, p_y, obstacle)
        p_z = obst_zero_val(Z, p_z, obstacle)

    # Pad with boundary values by expanding from interior
    # (This is done only for collocated formulation)
    if uvw[X].pos == C:
        p_x = avg_x(cat_x((p_x[:1, :, :], p_x, p_x[-1:, :, :])))
        p_y = avg_y(cat_y((p_y[:, :1, :], p_y, p_y[:, -1:, :])))
        p_z = avg_z(cat_z((p_z[:, :, :1], p_z, p_z[:, :, -1:])))

    # Correct the velocities
    uvw[X].val[:] = uvw[X].val[:] - dt / avg(uvw[X].pos, rho) * p_x
    uvw[Y].val[:] = uvw[Y].val[:] - dt / avg(uvw[Y].pos, rho) * p_y
    uvw[Z].val[:] = uvw[Z].val[:] - dt / avg(uvw[Z].pos, rho) * p_z

    # Compute volume balance for checking
    if verbose is True:
        if not uvw[X].pos == C:
            err = vol_balance(uvw, (dx, dy, dz), obstacle)
            write.at(__name__)
            print("  Maximum volume error after correction: %12.5e" %
                  abs(err).max())

    return  # end of function
Пример #2
0
def calc_p(p, uvwf, rho, dt, dxyz, obstacle=None, verbose=True):
    # -----------------------------------------------------------------------------
    """
    Args:
      p: ...... Object of the type "Unknown", holding the pressure.
      uvwf: ... Tuple with three staggered velocity components (where each
                component is an object of type "Unknown".
      rho: .... Three-dimensional array holding density for all cells.
      dt: ..... Time step.
      dxyz: ... Tuple holding cell dimensions in "x", "y" and "z" directions.
                Each cell dimension is a three-dimensional array.
      obstacle: Obstacle, three-dimensional array with zeros and ones.
                It is zero in fluid, one in solid.

    Returns:
      None, but input argument p is modified!
    """

    # Fetch the resolution
    rc = p.val.shape

    # Create system matrix and right hand side
    A_p = diffusion(p, zeros(rc), dt / rho, dxyz, obstacle, NEUMANN)
    b_p = zeros(rc)

    # Compute the source for the pressure.  Important: don't send "obst"
    # as a parameter here, because you don't want to take it into
    # account at this stage.  After velocity corrections, you should.
    b_p = vol_balance(uvwf, dxyz, zeros(rc))

    if verbose is True:
        write.at(__name__)
        print("  Volume error before correction     : %12.5e" % abs(b_p).max())
        print("  Volume imbalance before correction : %12.5e" % b_p.sum())

    # Solve for pressure
    p.val[:] = bicgstab(A_p, p, b_p, TOL, False)

    # Anchor it to values around zero (the absolute value of pressure
    # correction can get really volatile.  Although it is in prinicple not
    # important for incompressible flows, it is ugly for post-processing.
    p.val[:] = p.val[:] - p.val.mean()

    # Set to zero in obstacle (it can get strange
    # values during the iterative solution procedure)
    if obstacle is not None:
        p.val[:] = obst_zero_val(p.pos, p.val, obstacle)

    # Finally adjust the boundary values
    adj_n_bnds(p)

    return  # end of function
Пример #3
0
def cfl_max(uvw, dt, dxyz, verbose=True):
    # -----------------------------------------------------------------------------
    """
    Args:
      uvw:  Tuple with three staggered or centered velocity components.
            (Each component is an object of type "Unknown".
      dt:   Time step
      dxyz: Tuple holding cell dimensions in "x", "y" and "z" directions.
            Each cell dimension is a three-dimensional array.

    Returns:
      cfl: Floating point number holding the maximum value of CFL.

    Note:
      It could be written in a more compact way, without unpacking the
      tuples, but that would only lead to poorer readability of the code.
    """

    # Unpack received tuples
    u, v, w = uvw
    dx, dy, dz = dxyz

    # Take velocity's position
    d = u.pos

    # Mesh is cell-centered
    if d == C:
        cfl = dt * max( abs(u.val/dx).max(),   \
                        abs(v.val/dy).max(),   \
                        abs(w.val/dz).max() )

    # Mesh is staggered
    else:
        cfl = dt * max( abs(u.val/avg_x(dx)).max(),   \
                        abs(v.val/avg_y(dy)).max(),   \
                        abs(w.val/avg_z(dz)).max() )

    if verbose is True:
        write.at(__name__)
        print("  Maximum CFL number: %12.5e" % cfl)

    return cfl
Пример #4
0
    def __init__(self,
                 name,
                 pos,
                 res,
                 default_bc,
                 per=(False, False, False),
                 verbose=False):
        # -------------------------------------------------------------------------
        """
        Args:
          name: ..... String holding the name of the variable.  
                      It is intended to be used for post-processing.
          pos: ...... Integer specifying if the variable is cell centered
                      (value C), staggered in "x" (value X), "y" (value Y)
                      or in "z" direction (value Z).
          res: ...... Vector specifying resolutions in "x", "y" and "z" 
                      directions.
          default_bc: Integer specifying if the default boundary condition is
                      of Dirichlet, Neumann or Outlet type.
          per: ...... Tuple holding three Boolean type variables which specify
                      if the unknown is periodic in "x", "y" or "z" direction.

        Returns:
          Oh well, its own self, isn't it?
        """

        if verbose is True:
            write.at(__name__)

        # Store name, position and resolution
        self.name = name
        self.pos = pos
        self.per = per
        self.nx, self.ny, self.nz = res

        # Allocate memory space for new and old values
        self.val = zeros((self.nx, self.ny, self.nz))
        self.old = zeros((self.nx, self.ny, self.nz))

        # Create boundary tuple
        nx, ny, nz = res
        key = namedtuple("key", "typ val")
        self.bnd = (key(ndarray(shape=(1, ny, nz), dtype=int),
                        zeros((1, ny, nz))),
                    key(ndarray(shape=(1, ny, nz), dtype=int),
                        zeros((1, ny, nz))),
                    key(ndarray(shape=(nx, 1, nz), dtype=int),
                        zeros((nx, 1, nz))),
                    key(ndarray(shape=(nx, 1, nz), dtype=int),
                        zeros((nx, 1, nz))),
                    key(ndarray(shape=(nx, ny, 1), dtype=int),
                        zeros((nx, ny, 1))),
                    key(ndarray(shape=(nx, ny, 1), dtype=int),
                        zeros((nx, ny, 1))))

        # Prescribe default boundary conditions
        if self.per[X] == False:
            self.bnd[W].typ[0, :, :] = default_bc
            self.bnd[E].typ[0, :, :] = default_bc
        else:
            if verbose is True:
                print("  ", self.name, "is periodic in x direction;", end="")
                print("  skipping default boundary condition for it!")
        if self.per[Y] == False:
            self.bnd[S].typ[:, 0, :] = default_bc
            self.bnd[N].typ[:, 0, :] = default_bc
        else:
            if verbose is True:
                print("  ", self.name, "is periodic in y direction;", end="")
                print("  skipping default boundary condition for it!")
        if self.per[Z] == False:
            self.bnd[B].typ[:, :, 0] = default_bc
            self.bnd[T].typ[:, :, 0] = default_bc
        else:
            if verbose is True:
                print("  ", self.name, "is periodic in z direction;", end="")
                print("  skipping default boundary condition for it!")

        self.bnd[W].val[0, :, :] = 0
        self.bnd[E].val[0, :, :] = 0
        self.bnd[S].val[:, 0, :] = 0
        self.bnd[N].val[:, 0, :] = 0
        self.bnd[B].val[:, :, 0] = 0
        self.bnd[T].val[:, :, 0] = 0

        if verbose is True:
            print("  Created unknown:", self.name)

        return  # end of function
Пример #5
0
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
Пример #6
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
Пример #7
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
Пример #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
Пример #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