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-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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 "PrecisionAdaptor.H"
34#include "OFstream.H"
35#include <limits>
36
37// Probably not needed, but in case we pickup a ptscotch.h ...
38#define MPICH_SKIP_MPICXX
39#define OMPI_SKIP_MPICXX
40
41#include "scotch.h"
42
43// Hack: scotch generates floating point errors so need to switch off error
44// trapping!
45#ifdef __GLIBC__
46 #ifndef _GNU_SOURCE
47 #define _GNU_SOURCE
48 #endif
49 #include <fenv.h>
50#endif
51
52// Error if we attempt narrowing
53static_assert
54(
55 sizeof(Foam::label) <= sizeof(SCOTCH_Num),
56 "SCOTCH_Num is too small for Foam::label, check your scotch headers"
57);
58
59// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
60
61namespace Foam
62{
63 defineTypeNameAndDebug(scotchDecomp, 0);
65 (
66 decompositionMethod,
67 scotchDecomp,
68 dictionary
69 );
70}
71
72
73// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
74
75namespace Foam
76{
77
78// Check and print error message
79static inline void check(const int retVal, const char* what)
80{
81 if (retVal)
82 {
84 << "Call to scotch routine " << what
85 << " failed (" << retVal << ")\n"
86 << exit(FatalError);
87 }
88}
89
90
91// The mesh-relative graph path/name (without extension)
93{
94 return mesh.time().path()/mesh.name();
95}
96
97
98} // End namespace Foam
99
100
101// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
102
104(
105 const labelList& adjncy,
106 const labelList& xadj,
107 const List<scalar>& cWeights,
108 labelList& decomp
109) const
110{
111 const SCOTCH_Num numCells = max(0, (xadj.size()-1));
112
113 // Addressing
114 ConstPrecisionAdaptor<SCOTCH_Num, label, List> adjncy_param(adjncy);
115 ConstPrecisionAdaptor<SCOTCH_Num, label, List> xadj_param(xadj);
116
117 // Output: cell -> processor addressing
118 decomp.resize(numCells);
119 decomp = 0;
120 PrecisionAdaptor<SCOTCH_Num, label, List> decomp_param(decomp, false);
121
122 // Avoid potential nullptr issues with zero-sized arrays
123 labelList adjncy_dummy, xadj_dummy, decomp_dummy;
124 if (!numCells)
125 {
126 adjncy_dummy.resize(1, 0);
127 adjncy_param.set(adjncy_dummy);
128
129 xadj_dummy.resize(2, 0);
130 xadj_param.set(xadj_dummy);
131
132 decomp_dummy.resize(1, 0);
133 decomp_param.clear(); // Avoid propagating spurious values
134 decomp_param.set(decomp_dummy);
135 }
136
137
138 // Dump graph
139 if (coeffsDict_.getOrDefault("writeGraph", false))
140 {
141 OFstream str(graphPath_ + ".grf");
142
143 Info<< "Dumping Scotch graph file to " << str.name() << nl
144 << "Use this in combination with gpart." << endl;
145
146 const label numConnect = adjncy.size();
147
148 // Version 0 = Graph file (.grf)
149 str << "0" << nl;
150
151 // Number of vertices,
152 // number of edges (connections)
153 str << numCells << ' ' << numConnect << nl;
154
155 // Numbering starts from 0
156 // 100*hasVertlabels+10*hasEdgeWeights+1*hasVertWeights
157 str << "0 000" << nl;
158
159 for (label celli = 0; celli < numCells; ++celli)
160 {
161 const label beg = xadj[celli];
162 const label end = xadj[celli+1];
163
164 str << (end-beg); // size
165
166 for (label i = beg; i < end; ++i)
167 {
168 str << ' ' << adjncy[i];
169 }
170 str << nl;
171 }
172 }
173
174
175 // Make repeatable
176 SCOTCH_randomReset();
177
178 // Strategy
179 // ~~~~~~~~
180
181 // Default.
182 SCOTCH_Strat stradat;
183 check
184 (
185 SCOTCH_stratInit(&stradat),
186 "SCOTCH_stratInit"
187 );
188
189 string strategy;
190 if (coeffsDict_.readIfPresent("strategy", strategy))
191 {
192 DebugInfo << "scotchDecomp : Using strategy " << strategy << endl;
193
194 SCOTCH_stratGraphMap(&stradat, strategy.c_str());
195 //fprintf(stdout, "S\tStrat=");
196 //SCOTCH_stratSave(&stradat, stdout);
197 //fprintf(stdout, "\n");
198 }
199
200
201 // Graph
202 // ~~~~~
203
204 // Check for externally provided cellweights and if so initialise weights
205
206 bool hasWeights = !cWeights.empty();
207
208 // Note: min, not gMin since routine runs on master only.
209 const scalar minWeights = hasWeights ? min(cWeights) : scalar(1);
210
211 if (minWeights <= 0)
212 {
213 hasWeights = false;
215 << "Illegal minimum weight " << minWeights
216 << " ... ignoring"
217 << endl;
218 }
219 else if (hasWeights && (cWeights.size() != numCells))
220 {
222 << "Number of cell weights " << cWeights.size()
223 << " does not equal number of cells " << numCells
224 << exit(FatalError);
225 }
226
227
228 List<SCOTCH_Num> velotab;
229
230 if (hasWeights)
231 {
232 scalar rangeScale(1);
233
234 const scalar velotabSum = sum(cWeights)/minWeights;
235
236 const scalar upperRange = static_cast<scalar>
237 (
238 std::numeric_limits<SCOTCH_Num>::max()-1
239 );
240
241 if (velotabSum > upperRange)
242 {
243 // 0.9 factor of safety to avoid floating point round-off in
244 // rangeScale tipping the subsequent sum over the integer limit.
245 rangeScale = 0.9*upperRange/velotabSum;
246
248 << "Sum of weights overflows SCOTCH_Num: " << velotabSum
249 << ", compressing by factor " << rangeScale << endl;
250 }
251
252 {
253 // Convert to integers.
254 velotab.resize(cWeights.size());
255
256 forAll(velotab, i)
257 {
258 velotab[i] = static_cast<SCOTCH_Num>
259 (
260 ((cWeights[i]/minWeights - 1)*rangeScale) + 1
261 );
262 }
263 }
264 }
265
266
267 //
268 // Decomposition graph
269 //
270
271 SCOTCH_Graph grafdat;
272 check
273 (
274 SCOTCH_graphInit(&grafdat),
275 "SCOTCH_graphInit"
276 );
277 check
278 (
279 SCOTCH_graphBuild
280 (
281 &grafdat, // Graph to build
282 0, // Base for indexing (C-style)
283
284 numCells, // Number of vertices [== nCells]
285 xadj_param().cdata(), // verttab, start index per cell into adjncy
286 nullptr, // vendtab, end index (nullptr == automatic)
287
288 velotab.cdata(), // velotab, vertex weights
289 nullptr, // Vertex labels (nullptr == ignore)
290
291 adjncy.size(), // Number of graph edges
292 adjncy_param().cdata(), // Edge array
293 nullptr // Edge weights (nullptr == ignore)
294 ),
295 "SCOTCH_graphBuild"
296 );
297 check
298 (
299 SCOTCH_graphCheck(&grafdat),
300 "SCOTCH_graphCheck"
301 );
302
303
304 // Architecture
305 // ~~~~~~~~~~~~
306 // (fully connected network topology since using switch)
307
308 SCOTCH_Arch archdat;
309 check
310 (
311 SCOTCH_archInit(&archdat),
312 "SCOTCH_archInit"
313 );
314
315 List<SCOTCH_Num> procWeights;
316 if
317 (
318 coeffsDict_.readIfPresent("processorWeights", procWeights)
319 && !procWeights.empty()
320 )
321 {
322 if (procWeights.size() != nDomains_)
323 {
325 << "processorWeights (" << procWeights.size()
326 << ") != number of domains (" << nDomains_ << ")" << nl
327 << exit(FatalIOError);
328 }
329
331 << "scotchDecomp : Using procesor weights "
332 << procWeights << endl;
333
334 check
335 (
336 SCOTCH_archCmpltw(&archdat, nDomains_, procWeights.cdata()),
337 "SCOTCH_archCmpltw"
338 );
339 }
340 else
341 {
342 check
343 (
344 SCOTCH_archCmplt(&archdat, nDomains_),
345 "SCOTCH_archCmplt"
346 );
347
348
349 //- Hack to test clustering. Note that decomp is non-compact
350 // numbers!
351 //
353 //check
354 //(
355 // SCOTCH_archVcmplt(&archdat),
356 // "SCOTCH_archVcmplt"
357 //);
358 //
360 //SCOTCH_Num straval = 0;
363 //
366 //SCOTCH_Num agglomSize = 3;
367 //
369 //check
370 //(
371 // SCOTCH_stratGraphClusterBuild
372 // (
373 // &stradat, // strategy to build
374 // straval, // strategy flags
375 // agglomSize, // cells per cluster
376 // 1.0, // weight?
377 // 0.01 // max load imbalance
378 // ),
379 // "SCOTCH_stratGraphClusterBuild"
380 //);
381 }
382
383
384 //SCOTCH_Mapping mapdat;
385 //SCOTCH_graphMapInit(&grafdat, &mapdat, &archdat, nullptr);
386 //SCOTCH_graphMapCompute(&grafdat, &mapdat, &stradat); /* Perform mapping */
387 //SCOTCH_graphMapExit(&grafdat, &mapdat);
388
389
390 // Hack:switch off fpu error trapping
391 #ifdef FE_NOMASK_ENV
392 int oldExcepts = fedisableexcept
393 (
394 FE_DIVBYZERO
395 | FE_INVALID
396 | FE_OVERFLOW
397 );
398 #endif
399
400 check
401 (
402 SCOTCH_graphMap
403 (
404 &grafdat,
405 &archdat,
406 &stradat, // const SCOTCH_Strat *
407 decomp_param.ref().data() // parttab
408 ),
409 "SCOTCH_graphMap"
410 );
411
412 #ifdef FE_NOMASK_ENV
413 feenableexcept(oldExcepts);
414 #endif
415
416 //decomp.resize(numCells);
417 //check
418 //(
419 // SCOTCH_graphPart
420 // (
421 // &grafdat,
422 // nDomains_, // partnbr
423 // &stradat, // const SCOTCH_Strat *
424 // decomp_param.ref().data() // parttab
425 // ),
426 // "SCOTCH_graphPart"
427 //);
428
429 SCOTCH_graphExit(&grafdat); // Release storage for graph
430 SCOTCH_stratExit(&stradat); // Release storage for strategy
431 SCOTCH_archExit(&archdat); // Release storage for network topology
432
433 return 0;
434}
435
436
437// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
438
440(
441 const dictionary& decompDict,
442 const word& regionName
443)
444:
445 metisLikeDecomp(typeName, decompDict, regionName, selectionType::NULL_DICT)
446{}
447
448
449// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
450
452(
453 const polyMesh& mesh,
454 const pointField& points,
455 const scalarField& pointWeights
456) const
457{
458 // Where to write graph
459 graphPath_ = getGraphPathBase(mesh);
460
462 (
463 mesh,
464 points,
465 pointWeights
466 );
467}
468
469
471(
472 const polyMesh& mesh,
473 const labelList& agglom,
474 const pointField& agglomPoints,
475 const scalarField& pointWeights
476) const
477{
478 // Where to write graph
479 graphPath_ = getGraphPathBase(mesh);
480
482 (
483 mesh,
484 agglom,
485 agglomPoints,
486 pointWeights
487 );
488}
489
490
492(
493 const labelListList& globalCellCells,
494 const pointField& cellCentres,
495 const scalarField& cWeights
496) const
497{
498 // Where to write graph
499 graphPath_ = "scotch.grf";
500
502 (
503 globalCellCells,
504 cellCentres,
505 cWeights
506 );
507}
508
509
510// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
fileName path() const
Return path.
Definition: Time.H:358
label nDomains_
Number of domains for the decomposition.
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
A class for handling file names.
Definition: fileName.H:76
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:290
const word & name() const
Return reference to name.
Definition: fvMesh.H:310
const dictionary & coeffsDict_
Coefficients for all derived methods.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
Scotch domain decomposition.
Definition: scotchDecomp.H:233
virtual label decomposeSerial(const labelList &adjncy, const labelList &xadj, const List< scalar > &cWeights, labelList &decomp) const
Decompose non-parallel.
bool decompose() const noexcept
Query the decompose flag (normally off)
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
dynamicFvMesh & mesh
Foam::word regionName(Foam::polyMesh::defaultRegion)
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const pointField & points
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
List< label > labelList
A List of labels.
Definition: List.H:66
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
messageStream Info
Information stream (stdout output on master, null elsewhere)
static void check(const int retVal, const char *what)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
IOerror FatalIOError
static Foam::fileName getGraphPathBase(const polyMesh &mesh)
error FatalError
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:158
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333