mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: handle sub-mesh connectivity by subsetting of adjacency matrix
- in renumberMesh replace calculation of a subMesh connectivity with calculation of the full mesh connectivity followed by subsetting of the full adjacency matrix. This should reduce the overall number of operations. (MR !669)
This commit is contained in:
@ -145,6 +145,7 @@ Usage
|
|||||||
#include "hexRef8Data.H"
|
#include "hexRef8Data.H"
|
||||||
#include "regionProperties.H"
|
#include "regionProperties.H"
|
||||||
#include "polyMeshTools.H"
|
#include "polyMeshTools.H"
|
||||||
|
#include "subsetAdjacency.H"
|
||||||
|
|
||||||
using namespace Foam;
|
using namespace Foam;
|
||||||
|
|
||||||
@ -194,21 +195,56 @@ tmp<volScalarField> createScalarField
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Calculate band of matrix
|
// Calculate band of mesh
|
||||||
label getBand(const labelList& owner, const labelList& neighbour)
|
// label getBand(const labelUList& owner, const labelUList& neighbour)
|
||||||
{
|
// {
|
||||||
label band = 0;
|
// label bandwidth = 0;
|
||||||
|
//
|
||||||
|
// forAll(neighbour, facei)
|
||||||
|
// {
|
||||||
|
// const label width = neighbour[facei] - owner[facei];
|
||||||
|
//
|
||||||
|
// if (bandwidth < width)
|
||||||
|
// {
|
||||||
|
// bandwidth = width;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return bandwidth;
|
||||||
|
// }
|
||||||
|
|
||||||
forAll(neighbour, facei)
|
|
||||||
{
|
|
||||||
label diff = neighbour[facei] - owner[facei];
|
|
||||||
|
|
||||||
if (diff > band)
|
// Calculate band and profile of matrix. Profile is scalar to avoid overflow
|
||||||
|
Tuple2<label, scalar> getBand
|
||||||
|
(
|
||||||
|
const CompactListList<label>& mat
|
||||||
|
)
|
||||||
{
|
{
|
||||||
band = diff;
|
Tuple2<label, scalar> metrics(0, 0);
|
||||||
|
|
||||||
|
auto& bandwidth = metrics.first();
|
||||||
|
auto& profile = metrics.second();
|
||||||
|
|
||||||
|
forAll(mat, celli)
|
||||||
|
{
|
||||||
|
const auto& neighbours = mat[celli];
|
||||||
|
|
||||||
|
const label nNbr = neighbours.size();
|
||||||
|
|
||||||
|
if (nNbr)
|
||||||
|
{
|
||||||
|
// Max distance
|
||||||
|
const label width = (neighbours[nNbr-1] - celli);
|
||||||
|
|
||||||
|
if (bandwidth < width)
|
||||||
|
{
|
||||||
|
bandwidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile += scalar(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return band;
|
|
||||||
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -217,27 +253,35 @@ void getBand
|
|||||||
(
|
(
|
||||||
const bool calculateIntersect,
|
const bool calculateIntersect,
|
||||||
const label nCells,
|
const label nCells,
|
||||||
const labelList& owner,
|
const labelUList& owner,
|
||||||
const labelList& neighbour,
|
const labelUList& neighbour,
|
||||||
label& bandwidth,
|
label& bandwidth,
|
||||||
scalar& profile, // scalar to avoid overflow
|
scalar& profile, // scalar to avoid overflow
|
||||||
scalar& sumSqrIntersect // scalar to avoid overflow
|
scalar& sumSqrIntersect // scalar to avoid overflow
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
labelList cellBandwidth(nCells, Foam::zero{});
|
labelList cellBandwidth(nCells, Foam::zero{});
|
||||||
scalarField nIntersect(nCells, Foam::zero{});
|
|
||||||
|
bandwidth = 0;
|
||||||
|
|
||||||
forAll(neighbour, facei)
|
forAll(neighbour, facei)
|
||||||
{
|
{
|
||||||
label own = owner[facei];
|
const label own = owner[facei];
|
||||||
label nei = neighbour[facei];
|
const label nei = neighbour[facei];
|
||||||
|
|
||||||
// Note: mag not necessary for correct (upper-triangular) ordering.
|
// Note: mag not necessary for correct (upper-triangular) ordering.
|
||||||
label diff = nei-own;
|
const label width = nei - own;
|
||||||
cellBandwidth[nei] = max(cellBandwidth[nei], diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
bandwidth = max(cellBandwidth);
|
if (cellBandwidth[nei] < width)
|
||||||
|
{
|
||||||
|
cellBandwidth[nei] = width;
|
||||||
|
|
||||||
|
if (bandwidth < width)
|
||||||
|
{
|
||||||
|
bandwidth = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Do not use field algebra because of conversion label to scalar
|
// Do not use field algebra because of conversion label to scalar
|
||||||
profile = 0;
|
profile = 0;
|
||||||
@ -246,14 +290,16 @@ void getBand
|
|||||||
profile += scalar(width);
|
profile += scalar(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
sumSqrIntersect = 0.0;
|
sumSqrIntersect = 0;
|
||||||
if (calculateIntersect)
|
if (calculateIntersect)
|
||||||
{
|
{
|
||||||
|
scalarField nIntersect(nCells, Foam::zero{});
|
||||||
|
|
||||||
forAll(nIntersect, celli)
|
forAll(nIntersect, celli)
|
||||||
{
|
{
|
||||||
for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++)
|
for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++)
|
||||||
{
|
{
|
||||||
nIntersect[colI] += 1.0;
|
nIntersect[colI] += scalar(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,9 +721,8 @@ CompactListList<label> regionRenumber
|
|||||||
|
|
||||||
forAll(regionCellOrder, regioni)
|
forAll(regionCellOrder, regioni)
|
||||||
{
|
{
|
||||||
// Info<< " region " << regioni
|
// Info<< " region " << regioni << " starts at "
|
||||||
// << " starts at " << regionCellOrder.localStart(regioni)
|
// << regionCellOrder.localStart(regioni) << nl;
|
||||||
// << nl;
|
|
||||||
|
|
||||||
// No parallel communication
|
// No parallel communication
|
||||||
const bool oldParRun = UPstream::parRun(false);
|
const bool oldParRun = UPstream::parRun(false);
|
||||||
@ -703,27 +748,42 @@ CompactListList<label> regionRenumber
|
|||||||
{
|
{
|
||||||
timer.resetTimeIncrement();
|
timer.resetTimeIncrement();
|
||||||
|
|
||||||
forAll(regionCellOrder, regioni)
|
// Create adjacency matrix of the full mesh and subset subsequently.
|
||||||
{
|
// This is more efficient than creating adjacency matrices of
|
||||||
// Info<< " region " << regioni
|
// sub-meshes.
|
||||||
// << " starts at " << regionCellOrder.localStart(regioni)
|
|
||||||
// << nl;
|
|
||||||
|
|
||||||
// No parallel communication
|
// No parallel communication
|
||||||
const bool oldParRun = UPstream::parRun(false);
|
const bool oldParRun = UPstream::parRun(false);
|
||||||
|
|
||||||
// Connectivity of local sub-mesh
|
// The local connectivity of the full (non-subsetted) mesh
|
||||||
CompactListList<label> cellCells;
|
CompactListList<label> meshCellCells;
|
||||||
labelList cellMap = globalMeshData::calcCellCells
|
globalMeshData::calcCellCells(mesh, meshCellCells);
|
||||||
(
|
UPstream::parRun(oldParRun); // Restore parallel state
|
||||||
mesh,
|
|
||||||
regionCellOrder[regioni],
|
|
||||||
cellCells
|
|
||||||
);
|
|
||||||
|
|
||||||
timings[TimingType::CELL_CELLS] += timer.timeIncrement();
|
timings[TimingType::CELL_CELLS] += timer.timeIncrement();
|
||||||
|
|
||||||
labelList subCellOrder = method.renumber(cellCells);
|
// For the respective subMesh selections
|
||||||
|
bitSet subsetCells(mesh.nCells());
|
||||||
|
|
||||||
|
forAll(regionCellOrder, regioni)
|
||||||
|
{
|
||||||
|
// Info<< " region " << regioni << " starts at "
|
||||||
|
// << regionCellOrder.localStart(regioni) << nl;
|
||||||
|
|
||||||
|
subsetCells = false;
|
||||||
|
subsetCells.set(regionCellOrder[regioni]);
|
||||||
|
|
||||||
|
// Connectivity of local sub-mesh
|
||||||
|
labelList cellMap;
|
||||||
|
CompactListList<label> subCellCells =
|
||||||
|
subsetAdjacency(subsetCells, meshCellCells, cellMap);
|
||||||
|
|
||||||
|
timings[TimingType::CELL_CELLS] += timer.timeIncrement();
|
||||||
|
|
||||||
|
// No parallel communication
|
||||||
|
const bool oldParRun = UPstream::parRun(false);
|
||||||
|
|
||||||
|
labelList subCellOrder = method.renumber(subCellCells);
|
||||||
|
|
||||||
UPstream::parRun(oldParRun); // Restore parallel state
|
UPstream::parRun(oldParRun); // Restore parallel state
|
||||||
|
|
||||||
@ -835,10 +895,10 @@ int main(int argc, char *argv[])
|
|||||||
const bool dryrun = args.dryRun();
|
const bool dryrun = args.dryRun();
|
||||||
|
|
||||||
const bool readDict = args.found("dict");
|
const bool readDict = args.found("dict");
|
||||||
const bool doFrontWidth = args.found("frontWidth");
|
const bool doDecompose = args.found("decompose");
|
||||||
const bool overwrite = args.found("overwrite");
|
const bool overwrite = args.found("overwrite");
|
||||||
const bool doFields = !args.found("no-fields");
|
const bool doFields = !args.found("no-fields");
|
||||||
const bool doDecompose = args.found("decompose");
|
const bool doFrontWidth = args.found("frontWidth") && !doDecompose;
|
||||||
|
|
||||||
word renumberMethodName;
|
word renumberMethodName;
|
||||||
args.readIfPresent("renumber-method", renumberMethodName);
|
args.readIfPresent("renumber-method", renumberMethodName);
|
||||||
@ -846,8 +906,7 @@ int main(int argc, char *argv[])
|
|||||||
if (doDecompose && UPstream::parRun())
|
if (doDecompose && UPstream::parRun())
|
||||||
{
|
{
|
||||||
FatalErrorIn(args.executable())
|
FatalErrorIn(args.executable())
|
||||||
<< "Cannot use -decompose option in parallel"
|
<< "Cannot use -decompose option in parallel ... giving up" << nl
|
||||||
<< " ... giving up" << nl
|
|
||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,21 +967,21 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
reduce(band, maxOp<label>());
|
reduce(band, maxOp<label>());
|
||||||
reduce(profile, sumOp<scalar>());
|
reduce(profile, sumOp<scalar>());
|
||||||
reduce(sumSqrIntersect, sumOp<scalar>());
|
|
||||||
|
|
||||||
scalar rmsFrontwidth = Foam::sqrt
|
|
||||||
(
|
|
||||||
sumSqrIntersect/mesh.globalData().nTotalCells()
|
|
||||||
);
|
|
||||||
|
|
||||||
Info<< "Mesh " << mesh.name()
|
Info<< "Mesh " << mesh.name()
|
||||||
<< " size: " << mesh.globalData().nTotalCells() << nl
|
<< " size: " << mesh.globalData().nTotalCells() << nl
|
||||||
<< "Before renumbering :" << nl
|
<< "Before renumbering" << nl
|
||||||
<< " band : " << band << nl
|
<< " band : " << band << nl
|
||||||
<< " profile : " << profile << nl;
|
<< " profile : " << profile << nl;
|
||||||
|
|
||||||
if (doFrontWidth)
|
if (doFrontWidth)
|
||||||
{
|
{
|
||||||
|
reduce(sumSqrIntersect, sumOp<scalar>());
|
||||||
|
scalar rmsFrontwidth = Foam::sqrt
|
||||||
|
(
|
||||||
|
sumSqrIntersect/mesh.globalData().nTotalCells()
|
||||||
|
);
|
||||||
|
|
||||||
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
|
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1091,10 +1150,7 @@ int main(int argc, char *argv[])
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// List of objects read from time directory
|
// List of stored objects to clear from mesh (after reading)
|
||||||
// List of stored objects to clear from mesh
|
|
||||||
|
|
||||||
IOobjectList objects;
|
|
||||||
DynamicList<regIOobject*> storedObjects;
|
DynamicList<regIOobject*> storedObjects;
|
||||||
|
|
||||||
if (!dryrun && doFields)
|
if (!dryrun && doFields)
|
||||||
@ -1103,55 +1159,60 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
timer.resetTimeIncrement();
|
timer.resetTimeIncrement();
|
||||||
|
|
||||||
objects = IOobjectList(mesh, runTime.timeName());
|
IOobjectList objects(mesh, runTime.timeName());
|
||||||
storedObjects.reserve(objects.size());
|
storedObjects.reserve(objects.size());
|
||||||
|
|
||||||
const predicates::always nameMatcher;
|
const predicates::always nameMatcher;
|
||||||
|
|
||||||
// Read GeometricFields
|
// Read GeometricFields
|
||||||
|
|
||||||
#undef ReadFields
|
#undef doLocalCode
|
||||||
#define ReadFields(FieldType) \
|
#define doLocalCode(FieldType) \
|
||||||
readFields<FieldType>(mesh, objects, nameMatcher, storedObjects);
|
readFields<FieldType>(mesh, objects, nameMatcher, storedObjects);
|
||||||
|
|
||||||
// Read volume fields
|
// Read volume fields
|
||||||
ReadFields(volScalarField);
|
doLocalCode(volScalarField);
|
||||||
ReadFields(volVectorField);
|
doLocalCode(volVectorField);
|
||||||
ReadFields(volSphericalTensorField);
|
doLocalCode(volSphericalTensorField);
|
||||||
ReadFields(volSymmTensorField);
|
doLocalCode(volSymmTensorField);
|
||||||
ReadFields(volTensorField);
|
doLocalCode(volTensorField);
|
||||||
|
|
||||||
// Read internal fields
|
// Read internal fields
|
||||||
ReadFields(volScalarField::Internal);
|
doLocalCode(volScalarField::Internal);
|
||||||
ReadFields(volVectorField::Internal);
|
doLocalCode(volVectorField::Internal);
|
||||||
ReadFields(volSphericalTensorField::Internal);
|
doLocalCode(volSphericalTensorField::Internal);
|
||||||
ReadFields(volSymmTensorField::Internal);
|
doLocalCode(volSymmTensorField::Internal);
|
||||||
ReadFields(volTensorField::Internal);
|
doLocalCode(volTensorField::Internal);
|
||||||
|
|
||||||
// Read surface fields
|
// Read surface fields
|
||||||
ReadFields(surfaceScalarField);
|
doLocalCode(surfaceScalarField);
|
||||||
ReadFields(surfaceVectorField);
|
doLocalCode(surfaceVectorField);
|
||||||
ReadFields(surfaceSphericalTensorField);
|
doLocalCode(surfaceSphericalTensorField);
|
||||||
ReadFields(surfaceSymmTensorField);
|
doLocalCode(surfaceSymmTensorField);
|
||||||
ReadFields(surfaceTensorField);
|
doLocalCode(surfaceTensorField);
|
||||||
|
|
||||||
|
|
||||||
// Read point fields
|
// Read point fields
|
||||||
const pointMesh& pMesh = pointMesh::New(mesh);
|
const pointMesh& pMesh = pointMesh::New(mesh);
|
||||||
#undef ReadPointFields
|
#undef doLocalCode
|
||||||
#define ReadPointFields(FieldType) \
|
#define doLocalCode(FieldType) \
|
||||||
readFields<FieldType>(pMesh, objects, nameMatcher, storedObjects);
|
readFields<FieldType>(pMesh, objects, nameMatcher, storedObjects);
|
||||||
|
|
||||||
ReadPointFields(pointScalarField);
|
doLocalCode(pointScalarField);
|
||||||
ReadPointFields(pointVectorField);
|
doLocalCode(pointVectorField);
|
||||||
ReadPointFields(pointSphericalTensorField);
|
doLocalCode(pointSphericalTensorField);
|
||||||
ReadPointFields(pointSymmTensorField);
|
doLocalCode(pointSymmTensorField);
|
||||||
ReadPointFields(pointTensorField);
|
doLocalCode(pointTensorField);
|
||||||
|
|
||||||
#undef ReadFields
|
#undef doLocalCode
|
||||||
#undef ReadPointFields
|
|
||||||
|
|
||||||
timings[TimingType::READ_FIELDS] += timer.timeIncrement();
|
timings[TimingType::READ_FIELDS] += timer.timeIncrement();
|
||||||
|
|
||||||
|
// Write loaded fields when mesh.write() is called
|
||||||
|
for (auto* fldptr : storedObjects)
|
||||||
|
{
|
||||||
|
fldptr->writeOpt(IOobject::AUTO_WRITE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1224,7 +1285,13 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
|
|
||||||
CompactListList<label> regionCellOrder =
|
CompactListList<label> regionCellOrder =
|
||||||
regionRenumber(renumberPtr(), mesh, cellToRegion);
|
regionRenumber
|
||||||
|
(
|
||||||
|
renumberPtr(),
|
||||||
|
mesh,
|
||||||
|
cellToRegion,
|
||||||
|
decomposePtr().nDomains()
|
||||||
|
);
|
||||||
|
|
||||||
cellOrder = regionCellOrder.values();
|
cellOrder = regionCellOrder.values();
|
||||||
|
|
||||||
@ -1586,19 +1653,25 @@ int main(int argc, char *argv[])
|
|||||||
);
|
);
|
||||||
reduce(band, maxOp<label>());
|
reduce(band, maxOp<label>());
|
||||||
reduce(profile, sumOp<scalar>());
|
reduce(profile, sumOp<scalar>());
|
||||||
reduce(sumSqrIntersect, sumOp<scalar>());
|
|
||||||
|
|
||||||
scalar rmsFrontwidth = Foam::sqrt
|
Info<< "After renumbering";
|
||||||
(
|
if (doDecompose)
|
||||||
sumSqrIntersect/mesh.globalData().nTotalCells()
|
{
|
||||||
);
|
Info<< " [values are misleading with -decompose option]";
|
||||||
|
}
|
||||||
|
|
||||||
Info<< "After renumbering :" << nl
|
Info<< nl
|
||||||
<< " band : " << band << nl
|
<< " band : " << band << nl
|
||||||
<< " profile : " << profile << nl;
|
<< " profile : " << profile << nl;
|
||||||
|
|
||||||
if (doFrontWidth)
|
if (doFrontWidth)
|
||||||
{
|
{
|
||||||
|
reduce(sumSqrIntersect, sumOp<scalar>());
|
||||||
|
scalar rmsFrontwidth = Foam::sqrt
|
||||||
|
(
|
||||||
|
sumSqrIntersect/mesh.globalData().nTotalCells()
|
||||||
|
);
|
||||||
|
|
||||||
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
|
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,168 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2024 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
|
||||||
|
|
||||||
|
Description
|
||||||
|
Subsetting of an adjacency matrix (as CompactListList).
|
||||||
|
Can be relocated elsewhere.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "CompactListList.H"
|
||||||
|
#include "bitSet.H"
|
||||||
|
#include "ListOps.H"
|
||||||
|
#include "Map.H"
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// Perform a subset of the adjacency matrix
|
||||||
|
CompactListList<label> subsetAdjacency
|
||||||
|
(
|
||||||
|
const bitSet& select, // could also be labelHashSet
|
||||||
|
const CompactListList<label>& input,
|
||||||
|
labelList& subMap
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Corresponds to cellMap etc (the original selection)
|
||||||
|
subMap = select.sortedToc();
|
||||||
|
|
||||||
|
// Ensure that the subMap corresponds to a valid subset
|
||||||
|
{
|
||||||
|
label validSize = 0;
|
||||||
|
|
||||||
|
const label nTotal = input.size();
|
||||||
|
|
||||||
|
forAllReverse(subMap, i)
|
||||||
|
{
|
||||||
|
if (subMap[i] < nTotal)
|
||||||
|
{
|
||||||
|
validSize = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subMap.resize(validSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Assumed to be sparse - use Map for reverse lookup
|
||||||
|
const Map<label> reverseMap(invertToMap(subMap));
|
||||||
|
|
||||||
|
|
||||||
|
// Pass 1: determine the selected sub-sizes
|
||||||
|
labelList sizes(subMap.size(), Foam::zero{});
|
||||||
|
|
||||||
|
forAll(subMap, idx)
|
||||||
|
{
|
||||||
|
for (const label nbr : input[subMap[idx]])
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
select.test(nbr)
|
||||||
|
&& reverseMap.contains(nbr) // extra consistency (paranoid)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++sizes[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CompactListList<label> output(sizes);
|
||||||
|
|
||||||
|
// Reuse sizes as output offset into output.values()
|
||||||
|
sizes = labelList::subList(output.offsets(), output.size());
|
||||||
|
labelList& values = output.values();
|
||||||
|
|
||||||
|
|
||||||
|
// Pass 2: extract sub-adjacent matrix
|
||||||
|
|
||||||
|
label newNbr = -1;
|
||||||
|
|
||||||
|
forAll(subMap, idx)
|
||||||
|
{
|
||||||
|
for (const label nbr : input[subMap[idx]])
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
select.test(nbr)
|
||||||
|
&& (newNbr = reverseMap.lookup(nbr, -1)) >= 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
values[sizes[idx]++] = newNbr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Perform a subset of the adjacency matrix
|
||||||
|
CompactListList<label> subsetAdjacency
|
||||||
|
(
|
||||||
|
const labelRange& slice,
|
||||||
|
const CompactListList<label>& input,
|
||||||
|
labelList& subMap
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Ensure that the selection corresponds to a valid subset
|
||||||
|
const labelRange select = slice.subset0(input.size());
|
||||||
|
|
||||||
|
// Corresponds to cellMap etc (the original selection)
|
||||||
|
subMap = Foam::identity(select);
|
||||||
|
|
||||||
|
|
||||||
|
// Pass 1: determine the selected sub-sizes
|
||||||
|
labelList sizes(subMap.size(), Foam::zero{});
|
||||||
|
|
||||||
|
forAll(subMap, idx)
|
||||||
|
{
|
||||||
|
for (const label nbr : input[subMap[idx]])
|
||||||
|
{
|
||||||
|
if (select.contains(nbr))
|
||||||
|
{
|
||||||
|
++sizes[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CompactListList<label> output(sizes);
|
||||||
|
|
||||||
|
// Reuse sizes as output offset into output.values()
|
||||||
|
sizes = labelList::subList(output.offsets(), output.size());
|
||||||
|
labelList& values = output.values();
|
||||||
|
|
||||||
|
|
||||||
|
// Pass 2: extract sub-adjacent matrix
|
||||||
|
|
||||||
|
const label localOffset = select.start();
|
||||||
|
|
||||||
|
forAll(subMap, idx)
|
||||||
|
{
|
||||||
|
for (const label nbr : input[subMap[idx]])
|
||||||
|
{
|
||||||
|
if (select.contains(nbr))
|
||||||
|
{
|
||||||
|
values[sizes[idx]++] = nbr - localOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user