Loading...
Searching...
No Matches
globalMeshDataTopology.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 OpenFOAM Foundation
9 Copyright (C) 2015-2024 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
29#include "globalMeshData.H"
30#include "globalIndex.H"
31#include "CompactListList.H"
32#include "processorPolyPatch.H"
33#include "syncTools.H"
34
35// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
36
37namespace Foam
39
40// NOTE: the AgglomerationType is anything that behaves like a List with
41// an operator[] and provides coverage in the (0-nCells) range.
42// - identityOp() does this
43
44template<class AgglomerationType>
45static void calcCellCellsImpl
46(
47 const polyMesh& mesh,
48 const AgglomerationType& agglom,
49 const label nLocalCoarse,
50 const bool parallel,
51 CompactListList<label>& cellCells,
52 CompactListList<scalar>* cellCellWeightsPtr = nullptr
53)
54{
55 const labelList& faceOwner = mesh.faceOwner();
56 const labelList& faceNeigh = mesh.faceNeighbour();
57 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
58
59 // Global cell numbers (agglomerated numbering)
60 const label myProci = UPstream::myProcNo(UPstream::worldComm);
61 const globalIndex globalAgglom(nLocalCoarse, UPstream::worldComm, parallel);
62
63 // The agglomerated owner per boundary faces (global numbering)
64 // from the other side (of coupled patches)
65
66 labelList globalNeighbour;
67 {
68 const label myAgglomOffset = globalAgglom.localStart(myProci);
69
70 const labelList::subList bndFaceOwner = pbm.faceOwner();
71
72 const label nBoundaryFaces = bndFaceOwner.size();
73
74 globalNeighbour.resize(nBoundaryFaces);
75
76 for (label bfacei = 0; bfacei < nBoundaryFaces; ++bfacei)
77 {
78 label val = agglom[bndFaceOwner[bfacei]];
79 if (val >= 0)
80 {
81 // Only offset 'real' (non-negative) agglomerations
82 val += myAgglomOffset;
83 }
84 globalNeighbour[bfacei] = val;
85 }
86 }
87
88 // Swap boundary neighbour information:
89 // - cyclics and (optionally) processor
90 syncTools::swapBoundaryFaceList(mesh, globalNeighbour, parallel);
91
92
93 // Count number of faces (internal + coupled)
94 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95
96 // Number of faces per coarse cell
97 labelList nFacesPerCell(nLocalCoarse, Foam::zero{});
98
99 for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
100 {
101 const label own = agglom[faceOwner[facei]];
102 const label nei = agglom[faceNeigh[facei]];
103
104 // Negative agglomeration (exclude from subset)
105 if (own < 0 || nei < 0) continue;
106
107 ++nFacesPerCell[own];
108 ++nFacesPerCell[nei];
109 }
110
111 for (const polyPatch& pp : pbm)
112 {
113 if (pp.coupled() && (parallel || !isA<processorPolyPatch>(pp)))
114 {
115 const label bndOffset = mesh.nInternalFaces();
116
117 for (const label facei : pp.range())
118 {
119 const label own = agglom[faceOwner[facei]];
120 const label globalNei = globalNeighbour[facei-bndOffset];
121
122 // Negative agglomeration (exclude from subset)
123 if (own < 0 || globalNei < 0) continue;
124
125 if
126 (
127 !globalAgglom.isLocal(myProci, globalNei)
128 || globalAgglom.toLocal(myProci, globalNei) != own
129 )
130 {
131 ++nFacesPerCell[own];
132 }
133 }
134 }
135 }
136
137
138 // Fill in offset and data
139 // ~~~~~~~~~~~~~~~~~~~~~~~
140
141 cellCells.resize_nocopy(nFacesPerCell);
142 nFacesPerCell = 0; // Restart the count
143
144
145 // CSR indexing
146 const labelList& offsets = cellCells.offsets();
147
148 // CSR connections
149 labelList& connect = cellCells.values();
150
151
152 // CSR connection weights
153 scalarList weights;
154 if (cellCellWeightsPtr)
155 {
156 cellCellWeightsPtr->clear();
157 weights.resize(cellCells.totalSize());
158 }
159
160
161 // For internal faces is just offsetted owner and neighbour
162 for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
163 {
164 const label own = agglom[faceOwner[facei]];
165 const label nei = agglom[faceNeigh[facei]];
166
167 // Negative agglomeration (exclude from subset)
168 if (own < 0 || nei < 0) continue;
169
170 const label ownIndex = offsets[own] + nFacesPerCell[own]++;
171 const label neiIndex = offsets[nei] + nFacesPerCell[nei]++;
172
173 connect[ownIndex] = globalAgglom.toGlobal(myProci, nei);
174 connect[neiIndex] = globalAgglom.toGlobal(myProci, own);
175
176 if (!weights.empty())
177 {
178 weights[ownIndex] = Foam::mag(mesh.faceAreas()[facei]);
179 weights[neiIndex] = weights[ownIndex];
180 }
181 }
182
183 // For boundary faces is offsetted coupled neighbour
184 for (const polyPatch& pp : pbm)
185 {
186 if (pp.coupled() && (parallel || !isA<processorPolyPatch>(pp)))
187 {
188 const label bndOffset = mesh.nInternalFaces();
189
190 for (const label facei : pp.range())
191 {
192 const label own = agglom[faceOwner[facei]];
193 const label globalNei = globalNeighbour[facei-bndOffset];
194
195 // Negative agglomeration (exclude from subset)
196 if (own < 0 || globalNei < 0) continue;
197
198 if
199 (
200 !globalAgglom.isLocal(myProci, globalNei)
201 || globalAgglom.toLocal(myProci, globalNei) != own
202 )
203 {
204 const label ownIndex = offsets[own] + nFacesPerCell[own]++;
205
206 connect[ownIndex] = globalNei;
207
208 if (!weights.empty())
209 {
210 weights[ownIndex] = Foam::mag(mesh.faceAreas()[facei]);
211 }
212 }
213 }
214 }
215 }
216
217
218 // Check for duplicates connections between cells
219 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
220 // Done as postprocessing step since we now have cellCells.
221
222 // NB: Because of agglomeration, self-connections will occur
223 // and must be filtered out.
224
225 if (!cellCells.empty())
226 {
227 // Need non-const access to CSR indexing
228 labelList& offsets = cellCells.offsets();
229
230 label startIndex = offsets[0];
231 label newIndex = 0;
232 labelHashSet nbrCells;
233
234 const label nCellCells = cellCells.size();
235
236 for (label celli = 0; celli < nCellCells; ++celli)
237 {
238 // Could be done as combination of std::sort, std::unique_copy
239 // except need to block out 'self' and std::copy_if/remove_if
240 // are undefined for overlapping regions
241
242 const label self = globalAgglom.toGlobal(myProci, celli);
243
244 nbrCells.clear();
245 nbrCells.insert(self);
246
247 const label endIndex = offsets[celli+1];
248
249 for (label i = startIndex; i < endIndex; ++i)
250 {
251 if (nbrCells.insert(connect[i]))
252 {
253 connect[newIndex] = connect[i];
254
255 if (!weights.empty())
256 {
257 weights[newIndex] = weights[i];
258 }
259
260 ++newIndex;
261 }
262 }
263 startIndex = endIndex;
264 offsets[celli+1] = newIndex;
265 }
266
267 connect.resize(newIndex);
268 if (!weights.empty())
269 {
270 weights.resize(newIndex);
271 }
272 }
273
274
275 // CSR connection weights
276 // - addressing is identical to the connections
277 if (cellCellWeightsPtr)
278 {
279 cellCellWeightsPtr->offsets() = cellCells.offsets();
280 cellCellWeightsPtr->values() = std::move(weights);
281 }
282
283
284 //forAll(cellCells, celli)
285 //{
286 // Pout<< "Original: Coarse cell " << celli << endl;
287 // forAll(mesh.cellCells()[celli], i)
288 // {
289 // Pout<< " nbr:" << mesh.cellCells()[celli][i] << endl;
290 // }
291 // Pout<< "Compacted: Coarse cell " << celli << endl;
292 // const labelUList cCells = cellCells[celli];
293 // forAll(cCells, i)
294 // {
295 // Pout<< " nbr:" << cCells[i] << endl;
296 // }
297 //}
299
300} // End namespace Foam
301
302
303// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
304
306(
307 const polyMesh& mesh,
308 const labelUList& agglom,
309 const label nLocalCoarse,
310 const bool parallel,
311 CompactListList<label>& cellCells
312)
313{
315 (
316 mesh,
317 agglom,
318 nLocalCoarse,
319 parallel,
320 cellCells
321 );
322}
323
324
326(
327 const polyMesh& mesh,
328 const labelUList& agglom,
329 const label nLocalCoarse,
330 const bool parallel,
331 CompactListList<label>& cellCells,
332 CompactListList<scalar>& cellCellWeights
333)
334{
336 (
337 mesh,
338 agglom,
339 nLocalCoarse,
340 parallel,
341 cellCells,
342 &cellCellWeights
343 );
344}
345
346
347// Convenience forms
348
350(
351 const polyMesh& mesh,
352 CompactListList<label>& cellCells,
353 const bool parallel
354)
355{
357 (
358 mesh,
360 mesh.nCells(),
361 parallel,
362 cellCells
363 );
364}
365
366
368(
369 const polyMesh& mesh,
370 const bitSet& selectedCells,
371 CompactListList<label>& cellCells,
372 const bool parallel
373)
374{
375 const label nCells = mesh.nCells();
376
377 labelList agglom(nCells, -1);
378 labelList cellMap;
379
380 // First pass - sorted order without duplicates
381 label nCompact = 0;
382 for (const label celli : selectedCells)
383 {
384 // A bitSet has no negatives/duplicates, so just check the upper range
385 if (celli >= nCells)
386 {
387 break;
388 }
389 else
390 {
391 agglom[celli] = celli;
392 ++nCompact;
393 }
394 }
395
396 // Second pass - finalize mappings
397 if (nCompact)
398 {
399 cellMap.resize(nCompact);
400 nCompact = 0;
401
402 for (label& celli : agglom)
403 {
404 if (celli >= 0)
405 {
406 cellMap[nCompact] = celli;
407 celli = nCompact;
408 ++nCompact;
409
410 if (nCompact == cellMap.size())
411 {
412 break; // Early termination
413 }
414 }
415 }
416 }
417
419 (
420 mesh,
421 agglom,
422 nCompact, // == cellMap.size()
423 parallel,
424 cellCells
425 );
426
427 return cellMap;
428}
429
430
432(
433 const polyMesh& mesh,
434 const labelUList& selectedCells,
435 CompactListList<label>& cellCells,
436 const bool parallel
437)
438{
439 const label nCells = mesh.nCells();
440
441 labelList agglom(nCells, -1);
442 labelList cellMap;
443
444 // First pass - creates a sorted order without duplicates
445 label nCompact = 0;
446 for (const label celli : selectedCells)
447 {
448 // Check cell is in range, and squash out duplicates
449 if (celli >= 0 && celli < nCells && agglom[celli] < 0)
450 {
451 agglom[celli] = celli;
452 ++nCompact;
453 }
454 }
455
456 // Second pass - finalize mappings
457 if (nCompact)
458 {
459 cellMap.resize(nCompact);
460 nCompact = 0;
461
462 for (label& celli : agglom)
463 {
464 if (celli >= 0)
465 {
466 cellMap[nCompact] = celli;
467 celli = nCompact;
468 ++nCompact;
469
470 if (nCompact == cellMap.size())
471 {
472 break; // Early termination
473 }
474 }
475 }
476 }
477
479 (
480 mesh,
481 agglom,
482 nCompact, // == cellMap.size()
483 parallel,
484 cellCells
485 );
486
487 return cellMap;
488}
489
490
491// ************************************************************************* //
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const polyBoundaryMesh & pbm
A packed storage of objects of type <T> using an offset table for access.
void resize_nocopy(const label mRows, const label nVals)
Redimension without preserving existing content.
label totalSize() const noexcept
The total addressed size, which corresponds to the end (back) offset and also the sum of all localSiz...
bool empty() const noexcept
True if the number of rows/sublists is zero.
const labelList & offsets() const noexcept
Return the offset table (= size()+1).
const List< T > & values() const noexcept
Return the packed values.
label size() const noexcept
The primary size (the number of rows/sublists).
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
void clear()
Remove all entries from table.
Definition HashTable.C:742
SubList< label > subList
Definition List.H:129
void resize(const label len)
Adjust allocated size of list.
Definition ListI.H:153
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition UPstream.H:1069
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
label toLocal(const label proci, const label i) const
From global to local on proci.
bool isLocal(const label proci, const label i) const
Is on processor proci.
label toGlobal(const label proci, const label i) const
From local to global on proci.
label localStart(const label proci) const
Start of proci data.
bool parallel() const noexcept
Does the mesh contain processor patches? (also valid when not running parallel).
static void calcCellCells(const polyMesh &mesh, const labelUList &agglom, const label nLocalCoarse, const bool parallel, CompactListList< label > &cellCells)
Determine (local or global) cellCells from mesh agglomeration.
const polyMesh & mesh() const noexcept
Return the mesh reference.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition syncTools.H:524
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition zero.H:58
dynamicFvMesh & mesh
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
static void calcCellCellsImpl(const polyMesh &mesh, const AgglomerationType &agglom, const label nLocalCoarse, const bool parallel, CompactListList< label > &cellCells, CompactListList< scalar > *cellCellWeightsPtr=nullptr)
UList< label > labelUList
A UList of labels.
Definition UList.H:75
List< scalar > scalarList
List of scalar.
Definition scalarList.H:32
A functor that returns its argument unchanged (cf. C++20 std::identity) Should never be specialized.
Definition stdFoam.H:108