LCOV - code coverage report
Current view: top level - include/parallel - parallel_ghost_sync.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 190 190 100.0 %
Date: 2025-08-19 19:27:09 Functions: 95 98 96.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : #ifndef LIBMESH_PARALLEL_GHOST_SYNC_H
      21             : #define LIBMESH_PARALLEL_GHOST_SYNC_H
      22             : 
      23             : // libMesh includes
      24             : #include "libmesh/elem.h"
      25             : #include "libmesh/int_range.h"
      26             : #include "libmesh/location_maps.h"
      27             : #include "libmesh/mesh_base.h"
      28             : #include "libmesh/parallel_algebra.h"
      29             : 
      30             : // TIMPI includes
      31             : #include "timpi/communicator.h"
      32             : #include "timpi/parallel_sync.h"
      33             : 
      34             : // C++ includes
      35             : #include <map> // FIXME - pid > comm.size() breaks with unordered_map
      36             : #include <vector>
      37             : 
      38             : 
      39             : namespace libMesh
      40             : {
      41             : 
      42             : 
      43             : 
      44             : //--------------------------------------------------------------------------
      45             : namespace Parallel {
      46             : 
      47             : //------------------------------------------------------------------------
      48             : /**
      49             :  * Request data about a range of ghost nodes uniquely identified by
      50             :  * their xyz location or a range of active ghost elements uniquely
      51             :  * identified by their vertex averages' xyz location.  Fulfill requests
      52             :  * with
      53             :  * sync.gather_data(const std::vector<unsigned int> & ids,
      54             :  *                  std::vector<sync::datum> & data),
      55             :  * by resizing and setting the values of the data vector.
      56             :  * Respond to fulfillment with
      57             :  * sync.act_on_data(const std::vector<unsigned int> & ids,
      58             :  *                  std::vector<sync::datum> & data)
      59             :  * The user must define Parallel::StandardType<sync::datum> if
      60             :  * sync::datum isn't a built-in type.
      61             :  * The user-provided location_map should be already filled.
      62             :  *
      63             :  * This method may fail in cases of overlapping nodes or vertex
      64             :  * averages, e.g. with slit meshes and/or overset meshes.
      65             :  */
      66             : template <typename Iterator,
      67             :           typename DofObjType,
      68             :           typename SyncFunctor>
      69             : void sync_dofobject_data_by_xyz(const Communicator &      comm,
      70             :                                 const Iterator &          range_begin,
      71             :                                 const Iterator &          range_end,
      72             :                                 LocationMap<DofObjType> & location_map,
      73             :                                 SyncFunctor &             sync);
      74             : 
      75             : //------------------------------------------------------------------------
      76             : /**
      77             :  * Request data about a range of ghost dofobjects uniquely
      78             :  * identified by their id.  Fulfill requests with
      79             :  * sync.gather_data(const std::vector<dof_id_type> & ids,
      80             :  *                  std::vector<sync::datum> & data),
      81             :  * by resizing and setting the values of the data vector.
      82             :  * Respond to fulfillment with
      83             :  * sync.act_on_data(const std::vector<dof_id_type> & ids,
      84             :  *                  std::vector<sync::datum> & data)
      85             :  * The user must define Parallel::StandardType<sync::datum> if
      86             :  * sync::datum isn't a built-in type.
      87             :  */
      88             : template <typename Iterator,
      89             :           typename SyncFunctor>
      90             : void sync_dofobject_data_by_id(const Communicator & comm,
      91             :                                const Iterator &     range_begin,
      92             :                                const Iterator &     range_end,
      93             :                                SyncFunctor &        sync);
      94             : 
      95             : /**
      96             :  * Request data about a range of ghost dofobjects uniquely
      97             :  * identified by their id.
      98             :  *
      99             :  * Elements within the range can be excluded from the request by
     100             :  * returning false from dofobj_check(dof_object)
     101             :  */
     102             : template <typename Iterator,
     103             :           typename DofObjectCheckFunctor,
     104             :           typename SyncFunctor>
     105             : void sync_dofobject_data_by_id(const Communicator & comm,
     106             :                                const Iterator & range_begin,
     107             :                                const Iterator & range_end,
     108             :                                const DofObjectCheckFunctor & dofobj_check,
     109             :                                SyncFunctor &    sync);
     110             : 
     111             : //------------------------------------------------------------------------
     112             : /**
     113             :  * Request data about a range of ghost elements uniquely
     114             :  * identified by their parent id and which child they are.
     115             :  * Fulfill requests with
     116             :  * sync.gather_data(const std::vector<unsigned int> & ids,
     117             :  *                  std::vector<sync::datum> & data),
     118             :  * by resizing and setting the values of the data vector.
     119             :  * Respond to fulfillment with
     120             :  * sync.act_on_data(const std::vector<unsigned int> & ids,
     121             :  *                  std::vector<sync::datum> & data)
     122             :  * The user must define Parallel::StandardType<sync::datum> if
     123             :  * sync::datum isn't a built-in type.
     124             :  */
     125             : template <typename Iterator,
     126             :           typename SyncFunctor>
     127             : void sync_element_data_by_parent_id(MeshBase &       mesh,
     128             :                                     const Iterator & range_begin,
     129             :                                     const Iterator & range_end,
     130             :                                     SyncFunctor &    sync);
     131             : 
     132             : //------------------------------------------------------------------------
     133             : /**
     134             :  * Synchronize data about a range of ghost nodes uniquely identified
     135             :  * by an element id and local node id, assuming a single
     136             :  * synchronization pass is necessary.
     137             :  *
     138             :  * Data for all nodes connected to elements in the given range of
     139             :  * *element* iterators will be requested.
     140             :  *
     141             :  * Elements can be further excluded from the request by returning
     142             :  * false from element_check(elem)
     143             :  *
     144             :  * Nodes can be further excluded from the request by returning false
     145             :  * from node_check(elem, local_node_num)
     146             :  *
     147             :  * Fulfill requests with
     148             :  * sync.gather_data(const std::vector<unsigned int> & ids,
     149             :  *                  std::vector<sync::datum> & data),
     150             :  * by resizing and setting the values of the data vector.
     151             :  * Respond to fulfillment with
     152             :  * bool sync.act_on_data(const std::vector<unsigned int> & ids,
     153             :  *                       std::vector<sync::datum> & data)
     154             :  * and return true iff the response changed any data.
     155             :  *
     156             :  * The user must define Parallel::StandardType<sync::datum> if
     157             :  * sync::datum isn't a built-in type.
     158             :  *
     159             :  * This method returns true iff the sync pass changed any data on any
     160             :  * processor.
     161             :  */
     162             : template <typename ElemCheckFunctor,
     163             :           typename NodeCheckFunctor,
     164             :           typename SyncFunctor>
     165             : bool sync_node_data_by_element_id_once(MeshBase & mesh,
     166             :                                        const MeshBase::const_element_iterator & range_begin,
     167             :                                        const MeshBase::const_element_iterator & range_end,
     168             :                                        const ElemCheckFunctor & elem_check,
     169             :                                        const NodeCheckFunctor & node_check,
     170             :                                        SyncFunctor & sync);
     171             : 
     172             : 
     173             : 
     174             : //------------------------------------------------------------------------
     175             : /**
     176             :  * Synchronize data about a range of ghost nodes uniquely identified
     177             :  * by an element id and local node id, iterating until data is
     178             :  * completely in sync and further synchronization passes cause no
     179             :  * changes.
     180             :  *
     181             :  * Imagine a vertex surrounded by triangles, each on a different
     182             :  * processor, with a ghosting policy that include only face neighbors
     183             :  * and not point neighbors.  Then the only way for authoritative
     184             :  * information to trickle out from that vertex is by being passed
     185             :  * along, one neighbor at a time, to processors who mostly don't even
     186             :  * see the node's true owner!
     187             :  *
     188             :  * Data for all nodes connected to elements in the given range of
     189             :  * *element* iterators will be requested.
     190             :  *
     191             :  * Elements can be further excluded from the request by returning
     192             :  * false from element_check(elem)
     193             :  *
     194             :  * Nodes can be further excluded from the request by returning false
     195             :  * from node_check(elem, local_node_num)
     196             :  *
     197             :  * Fulfill requests with
     198             :  * sync.gather_data(const std::vector<unsigned int> & ids,
     199             :  *                  std::vector<sync::datum> & data),
     200             :  * by resizing and setting the values of the data vector.
     201             :  * Respond to fulfillment with
     202             :  * bool sync.act_on_data(const std::vector<unsigned int> & ids,
     203             :  *                       std::vector<sync::datum> & data)
     204             :  * and return true iff the response changed any data.
     205             :  *
     206             :  * The user must define Parallel::StandardType<sync::datum> if
     207             :  * sync::datum isn't a built-in type.
     208             :  */
     209             : template <typename ElemCheckFunctor,
     210             :           typename NodeCheckFunctor,
     211             :           typename SyncFunctor>
     212             : void sync_node_data_by_element_id(MeshBase & mesh,
     213             :                                   const MeshBase::const_element_iterator & range_begin,
     214             :                                   const MeshBase::const_element_iterator & range_end,
     215             :                                   const ElemCheckFunctor & elem_check,
     216             :                                   const NodeCheckFunctor & node_check,
     217             :                                   SyncFunctor & sync);
     218             : 
     219             : 
     220             : //------------------------------------------------------------------------
     221             : // Parallel members
     222             : 
     223             : 
     224             : // "Check" Functor to perform sync operations with no exclusions
     225             : struct SyncEverything
     226             : {
     227        6598 :   SyncEverything() {}
     228             : 
     229     6078442 :   bool operator() (const DofObject *) const { return true; }
     230             : 
     231      312780 :   bool operator() (const Elem *, unsigned int) const
     232      312780 :   { return true; }
     233             : };
     234             : 
     235             : 
     236             : 
     237             : template <typename Iterator,
     238             :           typename DofObjType,
     239             :           typename SyncFunctor>
     240             : void sync_dofobject_data_by_xyz(const Communicator & comm,
     241             :                                 const Iterator & range_begin,
     242             :                                 const Iterator & range_end,
     243             :                                 LocationMap<DofObjType> & location_map,
     244             :                                 SyncFunctor & sync)
     245             : {
     246             :   // This function must be run on all processors at once
     247             :   libmesh_parallel_only(comm);
     248             : 
     249             :   // We need a valid location_map
     250             : #ifdef DEBUG
     251             :   bool need_map_update = (range_begin != range_end && location_map.empty());
     252             :   comm.max(need_map_update);
     253             :   libmesh_assert(!need_map_update);
     254             : #endif
     255             : 
     256             :   // Count the objects to ask each processor about
     257             :   std::map<processor_id_type, dof_id_type>
     258             :     ghost_objects_from_proc;
     259             : 
     260             :   for (Iterator it = range_begin; it != range_end; ++it)
     261             :     {
     262             :       DofObjType * obj = *it;
     263             :       libmesh_assert (obj);
     264             :       processor_id_type obj_procid = obj->processor_id();
     265             :       if (obj_procid != DofObject::invalid_processor_id)
     266             :         ghost_objects_from_proc[obj_procid]++;
     267             :     }
     268             : 
     269             :   // Request sets to send to each processor
     270             :   std::map<processor_id_type, std::vector<Point>>
     271             :     requested_objs_pt;
     272             :   // Corresponding ids to keep track of
     273             :   std::map<processor_id_type, std::vector<dof_id_type>>
     274             :     requested_objs_id;
     275             : 
     276             :   // We know how many objects live on each processor, so reserve()
     277             :   // space for each.
     278             :   for (auto pair : ghost_objects_from_proc)
     279             :     {
     280             :       const processor_id_type p = pair.first;
     281             :       if (p != comm.rank())
     282             :         {
     283             :           requested_objs_pt[p].reserve(pair.second);
     284             :           requested_objs_id[p].reserve(pair.second);
     285             :         }
     286             :     }
     287             : 
     288             :   for (Iterator it = range_begin; it != range_end; ++it)
     289             :     {
     290             :       DofObjType * obj = *it;
     291             :       processor_id_type obj_procid = obj->processor_id();
     292             :       if (obj_procid == comm.rank() ||
     293             :           obj_procid == DofObject::invalid_processor_id)
     294             :         continue;
     295             : 
     296             :       Point p = location_map.point_of(*obj);
     297             :       requested_objs_pt[obj_procid].push_back(p);
     298             :       requested_objs_id[obj_procid].push_back(obj->id());
     299             :     }
     300             : 
     301             :   std::map<const std::vector<Point> *, processor_id_type>
     302             :     requested_objs_pt_inv;
     303             :   for (auto & pair : requested_objs_pt)
     304             :     requested_objs_pt_inv[&pair.second] = pair.first;
     305             : 
     306             :   auto gather_functor =
     307             :     [&location_map, &sync]
     308             :     (processor_id_type /*pid*/, const std::vector<Point> & pts,
     309             :      std::vector<typename SyncFunctor::datum> & data)
     310             :     {
     311             :       // Find the local id of each requested object
     312             :       std::size_t query_size = pts.size();
     313             :       std::vector<dof_id_type> query_id(query_size);
     314             :       for (std::size_t i=0; i != query_size; ++i)
     315             :         {
     316             :           Point pt = pts[i];
     317             : 
     318             :           // Look for this object in the multimap
     319             :           DofObjType * obj = location_map.find(pt);
     320             : 
     321             :           // We'd better find every object we're asked for
     322             :           libmesh_assert (obj);
     323             : 
     324             :           // Return the object's correct processor id,
     325             :           // and our (correct if it's local) id for it.
     326             :           query_id[i] = obj->id();
     327             :         }
     328             : 
     329             :       // Gather whatever data the user wants
     330             :       sync.gather_data(query_id, data);
     331             :     };
     332             : 
     333             :   auto action_functor =
     334             :     [&sync, &requested_objs_id,
     335             :      &requested_objs_pt_inv]
     336             :     (processor_id_type /* pid */, const std::vector<Point> & point_request,
     337             :      const std::vector<typename SyncFunctor::datum> & data)
     338             :     {
     339             :       // With splits working on more pids than ranks, query_pid may not equal pid
     340             :       const processor_id_type query_pid =
     341             :         requested_objs_pt_inv[&point_request];
     342             : 
     343             :       // Let the user process the results
     344             :       sync.act_on_data(requested_objs_id[query_pid], data);
     345             :     };
     346             : 
     347             :   // Trade requests with other processors
     348             :   typename SyncFunctor::datum * ex = nullptr;
     349             :   pull_parallel_vector_data
     350             :     (comm, requested_objs_pt, gather_functor, action_functor, ex);
     351             : }
     352             : 
     353             : 
     354             : 
     355             : template <typename Iterator,
     356             :           typename SyncFunctor>
     357        5924 : void sync_dofobject_data_by_id(const Communicator & comm,
     358             :                                const Iterator & range_begin,
     359             :                                const Iterator & range_end,
     360             :                                SyncFunctor &    sync)
     361             : {
     362      806179 :   sync_dofobject_data_by_id(comm, range_begin, range_end, SyncEverything(), sync);
     363        5924 : }
     364             : 
     365             : template <typename Iterator,
     366             :           typename DofObjectCheckFunctor,
     367             :           typename SyncFunctor>
     368      814158 : void sync_dofobject_data_by_id(const Communicator & comm,
     369             :                                const Iterator & range_begin,
     370             :                                const Iterator & range_end,
     371             :                                const DofObjectCheckFunctor & dofobj_check,
     372             :                                SyncFunctor &    sync)
     373             : {
     374             :   // This function must be run on all processors at once
     375        6082 :   libmesh_parallel_only(comm);
     376             : 
     377             :   // Count the objects to ask each processor about
     378             :   std::map<processor_id_type, dof_id_type>
     379       12164 :     ghost_objects_from_proc;
     380             : 
     381   224018769 :   for (Iterator it = range_begin; it != range_end; ++it)
     382             :     {
     383   114390872 :       const DofObject * obj = *it;
     384     3238509 :       libmesh_assert (obj);
     385             : 
     386             :       // We may want to pass Elem* or Node* to the check function, not
     387             :       // just DofObject*
     388     7196292 :       if (!dofobj_check(*it))
     389     2610840 :         continue;
     390             : 
     391   111780032 :       processor_id_type obj_procid = obj->processor_id();
     392   111780032 :       if (obj_procid != DofObject::invalid_processor_id)
     393   111776208 :         ghost_objects_from_proc[obj_procid]++;
     394             :     }
     395             : 
     396             :   // Request sets to send to each processor
     397             :   std::map<processor_id_type, std::vector<dof_id_type>>
     398       12164 :     requested_objs_id;
     399             : 
     400             :   // We know how many objects live on each processor, so reserve()
     401             :   // space for each.
     402     5179650 :   for (auto pair : ghost_objects_from_proc)
     403             :     {
     404     4365492 :       const processor_id_type p = pair.first;
     405     4365492 :       if (p != comm.rank())
     406     3824145 :         requested_objs_id[p].reserve(pair.second);
     407             :     }
     408             : 
     409   224018769 :   for (Iterator it = range_begin; it != range_end; ++it)
     410             :     {
     411   114390872 :       const DofObject * obj = *it;
     412             : 
     413     7196292 :       if (!dofobj_check(*it))
     414    33707943 :         continue;
     415             : 
     416   111780032 :       processor_id_type obj_procid = obj->processor_id();
     417   113298091 :       if (obj_procid == comm.rank() ||
     418     1518059 :           obj_procid == DofObject::invalid_processor_id)
     419     2386132 :         continue;
     420             : 
     421    80682929 :       requested_objs_id[obj_procid].push_back(obj->id());
     422             :     }
     423             : 
     424      825704 :   auto gather_functor =
     425     3813994 :     [&sync]
     426             :     (processor_id_type, const std::vector<dof_id_type> & ids,
     427        5773 :      std::vector<typename SyncFunctor::datum> & data)
     428             :     {
     429     3824464 :       sync.gather_data(ids, data);
     430             :     };
     431             : 
     432      826154 :   auto action_functor =
     433     3973023 :     [&sync]
     434             :     (processor_id_type, const std::vector<dof_id_type> & ids,
     435        5998 :      const std::vector<typename SyncFunctor::datum> & data)
     436             :     {
     437             :       // Let the user process the results
     438     3983674 :       sync.act_on_data(ids, data);
     439             :     };
     440             : 
     441             :   // Trade requests with other processors
     442        6082 :   typename SyncFunctor::datum * ex = nullptr;
     443             :   pull_parallel_vector_data
     444      814158 :     (comm, requested_objs_id, gather_functor, action_functor, ex);
     445      814158 : }
     446             : 
     447             : 
     448             : 
     449             : // If there's no refined elements, there's nothing to sync
     450             : #ifdef LIBMESH_ENABLE_AMR
     451             : template <typename Iterator,
     452             :           typename SyncFunctor>
     453       21505 : void sync_element_data_by_parent_id(MeshBase &       mesh,
     454             :                                     const Iterator & range_begin,
     455             :                                     const Iterator & range_end,
     456             :                                     SyncFunctor &    sync)
     457             : {
     458          76 :   const Communicator & comm (mesh.comm());
     459             : 
     460             :   // This function must be run on all processors at once
     461          38 :   libmesh_parallel_only(comm);
     462             : 
     463             :   // Count the objects to ask each processor about
     464             :   std::map<processor_id_type, dof_id_type>
     465          76 :     ghost_objects_from_proc;
     466             : 
     467     7741847 :   for (Iterator it = range_begin; it != range_end; ++it)
     468             :     {
     469     3864119 :       Elem * elem = *it;
     470     3864119 :       processor_id_type obj_procid = elem->processor_id();
     471     3865351 :       if (obj_procid == comm.rank() ||
     472        1232 :           obj_procid == DofObject::invalid_processor_id)
     473     1221561 :         continue;
     474        2464 :       const Elem * parent = elem->parent();
     475     2660708 :       if (!parent || !elem->active())
     476       18150 :         continue;
     477             : 
     478     2642558 :       ghost_objects_from_proc[obj_procid]++;
     479             :     }
     480             : 
     481             :   // Request sets to send to each processor
     482             :   std::map<processor_id_type, std::vector<dof_id_type>>
     483          76 :     requested_objs_id;
     484             :   std::map<processor_id_type, std::vector<std::pair<dof_id_type,unsigned char>>>
     485          76 :     requested_objs_parent_id_child_num;
     486             : 
     487             :   // We know how many objects live on each processor, so reserve()
     488             :   // space for each.
     489       86015 :   for (auto pair : ghost_objects_from_proc)
     490             :     {
     491       64510 :       const processor_id_type p = pair.first;
     492       64510 :       if (p != comm.rank())
     493             :         {
     494       64510 :           requested_objs_id[p].reserve(pair.second);
     495       64510 :           requested_objs_parent_id_child_num[p].reserve(pair.second);
     496             :         }
     497             :     }
     498             : 
     499     7741847 :   for (Iterator it = range_begin; it != range_end; ++it)
     500             :     {
     501     3864119 :       Elem * elem = *it;
     502     3864119 :       processor_id_type obj_procid = elem->processor_id();
     503     3865351 :       if (obj_procid == comm.rank() ||
     504        1232 :           obj_procid == DofObject::invalid_processor_id)
     505     1221561 :         continue;
     506        2464 :       const Elem * parent = elem->parent();
     507     2660708 :       if (!parent || !elem->active())
     508       18150 :         continue;
     509             : 
     510     2642558 :       requested_objs_id[obj_procid].push_back(elem->id());
     511             :       requested_objs_parent_id_child_num[obj_procid].emplace_back
     512     2642558 :         (parent->id(), cast_int<unsigned char>(parent->which_child_am_i(elem)));
     513             :     }
     514             : 
     515             :   std::map<const std::vector<std::pair<dof_id_type,unsigned char>> *, processor_id_type>
     516          76 :     requested_objs_parent_id_child_num_inv;
     517       86015 :   for (auto & pair : requested_objs_parent_id_child_num)
     518       64510 :     requested_objs_parent_id_child_num_inv[&pair.second] = pair.first;
     519             : 
     520       21497 :   auto gather_functor =
     521      128884 :     [&mesh, &sync]
     522             :     (processor_id_type,
     523             :      const std::vector<std::pair<dof_id_type, unsigned char>> & parent_id_child_num,
     524          68 :      std::vector<typename SyncFunctor::datum> & data)
     525             :     {
     526             :       // Find the id of each requested element
     527          68 :       std::size_t query_size = parent_id_child_num.size();
     528       64544 :       std::vector<dof_id_type> query_id(query_size);
     529     2707068 :       for (std::size_t i=0; i != query_size; ++i)
     530             :         {
     531     2643790 :           Elem & parent = mesh.elem_ref(parent_id_child_num[i].first);
     532        1232 :           libmesh_assert(parent.has_children());
     533     2643790 :           Elem * child = parent.child_ptr(parent_id_child_num[i].second);
     534        1232 :           libmesh_assert(child);
     535        1232 :           libmesh_assert(child->active());
     536     2643790 :           query_id[i] = child->id();
     537             :         }
     538             : 
     539             :       // Gather whatever data the user wants
     540          34 :       sync.gather_data(query_id, data);
     541             :     };
     542             : 
     543       21463 :   auto action_functor =
     544      193326 :     [&sync, &requested_objs_id,
     545             :      &requested_objs_parent_id_child_num_inv]
     546             :     (processor_id_type /* pid */,
     547             :      const std::vector<std::pair<dof_id_type, unsigned char>> & parent_id_child_num_request,
     548          68 :      const std::vector<typename SyncFunctor::datum> & data)
     549             :     {
     550             :       // With splits working on more pids than ranks, query_pid may not equal pid
     551      128952 :       const processor_id_type query_pid =
     552       64442 :         requested_objs_parent_id_child_num_inv[&parent_id_child_num_request];
     553             : 
     554             :       // Let the user process the results
     555       64510 :       sync.act_on_data(requested_objs_id[query_pid], data);
     556             :     };
     557             : 
     558             :   // Trade requests with other processors
     559          38 :   typename SyncFunctor::datum * ex = nullptr;
     560             :   pull_parallel_vector_data
     561       21505 :     (comm, requested_objs_parent_id_child_num, gather_functor,
     562             :      action_functor, ex);
     563       21505 : }
     564             : #else
     565             : template <typename Iterator,
     566             :           typename SyncFunctor>
     567             : void sync_element_data_by_parent_id(MeshBase &,
     568             :                                     const Iterator &,
     569             :                                     const Iterator &,
     570             :                                     SyncFunctor &)
     571             : {
     572             : }
     573             : #endif // LIBMESH_ENABLE_AMR
     574             : 
     575             : 
     576             : 
     577             : template <typename ElemCheckFunctor,
     578             :           typename NodeCheckFunctor,
     579             :           typename SyncFunctor>
     580      306426 : bool sync_node_data_by_element_id_once(MeshBase & mesh,
     581             :                                        const MeshBase::const_element_iterator & range_begin,
     582             :                                        const MeshBase::const_element_iterator & range_end,
     583             :                                        const ElemCheckFunctor & elem_check,
     584             :                                        const NodeCheckFunctor & node_check,
     585             :                                        SyncFunctor & sync)
     586             : {
     587         430 :   const Communicator & comm (mesh.comm());
     588             : 
     589             :   // Count the objects to ask each processor about
     590             :   std::map<processor_id_type, dof_id_type>
     591         860 :     ghost_objects_from_proc;
     592             : 
     593    77183878 :   for (const auto & elem : as_range(range_begin, range_end))
     594             :     {
     595       42840 :       libmesh_assert (elem);
     596             : 
     597    38154150 :       if (!elem_check(elem))
     598     1255564 :         continue;
     599             : 
     600    36898586 :       const processor_id_type proc_id = elem->processor_id();
     601             : 
     602       41536 :       bool i_have_elem =
     603    36898586 :         (proc_id == comm.rank() ||
     604             :          proc_id == DofObject::invalid_processor_id);
     605             : 
     606    31956416 :       if (elem->active() && i_have_elem)
     607     8409619 :         continue;
     608             : 
     609   288447904 :       for (auto n : elem->node_index_range())
     610             :         {
     611   259958937 :           if (!node_check(elem, n))
     612    35520899 :             continue;
     613             : 
     614   232647819 :           const processor_id_type node_pid =
     615      170262 :             elem->node_ref(n).processor_id();
     616             : 
     617   232647819 :           if (i_have_elem && (node_pid == comm.rank()))
     618       42266 :             continue;
     619             : 
     620   224438038 :           if (i_have_elem)
     621             :             {
     622        2116 :               libmesh_assert_not_equal_to
     623             :                 (node_pid, DofObject::invalid_processor_id);
     624     1729803 :               ghost_objects_from_proc[node_pid]++;
     625             :             }
     626             :           else
     627             :             {
     628   222708235 :               const processor_id_type request_pid =
     629   206409528 :                 (node_pid == DofObject::invalid_processor_id) ?
     630             :                  proc_id : node_pid;
     631   222708235 :               ghost_objects_from_proc[request_pid]++;
     632             :             }
     633             :         }
     634             :     }
     635             : 
     636             :   // Now repeat that iteration, filling request sets this time.
     637             : 
     638             :   // Request sets to send to each processor
     639             :   std::map<processor_id_type, std::vector<std::pair<dof_id_type, unsigned char>>>
     640         430 :     requested_objs_elem_id_node_num;
     641             : 
     642             :   // We know how many objects live on each processor, so reserve()
     643             :   // space for each.
     644     2015531 :   for (auto pair : ghost_objects_from_proc)
     645             :     {
     646     1709105 :       const processor_id_type p = pair.first;
     647     1709105 :       if (p != comm.rank())
     648     1514493 :         requested_objs_elem_id_node_num[p].reserve(ghost_objects_from_proc[p]);
     649             :     }
     650             : 
     651    77183878 :   for (const auto & elem : as_range(range_begin, range_end))
     652             :     {
     653       42840 :       libmesh_assert (elem);
     654             : 
     655    38154150 :       if (!elem_check(elem))
     656     9665183 :         continue;
     657             : 
     658    36898586 :       const processor_id_type proc_id = elem->processor_id();
     659             : 
     660       41536 :       bool i_have_elem =
     661    36898586 :         (proc_id == comm.rank() ||
     662             :          proc_id == DofObject::invalid_processor_id);
     663             : 
     664    31956416 :       if (elem->active() && i_have_elem)
     665     1865020 :         continue;
     666             : 
     667    28488967 :       const dof_id_type elem_id = elem->id();
     668             : 
     669   288447904 :       for (auto n : elem->node_index_range())
     670             :         {
     671   259958937 :           if (!node_check(elem, n))
     672    35520899 :             continue;
     673             : 
     674      170262 :           const Node & node = elem->node_ref(n);
     675   232647819 :           const processor_id_type node_pid = node.processor_id();
     676             : 
     677   232647819 :           if (i_have_elem && (node_pid == comm.rank()))
     678       42266 :             continue;
     679             : 
     680   224438038 :           if (i_have_elem)
     681             :             {
     682        2116 :               libmesh_assert_not_equal_to
     683             :                 (node_pid, DofObject::invalid_processor_id);
     684             :               requested_objs_elem_id_node_num[node_pid].emplace_back
     685     1729803 :                 (elem_id, cast_int<unsigned char>(n));
     686             :             }
     687             :           else
     688             :             {
     689   222708235 :               const processor_id_type request_pid =
     690   206409528 :                 (node_pid == DofObject::invalid_processor_id) ?
     691             :                  proc_id : node_pid;
     692             :               requested_objs_elem_id_node_num[request_pid].emplace_back
     693   222708235 :                 (elem_id,cast_int<unsigned char>(n));
     694             :             }
     695             :         }
     696             :     }
     697             : 
     698      307370 :   auto gather_functor =
     699     3417006 :     [&mesh, &sync]
     700             :     (processor_id_type,
     701             :      const std::vector<std::pair<dof_id_type, unsigned char>> & elem_id_node_num,
     702        1204 :      std::vector<typename SyncFunctor::datum> & data)
     703             :     {
     704             :       // Find the id of each requested element
     705        1204 :       std::size_t request_size = elem_id_node_num.size();
     706     1710309 :       std::vector<dof_id_type> query_id(request_size);
     707   226275741 :       for (std::size_t i=0; i != request_size; ++i)
     708             :         {
     709             :           // We might now get queries about remote elements, in which
     710             :           // case we'll have to ignore them and wait for the query
     711             :           // answer to filter to the querier via another source.
     712   224694030 :           const Elem * elem = mesh.query_elem_ptr(elem_id_node_num[i].first);
     713             : 
     714   224566034 :           if (elem)
     715             :             {
     716   224678471 :               const unsigned int n = elem_id_node_num[i].second;
     717      127996 :               libmesh_assert_less (n, elem->n_nodes());
     718             : 
     719      127996 :               const Node & node = elem->node_ref(n);
     720             : 
     721             :               // This isn't a safe assertion in the case where we're
     722             :               // syncing processor ids
     723             :               // libmesh_assert_equal_to (node->processor_id(), comm.rank());
     724             : 
     725   224678471 :               query_id[i] = node.id();
     726             :             }
     727             :           else
     728       15559 :             query_id[i] = DofObject::invalid_id;
     729             :         }
     730             : 
     731             :       // Gather whatever data the user wants
     732     1709707 :       sync.gather_data(query_id, data);
     733             :     };
     734             : 
     735      306426 :   bool data_changed = false;
     736             : 
     737      307370 :   auto action_functor =
     738     3417006 :     [&sync, &mesh, &data_changed]
     739             :     (processor_id_type /* pid */,
     740             :      const std::vector<std::pair<dof_id_type, unsigned char>> & elem_id_node_num,
     741        1204 :      const std::vector<typename SyncFunctor::datum> & data)
     742             :     {
     743        1204 :       const std::size_t data_size = data.size();
     744             : 
     745         602 :       libmesh_assert_equal_to(elem_id_node_num.size(), data_size);
     746             : 
     747     1710309 :       std::vector<dof_id_type> requested_objs_id(data.size());
     748             : 
     749   226275741 :       for (auto i : IntRange<std::size_t>(0,data_size))
     750             :         {
     751   224694030 :           const Elem & elem = mesh.elem_ref(elem_id_node_num[i].first);
     752   224694030 :           const Node & node = elem.node_ref(elem_id_node_num[i].second);
     753   224694030 :           requested_objs_id[i] = node.id();
     754             :         }
     755             : 
     756             :       // Let the user process the results.  If any of the results
     757             :       // were different than what the user expected, then we may
     758             :       // need to sync again just in case this processor has to
     759             :       // pass on the changes to yet another processor.
     760     3143578 :       if (sync.act_on_data(requested_objs_id, data))
     761      203018 :         data_changed = true;
     762             :     };
     763             : 
     764             :   // Trade requests with other processors
     765         430 :   typename SyncFunctor::datum * ex = nullptr;
     766             :   pull_parallel_vector_data
     767      306426 :     (comm, requested_objs_elem_id_node_num, gather_functor,
     768             :      action_functor, ex);
     769             : 
     770      306426 :   comm.max(data_changed);
     771             : 
     772      612852 :   return data_changed;
     773             : }
     774             : 
     775             : 
     776             : 
     777             : template <typename ElemCheckFunctor,
     778             :           typename NodeCheckFunctor,
     779             :           typename SyncFunctor>
     780         356 : void sync_node_data_by_element_id(MeshBase & mesh,
     781             :                                   const MeshBase::const_element_iterator & range_begin,
     782             :                                   const MeshBase::const_element_iterator & range_end,
     783             :                                   const ElemCheckFunctor & elem_check,
     784             :                                   const NodeCheckFunctor & node_check,
     785             :                                   SyncFunctor & sync)
     786             : {
     787             :   // This function must be run on all processors at once
     788         356 :   libmesh_parallel_only(mesh.comm());
     789             : 
     790         356 :   bool need_sync = false;
     791             : 
     792      284995 :   do
     793             :     {
     794             :       need_sync =
     795             :         sync_node_data_by_element_id_once
     796      285351 :           (mesh, range_begin, range_end, elem_check, node_check,
     797             :            sync);
     798             :     } while (need_sync);
     799         356 : }
     800             : 
     801             : 
     802             : }
     803             : 
     804             : 
     805             : 
     806             : // This struct can be created and passed to the
     807             : // Parallel::sync_dofobject_data_by_id() function.
     808             : struct SyncNodalPositions
     809             : {
     810             :   // The constructor.  You need a reference to the mesh where you will
     811             :   // be setting/getting nodal positions.
     812             :   explicit
     813             :   SyncNodalPositions(MeshBase & m);
     814             : 
     815             :   // The datum typedef is required of this functor, so that the
     816             :   // Parallel::sync_dofobject_data_by_id() function can create e.g.
     817             :   // std::vector<datum>.
     818             :   typedef Point datum;
     819             : 
     820             :   // First required interface.  This function must fill up the data vector for the
     821             :   // ids specified in the ids vector.
     822             :   void gather_data (const std::vector<dof_id_type> & ids, std::vector<datum> & data) const;
     823             : 
     824             :   // Second required interface.  This function must do something with the data in
     825             :   // the data vector for the ids in the ids vector.
     826             :   void act_on_data (const std::vector<dof_id_type> & ids, const std::vector<datum> & data) const;
     827             : 
     828             :   MeshBase & mesh;
     829             : };
     830             : 
     831             : // This struct can be created and passed to the
     832             : // Parallel::sync_dofobject_data_by_id() function.
     833             : struct SyncSubdomainIds
     834             : {
     835             :   // The constructor.  You need a reference to the mesh where you will
     836             :   // be setting/getting element subdomain IDs.
     837             :   explicit
     838             :   SyncSubdomainIds(MeshBase & m);
     839             : 
     840             :   // The datum typedef is required of this functor, so that the
     841             :   // Parallel::sync_dofobject_data_by_id() function can create e.g.
     842             :   // std::vector<datum>.
     843             :   typedef subdomain_id_type datum;
     844             : 
     845             :   // First required interface.  This function must fill up the data vector for the
     846             :   // ids specified in the ids vector.
     847             :   void gather_data (const std::vector<dof_id_type> & ids, std::vector<datum> & data) const;
     848             : 
     849             :   // Second required interface.  This function must do something with the data in
     850             :   // the data vector for the ids in the ids vector.
     851             :   void act_on_data (const std::vector<dof_id_type> & ids, const std::vector<datum> & data) const;
     852             : 
     853             :   MeshBase & mesh;
     854             : };
     855             : 
     856             : // This struct can be created and passed to the
     857             : // Parallel::sync_dofobject_data_by_id() function
     858             : // for sync element integers.
     859             : struct SyncElementIntegers
     860             : {
     861             :   // The constructor.  You need a reference to the mesh where you will
     862             :   // be setting/getting element integers and an existing element integer name.
     863             :   explicit
     864             :   SyncElementIntegers(MeshBase & m, const std::string & integer_name);
     865             : 
     866             :   // The datum typedef is required of this functor, so that the
     867             :   // Parallel::sync_dofobject_data_by_id() function can create e.g.
     868             :   // std::vector<datum>.
     869             :   typedef dof_id_type datum;
     870             : 
     871             :   // First required interface.  This function must fill up the data vector for the
     872             :   // ids specified in the ids vector.
     873             :   void gather_data(const std::vector<dof_id_type> & ids, std::vector<datum> & data) const;
     874             : 
     875             :   // Second required interface.  This function must do something with the data in
     876             :   // the data vector for the ids in the ids vector.
     877             :   void act_on_data(const std::vector<dof_id_type> & ids,  const std::vector<datum> & data) const;
     878             : 
     879             :   MeshBase & mesh;
     880             :   unsigned int ind;
     881             : };
     882             : 
     883             : } // namespace libMesh
     884             : 
     885             : #endif // LIBMESH_PARALLEL_GHOST_SYNC_H

Generated by: LCOV version 1.14