@@ -463,12 +463,12 @@ def test_submesh_solve_cell_cell_equation_bc(nref, degree, simplex):
463463 assert sqrt (assemble (inner (sol [1 ] - x * y , sol [1 ] - x * y ) * dx_inner )) < 1.e-12
464464
465465
466- def _test_submesh_solve_quad_triangle_convergence (nref , degree ):
466+ def _test_submesh_solve_quad_triangle_poisson (nref , degree ):
467467 dim = 2
468468 label_ext = 1
469469 label_interf = 2
470470 distribution_parameters_noop = {
471- "partition" : False ,
471+ "partition" : True ,
472472 "overlap_type" : (DistributedMeshOverlapType .NONE , 0 ),
473473 }
474474 mesh = Mesh (os .path .join (cwd , ".." , "meshes" , "mixed_cell_unit_square.msh" ), distribution_parameters = distribution_parameters_noop )
@@ -523,20 +523,20 @@ def _test_submesh_solve_quad_triangle_convergence(nref, degree):
523523 bc_q = DirichletBC (V .sub (1 ), g_q , label_ext )
524524 solve (a == L , sol , bcs = [bc_q ])
525525 sol_t , sol_q = split (sol )
526- L2error_t = assemble (inner (sol_t - g_t , sol_t - g_t ) * dx_t )
527- L2error_q = assemble (inner (sol_q - g_q , sol_q - g_q ) * dx_q )
528- H1error_t = assemble (( inner ( sol_t - g_t , sol_t - g_t ) + inner (grad (sol_t - g_t ), grad (sol_t - g_t ) ))* dx_t )
529- H1error_q = assemble (( inner ( sol_q - g_q , sol_q - g_q ) + inner (grad (sol_q - g_q ), grad (sol_q - g_q ) ))* dx_q )
530- return sqrt (L2error_t + L2error_q ), sqrt (H1error_t + H1error_q )
526+ L2Error_t = assemble (inner (sol_t - g_t , sol_t - g_t ) * dx_t )
527+ L2Error_q = assemble (inner (sol_q - g_q , sol_q - g_q ) * dx_q )
528+ H1Error_t = L2Error_t + assemble ( inner (grad (sol_t - g_t ), grad (sol_t - g_t ))* dx_t )
529+ H1Error_q = L2Error_q + assemble ( inner (grad (sol_q - g_q ), grad (sol_q - g_q ))* dx_q )
530+ return sqrt (L2Error_t + L2Error_q ), sqrt (H1Error_t + H1Error_q )
531531
532532
533533@pytest .mark .parallel (nprocs = 8 )
534- def test_submesh_solve_quad_triangle_convergence ():
534+ def test_submesh_solve_quad_triangle_poisson_convergence ():
535535 for degree in range (1 , 5 ):
536536 L2Errors = []
537537 H1Errors = []
538538 for nref in range (4 ):
539- L2Error , H1Error = _test_submesh_solve_quad_triangle_convergence (nref , degree )
539+ L2Error , H1Error = _test_submesh_solve_quad_triangle_poisson (nref , degree )
540540 L2Errors .append (L2Error )
541541 H1Errors .append (H1Error )
542542 L2Errors = [np .log2 (c ) - np .log2 (f ) for c , f in zip (L2Errors [:- 1 ], L2Errors [1 :])]
@@ -545,25 +545,26 @@ def test_submesh_solve_quad_triangle_convergence():
545545 assert (np .array (H1Errors ) > (degree ) * 0.995 ).all ()
546546
547547
548- @pytest .mark .parallel (nprocs = 8 )
549- @pytest .mark .parametrize ('simplex' , [True , False ])
550- @pytest .mark .parametrize ('direction' , [0 , 1 , 2 ])
551- def test_submesh_solve_hex_quad_convergence (simplex , direction ):
548+ def _test_submesh_solve_3d_2d_poisson (simplex , direction , nref , degree ):
552549 dim = 3
550+ distribution_parameters_noop = {
551+ "partition" : True ,
552+ "overlap_type" : (DistributedMeshOverlapType .NONE , 0 ),
553+ }
553554 distribution_parameters = {
554555 "overlap_type" : (DistributedMeshOverlapType .RIDGE , 1 ),
555556 }
556557 if simplex :
557- nref = 3
558- mesh = BoxMesh (2 ** nref , 2 ** nref , 2 ** nref , 1. , 1. , 1. , hexahedral = False , distribution_parameters = distribution_parameters )
558+ nref_simplex = 3
559+ mesh = BoxMesh (2 ** nref_simplex , 2 ** nref_simplex , 2 ** nref_simplex , 1. , 1. , 1. , hexahedral = False , distribution_parameters = distribution_parameters_noop )
559560 xyz = SpatialCoordinate (mesh )
560561 DG0 = FunctionSpace (mesh , "DG" , 0 )
561562 c1 = Function (DG0 ).interpolate (conditional (xyz [direction ] < 0.318310 , 1 , 0 ))
562563 c2 = Function (DG0 ).interpolate (conditional (xyz [direction ] > 0.318310 , 1 , 0 ))
563564 mesh = RelabeledMesh (mesh , [c1 , c2 ], [1 , 2 ])
564565 family = "P"
565566 else :
566- mesh = Mesh (join (cwd , ".." , "meshes" , "cube_hex.msh" ), distribution_parameters = distribution_parameters )
567+ mesh = Mesh (join (cwd , ".." , "meshes" , "cube_hex.msh" ), distribution_parameters = distribution_parameters_noop )
567568 xyz = SpatialCoordinate (mesh )
568569 DG0 = FunctionSpace (mesh , "DQ" , 0 )
569570 c1 = Function (DG0 ).interpolate (conditional (xyz [direction ] < 0.318310 , 1 , 0 ))
@@ -577,6 +578,13 @@ def test_submesh_solve_hex_quad_convergence(simplex, direction):
577578 f6 = Function (HDivTrace0 ).interpolate (conditional (xyz [2 ] < .999 , 1 , 0 ))
578579 mesh = RelabeledMesh (mesh , [c1 , c2 , f1 , f2 , f3 , f4 , f5 , f6 ], [1 , 2 , 1 , 2 , 3 , 4 , 5 , 6 ])
579580 family = "Q"
581+ plex = mesh .topology_dm
582+ for _ in range (nref ):
583+ plex = plex .refine ()
584+ plex .removeLabel ("pyop2_core" )
585+ plex .removeLabel ("pyop2_owned" )
586+ plex .removeLabel ("pyop2_ghost" )
587+ mesh = Mesh (plex , distribution_parameters = distribution_parameters )
580588 mesh1 = Submesh (mesh , dim , 1 )
581589 x1 , y1 , z1 = SpatialCoordinate (mesh1 )
582590 mesh2 = Submesh (mesh , dim , 2 )
@@ -586,17 +594,23 @@ def test_submesh_solve_hex_quad_convergence(simplex, direction):
586594 dx1 = Measure ("dx" , mesh1 )
587595 dx2 = Measure ("dx" , mesh2 )
588596 dx12 = Measure ("dx" , mesh12 )
589- dx12_ds1 = Measure ("dx" , mesh12 , intersect_measures = (Measure ("ds" , mesh1 ),))
590- ds1_dx12 = Measure ("ds" , mesh1 , intersect_measures = (Measure ("dx" , mesh12 ),))
597+ ds1_ds2 = Measure ("ds" , mesh1 , intersect_measures = (Measure ("ds" , mesh2 ),))
591598 ds2_dx12 = Measure ("ds" , mesh2 , intersect_measures = (Measure ("dx" , mesh12 ),))
599+ dx12_ds1_ds2 = Measure (
600+ "dx" , mesh12 ,
601+ intersect_measures = (
602+ Measure ("ds" , mesh1 ),
603+ Measure ("ds" , mesh2 ),
604+ )
605+ )
592606 # Check sanity.
593607 vol1 = assemble (Constant (1 ) * dx1 )
594608 vol2 = assemble (Constant (1 ) * dx2 )
595- assert abs (vol1 + vol2 - 1. ) < 1.e-14
609+ assert abs (vol1 + vol2 - 1. ) < 1.e-13
596610 # Solve Poisson problem.
597- V1 = FunctionSpace (mesh1 , family , 3 )
598- V12 = FunctionSpace (mesh12 , family , 5 )
599- V2 = FunctionSpace (mesh2 , family , 4 )
611+ V1 = FunctionSpace (mesh1 , family , degree )
612+ V12 = FunctionSpace (mesh12 , family , degree )
613+ V2 = FunctionSpace (mesh2 , family , degree )
600614 V = V1 * V12 * V2
601615 u = TrialFunction (V )
602616 v = TestFunction (V )
@@ -607,22 +621,70 @@ def test_submesh_solve_hex_quad_convergence(simplex, direction):
607621 f1 = 12 * pi ** 2 * g1
608622 f2 = 12 * pi ** 2 * g2
609623 n1 = FacetNormal (mesh1 )
624+ n2 = FacetNormal (mesh2 )
625+ h = 0.1 / 2 ** nref # roughly
610626 a = (
611- inner (grad (u1 ), grad (v1 )) * dx1 - inner (u12 , v1 ) * ds1_dx12 (label_interf ) +
612- inner (u12 , v12 ) * dx12 +
613- inner (grad (u2 ), grad (v2 )) * dx2 + inner (u12 , v2 ) * ds2_dx12 (label_interf )
627+ inner (grad (u1 ), grad (v1 )) * dx1 +
628+ inner (grad (u2 ), grad (v2 )) * dx2
629+ - inner (
630+ u12 ,
631+ (v1 - v2 )
632+ ) * dx12_ds1_ds2
633+ - inner (
634+ (u1 * n1 + u2 * n2 ),
635+ (grad (v1 ) + grad (v2 )) / 2
636+ ) * dx12_ds1_ds2
637+ + 100 / h * inner (u1 - u2 , v1 - v2 ) * ds1_ds2 (label_interf ) # Can also use dx12_ds1_ds2.
638+ + inner (
639+ (dot (grad (u1 ), n1 ) - dot (grad (u2 ), n1 )) / 2 - u12 ,
640+ v12
641+ ) * dx12_ds1_ds2
614642 )
615643 L = (
616644 inner (f1 , v1 ) * dx1 +
617- inner (dot (grad (g1 ), n1 ), v12 ) * dx12_ds1 +
618645 inner (f2 , v2 ) * dx2
619646 )
620647 sol = Function (V )
621- bc1 = DirichletBC (V .sub (0 ), g1 , (2 * direction + 1 ,))
622- bc2 = DirichletBC (V .sub (2 ), g2 , (2 * direction + 2 ,))
623- solve (a == L , sol , bcs = [bc1 , bc2 ])
648+ bc1 = DirichletBC (V .sub (0 ), g1 , [i for i in range (1 , 7 ) if i != 2 * direction + 2 ])
649+ bc2 = DirichletBC (V .sub (2 ), g2 , [i for i in range (1 , 7 ) if i != 2 * direction + 1 ])
650+ solver_parameters = {
651+ "mat_type" : "matfree" ,
652+ "ksp_type" : "gmres" ,
653+ "ksp_rtol" : 1.e-14 ,
654+ "pc_type" : "jacobi" ,
655+ }
656+ solve (a == L , sol , bcs = [bc1 , bc2 ], solver_parameters = solver_parameters )
624657 sol1 , sol12 , sol2 = split (sol )
625- error1 = assemble (inner (sol1 - g1 , sol1 - g1 ) * dx1 )
626- error2 = assemble (inner (sol2 - g2 , sol2 - g2 ) * dx2 )
627- assert sqrt (error1 ) < 4.e-4
628- assert sqrt (error2 ) < 4.e-5
658+ L2Error1 = assemble (inner (sol1 - g1 , sol1 - g1 ) * dx1 )
659+ L2Error2 = assemble (inner (sol2 - g2 , sol2 - g2 ) * dx2 )
660+ H1Error1 = L2Error1 + assemble (inner (grad (sol1 - g1 ), grad (sol1 - g1 ))* dx1 )
661+ H1Error2 = L2Error2 + assemble (inner (grad (sol2 - g2 ), grad (sol2 - g2 ))* dx2 )
662+ return sqrt (L2Error1 + L2Error2 ), sqrt (H1Error2 + H1Error2 )
663+
664+
665+ @pytest .mark .parallel (nprocs = 6 )
666+ @pytest .mark .parametrize ('simplex' , [True , False ])
667+ @pytest .mark .parametrize ('direction' , [0 , 1 , 2 ])
668+ def test_submesh_solve_3d_2d_poisson_sanity (simplex , direction ):
669+ nref = 0
670+ degree = 4
671+ L2Error , H1Error = _test_submesh_solve_3d_2d_poisson (simplex , direction , nref , degree )
672+ assert L2Error < 2.e-4
673+ assert H1Error < 3.e-2
674+
675+
676+ @pytest .mark .parallel (nprocs = 8 )
677+ @pytest .mark .parametrize ('simplex' , [False ])
678+ @pytest .mark .parametrize ('direction' , [0 ])
679+ @pytest .mark .parametrize ('degree' , [3 ])
680+ def test_submesh_solve_3d_2d_poisson_convergence (simplex , direction , degree ):
681+ L2Errors = []
682+ H1Errors = []
683+ for nref in range (2 ):
684+ L2Error , H1Error = _test_submesh_solve_3d_2d_poisson (simplex , direction , nref , degree )
685+ L2Errors .append (L2Error )
686+ H1Errors .append (H1Error )
687+ L2Errors = [np .log2 (c ) - np .log2 (f ) for c , f in zip (L2Errors [:- 1 ], L2Errors [1 :])]
688+ H1Errors = [np .log2 (c ) - np .log2 (f ) for c , f in zip (H1Errors [:- 1 ], H1Errors [1 :])]
689+ assert (np .array (L2Errors ) > (degree + 1 ) * 0.98 ).all ()
690+ assert (np .array (H1Errors ) > (degree ) * 0.98 ).all ()
0 commit comments