void Partitioner::set_parent_processor_ids(MeshBase & mesh) { // Ignore the parameter when !LIBMESH_ENABLE_AMR libmesh_ignore(mesh); LOG_SCOPE("set_parent_processor_ids()", "Partitioner"); #ifdef LIBMESH_ENABLE_AMR // If the mesh is serial we have access to all the elements, // in particular all the active ones. We can therefore set // the parent processor ids indirecly through their children, and // set the subactive processor ids while examining their active // ancestors. // By convention a parent is assigned to the minimum processor // of all its children, and a subactive is assigned to the processor // of its active ancestor. if (mesh.is_serial()) { // Loop over all the active elements in the mesh MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) { Elem * child = *it; // First set descendents std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (unsigned int i = 0; i != subactive_family.size(); ++i) const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id(); // Then set ancestors Elem * parent = child->parent(); while (parent) { // invalidate the parent id, otherwise the min below // will not work if the current parent id is less // than all the children! parent->invalidate_processor_id(); for (unsigned int c=0; c<parent->n_children(); c++) { child = parent->child_ptr(c); libmesh_assert(child); libmesh_assert(!child->is_remote()); libmesh_assert_not_equal_to (child->processor_id(), DofObject::invalid_processor_id); parent->processor_id() = std::min(parent->processor_id(), child->processor_id()); } parent = parent->parent(); } } } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. else { // Setting subactive processor ids is easy: we can guarantee // that children have access to all their parents. // Loop over all the active elements in the mesh MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) { Elem * child = *it; std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (unsigned int i = 0; i != subactive_family.size(); ++i) const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id(); } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. // We will use a brute-force approach here. Each processor finds its parent // elements and sets the parent pid to the minimum of its // semilocal descendants. // A global reduction is then performed to make sure the true minimum is found. // As noted, this is required because we cannot guarantee that a parent has // access to all its children on any single processor. libmesh_parallel_only(mesh.comm()); libmesh_assert(MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); const dof_id_type max_elem_id = mesh.max_elem_id(); std::vector<processor_id_type> parent_processor_ids (std::min(communication_blocksize, max_elem_id)); for (dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++) { last_elem_id = std::min(static_cast<dof_id_type>((blk+1)*communication_blocksize), max_elem_id); const dof_id_type first_elem_id = blk*communication_blocksize; std::fill (parent_processor_ids.begin(), parent_processor_ids.end(), DofObject::invalid_processor_id); // first build up local contributions to parent_processor_ids MeshBase::element_iterator not_it = mesh.ancestor_elements_begin(); const MeshBase::element_iterator not_end = mesh.ancestor_elements_end(); bool have_parent_in_block = false; for ( ; not_it != not_end; ++not_it) { Elem * parent = *not_it; const dof_id_type parent_idx = parent->id(); libmesh_assert_less (parent_idx, max_elem_id); if ((parent_idx >= first_elem_id) && (parent_idx < last_elem_id)) { have_parent_in_block = true; processor_id_type parent_pid = DofObject::invalid_processor_id; std::vector<const Elem *> active_family; parent->active_family_tree(active_family); for (unsigned int i = 0; i != active_family.size(); ++i) parent_pid = std::min (parent_pid, active_family[i]->processor_id()); const dof_id_type packed_idx = parent_idx - first_elem_id; libmesh_assert_less (packed_idx, parent_processor_ids.size()); parent_processor_ids[packed_idx] = parent_pid; } } // then find the global minimum mesh.comm().min (parent_processor_ids); // and assign the ids, if we have a parent in this block. if (have_parent_in_block) for (not_it = mesh.ancestor_elements_begin(); not_it != not_end; ++not_it) { Elem * parent = *not_it; const dof_id_type parent_idx = parent->id(); if ((parent_idx >= first_elem_id) && (parent_idx < last_elem_id)) { const dof_id_type packed_idx = parent_idx - first_elem_id; libmesh_assert_less (packed_idx, parent_processor_ids.size()); const processor_id_type parent_pid = parent_processor_ids[packed_idx]; libmesh_assert_not_equal_to (parent_pid, DofObject::invalid_processor_id); parent->processor_id() = parent_pid; } } } } #endif // LIBMESH_ENABLE_AMR }