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 "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"
44 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
48 defineTypeNameAndDebug(parMetisDecomp, 0);
50 addToRunTimeSelectionTable
59 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
61 //- Does prevention of 0 cell domains and calls parmetis.
62 Foam::label Foam::parMetisDecomp::decompose
66 const pointField& cellCentres,
67 Field<int>& cellWeights,
68 Field<int>& faceWeights,
69 const List<int>& options,
71 List<int>& finalDecomp
77 // Number of dimensions
81 if (cellCentres.size() != xadj.size()-1)
83 FatalErrorIn("parMetisDecomp::decompose(..)")
84 << "cellCentres:" << cellCentres.size()
85 << " xadj:" << xadj.size()
90 // Get number of cells on all processors
91 List<int> nLocalCells(Pstream::nProcs());
92 nLocalCells[Pstream::myProcNo()] = xadj.size()-1;
93 Pstream::gatherList(nLocalCells);
94 Pstream::scatterList(nLocalCells);
97 List<int> cellOffsets(Pstream::nProcs()+1);
99 forAll(nLocalCells, procI)
101 cellOffsets[procI] = nGlobalCells;
102 nGlobalCells += nLocalCells[procI];
104 cellOffsets[Pstream::nProcs()] = nGlobalCells;
106 // Convert pointField into float
107 Field<floatScalar> xyz(3*cellCentres.size());
109 forAll(cellCentres, cellI)
111 const point& cc = cellCentres[cellI];
112 xyz[compI++] = float(cc.x());
113 xyz[compI++] = float(cc.y());
114 xyz[compI++] = float(cc.z());
117 // Make sure every domain has at least one cell
118 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119 // (Metis falls over with zero sized domains)
120 // Trickle cells from processors that have them up to those that
124 // Number of cells to send to the next processor
125 // (is same as number of cells next processor has to receive)
126 List<int> nSendCells(Pstream::nProcs(), 0);
128 for (label procI = nLocalCells.size()-1; procI >=1; procI--)
130 if (nLocalCells[procI]-nSendCells[procI] < 1)
132 nSendCells[procI-1] = nSendCells[procI]-nLocalCells[procI]+1;
136 // First receive (so increasing the sizes of all arrays)
138 if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
140 // Receive cells from previous processor
141 IPstream fromPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
143 Field<int> prevXadj(fromPrevProc);
144 Field<int> prevAdjncy(fromPrevProc);
145 Field<floatScalar> prevXyz(fromPrevProc);
146 Field<int> prevCellWeights(fromPrevProc);
147 Field<int> prevFaceWeights(fromPrevProc);
149 if (prevXadj.size() != nSendCells[Pstream::myProcNo()-1])
151 FatalErrorIn("parMetisDecomp::decompose(..)")
152 << "Expected from processor " << Pstream::myProcNo()-1
153 << " connectivity for " << nSendCells[Pstream::myProcNo()-1]
154 << " nCells but only received " << prevXadj.size()
155 << abort(FatalError);
159 prepend(prevAdjncy, adjncy);
160 // Adapt offsets and prepend xadj
161 xadj += prevAdjncy.size();
162 prepend(prevXadj, xadj);
164 prepend(prevXyz, xyz);
166 prepend(prevCellWeights, cellWeights);
167 prepend(prevFaceWeights, faceWeights);
171 // Send to my next processor
173 if (nSendCells[Pstream::myProcNo()] > 0)
175 // Send cells to next processor
176 OPstream toNextProc(Pstream::blocking, Pstream::myProcNo()+1);
178 int nCells = nSendCells[Pstream::myProcNo()];
179 int startCell = xadj.size()-1 - nCells;
180 int startFace = xadj[startCell];
181 int nFaces = adjncy.size()-startFace;
183 // Send for all cell data: last nCells elements
184 // Send for all face data: last nFaces elements
186 << Field<int>::subField(xadj, nCells, startCell)-startFace
187 << Field<int>::subField(adjncy, nFaces, startFace)
188 << SubField<floatScalar>(xyz, nDims*nCells, nDims*startCell)
192 ? static_cast<const Field<int>&>
194 Field<int>::subField(cellWeights, nCells, startCell)
201 ? static_cast<const Field<int>&>
203 Field<int>::subField(faceWeights, nFaces, startFace)
208 // Remove data that has been sent
209 if (faceWeights.size())
211 faceWeights.setSize(faceWeights.size()-nFaces);
213 if (cellWeights.size())
215 cellWeights.setSize(cellWeights.size()-nCells);
217 xyz.setSize(xyz.size()-nDims*nCells);
218 adjncy.setSize(adjncy.size()-nFaces);
219 xadj.setSize(xadj.size() - nCells);
224 // Adapt number of cells
225 forAll(nSendCells, procI)
228 nLocalCells[procI] -= nSendCells[procI];
233 nLocalCells[procI] += nSendCells[procI-1];
238 forAll(nLocalCells, procI)
240 cellOffsets[procI] = nGlobalCells;
241 nGlobalCells += nLocalCells[procI];
245 if (nLocalCells[Pstream::myProcNo()] != (xadj.size()-1))
247 FatalErrorIn("parMetisDecomp::decompose(..)")
248 << "Have connectivity for " << xadj.size()-1
249 << " cells but nLocalCells:" << nLocalCells[Pstream::myProcNo()]
250 << abort(FatalError);
256 int* adjwgtPtr = NULL;
258 if (cellWeights.size())
260 vwgtPtr = cellWeights.begin();
261 wgtFlag += 2; // Weights on vertices
263 if (faceWeights.size())
265 adjwgtPtr = faceWeights.begin();
266 wgtFlag += 1; // Weights on edges
270 // Number of weights or balance constraints
272 // Per processor, per constraint the weight
273 Field<floatScalar> tpwgts(nCon*nProcessors_, 1./nProcessors_);
274 // Imbalance tolerance
275 Field<floatScalar> ubvec(nCon, 1.02);
276 if (nProcessors_ == 1)
278 // If only one processor there is no imbalance.
282 MPI_Comm comm = MPI_COMM_WORLD;
284 // output: cell -> processor addressing
285 finalDecomp.setSize(nLocalCells[Pstream::myProcNo()]);
287 // output: number of cut edges
291 ParMETIS_V3_PartGeomKway
293 cellOffsets.begin(), // vtxDist
296 vwgtPtr, // vertexweights
297 adjwgtPtr, // edgeweights
303 &nProcessors_, // nParts
306 const_cast<List<int>&>(options).begin(),
313 // If we sent cells across make sure we undo it
314 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
316 // Receive back from next processor if I sent something
317 if (nSendCells[Pstream::myProcNo()] > 0)
319 IPstream fromNextProc(Pstream::blocking, Pstream::myProcNo()+1);
321 List<int> nextFinalDecomp(fromNextProc);
323 if (nextFinalDecomp.size() != nSendCells[Pstream::myProcNo()])
325 FatalErrorIn("parMetisDecomp::decompose(..)")
326 << "Expected from processor " << Pstream::myProcNo()+1
327 << " decomposition for " << nSendCells[Pstream::myProcNo()]
328 << " nCells but only received " << nextFinalDecomp.size()
329 << abort(FatalError);
332 append(nextFinalDecomp, finalDecomp);
335 // Send back to previous processor.
336 if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
338 OPstream toPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
340 int nToPrevious = nSendCells[Pstream::myProcNo()-1];
347 finalDecomp.size()-nToPrevious
350 // Remove locally what has been sent
351 finalDecomp.setSize(finalDecomp.size()-nToPrevious);
358 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
360 Foam::parMetisDecomp::parMetisDecomp
362 const dictionary& decompositionDict,
366 decompositionMethod(decompositionDict),
371 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
373 Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
375 if (points.size() != mesh_.nCells())
377 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
378 << "Can use this decomposition method only for the whole mesh"
380 << "and supply one coordinate (cellCentre) for every cell." << endl
381 << "The number of coordinates " << points.size() << endl
382 << "The number of cells in the mesh " << mesh_.nCells()
386 // For running sequential ...
387 if (Pstream::nProcs() <= 1)
389 return metisDecomp(decompositionDict_, mesh_).decompose(points);
392 // Create global cell numbers
393 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
395 // Get number of cells on all processors
396 List<int> nLocalCells(Pstream::nProcs());
397 nLocalCells[Pstream::myProcNo()] = mesh_.nCells();
398 Pstream::gatherList(nLocalCells);
399 Pstream::scatterList(nLocalCells);
402 List<int> cellOffsets(Pstream::nProcs()+1);
403 int nGlobalCells = 0;
404 forAll(nLocalCells, procI)
406 cellOffsets[procI] = nGlobalCells;
407 nGlobalCells += nLocalCells[procI];
409 cellOffsets[Pstream::nProcs()] = nGlobalCells;
411 int myOffset = cellOffsets[Pstream::myProcNo()];
415 // Make Metis Distributed CSR (Compressed Storage Format) storage
416 // adjncy : contains cellCells (= edges in graph)
417 // xadj(celli) : start of information in adjncy for celli
422 const labelList& faceOwner = mesh_.faceOwner();
423 const labelList& faceNeighbour = mesh_.faceNeighbour();
424 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
427 // Get renumbered owner on other side of coupled faces
428 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
430 List<int> globalNeighbour(mesh_.nFaces()-mesh_.nInternalFaces());
432 forAll(patches, patchI)
434 const polyPatch& pp = patches[patchI];
438 label faceI = pp.start();
439 label bFaceI = pp.start() - mesh_.nInternalFaces();
443 globalNeighbour[bFaceI++] = faceOwner[faceI++] + myOffset;
448 // Get the cell on the other side of coupled patches
449 syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
452 // Count number of faces (internal + coupled)
453 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
455 // Number of faces per cell
456 List<int> nFacesPerCell(mesh_.nCells(), 0);
458 // Number of coupled faces
459 label nCoupledFaces = 0;
461 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
463 nFacesPerCell[faceOwner[faceI]]++;
464 nFacesPerCell[faceNeighbour[faceI]]++;
466 // Handle coupled faces
467 forAll(patches, patchI)
469 const polyPatch& pp = patches[patchI];
473 label faceI = pp.start();
478 nFacesPerCell[faceOwner[faceI++]]++;
487 Field<int> xadj(mesh_.nCells()+1, -1);
491 for (label cellI = 0; cellI < mesh_.nCells(); cellI++)
493 xadj[cellI] = freeAdj;
495 freeAdj += nFacesPerCell[cellI];
497 xadj[mesh_.nCells()] = freeAdj;
504 Field<int> adjncy(2*mesh_.nInternalFaces() + nCoupledFaces, -1);
508 // For internal faces is just offsetted owner and neighbour
509 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
511 label own = faceOwner[faceI];
512 label nei = faceNeighbour[faceI];
514 adjncy[xadj[own] + nFacesPerCell[own]++] = nei + myOffset;
515 adjncy[xadj[nei] + nFacesPerCell[nei]++] = own + myOffset;
517 // For boundary faces is offsetted coupled neighbour
518 forAll(patches, patchI)
520 const polyPatch& pp = patches[patchI];
524 label faceI = pp.start();
525 label bFaceI = pp.start()-mesh_.nInternalFaces();
529 label own = faceOwner[faceI];
530 adjncy[xadj[own] + nFacesPerCell[own]++] =
531 globalNeighbour[bFaceI];
541 // decomposition options. 0 = use defaults
542 List<int> options(3, 0);
543 //options[0] = 1; // don't use defaults but use values below
544 //options[1] = -1; // full debug info
545 //options[2] = 15; // random number seed
547 // cell weights (so on the vertices of the dual)
548 Field<int> cellWeights;
550 // face weights (so on the edges of the dual)
551 Field<int> faceWeights;
553 // Check for user supplied weights and decomp options
554 if (decompositionDict_.found("metisCoeffs"))
556 const dictionary& metisCoeffs =
557 decompositionDict_.subDict("metisCoeffs");
560 if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
562 Info<< "parMetisDecomp : Using cell-based weights read from "
563 << weightsFile << endl;
565 labelIOField cellIOWeights
570 mesh_.time().timeName(),
576 cellWeights.transfer(cellIOWeights);
578 if (cellWeights.size() != mesh_.nCells())
580 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
581 << "Number of cell weights " << cellWeights.size()
582 << " read from " << cellIOWeights.objectPath()
583 << " does not equal number of cells " << mesh_.nCells()
588 if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
590 Info<< "parMetisDecomp : Using face-based weights read from "
591 << weightsFile << endl;
598 mesh_.time().timeName(),
605 if (weights.size() != mesh_.nFaces())
607 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
608 << "Number of face weights " << weights.size()
609 << " does not equal number of internal and boundary faces "
614 faceWeights.setSize(2*mesh_.nInternalFaces()+nCoupledFaces);
616 // Assume symmetric weights. Keep same ordering as adjncy.
619 // Handle internal faces
620 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
622 label w = weights[faceI];
624 label own = faceOwner[faceI];
625 label nei = faceNeighbour[faceI];
627 faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
628 faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
630 // Coupled boundary faces
631 forAll(patches, patchI)
633 const polyPatch& pp = patches[patchI];
637 label faceI = pp.start();
641 label w = weights[faceI];
642 label own = faceOwner[faceI];
643 adjncy[xadj[own] + nFacesPerCell[own]++] = w;
650 if (metisCoeffs.readIfPresent("options", options))
652 Info<< "Using Metis options " << options
655 if (options.size() != 3)
657 FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
658 << "Number of options " << options.size()
659 << " should be three." << exit(FatalError);
665 // Do actual decomposition
666 List<int> finalDecomp;
679 // Copy back to labelList
680 labelList decomp(finalDecomp.size());
683 decomp[i] = finalDecomp[i];
689 Foam::labelList Foam::parMetisDecomp::decompose
691 const labelList& cellToRegion,
692 const pointField& regionPoints
695 const labelList& faceOwner = mesh_.faceOwner();
696 const labelList& faceNeighbour = mesh_.faceNeighbour();
697 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
699 if (cellToRegion.size() != mesh_.nCells())
703 "parMetisDecomp::decompose(const labelList&, const pointField&)"
704 ) << "Size of cell-to-coarse map " << cellToRegion.size()
705 << " differs from number of cells in mesh " << mesh_.nCells()
710 // Global region numbering engine
711 globalIndex globalRegions(regionPoints.size());
714 // Get renumbered owner region on other side of coupled faces
715 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
717 List<int> globalNeighbour(mesh_.nFaces()-mesh_.nInternalFaces());
719 forAll(patches, patchI)
721 const polyPatch& pp = patches[patchI];
725 label faceI = pp.start();
726 label bFaceI = pp.start() - mesh_.nInternalFaces();
730 label ownRegion = cellToRegion[faceOwner[faceI]];
731 globalNeighbour[bFaceI++] = globalRegions.toGlobal(ownRegion);
737 // Get the cell on the other side of coupled patches
738 syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
741 // Get globalCellCells on coarse mesh
742 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
744 labelListList globalRegionRegions;
746 List<DynamicList<label> > dynRegionRegions(regionPoints.size());
748 // Internal faces first
749 forAll(faceNeighbour, faceI)
751 label ownRegion = cellToRegion[faceOwner[faceI]];
752 label neiRegion = cellToRegion[faceNeighbour[faceI]];
754 if (ownRegion != neiRegion)
756 label globalOwn = globalRegions.toGlobal(ownRegion);
757 label globalNei = globalRegions.toGlobal(neiRegion);
759 if (findIndex(dynRegionRegions[ownRegion], globalNei) == -1)
761 dynRegionRegions[ownRegion].append(globalNei);
763 if (findIndex(dynRegionRegions[neiRegion], globalOwn) == -1)
765 dynRegionRegions[neiRegion].append(globalOwn);
770 // Coupled boundary faces
771 forAll(patches, patchI)
773 const polyPatch& pp = patches[patchI];
777 label faceI = pp.start();
778 label bFaceI = pp.start() - mesh_.nInternalFaces();
782 label ownRegion = cellToRegion[faceOwner[faceI]];
783 label globalNei = globalNeighbour[bFaceI++];
786 if (findIndex(dynRegionRegions[ownRegion], globalNei) == -1)
788 dynRegionRegions[ownRegion].append(globalNei);
794 globalRegionRegions.setSize(dynRegionRegions.size());
795 forAll(dynRegionRegions, i)
797 globalRegionRegions[i].transfer(dynRegionRegions[i]);
801 labelList regionDecomp(decompose(globalRegionRegions, regionPoints));
803 // Rework back into decomposition for original mesh_
804 labelList cellDistribution(cellToRegion.size());
806 forAll(cellDistribution, cellI)
808 cellDistribution[cellI] = regionDecomp[cellToRegion[cellI]];
810 return cellDistribution;
814 Foam::labelList Foam::parMetisDecomp::decompose
816 const labelListList& globalCellCells,
817 const pointField& cellCentres
820 if (cellCentres.size() != globalCellCells.size())
824 "parMetisDecomp::decompose(const labelListList&, const pointField&)"
825 ) << "Inconsistent number of cells (" << globalCellCells.size()
826 << ") and number of cell centres (" << cellCentres.size()
827 << ")." << exit(FatalError);
830 // For running sequential ...
831 if (Pstream::nProcs() <= 1)
833 return metisDecomp(decompositionDict_, mesh_)
834 .decompose(globalCellCells, cellCentres);
838 // Make Metis Distributed CSR (Compressed Storage Format) storage
842 // Offsets into adjncy
844 metisDecomp::calcMetisCSR(globalCellCells, adjncy, xadj);
846 // decomposition options. 0 = use defaults
847 List<int> options(3, 0);
848 //options[0] = 1; // don't use defaults but use values below
849 //options[1] = -1; // full debug info
850 //options[2] = 15; // random number seed
852 // cell weights (so on the vertices of the dual)
853 Field<int> cellWeights;
855 // face weights (so on the edges of the dual)
856 Field<int> faceWeights;
858 // Check for user supplied weights and decomp options
859 if (decompositionDict_.found("metisCoeffs"))
861 const dictionary& metisCoeffs =
862 decompositionDict_.subDict("metisCoeffs");
865 if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
867 Info<< "parMetisDecomp : Using cell-based weights read from "
868 << weightsFile << endl;
870 labelIOField cellIOWeights
875 mesh_.time().timeName(),
881 cellWeights.transfer(cellIOWeights);
883 if (cellWeights.size() != cellCentres.size())
887 "parMetisDecomp::decompose"
888 "(const labelListList&, const pointField&)"
889 ) << "Number of cell weights " << cellWeights.size()
890 << " read from " << cellIOWeights.objectPath()
891 << " does not equal number of cells " << cellCentres.size()
896 //- faceWeights disabled. Only makes sense for cellCells from mesh.
897 //if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
899 // Info<< "parMetisDecomp : Using face-based weights read from "
900 // << weightsFile << endl;
902 // labelIOField weights
907 // mesh_.time().timeName(),
909 // IOobject::MUST_READ,
910 // IOobject::AUTO_WRITE
914 // if (weights.size() != mesh_.nFaces())
916 // FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
917 // << "Number of face weights " << weights.size()
918 // << " does not equal number of internal and boundary faces "
920 // << exit(FatalError);
923 // faceWeights.setSize(2*mesh_.nInternalFaces()+nCoupledFaces);
925 // // Assume symmetric weights. Keep same ordering as adjncy.
926 // nFacesPerCell = 0;
928 // // Handle internal faces
929 // for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
931 // label w = weights[faceI];
933 // label own = faceOwner[faceI];
934 // label nei = faceNeighbour[faceI];
936 // faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
937 // faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
939 // // Coupled boundary faces
940 // forAll(patches, patchI)
942 // const polyPatch& pp = patches[patchI];
946 // label faceI = pp.start();
950 // label w = weights[faceI];
951 // label own = faceOwner[faceI];
952 // adjncy[xadj[own] + nFacesPerCell[own]++] = w;
959 if (metisCoeffs.readIfPresent("options", options))
961 Info<< "Using Metis options " << options
964 if (options.size() != 3)
968 "parMetisDecomp::decompose"
969 "(const labelListList&, const pointField&)"
970 ) << "Number of options " << options.size()
971 << " should be three." << exit(FatalError);
977 // Do actual decomposition
978 List<int> finalDecomp;
991 // Copy back to labelList
992 labelList decomp(finalDecomp.size());
995 decomp[i] = finalDecomp[i];
1001 // ************************************************************************* //