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