scotchDecomp.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "scotchDecomp.H"
31 #include "floatScalar.H"
32 #include "Time.H"
33 #include "OFstream.H"
34 
35 // Probably not needed, but in case we pickup a ptscotch.h ...
36 #define MPICH_SKIP_MPICXX
37 #define OMPI_SKIP_MPICXX
38 
39 #include "scotch.h"
40 
41 // Hack: scotch generates floating point errors so need to switch off error
42 // trapping!
43 #ifdef __GLIBC__
44  #ifndef _GNU_SOURCE
45  #define _GNU_SOURCE
46  #endif
47  #include <fenv.h>
48 #endif
49 
50 // Provide a clear error message if we have a size mismatch
51 static_assert
52 (
53  sizeof(Foam::label) == sizeof(SCOTCH_Num),
54  "sizeof(Foam::label) == sizeof(SCOTCH_Num), check your scotch headers"
55 );
56 
57 
58 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
59 
60 namespace Foam
61 {
62  defineTypeNameAndDebug(scotchDecomp, 0);
63 
65  (
66  decompositionMethod,
67  scotchDecomp,
68  dictionary
69  );
70 
72  (
73  decompositionMethod,
74  scotchDecomp,
75  dictionaryRegion
76  );
77 }
78 
79 
80 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
81 
82 void Foam::scotchDecomp::graphPath(const polyMesh& mesh) const
83 {
84  graphPath_ = mesh.time().path()/mesh.name() + ".grf";
85 }
86 
87 
88 void Foam::scotchDecomp::check(const int retVal, const char* str)
89 {
90  if (retVal)
91  {
93  << "Call to scotch routine " << str << " failed.\n"
94  << exit(FatalError);
95  }
96 }
97 
98 
99 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
100 
102 (
103  const labelList& adjncy,
104  const labelList& xadj,
105  const List<scalar>& cWeights,
106  labelList& decomp
107 ) const
108 {
109  // Dump graph
110  if (coeffsDict_.getOrDefault("writeGraph", false))
111  {
112  OFstream str(graphPath_);
113 
114  Info<< "Dumping Scotch graph file to " << str.name() << nl
115  << "Use this in combination with gpart." << endl;
116 
117  const label version = 0;
118  str << version << nl;
119  // Number of vertices
120  str << xadj.size()-1 << ' ' << adjncy.size() << nl;
121 
122  // Numbering starts from 0
123  const label baseval = 0;
124 
125  // Has weights?
126  const label hasEdgeWeights = 0;
127  const label hasVertexWeights = 0;
128  const label numericflag = 10*hasEdgeWeights+hasVertexWeights;
129  str << baseval << ' ' << numericflag << nl;
130 
131  for (label celli = 1; celli < xadj.size(); ++celli)
132  {
133  const label start = xadj[celli-1];
134  const label end = xadj[celli];
135 
136  str << end-start; // size
137 
138  for (label i = start; i < end; ++i)
139  {
140  str << ' ' << adjncy[i];
141  }
142  str << nl;
143  }
144  }
145 
146  // Make repeatable
147  SCOTCH_randomReset();
148 
149  // Strategy
150  // ~~~~~~~~
151 
152  // Default.
153  SCOTCH_Strat stradat;
154  check(SCOTCH_stratInit(&stradat), "SCOTCH_stratInit");
155 
156  string strategy;
157  if (coeffsDict_.readIfPresent("strategy", strategy))
158  {
159  if (debug)
160  {
161  Info<< "scotchDecomp : Using strategy " << strategy << endl;
162  }
163  SCOTCH_stratGraphMap(&stradat, strategy.c_str());
164  //fprintf(stdout, "S\tStrat=");
165  //SCOTCH_stratSave(&stradat, stdout);
166  //fprintf(stdout, "\n");
167  }
168 
169 
170  // Graph
171  // ~~~~~
172 
173  labelList velotab;
174 
175  // Check for externally provided cellweights and if so initialise weights
176  // Note: min, not gMin since routine runs on master only.
177  const scalar minWeights = min(cWeights);
178  if (!cWeights.empty())
179  {
180  if (minWeights <= 0)
181  {
183  << "Illegal minimum weight " << minWeights
184  << endl;
185  }
186 
187  if (cWeights.size() != xadj.size()-1)
188  {
190  << "Number of cell weights " << cWeights.size()
191  << " does not equal number of cells " << xadj.size()-1
192  << exit(FatalError);
193  }
194 
195  scalar velotabSum = sum(cWeights)/minWeights;
196 
197  scalar rangeScale(1.0);
198 
199  if (velotabSum > scalar(labelMax - 1))
200  {
201  // 0.9 factor of safety to avoid floating point round-off in
202  // rangeScale tipping the subsequent sum over the integer limit.
203  rangeScale = 0.9*scalar(labelMax - 1)/velotabSum;
204 
206  << "Sum of weights has overflowed integer: " << velotabSum
207  << ", compressing weight scale by a factor of " << rangeScale
208  << endl;
209  }
210 
211  // Convert to integers.
212  velotab.setSize(cWeights.size());
213 
214  forAll(velotab, i)
215  {
216  velotab[i] = int((cWeights[i]/minWeights - 1)*rangeScale) + 1;
217  }
218  }
219 
220 
221  SCOTCH_Graph grafdat;
222  check(SCOTCH_graphInit(&grafdat), "SCOTCH_graphInit");
223  check
224  (
225  SCOTCH_graphBuild
226  (
227  &grafdat,
228  0, // baseval, c-style numbering
229  xadj.size()-1, // vertnbr, nCells
230  xadj.begin(), // verttab, start index per cell into adjncy
231  &xadj[1], // vendtab, end index ,,
232  velotab.begin(), // velotab, vertex weights
233  nullptr, // vlbltab
234  adjncy.size(), // edgenbr, number of arcs
235  adjncy.begin(), // edgetab
236  nullptr // edlotab, edge weights
237  ),
238  "SCOTCH_graphBuild"
239  );
240  check(SCOTCH_graphCheck(&grafdat), "SCOTCH_graphCheck");
241 
242 
243  // Architecture
244  // ~~~~~~~~~~~~
245  // (fully connected network topology since using switch)
246 
247  SCOTCH_Arch archdat;
248  check(SCOTCH_archInit(&archdat), "SCOTCH_archInit");
249 
250  labelList processorWeights;
251  if
252  (
253  coeffsDict_.readIfPresent("processorWeights", processorWeights)
254  && processorWeights.size()
255  )
256  {
257  if (debug)
258  {
259  Info<< "scotchDecomp : Using procesor weights " << processorWeights
260  << endl;
261  }
262  if (processorWeights.size() != nDomains_)
263  {
264  FatalIOErrorInFunction(coeffsDict_)
265  << "processorWeights not the same size"
266  << " as the wanted number of domains " << nDomains_
267  << exit(FatalIOError);
268  }
269 
270  check
271  (
272  SCOTCH_archCmpltw
273  (
274  &archdat, nDomains_, processorWeights.begin()
275  ),
276  "SCOTCH_archCmpltw"
277  );
278  }
279  else
280  {
281  check
282  (
283  SCOTCH_archCmplt(&archdat, nDomains_),
284  "SCOTCH_archCmplt"
285  );
286 
287 
288  //- Hack to test clustering. Note that decomp is non-compact
289  // numbers!
290  //
292  //check
293  //(
294  // SCOTCH_archVcmplt(&archdat),
295  // "SCOTCH_archVcmplt"
296  //);
297  //
299  //SCOTCH_Num straval = 0;
302  //
305  //SCOTCH_Num agglomSize = 3;
306  //
308  //check
309  //(
310  // SCOTCH_stratGraphClusterBuild
311  // (
312  // &stradat, // strategy to build
313  // straval, // strategy flags
314  // agglomSize, // cells per cluster
315  // 1.0, // weight?
316  // 0.01 // max load imbalance
317  // ),
318  // "SCOTCH_stratGraphClusterBuild"
319  //);
320  }
321 
322 
323  //SCOTCH_Mapping mapdat;
324  //SCOTCH_graphMapInit(&grafdat, &mapdat, &archdat, nullptr);
325  //SCOTCH_graphMapCompute(&grafdat, &mapdat, &stradat); /* Perform mapping */
326  //SCOTCH_graphMapExit(&grafdat, &mapdat);
327 
328 
329  // Hack:switch off fpu error trapping
330  #ifdef FE_NOMASK_ENV
331  int oldExcepts = fedisableexcept
332  (
333  FE_DIVBYZERO
334  | FE_INVALID
335  | FE_OVERFLOW
336  );
337  #endif
338 
339  decomp.setSize(xadj.size()-1);
340  decomp = 0;
341  check
342  (
343  SCOTCH_graphMap
344  (
345  &grafdat,
346  &archdat,
347  &stradat, // const SCOTCH_Strat *
348  decomp.begin() // parttab
349  ),
350  "SCOTCH_graphMap"
351  );
352 
353  #ifdef FE_NOMASK_ENV
354  feenableexcept(oldExcepts);
355  #endif
356 
357  //decomp.setSize(xadj.size()-1);
358  //check
359  //(
360  // SCOTCH_graphPart
361  // (
362  // &grafdat,
363  // nDomains_, // partnbr
364  // &stradat, // const SCOTCH_Strat *
365  // decomp.begin() // parttab
366  // ),
367  // "SCOTCH_graphPart"
368  //);
369 
370  // Release storage for graph
371  SCOTCH_graphExit(&grafdat);
372  // Release storage for strategy
373  SCOTCH_stratExit(&stradat);
374  // Release storage for network topology
375  SCOTCH_archExit(&archdat);
376 
377  return 0;
378 }
379 
380 
381 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
382 
383 Foam::scotchDecomp::scotchDecomp(const dictionary& decompDict)
384 :
385  metisLikeDecomp(typeName, decompDict, selectionType::NULL_DICT)
386 {}
387 
388 
390 (
391  const dictionary& decompDict,
392  const word& regionName
393 )
394 :
395  metisLikeDecomp(typeName, decompDict, regionName, selectionType::NULL_DICT)
396 {}
397 
398 
399 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
400 
402 (
403  const polyMesh& mesh,
404  const pointField& points,
405  const scalarField& pointWeights
406 ) const
407 {
408  // Where to write graph
409  graphPath(mesh);
410 
412  (
413  mesh,
414  points,
415  pointWeights
416  );
417 }
418 
419 
421 (
422  const polyMesh& mesh,
423  const labelList& agglom,
424  const pointField& agglomPoints,
425  const scalarField& pointWeights
426 ) const
427 {
428  // Where to write graph
429  graphPath(mesh);
430 
432  (
433  mesh,
434  agglom,
435  agglomPoints,
436  pointWeights
437  );
438 }
439 
440 
442 (
443  const labelListList& globalCellCells,
444  const pointField& cellCentres,
445  const scalarField& cWeights
446 ) const
447 {
448  // Where to write graph
449  graphPath_ = "scotch.grf";
450 
452  (
453  globalCellCells,
454  cellCentres,
455  cWeights
456  );
457 }
458 
459 
460 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(decompositionMethod, kahipDecomp, dictionary)
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::scotchDecomp::decomposeSerial
virtual label decomposeSerial(const labelList &adjncy, const labelList &xadj, const List< scalar > &cWeights, labelList &decomp) const
Decompose non-parallel.
Definition: dummyScotchDecomp.C:67
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
OFstream.H
regionName
Foam::word regionName
Definition: createNamedDynamicFvMesh.H:1
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
scotchDecomp.H
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::foamVersion::version
const std::string version
OpenFOAM version (name or stringified number) as a std::string.
Foam::metisLikeDecomp::decompose
virtual labelList decompose(const polyMesh &mesh, const pointField &points, const scalarField &pointWeights) const
Return for every coordinate the wanted processor number.
Definition: metisLikeDecomp.C:185
Foam::scotchDecomp::scotchDecomp
scotchDecomp(const scotchDecomp &)=delete
No copy construct.
Time.H
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::List< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
floatScalar.H
Foam::scotchDecomp::decompose
virtual labelList decompose(const polyMesh &mesh, const pointField &points, const scalarField &pointWeights) const
Return for every coordinate the wanted processor number.
Definition: dummyScotchDecomp.C:106
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:401
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:303