def initialize(self): """ Initialize the grid and variables for compressible flow and set the initial conditions for the chosen problem. """ my_grid = grid_setup(self.rp, ng=4) my_data = patch.CellCenterData2d(my_grid) # define solver specific boundary condition routines patch.define_bc("hse", BC.user, is_solid=False) bc, bc_xodd, bc_yodd = bc_setup(self.rp) # are we dealing with solid boundaries? we'll use these for # the Riemann solver self.solid = BCProp(int(patch.bc_props[self.rp.get_param("mesh.xlboundary")]), int(patch.bc_props[self.rp.get_param("mesh.xrboundary")]), int(patch.bc_props[self.rp.get_param("mesh.ylboundary")]), int(patch.bc_props[self.rp.get_param("mesh.yrboundary")])) # density and energy my_data.register_var("density", bc) my_data.register_var("energy", bc) my_data.register_var("x-momentum", bc_xodd) my_data.register_var("y-momentum", bc_yodd) # store the EOS gamma as an auxillary quantity so we can have a # self-contained object stored in output files to make plots. # store grav because we'll need that in some BCs my_data.set_aux("gamma", self.rp.get_param("eos.gamma")) my_data.set_aux("grav", self.rp.get_param("compressible.grav")) my_data.create() self.cc_data = my_data # some auxillary data that we'll need to fill GC in, but isn't # really part of the main solution aux_data = patch.CellCenterData2d(my_grid) aux_data.register_var("ymom_src", bc_yodd) aux_data.register_var("E_src", bc) aux_data.create() self.aux_data = aux_data self.vars = Variables(idens = my_data.vars.index("density"), ixmom = my_data.vars.index("x-momentum"), iymom = my_data.vars.index("y-momentum"), iener = my_data.vars.index("energy")) # initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.rp)') if self.verbose > 0: print(my_data)
def initialize(self, extra_vars=None): """ Initialize the grid and variables for compressible flow and set the initial conditions for the chosen problem. """ my_grid = grid_setup(self.rp, ng=4) my_data = patch.CellCenterData2d(my_grid) # define solver specific boundary condition routines bnd.define_bc("hse", BC.user, is_solid=False) bc, bc_xodd, bc_yodd = bc_setup(self.rp) # are we dealing with solid boundaries? we'll use these for # the Riemann solver self.solid = bnd.bc_is_solid(self.rp) # density and energy my_data.register_var("density", bc) my_data.register_var("energy", bc) my_data.register_var("x-momentum", bc_xodd) my_data.register_var("y-momentum", bc_yodd) # any extras? if extra_vars is not None: for v in extra_vars: my_data.register_var(v, bc) # store the EOS gamma as an auxillary quantity so we can have a # self-contained object stored in output files to make plots. # store grav because we'll need that in some BCs my_data.set_aux("gamma", self.rp.get_param("eos.gamma")) my_data.set_aux("grav", self.rp.get_param("compressible.grav")) my_data.create() self.cc_data = my_data # some auxillary data that we'll need to fill GC in, but isn't # really part of the main solution aux_data = patch.CellCenterData2d(my_grid) aux_data.register_var("ymom_src", bc_yodd) aux_data.register_var("E_src", bc) aux_data.create() self.aux_data = aux_data self.ivars = Variables(my_data) # derived variables self.cc_data.add_derived(derives.derive_primitives) # initial conditions for the problem problem = importlib.import_module("{}.problems.{}".format( self.solver_name, self.problem_name)) problem.init_data(self.cc_data, self.rp) if self.verbose > 0: print(my_data)
def doit(): # create our base grid and initialize it with sequential data myg = patch.Grid2d(4, 8, ng=1) myd = patch.CellCenterData2d(myg) bc = bnd.BC() myd.register_var("a", bc) myd.create() a = myd.get_var("a") a[myg.ilo:myg.ihi + 1, myg.jlo:myg.jhi + 1].flat = np.arange(myg.nx * myg.ny) print("restriction test") print("original (fine) array") myd.pretty_print("a") # create a coarse grid and fill the variable in it with restricted data print(" ") print("restricted array") cg = patch.Grid2d(2, 4, ng=1) cd = patch.CellCenterData2d(cg) cd.register_var("a", bc) cd.create() a_coarse = cd.get_var("a") a_coarse[:, :] = myd.restrict("a")[:, :] cd.pretty_print("a") print(" ") print("prolongation test") print("original (coarse) array w/ ghost cells") a_coarse[:, :].flat = np.arange(cg.qx * cg.qy) cd.pretty_print("a") # create a new fine (base) grid and fill the variable in it prolonged data # from the coarsened grid print(" ") print("prolonged array") fg = patch.Grid2d(4, 8, ng=1) fd = patch.CellCenterData2d(fg) fd.register_var("a", bc) fd.create() a_fine = fd.get_var("a") a_fine[:, :] = cd.prolong("a")[:, :] fd.pretty_print("a")
def initialize(self): """ Initialize the grid and variables for advection and set the initial conditions for the chosen problem. """ my_grid = grid_setup(self.rp, ng=4) # create the variables my_data = patch.CellCenterData2d(my_grid) bc = bc_setup(self.rp)[0] my_data.register_var("density", bc) my_data.create() self.cc_data = my_data if self.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) # now set the initial conditions for the problem problem = importlib.import_module("advection.problems.{}".format( self.problem_name)) problem.init_data(self.cc_data, self.rp)
def initialize(self): """ 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 variables bc, bc_xodd, bc_yodd = bc_setup(self.rp) my_data = patch.CellCenterData2d(my_grid) # velocities my_data.register_var("x-velocity", bc_xodd) my_data.register_var("y-velocity", bc_yodd) # phi -- used for the projections my_data.register_var("phi-MAC", bc) my_data.register_var("phi", bc) my_data.register_var("gradp_x", bc) my_data.register_var("gradp_y", bc) my_data.create() self.cc_data = my_data if self.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) # now set the initial conditions for the problem problem = importlib.import_module("incompressible.problems.{}".format(self.problem_name)) problem.init_data(self.cc_data, self.rp)
def initialize(self): """ 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 variables bc, bc_xodd, bc_yodd = bc_setup(self.rp) my_data = patch.CellCenterData2d(my_grid) # velocities my_data.register_var("x-velocity", bc_xodd) my_data.register_var("y-velocity", bc_yodd) # phi -- used for the projections my_data.register_var("phi-MAC", bc) my_data.register_var("phi", bc) my_data.register_var("gradp_x", bc) my_data.register_var("gradp_y", bc) my_data.create() self.cc_data = my_data # now set the initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.rp)')
def initialize(self): """ Initialize the grid and variables for advection and set the initial conditions for the chosen problem. """ def shift(velocity): """ Computes the direction of shift for each node for upwind discretization based on sign of veclocity """ shift_vel = np.sign(velocity) shift_vel[np.where(shift_vel <= 0)] = 0 shift_vel[np.where(shift_vel > 0)] = -1 return shift_vel my_grid = grid_setup(self.rp, ng=4) # create the variables bc, bc_xodd, bc_yodd = bc_setup(self.rp) my_data = patch.CellCenterData2d(my_grid) # velocities my_data.register_var("x-velocity", bc_xodd) my_data.register_var("y-velocity", bc_yodd) # shift my_data.register_var("x-shift", bc_xodd) my_data.register_var("y-shift", bc_yodd) # density my_data.register_var("density", bc) my_data.create() self.cc_data = my_data if self.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) # now set the initial conditions for the problem problem = importlib.import_module( "advection_nonuniform.problems.{}".format(self.problem_name)) problem.init_data(self.cc_data, self.rp) # compute the required shift for each node using corresponding velocity at the node shx = self.cc_data.get_var("x-shift") shx[:, :] = shift(self.cc_data.get_var("x-velocity")) shy = self.cc_data.get_var("y-shift") shy[:, :] = shift(self.cc_data.get_var("y-velocity"))
def initialize(rp): """ initialize the grid and variables for diffusion """ # setup the grid nx = rp.get_param("mesh.nx") ny = rp.get_param("mesh.ny") xmin = rp.get_param("mesh.xmin") xmax = rp.get_param("mesh.xmax") ymin = rp.get_param("mesh.ymin") ymax = rp.get_param("mesh.ymax") my_grid = patch.Grid2d(nx, ny, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, ng=1) # create the variables # first figure out the boundary conditions -- we allow periodic, # Dirichlet, and Neumann. xlb_type = rp.get_param("mesh.xlboundary") xrb_type = rp.get_param("mesh.xrboundary") ylb_type = rp.get_param("mesh.ylboundary") yrb_type = rp.get_param("mesh.yrboundary") bcparam = [] for bc in [xlb_type, xrb_type, ylb_type, yrb_type]: if (bc == "periodic"): bcparam.append("periodic") elif (bc == "neumann"): bcparam.append("neumann") elif (bc == "dirichlet"): bcparam.append("dirichlet") else: msg.fail("invalid BC") bc = patch.BCObject(xlb=bcparam[0], xrb=bcparam[1], ylb=bcparam[2], yrb=bcparam[3]) my_data = patch.CellCenterData2d(my_grid, runtime_parameters=rp) my_data.register_var("phi", bc) my_data.create() return my_grid, my_data
def initialize(self): """ Initialize the grid and variables for diffusion and set the initial conditions for the chosen problem. """ # setup the grid my_grid = grid_setup(self.rp, ng=1) # for MG, we need to be a power of two if my_grid.nx != my_grid.ny: msg.fail("need nx = ny for diffusion problems") n = int(math.log(my_grid.nx) / math.log(2.0)) if 2**n != my_grid.nx: msg.fail("grid needs to be a power of 2") # create the variables # first figure out the boundary conditions -- we allow periodic, # Dirichlet, and Neumann. xlb_type = self.rp.get_param("mesh.xlboundary") xrb_type = self.rp.get_param("mesh.xrboundary") ylb_type = self.rp.get_param("mesh.ylboundary") yrb_type = self.rp.get_param("mesh.yrboundary") bcparam = [] for bc in [xlb_type, xrb_type, ylb_type, yrb_type]: if bc == "periodic": bcparam.append("periodic") elif bc == "neumann": bcparam.append("neumann") elif bc == "dirichlet": bcparam.append("dirichlet") else: msg.fail("invalid BC") bc = bnd.BC(xlb=bcparam[0], xrb=bcparam[1], ylb=bcparam[2], yrb=bcparam[3]) my_data = patch.CellCenterData2d(my_grid) my_data.register_var("phi", bc) my_data.create() self.cc_data = my_data # now set the initial conditions for the problem problem = importlib.import_module("diffusion.problems.{}".format( self.problem_name)) problem.init_data(self.cc_data, self.rp)
def setup_method(self): """ this is run before each test """ nx = 8 ny = 8 self.g = patch.Grid2d(nx, ny, ng=2, xmax=1.0, ymax=1.0) self.d = patch.CellCenterData2d(self.g, dtype=np.int) bco = bnd.BC(xlb="outflow", xrb="outflow", ylb="outflow", yrb="outflow") self.d.register_var("a", bco) self.d.register_var("b", bco) self.d.create()
def initialize(self): """ Initialize the grid and variables for advection and set the initial conditions for the chosen problem. """ my_grid = grid_setup(self.rp, ng=4) # create the variables my_data = patch.CellCenterData2d(my_grid) bc = bc_setup(self.rp)[0] my_data.register_var("density", bc) my_data.create() self.cc_data = my_data # now set the initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.rp)')
def setup_method(self): """ this is run before each test """ self.rp = runparams.RuntimeParameters() self.rp.params["driver.tmax"] = 1.0 self.rp.params["driver.max_steps"] = 100 self.rp.params["driver.init_tstep_factor"] = 0.5 self.rp.params["driver.max_dt_change"] = 1.2 self.rp.params["driver.fix_dt"] = -1.0 self.sim = sn.NullSimulation("test", "test", self.rp) myg = patch.Grid2d(8, 16) myd = patch.CellCenterData2d(myg) bc = bnd.BC() myd.register_var("a", bc) myd.create() self.sim.cc_data = myd
def initialize(rp): """ initialize the grid and variables for advection """ # setup the grid nx = rp.get_param("mesh.nx") ny = rp.get_param("mesh.ny") xmin = rp.get_param("mesh.xmin") xmax = rp.get_param("mesh.xmax") ymin = rp.get_param("mesh.ymin") ymax = rp.get_param("mesh.ymax") my_grid = patch.Grid2d(nx, ny, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, ng=4) # create the variables # first figure out the boundary conditions -- we need to translate # between the descriptive type of the boundary specified by the # user and the action that will be performed by the fill_BC routine. # Usually the actions can vary depending on the variable, but we # only have one variable. xlb_type = rp.get_param("mesh.xlboundary") xrb_type = rp.get_param("mesh.xrboundary") ylb_type = rp.get_param("mesh.ylboundary") yrb_type = rp.get_param("mesh.yrboundary") bc = patch.BCObject(xlb=xlb_type, xrb=xrb_type, ylb=ylb_type, yrb=yrb_type) my_data = patch.CellCenterData2d(my_grid, runtime_parameters=rp) my_data.register_var("density", bc) my_data.create() return my_grid, my_data
def setup_test(n_particles=50, extra_rp_params=None): """ Function for setting up Particles tests. Would use unittest for this, but it doesn't seem to be possible/easy to pass in options to a setUp function. Sets up runtime paramters, a blank simulation, fills it with a grid and sets up the boundary conditions and simulation data. Parameters ---------- n_particles : int Number of particles to be generated. extra_rp_params : dict Dictionary of extra rp parameters. """ rp = runparams.RuntimeParameters() rp.params["mesh.nx"] = 8 rp.params["mesh.ny"] = 8 rp.params["mesh.xmin"] = 0 rp.params["mesh.xmax"] = 1 rp.params["mesh.ymin"] = 0 rp.params["mesh.ymax"] = 1 rp.params["particles.do_particles"] = 1 n_particles = n_particles if extra_rp_params is not None: for param, value in extra_rp_params.items(): rp.params[param] = value # set up sim sim = NullSimulation("", "", rp) # set up grid my_grid = grid_setup(rp) my_data = patch.CellCenterData2d(my_grid) bc = bc_setup(rp)[0] my_data.create() sim.cc_data = my_data return sim.cc_data, bc, n_particles
def test_write_read(): myg = patch.Grid2d(8, 6, ng=2, xmax=1.0, ymax=1.0) myd = patch.CellCenterData2d(myg) bco = bnd.BC(xlb="outflow", xrb="outflow", ylb="outflow", yrb="outflow") myd.register_var("a", bco) myd.create() a = myd.get_var("a") a.v()[:, :] = np.arange(48).reshape(8, 6) myd.write("io_test") # now read it in nd = io.read("io_test") anew = nd.get_var("a") assert_array_equal(anew.v(), a.v())
def initialize(self): """ Initialize the grid and variables for diffusion and set the initial conditions for the chosen problem. """ # setup the grid my_grid = grid_setup(self.rp, ng=1) # create the variables # first figure out the boundary conditions -- we allow periodic, # Dirichlet, and Neumann. xlb_type = self.rp.get_param("mesh.xlboundary") xrb_type = self.rp.get_param("mesh.xrboundary") ylb_type = self.rp.get_param("mesh.ylboundary") yrb_type = self.rp.get_param("mesh.yrboundary") bcparam = [] for bc in [xlb_type, xrb_type, ylb_type, yrb_type]: if bc == "periodic": bcparam.append("periodic") elif bc == "neumann": bcparam.append("neumann") elif bc == "dirichlet": bcparam.append("dirichlet") else: msg.fail("invalid BC") bc = patch.BCObject(xlb=bcparam[0], xrb=bcparam[1], ylb=bcparam[2], yrb=bcparam[3]) my_data = patch.CellCenterData2d(my_grid) my_data.register_var("phi", bc) my_data.create() self.cc_data = my_data # now set the initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.rp)')
def initialize(self): """ Initialize the grid and variables for compressible flow and set the initial conditions for the chosen problem. """ my_grid = grid_setup(self.rp, ng=4) my_data = patch.CellCenterData2d(my_grid) # define solver specific boundary condition routines patch.define_bc("hse", BC.user) bc, bc_xodd, bc_yodd = bc_setup(self.rp) # density and energy my_data.register_var("density", bc) my_data.register_var("energy", bc) my_data.register_var("x-momentum", bc_xodd) my_data.register_var("y-momentum", bc_yodd) # store the EOS gamma as an auxillary quantity so we can have a # self-contained object stored in output files to make plots. # store grav because we'll need that in some BCs my_data.set_aux("gamma", self.rp.get_param("eos.gamma")) my_data.set_aux("grav", self.rp.get_param("compressible.grav")) my_data.create() self.cc_data = my_data self.vars = Variables(idens=my_data.vars.index("density"), ixmom=my_data.vars.index("x-momentum"), iymom=my_data.vars.index("y-momentum"), iener=my_data.vars.index("energy")) # initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.rp)') if self.verbose > 0: print(my_data)
def initialize(self): """ Initialize the grid and variables for diffusion and set the initial conditions for the chosen problem. """ # setup the grid my_grid = grid_setup(self.rp, ng=1) # for MG, we need to be a power of two if my_grid.nx != my_grid.ny: msg.fail("need nx = ny for diffusion problems") n = int(math.log(my_grid.nx) / math.log(2.0)) if 2**n != my_grid.nx: msg.fail("grid needs to be a power of 2") # create the variables # first figure out the boundary conditions -- we allow periodic, # Dirichlet, and Neumann. bc, _, _ = bc_setup(self.rp) for bnd in [bc.xlb, bc.xrb, bc.ylb, bc.yrb]: if bnd not in ["periodic", "neumann", "dirichlet"]: msg.fail("invalid BC") my_data = patch.CellCenterData2d(my_grid) my_data.register_var("phi", bc) my_data.create() self.cc_data = my_data # now set the initial conditions for the problem problem = importlib.import_module("diffusion.problems.{}".format( self.problem_name)) problem.init_data(self.cc_data, self.rp)
def __init__(self, nx, ny, ng=1, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xl_BC_type="dirichlet", xr_BC_type="dirichlet", yl_BC_type="dirichlet", yr_BC_type="dirichlet", xl_BC=None, xr_BC=None, yl_BC=None, yr_BC=None, alpha=0.0, beta=-1.0, nsmooth=10, nsmooth_bottom=50, verbose=0, aux_field=None, aux_bc=None, true_function=None, vis=0, vis_title=""): """ Create the CellCenterMG2d object. Note that this requires a grid to be a power of 2 in size and square. Parameters ---------- nx : int number of cells in x-direction ny : int number of cells in y-direction. xmin : float, optional minimum physical coordinate in x-direction xmax : float, optional maximum physical coordinate in x-direction ymin : float, optional minimum physical coordinate in y-direction ymax : float, optional maximum physical coordinate in y-direction xl_BC_type : {'neumann', 'dirichlet', 'periodic'}, optional boundary condition to enforce on lower x face xr_BC_type : {'neumann', 'dirichlet', 'periodic'}, optional boundary condition to enforce on upper x face yl_BC_type : {'neumann', 'dirichlet', 'periodic'}, optional boundary condition to enforce on lower y face yr_BC_type : {'neumann', 'dirichlet', 'periodic'}, optional boundary condition to enforce on upper y face xl_BC : function, optional function (of y) to call to get -x boundary values (homogeneous assumed otherwise) xr_BC : function, optional function (of y) to call to get +x boundary values (homogeneous assumed otherwise) yl_BC : function, optional function (of x) to call to get -y boundary values (homogeneous assumed otherwise) yr_BC : function, optional function (of x) to call to get +y boundary values (homogeneous assumed otherwise) alpha : float, optional coefficient in Helmholtz equation (alpha - beta L) phi = f beta : float, optional coefficient in Helmholtz equation (alpha - beta L) phi = f nsmooth : int, optional number of smoothing iterations to be done at each intermediate level in the V-cycle (up and down) nsmooth_bottom : int, optional number of smoothing iterations to be done during the bottom solve verbose : int, optional increase verbosity during the solve (for verbose=1) aux_field : list of str, optional extra fields to define and carry at each level. Useful for subclassing. aux_bc : list of BC objects, optional the boundary conditions corresponding to the aux fields true_function : function, optional a function (of x,y) that provides the exact solution to the elliptic problem we are solving. This is used only for visualization purposes vis : int, optional output a detailed visualization of every smoothing step all throughout the V-cycle (if vis=1) vis_title : string, optional a descriptive title to write on the visualization plots Returns ------- out: CellCenterMG2d object """ if nx != ny: raise ValueError("ERROR: multigrid currently requires nx = ny") self.nx = nx self.ny = ny self.ng = ng self.xmin = xmin self.xmax = xmax self.ymin = ymin self.ymax = ymax if (xmax-xmin) != (ymax-ymin): raise ValueError("ERROR: multigrid currently requires a square domain") self.alpha = alpha self.beta = beta self.nsmooth = nsmooth self.nsmooth_bottom = nsmooth_bottom self.max_cycles = 100 self.verbose = verbose # for visualization purposes, we can set a function name that # provides the true solution to our elliptic problem. if true_function is not None: self.true_function = true_function # a small number used in computing the error, so we don't divide by 0 self.small = 1.e-16 # keep track of whether we've initialized the RHS self.initialized_rhs = 0 # assume that self.nx = 2^(nlevels-1) and that nx = ny # this defines nlevels such that we end exactly on a 2x2 grid self.nlevels = int(math.log(self.nx)/math.log(2.0)) # a multigrid object will be a list of grids self.grids = [] # create the grids. Here, self.grids[0] will be the coarsest # grid and self.grids[nlevel-1] will be the finest grid # we store the solution, v, the rhs, f. # create the boundary condition object bc = bnd.BC(xlb=xl_BC_type, xrb=xr_BC_type, ylb=yl_BC_type, yrb=yr_BC_type) nx_t = ny_t = 2 for i in range(self.nlevels): # create the grid my_grid = patch.Grid2d(nx_t, ny_t, ng=self.ng, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) # add a CellCenterData2d object for this level to our list self.grids.append(patch.CellCenterData2d(my_grid, dtype=np.float64)) # create the phi BC object -- this only applies for the finest # level. On the coarser levels, phi represents the residual, # which has homogeneous BCs bc_p = bnd.BC(xlb=xl_BC_type, xrb=xr_BC_type, ylb=yl_BC_type, yrb=yr_BC_type, xl_func=xl_BC, xr_func=xr_BC, yl_func=yl_BC, yr_func=yr_BC, grid=my_grid) if i == self.nlevels-1: self.grids[i].register_var("v", bc_p) else: self.grids[i].register_var("v", bc) self.grids[i].register_var("f", bc) self.grids[i].register_var("r", bc) if aux_field is not None: for f, b in zip(aux_field, aux_bc): self.grids[i].register_var(f, b) self.grids[i].create() if self.verbose: print(self.grids[i]) nx_t = nx_t*2 ny_t = ny_t*2 # provide coordinate and indexing information for the solution mesh soln_grid = self.grids[self.nlevels-1].grid self.ilo = soln_grid.ilo self.ihi = soln_grid.ihi self.jlo = soln_grid.jlo self.jhi = soln_grid.jhi self.x = soln_grid.x self.dx = soln_grid.dx self.x2d = soln_grid.x2d self.y = soln_grid.y self.dy = soln_grid.dy # note, dy = dx is assumed self.y2d = soln_grid.y2d self.soln_grid = soln_grid # store the source norm self.source_norm = 0.0 # after solving, keep track of the number of cycles taken, the # relative error from the previous cycle, and the residual error # (normalized to the source norm) self.num_cycles = 0 self.residual_error = 1.e33 self.relative_error = 1.e33 # keep track of where we are in the V self.current_cycle = -1 self.current_level = -1 self.up_or_down = "" # for visualization -- what frame are we outputting? self.vis = vis self.vis_title = vis_title self.frame = 0
def test_general_poisson_dirichlet(N, store_bench=False, comp_bench=False, make_plot=False, verbose=1): """ test the general MG solver. The return value here is the error compared to the exact solution, UNLESS comp_bench=True, in which case the return value is the error compared to the stored benchmark """ # test the multigrid solver nx = N ny = nx # create the coefficient variable g = patch.Grid2d(nx, ny, ng=1) d = patch.CellCenterData2d(g) bc_c = bnd.BC(xlb="neumann", xrb="neumann", ylb="neumann", yrb="neumann") d.register_var("alpha", bc_c) d.register_var("beta", bc_c) d.register_var("gamma_x", bc_c) d.register_var("gamma_y", bc_c) d.create() a = d.get_var("alpha") a[:, :] = alpha(g.x2d, g.y2d) b = d.get_var("beta") b[:, :] = beta(g.x2d, g.y2d) gx = d.get_var("gamma_x") gx[:, :] = gamma_x(g.x2d, g.y2d) gy = d.get_var("gamma_y") gy[:, :] = gamma_y(g.x2d, g.y2d) # create the multigrid object a = MG.GeneralMG2d(nx, ny, xl_BC_type="dirichlet", yl_BC_type="dirichlet", xr_BC_type="dirichlet", yr_BC_type="dirichlet", coeffs=d, verbose=verbose, vis=0, true_function=true) # initialize the solution to 0 a.init_zeros() # initialize the RHS using the function f rhs = f(a.x2d, a.y2d) a.init_RHS(rhs) # solve to a relative tolerance of 1.e-11 a.solve(rtol=1.e-11) # alternately, we can just use smoothing by uncommenting the following # a.smooth(a.nlevels-1,50000) # get the solution v = a.get_solution() # compute the error from the analytic solution b = true(a.x2d, a.y2d) e = v - b enorm = e.norm() print( " L2 error from true solution = %g\n rel. err from previous cycle = %g\n num. cycles = %d" % (enorm, a.relative_error, a.num_cycles)) # plot the solution if make_plot: plt.clf() plt.figure(figsize=(10.0, 4.0), dpi=100, facecolor='w') plt.subplot(121) plt.imshow(np.transpose(v.v()), interpolation="nearest", origin="lower", extent=[a.xmin, a.xmax, a.ymin, a.ymax]) plt.xlabel("x") plt.ylabel("y") plt.title("nx = {}".format(nx)) plt.colorbar() plt.subplot(122) plt.imshow(np.transpose(e.v()), interpolation="nearest", origin="lower", extent=[a.xmin, a.xmax, a.ymin, a.ymax]) plt.xlabel("x") plt.ylabel("y") plt.title("error") plt.colorbar() plt.tight_layout() plt.savefig("mg_general_dirichlet_test.png") # store the output for later comparison bench = "mg_general_poisson_dirichlet" bench_dir = os.environ["PYRO_HOME"] + "/multigrid/tests/" my_data = a.get_solution_object() if store_bench: my_data.write("{}/{}".format(bench_dir, bench)) # do we do a comparison? if comp_bench: compare_file = "{}/{}".format(bench_dir, bench) msg.warning("comparing to: %s " % (compare_file)) bench = io.read(compare_file) result = compare.compare(my_data, bench) if result == 0: msg.success("results match benchmark\n") else: msg.warning("ERROR: " + compare.errors[result] + "\n") return result # normal return -- error wrt true solution return enorm
""" if not len(sys.argv) == 2: print(usage) sys.exit(2) try: file1 = sys.argv[1] except: print(usage) sys.exit(2) myg, myd = patch.read(file1) # create a new data object on the same grid analytic = patch.CellCenterData2d(myg, dtype=np.float64) bco = myd.BCs[myd.vars[0]] analytic.register_var("density", bco) analytic.create() # use the original initialization routine to set the analytic solution smooth.init_data(analytic, None) # compare the error dens_numerical = myd.get_var("density") dens_analytic = analytic.get_var("density") print("mesh details") print(myg)
def initialize(self): """ Initialize the grid and variables for low Mach atmospheric flow and set the initial conditions for the chosen problem. """ myg = grid_setup(self.rp, ng=4) bc_dens, bc_xodd, bc_yodd = bc_setup(self.rp) my_data = patch.CellCenterData2d(myg) my_data.register_var("density", bc_dens) my_data.register_var("x-velocity", bc_xodd) my_data.register_var("y-velocity", bc_yodd) # we'll keep the internal energy around just as a diagnostic my_data.register_var("eint", bc_dens) # phi -- used for the projections. The boundary conditions # here depend on velocity. At a wall or inflow, we already # have the velocity we want on the boundary, so we want # Neumann (dphi/dn = 0). For outflow, we want Dirichlet (phi # = 0) -- this ensures that we do not introduce any tangental # acceleration. bcs = [] for bc in [self.rp.get_param("mesh.xlboundary"), self.rp.get_param("mesh.xrboundary"), self.rp.get_param("mesh.ylboundary"), self.rp.get_param("mesh.yrboundary")]: if bc == "periodic": bctype = "periodic" elif bc in ["reflect", "slipwall"]: bctype = "neumann" elif bc in ["outflow"]: bctype = "dirichlet" bcs.append(bctype) bc_phi = patch.BCObject(xlb=bcs[0], xrb=bcs[1], ylb=bcs[2], yrb=bcs[3]) my_data.register_var("phi-MAC", bc_phi) my_data.register_var("phi", bc_phi) # gradp -- used in the projection and interface states. We'll do the # same BCs as density my_data.register_var("gradp_x", bc_dens) my_data.register_var("gradp_y", bc_dens) my_data.create() self.cc_data = my_data # some auxillary data that we'll need to fill GC in, but isn't # really part of the main solution aux_data = patch.CellCenterData2d(myg) aux_data.register_var("coeff", bc_dens) aux_data.register_var("source_y", bc_yodd) aux_data.create() self.aux_data = aux_data # we also need storage for the 1-d base state -- we'll store this # in the main class directly. self.base["rho0"] = Basestate(myg.ny, ng=myg.ng) self.base["p0"] = Basestate(myg.ny, ng=myg.ng) # now set the initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.base, self.rp)') # Construct beta_0 gamma = self.rp.get_param("eos.gamma") self.base["beta0"] = Basestate(myg.ny, ng=myg.ng) self.base["beta0"].d[:] = self.base["p0"].d**(1.0/gamma) # we'll also need beta_0 on vertical edges -- on the domain edges, # just do piecewise constant self.base["beta0-edges"] = Basestate(myg.ny, ng=myg.ng) self.base["beta0-edges"].jp(1)[:] = \ 0.5*(self.base["beta0"].v() + self.base["beta0"].jp(1)) self.base["beta0-edges"].d[myg.jlo] = self.base["beta0"].d[myg.jlo] self.base["beta0-edges"].d[myg.jhi+1] = self.base["beta0"].d[myg.jhi]
def test_bcs(): myg = patch.Grid2d(4, 4, ng=2, xmax=1.0, ymax=1.0) myd = patch.CellCenterData2d(myg, dtype=np.int) bco = bnd.BC(xlb="outflow", xrb="outflow", ylb="outflow", yrb="outflow") myd.register_var("outflow", bco) bcp = bnd.BC(xlb="periodic", xrb="periodic", ylb="periodic", yrb="periodic") myd.register_var("periodic", bcp) bcre = bnd.BC(xlb="reflect-even", xrb="reflect-even", ylb="reflect-even", yrb="reflect-even") myd.register_var("reflect-even", bcre) bcro = bnd.BC(xlb="reflect-odd", xrb="reflect-odd", ylb="reflect-odd", yrb="reflect-odd") myd.register_var("reflect-odd", bcro) myd.create() a = myd.get_var("outflow") a.v()[:, :] = np.fromfunction(lambda i, j: i + 10 * j + 1, (4, 4), dtype=int) b = myd.get_var("periodic") c = myd.get_var("reflect-even") d = myd.get_var("reflect-odd") b[:, :] = a[:, :] c[:, :] = a[:, :] d[:, :] = a[:, :] myd.fill_BC("outflow") # left ghost assert_array_equal(a[myg.ilo - 1, myg.jlo:myg.jhi + 1], np.array([1, 11, 21, 31])) # right ghost assert_array_equal(a[myg.ihi + 1, myg.jlo:myg.jhi + 1], np.array([4, 14, 24, 34])) # bottom ghost assert_array_equal(a[myg.ilo:myg.ihi + 1, myg.jlo - 1], np.array([1, 2, 3, 4])) # top ghost assert_array_equal(a[myg.ilo:myg.ihi + 1, myg.jhi + 1], np.array([31, 32, 33, 34])) myd.fill_BC("periodic") # x-boundaries assert_array_equal(b[myg.ilo - 1, myg.jlo:myg.jhi + 1], b[myg.ihi, myg.jlo:myg.jhi + 1]) assert_array_equal(b[myg.ilo, myg.jlo:myg.jhi + 1], b[myg.ihi + 1, myg.jlo:myg.jhi + 1]) # y-boundaries assert_array_equal(b[myg.ilo:myg.ihi + 1, myg.jlo - 1], b[myg.ilo:myg.ihi + 1, myg.jhi]) assert_array_equal(b[myg.ilo:myg.ihi + 1, myg.jlo], b[myg.ilo:myg.ihi + 1, myg.jhi + 1]) myd.fill_BC("reflect-even") # left -- we'll check 2 ghost cells here -- now we use flipud here # because our 'x' is the row index # left assert_array_equal(c[myg.ilo:myg.ilo + 2, myg.jlo:myg.ihi + 1], np.flipud(c[myg.ilo - 2:myg.ilo, myg.jlo:myg.jhi + 1])) # right assert_array_equal( c[myg.ihi - 1:myg.ihi + 1, myg.jlo:myg.jhi + 1], np.flipud(c[myg.ihi + 1:myg.ihi + 3, myg.jlo:myg.jhi + 1])) # bottom assert_array_equal(c[myg.ilo:myg.ihi + 1, myg.jlo:myg.jlo + 2], np.fliplr(c[myg.ilo:myg.ihi + 1, myg.jlo - 2:myg.jlo])) # top assert_array_equal( c[myg.ilo:myg.ihi + 1, myg.jhi - 1:myg.jhi + 1], np.fliplr(c[myg.ilo:myg.ihi + 1, myg.jhi + 1:myg.jhi + 3])) myd.fill_BC("reflect-odd") # left -- we'll check 2 ghost cells here -- now we use flipud here # because our 'x' is the row index # left assert_array_equal(d[myg.ilo:myg.ilo + 2, myg.jlo:myg.ihi + 1], -np.flipud(d[myg.ilo - 2:myg.ilo, myg.jlo:myg.jhi + 1])) # right assert_array_equal( d[myg.ihi - 1:myg.ihi + 1, myg.jlo:myg.jhi + 1], -np.flipud(d[myg.ihi + 1:myg.ihi + 3, myg.jlo:myg.jhi + 1])) # bottom assert_array_equal(d[myg.ilo:myg.ihi + 1, myg.jlo:myg.jlo + 2], -np.fliplr(d[myg.ilo:myg.ihi + 1, myg.jlo - 2:myg.jlo])) # top assert_array_equal( d[myg.ilo:myg.ihi + 1, myg.jhi - 1:myg.jhi + 1], -np.fliplr(d[myg.ilo:myg.ihi + 1, myg.jhi + 1:myg.jhi + 3]))
# test the prolongation and restriction operations from the patch stuff import mesh.patch as patch import numpy # create our base grid and initialize it with sequential data myg = patch.Grid2d(4,8,ng=1) myd = patch.CellCenterData2d(myg) bc = patch.BCObject() myd.register_var("a", bc) myd.create() a = myd.get_var("a") a[myg.ilo:myg.ihi+1,myg.jlo:myg.jhi+1].flat = numpy.arange(myg.nx*myg.ny) print "restriction test" print "original (fine) array" myd.pretty_print("a") # create a coarse grid and fill the variable in it with restricted data print " " print "restricted array" cg = patch.Grid2d(2,4,ng=1) cd = patch.CellCenterData2d(cg) cd.register_var("a", bc) cd.create() a_coarse = cd.get_var("a")
def test_vc_poisson_periodic(N, store_bench=False, comp_bench=False, make_plot=False, verbose=1): """ test the variable-coefficient MG solver. The return value here is the error compared to the exact solution, UNLESS comp_bench=True, in which case the return value is the error compared to the stored benchmark """ # test the multigrid solver nx = N ny = nx # create the coefficient variable g = patch.Grid2d(nx, ny, ng=1) d = patch.CellCenterData2d(g) bc_c = bnd.BC(xlb="periodic", xrb="periodic", ylb="periodic", yrb="periodic") d.register_var("c", bc_c) d.create() c = d.get_var("c") c[:, :] = alpha(g.x2d, g.y2d) # check whether the RHS sums to zero (necessary for periodic data) rhs = f(g.x2d, g.y2d) print("rhs sum: {}".format(np.sum(rhs[g.ilo:g.ihi + 1, g.jlo:g.jhi + 1]))) # create the multigrid object a = MG.VarCoeffCCMG2d(nx, ny, xl_BC_type="periodic", yl_BC_type="periodic", xr_BC_type="periodic", yr_BC_type="periodic", coeffs=c, coeffs_bc=bc_c, verbose=verbose, vis=0, true_function=true) # initialize the solution to 0 a.init_zeros() # initialize the RHS using the function f rhs = f(a.x2d, a.y2d) a.init_RHS(rhs) # solve to a relative tolerance of 1.e-11 a.solve(rtol=1.e-11) # alternately, we can just use smoothing by uncommenting the following #a.smooth(a.nlevels-1,10000) # get the solution v = a.get_solution() # get the true solution b = true(a.x2d, a.y2d) # compute the error from the analytic solution -- note that with # periodic BCs all around, there is nothing to normalize the # solution. We subtract off the average of phi from the MG # solution (we do the same for the true solution to put them on # the same footing) e = v - np.sum(v.v()) / (nx * ny) - ( b - np.sum(b[a.ilo:a.ihi + 1, a.jlo:a.jhi + 1]) / (nx * ny)) enorm = e.norm() print(" L2 error from true solution = %g\n rel. err from previous cycle = %g\n num. cycles = %d" % \ (enorm, a.relative_error, a.num_cycles)) # plot the solution if make_plot: plt.clf() plt.figure(figsize=(10.0, 4.0), dpi=100, facecolor='w') plt.subplot(121) plt.imshow(np.transpose(v.v()), interpolation="nearest", origin="lower", extent=[a.xmin, a.xmax, a.ymin, a.ymax]) plt.xlabel("x") plt.ylabel("y") plt.title("nx = {}".format(nx)) plt.colorbar() plt.subplot(122) plt.imshow(np.transpose(e.v()), interpolation="nearest", origin="lower", extent=[a.xmin, a.xmax, a.ymin, a.ymax]) plt.xlabel("x") plt.ylabel("y") plt.title("error") plt.colorbar() plt.tight_layout() plt.savefig("mg_vc_periodic_test.png") # store the output for later comparison bench = "mg_vc_poisson_periodic" bench_dir = os.environ["PYRO_HOME"] + "/multigrid/tests/" my_data = a.get_solution_object() if store_bench: my_data.write("{}/{}".format(bench_dir, bench)) # do we do a comparison? if comp_bench: compare_file = "{}/{}".format(bench_dir, bench) msg.warning("comparing to {}".format(compare_file)) bench_grid, bench_data = patch.read(compare_file) result = compare.compare(my_data.grid, my_data, bench_grid, bench_data) if result == 0: msg.success("results match benchmark\n") else: msg.warning("ERROR: {}\n".format(compare.errors[result])) return result # normal return -- error wrt true solution return enorm
def initialize(self): """ Initialize the grid and variables for compressible flow and set the initial conditions for the chosen problem. """ # setup the grid nx = self.rp.get_param("mesh.nx") ny = self.rp.get_param("mesh.ny") xmin = self.rp.get_param("mesh.xmin") xmax = self.rp.get_param("mesh.xmax") ymin = self.rp.get_param("mesh.ymin") ymax = self.rp.get_param("mesh.ymax") verbose = self.rp.get_param("driver.verbose") my_grid = patch.Grid2d(nx, ny, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, ng=4) # create the variables my_data = patch.CellCenterData2d(my_grid) # define solver specific boundary condition routines patch.define_bc("hse", BC.user) # first figure out the boundary conditions. Note: the action # can depend on the variable (for reflecting BCs) xlb_type = self.rp.get_param("mesh.xlboundary") xrb_type = self.rp.get_param("mesh.xrboundary") ylb_type = self.rp.get_param("mesh.ylboundary") yrb_type = self.rp.get_param("mesh.yrboundary") bc = patch.BCObject(xlb=xlb_type, xrb=xrb_type, ylb=ylb_type, yrb=yrb_type) # density and energy my_data.register_var("density", bc) my_data.register_var("energy", bc) my_data.register_var("erad", bc) # for velocity, if we are reflecting, we need odd reflection # in the normal direction. # x-momentum -- if we are reflecting in x, then we need to # reflect odd bc_xodd = patch.BCObject(xlb=xlb_type, xrb=xrb_type, ylb=ylb_type, yrb=yrb_type, odd_reflect_dir="x") my_data.register_var("x-momentum", bc_xodd) # y-momentum -- if we are reflecting in y, then we need to # reflect odd bc_yodd = patch.BCObject(xlb=xlb_type, xrb=xrb_type, ylb=ylb_type, yrb=yrb_type, odd_reflect_dir="y") my_data.register_var("y-momentum", bc_yodd) # store grav because we'll need that in some BCs my_data.set_aux("grav", self.rp.get_param("compressible.grav")) my_data.create() self.cc_data = my_data self.vars = Variables(idens=my_data.vars.index("density"), ixmom=my_data.vars.index("x-momentum"), iymom=my_data.vars.index("y-momentum"), iener=my_data.vars.index("energy"), ierad=my_data.vars.index("erad")) # initial conditions for the problem exec(self.problem_name + '.init_data(self.cc_data, self.rp)') if verbose > 0: print(my_data)
def read(filename): if not filename.endswith(".h5"): filename += ".h5" with h5py.File(filename, "r") as f: # read the simulation information -- this only exists if the # file was created as a simulation object try: solver_name = f.attrs["solver"] problem_name = f.attrs["problem"] t = f.attrs["time"] n = f.attrs["nsteps"] except KeyError: # this was just a patch written out solver_name = None # read in the grid info and create our grid grid = f["grid"].attrs myg = patch.Grid2d(grid["nx"], grid["ny"], ng=grid["ng"], xmin=grid["xmin"], xmax=grid["xmax"], ymin=grid["ymin"], ymax=grid["ymax"]) # read in the variable info -- start by getting the names gs = f["state"] names = [] for n in gs: names.append(n) # create the CellCenterData2d object myd = patch.CellCenterData2d(myg) for n in names: grp = gs[n] bc = bnd.BC(xlb=grp.attrs["xlb"], xrb=grp.attrs["xrb"], ylb=grp.attrs["ylb"], yrb=grp.attrs["yrb"]) myd.register_var(n, bc) myd.create() # auxillary data for k in f["aux"].attrs: myd.set_aux(k, f["aux"].attrs[k]) # restore the variable data for n in names: grp = gs[n] data = grp["data"] v = myd.get_var(n) v.v()[:,:] = data[:,:] if solver_name is not None: solver = importlib.import_module(solver_name) sim = solver.Simulation(solver_name, problem_name, None) sim.n = n sim.cc_data = myd sim.cc_data.t = t sim.read_extras(f) if solver_name is not None: return sim else: return myd
arrays = [self.jp1, self.jm1, self.jp2, self.jm2] shifts = [1, -1, 2, -2] for a, s in zip(arrays, shifts): a[ilo:ihi + 1, jlo + s:jhi + 1 + s] = True def _mask_array(self, nx, ny, ng): return np.zeros((nx + 2 * ng, ny + 2 * ng), dtype=bool) n = 1024 myg = patch.Grid2d(n, 2 * n, xmax=1.0, ymax=2.0) myd = patch.CellCenterData2d(myg) bc = bnd.BC() myd.register_var("a", bc) myd.create() a = myd.get_var("a") a[:, :] = np.random.rand(myg.qx, myg.qy) #a[:,:] = np.arange(myg.qx*myg.qy).reshape(myg.qx, myg.qy) # slicing method start = time.time() da = myg.scratch_array() da[myg.ilo:myg.ihi+1,myg.jlo:myg.jhi+1] = \ a[myg.ilo+1:myg.ihi+2,myg.jlo:myg.jhi+1] - \
def read(filename): """read an HDF5 file and recreate the simulation object that holds the data and state of the simulation. """ if not filename.endswith(".h5"): filename += ".h5" with h5py.File(filename, "r") as f: # read the simulation information -- this only exists if the # file was created as a simulation object try: solver_name = f.attrs["solver"] problem_name = f.attrs["problem"] t = f.attrs["time"] n = f.attrs["nsteps"] except KeyError: # this was just a patch written out solver_name = None # read in the grid info and create our grid grid = f["grid"].attrs myg = patch.Grid2d(grid["nx"], grid["ny"], ng=grid["ng"], xmin=grid["xmin"], xmax=grid["xmax"], ymin=grid["ymin"], ymax=grid["ymax"]) # sometimes problems define custom BCs -- at the moment, we # are going to assume that these always map to BC.user. We # need to read these in now, since the variable creation # requires it. custom_bcs = read_bcs(f) if custom_bcs is not None: if solver_name in [ "compressible_fv4", "compressible_rk", "compressible_sdc" ]: bc_solver = "compressible" else: bc_solver = solver_name bcmod = importlib.import_module("{}.{}".format(bc_solver, "BC")) for name in custom_bcs: bnd.define_bc(name, bcmod.user, is_solid=custom_bcs[name]) # read in the variable info -- start by getting the names gs = f["state"] names = [] for n in gs: names.append(n) # create the CellCenterData2d object myd = patch.CellCenterData2d(myg) for n in names: grp = gs[n] bc = bnd.BC(xlb=grp.attrs["xlb"], xrb=grp.attrs["xrb"], ylb=grp.attrs["ylb"], yrb=grp.attrs["yrb"]) myd.register_var(n, bc) myd.create() # auxillary data for k in f["aux"].attrs: myd.set_aux(k, f["aux"].attrs[k]) # restore the variable data for n in names: grp = gs[n] data = grp["data"] v = myd.get_var(n) v.v()[:, :] = data[:, :] # restore the particle data try: gparticles = f["particles"] particle_data = gparticles["particle_positions"] init_data = gparticles["init_particle_positions"] my_particles = particles.Particles(myd, None, len(particle_data), "array", particle_data, init_data) except KeyError: my_particles = None if solver_name is not None: solver = importlib.import_module(solver_name) sim = solver.Simulation(solver_name, problem_name, None) sim.n = n sim.cc_data = myd sim.cc_data.t = t sim.particles = my_particles sim.read_extras(f) if solver_name is not None: return sim return myd
def doit(nx, ny): nproj = 2 # create a mesh containing the x- and y-velocities, and periodic boundary # conditions myg = patch.Grid2d(nx, ny, ng=1) bc = bnd.BC(xlb="periodic", xrb="periodic", ylb="periodic", yrb="periodic") U = patch.CellCenterData2d(myg) U.register_var('u-old', bc) U.register_var('v-old', bc) U.register_var('u+gphi', bc) U.register_var('v+gphi', bc) U.register_var('u', bc) U.register_var('v', bc) U.register_var('divU', bc) U.register_var('phi-old', bc) U.register_var('phi', bc) U.register_var('dphi', bc) U.register_var('gradphi_x-old', bc) U.register_var('gradphi_y-old', bc) U.register_var('gradphi_x', bc) U.register_var('gradphi_y', bc) U.create() # initialize a divergence free velocity field, # u = -sin^2(pi x) sin(2 pi y), v = sin^2(pi y) sin(2 pi x) u = U.get_var('u') v = U.get_var('v') u[:, :] = -(np.sin(np.pi * myg.x2d)**2) * np.sin(2.0 * np.pi * myg.y2d) v[:, :] = (np.sin(np.pi * myg.y2d)**2) * np.sin(2.0 * np.pi * myg.x2d) # store the original, divergence free velocity field for comparison later uold = U.get_var('u-old') vold = U.get_var('v-old') uold[:, :] = u.copy() vold[:, :] = v.copy() # the projection routine should decompose U into a divergence free # part, U_d, plus the gradient of a scalar. Add on the gradient # of a scalar that satisfies gradphi.n = 0. After the projection, # we should recover the divergence free field above. Take phi to # be a gaussian, exp(-((x-x0)^2 + (y-y0)^2)/R) R = 0.1 x0 = 0.5 y0 = 0.5 phi = U.get_var('phi-old') gradphi_x = U.get_var('gradphi_x-old') gradphi_y = U.get_var('gradphi_y-old') phi[:, :] = np.exp(-((myg.x2d - x0)**2 + (myg.y2d - y0)**2) / R**2) gradphi_x[:, :] = phi * (-2.0 * (myg.x2d - x0) / R**2) gradphi_y[:, :] = phi * (-2.0 * (myg.y2d - y0) / R**2) u += gradphi_x v += gradphi_y u_plus_gradphi = U.get_var('u+gphi') v_plus_gradphi = U.get_var('v+gphi') u_plus_gradphi[:, :] = u[:, :] v_plus_gradphi[:, :] = v[:, :] # use the mesh class to enforce the periodic BCs on the velocity field U.fill_BC_all() # now compute the cell-centered, centered-difference divergence divU = U.get_var('divU') divU[myg.ilo:myg.ihi+1, myg.jlo:myg.jhi+1] = \ 0.5*(u[myg.ilo+1:myg.ihi+2, myg.jlo:myg.jhi+1] - u[myg.ilo-1:myg.ihi, myg.jlo:myg.jhi+1])/myg.dx + \ 0.5*(v[myg.ilo:myg.ihi+1, myg.jlo+1:myg.jhi+2] - v[myg.ilo:myg.ihi+1, myg.jlo-1:myg.jhi])/myg.dy # create the multigrid object with Neumann BCs a = MG.CellCenterMG2d(nx, ny, xl_BC_type="periodic", xr_BC_type="periodic", yl_BC_type="periodic", yr_BC_type="periodic", verbose=1) #-------------------------------------------------------------------------- # projections #-------------------------------------------------------------------------- for iproj in range(nproj): a.init_zeros() a.init_RHS(divU) a.solve(rtol=1.e-12) phi = U.get_var('phi') solution = a.get_solution() phi[myg.ilo-1:myg.ihi+2, myg.jlo-1:myg.jhi+2] = \ solution[a.ilo-1:a.ihi+2, a.jlo-1:a.jhi+2] dphi = U.get_var('dphi') dphi[:, :] = phi - U.get_var('phi-old') # compute the gradient of phi using centered differences gradphi_x = U.get_var('gradphi_x') gradphi_y = U.get_var('gradphi_y') gradphi_x[myg.ilo:myg.ihi+1, myg.jlo:myg.jhi+1] = \ 0.5*(phi[myg.ilo+1:myg.ihi+2, myg.jlo:myg.jhi+1] - phi[myg.ilo-1:myg.ihi, myg.jlo:myg.jhi+1])/myg.dx gradphi_y[myg.ilo:myg.ihi+1, myg.jlo:myg.jhi+1] = \ 0.5*(phi[myg.ilo:myg.ihi+1, myg.jlo+1:myg.jhi+2] - phi[myg.ilo:myg.ihi+1, myg.jlo-1:myg.jhi])/myg.dy # update the velocity field u -= gradphi_x v -= gradphi_y U.fill_BC_all() # recompute the divergence diagnostic divU[myg.ilo:myg.ihi+1, myg.jlo:myg.jhi+1] = \ 0.5*(u[myg.ilo+1:myg.ihi+2, myg.jlo:myg.jhi+1] - u[myg.ilo-1:myg.ihi, myg.jlo:myg.jhi+1])/myg.dx + \ 0.5*(v[myg.ilo:myg.ihi+1, myg.jlo+1:myg.jhi+2] - v[myg.ilo:myg.ihi+1, myg.jlo-1:myg.jhi])/myg.dy U.write("proj-periodic.after" + ("%d" % iproj))