Files
openfoam/src/parallel/decompose/metisDecomp/metisDecomp.C
2019-10-29 11:42:55 +01:00

265 lines
8.1 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#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<scalar>& 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<idx_t> options(METIS_NOPTIONS);
METIS_SetDefaultOptions(options.data());
// Processor weights initialised with no size, only used if specified in
// a file
Field<real_t> processorWeights;
// Cell weights (so on the vertices of the dual)
List<idx_t> cellWeights;
// Face weights (so on the edges of the dual)
List<idx_t> 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<idx_t, label, List> xadj_param(xadj);
ConstPrecisionAdaptor<idx_t, label, List> adjncy_param(adjncy);
// Output: cell -> processor addressing
decomp.resize(numCells);
PrecisionAdaptor<idx_t, label, List> 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)
{}
// ************************************************************************* //