hexRef8.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-2017 OpenFOAM Foundation
9  Copyright (C) 2016-2021 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 "hexRef8.H"
30 
31 #include "polyMesh.H"
32 #include "polyTopoChange.H"
33 #include "meshTools.H"
34 #include "polyAddFace.H"
35 #include "polyAddPoint.H"
36 #include "polyAddCell.H"
37 #include "polyModifyFace.H"
38 #include "syncTools.H"
39 #include "faceSet.H"
40 #include "cellSet.H"
41 #include "pointSet.H"
42 #include "labelPairHashes.H"
43 #include "OFstream.H"
44 #include "Time.H"
45 #include "FaceCellWave.H"
46 #include "mapDistributePolyMesh.H"
47 #include "refinementData.H"
48 #include "refinementDistanceData.H"
49 #include "degenerateMatcher.H"
50 
51 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
52 
53 namespace Foam
54 {
55  defineTypeNameAndDebug(hexRef8, 0);
56 
57  //- Reduction class. If x and y are not equal assign value.
58  template<label value>
59  struct ifEqEqOp
60  {
61  void operator()(label& x, const label y) const
62  {
63  x = (x == y) ? x : value;
64  }
65  };
66 }
67 
68 
69 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
70 
71 void Foam::hexRef8::reorder
72 (
73  const labelList& map,
74  const label len,
75  const label null,
76  labelList& elems
77 )
78 {
79  labelList newElems(len, null);
80 
81  forAll(elems, i)
82  {
83  label newI = map[i];
84 
85  if (newI >= len)
86  {
88  }
89 
90  if (newI >= 0)
91  {
92  newElems[newI] = elems[i];
93  }
94  }
95 
96  elems.transfer(newElems);
97 }
98 
99 
100 void Foam::hexRef8::getFaceInfo
101 (
102  const label facei,
103  label& patchID,
104  label& zoneID,
105  label& zoneFlip
106 ) const
107 {
108  patchID = -1;
109 
110  if (!mesh_.isInternalFace(facei))
111  {
112  patchID = mesh_.boundaryMesh().whichPatch(facei);
113  }
114 
115  zoneID = mesh_.faceZones().whichZone(facei);
116 
117  zoneFlip = false;
118 
119  if (zoneID >= 0)
120  {
121  const faceZone& fZone = mesh_.faceZones()[zoneID];
122 
123  zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
124  }
125 }
126 
127 
128 // Adds a face on top of existing facei.
129 Foam::label Foam::hexRef8::addFace
130 (
131  polyTopoChange& meshMod,
132  const label facei,
133  const face& newFace,
134  const label own,
135  const label nei
136 ) const
137 {
138  label patchID, zoneID, zoneFlip;
139 
140  getFaceInfo(facei, patchID, zoneID, zoneFlip);
141 
142  label newFacei = -1;
143 
144  if ((nei == -1) || (own < nei))
145  {
146  // Ordering ok.
147  newFacei = meshMod.setAction
148  (
149  polyAddFace
150  (
151  newFace, // face
152  own, // owner
153  nei, // neighbour
154  -1, // master point
155  -1, // master edge
156  facei, // master face for addition
157  false, // flux flip
158  patchID, // patch for face
159  zoneID, // zone for face
160  zoneFlip // face zone flip
161  )
162  );
163  }
164  else
165  {
166  // Reverse owner/neighbour
167  newFacei = meshMod.setAction
168  (
169  polyAddFace
170  (
171  newFace.reverseFace(), // face
172  nei, // owner
173  own, // neighbour
174  -1, // master point
175  -1, // master edge
176  facei, // master face for addition
177  false, // flux flip
178  patchID, // patch for face
179  zoneID, // zone for face
180  zoneFlip // face zone flip
181  )
182  );
183  }
184  return newFacei;
185 }
186 
187 
188 // Adds an internal face from an edge. Assumes orientation correct.
189 // Problem is that the face is between four new vertices. So what do we provide
190 // as master? The only existing mesh item we have is the edge we have split.
191 // Have to be careful in only using it if it has internal faces since otherwise
192 // polyMeshMorph will complain (because it cannot generate a sensible mapping
193 // for the face)
194 Foam::label Foam::hexRef8::addInternalFace
195 (
196  polyTopoChange& meshMod,
197  const label meshFacei,
198  const label meshPointi,
199  const face& newFace,
200  const label own,
201  const label nei
202 ) const
203 {
204  if (mesh_.isInternalFace(meshFacei))
205  {
206  return meshMod.setAction
207  (
208  polyAddFace
209  (
210  newFace, // face
211  own, // owner
212  nei, // neighbour
213  -1, // master point
214  -1, // master edge
215  -1, // master face for addition
216  false, // flux flip
217  -1, // patch for face
218  -1, // zone for face
219  false // face zone flip
220  )
221  );
222  }
223  else
224  {
225  // Two choices:
226  // - append (i.e. create out of nothing - will not be mapped)
227  // problem: field does not get mapped.
228  // - inflate from point.
229  // problem: does interpolative mapping which constructs full
230  // volPointInterpolation!
231 
232  // For now create out of nothing
233 
234  return meshMod.setAction
235  (
236  polyAddFace
237  (
238  newFace, // face
239  own, // owner
240  nei, // neighbour
241  -1, // master point
242  -1, // master edge
243  -1, // master face for addition
244  false, // flux flip
245  -1, // patch for face
246  -1, // zone for face
247  false // face zone flip
248  )
249  );
250 
251 
254  //label masterPointi = -1;
255  //
256  //const labelList& pFaces = mesh_.pointFaces()[meshPointi];
257  //
258  //forAll(pFaces, i)
259  //{
260  // if (mesh_.isInternalFace(pFaces[i]))
261  // {
262  // // meshPoint uses internal faces so ok to inflate from it
263  // masterPointi = meshPointi;
264  //
265  // break;
266  // }
267  //}
268  //
269  //return meshMod.setAction
270  //(
271  // polyAddFace
272  // (
273  // newFace, // face
274  // own, // owner
275  // nei, // neighbour
276  // masterPointi, // master point
277  // -1, // master edge
278  // -1, // master face for addition
279  // false, // flux flip
280  // -1, // patch for face
281  // -1, // zone for face
282  // false // face zone flip
283  // )
284  //);
285  }
286 }
287 
288 
289 // Modifies existing facei for either new owner/neighbour or new face points.
290 void Foam::hexRef8::modFace
291 (
292  polyTopoChange& meshMod,
293  const label facei,
294  const face& newFace,
295  const label own,
296  const label nei
297 ) const
298 {
299  label patchID, zoneID, zoneFlip;
300 
301  getFaceInfo(facei, patchID, zoneID, zoneFlip);
302 
303  if
304  (
305  (own != mesh_.faceOwner()[facei])
306  || (
307  mesh_.isInternalFace(facei)
308  && (nei != mesh_.faceNeighbour()[facei])
309  )
310  || (newFace != mesh_.faces()[facei])
311  )
312  {
313  if ((nei == -1) || (own < nei))
314  {
315  meshMod.setAction
316  (
317  polyModifyFace
318  (
319  newFace, // modified face
320  facei, // label of face being modified
321  own, // owner
322  nei, // neighbour
323  false, // face flip
324  patchID, // patch for face
325  false, // remove from zone
326  zoneID, // zone for face
327  zoneFlip // face flip in zone
328  )
329  );
330  }
331  else
332  {
333  meshMod.setAction
334  (
335  polyModifyFace
336  (
337  newFace.reverseFace(), // modified face
338  facei, // label of face being modified
339  nei, // owner
340  own, // neighbour
341  false, // face flip
342  patchID, // patch for face
343  false, // remove from zone
344  zoneID, // zone for face
345  zoneFlip // face flip in zone
346  )
347  );
348  }
349  }
350 }
351 
352 
353 // Bit complex way to determine the unrefined edge length.
354 Foam::scalar Foam::hexRef8::getLevel0EdgeLength() const
355 {
356  if (cellLevel_.size() != mesh_.nCells())
357  {
359  << "Number of cells in mesh:" << mesh_.nCells()
360  << " does not equal size of cellLevel:" << cellLevel_.size()
361  << endl
362  << "This might be because of a restart with inconsistent cellLevel."
363  << abort(FatalError);
364  }
365 
366  // Determine minimum edge length per refinement level
367  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
368 
369  const scalar GREAT2 = sqr(GREAT);
370 
371  label nLevels = gMax(cellLevel_)+1;
372 
373  scalarField typEdgeLenSqr(nLevels, GREAT2);
374 
375 
376  // 1. Look only at edges surrounded by cellLevel cells only.
377  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
378 
379  {
380  // Per edge the cellLevel of connected cells. -1 if not set,
381  // labelMax if different levels, otherwise levels of connected cells.
382  labelList edgeLevel(mesh_.nEdges(), -1);
383 
384  forAll(cellLevel_, celli)
385  {
386  const label cLevel = cellLevel_[celli];
387 
388  const labelList& cEdges = mesh_.cellEdges(celli);
389 
390  forAll(cEdges, i)
391  {
392  label edgeI = cEdges[i];
393 
394  if (edgeLevel[edgeI] == -1)
395  {
396  edgeLevel[edgeI] = cLevel;
397  }
398  else if (edgeLevel[edgeI] == labelMax)
399  {
400  // Already marked as on different cellLevels
401  }
402  else if (edgeLevel[edgeI] != cLevel)
403  {
404  edgeLevel[edgeI] = labelMax;
405  }
406  }
407  }
408 
409  // Make sure that edges with different levels on different processors
410  // are also marked. Do the same test (edgeLevel != cLevel) on coupled
411  // edges.
413  (
414  mesh_,
415  edgeLevel,
416  ifEqEqOp<labelMax>(),
417  labelMin
418  );
419 
420  // Now use the edgeLevel with a valid value to determine the
421  // length per level.
422  forAll(edgeLevel, edgeI)
423  {
424  const label eLevel = edgeLevel[edgeI];
425 
426  if (eLevel >= 0 && eLevel < labelMax)
427  {
428  const edge& e = mesh_.edges()[edgeI];
429 
430  scalar edgeLenSqr = magSqr(e.vec(mesh_.points()));
431 
432  typEdgeLenSqr[eLevel] = min(typEdgeLenSqr[eLevel], edgeLenSqr);
433  }
434  }
435  }
436 
437  // Get the minimum per level over all processors. Note minimum so if
438  // cells are not cubic we use the smallest edge side.
439  Pstream::listCombineGather(typEdgeLenSqr, minEqOp<scalar>());
440  Pstream::listCombineScatter(typEdgeLenSqr);
441 
442  if (debug)
443  {
444  Pout<< "hexRef8::getLevel0EdgeLength() :"
445  << " After phase1: Edgelengths (squared) per refinementlevel:"
446  << typEdgeLenSqr << endl;
447  }
448 
449 
450  // 2. For any levels where we haven't determined a valid length yet
451  // use any surrounding cell level. Here we use the max so we don't
452  // pick up levels between celllevel and higher celllevel (will have
453  // edges sized according to highest celllevel)
454  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
455 
456  scalarField maxEdgeLenSqr(nLevels, -GREAT2);
457 
458  forAll(cellLevel_, celli)
459  {
460  const label cLevel = cellLevel_[celli];
461 
462  const labelList& cEdges = mesh_.cellEdges(celli);
463 
464  forAll(cEdges, i)
465  {
466  const edge& e = mesh_.edges()[cEdges[i]];
467 
468  scalar edgeLenSqr = magSqr(e.vec(mesh_.points()));
469 
470  maxEdgeLenSqr[cLevel] = max(maxEdgeLenSqr[cLevel], edgeLenSqr);
471  }
472  }
473 
474  Pstream::listCombineGather(maxEdgeLenSqr, maxEqOp<scalar>());
475  Pstream::listCombineScatter(maxEdgeLenSqr);
476 
477  if (debug)
478  {
479  Pout<< "hexRef8::getLevel0EdgeLength() :"
480  << " Poor Edgelengths (squared) per refinementlevel:"
481  << maxEdgeLenSqr << endl;
482  }
483 
484 
485  // 3. Combine the two sets of lengths
486  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
487 
488  forAll(typEdgeLenSqr, levelI)
489  {
490  if (typEdgeLenSqr[levelI] == GREAT2 && maxEdgeLenSqr[levelI] >= 0)
491  {
492  typEdgeLenSqr[levelI] = maxEdgeLenSqr[levelI];
493  }
494  }
495 
496  if (debug)
497  {
498  Pout<< "hexRef8::getLevel0EdgeLength() :"
499  << " Final Edgelengths (squared) per refinementlevel:"
500  << typEdgeLenSqr << endl;
501  }
502 
503  // Find lowest level present
504  scalar level0Size = -1;
505 
506  forAll(typEdgeLenSqr, levelI)
507  {
508  scalar lenSqr = typEdgeLenSqr[levelI];
509 
510  if (lenSqr < GREAT2)
511  {
512  level0Size = Foam::sqrt(lenSqr)*(1<<levelI);
513 
514  if (debug)
515  {
516  Pout<< "hexRef8::getLevel0EdgeLength() :"
517  << " For level:" << levelI
518  << " have edgeLen:" << Foam::sqrt(lenSqr)
519  << " with equivalent level0 len:" << level0Size
520  << endl;
521  }
522  break;
523  }
524  }
525 
526  if (level0Size == -1)
527  {
529  << "Problem : typEdgeLenSqr:" << typEdgeLenSqr << abort(FatalError);
530  }
531 
532  return level0Size;
533 }
534 
535 
536 // Check whether pointi is an anchor on celli.
537 // If it is not check whether any other point on the face is an anchor cell.
538 Foam::label Foam::hexRef8::getAnchorCell
539 (
540  const labelListList& cellAnchorPoints,
541  const labelListList& cellAddedCells,
542  const label celli,
543  const label facei,
544  const label pointi
545 ) const
546 {
547  if (cellAnchorPoints[celli].size())
548  {
549  label index = cellAnchorPoints[celli].find(pointi);
550 
551  if (index != -1)
552  {
553  return cellAddedCells[celli][index];
554  }
555 
556 
557  // pointi is not an anchor cell.
558  // Maybe we are already a refined face so check all the face
559  // vertices.
560  const face& f = mesh_.faces()[facei];
561 
562  forAll(f, fp)
563  {
564  label index = cellAnchorPoints[celli].find(f[fp]);
565 
566  if (index != -1)
567  {
568  return cellAddedCells[celli][index];
569  }
570  }
571 
572  // Problem.
573  dumpCell(celli);
574  Perr<< "cell:" << celli << " anchorPoints:" << cellAnchorPoints[celli]
575  << endl;
576 
578  << "Could not find point " << pointi
579  << " in the anchorPoints for cell " << celli << endl
580  << "Does your original mesh obey the 2:1 constraint and"
581  << " did you use consistentRefinement to make your cells to refine"
582  << " obey this constraint as well?"
583  << abort(FatalError);
584 
585  return -1;
586  }
587  else
588  {
589  return celli;
590  }
591 }
592 
593 
594 // Get new owner and neighbour
595 void Foam::hexRef8::getFaceNeighbours
596 (
597  const labelListList& cellAnchorPoints,
598  const labelListList& cellAddedCells,
599  const label facei,
600  const label pointi,
601 
602  label& own,
603  label& nei
604 ) const
605 {
606  // Is owner split?
607  own = getAnchorCell
608  (
609  cellAnchorPoints,
610  cellAddedCells,
611  mesh_.faceOwner()[facei],
612  facei,
613  pointi
614  );
615 
616  if (mesh_.isInternalFace(facei))
617  {
618  nei = getAnchorCell
619  (
620  cellAnchorPoints,
621  cellAddedCells,
622  mesh_.faceNeighbour()[facei],
623  facei,
624  pointi
625  );
626  }
627  else
628  {
629  nei = -1;
630  }
631 }
632 
633 
634 // Get point with the lowest pointLevel
635 Foam::label Foam::hexRef8::findMinLevel(const labelList& f) const
636 {
637  label minLevel = labelMax;
638  label minFp = -1;
639 
640  forAll(f, fp)
641  {
642  label level = pointLevel_[f[fp]];
643 
644  if (level < minLevel)
645  {
646  minLevel = level;
647  minFp = fp;
648  }
649  }
650 
651  return minFp;
652 }
653 
654 
655 // Get point with the highest pointLevel
656 Foam::label Foam::hexRef8::findMaxLevel(const labelList& f) const
657 {
658  label maxLevel = labelMin;
659  label maxFp = -1;
660 
661  forAll(f, fp)
662  {
663  label level = pointLevel_[f[fp]];
664 
665  if (level > maxLevel)
666  {
667  maxLevel = level;
668  maxFp = fp;
669  }
670  }
671 
672  return maxFp;
673 }
674 
675 
676 Foam::label Foam::hexRef8::countAnchors
677 (
678  const labelList& f,
679  const label anchorLevel
680 ) const
681 {
682  label nAnchors = 0;
683 
684  forAll(f, fp)
685  {
686  if (pointLevel_[f[fp]] <= anchorLevel)
687  {
688  nAnchors++;
689  }
690  }
691  return nAnchors;
692 }
693 
694 
695 void Foam::hexRef8::dumpCell(const label celli) const
696 {
697  OFstream str(mesh_.time().path()/"cell_" + Foam::name(celli) + ".obj");
698  Pout<< "hexRef8 : Dumping cell as obj to " << str.name() << endl;
699 
700  const cell& cFaces = mesh_.cells()[celli];
701 
702  Map<label> pointToObjVert;
703  label objVertI = 0;
704 
705  forAll(cFaces, i)
706  {
707  const face& f = mesh_.faces()[cFaces[i]];
708 
709  forAll(f, fp)
710  {
711  if (pointToObjVert.insert(f[fp], objVertI))
712  {
713  meshTools::writeOBJ(str, mesh_.points()[f[fp]]);
714  objVertI++;
715  }
716  }
717  }
718 
719  forAll(cFaces, i)
720  {
721  const face& f = mesh_.faces()[cFaces[i]];
722 
723  forAll(f, fp)
724  {
725  label pointi = f[fp];
726  label nexPointi = f[f.fcIndex(fp)];
727 
728  str << "l " << pointToObjVert[pointi]+1
729  << ' ' << pointToObjVert[nexPointi]+1 << nl;
730  }
731  }
732 }
733 
734 
735 // Find point with certain pointLevel. Skip any higher levels.
736 Foam::label Foam::hexRef8::findLevel
737 (
738  const label facei,
739  const face& f,
740  const label startFp,
741  const bool searchForward,
742  const label wantedLevel
743 ) const
744 {
745  label fp = startFp;
746 
747  forAll(f, i)
748  {
749  label pointi = f[fp];
750 
751  if (pointLevel_[pointi] < wantedLevel)
752  {
753  dumpCell(mesh_.faceOwner()[facei]);
754  if (mesh_.isInternalFace(facei))
755  {
756  dumpCell(mesh_.faceNeighbour()[facei]);
757  }
758 
760  << "face:" << f
761  << " level:" << labelUIndList(pointLevel_, f)
762  << " startFp:" << startFp
763  << " wantedLevel:" << wantedLevel
764  << abort(FatalError);
765  }
766  else if (pointLevel_[pointi] == wantedLevel)
767  {
768  return fp;
769  }
770 
771  if (searchForward)
772  {
773  fp = f.fcIndex(fp);
774  }
775  else
776  {
777  fp = f.rcIndex(fp);
778  }
779  }
780 
781  dumpCell(mesh_.faceOwner()[facei]);
782  if (mesh_.isInternalFace(facei))
783  {
784  dumpCell(mesh_.faceNeighbour()[facei]);
785  }
786 
788  << "face:" << f
789  << " level:" << labelUIndList(pointLevel_, f)
790  << " startFp:" << startFp
791  << " wantedLevel:" << wantedLevel
792  << abort(FatalError);
793 
794  return -1;
795 }
796 
797 
798 // Gets cell level such that the face has four points <= level.
799 Foam::label Foam::hexRef8::faceLevel(const label facei) const
800 {
801  const face& f = mesh_.faces()[facei];
802 
803  if (f.size() <= 4)
804  {
805  return pointLevel_[f[findMaxLevel(f)]];
806  }
807  else
808  {
809  label ownLevel = cellLevel_[mesh_.faceOwner()[facei]];
810 
811  if (countAnchors(f, ownLevel) == 4)
812  {
813  return ownLevel;
814  }
815  else if (countAnchors(f, ownLevel+1) == 4)
816  {
817  return ownLevel+1;
818  }
819  else
820  {
821  return -1;
822  }
823  }
824 }
825 
826 
827 void Foam::hexRef8::checkInternalOrientation
828 (
829  polyTopoChange& meshMod,
830  const label celli,
831  const label facei,
832  const point& ownPt,
833  const point& neiPt,
834  const face& newFace
835 )
836 {
837  face compactFace(identity(newFace.size()));
838  pointField compactPoints(meshMod.points(), newFace);
839 
840  const vector areaNorm(compactFace.areaNormal(compactPoints));
841 
842  const vector dir(neiPt - ownPt);
843 
844  if ((dir & areaNorm) < 0)
845  {
847  << "cell:" << celli << " old face:" << facei
848  << " newFace:" << newFace << endl
849  << " coords:" << compactPoints
850  << " ownPt:" << ownPt
851  << " neiPt:" << neiPt
852  << abort(FatalError);
853  }
854 
855  const vector fcToOwn(compactFace.centre(compactPoints) - ownPt);
856 
857  const scalar s = (fcToOwn & areaNorm) / (dir & areaNorm);
858 
859  if (s < 0.1 || s > 0.9)
860  {
862  << "cell:" << celli << " old face:" << facei
863  << " newFace:" << newFace << endl
864  << " coords:" << compactPoints
865  << " ownPt:" << ownPt
866  << " neiPt:" << neiPt
867  << " s:" << s
868  << abort(FatalError);
869  }
870 }
871 
872 
873 void Foam::hexRef8::checkBoundaryOrientation
874 (
875  polyTopoChange& meshMod,
876  const label celli,
877  const label facei,
878  const point& ownPt,
879  const point& boundaryPt,
880  const face& newFace
881 )
882 {
883  face compactFace(identity(newFace.size()));
884  pointField compactPoints(meshMod.points(), newFace);
885 
886  const vector areaNorm(compactFace.areaNormal(compactPoints));
887 
888  const vector dir(boundaryPt - ownPt);
889 
890  if ((dir & areaNorm) < 0)
891  {
893  << "cell:" << celli << " old face:" << facei
894  << " newFace:" << newFace
895  << " coords:" << compactPoints
896  << " ownPt:" << ownPt
897  << " boundaryPt:" << boundaryPt
898  << abort(FatalError);
899  }
900 
901  const vector fcToOwn(compactFace.centre(compactPoints) - ownPt);
902 
903  const scalar s = (fcToOwn & dir) / magSqr(dir);
904 
905  if (s < 0.7 || s > 1.3)
906  {
908  << "cell:" << celli << " old face:" << facei
909  << " newFace:" << newFace
910  << " coords:" << compactPoints
911  << " ownPt:" << ownPt
912  << " boundaryPt:" << boundaryPt
913  << " s:" << s
914  << endl;
915  //<< abort(FatalError);
916  }
917 }
918 
919 
920 // If p0 and p1 are existing vertices check if edge is split and insert
921 // splitPoint.
922 void Foam::hexRef8::insertEdgeSplit
923 (
924  const labelList& edgeMidPoint,
925  const label p0,
926  const label p1,
927  DynamicList<label>& verts
928 ) const
929 {
930  if (p0 < mesh_.nPoints() && p1 < mesh_.nPoints())
931  {
932  label edgeI = meshTools::findEdge(mesh_, p0, p1);
933 
934  if (edgeI != -1 && edgeMidPoint[edgeI] != -1)
935  {
936  verts.append(edgeMidPoint[edgeI]);
937  }
938  }
939 }
940 
941 
942 // Internal faces are one per edge between anchor points. So one per midPoint
943 // between the anchor points. Here we store the information on the midPoint
944 // and if we have enough information:
945 // - two anchors
946 // - two face mid points
947 // we add the face. Note that this routine can get called anywhere from
948 // two times (two unrefined faces) to four times (two refined faces) so
949 // the first call that adds the information creates the face.
950 Foam::label Foam::hexRef8::storeMidPointInfo
951 (
952  const labelListList& cellAnchorPoints,
953  const labelListList& cellAddedCells,
954  const labelList& cellMidPoint,
955  const labelList& edgeMidPoint,
956  const label celli,
957  const label facei,
958  const bool faceOrder,
959  const label edgeMidPointi,
960  const label anchorPointi,
961  const label faceMidPointi,
962 
963  Map<edge>& midPointToAnchors,
964  Map<edge>& midPointToFaceMids,
965  polyTopoChange& meshMod
966 ) const
967 {
968  // See if need to store anchors.
969 
970  bool changed = false;
971  bool haveTwoAnchors = false;
972 
973  auto edgeMidFnd = midPointToAnchors.find(edgeMidPointi);
974 
975  if (!edgeMidFnd.found())
976  {
977  midPointToAnchors.insert(edgeMidPointi, edge(anchorPointi, -1));
978  }
979  else
980  {
981  edge& e = edgeMidFnd.val();
982 
983  if (anchorPointi != e[0])
984  {
985  if (e[1] == -1)
986  {
987  e[1] = anchorPointi;
988  changed = true;
989  }
990  }
991 
992  if (e[0] != -1 && e[1] != -1)
993  {
994  haveTwoAnchors = true;
995  }
996  }
997 
998  bool haveTwoFaceMids = false;
999 
1000  auto faceMidFnd = midPointToFaceMids.find(edgeMidPointi);
1001 
1002  if (!faceMidFnd.found())
1003  {
1004  midPointToFaceMids.insert(edgeMidPointi, edge(faceMidPointi, -1));
1005  }
1006  else
1007  {
1008  edge& e = faceMidFnd.val();
1009 
1010  if (faceMidPointi != e[0])
1011  {
1012  if (e[1] == -1)
1013  {
1014  e[1] = faceMidPointi;
1015  changed = true;
1016  }
1017  }
1018 
1019  if (e[0] != -1 && e[1] != -1)
1020  {
1021  haveTwoFaceMids = true;
1022  }
1023  }
1024 
1025  // Check if this call of storeMidPointInfo is the one that completed all
1026  // the necessary information.
1027 
1028  if (changed && haveTwoAnchors && haveTwoFaceMids)
1029  {
1030  const edge& anchors = midPointToAnchors[edgeMidPointi];
1031  const edge& faceMids = midPointToFaceMids[edgeMidPointi];
1032 
1033  label otherFaceMidPointi = faceMids.otherVertex(faceMidPointi);
1034 
1035  // Create face consistent with anchorI being the owner.
1036  // Note that the edges between the edge mid point and the face mids
1037  // might be marked for splitting. Note that these edge splits cannot
1038  // be between cellMid and face mids.
1039 
1040  DynamicList<label> newFaceVerts(4);
1041  if (faceOrder == (mesh_.faceOwner()[facei] == celli))
1042  {
1043  newFaceVerts.append(faceMidPointi);
1044 
1045  // Check & insert edge split if any
1046  insertEdgeSplit
1047  (
1048  edgeMidPoint,
1049  faceMidPointi, // edge between faceMid and
1050  edgeMidPointi, // edgeMid
1051  newFaceVerts
1052  );
1053 
1054  newFaceVerts.append(edgeMidPointi);
1055 
1056  insertEdgeSplit
1057  (
1058  edgeMidPoint,
1059  edgeMidPointi,
1060  otherFaceMidPointi,
1061  newFaceVerts
1062  );
1063 
1064  newFaceVerts.append(otherFaceMidPointi);
1065  newFaceVerts.append(cellMidPoint[celli]);
1066  }
1067  else
1068  {
1069  newFaceVerts.append(otherFaceMidPointi);
1070 
1071  insertEdgeSplit
1072  (
1073  edgeMidPoint,
1074  otherFaceMidPointi,
1075  edgeMidPointi,
1076  newFaceVerts
1077  );
1078 
1079  newFaceVerts.append(edgeMidPointi);
1080 
1081  insertEdgeSplit
1082  (
1083  edgeMidPoint,
1084  edgeMidPointi,
1085  faceMidPointi,
1086  newFaceVerts
1087  );
1088 
1089  newFaceVerts.append(faceMidPointi);
1090  newFaceVerts.append(cellMidPoint[celli]);
1091  }
1092 
1093  face newFace;
1094  newFace.transfer(newFaceVerts);
1095 
1096  label anchorCell0 = getAnchorCell
1097  (
1098  cellAnchorPoints,
1099  cellAddedCells,
1100  celli,
1101  facei,
1102  anchorPointi
1103  );
1104  label anchorCell1 = getAnchorCell
1105  (
1106  cellAnchorPoints,
1107  cellAddedCells,
1108  celli,
1109  facei,
1110  anchors.otherVertex(anchorPointi)
1111  );
1112 
1113 
1114  label own, nei;
1115  point ownPt, neiPt;
1116 
1117  if (anchorCell0 < anchorCell1)
1118  {
1119  own = anchorCell0;
1120  nei = anchorCell1;
1121 
1122  ownPt = mesh_.points()[anchorPointi];
1123  neiPt = mesh_.points()[anchors.otherVertex(anchorPointi)];
1124 
1125  }
1126  else
1127  {
1128  own = anchorCell1;
1129  nei = anchorCell0;
1130  newFace.flip();
1131 
1132  ownPt = mesh_.points()[anchors.otherVertex(anchorPointi)];
1133  neiPt = mesh_.points()[anchorPointi];
1134  }
1135 
1136  if (debug)
1137  {
1138  point ownPt, neiPt;
1139 
1140  if (anchorCell0 < anchorCell1)
1141  {
1142  ownPt = mesh_.points()[anchorPointi];
1143  neiPt = mesh_.points()[anchors.otherVertex(anchorPointi)];
1144  }
1145  else
1146  {
1147  ownPt = mesh_.points()[anchors.otherVertex(anchorPointi)];
1148  neiPt = mesh_.points()[anchorPointi];
1149  }
1150 
1151  checkInternalOrientation
1152  (
1153  meshMod,
1154  celli,
1155  facei,
1156  ownPt,
1157  neiPt,
1158  newFace
1159  );
1160  }
1161 
1162  return addInternalFace
1163  (
1164  meshMod,
1165  facei,
1166  anchorPointi,
1167  newFace,
1168  own,
1169  nei
1170  );
1171  }
1172  else
1173  {
1174  return -1;
1175  }
1176 }
1177 
1178 
1179 // Creates all the 12 internal faces for celli.
1180 void Foam::hexRef8::createInternalFaces
1181 (
1182  const labelListList& cellAnchorPoints,
1183  const labelListList& cellAddedCells,
1184  const labelList& cellMidPoint,
1185  const labelList& faceMidPoint,
1186  const labelList& faceAnchorLevel,
1187  const labelList& edgeMidPoint,
1188  const label celli,
1189 
1190  polyTopoChange& meshMod
1191 ) const
1192 {
1193  // Find in every face the cellLevel+1 points (from edge subdivision)
1194  // and the anchor points.
1195 
1196  const cell& cFaces = mesh_.cells()[celli];
1197  const label cLevel = cellLevel_[celli];
1198 
1199  // From edge mid to anchor points
1200  Map<edge> midPointToAnchors(24);
1201  // From edge mid to face mids
1202  Map<edge> midPointToFaceMids(24);
1203 
1204  // Storage for on-the-fly addressing
1205  DynamicList<label> storage;
1206 
1207 
1208  // Running count of number of internal faces added so far.
1209  label nFacesAdded = 0;
1210 
1211  forAll(cFaces, i)
1212  {
1213  label facei = cFaces[i];
1214 
1215  const face& f = mesh_.faces()[facei];
1216  const labelList& fEdges = mesh_.faceEdges(facei, storage);
1217 
1218  // We are on the celli side of face f. The face will have 1 or 4
1219  // cLevel points and lots of higher numbered ones.
1220 
1221  label faceMidPointi = -1;
1222 
1223  label nAnchors = countAnchors(f, cLevel);
1224 
1225  if (nAnchors == 1)
1226  {
1227  // Only one anchor point. So the other side of the face has already
1228  // been split using cLevel+1 and cLevel+2 points.
1229 
1230  // Find the one anchor.
1231  label anchorFp = -1;
1232 
1233  forAll(f, fp)
1234  {
1235  if (pointLevel_[f[fp]] <= cLevel)
1236  {
1237  anchorFp = fp;
1238  break;
1239  }
1240  }
1241 
1242  // Now the face mid point is the second cLevel+1 point
1243  label edgeMid = findLevel
1244  (
1245  facei,
1246  f,
1247  f.fcIndex(anchorFp),
1248  true,
1249  cLevel+1
1250  );
1251  label faceMid = findLevel
1252  (
1253  facei,
1254  f,
1255  f.fcIndex(edgeMid),
1256  true,
1257  cLevel+1
1258  );
1259 
1260  faceMidPointi = f[faceMid];
1261  }
1262  else if (nAnchors == 4)
1263  {
1264  // There is no face middle yet but the face will be marked for
1265  // splitting.
1266 
1267  faceMidPointi = faceMidPoint[facei];
1268  }
1269  else
1270  {
1271  dumpCell(mesh_.faceOwner()[facei]);
1272  if (mesh_.isInternalFace(facei))
1273  {
1274  dumpCell(mesh_.faceNeighbour()[facei]);
1275  }
1276 
1278  << "nAnchors:" << nAnchors
1279  << " facei:" << facei
1280  << abort(FatalError);
1281  }
1282 
1283 
1284 
1285  // Now loop over all the anchors (might be just one) and store
1286  // the edge mids connected to it. storeMidPointInfo will collect
1287  // all the info and combine it all.
1288 
1289  forAll(f, fp0)
1290  {
1291  label point0 = f[fp0];
1292 
1293  if (pointLevel_[point0] <= cLevel)
1294  {
1295  // Anchor.
1296 
1297  // Walk forward
1298  // ~~~~~~~~~~~~
1299  // to cLevel+1 or edgeMidPoint of this level.
1300 
1301 
1302  label edgeMidPointi = -1;
1303 
1304  label fp1 = f.fcIndex(fp0);
1305 
1306  if (pointLevel_[f[fp1]] <= cLevel)
1307  {
1308  // Anchor. Edge will be split.
1309  label edgeI = fEdges[fp0];
1310 
1311  edgeMidPointi = edgeMidPoint[edgeI];
1312 
1313  if (edgeMidPointi == -1)
1314  {
1315  dumpCell(celli);
1316 
1317  const labelList& cPoints = mesh_.cellPoints(celli);
1318 
1320  << "cell:" << celli << " cLevel:" << cLevel
1321  << " cell points:" << cPoints
1322  << " pointLevel:"
1323  << labelUIndList(pointLevel_, cPoints)
1324  << " face:" << facei
1325  << " f:" << f
1326  << " pointLevel:"
1327  << labelUIndList(pointLevel_, f)
1328  << " faceAnchorLevel:" << faceAnchorLevel[facei]
1329  << " faceMidPoint:" << faceMidPoint[facei]
1330  << " faceMidPointi:" << faceMidPointi
1331  << " fp:" << fp0
1332  << abort(FatalError);
1333  }
1334  }
1335  else
1336  {
1337  // Search forward in face to clevel+1
1338  label edgeMid = findLevel(facei, f, fp1, true, cLevel+1);
1339 
1340  edgeMidPointi = f[edgeMid];
1341  }
1342 
1343  label newFacei = storeMidPointInfo
1344  (
1345  cellAnchorPoints,
1346  cellAddedCells,
1347  cellMidPoint,
1348  edgeMidPoint,
1349 
1350  celli,
1351  facei,
1352  true, // mid point after anchor
1353  edgeMidPointi, // edgemid
1354  point0, // anchor
1355  faceMidPointi,
1356 
1357  midPointToAnchors,
1358  midPointToFaceMids,
1359  meshMod
1360  );
1361 
1362  if (newFacei != -1)
1363  {
1364  nFacesAdded++;
1365 
1366  if (nFacesAdded == 12)
1367  {
1368  break;
1369  }
1370  }
1371 
1372 
1373 
1374  // Walk backward
1375  // ~~~~~~~~~~~~~
1376 
1377  label fpMin1 = f.rcIndex(fp0);
1378 
1379  if (pointLevel_[f[fpMin1]] <= cLevel)
1380  {
1381  // Anchor. Edge will be split.
1382  label edgeI = fEdges[fpMin1];
1383 
1384  edgeMidPointi = edgeMidPoint[edgeI];
1385 
1386  if (edgeMidPointi == -1)
1387  {
1388  dumpCell(celli);
1389 
1390  const labelList& cPoints = mesh_.cellPoints(celli);
1391 
1393  << "cell:" << celli << " cLevel:" << cLevel
1394  << " cell points:" << cPoints
1395  << " pointLevel:"
1396  << labelUIndList(pointLevel_, cPoints)
1397  << " face:" << facei
1398  << " f:" << f
1399  << " pointLevel:"
1400  << labelUIndList(pointLevel_, f)
1401  << " faceAnchorLevel:" << faceAnchorLevel[facei]
1402  << " faceMidPoint:" << faceMidPoint[facei]
1403  << " faceMidPointi:" << faceMidPointi
1404  << " fp:" << fp0
1405  << abort(FatalError);
1406  }
1407  }
1408  else
1409  {
1410  // Search back to clevel+1
1411  label edgeMid = findLevel
1412  (
1413  facei,
1414  f,
1415  fpMin1,
1416  false,
1417  cLevel+1
1418  );
1419 
1420  edgeMidPointi = f[edgeMid];
1421  }
1422 
1423  newFacei = storeMidPointInfo
1424  (
1425  cellAnchorPoints,
1426  cellAddedCells,
1427  cellMidPoint,
1428  edgeMidPoint,
1429 
1430  celli,
1431  facei,
1432  false, // mid point before anchor
1433  edgeMidPointi, // edgemid
1434  point0, // anchor
1435  faceMidPointi,
1436 
1437  midPointToAnchors,
1438  midPointToFaceMids,
1439  meshMod
1440  );
1441 
1442  if (newFacei != -1)
1443  {
1444  nFacesAdded++;
1445 
1446  if (nFacesAdded == 12)
1447  {
1448  break;
1449  }
1450  }
1451  } // done anchor
1452  } // done face
1453 
1454  if (nFacesAdded == 12)
1455  {
1456  break;
1457  }
1458  }
1459 }
1460 
1461 
1462 void Foam::hexRef8::walkFaceToMid
1463 (
1464  const labelList& edgeMidPoint,
1465  const label cLevel,
1466  const label facei,
1467  const label startFp,
1468  DynamicList<label>& faceVerts
1469 ) const
1470 {
1471  const face& f = mesh_.faces()[facei];
1472  const labelList& fEdges = mesh_.faceEdges(facei);
1473 
1474  label fp = startFp;
1475 
1476  // Starting from fp store all (1 or 2) vertices until where the face
1477  // gets split
1478 
1479  while (true)
1480  {
1481  if (edgeMidPoint[fEdges[fp]] >= 0)
1482  {
1483  faceVerts.append(edgeMidPoint[fEdges[fp]]);
1484  }
1485 
1486  fp = f.fcIndex(fp);
1487 
1488  if (pointLevel_[f[fp]] <= cLevel)
1489  {
1490  // Next anchor. Have already append split point on edge in code
1491  // above.
1492  return;
1493  }
1494  else if (pointLevel_[f[fp]] == cLevel+1)
1495  {
1496  // Mid level
1497  faceVerts.append(f[fp]);
1498 
1499  return;
1500  }
1501  else if (pointLevel_[f[fp]] == cLevel+2)
1502  {
1503  // Store and continue to cLevel+1.
1504  faceVerts.append(f[fp]);
1505  }
1506  }
1507 }
1508 
1509 
1510 // Same as walkFaceToMid but now walk back.
1511 void Foam::hexRef8::walkFaceFromMid
1512 (
1513  const labelList& edgeMidPoint,
1514  const label cLevel,
1515  const label facei,
1516  const label startFp,
1517  DynamicList<label>& faceVerts
1518 ) const
1519 {
1520  const face& f = mesh_.faces()[facei];
1521  const labelList& fEdges = mesh_.faceEdges(facei);
1522 
1523  label fp = f.rcIndex(startFp);
1524 
1525  while (true)
1526  {
1527  if (pointLevel_[f[fp]] <= cLevel)
1528  {
1529  // anchor.
1530  break;
1531  }
1532  else if (pointLevel_[f[fp]] == cLevel+1)
1533  {
1534  // Mid level
1535  faceVerts.append(f[fp]);
1536  break;
1537  }
1538  else if (pointLevel_[f[fp]] == cLevel+2)
1539  {
1540  // Continue to cLevel+1.
1541  }
1542  fp = f.rcIndex(fp);
1543  }
1544 
1545  // Store
1546  while (true)
1547  {
1548  if (edgeMidPoint[fEdges[fp]] >= 0)
1549  {
1550  faceVerts.append(edgeMidPoint[fEdges[fp]]);
1551  }
1552 
1553  fp = f.fcIndex(fp);
1554 
1555  if (fp == startFp)
1556  {
1557  break;
1558  }
1559  faceVerts.append(f[fp]);
1560  }
1561 }
1562 
1563 
1564 // Updates refineCell (cells marked for refinement) so across all faces
1565 // there will be 2:1 consistency after refinement.
1566 Foam::label Foam::hexRef8::faceConsistentRefinement
1567 (
1568  const bool maxSet,
1569  const labelUList& cellLevel,
1570  bitSet& refineCell
1571 ) const
1572 {
1573  label nChanged = 0;
1574 
1575  // Internal faces.
1576  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1577  {
1578  label own = mesh_.faceOwner()[facei];
1579  label ownLevel = cellLevel[own] + refineCell.get(own);
1580 
1581  label nei = mesh_.faceNeighbour()[facei];
1582  label neiLevel = cellLevel[nei] + refineCell.get(nei);
1583 
1584  if (ownLevel > (neiLevel+1))
1585  {
1586  if (maxSet)
1587  {
1588  refineCell.set(nei);
1589  }
1590  else
1591  {
1592  refineCell.unset(own);
1593  }
1594  nChanged++;
1595  }
1596  else if (neiLevel > (ownLevel+1))
1597  {
1598  if (maxSet)
1599  {
1600  refineCell.set(own);
1601  }
1602  else
1603  {
1604  refineCell.unset(nei);
1605  }
1606  nChanged++;
1607  }
1608  }
1609 
1610 
1611  // Coupled faces. Swap owner level to get neighbouring cell level.
1612  // (only boundary faces of neiLevel used)
1613  labelList neiLevel(mesh_.nBoundaryFaces());
1614 
1615  forAll(neiLevel, i)
1616  {
1617  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1618 
1619  neiLevel[i] = cellLevel[own] + refineCell.get(own);
1620  }
1621 
1622  // Swap to neighbour
1623  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
1624 
1625  // Now we have neighbour value see which cells need refinement
1626  forAll(neiLevel, i)
1627  {
1628  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1629  label ownLevel = cellLevel[own] + refineCell.get(own);
1630 
1631  if (ownLevel > (neiLevel[i]+1))
1632  {
1633  if (!maxSet)
1634  {
1635  refineCell.unset(own);
1636  nChanged++;
1637  }
1638  }
1639  else if (neiLevel[i] > (ownLevel+1))
1640  {
1641  if (maxSet)
1642  {
1643  refineCell.set(own);
1644  nChanged++;
1645  }
1646  }
1647  }
1648 
1649  return nChanged;
1650 }
1651 
1652 
1653 // Debug: check if wanted refinement is compatible with 2:1
1654 void Foam::hexRef8::checkWantedRefinementLevels
1655 (
1656  const labelUList& cellLevel,
1657  const labelList& cellsToRefine
1658 ) const
1659 {
1660  bitSet refineCell(mesh_.nCells(), cellsToRefine);
1661 
1662  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1663  {
1664  label own = mesh_.faceOwner()[facei];
1665  label ownLevel = cellLevel[own] + refineCell.get(own);
1666 
1667  label nei = mesh_.faceNeighbour()[facei];
1668  label neiLevel = cellLevel[nei] + refineCell.get(nei);
1669 
1670  if (mag(ownLevel-neiLevel) > 1)
1671  {
1672  dumpCell(own);
1673  dumpCell(nei);
1675  << "cell:" << own
1676  << " current level:" << cellLevel[own]
1677  << " level after refinement:" << ownLevel
1678  << nl
1679  << "neighbour cell:" << nei
1680  << " current level:" << cellLevel[nei]
1681  << " level after refinement:" << neiLevel
1682  << nl
1683  << "which does not satisfy 2:1 constraints anymore."
1684  << abort(FatalError);
1685  }
1686  }
1687 
1688  // Coupled faces. Swap owner level to get neighbouring cell level.
1689  // (only boundary faces of neiLevel used)
1690  labelList neiLevel(mesh_.nBoundaryFaces());
1691 
1692  forAll(neiLevel, i)
1693  {
1694  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1695 
1696  neiLevel[i] = cellLevel[own] + refineCell.get(own);
1697  }
1698 
1699  // Swap to neighbour
1700  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
1701 
1702  // Now we have neighbour value see which cells need refinement
1703  forAll(neiLevel, i)
1704  {
1705  label facei = i + mesh_.nInternalFaces();
1706 
1707  label own = mesh_.faceOwner()[facei];
1708  label ownLevel = cellLevel[own] + refineCell.get(own);
1709 
1710  if (mag(ownLevel - neiLevel[i]) > 1)
1711  {
1712  label patchi = mesh_.boundaryMesh().whichPatch(facei);
1713 
1714  dumpCell(own);
1716  << "Celllevel does not satisfy 2:1 constraint."
1717  << " On coupled face "
1718  << facei
1719  << " on patch " << patchi << " "
1720  << mesh_.boundaryMesh()[patchi].name()
1721  << " owner cell " << own
1722  << " current level:" << cellLevel[own]
1723  << " level after refinement:" << ownLevel
1724  << nl
1725  << " (coupled) neighbour cell will get refinement "
1726  << neiLevel[i]
1727  << abort(FatalError);
1728  }
1729  }
1730 }
1731 
1732 
1733 // Set instance for mesh files
1735 {
1736  if (debug)
1737  {
1738  Pout<< "hexRef8::setInstance(const fileName& inst) : "
1739  << "Resetting file instance to " << inst << endl;
1740  }
1741 
1742  cellLevel_.instance() = inst;
1743  pointLevel_.instance() = inst;
1744  level0Edge_.instance() = inst;
1745  history_.instance() = inst;
1746 }
1747 
1748 
1749 void Foam::hexRef8::collectLevelPoints
1750 (
1751  const labelList& f,
1752  const label level,
1754 ) const
1755 {
1756  forAll(f, fp)
1757  {
1758  if (pointLevel_[f[fp]] <= level)
1759  {
1760  points.append(f[fp]);
1761  }
1762  }
1763 }
1764 
1765 
1766 void Foam::hexRef8::collectLevelPoints
1767 (
1768  const labelList& meshPoints,
1769  const labelList& f,
1770  const label level,
1771  DynamicList<label>& points
1772 ) const
1773 {
1774  forAll(f, fp)
1775  {
1776  label pointi = meshPoints[f[fp]];
1777  if (pointLevel_[pointi] <= level)
1778  {
1779  points.append(pointi);
1780  }
1781  }
1782 }
1783 
1784 
1785 // Return true if we've found 6 quads. faces guaranteed to be outwards pointing.
1786 bool Foam::hexRef8::matchHexShape
1787 (
1788  const label celli,
1789  const label cellLevel,
1790  DynamicList<face>& quads
1791 ) const
1792 {
1793  const cell& cFaces = mesh_.cells()[celli];
1794 
1795  // Work arrays
1796  DynamicList<label> verts(4);
1797  quads.clear();
1798 
1799 
1800  // 1. pick up any faces with four cellLevel points
1801 
1802  forAll(cFaces, i)
1803  {
1804  label facei = cFaces[i];
1805  const face& f = mesh_.faces()[facei];
1806 
1807  verts.clear();
1808  collectLevelPoints(f, cellLevel, verts);
1809  if (verts.size() == 4)
1810  {
1811  if (mesh_.faceOwner()[facei] != celli)
1812  {
1813  reverse(verts);
1814  }
1815  quads.append(face(0));
1816  labelList& quadVerts = quads.last();
1817  quadVerts.transfer(verts);
1818  }
1819  }
1820 
1821 
1822  if (quads.size() < 6)
1823  {
1824  Map<labelList> pointFaces(2*cFaces.size());
1825 
1826  forAll(cFaces, i)
1827  {
1828  label facei = cFaces[i];
1829  const face& f = mesh_.faces()[facei];
1830 
1831  // Pick up any faces with only one level point.
1832  // See if there are four of these where the common point
1833  // is a level+1 point. This common point is then the mid of
1834  // a split face.
1835 
1836  verts.clear();
1837  collectLevelPoints(f, cellLevel, verts);
1838  if (verts.size() == 1)
1839  {
1840  // Add to pointFaces for any level+1 point (this might be
1841  // a midpoint of a split face)
1842  forAll(f, fp)
1843  {
1844  label pointi = f[fp];
1845  if (pointLevel_[pointi] == cellLevel+1)
1846  {
1847  auto iter = pointFaces.find(pointi);
1848 
1849  if (iter.found())
1850  {
1851  labelList& pFaces = iter.val();
1852  pFaces.appendUniq(facei);
1853  }
1854  else
1855  {
1856  pointFaces.insert
1857  (
1858  pointi,
1859  labelList(one{}, facei)
1860  );
1861  }
1862  }
1863  }
1864  }
1865  }
1866 
1867  // 2. Check if we've collected any midPoints.
1868  forAllConstIters(pointFaces, iter)
1869  {
1870  const labelList& pFaces = iter.val();
1871 
1872  if (pFaces.size() == 4)
1873  {
1874  // Collect and orient.
1875  faceList fourFaces(pFaces.size());
1876  forAll(pFaces, pFacei)
1877  {
1878  label facei = pFaces[pFacei];
1879  const face& f = mesh_.faces()[facei];
1880  if (mesh_.faceOwner()[facei] == celli)
1881  {
1882  fourFaces[pFacei] = f;
1883  }
1884  else
1885  {
1886  fourFaces[pFacei] = f.reverseFace();
1887  }
1888  }
1889 
1890  primitivePatch bigFace
1891  (
1892  SubList<face>(fourFaces, fourFaces.size()),
1893  mesh_.points()
1894  );
1895  const labelListList& edgeLoops = bigFace.edgeLoops();
1896 
1897  if (edgeLoops.size() == 1)
1898  {
1899  // Collect the 4 cellLevel points
1900  verts.clear();
1901  collectLevelPoints
1902  (
1903  bigFace.meshPoints(),
1904  bigFace.edgeLoops()[0],
1905  cellLevel,
1906  verts
1907  );
1908 
1909  if (verts.size() == 4)
1910  {
1911  quads.append(face(0));
1912  labelList& quadVerts = quads.last();
1913  quadVerts.transfer(verts);
1914  }
1915  }
1916  }
1917  }
1918  }
1919 
1920  return (quads.size() == 6);
1921 }
1922 
1923 
1924 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1925 
1926 // Construct from mesh, read refinement data
1927 Foam::hexRef8::hexRef8(const polyMesh& mesh, const bool readHistory)
1928 :
1929  mesh_(mesh),
1930  cellLevel_
1931  (
1932  IOobject
1933  (
1934  "cellLevel",
1935  mesh_.facesInstance(),
1936  polyMesh::meshSubDir,
1937  mesh_,
1938  IOobject::READ_IF_PRESENT,
1939  IOobject::NO_WRITE
1940  ),
1941  labelList(mesh_.nCells(), Zero)
1942  ),
1943  pointLevel_
1944  (
1945  IOobject
1946  (
1947  "pointLevel",
1948  mesh_.facesInstance(),
1949  polyMesh::meshSubDir,
1950  mesh_,
1951  IOobject::READ_IF_PRESENT,
1952  IOobject::NO_WRITE
1953  ),
1954  labelList(mesh_.nPoints(), Zero)
1955  ),
1956  level0Edge_
1957  (
1958  IOobject
1959  (
1960  "level0Edge",
1961  mesh_.facesInstance(),
1962  polyMesh::meshSubDir,
1963  mesh_,
1964  IOobject::READ_IF_PRESENT,
1965  IOobject::NO_WRITE
1966  ),
1967  // Needs name:
1968  dimensionedScalar("level0Edge", dimLength, getLevel0EdgeLength())
1969  ),
1970  history_
1971  (
1972  IOobject
1973  (
1974  "refinementHistory",
1975  mesh_.facesInstance(),
1976  polyMesh::meshSubDir,
1977  mesh_,
1978  IOobject::NO_READ,
1979  IOobject::NO_WRITE
1980  ),
1981  // All cells visible if not read or readHistory = false
1982  (readHistory ? mesh_.nCells() : 0)
1983  ),
1984  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
1985  savedPointLevel_(0),
1986  savedCellLevel_(0)
1987 {
1988  if (readHistory)
1989  {
1991  if (history_.typeHeaderOk<refinementHistory>(true))
1992  {
1993  history_.read();
1994  }
1995  }
1996 
1997  if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
1998  {
2000  << "History enabled but number of visible cells "
2001  << history_.visibleCells().size() << " in "
2002  << history_.objectPath()
2003  << " is not equal to the number of cells in the mesh "
2004  << mesh_.nCells()
2005  << abort(FatalError);
2006  }
2007 
2008  if
2009  (
2010  cellLevel_.size() != mesh_.nCells()
2011  || pointLevel_.size() != mesh_.nPoints()
2012  )
2013  {
2015  << "Restarted from inconsistent cellLevel or pointLevel files."
2016  << endl
2017  << "cellLevel file " << cellLevel_.objectPath() << endl
2018  << "pointLevel file " << pointLevel_.objectPath() << endl
2019  << "Number of cells in mesh:" << mesh_.nCells()
2020  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2021  << "Number of points in mesh:" << mesh_.nPoints()
2022  << " does not equal size of pointLevel:" << pointLevel_.size()
2023  << abort(FatalError);
2024  }
2025 
2026 
2027  // Check refinement levels for consistency
2029 
2030 
2031  // Check initial mesh for consistency
2032 
2033  //if (debug)
2034  {
2035  checkMesh();
2036  }
2037 }
2038 
2039 
2040 Foam::hexRef8::hexRef8
2042  const polyMesh& mesh,
2043  const labelList& cellLevel,
2044  const labelList& pointLevel,
2045  const refinementHistory& history,
2046  const scalar level0Edge
2047 )
2048 :
2049  mesh_(mesh),
2050  cellLevel_
2051  (
2052  IOobject
2053  (
2054  "cellLevel",
2055  mesh_.facesInstance(),
2057  mesh_,
2060  ),
2061  cellLevel
2062  ),
2063  pointLevel_
2064  (
2065  IOobject
2066  (
2067  "pointLevel",
2068  mesh_.facesInstance(),
2070  mesh_,
2073  ),
2074  pointLevel
2075  ),
2076  level0Edge_
2077  (
2078  IOobject
2079  (
2080  "level0Edge",
2081  mesh_.facesInstance(),
2083  mesh_,
2086  ),
2087  // Needs name:
2089  (
2090  "level0Edge",
2091  dimLength,
2092  (level0Edge >= 0 ? level0Edge : getLevel0EdgeLength())
2093  )
2094  ),
2095  history_
2096  (
2097  IOobject
2098  (
2099  "refinementHistory",
2100  mesh_.facesInstance(),
2102  mesh_,
2105  ),
2106  history
2107  ),
2108  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
2109  savedPointLevel_(0),
2110  savedCellLevel_(0)
2111 {
2112  if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
2113  {
2115  << "History enabled but number of visible cells in it "
2116  << history_.visibleCells().size()
2117  << " is not equal to the number of cells in the mesh "
2118  << mesh_.nCells() << abort(FatalError);
2119  }
2120 
2121  if
2122  (
2123  cellLevel_.size() != mesh_.nCells()
2124  || pointLevel_.size() != mesh_.nPoints()
2125  )
2126  {
2128  << "Incorrect cellLevel or pointLevel size." << endl
2129  << "Number of cells in mesh:" << mesh_.nCells()
2130  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2131  << "Number of points in mesh:" << mesh_.nPoints()
2132  << " does not equal size of pointLevel:" << pointLevel_.size()
2133  << abort(FatalError);
2134  }
2135 
2136  // Check refinement levels for consistency
2137  checkRefinementLevels(-1, labelList(0));
2138 
2139 
2140  // Check initial mesh for consistency
2141 
2142  //if (debug)
2143  {
2144  checkMesh();
2145  }
2146 }
2147 
2148 
2149 Foam::hexRef8::hexRef8
2151  const polyMesh& mesh,
2152  const labelList& cellLevel,
2153  const labelList& pointLevel,
2154  const scalar level0Edge
2155 )
2156 :
2157  mesh_(mesh),
2158  cellLevel_
2159  (
2160  IOobject
2161  (
2162  "cellLevel",
2163  mesh_.facesInstance(),
2165  mesh_,
2168  ),
2169  cellLevel
2170  ),
2171  pointLevel_
2172  (
2173  IOobject
2174  (
2175  "pointLevel",
2176  mesh_.facesInstance(),
2178  mesh_,
2181  ),
2182  pointLevel
2183  ),
2184  level0Edge_
2185  (
2186  IOobject
2187  (
2188  "level0Edge",
2189  mesh_.facesInstance(),
2191  mesh_,
2194  ),
2195  // Needs name:
2197  (
2198  "level0Edge",
2199  dimLength,
2200  (level0Edge >= 0 ? level0Edge : getLevel0EdgeLength())
2201  )
2202  ),
2203  history_
2204  (
2205  IOobject
2206  (
2207  "refinementHistory",
2208  mesh_.facesInstance(),
2210  mesh_,
2213  ),
2215  labelList(0),
2216  false
2217  ),
2218  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
2219  savedPointLevel_(0),
2220  savedCellLevel_(0)
2221 {
2222  if
2223  (
2224  cellLevel_.size() != mesh_.nCells()
2225  || pointLevel_.size() != mesh_.nPoints()
2226  )
2227  {
2229  << "Incorrect cellLevel or pointLevel size." << endl
2230  << "Number of cells in mesh:" << mesh_.nCells()
2231  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2232  << "Number of points in mesh:" << mesh_.nPoints()
2233  << " does not equal size of pointLevel:" << pointLevel_.size()
2234  << abort(FatalError);
2235  }
2236 
2237  // Check refinement levels for consistency
2238  checkRefinementLevels(-1, labelList(0));
2239 
2240  // Check initial mesh for consistency
2241 
2242  //if (debug)
2243  {
2244  checkMesh();
2245  }
2246 }
2247 
2248 
2249 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2250 
2253  const labelUList& cellLevel,
2254  const labelList& cellsToRefine,
2255  const bool maxSet
2256 ) const
2257 {
2258  // Loop, modifying cellsToRefine, until no more changes to due to 2:1
2259  // conflicts.
2260  // maxSet = false : unselect cells to refine
2261  // maxSet = true : select cells to refine
2262 
2263  bitSet refineCell(mesh_.nCells(), cellsToRefine);
2264 
2265  while (true)
2266  {
2267  label nChanged = faceConsistentRefinement
2268  (
2269  maxSet,
2270  cellLevel,
2271  refineCell
2272  );
2273 
2274  reduce(nChanged, sumOp<label>());
2275 
2276  if (debug)
2277  {
2278  Pout<< "hexRef8::consistentRefinement : Changed " << nChanged
2279  << " refinement levels due to 2:1 conflicts."
2280  << endl;
2281  }
2282 
2283  if (nChanged == 0)
2284  {
2285  break;
2286  }
2287  }
2288 
2289  // Convert back to labelList.
2290  labelList newCellsToRefine(refineCell.toc());
2291 
2292  if (debug)
2293  {
2294  checkWantedRefinementLevels(cellLevel, newCellsToRefine);
2295  }
2296 
2297  return newCellsToRefine;
2298 }
2299 
2300 
2301 // Given a list of cells to refine determine additional cells to refine
2302 // such that the overall refinement:
2303 // - satisfies maxFaceDiff (e.g. 2:1) across neighbouring faces
2304 // - satisfies maxPointDiff (e.g. 4:1) across selected point connected
2305 // cells. This is used to ensure that e.g. cells on the surface are not
2306 // point connected to cells which are 8 times smaller.
2309  const label maxFaceDiff,
2310  const labelList& cellsToRefine,
2311  const labelList& facesToCheck,
2312  const label maxPointDiff,
2313  const labelList& pointsToCheck
2314 ) const
2315 {
2316  const labelList& faceOwner = mesh_.faceOwner();
2317  const labelList& faceNeighbour = mesh_.faceNeighbour();
2318 
2319 
2320  if (maxFaceDiff <= 0)
2321  {
2323  << "Illegal maxFaceDiff " << maxFaceDiff << nl
2324  << "Value should be >= 1" << exit(FatalError);
2325  }
2326 
2327 
2328  // Bit tricky. Say we want a distance of three cells between two
2329  // consecutive refinement levels. This is done by using FaceCellWave to
2330  // transport out the new refinement level. It gets decremented by one
2331  // every cell it crosses so if we initialize it to maxFaceDiff
2332  // we will get a field everywhere that tells us whether an unselected cell
2333  // needs refining as well.
2334 
2335 
2336  // Initial information about (distance to) cellLevel on all cells
2337  List<refinementData> allCellInfo(mesh_.nCells());
2338 
2339  // Initial information about (distance to) cellLevel on all faces
2340  List<refinementData> allFaceInfo(mesh_.nFaces());
2341 
2342  forAll(allCellInfo, celli)
2343  {
2344  // maxFaceDiff since refinementData counts both
2345  // faces and cells.
2346  allCellInfo[celli] = refinementData
2347  (
2348  maxFaceDiff*(cellLevel_[celli]+1),// when cell is to be refined
2349  maxFaceDiff*cellLevel_[celli] // current level
2350  );
2351  }
2352 
2353  // Cells to be refined will have cellLevel+1
2354  forAll(cellsToRefine, i)
2355  {
2356  label celli = cellsToRefine[i];
2357 
2358  allCellInfo[celli].count() = allCellInfo[celli].refinementCount();
2359  }
2360 
2361 
2362  // Labels of seed faces
2363  DynamicList<label> seedFaces(mesh_.nFaces()/100);
2364  // refinementLevel data on seed faces
2365  DynamicList<refinementData> seedFacesInfo(mesh_.nFaces()/100);
2366 
2367  // Dummy additional info for FaceCellWave
2368  int dummyTrackData = 0;
2369 
2370 
2371  // Additional buffer layer thickness by changing initial count. Usually
2372  // this happens on boundary faces. Bit tricky. Use allFaceInfo to mark
2373  // off thus marked faces so they're skipped in the next loop.
2374  forAll(facesToCheck, i)
2375  {
2376  label facei = facesToCheck[i];
2377 
2378  if (allFaceInfo[facei].valid(dummyTrackData))
2379  {
2380  // Can only occur if face has already gone through loop below.
2382  << "Argument facesToCheck seems to have duplicate entries!"
2383  << endl
2384  << "face:" << facei << " occurs at positions "
2385  << findIndices(facesToCheck, facei)
2386  << abort(FatalError);
2387  }
2388 
2389 
2390  const refinementData& ownData = allCellInfo[faceOwner[facei]];
2391 
2392  if (mesh_.isInternalFace(facei))
2393  {
2394  // Seed face if neighbouring cell (after possible refinement)
2395  // will be refined one more than the current owner or neighbour.
2396 
2397  const refinementData& neiData = allCellInfo[faceNeighbour[facei]];
2398 
2399  label faceCount;
2400  label faceRefineCount;
2401  if (neiData.count() > ownData.count())
2402  {
2403  faceCount = neiData.count() + maxFaceDiff;
2404  faceRefineCount = faceCount + maxFaceDiff;
2405  }
2406  else
2407  {
2408  faceCount = ownData.count() + maxFaceDiff;
2409  faceRefineCount = faceCount + maxFaceDiff;
2410  }
2411 
2412  seedFaces.append(facei);
2413  seedFacesInfo.append
2414  (
2416  (
2417  faceRefineCount,
2418  faceCount
2419  )
2420  );
2421  allFaceInfo[facei] = seedFacesInfo.last();
2422  }
2423  else
2424  {
2425  label faceCount = ownData.count() + maxFaceDiff;
2426  label faceRefineCount = faceCount + maxFaceDiff;
2427 
2428  seedFaces.append(facei);
2429  seedFacesInfo.append
2430  (
2432  (
2433  faceRefineCount,
2434  faceCount
2435  )
2436  );
2437  allFaceInfo[facei] = seedFacesInfo.last();
2438  }
2439  }
2440 
2441 
2442  // Just seed with all faces inbetween different refinement levels for now
2443  // (alternatively only seed faces on cellsToRefine but that gives problems
2444  // if no cells to refine)
2445  forAll(faceNeighbour, facei)
2446  {
2447  // Check if face already handled in loop above
2448  if (!allFaceInfo[facei].valid(dummyTrackData))
2449  {
2450  label own = faceOwner[facei];
2451  label nei = faceNeighbour[facei];
2452 
2453  // Seed face with transported data from highest cell.
2454 
2455  if (allCellInfo[own].count() > allCellInfo[nei].count())
2456  {
2457  allFaceInfo[facei].updateFace
2458  (
2459  mesh_,
2460  facei,
2461  own,
2462  allCellInfo[own],
2464  dummyTrackData
2465  );
2466  seedFaces.append(facei);
2467  seedFacesInfo.append(allFaceInfo[facei]);
2468  }
2469  else if (allCellInfo[own].count() < allCellInfo[nei].count())
2470  {
2471  allFaceInfo[facei].updateFace
2472  (
2473  mesh_,
2474  facei,
2475  nei,
2476  allCellInfo[nei],
2478  dummyTrackData
2479  );
2480  seedFaces.append(facei);
2481  seedFacesInfo.append(allFaceInfo[facei]);
2482  }
2483  }
2484  }
2485 
2486  // Seed all boundary faces with owner value. This is to make sure that
2487  // they are visited (probably only important for coupled faces since
2488  // these need to be visited from both sides)
2489  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
2490  {
2491  // Check if face already handled in loop above
2492  if (!allFaceInfo[facei].valid(dummyTrackData))
2493  {
2494  label own = faceOwner[facei];
2495 
2496  // Seed face with transported data from owner.
2497  refinementData faceData;
2498  faceData.updateFace
2499  (
2500  mesh_,
2501  facei,
2502  own,
2503  allCellInfo[own],
2505  dummyTrackData
2506  );
2507  seedFaces.append(facei);
2508  seedFacesInfo.append(faceData);
2509  }
2510  }
2511 
2512 
2513  // face-cell-face transport engine
2515  (
2516  mesh_,
2517  allFaceInfo,
2518  allCellInfo,
2519  dummyTrackData
2520  );
2521 
2522  while (true)
2523  {
2524  if (debug)
2525  {
2526  Pout<< "hexRef8::consistentSlowRefinement : Seeded "
2527  << seedFaces.size() << " faces between cells with different"
2528  << " refinement level." << endl;
2529  }
2530 
2531  // Set seed faces
2532  levelCalc.setFaceInfo(seedFaces.shrink(), seedFacesInfo.shrink());
2533  seedFaces.clear();
2534  seedFacesInfo.clear();
2535 
2536  // Iterate until no change. Now 2:1 face difference should be satisfied
2537  levelCalc.iterate(mesh_.globalData().nTotalFaces()+1);
2538 
2539 
2540  // Now check point-connected cells (face-connected cells already ok):
2541  // - get per point max of connected cells
2542  // - sync across coupled points
2543  // - check cells against above point max
2544 
2545  if (maxPointDiff == -1)
2546  {
2547  // No need to do any point checking.
2548  break;
2549  }
2550 
2551  // Determine per point the max cell level. (done as count, not
2552  // as cell level purely for ease)
2553  labelList maxPointCount(mesh_.nPoints(), Zero);
2554 
2555  forAll(maxPointCount, pointi)
2556  {
2557  label& pLevel = maxPointCount[pointi];
2558 
2559  const labelList& pCells = mesh_.pointCells(pointi);
2560 
2561  forAll(pCells, i)
2562  {
2563  pLevel = max(pLevel, allCellInfo[pCells[i]].count());
2564  }
2565  }
2566 
2567  // Sync maxPointCount to neighbour
2569  (
2570  mesh_,
2571  maxPointCount,
2572  maxEqOp<label>(),
2573  labelMin // null value
2574  );
2575 
2576  // Update allFaceInfo from maxPointCount for all points to check
2577  // (usually on boundary faces)
2578 
2579  // Per face the new refinement data
2580  Map<refinementData> changedFacesInfo(pointsToCheck.size());
2581 
2582  forAll(pointsToCheck, i)
2583  {
2584  label pointi = pointsToCheck[i];
2585 
2586  // Loop over all cells using the point and check whether their
2587  // refinement level is much less than the maximum.
2588 
2589  const labelList& pCells = mesh_.pointCells(pointi);
2590 
2591  forAll(pCells, pCelli)
2592  {
2593  label celli = pCells[pCelli];
2594 
2595  refinementData& cellInfo = allCellInfo[celli];
2596 
2597  if
2598  (
2599  !cellInfo.isRefined()
2600  && (
2601  maxPointCount[pointi]
2602  > cellInfo.count() + maxFaceDiff*maxPointDiff
2603  )
2604  )
2605  {
2606  // Mark cell for refinement
2607  cellInfo.count() = cellInfo.refinementCount();
2608 
2609  // Insert faces of cell as seed faces.
2610  const cell& cFaces = mesh_.cells()[celli];
2611 
2612  forAll(cFaces, cFacei)
2613  {
2614  label facei = cFaces[cFacei];
2615 
2616  refinementData faceData;
2617  faceData.updateFace
2618  (
2619  mesh_,
2620  facei,
2621  celli,
2622  cellInfo,
2624  dummyTrackData
2625  );
2626 
2627  if (faceData.count() > allFaceInfo[facei].count())
2628  {
2629  changedFacesInfo.insert(facei, faceData);
2630  }
2631  }
2632  }
2633  }
2634  }
2635 
2636  label nChanged = changedFacesInfo.size();
2637  reduce(nChanged, sumOp<label>());
2638 
2639  if (nChanged == 0)
2640  {
2641  break;
2642  }
2643 
2644 
2645  // Transfer into seedFaces, seedFacesInfo
2646  seedFaces.setCapacity(changedFacesInfo.size());
2647  seedFacesInfo.setCapacity(changedFacesInfo.size());
2648 
2649  forAllConstIters(changedFacesInfo, iter)
2650  {
2651  seedFaces.append(iter.key());
2652  seedFacesInfo.append(iter.val());
2653  }
2654  }
2655 
2656 
2657  if (debug)
2658  {
2659  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
2660  {
2661  label own = mesh_.faceOwner()[facei];
2662  label ownLevel =
2663  cellLevel_[own]
2664  + (allCellInfo[own].isRefined() ? 1 : 0);
2665 
2666  label nei = mesh_.faceNeighbour()[facei];
2667  label neiLevel =
2668  cellLevel_[nei]
2669  + (allCellInfo[nei].isRefined() ? 1 : 0);
2670 
2671  if (mag(ownLevel-neiLevel) > 1)
2672  {
2673  dumpCell(own);
2674  dumpCell(nei);
2676  << "cell:" << own
2677  << " current level:" << cellLevel_[own]
2678  << " current refData:" << allCellInfo[own]
2679  << " level after refinement:" << ownLevel
2680  << nl
2681  << "neighbour cell:" << nei
2682  << " current level:" << cellLevel_[nei]
2683  << " current refData:" << allCellInfo[nei]
2684  << " level after refinement:" << neiLevel
2685  << nl
2686  << "which does not satisfy 2:1 constraints anymore." << nl
2687  << "face:" << facei << " faceRefData:" << allFaceInfo[facei]
2688  << abort(FatalError);
2689  }
2690  }
2691 
2692 
2693  // Coupled faces. Swap owner level to get neighbouring cell level.
2694  // (only boundary faces of neiLevel used)
2695 
2696  labelList neiLevel(mesh_.nBoundaryFaces());
2697  labelList neiCount(mesh_.nBoundaryFaces());
2698  labelList neiRefCount(mesh_.nBoundaryFaces());
2699 
2700  forAll(neiLevel, i)
2701  {
2702  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
2703  neiLevel[i] = cellLevel_[own];
2704  neiCount[i] = allCellInfo[own].count();
2705  neiRefCount[i] = allCellInfo[own].refinementCount();
2706  }
2707 
2708  // Swap to neighbour
2709  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
2710  syncTools::swapBoundaryFaceList(mesh_, neiCount);
2711  syncTools::swapBoundaryFaceList(mesh_, neiRefCount);
2712 
2713  // Now we have neighbour value see which cells need refinement
2714  forAll(neiLevel, i)
2715  {
2716  label facei = i+mesh_.nInternalFaces();
2717 
2718  label own = mesh_.faceOwner()[facei];
2719  label ownLevel =
2720  cellLevel_[own]
2721  + (allCellInfo[own].isRefined() ? 1 : 0);
2722 
2723  label nbrLevel =
2724  neiLevel[i]
2725  + ((neiCount[i] >= neiRefCount[i]) ? 1 : 0);
2726 
2727  if (mag(ownLevel - nbrLevel) > 1)
2728  {
2729  dumpCell(own);
2730  label patchi = mesh_.boundaryMesh().whichPatch(facei);
2731 
2733  << "Celllevel does not satisfy 2:1 constraint."
2734  << " On coupled face "
2735  << facei
2736  << " refData:" << allFaceInfo[facei]
2737  << " on patch " << patchi << " "
2738  << mesh_.boundaryMesh()[patchi].name() << nl
2739  << "owner cell " << own
2740  << " current level:" << cellLevel_[own]
2741  << " current count:" << allCellInfo[own].count()
2742  << " current refCount:"
2743  << allCellInfo[own].refinementCount()
2744  << " level after refinement:" << ownLevel
2745  << nl
2746  << "(coupled) neighbour cell"
2747  << " has current level:" << neiLevel[i]
2748  << " current count:" << neiCount[i]
2749  << " current refCount:" << neiRefCount[i]
2750  << " level after refinement:" << nbrLevel
2751  << abort(FatalError);
2752  }
2753  }
2754  }
2755 
2756  // Convert back to labelList of cells to refine.
2757 
2758  label nRefined = 0;
2759 
2760  forAll(allCellInfo, celli)
2761  {
2762  if (allCellInfo[celli].isRefined())
2763  {
2764  nRefined++;
2765  }
2766  }
2767 
2768  // Updated list of cells to refine
2769  labelList newCellsToRefine(nRefined);
2770  nRefined = 0;
2771 
2772  forAll(allCellInfo, celli)
2773  {
2774  if (allCellInfo[celli].isRefined())
2775  {
2776  newCellsToRefine[nRefined++] = celli;
2777  }
2778  }
2779 
2780  if (debug)
2781  {
2782  Pout<< "hexRef8::consistentSlowRefinement : From "
2783  << cellsToRefine.size() << " to " << newCellsToRefine.size()
2784  << " cells to refine." << endl;
2785  }
2786 
2787  return newCellsToRefine;
2788 }
2789 
2790 
2793  const label maxFaceDiff,
2794  const labelList& cellsToRefine,
2795  const labelList& facesToCheck
2796 ) const
2797 {
2798  const labelList& faceOwner = mesh_.faceOwner();
2799  const labelList& faceNeighbour = mesh_.faceNeighbour();
2800 
2801  if (maxFaceDiff <= 0)
2802  {
2804  << "Illegal maxFaceDiff " << maxFaceDiff << nl
2805  << "Value should be >= 1" << exit(FatalError);
2806  }
2807 
2808  const scalar level0Size = 2*maxFaceDiff*level0EdgeLength();
2809 
2810 
2811  // Bit tricky. Say we want a distance of three cells between two
2812  // consecutive refinement levels. This is done by using FaceCellWave to
2813  // transport out the 'refinement shell'. Anything inside the refinement
2814  // shell (given by a distance) gets marked for refinement.
2815 
2816  // Initial information about (distance to) cellLevel on all cells
2817  List<refinementDistanceData> allCellInfo(mesh_.nCells());
2818 
2819  // Initial information about (distance to) cellLevel on all faces
2820  List<refinementDistanceData> allFaceInfo(mesh_.nFaces());
2821 
2822  // Dummy additional info for FaceCellWave
2823  int dummyTrackData = 0;
2824 
2825 
2826  // Mark cells with wanted refinement level
2827  forAll(cellsToRefine, i)
2828  {
2829  label celli = cellsToRefine[i];
2830 
2831  allCellInfo[celli] = refinementDistanceData
2832  (
2833  level0Size,
2834  mesh_.cellCentres()[celli],
2835  cellLevel_[celli]+1 // wanted refinement
2836  );
2837  }
2838  // Mark all others with existing refinement level
2839  forAll(allCellInfo, celli)
2840  {
2841  if (!allCellInfo[celli].valid(dummyTrackData))
2842  {
2843  allCellInfo[celli] = refinementDistanceData
2844  (
2845  level0Size,
2846  mesh_.cellCentres()[celli],
2847  cellLevel_[celli] // wanted refinement
2848  );
2849  }
2850  }
2851 
2852 
2853  // Labels of seed faces
2854  DynamicList<label> seedFaces(mesh_.nFaces()/100);
2855  // refinementLevel data on seed faces
2856  DynamicList<refinementDistanceData> seedFacesInfo(mesh_.nFaces()/100);
2857 
2858  const pointField& cc = mesh_.cellCentres();
2859 
2860  forAll(facesToCheck, i)
2861  {
2862  label facei = facesToCheck[i];
2863 
2864  if (allFaceInfo[facei].valid(dummyTrackData))
2865  {
2866  // Can only occur if face has already gone through loop below.
2868  << "Argument facesToCheck seems to have duplicate entries!"
2869  << endl
2870  << "face:" << facei << " occurs at positions "
2871  << findIndices(facesToCheck, facei)
2872  << abort(FatalError);
2873  }
2874 
2875  label own = faceOwner[facei];
2876 
2877  label ownLevel =
2878  (
2879  allCellInfo[own].valid(dummyTrackData)
2880  ? allCellInfo[own].originLevel()
2881  : cellLevel_[own]
2882  );
2883 
2884  if (!mesh_.isInternalFace(facei))
2885  {
2886  // Do as if boundary face would have neighbour with one higher
2887  // refinement level.
2888  const point& fc = mesh_.faceCentres()[facei];
2889 
2890  refinementDistanceData neiData
2891  (
2892  level0Size,
2893  2*fc - cc[own], // est'd cell centre
2894  ownLevel+1
2895  );
2896 
2897  allFaceInfo[facei].updateFace
2898  (
2899  mesh_,
2900  facei,
2901  own, // not used (should be nei)
2902  neiData,
2904  dummyTrackData
2905  );
2906  }
2907  else
2908  {
2909  label nei = faceNeighbour[facei];
2910 
2911  label neiLevel =
2912  (
2913  allCellInfo[nei].valid(dummyTrackData)
2914  ? allCellInfo[nei].originLevel()
2915  : cellLevel_[nei]
2916  );
2917 
2918  if (ownLevel == neiLevel)
2919  {
2920  // Fake as if nei>own or own>nei (whichever one 'wins')
2921  allFaceInfo[facei].updateFace
2922  (
2923  mesh_,
2924  facei,
2925  nei,
2926  refinementDistanceData(level0Size, cc[nei], neiLevel+1),
2928  dummyTrackData
2929  );
2930  allFaceInfo[facei].updateFace
2931  (
2932  mesh_,
2933  facei,
2934  own,
2935  refinementDistanceData(level0Size, cc[own], ownLevel+1),
2937  dummyTrackData
2938  );
2939  }
2940  else
2941  {
2942  // Difference in level anyway.
2943  allFaceInfo[facei].updateFace
2944  (
2945  mesh_,
2946  facei,
2947  nei,
2948  refinementDistanceData(level0Size, cc[nei], neiLevel),
2950  dummyTrackData
2951  );
2952  allFaceInfo[facei].updateFace
2953  (
2954  mesh_,
2955  facei,
2956  own,
2957  refinementDistanceData(level0Size, cc[own], ownLevel),
2959  dummyTrackData
2960  );
2961  }
2962  }
2963  seedFaces.append(facei);
2964  seedFacesInfo.append(allFaceInfo[facei]);
2965  }
2966 
2967 
2968  // Create some initial seeds to start walking from. This is only if there
2969  // are no facesToCheck.
2970  // Just seed with all faces inbetween different refinement levels for now
2971  forAll(faceNeighbour, facei)
2972  {
2973  // Check if face already handled in loop above
2974  if (!allFaceInfo[facei].valid(dummyTrackData))
2975  {
2976  label own = faceOwner[facei];
2977 
2978  label ownLevel =
2979  (
2980  allCellInfo[own].valid(dummyTrackData)
2981  ? allCellInfo[own].originLevel()
2982  : cellLevel_[own]
2983  );
2984 
2985  label nei = faceNeighbour[facei];
2986 
2987  label neiLevel =
2988  (
2989  allCellInfo[nei].valid(dummyTrackData)
2990  ? allCellInfo[nei].originLevel()
2991  : cellLevel_[nei]
2992  );
2993 
2994  if (ownLevel > neiLevel)
2995  {
2996  // Set face to owner data. (since face not yet would be copy)
2997  seedFaces.append(facei);
2998  allFaceInfo[facei].updateFace
2999  (
3000  mesh_,
3001  facei,
3002  own,
3003  refinementDistanceData(level0Size, cc[own], ownLevel),
3005  dummyTrackData
3006  );
3007  seedFacesInfo.append(allFaceInfo[facei]);
3008  }
3009  else if (neiLevel > ownLevel)
3010  {
3011  seedFaces.append(facei);
3012  allFaceInfo[facei].updateFace
3013  (
3014  mesh_,
3015  facei,
3016  nei,
3017  refinementDistanceData(level0Size, cc[nei], neiLevel),
3019  dummyTrackData
3020  );
3021  seedFacesInfo.append(allFaceInfo[facei]);
3022  }
3023  }
3024  }
3025 
3026  seedFaces.shrink();
3027  seedFacesInfo.shrink();
3028 
3029  // face-cell-face transport engine
3031  (
3032  mesh_,
3033  seedFaces,
3034  seedFacesInfo,
3035  allFaceInfo,
3036  allCellInfo,
3037  mesh_.globalData().nTotalCells()+1,
3038  dummyTrackData
3039  );
3040 
3041 
3042  //if (debug)
3043  //{
3044  // // Dump wanted level
3045  // volScalarField wantedLevel
3046  // (
3047  // IOobject
3048  // (
3049  // "wantedLevel",
3050  // fMesh.time().timeName(),
3051  // fMesh,
3052  // IOobject::NO_READ,
3053  // IOobject::NO_WRITE,
3054  // false
3055  // ),
3056  // fMesh,
3057  // dimensionedScalar(dimless, Zero)
3058  // );
3059  //
3060  // forAll(wantedLevel, celli)
3061  // {
3062  // wantedLevel[celli] = allCellInfo[celli].wantedLevel(cc[celli]);
3063  // }
3064  //
3065  // Pout<< "Writing " << wantedLevel.objectPath() << endl;
3066  // wantedLevel.write();
3067  //}
3068 
3069 
3070  // Convert back to labelList of cells to refine.
3071  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3072 
3073  // 1. Force original refinement cells to be picked up by setting the
3074  // originLevel of input cells to be a very large level (but within range
3075  // of 1<< shift inside refinementDistanceData::wantedLevel)
3076  forAll(cellsToRefine, i)
3077  {
3078  label celli = cellsToRefine[i];
3079 
3080  allCellInfo[celli].originLevel() = sizeof(label)*8-2;
3081  allCellInfo[celli].origin() = cc[celli];
3082  }
3083 
3084  // 2. Extend to 2:1. I don't understand yet why this is not done
3085  // 2. Extend to 2:1. For non-cube cells the scalar distance does not work
3086  // so make sure it at least provides 2:1.
3087  bitSet refineCell(mesh_.nCells());
3088  forAll(allCellInfo, celli)
3089  {
3090  label wanted = allCellInfo[celli].wantedLevel(cc[celli]);
3091 
3092  if (wanted > cellLevel_[celli]+1)
3093  {
3094  refineCell.set(celli);
3095  }
3096  }
3097  faceConsistentRefinement(true, cellLevel_, refineCell);
3098 
3099  while (true)
3100  {
3101  label nChanged = faceConsistentRefinement(true, cellLevel_, refineCell);
3102 
3103  reduce(nChanged, sumOp<label>());
3104 
3105  if (debug)
3106  {
3107  Pout<< "hexRef8::consistentSlowRefinement2 : Changed " << nChanged
3108  << " refinement levels due to 2:1 conflicts."
3109  << endl;
3110  }
3111 
3112  if (nChanged == 0)
3113  {
3114  break;
3115  }
3116  }
3117 
3118  // 3. Convert back to labelList.
3119  labelList newCellsToRefine(refineCell.toc());
3120 
3121  if (debug)
3122  {
3123  Pout<< "hexRef8::consistentSlowRefinement2 : From "
3124  << cellsToRefine.size() << " to " << newCellsToRefine.size()
3125  << " cells to refine." << endl;
3126 
3127  // Check that newCellsToRefine obeys at least 2:1.
3128 
3129  {
3130  cellSet cellsIn(mesh_, "cellsToRefineIn", cellsToRefine);
3131  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3132  << cellsIn.size() << " to cellSet "
3133  << cellsIn.objectPath() << endl;
3134  cellsIn.write();
3135  }
3136  {
3137  cellSet cellsOut(mesh_, "cellsToRefineOut", newCellsToRefine);
3138  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3139  << cellsOut.size() << " to cellSet "
3140  << cellsOut.objectPath() << endl;
3141  cellsOut.write();
3142  }
3143 
3144  // Extend to 2:1
3145  bitSet refineCell(mesh_.nCells(), newCellsToRefine);
3146 
3147  const bitSet savedRefineCell(refineCell);
3148  label nChanged = faceConsistentRefinement(true, cellLevel_, refineCell);
3149 
3150  {
3151  cellSet cellsOut2
3152  (
3153  mesh_, "cellsToRefineOut2", newCellsToRefine.size()
3154  );
3155  forAll(refineCell, celli)
3156  {
3157  if (refineCell.test(celli))
3158  {
3159  cellsOut2.insert(celli);
3160  }
3161  }
3162  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3163  << cellsOut2.size() << " to cellSet "
3164  << cellsOut2.objectPath() << endl;
3165  cellsOut2.write();
3166  }
3167 
3168  if (nChanged > 0)
3169  {
3170  forAll(refineCell, celli)
3171  {
3172  if (refineCell.test(celli) && !savedRefineCell.test(celli))
3173  {
3174  dumpCell(celli);
3176  << "Cell:" << celli << " cc:"
3177  << mesh_.cellCentres()[celli]
3178  << " was not marked for refinement but does not obey"
3179  << " 2:1 constraints."
3180  << abort(FatalError);
3181  }
3182  }
3183  }
3184  }
3185 
3186  return newCellsToRefine;
3187 }
3188 
3189 
3190 // Top level driver to insert topo changes to do all refinement.
3193  const labelList& cellLabels,
3194  polyTopoChange& meshMod
3195 )
3196 {
3197  if (debug)
3198  {
3199  Pout<< "hexRef8::setRefinement :"
3200  << " Checking initial mesh just to make sure" << endl;
3201 
3202  checkMesh();
3203  // Cannot call checkRefinementlevels since hanging points might
3204  // get triggered by the mesher after subsetting.
3205  //checkRefinementLevels(-1, labelList(0));
3206  }
3207 
3208  // Clear any saved point/cell data.
3209  savedPointLevel_.clear();
3210  savedCellLevel_.clear();
3211 
3212 
3213  // New point/cell level. Copy of pointLevel for existing points.
3214  DynamicList<label> newCellLevel(cellLevel_.size());
3215  forAll(cellLevel_, celli)
3216  {
3217  newCellLevel.append(cellLevel_[celli]);
3218  }
3219  DynamicList<label> newPointLevel(pointLevel_.size());
3220  forAll(pointLevel_, pointi)
3221  {
3222  newPointLevel.append(pointLevel_[pointi]);
3223  }
3224 
3225 
3226  if (debug)
3227  {
3228  Pout<< "hexRef8::setRefinement :"
3229  << " Allocating " << cellLabels.size() << " cell midpoints."
3230  << endl;
3231  }
3232 
3233 
3234  // Mid point per refined cell.
3235  // -1 : not refined
3236  // >=0: label of mid point.
3237  labelList cellMidPoint(mesh_.nCells(), -1);
3238 
3239  forAll(cellLabels, i)
3240  {
3241  label celli = cellLabels[i];
3242 
3243  label anchorPointi = mesh_.faces()[mesh_.cells()[celli][0]][0];
3244 
3245  cellMidPoint[celli] = meshMod.setAction
3246  (
3247  polyAddPoint
3248  (
3249  mesh_.cellCentres()[celli], // point
3250  anchorPointi, // master point
3251  -1, // zone for point
3252  true // supports a cell
3253  )
3254  );
3255 
3256  newPointLevel(cellMidPoint[celli]) = cellLevel_[celli]+1;
3257  }
3258 
3259 
3260  if (debug)
3261  {
3262  cellSet splitCells(mesh_, "splitCells", cellLabels.size());
3263 
3264  forAll(cellMidPoint, celli)
3265  {
3266  if (cellMidPoint[celli] >= 0)
3267  {
3268  splitCells.insert(celli);
3269  }
3270  }
3271 
3272  Pout<< "hexRef8::setRefinement : Dumping " << splitCells.size()
3273  << " cells to split to cellSet " << splitCells.objectPath()
3274  << endl;
3275 
3276  splitCells.write();
3277  }
3278 
3279 
3280 
3281  // Split edges
3282  // ~~~~~~~~~~~
3283 
3284  if (debug)
3285  {
3286  Pout<< "hexRef8::setRefinement :"
3287  << " Allocating edge midpoints."
3288  << endl;
3289  }
3290 
3291  // Unrefined edges are ones between cellLevel or lower points.
3292  // If any cell using this edge gets split then the edge needs to be split.
3293 
3294  // -1 : no need to split edge
3295  // >=0 : label of introduced mid point
3296  labelList edgeMidPoint(mesh_.nEdges(), -1);
3297 
3298  // Note: Loop over cells to be refined or edges?
3299  forAll(cellMidPoint, celli)
3300  {
3301  if (cellMidPoint[celli] >= 0)
3302  {
3303  const labelList& cEdges = mesh_.cellEdges(celli);
3304 
3305  forAll(cEdges, i)
3306  {
3307  label edgeI = cEdges[i];
3308 
3309  const edge& e = mesh_.edges()[edgeI];
3310 
3311  if
3312  (
3313  pointLevel_[e[0]] <= cellLevel_[celli]
3314  && pointLevel_[e[1]] <= cellLevel_[celli]
3315  )
3316  {
3317  edgeMidPoint[edgeI] = 12345; // mark need for splitting
3318  }
3319  }
3320  }
3321  }
3322 
3323  // Synchronize edgeMidPoint across coupled patches. Take max so that
3324  // any split takes precedence.
3326  (
3327  mesh_,
3328  edgeMidPoint,
3329  maxEqOp<label>(),
3330  labelMin
3331  );
3332 
3333 
3334  // Introduce edge points
3335  // ~~~~~~~~~~~~~~~~~~~~~
3336 
3337  {
3338  // Phase 1: calculate midpoints and sync.
3339  // This needs doing for if people do not write binary and we slowly
3340  // get differences.
3341 
3342  pointField edgeMids(mesh_.nEdges(), point(-GREAT, -GREAT, -GREAT));
3343 
3344  forAll(edgeMidPoint, edgeI)
3345  {
3346  if (edgeMidPoint[edgeI] >= 0)
3347  {
3348  // Edge marked to be split.
3349  edgeMids[edgeI] = mesh_.edges()[edgeI].centre(mesh_.points());
3350  }
3351  }
3353  (
3354  mesh_,
3355  edgeMids,
3356  maxEqOp<vector>(),
3357  point(-GREAT, -GREAT, -GREAT)
3358  );
3359 
3360 
3361  // Phase 2: introduce points at the synced locations.
3362  forAll(edgeMidPoint, edgeI)
3363  {
3364  if (edgeMidPoint[edgeI] >= 0)
3365  {
3366  // Edge marked to be split. Replace edgeMidPoint with actual
3367  // point label.
3368 
3369  const edge& e = mesh_.edges()[edgeI];
3370 
3371  edgeMidPoint[edgeI] = meshMod.setAction
3372  (
3373  polyAddPoint
3374  (
3375  edgeMids[edgeI], // point
3376  e[0], // master point
3377  -1, // zone for point
3378  true // supports a cell
3379  )
3380  );
3381 
3382  newPointLevel(edgeMidPoint[edgeI]) =
3383  max
3384  (
3385  pointLevel_[e[0]],
3386  pointLevel_[e[1]]
3387  )
3388  + 1;
3389  }
3390  }
3391  }
3392 
3393  if (debug)
3394  {
3395  OFstream str(mesh_.time().path()/"edgeMidPoint.obj");
3396 
3397  forAll(edgeMidPoint, edgeI)
3398  {
3399  if (edgeMidPoint[edgeI] >= 0)
3400  {
3401  const edge& e = mesh_.edges()[edgeI];
3402 
3403  meshTools::writeOBJ(str, e.centre(mesh_.points()));
3404  }
3405  }
3406 
3407  Pout<< "hexRef8::setRefinement :"
3408  << " Dumping edge centres to split to file " << str.name() << endl;
3409  }
3410 
3411 
3412  // Calculate face level
3413  // ~~~~~~~~~~~~~~~~~~~~
3414  // (after splitting)
3415 
3416  if (debug)
3417  {
3418  Pout<< "hexRef8::setRefinement :"
3419  << " Allocating face midpoints."
3420  << endl;
3421  }
3422 
3423  // Face anchor level. There are guaranteed 4 points with level
3424  // <= anchorLevel. These are the corner points.
3425  labelList faceAnchorLevel(mesh_.nFaces());
3426 
3427  for (label facei = 0; facei < mesh_.nFaces(); facei++)
3428  {
3429  faceAnchorLevel[facei] = faceLevel(facei);
3430  }
3431 
3432  // -1 : no need to split face
3433  // >=0 : label of introduced mid point
3434  labelList faceMidPoint(mesh_.nFaces(), -1);
3435 
3436 
3437  // Internal faces: look at cells on both sides. Uniquely determined since
3438  // face itself guaranteed to be same level as most refined neighbour.
3439  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
3440  {
3441  if (faceAnchorLevel[facei] >= 0)
3442  {
3443  label own = mesh_.faceOwner()[facei];
3444  label ownLevel = cellLevel_[own];
3445  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3446 
3447  label nei = mesh_.faceNeighbour()[facei];
3448  label neiLevel = cellLevel_[nei];
3449  label newNeiLevel = neiLevel + (cellMidPoint[nei] >= 0 ? 1 : 0);
3450 
3451  if
3452  (
3453  newOwnLevel > faceAnchorLevel[facei]
3454  || newNeiLevel > faceAnchorLevel[facei]
3455  )
3456  {
3457  faceMidPoint[facei] = 12345; // mark to be split
3458  }
3459  }
3460  }
3461 
3462  // Coupled patches handled like internal faces except now all information
3463  // from neighbour comes from across processor.
3464  // Boundary faces are more complicated since the boundary face can
3465  // be more refined than its owner (or neighbour for coupled patches)
3466  // (does not happen if refining/unrefining only, but does e.g. when
3467  // refinining and subsetting)
3468 
3469  {
3470  labelList newNeiLevel(mesh_.nBoundaryFaces());
3471 
3472  forAll(newNeiLevel, i)
3473  {
3474  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
3475  label ownLevel = cellLevel_[own];
3476  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3477 
3478  newNeiLevel[i] = newOwnLevel;
3479  }
3480 
3481  // Swap.
3482  syncTools::swapBoundaryFaceList(mesh_, newNeiLevel);
3483 
3484  // So now we have information on the neighbour.
3485 
3486  forAll(newNeiLevel, i)
3487  {
3488  label facei = i+mesh_.nInternalFaces();
3489 
3490  if (faceAnchorLevel[facei] >= 0)
3491  {
3492  label own = mesh_.faceOwner()[facei];
3493  label ownLevel = cellLevel_[own];
3494  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3495 
3496  if
3497  (
3498  newOwnLevel > faceAnchorLevel[facei]
3499  || newNeiLevel[i] > faceAnchorLevel[facei]
3500  )
3501  {
3502  faceMidPoint[facei] = 12345; // mark to be split
3503  }
3504  }
3505  }
3506  }
3507 
3508 
3509  // Synchronize faceMidPoint across coupled patches. (logical or)
3511  (
3512  mesh_,
3513  faceMidPoint,
3514  maxEqOp<label>()
3515  );
3516 
3517 
3518 
3519  // Introduce face points
3520  // ~~~~~~~~~~~~~~~~~~~~~
3521 
3522  {
3523  // Phase 1: determine mid points and sync. See comment for edgeMids
3524  // above
3525  pointField bFaceMids
3526  (
3527  mesh_.nBoundaryFaces(),
3528  point(-GREAT, -GREAT, -GREAT)
3529  );
3530 
3531  forAll(bFaceMids, i)
3532  {
3533  label facei = i+mesh_.nInternalFaces();
3534 
3535  if (faceMidPoint[facei] >= 0)
3536  {
3537  bFaceMids[i] = mesh_.faceCentres()[facei];
3538  }
3539  }
3541  (
3542  mesh_,
3543  bFaceMids,
3544  maxEqOp<vector>()
3545  );
3546 
3547  forAll(faceMidPoint, facei)
3548  {
3549  if (faceMidPoint[facei] >= 0)
3550  {
3551  // Face marked to be split. Replace faceMidPoint with actual
3552  // point label.
3553 
3554  const face& f = mesh_.faces()[facei];
3555 
3556  faceMidPoint[facei] = meshMod.setAction
3557  (
3558  polyAddPoint
3559  (
3560  (
3561  facei < mesh_.nInternalFaces()
3562  ? mesh_.faceCentres()[facei]
3563  : bFaceMids[facei-mesh_.nInternalFaces()]
3564  ), // point
3565  f[0], // master point
3566  -1, // zone for point
3567  true // supports a cell
3568  )
3569  );
3570 
3571  // Determine the level of the corner points and midpoint will
3572  // be one higher.
3573  newPointLevel(faceMidPoint[facei]) = faceAnchorLevel[facei]+1;
3574  }
3575  }
3576  }
3577 
3578  if (debug)
3579  {
3580  faceSet splitFaces(mesh_, "splitFaces", cellLabels.size());
3581 
3582  forAll(faceMidPoint, facei)
3583  {
3584  if (faceMidPoint[facei] >= 0)
3585  {
3586  splitFaces.insert(facei);
3587  }
3588  }
3589 
3590  Pout<< "hexRef8::setRefinement : Dumping " << splitFaces.size()
3591  << " faces to split to faceSet " << splitFaces.objectPath() << endl;
3592 
3593  splitFaces.write();
3594  }
3595 
3596 
3597  // Information complete
3598  // ~~~~~~~~~~~~~~~~~~~~
3599  // At this point we have all the information we need. We should no
3600  // longer reference the cellLabels to refine. All the information is:
3601  // - cellMidPoint >= 0 : cell needs to be split
3602  // - faceMidPoint >= 0 : face needs to be split
3603  // - edgeMidPoint >= 0 : edge needs to be split
3604 
3605 
3606 
3607  // Get the corner/anchor points
3608  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3609 
3610  if (debug)
3611  {
3612  Pout<< "hexRef8::setRefinement :"
3613  << " Finding cell anchorPoints (8 per cell)"
3614  << endl;
3615  }
3616 
3617  // There will always be 8 points on the hex that have were introduced
3618  // with the hex and will have the same or lower refinement level.
3619 
3620  // Per cell the 8 corner points.
3621  labelListList cellAnchorPoints(mesh_.nCells());
3622 
3623  {
3624  labelList nAnchorPoints(mesh_.nCells(), Zero);
3625 
3626  forAll(cellMidPoint, celli)
3627  {
3628  if (cellMidPoint[celli] >= 0)
3629  {
3630  cellAnchorPoints[celli].setSize(8);
3631  }
3632  }
3633 
3634  forAll(pointLevel_, pointi)
3635  {
3636  const labelList& pCells = mesh_.pointCells(pointi);
3637 
3638  forAll(pCells, pCelli)
3639  {
3640  label celli = pCells[pCelli];
3641 
3642  if
3643  (
3644  cellMidPoint[celli] >= 0
3645  && pointLevel_[pointi] <= cellLevel_[celli]
3646  )
3647  {
3648  if (nAnchorPoints[celli] == 8)
3649  {
3650  dumpCell(celli);
3652  << "cell " << celli
3653  << " of level " << cellLevel_[celli]
3654  << " uses more than 8 points of equal or"
3655  << " lower level" << nl
3656  << "Points so far:" << cellAnchorPoints[celli]
3657  << abort(FatalError);
3658  }
3659 
3660  cellAnchorPoints[celli][nAnchorPoints[celli]++] = pointi;
3661  }
3662  }
3663  }
3664 
3665  forAll(cellMidPoint, celli)
3666  {
3667  if (cellMidPoint[celli] >= 0)
3668  {
3669  if (nAnchorPoints[celli] != 8)
3670  {
3671  dumpCell(celli);
3672 
3673  const labelList& cPoints = mesh_.cellPoints(celli);
3674 
3676  << "cell " << celli
3677  << " of level " << cellLevel_[celli]
3678  << " does not seem to have 8 points of equal or"
3679  << " lower level" << endl
3680  << "cellPoints:" << cPoints << endl
3681  << "pointLevels:"
3682  << labelUIndList(pointLevel_, cPoints) << endl
3683  << abort(FatalError);
3684  }
3685  }
3686  }
3687  }
3688 
3689 
3690  // Add the cells
3691  // ~~~~~~~~~~~~~
3692 
3693  if (debug)
3694  {
3695  Pout<< "hexRef8::setRefinement :"
3696  << " Adding cells (1 per anchorPoint)"
3697  << endl;
3698  }
3699 
3700  // Per cell the 7 added cells (+ original cell)
3701  labelListList cellAddedCells(mesh_.nCells());
3702 
3703  forAll(cellAnchorPoints, celli)
3704  {
3705  const labelList& cAnchors = cellAnchorPoints[celli];
3706 
3707  if (cAnchors.size() == 8)
3708  {
3709  labelList& cAdded = cellAddedCells[celli];
3710  cAdded.setSize(8);
3711 
3712  // Original cell at 0
3713  cAdded[0] = celli;
3714 
3715  // Update cell level
3716  newCellLevel[celli] = cellLevel_[celli]+1;
3717 
3718 
3719  for (label i = 1; i < 8; i++)
3720  {
3721  cAdded[i] = meshMod.setAction
3722  (
3723  polyAddCell
3724  (
3725  -1, // master point
3726  -1, // master edge
3727  -1, // master face
3728  celli, // master cell
3729  mesh_.cellZones().whichZone(celli) // zone for cell
3730  )
3731  );
3732 
3733  newCellLevel(cAdded[i]) = cellLevel_[celli]+1;
3734  }
3735  }
3736  }
3737 
3738 
3739  // Faces
3740  // ~~~~~
3741  // 1. existing faces that get split (into four always)
3742  // 2. existing faces that do not get split but only edges get split
3743  // 3. existing faces that do not get split but get new owner/neighbour
3744  // 4. new internal faces inside split cells.
3745 
3746  if (debug)
3747  {
3748  Pout<< "hexRef8::setRefinement :"
3749  << " Marking faces to be handled"
3750  << endl;
3751  }
3752 
3753  // Get all affected faces.
3754  bitSet affectedFace(mesh_.nFaces());
3755 
3756  {
3757  forAll(cellMidPoint, celli)
3758  {
3759  if (cellMidPoint[celli] >= 0)
3760  {
3761  const cell& cFaces = mesh_.cells()[celli];
3762 
3763  affectedFace.set(cFaces);
3764  }
3765  }
3766 
3767  forAll(faceMidPoint, facei)
3768  {
3769  if (faceMidPoint[facei] >= 0)
3770  {
3771  affectedFace.set(facei);
3772  }
3773  }
3774 
3775  forAll(edgeMidPoint, edgeI)
3776  {
3777  if (edgeMidPoint[edgeI] >= 0)
3778  {
3779  const labelList& eFaces = mesh_.edgeFaces(edgeI);
3780 
3781  affectedFace.set(eFaces);
3782  }
3783  }
3784  }
3785 
3786 
3787  // 1. Faces that get split
3788  // ~~~~~~~~~~~~~~~~~~~~~~~
3789 
3790  if (debug)
3791  {
3792  Pout<< "hexRef8::setRefinement : Splitting faces" << endl;
3793  }
3794 
3795  forAll(faceMidPoint, facei)
3796  {
3797  if (faceMidPoint[facei] >= 0 && affectedFace.test(facei))
3798  {
3799  // Face needs to be split and hasn't yet been done in some way
3800  // (affectedFace - is impossible since this is first change but
3801  // just for completeness)
3802 
3803  const face& f = mesh_.faces()[facei];
3804 
3805  // Has original facei been used (three faces added, original gets
3806  // modified)
3807  bool modifiedFace = false;
3808 
3809  label anchorLevel = faceAnchorLevel[facei];
3810 
3811  face newFace(4);
3812 
3813  forAll(f, fp)
3814  {
3815  label pointi = f[fp];
3816 
3817  if (pointLevel_[pointi] <= anchorLevel)
3818  {
3819  // point is anchor. Start collecting face.
3820 
3821  DynamicList<label> faceVerts(4);
3822 
3823  faceVerts.append(pointi);
3824 
3825  // Walk forward to mid point.
3826  // - if next is +2 midpoint is +1
3827  // - if next is +1 it is midpoint
3828  // - if next is +0 there has to be edgeMidPoint
3829 
3830  walkFaceToMid
3831  (
3832  edgeMidPoint,
3833  anchorLevel,
3834  facei,
3835  fp,
3836  faceVerts
3837  );
3838 
3839  faceVerts.append(faceMidPoint[facei]);
3840 
3841  walkFaceFromMid
3842  (
3843  edgeMidPoint,
3844  anchorLevel,
3845  facei,
3846  fp,
3847  faceVerts
3848  );
3849 
3850  // Convert dynamiclist to face.
3851  newFace.transfer(faceVerts);
3852 
3853  //Pout<< "Split face:" << facei << " verts:" << f
3854  // << " into quad:" << newFace << endl;
3855 
3856  // Get new owner/neighbour
3857  label own, nei;
3858  getFaceNeighbours
3859  (
3860  cellAnchorPoints,
3861  cellAddedCells,
3862  facei,
3863  pointi, // Anchor point
3864 
3865  own,
3866  nei
3867  );
3868 
3869 
3870  if (debug)
3871  {
3872  if (mesh_.isInternalFace(facei))
3873  {
3874  label oldOwn = mesh_.faceOwner()[facei];
3875  label oldNei = mesh_.faceNeighbour()[facei];
3876 
3877  checkInternalOrientation
3878  (
3879  meshMod,
3880  oldOwn,
3881  facei,
3882  mesh_.cellCentres()[oldOwn],
3883  mesh_.cellCentres()[oldNei],
3884  newFace
3885  );
3886  }
3887  else
3888  {
3889  label oldOwn = mesh_.faceOwner()[facei];
3890 
3891  checkBoundaryOrientation
3892  (
3893  meshMod,
3894  oldOwn,
3895  facei,
3896  mesh_.cellCentres()[oldOwn],
3897  mesh_.faceCentres()[facei],
3898  newFace
3899  );
3900  }
3901  }
3902 
3903 
3904  if (!modifiedFace)
3905  {
3906  modifiedFace = true;
3907 
3908  modFace(meshMod, facei, newFace, own, nei);
3909  }
3910  else
3911  {
3912  addFace(meshMod, facei, newFace, own, nei);
3913  }
3914  }
3915  }
3916 
3917  // Mark face as having been handled
3918  affectedFace.unset(facei);
3919  }
3920  }
3921 
3922 
3923  // 2. faces that do not get split but use edges that get split
3924  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3925 
3926  if (debug)
3927  {
3928  Pout<< "hexRef8::setRefinement :"
3929  << " Adding edge splits to unsplit faces"
3930  << endl;
3931  }
3932 
3933  DynamicList<label> eFacesStorage;
3934  DynamicList<label> fEdgesStorage;
3935 
3936  forAll(edgeMidPoint, edgeI)
3937  {
3938  if (edgeMidPoint[edgeI] >= 0)
3939  {
3940  // Split edge. Check that face not already handled above.
3941 
3942  const labelList& eFaces = mesh_.edgeFaces(edgeI, eFacesStorage);
3943 
3944  forAll(eFaces, i)
3945  {
3946  label facei = eFaces[i];
3947 
3948  if (faceMidPoint[facei] < 0 && affectedFace.test(facei))
3949  {
3950  // Unsplit face. Add edge splits to face.
3951 
3952  const face& f = mesh_.faces()[facei];
3953  const labelList& fEdges = mesh_.faceEdges
3954  (
3955  facei,
3956  fEdgesStorage
3957  );
3958 
3959  DynamicList<label> newFaceVerts(f.size());
3960 
3961  forAll(f, fp)
3962  {
3963  newFaceVerts.append(f[fp]);
3964 
3965  label edgeI = fEdges[fp];
3966 
3967  if (edgeMidPoint[edgeI] >= 0)
3968  {
3969  newFaceVerts.append(edgeMidPoint[edgeI]);
3970  }
3971  }
3972 
3973  face newFace;
3974  newFace.transfer(newFaceVerts);
3975 
3976  // The point with the lowest level should be an anchor
3977  // point of the neighbouring cells.
3978  label anchorFp = findMinLevel(f);
3979 
3980  label own, nei;
3981  getFaceNeighbours
3982  (
3983  cellAnchorPoints,
3984  cellAddedCells,
3985  facei,
3986  f[anchorFp], // Anchor point
3987 
3988  own,
3989  nei
3990  );
3991 
3992 
3993  if (debug)
3994  {
3995  if (mesh_.isInternalFace(facei))
3996  {
3997  label oldOwn = mesh_.faceOwner()[facei];
3998  label oldNei = mesh_.faceNeighbour()[facei];
3999 
4000  checkInternalOrientation
4001  (
4002  meshMod,
4003  oldOwn,
4004  facei,
4005  mesh_.cellCentres()[oldOwn],
4006  mesh_.cellCentres()[oldNei],
4007  newFace
4008  );
4009  }
4010  else
4011  {
4012  label oldOwn = mesh_.faceOwner()[facei];
4013 
4014  checkBoundaryOrientation
4015  (
4016  meshMod,
4017  oldOwn,
4018  facei,
4019  mesh_.cellCentres()[oldOwn],
4020  mesh_.faceCentres()[facei],
4021  newFace
4022  );
4023  }
4024  }
4025 
4026  modFace(meshMod, facei, newFace, own, nei);
4027 
4028  // Mark face as having been handled
4029  affectedFace.unset(facei);
4030  }
4031  }
4032  }
4033  }
4034 
4035 
4036  // 3. faces that do not get split but whose owner/neighbour change
4037  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4038 
4039  if (debug)
4040  {
4041  Pout<< "hexRef8::setRefinement :"
4042  << " Changing owner/neighbour for otherwise unaffected faces"
4043  << endl;
4044  }
4045 
4046  forAll(affectedFace, facei)
4047  {
4048  if (affectedFace.test(facei))
4049  {
4050  const face& f = mesh_.faces()[facei];
4051 
4052  // The point with the lowest level should be an anchor
4053  // point of the neighbouring cells.
4054  label anchorFp = findMinLevel(f);
4055 
4056  label own, nei;
4057  getFaceNeighbours
4058  (
4059  cellAnchorPoints,
4060  cellAddedCells,
4061  facei,
4062  f[anchorFp], // Anchor point
4063 
4064  own,
4065  nei
4066  );
4067 
4068  modFace(meshMod, facei, f, own, nei);
4069 
4070  // Mark face as having been handled
4071  affectedFace.unset(facei);
4072  }
4073  }
4074 
4075 
4076  // 4. new internal faces inside split cells.
4077  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4078 
4079 
4080  // This is the hard one. We have to find the splitting points between
4081  // the anchor points. But the edges between the anchor points might have
4082  // been split (into two,three or four edges).
4083 
4084  if (debug)
4085  {
4086  Pout<< "hexRef8::setRefinement :"
4087  << " Create new internal faces for split cells"
4088  << endl;
4089  }
4090 
4091  forAll(cellMidPoint, celli)
4092  {
4093  if (cellMidPoint[celli] >= 0)
4094  {
4095  createInternalFaces
4096  (
4097  cellAnchorPoints,
4098  cellAddedCells,
4099  cellMidPoint,
4100  faceMidPoint,
4101  faceAnchorLevel,
4102  edgeMidPoint,
4103  celli,
4104  meshMod
4105  );
4106  }
4107  }
4108 
4109  // Extend pointLevels and cellLevels for the new cells. Could also be done
4110  // in updateMesh but saves passing cellAddedCells out of this routine.
4111 
4112  // Check
4113  if (debug)
4114  {
4115  label minPointi = labelMax;
4116  label maxPointi = labelMin;
4117 
4118  forAll(cellMidPoint, celli)
4119  {
4120  if (cellMidPoint[celli] >= 0)
4121  {
4122  minPointi = min(minPointi, cellMidPoint[celli]);
4123  maxPointi = max(maxPointi, cellMidPoint[celli]);
4124  }
4125  }
4126  forAll(faceMidPoint, facei)
4127  {
4128  if (faceMidPoint[facei] >= 0)
4129  {
4130  minPointi = min(minPointi, faceMidPoint[facei]);
4131  maxPointi = max(maxPointi, faceMidPoint[facei]);
4132  }
4133  }
4134  forAll(edgeMidPoint, edgeI)
4135  {
4136  if (edgeMidPoint[edgeI] >= 0)
4137  {
4138  minPointi = min(minPointi, edgeMidPoint[edgeI]);
4139  maxPointi = max(maxPointi, edgeMidPoint[edgeI]);
4140  }
4141  }
4142 
4143  if (minPointi != labelMax && minPointi != mesh_.nPoints())
4144  {
4146  << "Added point labels not consecutive to existing mesh points."
4147  << nl
4148  << "mesh_.nPoints():" << mesh_.nPoints()
4149  << " minPointi:" << minPointi
4150  << " maxPointi:" << maxPointi
4151  << abort(FatalError);
4152  }
4153  }
4154 
4155  pointLevel_.transfer(newPointLevel);
4156  cellLevel_.transfer(newCellLevel);
4157 
4158  // Mark files as changed
4159  setInstance(mesh_.facesInstance());
4160 
4161 
4162  // Update the live split cells tree.
4163  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4164 
4165  // New unrefinement structure
4166  if (history_.active())
4167  {
4168  if (debug)
4169  {
4170  Pout<< "hexRef8::setRefinement :"
4171  << " Updating refinement history to " << cellLevel_.size()
4172  << " cells" << endl;
4173  }
4174 
4175  // Extend refinement history for new cells
4176  history_.resize(cellLevel_.size());
4177 
4178  forAll(cellAddedCells, celli)
4179  {
4180  const labelList& addedCells = cellAddedCells[celli];
4181 
4182  if (addedCells.size())
4183  {
4184  // Cell was split.
4185  history_.storeSplit(celli, addedCells);
4186  }
4187  }
4188  }
4189 
4190  // Compact cellAddedCells.
4191 
4192  labelListList refinedCells(cellLabels.size());
4193 
4194  forAll(cellLabels, i)
4195  {
4196  label celli = cellLabels[i];
4197 
4198  refinedCells[i].transfer(cellAddedCells[celli]);
4199  }
4200 
4201  return refinedCells;
4202 }
4203 
4204 
4207  const labelList& pointsToStore,
4208  const labelList& facesToStore,
4209  const labelList& cellsToStore
4210 )
4211 {
4212  savedPointLevel_.clear();
4213  savedPointLevel_.resize(2*pointsToStore.size());
4214  forAll(pointsToStore, i)
4215  {
4216  label pointi = pointsToStore[i];
4217  savedPointLevel_.insert(pointi, pointLevel_[pointi]);
4218  }
4219 
4220  savedCellLevel_.clear();
4221  savedCellLevel_.resize(2*cellsToStore.size());
4222  forAll(cellsToStore, i)
4223  {
4224  label celli = cellsToStore[i];
4225  savedCellLevel_.insert(celli, cellLevel_[celli]);
4226  }
4227 }
4228 
4229 
4230 // Gets called after the mesh change. setRefinement will already have made
4231 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4232 // only need to account for reordering.
4234 {
4235  Map<label> dummyMap(0);
4236 
4237  updateMesh(map, dummyMap, dummyMap, dummyMap);
4238 }
4239 
4240 
4241 // Gets called after the mesh change. setRefinement will already have made
4242 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4243 // only need to account for reordering.
4246  const mapPolyMesh& map,
4247  const Map<label>& pointsToRestore,
4248  const Map<label>& facesToRestore,
4249  const Map<label>& cellsToRestore
4250 )
4251 {
4252  // Update celllevel
4253  if (debug)
4254  {
4255  Pout<< "hexRef8::updateMesh :"
4256  << " Updating various lists"
4257  << endl;
4258  }
4259 
4260  {
4261  const labelList& reverseCellMap = map.reverseCellMap();
4262 
4263  if (debug)
4264  {
4265  Pout<< "hexRef8::updateMesh :"
4266  << " reverseCellMap:" << map.reverseCellMap().size()
4267  << " cellMap:" << map.cellMap().size()
4268  << " nCells:" << mesh_.nCells()
4269  << " nOldCells:" << map.nOldCells()
4270  << " cellLevel_:" << cellLevel_.size()
4271  << " reversePointMap:" << map.reversePointMap().size()
4272  << " pointMap:" << map.pointMap().size()
4273  << " nPoints:" << mesh_.nPoints()
4274  << " nOldPoints:" << map.nOldPoints()
4275  << " pointLevel_:" << pointLevel_.size()
4276  << endl;
4277  }
4278 
4279  if (reverseCellMap.size() == cellLevel_.size())
4280  {
4281  // Assume it is after hexRef8 that this routine is called.
4282  // Just account for reordering. We cannot use cellMap since
4283  // then cells created from cells would get cellLevel_ of
4284  // cell they were created from.
4285  reorder(reverseCellMap, mesh_.nCells(), -1, cellLevel_);
4286  }
4287  else
4288  {
4289  // Map data
4290  const labelList& cellMap = map.cellMap();
4291 
4292  labelList newCellLevel(cellMap.size());
4293  forAll(cellMap, newCelli)
4294  {
4295  label oldCelli = cellMap[newCelli];
4296 
4297  if (oldCelli == -1)
4298  {
4299  newCellLevel[newCelli] = -1;
4300  }
4301  else
4302  {
4303  newCellLevel[newCelli] = cellLevel_[oldCelli];
4304  }
4305  }
4306  cellLevel_.transfer(newCellLevel);
4307  }
4308 
4309  // See if any cells to restore. This will be for some new cells
4310  // the corresponding old cell.
4311  forAllConstIters(cellsToRestore, iter)
4312  {
4313  const label newCelli = iter.key();
4314  const label storedCelli = iter.val();
4315 
4316  const auto fnd = savedCellLevel_.cfind(storedCelli);
4317 
4318  if (!fnd.found())
4319  {
4321  << "Problem : trying to restore old value for new cell "
4322  << newCelli << " but cannot find old cell " << storedCelli
4323  << " in map of stored values " << savedCellLevel_
4324  << abort(FatalError);
4325  }
4326  cellLevel_[newCelli] = fnd.val();
4327  }
4328 
4329  //if (cellLevel_.found(-1))
4330  //{
4331  // WarningInFunction
4332  // << "Problem : "
4333  // << "cellLevel_ contains illegal value -1 after mapping
4334  // << " at cell " << cellLevel_.find(-1) << endl
4335  // << "This means that another program has inflated cells"
4336  // << " (created cells out-of-nothing) and hence we don't know"
4337  // << " their cell level. Continuing with illegal value."
4338  // << abort(FatalError);
4339  //}
4340  }
4341 
4342 
4343  // Update pointlevel
4344  {
4345  const labelList& reversePointMap = map.reversePointMap();
4346 
4347  if (reversePointMap.size() == pointLevel_.size())
4348  {
4349  // Assume it is after hexRef8 that this routine is called.
4350  reorder(reversePointMap, mesh_.nPoints(), -1, pointLevel_);
4351  }
4352  else
4353  {
4354  // Map data
4355  const labelList& pointMap = map.pointMap();
4356 
4357  labelList newPointLevel(pointMap.size());
4358 
4359  forAll(pointMap, newPointi)
4360  {
4361  const label oldPointi = pointMap[newPointi];
4362 
4363  if (oldPointi == -1)
4364  {
4365  //FatalErrorInFunction
4366  // << "Problem : point " << newPointi
4367  // << " at " << mesh_.points()[newPointi]
4368  // << " does not originate from another point"
4369  // << " (i.e. is inflated)." << nl
4370  // << "Hence we cannot determine the new pointLevel"
4371  // << " for it." << abort(FatalError);
4372  newPointLevel[newPointi] = -1;
4373  }
4374  else
4375  {
4376  newPointLevel[newPointi] = pointLevel_[oldPointi];
4377  }
4378  }
4379  pointLevel_.transfer(newPointLevel);
4380  }
4381 
4382  // See if any points to restore. This will be for some new points
4383  // the corresponding old point (the one from the call to storeData)
4384  forAllConstIters(pointsToRestore, iter)
4385  {
4386  const label newPointi = iter.key();
4387  const label storedPointi = iter.val();
4388 
4389  auto fnd = savedPointLevel_.find(storedPointi);
4390 
4391  if (!fnd.found())
4392  {
4394  << "Problem : trying to restore old value for new point "
4395  << newPointi << " but cannot find old point "
4396  << storedPointi
4397  << " in map of stored values " << savedPointLevel_
4398  << abort(FatalError);
4399  }
4400  pointLevel_[newPointi] = fnd.val();
4401  }
4402 
4403  //if (pointLevel_.found(-1))
4404  //{
4405  // WarningInFunction
4406  // << "Problem : "
4407  // << "pointLevel_ contains illegal value -1 after mapping"
4408  // << " at point" << pointLevel_.find(-1) << endl
4409  // << "This means that another program has inflated points"
4410  // << " (created points out-of-nothing) and hence we don't know"
4411  // << " their point level. Continuing with illegal value."
4412  // //<< abort(FatalError);
4413  //}
4414  }
4415 
4416  // Update refinement tree
4417  if (history_.active())
4418  {
4419  history_.updateMesh(map);
4420  }
4421 
4422  // Mark files as changed
4423  setInstance(mesh_.facesInstance());
4424 
4425  // Update face removal engine
4426  faceRemover_.updateMesh(map);
4427 
4428  // Clear cell shapes
4429  cellShapesPtr_.clear();
4430 }
4431 
4432 
4433 // Gets called after mesh subsetting. Maps are from new back to old.
4436  const labelList& pointMap,
4437  const labelList& faceMap,
4438  const labelList& cellMap
4439 )
4440 {
4441  // Update celllevel
4442  if (debug)
4443  {
4444  Pout<< "hexRef8::subset :"
4445  << " Updating various lists"
4446  << endl;
4447  }
4448 
4449  if (history_.active())
4450  {
4452  << "Subsetting will not work in combination with unrefinement."
4453  << nl
4454  << "Proceed at your own risk." << endl;
4455  }
4456 
4457 
4458  // Update celllevel
4459  {
4460  labelList newCellLevel(cellMap.size());
4461 
4462  forAll(cellMap, newCelli)
4463  {
4464  newCellLevel[newCelli] = cellLevel_[cellMap[newCelli]];
4465  }
4466 
4467  cellLevel_.transfer(newCellLevel);
4468 
4469  if (cellLevel_.found(-1))
4470  {
4472  << "Problem : "
4473  << "cellLevel_ contains illegal value -1 after mapping:"
4474  << cellLevel_
4475  << abort(FatalError);
4476  }
4477  }
4478 
4479  // Update pointlevel
4480  {
4481  labelList newPointLevel(pointMap.size());
4482 
4483  forAll(pointMap, newPointi)
4484  {
4485  newPointLevel[newPointi] = pointLevel_[pointMap[newPointi]];
4486  }
4487 
4488  pointLevel_.transfer(newPointLevel);
4489 
4490  if (pointLevel_.found(-1))
4491  {
4493  << "Problem : "
4494  << "pointLevel_ contains illegal value -1 after mapping:"
4495  << pointLevel_
4496  << abort(FatalError);
4497  }
4498  }
4499 
4500  // Update refinement tree
4501  if (history_.active())
4502  {
4503  history_.subset(pointMap, faceMap, cellMap);
4504  }
4505 
4506  // Mark files as changed
4507  setInstance(mesh_.facesInstance());
4508 
4509  // Nothing needs doing to faceRemover.
4510  //faceRemover_.subset(pointMap, faceMap, cellMap);
4511 
4512  // Clear cell shapes
4513  cellShapesPtr_.clear();
4514 }
4515 
4516 
4517 // Gets called after the mesh distribution
4519 {
4520  if (debug)
4521  {
4522  Pout<< "hexRef8::distribute :"
4523  << " Updating various lists"
4524  << endl;
4525  }
4526 
4527  // Update celllevel
4528  map.distributeCellData(cellLevel_);
4529  // Update pointlevel
4530  map.distributePointData(pointLevel_);
4531 
4532  // Update refinement tree
4533  if (history_.active())
4534  {
4535  history_.distribute(map);
4536  }
4537 
4538  // Update face removal engine
4539  faceRemover_.distribute(map);
4540 
4541  // Clear cell shapes
4542  cellShapesPtr_.clear();
4543 }
4544 
4545 
4547 {
4548  const scalar smallDim = 1e-6 * mesh_.bounds().mag();
4549 
4550  if (debug)
4551  {
4552  Pout<< "hexRef8::checkMesh : Using matching tolerance smallDim:"
4553  << smallDim << endl;
4554  }
4555 
4556  // Check owner on coupled faces.
4557  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4558 
4559  // There should be only one coupled face between two cells. Why? Since
4560  // otherwise mesh redistribution might cause multiple faces between two
4561  // cells
4562  {
4563  labelList nei(mesh_.nBoundaryFaces());
4564  forAll(nei, i)
4565  {
4566  nei[i] = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4567  }
4568 
4569  // Replace data on coupled patches with their neighbour ones.
4570  syncTools::swapBoundaryFaceList(mesh_, nei);
4571 
4572  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4573 
4574  forAll(patches, patchi)
4575  {
4576  const polyPatch& pp = patches[patchi];
4577 
4578  if (pp.coupled())
4579  {
4580  // Check how many faces between owner and neighbour.
4581  // Should be only one.
4582  labelPairLookup cellToFace(2*pp.size());
4583 
4584  label facei = pp.start();
4585 
4586  forAll(pp, i)
4587  {
4588  label own = mesh_.faceOwner()[facei];
4589  label bFacei = facei-mesh_.nInternalFaces();
4590 
4591  if (!cellToFace.insert(labelPair(own, nei[bFacei]), facei))
4592  {
4593  dumpCell(own);
4595  << "Faces do not seem to be correct across coupled"
4596  << " boundaries" << endl
4597  << "Coupled face " << facei
4598  << " between owner " << own
4599  << " on patch " << pp.name()
4600  << " and coupled neighbour " << nei[bFacei]
4601  << " has two faces connected to it:"
4602  << facei << " and "
4603  << cellToFace[labelPair(own, nei[bFacei])]
4604  << abort(FatalError);
4605  }
4606 
4607  facei++;
4608  }
4609  }
4610  }
4611  }
4612 
4613  // Check face areas.
4614  // ~~~~~~~~~~~~~~~~~
4615 
4616  {
4617  scalarField neiFaceAreas(mesh_.nBoundaryFaces());
4618  forAll(neiFaceAreas, i)
4619  {
4620  neiFaceAreas[i] = mag(mesh_.faceAreas()[i+mesh_.nInternalFaces()]);
4621  }
4622 
4623  // Replace data on coupled patches with their neighbour ones.
4624  syncTools::swapBoundaryFaceList(mesh_, neiFaceAreas);
4625 
4626  forAll(neiFaceAreas, i)
4627  {
4628  label facei = i+mesh_.nInternalFaces();
4629 
4630  const scalar magArea = mag(mesh_.faceAreas()[facei]);
4631 
4632  if (mag(magArea - neiFaceAreas[i]) > smallDim)
4633  {
4634  const face& f = mesh_.faces()[facei];
4635  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4636 
4637  dumpCell(mesh_.faceOwner()[facei]);
4638 
4640  << "Faces do not seem to be correct across coupled"
4641  << " boundaries" << endl
4642  << "Coupled face " << facei
4643  << " on patch " << patchi
4644  << " " << mesh_.boundaryMesh()[patchi].name()
4645  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4646  << " has face area:" << magArea
4647  << " (coupled) neighbour face area differs:"
4648  << neiFaceAreas[i]
4649  << " to within tolerance " << smallDim
4650  << abort(FatalError);
4651  }
4652  }
4653  }
4654 
4655 
4656  // Check number of points on faces.
4657  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4658  {
4659  labelList nVerts(mesh_.nBoundaryFaces());
4660 
4661  forAll(nVerts, i)
4662  {
4663  nVerts[i] = mesh_.faces()[i+mesh_.nInternalFaces()].size();
4664  }
4665 
4666  // Replace data on coupled patches with their neighbour ones.
4667  syncTools::swapBoundaryFaceList(mesh_, nVerts);
4668 
4669  forAll(nVerts, i)
4670  {
4671  label facei = i+mesh_.nInternalFaces();
4672 
4673  const face& f = mesh_.faces()[facei];
4674 
4675  if (f.size() != nVerts[i])
4676  {
4677  dumpCell(mesh_.faceOwner()[facei]);
4678 
4679  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4680 
4682  << "Faces do not seem to be correct across coupled"
4683  << " boundaries" << endl
4684  << "Coupled face " << facei
4685  << " on patch " << patchi
4686  << " " << mesh_.boundaryMesh()[patchi].name()
4687  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4688  << " has size:" << f.size()
4689  << " (coupled) neighbour face has size:"
4690  << nVerts[i]
4691  << abort(FatalError);
4692  }
4693  }
4694  }
4695 
4696 
4697  // Check points of face
4698  // ~~~~~~~~~~~~~~~~~~~~
4699  {
4700  // Anchor points.
4701  pointField anchorPoints(mesh_.nBoundaryFaces());
4702 
4703  forAll(anchorPoints, i)
4704  {
4705  label facei = i+mesh_.nInternalFaces();
4706  const point& fc = mesh_.faceCentres()[facei];
4707  const face& f = mesh_.faces()[facei];
4708  const vector anchorVec(mesh_.points()[f[0]] - fc);
4709 
4710  anchorPoints[i] = anchorVec;
4711  }
4712 
4713  // Replace data on coupled patches with their neighbour ones. Apply
4714  // rotation transformation (but not separation since is relative vector
4715  // to point on same face.
4716  syncTools::swapBoundaryFaceList(mesh_, anchorPoints);
4717 
4718  forAll(anchorPoints, i)
4719  {
4720  label facei = i+mesh_.nInternalFaces();
4721  const point& fc = mesh_.faceCentres()[facei];
4722  const face& f = mesh_.faces()[facei];
4723  const vector anchorVec(mesh_.points()[f[0]] - fc);
4724 
4725  if (mag(anchorVec - anchorPoints[i]) > smallDim)
4726  {
4727  dumpCell(mesh_.faceOwner()[facei]);
4728 
4729  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4730 
4732  << "Faces do not seem to be correct across coupled"
4733  << " boundaries" << endl
4734  << "Coupled face " << facei
4735  << " on patch " << patchi
4736  << " " << mesh_.boundaryMesh()[patchi].name()
4737  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4738  << " has anchor vector:" << anchorVec
4739  << " (coupled) neighbour face anchor vector differs:"
4740  << anchorPoints[i]
4741  << " to within tolerance " << smallDim
4742  << abort(FatalError);
4743  }
4744  }
4745  }
4746 
4747  if (debug)
4748  {
4749  Pout<< "hexRef8::checkMesh : Returning" << endl;
4750  }
4751 }
4752 
4753 
4756  const label maxPointDiff,
4757  const labelList& pointsToCheck
4758 ) const
4759 {
4760  if (debug)
4761  {
4762  Pout<< "hexRef8::checkRefinementLevels :"
4763  << " Checking 2:1 refinement level" << endl;
4764  }
4765 
4766  if
4767  (
4768  cellLevel_.size() != mesh_.nCells()
4769  || pointLevel_.size() != mesh_.nPoints()
4770  )
4771  {
4773  << "cellLevel size should be number of cells"
4774  << " and pointLevel size should be number of points."<< nl
4775  << "cellLevel:" << cellLevel_.size()
4776  << " mesh.nCells():" << mesh_.nCells() << nl
4777  << "pointLevel:" << pointLevel_.size()
4778  << " mesh.nPoints():" << mesh_.nPoints()
4779  << abort(FatalError);
4780  }
4781 
4782 
4783  // Check 2:1 consistency.
4784  // ~~~~~~~~~~~~~~~~~~~~~~
4785 
4786  {
4787  // Internal faces.
4788  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
4789  {
4790  label own = mesh_.faceOwner()[facei];
4791  label nei = mesh_.faceNeighbour()[facei];
4792 
4793  if (mag(cellLevel_[own] - cellLevel_[nei]) > 1)
4794  {
4795  dumpCell(own);
4796  dumpCell(nei);
4797 
4799  << "Celllevel does not satisfy 2:1 constraint." << nl
4800  << "On face " << facei << " owner cell " << own
4801  << " has refinement " << cellLevel_[own]
4802  << " neighbour cell " << nei << " has refinement "
4803  << cellLevel_[nei]
4804  << abort(FatalError);
4805  }
4806  }
4807 
4808  // Coupled faces. Get neighbouring value
4809  labelList neiLevel(mesh_.nBoundaryFaces());
4810 
4811  forAll(neiLevel, i)
4812  {
4813  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4814 
4815  neiLevel[i] = cellLevel_[own];
4816  }
4817 
4818  // No separation
4819  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
4820 
4821  forAll(neiLevel, i)
4822  {
4823  label facei = i+mesh_.nInternalFaces();
4824 
4825  label own = mesh_.faceOwner()[facei];
4826 
4827  if (mag(cellLevel_[own] - neiLevel[i]) > 1)
4828  {
4829  dumpCell(own);
4830 
4831  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4832 
4834  << "Celllevel does not satisfy 2:1 constraint."
4835  << " On coupled face " << facei
4836  << " on patch " << patchi << " "
4837  << mesh_.boundaryMesh()[patchi].name()
4838  << " owner cell " << own << " has refinement "
4839  << cellLevel_[own]
4840  << " (coupled) neighbour cell has refinement "
4841  << neiLevel[i]
4842  << abort(FatalError);
4843  }
4844  }
4845  }
4846 
4847 
4848  // Check pointLevel is synchronized
4849  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4850  {
4851  labelList syncPointLevel(pointLevel_);
4852 
4853  // Get min level
4855  (
4856  mesh_,
4857  syncPointLevel,
4858  minEqOp<label>(),
4859  labelMax
4860  );
4861 
4862 
4863  forAll(syncPointLevel, pointi)
4864  {
4865  if (pointLevel_[pointi] != syncPointLevel[pointi])
4866  {
4868  << "PointLevel is not consistent across coupled patches."
4869  << endl
4870  << "point:" << pointi << " coord:" << mesh_.points()[pointi]
4871  << " has level " << pointLevel_[pointi]
4872  << " whereas the coupled point has level "
4873  << syncPointLevel[pointi]
4874  << abort(FatalError);
4875  }
4876  }
4877  }
4878 
4879 
4880  // Check 2:1 across points (instead of faces)
4881  if (maxPointDiff != -1)
4882  {
4883  // Determine per point the max cell level.
4884  labelList maxPointLevel(mesh_.nPoints(), Zero);
4885 
4886  forAll(maxPointLevel, pointi)
4887  {
4888  const labelList& pCells = mesh_.pointCells(pointi);
4889 
4890  label& pLevel = maxPointLevel[pointi];
4891 
4892  forAll(pCells, i)
4893  {
4894  pLevel = max(pLevel, cellLevel_[pCells[i]]);
4895  }
4896  }
4897 
4898  // Sync maxPointLevel to neighbour
4900  (
4901  mesh_,
4902  maxPointLevel,
4903  maxEqOp<label>(),
4904  labelMin // null value
4905  );
4906 
4907  // Check 2:1 across boundary points
4908  forAll(pointsToCheck, i)
4909  {
4910  label pointi = pointsToCheck[i];
4911 
4912  const labelList& pCells = mesh_.pointCells(pointi);
4913 
4914  forAll(pCells, i)
4915  {
4916  label celli = pCells[i];
4917 
4918  if
4919  (
4920  mag(cellLevel_[celli]-maxPointLevel[pointi])
4921  > maxPointDiff
4922  )
4923  {
4924  dumpCell(celli);
4925 
4927  << "Too big a difference between"
4928  << " point-connected cells." << nl
4929  << "cell:" << celli
4930  << " cellLevel:" << cellLevel_[celli]
4931  << " uses point:" << pointi
4932  << " coord:" << mesh_.points()[pointi]
4933  << " which is also used by a cell with level:"
4934  << maxPointLevel[pointi]
4935  << abort(FatalError);
4936  }
4937  }
4938  }
4939  }
4940 
4941 
4942  //- Gives problems after first splitting off inside mesher.
4944  //{
4945  // // Any patches with points having only two edges.
4946  //
4947  // boolList isHangingPoint(mesh_.nPoints(), false);
4948  //
4949  // const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4950  //
4951  // forAll(patches, patchi)
4952  // {
4953  // const polyPatch& pp = patches[patchi];
4954  //
4955  // const labelList& meshPoints = pp.meshPoints();
4956  //
4957  // forAll(meshPoints, i)
4958  // {
4959  // label pointi = meshPoints[i];
4960  //
4961  // const labelList& pEdges = mesh_.pointEdges()[pointi];
4962  //
4963  // if (pEdges.size() == 2)
4964  // {
4965  // isHangingPoint[pointi] = true;
4966  // }
4967  // }
4968  // }
4969  //
4970  // syncTools::syncPointList
4971  // (
4972  // mesh_,
4973  // isHangingPoint,
4974  // andEqOp<bool>(), // only if all decide it is hanging point
4975  // true, // null
4976  // false // no separation
4977  // );
4978  //
4979  // //OFstream str(mesh_.time().path()/"hangingPoints.obj");
4980  //
4981  // label nHanging = 0;
4982  //
4983  // forAll(isHangingPoint, pointi)
4984  // {
4985  // if (isHangingPoint[pointi])
4986  // {
4987  // nHanging++;
4988  //
4989  // Pout<< "Hanging boundary point " << pointi
4990  // << " at " << mesh_.points()[pointi]
4991  // << endl;
4992  // //meshTools::writeOBJ(str, mesh_.points()[pointi]);
4993  // }
4994  // }
4995  //
4996  // if (returnReduce(nHanging, sumOp<label>()) > 0)
4997  // {
4998  // FatalErrorInFunction
4999  // << "Detected a point used by two edges only (hanging point)"
5000  // << nl << "This is not allowed"
5001  // << abort(FatalError);
5002  // }
5003  //}
5004 }
5005 
5006 
5008 {
5009  if (!cellShapesPtr_)
5010  {
5011  if (debug)
5012  {
5013  Pout<< "hexRef8::cellShapes() : calculating splitHex cellShapes."
5014  << " cellLevel:" << cellLevel_.size()
5015  << " pointLevel:" << pointLevel_.size()
5016  << endl;
5017  }
5018 
5019  const cellShapeList& meshShapes = mesh_.cellShapes();
5020  cellShapesPtr_.reset(new cellShapeList(meshShapes));
5021 
5022  label nSplitHex = 0;
5023  label nUnrecognised = 0;
5024 
5025  forAll(cellLevel_, celli)
5026  {
5027  if (meshShapes[celli].model().index() == 0)
5028  {
5029  label level = cellLevel_[celli];
5030 
5031  // Return true if we've found 6 quads
5032  DynamicList<face> quads;
5033  bool haveQuads = matchHexShape
5034  (
5035  celli,
5036  level,
5037  quads
5038  );
5039 
5040  if (haveQuads)
5041  {
5042  faceList faces(std::move(quads));
5043  cellShapesPtr_()[celli] = degenerateMatcher::match(faces);
5044  nSplitHex++;
5045  }
5046  else
5047  {
5048  nUnrecognised++;
5049  }
5050  }
5051  }
5052  if (debug)
5053  {
5054  Pout<< "hexRef8::cellShapes() :"
5055  << " nCells:" << mesh_.nCells() << " of which" << nl
5056  << " primitive:" << (mesh_.nCells()-nSplitHex-nUnrecognised)
5057  << nl
5058  << " split-hex:" << nSplitHex << nl
5059  << " poly :" << nUnrecognised << nl
5060  << endl;
5061  }
5062  }
5063  return *cellShapesPtr_;
5064 }
5065 
5066 
5068 {
5069  if (debug)
5070  {
5071  checkRefinementLevels(-1, labelList(0));
5072  }
5073 
5074  if (debug)
5075  {
5076  Pout<< "hexRef8::getSplitPoints :"
5077  << " Calculating unrefineable points" << endl;
5078  }
5079 
5080 
5081  if (!history_.active())
5082  {
5084  << "Only call if constructed with history capability"
5085  << abort(FatalError);
5086  }
5087 
5088  // Master cell
5089  // -1 undetermined
5090  // -2 certainly not split point
5091  // >= label of master cell
5092  labelList splitMaster(mesh_.nPoints(), -1);
5093  labelList splitMasterLevel(mesh_.nPoints(), Zero);
5094 
5095  // Unmark all with not 8 cells
5096  //const labelListList& pointCells = mesh_.pointCells();
5097 
5098  for (label pointi = 0; pointi < mesh_.nPoints(); pointi++)
5099  {
5100  const labelList& pCells = mesh_.pointCells(pointi);
5101 
5102  if (pCells.size() != 8)
5103  {
5104  splitMaster[pointi] = -2;
5105  }
5106  }
5107 
5108  // Unmark all with different master cells
5109  const labelList& visibleCells = history_.visibleCells();
5110 
5111  forAll(visibleCells, celli)
5112  {
5113  const labelList& cPoints = mesh_.cellPoints(celli);
5114 
5115  if (visibleCells[celli] != -1 && history_.parentIndex(celli) >= 0)
5116  {
5117  label parentIndex = history_.parentIndex(celli);
5118 
5119  // Check same master.
5120  forAll(cPoints, i)
5121  {
5122  label pointi = cPoints[i];
5123 
5124  label masterCelli = splitMaster[pointi];
5125 
5126  if (masterCelli == -1)
5127  {
5128  // First time visit of point. Store parent cell and
5129  // level of the parent cell (with respect to celli). This
5130  // is additional guarantee that we're referring to the
5131  // same master at the same refinement level.
5132 
5133  splitMaster[pointi] = parentIndex;
5134  splitMasterLevel[pointi] = cellLevel_[celli] - 1;
5135  }
5136  else if (masterCelli == -2)
5137  {
5138  // Already decided that point is not splitPoint
5139  }
5140  else if
5141  (
5142  (masterCelli != parentIndex)
5143  || (splitMasterLevel[pointi] != cellLevel_[celli] - 1)
5144  )
5145  {
5146  // Different masters so point is on two refinement
5147  // patterns
5148  splitMaster[pointi] = -2;
5149  }
5150  }
5151  }
5152  else
5153  {
5154  // Either not visible or is unrefined cell
5155  forAll(cPoints, i)
5156  {
5157  label pointi = cPoints[i];
5158 
5159  splitMaster[pointi] = -2;
5160  }
5161  }
5162  }
5163 
5164  // Unmark boundary faces
5165  for
5166  (
5167  label facei = mesh_.nInternalFaces();
5168  facei < mesh_.nFaces();
5169  facei++
5170  )
5171  {
5172  const face& f = mesh_.faces()[facei];
5173 
5174  forAll(f, fp)
5175  {
5176  splitMaster[f[fp]] = -2;
5177  }
5178  }
5179 
5180 
5181  // Collect into labelList
5182 
5183  label nSplitPoints = 0;
5184 
5185  forAll(splitMaster, pointi)
5186  {
5187  if (splitMaster[pointi] >= 0)
5188  {
5189  nSplitPoints++;
5190  }
5191  }
5192 
5193  labelList splitPoints(nSplitPoints);
5194  nSplitPoints = 0;
5195 
5196  forAll(splitMaster, pointi)
5197  {
5198  if (splitMaster[pointi] >= 0)
5199  {
5200  splitPoints[nSplitPoints++] = pointi;
5201  }
5202  }
5203 
5204  return splitPoints;
5205 }
5206 
5207 
5208 //void Foam::hexRef8::markIndex
5209 //(
5210 // const label maxLevel,
5211 // const label level,
5212 // const label index,
5213 // const label markValue,
5214 // labelList& indexValues
5215 //) const
5216 //{
5217 // if (level < maxLevel && indexValues[index] == -1)
5218 // {
5219 // // Mark
5220 // indexValues[index] = markValue;
5221 //
5222 // // Mark parent
5223 // const splitCell8& split = history_.splitCells()[index];
5224 //
5225 // if (split.parent_ >= 0)
5226 // {
5227 // markIndex
5228 // (
5229 // maxLevel, level+1, split.parent_, markValue, indexValues);
5230 // )
5231 // }
5232 // }
5233 //}
5234 //
5235 //
5240 //void Foam::hexRef8::markCellClusters
5241 //(
5242 // const label maxLevel,
5243 // labelList& cluster
5244 //) const
5245 //{
5246 // cluster.setSize(mesh_.nCells());
5247 // cluster = -1;
5248 //
5249 // const DynamicList<splitCell8>& splitCells = history_.splitCells();
5250 //
5251 // // Mark all splitCells down to level maxLevel with a cell originating from
5252 // // it.
5253 //
5254 // labelList indexLevel(splitCells.size(), -1);
5255 //
5256 // forAll(visibleCells, celli)
5257 // {
5258 // label index = visibleCells[celli];
5259 //
5260 // if (index >= 0)
5261 // {
5262 // markIndex(maxLevel, 0, index, celli, indexLevel);
5263 // }
5264 // }
5265 //
5266 // // Mark cells with splitCell
5267 //}
5268 
5269 
5272  const labelList& pointsToUnrefine,
5273  const bool maxSet
5274 ) const
5275 {
5276  if (debug)
5277  {
5278  Pout<< "hexRef8::consistentUnrefinement :"
5279  << " Determining 2:1 consistent unrefinement" << endl;
5280  }
5281 
5282  if (maxSet)
5283  {
5285  << "maxSet not implemented yet."
5286  << abort(FatalError);
5287  }
5288 
5289  // Loop, modifying pointsToUnrefine, until no more changes to due to 2:1
5290  // conflicts.
5291  // maxSet = false : unselect points to refine
5292  // maxSet = true: select points to refine
5293 
5294  // Maintain bitset for pointsToUnrefine and cellsToUnrefine
5295  bitSet unrefinePoint(mesh_.nPoints(), pointsToUnrefine);
5296 
5297  while (true)
5298  {
5299  // Construct cells to unrefine
5300  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5301 
5302  bitSet unrefineCell(mesh_.nCells());
5303 
5304  forAll(unrefinePoint, pointi)
5305  {
5306  if (unrefinePoint.test(pointi))
5307  {
5308  const labelList& pCells = mesh_.pointCells(pointi);
5309 
5310  unrefineCell.set(pCells);
5311  }
5312  }
5313 
5314 
5315  label nChanged = 0;
5316 
5317 
5318  // Check 2:1 consistency taking refinement into account
5319  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5320 
5321  // Internal faces.
5322  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
5323  {
5324  label own = mesh_.faceOwner()[facei];
5325  label nei = mesh_.faceNeighbour()[facei];
5326 
5327  label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5328  label neiLevel = cellLevel_[nei] - unrefineCell.get(nei);
5329 
5330  if (ownLevel < (neiLevel-1))
5331  {
5332  // Since was 2:1 this can only occur if own is marked for
5333  // unrefinement.
5334 
5335  if (maxSet)
5336  {
5337  unrefineCell.set(nei);
5338  }
5339  else
5340  {
5341  // could also combine with unset:
5342  // if (!unrefineCell.unset(own))
5343  // {
5344  // FatalErrorInFunction
5345  // << "problem cell already unset"
5346  // << abort(FatalError);
5347  // }
5348  if (!unrefineCell.test(own))
5349  {
5351  << "problem" << abort(FatalError);
5352  }
5353 
5354  unrefineCell.unset(own);
5355  }
5356  nChanged++;
5357  }
5358  else if (neiLevel < (ownLevel-1))
5359  {
5360  if (maxSet)
5361  {
5362  unrefineCell.set(own);
5363  }
5364  else
5365  {
5366  if (!unrefineCell.test(nei))
5367  {
5369  << "problem" << abort(FatalError);
5370  }
5371 
5372  unrefineCell.unset(nei);
5373  }
5374  nChanged++;
5375  }
5376  }
5377 
5378 
5379  // Coupled faces. Swap owner level to get neighbouring cell level.
5380  labelList neiLevel(mesh_.nBoundaryFaces());
5381 
5382  forAll(neiLevel, i)
5383  {
5384  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
5385 
5386  neiLevel[i] = cellLevel_[own] - unrefineCell.get(own);
5387  }
5388 
5389  // Swap to neighbour
5390  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
5391 
5392  forAll(neiLevel, i)
5393  {
5394  label facei = i+mesh_.nInternalFaces();
5395  label own = mesh_.faceOwner()[facei];
5396  label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5397 
5398  if (ownLevel < (neiLevel[i]-1))
5399  {
5400  if (!maxSet)
5401  {
5402  if (!unrefineCell.test(own))
5403  {
5405  << "problem" << abort(FatalError);
5406  }
5407 
5408  unrefineCell.unset(own);
5409  nChanged++;
5410  }
5411  }
5412  else if (neiLevel[i] < (ownLevel-1))
5413  {
5414  if (maxSet)
5415  {
5416  if (unrefineCell.test(own))
5417  {
5419  << "problem" << abort(FatalError);
5420  }
5421 
5422  unrefineCell.set(own);
5423  nChanged++;
5424  }
5425  }
5426  }
5427 
5428  reduce(nChanged, sumOp<label>());
5429 
5430  if (debug)
5431  {
5432  Pout<< "hexRef8::consistentUnrefinement :"
5433  << " Changed " << nChanged
5434  << " refinement levels due to 2:1 conflicts."
5435  << endl;
5436  }
5437 
5438  if (nChanged == 0)
5439  {
5440  break;
5441  }
5442 
5443 
5444  // Convert cellsToUnrefine back into points to unrefine
5445  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5446 
5447  // Knock out any point whose cell neighbour cannot be unrefined.
5448  forAll(unrefinePoint, pointi)
5449  {
5450  if (unrefinePoint.test(pointi))
5451  {
5452  const labelList& pCells = mesh_.pointCells(pointi);
5453 
5454  forAll(pCells, j)
5455  {
5456  if (!unrefineCell.test(pCells[j]))
5457  {
5458  unrefinePoint.unset(pointi);
5459  break;
5460  }
5461  }
5462  }
5463  }
5464  }
5465 
5466 
5467  // Convert back to labelList.
5468  label nSet = 0;
5469 
5470  forAll(unrefinePoint, pointi)
5471  {
5472  if (unrefinePoint.test(pointi))
5473  {
5474  nSet++;
5475  }
5476  }
5477 
5478  labelList newPointsToUnrefine(nSet);
5479  nSet = 0;
5480 
5481  forAll(unrefinePoint, pointi)
5482  {
5483  if (unrefinePoint.test(pointi))
5484  {
5485  newPointsToUnrefine[nSet++] = pointi;
5486  }
5487  }
5488 
5489  return newPointsToUnrefine;
5490 }
5491 
5492 
5495  const labelList& splitPointLabels,
5496  polyTopoChange& meshMod
5497 )
5498 {
5499  if (!history_.active())
5500  {
5502  << "Only call if constructed with history capability"
5503  << abort(FatalError);
5504  }
5505 
5506  if (debug)
5507  {
5508  Pout<< "hexRef8::setUnrefinement :"
5509  << " Checking initial mesh just to make sure" << endl;
5510 
5511  checkMesh();
5512 
5513  forAll(cellLevel_, celli)
5514  {
5515  if (cellLevel_[celli] < 0)
5516  {
5518  << "Illegal cell level " << cellLevel_[celli]
5519  << " for cell " << celli
5520  << abort(FatalError);
5521  }
5522  }
5523 
5524 
5525  // Write to sets.
5526  pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5527  pSet.write();
5528 
5529  cellSet cSet(mesh_, "splitPointCells", splitPointLabels.size());
5530 
5531  forAll(splitPointLabels, i)
5532  {
5533  const labelList& pCells = mesh_.pointCells(splitPointLabels[i]);
5534 
5535  cSet.insert(pCells);
5536  }
5537  cSet.write();
5538 
5539  Pout<< "hexRef8::setRefinement : Dumping " << pSet.size()
5540  << " points and "
5541  << cSet.size() << " cells for unrefinement to" << nl
5542  << " pointSet " << pSet.objectPath() << nl
5543  << " cellSet " << cSet.objectPath()
5544  << endl;
5545  }
5546 
5547 
5548  labelList cellRegion;
5549  labelList cellRegionMaster;
5550  labelList facesToRemove;
5551 
5552  {
5553  labelHashSet splitFaces(12*splitPointLabels.size());
5554 
5555  forAll(splitPointLabels, i)
5556  {
5557  const labelList& pFaces = mesh_.pointFaces()[splitPointLabels[i]];
5558 
5559  splitFaces.insert(pFaces);
5560  }
5561 
5562  // Check with faceRemover what faces will get removed. Note that this
5563  // can be more (but never less) than splitFaces provided.
5564  faceRemover_.compatibleRemoves
5565  (
5566  splitFaces.toc(), // pierced faces
5567  cellRegion, // per cell -1 or region it is merged into
5568  cellRegionMaster, // per region the master cell
5569  facesToRemove // new faces to be removed.
5570  );
5571 
5572  if (facesToRemove.size() != splitFaces.size())
5573  {
5574  // Dump current mesh
5575  {
5576  const_cast<polyMesh&>(mesh_).setInstance
5577  (
5578  mesh_.time().timeName()
5579  );
5580  mesh_.write();
5581  pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5582  pSet.write();
5583  faceSet fSet(mesh_, "splitFaces", splitFaces);
5584  fSet.write();
5585  faceSet removeSet(mesh_, "facesToRemove", facesToRemove);
5586  removeSet.write();
5587  }
5588 
5590  << "Ininitial set of split points to unrefine does not"
5591  << " seem to be consistent or not mid points of refined cells"
5592  << " splitPoints:" << splitPointLabels.size()
5593  << " splitFaces:" << splitFaces.size()
5594  << " facesToRemove:" << facesToRemove.size()
5595  << abort(FatalError);
5596  }
5597  }
5598 
5599  // Redo the region master so it is consistent with our master.
5600  // This will guarantee that the new cell (for which faceRemover uses
5601  // the region master) is already compatible with our refinement structure.
5602 
5603  forAll(splitPointLabels, i)
5604  {
5605  label pointi = splitPointLabels[i];
5606 
5607  // Get original cell label
5608 
5609  const labelList& pCells = mesh_.pointCells(pointi);
5610 
5611  // Check
5612  if (pCells.size() != 8)
5613  {
5615  << "splitPoint " << pointi
5616  << " should have 8 cells using it. It has " << pCells
5617  << abort(FatalError);
5618  }
5619 
5620 
5621  // Check that the lowest numbered pCells is the master of the region
5622  // (should be guaranteed by directRemoveFaces)
5623  //if (debug)
5624  {
5625  label masterCelli = min(pCells);
5626 
5627  forAll(pCells, j)
5628  {
5629  label celli = pCells[j];
5630 
5631  label region = cellRegion[celli];
5632 
5633  if (region == -1)
5634  {
5636  << "Ininitial set of split points to unrefine does not"
5637  << " seem to be consistent or not mid points"
5638  << " of refined cells" << nl
5639  << "cell:" << celli << " on splitPoint " << pointi
5640  << " has no region to be merged into"
5641  << abort(FatalError);
5642  }
5643 
5644  if (masterCelli != cellRegionMaster[region])
5645  {
5647  << "cell:" << celli << " on splitPoint:" << pointi
5648  << " in region " << region
5649  << " has master:" << cellRegionMaster[region]
5650  << " which is not the lowest numbered cell"
5651  << " among the pointCells:" << pCells
5652  << abort(FatalError);
5653  }
5654  }
5655  }
5656  }
5657 
5658  // Insert all commands to combine cells. Never fails so don't have to
5659  // test for success.
5660  faceRemover_.setRefinement
5661  (
5662  facesToRemove,
5663  cellRegion,
5664  cellRegionMaster,
5665  meshMod
5666  );
5667 
5668  // Remove the 8 cells that originated from merging around the split point
5669  // and adapt cell levels (not that pointLevels stay the same since points
5670  // either get removed or stay at the same position.
5671  forAll(splitPointLabels, i)
5672  {
5673  label pointi = splitPointLabels[i];
5674 
5675  const labelList& pCells = mesh_.pointCells(pointi);
5676 
5677  label masterCelli = min(pCells);
5678 
5679  forAll(pCells, j)
5680  {
5681  cellLevel_[pCells[j]]--;
5682  }
5683 
5684  history_.combineCells(masterCelli, pCells);
5685  }
5686 
5687  // Mark files as changed
5688  setInstance(mesh_.facesInstance());
5689 
5690  // history_.updateMesh will take care of truncating.
5691 }
5692 
5693 
5694 // Write refinement to polyMesh directory.
5695 bool Foam::hexRef8::write(const bool valid) const
5696 {
5697  bool writeOk =
5698  cellLevel_.write(valid)
5699  && pointLevel_.write(valid)
5700  && level0Edge_.write(valid);
5701 
5702  if (history_.active())
5703  {
5704  writeOk = writeOk && history_.write(valid);
5705  }
5706  else
5707  {
5709  }
5710 
5711  return writeOk;
5712 }
5713 
5714 
5716 {
5717  IOobject io
5718  (
5719  "dummy",
5720  mesh.facesInstance(),
5721  mesh.meshSubDir,
5722  mesh
5723  );
5724  fileName setsDir(io.path());
5725 
5726  if (topoSet::debug) DebugVar(setsDir);
5727 
5728  if (exists(setsDir/"cellLevel"))
5729  {
5730  rm(setsDir/"cellLevel");
5731  }
5732  if (exists(setsDir/"pointLevel"))
5733  {
5734  rm(setsDir/"pointLevel");
5735  }
5736  if (exists(setsDir/"level0Edge"))
5737  {
5738  rm(setsDir/"level0Edge");
5739  }
5741 }
5742 
5743 
5744 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::refinementHistory::visibleCells
const labelList & visibleCells() const
Definition: refinementHistory.H:268
Foam::syncTools::syncEdgeList
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
Definition: syncToolsTemplates.C:800
Foam::reverse
void reverse(UList< T > &list, const label n)
Definition: UListI.H:449
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:169
meshTools.H
Foam::exists
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: MSwindows.C:625
Foam::faceMap
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Definition: blockMeshMergeTopological.C:94
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
Foam::refinementData
Transfers refinement levels such that slow transition between levels is maintained....
Definition: refinementData.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
Foam::refinementHistory::read
virtual bool read()
Read object. If global number of visible cells > 0 becomes active.
Definition: refinementHistory.C:1701
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:63
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:52
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::DynamicList< label >
Foam::polyTopoChange::points
const DynamicList< point > & points() const
Points. Shrunk after constructing mesh (or calling of compact())
Definition: polyTopoChange.H:450
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
Foam::IOobject::typeHeaderOk
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (uses typeFilePath to find file) and check its info.
Definition: IOobjectTemplates.C:39
polyAddFace.H
Foam::hexRef8::getSplitPoints
labelList getSplitPoints() const
Return the points at the centre of top-level split cells.
Definition: hexRef8.C:5067
Foam::mapDistributePolyMesh::distributeCellData
void distributeCellData(List< T > &lst) const
Distribute list of cell data.
Definition: mapDistributePolyMesh.H:256
Foam::polyPatch::coupled
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:377
Foam::polyMesh::meshSubDir
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:321
polyTopoChange.H
Foam::cellShapeList
List< cellShape > cellShapeList
List of cellShapes and PtrList of List of cellShape.
Definition: cellShapeList.H:45
Foam::hexRef8::write
bool write(const bool valid=true) const
Force writing refinement+history to polyMesh directory.
Definition: hexRef8.C:5695
Foam::polyTopoChange
Direct mesh changes based on v1.3 polyTopoChange syntax.
Definition: polyTopoChange.H:99
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::refinementHistory::active
bool active() const
Is there unrefinement history?
Definition: refinementHistory.H:286
Foam::polyMesh::facesInstance
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:852
Foam::Map
A HashTable to objects of type <T> with a label key.
Definition: lumpedPointController.H:69
Foam::hexRef8::updateMesh
void updateMesh(const mapPolyMesh &)
Update local numbering for changed mesh.
Definition: hexRef8.C:4233
Foam::syncTools::swapBoundaryFaceList
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:445
Foam::faceSet
A list of face labels.
Definition: faceSet.H:51
Foam::rm
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: MSwindows.C:1004
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::hexRef8::setInstance
void setInstance(const fileName &inst)
Definition: hexRef8.C:1734
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::ifEqEqOp
Reduction class. If x and y are not equal assign value.
Definition: hexRef8.C:59
Foam::hexRef8::removeFiles
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
Definition: hexRef8.C:5715
Foam::FaceCellWave::iterate
virtual label iterate(const label maxIter)
Iterate until no changes or maxIter reached.
Definition: FaceCellWave.C:1227
polyMesh.H
Foam::HashSet< label, Hash< label > >
syncTools.H
Foam::hexRef8::cellShapes
const cellShapeList & cellShapes() const
Utility: get hexes as cell shapes.
Definition: hexRef8.C:5007
Foam::hexRef8::consistentRefinement
labelList consistentRefinement(const labelUList &cellLevel, const labelList &cellsToRefine, const bool maxSet) const
Given valid mesh and current cell level and proposed.
Definition: hexRef8.C:2252
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
Foam::syncTools::syncPointList
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
Definition: syncToolsTemplates.C:721
Foam::sumOp
Definition: ops.H:213
Foam::primitiveMesh::nPoints
label nPoints() const noexcept
Number of mesh points.
Definition: primitiveMeshI.H:37
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::refinementDistanceData
Transfers refinement levels such that slow transition between levels is maintained....
Definition: refinementDistanceData.H:63
Foam::minEqOp
Definition: ops.H:81
OFstream.H
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::refinementHistory
All refinement history. Used in unrefinement.
Definition: refinementHistory.H:102
mapDistributePolyMesh.H
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::syncTools::syncFaceList
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:396
Foam::FaceCellWave::setFaceInfo
void setFaceInfo(const label facei, const Type &faceInfo)
Set single initial changed face.
Definition: FaceCellWave.C:318
Foam::primitiveMesh::nCells
label nCells() const noexcept
Number of mesh cells.
Definition: primitiveMeshI.H:96
Foam::hexRef8::setRefinement
labelListList setRefinement(const labelList &cells, polyTopoChange &)
Insert refinement. All selected cells will be split into 8.
Definition: hexRef8.C:3192
labelPairHashes.H
A HashTable to objects of type <T> with a labelPair key. The hashing is based on labelPair (FixedList...
Foam::hexRef8::checkRefinementLevels
void checkRefinementLevels(const label maxPointDiff, const labelList &pointsToCheck) const
Debug: Check 2:1 consistency across faces.
Definition: hexRef8.C:4755
Foam::meshTools::findEdge
label findEdge(const edgeList &edges, const labelList &candidates, const label v0, const label v1)
Return edge among candidates that uses the two vertices.
Definition: meshTools.C:359
Foam::Field< vector >
Foam::regIOobject::write
virtual bool write(const bool valid=true) const
Write using setting from DB.
Definition: regIOobjectWrite.C:132
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::mapPolyMesh::nOldPoints
label nOldPoints() const
Number of old points.
Definition: mapPolyMesh.H:369
Foam::syncTools::syncEdgePositions
static void syncEdgePositions(const polyMesh &mesh, List< point > &positions, const CombineOp &cop, const point &nullValue)
Synchronize locations on all mesh edges.
Definition: syncTools.H:289
hexRef8.H
degenerateMatcher.H
Foam::OSstream::name
virtual const fileName & name() const
Get the name of the stream.
Definition: OSstream.H:107
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
patchID
label patchID
Definition: boundaryProcessorFaPatchPoints.H:5
faceSet.H
Foam::List::transfer
void transfer(List< T > &list)
Definition: List.C:456
Foam::IOobject::READ_IF_PRESENT
Definition: IOobject.H:187
Foam::reorder
ListType reorder(const labelUList &oldToNew, const ListType &input, const bool prune=false)
Reorder the elements of a list.
Definition: ListOpsTemplates.C:80
Foam::IOstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.C:40
Foam::hexRef8::subset
void subset(const labelList &pointMap, const labelList &faceMap, const labelList &cellMap)
Update local numbering for subsetted mesh.
Definition: hexRef8.C:4435
polyAddPoint.H
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
newPointi
label newPointi
Definition: readKivaGrid.H:496
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::dimensioned< scalar >
zoneID
const labelIOList & zoneID
Definition: interpolatedFaces.H:22
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::ifEqEqOp::operator()
void operator()(label &x, const label y) const
Definition: hexRef8.C:61
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::refinementHistory::removeFiles
static void removeFiles(const polyMesh &)
Helper: remove all sets files from mesh instance.
Definition: refinementHistory.C:1727
Foam::cellSet
A collection of cell labels.
Definition: cellSet.H:51
Foam::polyAddCell
Class containing data for cell addition.
Definition: polyAddCell.H:48
Foam::hexRef8::consistentSlowRefinement2
labelList consistentSlowRefinement2(const label maxFaceDiff, const labelList &cellsToRefine, const labelList &facesToCheck) const
Like consistentSlowRefinement but uses different meshWave.
Definition: hexRef8.C:2792
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:361
Foam::maxEqOp
Definition: ops.H:80
polyModifyFace.H
Foam::hexRef8::storeData
void storeData(const labelList &pointsToStore, const labelList &facesToStore, const labelList &cellsToStore)
Signal points/face/cells for which to store data.
Definition: hexRef8.C:4206
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
Foam::IOobject::readOpt
readOption readOpt() const noexcept
The read option.
Definition: IOobjectI.H:164
refinementData.H
Foam::HashTable< label, labelPair, Foam::Hash< labelPair > >
Foam::Pstream::listCombineGather
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
Definition: combineGatherScatter.C:290
Foam::Perr
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
polyAddCell.H
refinementDistanceData.H
Foam::FaceCellWave
Wave propagation of information through grid. Every iteration information goes through one layer of c...
Definition: FaceCellWave.H:78
Foam::hexRef8::consistentSlowRefinement
labelList consistentSlowRefinement(const label maxFaceDiff, const labelList &cellsToRefine, const labelList &facesToCheck, const label maxPointDiff, const labelList &pointsToCheck) const
Like consistentRefinement but slower:
Definition: hexRef8.C:2308
Time.H
Foam::hexRef8::setUnrefinement
void setUnrefinement(const labelList &splitPointLabels, polyTopoChange &)
Remove some refinement. Needs to be supplied output of.
Definition: hexRef8.C:5494
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::mapPolyMesh::reverseCellMap
const labelList & reverseCellMap() const
Reverse cell map.
Definition: mapPolyMesh.H:532
Foam::cellInfo
Holds information regarding type of cell. Used in inside/outside determination in cellClassification.
Definition: cellInfo.H:64
Foam::refineCell
Container with cells to refine. Refinement given as single direction.
Definition: refineCell.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::polyTopoChange::setAction
label setAction(const topoAction &action)
For compatibility with polyTopoChange: set topological action.
Definition: polyTopoChange.C:2481
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::Pair< label >
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::pointSet
A set of point labels.
Definition: pointSet.H:51
f
labelList f(nPoints)
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::mapPolyMesh::reversePointMap
const labelList & reversePointMap() const
Reverse point map.
Definition: mapPolyMesh.H:469
Foam::Vector< scalar >
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::mapPolyMesh::pointMap
const labelList & pointMap() const
Old point map.
Definition: mapPolyMesh.H:396
Foam::mapPolyMesh::nOldCells
label nOldCells() const
Number of old cells.
Definition: mapPolyMesh.H:387
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
FaceCellWave.H
Foam::UList< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
x
x
Definition: LISASMDCalcMethod2.H:52
Foam::List::set
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:341
Foam::polyAddPoint
Class containing data for point addition.
Definition: polyAddPoint.H:49
Foam::labelMin
constexpr label labelMin
Definition: label.H:60
Foam::mapPolyMesh
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:161
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::hexRef8::distribute
void distribute(const mapDistributePolyMesh &)
Update local numbering for mesh redistribution.
Definition: hexRef8.C:4518
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::primitivePatch
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field.
Definition: primitivePatch.H:51
Foam::findIndices
labelList findIndices(const ListType &input, typename ListType::const_reference val, label start=0)
Linear search to find all occurrences of given element.
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::patchIdentifier::name
const word & name() const noexcept
The patch name.
Definition: patchIdentifier.H:135
cellSet.H
Foam::hexRef8::checkMesh
void checkMesh() const
Debug: Check coupled mesh for correctness.
Definition: hexRef8.C:4546
p0
const volScalarField & p0
Definition: EEqn.H:36
Foam::hexRef8::faceLevel
label faceLevel(const label facei) const
Gets level such that the face has four points <= level.
Definition: hexRef8.C:799
Foam::mapDistributePolyMesh
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
Definition: mapDistributePolyMesh.H:66
Foam::hexRef8::consistentUnrefinement
labelList consistentUnrefinement(const labelList &pointsToUnrefine, const bool maxSet) const
Given proposed.
Definition: hexRef8.C:5271
Foam::Pstream::listCombineScatter
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
Definition: combineGatherScatter.C:432
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::labelUList
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
Foam::IOobject::objectPath
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:214
Foam::IOobject::NO_READ
Definition: IOobject.H:188
Foam::refinementData::updateFace
bool updateFace(const polyMesh &, const label thisFacei, const label neighbourCelli, const refinementData &neighbourInfo, const scalar tol, TrackingData &td)
Influence of neighbouring cell.
Definition: refinementDataI.H:174
Foam::mapDistributePolyMesh::distributePointData
void distributePointData(List< T > &lst) const
Distribute list of point data.
Definition: mapDistributePolyMesh.H:242
DebugVar
#define DebugVar(var)
Report a variable name and value.
Definition: messageStream.H:404
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
Foam::syncTools::syncBoundaryFacePositions
static void syncBoundaryFacePositions(const polyMesh &mesh, UList< point > &positions, const CombineOp &cop)
Synchronize locations on boundary faces only.
Definition: syncTools.H:378
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:592
Foam::mapPolyMesh::cellMap
const labelList & cellMap() const
Old cell map.
Definition: mapPolyMesh.H:435
Foam::refinementData::count
label count() const
Definition: refinementData.H:96
y
scalar y
Definition: LISASMDCalcMethod1.H:14
Foam::labelUIndList
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: UIndirectList.H:58
pointSet.H