/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2016-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011-2016 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "metisDecomp.H" #include "addToRunTimeSelectionTable.H" #include "Time.H" #include "PrecisionAdaptor.H" // Probably not needed... #define MPICH_SKIP_MPICXX #define OMPI_SKIP_MPICXX #include "metis.h" // Provide a clear error message if we have a severe size mismatch // Allow widening, but not narrowing // // Metis has an 'idx_t' type, but the IDXTYPEWIDTH define is perhaps // more future-proof? //#ifdef IDXTYPEWIDTH //static_assert //( // sizeof(Foam::label) > (IDXTYPEWIDTH/8), // "sizeof(Foam::label) > (IDXTYPEWIDTH/8), check your metis headers" //); //#endif // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(metisDecomp, 0); addToRunTimeSelectionTable ( decompositionMethod, metisDecomp, dictionary ); addToRunTimeSelectionTable ( decompositionMethod, metisDecomp, dictionaryRegion ); } // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // Foam::label Foam::metisDecomp::decomposeSerial ( const labelList& adjncy, const labelList& xadj, const List& cWeights, labelList& decomp ) const { // Method of decomposition // recursive: multi-level recursive bisection (default) // k-way: multi-level k-way word method("recursive"); const dictionary* coeffsDictPtr = decompDict_.findDict("metisCoeffs"); idx_t numCells = xadj.size()-1; // Decomposition options List options(METIS_NOPTIONS); METIS_SetDefaultOptions(options.data()); // Processor weights initialised with no size, only used if specified in // a file Field processorWeights; // Cell weights (so on the vertices of the dual) List cellWeights; // Face weights (so on the edges of the dual) List faceWeights; // Check for externally provided cellweights and if so initialise weights // Note: min, not gMin since routine runs on master only. const scalar minWeights = min(cWeights); if (!cWeights.empty()) { if (minWeights <= 0) { WarningInFunction << "Illegal minimum weight " << minWeights << endl; } if (cWeights.size() != numCells) { FatalErrorInFunction << "Number of cell weights " << cWeights.size() << " does not equal number of cells " << numCells << exit(FatalError); } // Convert to integers. cellWeights.setSize(cWeights.size()); forAll(cellWeights, i) { cellWeights[i] = idx_t(cWeights[i]/minWeights); } } // Check for user supplied weights and decomp options if (coeffsDictPtr) { const dictionary& coeffDict = *coeffsDictPtr; word weightsFile; if (coeffDict.readIfPresent("method", method)) { if (method != "recursive" && method != "k-way") { FatalErrorInFunction << "Method " << method << " in metisCoeffs in dictionary : " << decompDict_.name() << " should be 'recursive' or 'k-way'" << exit(FatalError); } Info<< "metisDecomp : Using Metis method " << method << nl << endl; } if (coeffDict.readIfPresent("options", options)) { if (options.size() != METIS_NOPTIONS) { FatalErrorInFunction << "Number of options in metisCoeffs in dictionary : " << decompDict_.name() << " should be " << METIS_NOPTIONS << exit(FatalError); } Info<< "metisDecomp : Using Metis options " << options << nl << endl; } if (coeffDict.readIfPresent("processorWeights", processorWeights)) { processorWeights /= sum(processorWeights); if (processorWeights.size() != nDomains_) { FatalErrorInFunction << "Number of processor weights " << processorWeights.size() << " does not equal number of domains " << nDomains_ << exit(FatalError); } } } idx_t ncon = 1; idx_t nProcs = nDomains_; // Addressing ConstPrecisionAdaptor xadj_param(xadj); ConstPrecisionAdaptor adjncy_param(adjncy); // Output: cell -> processor addressing decomp.resize(numCells); PrecisionAdaptor decomp_param(decomp); // Output: number of cut edges idx_t edgeCut = 0; if (method == "recursive") { METIS_PartGraphRecursive ( &numCells, // num vertices in graph &ncon, // num balancing constraints xadj_param.constCast().data(), // indexing into adjncy adjncy_param.constCast().data(), // neighbour info cellWeights.data(), // vertex wts nullptr, // vsize: total communication vol faceWeights.data(), // edge wts &nProcs, // nParts processorWeights.data(), // tpwgts nullptr, // ubvec: processor imbalance (default) options.data(), &edgeCut, decomp_param.ref().data() ); } else { METIS_PartGraphKway ( &numCells, // num vertices in graph &ncon, // num balancing constraints xadj_param.constCast().data(), // indexing into adjncy adjncy_param.constCast().data(), // neighbour info cellWeights.data(), // vertex wts nullptr, // vsize: total communication vol faceWeights.data(), // edge wts &nProcs, // nParts processorWeights.data(), // tpwgts nullptr, // ubvec: processor imbalance (default) options.data(), &edgeCut, decomp_param.ref().data() ); } return edgeCut; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::metisDecomp::metisDecomp(const dictionary& decompDict) : metisLikeDecomp(typeName, decompDict, selectionType::NULL_DICT) {} Foam::metisDecomp::metisDecomp ( const dictionary& decompDict, const word& regionName ) : metisLikeDecomp(typeName, decompDict, regionName, selectionType::NULL_DICT) {} // ************************************************************************* //