1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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"
32 #include "cyclicPolyPatch.H"
36 #define OMPI_SKIP_MPICXX
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(metisDecomp, 0);
47 addToRunTimeSelectionTable
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
58 // Call Metis with options from dictionary.
59 Foam::label Foam::metisDecomp::decompose
61 const List<int>& adjncy,
62 const List<int>& xadj,
63 const scalarField& cWeights,
65 List<int>& finalDecomp
71 // Method of decomposition
72 // recursive: multi-level recursive bisection (default)
73 // k-way: multi-level k-way
76 int numCells = xadj.size()-1;
78 // decomposition options. 0 = use defaults
79 List<int> options(5, 0);
81 // processor weights initialised with no size, only used if specified in
83 Field<floatScalar> processorWeights;
85 // cell weights (so on the vertices of the dual)
86 List<int> cellWeights;
88 // face weights (so on the edges of the dual)
89 List<int> faceWeights;
92 // Check for externally provided cellweights and if so initialise weights
93 scalar minWeights = gMin(cWeights);
94 if (cWeights.size() > 0)
100 "metisDecomp::decompose"
101 "(const pointField&, const scalarField&)"
102 ) << "Illegal minimum weight " << minWeights
106 if (cWeights.size() != numCells)
110 "metisDecomp::decompose"
111 "(const pointField&, const scalarField&)"
112 ) << "Number of cell weights " << cWeights.size()
113 << " does not equal number of cells " << numCells
116 // Convert to integers.
117 cellWeights.setSize(cWeights.size());
118 forAll(cellWeights, i)
120 cellWeights[i] = int(cWeights[i]/minWeights);
125 // Check for user supplied weights and decomp options
126 if (decompositionDict_.found("metisCoeffs"))
128 const dictionary& metisCoeffs =
129 decompositionDict_.subDict("metisCoeffs");
132 if (metisCoeffs.readIfPresent("method", method))
134 if (method != "recursive" && method != "k-way")
136 FatalErrorIn("metisDecomp::decompose()")
137 << "Method " << method << " in metisCoeffs in dictionary : "
138 << decompositionDict_.name()
139 << " should be 'recursive' or 'k-way'"
143 Info<< "metisDecomp : Using Metis method " << method
147 if (metisCoeffs.readIfPresent("options", options))
149 if (options.size() != 5)
151 FatalErrorIn("metisDecomp::decompose()")
152 << "Number of options in metisCoeffs in dictionary : "
153 << decompositionDict_.name()
158 Info<< "metisDecomp : Using Metis options " << options
162 if (metisCoeffs.readIfPresent("processorWeights", processorWeights))
164 processorWeights /= sum(processorWeights);
166 if (processorWeights.size() != nProcessors_)
168 FatalErrorIn("metisDecomp::decompose(const pointField&)")
169 << "Number of processor weights "
170 << processorWeights.size()
171 << " does not equal number of domains " << nProcessors_
176 if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
178 Info<< "metisDecomp : Using cell-based weights." << endl;
180 IOList<int> cellIOWeights
185 mesh_.time().timeName(),
191 cellWeights.transfer(cellIOWeights);
193 if (cellWeights.size() != xadj.size()-1)
195 FatalErrorIn("metisDecomp::decompose(const pointField&)")
196 << "Number of cell weights " << cellWeights.size()
197 << " does not equal number of cells " << xadj.size()-1
203 int nProcs = nProcessors_;
205 // output: cell -> processor addressing
206 finalDecomp.setSize(numCells);
208 // output: number of cut edges
211 // Vertex weight info
214 int* adjwgtPtr = NULL;
216 if (cellWeights.size())
218 vwgtPtr = cellWeights.begin();
219 wgtFlag += 2; // Weights on vertices
221 if (faceWeights.size())
223 adjwgtPtr = faceWeights.begin();
224 wgtFlag += 1; // Weights on edges
227 if (method == "recursive")
229 if (processorWeights.size())
231 METIS_WPartGraphRecursive
233 &numCells, // num vertices in graph
234 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
235 const_cast<List<int>&>(adjncy).begin(), // neighbour info
236 vwgtPtr, // vertexweights
237 adjwgtPtr, // no edgeweights
241 processorWeights.begin(),
249 METIS_PartGraphRecursive
251 &numCells, // num vertices in graph
252 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
253 const_cast<List<int>&>(adjncy).begin(), // neighbour info
254 vwgtPtr, // vertexweights
255 adjwgtPtr, // no edgeweights
267 if (processorWeights.size())
271 &numCells, // num vertices in graph
272 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
273 const_cast<List<int>&>(adjncy).begin(), // neighbour info
274 vwgtPtr, // vertexweights
275 adjwgtPtr, // no edgeweights
279 processorWeights.begin(),
289 &numCells, // num vertices in graph
290 const_cast<List<int>&>(xadj).begin(), // indexing into adjncy
291 const_cast<List<int>&>(adjncy).begin(), // neighbour info
292 vwgtPtr, // vertexweights
293 adjwgtPtr, // no edgeweights
308 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
310 Foam::metisDecomp::metisDecomp
312 const dictionary& decompositionDict,
316 decompositionMethod(decompositionDict),
321 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
323 Foam::labelList Foam::metisDecomp::decompose
325 const pointField& points,
326 const scalarField& pointWeights
329 if (points.size() != mesh_.nCells())
333 "metisDecomp::decompose(const pointField&,const scalarField&)"
334 ) << "Can use this decomposition method only for the whole mesh"
336 << "and supply one coordinate (cellCentre) for every cell." << endl
337 << "The number of coordinates " << points.size() << endl
338 << "The number of cells in the mesh " << mesh_.nCells()
351 // Decompose using default weights
352 List<int> finalDecomp;
353 decompose(adjncy, xadj, pointWeights, finalDecomp);
355 // Copy back to labelList
356 labelList decomp(finalDecomp.size());
359 decomp[i] = finalDecomp[i];
365 void Foam::metisDecomp::calcMetisCSR
367 const polyMesh& mesh,
372 // Make Metis CSR (Compressed Storage Format) storage
373 // adjncy : contains neighbours (= edges in graph)
374 // xadj(celli) : start of information in adjncy for celli
376 xadj.setSize(mesh.nCells()+1);
378 // Initialise the number of internal faces of the cells to twice the
379 // number of internal faces
380 label nInternalFaces = 2*mesh.nInternalFaces();
382 // Check the boundary for coupled patches and add to the number of
384 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
388 if (isA<cyclicPolyPatch>(pbm[patchi]))
390 nInternalFaces += pbm[patchi].size();
394 // Create the adjncy array the size of the total number of internal and
396 adjncy.setSize(nInternalFaces);
402 for (label cellI = 0; cellI < mesh.nCells(); cellI++)
404 xadj[cellI] = freeAdj;
406 const labelList& cFaces = mesh.cells()[cellI];
410 label faceI = cFaces[i];
414 mesh.isInternalFace(faceI)
415 || isA<cyclicPolyPatch>(pbm[pbm.whichPatch(faceI)])
422 xadj[mesh.nCells()] = freeAdj;
428 labelList nFacesPerCell(mesh.nCells(), 0);
431 for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
433 label own = mesh.faceOwner()[faceI];
434 label nei = mesh.faceNeighbour()[faceI];
436 adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
437 adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
440 // Coupled faces. Only cyclics done.
443 if (isA<cyclicPolyPatch>(pbm[patchi]))
445 const unallocLabelList& faceCells = pbm[patchi].faceCells();
447 label sizeby2 = faceCells.size()/2;
449 for (label facei=0; facei<sizeby2; facei++)
451 label own = faceCells[facei];
452 label nei = faceCells[facei + sizeby2];
454 adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
455 adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
462 // From cell-cell connections to Metis format (like CompactListList)
463 void Foam::metisDecomp::calcMetisCSR
465 const labelListList& cellCells,
470 // Count number of internal faces
471 label nConnections = 0;
473 forAll(cellCells, coarseI)
475 nConnections += cellCells[coarseI].size();
478 // Create the adjncy array as twice the size of the total number of
480 adjncy.setSize(nConnections);
482 xadj.setSize(cellCells.size()+1);
489 forAll(cellCells, coarseI)
491 xadj[coarseI] = freeAdj;
493 const labelList& cCells = cellCells[coarseI];
497 adjncy[freeAdj++] = cCells[i];
500 xadj[cellCells.size()] = freeAdj;
504 Foam::labelList Foam::metisDecomp::decompose
506 const labelList& agglom,
507 const pointField& agglomPoints,
508 const scalarField& agglomWeights
511 if (agglom.size() != mesh_.nCells())
515 "metisDecomp::decompose"
516 "(const labelList&, const pointField&, const scalarField&)"
517 ) << "Size of cell-to-coarse map " << agglom.size()
518 << " differs from number of cells in mesh " << mesh_.nCells()
522 // Make Metis CSR (Compressed Storage Format) storage
523 // adjncy : contains neighbours (= edges in graph)
524 // xadj(celli) : start of information in adjncy for celli
528 // Get cellCells on coarse mesh.
529 labelListList cellCells;
538 calcMetisCSR(cellCells, adjncy, xadj);
541 // Decompose using default weights
542 List<int> finalDecomp;
543 decompose(adjncy, xadj, agglomWeights, finalDecomp);
546 // Rework back into decomposition for original mesh_
547 labelList fineDistribution(agglom.size());
549 forAll(fineDistribution, i)
551 fineDistribution[i] = finalDecomp[agglom[i]];
554 return fineDistribution;
558 Foam::labelList Foam::metisDecomp::decompose
560 const labelListList& globalCellCells,
561 const pointField& cellCentres,
562 const scalarField& cellWeights
565 if (cellCentres.size() != globalCellCells.size())
569 "metisDecomp::decompose"
570 "(const pointField&, const labelListList&, const scalarField&)"
571 ) << "Inconsistent number of cells (" << globalCellCells.size()
572 << ") and number of cell centres (" << cellCentres.size()
573 << ")." << exit(FatalError);
577 // Make Metis CSR (Compressed Storage Format) storage
578 // adjncy : contains neighbours (= edges in graph)
579 // xadj(celli) : start of information in adjncy for celli
583 calcMetisCSR(globalCellCells, adjncy, xadj);
586 // Decompose using default weights
587 List<int> finalDecomp;
588 decompose(adjncy, xadj, cellWeights, finalDecomp);
590 // Copy back to labelList
591 labelList decomp(finalDecomp.size());
594 decomp[i] = finalDecomp[i];
600 // ************************************************************************* //