示例#1
0
def main(show_plot=True, time_steps=1, plot_freq=1):

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

    NX = 32
    NY = NX
    NZ = 32

    xn = nodes(0, 1, NX)
    yn = nodes(0, 1, NY)
    zn = nodes(0, 1, NZ)

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

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

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

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

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

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

    t_src = zeros(t.val.shape)
    t_src[NX // 8:NY // 2, NX // 8:NY // 2, :] = 1.0
    t_src[5 * NX // 8:3 * NY // 4, 5 * NX // 8:3 * NY // 4, :] = -4.0

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

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

        write.time_step(ts)

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

        # -----------------------
        # Temperature (enthalpy)
        # -----------------------
        calc_phi(t, (uf, vf, wf), (rho * cap),
                 kappa,
                 dt, (dx, dy, dz),
                 source=t_src)

        # =============================================================================
        #
        # Visualisation
        #
        # =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                plot.isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z, levels=21)
                plot.gmv("tdc-staggered-%6.6d.gmv" % ts, (xn, yn, zn),
                         (uf, vf, wf, t))
示例#2
0
def main(show_plot=True, time_steps=500, plot_freq=10):
    
    # Node coordinates
    xn = nodes(0, 1,    160)
    yn = nodes(0, 1,    160)
    zn = nodes(0, 0.25,   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.air(rc)

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

    # Create unknowns names, positions and sizes
    uf = Unknown("face-u-vel",  X, ru, DIRICHLET)
    vf = Unknown("face-v-vel",  Y, rv, DIRICHLET)
    wf = Unknown("face-w-vel",  Z, rw, DIRICHLET)
    p  = Unknown("pressure",    C, rc, NEUMANN)
    
    # Imposing the geometry by creating an obstacle
    #
    #
    #                             INLET
    #                       |                |
    #                       |                |
    #                       |                |
    #                       |                |
    #                       |                |
    #                       |                |
    #                       |                |
    #                       |                |
    #     __________________|                |___________________
    #   O                                                          O
    #   U                                                          U
    #   T                                                          T
    #   L                                                          L
    #   E                                                          E
    #   T ________________________________________________________ T
    
    obst = zeros(rc)
    
    for k in range(0,nz):
        for i in range(0,nx//3):
            for j in range(ny//4,ny):
                obst[i,j,k] = 1
                
    for k in range(0,nz):
        for i in range(2*nx//3,nx):
            for j in range(ny//4,ny):
                obst[i,j,k] = 1
    
    for k in range(0,nz):
        vf.bnd[N].val[nx//3:2*nx//3, 0, k] = -par(0.01, xn[nx//3:2*nx//3+1])
        uf.bnd[E].typ[0, :ny//4, k] = OUTLET
        uf.bnd[W].typ[0, :ny//4, k] = OUTLET
        
    for j in (B,T):
        uf.bnd[j].typ[:] = NEUMANN
        vf.bnd[j].typ[:] = NEUMANN
        wf.bnd[j].typ[:] = NEUMANN


    # Initialising the particles. 
    n = 10000  # number of particles 
    
    pt = initialiser(n, rho_p = 1000, d = 2.5e-6, verbose = False)

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

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

        write.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, dt, (dx,dy,dz), 
                 obstacle = obst)

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

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

        # Check the CFL number too
        cfl = cfl_max((uf,vf,wf), dt, (dx,dy,dz))
        
        # Calculate the nodal velocities
        
        (un, vn, wn) = nodal_uvw((xn,yn,zn), (uf,vf,wf), 
                                  obstacle = obst)

        # ----------------------------
        # Lagrangian Particle Tracking
        # ----------------------------
    
        # Iterate through the number of particles to update their positions
        # and velocities. 

        calc_traj(pt, (un,vn,wn), rho, mu, (xn,yn,zn), (xc,yc,zc), dt, obst, n)
        
# =============================================================================
#
# Visualisation
#
# =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                
               plot.gmv("impactor-%6.6d" % ts, (xn,yn,zn), 
                        unknowns = (uf, vf, wf, p),
                        arrays   = (un, vn, wn),
                        tracers  = (pt))
示例#3
0
def main(show_plot=True, time_steps=12, plot_freq=1):

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

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

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

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

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

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

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

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

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


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

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

        write.time_step(ts)

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

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

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

        for inner in range(1, 33):

            write.iteration(inner)

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

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

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

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

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

            p_tot.val += 0.25 * p.val

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

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

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

        # =============================================================================
        #
        # Visualisation
        #
        # =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                plot.isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z)
                plot.gmv("tdc-staggered-%6.6d" % ts, (xn, yn, zn),
                         (uf, vf, wf, t))
def main(show_plot=True, time_steps=1200, plot_freq=120):

# =============================================================================
#
# 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 = time_steps  # number of time steps

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

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

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

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

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

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

        write.time_step(ts)

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

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

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

        calc_uvw((uf,vf,wf), (uf,vf,wf), rho, mu, dt, (dx,dy,dz),
                 pressure = p_tot,
                 force    = ext_f)

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

        p_tot.val += p.val

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

        # Check the CFL number too
        cfl = cfl_max((uf,vf,wf), dt, (dx,dy,dz))

# =============================================================================
#
# Visualisation
#
# =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                plot.isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z)
                plot.gmv("tdc-staggered-%6.6d" % ts, 
                         (xn, yn, zn), (uf, vf, wf, t))
示例#5
0
def main(show_plot=True, time_steps=1800, plot_freq=180):

# =============================================================================
#
# 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.air(rc)

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

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

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

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

    # Create obstacles
    plates = zeros(rc)

    class key:
        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(int(floor(block[o].im)), int(floor(block[o].ip))):
            for j in range(int(floor(block[o].jm)), int(floor(block[o].jp))):
                for k in range(int(floor(block[o].km)), int(floor(block[o].kp))):
                    plates[i, j, k] = 1
# =============================================================================
#
# Solution algorithm
#
# =============================================================================

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

        write.time_step(ts)

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

        # ----------------------
        # Momentum conservation
        # ----------------------
        calc_uvw((uf,vf,wf), (uf,vf,wf), rho, mu, dt, (dx,dy,dz), 
                 obstacle = plates)

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

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

        # Check the CFL number too
        cfl = cfl_max((uf,vf,wf), dt, (dx,dy,dz))

# =============================================================================
#
# Visualisation
#
# =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                plot.isolines(p.val, (uf,vf,wf), (xn,yn,zn), Y)
                plot.isolines(p.val, (uf,vf,wf), (xn,yn,zn), Z)
                plot.gmv("obst-thinner-staggered-%6.6d" % ts, 
                         (xn,yn,zn), (uf,vf,wf,p))
示例#6
0
def main(show_plot=True, time_steps=1200, plot_freq=120):

# =============================================================================
#
# 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 = time_steps  # number of time steps

    # Create unknowns; names, positions and sizes
    uc = Unknown('cell-u-vel',  C, rc, DIRICHLET)
    vc = Unknown('cell-v-vel',  C, rc, DIRICHLET)
    wc = Unknown('cell-w-vel',  C, rc, DIRICHLET)
    uf = Unknown('face-u-vel',  X, ru, DIRICHLET)
    vf = Unknown('face-v-vel',  Y, rv, DIRICHLET)
    wf = Unknown('face-w-vel',  Z, rw, DIRICHLET)
    t  = Unknown('temperature', C, rc, NEUMANN)
    p  = Unknown('pressure',    C, rc, NEUMANN)
    p_tot = 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):
        uc.bnd[j].typ[:] = NEUMANN
        vc.bnd[j].typ[:] = NEUMANN
        wc.bnd[j].typ[:] = NEUMANN

    obst = zeros(rc)

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

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

        write.time_step(ts)

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

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

        #-----------------------
        # Momentum conservation
        #-----------------------
        ef = zeros(rc), t.val, zeros(rc)

        calc_uvw((uc,vc,wc), (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((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 % plot_freq == 0:
                plot.isolines(t.val, (uc, vc, wc), (xn, yn, zn), Z)
                plot.gmv("tdc-collocated-%6.6d.gmv" % ts, 
                         (xn, yn, zn), (uc, vc, wc, t))
示例#7
0
def main(show_plot=True, time_steps=6000, plot_freq=60):

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

    # Node coordinates
    xn = nodes(0, 0.6, 60)
    yn = nodes(0, 0.6, 60)
    zn = nodes(0, 0.3, 30)

    # 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.air(rc)

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

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

    cube = zeros(rc)
    for j in range(22, 38):
        for i in range(22, 38):
            for k in range(0,16):
                cube[i,j,k] = 1

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

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

        write.time_step(ts)

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

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

        calc_uvw((uf,vf,wf), (uf,vf,wf), rho, mu, dt, (dx,dy,dz), cube,
                 force = ef)

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

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

        # Check the CFL number too
        cfl = cfl_max((uf,vf,wf), dt, (dx,dy,dz))

# =============================================================================
#
# Visualisation
#
# =============================================================================
        if show_plot:
            if ts % plot_freq == 0:
                
                # Compute nodal velocities
                un, vn, wn = nodal_uvw((xn,yn,zn), (uf,vf,wf), cube) 
                
                # Plot everything
                plot.gmv("cube-matrix-%6.6d" % ts, (xn,yn,zn), 
                         unknowns = (uf, vf, wf, p),
                         arrays   = (un, vn, wn) )