[docs]definitialize(self,*,other_bc=False,aux_vars=()):""" Initialize the grid and variables for incompressible flow and set the initial conditions for the chosen problem. """my_grid=grid_setup(self.rp,ng=4)# create the variablesmy_data=patch.CellCenterData2d(my_grid)ifother_bc:self.define_other_bc()bc,bc_xodd,bc_yodd=bc_setup(self.rp)# velocitiesmy_data.register_var("x-velocity",bc_xodd)my_data.register_var("y-velocity",bc_yodd)# phi -- used for the projections. Has neumann BC's if v is dirichlet# Assuming BC's are either all periodic or all dirichletphi_bc=Noneifbc.xlb=="periodic":phi_bc=bcelifbc.xlb=="dirichlet":phi_bc=bnd.BC(xlb='neumann',xrb='neumann',ylb='neumann',yrb='neumann')my_data.register_var("phi-MAC",phi_bc)my_data.register_var("phi",phi_bc)my_data.register_var("gradp_x",phi_bc)my_data.register_var("gradp_y",phi_bc)forvinaux_vars:my_data.set_aux(keyword=v[0],value=v[1])my_data.create()self.cc_data=my_dataifself.rp.get_param("particles.do_particles")==1:n_particles=self.rp.get_param("particles.n_particles")particle_generator=self.rp.get_param("particles.particle_generator")self.particles=particles.Particles(self.cc_data,bc,n_particles,particle_generator)self.in_preevolve=False# now set the initial conditions for the problemself.problem_func(self.cc_data,self.rp)
[docs]defpreevolve(self):""" preevolve is called before we being the timestepping loop. For the incompressible solver, this does an initial projection on the velocity field and then goes through the full evolution to get the value of phi. The fluid state (u, v) is then reset to values before this evolve. """self.in_preevolve=Truemyg=self.cc_data.gridu=self.cc_data.get_var("x-velocity")v=self.cc_data.get_var("y-velocity")self.cc_data.fill_BC("x-velocity")self.cc_data.fill_BC("y-velocity")# 1. do the initial projection. This makes sure that our original# velocity field satisfies div U = 0# next create the multigrid object. We want Neumann BCs on phi# at solid walls and periodic on phi for periodic BCsmg=MG.CellCenterMG2d(myg.nx,myg.ny,xl_BC_type="periodic",xr_BC_type="periodic",yl_BC_type="periodic",yr_BC_type="periodic",xmin=myg.xmin,xmax=myg.xmax,ymin=myg.ymin,ymax=myg.ymax,verbose=0)# first compute divUdivU=mg.soln_grid.scratch_array()divU.v()[:,:]= \
0.5*(u.ip(1)-u.ip(-1))/myg.dx+0.5*(v.jp(1)-v.jp(-1))/myg.dy# solve L phi = DU# initialize our guess to the solution, set the RHS to divU and# solvemg.init_zeros()mg.init_RHS(divU)mg.solve(rtol=1.e-10)# store the solution in our self.cc_data object -- include a single# ghostcellphi=self.cc_data.get_var("phi")phi[:,:]=mg.get_solution(grid=myg)# compute the cell-centered gradient of phi and update the# velocitiesgradp_x,gradp_y=mg.get_solution_gradient(grid=myg)u[:,:]-=gradp_xv[:,:]-=gradp_y# fill the ghostcellsself.cc_data.fill_BC("x-velocity")self.cc_data.fill_BC("y-velocity")# 2. now get an approximation to gradp at n-1/2 by going through the# evolution.# store the current solution -- we'll restore it in a bitorig_data=patch.cell_center_data_clone(self.cc_data)# get the timestepself.method_compute_timestep()# evolveself.evolve()# update gradp_x and gradp_y in our main data objectnew_gp_x=self.cc_data.get_var("gradp_x")new_gp_y=self.cc_data.get_var("gradp_y")orig_gp_x=orig_data.get_var("gradp_x")orig_gp_y=orig_data.get_var("gradp_y")orig_gp_x[:,:]=new_gp_x[:,:]orig_gp_y[:,:]=new_gp_y[:,:]self.cc_data=orig_dataifself.verbose>0:print("done with the pre-evolution")self.in_preevolve=False
[docs]defevolve(self,other_update_velocity=False,other_source_term=False):""" Evolve the incompressible equations through one timestep. """u=self.cc_data.get_var("x-velocity")v=self.cc_data.get_var("y-velocity")gradp_x=self.cc_data.get_var("gradp_x")gradp_y=self.cc_data.get_var("gradp_y")phi=self.cc_data.get_var("phi")myg=self.cc_data.gridifother_source_term:source_x,source_y=self.other_source_term()else:source_x,source_y=None,None# ---------------------------------------------------------------------# create the limited slopes of u and v (in both directions)# ---------------------------------------------------------------------limiter=self.rp.get_param("incompressible.limiter")ldelta_ux=reconstruction.limit(u,myg,1,limiter)ldelta_vx=reconstruction.limit(v,myg,1,limiter)ldelta_uy=reconstruction.limit(u,myg,2,limiter)ldelta_vy=reconstruction.limit(v,myg,2,limiter)# ---------------------------------------------------------------------# get the advective velocities# ---------------------------------------------------------------------""" the advective velocities are the normal velocity through each cell interface, and are defined on the cell edges, in a MAC type staggered form n+1/2 v i,j+1/2 +------+------+ | | n+1/2 | | n+1/2 u + U + u i-1/2,j | i,j | i+1/2,j | | +------+------+ n+1/2 v i,j-1/2 """# this returns u on x-interfaces and v on y-interfaces. These# constitute the MAC gridifself.verbose>0:print(" making MAC velocities")_um,_vm=incomp_interface.mac_vels(myg,self.dt,u,v,ldelta_ux,ldelta_vx,ldelta_uy,ldelta_vy,gradp_x,gradp_y,source_x,source_y)u_MAC=ai.ArrayIndexer(d=_um,grid=myg)v_MAC=ai.ArrayIndexer(d=_vm,grid=myg)# ---------------------------------------------------------------------# do a MAC projection to make the advective velocities divergence# free# ---------------------------------------------------------------------# we will solve L phi = D U^MAC, where phi is cell centered, and# U^MAC is the MAC-type staggered grid of the advective# velocities.ifself.verbose>0:print(" MAC projection")# create the multigrid objectmg=MG.CellCenterMG2d(myg.nx,myg.ny,xl_BC_type=self.cc_data.BCs["phi"].xlb,xr_BC_type=self.cc_data.BCs["phi"].xrb,yl_BC_type=self.cc_data.BCs["phi"].ylb,yr_BC_type=self.cc_data.BCs["phi"].yrb,xmin=myg.xmin,xmax=myg.xmax,ymin=myg.ymin,ymax=myg.ymax,verbose=0)# first compute divUdivU=mg.soln_grid.scratch_array()# MAC velocities are edge-centered. divU is cell-centered.divU.v()[:,:]= \
(u_MAC.ip(1)-u_MAC.v())/myg.dx+(v_MAC.jp(1)-v_MAC.v())/myg.dy# solve the Poisson problemmg.init_zeros()mg.init_RHS(divU)mg.solve(rtol=1.e-12)# update the normal velocities with the pressure gradient -- these# constitute our advective velocitiesphi_MAC=self.cc_data.get_var("phi-MAC")solution=mg.get_solution()phi_MAC.v(buf=1)[:,:]=solution.v(buf=1)# we need the MAC velocities on all edges of the computational domainb=(0,1,0,0)u_MAC.v(buf=b)[:,:]-=(phi_MAC.v(buf=b)-phi_MAC.ip(-1,buf=b))/myg.dxb=(0,0,0,1)v_MAC.v(buf=b)[:,:]-=(phi_MAC.v(buf=b)-phi_MAC.jp(-1,buf=b))/myg.dy# ---------------------------------------------------------------------# recompute the interface states, using the advective velocity# from above# ---------------------------------------------------------------------ifself.verbose>0:print(" making u, v edge states")_ux,_vx,_uy,_vy= \
incomp_interface.states(myg,self.dt,u,v,ldelta_ux,ldelta_vx,ldelta_uy,ldelta_vy,gradp_x,gradp_y,u_MAC,v_MAC,source_x,source_y)u_xint=ai.ArrayIndexer(d=_ux,grid=myg)v_xint=ai.ArrayIndexer(d=_vx,grid=myg)u_yint=ai.ArrayIndexer(d=_uy,grid=myg)v_yint=ai.ArrayIndexer(d=_vy,grid=myg)# ---------------------------------------------------------------------# update U to get the provisional velocity field# ---------------------------------------------------------------------proj_type=self.rp.get_param("incompressible.proj_type")ifother_update_velocity:U_MAC=(u_MAC,v_MAC)U_INT=(u_xint,u_yint,v_xint,v_yint)self.do_other_update_velocity(U_MAC,U_INT)else:ifself.verbose>0:print(" doing provisional update of u, v")# compute (U.grad)U# we want u_MAC U_x + v_MAC U_yadvect_x=myg.scratch_array()advect_y=myg.scratch_array()# u u_x + v u_yadvect_x.v()[:,:]= \
0.5*(u_MAC.v()+u_MAC.ip(1))*(u_xint.ip(1)-u_xint.v())/myg.dx+ \
0.5*(v_MAC.v()+v_MAC.jp(1))*(u_yint.jp(1)-u_yint.v())/myg.dy# u v_x + v v_yadvect_y.v()[:,:]= \
0.5*(u_MAC.v()+u_MAC.ip(1))*(v_xint.ip(1)-v_xint.v())/myg.dx+ \
0.5*(v_MAC.v()+v_MAC.jp(1))*(v_yint.jp(1)-v_yint.v())/myg.dyifproj_type==1:u[:,:]-=(self.dt*advect_x[:,:]+self.dt*gradp_x[:,:])v[:,:]-=(self.dt*advect_y[:,:]+self.dt*gradp_y[:,:])elifproj_type==2:u[:,:]-=self.dt*advect_x[:,:]v[:,:]-=self.dt*advect_y[:,:]self.cc_data.fill_BC("x-velocity")self.cc_data.fill_BC("y-velocity")# ---------------------------------------------------------------------# project the final velocity# ---------------------------------------------------------------------# now we solve L phi = D (U* /dt)ifself.verbose>0:print(" final projection")# create the multigrid objectmg=MG.CellCenterMG2d(myg.nx,myg.ny,xl_BC_type=self.cc_data.BCs["phi"].xlb,xr_BC_type=self.cc_data.BCs["phi"].xrb,yl_BC_type=self.cc_data.BCs["phi"].ylb,yr_BC_type=self.cc_data.BCs["phi"].yrb,xmin=myg.xmin,xmax=myg.xmax,ymin=myg.ymin,ymax=myg.ymax,verbose=0)# first compute divU# u/v are cell-centered, divU is cell-centereddivU.v()[:,:]= \
0.5*(u.ip(1)-u.ip(-1))/myg.dx+0.5*(v.jp(1)-v.jp(-1))/myg.dymg.init_RHS(divU/self.dt)# use the old phi as our initial guessphiGuess=mg.soln_grid.scratch_array()phiGuess.v(buf=1)[:,:]=phi.v(buf=1)mg.init_solution(phiGuess)# solvemg.solve(rtol=1.e-12)# store the solutionphi[:,:]=mg.get_solution(grid=myg)# compute the cell-centered gradient of p and update the velocities# this differs depending on what we projected.gradphi_x,gradphi_y=mg.get_solution_gradient(grid=myg)# u = u - grad_x phi dtu[:,:]-=self.dt*gradphi_xv[:,:]-=self.dt*gradphi_y# store gradp for the next stepifproj_type==1:gradp_x[:,:]+=gradphi_x[:,:]gradp_y[:,:]+=gradphi_y[:,:]elifproj_type==2:gradp_x[:,:]=gradphi_x[:,:]gradp_y[:,:]=gradphi_y[:,:]self.cc_data.fill_BC("x-velocity")self.cc_data.fill_BC("y-velocity")ifself.particlesisnotNone:self.particles.update_particles(self.dt)# increment the timeifnotself.in_preevolve:self.cc_data.t+=self.dtself.n+=1
[docs]defdefine_other_bc(self):""" Used to set up user-defined BC's (see e.g. incompressible_viscous) """
[docs]defother_source_term(self):""" Add source terms (other than gradp) for getting interface state values, in the x and y directions """returnNone,None
[docs]defdo_other_update_velocity(self,U_MAC,U_INT):""" Change the method for updating the velocity from the projected velocity and interface states (see e.g. incompressible_viscous) """