@@ -296,7 +296,7 @@ def ref_interface(x):
296296def test_exterior_boundary_subdomain (dtype , ghost_mode , cell_type ):
297297 comm = MPI .COMM_WORLD
298298 mesh = dolfinx .mesh .create_unit_cube (
299- comm , 10 , 5 , 7 , cell_type = cell_type , ghost_mode = ghost_mode , dtype = dtype
299+ comm , 13 , 7 , 11 , cell_type = cell_type , ghost_mode = ghost_mode , dtype = dtype
300300 )
301301
302302 def center (x ):
@@ -305,35 +305,139 @@ def center(x):
305305 tdim = mesh .topology .dim
306306 cell_map = mesh .topology .index_map (tdim )
307307 all_cells = np .arange (cell_map .size_local + cell_map .num_ghosts , dtype = np .int32 )
308- values = np .full_like (all_cells , 1 , dtype = np .int32 )
309- values [dolfinx .mesh .locate_entities (mesh , tdim , center )] = 2
308+ value_map = dolfinx .la .vector (cell_map , 1 , dtype = np .int32 )
309+ value_map .array [:] = 0
310+ value_map .array [dolfinx .mesh .locate_entities (mesh , tdim , center )] = 1
311+ value_map .scatter_reverse (dolfinx .la .InsertMode .add )
312+ value_map .scatter_forward ()
313+
314+ values = np .ones_like (all_cells , dtype = np .int32 )
315+ values [value_map .array > 0 ] = 2
316+
310317 cell_tags = dolfinx .mesh .meshtags (mesh , tdim , all_cells , values )
311318
312- ext_facets_1 = scifem .compute_subdomain_exterior_facets (mesh , cell_tags , (1 ,))
319+ def boundary_check (mesh , facets , cell_tags , values ):
320+ is_in_subdomain = np .isin (cell_tags .values , np .asarray (values ))
321+ mesh .topology .create_connectivity (mesh .topology .dim - 1 , mesh .topology .dim )
322+ num_facets_local = mesh .topology .index_map (mesh .topology .dim - 1 ).size_local
323+ f_to_c = mesh .topology .connectivity (mesh .topology .dim - 1 , mesh .topology .dim )
324+ cell_map = mesh .topology .index_map (mesh .topology .dim )
325+ owned_facets_in_subdomain = []
326+ owned_facets_on_outside = []
327+ ghosted_facets_in_subdomain = []
328+ ghosted_facets_on_outside = []
329+
330+ facet_map = mesh .topology .index_map (mesh .topology .dim - 1 )
331+
332+ for facet in facets :
333+ cells = f_to_c .links (facet )
334+ if len (cells ) != 1 :
335+ assert np .sum (is_in_subdomain [cells ]) == 1
336+ elif len (cells ) == 1 :
337+ if facet < num_facets_local :
338+ # If connected to only one cell, we send it to the other process
339+ # that has it to verify that it is a boundary facet
340+ if is_in_subdomain [cells [0 ]]:
341+ owned_facets_in_subdomain .append (facet )
342+ else :
343+ owned_facets_on_outside .append (facet )
344+ else :
345+ if is_in_subdomain [cells [0 ]]:
346+ ghosted_facets_in_subdomain .append (facet )
347+ else :
348+ ghosted_facets_on_outside .append (facet )
349+ # Receive facets from other process that is on subdomain on that process
350+ facet_vector = dolfinx .la .vector (
351+ mesh .topology .index_map (mesh .topology .dim - 1 ), 1 , dtype = np .int32
352+ )
353+ facet_vector .array [:] = 0
354+ facet_vector .array [ghosted_facets_in_subdomain ] = 1
355+ facet_vector .scatter_reverse (dolfinx .la .InsertMode .add )
313356
314- # Exterior facets for domain 1 are the original exterior facets + those at the interface
315- mesh .topology .create_connectivity (mesh .topology .dim - 1 , mesh .topology .dim )
316- owned_exterior_facets = dolfinx .mesh .exterior_facet_indices (mesh .topology )
317- exterior_facet_indices = scifem .reverse_mark_entities (
318- mesh .topology .index_map (tdim - 1 ), owned_exterior_facets
319- )
357+ exterior_facets = dolfinx .mesh .exterior_facet_indices (mesh .topology )
358+ all_local_exterior_facets = scifem .reverse_mark_entities (facet_map , exterior_facets )
320359
321- # Compute reference exterior facets by interface computations
322- twosided_interface = scifem .find_interface (cell_tags , (1 ,), (2 ,))
323- interface = scifem .reverse_mark_entities (mesh .topology .index_map (tdim - 1 ), twosided_interface )
360+ facets_inside_subdomain = np .flatnonzero (facet_vector .array [:num_facets_local ]).astype (
361+ np .int32
362+ )
363+ mesh .topology .create_connectivity (mesh .topology .dim , mesh .topology .dim - 1 )
364+ for facet in facets_inside_subdomain :
365+ cells = f_to_c .links (facet )
366+ if facet in all_local_exterior_facets :
367+ assert is_in_subdomain [cells [0 ]]
368+ continue
369+ if len (cells ) == 1 :
370+ assert cells [0 ] < cell_map .size_local
371+ assert not is_in_subdomain [cells [0 ]]
372+ else :
373+ assert len (cells ) == 2
374+ assert np .sum (is_in_subdomain [cells ]) == 1
375+
376+ facet_vector .array [:] = 0
377+ facet_vector .array [ghosted_facets_on_outside ] = 1
378+ facet_vector .scatter_reverse (dolfinx .la .InsertMode .add )
379+ facets_outside_subdomain = np .flatnonzero (facet_vector .array [:num_facets_local ]).astype (
380+ np .int32
381+ )
382+ for facet in facets_outside_subdomain :
383+ cells = f_to_c .links (facet )
384+ if facet in all_local_exterior_facets :
385+ assert is_in_subdomain [cells [0 ]]
386+ continue
387+ if len (cells ) == 1 :
388+ assert cells [0 ] < cell_map .size_local
389+ assert is_in_subdomain [cells [0 ]]
390+ else :
391+ assert len (cells ) == 2
392+ assert np .sum (is_in_subdomain [cells ]) == 1
393+
394+ facet_vector .array [:] = 0
395+ facet_vector .array [owned_facets_in_subdomain ] = 1
396+ facet_vector .scatter_forward ()
397+ facets_inside_subdomain = np .flatnonzero (facet_vector .array [num_facets_local :]).astype (
398+ np .int32
399+ )
400+ for facet in facets_inside_subdomain :
401+ cells = f_to_c .links (num_facets_local + facet )
402+ if num_facets_local + facet in all_local_exterior_facets :
403+ assert is_in_subdomain [cells [0 ]]
404+ continue
405+
406+ if len (cells ) == 1 :
407+ assert cells [0 ] <= cell_map .size_local
408+ assert not is_in_subdomain [cells [0 ]]
409+ else :
410+ assert len (cells ) == 2
411+ assert np .sum (is_in_subdomain [cells ]) == 1
412+
413+ facet_vector .array [:] = 0
414+ facet_vector .array [owned_facets_on_outside ] = 1
415+ facet_vector .scatter_forward ()
416+ facets_outside_subdomain = np .flatnonzero (facet_vector .array [num_facets_local :]).astype (
417+ np .int32
418+ )
419+ for facet in facets_outside_subdomain :
420+ cells = f_to_c .links (num_facets_local + facet )
421+ if num_facets_local + facet in all_local_exterior_facets :
422+ assert is_in_subdomain [cells [0 ]]
423+ continue
424+ if len (cells ) == 1 :
425+ assert cells [0 ] <= cell_map .size_local
426+ assert is_in_subdomain [cells [0 ]]
427+ else :
428+ assert len (cells ) == 2
429+ assert np .sum (is_in_subdomain [cells ]) == 1
324430
325- ref_ext_facets_1 = np .unique (np .concatenate ([exterior_facet_indices , interface ])).astype (
326- np .int32
327- )
328- np .testing .assert_allclose (ext_facets_1 , ref_ext_facets_1 )
431+ ext_facets_1 = scifem .compute_subdomain_exterior_facets (mesh , cell_tags , (1 ,))
432+ boundary_check (mesh , ext_facets_1 , cell_tags , (1 ,))
329433
330434 # Exterior facets are only those at the interface
331435 ext_facets_2 = scifem .compute_subdomain_exterior_facets (mesh , cell_tags , (2 ,))
332- np . testing . assert_allclose ( ext_facets_2 , interface )
436+ boundary_check ( mesh , ext_facets_2 , cell_tags , ( 2 ,) )
333437
334438 # Exterior facets are only exterior
335439 ext_facets = scifem .compute_subdomain_exterior_facets (mesh , cell_tags , (1 , 2 ))
336- np . testing . assert_allclose ( ext_facets , exterior_facet_indices )
440+ boundary_check ( mesh , ext_facets , cell_tags , ( 1 , 2 ) )
337441
338442
339443@pytest .mark .parametrize (
0 commit comments