00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00046
00047 namespace Foam
00048 {
00049 defineTypeNameAndDebug(parMetisDecomp, 0);
00050
00051 addToRunTimeSelectionTable
00052 (
00053 decompositionMethod,
00054 parMetisDecomp,
00055 dictionaryMesh
00056 );
00057 }
00058
00059
00060
00061
00062
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
00076 int numFlag = 0;
00077
00078
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
00092 List<int> nLocalCells(Pstream::nProcs());
00093 nLocalCells[Pstream::myProcNo()] = xadj.size()-1;
00094 Pstream::gatherList(nLocalCells);
00095 Pstream::scatterList(nLocalCells);
00096
00097
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
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
00119
00120
00121
00122
00123
00124
00125
00126
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
00138
00139 if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
00140 {
00141
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
00160 prepend(prevAdjncy, adjncy);
00161
00162 xadj += prevAdjncy.size();
00163 prepend(prevXadj, xadj);
00164
00165 prepend(prevXyz, xyz);
00166
00167 prepend(prevCellWeights, cellWeights);
00168 prepend(prevFaceWeights, faceWeights);
00169 }
00170
00171
00172
00173
00174 if (nSendCells[Pstream::myProcNo()] > 0)
00175 {
00176
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
00185
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
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
00226 forAll(nSendCells, procI)
00227 {
00228
00229 nLocalCells[procI] -= nSendCells[procI];
00230
00231 if (procI >= 1)
00232 {
00233
00234 nLocalCells[procI] += nSendCells[procI-1];
00235 }
00236 }
00237
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
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;
00263 }
00264 if (faceWeights.size())
00265 {
00266 adjwgtPtr = faceWeights.begin();
00267 wgtFlag += 1;
00268 }
00269
00270
00271
00272 int nCon = 1;
00273
00274 Field<floatScalar> tpwgts(nCon*nProcessors_, 1./nProcessors_);
00275
00276 Field<floatScalar> ubvec(nCon, 1.02);
00277 if (nProcessors_ == 1)
00278 {
00279
00280 ubvec[0] = 1;
00281 }
00282
00283 MPI_Comm comm = MPI_COMM_WORLD;
00284
00285
00286 finalDecomp.setSize(nLocalCells[Pstream::myProcNo()]);
00287
00288
00289 int edgeCut = 0;
00290
00291
00292 ParMETIS_V3_PartGeomKway
00293 (
00294 cellOffsets.begin(),
00295 xadj.begin(),
00296 adjncy.begin(),
00297 vwgtPtr,
00298 adjwgtPtr,
00299 &wgtFlag,
00300 &numFlag,
00301 &nDims,
00302 xyz.begin(),
00303 &nCon,
00304 &nProcessors_,
00305 tpwgts.begin(),
00306 ubvec.begin(),
00307 const_cast<List<int>&>(options).begin(),
00308 &edgeCut,
00309 finalDecomp.begin(),
00310 &comm
00311 );
00312
00313
00314
00315
00316
00317
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
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
00352 finalDecomp.setSize(finalDecomp.size()-nToPrevious);
00353 }
00354
00355 return edgeCut;
00356 }
00357
00358
00359
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
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
00407 if (Pstream::nProcs() <= 1)
00408 {
00409 return metisDecomp(decompositionDict_, mesh_).decompose
00410 (
00411 cc,
00412 cWeights
00413 );
00414 }
00415
00416
00417
00418 Field<int> adjncy;
00419
00420 Field<int> xadj;
00421 calcMetisDistributedCSR
00422 (
00423 mesh_,
00424 adjncy,
00425 xadj
00426 );
00427
00428
00429
00430 List<int> options(3, 0);
00431
00432
00433
00434
00435
00436 Field<int> cellWeights;
00437
00438
00439 Field<int> faceWeights;
00440
00441
00442
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
00468 cellWeights.setSize(cWeights.size());
00469 forAll(cellWeights, i)
00470 {
00471 cellWeights[i] = int(cWeights[i]/minWeights);
00472 }
00473 }
00474
00475
00476
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
00546 List<int> nFacesPerCell(mesh_.nCells(), 0);
00547
00548
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
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
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
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
00646 globalIndex globalRegions(regionPoints.size());
00647
00648
00649
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
00673 syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
00674
00675
00676
00677
00678
00679 labelListList globalRegionRegions;
00680 {
00681 List<DynamicList<label> > dynRegionRegions(regionPoints.size());
00682
00683
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
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
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
00776 if (Pstream::nProcs() <= 1)
00777 {
00778 return metisDecomp(decompositionDict_, mesh_)
00779 .decompose(globalCellCells, cellCentres, cWeights);
00780 }
00781
00782
00783
00784
00785
00786 Field<int> adjncy;
00787
00788 Field<int> xadj;
00789 scotchDecomp::calcCSR(globalCellCells, adjncy, xadj);
00790
00791
00792 List<int> options(3, 0);
00793
00794
00795
00796
00797
00798 Field<int> cellWeights;
00799
00800
00801 Field<int> faceWeights;
00802
00803
00804
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
00830 cellWeights.setSize(cWeights.size());
00831 forAll(cellWeights, i)
00832 {
00833 cellWeights[i] = int(cWeights[i]/minWeights);
00834 }
00835 }
00836
00837
00838
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
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
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
00894
00895
00896 globalIndex globalCells(mesh.nCells());
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906 const labelList& faceOwner = mesh.faceOwner();
00907 const labelList& faceNeighbour = mesh.faceNeighbour();
00908 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00909
00910
00911
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
00936 syncTools::swapBoundaryFaceList(mesh, globalNeighbour, false);
00937
00938
00939
00940
00941
00942
00943 List<int> nFacesPerCell(mesh.nCells(), 0);
00944
00945
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
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
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
00998
00999
01000 adjncy.setSize(2*mesh.nInternalFaces() + nCoupledFaces);
01001
01002 nFacesPerCell = 0;
01003
01004
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
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