1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "engineScotchDecomp.H"
27 #include "addToRunTimeSelectionTable.H"
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 defineTypeNameAndDebug(engineScotchDecomp, 0);
35 addToRunTimeSelectionTable
43 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
45 Foam::engineScotchDecomp::engineScotchDecomp
47 const dictionary& decompositionDict,
51 scotchDecomp(decompositionDict, mesh),
52 dict_(decompositionDict.subDict(typeName + "Coeffs")),
53 slidingPatchPairs_(dict_.lookup("slidingPatchPairs")),
54 expandSliding_(dict_.lookup("expandSliding"))
58 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
60 Foam::labelList Foam::engineScotchDecomp::decompose
62 const pointField& points,
63 const scalarField& pointWeights
66 if (points.size() != mesh().nCells())
70 "engineScotchDecomp::decompose\n"
72 " const pointField&,\n"
73 " const scalarField&\n"
75 ) << "Can use this decomposition method only for the whole mesh"
77 << "and supply one coordinate (cellCentre) for every cell." << endl
78 << "The number of coordinates " << points.size() << endl
79 << "The number of cells in the mesh " << mesh().nCells()
83 // Create clustering to coarse level
85 labelList fineToCoarse(mesh().nCells(), -1);
87 // Mask all cells in the cylinder layering region with true
88 // Used in two-pass decomposition later
89 boolList cylinderMask(mesh().nCells(), false);
92 // Locate piston patch and cluster up colums, using opposite faces
93 label pistonPatchID = mesh().boundaryMesh().findPatchID("piston");
95 // Go through the sliding pairs and mark clustering
96 forAll (slidingPatchPairs_, pairI)
98 // Locate patch and cluster up colums, using opposite faces
99 label firstPatchID = mesh().boundaryMesh().findPatchID
101 slidingPatchPairs_[pairI].first()
104 label secondPatchID = mesh().boundaryMesh().findPatchID
106 slidingPatchPairs_[pairI].second()
109 if (firstPatchID == -1 || secondPatchID == -1)
113 "labelList engineScotchDecomp::decompose\n"
115 " const pointField& points,\n"
116 " const scalarField& pointWeights\n"
118 ) << "Cannot find sliding patch pair "
119 << slidingPatchPairs_[pairI]
120 << abort(FatalError);
123 // Put all cells next to the patch into a cluster
126 // Use point-cell addressing from patch points
127 const labelListList& pc = mesh().pointCells();
130 const labelList& mp1 =
131 mesh().boundaryMesh()[firstPatchID].meshPoints();
135 const labelList& curCells = pc[mp1[pointI]];
137 forAll (curCells, cellI)
139 fineToCoarse[curCells[cellI]] = nClusters;
140 cylinderMask[curCells[cellI]] = true;
146 const labelList& mp2 =
147 mesh().boundaryMesh()[secondPatchID].meshPoints();
151 const labelList& curCells = pc[mp2[pointI]];
153 forAll (curCells, cellI)
155 fineToCoarse[curCells[cellI]] = nClusters;
156 cylinderMask[curCells[cellI]] = true;
165 const labelList& fc1 =
166 mesh().boundaryMesh()[firstPatchID].faceCells();
170 fineToCoarse[fc1[fcI]] = nClusters;
171 cylinderMask[fc1[fcI]] = true;
177 const labelList& fc2 =
178 mesh().boundaryMesh()[secondPatchID].faceCells();
182 fineToCoarse[fc2[fcI]] = nClusters;
183 cylinderMask[fc2[fcI]] = true;
191 if (pistonPatchID > -1)
193 // Found piston patch
194 const faceList& f = mesh().allFaces();
195 const cellList& c = mesh().cells();
196 const labelList& owner = mesh().faceOwner();
197 const labelList& neighbour = mesh().faceNeighbour();
199 const labelList& faceCells =
200 mesh().boundaryMesh()[pistonPatchID].faceCells();
202 forAll (faceCells, faceI)
205 label curFaceNo = faceI
206 + mesh().boundaryMesh()[pistonPatchID].start();
209 label curCellNo = faceCells[faceI];
211 // Mark cell to cluster
212 if (fineToCoarse[curCellNo] < 0)
215 fineToCoarse[curCellNo] = nClusters;
216 cylinderMask[curCellNo] = true;
220 // Attempt to find the next face and cell
221 curFaceNo = c[curCellNo].opposingFaceLabel(curFaceNo, f);
225 // Face found, try for a cell
226 if (curFaceNo < mesh().nInternalFaces())
228 if (owner[curFaceNo] == curCellNo)
230 curCellNo = neighbour[curFaceNo];
232 else if (neighbour[curFaceNo] == curCellNo)
234 curCellNo = owner[curFaceNo];
238 // Error in layering. Should never happen
242 // Mark cell to cluster
243 fineToCoarse[curCellNo] = nClusters;
244 cylinderMask[curCellNo] = true;
254 // Cannot find opposing face: out of prismatic region
265 // Count cylinder cells from mask
266 label nCylinderCells = 0;
268 forAll (cylinderMask, cellI)
270 if (cylinderMask[cellI]) nCylinderCells++;
273 label nStaticCells = mesh().nCells() - nCylinderCells;
274 label nCylClusters = nClusters;
276 // Visit all unmarked cells and put them into single clusters
277 forAll (fineToCoarse, cellI)
279 if (fineToCoarse[cellI] == -1)
281 fineToCoarse[cellI] = nClusters;
286 label nStaticClusters = nClusters - nCylClusters;
288 Info<< "Number of cells: " << mesh().nCells()
289 << ", in cylinder + sliding: " << nCylinderCells
290 << ", in static part: " << nStaticCells << nl
291 << "Number of cylinder clusters " << nCylClusters
292 << ", static clusters " << nStaticClusters
293 << ", total clusters " << nClusters << endl;
295 // Mark-up complete. Create point centres and weights for all clusters
296 vectorField clusterCentres(nClusters, vector::zero);
298 // Stabilise cluster volumes in case a cluster ends up empty
299 // It is possible to have empty clusters without connectivity
300 scalarField clusterVols(nClusters, SMALL);
301 scalarField clusterWeights(nClusters, 0);
303 const vectorField& centres = mesh().cellCentres();
304 const scalarField& vols = mesh().cellVolumes();
306 forAll (fineToCoarse, cellI)
308 const label& curCoarse = fineToCoarse[cellI];
310 clusterCentres[curCoarse] += centres[cellI]*vols[cellI];
311 clusterVols[curCoarse] += vols[cellI];
312 clusterWeights[curCoarse] += 1;
315 clusterCentres /= clusterVols;
317 // Execute decomposition, first on cylinder layering zone, then on the rest
319 // Collect cell-cells in cylinder layering zone and the rest
321 // Create and cellCells hash lookup on two pieces
323 // Note: cell clusters come first and they will be done
324 // on a shortened list. Static clusters need to be renumbered by
325 // throwing away the first part of the list
327 List<labelHashSet> cylCellCellsHash(nCylClusters);
328 List<labelHashSet> staticCellCellsHash(nStaticClusters);
330 const labelListList cellCells = mesh().cellCells();
332 forAll (cellCells, cellI)
334 const labelList& curCC = cellCells[cellI];
336 label curCluster = fineToCoarse[cellI];
338 if (cylinderMask[cellI])
340 labelHashSet& curCylAddr = cylCellCellsHash[curCluster];
342 // Collect neighbour cluster addressing
345 // Add neighbour if marked
346 if (cylinderMask[curCC[neiI]])
348 label nbrCluster = fineToCoarse[curCC[neiI]];
350 if (nbrCluster != curCluster)
352 if (!curCylAddr.found(nbrCluster))
354 curCylAddr.insert(nbrCluster);
363 curCluster -= nCylClusters;
365 labelHashSet& curStaticAddr = staticCellCellsHash[curCluster];
369 // Add neighbour if marked
370 if (!cylinderMask[curCC[neiI]])
372 label nbrCluster = fineToCoarse[curCC[neiI]]
375 if (nbrCluster != curCluster)
377 if (!curStaticAddr.found(nbrCluster))
379 curStaticAddr.insert(nbrCluster);
387 // Pack cellCells on the cylinder
388 labelListList cylCellCells(nCylClusters);
390 forAll (cylCellCellsHash, clusterI)
392 cylCellCells[clusterI] = cylCellCellsHash[clusterI].toc();
395 // Decompose cylinder: size of list equals the number of clusters
396 // in the cylinder region
397 vectorField clusterCentresCyl = clusterCentres;
398 scalarField clusterWeightsCyl = clusterWeights;
400 clusterCentresCyl.setSize(nCylClusters);
401 clusterWeightsCyl.setSize(nCylClusters);
403 labelList cylDecomp = scotchDecomp::decompose
410 // Decompose static: size of list equals the number of clusters
412 labelListList staticCellCells(nStaticClusters);
414 forAll (staticCellCellsHash, clusterI)
416 staticCellCells[clusterI] = staticCellCellsHash[clusterI].toc();
419 vectorField clusterCentresStatic(nStaticClusters);
420 scalarField clusterWeightsStatic(nStaticClusters);
422 forAll (clusterCentresStatic, i)
424 clusterCentresStatic[i] = clusterCentres[nCylClusters + i];
425 clusterWeightsStatic[i] = clusterWeights[nCylClusters + i];
428 labelList staticDecomp = scotchDecomp::decompose
431 clusterCentresStatic,
435 // Reconstruct final decomposition
437 labelList finalDecomp(mesh().nCells(), -1);
439 forAll (cylinderMask, cellI)
441 if (cylinderMask[cellI])
444 finalDecomp[cellI] = cylDecomp[fineToCoarse[cellI]];
450 staticDecomp[fineToCoarse[cellI] - nCylClusters];
458 // ************************************************************************* //