1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 "syncTools.H"
28 #include "parMetisDecomp.H"
29 #include "metisDecomp.H"
30 #include "addToRunTimeSelectionTable.H"
31 #include "floatScalar.H"
34 #include "labelIOField.H"
35 #include "globalIndex.H"
41 # include "parmetis.h"
45 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 defineTypeNameAndDebug(parMetisDecomp, 0);
51 addToRunTimeSelectionTable
60 //- Does prevention of 0 cell domains and calls parmetis.
61 Foam::label Foam::parMetisDecomp::decompose
65 const pointField& cellCentres,
66 Field<int>& cellWeights,
67 Field<int>& faceWeights,
68 const List<int>& options,
70 List<int>& finalDecomp
76 // Number of dimensions
79 // Get number of cells on all processors
80 List<int> nLocalCells(Pstream::nProcs());
81 nLocalCells[Pstream::myProcNo()] = xadj.size()-1;
82 Pstream::gatherList(nLocalCells);
83 Pstream::scatterList(nLocalCells);
86 List<int> cellOffsets(Pstream::nProcs()+1);
88 forAll(nLocalCells, procI)
90 cellOffsets[procI] = nGlobalCells;
91 nGlobalCells += nLocalCells[procI];
93 cellOffsets[Pstream::nProcs()] = nGlobalCells;
95 // Convert pointField into float
96 Field<floatScalar> xyz(3*cellCentres.size());
98 forAll(cellCentres, cellI)
100 const point& cc = cellCentres[cellI];
101 xyz[compI++] = float(cc.x());
102 xyz[compI++] = float(cc.y());
103 xyz[compI++] = float(cc.z());
106 // Make sure every domain has at least one cell
107 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108 // (Metis falls over with zero sized domains)
109 // Trickle cells from processors that have them down to those that
113 // Number of cells to send down (is same as number of cells next processor
115 List<int> nSendCells(Pstream::nProcs(), 0);
117 for (label procI = nLocalCells.size()-1; procI >=1; procI--)
119 if (nLocalCells[procI]-nSendCells[procI] < 1)
121 nSendCells[procI-1] = nSendCells[procI]-nLocalCells[procI]+1;
125 // First receive (so increasing the sizes of all arrays)
127 if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
129 // Receive cells from previous processor
130 IPstream fromPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
132 Field<int> prevXadj(fromPrevProc);
133 Field<int> prevAdjncy(fromPrevProc);
134 Field<floatScalar> prevXyz(fromPrevProc);
135 Field<int> prevCellWeights(fromPrevProc);
136 Field<int> prevFaceWeights(fromPrevProc);
139 prepend(prevAdjncy, adjncy);
140 // Adapt offsets and prepend xadj
141 xadj += prevAdjncy.size();
142 prepend(prevXadj, xadj);
144 prepend(prevXyz, xyz);
146 prepend(prevCellWeights, cellWeights);
147 prepend(prevFaceWeights, faceWeights);
151 // Send to my next processor
153 if (nSendCells[Pstream::myProcNo()] > 0)
155 // Send cells to next processor
156 OPstream toNextProc(Pstream::blocking, Pstream::myProcNo()+1);
158 int nCells = nSendCells[Pstream::myProcNo()];
159 int startCell = xadj.size()-1 - nCells;
160 int startFace = xadj[startCell];
161 int nFaces = adjncy.size()-startFace;
163 // Send for all cell data: last nCells elements
164 // Send for all face data: last nFaces elements
166 << Field<int>::subField(xadj, nCells, startCell)-startFace
167 << Field<int>::subField(adjncy, nFaces, startFace)
168 << SubField<floatScalar>(xyz, nDims*nCells, nDims*startCell)
171 (cellWeights.size() > 0)
172 ? static_cast<const Field<int>&>
174 Field<int>::subField(cellWeights, nCells, startCell)
180 (faceWeights.size() > 0)
181 ? static_cast<const Field<int>&>
183 Field<int>::subField(faceWeights, nFaces, startFace)
188 // Remove data that has been sent
189 if (faceWeights.size() > 0)
191 faceWeights.setSize(faceWeights.size()-nFaces);
193 if (cellWeights.size() > 0)
195 cellWeights.setSize(cellWeights.size()-nCells);
197 xyz.setSize(xyz.size()-nDims*nCells);
198 adjncy.setSize(adjncy.size()-nFaces);
199 xadj.setSize(xadj.size() - nCells);
204 // Adapt number of cells
205 forAll(nSendCells, procI)
208 nLocalCells[procI] -= nSendCells[procI];
213 nLocalCells[procI] += nSendCells[procI-1];
218 forAll(nLocalCells, procI)
220 cellOffsets[procI] = nGlobalCells;
221 nGlobalCells += nLocalCells[procI];
228 int* adjwgtPtr = NULL;
230 if (cellWeights.size() > 0)
232 vwgtPtr = cellWeights.begin();
233 wgtFlag += 2; // Weights on vertices
235 if (faceWeights.size() > 0)
237 adjwgtPtr = faceWeights.begin();
238 wgtFlag += 1; // Weights on edges
242 // Number of weights or balance constraints
244 // Per processor, per constraint the weight
245 Field<floatScalar> tpwgts(nCon*nProcessors_, 1./nProcessors_);
246 // Imbalance tolerance
247 Field<floatScalar> ubvec(nCon, 1.02);
248 if (nProcessors_ == 1)
250 // If only one processor there is no imbalance.
254 MPI_Comm comm = MPI_COMM_WORLD;
256 // output: cell -> processor addressing
257 finalDecomp.setSize(nLocalCells[Pstream::myProcNo()]);
259 // output: number of cut edges
263 ParMETIS_V3_PartGeomKway
265 cellOffsets.begin(), // vtxDist
268 vwgtPtr, // vertexweights
269 adjwgtPtr, // edgeweights
275 &nProcessors_, // nParts
278 const_cast<List<int>&>(options).begin(),
285 // If we sent cells across make sure we undo it
286 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
288 // Receive back from next processor if I sent something
289 if (nSendCells[Pstream::myProcNo()] > 0)
291 IPstream fromNextProc(Pstream::blocking, Pstream::myProcNo()+1);
293 List<int> nextFinalDecomp(fromNextProc);
295 append(nextFinalDecomp, finalDecomp);
298 // Send back to previous processor.
299 if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
301 OPstream toPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
303 int nToPrevious = nSendCells[Pstream::myProcNo()-1];
310 finalDecomp.size()-nToPrevious
313 // Remove locally what has been sent
314 finalDecomp.setSize(finalDecomp.size()-nToPrevious);
321 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
323 Foam::parMetisDecomp::parMetisDecomp
325 const dictionary& decompositionDict,
329 decompositionMethod(decompositionDict),
334 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
336 Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
338 if (points.size() != mesh_.nCells())
340 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
341 << "Can use this decomposition method only for the whole mesh"
343 << "and supply one coordinate (cellCentre) for every cell." << endl
344 << "The number of coordinates " << points.size() << endl
345 << "The number of cells in the mesh " << mesh_.nCells()
349 // For running sequential ...
350 if (Pstream::nProcs() <= 1)
352 return metisDecomp(decompositionDict_, mesh_).decompose(points);
355 // Create global cell numbers
356 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
358 // Get number of cells on all processors
359 List<int> nLocalCells(Pstream::nProcs());
360 nLocalCells[Pstream::myProcNo()] = mesh_.nCells();
361 Pstream::gatherList(nLocalCells);
362 Pstream::scatterList(nLocalCells);
365 List<int> cellOffsets(Pstream::nProcs()+1);
366 int nGlobalCells = 0;
367 forAll(nLocalCells, procI)
369 cellOffsets[procI] = nGlobalCells;
370 nGlobalCells += nLocalCells[procI];
372 cellOffsets[Pstream::nProcs()] = nGlobalCells;
374 int myOffset = cellOffsets[Pstream::myProcNo()];
378 // Make Metis Distributed CSR (Compressed Storage Format) storage
379 // adjncy : contains cellCells (= edges in graph)
380 // xadj(celli) : start of information in adjncy for celli
385 const labelList& faceOwner = mesh_.faceOwner();
386 const labelList& faceNeighbour = mesh_.faceNeighbour();
387 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
390 // Get renumbered owner on other side of coupled faces
391 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
393 List<int> globalNeighbour(mesh_.nFaces()-mesh_.nInternalFaces());
395 forAll(patches, patchI)
397 const polyPatch& pp = patches[patchI];
401 label faceI = pp.start();
402 label bFaceI = pp.start() - mesh_.nInternalFaces();
406 globalNeighbour[bFaceI++] = faceOwner[faceI++] + myOffset;
411 // Get the cell on the other side of coupled patches
412 syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
415 // Count number of faces (internal + coupled)
416 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
418 // Number of faces per cell
419 List<int> nFacesPerCell(mesh_.nCells(), 0);
421 // Number of coupled faces
422 label nCoupledFaces = 0;
424 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
426 nFacesPerCell[faceOwner[faceI]]++;
427 nFacesPerCell[faceNeighbour[faceI]]++;
429 // Handle coupled faces
430 forAll(patches, patchI)
432 const polyPatch& pp = patches[patchI];
436 label faceI = pp.start();
441 nFacesPerCell[faceOwner[faceI++]]++;
450 Field<int> xadj(mesh_.nCells()+1, -1);
454 for (label cellI = 0; cellI < mesh_.nCells(); cellI++)
456 xadj[cellI] = freeAdj;
458 freeAdj += nFacesPerCell[cellI];
460 xadj[mesh_.nCells()] = freeAdj;
467 Field<int> adjncy(2*mesh_.nInternalFaces() + nCoupledFaces, -1);
471 // For internal faces is just offsetted owner and neighbour
472 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
474 label own = faceOwner[faceI];
475 label nei = faceNeighbour[faceI];
477 adjncy[xadj[own] + nFacesPerCell[own]++] = nei + myOffset;
478 adjncy[xadj[nei] + nFacesPerCell[nei]++] = own + myOffset;
480 // For boundary faces is offsetted coupled neighbour
481 forAll(patches, patchI)
483 const polyPatch& pp = patches[patchI];
487 label faceI = pp.start();
488 label bFaceI = pp.start()-mesh_.nInternalFaces();
492 label own = faceOwner[faceI];
493 adjncy[xadj[own] + nFacesPerCell[own]++] =
494 globalNeighbour[bFaceI];
504 // decomposition options. 0 = use defaults
505 List<int> options(3, 0);
506 //options[0] = 1; // don't use defaults but use values below
507 //options[1] = -1; // full debug info
508 //options[2] = 15; // random number seed
510 // cell weights (so on the vertices of the dual)
511 Field<int> cellWeights;
513 // face weights (so on the edges of the dual)
514 Field<int> faceWeights;
516 // Check for user supplied weights and decomp options
517 if (decompositionDict_.found("metisCoeffs"))
519 const dictionary& metisCoeffs =
520 decompositionDict_.subDict("metisCoeffs");
523 if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
525 Info<< "parMetisDecomp : Using cell-based weights read from "
526 << weightsFile << endl;
528 labelIOField cellIOWeights
533 mesh_.time().timeName(),
539 cellWeights.transfer(cellIOWeights);
541 if (cellWeights.size() != mesh_.nCells())
543 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
544 << "Number of cell weights " << cellWeights.size()
545 << " read from " << cellIOWeights.objectPath()
546 << " does not equal number of cells " << mesh_.nCells()
551 if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
553 Info<< "parMetisDecomp : Using face-based weights read from "
554 << weightsFile << endl;
561 mesh_.time().timeName(),
568 if (weights.size() != mesh_.nFaces())
570 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
571 << "Number of face weights " << weights.size()
572 << " does not equal number of internal and boundary faces "
577 faceWeights.setSize(2*mesh_.nInternalFaces()+nCoupledFaces);
579 // Assume symmetric weights. Keep same ordering as adjncy.
582 // Handle internal faces
583 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
585 label w = weights[faceI];
587 label own = faceOwner[faceI];
588 label nei = faceNeighbour[faceI];
590 faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
591 faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
593 // Coupled boundary faces
594 forAll(patches, patchI)
596 const polyPatch& pp = patches[patchI];
600 label faceI = pp.start();
604 label w = weights[faceI];
605 label own = faceOwner[faceI];
606 adjncy[xadj[own] + nFacesPerCell[own]++] = w;
613 if (metisCoeffs.readIfPresent("options", options))
615 Info<< "Using Metis options " << options
618 if (options.size() != 3)
620 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
621 << "Number of options " << options.size()
622 << " should be three." << exit(FatalError);
628 // Do actual decomposition
629 List<int> finalDecomp;
642 // Copy back to labelList
643 labelList decomp(finalDecomp.size());
646 decomp[i] = finalDecomp[i];
652 Foam::labelList Foam::parMetisDecomp::decompose
654 const labelList& cellToRegion,
655 const pointField& regionPoints
658 const labelList& faceOwner = mesh_.faceOwner();
659 const labelList& faceNeighbour = mesh_.faceNeighbour();
660 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
662 if (cellToRegion.size() != mesh_.nCells())
666 "parMetisDecomp::decompose(const labelList&, const pointField&)"
667 ) << "Size of cell-to-coarse map " << cellToRegion.size()
668 << " differs from number of cells in mesh " << mesh_.nCells()
673 // Global region numbering engine
674 globalIndex globalRegions(regionPoints.size());
677 // Get renumbered owner region on other side of coupled faces
678 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
680 List<int> globalNeighbour(mesh_.nFaces()-mesh_.nInternalFaces());
682 forAll(patches, patchI)
684 const polyPatch& pp = patches[patchI];
688 label faceI = pp.start();
689 label bFaceI = pp.start() - mesh_.nInternalFaces();
693 label ownRegion = cellToRegion[faceOwner[faceI]];
694 globalNeighbour[bFaceI++] = globalRegions.toGlobal(ownRegion);
700 // Get the cell on the other side of coupled patches
701 syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
704 // Get globalCellCells on coarse mesh
705 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
707 labelListList globalRegionRegions;
709 List<DynamicList<label> > dynRegionRegions(regionPoints.size());
711 // Internal faces first
712 forAll(faceNeighbour, faceI)
714 label ownRegion = cellToRegion[faceOwner[faceI]];
715 label neiRegion = cellToRegion[faceNeighbour[faceI]];
717 if (ownRegion != neiRegion)
719 label globalOwn = globalRegions.toGlobal(ownRegion);
720 label globalNei = globalRegions.toGlobal(neiRegion);
722 if (findIndex(dynRegionRegions[ownRegion], globalNei) == -1)
724 dynRegionRegions[ownRegion].append(globalNei);
726 if (findIndex(dynRegionRegions[neiRegion], globalOwn) == -1)
728 dynRegionRegions[neiRegion].append(globalOwn);
733 // Coupled boundary faces
734 forAll(patches, patchI)
736 const polyPatch& pp = patches[patchI];
740 label faceI = pp.start();
741 label bFaceI = pp.start() - mesh_.nInternalFaces();
745 label ownRegion = cellToRegion[faceOwner[faceI]];
746 label globalNei = globalNeighbour[bFaceI++];
749 if (findIndex(dynRegionRegions[ownRegion], globalNei) == -1)
751 dynRegionRegions[ownRegion].append(globalNei);
757 globalRegionRegions.setSize(dynRegionRegions.size());
758 forAll(dynRegionRegions, i)
760 globalRegionRegions[i].transfer(dynRegionRegions[i].shrink());
761 dynRegionRegions[i].clear();
765 labelList regionDecomp(decompose(globalRegionRegions, regionPoints));
767 // Rework back into decomposition for original mesh_
768 labelList cellDistribution(cellToRegion.size());
770 forAll(cellDistribution, cellI)
772 cellDistribution[cellI] = regionDecomp[cellToRegion[cellI]];
774 return cellDistribution;
778 Foam::labelList Foam::parMetisDecomp::decompose
780 const labelListList& globalCellCells,
781 const pointField& cellCentres
784 if (cellCentres.size() != globalCellCells.size())
788 "parMetisDecomp::decompose(const labelListList&, const pointField&)"
789 ) << "Inconsistent number of cells (" << globalCellCells.size()
790 << ") and number of cell centres (" << cellCentres.size()
791 << ")." << exit(FatalError);
794 // For running sequential ...
795 if (Pstream::nProcs() <= 1)
797 return metisDecomp(decompositionDict_, mesh_)
798 .decompose(globalCellCells, cellCentres);
802 // Make Metis Distributed CSR (Compressed Storage Format) storage
806 // Offsets into adjncy
808 metisDecomp::calcMetisCSR(globalCellCells, adjncy, xadj);
810 // decomposition options. 0 = use defaults
811 List<int> options(3, 0);
812 //options[0] = 1; // don't use defaults but use values below
813 //options[1] = -1; // full debug info
814 //options[2] = 15; // random number seed
816 // cell weights (so on the vertices of the dual)
817 Field<int> cellWeights;
819 // face weights (so on the edges of the dual)
820 Field<int> faceWeights;
822 // Check for user supplied weights and decomp options
823 if (decompositionDict_.found("metisCoeffs"))
825 const dictionary& metisCoeffs =
826 decompositionDict_.subDict("metisCoeffs");
829 if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
831 Info<< "parMetisDecomp : Using cell-based weights read from "
832 << weightsFile << endl;
834 labelIOField cellIOWeights
839 mesh_.time().timeName(),
845 cellWeights.transfer(cellIOWeights);
847 if (cellWeights.size() != cellCentres.size())
851 "parMetisDecomp::decompose"
852 "(const labelListList&, const pointField&)"
853 ) << "Number of cell weights " << cellWeights.size()
854 << " read from " << cellIOWeights.objectPath()
855 << " does not equal number of cells " << cellCentres.size()
860 //- faceWeights disabled. Only makes sense for cellCells from mesh.
861 //if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
863 // Info<< "parMetisDecomp : Using face-based weights read from "
864 // << weightsFile << endl;
866 // labelIOField weights
871 // mesh_.time().timeName(),
873 // IOobject::MUST_READ,
874 // IOobject::AUTO_WRITE
878 // if (weights.size() != mesh_.nFaces())
880 // FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
881 // << "Number of face weights " << weights.size()
882 // << " does not equal number of internal and boundary faces "
884 // << exit(FatalError);
887 // faceWeights.setSize(2*mesh_.nInternalFaces()+nCoupledFaces);
889 // // Assume symmetric weights. Keep same ordering as adjncy.
890 // nFacesPerCell = 0;
892 // // Handle internal faces
893 // for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
895 // label w = weights[faceI];
897 // label own = faceOwner[faceI];
898 // label nei = faceNeighbour[faceI];
900 // faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
901 // faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
903 // // Coupled boundary faces
904 // forAll(patches, patchI)
906 // const polyPatch& pp = patches[patchI];
910 // label faceI = pp.start();
914 // label w = weights[faceI];
915 // label own = faceOwner[faceI];
916 // adjncy[xadj[own] + nFacesPerCell[own]++] = w;
923 if (metisCoeffs.readIfPresent("options", options))
925 Info<< "Using Metis options " << options
928 if (options.size() != 3)
932 "parMetisDecomp::decompose"
933 "(const labelListList&, const pointField&)"
934 ) << "Number of options " << options.size()
935 << " should be three." << exit(FatalError);
941 // Do actual decomposition
942 List<int> finalDecomp;
955 // Copy back to labelList
956 labelList decomp(finalDecomp.size());
959 decomp[i] = finalDecomp[i];
965 // ************************************************************************* //