Loading...
Searching...
No Matches
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-2025 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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
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
45 nCells_.resize(maxLevels_);
47 nFaces_.resize(maxLevels_);
52 meshLevels_.resize(maxLevels_);
53 // Have procCommunicator_ always, even if not procAgglomerating.
54 // Use value -1 to indicate nothing is proc-agglomerated
55 procCommunicator_.resize(maxLevels_ + 1, -1);
57 {
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 // Small tolerance to account for faces potentially having slightly
225 // different truncation error in their weights from run to run
226 // (e.g. due to offloading). If all the largest faces per cell are
227 // within this tolerance use the first one. This guarantees repeatability.
228 // Disabled on non-offload situations for now since makes comparison
229 // to previous versions harder. TBD.
230 #ifdef _OPENMP
231 const scalar tol = 1E-10;
232 #else
233 const scalar tol = 0;
234 #endif
235
236 nCoarseCells = 0;
237 label celli;
238 for (label cellfi=0; cellfi<nFineCells; cellfi++)
239 {
240 // Change cell ordering depending on direction for this level
241 celli = forward_ ? cellfi : nFineCells - cellfi - 1;
242
243 if (coarseCellMap[celli] < 0)
244 {
245 label matchFaceNo = -1;
246 scalar maxFaceWeight = -GREAT;
247
248 // check faces to find ungrouped neighbour with largest face weight
249 for
250 (
251 label faceOs=cellFaceOffsets[celli];
252 faceOs<cellFaceOffsets[celli+1];
253 faceOs++
254 )
255 {
256 label facei = cellFaces[faceOs];
257
258 // I don't know whether the current cell is owner or neighbour.
259 // Therefore I'll check both sides
260 if
261 (
262 coarseCellMap[upperAddr[facei]] < 0
263 && coarseCellMap[lowerAddr[facei]] < 0
264 && faceWeights[facei] > maxFaceWeight*(1.0 + tol)
265 )
266 {
267 // Match found. Pick up all the necessary data
268 matchFaceNo = facei;
269 maxFaceWeight = faceWeights[facei];
270 }
271 }
272
273 if (matchFaceNo >= 0)
274 {
275 // Make a new group
276 coarseCellMap[upperAddr[matchFaceNo]] = nCoarseCells;
277 coarseCellMap[lowerAddr[matchFaceNo]] = nCoarseCells;
278 nCoarseCells++;
279 }
280 else
281 {
282 // No match. Find the best neighbouring cluster and
283 // put the cell there
284 label clusterMatchFaceNo = -1;
285 scalar clusterMaxFaceCoeff = -GREAT;
286
287 for
288 (
289 label faceOs=cellFaceOffsets[celli];
290 faceOs<cellFaceOffsets[celli+1];
291 faceOs++
292 )
293 {
294 label facei = cellFaces[faceOs];
295
296 if (faceWeights[facei] > clusterMaxFaceCoeff*(1.0 + tol))
297 {
298 clusterMatchFaceNo = facei;
299 clusterMaxFaceCoeff = faceWeights[facei];
300 }
301 }
302
303 if (clusterMatchFaceNo >= 0)
304 {
305 // Add the cell to the best cluster
306 coarseCellMap[celli] = max
307 (
308 coarseCellMap[upperAddr[clusterMatchFaceNo]],
309 coarseCellMap[lowerAddr[clusterMatchFaceNo]]
310 );
311 }
312 }
313 }
314 }
315
316 // Check that all cells are part of clusters,
317 // if not create single-cell "clusters" for each
318 for (label cellfi=0; cellfi<nFineCells; cellfi++)
319 {
320 // Change cell ordering depending on direction for this level
321 celli = forward_ ? cellfi : nFineCells - cellfi - 1;
322
323 if (coarseCellMap[celli] < 0)
324 {
325 coarseCellMap[celli] = nCoarseCells;
326 nCoarseCells++;
327 }
328 }
329
330 if (!forward_)
331 {
332 nCoarseCells--;
333
334 forAll(coarseCellMap, celli)
335 {
336 coarseCellMap[celli] = nCoarseCells - coarseCellMap[celli];
337 }
338
339 nCoarseCells++;
340 }
341
342 // Reverse the map ordering for the next level
343 // to improve the next level of agglomeration
344 forward_ = !forward_;
345
346 return tcoarseCellMap;
347}
348
349
350// ************************************************************************* //
bool processorAgglomerate() const
Whether to agglomerate across processors.
void agglomerateLduAddressing(const label fineLevelIndex)
Assemble coarse mesh addressing.
PtrList< labelListList > patchFaceRestrictAddressing_
Patch-local face restriction addressing array.
PtrList< boolList > faceFlipMap_
Face flip: for faces mapped to internal faces stores whether.
PtrList< labelList > nPatchFaces_
The number of (coarse) patch faces in each level.
const label maxLevels_
Max number of levels.
void compactLevels(const label nCreatedLevels, const bool doProcessorAgglomerate)
Shrink the number of levels to that specified. Optionally do.
labelList nFaces_
The number of (coarse) faces in each level.
PtrList< lduPrimitiveMesh > meshLevels_
Hierarchy of mesh addressing.
labelList nCells_
The number of cells in each level.
bool continueAgglomerating(const label nCellsInCoarsestLevel, const label nCells, const label nCoarseCells, const label comm) const
Check the need for further agglomeration.
labelList procCommunicator_
Communicator for given level.
PtrList< labelList > agglomProcIDs_
Per level the set of processors to agglomerate. Element 0 is.
void restrictFaceField(Field< Type > &cf, const Field< Type > &ff, const label fineLevelIndex) const
Restrict (integrate by summation) face field.
PtrList< labelList > procAgglomMap_
Per level, per processor the processor it agglomerates into.
PtrList< labelListList > procBoundaryMap_
Mapping from processor to procMeshLevel boundary.
void combineLevels(const label curLevel)
Combine a level with the previous one.
PtrList< labelList > procCellOffsets_
Mapping from processor to procMeshLevel cells.
PtrList< labelField > restrictAddressing_
Cell restriction addressing array.
PtrList< labelListList > procFaceMap_
Mapping from processor to procMeshLevel face.
PtrList< labelList > faceRestrictAddressing_
Face restriction addressing array.
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
PtrList< labelListListList > procBoundaryFaceMap_
Mapping from processor to procMeshLevel boundary face.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
The class contains the addressing required by the lduMatrix: upper, lower and losort.
virtual const labelUList & upperAddr() const =0
Return upper addressing.
virtual const labelUList & lowerAddr() const =0
Return lower addressing.
label size() const noexcept
Return number of equations.
static tmp< labelField > agglomerate(label &nCoarseCells, const lduAddressing &fineMatrixAddressing, const scalarField &faceWeights)
Calculate and return agglomeration.
A class for managing temporary objects.
Definition tmp.H:75
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
List< label > labelList
A List of labels.
Definition List.H:62
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299