pairGAMGAgglomerate.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "pairGAMGAgglomeration.H"
30 #include "lduAddressing.H"
31 
32 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
33 
35 (
36  const label nCellsInCoarsestLevel,
37  const label startLevel,
38  const scalarField& startFaceWeights,
39  const bool doProcessorAgglomerate
40 )
41 {
42  if (nCells_.size() < maxLevels_)
43  {
44  // See compactLevels. Make space if not enough
49  faceFlipMap_.resize(maxLevels_);
50  nPatchFaces_.resize(maxLevels_);
52  meshLevels_.resize(maxLevels_);
53  // Have procCommunicator_ always, even if not procAgglomerating.
54  // Use value -1 to indicate nothing is proc-agglomerated
57  {
58  procAgglomMap_.resize(maxLevels_);
59  agglomProcIDs_.resize(maxLevels_);
62  procFaceMap_.resize(maxLevels_);
65  }
66  }
67 
68 
69  // Start geometric agglomeration from the given faceWeights
70  scalarField faceWeights = startFaceWeights;
71 
72  // Agglomerate until the required number of cells in the coarsest level
73  // is reached
74 
75  label nPairLevels = 0;
76  label nCreatedLevels = startLevel;
77 
78  while (nCreatedLevels < maxLevels_ - 1)
79  {
80  if (!hasMeshLevel(nCreatedLevels))
81  {
82  FatalErrorInFunction<< "No mesh at nCreatedLevels:"
83  << nCreatedLevels
84  << exit(FatalError);
85  }
86 
87  const auto& fineMesh = meshLevel(nCreatedLevels);
88 
89 
90  label nCoarseCells = -1;
91 
92  tmp<labelField> finalAgglomPtr = agglomerate
93  (
94  nCoarseCells,
95  fineMesh.lduAddr(),
96  faceWeights
97  );
98 
99  if
100  (
102  (
103  nCellsInCoarsestLevel,
104  finalAgglomPtr().size(),
105  nCoarseCells,
106  fineMesh.comm()
107  )
108  )
109  {
110  nCells_[nCreatedLevels] = nCoarseCells;
111  restrictAddressing_.set(nCreatedLevels, finalAgglomPtr);
112  }
113  else
114  {
115  break;
116  }
117 
118  // Create coarse mesh
119  agglomerateLduAddressing(nCreatedLevels);
120 
121  // Agglomerate the faceWeights field for the next level
122  {
123  scalarField aggFaceWeights
124  (
125  meshLevels_[nCreatedLevels].upperAddr().size(),
126  0.0
127  );
128 
130  (
131  aggFaceWeights,
132  faceWeights,
133  nCreatedLevels
134  );
135 
136  faceWeights = std::move(aggFaceWeights);
137  }
138 
139  if (nPairLevels % mergeLevels_)
140  {
141  combineLevels(nCreatedLevels);
142  }
143  else
144  {
145  nCreatedLevels++;
146  }
147 
148  nPairLevels++;
149  }
150 
151  // Shrink the storage of the levels to those created
152  compactLevels(nCreatedLevels, doProcessorAgglomerate);
153 }
154 
155 
156 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
157 
159 (
160  label& nCoarseCells,
161  const lduAddressing& fineMatrixAddressing,
162  const scalarField& faceWeights
163 )
164 {
165  const label nFineCells = fineMatrixAddressing.size();
166 
167  const labelUList& upperAddr = fineMatrixAddressing.upperAddr();
168  const labelUList& lowerAddr = fineMatrixAddressing.lowerAddr();
169 
170  // For each cell calculate faces
171  labelList cellFaces(upperAddr.size() + lowerAddr.size());
172  labelList cellFaceOffsets(nFineCells + 1);
173 
174  // memory management
175  {
176  labelList nNbrs(nFineCells, Zero);
177 
178  forAll(upperAddr, facei)
179  {
180  nNbrs[upperAddr[facei]]++;
181  }
182 
183  forAll(lowerAddr, facei)
184  {
185  nNbrs[lowerAddr[facei]]++;
186  }
187 
188  cellFaceOffsets[0] = 0;
189  forAll(nNbrs, celli)
190  {
191  cellFaceOffsets[celli+1] = cellFaceOffsets[celli] + nNbrs[celli];
192  }
193 
194  // reset the whole list to use as counter
195  nNbrs = 0;
196 
197  forAll(upperAddr, facei)
198  {
199  cellFaces
200  [
201  cellFaceOffsets[upperAddr[facei]] + nNbrs[upperAddr[facei]]
202  ] = facei;
203 
204  nNbrs[upperAddr[facei]]++;
205  }
206 
207  forAll(lowerAddr, facei)
208  {
209  cellFaces
210  [
211  cellFaceOffsets[lowerAddr[facei]] + nNbrs[lowerAddr[facei]]
212  ] = facei;
213 
214  nNbrs[lowerAddr[facei]]++;
215  }
216  }
217 
218 
219  // go through the faces and create clusters
220 
221  auto tcoarseCellMap = tmp<labelField>::New(nFineCells, -1);
222  auto& coarseCellMap = tcoarseCellMap.ref();
223 
224  nCoarseCells = 0;
225  label celli;
226 
227  for (label cellfi=0; cellfi<nFineCells; cellfi++)
228  {
229  // Change cell ordering depending on direction for this level
230  celli = forward_ ? cellfi : nFineCells - cellfi - 1;
231 
232  if (coarseCellMap[celli] < 0)
233  {
234  label matchFaceNo = -1;
235  scalar maxFaceWeight = -GREAT;
236 
237  // check faces to find ungrouped neighbour with largest face weight
238  for
239  (
240  label faceOs=cellFaceOffsets[celli];
241  faceOs<cellFaceOffsets[celli+1];
242  faceOs++
243  )
244  {
245  label facei = cellFaces[faceOs];
246 
247  // I don't know whether the current cell is owner or neighbour.
248  // Therefore I'll check both sides
249  if
250  (
251  coarseCellMap[upperAddr[facei]] < 0
252  && coarseCellMap[lowerAddr[facei]] < 0
253  && faceWeights[facei] > maxFaceWeight
254  )
255  {
256  // Match found. Pick up all the necessary data
257  matchFaceNo = facei;
258  maxFaceWeight = faceWeights[facei];
259  }
260  }
261 
262  if (matchFaceNo >= 0)
263  {
264  // Make a new group
265  coarseCellMap[upperAddr[matchFaceNo]] = nCoarseCells;
266  coarseCellMap[lowerAddr[matchFaceNo]] = nCoarseCells;
267  nCoarseCells++;
268  }
269  else
270  {
271  // No match. Find the best neighbouring cluster and
272  // put the cell there
273  label clusterMatchFaceNo = -1;
274  scalar clusterMaxFaceCoeff = -GREAT;
275 
276  for
277  (
278  label faceOs=cellFaceOffsets[celli];
279  faceOs<cellFaceOffsets[celli+1];
280  faceOs++
281  )
282  {
283  label facei = cellFaces[faceOs];
284 
285  if (faceWeights[facei] > clusterMaxFaceCoeff)
286  {
287  clusterMatchFaceNo = facei;
288  clusterMaxFaceCoeff = faceWeights[facei];
289  }
290  }
291 
292  if (clusterMatchFaceNo >= 0)
293  {
294  // Add the cell to the best cluster
295  coarseCellMap[celli] = max
296  (
297  coarseCellMap[upperAddr[clusterMatchFaceNo]],
298  coarseCellMap[lowerAddr[clusterMatchFaceNo]]
299  );
300  }
301  }
302  }
303  }
304 
305  // Check that all cells are part of clusters,
306  // if not create single-cell "clusters" for each
307  for (label cellfi=0; cellfi<nFineCells; cellfi++)
308  {
309  // Change cell ordering depending on direction for this level
310  celli = forward_ ? cellfi : nFineCells - cellfi - 1;
311 
312  if (coarseCellMap[celli] < 0)
313  {
314  coarseCellMap[celli] = nCoarseCells;
315  nCoarseCells++;
316  }
317  }
318 
319  if (!forward_)
320  {
321  nCoarseCells--;
322 
323  forAll(coarseCellMap, celli)
324  {
325  coarseCellMap[celli] = nCoarseCells - coarseCellMap[celli];
326  }
327 
328  nCoarseCells++;
329  }
330 
331  // Reverse the map ordering for the next level
332  // to improve the next level of agglomeration
333  forward_ = !forward_;
334 
335  return tcoarseCellMap;
336 }
337 
338 
339 // ************************************************************************* //
PtrList< labelListList > procBoundaryMap_
Mapping from processor to procMeshLevel boundary.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
bool continueAgglomerating(const label nCellsInCoarsestLevel, const label nCells, const label nCoarseCells, const label comm) const
Check the need for further agglomeration.
PtrList< labelListList > procFaceMap_
Mapping from processor to procMeshLevel face.
PtrList< labelListList > patchFaceRestrictAddressing_
Patch-local face restriction addressing array.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
PtrList< labelListListList > procBoundaryFaceMap_
Mapping from processor to procMeshLevel boundary face.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
PtrList< labelList > procCellOffsets_
Mapping from processor to procMeshLevel cells.
void restrictFaceField(Field< Type > &cf, const Field< Type > &ff, const label fineLevelIndex) const
Restrict (integrate by summation) face field.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
PtrList< labelList > faceRestrictAddressing_
Face restriction addressing array.
PtrList< labelList > nPatchFaces_
The number of (coarse) patch faces in each level.
virtual const labelUList & lowerAddr() const =0
Return lower addressing.
PtrList< labelList > agglomProcIDs_
Per level the set of processors to agglomerate. Element 0 is.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static tmp< labelField > agglomerate(label &nCoarseCells, const lduAddressing &fineMatrixAddressing, const scalarField &faceWeights)
Calculate and return agglomeration.
labelList procCommunicator_
Communicator for given level.
bool processorAgglomerate() const
Whether to agglomerate across processors.
PtrList< lduPrimitiveMesh > meshLevels_
Hierarchy of mesh addressing.
virtual const labelUList & upperAddr() const =0
Return upper addressing.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
labelList nCells_
The number of cells in each level.
labelList nFaces_
The number of (coarse) faces in each level.
PtrList< labelField > restrictAddressing_
Cell restriction addressing array.
void agglomerateLduAddressing(const label fineLevelIndex)
Assemble coarse mesh addressing.
const label maxLevels_
Max number of levels.
PtrList< labelList > procAgglomMap_
Per level, per processor the processor it agglomerates into.
The class contains the addressing required by the lduMatrix: upper, lower and losort.
PtrList< boolList > faceFlipMap_
Face flip: for faces mapped to internal faces stores whether.
A class for managing temporary objects.
Definition: HashPtrTable.H:50
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
void combineLevels(const label curLevel)
Combine a level with the previous one.
void compactLevels(const label nCreatedLevels, const bool doProcessorAgglomerate)
Shrink the number of levels to that specified. Optionally do.
label size() const
Return number of equations.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127