@@ -478,12 +478,18 @@ void BoundaryInfo::sync (const std::set<boundary_id_type> & requested_boundary_i
478478 * into dangling pointers, and it won't be easy to tell which. So
479479 * we'll keep around a distributed copy for that case, and query it
480480 * to fix up interior_parent() links as necessary.
481+ *
482+ * We'll also need to make sure to unserialize the mesh *before* we
483+ * prepare the boundary mesh for use, or the prepare_for_use() call
484+ * on a refined boundary mesh will happily notice that it can find
485+ * and restore some refined elements' interior_parent pointers, not
486+ * knowing that those interior parents are about to go remote.
481487 */
482488 std ::unique_ptr < MeshBase > mesh_copy ;
483489 if (boundary_mesh .is_serial () && !_mesh -> is_serial ())
484490 mesh_copy = _mesh -> clone ();
485491
486- MeshSerializer serializer
492+ auto serializer = std :: make_unique < MeshSerializer >
487493 (const_cast < MeshBase & > (* _mesh ), boundary_mesh .is_serial ());
488494
489495 /**
@@ -566,6 +572,11 @@ void BoundaryInfo::sync (const std::set<boundary_id_type> & requested_boundary_i
566572 // interior partitioning.
567573 boundary_mesh .partitioner ().reset (nullptr );
568574
575+ // Deserialize the interior mesh before the boundary mesh
576+ // prepare_for_use() can come to erroneous conclusions about which
577+ // of its elements are semilocal
578+ serializer .reset ();
579+
569580 // Make boundary_mesh nodes and elements contiguous
570581 boundary_mesh .prepare_for_use ();
571582
@@ -650,10 +661,22 @@ void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_bou
650661 LOG_SCOPE ("add_elements()" , "BoundaryInfo" );
651662
652663 // We're not prepared to mix serial and distributed meshes in this
653- // method, so make sure they match from the start.
664+ // method, so make sure their statuses match from the start.
665+ //
666+ // Specifically test *is_serial* here - we can handle a mix of
667+ // ReplicatedMesh and serialized DistributedMesh.
654668 libmesh_assert_equal_to (_mesh -> is_serial (),
655669 boundary_mesh .is_serial ());
656670
671+ // If the boundary mesh already has interior pointers pointing at
672+ // elements in a third mesh then we're in trouble
673+ libmesh_assert (& boundary_mesh .interior_mesh () == & boundary_mesh ||
674+ & boundary_mesh .interior_mesh () == _mesh );
675+
676+ // And now we're going to add interior pointers to elements from
677+ // this mesh
678+ boundary_mesh .set_interior_mesh (* _mesh );
679+
657680 std ::map < std ::pair < dof_id_type , unsigned char > , dof_id_type > side_id_map ;
658681 this -> _find_id_maps (requested_boundary_ids ,
659682 0 ,
@@ -682,25 +705,18 @@ void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_bou
682705 !subdomains_relative_to .count (elem -> subdomain_id ()))
683706 continue ;
684707
685- // Get the top-level parent for this element
686- const Elem * top_parent = elem -> top_parent ();
687-
688- // Find all the boundary side ids for this Elem.
689- auto bounds = _boundary_side_id .equal_range (top_parent );
690-
691708 for (auto s : elem -> side_index_range ())
692709 {
693710 bool add_this_side = false;
694- boundary_id_type this_bcid = invalid_id ;
695711
696- for ( const auto & pr : as_range ( bounds ))
697- {
698- this_bcid = pr . second . second ;
712+ // Find all the boundary side ids for this Elem side.
713+ std :: vector < boundary_id_type > bcids ;
714+ this -> boundary_ids ( elem , s , bcids ) ;
699715
700- // if this side is flagged with a boundary condition
701- // and the user wants this id
702- if (( pr . second . first == s ) &&
703- (requested_boundary_ids .count (this_bcid ) ))
716+ for ( const boundary_id_type bcid : bcids )
717+ {
718+ // if the user wants this id, we want this side
719+ if (requested_boundary_ids .count (bcid ))
704720 {
705721 add_this_side = true;
706722 break ;
@@ -713,8 +729,7 @@ void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_bou
713729 // boundary was copied to the BoundaryMesh, and handles the
714730 // case where elements on the geometric boundary are not in
715731 // any sidesets.
716- if (bounds .first == bounds .second &&
717- requested_boundary_ids .count (invalid_id ) &&
732+ if (requested_boundary_ids .count (invalid_id ) &&
718733 elem -> neighbor_ptr (s ) == nullptr )
719734 add_this_side = true;
720735
@@ -765,6 +780,9 @@ void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_bou
765780 new_elem -> set_extra_integer (parent_side_index_tag , s );
766781
767782#ifdef LIBMESH_ENABLE_AMR
783+ new_elem -> set_refinement_flag (elem -> refinement_flag ());
784+ new_elem -> set_p_refinement_flag (elem -> p_refinement_flag ());
785+
768786 // Set parent links
769787 if (elem -> parent ())
770788 {
@@ -778,8 +796,6 @@ void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_bou
778796
779797 new_elem -> set_parent (side_parent );
780798
781- side_parent -> set_refinement_flag (Elem ::INACTIVE );
782-
783799 // Figuring out which child we are of our parent
784800 // is a trick. Due to libMesh child numbering
785801 // conventions, if we are an element on a vertex,
@@ -802,6 +818,22 @@ void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_bou
802818 side_parent -> add_child (new_elem , 3 );
803819 }
804820 }
821+
822+ // Set remote_elem child links if necessary. Rather than
823+ // worrying about which interior child corresponds to which side
824+ // child we'll just set all null links to be remote and we'll
825+ // rely on our detection of actual semilocal children to
826+ // overwrite the links that shouldn't be remote.
827+ if (elem -> has_children ())
828+ for (auto c : make_range (elem -> n_children ()))
829+ if (elem -> child_ptr (c ) == remote_elem &&
830+ elem -> is_child_on_side (c , s ))
831+ {
832+ for (auto sc : make_range (new_elem -> n_children ()))
833+ if (!new_elem - > raw_child_ptr (sc ))
834+ new_elem -> add_child
835+ (const_cast < RemoteElem * > (remote_elem ), sc );
836+ }
805837#endif
806838
807839 new_elem -> set_interior_parent (elem );
@@ -3136,26 +3168,18 @@ void BoundaryInfo::_find_id_maps(const std::set<boundary_id_type> & requested_bo
31363168 !subdomains_relative_to .count (elem -> subdomain_id ()))
31373169 continue ;
31383170
3139- // Get the top-level parent for this element. This is used for
3140- // searching for boundary sides on this element.
3141- const Elem * top_parent = elem -> top_parent ();
3142-
3143- // Find all the boundary side ids for this Elem.
3144- auto bounds = _boundary_side_id .equal_range (top_parent );
3145-
31463171 for (auto s : elem -> side_index_range ())
31473172 {
31483173 bool add_this_side = false;
3149- boundary_id_type this_bcid = invalid_id ;
31503174
3151- for ( const auto & pr : as_range ( bounds ))
3152- {
3153- this_bcid = pr . second . second ;
3175+ // Find all the boundary side ids for this Elem side.
3176+ std :: vector < boundary_id_type > bcids ;
3177+ this -> boundary_ids ( elem , s , bcids ) ;
31543178
3155- // if this side is flagged with a boundary condition
3156- // and the user wants this id
3157- if (( pr . second . first == s ) &&
3158- (requested_boundary_ids .count (this_bcid ) ))
3179+ for ( const boundary_id_type bcid : bcids )
3180+ {
3181+ // if the user wants this id, we want this side
3182+ if (requested_boundary_ids .count (bcid ))
31593183 {
31603184 add_this_side = true;
31613185 break ;
@@ -3168,8 +3192,7 @@ void BoundaryInfo::_find_id_maps(const std::set<boundary_id_type> & requested_bo
31683192 // boundary was copied to the BoundaryMesh, and handles the
31693193 // case where elements on the geometric boundary are not in
31703194 // any sidesets.
3171- if (bounds .first == bounds .second &&
3172- requested_boundary_ids .count (invalid_id ) &&
3195+ if (requested_boundary_ids .count (invalid_id ) &&
31733196 elem -> neighbor_ptr (s ) == nullptr )
31743197 add_this_side = true;
31753198
0 commit comments