zoltanDecomp.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "zoltanDecomp.H"
27 #include "globalIndex.H"
28 #include "PstreamGlobals.H"
30 
31 #include "sigFpe.H"
32 #ifdef LINUX_GNUC
33  #ifndef __USE_GNU
34  #define __USE_GNU
35  #endif
36  #include <fenv.h>
37 #endif
38 
39 #include "zoltan.h"
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45  defineTypeNameAndDebug(zoltanDecomp, 0);
46 
48  (
49  decompositionMethod,
50  zoltanDecomp,
51  distributor
52  );
53 }
54 
55 
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 
58 static int get_number_of_vertices(void *data, int *ierr)
59 {
60  const Foam::pointField& points =
61  *static_cast<const Foam::pointField*>(data);
62 
63  *ierr = ZOLTAN_OK;
64 
65  return points.size();
66 }
67 
68 
69 static void get_vertex_list
70 (
71  void* data,
72  int nGID,
73  int nLID,
74  ZOLTAN_ID_PTR globalIDs,
75  ZOLTAN_ID_PTR localIDs,
76  int wgt_dim,
77  float* obj_wgts,
78  int* ierr
79 )
80 {
82  vertexData =
83  *static_cast
84  <
85  const Foam::Tuple2
86  <
87  const Foam::pointField&,
88  const Foam::scalarField&
89  >*
90  >(data);
91 
92  const Foam::pointField& points = vertexData.first();
93  const Foam::scalarField& weights = vertexData.second();
94 
95  if (wgt_dim != weights.size()/points.size())
96  {
97  *ierr = ZOLTAN_FATAL;
98  return;
99  }
100 
101  Foam::globalIndex globalMap(points.size());
102 
103  for (Foam::label i=0; i<points.size(); i++)
104  {
105  localIDs[i] = i;
106  globalIDs[i] = globalMap.toGlobal(i);
107 
108  for(int j=0; j<wgt_dim; j++)
109  {
110  obj_wgts[wgt_dim*i + j] = weights[wgt_dim*i + j];
111  }
112  }
113 
114  *ierr = ZOLTAN_OK;
115 }
116 
117 
118 static int get_mesh_dim(void* data, int* ierr)
119 {
120  return 3;
121 }
122 
123 
124 static void get_geom_list
125 (
126  void* data,
127  int nGID,
128  int nLID,
129  int nPoints,
130  ZOLTAN_ID_PTR globalIDs,
131  ZOLTAN_ID_PTR localIDs,
132  int nDim,
133  double* vertices,
134  int* ierr
135 )
136 {
137  const Foam::pointField& points =
138  *static_cast<const Foam::pointField*>(data);
139 
140  if
141  (
142  (nGID != 1)
143  || (nLID != 1)
144  || (nPoints != points.size())
145  || (nDim != 3)
146  )
147  {
148  *ierr = ZOLTAN_FATAL;
149  return;
150  }
151 
152  double* p = vertices;
153 
154  for (Foam::label celli=0; celli<nPoints; celli++)
155  {
156  const Foam::point& pt = points[celli];
157 
158  for (Foam::direction cmpt=0; cmpt<Foam::vector::nComponents; cmpt++)
159  {
160  *p++ = pt[cmpt];
161  }
162  }
163 
164  *ierr = ZOLTAN_OK;
165 }
166 
167 
168 static void get_num_edges_list
169 (
170  void* data,
171  int nGID,
172  int nLID,
173  int nPoints,
174  ZOLTAN_ID_PTR globalIDs,
175  ZOLTAN_ID_PTR localIDs,
176  int* numEdges,
177  int* ierr
178 )
179 {
180  const Foam::CompactListList<Foam::label>& adjacency =
181  *static_cast<const Foam::CompactListList<Foam::label>*>(data);
182 
183  Foam::labelList sizes(adjacency.sizes());
184 
185  if ((nGID != 1) || (nLID != 1) || (nPoints != sizes.size()))
186  {
187  *ierr = ZOLTAN_FATAL;
188  return;
189  }
190 
191  for (Foam::label i=0; i<nPoints; i++)
192  {
193  numEdges[i] = sizes[i];
194  }
195 
196  *ierr = ZOLTAN_OK;
197 }
198 
199 
200 static void get_edge_list
201 (
202  void* data,
203  int nGID,
204  int nLID,
205  int nPoints,
206  ZOLTAN_ID_PTR globalIDs,
207  ZOLTAN_ID_PTR localIDs,
208  int* num_edges,
209  ZOLTAN_ID_PTR nborGID,
210  int* nborProc,
211  int wgt_dim,
212  float* ewgts,
213  int* ierr
214 )
215 {
216  const Foam::CompactListList<Foam::label>& adjacency =
217  *static_cast<const Foam::CompactListList<Foam::label>*>(data);
218 
219  const Foam::labelList& m(adjacency.m());
220 
221  Foam::globalIndex globalMap(nPoints);
222 
223  if
224  (
225  (nGID != 1)
226  || (nLID != 1)
227  )
228  {
229  *ierr = ZOLTAN_FATAL;
230  return;
231  }
232 
233  forAll(m, i)
234  {
235  nborGID[i] = m[i];
236  nborProc[i] = globalMap.whichProcID(m[i]);
237  }
238 
239  *ierr = ZOLTAN_OK;
240 }
241 
242 
243 Foam::label Foam::zoltanDecomp::decompose
244 (
245  const CompactListList<label>& adjacency,
246  const pointField& points,
247  const scalarField& pWeights,
248  List<label>& finalDecomp
249 ) const
250 {
251  stringList args(1);
252  args[0] = "zoltanDecomp";
253 
254  int argc = args.size();
255  char* argv[argc];
256  for (label i = 0; i < argc; i++)
257  {
258  argv[i] = strdup(args[i].c_str());
259  }
260 
261  float ver;
262  int rc = Zoltan_Initialize(argc, argv, &ver);
263 
264  if (rc != ZOLTAN_OK)
265  {
267  << "Failed initialising Zoltan" << exit(FatalError);
268  }
269 
270  struct Zoltan_Struct *zz = Zoltan_Create(PstreamGlobals::MPI_COMM_FOAM);
271 
272  const int nWeights = pWeights.size()/points.size();
273 
274  // Set internal parameters
275  Zoltan_Set_Param(zz, "return_lists", "export");
276  Zoltan_Set_Param(zz, "obj_weight_dim", name(nWeights).c_str());
277  Zoltan_Set_Param(zz, "edge_weight_dim", "0");
278 
279  // General default parameters
280  Zoltan_Set_Param(zz, "debug_level", "0");
281  Zoltan_Set_Param(zz, "imbalance_tol", "1.05");
282 
283  // Set default method parameters
284  Zoltan_Set_Param(zz, "lb_method", "graph");
285  Zoltan_Set_Param(zz, "lb_approach", "repartition");
286 
287  if (decompositionDict_.found("zoltanCoeffs"))
288  {
289  const dictionary& coeffsDict_ =
290  decompositionDict_.subDict("zoltanCoeffs");
291 
292  forAllConstIter(IDLList<entry>, coeffsDict_, iter)
293  {
294  if (!iter().isDict())
295  {
296  const word& key = iter().keyword();
297  const word value(iter().stream());
298 
299  if (debug)
300  {
301  Info<< typeName << " : setting parameter " << key
302  << " to " << value << endl;
303  }
304 
305  Zoltan_Set_Param(zz, key.c_str(), value.c_str());
306  }
307  }
308  }
309 
310  void* pointsPtr = &const_cast<pointField&>(points);
311  Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, pointsPtr);
312 
313  Tuple2<const pointField&, const scalarField&> vertexData(points, pWeights);
314  Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &vertexData);
315 
316  // Callbacks for geometry
317  Zoltan_Set_Num_Geom_Fn(zz, get_mesh_dim, pointsPtr);
318  Zoltan_Set_Geom_Multi_Fn(zz, get_geom_list, pointsPtr);
319 
320  // Callbacks for connectivity
321  void* adjacencyPtr = &const_cast<CompactListList<label>&>(adjacency);
322  Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, adjacencyPtr);
323  Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, adjacencyPtr);
324 
325  int changed, num_imp, num_exp, *imp_procs, *exp_procs;
326  int *imp_to_part, *exp_to_part;
327  int num_gid_entries, num_lid_entries;
328  ZOLTAN_ID_PTR imp_global_ids, exp_global_ids;
329  ZOLTAN_ID_PTR imp_local_ids, exp_local_ids;
330 
331  // Switch off FPU error trapping to work around divide-by-zero bug
332  // in the Zoltan graph and hypergraph methods
333  #ifdef FE_NOMASK_ENV
334  int oldExcepts = fedisableexcept
335  (
336  FE_DIVBYZERO
337  | FE_INVALID
338  | FE_OVERFLOW
339  );
340  #endif
341 
342  // Perform load balancing
343  Zoltan_LB_Partition
344  (
345  zz,
346  &changed,
347  &num_gid_entries,
348  &num_lid_entries,
349  &num_imp,
350  &imp_global_ids,
351  &imp_local_ids,
352  &imp_procs,
353  &imp_to_part,
354  &num_exp,
355  &exp_global_ids,
356  &exp_local_ids,
357  &exp_procs,
358  &exp_to_part
359  );
360 
361  // Reinstate FPU error trapping
362  #ifdef FE_NOMASK_ENV
363  feenableexcept(oldExcepts);
364  #endif
365 
366  if (debug && changed)
367  {
368  Pout << "Zoltan number to move " << changed << " " << num_exp << endl;
369  }
370 
371  finalDecomp.setSize(points.size());
372  finalDecomp = Pstream::myProcNo();
373 
374  if (changed)
375  {
376  for(int i=0; i<num_exp; i++)
377  {
378  finalDecomp[exp_local_ids[i]] = exp_procs[i];
379  }
380  }
381 
382  // Free memory allocated for load-balancing results by Zoltan library
383 
384  Zoltan_LB_Free_Part
385  (
386  &imp_global_ids,
387  &imp_local_ids,
388  &imp_procs,
389  &imp_to_part
390  );
391 
392  Zoltan_LB_Free_Part
393  (
394  &exp_global_ids,
395  &exp_local_ids,
396  &exp_procs,
397  &exp_to_part
398  );
399 
400  Zoltan_Destroy(&zz);
401 
402  return 0;
403 }
404 
405 
406 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
407 
409 :
410  decompositionMethod(decompositionDict)
411 {}
412 
413 
414 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
415 
416 Foam::labelList Foam::zoltanDecomp::decompose
417 (
418  const polyMesh& mesh,
419  const pointField& cellCentres,
420  const scalarField& cellWeights
421 )
422 {
423  if (cellCentres.size() != mesh.nCells())
424  {
426  << "Can use this decomposition method only for the whole mesh"
427  << endl
428  << "and supply one coordinate (cellCentre) for every cell." << endl
429  << "The number of coordinates " << cellCentres.size() << endl
430  << "The number of cells in the mesh " << mesh.nCells()
431  << exit(FatalError);
432  }
433 
434 
435  // Convert mesh.cellCells() into compressed format
436  CompactListList<label> cellCells;
438  (
439  mesh,
440  identity(mesh.nCells()),
441  mesh.nCells(),
442  true,
443  cellCells
444  );
445 
446  // Decompose using default weights
447  List<label> finalDecomp;
448  decompose
449  (
450  cellCells,
451  cellCentres,
452  cellWeights,
453  finalDecomp
454  );
455 
456  // Copy back to labelList
457  labelList decomp(cellCentres.size());
458  forAll(decomp, i)
459  {
460  decomp[i] = finalDecomp[i];
461  }
462  return decomp;
463 }
464 
465 
466 Foam::labelList Foam::zoltanDecomp::decompose
467 (
468  const polyMesh& mesh,
469  const labelList& agglom,
470  const pointField& agglomPoints,
471  const scalarField& pointWeights
472 )
473 {
474  if (agglom.size() != mesh.nCells())
475  {
477  << "Size of cell-to-coarse map " << agglom.size()
478  << " differs from number of cells in mesh " << mesh.nCells()
479  << exit(FatalError);
480  }
481 
482  // Convert agglom into compressed format
483  CompactListList<label> cellCells;
485  (
486  mesh,
487  agglom,
488  agglomPoints.size(),
489  true,
490  cellCells
491  );
492 
493  // Decompose using weights
494  List<label> finalDecomp;
495  decompose
496  (
497  cellCells,
498  agglomPoints,
499  pointWeights,
500  finalDecomp
501  );
502 
503  // Rework back into decomposition for original mesh
504  labelList fineDistribution(agglom.size());
505 
506  forAll(fineDistribution, i)
507  {
508  fineDistribution[i] = finalDecomp[agglom[i]];
509  }
510 
511  return fineDistribution;
512 }
513 
514 
515 Foam::labelList Foam::zoltanDecomp::decompose
516 (
517  const labelListList& globalPointPoints,
518  const pointField& points,
519  const scalarField& pWeights
520 )
521 {
522  if (points.size() != globalPointPoints.size())
523  {
525  << "Inconsistent number of cells (" << globalPointPoints.size()
526  << ") and number of cell centres (" << points.size()
527  << ")." << exit(FatalError);
528  }
529 
530 
531  // Convert globalPointPoints into compressed format
532  CompactListList<label> pointPoints(globalPointPoints);
533 
534  // Decompose using weights
535  List<label> finalDecomp;
536  decompose
537  (
538  pointPoints,
539  points,
540  pWeights,
541  finalDecomp
542  );
543 
544  return finalDecomp;
545 }
546 
547 
548 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
const UList< T > & m() const
Return the packed matrix of data.
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:65
const Type1 & first() const
Return first.
Definition: Tuple2.H:116
static void get_geom_list(void *data, int nGID, int nLID, int nPoints, ZOLTAN_ID_PTR globalIDs, ZOLTAN_ID_PTR localIDs, int nDim, double *vertices, int *ierr)
Definition: zoltanDecomp.C:125
uint8_t direction
Definition: direction.H:45
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
label nCells() const
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Holds information (coordinate and normal) regarding nearest wall point.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Macros for easy insertion into run-time selection tables.
static void calcCellCells(const polyMesh &mesh, const labelList &agglom, const label nLocalCoarse, const bool global, CompactListList< label > &cellCells)
Helper: determine (local or global) cellCells from mesh.
pointField vertices(const blockVertexList &bvl)
zoltanDecomp(const dictionary &decompositionDict)
Construct given the decomposition dictionary and mesh.
Definition: zoltanDecomp.C:408
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
static const direction nComponents
Number of components in this vector space.
Definition: VectorSpace.H:99
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
static int get_number_of_vertices(void *data, int *ierr)
Definition: zoltanDecomp.C:58
labelList sizes() const
Return sizes (to be used e.g. for construction)
const pointField & points
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static void get_num_edges_list(void *data, int nGID, int nLID, int nPoints, ZOLTAN_ID_PTR globalIDs, ZOLTAN_ID_PTR localIDs, int *numEdges, int *ierr)
Definition: zoltanDecomp.C:169
Abstract base class for decomposition.
A packed storage unstructured matrix of objects of type <T> using an offset table for access...
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
defineTypeNameAndDebug(combustionModel, 0)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
static int get_mesh_dim(void *data, int *ierr)
Definition: zoltanDecomp.C:118
List< string > stringList
A List of strings.
Definition: stringList.H:50
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
messageStream Info
const Type2 & second() const
Return second.
Definition: Tuple2.H:128
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
volScalarField & p
Foam::argList args(argc, argv)
static void get_vertex_list(void *data, int nGID, int nLID, ZOLTAN_ID_PTR globalIDs, ZOLTAN_ID_PTR localIDs, int wgt_dim, float *obj_wgts, int *ierr)
Definition: zoltanDecomp.C:70
Namespace for OpenFOAM.
static void get_edge_list(void *data, int nGID, int nLID, int nPoints, ZOLTAN_ID_PTR globalIDs, ZOLTAN_ID_PTR localIDs, int *num_edges, ZOLTAN_ID_PTR nborGID, int *nborProc, int wgt_dim, float *ewgts, int *ierr)
Definition: zoltanDecomp.C:201