singleCellFvMesh.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-2024 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 "singleCellFvMesh.H"
27 #include "syncTools.H"
29 
30 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
31 
32 void Foam::singleCellFvMesh::agglomerateMesh
33 (
34  const fvMesh& mesh,
35  const labelListList& agglom
36 )
37 {
38  // Conversion is a two step process:
39  // - from original (fine) patch faces to agglomerations (aggloms might not
40  // be in correct patch order)
41  // - from agglomerations to coarse patch faces
42 
43  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
44 
45  // Check agglomeration within patch face range and continuous
46  labelList nAgglom(oldPatches.size(), 0);
47 
48  forAll(oldPatches, patchi)
49  {
50  const polyPatch& pp = oldPatches[patchi];
51  if (pp.size() > 0)
52  {
53  nAgglom[patchi] = max(agglom[patchi])+1;
54 
55  forAll(pp, i)
56  {
57  if (agglom[patchi][i] < 0 || agglom[patchi][i] >= pp.size())
58  {
60  << "agglomeration on patch " << patchi
61  << " is out of range 0.." << pp.size()-1
62  << exit(FatalError);
63  }
64  }
65  }
66  }
67 
68  // Check agglomeration is sync
69  {
70  // Get neighbouring agglomeration
71  labelList nbrAgglom(mesh.nFaces()-mesh.nInternalFaces());
72  forAll(oldPatches, patchi)
73  {
74  const polyPatch& pp = oldPatches[patchi];
75 
76  if (pp.coupled())
77  {
78  label offset = pp.start()-mesh.nInternalFaces();
79  forAll(pp, i)
80  {
81  nbrAgglom[offset+i] = agglom[patchi][i];
82  }
83  }
84  }
86 
87 
88  // Get correspondence between this agglomeration and remote one
89  Map<label> localToNbr(nbrAgglom.size()/10);
90 
91  forAll(oldPatches, patchi)
92  {
93  const polyPatch& pp = oldPatches[patchi];
94 
95  if (pp.coupled())
96  {
97  label offset = pp.start()-mesh.nInternalFaces();
98 
99  forAll(pp, i)
100  {
101  label bFacei = offset+i;
102  label myZone = agglom[patchi][i];
103  label nbrZone = nbrAgglom[bFacei];
104 
105  Map<label>::const_iterator iter = localToNbr.find(myZone);
106 
107  if (iter == localToNbr.end())
108  {
109  // First occurrence of this zone. Store correspondence
110  // to remote zone number.
111  localToNbr.insert(myZone, nbrZone);
112  }
113  else
114  {
115  // Check that zone numbers are still the same.
116  if (iter() != nbrZone)
117  {
119  << "agglomeration is not synchronised across"
120  << " coupled patch " << pp.name()
121  << endl
122  << "Local agglomeration " << myZone
123  << ". Remote agglomeration " << nbrZone
124  << exit(FatalError);
125  }
126  }
127  }
128  }
129  }
130  }
131 
132 
133  label coarseI = 0;
134  forAll(nAgglom, patchi)
135  {
136  coarseI += nAgglom[patchi];
137  }
138  // New faces
139  faceList patchFaces(coarseI);
140  // New patch start and size
141  labelList patchStarts(oldPatches.size());
142  labelList patchSizes(oldPatches.size());
143 
144  // From new patch face back to agglomeration
145  patchFaceMap_.setSize(oldPatches.size());
146 
147  // From fine face to coarse face (or -1)
148  reverseFaceMap_.setSize(mesh.nFaces());
149  reverseFaceMap_.labelList::operator=(-1);
150 
151  // Face counter
152  coarseI = 0;
153 
154 
155  forAll(oldPatches, patchi)
156  {
157  patchStarts[patchi] = coarseI;
158 
159  const polyPatch& pp = oldPatches[patchi];
160 
161  if (pp.size() > 0)
162  {
163  patchFaceMap_[patchi].setSize(nAgglom[patchi]);
164 
165  // Patchfaces per agglomeration
166  labelListList agglomToPatch
167  (
168  invertOneToMany(nAgglom[patchi], agglom[patchi])
169  );
170 
171  // From agglomeration to compact patch face
172  labelList agglomToFace(nAgglom[patchi], -1);
173 
174  forAll(pp, i)
175  {
176  label myAgglom = agglom[patchi][i];
177 
178  if (agglomToFace[myAgglom] == -1)
179  {
180  // Agglomeration not yet done. We now have:
181  // - coarseI : current coarse mesh face
182  // - patchStarts[patchi] : coarse mesh patch start
183  // - myAgglom : agglomeration
184  // - agglomToPatch[myAgglom] : fine mesh faces for zone
185  label coarsePatchFacei = coarseI - patchStarts[patchi];
186  patchFaceMap_[patchi][coarsePatchFacei] = myAgglom;
187  agglomToFace[myAgglom] = coarsePatchFacei;
188 
189  const labelList& fineFaces = agglomToPatch[myAgglom];
190 
191  // Create overall map from fine mesh faces to coarseI.
192  forAll(fineFaces, fineI)
193  {
194  reverseFaceMap_[pp.start()+fineFaces[fineI]] = coarseI;
195  }
196 
197  // Construct single face
199  (
200  UIndirectList<face>(pp, fineFaces),
201  pp.points()
202  );
203 
204  if (upp.edgeLoops().size() != 1)
205  {
207  << "agglomeration does not create a"
208  << " single, non-manifold"
209  << " face for agglomeration " << myAgglom
210  << " on patch " << patchi
211  << exit(FatalError);
212  }
213 
214  patchFaces[coarseI++] = face
215  (
216  renumber
217  (
218  upp.meshPoints(),
219  upp.edgeLoops()[0]
220  )
221  );
222  }
223  }
224  }
225 
226  patchSizes[patchi] = coarseI-patchStarts[patchi];
227  }
228 
229  // Pout<< "patchStarts:" << patchStarts << endl;
230  // Pout<< "patchSizes:" << patchSizes << endl;
231 
232  // Compact numbering for points
233  reversePointMap_.setSize(mesh.nPoints());
234  reversePointMap_.labelList::operator=(-1);
235  label newI = 0;
236 
237  forAll(patchFaces, coarseI)
238  {
239  face& f = patchFaces[coarseI];
240 
241  forAll(f, fp)
242  {
243  if (reversePointMap_[f[fp]] == -1)
244  {
245  reversePointMap_[f[fp]] = newI++;
246  }
247 
248  f[fp] = reversePointMap_[f[fp]];
249  }
250  }
251 
252  pointMap_ = invert(newI, reversePointMap_);
253 
254  // Subset used points
255  pointField boundaryPoints(mesh.points(), pointMap_);
256 
257  // Add patches (on still zero sized mesh)
258  List<polyPatch*> newPatches(oldPatches.size());
259  forAll(oldPatches, patchi)
260  {
261  newPatches[patchi] = oldPatches[patchi].clone
262  (
263  boundaryMesh(),
264  patchi,
265  0,
266  0
267  ).ptr();
268  }
269  addFvPatches(newPatches);
270 
271  // Owner, neighbour is trivial
272  labelList owner(patchFaces.size(), 0);
273  labelList neighbour(0);
274 
275 
276  // actually change the mesh
278  (
279  std::move(boundaryPoints),
280  std::move(patchFaces),
281  std::move(owner),
282  std::move(neighbour),
283  patchSizes,
284  patchStarts,
285  true // syncPar
286  );
287 
288 
289  // Adapt the zones
290  cellZones().clear();
292  {
293  forAll(mesh.cellZones(), zoneI)
294  {
295  const cellZone& oldCz = mesh.cellZones()[zoneI];
296 
297  DynamicList<label> newAddressing;
298 
299  cellZones().set
300  (
301  zoneI,
302  oldCz.clone
303  (
304  newAddressing,
305  cellZones()
306  )
307  );
308  }
309  }
310 
311  faceZones().clear();
313  {
314  forAll(mesh.faceZones(), zoneI)
315  {
316  const faceZone& oldFz = mesh.faceZones()[zoneI];
317 
318  DynamicList<label> newAddressing(oldFz.size());
319  DynamicList<bool> newFlipMap(oldFz.size());
320 
321  forAll(oldFz, i)
322  {
323  label newFacei = reverseFaceMap_[oldFz[i]];
324 
325  if (newFacei != -1)
326  {
327  newAddressing.append(newFacei);
328  newFlipMap.append(oldFz.flipMap()[i]);
329  }
330  }
331 
332  faceZones().set
333  (
334  zoneI,
335  oldFz.clone
336  (
337  newAddressing,
338  newFlipMap,
339  faceZones()
340  )
341  );
342  }
343  }
344 
345 
346  pointZones().clear();
348  {
349  forAll(mesh.pointZones(), zoneI)
350  {
351  const pointZone& oldPz = mesh.pointZones()[zoneI];
352 
353  DynamicList<label> newAddressing(oldPz.size());
354 
355  forAll(oldPz, i)
356  {
357  label newPointi = reversePointMap_[oldPz[i]];
358  if (newPointi != -1)
359  {
360  newAddressing.append(newPointi);
361  }
362  }
363 
364  pointZones().set
365  (
366  zoneI,
367  oldPz.clone
368  (
369  newAddressing,
370  pointZones()
371  )
372  );
373  }
374  }
375 }
376 
377 
378 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
379 
381 (
382  const IOobject& io,
383  const fvMesh& mesh
384 )
385 :
386  fvMesh
387  (
388  io,
389  pointField(), // points
390  faceList(), // faces
391  labelList(), // allOwner
392  labelList(), // allNeighbour
393  false // syncPar
394  ),
395  patchFaceAgglomeration_
396  (
397  IOobject
398  (
399  "patchFaceAgglomeration",
400  io.instance(),
401  fvMesh::meshSubDir,
402  *this,
403  io.readOpt(),
404  io.writeOpt()
405  ),
406  label(0)
407  ),
408  patchFaceMap_
409  (
410  IOobject
411  (
412  "patchFaceMap",
413  io.instance(),
414  fvMesh::meshSubDir,
415  *this,
416  io.readOpt(),
417  io.writeOpt()
418  ),
419  mesh.boundaryMesh().size()
420  ),
421  reverseFaceMap_
422  (
423  IOobject
424  (
425  "reverseFaceMap",
426  io.instance(),
427  fvMesh::meshSubDir,
428  *this,
429  io.readOpt(),
430  io.writeOpt()
431  ),
432  mesh.nFaces()
433  ),
434  pointMap_
435  (
436  IOobject
437  (
438  "pointMap",
439  io.instance(),
440  fvMesh::meshSubDir,
441  *this,
442  io.readOpt(),
443  io.writeOpt()
444  ),
445  mesh.nPoints()
446  ),
447  reversePointMap_
448  (
449  IOobject
450  (
451  "reversePointMap",
452  io.instance(),
453  fvMesh::meshSubDir,
454  *this,
455  io.readOpt(),
456  io.writeOpt()
457  ),
458  mesh.nPoints()
459  )
460 {
461  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
462 
463  labelListList agglom(oldPatches.size());
464 
465  forAll(oldPatches, patchi)
466  {
467  agglom[patchi] = identityMap(oldPatches[patchi].size());
468  }
469 
470  agglomerateMesh(mesh, agglom);
471 }
472 
473 
475 (
476  const IOobject& io,
477  const fvMesh& mesh,
478  const labelListList& patchFaceAgglomeration
479 )
480 :
481  fvMesh
482  (
483  io,
484  pointField(), // points
485  faceList(), // faces
486  labelList(), // allOwner
487  labelList(), // allNeighbour
488  false // syncPar
489  ),
490  patchFaceAgglomeration_
491  (
492  IOobject
493  (
494  "patchFaceAgglomeration",
495  io.instance(),
496  fvMesh::meshSubDir,
497  *this,
498  io.readOpt(),
499  io.writeOpt()
500  ),
501  patchFaceAgglomeration
502  ),
503  patchFaceMap_
504  (
505  IOobject
506  (
507  "patchFaceMap",
508  io.instance(),
509  fvMesh::meshSubDir,
510  *this,
511  io.readOpt(),
512  io.writeOpt()
513  ),
514  mesh.boundaryMesh().size()
515  ),
516  reverseFaceMap_
517  (
518  IOobject
519  (
520  "reverseFaceMap",
521  io.instance(),
522  fvMesh::meshSubDir,
523  *this,
524  io.readOpt(),
525  io.writeOpt()
526  ),
527  mesh.nFaces()
528  ),
529  pointMap_
530  (
531  IOobject
532  (
533  "pointMap",
534  io.instance(),
535  fvMesh::meshSubDir,
536  *this,
537  io.readOpt(),
538  io.writeOpt()
539  ),
540  mesh.nPoints()
541  ),
542  reversePointMap_
543  (
544  IOobject
545  (
546  "reversePointMap",
547  io.instance(),
548  fvMesh::meshSubDir,
549  *this,
550  io.readOpt(),
551  io.writeOpt()
552  ),
553  mesh.nPoints()
554  )
555 {
556  agglomerateMesh(mesh, patchFaceAgglomeration);
557 }
558 
559 
561 :
562  fvMesh(io),
563  patchFaceAgglomeration_
564  (
565  IOobject
566  (
567  "patchFaceAgglomeration",
568  io.instance(),
569  fvMesh::meshSubDir,
570  *this,
571  io.readOpt(),
572  io.writeOpt()
573  )
574  ),
575  patchFaceMap_
576  (
577  IOobject
578  (
579  "patchFaceMap",
580  io.instance(),
581  fvMesh::meshSubDir,
582  *this,
583  io.readOpt(),
584  io.writeOpt()
585  )
586  ),
587  reverseFaceMap_
588  (
589  IOobject
590  (
591  "reverseFaceMap",
592  io.instance(),
593  fvMesh::meshSubDir,
594  *this,
595  io.readOpt(),
596  io.writeOpt()
597  )
598  ),
599  pointMap_
600  (
601  IOobject
602  (
603  "pointMap",
604  io.instance(),
605  fvMesh::meshSubDir,
606  *this,
607  io.readOpt(),
608  io.writeOpt()
609  )
610  ),
611  reversePointMap_
612  (
613  IOobject
614  (
615  "reversePointMap",
616  io.instance(),
617  fvMesh::meshSubDir,
618  *this,
619  io.readOpt(),
620  io.writeOpt()
621  )
622  )
623 {}
624 
625 
626 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
627 
628 
629 
630 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
friend class const_iterator
Declare friendship with the const_iterator.
Definition: HashTable.H:197
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
autoPtr< T > set(const label, const word &key, T *)
Set element to pointer provided and return old element.
void setSize(const label)
Reset size of PtrList. If extending the PtrList, new entries are.
Definition: PtrList.C:131
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
void clear()
Clear the zones.
Definition: ZoneList.C:236
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:99
const labelUList & owner() const
Internal face owner.
Definition: fvMesh.H:469
void addFvPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:680
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:475
const polyMesh & mesh() const
Return reference to polyMesh.
Definition: fvMesh.H:441
Foam::polyBoundaryMesh.
const pointZoneList & pointZones() const
Return point zones.
Definition: polyMesh.H:440
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:452
void resetPrimitives(pointField &&points, faceList &&faces, labelList &&owner, labelList &&neighbour, const labelList &patchSizes, const labelList &patchStarts, const bool validBoundary=true)
Reset mesh primitive data. Assumes all patch info correct.
Definition: polyMesh.C:703
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:446
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:404
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1313
label nPoints() const
label nInternalFaces() const
label nFaces() const
singleCellFvMesh(const IOobject &io, const fvMesh &)
Construct from fvMesh and no agglomeration.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
label nPoints
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
labelListList invertOneToMany(const label len, const labelUList &)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:67
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
Foam::uindirectPrimitivePatch.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
void offset(label &lst, const label o)
List< face > faceList
Definition: faceListFwd.H:41
label newPointi
Definition: readKivaGrid.H:495
labelList f(nPoints)