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

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

    # Unpack received tuples
    dx, dy, dz = dxyz

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

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

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

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

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

    return  # end of function
Esempio n. 2
0
def vol_balance(uvwf, dxyz, obst):
    # -----------------------------------------------------------------------------
    """
    Args:
      uvwf: Tuple with three staggered velocity components (where each
            component is created with "create_unknown" function.
      dxyz: Tuple holding cell dimensions in "x", "y" and "z" directions.
            Each cell dimension is a three-dimensional array.
      obst: Obstacle, three-dimensional matrix with zeros and ones.
            It is zero in fluid, one in solid.

    Note:
      "obst" is an optional parameter.  If it is not sent, the source
      won't be set to zero inside the obstacle.  That is important for
      calculation of pressure, see function "calc_p" as well.
    """

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

    # Compute it throughout the domain
    src = - dif_x(cat_x((uf.bnd[W].val, uf.val, uf.bnd[E].val)))*dy*dz  \
          - dif_y(cat_y((vf.bnd[S].val, vf.val, vf.bnd[N].val)))*dx*dz  \
          - dif_z(cat_z((wf.bnd[B].val, wf.val, wf.bnd[T].val)))*dx*dy

    # Zero it inside obstacles, if obstacle is sent as parameter
    if obst.any() != 0:
        src = obst_zero_val(C, src, obst)

    return src  # end of function
Esempio n. 3
0
def corr_uvw(uvw, p, rho, dt, dxyz, obst):
    # -----------------------------------------------------------------------------
    """
    Args:
      uvw:  Tuple with three staggered or centered velocity components
            (each component is created with "create_unknown" function.
      p:    Unknown holding the pressure correction.
      rho:  Three-dimensional matrix holding density for all cells.
      dt:   Time step
      dxyz: Tuple holding cell dimensions in "x", "y" and "z" directions.
            Each cell dimension is a three-dimensional array.
      obst: Obstacle, three-dimensional matrix with zeros and ones.
            It is zero in fluid, one in solid.

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

    # Unpack received tuples
    dx, dy, dz = dxyz

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

    # Set to zero in obst
    if 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
Esempio n. 4
0
def calc_p(p, uvwf, rho, dt, dxyz, obstacle=None, verbose=True):
    # -----------------------------------------------------------------------------
    """
    Args:
      p: ...... Object of the type "Unknown", holding the pressure.
      uvwf: ... Tuple with three staggered velocity components (where each
                component is an object of type "Unknown".
      rho: .... Three-dimensional array holding density for all cells.
      dt: ..... Time step.
      dxyz: ... Tuple holding cell dimensions in "x", "y" and "z" directions.
                Each cell dimension is a three-dimensional array.
      obstacle: Obstacle, three-dimensional array with zeros and ones.
                It is zero in fluid, one in solid.

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

    # Fetch the resolution
    rc = p.val.shape

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

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

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

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

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

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

    # Finally adjust the boundary values
    adj_n_bnds(p)

    return  # end of function
Esempio n. 5
0
def calc_p(p, uvwf, rho, dt, dxyz, obst):
    # -----------------------------------------------------------------------------
    """
    Args:
      p:    Pressure unknown (created with "pyns.create_unknown" function)
      uvwf: Tuple with three staggered velocity components (where each
            component is created with "pyns.create_unknown" function.
      rho:  Three-dimensional matrix holding density for all cells.
      dt:   Time step.
      dxyz: Tuple holding cell dimensions in "x", "y" and "z" directions.
            Each cell dimension is a three-dimensional matrix.
      obst: Obstacle, three-dimensional matrix with zeros and ones.
            It is zero in fluid, one in solid.

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

    # Fetch the resolution
    rc = p.val.shape

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

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

    print('Maximum volume error before correction: %12.5e' % abs(b_p).max())
    print('Volume imbalance before correction    : %12.5e' % b_p.sum())

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

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

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

    # Finally adjust the boundary values
    p = adj_n_bnds(p)

    return  # end of function
Esempio n. 6
0
def calc_uvw(uvw,
             uvwf,
             rho,
             mu,
             dt,
             dxyz,
             obstacle=None,
             pressure=None,
             force=None,
             under_relaxation=1.0,
             advection_scheme="superbee"):
    # -----------------------------------------------------------------------------
    """
    Args:
      uvw: ............ Tuple with three velocity components, staggered or 
                        collocated.  
                        (Each component is object of type "Unknown".)
      uvwf: ........... Tuple with three staggered velocity components. 
                        (Each component is object of type "Unknown".)
      rho: ............ Three-dimensional array holding density for all cells.
      mu: ............. Three-dimensional array holding dynamic viscosity.
      pressure: ....... Object "Unknown" holding total pressure.
      force: .......... Tuple containing three-dimensional matrices holding 
                        external forces in each direction.
      dt: ............. Time step.
      dxyz: ........... Tuple holding cell dimensions in "x", "y" and "z" 
                        directions.  Each component (each cell dimension) is 
                        a three-dimensional array.
      obstacle: ....... Obstacle, three-dimensional array with zeros and ones.
                        It is zero in fluid, one in solid.
      under_relaxation: Under relaxation factor.
      advection_scheme: Advection scheme.

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

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

    # 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 system matrices and right hand sides
    A_u = diffusion(u, rho / dt, mu, dxyz, obstacle, DIRICHLET)
    A_v = diffusion(v, rho / dt, mu, dxyz, obstacle, DIRICHLET)
    A_w = diffusion(w, rho / dt, mu, dxyz, obstacle, DIRICHLET)
    b_u = zeros(ru)
    b_v = zeros(rv)
    b_w = zeros(rw)

    # Advection terms for momentum
    c_u = advection(rho, u, uvwf, dxyz, dt, advection_scheme, matrix=A_u)
    c_v = advection(rho, v, uvwf, dxyz, dt, advection_scheme, matrix=A_v)
    c_w = advection(rho, w, uvwf, dxyz, dt, advection_scheme, matrix=A_w)

    # Innertial term for momentum (this works for collocated and staggered)
    A_u.C += avg(u.pos, rho) * avg(u.pos, dv) / dt
    A_v.C += avg(v.pos, rho) * avg(v.pos, dv) / dt
    A_w.C += avg(w.pos, rho) * avg(w.pos, dv) / dt
    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

    # Full force terms for momentum equations (collocated and staggered)
    f_u = b_u - c_u + i_u
    f_v = b_v - c_v + i_v
    f_w = b_w - c_w + i_w

    # Compute staggered pressure gradients
    if pressure is not None:
        pressure.exchange()
        p_tot_x = dif_x(pressure.val) / avg_x(dx)
        p_tot_y = dif_y(pressure.val) / avg_y(dy)
        p_tot_z = dif_z(pressure.val) / 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)

        f_u -= p_st_u
        f_v -= p_st_v
        f_w -= p_st_w

    # If external force is given
    if force is not None:

        # Unpack the tuple
        e_u, e_v, e_w = force

        # Add to right hand side
        f_u += e_u * avg(u.pos, dv)
        f_v += e_v * avg(v.pos, dv)
        f_w += e_w * avg(w.pos, dv)

    # Take care of obsts in the domian
    if obstacle is not None:
        f_u = obst_zero_val(u.pos, f_u, obstacle)
        f_v = obst_zero_val(v.pos, f_v, obstacle)
        f_w = obst_zero_val(w.pos, f_w, obstacle)

    # Solve for velocities
    ur = under_relaxation
    u.val[:] = (1 - ur) * u.val[:] + ur * bicgstab(A_u, u, f_u, TOL, False)
    v.val[:] = (1 - ur) * v.val[:] + ur * bicgstab(A_v, v, f_v, TOL, False)
    w.val[:] = (1 - ur) * w.val[:] + ur * bicgstab(A_w, w, f_w, TOL, False)

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

    # Update face velocities
    # (For collocated arrangement also substract cell-centered
    # pressure gradients and add staggered pressure gradients)
    if d == C:
        uf.val[:] = avg_x(u.val)
        vf.val[:] = avg_y(v.val)
        wf.val[:] = avg_z(w.val)

        if pressure is not None:
            uf.val[:] += avg_x(dt / rho * p_tot_x)
            uf.val[:] -= dt / avg_x(rho) * (dif_x(pressure.val) / avg_x(dx))

            vf.val[:] += avg_y(dt / rho * p_tot_y)
            vf.val[:] -= dt / avg_y(rho) * (dif_y(pressure.val) / avg_y(dy))

            wf.val[:] += avg_z(dt / rho * p_tot_z)
            wf.val[:] -= dt / avg_z(rho) * (dif_z(pressure.val) / 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 obstacle is not None:
        uf.val[:] = obst_zero_val(X, uf.val, obstacle)
        vf.val[:] = obst_zero_val(Y, vf.val, obstacle)
        wf.val[:] = obst_zero_val(Z, wf.val, obstacle)

    return  # end of function