def test_vc_poisson_dirichlet(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 = patch.BCObject(xlb="neumann", xrb="neumann", ylb="neumann", yrb="neumann") d.register_var("c", bc_c) d.create() c = d.get_var("c") c.d[:, :] = alpha(g.x2d, g.y2d) # create the multigrid object a = MG.VarCoeffCCMG2d(nx, ny, xl_BC_type="dirichlet", yl_BC_type="dirichlet", xr_BC_type="dirichlet", yr_BC_type="dirichlet", 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,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_vc_dirichlet_test.png") # store the output for later comparison bench = "mg_vc_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_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: " + compare.errors[result] + "\n") return result # normal return -- error wrt true solution return enorm
def evolve(self): """ Evolve the low Mach system through one timestep. """ rho = self.cc_data.get_var("density") 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") # note: the base state quantities do not have valid ghost cells beta0 = self.base["beta0"] beta0_edges = self.base["beta0-edges"] rho0 = self.base["rho0"] phi = self.cc_data.get_var("phi") myg = self.cc_data.grid #--------------------------------------------------------------------- # create the limited slopes of rho, u and v (in both directions) #--------------------------------------------------------------------- limiter = self.rp.get_param("lm-atmosphere.limiter") if limiter == 0: limitFunc = reconstruction_f.nolimit elif limiter == 1: limitFunc = reconstruction_f.limit2 else: limitFunc = reconstruction_f.limit4 ldelta_rx = limitFunc(1, rho.d, myg.qx, myg.qy, myg.ng) ldelta_ux = limitFunc(1, u.d, myg.qx, myg.qy, myg.ng) ldelta_vx = limitFunc(1, v.d, myg.qx, myg.qy, myg.ng) ldelta_ry = limitFunc(2, rho.d, myg.qx, myg.qy, myg.ng) ldelta_uy = limitFunc(2, u.d, myg.qx, myg.qy, myg.ng) ldelta_vy = limitFunc(2, v.d, myg.qx, myg.qy, myg.ng) #--------------------------------------------------------------------- # 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 grid if self.verbose > 0: print(" making MAC velocities") # create the coefficient to the grad (pi/beta) term coeff = self.aux_data.get_var("coeff") coeff.v()[:,:] = 1.0/rho.v() coeff.v()[:,:] = coeff.v()*beta0.v2d() self.aux_data.fill_BC("coeff") # create the source term source = self.aux_data.get_var("source_y") g = self.rp.get_param("lm-atmosphere.grav") rhoprime = self.make_prime(rho, rho0) source.v()[:,:] = rhoprime.v()*g/rho.v() self.aux_data.fill_BC("source_y") _um, _vm = lm_interface_f.mac_vels(myg.qx, myg.qy, myg.ng, myg.dx, myg.dy, self.dt, u.d, v.d, ldelta_ux, ldelta_vx, ldelta_uy, ldelta_vy, coeff.d*gradp_x.d, coeff.d*gradp_y.d, source.d) u_MAC = patch.ArrayIndexer(d=_um, grid=myg) v_MAC = patch.ArrayIndexer(d=_vm, grid=myg) #--------------------------------------------------------------------- # do a MAC projection to make the advective velocities divergence # free #--------------------------------------------------------------------- # we will solve D (beta_0^2/rho) G phi = D (beta_0 U^MAC), where # phi is cell centered, and U^MAC is the MAC-type staggered # grid of the advective velocities. if self.verbose > 0: print(" MAC projection") # create the coefficient array: beta0**2/rho # MZ!!!! probably don't need the buf here coeff.v(buf=1)[:,:] = 1.0/rho.v(buf=1) coeff.v(buf=1)[:,:] = coeff.v(buf=1)*beta0.v2d(buf=1)**2 # create the multigrid object mg = vcMG.VarCoeffCCMG2d(myg.nx, myg.ny, xl_BC_type=self.cc_data.BCs["phi-MAC"].xlb, xr_BC_type=self.cc_data.BCs["phi-MAC"].xrb, yl_BC_type=self.cc_data.BCs["phi-MAC"].ylb, yr_BC_type=self.cc_data.BCs["phi-MAC"].yrb, xmin=myg.xmin, xmax=myg.xmax, ymin=myg.ymin, ymax=myg.ymax, coeffs=coeff, coeffs_bc=self.cc_data.BCs["density"], verbose=0) # first compute div{beta_0 U} div_beta_U = mg.soln_grid.scratch_array() # MAC velocities are edge-centered. div{beta_0 U} is cell-centered. div_beta_U.v()[:,:] = \ beta0.v2d()*(u_MAC.ip(1) - u_MAC.v())/myg.dx + \ (beta0_edges.v2dp(1)*v_MAC.jp(1) - beta0_edges.v2d()*v_MAC.v())/myg.dy # solve the Poisson problem mg.init_RHS(div_beta_U.d) mg.solve(rtol=1.e-12) # update the normal velocities with the pressure gradient -- these # constitute our advective velocities. Note that what we actually # solved for here is phi/beta_0 phi_MAC = self.cc_data.get_var("phi-MAC") phi_MAC.d[:,:] = mg.get_solution(grid=myg).d coeff = self.aux_data.get_var("coeff") coeff.v()[:,:] = 1.0/rho.v() coeff.v()[:,:] = coeff.v()*beta0.v2d() self.aux_data.fill_BC("coeff") coeff_x = myg.scratch_array() b = (3, 1, 0, 0) # this seems more than we need coeff_x.v(buf=b)[:,:] = 0.5*(coeff.ip(-1, buf=b) + coeff.v(buf=b)) coeff_y = myg.scratch_array() b = (0, 0, 3, 1) coeff_y.v(buf=b)[:,:] = 0.5*(coeff.jp(-1, buf=b) + coeff.v(buf=b)) # we need the MAC velocities on all edges of the computational domain # here we do U = U - (beta_0/rho) grad (phi/beta_0) b = (0, 1, 0, 0) u_MAC.v(buf=b)[:,:] -= \ coeff_x.v(buf=b)*(phi_MAC.v(buf=b) - phi_MAC.ip(-1, buf=b))/myg.dx b = (0, 0, 0, 1) v_MAC.v(buf=b)[:,:] -= \ coeff_y.v(buf=b)*(phi_MAC.v(buf=b) - phi_MAC.jp(-1, buf=b))/myg.dy #--------------------------------------------------------------------- # predict rho to the edges and do its conservative update #--------------------------------------------------------------------- _rx, _ry = lm_interface_f.rho_states(myg.qx, myg.qy, myg.ng, myg.dx, myg.dy, self.dt, rho.d, u_MAC.d, v_MAC.d, ldelta_rx, ldelta_ry) rho_xint = patch.ArrayIndexer(d=_rx, grid=myg) rho_yint = patch.ArrayIndexer(d=_ry, grid=myg) rho_old = rho.copy() rho.v()[:,:] -= self.dt*( # (rho u)_x (rho_xint.ip(1)*u_MAC.ip(1) - rho_xint.v()*u_MAC.v())/myg.dx + # (rho v)_y (rho_yint.jp(1)*v_MAC.jp(1) - rho_yint.v()*v_MAC.v())/myg.dy ) self.cc_data.fill_BC("density") # update eint as a diagnostic eint = self.cc_data.get_var("eint") gamma = self.rp.get_param("eos.gamma") eint.v()[:,:] = self.base["p0"].v2d()/(gamma - 1.0)/rho.v() #--------------------------------------------------------------------- # recompute the interface states, using the advective velocity # from above #--------------------------------------------------------------------- if self.verbose > 0: print(" making u, v edge states") coeff = self.aux_data.get_var("coeff") coeff.v()[:,:] = 2.0/(rho.v() + rho_old.v()) coeff.v()[:,:] = coeff.v()*beta0.v2d() self.aux_data.fill_BC("coeff") _ux, _vx, _uy, _vy = \ lm_interface_f.states(myg.qx, myg.qy, myg.ng, myg.dx, myg.dy, self.dt, u.d, v.d, ldelta_ux, ldelta_vx, ldelta_uy, ldelta_vy, coeff.d*gradp_x.d, coeff.d*gradp_y.d, source.d, u_MAC.d, v_MAC.d) u_xint = patch.ArrayIndexer(d=_ux, grid=myg) v_xint = patch.ArrayIndexer(d=_vx, grid=myg) u_yint = patch.ArrayIndexer(d=_uy, grid=myg) v_yint = patch.ArrayIndexer(d=_vy, grid=myg) #--------------------------------------------------------------------- # update U to get the provisional velocity field #--------------------------------------------------------------------- if self.verbose > 0: print(" doing provisional update of u, v") # compute (U.grad)U # we want u_MAC U_x + v_MAC U_y advect_x = myg.scratch_array() advect_y = myg.scratch_array() advect_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 advect_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.dy proj_type = self.rp.get_param("lm-atmosphere.proj_type") if proj_type == 1: u.v()[:,:] -= (self.dt*advect_x.v() + self.dt*gradp_x.v()) v.v()[:,:] -= (self.dt*advect_y.v() + self.dt*gradp_y.v()) elif proj_type == 2: u.v()[:,:] -= self.dt*advect_x.v() v.v()[:,:] -= self.dt*advect_y.v() # add the gravitational source rho_half = 0.5*(rho + rho_old) rhoprime = self.make_prime(rho_half, rho0) source.d[:,:] = (rhoprime*g/rho_half).d self.aux_data.fill_BC("source_y") v.d[:,:] += self.dt*source.d self.cc_data.fill_BC("x-velocity") self.cc_data.fill_BC("y-velocity") if self.verbose > 0: print("min/max rho = {}, {}".format(self.cc_data.min("density"), self.cc_data.max("density"))) print("min/max u = {}, {}".format(self.cc_data.min("x-velocity"), self.cc_data.max("x-velocity"))) print("min/max v = {}, {}".format(self.cc_data.min("y-velocity"), self.cc_data.max("y-velocity"))) #--------------------------------------------------------------------- # project the final velocity #--------------------------------------------------------------------- # now we solve L phi = D (U* /dt) if self.verbose > 0: print(" final projection") # create the coefficient array: beta0**2/rho coeff = 1.0/rho coeff.v()[:,:] = coeff.v()*beta0.v2d()**2 # create the multigrid object mg = vcMG.VarCoeffCCMG2d(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, coeffs=coeff, coeffs_bc=self.cc_data.BCs["density"], verbose=0) # first compute div{beta_0 U} # u/v are cell-centered, divU is cell-centered div_beta_U.v()[:,:] = \ 0.5*beta0.v2d()*(u.ip(1) - u.ip(-1))/myg.dx + \ 0.5*(beta0.v2dp(1)*v.jp(1) - beta0.v2dp(-1)*v.jp(-1))/myg.dy mg.init_RHS(div_beta_U.d/self.dt) # use the old phi as our initial guess phiGuess = mg.soln_grid.scratch_array() phiGuess.v(buf=1)[:,:] = phi.v(buf=1) mg.init_solution(phiGuess.d) # solve mg.solve(rtol=1.e-12) # store the solution in our self.cc_data object -- include a single # ghostcell phi.d[:,:] = mg.get_solution(grid=myg).d # get 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 - (beta_0/rho) grad (phi/beta_0) coeff = 1.0/rho coeff.v()[:,:] = coeff.v()*beta0.v2d() u.v()[:,:] -= self.dt*coeff.v()*gradphi_x.v() v.v()[:,:] -= self.dt*coeff.v()*gradphi_y.v() # store gradp for the next step if proj_type == 1: gradp_x.v()[:,:] += gradphi_x.v() gradp_y.v()[:,:] += gradphi_y.v() elif proj_type == 2: gradp_x.v()[:,:] = gradphi_x.v() gradp_y.v()[:,:] = gradphi_y.v() self.cc_data.fill_BC("x-velocity") self.cc_data.fill_BC("y-velocity") self.cc_data.fill_BC("gradp_x") self.cc_data.fill_BC("gradp_y") # increment the time if not self.in_preevolve: self.cc_data.t += self.dt self.n += 1
def preevolve(self): """ preevolve is called before we being the timestepping loop. For the low Mach 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 (rho, u, v) is then reset to values before this evolve. """ self.in_preevolve = True myg = self.cc_data.grid rho = self.cc_data.get_var("density") u = self.cc_data.get_var("x-velocity") v = self.cc_data.get_var("y-velocity") self.cc_data.fill_BC("density") 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 satisties div U = 0 # the coefficent for the elliptic equation is beta_0^2/rho coeff = 1/rho beta0 = self.base["beta0"] coeff.v()[:,:] = coeff.v()*beta0.v2d()**2 # next create the multigrid object. We defined phi with # the right BCs previously mg = vcMG.VarCoeffCCMG2d(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, coeffs=coeff, coeffs_bc=self.cc_data.BCs["density"], verbose=0) # first compute div{beta_0 U} div_beta_U = mg.soln_grid.scratch_array() # u/v are cell-centered, divU is cell-centered div_beta_U.v()[:,:] = \ 0.5*beta0.v2d()*(u.ip(1) - u.ip(-1))/myg.dx + \ 0.5*(beta0.v2dp(1)*v.jp(1) - beta0.v2dp(-1)*v.jp(-1))/myg.dy # solve D (beta_0^2/rho) G (phi/beta_0) = D( beta_0 U ) # set the RHS to divU and solve mg.init_RHS(div_beta_U.d) mg.solve(rtol=1.e-10) # store the solution in our self.cc_data object -- include a single # ghostcell phi = self.cc_data.get_var("phi") phi.d[:,:] = mg.get_solution(grid=myg).d # get the cell-centered gradient of phi and update the # velocities # FIXME: this update only needs to be done on the interior # cells -- not ghost cells gradp_x, gradp_y = mg.get_solution_gradient(grid=myg) coeff = 1.0/rho coeff.v()[:,:] = coeff.v()*beta0.v2d() u.v()[:,:] -= coeff.v()*gradp_x.v() v.v()[:,:] -= coeff.v()*gradp_y.v() # fill the ghostcells self.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 bit orig_data = patch.cell_center_data_clone(self.cc_data) # get the timestep self.compute_timestep() # evolve self.evolve() # update gradp_x and gradp_y in our main data object new_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.d[:,:] = new_gp_x.d[:,:] orig_gp_y.d[:,:] = new_gp_y.d[:,:] self.cc_data = orig_data if self.verbose > 0: print("done with the pre-evolution") self.in_preevolve = False
def test_vc_constant(N): # test the multigrid solver nx = N ny = nx # create the coefficient variable -- note we don't want Dirichlet here, # because that will try to make alpha = 0 on the interface. alpha can # have different BCs than phi 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("c", bc_c) d.create() c = d.get_var("c") c[:, :] = alpha(g.x2d, g.y2d) plt.clf() plt.figure(num=1, figsize=(5.0, 5.0), dpi=100, facecolor='w') plt.imshow(np.transpose(c[g.ilo:g.ihi + 1, g.jlo:g.jhi + 1]), interpolation="nearest", origin="lower", extent=[g.xmin, g.xmax, g.ymin, g.ymax]) plt.xlabel("x") plt.ylabel("y") plt.title("nx = {}".format(nx)) plt.colorbar() plt.savefig("mg_alpha.png") # 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="dirichlet", yl_BC_type="dirichlet", xr_BC_type="dirichlet", yr_BC_type="dirichlet", coeffs=c, coeffs_bc=bc_c, verbose=1) # 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 print( " L2 error from true solution = %g\n rel. err from previous cycle = %g\n num. cycles = %d" % (a.soln_grid.norm(e), a.relative_error, a.num_cycles)) # plot it plt.clf() plt.figure(num=1, figsize=(10.0, 5.0), dpi=100, facecolor='w') plt.subplot(121) plt.imshow(np.transpose(v[a.ilo:a.ihi + 1, a.jlo:a.jhi + 1]), 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[a.ilo:a.ihi + 1, a.jlo:a.jhi + 1]), 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_test.png") # store the output for later comparison my_data = a.get_solution_object() my_data.write("mg_test")
def test_vc_poisson_periodic(N, store_bench=False, comp_bench=False, make_plot=False, verbose=1, rtol=1.e-12): """ 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 = io.read(compare_file) result = compare.compare(my_data, bench, rtol) if result == 0: msg.success( "results match benchmark to within relative tolerance of {}\n". format(rtol)) else: msg.warning("ERROR: {}\n".format(compare.errors[result])) return result # normal return -- error wrt true solution return enorm
plt.title("nx = {}".format(nx)) plt.colorbar() plt.savefig("mg_alpha.png") # 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="dirichlet", yl_BC_type="dirichlet", xr_BC_type="dirichlet", yr_BC_type="dirichlet", coeffs=c, coeffs_bc=bc_c, verbose=1) # 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)