1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "metisDecomp.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "floatScalar.H"
33 #define OMPI_SKIP_MPICXX
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(metisDecomp, 0);
44 addToRunTimeSelectionTable(decompositionMethod, metisDecomp, dictionary);
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 // Call Metis with options from dictionary.
51 Foam::label Foam::metisDecomp::decompose
53 const List<int>& adjncy,
54 const List<int>& xadj,
55 const scalarField& cWeights,
57 List<int>& finalDecomp
63 // Method of decomposition
64 // recursive: multi-level recursive bisection (default)
65 // k-way: multi-level k-way
68 int numCells = xadj.size()-1;
70 // decomposition options. 0 = use defaults
71 List<int> options(5, 0);
73 // processor weights initialised with no size, only used if specified in
75 Field<floatScalar> processorWeights;
77 // cell weights (so on the vertices of the dual)
78 List<int> cellWeights;
80 // face weights (so on the edges of the dual)
81 List<int> faceWeights;
84 // Check for externally provided cellweights and if so initialise weights
85 scalar minWeights = gMin(cWeights);
86 if (cWeights.size() > 0)
92 "metisDecomp::decompose"
93 "(const pointField&, const scalarField&)"
94 ) << "Illegal minimum weight " << minWeights
98 if (cWeights.size() != numCells)
102 "metisDecomp::decompose"
103 "(const pointField&, const scalarField&)"
104 ) << "Number of cell weights " << cWeights.size()
105 << " does not equal number of cells " << numCells
108 // Convert to integers.
109 cellWeights.setSize(cWeights.size());
110 forAll(cellWeights, i)
112 cellWeights[i] = int(cWeights[i]/minWeights);
117 // Check for user supplied weights and decomp options
118 if (decompositionDict_.found("metisCoeffs"))
120 const dictionary& metisCoeffs =
121 decompositionDict_.subDict("metisCoeffs");
124 if (metisCoeffs.readIfPresent("method", method))
126 if (method != "recursive" && method != "k-way")
128 FatalErrorIn("metisDecomp::decompose()")
129 << "Method " << method << " in metisCoeffs in dictionary : "
130 << decompositionDict_.name()
131 << " should be 'recursive' or 'k-way'"
135 Info<< "metisDecomp : Using Metis method " << method
139 if (metisCoeffs.readIfPresent("options", options))
141 if (options.size() != 5)
143 FatalErrorIn("metisDecomp::decompose()")
144 << "Number of options in metisCoeffs in dictionary : "
145 << decompositionDict_.name()
150 Info<< "metisDecomp : Using Metis options " << options
154 if (metisCoeffs.readIfPresent("processorWeights", processorWeights))
156 processorWeights /= sum(processorWeights);
158 if (processorWeights.size() != nProcessors_)
160 FatalErrorIn("metisDecomp::decompose(const pointField&)")
161 << "Number of processor weights "
162 << processorWeights.size()
163 << " does not equal number of domains " << nProcessors_
168 //if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
170 // Info<< "metisDecomp : Using cell-based weights." << endl;
172 // IOList<int> cellIOWeights
177 // mesh_.time().timeName(),
179 // IOobject::MUST_READ,
180 // IOobject::AUTO_WRITE
183 // cellWeights.transfer(cellIOWeights);
185 // if (cellWeights.size() != xadj.size()-1)
187 // FatalErrorIn("metisDecomp::decompose(const pointField&)")
188 // << "Number of cell weights " << cellWeights.size()
189 // << " does not equal number of cells " << xadj.size()-1
190 // << exit(FatalError);
195 int nProcs = nProcessors_;
197 // output: cell -> processor addressing
198 finalDecomp.setSize(numCells);
200 // output: number of cut edges
203 // Vertex weight info
206 int* adjwgtPtr = NULL;
208 if (cellWeights.size())
210 vwgtPtr = cellWeights.begin();
211 wgtFlag += 2; // Weights on vertices
213 if (faceWeights.size())
215 adjwgtPtr = faceWeights.begin();
216 wgtFlag += 1; // Weights on edges
219 if (method == "recursive")
221 if (processorWeights.size())
223 METIS_WPartGraphRecursive
225 &numCells, // num vertices in graph
226 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
227 const_cast<List<int>&>(adjncy).begin(), // neighbour info
228 vwgtPtr, // vertexweights
229 adjwgtPtr, // no edgeweights
233 processorWeights.begin(),
241 METIS_PartGraphRecursive
243 &numCells, // num vertices in graph
244 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
245 const_cast<List<int>&>(adjncy).begin(), // neighbour info
246 vwgtPtr, // vertexweights
247 adjwgtPtr, // no edgeweights
259 if (processorWeights.size())
263 &numCells, // num vertices in graph
264 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
265 const_cast<List<int>&>(adjncy).begin(), // neighbour info
266 vwgtPtr, // vertexweights
267 adjwgtPtr, // no edgeweights
271 processorWeights.begin(),
281 &numCells, // num vertices in graph
282 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
283 const_cast<List<int>&>(adjncy).begin(), // neighbour info
284 vwgtPtr, // vertexweights
285 adjwgtPtr, // no edgeweights
300 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
302 Foam::metisDecomp::metisDecomp(const dictionary& decompositionDict)
304 decompositionMethod(decompositionDict)
308 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
310 Foam::labelList Foam::metisDecomp::decompose
312 const polyMesh& mesh,
313 const pointField& points,
314 const scalarField& pointWeights
317 if (points.size() != mesh.nCells())
321 "metisDecomp::decompose(const pointField&,const scalarField&)"
322 ) << "Can use this decomposition method only for the whole mesh"
324 << "and supply one coordinate (cellCentre) for every cell." << endl
325 << "The number of coordinates " << points.size() << endl
326 << "The number of cells in the mesh " << mesh.nCells()
330 CompactListList<label> cellCells;
331 calcCellCells(mesh, identity(mesh.nCells()), mesh.nCells(), cellCells);
333 // Decompose using default weights
335 decompose(cellCells.m(), cellCells.offsets(), pointWeights, decomp);
341 Foam::labelList Foam::metisDecomp::decompose
343 const polyMesh& mesh,
344 const labelList& agglom,
345 const pointField& agglomPoints,
346 const scalarField& agglomWeights
349 if (agglom.size() != mesh.nCells())
353 "metisDecomp::decompose"
354 "(const labelList&, const pointField&, const scalarField&)"
355 ) << "Size of cell-to-coarse map " << agglom.size()
356 << " differs from number of cells in mesh " << mesh.nCells()
360 // Make Metis CSR (Compressed Storage Format) storage
361 // adjncy : contains neighbours (= edges in graph)
362 // xadj(celli) : start of information in adjncy for celli
364 CompactListList<label> cellCells;
365 calcCellCells(mesh, agglom, agglomPoints.size(), cellCells);
367 // Decompose using default weights
368 labelList finalDecomp;
369 decompose(cellCells.m(), cellCells.offsets(), agglomWeights, finalDecomp);
372 // Rework back into decomposition for original mesh
373 labelList fineDistribution(agglom.size());
375 forAll(fineDistribution, i)
377 fineDistribution[i] = finalDecomp[agglom[i]];
384 Foam::labelList Foam::metisDecomp::decompose
386 const labelListList& globalCellCells,
387 const pointField& cellCentres,
388 const scalarField& cellWeights
391 if (cellCentres.size() != globalCellCells.size())
395 "metisDecomp::decompose"
396 "(const pointField&, const labelListList&, const scalarField&)"
397 ) << "Inconsistent number of cells (" << globalCellCells.size()
398 << ") and number of cell centres (" << cellCentres.size()
399 << ")." << exit(FatalError);
403 // Make Metis CSR (Compressed Storage Format) storage
404 // adjncy : contains neighbours (= edges in graph)
405 // xadj(celli) : start of information in adjncy for celli
407 CompactListList<label> cellCells(globalCellCells);
409 // Decompose using default weights
411 decompose(cellCells.m(), cellCells.offsets(), cellWeights, decomp);
417 // ************************************************************************* //