Exemple #1
0
def obst_zero_val(d, val, obst):
    """
    Set value to zero inside obstacle.

    d    - position of the variable, C, X, Y or Z
    val  - value to be zeroed in obstacle
    obst - matrix holding positions of obstacle
    """

    if d == C:
        val = val * lnot(obst)

    elif d == X:
        obst_x = mx(obst[:-1, :, :], obst[1:, :, :])
        val = val * lnot(obst_x)

    elif d == Y:
        obst_y = mx(obst[:, :-1, :], obst[:, 1:, :])
        val = val * lnot(obst_y)

    elif d == Z:
        obst_z = mx(obst[:, :, :-1], obst[:, :, 1:])
        val = val * lnot(obst_z)

    return val  # end of function
Exemple #2
0
def adj_n_bnds(phi):
    """
    Copies last domain cell values to Neumann boundary condition values.
    :param phi: pressure TODO: why here phi and not p?
    :return: None
    """
    # These arrays will hold values true (0) in cells with boundary ...
    # ... condition of Neumann type, and false (0) otherwise

    if_w_n = phi.bnd[W].typ[0, :, :] == NEUMANN  # 1 if west is Neumann
    if_e_n = phi.bnd[E].typ[0, :, :] == NEUMANN  # 1 if east is Neumann
    if_s_n = phi.bnd[S].typ[:, 0, :] == NEUMANN  # 1 if south is Neumann
    if_n_n = phi.bnd[N].typ[:, 0, :] == NEUMANN  # 1 if north is Neumann
    if_b_n = phi.bnd[B].typ[:, :, 0] == NEUMANN  # 1 if bottom is Neumann
    if_t_n = phi.bnd[T].typ[:, :, 0] == NEUMANN  # 1 if top is Neumann

    # In what follows, a linear combination of true (0] and false (0)
    # will copy the values of variable phi to the boundaries.
    phi.bnd[W].val[0, :, :] = (phi.bnd[W].val[0, :, :] * lnot(if_w_n) +
                               phi.val[0, :, :] * if_w_n)
    phi.bnd[E].val[0, :, :] = (phi.bnd[E].val[0, :, :] * lnot(if_e_n) +
                               phi.val[-1, :, :] * if_e_n)

    phi.bnd[S].val[:, 0, :] = (phi.bnd[S].val[:, 0, :] * lnot(if_s_n) +
                               phi.val[:, 0, :] * if_s_n)
    phi.bnd[N].val[:, 0, :] = (phi.bnd[N].val[:, 0, :] * lnot(if_n_n) +
                               phi.val[:, -1, :] * if_n_n)

    phi.bnd[B].val[:, :, 0] = (phi.bnd[B].val[:, :, 0] * lnot(if_b_n) +
                               phi.val[:, :, 0] * if_b_n)
    phi.bnd[T].val[:, :, 0] = (phi.bnd[T].val[:, :, 0] * lnot(if_t_n) +
                               phi.val[:, :, -1] * if_t_n)
Exemple #3
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)
Exemple #4
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
Exemple #5
0
def obst_mod_matrix(phi, c, obst, obc):
    """
    Adjusts the system matrix for obstacles and cell centered varaibles
    (such as pressure)

    phi  - variable
    c    - coefficients in system matrix
    obst - obstacle array
    obc  - obstacles's boundary condition, ('n' - Neumann, 'd' - Dirichlet)
    """
    pos = phi.pos
    #--------------------------
    #
    # For collocated variables
    #
    #--------------------------
    if pos == C:
        #------------------------------------
        # Neumann's boundary on the obstacle
        #------------------------------------
        if obc == 'n':

            # Correct west and east
            sol_x = dif(X, obst)  # will be +1 east of obst, -1 west of obst
            corr = 1 - (sol_x < 0)
            c.W[1:, :, :] = c.W[1:, :, :] * corr
            corr = 1 - (sol_x > 0)
            c.E[:-1, :, :] = c.E[:-1, :, :] * corr

            # Correct south and north
            sol_y = dif(Y, obst)  # will be +1 north of obst, -1 south of obst
            corr = 1 - (sol_y < 0)
            c.S[:, 1:, :] = c.S[:, 1:, :] * corr
            corr = 1 - (sol_y > 0)
            c.N[:, :-1, :] = c.N[:, :-1, :] * corr

            # Correct bottom and top
            sol_z = dif(Z, obst)  # will be +1 north of obst, -1 south of obst
            corr = 1 - (sol_z < 0)
            c.B[:, :, 1:] = c.B[:, :, 1:] * corr
            corr = 1 - (sol_z > 0)
            c.T[:, :, :-1] = c.T[:, :, :-1] * corr

        #--------------------------------------
        # Dirichlet's boundary on the obstacle
        #--------------------------------------
        elif obc == 'd':
            # Set central coefficient to 1 in obst, unchanged elsewhere
            c.P[:] = c.P[:] * lnot(obst) + obst

            # Set neighbour coefficients to zero in obst
            c.W[:] = c.W[:] * lnot(obst)
            c.E[:] = c.E[:] * lnot(obst)
            c.S[:] = c.S[:] * lnot(obst)
            c.N[:] = c.N[:] * lnot(obst)
            c.B[:] = c.B[:] * lnot(obst)
            c.T[:] = c.T[:] * lnot(obst)

            # Increase coefficients close to obst (makes sense for momentum)
            sol_x = dif(X, obst)  # will be +1 east of obst, -1 west of obst
            corr = 1 + (sol_x > 0)
            c.E[:-1, :, :] = c.E[:-1, :, :] * corr
            corr = 1 + (sol_x < 0)
            c.W[1:, :, :] = c.W[1:, :, :] * corr

            sol_y = dif(Y, obst)  # will be +1 north of obst, -1 south of obst
            corr = 1 + (sol_y > 0)
            c.N[:, :-1, :] = c.N[:, :-1, :] * corr
            corr = 1 + (sol_y < 0)
            c.S[:, 1:, :] = c.S[:, 1:, :] * corr

            sol_z = dif(Z, obst)  # will be +1 top of obst, -1 bottom of obst
            corr = 1 + (sol_z > 0)
            c.T[:, :, :-1] = c.T[:, :, :-1] * corr
            corr = 1 + (sol_z < 0)
            c.B[:, :, 1:] = c.B[:, :, 1:] * corr

        #-------------------------
        #
        # For staggered variables
        #
        #-------------------------
        elif pos == X:
            # Set central coefficient to 1 in obst, unchanged elsewhere
            obst_x = mx(obst[:-1, :, :], obst[1:, :, :])
            c.P[:] = c.P[:] * lnot(obst_x) + obst_x

            # Set neighbour coefficients to zero in obst
            c.W[:] = c.W[:] * lnot(obst_x)
            c.E[:] = c.E[:] * lnot(obst_x)
            c.S[:] = c.S[:] * lnot(obst_x)
            c.N[:] = c.N[:] * lnot(obst_x)
            c.B[:] = c.B[:] * lnot(obst_x)
            c.T[:] = c.T[:] * lnot(obst_x)

            # Increase coefficients close to obst (makes sense for momentum)
            sol_y = dif(Y, obst_x)  # will be +1 north of obst,-1 south of obst
            corr = 1 + (sol_y > 0)
            c.N[:, :-1, :] = c.N[:, :-1, :] * corr
            corr = 1 + (sol_y < 0)
            c.S[:, 1:, :] = c.S[:, 1:, :] * corr

            sol_z = dif(Z, obst_x)  # will be +1 top of obst, -1 bottom of obst
            corr = 1 + (sol_z > 0)
            c.T[:, :, :-1] = c.T[:, :, :-1] * corr
            corr = 1 + (sol_z < 0)
            c.B[:, :, 1:] = c.B[:, :, 1:] * corr

        elif pos == Y:

            # Set central coefficient to 1 in obst, unchanged elsewhere
            obst_y = mx(obst[:, :-1, :], obst[:, 1:, :])
            c.P[:] = c.P[:] * lnot(obst_y) + obst_y

            # Set neighbour coefficients to zero in obst
            c.W[:] = c.W[:] * lnot(obst_y)
            c.E[:] = c.E[:] * lnot(obst_y)
            c.S[:] = c.S[:] * lnot(obst_y)
            c.N[:] = c.N[:] * lnot(obst_y)
            c.B[:] = c.B[:] * lnot(obst_y)
            c.T[:] = c.T[:] * lnot(obst_y)

            # Increase coefficients close to obst (makes sense for momentum)
            sol_x = dif(X, obst_y)  # will be +1 north of obst,-1 south of obst
            corr = 1 + (sol_x > 0)
            c.E[:-1, :, :] = c.E[:-1, :, :] * corr
            corr = 1 + (sol_x < 0)
            c.W[1:, :, :] = c.W[1:, :, :] * corr

            sol_z = dif(Z, obst_y)  # will be +1 north of obst,-1 south of obst
            corr = 1 + (sol_z > 0)
            c.T[:, :, :-1] = c.T[:, :, :-1] * corr
            corr = 1 + (sol_z < 0)
            c.B[:, :, 1:] = c.B[:, :, 1:] * corr

        elif pos == Z:

            # Set central coefficient to 1 in obst, unchanged elsewhere
            obst_z = mx(obst[:, :, :-1], obst[:, :, 1:])
            c.P[:] = c.P[:] * lnot(obst_z) + obst_z

            # Set neighbour coefficients to zero in obst
            c.W[:] = c.W[:] * lnot(obst_z)
            c.E[:] = c.E[:] * lnot(obst_z)
            c.S[:] = c.S[:] * lnot(obst_z)
            c.N[:] = c.N[:] * lnot(obst_z)
            c.B[:] = c.B[:] * lnot(obst_z)
            c.T[:] = c.T[:] * lnot(obst_z)

            # Increase coefficients close to obst (makes sense for momentum)
            sol_x = dif(X, obst_z)  # will be +1 north of obst,-1 south of obst
            corr = 1 + (sol_x > 0)
            c.E[:-1, :, :] = c.E[:-1, :, :] * corr
            corr = 1 + (sol_x < 0)
            c.W[1:, :, :] = c.W[1:, :, :] * corr

            sol_y = dif(Y, obst_z)  # will be +1 north of obst,-1 south of obst
            corr = 1 + (sol_y > 0)
            c.N[:, :-1, :] = c.N[:, :-1, :] * corr
            corr = 1 + (sol_y < 0)
            c.S[:, 1:, :] = c.S[:, 1:, :] * corr

    return c  # end of function