mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
weighted decomposition
This commit is contained in:
@ -25,8 +25,6 @@ License
|
||||
InClass
|
||||
decompositionMethod
|
||||
|
||||
Description
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "decompositionMethod.H"
|
||||
@ -104,14 +102,26 @@ Foam::autoPtr<Foam::decompositionMethod> Foam::decompositionMethod::New
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::decompositionMethod::decompose
|
||||
(
|
||||
const pointField& points
|
||||
)
|
||||
{
|
||||
scalarField weights(0);
|
||||
|
||||
return decompose(points, weights);
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::decompositionMethod::decompose
|
||||
(
|
||||
const labelList& fineToCoarse,
|
||||
const pointField& coarsePoints
|
||||
const pointField& coarsePoints,
|
||||
const scalarField& coarseWeights
|
||||
)
|
||||
{
|
||||
// Decompose based on agglomerated points
|
||||
labelList coarseDistribution(decompose(coarsePoints));
|
||||
labelList coarseDistribution(decompose(coarsePoints, coarseWeights));
|
||||
|
||||
// Rework back into decomposition for original mesh_
|
||||
labelList fineDistribution(fineToCoarse.size());
|
||||
@ -125,6 +135,18 @@ Foam::labelList Foam::decompositionMethod::decompose
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::decompositionMethod::decompose
|
||||
(
|
||||
const labelList& fineToCoarse,
|
||||
const pointField& coarsePoints
|
||||
)
|
||||
{
|
||||
scalarField coarseWeights(0);
|
||||
|
||||
return decompose(fineToCoarse, coarsePoints, coarseWeights);
|
||||
}
|
||||
|
||||
|
||||
void Foam::decompositionMethod::calcCellCells
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
@ -170,4 +192,16 @@ void Foam::decompositionMethod::calcCellCells
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::decompositionMethod::decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
)
|
||||
{
|
||||
scalarField cWeights(0);
|
||||
|
||||
return decompose(globalCellCells, cc, cWeights);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -150,20 +150,37 @@ public:
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Use the
|
||||
// mesh connectivity (if needed)
|
||||
virtual labelList decompose(const pointField&) = 0;
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
) = 0;
|
||||
|
||||
//- Like decompose but with uniform weights on the points
|
||||
virtual labelList decompose(const pointField&);
|
||||
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Gets
|
||||
// passed agglomeration map (from fine to coarse cells) and coarse cell
|
||||
// location. Can be overridden by decomposers that provide this
|
||||
// functionality natively. Coarse cells are local to the processor
|
||||
// (if in parallel). If you want to have coarse cells spanning
|
||||
// processors use the next function below instead.
|
||||
// processors use the globalCellCells instead.
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelList& cellToRegion,
|
||||
const pointField& regionPoints,
|
||||
const scalarField& regionWeights
|
||||
);
|
||||
|
||||
//- Like decompose but with uniform weights on the regions
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelList& cellToRegion,
|
||||
const pointField& regionPoints
|
||||
);
|
||||
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Explicitly
|
||||
// provided connectivity - does not use mesh_.
|
||||
// The connectivity is equal to mesh.cellCells() except for
|
||||
@ -174,9 +191,17 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
) = 0;
|
||||
|
||||
//- Like decompose but with uniform weights on the cells
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -142,6 +142,38 @@ Foam::label Foam::hierarchGeomDecomp::findLower
|
||||
}
|
||||
|
||||
|
||||
// Create a mapping between the index and the weighted size.
|
||||
// For convenience, sortedWeightedSize is one size bigger than current. This
|
||||
// avoids extra tests.
|
||||
void Foam::hierarchGeomDecomp::calculateSortedWeightedSizes
|
||||
(
|
||||
const labelList& current,
|
||||
const labelList& indices,
|
||||
const scalarField& weights,
|
||||
const label globalCurrentSize,
|
||||
|
||||
scalarField& sortedWeightedSizes
|
||||
)
|
||||
{
|
||||
// Evaluate cumulative weights.
|
||||
sortedWeightedSizes[0] = 0;
|
||||
forAll(current, i)
|
||||
{
|
||||
label pointI = current[indices[i]];
|
||||
sortedWeightedSizes[i + 1] = sortedWeightedSizes[i] + weights[pointI];
|
||||
}
|
||||
// Non-dimensionalise and multiply by size.
|
||||
scalar globalCurrentLength = returnReduce
|
||||
(
|
||||
sortedWeightedSizes[current.size()],
|
||||
sumOp<scalar>()
|
||||
);
|
||||
// Normalise weights by global sum of weights and multiply through
|
||||
// by global size.
|
||||
sortedWeightedSizes *= (globalCurrentSize/globalCurrentLength);
|
||||
}
|
||||
|
||||
|
||||
// Find position in values so between minIndex and this position there
|
||||
// are wantedSize elements.
|
||||
void Foam::hierarchGeomDecomp::findBinary
|
||||
@ -170,7 +202,6 @@ void Foam::hierarchGeomDecomp::findBinary
|
||||
label midPrev = -1;
|
||||
label highPrev = -1;
|
||||
|
||||
//while (low <= high)
|
||||
while (true)
|
||||
{
|
||||
label size = returnReduce(mid-minIndex, sumOp<label>());
|
||||
@ -204,7 +235,98 @@ void Foam::hierarchGeomDecomp::findBinary
|
||||
mid = findLower(values, midValue, low, high);
|
||||
|
||||
// Safeguard if same as previous.
|
||||
bool hasNotChanged = (mid == midPrev) && (low == lowPrev) && (high == highPrev);
|
||||
bool hasNotChanged =
|
||||
(mid == midPrev)
|
||||
&& (low == lowPrev)
|
||||
&& (high == highPrev);
|
||||
|
||||
if (returnReduce(hasNotChanged, andOp<bool>()))
|
||||
{
|
||||
WarningIn("hierarchGeomDecomp::findBinary(..)")
|
||||
<< "unable to find desired deomposition split, making do!"
|
||||
<< endl;
|
||||
break;
|
||||
}
|
||||
|
||||
midPrev = mid;
|
||||
lowPrev = low;
|
||||
highPrev = high;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Find position in values so between minIndex and this position there
|
||||
// are wantedSize elements.
|
||||
void Foam::hierarchGeomDecomp::findBinary
|
||||
(
|
||||
const label sizeTol,
|
||||
const List<scalar>& sortedWeightedSizes,
|
||||
const List<scalar>& values,
|
||||
const label minIndex, // index of previous value
|
||||
const scalar minValue, // value at minIndex
|
||||
const scalar maxValue, // global max of values
|
||||
const scalar wantedSize, // wanted size
|
||||
|
||||
label& mid, // index where size of bin is
|
||||
// wantedSize (to within sizeTol)
|
||||
scalar& midValue // value at mid
|
||||
)
|
||||
{
|
||||
label low = minIndex;
|
||||
scalar lowValue = minValue;
|
||||
|
||||
scalar highValue = maxValue;
|
||||
// (one beyond) index of highValue
|
||||
label high = values.size();
|
||||
|
||||
// Safeguards to avoid infinite loop.
|
||||
label lowPrev = -1;
|
||||
label midPrev = -1;
|
||||
label highPrev = -1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
label weightedSize = returnReduce
|
||||
(
|
||||
sortedWeightedSizes[mid] - sortedWeightedSizes[minIndex],
|
||||
sumOp<label>()
|
||||
);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "low:" << low << " lowValue:" << lowValue
|
||||
<< " high:" << high << " highValue:" << highValue
|
||||
<< " mid:" << mid << " midValue:" << midValue << nl
|
||||
<< "globalSize:" << weightedSize
|
||||
<< " wantedSize:" << wantedSize
|
||||
<< " sizeTol:" << sizeTol << endl;
|
||||
}
|
||||
|
||||
if (wantedSize < weightedSize - sizeTol)
|
||||
{
|
||||
high = mid;
|
||||
highValue = midValue;
|
||||
}
|
||||
else if (wantedSize > weightedSize + sizeTol)
|
||||
{
|
||||
low = mid;
|
||||
lowValue = midValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Update mid, midValue
|
||||
midValue = 0.5*(lowValue+highValue);
|
||||
mid = findLower(values, midValue, low, high);
|
||||
|
||||
// Safeguard if same as previous.
|
||||
bool hasNotChanged =
|
||||
(mid == midPrev)
|
||||
&& (low == lowPrev)
|
||||
&& (high == highPrev);
|
||||
|
||||
if (returnReduce(hasNotChanged, andOp<bool>()))
|
||||
{
|
||||
WarningIn("hierarchGeomDecomp::findBinary(..)")
|
||||
@ -394,6 +516,190 @@ void Foam::hierarchGeomDecomp::sortComponent
|
||||
}
|
||||
|
||||
|
||||
// Sort points into bins according to one component. Recurses to next component.
|
||||
void Foam::hierarchGeomDecomp::sortComponent
|
||||
(
|
||||
const label sizeTol,
|
||||
const scalarField& weights,
|
||||
const pointField& points,
|
||||
const labelList& current, // slice of points to decompose
|
||||
const direction componentIndex, // index in decompOrder_
|
||||
const label mult, // multiplication factor for finalDecomp
|
||||
labelList& finalDecomp
|
||||
)
|
||||
{
|
||||
// Current component
|
||||
label compI = decompOrder_[componentIndex];
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "sortComponent : Sorting slice of size " << current.size()
|
||||
<< " in component " << compI << endl;
|
||||
}
|
||||
|
||||
// Storage for sorted component compI
|
||||
SortableList<scalar> sortedCoord(current.size());
|
||||
|
||||
forAll(current, i)
|
||||
{
|
||||
label pointI = current[i];
|
||||
|
||||
sortedCoord[i] = points[pointI][compI];
|
||||
}
|
||||
sortedCoord.sort();
|
||||
|
||||
label globalCurrentSize = returnReduce(current.size(), sumOp<label>());
|
||||
|
||||
// Now evaluate local cumulative weights, based on the sorting.
|
||||
// Make one bigger than the nodes.
|
||||
scalarField sortedWeightedSizes(current.size()+1, 0);
|
||||
calculateSortedWeightedSizes
|
||||
(
|
||||
current,
|
||||
sortedCoord.indices(),
|
||||
weights,
|
||||
globalCurrentSize,
|
||||
sortedWeightedSizes
|
||||
);
|
||||
|
||||
scalar minCoord = returnReduce
|
||||
(
|
||||
(
|
||||
sortedCoord.size()
|
||||
? sortedCoord[0]
|
||||
: GREAT
|
||||
),
|
||||
minOp<scalar>()
|
||||
);
|
||||
|
||||
scalar maxCoord = returnReduce
|
||||
(
|
||||
(
|
||||
sortedCoord.size()
|
||||
? sortedCoord[sortedCoord.size()-1]
|
||||
: -GREAT
|
||||
),
|
||||
maxOp<scalar>()
|
||||
);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "sortComponent : minCoord:" << minCoord
|
||||
<< " maxCoord:" << maxCoord << endl;
|
||||
}
|
||||
|
||||
// starting index (in sortedCoord) of bin (= local)
|
||||
label leftIndex = 0;
|
||||
// starting value of bin (= global since coordinate)
|
||||
scalar leftCoord = minCoord;
|
||||
|
||||
// Sort bins of size n
|
||||
for (label bin = 0; bin < n_[compI]; bin++)
|
||||
{
|
||||
// Now we need to determine the size of the bin (dx). This is
|
||||
// determined by the 'pivot' values - everything to the left of this
|
||||
// value goes in the current bin, everything to the right into the next
|
||||
// bins.
|
||||
|
||||
// Local number of elements
|
||||
label localSize = -1; // offset from leftOffset
|
||||
|
||||
// Value at right of bin (leftIndex+localSize-1)
|
||||
scalar rightCoord = -GREAT;
|
||||
|
||||
if (bin == n_[compI]-1)
|
||||
{
|
||||
// Last bin. Copy all.
|
||||
localSize = current.size()-leftIndex;
|
||||
rightCoord = maxCoord; // note: not used anymore
|
||||
}
|
||||
else
|
||||
{
|
||||
// For the current bin (starting at leftCoord) we want a rightCoord
|
||||
// such that the sum of all weighted sizes are
|
||||
// globalCurrentLength/n_[compI].
|
||||
// We have to iterate to obtain this.
|
||||
|
||||
label rightIndex = current.size();
|
||||
rightCoord = maxCoord;
|
||||
|
||||
// Calculate rightIndex/rightCoord to have wanted size
|
||||
findBinary
|
||||
(
|
||||
sizeTol,
|
||||
sortedWeightedSizes,
|
||||
sortedCoord,
|
||||
leftIndex,
|
||||
leftCoord,
|
||||
maxCoord,
|
||||
globalCurrentSize/n_[compI], // wanted size
|
||||
|
||||
rightIndex,
|
||||
rightCoord
|
||||
);
|
||||
localSize = rightIndex - leftIndex;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "For component " << compI << ", bin " << bin
|
||||
<< " copying" << nl
|
||||
<< "from " << leftCoord << " at local index "
|
||||
<< leftIndex << nl
|
||||
<< "to " << rightCoord << " localSize:"
|
||||
<< localSize << nl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
// Copy localSize elements starting from leftIndex.
|
||||
labelList slice(localSize);
|
||||
|
||||
forAll(slice, i)
|
||||
{
|
||||
label pointI = current[sortedCoord.indices()[leftIndex+i]];
|
||||
|
||||
// Mark point into correct bin
|
||||
finalDecomp[pointI] += bin*mult;
|
||||
|
||||
// And collect for next sorting action
|
||||
slice[i] = pointI;
|
||||
}
|
||||
|
||||
// Sort slice in next component
|
||||
if (componentIndex < 2)
|
||||
{
|
||||
string oldPrefix;
|
||||
if (debug)
|
||||
{
|
||||
oldPrefix = Pout.prefix();
|
||||
Pout.prefix() = " " + oldPrefix;
|
||||
}
|
||||
|
||||
sortComponent
|
||||
(
|
||||
sizeTol,
|
||||
weights,
|
||||
points,
|
||||
slice,
|
||||
componentIndex+1,
|
||||
mult*n_[compI], // Multiplier to apply to decomposition.
|
||||
finalDecomp
|
||||
);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout.prefix() = oldPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
// Step to next bin.
|
||||
leftIndex += localSize;
|
||||
leftCoord = rightCoord;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::hierarchGeomDecomp::hierarchGeomDecomp
|
||||
@ -464,4 +770,47 @@ Foam::labelList Foam::hierarchGeomDecomp::decompose
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::hierarchGeomDecomp::decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& weights
|
||||
)
|
||||
{
|
||||
// construct a list for the final result
|
||||
labelList finalDecomp(points.size(), 0);
|
||||
|
||||
// Start off with every point sorted onto itself.
|
||||
labelList slice(points.size());
|
||||
forAll(slice, i)
|
||||
{
|
||||
slice[i] = i;
|
||||
}
|
||||
|
||||
pointField rotatedPoints = rotDelta_ & points;
|
||||
|
||||
|
||||
// Calculate tolerance of cell distribution. For large cases finding
|
||||
// distibution to the cell exact would cause too many iterations so allow
|
||||
// some slack.
|
||||
label allSize = points.size();
|
||||
reduce(allSize, sumOp<label>());
|
||||
|
||||
const label sizeTol = max(1, label(1E-3*allSize/nProcessors_));
|
||||
|
||||
// Sort recursive
|
||||
sortComponent
|
||||
(
|
||||
sizeTol,
|
||||
weights,
|
||||
rotatedPoints,
|
||||
slice,
|
||||
0, // Sort first component in decompOrder.
|
||||
1, // Offset for different x bins.
|
||||
finalDecomp
|
||||
);
|
||||
|
||||
return finalDecomp;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -80,6 +80,17 @@ class hierarchGeomDecomp
|
||||
//- Convert ordering string ("xyz") into list of components.
|
||||
void setDecompOrder();
|
||||
|
||||
//- Evaluates the weighted sizes for each sorted point.
|
||||
static void calculateSortedWeightedSizes
|
||||
(
|
||||
const labelList& current,
|
||||
const labelList& indices,
|
||||
const scalarField& weights,
|
||||
const label globalCurrentSize,
|
||||
|
||||
scalarField& sortedWeightedSizes
|
||||
);
|
||||
|
||||
//- Find index of t in list inbetween indices left and right
|
||||
static label findLower
|
||||
(
|
||||
@ -104,6 +115,22 @@ class hierarchGeomDecomp
|
||||
scalar& midValue // value at mid
|
||||
);
|
||||
|
||||
//- Find midValue (at local index mid) such that the number of
|
||||
// elements between mid and leftIndex are (globally summed) the
|
||||
// wantedSize. Binary search.
|
||||
static void findBinary
|
||||
(
|
||||
const label sizeTol, // size difference considered acceptible
|
||||
const List<scalar>& sortedWeightedSizes,
|
||||
const List<scalar>&,
|
||||
const label leftIndex, // index of previous value
|
||||
const scalar leftValue, // value at leftIndex
|
||||
const scalar maxValue, // global max of values
|
||||
const scalar wantedSize, // wanted size
|
||||
label& mid, // index where size of bin is wantedSize
|
||||
scalar& midValue // value at mid
|
||||
);
|
||||
|
||||
//- Recursively sort in x,y,z (or rather acc. to decompOrder_)
|
||||
void sortComponent
|
||||
(
|
||||
@ -115,6 +142,19 @@ class hierarchGeomDecomp
|
||||
labelList& finalDecomp // overall decomposition
|
||||
);
|
||||
|
||||
//- Recursively sort in x,y,z (or rather acc. to decompOrder_)
|
||||
//- using weighted points.
|
||||
void sortComponent
|
||||
(
|
||||
const label sizeTol,
|
||||
const scalarField& weights,
|
||||
const pointField&,
|
||||
const labelList& slice, // slice of points to decompose
|
||||
const direction componentIndex, // index in decompOrder_
|
||||
const label prevMult, // multiplication factor
|
||||
labelList& finalDecomp // overall decomposition
|
||||
);
|
||||
|
||||
|
||||
//- Disallow default bitwise copy construct and assignment
|
||||
void operator=(const hierarchGeomDecomp&);
|
||||
@ -156,6 +196,14 @@ public:
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Use the
|
||||
// mesh connectivity (if needed)
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField&,
|
||||
const scalarField& weights
|
||||
);
|
||||
|
||||
//- Without weights. Code for weighted decomposition is a bit complex
|
||||
// so kept separate for now.
|
||||
virtual labelList decompose(const pointField&);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Explicitly
|
||||
@ -165,6 +213,16 @@ public:
|
||||
// from 0 at processor0 and then incrementing all through the
|
||||
// processors)
|
||||
// - the connections are across coupled patches
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
)
|
||||
{
|
||||
return decompose(cc, cWeights);
|
||||
}
|
||||
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
|
||||
@ -82,7 +82,11 @@ Foam::manualDecomp::manualDecomp
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::labelList Foam::manualDecomp::decompose(const pointField& points)
|
||||
Foam::labelList Foam::manualDecomp::decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
)
|
||||
{
|
||||
const polyMesh& mesh = *meshPtr_;
|
||||
|
||||
@ -103,8 +107,10 @@ Foam::labelList Foam::manualDecomp::decompose(const pointField& points)
|
||||
|
||||
if (finalDecomp.size() != points.size())
|
||||
{
|
||||
FatalErrorIn("manualDecomp::decompose(const pointField&)")
|
||||
<< "Size of decomposition list does not correspond "
|
||||
FatalErrorIn
|
||||
(
|
||||
"manualDecomp::decompose(const pointField&, const scalarField&)"
|
||||
) << "Size of decomposition list does not correspond "
|
||||
<< "to the number of points. Size: "
|
||||
<< finalDecomp.size() << " Number of points: "
|
||||
<< points.size()
|
||||
@ -115,8 +121,10 @@ Foam::labelList Foam::manualDecomp::decompose(const pointField& points)
|
||||
|
||||
if (min(finalDecomp) < 0 || max(finalDecomp) > nProcessors_ - 1)
|
||||
{
|
||||
FatalErrorIn("labelList manualDecomp::decompose(const pointField&)")
|
||||
<< "According to the decomposition, cells assigned to "
|
||||
FatalErrorIn
|
||||
(
|
||||
"manualDecomp::decompose(const pointField&, const scalarField&)"
|
||||
) << "According to the decomposition, cells assigned to "
|
||||
<< "impossible processor numbers. Min processor = "
|
||||
<< min(finalDecomp) << " Max processor = " << max(finalDecomp)
|
||||
<< ".\n" << "Manual decomposition data read from file "
|
||||
|
||||
@ -99,7 +99,11 @@ public:
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Use the
|
||||
// mesh connectivity (if needed)
|
||||
virtual labelList decompose(const pointField&);
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Explicitly
|
||||
// provided connectivity - does not use mesh_.
|
||||
@ -111,10 +115,11 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
)
|
||||
{
|
||||
return decompose(cc);
|
||||
return decompose(cc, cWeights);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ Foam::label Foam::metisDecomp::decompose
|
||||
(
|
||||
const List<int>& adjncy,
|
||||
const List<int>& xadj,
|
||||
const scalarField& cWeights,
|
||||
|
||||
List<int>& finalDecomp
|
||||
)
|
||||
@ -72,6 +73,8 @@ Foam::label Foam::metisDecomp::decompose
|
||||
// k-way: multi-level k-way
|
||||
word method("k-way");
|
||||
|
||||
int numCells = xadj.size()-1;
|
||||
|
||||
// decomposition options. 0 = use defaults
|
||||
List<int> options(5, 0);
|
||||
|
||||
@ -85,6 +88,30 @@ Foam::label Foam::metisDecomp::decompose
|
||||
// face weights (so on the edges of the dual)
|
||||
List<int> faceWeights;
|
||||
|
||||
|
||||
// Check for externally provided cellweights and if so initialise weights
|
||||
scalar maxWeights = gMax(cWeights);
|
||||
if (cWeights.size() > 0)
|
||||
{
|
||||
if (cWeights.size() != numCells)
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"metisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "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] = int(1000000*cWeights[i]/maxWeights);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for user supplied weights and decomp options
|
||||
if (decompositionDict_.found("metisCoeffs"))
|
||||
{
|
||||
@ -161,52 +188,8 @@ Foam::label Foam::metisDecomp::decompose
|
||||
<< exit(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
//- faceWeights disabled. Only makes sense for cellCells from mesh.
|
||||
//if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
|
||||
//{
|
||||
// Info<< "metisDecomp : Using face-based weights." << endl;
|
||||
//
|
||||
// IOList<int> weights
|
||||
// (
|
||||
// IOobject
|
||||
// (
|
||||
// weightsFile,
|
||||
// mesh_.time().timeName(),
|
||||
// mesh_,
|
||||
// IOobject::MUST_READ,
|
||||
// IOobject::AUTO_WRITE
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// if (weights.size() != adjncy.size()/2)
|
||||
// {
|
||||
// FatalErrorIn("metisDecomp::decompose(const pointField&)")
|
||||
// << "Number of face weights " << weights.size()
|
||||
// << " does not equal number of internal faces "
|
||||
// << adjncy.size()/2
|
||||
// << exit(FatalError);
|
||||
// }
|
||||
//
|
||||
// // Assume symmetric weights. Keep same ordering as adjncy.
|
||||
// faceWeights.setSize(adjncy.size());
|
||||
//
|
||||
// labelList nFacesPerCell(mesh_.nCells(), 0);
|
||||
//
|
||||
// for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
// {
|
||||
// label w = weights[faceI];
|
||||
//
|
||||
// label own = mesh_.faceOwner()[faceI];
|
||||
// label nei = mesh_.faceNeighbour()[faceI];
|
||||
//
|
||||
// faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
|
||||
// faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
int numCells = xadj.size()-1;
|
||||
int nProcs = nProcessors_;
|
||||
|
||||
// output: cell -> processor addressing
|
||||
@ -327,12 +310,18 @@ Foam::metisDecomp::metisDecomp
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::labelList Foam::metisDecomp::decompose(const pointField& points)
|
||||
Foam::labelList Foam::metisDecomp::decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
)
|
||||
{
|
||||
if (points.size() != mesh_.nCells())
|
||||
{
|
||||
FatalErrorIn("metisDecomp::decompose(const pointField&)")
|
||||
<< "Can use this decomposition method only for the whole mesh"
|
||||
FatalErrorIn
|
||||
(
|
||||
"metisDecomp::decompose(const pointField&,const scalarField&)"
|
||||
) << "Can use this decomposition method only for the whole mesh"
|
||||
<< endl
|
||||
<< "and supply one coordinate (cellCentre) for every cell." << endl
|
||||
<< "The number of coordinates " << points.size() << endl
|
||||
@ -340,19 +329,49 @@ Foam::labelList Foam::metisDecomp::decompose(const pointField& points)
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
List<int> adjncy;
|
||||
List<int> xadj;
|
||||
calcMetisCSR
|
||||
(
|
||||
mesh_,
|
||||
adjncy,
|
||||
xadj
|
||||
);
|
||||
|
||||
// Decompose using default weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, pointWeights, finalDecomp);
|
||||
|
||||
// Copy back to labelList
|
||||
labelList decomp(finalDecomp.size());
|
||||
forAll(decomp, i)
|
||||
{
|
||||
decomp[i] = finalDecomp[i];
|
||||
}
|
||||
return decomp;
|
||||
}
|
||||
|
||||
|
||||
void Foam::metisDecomp::calcMetisCSR
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
List<int>& adjncy,
|
||||
List<int>& xadj
|
||||
)
|
||||
{
|
||||
// Make Metis CSR (Compressed Storage Format) storage
|
||||
// adjncy : contains neighbours (= edges in graph)
|
||||
// xadj(celli) : start of information in adjncy for celli
|
||||
|
||||
List<int> xadj(mesh_.nCells()+1);
|
||||
xadj.setSize(mesh.nCells()+1);
|
||||
|
||||
// Initialise the number of internal faces of the cells to twice the
|
||||
// number of internal faces
|
||||
label nInternalFaces = 2*mesh_.nInternalFaces();
|
||||
label nInternalFaces = 2*mesh.nInternalFaces();
|
||||
|
||||
// Check the boundary for coupled patches and add to the number of
|
||||
// internal faces
|
||||
const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
|
||||
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
|
||||
|
||||
forAll(pbm, patchi)
|
||||
{
|
||||
@ -364,17 +383,17 @@ Foam::labelList Foam::metisDecomp::decompose(const pointField& points)
|
||||
|
||||
// Create the adjncy array the size of the total number of internal and
|
||||
// coupled faces
|
||||
List<int> adjncy(nInternalFaces);
|
||||
adjncy.setSize(nInternalFaces);
|
||||
|
||||
// Fill in xadj
|
||||
// ~~~~~~~~~~~~
|
||||
label freeAdj = 0;
|
||||
|
||||
for (label cellI = 0; cellI < mesh_.nCells(); cellI++)
|
||||
for (label cellI = 0; cellI < mesh.nCells(); cellI++)
|
||||
{
|
||||
xadj[cellI] = freeAdj;
|
||||
|
||||
const labelList& cFaces = mesh_.cells()[cellI];
|
||||
const labelList& cFaces = mesh.cells()[cellI];
|
||||
|
||||
forAll(cFaces, i)
|
||||
{
|
||||
@ -382,7 +401,7 @@ Foam::labelList Foam::metisDecomp::decompose(const pointField& points)
|
||||
|
||||
if
|
||||
(
|
||||
mesh_.isInternalFace(faceI)
|
||||
mesh.isInternalFace(faceI)
|
||||
|| isA<cyclicPolyPatch>(pbm[pbm.whichPatch(faceI)])
|
||||
)
|
||||
{
|
||||
@ -390,19 +409,19 @@ Foam::labelList Foam::metisDecomp::decompose(const pointField& points)
|
||||
}
|
||||
}
|
||||
}
|
||||
xadj[mesh_.nCells()] = freeAdj;
|
||||
xadj[mesh.nCells()] = freeAdj;
|
||||
|
||||
|
||||
// Fill in adjncy
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
labelList nFacesPerCell(mesh_.nCells(), 0);
|
||||
labelList nFacesPerCell(mesh.nCells(), 0);
|
||||
|
||||
// Internal faces
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
|
||||
{
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
label own = mesh.faceOwner()[faceI];
|
||||
label nei = mesh.faceNeighbour()[faceI];
|
||||
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
|
||||
adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
|
||||
@ -427,18 +446,6 @@ Foam::labelList Foam::metisDecomp::decompose(const pointField& points)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decompose using default weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, finalDecomp);
|
||||
|
||||
// Copy back to labelList
|
||||
labelList decomp(finalDecomp.size());
|
||||
forAll(decomp, i)
|
||||
{
|
||||
decomp[i] = finalDecomp[i];
|
||||
}
|
||||
return decomp;
|
||||
}
|
||||
|
||||
|
||||
@ -487,14 +494,16 @@ void Foam::metisDecomp::calcMetisCSR
|
||||
Foam::labelList Foam::metisDecomp::decompose
|
||||
(
|
||||
const labelList& agglom,
|
||||
const pointField& agglomPoints
|
||||
const pointField& agglomPoints,
|
||||
const scalarField& agglomWeights
|
||||
)
|
||||
{
|
||||
if (agglom.size() != mesh_.nCells())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose(const labelList&, const pointField&)"
|
||||
"metisDecomp::decompose"
|
||||
"(const labelList&, const pointField&, const scalarField&)"
|
||||
) << "Size of cell-to-coarse map " << agglom.size()
|
||||
<< " differs from number of cells in mesh " << mesh_.nCells()
|
||||
<< exit(FatalError);
|
||||
@ -521,7 +530,7 @@ Foam::labelList Foam::metisDecomp::decompose
|
||||
|
||||
// Decompose using default weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, finalDecomp);
|
||||
decompose(adjncy, xadj, agglomWeights, finalDecomp);
|
||||
|
||||
|
||||
// Rework back into decomposition for original mesh_
|
||||
@ -539,14 +548,16 @@ Foam::labelList Foam::metisDecomp::decompose
|
||||
Foam::labelList Foam::metisDecomp::decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cellCentres
|
||||
const pointField& cellCentres,
|
||||
const scalarField& cellWeights
|
||||
)
|
||||
{
|
||||
if (cellCentres.size() != globalCellCells.size())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"metisDecomp::decompose(const pointField&, const labelListList&)"
|
||||
"metisDecomp::decompose"
|
||||
"(const pointField&, const labelListList&, const scalarField&)"
|
||||
) << "Inconsistent number of cells (" << globalCellCells.size()
|
||||
<< ") and number of cell centres (" << cellCentres.size()
|
||||
<< ")." << exit(FatalError);
|
||||
@ -564,7 +575,7 @@ Foam::labelList Foam::metisDecomp::decompose
|
||||
|
||||
// Decompose using default weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, finalDecomp);
|
||||
decompose(adjncy, xadj, cellWeights, finalDecomp);
|
||||
|
||||
// Copy back to labelList
|
||||
labelList decomp(finalDecomp.size());
|
||||
|
||||
@ -60,6 +60,7 @@ class metisDecomp
|
||||
(
|
||||
const List<int>& adjncy,
|
||||
const List<int>& xadj,
|
||||
const scalarField& cellWeights,
|
||||
List<int>& finalDecomp
|
||||
);
|
||||
|
||||
@ -100,7 +101,11 @@ public:
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Use the
|
||||
// mesh connectivity (if needed)
|
||||
virtual labelList decompose(const pointField&);
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Gets
|
||||
// passed agglomeration map (from fine to coarse cells) and coarse cell
|
||||
@ -109,7 +114,8 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelList& agglom,
|
||||
const pointField&
|
||||
const pointField& regionPoints,
|
||||
const scalarField& regionWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Explicitly
|
||||
@ -122,10 +128,21 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
);
|
||||
|
||||
//- Helper to convert cellcells into Metis storage
|
||||
//- Helper to convert connectivity (supplied as owner,neighbour) into
|
||||
// Metis storage
|
||||
static void calcMetisCSR
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
List<int>& adjncy,
|
||||
List<int>& xadj
|
||||
);
|
||||
|
||||
//- Helper to convert connectivity (supplied as cellcells) into
|
||||
// Metis storage
|
||||
static void calcMetisCSR
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
|
||||
@ -65,6 +65,7 @@ License
|
||||
#include "Time.H"
|
||||
#include "cyclicPolyPatch.H"
|
||||
#include "OFstream.H"
|
||||
#include "metisDecomp.H"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@ -125,6 +126,7 @@ Foam::label Foam::scotchDecomp::decompose
|
||||
(
|
||||
const List<int>& adjncy,
|
||||
const List<int>& xadj,
|
||||
const scalarField& cWeights,
|
||||
|
||||
List<int>& finalDecomp
|
||||
)
|
||||
@ -160,6 +162,33 @@ Foam::label Foam::scotchDecomp::decompose
|
||||
// Graph
|
||||
// ~~~~~
|
||||
|
||||
List<int> velotab;
|
||||
|
||||
|
||||
// Check for externally provided cellweights and if so initialise weights
|
||||
scalar maxWeights = gMax(cWeights);
|
||||
if (cWeights.size() > 0)
|
||||
{
|
||||
if (cWeights.size() != xadj.size()-1)
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "Number of cell weights " << cWeights.size()
|
||||
<< " does not equal number of cells " << xadj.size()-1
|
||||
<< exit(FatalError);
|
||||
}
|
||||
// Convert to integers.
|
||||
velotab.setSize(cWeights.size());
|
||||
forAll(velotab, i)
|
||||
{
|
||||
velotab[i] = int(1000000*cWeights[i]/maxWeights);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SCOTCH_Graph grafdat;
|
||||
check(SCOTCH_graphInit(&grafdat), "SCOTCH_graphInit");
|
||||
check
|
||||
@ -171,7 +200,7 @@ Foam::label Foam::scotchDecomp::decompose
|
||||
xadj.size()-1, // vertnbr, nCells
|
||||
xadj.begin(), // verttab, start index per cell into adjncy
|
||||
&xadj[1], // vendtab, end index ,,
|
||||
NULL, // velotab, vertex weights
|
||||
velotab.begin(), // velotab, vertex weights
|
||||
NULL, // vlbltab
|
||||
adjncy.size(), // edgenbr, number of arcs
|
||||
adjncy.begin(), // edgetab
|
||||
@ -340,7 +369,11 @@ Foam::scotchDecomp::scotchDecomp
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::labelList Foam::scotchDecomp::decompose(const pointField& points)
|
||||
Foam::labelList Foam::scotchDecomp::decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
)
|
||||
{
|
||||
if (points.size() != mesh_.nCells())
|
||||
{
|
||||
@ -356,94 +389,18 @@ Foam::labelList Foam::scotchDecomp::decompose(const pointField& points)
|
||||
// Make Metis CSR (Compressed Storage Format) storage
|
||||
// adjncy : contains neighbours (= edges in graph)
|
||||
// xadj(celli) : start of information in adjncy for celli
|
||||
|
||||
List<int> xadj(mesh_.nCells()+1);
|
||||
|
||||
// Initialise the number of internal faces of the cells to twice the
|
||||
// number of internal faces
|
||||
label nInternalFaces = 2*mesh_.nInternalFaces();
|
||||
|
||||
// Check the boundary for coupled patches and add to the number of
|
||||
// internal faces
|
||||
const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
|
||||
|
||||
forAll(pbm, patchi)
|
||||
{
|
||||
if (isA<cyclicPolyPatch>(pbm[patchi]))
|
||||
{
|
||||
nInternalFaces += pbm[patchi].size();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the adjncy array the size of the total number of internal and
|
||||
// coupled faces
|
||||
List<int> adjncy(nInternalFaces);
|
||||
|
||||
// Fill in xadj
|
||||
// ~~~~~~~~~~~~
|
||||
label freeAdj = 0;
|
||||
|
||||
for (label cellI = 0; cellI < mesh_.nCells(); cellI++)
|
||||
{
|
||||
xadj[cellI] = freeAdj;
|
||||
|
||||
const labelList& cFaces = mesh_.cells()[cellI];
|
||||
|
||||
forAll(cFaces, i)
|
||||
{
|
||||
label faceI = cFaces[i];
|
||||
|
||||
if
|
||||
(
|
||||
mesh_.isInternalFace(faceI)
|
||||
|| isA<cyclicPolyPatch>(pbm[pbm.whichPatch(faceI)])
|
||||
)
|
||||
{
|
||||
freeAdj++;
|
||||
}
|
||||
}
|
||||
}
|
||||
xadj[mesh_.nCells()] = freeAdj;
|
||||
|
||||
|
||||
// Fill in adjncy
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
labelList nFacesPerCell(mesh_.nCells(), 0);
|
||||
|
||||
// Internal faces
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
{
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
|
||||
adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
|
||||
}
|
||||
|
||||
// Coupled faces. Only cyclics done.
|
||||
forAll(pbm, patchi)
|
||||
{
|
||||
if (isA<cyclicPolyPatch>(pbm[patchi]))
|
||||
{
|
||||
const unallocLabelList& faceCells = pbm[patchi].faceCells();
|
||||
|
||||
label sizeby2 = faceCells.size()/2;
|
||||
|
||||
for (label facei=0; facei<sizeby2; facei++)
|
||||
{
|
||||
label own = faceCells[facei];
|
||||
label nei = faceCells[facei + sizeby2];
|
||||
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
|
||||
adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<int> adjncy;
|
||||
List<int> xadj;
|
||||
metisDecomp::calcMetisCSR
|
||||
(
|
||||
mesh_,
|
||||
adjncy,
|
||||
xadj
|
||||
);
|
||||
|
||||
// Decompose using default weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, finalDecomp);
|
||||
decompose(adjncy, xadj, pointWeights, finalDecomp);
|
||||
|
||||
// Copy back to labelList
|
||||
labelList decomp(finalDecomp.size());
|
||||
@ -455,52 +412,11 @@ Foam::labelList Foam::scotchDecomp::decompose(const pointField& points)
|
||||
}
|
||||
|
||||
|
||||
// From cell-cell connections to Metis format (like CompactListList)
|
||||
void Foam::scotchDecomp::calcMetisCSR
|
||||
(
|
||||
const labelListList& cellCells,
|
||||
List<int>& adjncy,
|
||||
List<int>& xadj
|
||||
)
|
||||
{
|
||||
// Count number of internal faces
|
||||
label nConnections = 0;
|
||||
|
||||
forAll(cellCells, coarseI)
|
||||
{
|
||||
nConnections += cellCells[coarseI].size();
|
||||
}
|
||||
|
||||
// Create the adjncy array as twice the size of the total number of
|
||||
// internal faces
|
||||
adjncy.setSize(nConnections);
|
||||
|
||||
xadj.setSize(cellCells.size()+1);
|
||||
|
||||
|
||||
// Fill in xadj
|
||||
// ~~~~~~~~~~~~
|
||||
label freeAdj = 0;
|
||||
|
||||
forAll(cellCells, coarseI)
|
||||
{
|
||||
xadj[coarseI] = freeAdj;
|
||||
|
||||
const labelList& cCells = cellCells[coarseI];
|
||||
|
||||
forAll(cCells, i)
|
||||
{
|
||||
adjncy[freeAdj++] = cCells[i];
|
||||
}
|
||||
}
|
||||
xadj[cellCells.size()] = freeAdj;
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::scotchDecomp::decompose
|
||||
(
|
||||
const labelList& agglom,
|
||||
const pointField& agglomPoints
|
||||
const pointField& agglomPoints,
|
||||
const scalarField& pointWeights
|
||||
)
|
||||
{
|
||||
if (agglom.size() != mesh_.nCells())
|
||||
@ -529,13 +445,12 @@ Foam::labelList Foam::scotchDecomp::decompose
|
||||
cellCells
|
||||
);
|
||||
|
||||
calcMetisCSR(cellCells, adjncy, xadj);
|
||||
metisDecomp::calcMetisCSR(cellCells, adjncy, xadj);
|
||||
}
|
||||
|
||||
// Decompose using default weights
|
||||
// Decompose using weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, finalDecomp);
|
||||
|
||||
decompose(adjncy, xadj, pointWeights, finalDecomp);
|
||||
|
||||
// Rework back into decomposition for original mesh_
|
||||
labelList fineDistribution(agglom.size());
|
||||
@ -552,7 +467,8 @@ Foam::labelList Foam::scotchDecomp::decompose
|
||||
Foam::labelList Foam::scotchDecomp::decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cellCentres
|
||||
const pointField& cellCentres,
|
||||
const scalarField& cWeights
|
||||
)
|
||||
{
|
||||
if (cellCentres.size() != globalCellCells.size())
|
||||
@ -572,12 +488,11 @@ Foam::labelList Foam::scotchDecomp::decompose
|
||||
|
||||
List<int> adjncy;
|
||||
List<int> xadj;
|
||||
calcMetisCSR(globalCellCells, adjncy, xadj);
|
||||
metisDecomp::calcMetisCSR(globalCellCells, adjncy, xadj);
|
||||
|
||||
|
||||
// Decompose using default weights
|
||||
// Decompose using weights
|
||||
List<int> finalDecomp;
|
||||
decompose(adjncy, xadj, finalDecomp);
|
||||
decompose(adjncy, xadj, cWeights, finalDecomp);
|
||||
|
||||
// Copy back to labelList
|
||||
labelList decomp(finalDecomp.size());
|
||||
|
||||
@ -63,6 +63,7 @@ class scotchDecomp
|
||||
(
|
||||
const List<int>& adjncy,
|
||||
const List<int>& xadj,
|
||||
const scalarField& cWeights,
|
||||
List<int>& finalDecomp
|
||||
);
|
||||
|
||||
@ -103,7 +104,11 @@ public:
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Use the
|
||||
// mesh connectivity (if needed)
|
||||
virtual labelList decompose(const pointField&);
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Gets
|
||||
// passed agglomeration map (from fine to coarse cells) and coarse cell
|
||||
@ -112,7 +117,8 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelList& agglom,
|
||||
const pointField&
|
||||
const pointField& regionPoints,
|
||||
const scalarField& regionWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Explicitly
|
||||
@ -125,15 +131,8 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
);
|
||||
|
||||
//- Helper to convert cellcells into compact row storage
|
||||
static void calcMetisCSR
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
List<int>& adjncy,
|
||||
List<int>& xadj
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
@ -22,8 +22,6 @@ License
|
||||
along with OpenFOAM; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Description
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "simpleGeomDecomp.H"
|
||||
@ -93,6 +91,49 @@ void Foam::simpleGeomDecomp::assignToProcessorGroup
|
||||
}
|
||||
|
||||
|
||||
void Foam::simpleGeomDecomp::assignToProcessorGroup
|
||||
(
|
||||
labelList& processorGroup,
|
||||
const label nProcGroup,
|
||||
const labelList& indices,
|
||||
const scalarField& weights,
|
||||
const scalar summedWeights
|
||||
)
|
||||
{
|
||||
// This routine gets the sorted points.
|
||||
// Easiest to explain with an example.
|
||||
// E.g. 400 points, sum of weights : 513.
|
||||
// Now with number of divisions in this direction (nProcGroup) : 4
|
||||
// gives the split at 513/4 = 128
|
||||
// So summed weight from 0..128 goes into bin 0,
|
||||
// ,, 128..256 goes into bin 1
|
||||
// etc.
|
||||
// Finally any remaining ones go into the last bin (3).
|
||||
|
||||
const scalar jump = summedWeights/nProcGroup;
|
||||
const label nProcGroupM1 = nProcGroup - 1;
|
||||
scalar sumWeights = 0;
|
||||
label ind = 0;
|
||||
label j = 0;
|
||||
|
||||
// assign cells to all except last group.
|
||||
for (j=0; j<nProcGroupM1; j++)
|
||||
{
|
||||
const scalar limit = jump*scalar(j + 1);
|
||||
while (sumWeights < limit)
|
||||
{
|
||||
sumWeights += weights[indices[ind]];
|
||||
processorGroup[ind++] = j;
|
||||
}
|
||||
}
|
||||
// Ensure last included.
|
||||
while (ind < processorGroup.size())
|
||||
{
|
||||
processorGroup[ind++] = nProcGroupM1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::simpleGeomDecomp::simpleGeomDecomp(const dictionary& decompositionDict)
|
||||
@ -121,7 +162,10 @@ Foam::labelList Foam::simpleGeomDecomp::decompose(const pointField& points)
|
||||
labelList processorGroups(points.size());
|
||||
|
||||
labelList pointIndices(points.size());
|
||||
forAll(pointIndices, i) {pointIndices[i] = i;}
|
||||
forAll(pointIndices, i)
|
||||
{
|
||||
pointIndices[i] = i;
|
||||
}
|
||||
|
||||
pointField rotatedPoints = rotDelta_ & points;
|
||||
|
||||
@ -175,9 +219,101 @@ Foam::labelList Foam::simpleGeomDecomp::decompose(const pointField& points)
|
||||
finalDecomp[pointIndices[i]] += n_.x()*n_.y()*processorGroups[i];
|
||||
}
|
||||
|
||||
|
||||
return finalDecomp;
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::simpleGeomDecomp::decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& weights
|
||||
)
|
||||
{
|
||||
// construct a list for the final result
|
||||
labelList finalDecomp(points.size());
|
||||
|
||||
labelList processorGroups(points.size());
|
||||
|
||||
labelList pointIndices(points.size());
|
||||
forAll(pointIndices, i)
|
||||
{
|
||||
pointIndices[i] = i;
|
||||
}
|
||||
|
||||
pointField rotatedPoints = rotDelta_ & points;
|
||||
|
||||
// and one to take the processor group id's. For each direction.
|
||||
// we assign the processors to groups of processors labelled
|
||||
// 0..nX to give a banded structure on the mesh. Then we
|
||||
// construct the actual processor number by treating this as
|
||||
// the units part of the processor number.
|
||||
sort
|
||||
(
|
||||
pointIndices,
|
||||
UList<scalar>::less(rotatedPoints.component(vector::X))
|
||||
);
|
||||
|
||||
const scalar summedWeights = sum(weights);
|
||||
assignToProcessorGroup
|
||||
(
|
||||
processorGroups,
|
||||
n_.x(),
|
||||
pointIndices,
|
||||
weights,
|
||||
summedWeights
|
||||
);
|
||||
|
||||
forAll(points, i)
|
||||
{
|
||||
finalDecomp[pointIndices[i]] = processorGroups[i];
|
||||
}
|
||||
|
||||
|
||||
// now do the same thing in the Y direction. These processor group
|
||||
// numbers add multiples of nX to the proc. number (columns)
|
||||
sort
|
||||
(
|
||||
pointIndices,
|
||||
UList<scalar>::less(rotatedPoints.component(vector::Y))
|
||||
);
|
||||
|
||||
assignToProcessorGroup
|
||||
(
|
||||
processorGroups,
|
||||
n_.y(),
|
||||
pointIndices,
|
||||
weights,
|
||||
summedWeights
|
||||
);
|
||||
|
||||
forAll(points, i)
|
||||
{
|
||||
finalDecomp[pointIndices[i]] += n_.x()*processorGroups[i];
|
||||
}
|
||||
|
||||
|
||||
// finally in the Z direction. Now we add multiples of nX*nY to give
|
||||
// layers
|
||||
sort
|
||||
(
|
||||
pointIndices,
|
||||
UList<scalar>::less(rotatedPoints.component(vector::Z))
|
||||
);
|
||||
|
||||
assignToProcessorGroup
|
||||
(
|
||||
processorGroups,
|
||||
n_.z(),
|
||||
pointIndices,
|
||||
weights,
|
||||
summedWeights
|
||||
);
|
||||
|
||||
forAll(points, i)
|
||||
{
|
||||
finalDecomp[pointIndices[i]] += n_.x()*n_.y()*processorGroups[i];
|
||||
}
|
||||
|
||||
return finalDecomp;
|
||||
}
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -52,6 +52,15 @@ class simpleGeomDecomp
|
||||
|
||||
void assignToProcessorGroup(labelList& processorGroup, const label);
|
||||
|
||||
void assignToProcessorGroup
|
||||
(
|
||||
labelList& processorGroup,
|
||||
const label nProcGroup,
|
||||
const labelList& indices,
|
||||
const scalarField& weights,
|
||||
const scalar summedWeights
|
||||
);
|
||||
|
||||
//- Disallow default bitwise copy construct and assignment
|
||||
void operator=(const simpleGeomDecomp&);
|
||||
simpleGeomDecomp(const simpleGeomDecomp&);
|
||||
@ -86,21 +95,31 @@ public:
|
||||
|
||||
virtual bool parallelAware() const
|
||||
{
|
||||
// simple decomp does not attempt to do anything across proc
|
||||
// simpleDecomp does not attempt to do anything across proc
|
||||
// boundaries
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual labelList decompose(const pointField&);
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points
|
||||
);
|
||||
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
);
|
||||
|
||||
//- Explicitly provided connectivity
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
)
|
||||
{
|
||||
return decompose(cc);
|
||||
return decompose(cc, cWeights);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -24,9 +24,9 @@ License
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "syncTools.H"
|
||||
#include "parMetisDecomp.H"
|
||||
#include "metisDecomp.H"
|
||||
#include "syncTools.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
#include "floatScalar.H"
|
||||
#include "polyMesh.H"
|
||||
@ -370,15 +370,22 @@ Foam::parMetisDecomp::parMetisDecomp
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
Foam::labelList Foam::parMetisDecomp::decompose
|
||||
(
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
)
|
||||
{
|
||||
if (points.size() != mesh_.nCells())
|
||||
if (cc.size() != mesh_.nCells())
|
||||
{
|
||||
FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
|
||||
<< "Can use this decomposition method only for the whole mesh"
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "Can use this decomposition method only for the whole mesh"
|
||||
<< endl
|
||||
<< "and supply one coordinate (cellCentre) for every cell." << endl
|
||||
<< "The number of coordinates " << points.size() << endl
|
||||
<< "The number of coordinates " << cc.size() << endl
|
||||
<< "The number of cells in the mesh " << mesh_.nCells()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
@ -386,156 +393,24 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
// For running sequential ...
|
||||
if (Pstream::nProcs() <= 1)
|
||||
{
|
||||
return metisDecomp(decompositionDict_, mesh_).decompose(points);
|
||||
}
|
||||
|
||||
// Create global cell numbers
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Get number of cells on all processors
|
||||
List<int> nLocalCells(Pstream::nProcs());
|
||||
nLocalCells[Pstream::myProcNo()] = mesh_.nCells();
|
||||
Pstream::gatherList(nLocalCells);
|
||||
Pstream::scatterList(nLocalCells);
|
||||
|
||||
// Get cell offsets.
|
||||
List<int> cellOffsets(Pstream::nProcs()+1);
|
||||
int nGlobalCells = 0;
|
||||
forAll(nLocalCells, procI)
|
||||
{
|
||||
cellOffsets[procI] = nGlobalCells;
|
||||
nGlobalCells += nLocalCells[procI];
|
||||
}
|
||||
cellOffsets[Pstream::nProcs()] = nGlobalCells;
|
||||
|
||||
int myOffset = cellOffsets[Pstream::myProcNo()];
|
||||
|
||||
|
||||
//
|
||||
// Make Metis Distributed CSR (Compressed Storage Format) storage
|
||||
// adjncy : contains cellCells (= edges in graph)
|
||||
// xadj(celli) : start of information in adjncy for celli
|
||||
//
|
||||
|
||||
|
||||
|
||||
const labelList& faceOwner = mesh_.faceOwner();
|
||||
const labelList& faceNeighbour = mesh_.faceNeighbour();
|
||||
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
|
||||
|
||||
|
||||
// Get renumbered owner on other side of coupled faces
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
List<int> globalNeighbour(mesh_.nFaces()-mesh_.nInternalFaces());
|
||||
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
|
||||
if (pp.coupled())
|
||||
{
|
||||
label faceI = pp.start();
|
||||
label bFaceI = pp.start() - mesh_.nInternalFaces();
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
globalNeighbour[bFaceI++] = faceOwner[faceI++] + myOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the cell on the other side of coupled patches
|
||||
syncTools::swapBoundaryFaceList(mesh_, globalNeighbour, false);
|
||||
|
||||
|
||||
// Count number of faces (internal + coupled)
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Number of faces per cell
|
||||
List<int> nFacesPerCell(mesh_.nCells(), 0);
|
||||
|
||||
// Number of coupled faces
|
||||
label nCoupledFaces = 0;
|
||||
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
{
|
||||
nFacesPerCell[faceOwner[faceI]]++;
|
||||
nFacesPerCell[faceNeighbour[faceI]]++;
|
||||
}
|
||||
// Handle coupled faces
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
|
||||
if (pp.coupled())
|
||||
{
|
||||
label faceI = pp.start();
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
nCoupledFaces++;
|
||||
nFacesPerCell[faceOwner[faceI++]]++;
|
||||
}
|
||||
}
|
||||
return metisDecomp(decompositionDict_, mesh_).decompose
|
||||
(
|
||||
cc,
|
||||
cWeights
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Fill in xadj
|
||||
// ~~~~~~~~~~~~
|
||||
|
||||
Field<int> xadj(mesh_.nCells()+1, -1);
|
||||
|
||||
int freeAdj = 0;
|
||||
|
||||
for (label cellI = 0; cellI < mesh_.nCells(); cellI++)
|
||||
{
|
||||
xadj[cellI] = freeAdj;
|
||||
|
||||
freeAdj += nFacesPerCell[cellI];
|
||||
}
|
||||
xadj[mesh_.nCells()] = freeAdj;
|
||||
|
||||
|
||||
|
||||
// Fill in adjncy
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
Field<int> adjncy(2*mesh_.nInternalFaces() + nCoupledFaces, -1);
|
||||
|
||||
nFacesPerCell = 0;
|
||||
|
||||
// For internal faces is just offsetted owner and neighbour
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
{
|
||||
label own = faceOwner[faceI];
|
||||
label nei = faceNeighbour[faceI];
|
||||
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] = nei + myOffset;
|
||||
adjncy[xadj[nei] + nFacesPerCell[nei]++] = own + myOffset;
|
||||
}
|
||||
// For boundary faces is offsetted coupled neighbour
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
|
||||
if (pp.coupled())
|
||||
{
|
||||
label faceI = pp.start();
|
||||
label bFaceI = pp.start()-mesh_.nInternalFaces();
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
label own = faceOwner[faceI];
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] =
|
||||
globalNeighbour[bFaceI];
|
||||
|
||||
faceI++;
|
||||
bFaceI++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connections
|
||||
Field<int> adjncy;
|
||||
// Offsets into adjncy
|
||||
Field<int> xadj;
|
||||
calcMetisDistributedCSR
|
||||
(
|
||||
mesh_,
|
||||
adjncy,
|
||||
xadj
|
||||
);
|
||||
|
||||
|
||||
// decomposition options. 0 = use defaults
|
||||
@ -550,6 +425,30 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
// face weights (so on the edges of the dual)
|
||||
Field<int> faceWeights;
|
||||
|
||||
|
||||
// Check for externally provided cellweights and if so initialise weights
|
||||
scalar maxWeights = gMax(cWeights);
|
||||
if (cWeights.size() > 0)
|
||||
{
|
||||
if (cWeights.size() != mesh_.nCells())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"metisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "Number of cell weights " << cWeights.size()
|
||||
<< " does not equal number of cells " << mesh_.nCells()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
// Convert to integers.
|
||||
cellWeights.setSize(cWeights.size());
|
||||
forAll(cellWeights, i)
|
||||
{
|
||||
cellWeights[i] = int(1000000*cWeights[i]/maxWeights);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for user supplied weights and decomp options
|
||||
if (decompositionDict_.found("metisCoeffs"))
|
||||
{
|
||||
@ -577,8 +476,11 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
|
||||
if (cellWeights.size() != mesh_.nCells())
|
||||
{
|
||||
FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
|
||||
<< "Number of cell weights " << cellWeights.size()
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "Number of cell weights " << cellWeights.size()
|
||||
<< " read from " << cellIOWeights.objectPath()
|
||||
<< " does not equal number of cells " << mesh_.nCells()
|
||||
<< exit(FatalError);
|
||||
@ -604,30 +506,35 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
|
||||
if (weights.size() != mesh_.nFaces())
|
||||
{
|
||||
FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
|
||||
<< "Number of face weights " << weights.size()
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "Number of face weights " << weights.size()
|
||||
<< " does not equal number of internal and boundary faces "
|
||||
<< mesh_.nFaces()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
faceWeights.setSize(2*mesh_.nInternalFaces()+nCoupledFaces);
|
||||
faceWeights.setSize(adjncy.size());
|
||||
|
||||
// Assume symmetric weights. Keep same ordering as adjncy.
|
||||
nFacesPerCell = 0;
|
||||
List<int> nFacesPerCell(mesh_.nCells(), 0);
|
||||
|
||||
// Handle internal faces
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
{
|
||||
label w = weights[faceI];
|
||||
|
||||
label own = faceOwner[faceI];
|
||||
label nei = faceNeighbour[faceI];
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
|
||||
faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
|
||||
faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
|
||||
}
|
||||
// Coupled boundary faces
|
||||
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
|
||||
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
@ -639,8 +546,8 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
forAll(pp, i)
|
||||
{
|
||||
label w = weights[faceI];
|
||||
label own = faceOwner[faceI];
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] = w;
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
|
||||
faceI++;
|
||||
}
|
||||
}
|
||||
@ -654,8 +561,11 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
|
||||
if (options.size() != 3)
|
||||
{
|
||||
FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
|
||||
<< "Number of options " << options.size()
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const pointField&, const scalarField&)"
|
||||
) << "Number of options " << options.size()
|
||||
<< " should be three." << exit(FatalError);
|
||||
}
|
||||
}
|
||||
@ -668,7 +578,7 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
(
|
||||
xadj,
|
||||
adjncy,
|
||||
points,
|
||||
cc,
|
||||
cellWeights,
|
||||
faceWeights,
|
||||
options,
|
||||
@ -689,7 +599,8 @@ Foam::labelList Foam::parMetisDecomp::decompose(const pointField& points)
|
||||
Foam::labelList Foam::parMetisDecomp::decompose
|
||||
(
|
||||
const labelList& cellToRegion,
|
||||
const pointField& regionPoints
|
||||
const pointField& regionPoints,
|
||||
const scalarField& regionWeights
|
||||
)
|
||||
{
|
||||
const labelList& faceOwner = mesh_.faceOwner();
|
||||
@ -798,7 +709,15 @@ Foam::labelList Foam::parMetisDecomp::decompose
|
||||
}
|
||||
}
|
||||
|
||||
labelList regionDecomp(decompose(globalRegionRegions, regionPoints));
|
||||
labelList regionDecomp
|
||||
(
|
||||
decompose
|
||||
(
|
||||
globalRegionRegions,
|
||||
regionPoints,
|
||||
regionWeights
|
||||
)
|
||||
);
|
||||
|
||||
// Rework back into decomposition for original mesh_
|
||||
labelList cellDistribution(cellToRegion.size());
|
||||
@ -814,24 +733,26 @@ Foam::labelList Foam::parMetisDecomp::decompose
|
||||
Foam::labelList Foam::parMetisDecomp::decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cellCentres
|
||||
const pointField& cellCentres,
|
||||
const scalarField& cWeights
|
||||
)
|
||||
{
|
||||
if (cellCentres.size() != globalCellCells.size())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose(const labelListList&, const pointField&)"
|
||||
"parMetisDecomp::decompose(const labelListList&"
|
||||
", const pointField&, const scalarField&)"
|
||||
) << "Inconsistent number of cells (" << globalCellCells.size()
|
||||
<< ") and number of cell centres (" << cellCentres.size()
|
||||
<< ")." << exit(FatalError);
|
||||
<< ") or weights (" << cWeights.size() << ")." << exit(FatalError);
|
||||
}
|
||||
|
||||
// For running sequential ...
|
||||
if (Pstream::nProcs() <= 1)
|
||||
{
|
||||
return metisDecomp(decompositionDict_, mesh_)
|
||||
.decompose(globalCellCells, cellCentres);
|
||||
.decompose(globalCellCells, cellCentres, cWeights);
|
||||
}
|
||||
|
||||
|
||||
@ -855,106 +776,35 @@ Foam::labelList Foam::parMetisDecomp::decompose
|
||||
// face weights (so on the edges of the dual)
|
||||
Field<int> faceWeights;
|
||||
|
||||
|
||||
// Check for externally provided cellweights and if so initialise weights
|
||||
scalar maxWeights = gMax(cWeights);
|
||||
if (cWeights.size() > 0)
|
||||
{
|
||||
if (cWeights.size() != globalCellCells.size())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose(const labelListList&"
|
||||
", const pointField&, const scalarField&)"
|
||||
) << "Number of cell weights " << cWeights.size()
|
||||
<< " does not equal number of cells " << globalCellCells.size()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
// Convert to integers.
|
||||
cellWeights.setSize(cWeights.size());
|
||||
forAll(cellWeights, i)
|
||||
{
|
||||
cellWeights[i] = int(1000000*cWeights[i]/maxWeights);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for user supplied weights and decomp options
|
||||
if (decompositionDict_.found("metisCoeffs"))
|
||||
{
|
||||
const dictionary& metisCoeffs =
|
||||
decompositionDict_.subDict("metisCoeffs");
|
||||
word weightsFile;
|
||||
|
||||
if (metisCoeffs.readIfPresent("cellWeightsFile", weightsFile))
|
||||
{
|
||||
Info<< "parMetisDecomp : Using cell-based weights read from "
|
||||
<< weightsFile << endl;
|
||||
|
||||
labelIOField cellIOWeights
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
weightsFile,
|
||||
mesh_.time().timeName(),
|
||||
mesh_,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::AUTO_WRITE
|
||||
)
|
||||
);
|
||||
cellWeights.transfer(cellIOWeights);
|
||||
|
||||
if (cellWeights.size() != cellCentres.size())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const labelListList&, const pointField&)"
|
||||
) << "Number of cell weights " << cellWeights.size()
|
||||
<< " read from " << cellIOWeights.objectPath()
|
||||
<< " does not equal number of cells " << cellCentres.size()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
//- faceWeights disabled. Only makes sense for cellCells from mesh.
|
||||
//if (metisCoeffs.readIfPresent("faceWeightsFile", weightsFile))
|
||||
//{
|
||||
// Info<< "parMetisDecomp : Using face-based weights read from "
|
||||
// << weightsFile << endl;
|
||||
//
|
||||
// labelIOField weights
|
||||
// (
|
||||
// IOobject
|
||||
// (
|
||||
// weightsFile,
|
||||
// mesh_.time().timeName(),
|
||||
// mesh_,
|
||||
// IOobject::MUST_READ,
|
||||
// IOobject::AUTO_WRITE
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// if (weights.size() != mesh_.nFaces())
|
||||
// {
|
||||
// FatalErrorIn("parMetisDecomp::decompose(const pointField&)")
|
||||
// << "Number of face weights " << weights.size()
|
||||
// << " does not equal number of internal and boundary faces "
|
||||
// << mesh_.nFaces()
|
||||
// << exit(FatalError);
|
||||
// }
|
||||
//
|
||||
// faceWeights.setSize(2*mesh_.nInternalFaces()+nCoupledFaces);
|
||||
//
|
||||
// // Assume symmetric weights. Keep same ordering as adjncy.
|
||||
// nFacesPerCell = 0;
|
||||
//
|
||||
// // Handle internal faces
|
||||
// for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
// {
|
||||
// label w = weights[faceI];
|
||||
//
|
||||
// label own = faceOwner[faceI];
|
||||
// label nei = faceNeighbour[faceI];
|
||||
//
|
||||
// faceWeights[xadj[own] + nFacesPerCell[own]++] = w;
|
||||
// faceWeights[xadj[nei] + nFacesPerCell[nei]++] = w;
|
||||
// }
|
||||
// // Coupled boundary faces
|
||||
// forAll(patches, patchI)
|
||||
// {
|
||||
// const polyPatch& pp = patches[patchI];
|
||||
//
|
||||
// if (pp.coupled())
|
||||
// {
|
||||
// label faceI = pp.start();
|
||||
//
|
||||
// forAll(pp, i)
|
||||
// {
|
||||
// label w = weights[faceI];
|
||||
// label own = faceOwner[faceI];
|
||||
// adjncy[xadj[own] + nFacesPerCell[own]++] = w;
|
||||
// faceI++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
if (metisCoeffs.readIfPresent("options", options))
|
||||
{
|
||||
@ -965,8 +815,8 @@ Foam::labelList Foam::parMetisDecomp::decompose
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"parMetisDecomp::decompose"
|
||||
"(const labelListList&, const pointField&)"
|
||||
"parMetisDecomp::decompose(const labelListList&"
|
||||
", const pointField&, const scalarField&)"
|
||||
) << "Number of options " << options.size()
|
||||
<< " should be three." << exit(FatalError);
|
||||
}
|
||||
@ -998,4 +848,146 @@ Foam::labelList Foam::parMetisDecomp::decompose
|
||||
}
|
||||
|
||||
|
||||
void Foam::parMetisDecomp::calcMetisDistributedCSR
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
List<int>& adjncy,
|
||||
List<int>& xadj
|
||||
)
|
||||
{
|
||||
// Create global cell numbers
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
globalIndex globalCells(mesh.nCells());
|
||||
|
||||
|
||||
//
|
||||
// Make Metis Distributed CSR (Compressed Storage Format) storage
|
||||
// adjncy : contains cellCells (= edges in graph)
|
||||
// xadj(celli) : start of information in adjncy for celli
|
||||
//
|
||||
|
||||
|
||||
const labelList& faceOwner = mesh.faceOwner();
|
||||
const labelList& faceNeighbour = mesh.faceNeighbour();
|
||||
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
||||
|
||||
|
||||
// Get renumbered owner on other side of coupled faces
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
List<int> globalNeighbour(mesh.nFaces()-mesh.nInternalFaces());
|
||||
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
|
||||
if (pp.coupled())
|
||||
{
|
||||
label faceI = pp.start();
|
||||
label bFaceI = pp.start() - mesh.nInternalFaces();
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
globalNeighbour[bFaceI++] = globalCells.toGlobal
|
||||
(
|
||||
faceOwner[faceI++]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the cell on the other side of coupled patches
|
||||
syncTools::swapBoundaryFaceList(mesh, globalNeighbour, false);
|
||||
|
||||
|
||||
// Count number of faces (internal + coupled)
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Number of faces per cell
|
||||
List<int> nFacesPerCell(mesh.nCells(), 0);
|
||||
|
||||
// Number of coupled faces
|
||||
label nCoupledFaces = 0;
|
||||
|
||||
for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
|
||||
{
|
||||
nFacesPerCell[faceOwner[faceI]]++;
|
||||
nFacesPerCell[faceNeighbour[faceI]]++;
|
||||
}
|
||||
// Handle coupled faces
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
|
||||
if (pp.coupled())
|
||||
{
|
||||
label faceI = pp.start();
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
nCoupledFaces++;
|
||||
nFacesPerCell[faceOwner[faceI++]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fill in xadj
|
||||
// ~~~~~~~~~~~~
|
||||
|
||||
xadj.setSize(mesh.nCells()+1);
|
||||
|
||||
int freeAdj = 0;
|
||||
|
||||
for (label cellI = 0; cellI < mesh.nCells(); cellI++)
|
||||
{
|
||||
xadj[cellI] = freeAdj;
|
||||
|
||||
freeAdj += nFacesPerCell[cellI];
|
||||
}
|
||||
xadj[mesh.nCells()] = freeAdj;
|
||||
|
||||
|
||||
|
||||
// Fill in adjncy
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
adjncy.setSize(2*mesh.nInternalFaces() + nCoupledFaces);
|
||||
|
||||
nFacesPerCell = 0;
|
||||
|
||||
// For internal faces is just offsetted owner and neighbour
|
||||
for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
|
||||
{
|
||||
label own = faceOwner[faceI];
|
||||
label nei = faceNeighbour[faceI];
|
||||
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] = globalCells.toGlobal(nei);
|
||||
adjncy[xadj[nei] + nFacesPerCell[nei]++] = globalCells.toGlobal(own);
|
||||
}
|
||||
// For boundary faces is offsetted coupled neighbour
|
||||
forAll(patches, patchI)
|
||||
{
|
||||
const polyPatch& pp = patches[patchI];
|
||||
|
||||
if (pp.coupled())
|
||||
{
|
||||
label faceI = pp.start();
|
||||
label bFaceI = pp.start()-mesh.nInternalFaces();
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
label own = faceOwner[faceI];
|
||||
adjncy[xadj[own] + nFacesPerCell[own]++] =
|
||||
globalNeighbour[bFaceI];
|
||||
|
||||
faceI++;
|
||||
bFaceI++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -112,7 +112,11 @@ public:
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Use the
|
||||
// mesh connectivity (if needed)
|
||||
virtual labelList decompose(const pointField&);
|
||||
virtual labelList decompose
|
||||
(
|
||||
const pointField& points,
|
||||
const scalarField& pointWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Gets
|
||||
// passed agglomeration map (from fine to coarse cells) and coarse cell
|
||||
@ -120,8 +124,9 @@ public:
|
||||
// functionality natively.
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelList& agglom,
|
||||
const pointField&
|
||||
const labelList& cellToRegion,
|
||||
const pointField& regionPoints,
|
||||
const scalarField& regionWeights
|
||||
);
|
||||
|
||||
//- Return for every coordinate the wanted processor number. Explicitly
|
||||
@ -134,7 +139,16 @@ public:
|
||||
virtual labelList decompose
|
||||
(
|
||||
const labelListList& globalCellCells,
|
||||
const pointField& cc
|
||||
const pointField& cc,
|
||||
const scalarField& cWeights
|
||||
);
|
||||
|
||||
//- Helper to convert mesh connectivity into distributed CSR
|
||||
static void calcMetisDistributedCSR
|
||||
(
|
||||
const polyMesh&,
|
||||
List<int>& adjncy,
|
||||
List<int>& xadj
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user