singleCellFvMesh.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) 2019-2022 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 "singleCellFvMesh.H"
30 #include "syncTools.H"
31 #include "indirectPrimitivePatch.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 void Foam::singleCellFvMesh::agglomerateMesh
36 (
37  const fvMesh& mesh,
38  const labelListList& agglom
39 )
40 {
41  // Conversion is a two step process:
42  // - from original (fine) patch faces to agglomerations (aggloms might not
43  // be in correct patch order)
44  // - from agglomerations to coarse patch faces
45 
46  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
47 
48  // Check agglomeration within patch face range and continuous
49  labelList nAgglom(oldPatches.size(), Zero);
50 
51  forAll(oldPatches, patchi)
52  {
53  const polyPatch& pp = oldPatches[patchi];
54  if (pp.size() > 0)
55  {
56  if (agglom[patchi].size() != pp.size())
57  {
59  << "agglomeration on patch " << patchi
60  << " (size " << pp.size()
61  << ") is of size " << agglom[patchi].size()
62  << exit(FatalError);
63  }
64 
65  nAgglom[patchi] = max(agglom[patchi])+1;
66 
67  forAll(pp, i)
68  {
69  if (agglom[patchi][i] < 0 || agglom[patchi][i] >= pp.size())
70  {
72  << "agglomeration on patch " << patchi
73  << " is out of range 0.." << pp.size()-1
74  << exit(FatalError);
75  }
76  }
77  }
78  }
79 
80  // Check agglomeration is sync
81  {
82  // Get neighbouring agglomeration
83  labelList nbrAgglom(mesh.nBoundaryFaces());
84  forAll(oldPatches, patchi)
85  {
86  const polyPatch& pp = oldPatches[patchi];
87 
88  if (pp.coupled())
89  {
90  label offset = pp.start()-mesh.nInternalFaces();
91  forAll(pp, i)
92  {
93  nbrAgglom[offset+i] = agglom[patchi][i];
94  }
95  }
96  }
98 
99 
100  // Get correspondence between this agglomeration and remote one
101  Map<label> localToNbr(nbrAgglom.size()/10);
102 
103  forAll(oldPatches, patchi)
104  {
105  const polyPatch& pp = oldPatches[patchi];
106 
107  if (pp.coupled())
108  {
109  label offset = pp.start()-mesh.nInternalFaces();
110 
111  forAll(pp, i)
112  {
113  label bFacei = offset+i;
114  label myZone = agglom[patchi][i];
115  label nbrZone = nbrAgglom[bFacei];
116 
117  const auto iter = localToNbr.cfind(myZone);
118 
119  if (iter.good())
120  {
121  // Check that zone numbers are still the same.
122  if (iter.val() != nbrZone)
123  {
125  << "agglomeration is not synchronised across"
126  << " coupled patch " << pp.name()
127  << endl
128  << "Local agglomeration " << myZone
129  << ". Remote agglomeration " << nbrZone
130  << exit(FatalError);
131  }
132  }
133  else
134  {
135  // First occurrence of this zone. Store correspondence
136  // to remote zone number.
137  localToNbr.insert(myZone, nbrZone);
138  }
139  }
140  }
141  }
142  }
143 
144 
145  label coarseI = 0;
146  forAll(nAgglom, patchi)
147  {
148  coarseI += nAgglom[patchi];
149  }
150  // New faces
151  faceList patchFaces(coarseI);
152  // New patch start and size
153  labelList patchStarts(oldPatches.size());
154  labelList patchSizes(oldPatches.size());
155 
156  // From new patch face back to agglomeration
157  patchFaceMap_.setSize(oldPatches.size());
158 
159  // From fine face to coarse face (or -1)
160  reverseFaceMap_.setSize(mesh.nFaces());
161  reverseFaceMap_.labelList::operator=(-1);
162 
163  // Face counter
164  coarseI = 0;
165 
166 
167  forAll(oldPatches, patchi)
168  {
169  patchStarts[patchi] = coarseI;
170 
171  const polyPatch& pp = oldPatches[patchi];
172 
173  if (pp.size() > 0)
174  {
175  patchFaceMap_[patchi].setSize(nAgglom[patchi]);
176 
177  // Patchfaces per agglomeration
178  labelListList agglomToPatch
179  (
180  invertOneToMany(nAgglom[patchi], agglom[patchi])
181  );
182 
183  // From agglomeration to compact patch face
184  labelList agglomToFace(nAgglom[patchi], -1);
185 
186  forAll(pp, i)
187  {
188  label myAgglom = agglom[patchi][i];
189 
190  if (agglomToFace[myAgglom] == -1)
191  {
192  // Agglomeration not yet done. We now have:
193  // - coarseI : current coarse mesh face
194  // - patchStarts[patchi] : coarse mesh patch start
195  // - myAgglom : agglomeration
196  // - agglomToPatch[myAgglom] : fine mesh faces for zone
197  label coarsePatchFacei = coarseI - patchStarts[patchi];
198  patchFaceMap_[patchi][coarsePatchFacei] = myAgglom;
199  agglomToFace[myAgglom] = coarsePatchFacei;
200 
201  const labelList& fineFaces = agglomToPatch[myAgglom];
202 
203  // Create overall map from fine mesh faces to coarseI.
204  forAll(fineFaces, fineI)
205  {
206  reverseFaceMap_[pp.start()+fineFaces[fineI]] = coarseI;
207  }
208 
209  // Construct single face
211  (
212  UIndirectList<face>(pp, fineFaces),
213  pp.points()
214  );
215 
216  if (upp.edgeLoops().size() != 1)
217  {
219  << "agglomeration does not create a"
220  << " single, non-manifold"
221  << " face for agglomeration " << myAgglom
222  << " on patch " << patchi
223  << exit(FatalError);
224  }
225 
226  patchFaces[coarseI++] = face
227  (
228  renumber
229  (
230  upp.meshPoints(),
231  upp.edgeLoops()[0]
232  )
233  );
234  }
235  }
236  }
237 
238  patchSizes[patchi] = coarseI-patchStarts[patchi];
239  }
240 
241  //patchFaces.setSize(coarseI);
242  //Pout<< "patchStarts:" << patchStarts << endl;
243  //Pout<< "patchSizes:" << patchSizes << endl;
244 
245  // Compact numbering for points
246  reversePointMap_.setSize(mesh.nPoints());
247  reversePointMap_.labelList::operator=(-1);
248  label newI = 0;
249 
250  forAll(patchFaces, coarseI)
251  {
252  face& f = patchFaces[coarseI];
253 
254  forAll(f, fp)
255  {
256  if (reversePointMap_[f[fp]] == -1)
257  {
258  reversePointMap_[f[fp]] = newI++;
259  }
260 
261  f[fp] = reversePointMap_[f[fp]];
262  }
263  }
264 
265  pointMap_ = invert(newI, reversePointMap_);
266 
267  // Subset used points
268  pointField boundaryPoints(mesh.points(), pointMap_);
269 
270  // Add patches (on still zero sized mesh)
271  polyPatchList newPatches(oldPatches.size());
272  forAll(oldPatches, patchi)
273  {
274  newPatches.set
275  (
276  patchi,
277  oldPatches[patchi].clone
278  (
279  boundaryMesh(),
280  patchi,
281  0,
282  0
283  )
284  );
285  }
286  addFvPatches(newPatches);
287 
288  const label nFace = patchFaces.size();
289 
290  // Actually change the mesh. // Owner, neighbour is trivial
292  (
293  autoPtr<pointField>::New(std::move(boundaryPoints)),
294  autoPtr<faceList>::New(std::move(patchFaces)),
295  autoPtr<labelList>::New(nFace, Zero), // owner
296  autoPtr<labelList>::New(), // neighbour
297  patchSizes,
298  patchStarts,
299  true // syncPar
300  );
301 
302  // Adapt the zones
303  cellZones().clear();
304  cellZones().setSize(mesh.cellZones().size());
305  {
306  forAll(mesh.cellZones(), zoneI)
307  {
308  const cellZone& oldFz = mesh.cellZones()[zoneI];
309 
310  DynamicList<label> newAddressing;
311 
312  //Note: uncomment if you think it makes sense. Note that value
313  // of cell0 is the average.
315  //if (oldFz.localID(0) != -1)
316  //{
317  // newAddressing.append(0);
318  //}
319 
320  cellZones().set
321  (
322  zoneI,
323  oldFz.clone
324  (
325  newAddressing,
326  zoneI,
327  cellZones()
328  )
329  );
330  }
331  }
332 
333  faceZones().clear();
334  faceZones().setSize(mesh.faceZones().size());
335  {
336  forAll(mesh.faceZones(), zoneI)
337  {
338  const faceZone& oldFz = mesh.faceZones()[zoneI];
339 
340  DynamicList<label> newAddressing(oldFz.size());
341  DynamicList<bool> newFlipMap(oldFz.size());
342 
343  forAll(oldFz, i)
344  {
345  label newFacei = reverseFaceMap_[oldFz[i]];
346 
347  if (newFacei != -1)
348  {
349  newAddressing.append(newFacei);
350  newFlipMap.append(oldFz.flipMap()[i]);
351  }
352  }
353 
354  faceZones().set
355  (
356  zoneI,
357  oldFz.clone
358  (
359  newAddressing,
360  newFlipMap,
361  zoneI,
362  faceZones()
363  )
364  );
365  }
366  }
367 
368 
369  pointZones().clear();
370  pointZones().setSize(mesh.pointZones().size());
371  {
372  forAll(mesh.pointZones(), zoneI)
373  {
374  const pointZone& oldFz = mesh.pointZones()[zoneI];
375 
376  DynamicList<label> newAddressing(oldFz.size());
377 
378  forAll(oldFz, i)
379  {
380  label newPointi = reversePointMap_[oldFz[i]];
381  if (newPointi != -1)
382  {
383  newAddressing.append(newPointi);
384  }
385  }
386 
387  pointZones().set
388  (
389  zoneI,
390  oldFz.clone
391  (
392  pointZones(),
393  zoneI,
394  newAddressing
395  )
396  );
397  }
398  }
399 
400  // Make sure we don't start dumping mesh every timestep (since
401  // resetPrimitives sets AUTO_WRITE)
403 }
404 
405 
406 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
407 
408 Foam::singleCellFvMesh::singleCellFvMesh
409 (
410  const IOobject& io,
411  const fvMesh& mesh,
412  const bool doInit
413 )
414 :
415  fvMesh(io, Zero, false),
416  patchFaceAgglomeration_
417  (
418  IOobject
419  (
420  "patchFaceAgglomeration",
421  io.instance(),
422  fvMesh::meshSubDir,
423  *this,
424  io.readOpt(),
425  io.writeOpt()
426  ),
427  0
428  ),
429  patchFaceMap_
430  (
431  IOobject
432  (
433  "patchFaceMap",
434  io.instance(),
435  fvMesh::meshSubDir,
436  *this,
437  io.readOpt(),
438  io.writeOpt()
439  ),
440  mesh.boundaryMesh().size()
441  ),
442  reverseFaceMap_
443  (
444  IOobject
445  (
446  "reverseFaceMap",
447  io.instance(),
448  fvMesh::meshSubDir,
449  *this,
450  io.readOpt(),
451  io.writeOpt()
452  ),
453  mesh.nFaces()
454  ),
455  pointMap_
456  (
457  IOobject
458  (
459  "pointMap",
460  io.instance(),
461  fvMesh::meshSubDir,
462  *this,
463  io.readOpt(),
464  io.writeOpt()
465  ),
466  mesh.nPoints()
467  ),
468  reversePointMap_
469  (
470  IOobject
471  (
472  "reversePointMap",
473  io.instance(),
474  fvMesh::meshSubDir,
475  *this,
476  io.readOpt(),
477  io.writeOpt()
478  ),
479  mesh.nPoints()
480  )
481 {
482  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
483 
484  labelListList agglom(oldPatches.size());
485 
486  forAll(oldPatches, patchi)
487  {
488  agglom[patchi] = identity(oldPatches[patchi].size());
489  }
490 
491  agglomerateMesh(mesh, agglom);
492 
493  // initialise all (lower levels and current)
494  if (doInit)
495  {
496  fvMesh::init(true); // initialise fvMesh and underlying levels
497  }
498 }
499 
500 
501 Foam::singleCellFvMesh::singleCellFvMesh
502 (
503  const IOobject& io,
504  const fvMesh& mesh,
505  const labelListList& patchFaceAgglomeration,
506  const bool doInit
507 )
508 :
509  fvMesh(io, Zero, false),
510  patchFaceAgglomeration_
511  (
512  IOobject
513  (
514  "patchFaceAgglomeration",
515  io.instance(),
516  fvMesh::meshSubDir,
517  *this,
518  io.readOpt(),
519  io.writeOpt()
520  ),
521  patchFaceAgglomeration
522  ),
523  patchFaceMap_
524  (
525  IOobject
526  (
527  "patchFaceMap",
528  io.instance(),
529  fvMesh::meshSubDir,
530  *this,
531  io.readOpt(),
532  io.writeOpt()
533  ),
534  mesh.boundaryMesh().size()
535  ),
536  reverseFaceMap_
537  (
538  IOobject
539  (
540  "reverseFaceMap",
541  io.instance(),
542  fvMesh::meshSubDir,
543  *this,
544  io.readOpt(),
545  io.writeOpt()
546  ),
547  mesh.nFaces()
548  ),
549  pointMap_
550  (
551  IOobject
552  (
553  "pointMap",
554  io.instance(),
555  fvMesh::meshSubDir,
556  *this,
557  io.readOpt(),
558  io.writeOpt()
559  ),
560  mesh.nPoints()
561  ),
562  reversePointMap_
563  (
564  IOobject
565  (
566  "reversePointMap",
567  io.instance(),
568  fvMesh::meshSubDir,
569  *this,
570  io.readOpt(),
571  io.writeOpt()
572  ),
573  mesh.nPoints()
574  )
575 {
576  agglomerateMesh(mesh, patchFaceAgglomeration);
577  // initialise all (lower levels and current)
578  if (doInit)
579  {
580  fvMesh::init(true); // initialise fvMesh and underlying levels
581  }
582 }
583 
584 
585 Foam::singleCellFvMesh::singleCellFvMesh(const IOobject& io, const bool doInit)
586 :
587  fvMesh(io, doInit),
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 // ************************************************************************* //
autoPtr< IOobject > clone() const
Clone.
Definition: IOobject.H:621
void clear()
Clear the zones.
Definition: ZoneMesh.C:841
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:517
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values (not the indices) of a list.
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void resetPrimitives(autoPtr< pointField > &&points, autoPtr< faceList > &&faces, autoPtr< labelList > &&owner, autoPtr< labelList > &&neighbour, const labelUList &patchSizes, const labelUList &patchStarts, const bool validBoundary=true)
Reset mesh primitive data. Assumes all patch info correct.
Definition: polyMesh.C:704
Ignore writing from objectRegistry::writeObject()
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
PtrList< polyPatch > polyPatchList
Store lists of polyPatch as a PtrList.
Definition: polyPatch.H:56
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:342
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
labelListList invertOneToMany(const label len, const labelUList &map)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:107
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
label nPoints
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:159
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:670
void addFvPatches(polyPatchList &plist, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:662
labelList f(nPoints)
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:337
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition: ListOps.C:29
const pointZoneMesh & pointZones() const noexcept
Return point zone mesh.
Definition: polyMesh.H:662
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
void setInstance(const fileName &instance, const IOobjectOption::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition: polyMeshIO.C:29
label newPointi
Definition: readKivaGrid.H:496
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
Definition: fvMesh.C:263
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition: polyMesh.H:678
List< label > labelList
A List of labels.
Definition: List.H:62
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
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
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127