Source code for pyro.multigrid.examples.mg_test_vc_dirichlet
#!/usr/bin/env python3"""Test the variable-coefficient MG solver with Dirichlet boundary conditions.Here we solve:: div . ( alpha grad phi ) = fwith:: alpha = 2.0 + cos(2.0*pi*x)*cos(2.0*pi*y) f = -16.0*pi**2*(cos(2*pi*x)*cos(2*pi*y) + 1)*sin(2*pi*x)*sin(2*pi*y)This has the exact solution:: phi = sin(2.0*pi*x)*sin(2.0*pi*y)on [0,1] x [0,1]We use Dirichlet BCs on phi. For alpha, we do not have to impose thesame BCs, since that may represent a different physical quantity.Here we take alpha to have Neumann BCs. (Dirichlet BCs for alpha willforce it to 0 on the boundary, which is not correct here)"""importmatplotlib.pyplotaspltimportnumpyasnpimportpyro.mesh.boundaryasbndimportpyro.multigrid.variable_coeff_MGasMGimportpyro.util.io_pyroasiofrompyro.meshimportpatchfrompyro.utilimportcompare,msg# the analytic solution
[docs]deftest_vc_poisson_dirichlet(N,store_bench=False,comp_bench=False,bench_dir="tests/",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 solvernx=Nny=nx# create the coefficient variableg=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)# create the multigrid objecta=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 0a.init_zeros()# initialize the RHS using the function frhs=f(a.x2d,a.y2d)a.init_RHS(rhs)# solve to a relative tolerance of 1.e-11a.solve(rtol=1.e-11)# alternately, we can just use smoothing by uncommenting the following# a.smooth(a.nlevels-1,50000)# get the solutionv=a.get_solution()# compute the error from the analytic solutionb=true(a.x2d,a.y2d)e=v-benorm=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 solutionifmake_plot:plt.clf()plt.figure(figsize=(10.0,4.0),dpi=100,facecolor='w')plt.subplot(121)img1=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(f"nx = {nx}")plt.colorbar(img1)plt.subplot(122)img2=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(img2)plt.tight_layout()plt.savefig("mg_vc_dirichlet_test.png")# store the output for later comparisonbench="mg_vc_poisson_dirichlet"my_data=a.get_solution_object()ifstore_bench:my_data.write(f"{bench_dir}/{bench}")# do we do a comparison?ifcomp_bench:compare_file=f"{bench_dir}/{bench}"msg.warning("comparing to: %s "%(compare_file))bench=io.read(compare_file)result=compare.compare(my_data,bench,rtol)ifresult==0:msg.success(f"results match benchmark to within relative tolerance of {rtol}\n")else:msg.warning("ERROR: "+compare.errors[result]+"\n")returnresult# normal return -- error wrt true solutionreturnenorm
[docs]defmain():N=[16,32,64,128,256,512]err=[]plot=Falsestore=Falsedo_compare=FalsefornxinN:ifnx==max(N):plot=True# store = Truedo_compare=Trueenorm=test_vc_poisson_dirichlet(nx,make_plot=plot,store_bench=store,comp_bench=do_compare)err.append(enorm)# plot the convergenceN=np.array(N,dtype=np.float64)err=np.array(err)plt.clf()plt.loglog(N,err,"x",color="r")plt.loglog(N,err[0]*(N[0]/N)**2,"--",color="k")plt.xlabel("N")plt.ylabel("error")fig=plt.gcf()fig.set_size_inches(7.0,6.0)plt.tight_layout()plt.savefig("mg_vc_dirichlet_converge.png")