FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

parMetisDecomp.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #include "parMetisDecomp.H"
00027 #include <metisDecomp/metisDecomp.H>
00028 #include <scotchDecomp/scotchDecomp.H>
00029 #include <OpenFOAM/syncTools.H>
00030 #include <OpenFOAM/addToRunTimeSelectionTable.H>
00031 #include <OpenFOAM/floatScalar.H>
00032 #include <OpenFOAM/polyMesh.H>
00033 #include <OpenFOAM/Time.H>
00034 #include <OpenFOAM/labelIOField.H>
00035 #include <OpenFOAM/globalIndex.H>
00036 #include <OpenFOAM/dlLibraryTable.H>
00037 
00038 #include <mpi.h>
00039 
00040 extern "C"
00041 {
00042 #   include <parmetis.h>
00043 }
00044 
00045 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00046 
00047 namespace Foam
00048 {
00049     defineTypeNameAndDebug(parMetisDecomp, 0);
00050 
00051     addToRunTimeSelectionTable
00052     (
00053         decompositionMethod,
00054         parMetisDecomp,
00055         dictionaryMesh
00056     );
00057 }
00058 
00059 
00060 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00061 
00062 //- Does prevention of 0 cell domains and calls parmetis.
00063 Foam::label Foam::parMetisDecomp::decompose
00064 (
00065     Field<int>& xadj,
00066     Field<int>& adjncy,
00067     const pointField& cellCentres,
00068     Field<int>& cellWeights,
00069     Field<int>& faceWeights,
00070     const List<int>& options,
00071 
00072     List<int>& finalDecomp
00073 )
00074 {
00075     // C style numbering
00076     int numFlag = 0;
00077 
00078     // Number of dimensions
00079     int nDims = 3;
00080 
00081 
00082     if (cellCentres.size() != xadj.size()-1)
00083     {
00084         FatalErrorIn("parMetisDecomp::decompose(..)")
00085             << "cellCentres:" << cellCentres.size()
00086             << " xadj:" << xadj.size()
00087             << abort(FatalError);
00088     }
00089 
00090 
00091     // Get number of cells on all processors
00092     List<int> nLocalCells(Pstream::nProcs());
00093     nLocalCells[Pstream::myProcNo()] = xadj.size()-1;
00094     Pstream::gatherList(nLocalCells);
00095     Pstream::scatterList(nLocalCells);
00096 
00097     // Get cell offsets.
00098     List<int> cellOffsets(Pstream::nProcs()+1);
00099     int nGlobalCells = 0;
00100     forAll(nLocalCells, procI)
00101     {
00102         cellOffsets[procI] = nGlobalCells;
00103         nGlobalCells += nLocalCells[procI];
00104     }
00105     cellOffsets[Pstream::nProcs()] = nGlobalCells;
00106 
00107     // Convert pointField into float
00108     Field<floatScalar> xyz(3*cellCentres.size());
00109     int compI = 0;
00110     forAll(cellCentres, cellI)
00111     {
00112         const point& cc = cellCentres[cellI];
00113         xyz[compI++] = float(cc.x());
00114         xyz[compI++] = float(cc.y());
00115         xyz[compI++] = float(cc.z());
00116     }
00117 
00118     // Make sure every domain has at least one cell
00119     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00120     // (Metis falls over with zero sized domains)
00121     // Trickle cells from processors that have them up to those that
00122     // don't.
00123 
00124 
00125     // Number of cells to send to the next processor
00126     // (is same as number of cells next processor has to receive)
00127     List<int> nSendCells(Pstream::nProcs(), 0);
00128 
00129     for (label procI = nLocalCells.size()-1; procI >=1; procI--)
00130     {
00131         if (nLocalCells[procI]-nSendCells[procI] < 1)
00132         {
00133             nSendCells[procI-1] = nSendCells[procI]-nLocalCells[procI]+1;
00134         }
00135     }
00136 
00137     // First receive (so increasing the sizes of all arrays)
00138 
00139     if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
00140     {
00141         // Receive cells from previous processor
00142         IPstream fromPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
00143 
00144         Field<int> prevXadj(fromPrevProc);
00145         Field<int> prevAdjncy(fromPrevProc);
00146         Field<floatScalar> prevXyz(fromPrevProc);
00147         Field<int> prevCellWeights(fromPrevProc);
00148         Field<int> prevFaceWeights(fromPrevProc);
00149 
00150         if (prevXadj.size() != nSendCells[Pstream::myProcNo()-1])
00151         {
00152             FatalErrorIn("parMetisDecomp::decompose(..)")
00153                 << "Expected from processor " << Pstream::myProcNo()-1
00154                 << " connectivity for " << nSendCells[Pstream::myProcNo()-1]
00155                 << " nCells but only received " << prevXadj.size()
00156                 << abort(FatalError);
00157         }
00158 
00159         // Insert adjncy
00160         prepend(prevAdjncy, adjncy);
00161         // Adapt offsets and prepend xadj
00162         xadj += prevAdjncy.size();
00163         prepend(prevXadj, xadj);
00164         // Coords
00165         prepend(prevXyz, xyz);
00166         // Weights
00167         prepend(prevCellWeights, cellWeights);
00168         prepend(prevFaceWeights, faceWeights);
00169     }
00170 
00171 
00172     // Send to my next processor
00173 
00174     if (nSendCells[Pstream::myProcNo()] > 0)
00175     {
00176         // Send cells to next processor
00177         OPstream toNextProc(Pstream::blocking, Pstream::myProcNo()+1);
00178 
00179         int nCells = nSendCells[Pstream::myProcNo()];
00180         int startCell = xadj.size()-1 - nCells;
00181         int startFace = xadj[startCell];
00182         int nFaces = adjncy.size()-startFace;
00183 
00184         // Send for all cell data: last nCells elements
00185         // Send for all face data: last nFaces elements
00186         toNextProc
00187             << Field<int>::subField(xadj, nCells, startCell)-startFace
00188             << Field<int>::subField(adjncy, nFaces, startFace)
00189             << SubField<floatScalar>(xyz, nDims*nCells, nDims*startCell)
00190             <<
00191             (
00192                 cellWeights.size()
00193               ? static_cast<const Field<int>&>
00194                 (
00195                     Field<int>::subField(cellWeights, nCells, startCell)
00196                 )
00197               : Field<int>(0)
00198             )
00199             <<
00200             (
00201                 faceWeights.size()
00202               ? static_cast<const Field<int>&>
00203                 (
00204                     Field<int>::subField(faceWeights, nFaces, startFace)
00205                 )
00206               : Field<int>(0)
00207             );
00208 
00209         // Remove data that has been sent
00210         if (faceWeights.size())
00211         {
00212             faceWeights.setSize(faceWeights.size()-nFaces);
00213         }
00214         if (cellWeights.size())
00215         {
00216             cellWeights.setSize(cellWeights.size()-nCells);
00217         }
00218         xyz.setSize(xyz.size()-nDims*nCells);
00219         adjncy.setSize(adjncy.size()-nFaces);
00220         xadj.setSize(xadj.size() - nCells);
00221     }
00222 
00223 
00224 
00225     // Adapt number of cells
00226     forAll(nSendCells, procI)
00227     {
00228         // Sent cells
00229         nLocalCells[procI] -= nSendCells[procI];
00230 
00231         if (procI >= 1)
00232         {
00233             // Received cells
00234             nLocalCells[procI] += nSendCells[procI-1];
00235         }
00236     }
00237     // Adapt cellOffsets
00238     nGlobalCells = 0;
00239     forAll(nLocalCells, procI)
00240     {
00241         cellOffsets[procI] = nGlobalCells;
00242         nGlobalCells += nLocalCells[procI];
00243     }
00244 
00245 
00246     if (nLocalCells[Pstream::myProcNo()] != (xadj.size()-1))
00247     {
00248         FatalErrorIn("parMetisDecomp::decompose(..)")
00249             << "Have connectivity for " << xadj.size()-1
00250             << " cells but nLocalCells:" << nLocalCells[Pstream::myProcNo()]
00251             << abort(FatalError);
00252     }
00253 
00254     // Weight info
00255     int wgtFlag = 0;
00256     int* vwgtPtr = NULL;
00257     int* adjwgtPtr = NULL;
00258 
00259     if (cellWeights.size())
00260     {
00261         vwgtPtr = cellWeights.begin();
00262         wgtFlag += 2;       // Weights on vertices
00263     }
00264     if (faceWeights.size())
00265     {
00266         adjwgtPtr = faceWeights.begin();
00267         wgtFlag += 1;       // Weights on edges
00268     }
00269 
00270 
00271     // Number of weights or balance constraints
00272     int nCon = 1;
00273     // Per processor, per constraint the weight
00274     Field<floatScalar> tpwgts(nCon*nProcessors_, 1./nProcessors_);
00275     // Imbalance tolerance
00276     Field<floatScalar> ubvec(nCon, 1.02);
00277     if (nProcessors_ == 1)
00278     {
00279         // If only one processor there is no imbalance.
00280         ubvec[0] = 1;
00281     }
00282 
00283     MPI_Comm comm = MPI_COMM_WORLD;
00284 
00285     // output: cell -> processor addressing
00286     finalDecomp.setSize(nLocalCells[Pstream::myProcNo()]);
00287 
00288     // output: number of cut edges
00289     int edgeCut = 0;
00290 
00291 
00292     ParMETIS_V3_PartGeomKway
00293     (
00294         cellOffsets.begin(),    // vtxDist
00295         xadj.begin(),
00296         adjncy.begin(),
00297         vwgtPtr,                // vertexweights
00298         adjwgtPtr,              // edgeweights
00299         &wgtFlag,
00300         &numFlag,
00301         &nDims,
00302         xyz.begin(),
00303         &nCon,
00304         &nProcessors_,          // nParts
00305         tpwgts.begin(),
00306         ubvec.begin(),
00307         const_cast<List<int>&>(options).begin(),
00308         &edgeCut,
00309         finalDecomp.begin(),
00310         &comm
00311     );
00312 
00313 
00314     // If we sent cells across make sure we undo it
00315     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00316 
00317     // Receive back from next processor if I sent something
00318     if (nSendCells[Pstream::myProcNo()] > 0)
00319     {
00320         IPstream fromNextProc(Pstream::blocking, Pstream::myProcNo()+1);
00321 
00322         List<int> nextFinalDecomp(fromNextProc);
00323 
00324         if (nextFinalDecomp.size() != nSendCells[Pstream::myProcNo()])
00325         {
00326             FatalErrorIn("parMetisDecomp::decompose(..)")
00327                 << "Expected from processor " << Pstream::myProcNo()+1
00328                 << " decomposition for " << nSendCells[Pstream::myProcNo()]
00329                 << " nCells but only received " << nextFinalDecomp.size()
00330                 << abort(FatalError);
00331         }
00332 
00333         append(nextFinalDecomp, finalDecomp);
00334     }
00335 
00336     // Send back to previous processor.
00337     if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
00338     {
00339         OPstream toPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
00340 
00341         int nToPrevious = nSendCells[Pstream::myProcNo()-1];
00342 
00343         toPrevProc <<
00344             SubList<int>
00345             (
00346                 finalDecomp,
00347                 nToPrevious,
00348                 finalDecomp.size()-nToPrevious
00349             );
00350 
00351         // Remove locally what has been sent
00352         finalDecomp.setSize(finalDecomp.size()-nToPrevious);
00353     }
00354 
00355     return edgeCut;
00356 }
00357 
00358 
00359 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00360 
00361 Foam::parMetisDecomp::parMetisDecomp
00362 (
00363     const dictionary& decompositionDict,
00364     const polyMesh& mesh
00365 )
00366 :
00367     decompositionMethod(decompositionDict),
00368     mesh_(mesh)
00369 {
00370     if (Pstream::nProcs() <= 1)
00371     {
00372         if(!dlLibraryTable::open("metisDecomp.so"))
00373         {
00374             FatalErrorIn
00375             (
00376                  "parMetisDecomp::parMetisDecomp()"
00377             ) << "Failed to load the library 'metisDecomp.so'" << endl
00378               << Foam::exit(FatalError);
00379         }
00380     }
00381 }
00382 
00383 
00384 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00385 
00386 Foam::labelList Foam::parMetisDecomp::decompose
00387 (
00388     const pointField& cc,
00389     const scalarField& cWeights
00390 )
00391 {
00392     if (cc.size() != mesh_.nCells())
00393     {
00394         FatalErrorIn
00395         (
00396             "parMetisDecomp::decompose"
00397             "(const pointField&, const scalarField&)"
00398         )   << "Can use this decomposition method only for the whole mesh"
00399             << endl
00400             << "and supply one coordinate (cellCentre) for every cell." << endl
00401             << "The number of coordinates " << cc.size() << endl
00402             << "The number of cells in the mesh " << mesh_.nCells()
00403             << exit(FatalError);
00404     }
00405 
00406     // For running sequential ...
00407     if (Pstream::nProcs() <= 1)
00408     {
00409         return metisDecomp(decompositionDict_, mesh_).decompose
00410         (
00411             cc,
00412             cWeights
00413         );
00414     }
00415 
00416 
00417     // Connections
00418     Field<int> adjncy;
00419     // Offsets into adjncy
00420     Field<int> xadj;
00421     calcMetisDistributedCSR
00422     (
00423         mesh_,
00424         adjncy,
00425         xadj
00426     );
00427 
00428 
00429     // decomposition options. 0 = use defaults
00430     List<int> options(3, 0);
00431     //options[0] = 1;     // don't use defaults but use values below
00432     //options[1] = -1;    // full debug info
00433     //options[2] = 15;    // random number seed
00434 
00435     // cell weights (so on the vertices of the dual)
00436     Field<int> cellWeights;
00437 
00438     // face weights (so on the edges of the dual)
00439     Field<int> faceWeights;
00440 
00441 
00442     // Check for externally provided cellweights and if so initialise weights
00443     scalar minWeights = gMin(cWeights);
00444     if (cWeights.size() > 0)
00445     {
00446         if (minWeights <= 0)
00447         {
00448             WarningIn
00449             (
00450                 "metisDecomp::decompose"
00451                 "(const pointField&, const scalarField&)"
00452             )   << "Illegal minimum weight " << minWeights
00453                 << endl;
00454         }
00455 
00456         if (cWeights.size() != mesh_.nCells())
00457         {
00458             FatalErrorIn
00459             (
00460                 "parMetisDecomp::decompose"
00461                 "(const pointField&, const scalarField&)"
00462             )   << "Number of cell weights " << cWeights.size()
00463                 << " does not equal number of cells " << mesh_.nCells()
00464                 << exit(FatalError);
00465         }
00466 
00467         // Convert to integers.
00468         cellWeights.setSize(cWeights.size());
00469         forAll(cellWeights, i)
00470         {
00471             cellWeights[i] = int(cWeights[i]/minWeights);
00472         }
00473     }
00474 
00475 
00476     // Check for user supplied weights and decomp options
00477     if (decompositionDict_.found("metisCoeffs"))
00478     {
00479         const dictionary& metisCoeffs =
00480             decompositionDict_.subDict("metisCoeffs");
00481         word weightsFile;
00482 
00483         if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
00484         {
00485             Info<< "parMetisDecomp : Using cell-based weights read from "
00486                 << weightsFile << endl;
00487 
00488             labelIOField cellIOWeights
00489             (
00490                 IOobject
00491                 (
00492                     weightsFile,
00493                     mesh_.time().timeName(),
00494                     mesh_,
00495                     IOobject::MUST_READ,
00496                     IOobject::AUTO_WRITE
00497                 )
00498             );
00499             cellWeights.transfer(cellIOWeights);
00500 
00501             if (cellWeights.size() != mesh_.nCells())
00502             {
00503                 FatalErrorIn
00504                 (
00505                     "parMetisDecomp::decompose"
00506                     "(const pointField&, const scalarField&)"
00507                 )   << "Number of cell weights " << cellWeights.size()
00508                     << " read from " << cellIOWeights.objectPath()
00509                     << " does not equal number of cells " << mesh_.nCells()
00510                     << exit(FatalError);
00511             }
00512         }
00513 
00514         if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
00515         {
00516             Info<< "parMetisDecomp : Using face-based weights read from "
00517                 << weightsFile << endl;
00518 
00519             labelIOField weights
00520             (
00521                 IOobject
00522                 (
00523                     weightsFile,
00524                     mesh_.time().timeName(),
00525                     mesh_,
00526                     IOobject::MUST_READ,
00527                     IOobject::AUTO_WRITE
00528                 )
00529             );
00530 
00531             if (weights.size() != mesh_.nFaces())
00532             {
00533                 FatalErrorIn
00534                 (
00535                     "parMetisDecomp::decompose"
00536                     "(const pointField&, const scalarField&)"
00537                 )   << "Number of face weights " << weights.size()
00538                     << " does not equal number of internal and boundary faces "
00539                     << mesh_.nFaces()
00540                     << exit(FatalError);
00541             }
00542 
00543             faceWeights.setSize(adjncy.size());
00544 
00545             // Assume symmetric weights. Keep same ordering as adjncy.
00546             List<int> nFacesPerCell(mesh_.nCells(), 0);
00547 
00548             // Handle internal faces
00549             for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
00550             {
00551                 label w = weights[faceI];
00552 
00553                 label own = mesh_.faceOwner()[faceI];
00554                 label nei = mesh_.faceNeighbour()[faceI];
00555 
00556                 faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
00557                 faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
00558             }
00559             // Coupled boundary faces
00560             const polyBoundaryMesh& patches = mesh_.boundaryMesh();
00561 
00562             forAll(patches, patchI)
00563             {
00564                 const polyPatch& pp = patches[patchI];
00565 
00566                 if (pp.coupled())
00567                 {
00568                     label faceI = pp.start();
00569 
00570                     forAll(pp, i)
00571                     {
00572                         label w = weights[faceI];
00573                         label own = mesh_.faceOwner()[faceI];
00574                         faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
00575                         faceI++;
00576                     }
00577                 }
00578             }
00579         }
00580 
00581         if (metisCoeffs.readIfPresent("options", options))
00582         {
00583             Info<< "Using Metis options     " << options
00584                 << nl << endl;
00585 
00586             if (options.size() != 3)
00587             {
00588                 FatalErrorIn
00589                 (
00590                     "parMetisDecomp::decompose"
00591                     "(const pointField&, const scalarField&)"
00592                 )   << "Number of options " << options.size()
00593                     << " should be three." << exit(FatalError);
00594             }
00595         }
00596     }
00597 
00598 
00599     // Do actual decomposition
00600     List<int> finalDecomp;
00601     decompose
00602     (
00603         xadj,
00604         adjncy,
00605         cc,
00606         cellWeights,
00607         faceWeights,
00608         options,
00609 
00610         finalDecomp
00611     );
00612 
00613     // Copy back to labelList
00614     labelList decomp(finalDecomp.size());
00615     forAll(decomp, i)
00616     {
00617         decomp[i] = finalDecomp[i];
00618     }
00619     return decomp;
00620 }
00621 
00622 
00623 Foam::labelList Foam::parMetisDecomp::decompose
00624 (
00625     const labelList& cellToRegion,
00626     const pointField& regionPoints,
00627     const scalarField& regionWeights
00628 )
00629 {
00630     const labelList& faceOwner = mesh_.faceOwner();
00631     const labelList& faceNeighbour = mesh_.faceNeighbour();
00632     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
00633 
00634     if (cellToRegion.size() != mesh_.nCells())
00635     {
00636         FatalErrorIn
00637         (
00638             "parMetisDecomp::decompose(const labelList&, const pointField&)"
00639         )   << "Size of cell-to-coarse map " << cellToRegion.size()
00640             << " differs from number of cells in mesh " << mesh_.nCells()
00641             << exit(FatalError);
00642     }
00643 
00644 
00645     // Global region numbering engine
00646     globalIndex globalRegions(regionPoints.size());
00647 
00648 
00649     // Get renumbered owner region on other side of coupled faces
00650     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00651 
00652     List<int> globalNeighbour(mesh_.nFaces()-mesh_.nInternalFaces());
00653 
00654     forAll(patches, patchI)
00655     {
00656         const polyPatch& pp = patches[patchI];
00657 
00658         if (pp.coupled())
00659         {
00660             label faceI = pp.start();
00661             label bFaceI = pp.start() - mesh_.nInternalFaces();
00662 
00663             forAll(pp, i)
00664             {
00665                 label ownRegion = cellToRegion[faceOwner[faceI]];
00666                 globalNeighbour[bFaceI++] = globalRegions.toGlobal(ownRegion);
00667                 faceI++;
00668             }
00669         }
00670     }
00671 
00672     // Get the cell on the other side of coupled patches
00673     syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
00674 
00675 
00676     // Get globalCellCells on coarse mesh
00677     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00678 
00679     labelListList globalRegionRegions;
00680     {
00681         List<DynamicList<label> > dynRegionRegions(regionPoints.size());
00682 
00683         // Internal faces first
00684         forAll(faceNeighbour, faceI)
00685         {
00686             label ownRegion = cellToRegion[faceOwner[faceI]];
00687             label neiRegion = cellToRegion[faceNeighbour[faceI]];
00688 
00689             if (ownRegion != neiRegion)
00690             {
00691                 label globalOwn = globalRegions.toGlobal(ownRegion);
00692                 label globalNei = globalRegions.toGlobal(neiRegion);
00693 
00694                 if (findIndex(dynRegionRegions[ownRegion], globalNei) == -1)
00695                 {
00696                     dynRegionRegions[ownRegion].append(globalNei);
00697                 }
00698                 if (findIndex(dynRegionRegions[neiRegion], globalOwn) == -1)
00699                 {
00700                     dynRegionRegions[neiRegion].append(globalOwn);
00701                 }
00702             }
00703         }
00704 
00705         // Coupled boundary faces
00706         forAll(patches, patchI)
00707         {
00708             const polyPatch& pp = patches[patchI];
00709 
00710             if (pp.coupled())
00711             {
00712                 label faceI = pp.start();
00713                 label bFaceI = pp.start() - mesh_.nInternalFaces();
00714 
00715                 forAll(pp, i)
00716                 {
00717                     label ownRegion = cellToRegion[faceOwner[faceI]];
00718                     label globalNei = globalNeighbour[bFaceI++];
00719                     faceI++;
00720 
00721                     if (findIndex(dynRegionRegions[ownRegion], globalNei) == -1)
00722                     {
00723                         dynRegionRegions[ownRegion].append(globalNei);
00724                     }
00725                 }
00726             }
00727         }
00728 
00729         globalRegionRegions.setSize(dynRegionRegions.size());
00730         forAll(dynRegionRegions, i)
00731         {
00732             globalRegionRegions[i].transfer(dynRegionRegions[i]);
00733         }
00734     }
00735 
00736     labelList regionDecomp
00737     (
00738         decompose
00739         (
00740             globalRegionRegions,
00741             regionPoints,
00742             regionWeights
00743         )
00744     );
00745 
00746     // Rework back into decomposition for original mesh_
00747     labelList cellDistribution(cellToRegion.size());
00748 
00749     forAll(cellDistribution, cellI)
00750     {
00751         cellDistribution[cellI] = regionDecomp[cellToRegion[cellI]];
00752     }
00753     return cellDistribution;
00754 }
00755 
00756 
00757 Foam::labelList Foam::parMetisDecomp::decompose
00758 (
00759     const labelListList& globalCellCells,
00760     const pointField& cellCentres,
00761     const scalarField& cWeights
00762 )
00763 {
00764     if (cellCentres.size() != globalCellCells.size())
00765     {
00766         FatalErrorIn
00767         (
00768             "parMetisDecomp::decompose(const labelListList&"
00769             ", const pointField&, const scalarField&)"
00770         )   << "Inconsistent number of cells (" << globalCellCells.size()
00771             << ") and number of cell centres (" << cellCentres.size()
00772             << ") or weights (" << cWeights.size() << ")." << exit(FatalError);
00773     }
00774 
00775     // For running sequential ...
00776     if (Pstream::nProcs() <= 1)
00777     {
00778         return metisDecomp(decompositionDict_, mesh_)
00779             .decompose(globalCellCells, cellCentres, cWeights);
00780     }
00781 
00782 
00783     // Make Metis Distributed CSR (Compressed Storage Format) storage
00784 
00785     // Connections
00786     Field<int> adjncy;
00787     // Offsets into adjncy
00788     Field<int> xadj;
00789     scotchDecomp::calcCSR(globalCellCells, adjncy, xadj);
00790 
00791     // decomposition options. 0 = use defaults
00792     List<int> options(3, 0);
00793     //options[0] = 1;     // don't use defaults but use values below
00794     //options[1] = -1;    // full debug info
00795     //options[2] = 15;    // random number seed
00796 
00797     // cell weights (so on the vertices of the dual)
00798     Field<int> cellWeights;
00799 
00800     // face weights (so on the edges of the dual)
00801     Field<int> faceWeights;
00802 
00803 
00804     // Check for externally provided cellweights and if so initialise weights
00805     scalar minWeights = gMin(cWeights);
00806     if (cWeights.size() > 0)
00807     {
00808         if (minWeights <= 0)
00809         {
00810             WarningIn
00811             (
00812                 "parMetisDecomp::decompose(const labelListList&"
00813                 ", const pointField&, const scalarField&)"
00814             )   << "Illegal minimum weight " << minWeights
00815                 << endl;
00816         }
00817 
00818         if (cWeights.size() != globalCellCells.size())
00819         {
00820             FatalErrorIn
00821             (
00822                 "parMetisDecomp::decompose(const labelListList&"
00823                 ", const pointField&, const scalarField&)"
00824             )   << "Number of cell weights " << cWeights.size()
00825                 << " does not equal number of cells " << globalCellCells.size()
00826                 << exit(FatalError);
00827         }
00828 
00829         // Convert to integers.
00830         cellWeights.setSize(cWeights.size());
00831         forAll(cellWeights, i)
00832         {
00833             cellWeights[i] = int(cWeights[i]/minWeights);
00834         }
00835     }
00836 
00837 
00838     // Check for user supplied weights and decomp options
00839     if (decompositionDict_.found("metisCoeffs"))
00840     {
00841         const dictionary& metisCoeffs =
00842             decompositionDict_.subDict("metisCoeffs");
00843 
00844         if (metisCoeffs.readIfPresent("options", options))
00845         {
00846             Info<< "Using Metis options     " << options
00847                 << nl << endl;
00848 
00849             if (options.size() != 3)
00850             {
00851                 FatalErrorIn
00852                 (
00853                     "parMetisDecomp::decompose(const labelListList&"
00854                     ", const pointField&, const scalarField&)"
00855                 )   << "Number of options " << options.size()
00856                     << " should be three." << exit(FatalError);
00857             }
00858         }
00859     }
00860 
00861 
00862     // Do actual decomposition
00863     List<int> finalDecomp;
00864     decompose
00865     (
00866         xadj,
00867         adjncy,
00868         cellCentres,
00869         cellWeights,
00870         faceWeights,
00871         options,
00872 
00873         finalDecomp
00874     );
00875 
00876     // Copy back to labelList
00877     labelList decomp(finalDecomp.size());
00878     forAll(decomp, i)
00879     {
00880         decomp[i] = finalDecomp[i];
00881     }
00882     return decomp;
00883 }
00884 
00885 
00886 void Foam::parMetisDecomp::calcMetisDistributedCSR
00887 (
00888     const polyMesh& mesh,
00889     List<int>& adjncy,
00890     List<int>& xadj
00891 )
00892 {
00893     // Create global cell numbers
00894     // ~~~~~~~~~~~~~~~~~~~~~~~~~~
00895 
00896     globalIndex globalCells(mesh.nCells());
00897 
00898 
00899     //
00900     // Make Metis Distributed CSR (Compressed Storage Format) storage
00901     //   adjncy      : contains cellCells (= edges in graph)
00902     //   xadj(celli) : start of information in adjncy for celli
00903     //
00904 
00905 
00906     const labelList& faceOwner = mesh.faceOwner();
00907     const labelList& faceNeighbour = mesh.faceNeighbour();
00908     const polyBoundaryMesh& patches = mesh.boundaryMesh();
00909 
00910 
00911     // Get renumbered owner on other side of coupled faces
00912     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00913 
00914     List<int> globalNeighbour(mesh.nFaces()-mesh.nInternalFaces());
00915 
00916     forAll(patches, patchI)
00917     {
00918         const polyPatch& pp = patches[patchI];
00919 
00920         if (pp.coupled())
00921         {
00922             label faceI = pp.start();
00923             label bFaceI = pp.start() - mesh.nInternalFaces();
00924 
00925             forAll(pp, i)
00926             {
00927                 globalNeighbour[bFaceI++] = globalCells.toGlobal
00928                 (
00929                     faceOwner[faceI++]
00930                 );
00931             }
00932         }
00933     }
00934 
00935     // Get the cell on the other side of coupled patches
00936     syncTools::swapBoundaryFaceList(mesh, globalNeighbour, false);
00937 
00938 
00939     // Count number of faces (internal + coupled)
00940     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00941 
00942     // Number of faces per cell
00943     List<int> nFacesPerCell(mesh.nCells(), 0);
00944 
00945     // Number of coupled faces
00946     label nCoupledFaces = 0;
00947 
00948     for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
00949     {
00950         nFacesPerCell[faceOwner[faceI]]++;
00951         nFacesPerCell[faceNeighbour[faceI]]++;
00952     }
00953     // Handle coupled faces
00954     HashSet<edge, Hash<edge> > cellPair(mesh.nFaces()-mesh.nInternalFaces());
00955 
00956     forAll(patches, patchI)
00957     {
00958         const polyPatch& pp = patches[patchI];
00959 
00960         if (pp.coupled())
00961         {
00962             label faceI = pp.start();
00963 
00964             forAll(pp, i)
00965             {
00966                 label own = faceOwner[faceI];
00967                 label globalNei = globalNeighbour[faceI-mesh.nInternalFaces()];
00968 
00969                 if (cellPair.insert(edge(own, globalNei)))
00970                 {
00971                     nCoupledFaces++;
00972                     nFacesPerCell[faceOwner[faceI]]++;
00973                 }
00974                 faceI++;
00975             }
00976         }
00977     }
00978 
00979 
00980     // Fill in xadj
00981     // ~~~~~~~~~~~~
00982 
00983     xadj.setSize(mesh.nCells()+1);
00984 
00985     int freeAdj = 0;
00986 
00987     for (label cellI = 0; cellI < mesh.nCells(); cellI++)
00988     {
00989         xadj[cellI] = freeAdj;
00990 
00991         freeAdj += nFacesPerCell[cellI];
00992     }
00993     xadj[mesh.nCells()] = freeAdj;
00994 
00995 
00996 
00997     // Fill in adjncy
00998     // ~~~~~~~~~~~~~~
00999 
01000     adjncy.setSize(2*mesh.nInternalFaces() + nCoupledFaces);
01001 
01002     nFacesPerCell = 0;
01003 
01004     // For internal faces is just offsetted owner and neighbour
01005     for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
01006     {
01007         label own = faceOwner[faceI];
01008         label nei = faceNeighbour[faceI];
01009 
01010         adjncy[xadj[own] + nFacesPerCell[own]++] = globalCells.toGlobal(nei);
01011         adjncy[xadj[nei] + nFacesPerCell[nei]++] = globalCells.toGlobal(own);
01012     }
01013     // For boundary faces is offsetted coupled neighbour
01014     cellPair.clear();
01015     forAll(patches, patchI)
01016     {
01017         const polyPatch& pp = patches[patchI];
01018 
01019         if (pp.coupled())
01020         {
01021             label faceI = pp.start();
01022             label bFaceI = pp.start()-mesh.nInternalFaces();
01023 
01024             forAll(pp, i)
01025             {
01026                 label own = faceOwner[faceI];
01027                 label globalNei = globalNeighbour[bFaceI];
01028 
01029                 if (cellPair.insert(edge(own, globalNei)))
01030                 {
01031                     adjncy[xadj[own] + nFacesPerCell[own]++] =
01032                         globalNeighbour[bFaceI];
01033                 }
01034 
01035                 faceI++;
01036                 bFaceI++;
01037             }
01038         }
01039     }
01040 }
01041 
01042 
01043 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines