Quinoa all test code coverage report
Current view: top level - Inciter - Sorter.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 165 166 99.4 %
Date: 2024-11-22 09:12:55 Functions: 19 20 95.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 134 184 72.8 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Inciter/Sorter.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \brief     Mesh sorter for global distributed mesh reordering
       9                 :            :   \see       Sorter.h for more info.
      10                 :            : */
      11                 :            : // *****************************************************************************
      12                 :            : 
      13                 :            : #include <vector>
      14                 :            : #include <algorithm>
      15                 :            : 
      16                 :            : #include "Sorter.hpp"
      17                 :            : #include "Reorder.hpp"
      18                 :            : #include "DerivedData.hpp"
      19                 :            : #include "Inciter/InputDeck/InputDeck.hpp"
      20                 :            : 
      21                 :            : namespace inciter {
      22                 :            : 
      23                 :            : extern ctr::InputDeck g_inputdeck;
      24                 :            : 
      25                 :            : } // inciter::
      26                 :            : 
      27                 :            : using inciter::Sorter;
      28                 :            : 
      29                 :       1943 : Sorter::Sorter( std::size_t meshid,
      30                 :            :                 const CProxy_Transporter& transporter,
      31                 :            :                 const tk::CProxy_MeshWriter& meshwriter,
      32                 :            :                 const tk::SorterCallback& cbs,
      33                 :            :                 const std::vector< Scheme >& scheme,
      34                 :            :                 CkCallback reorderRefiner,
      35                 :            :                 const std::vector< std::size_t >& ginpoel,
      36                 :            :                 const tk::UnsMesh::CoordMap& coordmap,
      37                 :            :                 const tk::UnsMesh::Chunk& el,
      38                 :            :                 const std::map< int, std::vector< std::size_t > >& bface,
      39                 :            :                 const std::vector< std::size_t >& triinpoel,
      40                 :            :                 const std::map< int, std::vector< std::size_t > >& bnode,
      41                 :            :                 const std::unordered_map< std::size_t, std::set< std::size_t > >&
      42                 :            :                   elemblockid,
      43                 :       1943 :                 int nchare ) :
      44                 :            :   m_meshid( meshid ),
      45                 :            :   m_host( transporter ),
      46                 :            :   m_meshwriter( meshwriter ),
      47                 :            :   m_cbs( cbs ),
      48                 :            :   m_scheme( scheme ),
      49                 :            :   m_reorderRefiner( reorderRefiner ),
      50                 :            :   m_ginpoel( ginpoel ),
      51                 :            :   m_coordmap( coordmap ),
      52                 :            :   m_el( el ),
      53                 :            :   m_nbnd( 0 ),
      54                 :            :   m_bface( bface ),
      55                 :            :   m_triinpoel( triinpoel ),
      56                 :            :   m_bnode( bnode ),
      57                 :            :   m_elemblockid( elemblockid ),
      58                 :            :   m_nchare( nchare ),
      59                 :            :   m_nodeset( begin(ginpoel), end(ginpoel) ),
      60                 :            :   m_noffset( 0 ),
      61                 :            :   m_nodech(),
      62                 :            :   m_chnode(),
      63                 :            :   m_edgech(),
      64                 :            :   m_chedge(),
      65                 :            :   m_msum(),
      66                 :            :   m_reordcomm(),
      67                 :            :   m_start( 0 ),
      68                 :            :   m_newnodes(),
      69                 :            :   m_newcoordmap(),
      70                 :            :   m_reqnodes(),
      71                 :            :   m_lower( 0 ),
      72 [ +  - ][ +  - ]:       7772 :   m_upper( 0 )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      73                 :            : // *****************************************************************************
      74                 :            : //  Constructor: prepare owned mesh node IDs for reordering
      75                 :            : //! \param[in] meshid Mesh ID
      76                 :            : //! \param[in] transporter Transporter (host) Charm++ proxy
      77                 :            : //! \param[in] meshwriter Mesh writer Charm++ proxy
      78                 :            : //! \param[in] cbs Charm++ callbacks for Sorter
      79                 :            : //! \param[in] scheme Discretization schemes (one per mesh)
      80                 :            : //! \param[in] reorderRefiner Callback to use to send reordered mesh to Refiner
      81                 :            : //! \param[in] ginpoel Mesh connectivity (this chare) using global node IDs
      82                 :            : //! \param[in] coordmap Mesh node coordinates (this chare) for global node IDs
      83                 :            : //! \param[in] bface Face lists mapped to side set ids
      84                 :            : //! \param[in] triinpoel Interconnectivity of points and boundary-faces
      85                 :            : //! \param[in] bnode Node ids mapped to side set ids
      86                 :            : //! \param[in] elemblockid Local tet ids associated to mesh block ids
      87                 :            : //! \param[in] nchare Total number of Charm++ worker chares
      88                 :            : // *****************************************************************************
      89                 :            : {
      90                 :            :   // Ensure boundary face ids will not index out of face connectivity
      91                 :            :   Assert( std::all_of( begin(m_bface), end(m_bface),
      92                 :            :             [&](const auto& s)
      93                 :            :             { return std::all_of( begin(s.second), end(s.second),
      94                 :            :                        [&](auto f){ return f*3+2 < m_triinpoel.size(); } ); } ),
      95                 :            :           "Boundary face data structures inconsistent" );
      96                 :       1943 : }
      97                 :            : 
      98                 :            : void
      99                 :       1943 : Sorter::setup( std::size_t npoin )
     100                 :            : // *****************************************************************************
     101                 :            : // Setup chare mesh boundary node communication map
     102                 :            : //! \param[in] npoin Total number of mesh points in mesh. Note that the number
     103                 :            : //!   of mesh points does not have to be exactly the total number of points in
     104                 :            : //!   the mesh. It can be a larger number, but not less. This is only used here
     105                 :            : //!   to assign nodes to workers that will assign ids to mesh nodes during node
     106                 :            : //!   reordering.
     107                 :            : // *****************************************************************************
     108                 :            : {
     109                 :            :   // Compute the number of nodes (chunksize) a chare will build a node
     110                 :            :   // communication map for. We compute two values of chunksize: one for when
     111                 :            :   // the global node ids are abounded between [0...npoin-1], inclusive, and
     112                 :            :   // another one for when the global node ids are assigned by a hash algorithm
     113                 :            :   // during initial mesh refinement. In the latter case, the maximum
     114                 :            :   // representable value of a std::size_t is assumed to be the large global node
     115                 :            :   // id and is used to compute the chunksize. To compute the bin id, we attempt
     116                 :            :   // to use the first chunksize first: if it gives a chare id that is
     117                 :            :   // (strictly) lower than the number of chares, that's good. If not, we compute
     118                 :            :   // the bin id based on the second chunksize, which almost always will give a
     119                 :            :   // bin id strictly lower than the number of chares, except if the global node
     120                 :            :   // id assigned by the hash algorithm in Refiner hits the maximum
     121                 :            :   // representable number in std::size_t. If that is the case, we just assign
     122                 :            :   // that node to the last chare.
     123                 :       1943 :   auto N = static_cast< std::size_t >( m_nchare );
     124                 :            :   std::array< std::size_t, 2 > chunksize{{
     125                 :       1943 :      npoin / N, std::numeric_limits< std::size_t >::max() / N }};
     126                 :            : 
     127         [ +  - ]:       1943 :   const auto scheme = g_inputdeck.get< tag::scheme >();
     128                 :            : 
     129                 :            :   // Find chare-boundary nodes and edges of our mesh chunk. This algorithm
     130                 :            :   // collects the global mesh node ids and edges on the chare boundary. A node
     131                 :            :   // is on a chare boundary if it belongs to a face of a tetrahedron that has
     132                 :            :   // no neighbor tet at a face. The edge is on the chare boundary if its first
     133                 :            :   // edge-end point is on a chare boundary. The nodes are categorized to bins
     134                 :            :   // that will be sent to different chares to build point-to-point
     135                 :            :   // communication maps across all chares. The binning is determined by the
     136                 :            :   // global node id divided by the chunksizes. See discussion above on how we
     137                 :            :   // use two chunksizes for global node ids assigned by the hash algorithm in
     138                 :            :   // Refiner (if initial mesh refinement has been done).
     139                 :            :   tk::CommMaps chbnd;
     140         [ +  - ]:       1943 :   auto el = tk::global2local( m_ginpoel );      // generate local mesh data
     141                 :            :   const auto& inpoel = std::get< 0 >( el );     // local connectivity
     142         [ +  - ]:       3886 :   auto esup = tk::genEsup( inpoel, 4 );         // elements surrounding points
     143         [ +  - ]:       1943 :   auto esuel = tk::genEsuelTet( inpoel, esup ); // elems surrounding elements
     144         [ +  + ]:     546990 :   for (std::size_t e=0; e<esuel.size()/4; ++e) {
     145                 :     545047 :     auto mark = e*4;
     146         [ +  + ]:    2725235 :     for (std::size_t f=0; f<4; ++f)
     147         [ +  + ]:    2180188 :       if (esuel[mark+f] == -1)
     148         [ +  + ]:    1223400 :         for (std::size_t n=0; n<3; ++n) {
     149         [ +  + ]:     917550 :           auto g = m_ginpoel[ mark+tk::lpofa[f][n] ];
     150                 :     917550 :           auto bin = g / chunksize[0];
     151         [ +  + ]:     917550 :           if (bin >= N) bin = g / chunksize[1];
     152         [ -  + ]:     917550 :           if (bin >= N) bin = N - 1;
     153                 :            :           Assert( bin < N, "Will index out of number of chares" );
     154 [ +  - ][ +  - ]:     917550 :           auto& b = chbnd[ static_cast< int >( bin ) ];
     155                 :            :           b.get< tag::node >().insert( g );
     156         [ +  + ]:     917550 :           if (scheme == ctr::SchemeType::ALECG ||
     157                 :            :             scheme == ctr::SchemeType::OversetFE) {
     158         [ +  + ]:     436512 :             auto h = m_ginpoel[ mark + tk::lpofa[ f ][ tk::lpoet[n][1] ] ];
     159 [ +  + ][ +  - ]:     654768 :             b.get< tag::edge >().insert( { std::min(g,h), std::max(g,h) } );
     160                 :            :           }
     161                 :            :         }
     162                 :            :   }
     163                 :            : 
     164                 :            :   // Send boundary data in bins to chares that will compute communication maps
     165                 :            :   // for the data in the bin. These bins form a distributed table.  Note that
     166                 :            :   // we only send data to those chares that have data to work on. The receiving
     167                 :            :   // sides do not know in advance if they receive messages or not.  Completion
     168                 :            :   // is detected by having the receiver respond back and counting the responses
     169                 :            :   // on the sender side, i.e., this chare.
     170                 :       1943 :   m_nbnd = chbnd.size();
     171         [ -  + ]:       1943 :   if (m_nbnd == 0)
     172         [ -  - ]:          0 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     173                 :            :                 m_cbs.get< tag::queried >() );
     174                 :            :   else
     175         [ +  + ]:      14227 :     for (const auto& [ targetchare, bnd ] : chbnd)
     176 [ +  - ][ +  - ]:      24568 :       thisProxy[ targetchare ].query( thisIndex, bnd );
                 [ -  - ]
     177                 :       1943 : }
     178                 :            : 
     179                 :            : void
     180                 :      12284 : Sorter::query( int fromch, const tk::AllCommMaps& bnd )
     181                 :            : // *****************************************************************************
     182                 :            : // Incoming query for a list of mesh nodes for which this chare compiles node
     183                 :            : // communication maps
     184                 :            : //! \param[in] fromch Sender chare ID
     185                 :            : //! \param[in] bnd Chare-boundary data from another chare
     186                 :            : // *****************************************************************************
     187                 :            : {
     188                 :            :   // Store incoming nodes in node->chare and its inverse, chare->node, maps
     189                 :            :   const auto& nodes = bnd.get< tag::node >();
     190         [ +  + ]:     163596 :   for (auto n : nodes) m_nodech[ n ].push_back( fromch );
     191                 :            :   m_chnode[ fromch ].insert( begin(nodes), end(nodes) );
     192                 :            : 
     193                 :            :   // Store incoming edges in edge->chare and its inverse, chare->edge, maps
     194                 :            :   const auto& edges = bnd.get< tag::edge >();
     195         [ +  + ]:     591624 :   for (const auto& e : edges) m_edgech[ e ].push_back( fromch );
     196                 :            :   m_chedge[ fromch ].insert( begin(edges), end(edges) );
     197                 :            : 
     198                 :            :   // Report back to chare message received from
     199         [ +  - ]:      12284 :   thisProxy[ fromch ].recvquery();
     200                 :      12284 : }
     201                 :            : 
     202                 :            : void
     203                 :      12284 : Sorter::recvquery()
     204                 :            : // *****************************************************************************
     205                 :            : // Receive receipt of boundary node lists to query
     206                 :            : // *****************************************************************************
     207                 :            : {
     208         [ +  + ]:      12284 :   if (--m_nbnd == 0)
     209                 :       1943 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     210                 :            :                 m_cbs.get< tag::queried >() );
     211                 :      12284 : }
     212                 :            : 
     213                 :            : void
     214                 :       1943 : Sorter::response()
     215                 :            : // *****************************************************************************
     216                 :            : //  Respond to boundary node list queries
     217                 :            : // *****************************************************************************
     218                 :            : {
     219                 :            :   std::unordered_map< int, tk::CommMaps > exp;
     220                 :            : 
     221                 :            :   // Compute node communication map to be sent back to chares
     222         [ +  + ]:      14227 :   for (const auto& [ neighborchare, bndnodes ] : m_chnode) {
     223                 :            :     auto& nc = exp[ neighborchare ];
     224         [ +  + ]:     163596 :     for (auto n : bndnodes)
     225         [ +  + ]:     429248 :       for (auto d : tk::cref_find(m_nodech,n))
     226         [ +  + ]:     277936 :         if (d != neighborchare)
     227         [ +  - ]:     126624 :           nc[d].get< tag::node >().insert( n );
     228                 :            :   }
     229                 :            : 
     230                 :            :   // Compute edge communication map to be sent back to chares
     231         [ +  + ]:      14227 :   for (const auto& [ neighborchare, bndedges ] : m_chedge) {
     232                 :            :     auto& ec = exp[ neighborchare ];
     233         [ +  + ]:     301954 :     for (const auto& e : bndedges)
     234         [ +  + ]:     761228 :       for (auto d : tk::cref_find(m_edgech,e))
     235         [ +  + ]:     471558 :         if (d != neighborchare)
     236         [ +  - ]:     181888 :           ec[d].get< tag::edge >().insert( e );
     237                 :            :   }
     238                 :            : 
     239                 :            :   // Send communication maps to chares that issued a query to us. Communication
     240                 :            :   // maps were computed above for those chares that queried this map from us.
     241                 :            :   // This data form a distributed table and we only work on a chunk of it. Note
     242                 :            :   // that we only send data back to those chares that have queried us. The
     243                 :            :   // receiving sides do not know in advance if the receive messages or not.
     244                 :            :   // Completion is detected by having the receiver respond back and counting
     245                 :            :   // the responses on the sender side, i.e., this chare.
     246                 :       1943 :   m_nbnd = exp.size();
     247         [ +  + ]:       1943 :   if (m_nbnd == 0)
     248         [ +  - ]:        932 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     249                 :            :                 m_cbs.get< tag::responded >() );
     250                 :            :   else
     251         [ +  + ]:      13295 :     for (const auto& [ targetchare, maps ] : exp)
     252 [ +  - ][ +  - ]:      24568 :       thisProxy[ targetchare ].bnd( thisIndex, maps );
     253                 :       1943 : }
     254                 :            : 
     255                 :            : void
     256                 :      12284 : Sorter::bnd( int fromch, const tk::CommMaps& msum )
     257                 :            : // *****************************************************************************
     258                 :            : // Receive boundary node communication maps for our mesh chunk
     259                 :            : //! \param[in] fromch Sender chare ID
     260                 :            : //! \param[in] msum Communication map(s) assembled by chare fromch
     261                 :            : // *****************************************************************************
     262                 :            : {
     263         [ +  + ]:      65274 :   for (const auto& [ neighborchare, maps ] : msum) {
     264                 :      52990 :     auto& m = m_msum[ neighborchare ];
     265                 :            :     const auto& nodemap = maps.get< tag::node >();
     266                 :            :     m.get< tag::node >().insert( begin(nodemap), end(nodemap) );
     267                 :            :     const auto& edgemap = maps.get< tag::edge >();
     268                 :            :     m.get< tag::edge >().insert( begin(edgemap), end(edgemap) );
     269                 :            :   }
     270                 :            : 
     271                 :            :   // Report back to chare message received from
     272         [ +  - ]:      12284 :   thisProxy[ fromch ].recvbnd();
     273                 :      12284 : }
     274                 :            : 
     275                 :            : void
     276                 :      12284 : Sorter::recvbnd()
     277                 :            : // *****************************************************************************
     278                 :            : // Receive receipt of boundary node communication map
     279                 :            : // *****************************************************************************
     280                 :            : {
     281         [ +  + ]:      12284 :   if (--m_nbnd == 0)
     282                 :       1011 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     283                 :            :                 m_cbs.get< tag::responded >() );
     284                 :      12284 : }
     285                 :            : 
     286                 :            : void
     287                 :       1943 : Sorter::start()
     288                 :            : // *****************************************************************************
     289                 :            : //  Start reordering (if enabled)
     290                 :            : // *****************************************************************************
     291                 :            : {
     292                 :            :   // Keep only those edges in edge comm map whose both end-points are in the
     293                 :            :   // node comm map
     294         [ +  + ]:      21595 :   for (auto& [ neighborchare, maps ] : m_msum) {
     295                 :            :     const auto& nodes = maps.get< tag::node >();
     296                 :            :     tk::EdgeSet edges;
     297         [ +  + ]:     134258 :     for (const auto& e : maps.get< tag::edge >())
     298 [ +  - ][ +  - ]:     229212 :       if (nodes.find(e[0]) != end(nodes) && nodes.find(e[1]) != end(nodes))
     299                 :            :         edges.insert( e );
     300                 :            :     maps.get< tag::edge >() = std::move(edges);
     301                 :            :   }
     302                 :            : 
     303         [ -  + ]:       1943 :   if (g_inputdeck.get< tag::cmd, tag::feedback >()) m_host.chcomm();
     304                 :            : 
     305                 :       1943 :   tk::destroy( m_nodech );
     306                 :       1943 :   tk::destroy( m_chnode );
     307                 :            : 
     308         [ +  + ]:       1943 :   if (g_inputdeck.get< tag::pelocal_reorder >())
     309                 :         18 :     mask();   // continue with mesh node reordering if requested (or required)
     310                 :            :   else
     311                 :       1925 :     createDiscWorkers();  // skip mesh node reordering
     312                 :       1943 : }
     313                 :            : 
     314                 :            : void
     315                 :         18 : Sorter::mask()
     316                 :            : // *****************************************************************************
     317                 :            : //  Start preparing for mesh node reordering in parallel
     318                 :            : // *****************************************************************************
     319                 :            : {
     320                 :            :   // Compute asymmetric communcation map that will be used for reordering. This
     321                 :            :   // communication map is asymmetric because it associates global mesh node IDs
     322                 :            :   // to chares only with lower IDs than thisIndex. That is because this chare
     323                 :            :   // will need to receive new (reorderd) node IDs only from chares with lower
     324                 :            :   // IDs than thisIndex during node reordering. Since it only stores data for
     325                 :            :   // lower chare IDs, it is asymmetric. Note that because of this algorithm the
     326                 :            :   // type of m_msum is an ordered map, because of the std::none_of() algorithm
     327                 :            :   // needs to look at ALL chares this chare potentially communicates nodes with
     328                 :            :   // that have lower chare IDs that thisIndex. Since the map is ordered, it can
     329                 :            :   // walk through from the beginning of m_msum until the outer loop variable c,
     330                 :            :   // which is the chare ID the outer loop works on in a given cycle.
     331         [ +  + ]:         30 :   for (auto c=m_msum.cbegin(); c!=m_msum.cend(); ++c)
     332         [ +  + ]:         12 :     if (thisIndex > c->first) {
     333                 :          6 :       auto& n = m_reordcomm[ c->first ];
     334         [ +  + ]:        307 :       for (auto j : c->second.get< tag::node >())
     335         [ +  - ]:        301 :         if (std::none_of( m_msum.cbegin(), c,
     336                 :            :              [j]( const auto& s ) {
     337                 :            :                const auto& nodemap = s.second.template get< tag::node >();
     338                 :            :                return nodemap.find(j) != end(nodemap); } ))
     339                 :            :         {
     340                 :            :           n.insert(j);
     341                 :            :         }
     342         [ -  + ]:          6 :       if (n.empty()) m_reordcomm.erase( c->first );
     343                 :            :     }
     344                 :            : 
     345                 :            :   // Count up total number of nodes this chare will need to receive
     346                 :            :   auto nrecv = tk::sumvalsize( m_reordcomm );
     347                 :            : 
     348         [ -  + ]:         18 :   if ( g_inputdeck.get< tag::cmd, tag::feedback >() ) m_host.chmask();
     349                 :            : 
     350                 :            :   // Compute number of mesh node IDs we will assign IDs to
     351                 :         18 :   auto nuniq = m_nodeset.size() - nrecv;
     352                 :            : 
     353                 :            :   // Start computing offsets for node reordering
     354                 :         18 :   thisProxy.offset( thisIndex, nuniq );
     355                 :         18 : }
     356                 :            : 
     357                 :            : void
     358                 :         30 : Sorter::offset( int c, std::size_t u )
     359                 :            : // *****************************************************************************
     360                 :            : //  Receive number of uniquely assigned global mesh node IDs from chares with
     361                 :            : //  lower IDs than thisIndex
     362                 :            : //! \param[in] c Chare ID
     363                 :            : //! \param[in] u Number of mesh node IDs chare c will assign IDs to
     364                 :            : //! \details This function computes the offset each chare will need to start
     365                 :            : //!   assigning its new node IDs from. The offset for a chare is the
     366                 :            : //!   offset for the previous chare plus the number of node IDs the previous
     367                 :            : //!   chare (uniquely) assigns new IDs for minus the number of node IDs the
     368                 :            : //!   previous chare receives from others (lower chares). This is computed here
     369                 :            : //!   in a parallel/distributed fashion by each chare sending its number of node
     370                 :            : //!   IDs (that it uniquely assigns) to all chares. Note that each chare would
     371                 :            : //!   only need to send this information to chares with higher IDs, but instead
     372                 :            : //!   this function is called in a broadcast fashion, because that is more
     373                 :            : //!   efficient than individual calls to only chares with higher IDs. Therefore
     374                 :            : //!   when computing the offsets, we only count the lower chares. When this is
     375                 :            : //!   done, we have the precise asymmetric communication map as well as the
     376                 :            : //!   start offset on all chares and so we can start the distributed global mesh
     377                 :            : //!   node ID reordering.
     378                 :            : // *****************************************************************************
     379                 :            : {
     380         [ +  + ]:         30 :   if (c < thisIndex) m_start += u;
     381         [ +  + ]:         30 :   if (++m_noffset == m_nchare) reorder();
     382                 :         30 : }
     383                 :            : 
     384                 :            : void
     385                 :         18 : Sorter::reorder()
     386                 :            : // *****************************************************************************
     387                 :            : //  Reorder global mesh node IDs
     388                 :            : // *****************************************************************************
     389                 :            : {
     390                 :            :   // Activate SDAG waits for arriving requests from other chares requesting new
     391                 :            :   // node IDs for node IDs we assign new IDs to during reordering; and for
     392                 :            :   // computing/receiving lower and upper bounds of global node IDs our chare's
     393                 :            :   // linear system will operate on after reordering.
     394         [ +  - ]:         36 :   thisProxy[ thisIndex ].wait4prep();
     395                 :            : 
     396                 :            :   // Send out request for new global node IDs for nodes we do not reorder
     397         [ +  + ]:         24 :   for (const auto& [ targetchare, nodes ] : m_reordcomm)
     398         [ +  - ]:         12 :     thisProxy[ targetchare ].request( thisIndex, nodes );
     399                 :            : 
     400                 :            :   // Lambda to decide if node is assigned a new ID by this chare. If node is not
     401                 :            :   // found in the asymmetric communication map, it is owned, i.e., this chare
     402                 :            :   // assigns its new id.
     403                 :      12389 :   auto ownnode = [ this ]( std::size_t p ) {
     404                 :            :     return std::all_of( m_reordcomm.cbegin(), m_reordcomm.cend(),
     405                 :            :                         [&](const auto& s)
     406                 :      12389 :                         { return s.second.find(p) == s.second.cend(); } );
     407                 :            :   };
     408                 :            : 
     409                 :            :   // Reorder our chunk of the mesh node IDs. Looping through all of our node
     410                 :            :   // IDs, we test if we are to assign a new ID to a node ID, and if so, we
     411                 :            :   // assign a new ID, i.e., reorder, by constructing a map associating new to
     412                 :            :   // old IDs (m_newnodes). We also count up the reordered nodes, which serves as
     413                 :            :   // the new node id. We also store the node coordinates associated to the new
     414                 :            :   // node ID.
     415         [ +  + ]:      12407 :   for (auto p : m_nodeset)
     416         [ +  + ]:      12389 :     if (ownnode(p)) {
     417                 :      12088 :       m_newnodes[ p ] = m_start;        // assign new node ID (reorder)
     418                 :      12088 :       m_newcoordmap.emplace( m_start, tk::cref_find(m_coordmap,p) );
     419                 :      12088 :       ++m_start;
     420                 :            :     }
     421                 :            : 
     422                 :            :   // Trigger SDAG wait indicating that reordering our node IDs are complete
     423                 :         18 :   reorderowned_complete();
     424                 :            : 
     425                 :            :   // If all our nodes have new IDs assigned, reordering complete on this chare
     426         [ +  + ]:         18 :   if (m_newnodes.size() == m_nodeset.size()) finish();
     427                 :         18 : }
     428                 :            : 
     429                 :            : void
     430                 :          6 : Sorter::request( int c, const std::unordered_set< std::size_t >& nd )
     431                 :            : // *****************************************************************************
     432                 :            : //  Request new global node IDs for old node IDs
     433                 :            : //! \param[in] c Chare request coming from and to which we send new IDs to
     434                 :            : //! \param[in] nd Set of old node IDs whose new IDs are requested
     435                 :            : // *****************************************************************************
     436                 :            : {
     437                 :            :   // Queue up requesting chare and node IDs
     438                 :          6 :   m_reqnodes.push_back( { c, nd } );
     439                 :            :   // Trigger SDAG wait signaling that node IDs have been requested from us
     440                 :          6 :   nodes_requested_complete();
     441                 :          6 : }
     442                 :            : 
     443                 :            : void
     444                 :          6 : Sorter::prepare()
     445                 :            : // *****************************************************************************
     446                 :            : //  Find new node IDs for old ones and return them to the requestor(s)
     447                 :            : // *****************************************************************************
     448                 :            : {
     449                 :            :   // Find and return new node IDs to sender
     450         [ +  + ]:         12 :   for (const auto& [ requestorchare, nodes ] : m_reqnodes) {
     451                 :            :     std::unordered_map< std::size_t,
     452                 :            :       std::tuple< std::size_t, tk::UnsMesh::Coord > > n;
     453         [ +  + ]:        307 :     for (auto p : nodes) {
     454                 :        301 :       auto newid = tk::cref_find( m_newnodes, p );
     455                 :            :       n.emplace( p,
     456                 :        301 :         std::make_tuple( newid, tk::cref_find(m_newcoordmap,newid) ) );
     457                 :            :     }
     458 [ +  - ][ +  - ]:         12 :     thisProxy[ requestorchare ].neworder( n );
     459                 :            :   }
     460                 :            : 
     461                 :            :   tk::destroy( m_reqnodes ); // Clear queue of requests just fulfilled
     462                 :            : 
     463                 :            :   // Re-enable SDAG wait for preparing new node requests
     464         [ +  - ]:          6 :   thisProxy[ thisIndex ].wait4prep();
     465                 :            : 
     466                 :            :   // Re-enable trigger signaling that reordering of owned node IDs are
     467                 :            :   // complete right away
     468                 :          6 :   reorderowned_complete();
     469                 :          6 : }
     470                 :            : 
     471                 :            : void
     472                 :          6 : Sorter::neworder( const std::unordered_map< std::size_t,
     473                 :            :                         std::tuple< std::size_t, tk::UnsMesh::Coord > >& nodes )
     474                 :            : // *****************************************************************************
     475                 :            : //  Receive new (reordered) global node IDs
     476                 :            : //! \param[in] nodes Map associating new to old node IDs
     477                 :            : // *****************************************************************************
     478                 :            : {
     479                 :            :   // Store new node IDs associated to old ones, and node coordinates associated
     480                 :            :   // to new node IDs.
     481         [ +  + ]:        307 :   for (const auto& [ oldid, newnodes ] : nodes) {
     482         [ +  - ]:        301 :     auto newid = std::get< 0 >( newnodes );
     483         [ +  - ]:        301 :     m_newnodes[ oldid ] = newid;
     484                 :            :     m_newcoordmap.emplace( newid, std::get< 1 >( newnodes ) );
     485                 :            :   }
     486                 :            : 
     487                 :            :   // If all our nodes have new IDs assigned, reorder complete on this PE
     488         [ +  - ]:          6 :   if (m_newnodes.size() == m_nodeset.size()) finish();
     489                 :          6 : }
     490                 :            : 
     491                 :            : void
     492                 :         18 : Sorter::finish()
     493                 :            : // *****************************************************************************
     494                 :            : //  Compute final result of reordering
     495                 :            : //! \details Reordering is now complete on this chare. We now remap all mesh
     496                 :            : //!   data to reflect the new ordering.
     497                 :            : // *****************************************************************************
     498                 :            : {
     499                 :            :   // Update elem connectivity with the reordered node IDs
     500                 :         18 :   tk::remap( m_ginpoel, m_newnodes );
     501                 :            : 
     502                 :            :   // Update node coordinate map with the reordered IDs
     503                 :            :   m_coordmap = m_newcoordmap;
     504                 :            : 
     505                 :            :   // Update mesh chunk data structure held in our state with new node order
     506                 :         36 :   m_el = tk::global2local( m_ginpoel );
     507                 :            : 
     508                 :            :   // Update symmetric chare-node communication map with the reordered IDs
     509         [ +  + ]:         30 :   for (auto& [ neighborchare, maps ] : m_msum) {
     510                 :            : 
     511                 :            :     tk::NodeSet n;
     512         [ +  + ]:        614 :     for (auto p : maps.get< tag::node >())
     513                 :            :       n.insert( tk::cref_find( m_newnodes, p ) );
     514                 :            :     maps.get< tag::node >() = std::move( n );
     515                 :            : 
     516                 :            :     tk::EdgeSet e;
     517         [ +  + ]:       1444 :     for (const auto& ed : maps.get< tag::edge >()) {
     518                 :       1432 :       e.insert( { tk::cref_find(m_newnodes,ed[0]),
     519         [ +  - ]:       2864 :                   tk::cref_find(m_newnodes,ed[1]) } );
     520                 :            :     }
     521                 :            :     maps.get< tag::edge >() = std::move( e );
     522                 :            : 
     523                 :            :   }
     524                 :            : 
     525                 :            :   // Update boundary face-node connectivity with the reordered node IDs
     526                 :         18 :   tk::remap( m_triinpoel, m_newnodes );
     527                 :            : 
     528                 :            :   // Update boundary node lists with the reordered node IDs
     529         [ -  + ]:         18 :   for (auto& [ setid, nodes ] : m_bnode) tk::remap( nodes, m_newnodes );
     530                 :            : 
     531                 :            :   // Update mesh in Refiner after reordering
     532                 :         18 :   m_reorderRefiner.send();
     533                 :            : 
     534                 :            :   // Progress report to host
     535         [ -  + ]:         18 :   if ( g_inputdeck.get< tag::cmd, tag::feedback >() ) m_host.chreordered();
     536                 :            : 
     537                 :         18 :   createDiscWorkers();
     538                 :         18 : }
     539                 :            : 
     540                 :            : void
     541                 :         18 : Sorter::mesh( std::vector< std::size_t >& ginpoel,
     542                 :            :               tk::UnsMesh::CoordMap& coordmap,
     543                 :            :               std::vector< std::size_t >& triinpoel,
     544                 :            :               std::map< int, std::vector< std::size_t > >& bnode )
     545                 :            : // *****************************************************************************
     546                 :            : // Update mesh data we hold for whoever calls this function
     547                 :            : //! \param[in,out] ginpoel Mesh connectivity using global IDs
     548                 :            : //! \param[in,out] coordmap Map of mesh node coordinates
     549                 :            : //! \param[in,out] triinpoel Boundary face-node connectivity
     550                 :            : //! \param[in] bnode Node lists of side sets
     551                 :            : // *****************************************************************************
     552                 :            : {
     553                 :         18 :   ginpoel = m_ginpoel;
     554                 :            :   coordmap = m_coordmap;
     555                 :         18 :   triinpoel = m_triinpoel;
     556                 :            :   bnode = m_bnode;
     557                 :         18 : }
     558                 :            : 
     559                 :            : void
     560                 :       1943 : Sorter::createDiscWorkers()
     561                 :            : // *****************************************************************************
     562                 :            : //  Create Discretization chare array elements on this PE
     563                 :            : //! \details We create chare array elements by calling the insert() member
     564                 :            : //!   function, which allows specifying the PE on which the array element is
     565                 :            : //!   created. and we send each chare array element the chunk of mesh it will
     566                 :            : //!   operate on.
     567                 :            : // *****************************************************************************
     568                 :            : {
     569                 :       1943 :   std::vector< CProxy_Discretization > disc;
     570 [ +  + ][ +  - ]:       3900 :   for (auto& d : m_scheme) disc.push_back( d.disc() );
     571                 :            : 
     572                 :            :   // Create worker array element using Charm++ dynamic chare array element
     573                 :            :   // insertion: last arg: PE chare is created on. See also Charm++ manual, Sec.
     574                 :            :   // "Dynamic Insertion".
     575                 :            : 
     576         [ +  - ]:       1943 :   m_scheme[m_meshid].disc()[ thisIndex ].insert( m_meshid, disc,
     577                 :            :     m_scheme[m_meshid].ale(),
     578                 :       1943 :     m_scheme[m_meshid].conjugategradients(), m_host, m_meshwriter, m_coordmap,
     579         [ +  - ]:       1943 :     m_el, m_msum, m_bface, m_triinpoel, m_elemblockid, m_nchare );
     580                 :            : 
     581         [ +  - ]:       1943 :   contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     582                 :            :               m_cbs.get< tag::discinserted >() );
     583                 :       1943 : }
     584                 :            : 
     585                 :            : void
     586                 :       1943 : Sorter::createWorkers()
     587                 :            : // *****************************************************************************
     588                 :            : //  Create worker chare array element
     589                 :            : // *****************************************************************************
     590                 :            : {
     591                 :            :   // Make sure (bound) base is already created and accessible
     592                 :            :   Assert( m_scheme[m_meshid].disc()[thisIndex].ckLocal() != nullptr,
     593                 :            :           "About to pass nullptr" );
     594                 :            : 
     595                 :            :   // Create worker array element using Charm++ dynamic chare array element
     596                 :            :   // insertion: 1st arg: chare id, other args: Discretization's child ctor args.
     597                 :            :   // See also Charm++ manual, Sec. "Dynamic Insertion".
     598                 :            : 
     599                 :       3886 :   m_scheme[m_meshid].insert( thisIndex, m_scheme[m_meshid].disc(),
     600                 :       1943 :     m_scheme[m_meshid].ghosts(), m_bface, m_bnode, m_triinpoel );
     601                 :            : 
     602         [ -  + ]:       1943 :   if ( g_inputdeck.get< tag::cmd, tag::feedback >() ) m_host.chcreated();
     603                 :            : 
     604                 :       1943 :   contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     605                 :            :               m_cbs.get< tag::workinserted >() );
     606                 :            : 
     607                 :            :   // Free up some memory
     608                 :            :   tk::destroy( m_ginpoel );
     609                 :       1943 :   tk::destroy( m_coordmap );
     610                 :       1943 :   tk::destroy( m_bface );
     611                 :            :   tk::destroy( m_triinpoel );
     612                 :       1943 :   tk::destroy( m_elemblockid );
     613                 :       1943 :   tk::destroy( m_bnode );
     614                 :       1943 :   tk::destroy( m_nodeset );
     615                 :       1943 :   tk::destroy( m_nodech );
     616                 :       1943 :   tk::destroy( m_chnode );
     617                 :       1943 :   tk::destroy( m_msum );
     618                 :       1943 :   tk::destroy( m_reordcomm );
     619                 :       1943 :   tk::destroy( m_newnodes );
     620                 :            :   tk::destroy( m_reqnodes );
     621                 :       1943 : }
     622                 :            : 
     623                 :            : #include "NoWarning/sorter.def.h"

Generated by: LCOV version 1.14