1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "metisDecomp.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "floatScalar.H"
31 #include "scotchDecomp.H"
35 #define OMPI_SKIP_MPICXX
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 defineTypeNameAndDebug(metisDecomp, 0);
46 addToRunTimeSelectionTable
55 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 // Call Metis with options from dictionary.
58 Foam::label Foam::metisDecomp::decompose
60 const List<int>& adjncy,
61 const List<int>& xadj,
62 const scalarField& cWeights,
64 List<int>& finalDecomp
70 // Method of decomposition
71 // recursive: multi-level recursive bisection (default)
72 // k-way: multi-level k-way
75 int numCells = xadj.size()-1;
77 // decomposition options. 0 = use defaults
78 List<int> options(5, 0);
80 // processor weights initialised with no size, only used if specified in
82 Field<floatScalar> processorWeights;
84 // cell weights (so on the vertices of the dual)
85 List<int> cellWeights;
87 // face weights (so on the edges of the dual)
88 List<int> faceWeights;
91 // Check for externally provided cellweights and if so initialise weights
92 scalar minWeights = gMin(cWeights);
93 if (cWeights.size() > 0)
99 "metisDecomp::decompose"
100 "(const pointField&, const scalarField&)"
101 ) << "Illegal minimum weight " << minWeights
105 if (cWeights.size() != numCells)
109 "metisDecomp::decompose"
110 "(const pointField&, const scalarField&)"
111 ) << "Number of cell weights " << cWeights.size()
112 << " does not equal number of cells " << numCells
115 // Convert to integers.
116 cellWeights.setSize(cWeights.size());
117 forAll(cellWeights, i)
119 cellWeights[i] = int(cWeights[i]/minWeights);
124 // Check for user supplied weights and decomp options
125 if (decompositionDict_.found("metisCoeffs"))
127 const dictionary& metisCoeffs =
128 decompositionDict_.subDict("metisCoeffs");
131 if (metisCoeffs.readIfPresent("method", method))
133 if (method != "recursive" && method != "k-way")
135 FatalErrorIn("metisDecomp::decompose()")
136 << "Method " << method << " in metisCoeffs in dictionary : "
137 << decompositionDict_.name()
138 << " should be 'recursive' or 'k-way'"
142 Info<< "metisDecomp : Using Metis method " << method
146 if (metisCoeffs.readIfPresent("options", options))
148 if (options.size() != 5)
150 FatalErrorIn("metisDecomp::decompose()")
151 << "Number of options in metisCoeffs in dictionary : "
152 << decompositionDict_.name()
157 Info<< "metisDecomp : Using Metis options " << options
161 if (metisCoeffs.readIfPresent("processorWeights", processorWeights))
163 processorWeights /= sum(processorWeights);
165 if (processorWeights.size() != nProcessors_)
167 FatalErrorIn("metisDecomp::decompose(const pointField&)")
168 << "Number of processor weights "
169 << processorWeights.size()
170 << " does not equal number of domains " << nProcessors_
175 if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
177 Info<< "metisDecomp : Using cell-based weights." << endl;
179 IOList<int> cellIOWeights
184 mesh_.time().timeName(),
190 cellWeights.transfer(cellIOWeights);
192 if (cellWeights.size() != xadj.size()-1)
194 FatalErrorIn("metisDecomp::decompose(const pointField&)")
195 << "Number of cell weights " << cellWeights.size()
196 << " does not equal number of cells " << xadj.size()-1
202 int nProcs = nProcessors_;
204 // output: cell -> processor addressing
205 finalDecomp.setSize(numCells);
207 // output: number of cut edges
210 // Vertex weight info
213 int* adjwgtPtr = NULL;
215 if (cellWeights.size())
217 vwgtPtr = cellWeights.begin();
218 wgtFlag += 2; // Weights on vertices
220 if (faceWeights.size())
222 adjwgtPtr = faceWeights.begin();
223 wgtFlag += 1; // Weights on edges
226 if (method == "recursive")
228 if (processorWeights.size())
230 METIS_WPartGraphRecursive
232 &numCells, // num vertices in graph
233 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
234 const_cast<List<int>&>(adjncy).begin(), // neighbour info
235 vwgtPtr, // vertexweights
236 adjwgtPtr, // no edgeweights
240 processorWeights.begin(),
248 METIS_PartGraphRecursive
250 &numCells, // num vertices in graph
251 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
252 const_cast<List<int>&>(adjncy).begin(), // neighbour info
253 vwgtPtr, // vertexweights
254 adjwgtPtr, // no edgeweights
266 if (processorWeights.size())
270 &numCells, // num vertices in graph
271 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
272 const_cast<List<int>&>(adjncy).begin(), // neighbour info
273 vwgtPtr, // vertexweights
274 adjwgtPtr, // no edgeweights
278 processorWeights.begin(),
288 &numCells, // num vertices in graph
289 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
290 const_cast<List<int>&>(adjncy).begin(), // neighbour info
291 vwgtPtr, // vertexweights
292 adjwgtPtr, // no edgeweights
307 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
309 Foam::metisDecomp::metisDecomp
311 const dictionary& decompositionDict,
315 decompositionMethod(decompositionDict),
320 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
322 Foam::labelList Foam::metisDecomp::decompose
324 const pointField& points,
325 const scalarField& pointWeights
328 if (points.size() != mesh_.nCells())
332 "metisDecomp::decompose(const pointField&,const scalarField&)"
333 ) << "Can use this decomposition method only for the whole mesh"
335 << "and supply one coordinate (cellCentre) for every cell." << endl
336 << "The number of coordinates " << points.size() << endl
337 << "The number of cells in the mesh " << mesh_.nCells()
343 scotchDecomp::calcCSR
350 // Decompose using default weights
351 List<int> finalDecomp;
352 decompose(adjncy, xadj, pointWeights, finalDecomp);
354 // Copy back to labelList
355 labelList decomp(finalDecomp.size());
358 decomp[i] = finalDecomp[i];
364 Foam::labelList Foam::metisDecomp::decompose
366 const labelList& agglom,
367 const pointField& agglomPoints,
368 const scalarField& agglomWeights
371 if (agglom.size() != mesh_.nCells())
375 "metisDecomp::decompose"
376 "(const labelList&, const pointField&, const scalarField&)"
377 ) << "Size of cell-to-coarse map " << agglom.size()
378 << " differs from number of cells in mesh " << mesh_.nCells()
382 // Make Metis CSR (Compressed Storage Format) storage
383 // adjncy : contains neighbours (= edges in graph)
384 // xadj(celli) : start of information in adjncy for celli
388 // Get cellCells on coarse mesh.
389 labelListList cellCells;
398 scotchDecomp::calcCSR(cellCells, adjncy, xadj);
401 // Decompose using default weights
402 List<int> finalDecomp;
403 decompose(adjncy, xadj, agglomWeights, finalDecomp);
406 // Rework back into decomposition for original mesh_
407 labelList fineDistribution(agglom.size());
409 forAll(fineDistribution, i)
411 fineDistribution[i] = finalDecomp[agglom[i]];
414 return fineDistribution;
418 Foam::labelList Foam::metisDecomp::decompose
420 const labelListList& globalCellCells,
421 const pointField& cellCentres,
422 const scalarField& cellWeights
425 if (cellCentres.size() != globalCellCells.size())
429 "metisDecomp::decompose"
430 "(const pointField&, const labelListList&, const scalarField&)"
431 ) << "Inconsistent number of cells (" << globalCellCells.size()
432 << ") and number of cell centres (" << cellCentres.size()
433 << ")." << exit(FatalError);
437 // Make Metis CSR (Compressed Storage Format) storage
438 // adjncy : contains neighbours (= edges in graph)
439 // xadj(celli) : start of information in adjncy for celli
443 scotchDecomp::calcCSR(globalCellCells, adjncy, xadj);
446 // Decompose using default weights
447 List<int> finalDecomp;
448 decompose(adjncy, xadj, cellWeights, finalDecomp);
450 // Copy back to labelList
451 labelList decomp(finalDecomp.size());
454 decomp[i] = finalDecomp[i];
460 // ************************************************************************* //