Xyst test code coverage report
Current view: top level - Partition - ZoltanGraph.cpp (source / functions) Coverage Total Hit
Commit: 1fb74642dd9d7732b67f32dec2f2762e238d3fa7 Lines: 98.1 % 103 101
Test Date: 2025-08-13 22:46:33 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 52.7 % 110 58

             Branch data     Line data    Source code
       1                 :             : // *****************************************************************************
       2                 :             : /*!
       3                 :             :   \file      src/Partition/ZoltanGraph.cpp
       4                 :             :   \copyright 2012-2015 J. Bakosi,
       5                 :             :              2016-2018 Los Alamos National Security, LLC.,
       6                 :             :              2019-2021 Triad National Security, LLC.,
       7                 :             :              2022-2025 J. Bakosi
       8                 :             :              All rights reserved. See the LICENSE file for details.
       9                 :             :   \brief     Interoperation with the Zoltan library's graph partitioners.
      10                 :             : */
      11                 :             : // *****************************************************************************
      12                 :             : 
      13                 :             : #include "Compiler.hpp"
      14                 :             : 
      15                 :             : #if defined(__clang__)
      16                 :             :   #pragma clang diagnostic push
      17                 :             : #elif defined(STRICT_GNUC)
      18                 :             :   #pragma GCC diagnostic push
      19                 :             :   #pragma GCC diagnostic ignored "-Wcast-function-type"
      20                 :             : #endif
      21                 :             : 
      22                 :             : #include "zoltan.h"
      23                 :             : 
      24                 :             : #if defined(__clang__)
      25                 :             :   #pragma clang diagnostic pop
      26                 :             : #elif defined(STRICT_GNUC)
      27                 :             :   #pragma GCC diagnostic pop
      28                 :             : #endif
      29                 :             : 
      30                 :             : #include "ZoltanGraph.hpp"
      31                 :             : #include "ContainerUtil.hpp"
      32                 :             : #include "DerivedData.hpp"
      33                 :             : #include "Reorder.hpp"
      34                 :             : 
      35                 :             : namespace inciter {
      36                 :             : 
      37                 :             : //! Zoltan mesh data structure
      38                 :             : struct MESH_DATA {
      39                 :             :   int numMyVertices;            //!< number of vertices that I own initially
      40                 :             :   ZOLTAN_ID_TYPE* vtxGID;       //!< global ID of these vertices
      41                 :             :   int numMyHEdges;              //!< number of my hyperedges
      42                 :             :   int numAllNbors;              //!< number of vertices in my hyperedges
      43                 :             :   ZOLTAN_ID_TYPE *edgeGID;      //!< global ID of each of my hyperedges
      44                 :             :   int *nborIndex;               //!< index into nborGID array of edge ids
      45                 :             :   ZOLTAN_ID_TYPE *nborGID;      //!< array of edge ids
      46                 :             : };
      47                 :             : 
      48                 :             : static int
      49                 :          42 : get_number_of_objects( void* data, int* ierr ) {
      50                 :          42 :   MESH_DATA* mesh = static_cast< MESH_DATA* >( data );
      51                 :          42 :   *ierr = ZOLTAN_OK;
      52                 :          42 :   return mesh->numMyVertices;
      53                 :             : }
      54                 :             : 
      55                 :             : static void
      56                 :          28 : get_object_list( void *data, int /* sizeGID */, int /* sizeLID */,
      57                 :             :                  ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
      58                 :             :                  int /* wgt_dim */, float* /*obj_wgts */, int* ierr )
      59                 :             : {
      60                 :          28 :   MESH_DATA* mesh = static_cast< MESH_DATA* >( data );
      61                 :          28 :   *ierr = ZOLTAN_OK;
      62         [ +  + ]:       55803 :   for (int i=0; i<mesh->numMyVertices; ++i){
      63                 :       55775 :     globalID[i] = mesh->vtxGID[i];
      64                 :       55775 :     localID[i] = static_cast< ZOLTAN_ID_TYPE >( i );
      65                 :             :   }
      66                 :          28 : }
      67                 :             : 
      68                 :             : static void
      69                 :          19 : get_hypergraph_size( void* data, int* num_lists, int* num_nonzeros,
      70                 :             :                      int* format, int* ierr )
      71                 :             : {
      72                 :          19 :   MESH_DATA* hg = static_cast< MESH_DATA* >( data );
      73                 :          19 :   *ierr = ZOLTAN_OK;
      74                 :          19 :   *num_lists = hg->numMyHEdges;
      75                 :          19 :   *num_nonzeros = hg->numAllNbors;
      76                 :          19 :   *format = ZOLTAN_COMPRESSED_EDGE;
      77                 :          19 : }
      78                 :             : 
      79                 :             : static void
      80                 :          19 : get_hypergraph( void* data, int /* sizeGID */, int num_edges, int num_nonzeros,
      81                 :             :                 int format, ZOLTAN_ID_PTR edgeGID, int* vtxPtr,
      82                 :             :                 ZOLTAN_ID_PTR vtxGID, int* ierr )
      83                 :             : {
      84                 :          19 :   MESH_DATA* hg = static_cast< MESH_DATA* >( data );
      85                 :          19 :   *ierr = ZOLTAN_OK;
      86                 :             : 
      87         [ +  - ]:          19 :   if ( (num_edges != hg->numMyHEdges) ||
      88 [ +  - ][ -  + ]:          19 :        (num_nonzeros != hg->numAllNbors) ||
      89                 :             :        (format != ZOLTAN_COMPRESSED_EDGE) )
      90                 :             :   {
      91                 :           0 :     *ierr = ZOLTAN_FATAL;
      92                 :           0 :     return;
      93                 :             :   }
      94                 :             : 
      95         [ +  + ]:       28968 :   for (int i=0; i<num_edges; ++i) {
      96                 :       28949 :     edgeGID[i] = hg->edgeGID[i];
      97                 :       28949 :     vtxPtr[i] = hg->nborIndex[i];
      98                 :             :   }
      99                 :             : 
     100         [ +  + ]:      395072 :   for (int i=0; i<num_nonzeros; ++i) vtxGID[i] = hg->nborGID[i];
     101                 :             : }
     102                 :             : 
     103                 :             : static void
     104                 :          19 : createHyperGraph( const std::vector< std::size_t >& gid,
     105                 :             :                   const std::unordered_map< std::size_t,
     106                 :             :                                             std::vector< std::size_t > >& graph,
     107                 :             :                   MESH_DATA& hg )
     108                 :             : // *****************************************************************************
     109                 :             : //  Create hypergraph data structure for Zoltan
     110                 :             : //! \param[in] gid Global node ids
     111                 :             : //! \param[in] graph Aggregated mesh graph point connectivity
     112                 :             : //! \param[inout] hg Hypergraph data structure to fill
     113                 :             : //! \return Number of hyperedges in graph (number of nodes in our mesh chunk)
     114                 :             : // *****************************************************************************
     115                 :             : {
     116                 :             :   // Get number of points from graph
     117                 :          19 :   const auto npoin = graph.size();
     118                 :             : 
     119                 :             :   // Create hypergraph data structure based on mesh graph
     120                 :          19 :   hg.numMyVertices = static_cast< int >( npoin );
     121                 :          19 :   hg.numMyHEdges = hg.numMyVertices;
     122                 :          19 :   hg.vtxGID = static_cast< ZOLTAN_ID_PTR >(
     123                 :          19 :                 malloc(sizeof(ZOLTAN_ID_TYPE) * npoin) );
     124                 :          19 :   hg.edgeGID = static_cast< ZOLTAN_ID_PTR >(
     125                 :          19 :                  malloc(sizeof(ZOLTAN_ID_TYPE) * npoin) );
     126                 :          19 :   hg.nborIndex = static_cast< int* >( malloc(sizeof(int) * (npoin+1)) );
     127                 :             : 
     128                 :             :   // generate linked vectors for points surrounding points and their indices
     129                 :          19 :   std::pair< std::vector< std::size_t >, std::vector< std::size_t > > psup;
     130                 :          19 :   auto& psup1 = psup.first;
     131                 :          19 :   auto& psup2 = psup.second;
     132         [ +  - ]:          19 :   psup1.resize( 1, 0 );
     133         [ +  - ]:          19 :   psup2.resize( 1, 0 );
     134                 :             : 
     135                 :          19 :   std::vector< std::size_t > gp;
     136         [ +  + ]:       57857 :   for (std::size_t p=0; p<gid.size(); ++p) {
     137         [ +  - ]:       57838 :     auto i = graph.find( gid[p] );
     138         [ +  + ]:       57838 :     if (i == end(graph)) continue;
     139         [ +  - ]:       28949 :     gp.push_back( gid[p] );
     140                 :       28949 :     const auto& n = i->second;
     141         [ +  - ]:       28949 :     psup2.push_back( psup2.back() + n.size() );
     142         [ +  - ]:       28949 :     psup1.insert( end(psup1), begin(n), end(n) );
     143                 :             :   }
     144                 :             : 
     145 [ -  + ][ -  - ]:          19 :   Assert( gp.size() == graph.size(), "Size mismatch" );
         [ -  - ][ -  - ]
     146                 :             : 
     147                 :             :   // Compute sum of number of vertices of hyperedges and allocate memory
     148                 :          19 :   auto nedge = psup.first.size() - 1 + npoin;
     149                 :          19 :   hg.numAllNbors = static_cast< int >( nedge );
     150                 :          19 :   hg.nborGID = static_cast< ZOLTAN_ID_PTR >(
     151                 :          19 :                  malloc(sizeof(ZOLTAN_ID_TYPE) * nedge) );
     152                 :             : 
     153                 :             :    // Fill up hypergraph edge ids and their indices
     154                 :          19 :    hg.nborIndex[0] = 0;
     155         [ +  + ]:       28968 :    for (std::size_t p=0; p<npoin; ++p) {
     156                 :       28949 :      auto g = static_cast< ZOLTAN_ID_TYPE >( gp[p] );
     157                 :       28949 :      hg.vtxGID[p] = hg.edgeGID[p] = hg.nborGID[ hg.nborIndex[p] ] = g;
     158                 :       28949 :      int j = 1;
     159         [ +  + ]:      395053 :      for (auto i=psup2[p]+1; i<=psup2[p+1]; ++i, ++j) {
     160                 :      366104 :        hg.nborGID[ hg.nborIndex[p] + j ] =
     161                 :      366104 :          static_cast< ZOLTAN_ID_TYPE >( psup1[i] );
     162                 :             :      }
     163                 :       28949 :      hg.nborIndex[p+1] = hg.nborIndex[p] + j;
     164                 :             :    }
     165                 :          19 : }
     166                 :             : 
     167                 :             : std::unordered_map< std::size_t, std::size_t >
     168                 :          19 : graphPartMesh( const std::vector< std::size_t >& ginpoel,
     169                 :             :                const std::unordered_map< std::size_t,
     170                 :             :                                 std::vector< std::size_t > >& graph,
     171                 :             :                const std::vector< std::string >& zoltan_params,
     172                 :             :                int npart )
     173                 :             : // *****************************************************************************
     174                 :             : //  Partition mesh using Zoltan with a geometric partitioner
     175                 :             : //! \param[in] ginpoel Mesh connectivity with global ids
     176                 :             : //! \param[in] graph Mesh graph point connectivity
     177                 :             : //! \param[in] zoltan_params Extra parameters pass to zoltan
     178                 :             : //! \param[in] npart Number of desired partitions
     179                 :             : //! \return Array of chare ownership IDs mapping points owned to chares
     180                 :             : //! \details This function uses Zoltan to partition the mesh in parallel.
     181                 :             : //!   It assumes that the mesh is distributed among all the MPI ranks.
     182                 :             : // *****************************************************************************
     183                 :             : {
     184                 :             :   float ver;
     185                 :             :   struct Zoltan_Struct *zz;
     186                 :             :   int changes, numGidEntries, numLidEntries, numImport, numExport;
     187                 :             :   ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids,
     188                 :             :                 exportLocalGids;
     189                 :             :   int *importProcs, *importToPart, *exportProcs, *exportToPart;
     190                 :             : 
     191         [ +  - ]:          19 :   Zoltan_Initialize( 0, nullptr, &ver );
     192                 :             : 
     193         [ +  - ]:          19 :   zz = Zoltan_Create( MPI_COMM_WORLD );
     194                 :             : 
     195         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "DEBUG_LEVEL", "0" );
     196         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "PHG_OUTPUT_LEVEL", "0" );
     197         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "LB_METHOD", "HYPERGRAPH" );
     198         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "HYPERGRAPH_PACKAGE", "PHG" );
     199         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "LB_APPROACH", "PARTITION" );
     200         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "NUM_GID_ENTRIES", "1" );
     201         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "NUM_LID_ENTRIES", "1" );
     202         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "OBJ_WEIGHT_DIM", "0" );
     203         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "EDGE_WEIGHT_DIM", "0" );
     204         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "RETURN_LISTS", "PART" );
     205         [ +  - ]:          19 :   Zoltan_Set_Param( zz, "NUM_GLOBAL_PARTS", std::to_string(npart).c_str() );
     206                 :             : 
     207         [ +  + ]:          29 :   for (std::size_t i=0; i<zoltan_params.size()/2; ++i) {
     208                 :          10 :     const auto p = zoltan_params.data() + i*2;
     209         [ +  - ]:          10 :     Zoltan_Set_Param( zz, p[0].c_str(), p[1].c_str() );
     210                 :             :   }
     211                 :             : 
     212                 :             :   // Generate element connectivity storing local node ids
     213         [ +  - ]:          19 :   const auto& [ inpoel, gid, lid ] = tk::global2local( ginpoel );
     214                 :             : 
     215                 :             :   MESH_DATA myMesh;
     216         [ +  - ]:          19 :   createHyperGraph( gid, graph, myMesh );
     217                 :             : 
     218                 :             :   // Set Zoltan query functions
     219         [ +  - ]:          19 :   Zoltan_Set_Num_Obj_Fn( zz, get_number_of_objects, &myMesh );
     220         [ +  - ]:          19 :   Zoltan_Set_Obj_List_Fn( zz, get_object_list, &myMesh );
     221         [ +  - ]:          19 :   Zoltan_Set_HG_Size_CS_Fn( zz, get_hypergraph_size, &myMesh );
     222         [ +  - ]:          19 :   Zoltan_Set_HG_CS_Fn( zz, get_hypergraph, &myMesh );
     223                 :             :   //Zoltan_Set_HG_Size_CS_Fn( zz, get_hypergraph_size, &myMesh );
     224                 :             : 
     225         [ +  - ]:          19 :   Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
     226                 :             :         &changes,        /* 1 if partitioning was changed, 0 otherwise */
     227                 :             :         &numGidEntries,  /* Number of integers used for a global ID */
     228                 :             :         &numLidEntries,  /* Number of integers used for a local ID */
     229                 :             :         &numImport,      /* Number of vertices to be sent to me */
     230                 :             :         &importGlobalGids,  /* Global IDs of vertices to be sent to me */
     231                 :             :         &importLocalGids,   /* Local IDs of vertices to be sent to me */
     232                 :             :         &importProcs,    /* Process rank for source of each incoming vertex */
     233                 :             :         &importToPart,   /* New partition for each incoming vertex */
     234                 :             :         &numExport,      /* Number of vertices I must send to other processes*/
     235                 :             :         &exportGlobalGids,  /* Global IDs of the vertices I must send */
     236                 :             :         &exportLocalGids,   /* Local IDs of the vertices I must send */
     237                 :             :         &exportProcs,    /* Process to which I send each of the vertices */
     238                 :             :         &exportToPart);  /* Partition to which each vertex will belong */
     239                 :             : 
     240 [ -  + ][ -  - ]:          19 :   Assert( numExport == static_cast< int >( graph.size() ), "Size mismatch" );
         [ -  - ][ -  - ]
     241                 :             : 
     242         [ +  - ]:          19 :   if (myMesh.numMyVertices > 0) free( myMesh.vtxGID );
     243         [ +  - ]:          19 :   if (myMesh.numMyHEdges > 0) free( myMesh.edgeGID );
     244         [ +  - ]:          19 :   if (myMesh.numMyHEdges >= 0) free( myMesh.nborIndex );
     245         [ +  - ]:          19 :   if (myMesh.numAllNbors > 0) free( myMesh.nborGID );
     246                 :             : 
     247                 :             :   // Copy over array of chare IDs corresponding to the ownership of vertices in
     248                 :             :   // our chunk of the mesh, i.e., the coloring or chare ids for the mesh nodes
     249                 :             :   // we operate on.
     250                 :          19 :   std::unordered_map< std::size_t, std::size_t > chp;
     251         [ +  + ]:       28968 :   for (std::size_t p=0; p<static_cast<std::size_t>(numExport); ++p ) {
     252         [ +  - ]:       28949 :     chp[ exportGlobalGids[p] ] = static_cast< std::size_t >( exportToPart[p] );
     253                 :             :   }
     254                 :             : 
     255                 :             :   // Free the arrays allocated by Zoltan_LB_Partition
     256         [ +  - ]:          19 :   Zoltan_LB_Free_Part( &importGlobalGids, &importLocalGids,
     257                 :             :                        &importProcs, &importToPart );
     258         [ +  - ]:          19 :   Zoltan_LB_Free_Part( &exportGlobalGids, &exportLocalGids,
     259                 :             :                        &exportProcs, &exportToPart );
     260                 :             :   // Fee the storage allocated for the Zoltan structure
     261         [ +  - ]:          19 :   Zoltan_Destroy( &zz );
     262                 :             : 
     263                 :          19 :   return chp;
     264                 :          19 : }
     265                 :             : 
     266                 :             : } // inciter::
        

Generated by: LCOV version 2.0-1