Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Partition/ZoltanGeom.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2024 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief Interoperation with the Zoltan library's geometric partitioners
10 : : */
11 : : // *****************************************************************************
12 : :
13 : : #include <numeric>
14 : :
15 : : #include "Compiler.hpp"
16 : :
17 : : #if defined(__clang__)
18 : : #pragma clang diagnostic push
19 : : #pragma clang diagnostic ignored "-Wold-style-cast"
20 : : #pragma clang diagnostic ignored "-Wsuggest-override"
21 : : #pragma clang diagnostic ignored "-Wsuggest-destructor-override"
22 : : #pragma clang diagnostic ignored "-Wsign-conversion"
23 : : #pragma clang diagnostic ignored "-Wcast-align"
24 : : #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
25 : : #pragma clang diagnostic ignored "-Wdocumentation"
26 : : #pragma clang diagnostic ignored "-Wundef"
27 : : #pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
28 : : #elif defined(STRICT_GNUC)
29 : : #pragma GCC diagnostic push
30 : : #pragma GCC diagnostic ignored "-Wcast-function-type"
31 : : #endif
32 : :
33 : : #include "zoltan.h"
34 : :
35 : : #if defined(__clang__)
36 : : #pragma clang diagnostic pop
37 : : #elif defined(STRICT_GNUC)
38 : : #pragma GCC diagnostic pop
39 : : #endif
40 : :
41 : : #include "ZoltanGeom.hpp"
42 : : #include "ContainerUtil.hpp"
43 : :
44 : : namespace inciter {
45 : :
46 : : //! Zoltan mesh data structure
47 : : struct MESH_DATA {
48 : : int numMyElems;
49 : : ZOLTAN_ID_PTR myGlobalIDs;
50 : : tk::real* x;
51 : : tk::real* y;
52 : : tk::real* z;
53 : : };
54 : :
55 : : static int
56 : 1829 : get_number_of_objects( void* data, int* ierr ) {
57 : 1829 : MESH_DATA* mesh = static_cast< MESH_DATA* >( data );
58 : 1829 : *ierr = ZOLTAN_OK;
59 : 1829 : return mesh->numMyElems;
60 : : }
61 : :
62 : : static void
63 : 1175 : get_object_list( void* data, int /* sizeGID */, int /* sizeLID */,
64 : : ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
65 : : int /* wgt_dim */, float* /*obj_wgts */, int* ierr )
66 : : {
67 : 1175 : MESH_DATA* mesh = static_cast< MESH_DATA* >( data );
68 : 1175 : *ierr = ZOLTAN_OK;
69 [ + + ]: 1256771 : for (int i=0; i<mesh->numMyElems; ++i){
70 : 1255596 : globalID[i] = mesh->myGlobalIDs[i];
71 : 1255596 : localID[i] = static_cast< ZOLTAN_ID_TYPE >( i );
72 : : }
73 : 1175 : }
74 : :
75 : : static int
76 : 723 : get_num_geometry( void* /*data */, int* ierr ) {
77 : 723 : *ierr = ZOLTAN_OK;
78 : 723 : return 3;
79 : : }
80 : :
81 : : static void
82 : 723 : get_geometry_list( void* data, int sizeGID, int sizeLID,
83 : : int num_obj, ZOLTAN_ID_PTR /* globalID */,
84 : : ZOLTAN_ID_PTR /* localID */,
85 : : int num_dim, double* geom_vec, int* ierr )
86 : : {
87 : 723 : MESH_DATA *mesh = static_cast< MESH_DATA* >( data );
88 [ + - ][ + - ]: 723 : if ( (sizeGID != 1) || (sizeLID != 1) || (num_dim != 3)){
[ - + ]
89 : 0 : *ierr = ZOLTAN_FATAL;
90 : 0 : return;
91 : : }
92 : 723 : *ierr = ZOLTAN_OK;
93 [ + + ]: 731097 : for (int i=0; i<num_obj; ++i) {
94 : 730374 : geom_vec[3*i+0] = static_cast< tk::real >( mesh->x[i] );
95 : 730374 : geom_vec[3*i+1] = static_cast< tk::real >( mesh->y[i] );
96 : 730374 : geom_vec[3*i+2] = static_cast< tk::real >( mesh->z[i] );
97 : : }
98 : : }
99 : :
100 : : static
101 : : std::array< std::vector< tk::real >, 3 >
102 : 723 : centroids( const std::vector< std::size_t >& inpoel,
103 : : const std::array< std::vector< tk::real >, 3 >& coord )
104 : : // *****************************************************************************
105 : : // Compute element centroid coordinates
106 : : //! \param[in] inpoel Mesh connectivity with local ids
107 : : //! \param[in] coord Node coordinates
108 : : //! \return Centroids for all cells on this compute node
109 : : // *****************************************************************************
110 : : {
111 [ + - ][ - + ]: 723 : Assert( tk::uniquecopy(inpoel).size() == coord[0].size(), "Size mismatch" );
[ - - ][ - - ]
[ - - ]
112 : :
113 : 723 : const auto& x = coord[0];
114 : 723 : const auto& y = coord[1];
115 : 723 : const auto& z = coord[2];
116 : :
117 : : // Make room for element centroid coordinates
118 : 723 : std::array< std::vector< tk::real >, 3 > cent;
119 : 723 : auto& cx = cent[0];
120 : 723 : auto& cy = cent[1];
121 : 723 : auto& cz = cent[2];
122 : 723 : auto num = inpoel.size()/4;
123 [ + - ]: 723 : cx.resize( num );
124 [ + - ]: 723 : cy.resize( num );
125 [ + - ]: 723 : cz.resize( num );
126 : :
127 : : // Compute element centroids for mesh passed in
128 [ + + ]: 731097 : for (std::size_t e=0; e<num; ++e) {
129 : 730374 : auto A = inpoel[e*4+0];
130 : 730374 : auto B = inpoel[e*4+1];
131 : 730374 : auto C = inpoel[e*4+2];
132 : 730374 : auto D = inpoel[e*4+3];
133 : 730374 : cx[e] = (x[A] + x[B] + x[C] + x[D]) / 4.0;
134 : 730374 : cy[e] = (y[A] + y[B] + y[C] + y[D]) / 4.0;
135 : 730374 : cz[e] = (z[A] + z[B] + z[C] + z[D]) / 4.0;
136 : : }
137 : :
138 : 723 : return cent;
139 : 0 : }
140 : :
141 : : std::vector< std::size_t >
142 : 723 : geomPartMesh( const char* alg,
143 : : const std::vector< std::string >& zoltan_params,
144 : : const std::vector< std::size_t >& inpoel,
145 : : const std::array< std::vector< tk::real >, 3 >& coord,
146 : : int npart )
147 : : // *****************************************************************************
148 : : // Partition mesh using Zoltan with a geometric partitioner
149 : : //! \param[in] alg Partitioning algorithm to use
150 : : //! \param[in] zoltan_params Extra parameters pass to zoltan
151 : : //! \param[in] inpoel Mesh connectivity with local ids
152 : : //! \param[in] coord Node coordinates
153 : : //! \param[in] npart Number of desired partitions
154 : : //! \return Array of chare ownership IDs mapping elements to chares
155 : : //! \details This function uses Zoltan to partition the mesh in parallel.
156 : : //! It assumes that the mesh is distributed among all the MPI ranks.
157 : : // *****************************************************************************
158 : : {
159 : : float ver;
160 : : struct Zoltan_Struct *zz;
161 : : int changes, numGidEntries, numLidEntries, numImport, numExport;
162 : : ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids,
163 : : exportLocalGids;
164 : : int *importProcs, *importToPart, *exportProcs, *exportToPart;
165 : :
166 [ + - ]: 723 : std::vector< unsigned int > elemid( inpoel.size()/4 );
167 : 723 : std::iota( begin(elemid), end(elemid), 0 );
168 : :
169 : : MESH_DATA myMesh;
170 : 723 : myMesh.numMyElems = static_cast< int >( elemid.size() );
171 : 723 : myMesh.myGlobalIDs = const_cast< unsigned int* >( elemid.data() );
172 : :
173 [ + - ]: 723 : auto cent = centroids( inpoel, coord );
174 : 723 : myMesh.x = const_cast< tk::real* >( cent[0].data() );
175 : 723 : myMesh.y = const_cast< tk::real* >( cent[1].data() );
176 : 723 : myMesh.z = const_cast< tk::real* >( cent[2].data() );
177 : :
178 [ + - ]: 723 : Zoltan_Initialize( 0, nullptr, &ver );
179 : :
180 [ + - ]: 723 : zz = Zoltan_Create( MPI_COMM_WORLD );
181 : :
182 [ + - ]: 723 : Zoltan_Set_Param( zz, "DEBUG_LEVEL", "0" );
183 [ + - ]: 723 : Zoltan_Set_Param( zz, "LB_METHOD", alg );
184 [ + - ]: 723 : Zoltan_Set_Param( zz, "LB_APPROACH", "PARTITION" );
185 [ + - ]: 723 : Zoltan_Set_Param( zz, "NUM_GID_ENTRIES", "1" );
186 [ + - ]: 723 : Zoltan_Set_Param( zz, "NUM_LID_ENTRIES", "1" );
187 [ + - ]: 723 : Zoltan_Set_Param( zz, "OBJ_WEIGHT_DIM", "0" );
188 [ + - ]: 723 : Zoltan_Set_Param( zz, "RETURN_LISTS", "PART" );
189 [ + - ]: 723 : Zoltan_Set_Param( zz, "RCB_OUTPUT_LEVEL", "0" );
190 [ + - ]: 723 : Zoltan_Set_Param( zz, "AVERAGE_CUTS", "1" );
191 [ + - ]: 723 : Zoltan_Set_Param( zz, "NUM_GLOBAL_PARTS", std::to_string(npart).c_str() );
192 : :
193 [ - + ]: 723 : for (std::size_t i=0; i<zoltan_params.size()/2; ++i) {
194 : 0 : const auto p = zoltan_params.data() + i*2;
195 [ - - ]: 0 : Zoltan_Set_Param( zz, p[0].c_str(), p[1].c_str() );
196 : : }
197 : :
198 : : /* Query functions, to provide geometry to Zoltan */
199 : :
200 [ + - ]: 723 : Zoltan_Set_Num_Obj_Fn( zz, get_number_of_objects, &myMesh );
201 [ + - ]: 723 : Zoltan_Set_Obj_List_Fn( zz, get_object_list, &myMesh );
202 [ + - ]: 723 : Zoltan_Set_Num_Geom_Fn( zz, get_num_geometry, &myMesh );
203 [ + - ]: 723 : Zoltan_Set_Geom_Multi_Fn( zz, get_geometry_list, &myMesh );
204 : :
205 [ + - ]: 723 : Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
206 : : &changes, /* 1 if partitioning was changed, 0 otherwise */
207 : : &numGidEntries, /* Number of integers used for a global ID */
208 : : &numLidEntries, /* Number of integers used for a local ID */
209 : : &numImport, /* Number of vertices to be sent to me */
210 : : &importGlobalGids, /* Global IDs of vertices to be sent to me */
211 : : &importLocalGids, /* Local IDs of vertices to be sent to me */
212 : : &importProcs, /* Process rank for source of each incoming vertex */
213 : : &importToPart, /* New partition for each incoming vertex */
214 : : &numExport, /* Number of vertices I must send to other processes*/
215 : : &exportGlobalGids, /* Global IDs of the vertices I must send */
216 : : &exportLocalGids, /* Local IDs of the vertices I must send */
217 : : &exportProcs, /* Process to which I send each of the vertices */
218 : : &exportToPart); /* Partition to which each vertex will belong */
219 : :
220 [ - + ][ - - ]: 723 : Assert( numExport == static_cast< int >( elemid.size() ), "Size mismatch" );
[ - - ][ - - ]
221 : :
222 : : // Copy over array of chare IDs corresponding to the ownership of elements in
223 : : // our chunk of the mesh, i.e., the coloring or chare ids for the mesh
224 : : // elements we operate on.
225 [ + - ]: 723 : std::vector< std::size_t > chare( elemid.size() );
226 [ + + ]: 731097 : for (std::size_t p=0; p<static_cast<std::size_t>(numExport); ++p )
227 : 730374 : chare[ exportLocalGids[p] ] = static_cast< std::size_t >( exportToPart[p] );
228 : :
229 : : /******************************************************************
230 : : ** Free the arrays allocated by Zoltan_LB_Partition, and free
231 : : ** the storage allocated for the Zoltan structure.
232 : : ******************************************************************/
233 : :
234 [ + - ]: 723 : Zoltan_LB_Free_Part( &importGlobalGids, &importLocalGids,
235 : : &importProcs, &importToPart );
236 [ + - ]: 723 : Zoltan_LB_Free_Part( &exportGlobalGids, &exportLocalGids,
237 : : &exportProcs, &exportToPart );
238 : :
239 [ + - ]: 723 : Zoltan_Destroy( &zz );
240 : :
241 : 1446 : return chare;
242 : 723 : }
243 : :
244 : : } // inciter::
|