pairGAMGAgglomerate.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2025 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "pairGAMGAgglomeration.H"
27 #include "lduAddressing.H"
28 
29 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
30 
32 (
33  const lduMesh& mesh,
35 )
36 {
37  // Start geometric agglomeration from the given faceWeights
38  scalarField* faceWeightsPtr = const_cast<scalarField*>(&faceWeights);
39 
40  // Agglomerate until the required number of cells in the coarsest level
41  // is reached
42 
43  label nPairLevels = 0;
44  label nCreatedLevels = 0;
45 
46  while (nCreatedLevels < maxLevels_ - 1)
47  {
48  label nCoarseCells = -1;
49 
50  tmp<labelField> finalAgglomPtr = agglomerate
51  (
52  nCoarseCells,
53  meshLevel(nCreatedLevels).lduAddr(),
54  *faceWeightsPtr
55  );
56 
57  if
58  (
59  continueAgglomerating(finalAgglomPtr().size(), nCoarseCells)
60  )
61  {
62  nCells_[nCreatedLevels] = nCoarseCells;
63  restrictAddressing_.set(nCreatedLevels, finalAgglomPtr);
64  }
65  else
66  {
67  break;
68  }
69 
70  agglomerateLduAddressing(nCreatedLevels);
71 
72  // Agglomerate the faceWeights field for the next level
73  {
74  scalarField* aggFaceWeightsPtr
75  (
76  new scalarField
77  (
78  meshLevels_[nCreatedLevels].upperAddr().size(),
79  0.0
80  )
81  );
82 
84  (
85  *aggFaceWeightsPtr,
86  *faceWeightsPtr,
87  nCreatedLevels
88  );
89 
90  if (nCreatedLevels)
91  {
92  delete faceWeightsPtr;
93  }
94 
95  faceWeightsPtr = aggFaceWeightsPtr;
96  }
97 
98  if (nPairLevels % mergeLevels_)
99  {
100  combineLevels(nCreatedLevels);
101  }
102  else
103  {
104  nCreatedLevels++;
105  }
106 
107  nPairLevels++;
108  }
109 
110  // Shrink the storage of the levels to those created
111  compactLevels(nCreatedLevels);
112 
113  // Delete temporary geometry storage
114  if (nCreatedLevels)
115  {
116  delete faceWeightsPtr;
117  }
118 }
119 
120 
121 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
122 
124 (
125  label& nCoarseCells,
126  const lduAddressing& fineMatrixAddressing,
127  const scalarField& faceWeights
128 )
129 {
130  const label nFineCells = fineMatrixAddressing.size();
131 
132  const labelUList& upperAddr = fineMatrixAddressing.upperAddr();
133  const labelUList& lowerAddr = fineMatrixAddressing.lowerAddr();
134 
135  // For each cell calculate faces
136  labelList cellFaces(upperAddr.size() + lowerAddr.size());
137  labelList cellFaceOffsets(nFineCells + 1);
138 
139  // memory management
140  {
141  labelList nNbrs(nFineCells, 0);
142 
143  forAll(upperAddr, facei)
144  {
145  nNbrs[upperAddr[facei]]++;
146  }
147 
148  forAll(lowerAddr, facei)
149  {
150  nNbrs[lowerAddr[facei]]++;
151  }
152 
153  cellFaceOffsets[0] = 0;
154  forAll(nNbrs, celli)
155  {
156  cellFaceOffsets[celli+1] = cellFaceOffsets[celli] + nNbrs[celli];
157  }
158 
159  // reset the whole list to use as counter
160  nNbrs = 0;
161 
162  forAll(upperAddr, facei)
163  {
164  cellFaces
165  [
166  cellFaceOffsets[upperAddr[facei]] + nNbrs[upperAddr[facei]]
167  ] = facei;
168 
169  nNbrs[upperAddr[facei]]++;
170  }
171 
172  forAll(lowerAddr, facei)
173  {
174  cellFaces
175  [
176  cellFaceOffsets[lowerAddr[facei]] + nNbrs[lowerAddr[facei]]
177  ] = facei;
178 
179  nNbrs[lowerAddr[facei]]++;
180  }
181  }
182 
183 
184  // go through the faces and create clusters
185 
186  tmp<labelField> tcoarseCellMap(new labelField(nFineCells, -1));
187  labelField& coarseCellMap = tcoarseCellMap.ref();
188 
189  nCoarseCells = 0;
190  label celli;
191 
192  for (label cellfi=0; cellfi<nFineCells; cellfi++)
193  {
194  // Change cell ordering depending on direction for this level
195  celli = forward_ ? cellfi : nFineCells - cellfi - 1;
196 
197  if (coarseCellMap[celli] < 0)
198  {
199  label matchFaceNo = -1;
200  scalar maxFaceWeight = -great;
201 
202  // check faces to find ungrouped neighbour with largest face weight
203  for
204  (
205  label faceOs=cellFaceOffsets[celli];
206  faceOs<cellFaceOffsets[celli+1];
207  faceOs++
208  )
209  {
210  label facei = cellFaces[faceOs];
211 
212  // I don't know whether the current cell is owner or neighbour.
213  // Therefore I'll check both sides
214  if
215  (
216  coarseCellMap[upperAddr[facei]] < 0
217  && coarseCellMap[lowerAddr[facei]] < 0
218  && faceWeights[facei] > maxFaceWeight
219  )
220  {
221  // Match found. Pick up all the necessary data
222  matchFaceNo = facei;
223  maxFaceWeight = faceWeights[facei];
224  }
225  }
226 
227  if (matchFaceNo >= 0)
228  {
229  // Make a new group
230  coarseCellMap[upperAddr[matchFaceNo]] = nCoarseCells;
231  coarseCellMap[lowerAddr[matchFaceNo]] = nCoarseCells;
232  nCoarseCells++;
233  }
234  else
235  {
236  // No match. Find the best neighbouring cluster and
237  // put the cell there
238  label clusterMatchFaceNo = -1;
239  scalar clusterMaxFaceCoeff = -great;
240 
241  for
242  (
243  label faceOs=cellFaceOffsets[celli];
244  faceOs<cellFaceOffsets[celli+1];
245  faceOs++
246  )
247  {
248  label facei = cellFaces[faceOs];
249 
250  if (faceWeights[facei] > clusterMaxFaceCoeff)
251  {
252  clusterMatchFaceNo = facei;
253  clusterMaxFaceCoeff = faceWeights[facei];
254  }
255  }
256 
257  if (clusterMatchFaceNo >= 0)
258  {
259  // Add the cell to the best cluster
260  coarseCellMap[celli] = max
261  (
262  coarseCellMap[upperAddr[clusterMatchFaceNo]],
263  coarseCellMap[lowerAddr[clusterMatchFaceNo]]
264  );
265  }
266  }
267  }
268  }
269 
270  // Check that all cells are part of clusters,
271  // if not create single-cell "clusters" for each
272  for (label cellfi=0; cellfi<nFineCells; cellfi++)
273  {
274  // Change cell ordering depending on direction for this level
275  celli = forward_ ? cellfi : nFineCells - cellfi - 1;
276 
277  if (coarseCellMap[celli] < 0)
278  {
279  coarseCellMap[celli] = nCoarseCells;
280  nCoarseCells++;
281  }
282  }
283 
284  if (!forward_)
285  {
286  nCoarseCells--;
287 
288  forAll(coarseCellMap, celli)
289  {
290  coarseCellMap[celli] = nCoarseCells - coarseCellMap[celli];
291  }
292 
293  nCoarseCells++;
294  }
295 
296  // Reverse the map ordering for the next level
297  // to improve the next level of agglomeration
298  forward_ = !forward_;
299 
300  return tcoarseCellMap;
301 }
302 
303 
304 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
void agglomerateLduAddressing(const label fineLevelIndex)
Assemble coarse mesh addressing.
const label maxLevels_
Max number of levels.
void compactLevels(const label nCreatedLevels)
Shrink the number of levels to that specified.
PtrList< lduPrimitiveMesh > meshLevels_
Hierarchy of mesh addressing.
bool continueAgglomerating(const label nCells, const label nCoarseCells) const
Check the need for further agglomeration.
labelList nCells_
The number of cells in each level.
void restrictFaceField(Field< Type > &cf, const Field< Type > &ff, const label fineLevelIndex) const
Restrict (integrate by summation) face field.
void combineLevels(const label curLevel)
Combine a level with the previous one.
PtrList< labelField > restrictAddressing_
Cell restriction addressing array.
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
The class contains the addressing required by the lduMatrix: upper, lower and losort.
label size() const
Return number of equations.
virtual const labelUList & upperAddr() const =0
Return upper addressing.
virtual const labelUList & lowerAddr() const =0
Return lower addressing.
Abstract base class for meshes which provide LDU addressing for the construction of lduMatrix and LDU...
Definition: lduMesh.H:60
void agglomerate(const lduMesh &mesh, const scalarField &faceWeights)
Agglomerate all levels starting from the given face weights.
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:197
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
tmp< scalarField > faceWeights(const polyMesh &mesh, const vectorField &fCtrs, const vectorField &fAreas, const vectorField &cellCtrs)
Generate interpolation factors field.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:49
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)