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-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 "globalMeshData.H"
30 #include "globalIndex.H"
32 #include "processorPolyPatch.H"
33 #include "syncTools.H"
34 
35 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
36 
38 (
39  const polyMesh& mesh,
40  const labelList& agglom,
41  const label nLocalCoarse,
42  const bool parallel,
43  CompactListList<label>& cellCells
44 )
45 {
46  const labelList& faceOwner = mesh.faceOwner();
47  const labelList& faceNeigh = mesh.faceNeighbour();
49 
50  // FUTURE? treat empty agglomeration like an identity map
51 
52  // Global cell numbers (agglomerated numbering)
53  const label myProci = UPstream::myProcNo(UPstream::worldComm);
54  const globalIndex globalAgglom(nLocalCoarse, UPstream::worldComm, parallel);
55 
56 
57  // The agglomerated owner per boundary faces (global numbering)
58  // from the other side (of coupled patches)
59 
60  labelList globalNeighbour(agglom, pbm.faceOwner());
61  globalAgglom.inplaceToGlobal(myProci, globalNeighbour);
62  syncTools::swapBoundaryFaceList(mesh, globalNeighbour);
63 
64 
65  // Count number of faces (internal + coupled)
66  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67 
68  // Number of faces per coarse cell
69  labelList nFacesPerCell(nLocalCoarse, Zero);
70 
71  for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
72  {
73  const label own = agglom[faceOwner[facei]];
74  const label nei = agglom[faceNeigh[facei]];
75 
76  ++nFacesPerCell[own];
77  ++nFacesPerCell[nei];
78  }
79 
80  for (const polyPatch& pp : pbm)
81  {
82  if (pp.coupled() && (parallel || !isA<processorPolyPatch>(pp)))
83  {
84  label bFacei = pp.start()-mesh.nInternalFaces();
85 
86  for (const label facei : pp.range())
87  {
88  const label own = agglom[faceOwner[facei]];
89  const label globalNei = globalNeighbour[bFacei];
90 
91  if
92  (
93  !globalAgglom.isLocal(myProci, globalNei)
94  || globalAgglom.toLocal(myProci, globalNei) != own
95  )
96  {
97  ++nFacesPerCell[own];
98  }
99 
100  ++bFacei;
101  }
102  }
103  }
104 
105 
106  // Fill in offset and data
107  // ~~~~~~~~~~~~~~~~~~~~~~~
108 
109  cellCells.resize_nocopy(nFacesPerCell);
110 
111  nFacesPerCell = 0; // Restart the count
112 
113  labelList& m = cellCells.values();
114  const labelList& offsets = cellCells.offsets();
115 
116  // For internal faces is just offsetted owner and neighbour
117  for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
118  {
119  const label own = agglom[faceOwner[facei]];
120  const label nei = agglom[faceNeigh[facei]];
121 
122  const label ownIndex = offsets[own] + nFacesPerCell[own]++;
123  const label neiIndex = offsets[nei] + nFacesPerCell[nei]++;
124 
125  m[ownIndex] = globalAgglom.toGlobal(myProci, nei);
126  m[neiIndex] = globalAgglom.toGlobal(myProci, own);
127  }
128 
129  // For boundary faces is offsetted coupled neighbour
130  for (const polyPatch& pp : pbm)
131  {
132  if (pp.coupled() && (parallel || !isA<processorPolyPatch>(pp)))
133  {
134  label bFacei = pp.start()-mesh.nInternalFaces();
135 
136  for (const label facei : pp.range())
137  {
138  const label own = agglom[faceOwner[facei]];
139  const label globalNei = globalNeighbour[bFacei];
140 
141  if
142  (
143  !globalAgglom.isLocal(myProci, globalNei)
144  || globalAgglom.toLocal(myProci, globalNei) != own
145  )
146  {
147  const label ownIndex = offsets[own] + nFacesPerCell[own]++;
148 
149  m[ownIndex] = globalNei;
150  }
151 
152  ++bFacei;
153  }
154  }
155  }
156 
157 
158  // Check for duplicates connections between cells
159  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160  // Done as postprocessing step since we now have cellCells.
161 
162  // NB: Because of agglomeration, self-connections will occur
163  // and must be filtered out.
164 
165  if (!cellCells.empty())
166  {
167  label newIndex = 0;
168  labelHashSet nbrCells;
169 
170  labelList& m = cellCells.values();
171  labelList& offsets = cellCells.offsets();
172 
173  label startIndex = offsets[0];
174 
175  const label nCellCells = cellCells.size();
176 
177  for (label celli = 0; celli < nCellCells; ++celli)
178  {
179  // Could be done as combination of std::sort, std::unique_copy
180  // except need to block out 'self' and std::copy_if/remove_if
181  // are undefined for overlapping regions
182 
183  const label self = globalAgglom.toGlobal(myProci, celli);
184 
185  nbrCells.clear();
186  nbrCells.insert(self);
187 
188  const label endIndex = offsets[celli+1];
189 
190  for (label i = startIndex; i < endIndex; ++i)
191  {
192  if (nbrCells.insert(m[i]))
193  {
194  m[newIndex] = m[i];
195  ++newIndex;
196  }
197  }
198  startIndex = endIndex;
199  offsets[celli+1] = newIndex;
200  }
201 
202  m.resize(newIndex);
203  }
204 
205  //forAll(cellCells, celli)
206  //{
207  // Pout<< "Original: Coarse cell " << celli << endl;
208  // forAll(mesh.cellCells()[celli], i)
209  // {
210  // Pout<< " nbr:" << mesh.cellCells()[celli][i] << endl;
211  // }
212  // Pout<< "Compacted: Coarse cell " << celli << endl;
213  // const labelUList cCells = cellCells[celli];
214  // forAll(cCells, i)
215  // {
216  // Pout<< " nbr:" << cCells[i] << endl;
217  // }
218  //}
219 }
220 
221 
223 (
224  const polyMesh& mesh,
225  const labelList& agglom,
226  const label nLocalCoarse,
227  const bool parallel,
228  CompactListList<label>& cellCells,
229  CompactListList<scalar>& cellCellWeights
230 )
231 {
232  const labelList& faceOwner = mesh.faceOwner();
233  const labelList& faceNeigh = mesh.faceNeighbour();
235 
236  // FUTURE? treat empty agglomeration like an identity map
237 
238  // Global cell numbers (agglomerated numbering)
239  const label myProci = UPstream::myProcNo(UPstream::worldComm);
240  const globalIndex globalAgglom(nLocalCoarse, UPstream::worldComm, parallel);
241 
242 
243  // The agglomerated owner per boundary faces (global numbering)
244  // from the other side (of coupled patches)
245 
246  labelList globalNeighbour(agglom, pbm.faceOwner());
247  globalAgglom.inplaceToGlobal(myProci, globalNeighbour);
248  syncTools::swapBoundaryFaceList(mesh, globalNeighbour);
249 
250 
251  // Count number of faces (internal + coupled)
252  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
253 
254  // Number of faces per coarse cell
255  labelList nFacesPerCell(nLocalCoarse, Zero);
256 
257  for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
258  {
259  const label own = agglom[faceOwner[facei]];
260  const label nei = agglom[faceNeigh[facei]];
261 
262  ++nFacesPerCell[own];
263  ++nFacesPerCell[nei];
264  }
265 
266  for (const polyPatch& pp : pbm)
267  {
268  if (pp.coupled() && (parallel || !isA<processorPolyPatch>(pp)))
269  {
270  label bFacei = pp.start()-mesh.nInternalFaces();
271 
272  for (const label facei : pp.range())
273  {
274  const label own = agglom[faceOwner[facei]];
275  const label globalNei = globalNeighbour[bFacei];
276 
277  if
278  (
279  !globalAgglom.isLocal(myProci, globalNei)
280  || globalAgglom.toLocal(myProci, globalNei) != own
281  )
282  {
283  ++nFacesPerCell[own];
284  }
285 
286  ++bFacei;
287  }
288  }
289  }
290 
291 
292  // Fill in offset and data
293  // ~~~~~~~~~~~~~~~~~~~~~~~
294 
295  cellCells.resize_nocopy(nFacesPerCell);
296  cellCellWeights.resize_nocopy(nFacesPerCell);
297 
298  nFacesPerCell = 0; // Restart the count
299 
300  labelList& m = cellCells.values();
301  scalarList& w = cellCellWeights.values();
302  const labelList& offsets = cellCells.offsets();
303 
304  // For internal faces is just offsetted owner and neighbour
305  for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
306  {
307  const label own = agglom[faceOwner[facei]];
308  const label nei = agglom[faceNeigh[facei]];
309 
310  const label ownIndex = offsets[own] + nFacesPerCell[own]++;
311  const label neiIndex = offsets[nei] + nFacesPerCell[nei]++;
312 
313  m[ownIndex] = globalAgglom.toGlobal(myProci, nei);
314  m[neiIndex] = globalAgglom.toGlobal(myProci, own);
315 
316  w[ownIndex] = mag(mesh.faceAreas()[facei]);
317  w[neiIndex] = w[ownIndex];
318  }
319 
320  // For boundary faces is offsetted coupled neighbour
321  for (const polyPatch& pp : pbm)
322  {
323  if (pp.coupled() && (parallel || !isA<processorPolyPatch>(pp)))
324  {
325  label bFacei = pp.start()-mesh.nInternalFaces();
326 
327  for (const label facei : pp.range())
328  {
329  const label own = agglom[faceOwner[facei]];
330  const label globalNei = globalNeighbour[bFacei];
331 
332  if
333  (
334  !globalAgglom.isLocal(myProci, globalNei)
335  || globalAgglom.toLocal(myProci, globalNei) != own
336  )
337  {
338  const label ownIndex = offsets[own] + nFacesPerCell[own]++;
339 
340  m[ownIndex] = globalNei;
341  w[ownIndex] = mag(mesh.faceAreas()[facei]);
342  }
343 
344  ++bFacei;
345  }
346  }
347  }
348 
349 
350  // Check for duplicates connections between cells
351  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352  // Done as postprocessing step since we now have cellCells.
353 
354  // NB: Because of agglomeration, self-connections will occur
355  // and must be filtered out.
356 
357  if (!cellCells.empty())
358  {
359  label newIndex = 0;
360  labelHashSet nbrCells;
361 
362  labelList& m = cellCells.values();
363  scalarList& w = cellCellWeights.values();
364  labelList& offsets = cellCells.offsets();
365 
366  label startIndex = offsets[0];
367 
368  const label nCellCells = cellCells.size();
369 
370  for (label celli = 0; celli < nCellCells; ++celli)
371  {
372  const label self = globalAgglom.toGlobal(myProci, celli);
373 
374  nbrCells.clear();
375  nbrCells.insert(self);
376 
377  const label endIndex = offsets[celli+1];
378 
379  for (label i = startIndex; i < endIndex; ++i)
380  {
381  if (nbrCells.insert(m[i]))
382  {
383  m[newIndex] = m[i];
384  w[newIndex] = w[i];
385  ++newIndex;
386  }
387  }
388  startIndex = endIndex;
389  offsets[celli+1] = newIndex;
390  }
391 
392  m.resize(newIndex);
393  w.resize(newIndex);
394 
395  // Weights has identical offsets as cellCells
396  cellCellWeights.offsets() = cellCells.offsets();
397  }
398 }
399 
400 
401 // ************************************************************************* //
label toLocal(const label proci, const label i) const
From global to local on proci.
Definition: globalIndexI.H:377
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
const polyBoundaryMesh & pbm
const labelList & offsets() const noexcept
Return the offset table (= size()+1)
bool empty() const noexcept
True if the number of rows/sublists is zero.
label size() const noexcept
The primary size (the number of rows/sublists)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1122
static void calcCellCells(const polyMesh &mesh, const labelList &agglom, const label nLocalCoarse, const bool parallel, CompactListList< label > &cellCells)
Determine (local or global) cellCells from mesh agglomeration.
bool parallel() const noexcept
Does the mesh contain processor patches? (also valid when not running parallel)
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:409
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:232
void inplaceToGlobal(const label proci, labelUList &labels) const
From local to global index on proci (inplace)
Definition: globalIndexI.H:351
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
dynamicFvMesh & mesh
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
void clear()
Remove all entries from table.
Definition: HashTable.C:725
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1116
label nInternalFaces() const noexcept
Number of internal faces.
bool isLocal(const label proci, const label i) const
Is on processor proci.
Definition: globalIndexI.H:294
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
A packed storage of objects of type <T> using an offset table for access.
label toGlobal(const label proci, const label i) const
From local to global on proci.
Definition: globalIndexI.H:308
const vectorField & faceAreas() const
const List< T > & values() const noexcept
Return the packed values.
void resize_nocopy(const label mRows, const label nVals)
Redimension without preserving existing content.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< label > labelList
A List of labels.
Definition: List.H:62
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:485
const polyMesh & mesh() const noexcept
Return the mesh reference.
const labelList::subList faceOwner() const
Return face owner for the entire boundary.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127