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-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 "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  DynamicList<label> newAddressing(oldFz.size());
318 
319  if (oldFz.oriented())
320  {
321  DynamicList<bool> newFlipMap(oldFz.size());
322 
323  forAll(oldFz, i)
324  {
325  label newFacei = reverseFaceMap_[oldFz[i]];
326 
327  if (newFacei != -1)
328  {
329  newAddressing.append(newFacei);
330  newFlipMap.append(oldFz.flipMap()[i]);
331  }
332  }
333 
334  faceZones().set
335  (
336  zoneI,
337  oldFz.clone
338  (
339  newAddressing,
340  newFlipMap,
341  faceZones()
342  )
343  );
344  }
345  else
346  {
347  forAll(oldFz, i)
348  {
349  label newFacei = reverseFaceMap_[oldFz[i]];
350 
351  if (newFacei != -1)
352  {
353  newAddressing.append(newFacei);
354  }
355  }
356 
357  faceZones().set
358  (
359  zoneI,
360  oldFz.clone
361  (
362  newAddressing,
363  faceZones()
364  )
365  );
366  }
367  }
368  }
369 
370 
371  pointZones().clear();
373  {
374  forAll(mesh.pointZones(), zoneI)
375  {
376  const pointZone& oldPz = mesh.pointZones()[zoneI];
377 
378  DynamicList<label> newAddressing(oldPz.size());
379 
380  forAll(oldPz, i)
381  {
382  label newPointi = reversePointMap_[oldPz[i]];
383  if (newPointi != -1)
384  {
385  newAddressing.append(newPointi);
386  }
387  }
388 
389  pointZones().set
390  (
391  zoneI,
392  oldPz.clone
393  (
394  newAddressing,
395  pointZones()
396  )
397  );
398  }
399  }
400 }
401 
402 
403 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
404 
406 (
407  const IOobject& io,
408  const fvMesh& mesh
409 )
410 :
411  fvMesh
412  (
413  io,
414  pointField(), // points
415  faceList(), // faces
416  labelList(), // allOwner
417  labelList(), // allNeighbour
418  false // syncPar
419  ),
420  patchFaceAgglomeration_
421  (
422  IOobject
423  (
424  "patchFaceAgglomeration",
425  io.instance(),
426  fvMesh::meshSubDir,
427  *this,
428  io.readOpt(),
429  io.writeOpt()
430  ),
431  label(0)
432  ),
433  patchFaceMap_
434  (
435  IOobject
436  (
437  "patchFaceMap",
438  io.instance(),
439  fvMesh::meshSubDir,
440  *this,
441  io.readOpt(),
442  io.writeOpt()
443  ),
444  mesh.boundaryMesh().size()
445  ),
446  reverseFaceMap_
447  (
448  IOobject
449  (
450  "reverseFaceMap",
451  io.instance(),
452  fvMesh::meshSubDir,
453  *this,
454  io.readOpt(),
455  io.writeOpt()
456  ),
457  mesh.nFaces()
458  ),
459  pointMap_
460  (
461  IOobject
462  (
463  "pointMap",
464  io.instance(),
465  fvMesh::meshSubDir,
466  *this,
467  io.readOpt(),
468  io.writeOpt()
469  ),
470  mesh.nPoints()
471  ),
472  reversePointMap_
473  (
474  IOobject
475  (
476  "reversePointMap",
477  io.instance(),
478  fvMesh::meshSubDir,
479  *this,
480  io.readOpt(),
481  io.writeOpt()
482  ),
483  mesh.nPoints()
484  )
485 {
486  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
487 
488  labelListList agglom(oldPatches.size());
489 
490  forAll(oldPatches, patchi)
491  {
492  agglom[patchi] = identityMap(oldPatches[patchi].size());
493  }
494 
495  agglomerateMesh(mesh, agglom);
496 }
497 
498 
500 (
501  const IOobject& io,
502  const fvMesh& mesh,
503  const labelListList& patchFaceAgglomeration
504 )
505 :
506  fvMesh
507  (
508  io,
509  pointField(), // points
510  faceList(), // faces
511  labelList(), // allOwner
512  labelList(), // allNeighbour
513  false // syncPar
514  ),
515  patchFaceAgglomeration_
516  (
517  IOobject
518  (
519  "patchFaceAgglomeration",
520  io.instance(),
521  fvMesh::meshSubDir,
522  *this,
523  io.readOpt(),
524  io.writeOpt()
525  ),
526  patchFaceAgglomeration
527  ),
528  patchFaceMap_
529  (
530  IOobject
531  (
532  "patchFaceMap",
533  io.instance(),
534  fvMesh::meshSubDir,
535  *this,
536  io.readOpt(),
537  io.writeOpt()
538  ),
539  mesh.boundaryMesh().size()
540  ),
541  reverseFaceMap_
542  (
543  IOobject
544  (
545  "reverseFaceMap",
546  io.instance(),
547  fvMesh::meshSubDir,
548  *this,
549  io.readOpt(),
550  io.writeOpt()
551  ),
552  mesh.nFaces()
553  ),
554  pointMap_
555  (
556  IOobject
557  (
558  "pointMap",
559  io.instance(),
560  fvMesh::meshSubDir,
561  *this,
562  io.readOpt(),
563  io.writeOpt()
564  ),
565  mesh.nPoints()
566  ),
567  reversePointMap_
568  (
569  IOobject
570  (
571  "reversePointMap",
572  io.instance(),
573  fvMesh::meshSubDir,
574  *this,
575  io.readOpt(),
576  io.writeOpt()
577  ),
578  mesh.nPoints()
579  )
580 {
581  agglomerateMesh(mesh, patchFaceAgglomeration);
582 }
583 
584 
586 :
587  fvMesh(io),
588  patchFaceAgglomeration_
589  (
590  IOobject
591  (
592  "patchFaceAgglomeration",
593  io.instance(),
594  fvMesh::meshSubDir,
595  *this,
596  io.readOpt(),
597  io.writeOpt()
598  )
599  ),
600  patchFaceMap_
601  (
602  IOobject
603  (
604  "patchFaceMap",
605  io.instance(),
606  fvMesh::meshSubDir,
607  *this,
608  io.readOpt(),
609  io.writeOpt()
610  )
611  ),
612  reverseFaceMap_
613  (
614  IOobject
615  (
616  "reverseFaceMap",
617  io.instance(),
618  fvMesh::meshSubDir,
619  *this,
620  io.readOpt(),
621  io.writeOpt()
622  )
623  ),
624  pointMap_
625  (
626  IOobject
627  (
628  "pointMap",
629  io.instance(),
630  fvMesh::meshSubDir,
631  *this,
632  io.readOpt(),
633  io.writeOpt()
634  )
635  ),
636  reversePointMap_
637  (
638  IOobject
639  (
640  "reversePointMap",
641  io.instance(),
642  fvMesh::meshSubDir,
643  *this,
644  io.readOpt(),
645  io.writeOpt()
646  )
647  )
648 {}
649 
650 
651 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
652 
653 
654 
655 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
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:282
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:96
const labelUList & owner() const
Internal face owner.
Definition: fvMesh.H:471
void addFvPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:785
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:477
const polyMesh & mesh() const
Return reference to polyMesh.
Definition: fvMesh.H:443
Foam::polyBoundaryMesh.
const pointZoneList & pointZones() const
Return point zones.
Definition: polyMesh.H:437
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:449
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:716
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:443
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:401
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1331
label nInternalFaces() const
label nPoints() 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
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#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:258
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)