示例#1
0
def cfl_max(uvw, dt, dxyz):
    #--------------------------------------------------------------------------
    """
    Docstring.
    """

    # 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())

    return cfl
示例#2
0
def corr_uvw(uvw, p, rho, dt, dxyz, obst):
    # --------------------------------------------------------------------------
    """
    Docstring.
    """
    # 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 obst.any() != 0:
        p_x = obst_zero_val(X, p_x, obst)
        p_y = obst_zero_val(Y, p_y, obst)
        p_z = obst_zero_val(Z, p_z, obst)

    # 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

    return  # end of function
示例#3
0
文件: par.py 项目: DanGiles/ScriNS-1
def par(mean_val, x_nodes):
    """
    A function to generate a parabolic profile over a set of cell centers,
    useful for specifying parabolic inlet velocity profiles.  It expects
    nodal coordinates as input, but sends values at cell centers back.

    Input coordinates:    |-----|-----|-----|-----|-----|-----|-----|
    Output values:           o-----o-----o-----o-----o-----o-----o

    Input parameters

    mean_val - mean value the parabola will have
    x_nodes  - nodal coordinatels
    -------------------------------------------------------------------------
    """

    # It is known that maximum of a parabola is 3/2 of its mean value
    max_val = mean_val * 3 / 2

    # Normalized x coordinates (from -1 to +1)
    xn = copy(x_nodes)

    xn -= xn.min()
    xn /= (xn.max() - xn.min())
    xn *= 2
    xn -= 1

    xc = avg(xn)

    yc = (1.0 - xc * xc) * max_val

    return yc  # end of function
示例#4
0
def plot_isolines(phi, uvw, xyzn, d):
    """
    Docstring.
    """

    # Unpack tuples
    u, v, w = uvw
    xn, yn, zn = xyzn

    # Cell coordinates
    xc = avg(xn)
    yc = avg(yn)
    zc = avg(zn)

    # Collocated velocity components
    if u.pos == C:
        uc = u.val
        vc = v.val
        wc = w.val
    else:
        uc = avg(X, cat(X, (u.bnd[W].val[:1, :, :], \
                          u.val,                  \
                          u.bnd[E].val[:1, :, :])))

        vc = avg(Y, cat(Y, (v.bnd[S].val[:, :1, :], \
                          v.val,                  \
                          v.bnd[N].val[:, :1, :])))

        wc = avg(Z, cat(Z, (w.bnd[B].val[:, :, :1], \
                          w.val,                  \
                          w.bnd[T].val[:, :, :1])))

    # Pick coordinates for plotting (xp, yp) and values for plotting
    if d == Y:
        jp = floor(yc.size / 2)
        xp, yp = meshgrid(xc, zc)
        zp = transpose(phi[:, jp, :], (1, 0))
        up = transpose(uc[:, jp, :], (1, 0))
        vp = transpose(wc[:, jp, :], (1, 0))
    if d == Z:
        kp = floor(zc.size / 2)
        xp, yp = meshgrid(xc, yc)
        zp = transpose(phi[:, :, kp], (1, 0))
        up = transpose(uc[:, :, kp], (1, 0))
        vp = transpose(vc[:, :, kp], (1, 0))

    # Set levels and normalize the colors
    levels = linspace(zp.min(), zp.max(), 11)
    norm = cm.colors.Normalize(vmax=zp.max(), vmin=zp.min())

    plt.figure()
    plt.gca(aspect='equal')
    plt.contour(xp, yp, zp, levels, cmap=plt.cm.rainbow, norm=norm)
    plt.quiver(xp, yp, up, vp)
    plt.axis([min(xn), max(xn), min(yn), max(yn)])
    plt.show()

    return  # end of function
示例#5
0
def adj_o_bnds(uvw, dxyz, dt):
    """
    Update velocities in boundary cells
    :param uvw: velocities u, v, w
    :param dxyz: deltas of x, y, z coordinates
    :param dt: time step
    :return:
    """

    # pylint:disable=invalid-name,too-many-locals,too-many-statements

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

    # Local variables used in this function
    area_in = 0.0  # area of the inlet
    area_out = 0.0  # area of the outlet
    vol_in = 0.0  # inlet volume flux; positive for inflow
    vol_out_1 = 0.0  # outlet volume flux; positive for outflow
    vol_out_2 = 0.0  # outlet volume flux; positive for outflow

    verbatim = False

    sx = dy * dz
    sy = dx * dz
    sz = dx * dy

    sx = sx[:1, :, :]
    sy = sy[:, :1, :]
    sz = sz[:, :, :1]

    # -----------------------------------------------------------------
    # Compute the volume flowing in (v_in), volume flowing out (v_out)
    # as well as inlet and outlet areas (a_in, a_out)
    # -----------------------------------------------------------------

    # Inlets: these arrays will hold values true (1) in cells
    # with inlet boundary conditions, and false (0) otherwise
    if_w_in = (u.bnd[W].typ[:1, :, :]
               == DIRICHLET) & (u.bnd[W].val[:1, :, :] > +TINY)
    if_e_in = (u.bnd[E].typ[:1, :, :]
               == DIRICHLET) & (u.bnd[E].val[:1, :, :] < -TINY)
    if_s_in = (v.bnd[S].typ[:, :1, :]
               == DIRICHLET) & (v.bnd[S].val[:, :1, :] > +TINY)
    if_n_in = (v.bnd[N].typ[:, :1, :]
               == DIRICHLET) & (v.bnd[N].val[:, :1, :] < -TINY)
    if_b_in = (w.bnd[B].typ[:, :, :1]
               == DIRICHLET) & (w.bnd[B].val[:, :, :1] > +TINY)
    if_t_in = (w.bnd[T].typ[:, :, :1]
               == DIRICHLET) & (w.bnd[T].val[:, :, :1] < -TINY)

    # Using the arrays defined above, compute inlet surface area
    area_in += (if_w_in * sx).sum()
    area_in += (if_e_in * sx).sum()
    area_in += (if_s_in * sy).sum()
    area_in += (if_n_in * sy).sum()
    area_in += (if_b_in * sz).sum()
    area_in += (if_t_in * sz).sum()

    # If there is no inlet, nothing to do here any longer
    if area_in < TINY:
        return u, v, w  # one end of function

    # Using the arrays defined above, compute inlet volume flux
    vol_in += (if_w_in * u.bnd[W].val[:1, :, :] * sx).sum()
    vol_in -= (if_e_in * u.bnd[E].val[:1, :, :] * sx).sum()
    vol_in += (if_s_in * v.bnd[S].val[:, :1, :] * sy).sum()
    vol_in -= (if_n_in * v.bnd[N].val[:, :1, :] * sy).sum()
    vol_in += (if_b_in * w.bnd[B].val[:, :, :1] * sz).sum()
    vol_in -= (if_t_in * w.bnd[T].val[:, :, :1] * sz).sum()

    # Outlets: these arrays will hold values true (1) in cells ...
    # with outlet boundary conditions, and false (0) otherwise
    if_w_out_u = (u.bnd[W].typ[:1, :, :] == OUTLET)
    if_w_out_v = avg(v.pos, if_w_out_u * 1) > 0.5
    if_w_out_w = avg(w.pos, if_w_out_u * 1) > 0.5

    if_e_out_u = (u.bnd[E].typ[:1, :, :] == OUTLET)
    if_e_out_v = avg(v.pos, if_e_out_u * 1) > 0.5
    if_e_out_w = avg(w.pos, if_e_out_u * 1) > 0.5

    if_s_out_v = (v.bnd[S].typ[:, :1, :] == OUTLET)
    if_s_out_u = avg(u.pos, if_s_out_v * 1) > 0.5
    if_s_out_w = avg(w.pos, if_s_out_v * 1) > 0.5

    if_n_out_v = (v.bnd[N].typ[:, :1, :] == OUTLET)
    if_n_out_u = avg(u.pos, if_n_out_v * 1) > 0.5
    if_n_out_w = avg(w.pos, if_n_out_v * 1) > 0.5

    if_b_out_w = (w.bnd[B].typ[:, :, :1] == OUTLET)
    if_b_out_u = avg(u.pos, if_b_out_w * 1) > 0.5
    if_b_out_v = avg(v.pos, if_b_out_w * 1) > 0.5

    if_t_out_w = (w.bnd[T].typ[:, :, :1] == OUTLET)
    if_t_out_u = avg(u.pos, if_t_out_w * 1) > 0.5
    if_t_out_v = avg(v.pos, if_t_out_w * 1) > 0.5

    # Using the arrays defined above, compute outlet surface area
    area_out += (if_w_out_u * sx).sum()
    area_out += (if_e_out_u * sx).sum()
    area_out += (if_s_out_v * sy).sum()
    area_out += (if_n_out_v * sy).sum()
    area_out += (if_b_out_w * sz).sum()
    area_out += (if_t_out_w * sz).sum()

    # Using the arrays defined above, compute outlet volume flux
    vol_out_1 -= (if_w_out_u * u.bnd[W].val[:1, :, :] * sx).sum()
    vol_out_1 += (if_e_out_u * u.bnd[E].val[:1, :, :] * sx).sum()
    vol_out_1 -= (if_s_out_v * v.bnd[S].val[:, :1, :] * sy).sum()
    vol_out_1 += (if_n_out_v * v.bnd[N].val[:, :1, :] * sy).sum()
    vol_out_1 -= (if_b_out_w * w.bnd[B].val[:, :, :1] * sz).sum()
    vol_out_1 += (if_t_out_w * w.bnd[T].val[:, :, :1] * sz).sum()

    # --------------------------------
    # Check and calculate corrections
    # --------------------------------

    if area_in == 0:
        ub_in = 0
    else:
        ub_in = vol_in / area_in

    if area_out == 0:
        ub_out = 0
    else:
        ub_out = vol_out_1 / area_out

    # ---------------------------------------------
    # If nothing comes out, make a bulk correction
    # ---------------------------------------------
    if ub_out < TINY:
        u_bulk_corr = ub_in * area_in / area_out

        u.bnd[W].val[:1, :, :] = (u.bnd[W].val[:1, :, :] * lnot(if_w_out_u) -
                                  u_bulk_corr * if_w_out_u)
        u.bnd[E].val[:1, :, :] = (u.bnd[E].val[:1, :, :] * lnot(if_e_out_u) +
                                  u_bulk_corr * if_e_out_u)
        v.bnd[S].val[:, :1, :] = (v.bnd[S].val[:, :1, :] * lnot(if_s_out_v) -
                                  u_bulk_corr * if_s_out_v)
        v.bnd[N].val[:, :1, :] = (v.bnd[N].val[:, :1, :] * lnot(if_n_out_v) +
                                  u_bulk_corr * if_n_out_v)
        w.bnd[B].val[:, :, :1] = (w.bnd[B].val[:, :, :1] * lnot(if_b_out_w) -
                                  u_bulk_corr * if_b_out_w)
        w.bnd[T].val[:, :, :1] = (w.bnd[T].val[:, :, :1] * lnot(if_t_out_w) +
                                  u_bulk_corr * if_t_out_w)

    # -------------------------------------------------------------
    # Correction outflow by applying convective boundary condition
    # -------------------------------------------------------------
    else:
        du_dx_w = (u.val[:1, :, :] - u.bnd[W].val[:1, :, :]) / dx[:1, :, :]
        dv_dx_w = ((v.val[:1, :, :] - v.bnd[W].val[:1, :, :]) /
                   avg(v.pos, dx[:1, :, :]))
        dw_dx_w = ((w.val[:1, :, :] - w.bnd[W].val[:1, :, :]) /
                   avg(w.pos, dx[:1, :, :]))

        du_dx_e = (u.val[-1:, :, :] - u.bnd[E].val[:1, :, :]) / dx[-1:, :, :]
        dv_dx_e = ((v.val[-1:, :, :] - v.bnd[E].val[:1, :, :]) /
                   avg(v.pos, dx[-1:, :, :]))
        dw_dx_e = ((w.val[-1:, :, :] - w.bnd[E].val[:1, :, :]) /
                   avg(w.pos, dx[-1:, :, :]))

        du_dy_s = ((u.val[:, :1, :] - u.bnd[S].val[:, :1, :]) /
                   avg(u.pos, dy[:, :1, :]))
        dv_dy_s = (v.val[:, :1, :] - v.bnd[S].val[:, :1, :]) / dy[:, :1, :]
        dw_dy_s = ((w.val[:, :1, :] - w.bnd[S].val[:, :1, :]) /
                   avg(w.pos, dy[:, :1, :]))

        du_dy_n = ((u.val[:, -1:, :] - u.bnd[N].val[:, :1, :]) /
                   avg(u.pos, dy[:, -1:, :]))
        dv_dy_n = (v.val[:, -1:, :] - v.bnd[N].val[:, :1, :]) / dy[:, -1:, :]
        dw_dy_n = ((w.val[:, -1:, :] - w.bnd[N].val[:, :1, :]) /
                   avg(w.pos, dy[:, -1:, :]))

        du_dz_b = ((u.val[:, :, :1] - u.bnd[B].val[:, :, :1]) /
                   avg(u.pos, dz[:, :, :1]))
        dv_dz_b = ((v.val[:, :, :1] - v.bnd[B].val[:, :, :1]) /
                   avg(v.pos, dz[:, :, :1]))
        dw_dz_b = (w.val[:, :, :1] - w.bnd[B].val[:, :, :1]) / dz[:, :, :1]

        du_dz_t = (((u.val[:, :, -1:] - u.bnd[T].val[:, :, :1]) /
                    avg(u.pos, dz[:, :, -1:])))
        dv_dz_t = ((v.val[:, :, -1:] - v.bnd[T].val[:, :, :1]) /
                   avg(v.pos, dz[:, :, -1:]))
        dw_dz_t = (w.val[:, :, -1:] - w.bnd[T].val[:, :, :1]) / dz[:, :, -1:]

        u_bnd_w_corr = (u.bnd[W].val[:1, :, :] + ub_out * dt * du_dx_w)
        v_bnd_w_corr = (v.bnd[W].val[:1, :, :] + ub_out * dt * dv_dx_w)
        w_bnd_w_corr = (w.bnd[W].val[:1, :, :] + ub_out * dt * dw_dx_w)

        u.bnd[W].val[:1, :, :] = (u.bnd[W].val[:1, :, :] * lnot(if_w_out_u) +
                                  u_bnd_w_corr * if_w_out_u)
        v.bnd[W].val[:1, :, :] = (v.bnd[W].val[:1, :, :] * lnot(if_w_out_v) +
                                  v_bnd_w_corr * if_w_out_v)
        w.bnd[W].val[:1, :, :] = (w.bnd[W].val[:1, :, :] * lnot(if_w_out_w) +
                                  w_bnd_w_corr * if_w_out_w)

        u_bnd_e_corr = (u.bnd[E].val[:1, :, :] + ub_out * dt * du_dx_e)
        v_bnd_e_corr = (v.bnd[E].val[:1, :, :] + ub_out * dt * dv_dx_e)
        w_bnd_e_corr = (w.bnd[E].val[:1, :, :] + ub_out * dt * dw_dx_e)

        u.bnd[E].val[:1, :, :] = (u.bnd[E].val[:1, :, :] * lnot(if_e_out_u) +
                                  u_bnd_e_corr * if_e_out_u)
        v.bnd[E].val[:1, :, :] = (v.bnd[E].val[:1, :, :] * lnot(if_e_out_v) +
                                  v_bnd_e_corr * if_e_out_v)
        w.bnd[E].val[:1, :, :] = (w.bnd[E].val[:1, :, :] * lnot(if_e_out_w) +
                                  w_bnd_e_corr * if_e_out_w)

        u_bnd_s_corr = (u.bnd[S].val[:, :1, :] + ub_out * dt * du_dy_s)
        v_bnd_s_corr = (v.bnd[S].val[:, :1, :] + ub_out * dt * dv_dy_s)
        w_bnd_s_corr = (w.bnd[S].val[:, :1, :] + ub_out * dt * dw_dy_s)

        u.bnd[S].val[:, :1, :] = (u.bnd[S].val[:, :1, :] * lnot(if_s_out_u) +
                                  u_bnd_s_corr * if_s_out_u)
        v.bnd[S].val[:, :1, :] = (v.bnd[S].val[:, :1, :] * lnot(if_s_out_v) +
                                  v_bnd_s_corr * if_s_out_v)
        w.bnd[S].val[:, :1, :] = (w.bnd[S].val[:, :1, :] * lnot(if_s_out_w) +
                                  w_bnd_s_corr * if_s_out_w)

        u_bnd_n_corr = (u.bnd[N].val[:, :1, :] + ub_out * dt * du_dy_n)
        v_bnd_n_corr = (v.bnd[N].val[:, :1, :] + ub_out * dt * dv_dy_n)
        w_bnd_n_corr = (w.bnd[N].val[:, :1, :] + ub_out * dt * dw_dy_n)

        u.bnd[N].val[:, :1, :] = (u.bnd[N].val[:, :1, :] * lnot(if_n_out_u) +
                                  u_bnd_n_corr * if_n_out_u)
        v.bnd[N].val[:, :1, :] = (v.bnd[N].val[:, :1, :] * lnot(if_n_out_v) +
                                  v_bnd_n_corr * if_n_out_v)
        w.bnd[N].val[:, :1, :] = (w.bnd[N].val[:, :1, :] * lnot(if_n_out_w) +
                                  w_bnd_n_corr * if_n_out_w)

        u_bnd_b_corr = (u.bnd[B].val[:, :, :1] + ub_out * dt * du_dz_b)
        v_bnd_b_corr = (v.bnd[B].val[:, :, :1] + ub_out * dt * dv_dz_b)
        w_bnd_b_corr = (w.bnd[B].val[:, :, :1] + ub_out * dt * dw_dz_b)

        u.bnd[B].val[:, :, :1] = (u.bnd[B].val[:, :, :1] * lnot(if_b_out_u) +
                                  u_bnd_b_corr * if_b_out_u)
        v.bnd[B].val[:, :, :1] = (v.bnd[B].val[:, :, :1] * lnot(if_b_out_v) +
                                  v_bnd_b_corr * if_b_out_v)
        w.bnd[B].val[:, :, :1] = (w.bnd[B].val[:, :, :1] * lnot(if_b_out_w) +
                                  w_bnd_b_corr * if_b_out_w)

        u_bnd_t_corr = (u.bnd[T].val[:, :, :1] + ub_out * dt * du_dz_t)
        v_bnd_t_corr = (v.bnd[T].val[:, :, :1] + ub_out * dt * dv_dz_t)
        w_bnd_t_corr = (w.bnd[T].val[:, :, :1] + ub_out * dt * dw_dz_t)

        u.bnd[T].val[:, :, :1] = (u.bnd[T].val[:, :, :1] * lnot(if_t_out_u) +
                                  u_bnd_t_corr * if_t_out_u)
        v.bnd[T].val[:, :, :1] = (v.bnd[T].val[:, :, :1] * lnot(if_t_out_v) +
                                  v_bnd_t_corr * if_t_out_v)
        w.bnd[T].val[:, :, :1] = (w.bnd[T].val[:, :, :1] * lnot(if_t_out_w) +
                                  w_bnd_t_corr * if_t_out_w)

    if verbatim:
        print('+----------------------------+')
        print('|  ub_in     = %12.5e  |' % ub_in)
        print('|  a_in      = %12.5e  |' % area_in)
        print('|  v_in      = %12.5e  |' % vol_in)
        print('|  ub_out    = %12.5e  |' % ub_out)
        print('|  a_out     = %12.5e  |' % area_out)
        print('|  v_out_1   = %12.5e  |' % vol_out_1)

    # ---------------------------------------------
    # Scaling correction to whatever you did above
    # (bulk correction or convective outflow)
    # ---------------------------------------------
    vol_out_2 = 0.0
    vol_out_2 -= (if_w_out_u * u.bnd[W].val[:1, :, :] * sx).sum()
    vol_out_2 += (if_e_out_u * u.bnd[E].val[:1, :, :] * sx).sum()
    vol_out_2 -= (if_s_out_v * v.bnd[S].val[:, :1, :] * sy).sum()
    vol_out_2 += (if_n_out_v * v.bnd[N].val[:, :1, :] * sy).sum()
    vol_out_2 -= (if_b_out_w * w.bnd[B].val[:, :, :1] * sz).sum()
    vol_out_2 += (if_t_out_w * w.bnd[T].val[:, :, :1] * sz).sum()

    if vol_out_2 > TINY:
        factor = vol_in / vol_out_2
    else:
        factor = 1.0

    if verbatim:
        print('+----------------------------+')
        print('|  v_out_2   = %12.5e  |' % vol_out_2)
        print('|  factor    = %12.5e  |' % factor)
        print('+----------------------------+')

    # -------------------------------------
    # Correction to satisfy volume balance
    # -------------------------------------
    u.bnd[W].val[:1, :, :] = (u.bnd[W].val[:1, :, :] * lnot(if_w_out_u) +
                              u.bnd[W].val[:1, :, :] * if_w_out_u * factor)
    u.bnd[E].val[:1, :, :] = (u.bnd[E].val[:1, :, :] * lnot(if_e_out_u) +
                              u.bnd[E].val[:1, :, :] * if_e_out_u * factor)
    v.bnd[S].val[:, :1, :] = (v.bnd[S].val[:, :1, :] * lnot(if_s_out_v) +
                              v.bnd[S].val[:, :1, :] * if_s_out_v * factor)
    v.bnd[N].val[:, :1, :] = (v.bnd[N].val[:, :1, :] * lnot(if_n_out_v) +
                              v.bnd[N].val[:, :1, :] * if_n_out_v * factor)
    w.bnd[B].val[:, :, :1] = (w.bnd[B].val[:, :, :1] * lnot(if_b_out_w) +
                              w.bnd[B].val[:, :, :1] * if_b_out_w * factor)
    w.bnd[T].val[:, :, :1] = (w.bnd[T].val[:, :, :1] * lnot(if_t_out_w) +
                              w.bnd[T].val[:, :, :1] * if_t_out_w * factor)
示例#6
0
def calc_uvw(uvw, uvwf, rho, mu, p_tot, e_f, dt, dxyz, obst):
    """
    Calculate uvw
    TODO: Write useful docstring

    :param uvw:
    :param uvwf:
    :param rho:
    :param mu:
    :param p_tot:
    :param e_f:
    :param dt:
    :param dxyz:
    :param obst:
    :return:
    """

    # pylint: disable=invalid-name, too-many-locals, too-many-statements

    # Unpack tuples
    u, v, w = uvw
    uf, vf, wf = uvwf
    dx, dy, dz = dxyz
    e_x, e_y, e_z = e_f

    # Fetch resolutions
    ru = u.val.shape
    rv = v.val.shape
    rw = w.val.shape

    # Pre-compute geometrical quantities
    dv = dx * dy * dz

    d = u.pos

    # Create linear systems
    A_u, b_u = create_matrix(u, rho / dt, mu, dxyz, obst, 'd')
    A_v, b_v = create_matrix(v, rho / dt, mu, dxyz, obst, 'd')
    A_w, b_w = create_matrix(w, rho / dt, mu, dxyz, obst, 'd')

    # Advection terms for momentum
    c_u = advection(rho, u, uvwf, dxyz, dt, 'superbee')
    c_v = advection(rho, v, uvwf, dxyz, dt, 'superbee')
    c_w = advection(rho, w, uvwf, dxyz, dt, 'superbee')

    # Innertial term for momentum (this works for collocated and staggered)
    i_u = u.old * avg(u.pos, rho) * avg(u.pos, dv) / dt
    i_v = v.old * avg(v.pos, rho) * avg(v.pos, dv) / dt
    i_w = w.old * avg(w.pos, rho) * avg(w.pos, dv) / dt

    # Compute staggered pressure gradients
    p_tot_x = dif(X, p_tot) / avg(X, dx)
    p_tot_y = dif(Y, p_tot) / avg(Y, dy)
    p_tot_z = dif(Z, p_tot) / avg(Z, dz)

    # Make pressure gradients cell-centered
    if d == C:
        p_tot_x = avg(X,
                      cat(X, (p_tot_x[:1, :, :], p_tot_x, p_tot_x[-1:, :, :])))
        p_tot_y = avg(Y,
                      cat(Y, (p_tot_y[:, :1, :], p_tot_y, p_tot_y[:, -1:, :])))
        p_tot_z = avg(Z,
                      cat(Z, (p_tot_z[:, :, :1], p_tot_z, p_tot_z[:, :, -1:])))

    # Total pressure gradients (this works for collocated and staggered)
    p_st_u = p_tot_x * avg(u.pos, dv)
    p_st_v = p_tot_y * avg(v.pos, dv)
    p_st_w = p_tot_z * avg(w.pos, dv)

    # Full force terms for momentum equations (collocated and staggered)
    f_u = b_u - c_u + i_u - p_st_u + e_x * avg(u.pos, dv)
    f_v = b_v - c_v + i_v - p_st_v + e_y * avg(v.pos, dv)
    f_w = b_w - c_w + i_w - p_st_w + e_z * avg(w.pos, dv)

    # Take care of obsts in the domian
    if obst.any() != 0:
        f_u = obst_zero_val(u.pos, f_u, obst)
        f_v = obst_zero_val(v.pos, f_v, obst)
        f_w = obst_zero_val(w.pos, f_w, obst)

    # Solve for velocities
    res0 = bicgstab(A_u, reshape(f_u, prod(ru)), tol=TOL)
    res1 = bicgstab(A_v, reshape(f_v, prod(rv)), tol=TOL)
    res2 = bicgstab(A_w, reshape(f_w, prod(rw)), tol=TOL)
    u.val[:] = reshape(res0[0], ru)
    v.val[:] = reshape(res1[0], rv)
    w.val[:] = reshape(res2[0], rw)

    # Update velocities in boundary cells
    adj_o_bnds((u, v, w), (dx, dy, dz), dt)

    # Update face velocities (also substract cell-centered pressure gradients
    #                         and add staggered pressure gradients)
    if d == C:
        uf.val[:] = (avg(X, u.val + dt / rho * (p_tot_x)) - dt / avg(X, rho) *
                     (dif(X, p_tot) / avg(X, dx)))
        vf.val[:] = (avg(Y, v.val + dt / rho * (p_tot_y)) - dt / avg(Y, rho) *
                     (dif(Y, p_tot) / avg(Y, dy)))
        wf.val[:] = (avg(Z, w.val + dt / rho * (p_tot_z)) - dt / avg(Z, rho) *
                     (dif(Z, p_tot) / avg(Z, dz)))

        for j in (W, E):
            uf.bnd[j].val[:] = u.bnd[j].val[:]
            vf.bnd[j].val[:] = avg(Y, v.bnd[j].val[:])
            wf.bnd[j].val[:] = avg(Z, w.bnd[j].val[:])
        for j in (S, N):
            uf.bnd[j].val[:] = avg(X, u.bnd[j].val[:])
            vf.bnd[j].val[:] = v.bnd[j].val[:]
            wf.bnd[j].val[:] = avg(Z, w.bnd[j].val[:])
        for j in (B, T):
            uf.bnd[j].val[:] = avg(X, u.bnd[j].val[:])
            vf.bnd[j].val[:] = avg(Y, v.bnd[j].val[:])
            wf.bnd[j].val[:] = w.bnd[j].val[:]

    else:
        uf.val[:] = u.val[:]
        vf.val[:] = v.val[:]
        wf.val[:] = w.val[:]
        for j in (W, E, S, N, B, T):
            uf.bnd[j].val[:] = u.bnd[j].val[:]
            vf.bnd[j].val[:] = v.bnd[j].val[:]
            wf.bnd[j].val[:] = w.bnd[j].val[:]

    if obst.any() != 0:
        uf.val[:] = obst_zero_val(X, uf.val, obst)
        vf.val[:] = obst_zero_val(Y, vf.val, obst)
        wf.val[:] = obst_zero_val(Z, wf.val, obst)

    return  # end of function
示例#7
0
def advection(rho, phi, uvwf, dxyz, dt, lim_name):
    """
    Docstring.
    """
    res = phi.val.shape
    nx, ny, nz = res

    # Unpack tuples
    uf, vf, wf = uvwf
    dx, dy, dz = dxyz

    d = phi.pos

    # Pre-compute geometrical quantities
    sx = dy * dz
    sy = dx * dz
    sz = dx * dy

    # -------------------------------------------------
    # Specific for cell-centered transported variable
    # -------------------------------------------------
    if d == C:

        # Facial values of physical properties including boundary cells
        rho_x_fac = cat(
            X, (rho[:1, :, :], avg(X, rho), rho[-1:, :, :]))  # nxp,ny, nz
        rho_y_fac = cat(
            Y, (rho[:, :1, :], avg(Y, rho), rho[:, -1:, :]))  # nx, nyp,nz
        rho_z_fac = cat(
            Z, (rho[:, :, :1], avg(Z, rho), rho[:, :, -1:]))  # nx, ny, nzp

        # Facial values of areas including boundary cells
        a_x_fac = cat(X, (sx[:1, :, :], avg(X, sx), sx[-1:, :, :]))
        a_y_fac = cat(Y, (sy[:, :1, :], avg(Y, sy), sy[:, -1:, :]))
        a_z_fac = cat(Z, (sz[:, :, :1], avg(Z, sz), sz[:, :, -1:]))

        del_x = avg(X, dx)
        del_y = avg(Y, dy)
        del_z = avg(Z, dz)

        # Facial values of velocities without boundary values
        u_fac = uf.val  # nxm,ny, nz
        v_fac = vf.val  # nx, nym,nz
        w_fac = wf.val  # nx, ny, nzm

        # Boundary velocity values
        u_bnd_W = uf.bnd[W].val
        u_bnd_E = uf.bnd[E].val
        v_bnd_S = vf.bnd[S].val
        v_bnd_N = vf.bnd[N].val
        w_bnd_B = wf.bnd[B].val
        w_bnd_T = wf.bnd[T].val

    # ------------------------------------------------------------
    # Specific for transported variable staggered in x direction
    # ------------------------------------------------------------
    if d == X:
        # Facial values of physical properties including boundary cells
        rho_x_fac = rho  # nx, ny, nz
        rho_nod_y = avg(X, avg(Y, rho))  # nxm,nym,nz
        rho_y_fac = cat(Y, (rho_nod_y[:, :1, :],     \
                            rho_nod_y[:, :, :],     \
                            rho_nod_y[:, -1:, :]))     # nxm,nyp,nz
        rho_nod_z = avg(X, avg(Z, rho))  # nxm,ny,nzm
        rho_z_fac = cat(Z, (rho_nod_z[:, :, :1],      \
                            rho_nod_z[:, :, :],      \
                            rho_nod_z[:, :, -1:]))     # nxm,ny,nzp

        # Facial values of areas including boundary cells
        a_x_fac = sx
        a_y_fac = cat(Y, ( \
                  avg(X, sy[:, :1, :]),\
                  avg(X, avg(Y, sy)), \
                  avg(X, sy[:, -1:, :])))
        a_z_fac = cat(Z, ( \
                  avg(X, sz[:, :, :1]), \
                  avg(X, avg(Z, sz)), \
                  avg(X, sz[:, :, -1:])))

        del_x = dx[1:-1, :, :]
        del_y = avg(X, avg(Y, dy))
        del_z = avg(X, avg(Z, dz))

        # Facial values of velocities without boundary values
        u_fac = avg(X, uf.val)  # nxmm,ny, nz
        v_fac = avg(X, vf.val)  # nxm, nym,nz
        w_fac = avg(X, wf.val)  # nxm, ny, nzm

        # Boundary velocity values
        u_bnd_W = uf.bnd[W].val
        u_bnd_E = uf.bnd[E].val
        v_bnd_S = avg(X, vf.bnd[S].val)
        v_bnd_N = avg(X, vf.bnd[N].val)
        w_bnd_B = avg(X, wf.bnd[B].val)
        w_bnd_T = avg(X, wf.bnd[T].val)

    # ------------------------------------------------------------
    # Specific for transported variable staggered in y direction
    # ------------------------------------------------------------
    if d == Y:
        # Facial values of physical properties including boundary cells
        rho_nod_x = avg(Y, avg(X, rho))  # nxm,nym,nz
        rho_x_fac = cat(X, (rho_nod_x[:1, :, :],      \
                            rho_nod_x[:, :, :],      \
                            rho_nod_x[-1:, :, :]))     # nxp,nym,nz
        rho_y_fac = rho  # nx, ny, nz
        rho_nod_z = avg(Y, avg(Z, rho))  # nx, nym,nzm
        rho_z_fac = cat(Z, (rho_nod_z[:, :, :1],      \
                            rho_nod_z[:, :, :],      \
                            rho_nod_z[:, :, -1:]))     # nx, nym,nzp

        # Facial values of areas including boundary cells
        a_x_fac = cat(X, (             \
                  avg(Y, sx[:1, :, :]),  \
                  avg(Y, avg(X, sx)),   \
                  avg(Y, sx[-1:, :, :])))
        a_y_fac = sy
        a_z_fac = cat(Z, (             \
                  avg(Y, sz[:, :, :1]),  \
                  avg(Y, avg(Z, sz)),   \
                  avg(Y, sz[:, :, -1:])))

        del_x = avg(Y, avg(X, dx))
        del_y = dy[:, 1:-1, :]
        del_z = avg(Y, avg(Z, dz))

        # Facial values of velocities without boundary values
        u_fac = avg(Y, uf.val)  # nxm,nym, nz
        v_fac = avg(Y, vf.val)  # nx, nymm,nz
        w_fac = avg(Y, wf.val)  # nx, nym, nzm

        # Facial values of velocities with boundary values
        u_bnd_W = avg(Y, uf.bnd[W].val)
        u_bnd_E = avg(Y, uf.bnd[E].val)
        v_bnd_S = vf.bnd[S].val
        v_bnd_N = vf.bnd[N].val
        w_bnd_B = avg(Y, wf.bnd[B].val)
        w_bnd_T = avg(Y, wf.bnd[T].val)

    # ------------------------------------------------------------
    # Specific for transported variable staggered in z direction
    # ------------------------------------------------------------
    if d == Z:

        # Facial values of physical properties including boundary cells
        rho_nod_x = avg(Z, avg(X, rho))  # nxm,ny, nzm
        rho_x_fac = cat(X, (rho_nod_x[ :1, :, :],      \
                            rho_nod_x[  :, :, :],      \
                            rho_nod_x[-1:, :, :]))     # nxp,ny, nzm
        rho_nod_y = avg(Z, avg(Y, rho))  # nx, nym,nzm
        rho_y_fac = cat(Y, (rho_nod_y[:, :1, :],      \
                            rho_nod_y[:, :, :],      \
                            rho_nod_y[:, -1:, :]))     # nx, nyp,nzm
        rho_z_fac = rho  # nx, ny, nz

        # Facial values of areas including boundary cells
        a_x_fac = cat(X, (             \
                  avg(Z, sx[:1, :, :]),  \
                  avg(Z, avg(X, sx)),   \
                  avg(Z, sx[-1:, :, :])))
        a_y_fac = cat(Y, (             \
                  avg(Z, sy[:, :1, :]),  \
                  avg(Z, avg(Y, sy)),   \
                  avg(Z, sy[:, -1:, :])))
        a_z_fac = sz

        del_x = avg(Z, avg(X, dx))
        del_y = avg(Z, avg(Y, dy))
        del_z = dz[:, :, 1:-1]

        # Facial values of velocities without boundary values
        u_fac = avg(Z, uf.val)  # nxm,ny,  nzm
        v_fac = avg(Z, vf.val)  # nx, nym, nzm
        w_fac = avg(Z, wf.val)  # nx, ny,  nzmm

        # Facial values of velocities with boundary values
        u_bnd_W = avg(Z, uf.bnd[W].val)
        u_bnd_E = avg(Z, uf.bnd[E].val)
        v_bnd_S = avg(Z, vf.bnd[S].val)
        v_bnd_N = avg(Z, vf.bnd[N].val)
        w_bnd_B = wf.bnd[B].val
        w_bnd_T = wf.bnd[T].val

    # ------------------------------
    # Common part of the algorithm
    # ------------------------------

    # ------------------------------------------------------------
    #
    #    |-o-|-o-|-o-|-o-|-o-|-o-|-o-|-o-|-o-|-o-|
    #      1   2   3   4   5   6   7   8   9   10     phi
    #        x---x---x---x---x---x---x---x---x
    #        1   2   3   4   5   6   7   8   9        d_x initial
    #    0---x---x---x---x---x---x---x---x---x---0
    #    1   2   3   4   5   6   7   8   9  10  11    d_x padded
    #
    # ------------------------------------------------------------

    # Compute consecutive differences (and avoid division by zero)
    d_x = dif(X, phi.val)  # nxm, ny, nz
    d_x[(d_x > -TINY) & (d_x <= 0.0)] = -TINY
    d_x[(d_x >= 0.0) & (d_x < +TINY)] = +TINY
    d_x = cat(X, (d_x[:1, :, :], d_x, d_x[-1:, :, :]))  # nxp, ny, nz

    d_y = dif(Y, phi.val)  # nx, nym, nz
    d_y[(d_y > -TINY) & (d_y <= 0.0)] = -TINY
    d_y[(d_y >= 0.0) & (d_y < +TINY)] = +TINY
    d_y = cat(Y, (d_y[:, :1, :], d_y, d_y[:, -1:, :]))  # nx, nyp, nz

    d_z = dif(Z, phi.val)  # nx, ny, nzm
    d_z[(d_z > -TINY) & (d_z <= 0.0)] = -TINY
    d_z[(d_z >= 0.0) & (d_z < +TINY)] = +TINY
    d_z = cat(Z, (d_z[:, :, :1], d_z, d_z[:, :, -1:]))  # nx, ny, nzp

    # Ratio of consecutive gradients for positive and negative flow
    r_x_we = d_x[1:-1, :, :] / d_x[0:-2, :, :]  # nxm,ny, nz
    r_x_ew = d_x[2:, :, :] / d_x[1:-1, :, :]  # nxm,ny, nz
    r_y_sn = d_y[:, 1:-1, :] / d_y[:, 0:-2, :]  # nx, nym,nz
    r_y_ns = d_y[:, 2:, :] / d_y[:, 1:-1, :]  # nx, nym,nz
    r_z_bt = d_z[:, :, 1:-1] / d_z[:, :, 0:-2]  # nx, ny, nzm
    r_z_tb = d_z[:, :, 2:] / d_z[:, :, 1:-1]  # nx, ny, nzm

    flow_we = u_fac >= 0
    flow_ew = lnot(flow_we)
    flow_sn = v_fac >= 0
    flow_ns = lnot(flow_sn)
    flow_bt = w_fac >= 0
    flow_tb = lnot(flow_bt)

    r_x = r_x_we * flow_we + r_x_ew * flow_ew
    r_y = r_y_sn * flow_sn + r_y_ns * flow_ns
    r_z = r_z_bt * flow_bt + r_z_tb * flow_tb

    # Apply a limiter
    if lim_name == 'upwind':
        psi_x = r_x * 0.0
        psi_y = r_y * 0.0
        psi_z = r_z * 0.0
    elif lim_name == 'minmod':
        psi_x = mx(zeros(r_x.shape), mn(r_x, ones(r_x.shape)))
        psi_y = mx(zeros(r_y.shape), mn(r_y, ones(r_y.shape)))
        psi_z = mx(zeros(r_z.shape), mn(r_z, ones(r_z.shape)))
    elif lim_name == 'superbee':
        psi_x = mx(zeros(r_x.shape), mn(2. * r_x, ones(r_x.shape)),
                   mn(r_x, 2.))
        psi_y = mx(zeros(r_y.shape), mn(2. * r_y, ones(r_y.shape)),
                   mn(r_y, 2.))
        psi_z = mx(zeros(r_z.shape), mn(2. * r_z, ones(r_z.shape)),
                   mn(r_z, 2.))
    elif lim_name == 'koren':
        psi_x = mx(zeros(r_x.shape), mn(2.*r_x, (2.+r_x)/3., \
                         2.*ones(r_x.shape)))
        psi_y = mx(zeros(r_y.shape), mn(2.*r_y, (2.+r_y)/3., \
                         2.*ones(r_y.shape)))
        psi_z = mx(zeros(r_z.shape), mn(2.*r_z, (2.+r_z)/3., \
                         2.*ones(r_z.shape)))

    flux_fac_lim_x = phi.val[0:-1, :, :] * u_fac * flow_we                 \
                     +   phi.val[1:, :, :] * u_fac * flow_ew               \
                     +   0.5 * abs(u_fac) * (1 - abs(u_fac) * dt / del_x)  \
                     *  (psi_x[:, :, :] * d_x[0:nx-1, :, :] * flow_we      \
                          + psi_x[:, :, :] * d_x[1:nx, :, :] * flow_ew)
    flux_fac_lim_y = phi.val[:, 0:-1, :] * v_fac * flow_sn                 \
                     +   phi.val[:, 1:, :] * v_fac * flow_ns               \
                     +   0.5 * abs(v_fac) * (1 - abs(v_fac) * dt / del_y)  \
                     *  (psi_y[:, :, :] * d_y[:, 0:ny-1, :] * flow_sn      \
                          + psi_y[:, :, :] * d_y[:, 1:ny, :] * flow_ns)
    flux_fac_lim_z = phi.val[:, :, 0:-1] * w_fac * flow_bt                 \
                     +   phi.val[:, :, 1:  ] * w_fac * flow_tb             \
                     +   0.5 * abs(w_fac) * (1 - abs(w_fac) * dt / del_z)  \
                     *  (psi_z[:, :, :] * d_z[:, :, 0:nz-1] * flow_bt      \
                          + psi_z[:, :, :] * d_z[:, :, 1:nz] * flow_tb)

    # Pad with boundary values
    flux_fac_lim_x = cat(X, (phi.bnd[W].val * u_bnd_W,      \
                               flux_fac_lim_x,              \
                               phi.bnd[E].val * u_bnd_E))
    flux_fac_lim_y = cat(Y, (phi.bnd[S].val * v_bnd_S,      \
                               flux_fac_lim_y,              \
                               phi.bnd[N].val * v_bnd_N))
    flux_fac_lim_z = cat(Z, (phi.bnd[B].val * w_bnd_B,      \
                               flux_fac_lim_z,              \
                               phi.bnd[T].val * w_bnd_T))

    # Multiply with face areas
    flux_fac_lim_x = rho_x_fac * flux_fac_lim_x * a_x_fac
    flux_fac_lim_y = rho_y_fac * flux_fac_lim_y * a_y_fac
    flux_fac_lim_z = rho_z_fac * flux_fac_lim_z * a_z_fac

    # Sum contributions from all directions up
    c = dif(X, flux_fac_lim_x) + \
        dif(Y, flux_fac_lim_y) + \
        dif(Z, flux_fac_lim_z)

    return c  # end of function
示例#8
0
def main(show_plot=True):
    """
    Docstring.
    """

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

    # Node coordinates
    xn = nodes(0, 10, 300)
    yn = nodes(0, 1, 40, 1 / 500, 1 / 500)
    zn = nodes(0, 3, 3)

    # Cell coordinates
    xc = avg(xn)
    yc = avg(yn)
    zc = avg(zn)

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

    # Set physical properties
    rho = zeros(rc)
    mu = zeros(rc)
    kappa = zeros(rc)
    cap = zeros(rc)
    rho[:, :, :] = 1.
    mu[:, :, :] = 0.1
    kappa[:, :, :] = 0.15
    cap[:, :, :] = 1.0

    # Time-stepping parameters
    dt = 0.003  # time step
    ndt = 1500  # number of time steps

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

    # Specify boundary conditions
    uf.bnd[W].typ[:1, :, :] = DIRICHLET
    for k in range(0, nz):
        uf.bnd[W].val[:1, :, k] = par(1.0, yn)

    uf.bnd[E].typ[:1, :, :] = OUTLET
    uf.bnd[E].val[:1, :, :] = 1.0

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

    t.bnd[W].typ[:1, :, :] = DIRICHLET
    for k in range(0, nz):
        t.bnd[W].val[:1, :, k] = 1.0 - yc

    t.bnd[S].typ[:, :1, :] = DIRICHLET
    t.bnd[S].val[:, :1, :] = +1.0
    t.bnd[N].typ[:, :1, :] = DIRICHLET
    t.bnd[N].val[:, :1, :] = 0.0

    adj_n_bnds(t)
    adj_n_bnds(p)

    # Specify initial conditions
    uf.val[:, :, :] = 1.0
    t.val[:, :, :] = 0

    obst = zeros(rc)

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

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

        print_time_step(ts)

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

        # ------------------------
        # Temperature (enthalpy)
        # ------------------------
        calc_t(t, (uf, vf, wf), (rho * cap), kappa, dt, (dx, dy, dz), obst)

        # -----------------------
        # Momentum conservation
        # -----------------------
        ef = zeros(ru), 150.0 * avg(Y, t.val), zeros(rw)

        calc_uvw((uf, vf, wf), (uf, vf, wf), rho, mu, \
                 zeros(rc), ef, dt, (dx, dy, dz), obst)

        # ----------
        # Pressure
        # ----------
        calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), obst)

        # ---------------------
        # Velocity correction
        # ---------------------
        corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), obst)

        # Compute volume balance for checking
        err = vol_balance((uf, vf, wf), (dx, dy, dz), obst)
        print('Maximum volume error after correction: %12.5e' % abs(err).max())

        # Check the CFL number too
        cfl = cfl_max((uf, vf, wf), dt, (dx, dy, dz))
        print('Maximum CFL number: %12.5e' % cfl)

        # =====================================================================
        #
        # Visualisation
        #
        # =====================================================================
        if show_plot:
            if ts % 150 == 0:
                plot_isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z)
                plot_isolines(p.val, (uf, vf, wf), (xn, yn, zn), Z)
示例#9
0
def main(show_plot=True):
    """
    inlet example
    :param show_plot: show plot or not
    :return: None
    """

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

    planes = ('XY', 'XZ', 'YZ')
    tests = array([11, 12, 13, 14, \
                   21, 22, 23, 24, \
                   31, 32, 33, 34, \
                   41, 42, 43, 44])
    TEST = tests[floor(random() * 16)]
    PLANE = planes[floor(random() * 3)]

    # Node coordinates
    xn = nodes(0, 1, 160)
    yn = nodes(0, 1, 160)
    zn = nodes(0, 0.025, 4)

    # Cell coordinates
    xc = avg(xn)
    yc = avg(yn)
    zc = avg(zn)

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

    # Set physical properties
    rho, mu, cap, kappa = properties_for_air(rc)

    # Time-stepping parameters
    dt = 0.15  # time step
    ndt = 200  # number of time steps

    # Create unknowns names, positions and sizes
    uf = create_unknown('face-u-vel', X, ru, DIRICHLET)
    vf = create_unknown('face-v-vel', Y, rv, DIRICHLET)
    wf = create_unknown('face-w-vel', Z, rw, DIRICHLET)
    p = create_unknown('pressure', C, rc, NEUMANN)

    print(TEST)

    # Specify boundary conditions
    if TEST == 11:
        for k in range(0, nz):
            uf.bnd[W].val[0, ny // 4:3 * ny // 4,
                          k] = +par(0.01, yn[ny // 4:3 * ny // 4 + 1])
            uf.bnd[E].typ[0, ny // 4:3 * ny // 4, k] = OUTLET

    elif TEST == 12:  # vertical mirror from 11
        for k in range(0, nz):
            uf.bnd[E].val[0, ny // 4:3 * ny // 4,
                          k] = -par(0.01, yn[ny // 4:3 * ny // 4 + 1])
            uf.bnd[W].typ[0, ny // 4:3 * ny // 4, k] = OUTLET

    elif TEST == 13:  # rotate 11
        for k in range(0, nz):
            vf.bnd[S].val[nx // 4:3 * nx // 4, 0,
                          k] = +par(0.01, xn[nx // 4:3 * nx // 4 + 1])
            vf.bnd[N].typ[nx // 4:3 * nx // 4, 0, k] = OUTLET

    elif TEST == 14:  # horizontal mirror 13
        for k in range(0, nz):
            vf.bnd[N].val[nx // 4:3 * nx // 4, 0,
                          k] = -par(0.01, xn[nx // 4:3 * nx // 4 + 1])
            vf.bnd[S].typ[nx // 4:3 * nx // 4, 0, k] = OUTLET

    elif TEST == 21:  # 2 exits
        for k in range(0, nz):
            uf.bnd[W].val[0, ny // 4:3 * ny // 4,
                          k] = +par(0.01, yn[ny // 4:3 * ny // 4 + 1])
            uf.bnd[E].typ[0, 0:ny // 4, k] = OUTLET
            uf.bnd[E].typ[0, 3 * ny // 4:ny, k] = OUTLET

    elif TEST == 22:  # vertical mirror 21
        for k in range(0, nz):
            uf.bnd[E].val[0, ny // 4:3 * ny // 4,
                          k] = -par(0.01, yn[ny // 4:3 * ny // 4 + 1])
            uf.bnd[W].typ[0, 0:ny // 4, k] = OUTLET
            uf.bnd[W].typ[0, 3 * ny // 4:ny, k] = OUTLET

    elif TEST == 23:  # rotated 21
        for k in range(0, nz):
            vf.bnd[S].val[nx // 4:3 * nx // 4, 0,
                          k] = +par(0.01, xn[nx // 4:3 * nx // 4 + 1])
            vf.bnd[N].typ[:nx // 4, 0, k] = OUTLET
            vf.bnd[N].typ[3 * nx // 4:nx, 0, k] = OUTLET

    elif TEST == 24:  # horizontal mirror of 23
        for k in range(0, nz):
            vf.bnd[N].val[nx // 4:3 * nx // 4, 0,
                          k] = -par(0.01, xn[nx // 4:3 * nx // 4 + 1])
            vf.bnd[S].typ[:nx // 4, 0, k] = OUTLET
            vf.bnd[S].typ[3 * nx // 4:nx, 0, k] = OUTLET

    elif TEST == 31:  # inlet and outlet at the same face
        for k in range(0, nz):
            uf.bnd[W].val[0, 3 * ny // 4:ny,
                          k] = +par(0.01, yn[3 * ny // 4:ny + 1])
            uf.bnd[W].typ[0, :ny // 4, k] = OUTLET

    elif TEST == 32:  # vertical mirror of 31
        for k in range(0, nz):
            uf.bnd[E].val[0, 3 * ny // 4:ny,
                          k] = -par(0.01, yn[3 * ny // 4:ny + 1])
            uf.bnd[E].typ[0, 0:ny // 4, k] = OUTLET

    elif TEST == 33:  # rotated 31
        for k in range(0, nz):
            vf.bnd[S].val[3 * nx // 4:nx, 0,
                          k] = +par(0.01, xn[3 * nx // 4:nx + 1])
            vf.bnd[S].typ[:nx // 4, 0, k] = OUTLET

    elif TEST == 34:  # horizontal mirror of 33
        for k in range(0, nz):
            vf.bnd[N].val[3 * nx // 4:nx, 0,
                          k] = -par(0.01, xn[3 * nx // 4:nx + 1])
            vf.bnd[N].typ[:nx // 4, 0, k] = OUTLET

    elif TEST == 41:  # inlet and outlet at the same face, one more outlet
        for k in range(0, nz):
            uf.bnd[W].val[0, 3 * ny // 4:ny,
                          k] = +par(0.01, yn[3 * ny // 4:ny + 1])
            uf.bnd[W].typ[0, :ny // 8, k] = OUTLET
            uf.bnd[E].typ[0, :ny // 8, k] = OUTLET

    elif TEST == 42:  # vertical mirror of 41
        for k in range(0, nz):
            uf.bnd[E].val[0, 3 * ny // 4:ny,
                          k] = -par(0.01, yn[3 * ny // 4:ny + 1])
            uf.bnd[E].typ[0, :ny // 8, k] = OUTLET
            uf.bnd[W].typ[0, :ny // 8, k] = OUTLET

    elif TEST == 43:  # rotated 41
        for k in range(0, nz):
            vf.bnd[S].val[3 * nx // 4:nx, 0,
                          k] = +par(0.01, xn[3 * nx // 4:nx + 1])
            vf.bnd[S].typ[0:nx // 8, 0, k] = OUTLET
            vf.bnd[N].typ[0:nx // 8, 0, k] = OUTLET

    elif TEST == 44:  # horizontal mirror of 43
        for k in range(0, nz):
            vf.bnd[N].val[3 * ny // 4:nx, 0,
                          k] = -par(0.01, xn[3 * nx // 4:nx + 1])
            vf.bnd[N].typ[:nx // 8, 0, k] = OUTLET
            vf.bnd[S].typ[:nx // 8, 0, k] = OUTLET

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

    # Create a cylindrical obstacle in the middle just for kicks
    obst = zeros(rc)
    for k in range(0, nz):
        for j in range(0, ny):
            for i in range(0, nx):
                dist = sqrt((j - ny / 2 + 1)**2 + (i - nx / 2 + 1)**2)
                if dist < ny / 4:
                    obst[i, j, k] = 1

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

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

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

        # -----------------------
        # Momentum conservation
        # -----------------------
        ef = zeros(ru), zeros(rv), zeros(rw)

        calc_uvw((uf, vf, wf), (uf, vf, wf), rho, mu, zeros(rc), ef, dt,
                 (dx, dy, dz), obst)

        # ----------
        # Pressure
        # ----------
        calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), obst)

        # ---------------------
        # Velocity correction
        # ---------------------
        corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), obst)

        # Compute volume balance for checking
        err = vol_balance((uf, vf, wf), (dx, dy, dz), obst)
        print('Maximum volume error after correction: %12.5e' % abs(err).max())

        # Check the CFL number too
        cfl = cfl_max((uf, vf, wf), dt, (dx, dy, dz))
        print('Maximum CFL number: %12.5e' % cfl)

    # =========================================================================
    #
    # Visualisation
    #
    # =========================================================================
    if show_plot:
        if ts % 10 == 0:
            plot_isolines(p.val, (uf, vf, wf), (xn, yn, zn), Z)
def main(show_plot=True):
    """
    Docstring.
    """

    # =========================================================================
    #
    # 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 = 0.02  # time step
    ndt = 1000  # number of time steps

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

    # 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

    obst = zeros(rc)

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

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

        print_time_step(ts)

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

        # ------------------------
        # Temperature (enthalpy)
        # ------------------------
        calc_t(t, (uf, vf, wf), (rho * cap), kappa, dt, (dx, dy, dz), obst)

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

        calc_uvw((uf, vf, wf), (uf, vf, wf), rho, mu, \
                 p_tot, ef, dt, (dx, dy, dz), obst)

        # ----------
        # Pressure
        # ----------
        calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), obst)

        p_tot = p_tot + p.val

        # ---------------------
        # Velocity correction
        # ---------------------
        corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), obst)

        # Compute volume balance for checking
        err = vol_balance((uf, vf, wf), (dx, dy, dz), obst)
        print('Maximum volume error after correction: %12.5e' % abs(err).max())

        # Check the CFL number too
        cfl = cfl_max((uf, vf, wf), dt, (dx, dy, dz))
        print('Maximum CFL number: %12.5e' % cfl)

        # =====================================================================
        #
        # Visualisation
        #
        # =====================================================================
        if show_plot:
            if ts % 20 == 0:
                plot_isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z)
示例#11
0
def main(show_plot=True):
    """Example
    """
    #==========================================================================
    #
    # Define problem
    #
    #==========================================================================

    # Node coordinates
    xn = nodes(0, 1, 256)
    yn = nodes(0, 0.125, 32)
    zn = nodes(0, 0.125, 4)

    # Cell coordinates
    xc = avg(xn)
    yc = avg(yn)
    zc = avg(zn)

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

    # Set physical properties
    rho, mu, cap, kappa = properties_for_air(rc)

    # Time-stepping parameters
    dt = 0.002  # time step
    ndt = 5000  # number of time steps

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

    # Specify boundary conditions
    uf.bnd[W].typ[:1, :, :] = DIRICHLET
    for k in range(0, nz):
        uf.bnd[W].val[:1, :, k] = par(0.1, yn)

    uf.bnd[E].typ[:1, :, :] = OUTLET

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

    adj_n_bnds(p)

    obst = zeros(rc)
    for j in range(0, 24):
        for i in range(64 + j, 64 + 24):
            for k in range(0, nz):
                obst[i, j, k] = 1

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

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

        print_time_step(ts)

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

        # -----------------------
        # Momentum conservation
        # -----------------------
        ef = zeros(ru), zeros(rv), zeros(rw)

        calc_uvw((uf, vf, wf), (uf, vf, wf), rho, mu,  \
                 zeros(rc), ef, dt, (dx, dy, dz), obst)

        # ----------
        # Pressure
        # ----------
        calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), obst)

        # ---------------------
        # Velocity correction
        # ---------------------
        corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), obst)

        # Compute volume balance for checking
        err = vol_balance((uf, vf, wf), (dx, dy, dz), obst)
        print('Maximum volume error after correction: %12.5e' % abs(err).max())

        # Check the CFL number too
        cfl = cfl_max((uf, vf, wf), dt, (dx, dy, dz))
        print('Maximum CFL number: %12.5e' % cfl)

        # =====================================================================
        #
        # Visualisation
        #
        # =====================================================================
        if show_plot:
            if ts % 20 == 0:
                plot_isolines(p.val, (uf, vf, wf), (xn, yn, zn), Z)
示例#12
0
def main(show_plot=True):
    """
    Docstring.
    """

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

    # Node coordinates
    xn = nodes(0, 1.25, 256)
    yn = nodes(0, 0.125, 32)
    zn = nodes(0, 0.125, 32)

    # Cell coordinates
    xc = avg(xn)
    yc = avg(yn)
    zc = avg(zn)

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

    # Set physical properties
    rho, mu, cap, kappa = properties_for_air(rc)

    # Time-stepping parameters
    dt = 0.005  # time step
    ndt = 2000  # number of time steps

    # Create unknowns; names, positions and sizes
    uc = create_unknown('cell-u-vel', C, rc, DIRICHLET)
    vc = create_unknown('cell-v-vel', C, rc, DIRICHLET)
    wc = create_unknown('cell-w-vel', C, rc, DIRICHLET)
    uf = create_unknown('face-u-vel', X, ru, DIRICHLET)
    vf = create_unknown('face-v-vel', Y, rv, DIRICHLET)
    wf = create_unknown('face-w-vel', Z, rw, DIRICHLET)
    p = create_unknown('pressure', C, rc, NEUMANN)

    # Specify boundary conditions
    uc.bnd[W].typ[:1, :, :] = DIRICHLET
    uc.bnd[W].val[:1, :, :] = 0.1 * outer(par(1.0, yn), par(1.0, zn))

    uc.bnd[E].typ[:1, :, :] = OUTLET

    for j in (B, T):
        uc.bnd[j].typ[:] = NEUMANN
        vc.bnd[j].typ[:] = NEUMANN
        wc.bnd[j].typ[:] = NEUMANN

    adj_n_bnds(p)

    # Create obstacles
    obst = zeros(rc)

    class key:
        """
        Class Docstring.
        """
        ip = -1
        im = -1
        jp = -1
        jm = -1
        kp = -1
        km = -1

    block = (key(), key(), key(), key())

    th = 5
    block[0].im = 3 * nx / 16  # i minus
    block[0].ip = block[0].im + th  # i plus
    block[0].jm = 0  # j minus
    block[0].jp = 3 * ny / 4  # j plus
    block[0].km = 0  # k minus
    block[0].kp = 3 * ny / 4  # k plus

    block[1].im = 5 * nx / 16  # i minus
    block[1].ip = block[1].im + th  # i plus
    block[1].jm = ny / 4  # j minus
    block[1].jp = ny  # j plus
    block[1].km = ny / 4  # k minus
    block[1].kp = ny  # k plus

    block[2].im = 7 * nx / 16  # i minus
    block[2].ip = block[2].im + th  # i plus
    block[2].jm = 0  # j minus
    block[2].jp = 3 * ny / 4  # j plus
    block[2].km = 0  # k minus
    block[2].kp = 3 * ny / 4  # k plus

    block[3].im = 9 * nx / 16  # i minus
    block[3].ip = block[3].im + th  # i plus
    block[3].jm = ny / 4  # j minus
    block[3].jp = ny  # j plus
    block[3].km = ny / 4  # k minus
    block[3].kp = ny  # k plus

    for o in range(0, 4):
        for i in range(floor(block[o].im), floor(block[o].ip)):
            for j in range(floor(block[o].jm), floor(block[o].jp)):
                for k in range(floor(block[o].km), floor(block[o].kp)):
                    obst[i, j, k] = 1

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

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

        print_time_step(ts)

        # ------------------
        # Store old values
        # ------------------
        uc.old[:] = uc.val[:]
        vc.old[:] = vc.val[:]
        wc.old[:] = wc.val[:]

        # -----------------------
        # Momentum conservation
        # -----------------------
        ef = zeros(rc), zeros(rc), zeros(rc)

        calc_uvw((uc, vc, wc), (uf, vf, wf), rho, mu, zeros(rc), ef, dt,
                 (dx, dy, dz), obst)

        # ----------
        # Pressure
        # ----------
        calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), obst)

        # ---------------------
        # Velocity correction
        # ---------------------
        corr_uvw((uc, vc, wc), p, rho, dt, (dx, dy, dz), obst)
        corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), obst)

        # Compute volume balance for checking
        err = vol_balance((uf, vf, wf), (dx, dy, dz), obst)
        print('Maximum volume error after correction: %12.5e' % abs(err).max())

        # Check the CFL number too
        cfl = cfl_max((uc, vc, wc), dt, (dx, dy, dz))
        print('Maximum CFL number: %12.5e' % cfl)

        # =====================================================================
        #
        # Visualisation
        #
        # =====================================================================
        if show_plot:
            if ts % 20 == 0:
                plot_isolines(p.val, (uc, vc, wc), (xn, yn, zn), Y)
                plot_isolines(p.val, (uc, vc, wc), (xn, yn, zn), Z)
示例#13
0
def create_matrix(phi, inn, mu, dxyz, obst, obc):
    """
    pos   - position of variable (C - central,
                                  X - staggered in x direction,
                                  Y - staggered in y direction,
                                  Z - staggered in z direction)
    inn         - innertial term
    mu         - viscous coefficient
    dx, dy, dz - cell size in x, y and z directions
    obc        - obstacles's boundary condition, ('n' - Neumann,
                                                  'd' - Dirichlet)
    -------------------------------------------------------------------------
    """
    # Unpack tuples
    dx, dy, dz = dxyz

    res = phi.val.shape

    # -------------------------------
    # Create right hand side vector
    # -------------------------------
    b = zeros(res)

    # ------------------------------------
    # Create default matrix coefficients
    # ------------------------------------
    coefficients = namedtuple('matrix_diagonal', 'W E S N B T P')
    c = coefficients(zeros(res), zeros(res), zeros(res), \
                     zeros(res), zeros(res), zeros(res), \
                     zeros(res))

    d = phi.pos

    # Handle central coefficient due to innertia
    c.P[:] = avg(d, inn) * avg(d, dx * dy * dz)

    # Pre-compute geometrical quantities
    sx = dy * dz
    sy = dx * dz
    sz = dx * dy

    if d != X:
        c.W[:] = cat(X, (                                    \
        avg(d, mu[:1, :, :])                                 \
        * avg(d, sx[:1, :, :]) / avg(d, (dx[:1, :, :])/2.0), \
        avg(d, avg(X, mu)) * avg(d, avg(X, sx)) / avg(d, avg(X, dx))))

        c.E[:] = cat(X, (                                               \
        avg(d, avg(X, mu)) * avg(d, avg(X, sx))  / avg(d, avg(X, dx)),  \
        avg(d, mu[-1:, :, :])                                           \
        * avg(d, sx[-1:, :, :])/ avg(d, (dx[-1:, :, :])/2.0)))

    if d != Y:
        c.S[:] = cat(Y, (                                               \
        avg(d, mu[:, :1, :])                                            \
        * avg(d, sy[:, :1, :]) / avg(d, (dy[:, :1, :])/2.0),            \
        avg(d, avg(Y, mu)) * avg(d, avg(Y, sy))  / avg(d, avg(Y, dy))))

        c.N[:] = cat(Y, (                                                \
        avg(d, avg(Y, mu))  * avg(d, avg(Y, sy))  / avg(d, avg(Y, dy)),  \
        avg(d, mu[:, -1:, :])                                            \
        * avg(d, sy[:, -1:, :]) / avg(d, (dy[:, -1:, :])/2.0)))

    if d != Z:
        c.B[:] = cat(Z, (                                                \
        avg(d, mu[:, :, :1])                                             \
        * avg(d, sz[:, :, :1]) / avg(d, (dz[:, :, :1])/2.0),             \
        avg(d, avg(Z, mu)) * avg(d, avg(Z, sz))  / avg(d, avg(Z, dz))))

        c.T[:] = cat(Z, (                                                \
        avg(d, avg(Z, mu))  * avg(d, avg(Z, sz))  / avg(d, avg(Z, dz)),  \
        avg(d, mu[:, :, -1:])                                            \
        * avg(d, sz[:, :, -1:]) / avg(d, (dz[:, :, -1:])/2.0)))

    # ---------------------------------
    # Correct for staggered variables
    # ---------------------------------
    if d == X:
        c.W[:] = mu[0:-1, :, :] * sx[0:-1, :, :] / dx[0:-1, :, :]
        c.E[:] = mu[1:, :, :] * sx[1:, :, :] / dx[1:, :, :]
    elif d == Y:
        c.S[:] = mu[:, 0:-1, :] * sy[:, 0:-1, :] / dy[:, 0:-1, :]
        c.N[:] = mu[:, 1:, :] * sy[:, 1:, :] / dy[:, 1:, :]
    elif d == Z:
        c.B[:] = mu[:, :, 0:-1] * sz[:, :, 0:-1] / dz[:, :, 0:-1]
        c.T[:] = mu[:, :, 1:] * sz[:, :, 1:] / dz[:, :, 1:]

    # -----------------------------------------------------------------------
    # Zero them (correct them) for vanishing derivative boundary condition.
    # -----------------------------------------------------------------------

    # The values defined here will be false (numerical value 0)
    # wherever there is or Neumann boundary condition.
    c.W[:1, :, :] *= (phi.bnd[W].typ[:] == DIRICHLET)
    c.E[-1:, :, :] *= (phi.bnd[E].typ[:] == DIRICHLET)
    c.S[:, :1, :] *= (phi.bnd[S].typ[:] == DIRICHLET)
    c.N[:, -1:, :] *= (phi.bnd[N].typ[:] == DIRICHLET)
    c.B[:, :, :1] *= (phi.bnd[B].typ[:] == DIRICHLET)
    c.T[:, :, -1:] *= (phi.bnd[T].typ[:] == DIRICHLET)

    # --------------------------------------------
    # Fill the source terms with boundary values
    # --------------------------------------------
    b[:1, :, :] += c.W[:1, :, :] * phi.bnd[W].val[:1, :, :]
    b[-1:, :, :] += c.E[-1:, :, :] * phi.bnd[E].val[:1, :, :]
    b[:, :1, :] += c.S[:, :1, :] * phi.bnd[S].val[:, :1, :]
    b[:, -1:, :] += c.N[:, -1:, :] * phi.bnd[N].val[:, :1, :]
    b[:, :, :1] += c.B[:, :, :1] * phi.bnd[B].val[:, :, :1]
    b[:, :, -1:] += c.T[:, :, -1:] * phi.bnd[T].val[:, :, :1]

    # ---------------------------------------
    # Correct system matrices for obstacles
    # ---------------------------------------
    if obst.any() != 0:
        c = obst_mod_matrix(phi, c, obst, obc)

    # -----------------------------------------------
    # Add all neighbours to the central matrix,
    # and zero the coefficients towards boundaries
    # -----------------------------------------------
    c.P[:] += c.W[:] + c.E[:] + c.S[:] + c.N[:] + c.B[:] + c.T[:]

    c.W[:1, :, :] = 0.0
    c.E[-1:, :, :] = 0.0
    c.S[:, :1, :] = 0.0
    c.N[:, -1:, :] = 0.0
    c.B[:, :, :1] = 0.0
    c.T[:, :, -1:] = 0.0

    # ----------------------
    # Create sparse matrix
    # ----------------------
    nx, ny, nz = res
    n = nx * ny * nz

    data = array([reshape(c.P, n),                     \
                  reshape(-c.W, n), reshape(-c.E, n),   \
                  reshape(-c.S, n), reshape(-c.N, n),   \
                  reshape(-c.B, n), reshape(-c.T, n)])

    diag = array([0, +ny * nz, -ny * nz, +nz, -nz, +1, -1])

    A = spdiags(data, diag, n, n)

    return A, b  # end of function