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-2020 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  if (!pFaces.found(facei))
1853  {
1854  pFaces.append(facei);
1855  }
1856  }
1857  else
1858  {
1859  pointFaces.insert
1860  (
1861  pointi,
1862  labelList(1, facei)
1863  );
1864  }
1865  }
1866  }
1867  }
1868  }
1869 
1870  // 2. Check if we've collected any midPoints.
1871  forAllConstIters(pointFaces, iter)
1872  {
1873  const labelList& pFaces = iter.val();
1874 
1875  if (pFaces.size() == 4)
1876  {
1877  // Collect and orient.
1878  faceList fourFaces(pFaces.size());
1879  forAll(pFaces, pFacei)
1880  {
1881  label facei = pFaces[pFacei];
1882  const face& f = mesh_.faces()[facei];
1883  if (mesh_.faceOwner()[facei] == celli)
1884  {
1885  fourFaces[pFacei] = f;
1886  }
1887  else
1888  {
1889  fourFaces[pFacei] = f.reverseFace();
1890  }
1891  }
1892 
1893  primitivePatch bigFace
1894  (
1895  SubList<face>(fourFaces, fourFaces.size()),
1896  mesh_.points()
1897  );
1898  const labelListList& edgeLoops = bigFace.edgeLoops();
1899 
1900  if (edgeLoops.size() == 1)
1901  {
1902  // Collect the 4 cellLevel points
1903  verts.clear();
1904  collectLevelPoints
1905  (
1906  bigFace.meshPoints(),
1907  bigFace.edgeLoops()[0],
1908  cellLevel,
1909  verts
1910  );
1911 
1912  if (verts.size() == 4)
1913  {
1914  quads.append(face(0));
1915  labelList& quadVerts = quads.last();
1916  quadVerts.transfer(verts);
1917  }
1918  }
1919  }
1920  }
1921  }
1922 
1923  return (quads.size() == 6);
1924 }
1925 
1926 
1927 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1928 
1929 // Construct from mesh, read refinement data
1930 Foam::hexRef8::hexRef8(const polyMesh& mesh, const bool readHistory)
1931 :
1932  mesh_(mesh),
1933  cellLevel_
1934  (
1935  IOobject
1936  (
1937  "cellLevel",
1938  mesh_.facesInstance(),
1939  polyMesh::meshSubDir,
1940  mesh_,
1941  IOobject::READ_IF_PRESENT,
1942  IOobject::NO_WRITE
1943  ),
1944  labelList(mesh_.nCells(), Zero)
1945  ),
1946  pointLevel_
1947  (
1948  IOobject
1949  (
1950  "pointLevel",
1951  mesh_.facesInstance(),
1952  polyMesh::meshSubDir,
1953  mesh_,
1954  IOobject::READ_IF_PRESENT,
1955  IOobject::NO_WRITE
1956  ),
1957  labelList(mesh_.nPoints(), Zero)
1958  ),
1959  level0Edge_
1960  (
1961  IOobject
1962  (
1963  "level0Edge",
1964  mesh_.facesInstance(),
1965  polyMesh::meshSubDir,
1966  mesh_,
1967  IOobject::READ_IF_PRESENT,
1968  IOobject::NO_WRITE
1969  ),
1970  // Needs name:
1971  dimensionedScalar("level0Edge", dimLength, getLevel0EdgeLength())
1972  ),
1973  history_
1974  (
1975  IOobject
1976  (
1977  "refinementHistory",
1978  mesh_.facesInstance(),
1979  polyMesh::meshSubDir,
1980  mesh_,
1981  IOobject::NO_READ,
1982  IOobject::NO_WRITE
1983  ),
1984  // All cells visible if not read or readHistory = false
1985  (readHistory ? mesh_.nCells() : 0)
1986  ),
1987  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
1988  savedPointLevel_(0),
1989  savedCellLevel_(0)
1990 {
1991  if (readHistory)
1992  {
1993  history_.readOpt() = IOobject::READ_IF_PRESENT;
1994  if (history_.typeHeaderOk<refinementHistory>(true))
1995  {
1996  history_.read();
1997  }
1998  }
1999 
2000  if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
2001  {
2003  << "History enabled but number of visible cells "
2004  << history_.visibleCells().size() << " in "
2005  << history_.objectPath()
2006  << " is not equal to the number of cells in the mesh "
2007  << mesh_.nCells()
2008  << abort(FatalError);
2009  }
2010 
2011  if
2012  (
2013  cellLevel_.size() != mesh_.nCells()
2014  || pointLevel_.size() != mesh_.nPoints()
2015  )
2016  {
2018  << "Restarted from inconsistent cellLevel or pointLevel files."
2019  << endl
2020  << "cellLevel file " << cellLevel_.objectPath() << endl
2021  << "pointLevel file " << pointLevel_.objectPath() << endl
2022  << "Number of cells in mesh:" << mesh_.nCells()
2023  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2024  << "Number of points in mesh:" << mesh_.nPoints()
2025  << " does not equal size of pointLevel:" << pointLevel_.size()
2026  << abort(FatalError);
2027  }
2028 
2029 
2030  // Check refinement levels for consistency
2032 
2033 
2034  // Check initial mesh for consistency
2035 
2036  //if (debug)
2037  {
2038  checkMesh();
2039  }
2040 }
2041 
2042 
2043 Foam::hexRef8::hexRef8
2045  const polyMesh& mesh,
2046  const labelList& cellLevel,
2047  const labelList& pointLevel,
2048  const refinementHistory& history,
2049  const scalar level0Edge
2050 )
2051 :
2052  mesh_(mesh),
2053  cellLevel_
2054  (
2055  IOobject
2056  (
2057  "cellLevel",
2058  mesh_.facesInstance(),
2060  mesh_,
2063  ),
2064  cellLevel
2065  ),
2066  pointLevel_
2067  (
2068  IOobject
2069  (
2070  "pointLevel",
2071  mesh_.facesInstance(),
2073  mesh_,
2076  ),
2077  pointLevel
2078  ),
2079  level0Edge_
2080  (
2081  IOobject
2082  (
2083  "level0Edge",
2084  mesh_.facesInstance(),
2086  mesh_,
2089  ),
2090  // Needs name:
2092  (
2093  "level0Edge",
2094  dimLength,
2095  (level0Edge >= 0 ? level0Edge : getLevel0EdgeLength())
2096  )
2097  ),
2098  history_
2099  (
2100  IOobject
2101  (
2102  "refinementHistory",
2103  mesh_.facesInstance(),
2105  mesh_,
2108  ),
2109  history
2110  ),
2111  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
2112  savedPointLevel_(0),
2113  savedCellLevel_(0)
2114 {
2115  if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
2116  {
2118  << "History enabled but number of visible cells in it "
2119  << history_.visibleCells().size()
2120  << " is not equal to the number of cells in the mesh "
2121  << mesh_.nCells() << abort(FatalError);
2122  }
2123 
2124  if
2125  (
2126  cellLevel_.size() != mesh_.nCells()
2127  || pointLevel_.size() != mesh_.nPoints()
2128  )
2129  {
2131  << "Incorrect cellLevel or pointLevel size." << endl
2132  << "Number of cells in mesh:" << mesh_.nCells()
2133  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2134  << "Number of points in mesh:" << mesh_.nPoints()
2135  << " does not equal size of pointLevel:" << pointLevel_.size()
2136  << abort(FatalError);
2137  }
2138 
2139  // Check refinement levels for consistency
2140  checkRefinementLevels(-1, labelList(0));
2141 
2142 
2143  // Check initial mesh for consistency
2144 
2145  //if (debug)
2146  {
2147  checkMesh();
2148  }
2149 }
2150 
2151 
2152 Foam::hexRef8::hexRef8
2154  const polyMesh& mesh,
2155  const labelList& cellLevel,
2156  const labelList& pointLevel,
2157  const scalar level0Edge
2158 )
2159 :
2160  mesh_(mesh),
2161  cellLevel_
2162  (
2163  IOobject
2164  (
2165  "cellLevel",
2166  mesh_.facesInstance(),
2168  mesh_,
2171  ),
2172  cellLevel
2173  ),
2174  pointLevel_
2175  (
2176  IOobject
2177  (
2178  "pointLevel",
2179  mesh_.facesInstance(),
2181  mesh_,
2184  ),
2185  pointLevel
2186  ),
2187  level0Edge_
2188  (
2189  IOobject
2190  (
2191  "level0Edge",
2192  mesh_.facesInstance(),
2194  mesh_,
2197  ),
2198  // Needs name:
2200  (
2201  "level0Edge",
2202  dimLength,
2203  (level0Edge >= 0 ? level0Edge : getLevel0EdgeLength())
2204  )
2205  ),
2206  history_
2207  (
2208  IOobject
2209  (
2210  "refinementHistory",
2211  mesh_.facesInstance(),
2213  mesh_,
2216  ),
2218  labelList(0),
2219  false
2220  ),
2221  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
2222  savedPointLevel_(0),
2223  savedCellLevel_(0)
2224 {
2225  if
2226  (
2227  cellLevel_.size() != mesh_.nCells()
2228  || pointLevel_.size() != mesh_.nPoints()
2229  )
2230  {
2232  << "Incorrect cellLevel or pointLevel size." << endl
2233  << "Number of cells in mesh:" << mesh_.nCells()
2234  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2235  << "Number of points in mesh:" << mesh_.nPoints()
2236  << " does not equal size of pointLevel:" << pointLevel_.size()
2237  << abort(FatalError);
2238  }
2239 
2240  // Check refinement levels for consistency
2241  checkRefinementLevels(-1, labelList(0));
2242 
2243  // Check initial mesh for consistency
2244 
2245  //if (debug)
2246  {
2247  checkMesh();
2248  }
2249 }
2250 
2251 
2252 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2253 
2256  const labelUList& cellLevel,
2257  const labelList& cellsToRefine,
2258  const bool maxSet
2259 ) const
2260 {
2261  // Loop, modifying cellsToRefine, until no more changes to due to 2:1
2262  // conflicts.
2263  // maxSet = false : unselect cells to refine
2264  // maxSet = true : select cells to refine
2265 
2266  bitSet refineCell(mesh_.nCells(), cellsToRefine);
2267 
2268  while (true)
2269  {
2270  label nChanged = faceConsistentRefinement
2271  (
2272  maxSet,
2273  cellLevel,
2274  refineCell
2275  );
2276 
2277  reduce(nChanged, sumOp<label>());
2278 
2279  if (debug)
2280  {
2281  Pout<< "hexRef8::consistentRefinement : Changed " << nChanged
2282  << " refinement levels due to 2:1 conflicts."
2283  << endl;
2284  }
2285 
2286  if (nChanged == 0)
2287  {
2288  break;
2289  }
2290  }
2291 
2292  // Convert back to labelList.
2293  labelList newCellsToRefine(refineCell.toc());
2294 
2295  if (debug)
2296  {
2297  checkWantedRefinementLevels(cellLevel, newCellsToRefine);
2298  }
2299 
2300  return newCellsToRefine;
2301 }
2302 
2303 
2304 // Given a list of cells to refine determine additional cells to refine
2305 // such that the overall refinement:
2306 // - satisfies maxFaceDiff (e.g. 2:1) across neighbouring faces
2307 // - satisfies maxPointDiff (e.g. 4:1) across selected point connected
2308 // cells. This is used to ensure that e.g. cells on the surface are not
2309 // point connected to cells which are 8 times smaller.
2312  const label maxFaceDiff,
2313  const labelList& cellsToRefine,
2314  const labelList& facesToCheck,
2315  const label maxPointDiff,
2316  const labelList& pointsToCheck
2317 ) const
2318 {
2319  const labelList& faceOwner = mesh_.faceOwner();
2320  const labelList& faceNeighbour = mesh_.faceNeighbour();
2321 
2322 
2323  if (maxFaceDiff <= 0)
2324  {
2326  << "Illegal maxFaceDiff " << maxFaceDiff << nl
2327  << "Value should be >= 1" << exit(FatalError);
2328  }
2329 
2330 
2331  // Bit tricky. Say we want a distance of three cells between two
2332  // consecutive refinement levels. This is done by using FaceCellWave to
2333  // transport out the new refinement level. It gets decremented by one
2334  // every cell it crosses so if we initialize it to maxFaceDiff
2335  // we will get a field everywhere that tells us whether an unselected cell
2336  // needs refining as well.
2337 
2338 
2339  // Initial information about (distance to) cellLevel on all cells
2340  List<refinementData> allCellInfo(mesh_.nCells());
2341 
2342  // Initial information about (distance to) cellLevel on all faces
2343  List<refinementData> allFaceInfo(mesh_.nFaces());
2344 
2345  forAll(allCellInfo, celli)
2346  {
2347  // maxFaceDiff since refinementData counts both
2348  // faces and cells.
2349  allCellInfo[celli] = refinementData
2350  (
2351  maxFaceDiff*(cellLevel_[celli]+1),// when cell is to be refined
2352  maxFaceDiff*cellLevel_[celli] // current level
2353  );
2354  }
2355 
2356  // Cells to be refined will have cellLevel+1
2357  forAll(cellsToRefine, i)
2358  {
2359  label celli = cellsToRefine[i];
2360 
2361  allCellInfo[celli].count() = allCellInfo[celli].refinementCount();
2362  }
2363 
2364 
2365  // Labels of seed faces
2366  DynamicList<label> seedFaces(mesh_.nFaces()/100);
2367  // refinementLevel data on seed faces
2368  DynamicList<refinementData> seedFacesInfo(mesh_.nFaces()/100);
2369 
2370  // Dummy additional info for FaceCellWave
2371  int dummyTrackData = 0;
2372 
2373 
2374  // Additional buffer layer thickness by changing initial count. Usually
2375  // this happens on boundary faces. Bit tricky. Use allFaceInfo to mark
2376  // off thus marked faces so they're skipped in the next loop.
2377  forAll(facesToCheck, i)
2378  {
2379  label facei = facesToCheck[i];
2380 
2381  if (allFaceInfo[facei].valid(dummyTrackData))
2382  {
2383  // Can only occur if face has already gone through loop below.
2385  << "Argument facesToCheck seems to have duplicate entries!"
2386  << endl
2387  << "face:" << facei << " occurs at positions "
2388  << findIndices(facesToCheck, facei)
2389  << abort(FatalError);
2390  }
2391 
2392 
2393  const refinementData& ownData = allCellInfo[faceOwner[facei]];
2394 
2395  if (mesh_.isInternalFace(facei))
2396  {
2397  // Seed face if neighbouring cell (after possible refinement)
2398  // will be refined one more than the current owner or neighbour.
2399 
2400  const refinementData& neiData = allCellInfo[faceNeighbour[facei]];
2401 
2402  label faceCount;
2403  label faceRefineCount;
2404  if (neiData.count() > ownData.count())
2405  {
2406  faceCount = neiData.count() + maxFaceDiff;
2407  faceRefineCount = faceCount + maxFaceDiff;
2408  }
2409  else
2410  {
2411  faceCount = ownData.count() + maxFaceDiff;
2412  faceRefineCount = faceCount + maxFaceDiff;
2413  }
2414 
2415  seedFaces.append(facei);
2416  seedFacesInfo.append
2417  (
2419  (
2420  faceRefineCount,
2421  faceCount
2422  )
2423  );
2424  allFaceInfo[facei] = seedFacesInfo.last();
2425  }
2426  else
2427  {
2428  label faceCount = ownData.count() + maxFaceDiff;
2429  label faceRefineCount = faceCount + maxFaceDiff;
2430 
2431  seedFaces.append(facei);
2432  seedFacesInfo.append
2433  (
2435  (
2436  faceRefineCount,
2437  faceCount
2438  )
2439  );
2440  allFaceInfo[facei] = seedFacesInfo.last();
2441  }
2442  }
2443 
2444 
2445  // Just seed with all faces inbetween different refinement levels for now
2446  // (alternatively only seed faces on cellsToRefine but that gives problems
2447  // if no cells to refine)
2448  forAll(faceNeighbour, facei)
2449  {
2450  // Check if face already handled in loop above
2451  if (!allFaceInfo[facei].valid(dummyTrackData))
2452  {
2453  label own = faceOwner[facei];
2454  label nei = faceNeighbour[facei];
2455 
2456  // Seed face with transported data from highest cell.
2457 
2458  if (allCellInfo[own].count() > allCellInfo[nei].count())
2459  {
2460  allFaceInfo[facei].updateFace
2461  (
2462  mesh_,
2463  facei,
2464  own,
2465  allCellInfo[own],
2467  dummyTrackData
2468  );
2469  seedFaces.append(facei);
2470  seedFacesInfo.append(allFaceInfo[facei]);
2471  }
2472  else if (allCellInfo[own].count() < allCellInfo[nei].count())
2473  {
2474  allFaceInfo[facei].updateFace
2475  (
2476  mesh_,
2477  facei,
2478  nei,
2479  allCellInfo[nei],
2481  dummyTrackData
2482  );
2483  seedFaces.append(facei);
2484  seedFacesInfo.append(allFaceInfo[facei]);
2485  }
2486  }
2487  }
2488 
2489  // Seed all boundary faces with owner value. This is to make sure that
2490  // they are visited (probably only important for coupled faces since
2491  // these need to be visited from both sides)
2492  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
2493  {
2494  // Check if face already handled in loop above
2495  if (!allFaceInfo[facei].valid(dummyTrackData))
2496  {
2497  label own = faceOwner[facei];
2498 
2499  // Seed face with transported data from owner.
2500  refinementData faceData;
2501  faceData.updateFace
2502  (
2503  mesh_,
2504  facei,
2505  own,
2506  allCellInfo[own],
2508  dummyTrackData
2509  );
2510  seedFaces.append(facei);
2511  seedFacesInfo.append(faceData);
2512  }
2513  }
2514 
2515 
2516  // face-cell-face transport engine
2518  (
2519  mesh_,
2520  allFaceInfo,
2521  allCellInfo,
2522  dummyTrackData
2523  );
2524 
2525  while (true)
2526  {
2527  if (debug)
2528  {
2529  Pout<< "hexRef8::consistentSlowRefinement : Seeded "
2530  << seedFaces.size() << " faces between cells with different"
2531  << " refinement level." << endl;
2532  }
2533 
2534  // Set seed faces
2535  levelCalc.setFaceInfo(seedFaces.shrink(), seedFacesInfo.shrink());
2536  seedFaces.clear();
2537  seedFacesInfo.clear();
2538 
2539  // Iterate until no change. Now 2:1 face difference should be satisfied
2540  levelCalc.iterate(mesh_.globalData().nTotalFaces()+1);
2541 
2542 
2543  // Now check point-connected cells (face-connected cells already ok):
2544  // - get per point max of connected cells
2545  // - sync across coupled points
2546  // - check cells against above point max
2547 
2548  if (maxPointDiff == -1)
2549  {
2550  // No need to do any point checking.
2551  break;
2552  }
2553 
2554  // Determine per point the max cell level. (done as count, not
2555  // as cell level purely for ease)
2556  labelList maxPointCount(mesh_.nPoints(), Zero);
2557 
2558  forAll(maxPointCount, pointi)
2559  {
2560  label& pLevel = maxPointCount[pointi];
2561 
2562  const labelList& pCells = mesh_.pointCells(pointi);
2563 
2564  forAll(pCells, i)
2565  {
2566  pLevel = max(pLevel, allCellInfo[pCells[i]].count());
2567  }
2568  }
2569 
2570  // Sync maxPointCount to neighbour
2572  (
2573  mesh_,
2574  maxPointCount,
2575  maxEqOp<label>(),
2576  labelMin // null value
2577  );
2578 
2579  // Update allFaceInfo from maxPointCount for all points to check
2580  // (usually on boundary faces)
2581 
2582  // Per face the new refinement data
2583  Map<refinementData> changedFacesInfo(pointsToCheck.size());
2584 
2585  forAll(pointsToCheck, i)
2586  {
2587  label pointi = pointsToCheck[i];
2588 
2589  // Loop over all cells using the point and check whether their
2590  // refinement level is much less than the maximum.
2591 
2592  const labelList& pCells = mesh_.pointCells(pointi);
2593 
2594  forAll(pCells, pCelli)
2595  {
2596  label celli = pCells[pCelli];
2597 
2598  refinementData& cellInfo = allCellInfo[celli];
2599 
2600  if
2601  (
2602  !cellInfo.isRefined()
2603  && (
2604  maxPointCount[pointi]
2605  > cellInfo.count() + maxFaceDiff*maxPointDiff
2606  )
2607  )
2608  {
2609  // Mark cell for refinement
2610  cellInfo.count() = cellInfo.refinementCount();
2611 
2612  // Insert faces of cell as seed faces.
2613  const cell& cFaces = mesh_.cells()[celli];
2614 
2615  forAll(cFaces, cFacei)
2616  {
2617  label facei = cFaces[cFacei];
2618 
2619  refinementData faceData;
2620  faceData.updateFace
2621  (
2622  mesh_,
2623  facei,
2624  celli,
2625  cellInfo,
2627  dummyTrackData
2628  );
2629 
2630  if (faceData.count() > allFaceInfo[facei].count())
2631  {
2632  changedFacesInfo.insert(facei, faceData);
2633  }
2634  }
2635  }
2636  }
2637  }
2638 
2639  label nChanged = changedFacesInfo.size();
2640  reduce(nChanged, sumOp<label>());
2641 
2642  if (nChanged == 0)
2643  {
2644  break;
2645  }
2646 
2647 
2648  // Transfer into seedFaces, seedFacesInfo
2649  seedFaces.setCapacity(changedFacesInfo.size());
2650  seedFacesInfo.setCapacity(changedFacesInfo.size());
2651 
2652  forAllConstIters(changedFacesInfo, iter)
2653  {
2654  seedFaces.append(iter.key());
2655  seedFacesInfo.append(iter.val());
2656  }
2657  }
2658 
2659 
2660  if (debug)
2661  {
2662  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
2663  {
2664  label own = mesh_.faceOwner()[facei];
2665  label ownLevel =
2666  cellLevel_[own]
2667  + (allCellInfo[own].isRefined() ? 1 : 0);
2668 
2669  label nei = mesh_.faceNeighbour()[facei];
2670  label neiLevel =
2671  cellLevel_[nei]
2672  + (allCellInfo[nei].isRefined() ? 1 : 0);
2673 
2674  if (mag(ownLevel-neiLevel) > 1)
2675  {
2676  dumpCell(own);
2677  dumpCell(nei);
2679  << "cell:" << own
2680  << " current level:" << cellLevel_[own]
2681  << " current refData:" << allCellInfo[own]
2682  << " level after refinement:" << ownLevel
2683  << nl
2684  << "neighbour cell:" << nei
2685  << " current level:" << cellLevel_[nei]
2686  << " current refData:" << allCellInfo[nei]
2687  << " level after refinement:" << neiLevel
2688  << nl
2689  << "which does not satisfy 2:1 constraints anymore." << nl
2690  << "face:" << facei << " faceRefData:" << allFaceInfo[facei]
2691  << abort(FatalError);
2692  }
2693  }
2694 
2695 
2696  // Coupled faces. Swap owner level to get neighbouring cell level.
2697  // (only boundary faces of neiLevel used)
2698 
2699  labelList neiLevel(mesh_.nBoundaryFaces());
2700  labelList neiCount(mesh_.nBoundaryFaces());
2701  labelList neiRefCount(mesh_.nBoundaryFaces());
2702 
2703  forAll(neiLevel, i)
2704  {
2705  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
2706  neiLevel[i] = cellLevel_[own];
2707  neiCount[i] = allCellInfo[own].count();
2708  neiRefCount[i] = allCellInfo[own].refinementCount();
2709  }
2710 
2711  // Swap to neighbour
2712  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
2713  syncTools::swapBoundaryFaceList(mesh_, neiCount);
2714  syncTools::swapBoundaryFaceList(mesh_, neiRefCount);
2715 
2716  // Now we have neighbour value see which cells need refinement
2717  forAll(neiLevel, i)
2718  {
2719  label facei = i+mesh_.nInternalFaces();
2720 
2721  label own = mesh_.faceOwner()[facei];
2722  label ownLevel =
2723  cellLevel_[own]
2724  + (allCellInfo[own].isRefined() ? 1 : 0);
2725 
2726  label nbrLevel =
2727  neiLevel[i]
2728  + ((neiCount[i] >= neiRefCount[i]) ? 1 : 0);
2729 
2730  if (mag(ownLevel - nbrLevel) > 1)
2731  {
2732  dumpCell(own);
2733  label patchi = mesh_.boundaryMesh().whichPatch(facei);
2734 
2736  << "Celllevel does not satisfy 2:1 constraint."
2737  << " On coupled face "
2738  << facei
2739  << " refData:" << allFaceInfo[facei]
2740  << " on patch " << patchi << " "
2741  << mesh_.boundaryMesh()[patchi].name() << nl
2742  << "owner cell " << own
2743  << " current level:" << cellLevel_[own]
2744  << " current count:" << allCellInfo[own].count()
2745  << " current refCount:"
2746  << allCellInfo[own].refinementCount()
2747  << " level after refinement:" << ownLevel
2748  << nl
2749  << "(coupled) neighbour cell"
2750  << " has current level:" << neiLevel[i]
2751  << " current count:" << neiCount[i]
2752  << " current refCount:" << neiRefCount[i]
2753  << " level after refinement:" << nbrLevel
2754  << abort(FatalError);
2755  }
2756  }
2757  }
2758 
2759  // Convert back to labelList of cells to refine.
2760 
2761  label nRefined = 0;
2762 
2763  forAll(allCellInfo, celli)
2764  {
2765  if (allCellInfo[celli].isRefined())
2766  {
2767  nRefined++;
2768  }
2769  }
2770 
2771  // Updated list of cells to refine
2772  labelList newCellsToRefine(nRefined);
2773  nRefined = 0;
2774 
2775  forAll(allCellInfo, celli)
2776  {
2777  if (allCellInfo[celli].isRefined())
2778  {
2779  newCellsToRefine[nRefined++] = celli;
2780  }
2781  }
2782 
2783  if (debug)
2784  {
2785  Pout<< "hexRef8::consistentSlowRefinement : From "
2786  << cellsToRefine.size() << " to " << newCellsToRefine.size()
2787  << " cells to refine." << endl;
2788  }
2789 
2790  return newCellsToRefine;
2791 }
2792 
2793 
2796  const label maxFaceDiff,
2797  const labelList& cellsToRefine,
2798  const labelList& facesToCheck
2799 ) const
2800 {
2801  const labelList& faceOwner = mesh_.faceOwner();
2802  const labelList& faceNeighbour = mesh_.faceNeighbour();
2803 
2804  if (maxFaceDiff <= 0)
2805  {
2807  << "Illegal maxFaceDiff " << maxFaceDiff << nl
2808  << "Value should be >= 1" << exit(FatalError);
2809  }
2810 
2811  const scalar level0Size = 2*maxFaceDiff*level0EdgeLength();
2812 
2813 
2814  // Bit tricky. Say we want a distance of three cells between two
2815  // consecutive refinement levels. This is done by using FaceCellWave to
2816  // transport out the 'refinement shell'. Anything inside the refinement
2817  // shell (given by a distance) gets marked for refinement.
2818 
2819  // Initial information about (distance to) cellLevel on all cells
2820  List<refinementDistanceData> allCellInfo(mesh_.nCells());
2821 
2822  // Initial information about (distance to) cellLevel on all faces
2823  List<refinementDistanceData> allFaceInfo(mesh_.nFaces());
2824 
2825  // Dummy additional info for FaceCellWave
2826  int dummyTrackData = 0;
2827 
2828 
2829  // Mark cells with wanted refinement level
2830  forAll(cellsToRefine, i)
2831  {
2832  label celli = cellsToRefine[i];
2833 
2834  allCellInfo[celli] = refinementDistanceData
2835  (
2836  level0Size,
2837  mesh_.cellCentres()[celli],
2838  cellLevel_[celli]+1 // wanted refinement
2839  );
2840  }
2841  // Mark all others with existing refinement level
2842  forAll(allCellInfo, celli)
2843  {
2844  if (!allCellInfo[celli].valid(dummyTrackData))
2845  {
2846  allCellInfo[celli] = refinementDistanceData
2847  (
2848  level0Size,
2849  mesh_.cellCentres()[celli],
2850  cellLevel_[celli] // wanted refinement
2851  );
2852  }
2853  }
2854 
2855 
2856  // Labels of seed faces
2857  DynamicList<label> seedFaces(mesh_.nFaces()/100);
2858  // refinementLevel data on seed faces
2859  DynamicList<refinementDistanceData> seedFacesInfo(mesh_.nFaces()/100);
2860 
2861  const pointField& cc = mesh_.cellCentres();
2862 
2863  forAll(facesToCheck, i)
2864  {
2865  label facei = facesToCheck[i];
2866 
2867  if (allFaceInfo[facei].valid(dummyTrackData))
2868  {
2869  // Can only occur if face has already gone through loop below.
2871  << "Argument facesToCheck seems to have duplicate entries!"
2872  << endl
2873  << "face:" << facei << " occurs at positions "
2874  << findIndices(facesToCheck, facei)
2875  << abort(FatalError);
2876  }
2877 
2878  label own = faceOwner[facei];
2879 
2880  label ownLevel =
2881  (
2882  allCellInfo[own].valid(dummyTrackData)
2883  ? allCellInfo[own].originLevel()
2884  : cellLevel_[own]
2885  );
2886 
2887  if (!mesh_.isInternalFace(facei))
2888  {
2889  // Do as if boundary face would have neighbour with one higher
2890  // refinement level.
2891  const point& fc = mesh_.faceCentres()[facei];
2892 
2893  refinementDistanceData neiData
2894  (
2895  level0Size,
2896  2*fc - cc[own], // est'd cell centre
2897  ownLevel+1
2898  );
2899 
2900  allFaceInfo[facei].updateFace
2901  (
2902  mesh_,
2903  facei,
2904  own, // not used (should be nei)
2905  neiData,
2907  dummyTrackData
2908  );
2909  }
2910  else
2911  {
2912  label nei = faceNeighbour[facei];
2913 
2914  label neiLevel =
2915  (
2916  allCellInfo[nei].valid(dummyTrackData)
2917  ? allCellInfo[nei].originLevel()
2918  : cellLevel_[nei]
2919  );
2920 
2921  if (ownLevel == neiLevel)
2922  {
2923  // Fake as if nei>own or own>nei (whichever one 'wins')
2924  allFaceInfo[facei].updateFace
2925  (
2926  mesh_,
2927  facei,
2928  nei,
2929  refinementDistanceData(level0Size, cc[nei], neiLevel+1),
2931  dummyTrackData
2932  );
2933  allFaceInfo[facei].updateFace
2934  (
2935  mesh_,
2936  facei,
2937  own,
2938  refinementDistanceData(level0Size, cc[own], ownLevel+1),
2940  dummyTrackData
2941  );
2942  }
2943  else
2944  {
2945  // Difference in level anyway.
2946  allFaceInfo[facei].updateFace
2947  (
2948  mesh_,
2949  facei,
2950  nei,
2951  refinementDistanceData(level0Size, cc[nei], neiLevel),
2953  dummyTrackData
2954  );
2955  allFaceInfo[facei].updateFace
2956  (
2957  mesh_,
2958  facei,
2959  own,
2960  refinementDistanceData(level0Size, cc[own], ownLevel),
2962  dummyTrackData
2963  );
2964  }
2965  }
2966  seedFaces.append(facei);
2967  seedFacesInfo.append(allFaceInfo[facei]);
2968  }
2969 
2970 
2971  // Create some initial seeds to start walking from. This is only if there
2972  // are no facesToCheck.
2973  // Just seed with all faces inbetween different refinement levels for now
2974  forAll(faceNeighbour, facei)
2975  {
2976  // Check if face already handled in loop above
2977  if (!allFaceInfo[facei].valid(dummyTrackData))
2978  {
2979  label own = faceOwner[facei];
2980 
2981  label ownLevel =
2982  (
2983  allCellInfo[own].valid(dummyTrackData)
2984  ? allCellInfo[own].originLevel()
2985  : cellLevel_[own]
2986  );
2987 
2988  label nei = faceNeighbour[facei];
2989 
2990  label neiLevel =
2991  (
2992  allCellInfo[nei].valid(dummyTrackData)
2993  ? allCellInfo[nei].originLevel()
2994  : cellLevel_[nei]
2995  );
2996 
2997  if (ownLevel > neiLevel)
2998  {
2999  // Set face to owner data. (since face not yet would be copy)
3000  seedFaces.append(facei);
3001  allFaceInfo[facei].updateFace
3002  (
3003  mesh_,
3004  facei,
3005  own,
3006  refinementDistanceData(level0Size, cc[own], ownLevel),
3008  dummyTrackData
3009  );
3010  seedFacesInfo.append(allFaceInfo[facei]);
3011  }
3012  else if (neiLevel > ownLevel)
3013  {
3014  seedFaces.append(facei);
3015  allFaceInfo[facei].updateFace
3016  (
3017  mesh_,
3018  facei,
3019  nei,
3020  refinementDistanceData(level0Size, cc[nei], neiLevel),
3022  dummyTrackData
3023  );
3024  seedFacesInfo.append(allFaceInfo[facei]);
3025  }
3026  }
3027  }
3028 
3029  seedFaces.shrink();
3030  seedFacesInfo.shrink();
3031 
3032  // face-cell-face transport engine
3034  (
3035  mesh_,
3036  seedFaces,
3037  seedFacesInfo,
3038  allFaceInfo,
3039  allCellInfo,
3040  mesh_.globalData().nTotalCells()+1,
3041  dummyTrackData
3042  );
3043 
3044 
3045  //if (debug)
3046  //{
3047  // // Dump wanted level
3048  // volScalarField wantedLevel
3049  // (
3050  // IOobject
3051  // (
3052  // "wantedLevel",
3053  // fMesh.time().timeName(),
3054  // fMesh,
3055  // IOobject::NO_READ,
3056  // IOobject::NO_WRITE,
3057  // false
3058  // ),
3059  // fMesh,
3060  // dimensionedScalar(dimless, Zero)
3061  // );
3062  //
3063  // forAll(wantedLevel, celli)
3064  // {
3065  // wantedLevel[celli] = allCellInfo[celli].wantedLevel(cc[celli]);
3066  // }
3067  //
3068  // Pout<< "Writing " << wantedLevel.objectPath() << endl;
3069  // wantedLevel.write();
3070  //}
3071 
3072 
3073  // Convert back to labelList of cells to refine.
3074  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3075 
3076  // 1. Force original refinement cells to be picked up by setting the
3077  // originLevel of input cells to be a very large level (but within range
3078  // of 1<< shift inside refinementDistanceData::wantedLevel)
3079  forAll(cellsToRefine, i)
3080  {
3081  label celli = cellsToRefine[i];
3082 
3083  allCellInfo[celli].originLevel() = sizeof(label)*8-2;
3084  allCellInfo[celli].origin() = cc[celli];
3085  }
3086 
3087  // 2. Extend to 2:1. I don't understand yet why this is not done
3088  // 2. Extend to 2:1. For non-cube cells the scalar distance does not work
3089  // so make sure it at least provides 2:1.
3090  bitSet refineCell(mesh_.nCells());
3091  forAll(allCellInfo, celli)
3092  {
3093  label wanted = allCellInfo[celli].wantedLevel(cc[celli]);
3094 
3095  if (wanted > cellLevel_[celli]+1)
3096  {
3097  refineCell.set(celli);
3098  }
3099  }
3100  faceConsistentRefinement(true, cellLevel_, refineCell);
3101 
3102  while (true)
3103  {
3104  label nChanged = faceConsistentRefinement(true, cellLevel_, refineCell);
3105 
3106  reduce(nChanged, sumOp<label>());
3107 
3108  if (debug)
3109  {
3110  Pout<< "hexRef8::consistentSlowRefinement2 : Changed " << nChanged
3111  << " refinement levels due to 2:1 conflicts."
3112  << endl;
3113  }
3114 
3115  if (nChanged == 0)
3116  {
3117  break;
3118  }
3119  }
3120 
3121  // 3. Convert back to labelList.
3122  labelList newCellsToRefine(refineCell.toc());
3123 
3124  if (debug)
3125  {
3126  Pout<< "hexRef8::consistentSlowRefinement2 : From "
3127  << cellsToRefine.size() << " to " << newCellsToRefine.size()
3128  << " cells to refine." << endl;
3129 
3130  // Check that newCellsToRefine obeys at least 2:1.
3131 
3132  {
3133  cellSet cellsIn(mesh_, "cellsToRefineIn", cellsToRefine);
3134  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3135  << cellsIn.size() << " to cellSet "
3136  << cellsIn.objectPath() << endl;
3137  cellsIn.write();
3138  }
3139  {
3140  cellSet cellsOut(mesh_, "cellsToRefineOut", newCellsToRefine);
3141  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3142  << cellsOut.size() << " to cellSet "
3143  << cellsOut.objectPath() << endl;
3144  cellsOut.write();
3145  }
3146 
3147  // Extend to 2:1
3148  bitSet refineCell(mesh_.nCells(), newCellsToRefine);
3149 
3150  const bitSet savedRefineCell(refineCell);
3151  label nChanged = faceConsistentRefinement(true, cellLevel_, refineCell);
3152 
3153  {
3154  cellSet cellsOut2
3155  (
3156  mesh_, "cellsToRefineOut2", newCellsToRefine.size()
3157  );
3158  forAll(refineCell, celli)
3159  {
3160  if (refineCell.test(celli))
3161  {
3162  cellsOut2.insert(celli);
3163  }
3164  }
3165  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3166  << cellsOut2.size() << " to cellSet "
3167  << cellsOut2.objectPath() << endl;
3168  cellsOut2.write();
3169  }
3170 
3171  if (nChanged > 0)
3172  {
3173  forAll(refineCell, celli)
3174  {
3175  if (refineCell.test(celli) && !savedRefineCell.test(celli))
3176  {
3177  dumpCell(celli);
3179  << "Cell:" << celli << " cc:"
3180  << mesh_.cellCentres()[celli]
3181  << " was not marked for refinement but does not obey"
3182  << " 2:1 constraints."
3183  << abort(FatalError);
3184  }
3185  }
3186  }
3187  }
3188 
3189  return newCellsToRefine;
3190 }
3191 
3192 
3193 // Top level driver to insert topo changes to do all refinement.
3196  const labelList& cellLabels,
3197  polyTopoChange& meshMod
3198 )
3199 {
3200  if (debug)
3201  {
3202  Pout<< "hexRef8::setRefinement :"
3203  << " Checking initial mesh just to make sure" << endl;
3204 
3205  checkMesh();
3206  // Cannot call checkRefinementlevels since hanging points might
3207  // get triggered by the mesher after subsetting.
3208  //checkRefinementLevels(-1, labelList(0));
3209  }
3210 
3211  // Clear any saved point/cell data.
3212  savedPointLevel_.clear();
3213  savedCellLevel_.clear();
3214 
3215 
3216  // New point/cell level. Copy of pointLevel for existing points.
3217  DynamicList<label> newCellLevel(cellLevel_.size());
3218  forAll(cellLevel_, celli)
3219  {
3220  newCellLevel.append(cellLevel_[celli]);
3221  }
3222  DynamicList<label> newPointLevel(pointLevel_.size());
3223  forAll(pointLevel_, pointi)
3224  {
3225  newPointLevel.append(pointLevel_[pointi]);
3226  }
3227 
3228 
3229  if (debug)
3230  {
3231  Pout<< "hexRef8::setRefinement :"
3232  << " Allocating " << cellLabels.size() << " cell midpoints."
3233  << endl;
3234  }
3235 
3236 
3237  // Mid point per refined cell.
3238  // -1 : not refined
3239  // >=0: label of mid point.
3240  labelList cellMidPoint(mesh_.nCells(), -1);
3241 
3242  forAll(cellLabels, i)
3243  {
3244  label celli = cellLabels[i];
3245 
3246  label anchorPointi = mesh_.faces()[mesh_.cells()[celli][0]][0];
3247 
3248  cellMidPoint[celli] = meshMod.setAction
3249  (
3250  polyAddPoint
3251  (
3252  mesh_.cellCentres()[celli], // point
3253  anchorPointi, // master point
3254  -1, // zone for point
3255  true // supports a cell
3256  )
3257  );
3258 
3259  newPointLevel(cellMidPoint[celli]) = cellLevel_[celli]+1;
3260  }
3261 
3262 
3263  if (debug)
3264  {
3265  cellSet splitCells(mesh_, "splitCells", cellLabels.size());
3266 
3267  forAll(cellMidPoint, celli)
3268  {
3269  if (cellMidPoint[celli] >= 0)
3270  {
3271  splitCells.insert(celli);
3272  }
3273  }
3274 
3275  Pout<< "hexRef8::setRefinement : Dumping " << splitCells.size()
3276  << " cells to split to cellSet " << splitCells.objectPath()
3277  << endl;
3278 
3279  splitCells.write();
3280  }
3281 
3282 
3283 
3284  // Split edges
3285  // ~~~~~~~~~~~
3286 
3287  if (debug)
3288  {
3289  Pout<< "hexRef8::setRefinement :"
3290  << " Allocating edge midpoints."
3291  << endl;
3292  }
3293 
3294  // Unrefined edges are ones between cellLevel or lower points.
3295  // If any cell using this edge gets split then the edge needs to be split.
3296 
3297  // -1 : no need to split edge
3298  // >=0 : label of introduced mid point
3299  labelList edgeMidPoint(mesh_.nEdges(), -1);
3300 
3301  // Note: Loop over cells to be refined or edges?
3302  forAll(cellMidPoint, celli)
3303  {
3304  if (cellMidPoint[celli] >= 0)
3305  {
3306  const labelList& cEdges = mesh_.cellEdges(celli);
3307 
3308  forAll(cEdges, i)
3309  {
3310  label edgeI = cEdges[i];
3311 
3312  const edge& e = mesh_.edges()[edgeI];
3313 
3314  if
3315  (
3316  pointLevel_[e[0]] <= cellLevel_[celli]
3317  && pointLevel_[e[1]] <= cellLevel_[celli]
3318  )
3319  {
3320  edgeMidPoint[edgeI] = 12345; // mark need for splitting
3321  }
3322  }
3323  }
3324  }
3325 
3326  // Synchronize edgeMidPoint across coupled patches. Take max so that
3327  // any split takes precedence.
3329  (
3330  mesh_,
3331  edgeMidPoint,
3332  maxEqOp<label>(),
3333  labelMin
3334  );
3335 
3336 
3337  // Introduce edge points
3338  // ~~~~~~~~~~~~~~~~~~~~~
3339 
3340  {
3341  // Phase 1: calculate midpoints and sync.
3342  // This needs doing for if people do not write binary and we slowly
3343  // get differences.
3344 
3345  pointField edgeMids(mesh_.nEdges(), point(-GREAT, -GREAT, -GREAT));
3346 
3347  forAll(edgeMidPoint, edgeI)
3348  {
3349  if (edgeMidPoint[edgeI] >= 0)
3350  {
3351  // Edge marked to be split.
3352  edgeMids[edgeI] = mesh_.edges()[edgeI].centre(mesh_.points());
3353  }
3354  }
3356  (
3357  mesh_,
3358  edgeMids,
3359  maxEqOp<vector>(),
3360  point(-GREAT, -GREAT, -GREAT)
3361  );
3362 
3363 
3364  // Phase 2: introduce points at the synced locations.
3365  forAll(edgeMidPoint, edgeI)
3366  {
3367  if (edgeMidPoint[edgeI] >= 0)
3368  {
3369  // Edge marked to be split. Replace edgeMidPoint with actual
3370  // point label.
3371 
3372  const edge& e = mesh_.edges()[edgeI];
3373 
3374  edgeMidPoint[edgeI] = meshMod.setAction
3375  (
3376  polyAddPoint
3377  (
3378  edgeMids[edgeI], // point
3379  e[0], // master point
3380  -1, // zone for point
3381  true // supports a cell
3382  )
3383  );
3384 
3385  newPointLevel(edgeMidPoint[edgeI]) =
3386  max
3387  (
3388  pointLevel_[e[0]],
3389  pointLevel_[e[1]]
3390  )
3391  + 1;
3392  }
3393  }
3394  }
3395 
3396  if (debug)
3397  {
3398  OFstream str(mesh_.time().path()/"edgeMidPoint.obj");
3399 
3400  forAll(edgeMidPoint, edgeI)
3401  {
3402  if (edgeMidPoint[edgeI] >= 0)
3403  {
3404  const edge& e = mesh_.edges()[edgeI];
3405 
3406  meshTools::writeOBJ(str, e.centre(mesh_.points()));
3407  }
3408  }
3409 
3410  Pout<< "hexRef8::setRefinement :"
3411  << " Dumping edge centres to split to file " << str.name() << endl;
3412  }
3413 
3414 
3415  // Calculate face level
3416  // ~~~~~~~~~~~~~~~~~~~~
3417  // (after splitting)
3418 
3419  if (debug)
3420  {
3421  Pout<< "hexRef8::setRefinement :"
3422  << " Allocating face midpoints."
3423  << endl;
3424  }
3425 
3426  // Face anchor level. There are guaranteed 4 points with level
3427  // <= anchorLevel. These are the corner points.
3428  labelList faceAnchorLevel(mesh_.nFaces());
3429 
3430  for (label facei = 0; facei < mesh_.nFaces(); facei++)
3431  {
3432  faceAnchorLevel[facei] = faceLevel(facei);
3433  }
3434 
3435  // -1 : no need to split face
3436  // >=0 : label of introduced mid point
3437  labelList faceMidPoint(mesh_.nFaces(), -1);
3438 
3439 
3440  // Internal faces: look at cells on both sides. Uniquely determined since
3441  // face itself guaranteed to be same level as most refined neighbour.
3442  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
3443  {
3444  if (faceAnchorLevel[facei] >= 0)
3445  {
3446  label own = mesh_.faceOwner()[facei];
3447  label ownLevel = cellLevel_[own];
3448  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3449 
3450  label nei = mesh_.faceNeighbour()[facei];
3451  label neiLevel = cellLevel_[nei];
3452  label newNeiLevel = neiLevel + (cellMidPoint[nei] >= 0 ? 1 : 0);
3453 
3454  if
3455  (
3456  newOwnLevel > faceAnchorLevel[facei]
3457  || newNeiLevel > faceAnchorLevel[facei]
3458  )
3459  {
3460  faceMidPoint[facei] = 12345; // mark to be split
3461  }
3462  }
3463  }
3464 
3465  // Coupled patches handled like internal faces except now all information
3466  // from neighbour comes from across processor.
3467  // Boundary faces are more complicated since the boundary face can
3468  // be more refined than its owner (or neighbour for coupled patches)
3469  // (does not happen if refining/unrefining only, but does e.g. when
3470  // refinining and subsetting)
3471 
3472  {
3473  labelList newNeiLevel(mesh_.nBoundaryFaces());
3474 
3475  forAll(newNeiLevel, i)
3476  {
3477  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
3478  label ownLevel = cellLevel_[own];
3479  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3480 
3481  newNeiLevel[i] = newOwnLevel;
3482  }
3483 
3484  // Swap.
3485  syncTools::swapBoundaryFaceList(mesh_, newNeiLevel);
3486 
3487  // So now we have information on the neighbour.
3488 
3489  forAll(newNeiLevel, i)
3490  {
3491  label facei = i+mesh_.nInternalFaces();
3492 
3493  if (faceAnchorLevel[facei] >= 0)
3494  {
3495  label own = mesh_.faceOwner()[facei];
3496  label ownLevel = cellLevel_[own];
3497  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3498 
3499  if
3500  (
3501  newOwnLevel > faceAnchorLevel[facei]
3502  || newNeiLevel[i] > faceAnchorLevel[facei]
3503  )
3504  {
3505  faceMidPoint[facei] = 12345; // mark to be split
3506  }
3507  }
3508  }
3509  }
3510 
3511 
3512  // Synchronize faceMidPoint across coupled patches. (logical or)
3514  (
3515  mesh_,
3516  faceMidPoint,
3517  maxEqOp<label>()
3518  );
3519 
3520 
3521 
3522  // Introduce face points
3523  // ~~~~~~~~~~~~~~~~~~~~~
3524 
3525  {
3526  // Phase 1: determine mid points and sync. See comment for edgeMids
3527  // above
3528  pointField bFaceMids
3529  (
3530  mesh_.nBoundaryFaces(),
3531  point(-GREAT, -GREAT, -GREAT)
3532  );
3533 
3534  forAll(bFaceMids, i)
3535  {
3536  label facei = i+mesh_.nInternalFaces();
3537 
3538  if (faceMidPoint[facei] >= 0)
3539  {
3540  bFaceMids[i] = mesh_.faceCentres()[facei];
3541  }
3542  }
3544  (
3545  mesh_,
3546  bFaceMids,
3547  maxEqOp<vector>()
3548  );
3549 
3550  forAll(faceMidPoint, facei)
3551  {
3552  if (faceMidPoint[facei] >= 0)
3553  {
3554  // Face marked to be split. Replace faceMidPoint with actual
3555  // point label.
3556 
3557  const face& f = mesh_.faces()[facei];
3558 
3559  faceMidPoint[facei] = meshMod.setAction
3560  (
3561  polyAddPoint
3562  (
3563  (
3564  facei < mesh_.nInternalFaces()
3565  ? mesh_.faceCentres()[facei]
3566  : bFaceMids[facei-mesh_.nInternalFaces()]
3567  ), // point
3568  f[0], // master point
3569  -1, // zone for point
3570  true // supports a cell
3571  )
3572  );
3573 
3574  // Determine the level of the corner points and midpoint will
3575  // be one higher.
3576  newPointLevel(faceMidPoint[facei]) = faceAnchorLevel[facei]+1;
3577  }
3578  }
3579  }
3580 
3581  if (debug)
3582  {
3583  faceSet splitFaces(mesh_, "splitFaces", cellLabels.size());
3584 
3585  forAll(faceMidPoint, facei)
3586  {
3587  if (faceMidPoint[facei] >= 0)
3588  {
3589  splitFaces.insert(facei);
3590  }
3591  }
3592 
3593  Pout<< "hexRef8::setRefinement : Dumping " << splitFaces.size()
3594  << " faces to split to faceSet " << splitFaces.objectPath() << endl;
3595 
3596  splitFaces.write();
3597  }
3598 
3599 
3600  // Information complete
3601  // ~~~~~~~~~~~~~~~~~~~~
3602  // At this point we have all the information we need. We should no
3603  // longer reference the cellLabels to refine. All the information is:
3604  // - cellMidPoint >= 0 : cell needs to be split
3605  // - faceMidPoint >= 0 : face needs to be split
3606  // - edgeMidPoint >= 0 : edge needs to be split
3607 
3608 
3609 
3610  // Get the corner/anchor points
3611  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3612 
3613  if (debug)
3614  {
3615  Pout<< "hexRef8::setRefinement :"
3616  << " Finding cell anchorPoints (8 per cell)"
3617  << endl;
3618  }
3619 
3620  // There will always be 8 points on the hex that have were introduced
3621  // with the hex and will have the same or lower refinement level.
3622 
3623  // Per cell the 8 corner points.
3624  labelListList cellAnchorPoints(mesh_.nCells());
3625 
3626  {
3627  labelList nAnchorPoints(mesh_.nCells(), Zero);
3628 
3629  forAll(cellMidPoint, celli)
3630  {
3631  if (cellMidPoint[celli] >= 0)
3632  {
3633  cellAnchorPoints[celli].setSize(8);
3634  }
3635  }
3636 
3637  forAll(pointLevel_, pointi)
3638  {
3639  const labelList& pCells = mesh_.pointCells(pointi);
3640 
3641  forAll(pCells, pCelli)
3642  {
3643  label celli = pCells[pCelli];
3644 
3645  if
3646  (
3647  cellMidPoint[celli] >= 0
3648  && pointLevel_[pointi] <= cellLevel_[celli]
3649  )
3650  {
3651  if (nAnchorPoints[celli] == 8)
3652  {
3653  dumpCell(celli);
3655  << "cell " << celli
3656  << " of level " << cellLevel_[celli]
3657  << " uses more than 8 points of equal or"
3658  << " lower level" << nl
3659  << "Points so far:" << cellAnchorPoints[celli]
3660  << abort(FatalError);
3661  }
3662 
3663  cellAnchorPoints[celli][nAnchorPoints[celli]++] = pointi;
3664  }
3665  }
3666  }
3667 
3668  forAll(cellMidPoint, celli)
3669  {
3670  if (cellMidPoint[celli] >= 0)
3671  {
3672  if (nAnchorPoints[celli] != 8)
3673  {
3674  dumpCell(celli);
3675 
3676  const labelList& cPoints = mesh_.cellPoints(celli);
3677 
3679  << "cell " << celli
3680  << " of level " << cellLevel_[celli]
3681  << " does not seem to have 8 points of equal or"
3682  << " lower level" << endl
3683  << "cellPoints:" << cPoints << endl
3684  << "pointLevels:"
3685  << labelUIndList(pointLevel_, cPoints) << endl
3686  << abort(FatalError);
3687  }
3688  }
3689  }
3690  }
3691 
3692 
3693  // Add the cells
3694  // ~~~~~~~~~~~~~
3695 
3696  if (debug)
3697  {
3698  Pout<< "hexRef8::setRefinement :"
3699  << " Adding cells (1 per anchorPoint)"
3700  << endl;
3701  }
3702 
3703  // Per cell the 7 added cells (+ original cell)
3704  labelListList cellAddedCells(mesh_.nCells());
3705 
3706  forAll(cellAnchorPoints, celli)
3707  {
3708  const labelList& cAnchors = cellAnchorPoints[celli];
3709 
3710  if (cAnchors.size() == 8)
3711  {
3712  labelList& cAdded = cellAddedCells[celli];
3713  cAdded.setSize(8);
3714 
3715  // Original cell at 0
3716  cAdded[0] = celli;
3717 
3718  // Update cell level
3719  newCellLevel[celli] = cellLevel_[celli]+1;
3720 
3721 
3722  for (label i = 1; i < 8; i++)
3723  {
3724  cAdded[i] = meshMod.setAction
3725  (
3726  polyAddCell
3727  (
3728  -1, // master point
3729  -1, // master edge
3730  -1, // master face
3731  celli, // master cell
3732  mesh_.cellZones().whichZone(celli) // zone for cell
3733  )
3734  );
3735 
3736  newCellLevel(cAdded[i]) = cellLevel_[celli]+1;
3737  }
3738  }
3739  }
3740 
3741 
3742  // Faces
3743  // ~~~~~
3744  // 1. existing faces that get split (into four always)
3745  // 2. existing faces that do not get split but only edges get split
3746  // 3. existing faces that do not get split but get new owner/neighbour
3747  // 4. new internal faces inside split cells.
3748 
3749  if (debug)
3750  {
3751  Pout<< "hexRef8::setRefinement :"
3752  << " Marking faces to be handled"
3753  << endl;
3754  }
3755 
3756  // Get all affected faces.
3757  bitSet affectedFace(mesh_.nFaces());
3758 
3759  {
3760  forAll(cellMidPoint, celli)
3761  {
3762  if (cellMidPoint[celli] >= 0)
3763  {
3764  const cell& cFaces = mesh_.cells()[celli];
3765 
3766  affectedFace.set(cFaces);
3767  }
3768  }
3769 
3770  forAll(faceMidPoint, facei)
3771  {
3772  if (faceMidPoint[facei] >= 0)
3773  {
3774  affectedFace.set(facei);
3775  }
3776  }
3777 
3778  forAll(edgeMidPoint, edgeI)
3779  {
3780  if (edgeMidPoint[edgeI] >= 0)
3781  {
3782  const labelList& eFaces = mesh_.edgeFaces(edgeI);
3783 
3784  affectedFace.set(eFaces);
3785  }
3786  }
3787  }
3788 
3789 
3790  // 1. Faces that get split
3791  // ~~~~~~~~~~~~~~~~~~~~~~~
3792 
3793  if (debug)
3794  {
3795  Pout<< "hexRef8::setRefinement : Splitting faces" << endl;
3796  }
3797 
3798  forAll(faceMidPoint, facei)
3799  {
3800  if (faceMidPoint[facei] >= 0 && affectedFace.test(facei))
3801  {
3802  // Face needs to be split and hasn't yet been done in some way
3803  // (affectedFace - is impossible since this is first change but
3804  // just for completeness)
3805 
3806  const face& f = mesh_.faces()[facei];
3807 
3808  // Has original facei been used (three faces added, original gets
3809  // modified)
3810  bool modifiedFace = false;
3811 
3812  label anchorLevel = faceAnchorLevel[facei];
3813 
3814  face newFace(4);
3815 
3816  forAll(f, fp)
3817  {
3818  label pointi = f[fp];
3819 
3820  if (pointLevel_[pointi] <= anchorLevel)
3821  {
3822  // point is anchor. Start collecting face.
3823 
3824  DynamicList<label> faceVerts(4);
3825 
3826  faceVerts.append(pointi);
3827 
3828  // Walk forward to mid point.
3829  // - if next is +2 midpoint is +1
3830  // - if next is +1 it is midpoint
3831  // - if next is +0 there has to be edgeMidPoint
3832 
3833  walkFaceToMid
3834  (
3835  edgeMidPoint,
3836  anchorLevel,
3837  facei,
3838  fp,
3839  faceVerts
3840  );
3841 
3842  faceVerts.append(faceMidPoint[facei]);
3843 
3844  walkFaceFromMid
3845  (
3846  edgeMidPoint,
3847  anchorLevel,
3848  facei,
3849  fp,
3850  faceVerts
3851  );
3852 
3853  // Convert dynamiclist to face.
3854  newFace.transfer(faceVerts);
3855 
3856  //Pout<< "Split face:" << facei << " verts:" << f
3857  // << " into quad:" << newFace << endl;
3858 
3859  // Get new owner/neighbour
3860  label own, nei;
3861  getFaceNeighbours
3862  (
3863  cellAnchorPoints,
3864  cellAddedCells,
3865  facei,
3866  pointi, // Anchor point
3867 
3868  own,
3869  nei
3870  );
3871 
3872 
3873  if (debug)
3874  {
3875  if (mesh_.isInternalFace(facei))
3876  {
3877  label oldOwn = mesh_.faceOwner()[facei];
3878  label oldNei = mesh_.faceNeighbour()[facei];
3879 
3880  checkInternalOrientation
3881  (
3882  meshMod,
3883  oldOwn,
3884  facei,
3885  mesh_.cellCentres()[oldOwn],
3886  mesh_.cellCentres()[oldNei],
3887  newFace
3888  );
3889  }
3890  else
3891  {
3892  label oldOwn = mesh_.faceOwner()[facei];
3893 
3894  checkBoundaryOrientation
3895  (
3896  meshMod,
3897  oldOwn,
3898  facei,
3899  mesh_.cellCentres()[oldOwn],
3900  mesh_.faceCentres()[facei],
3901  newFace
3902  );
3903  }
3904  }
3905 
3906 
3907  if (!modifiedFace)
3908  {
3909  modifiedFace = true;
3910 
3911  modFace(meshMod, facei, newFace, own, nei);
3912  }
3913  else
3914  {
3915  addFace(meshMod, facei, newFace, own, nei);
3916  }
3917  }
3918  }
3919 
3920  // Mark face as having been handled
3921  affectedFace.unset(facei);
3922  }
3923  }
3924 
3925 
3926  // 2. faces that do not get split but use edges that get split
3927  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3928 
3929  if (debug)
3930  {
3931  Pout<< "hexRef8::setRefinement :"
3932  << " Adding edge splits to unsplit faces"
3933  << endl;
3934  }
3935 
3936  DynamicList<label> eFacesStorage;
3937  DynamicList<label> fEdgesStorage;
3938 
3939  forAll(edgeMidPoint, edgeI)
3940  {
3941  if (edgeMidPoint[edgeI] >= 0)
3942  {
3943  // Split edge. Check that face not already handled above.
3944 
3945  const labelList& eFaces = mesh_.edgeFaces(edgeI, eFacesStorage);
3946 
3947  forAll(eFaces, i)
3948  {
3949  label facei = eFaces[i];
3950 
3951  if (faceMidPoint[facei] < 0 && affectedFace.test(facei))
3952  {
3953  // Unsplit face. Add edge splits to face.
3954 
3955  const face& f = mesh_.faces()[facei];
3956  const labelList& fEdges = mesh_.faceEdges
3957  (
3958  facei,
3959  fEdgesStorage
3960  );
3961 
3962  DynamicList<label> newFaceVerts(f.size());
3963 
3964  forAll(f, fp)
3965  {
3966  newFaceVerts.append(f[fp]);
3967 
3968  label edgeI = fEdges[fp];
3969 
3970  if (edgeMidPoint[edgeI] >= 0)
3971  {
3972  newFaceVerts.append(edgeMidPoint[edgeI]);
3973  }
3974  }
3975 
3976  face newFace;
3977  newFace.transfer(newFaceVerts);
3978 
3979  // The point with the lowest level should be an anchor
3980  // point of the neighbouring cells.
3981  label anchorFp = findMinLevel(f);
3982 
3983  label own, nei;
3984  getFaceNeighbours
3985  (
3986  cellAnchorPoints,
3987  cellAddedCells,
3988  facei,
3989  f[anchorFp], // Anchor point
3990 
3991  own,
3992  nei
3993  );
3994 
3995 
3996  if (debug)
3997  {
3998  if (mesh_.isInternalFace(facei))
3999  {
4000  label oldOwn = mesh_.faceOwner()[facei];
4001  label oldNei = mesh_.faceNeighbour()[facei];
4002 
4003  checkInternalOrientation
4004  (
4005  meshMod,
4006  oldOwn,
4007  facei,
4008  mesh_.cellCentres()[oldOwn],
4009  mesh_.cellCentres()[oldNei],
4010  newFace
4011  );
4012  }
4013  else
4014  {
4015  label oldOwn = mesh_.faceOwner()[facei];
4016 
4017  checkBoundaryOrientation
4018  (
4019  meshMod,
4020  oldOwn,
4021  facei,
4022  mesh_.cellCentres()[oldOwn],
4023  mesh_.faceCentres()[facei],
4024  newFace
4025  );
4026  }
4027  }
4028 
4029  modFace(meshMod, facei, newFace, own, nei);
4030 
4031  // Mark face as having been handled
4032  affectedFace.unset(facei);
4033  }
4034  }
4035  }
4036  }
4037 
4038 
4039  // 3. faces that do not get split but whose owner/neighbour change
4040  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4041 
4042  if (debug)
4043  {
4044  Pout<< "hexRef8::setRefinement :"
4045  << " Changing owner/neighbour for otherwise unaffected faces"
4046  << endl;
4047  }
4048 
4049  forAll(affectedFace, facei)
4050  {
4051  if (affectedFace.test(facei))
4052  {
4053  const face& f = mesh_.faces()[facei];
4054 
4055  // The point with the lowest level should be an anchor
4056  // point of the neighbouring cells.
4057  label anchorFp = findMinLevel(f);
4058 
4059  label own, nei;
4060  getFaceNeighbours
4061  (
4062  cellAnchorPoints,
4063  cellAddedCells,
4064  facei,
4065  f[anchorFp], // Anchor point
4066 
4067  own,
4068  nei
4069  );
4070 
4071  modFace(meshMod, facei, f, own, nei);
4072 
4073  // Mark face as having been handled
4074  affectedFace.unset(facei);
4075  }
4076  }
4077 
4078 
4079  // 4. new internal faces inside split cells.
4080  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4081 
4082 
4083  // This is the hard one. We have to find the splitting points between
4084  // the anchor points. But the edges between the anchor points might have
4085  // been split (into two,three or four edges).
4086 
4087  if (debug)
4088  {
4089  Pout<< "hexRef8::setRefinement :"
4090  << " Create new internal faces for split cells"
4091  << endl;
4092  }
4093 
4094  forAll(cellMidPoint, celli)
4095  {
4096  if (cellMidPoint[celli] >= 0)
4097  {
4098  createInternalFaces
4099  (
4100  cellAnchorPoints,
4101  cellAddedCells,
4102  cellMidPoint,
4103  faceMidPoint,
4104  faceAnchorLevel,
4105  edgeMidPoint,
4106  celli,
4107  meshMod
4108  );
4109  }
4110  }
4111 
4112  // Extend pointLevels and cellLevels for the new cells. Could also be done
4113  // in updateMesh but saves passing cellAddedCells out of this routine.
4114 
4115  // Check
4116  if (debug)
4117  {
4118  label minPointi = labelMax;
4119  label maxPointi = labelMin;
4120 
4121  forAll(cellMidPoint, celli)
4122  {
4123  if (cellMidPoint[celli] >= 0)
4124  {
4125  minPointi = min(minPointi, cellMidPoint[celli]);
4126  maxPointi = max(maxPointi, cellMidPoint[celli]);
4127  }
4128  }
4129  forAll(faceMidPoint, facei)
4130  {
4131  if (faceMidPoint[facei] >= 0)
4132  {
4133  minPointi = min(minPointi, faceMidPoint[facei]);
4134  maxPointi = max(maxPointi, faceMidPoint[facei]);
4135  }
4136  }
4137  forAll(edgeMidPoint, edgeI)
4138  {
4139  if (edgeMidPoint[edgeI] >= 0)
4140  {
4141  minPointi = min(minPointi, edgeMidPoint[edgeI]);
4142  maxPointi = max(maxPointi, edgeMidPoint[edgeI]);
4143  }
4144  }
4145 
4146  if (minPointi != labelMax && minPointi != mesh_.nPoints())
4147  {
4149  << "Added point labels not consecutive to existing mesh points."
4150  << nl
4151  << "mesh_.nPoints():" << mesh_.nPoints()
4152  << " minPointi:" << minPointi
4153  << " maxPointi:" << maxPointi
4154  << abort(FatalError);
4155  }
4156  }
4157 
4158  pointLevel_.transfer(newPointLevel);
4159  cellLevel_.transfer(newCellLevel);
4160 
4161  // Mark files as changed
4162  setInstance(mesh_.facesInstance());
4163 
4164 
4165  // Update the live split cells tree.
4166  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4167 
4168  // New unrefinement structure
4169  if (history_.active())
4170  {
4171  if (debug)
4172  {
4173  Pout<< "hexRef8::setRefinement :"
4174  << " Updating refinement history to " << cellLevel_.size()
4175  << " cells" << endl;
4176  }
4177 
4178  // Extend refinement history for new cells
4179  history_.resize(cellLevel_.size());
4180 
4181  forAll(cellAddedCells, celli)
4182  {
4183  const labelList& addedCells = cellAddedCells[celli];
4184 
4185  if (addedCells.size())
4186  {
4187  // Cell was split.
4188  history_.storeSplit(celli, addedCells);
4189  }
4190  }
4191  }
4192 
4193  // Compact cellAddedCells.
4194 
4195  labelListList refinedCells(cellLabels.size());
4196 
4197  forAll(cellLabels, i)
4198  {
4199  label celli = cellLabels[i];
4200 
4201  refinedCells[i].transfer(cellAddedCells[celli]);
4202  }
4203 
4204  return refinedCells;
4205 }
4206 
4207 
4210  const labelList& pointsToStore,
4211  const labelList& facesToStore,
4212  const labelList& cellsToStore
4213 )
4214 {
4215  savedPointLevel_.clear();
4216  savedPointLevel_.resize(2*pointsToStore.size());
4217  forAll(pointsToStore, i)
4218  {
4219  label pointi = pointsToStore[i];
4220  savedPointLevel_.insert(pointi, pointLevel_[pointi]);
4221  }
4222 
4223  savedCellLevel_.clear();
4224  savedCellLevel_.resize(2*cellsToStore.size());
4225  forAll(cellsToStore, i)
4226  {
4227  label celli = cellsToStore[i];
4228  savedCellLevel_.insert(celli, cellLevel_[celli]);
4229  }
4230 }
4231 
4232 
4233 // Gets called after the mesh change. setRefinement will already have made
4234 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4235 // only need to account for reordering.
4237 {
4238  Map<label> dummyMap(0);
4239 
4240  updateMesh(map, dummyMap, dummyMap, dummyMap);
4241 }
4242 
4243 
4244 // Gets called after the mesh change. setRefinement will already have made
4245 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4246 // only need to account for reordering.
4249  const mapPolyMesh& map,
4250  const Map<label>& pointsToRestore,
4251  const Map<label>& facesToRestore,
4252  const Map<label>& cellsToRestore
4253 )
4254 {
4255  // Update celllevel
4256  if (debug)
4257  {
4258  Pout<< "hexRef8::updateMesh :"
4259  << " Updating various lists"
4260  << endl;
4261  }
4262 
4263  {
4264  const labelList& reverseCellMap = map.reverseCellMap();
4265 
4266  if (debug)
4267  {
4268  Pout<< "hexRef8::updateMesh :"
4269  << " reverseCellMap:" << map.reverseCellMap().size()
4270  << " cellMap:" << map.cellMap().size()
4271  << " nCells:" << mesh_.nCells()
4272  << " nOldCells:" << map.nOldCells()
4273  << " cellLevel_:" << cellLevel_.size()
4274  << " reversePointMap:" << map.reversePointMap().size()
4275  << " pointMap:" << map.pointMap().size()
4276  << " nPoints:" << mesh_.nPoints()
4277  << " nOldPoints:" << map.nOldPoints()
4278  << " pointLevel_:" << pointLevel_.size()
4279  << endl;
4280  }
4281 
4282  if (reverseCellMap.size() == cellLevel_.size())
4283  {
4284  // Assume it is after hexRef8 that this routine is called.
4285  // Just account for reordering. We cannot use cellMap since
4286  // then cells created from cells would get cellLevel_ of
4287  // cell they were created from.
4288  reorder(reverseCellMap, mesh_.nCells(), -1, cellLevel_);
4289  }
4290  else
4291  {
4292  // Map data
4293  const labelList& cellMap = map.cellMap();
4294 
4295  labelList newCellLevel(cellMap.size());
4296  forAll(cellMap, newCelli)
4297  {
4298  label oldCelli = cellMap[newCelli];
4299 
4300  if (oldCelli == -1)
4301  {
4302  newCellLevel[newCelli] = -1;
4303  }
4304  else
4305  {
4306  newCellLevel[newCelli] = cellLevel_[oldCelli];
4307  }
4308  }
4309  cellLevel_.transfer(newCellLevel);
4310  }
4311 
4312  // See if any cells to restore. This will be for some new cells
4313  // the corresponding old cell.
4314  forAllConstIters(cellsToRestore, iter)
4315  {
4316  const label newCelli = iter.key();
4317  const label storedCelli = iter.val();
4318 
4319  const auto fnd = savedCellLevel_.cfind(storedCelli);
4320 
4321  if (!fnd.found())
4322  {
4324  << "Problem : trying to restore old value for new cell "
4325  << newCelli << " but cannot find old cell " << storedCelli
4326  << " in map of stored values " << savedCellLevel_
4327  << abort(FatalError);
4328  }
4329  cellLevel_[newCelli] = fnd.val();
4330  }
4331 
4332  //if (cellLevel_.found(-1))
4333  //{
4334  // WarningInFunction
4335  // << "Problem : "
4336  // << "cellLevel_ contains illegal value -1 after mapping
4337  // << " at cell " << cellLevel_.find(-1) << endl
4338  // << "This means that another program has inflated cells"
4339  // << " (created cells out-of-nothing) and hence we don't know"
4340  // << " their cell level. Continuing with illegal value."
4341  // << abort(FatalError);
4342  //}
4343  }
4344 
4345 
4346  // Update pointlevel
4347  {
4348  const labelList& reversePointMap = map.reversePointMap();
4349 
4350  if (reversePointMap.size() == pointLevel_.size())
4351  {
4352  // Assume it is after hexRef8 that this routine is called.
4353  reorder(reversePointMap, mesh_.nPoints(), -1, pointLevel_);
4354  }
4355  else
4356  {
4357  // Map data
4358  const labelList& pointMap = map.pointMap();
4359 
4360  labelList newPointLevel(pointMap.size());
4361 
4362  forAll(pointMap, newPointi)
4363  {
4364  const label oldPointi = pointMap[newPointi];
4365 
4366  if (oldPointi == -1)
4367  {
4368  //FatalErrorInFunction
4369  // << "Problem : point " << newPointi
4370  // << " at " << mesh_.points()[newPointi]
4371  // << " does not originate from another point"
4372  // << " (i.e. is inflated)." << nl
4373  // << "Hence we cannot determine the new pointLevel"
4374  // << " for it." << abort(FatalError);
4375  newPointLevel[newPointi] = -1;
4376  }
4377  else
4378  {
4379  newPointLevel[newPointi] = pointLevel_[oldPointi];
4380  }
4381  }
4382  pointLevel_.transfer(newPointLevel);
4383  }
4384 
4385  // See if any points to restore. This will be for some new points
4386  // the corresponding old point (the one from the call to storeData)
4387  forAllConstIters(pointsToRestore, iter)
4388  {
4389  const label newPointi = iter.key();
4390  const label storedPointi = iter.val();
4391 
4392  auto fnd = savedPointLevel_.find(storedPointi);
4393 
4394  if (!fnd.found())
4395  {
4397  << "Problem : trying to restore old value for new point "
4398  << newPointi << " but cannot find old point "
4399  << storedPointi
4400  << " in map of stored values " << savedPointLevel_
4401  << abort(FatalError);
4402  }
4403  pointLevel_[newPointi] = fnd.val();
4404  }
4405 
4406  //if (pointLevel_.found(-1))
4407  //{
4408  // WarningInFunction
4409  // << "Problem : "
4410  // << "pointLevel_ contains illegal value -1 after mapping"
4411  // << " at point" << pointLevel_.find(-1) << endl
4412  // << "This means that another program has inflated points"
4413  // << " (created points out-of-nothing) and hence we don't know"
4414  // << " their point level. Continuing with illegal value."
4415  // //<< abort(FatalError);
4416  //}
4417  }
4418 
4419  // Update refinement tree
4420  if (history_.active())
4421  {
4422  history_.updateMesh(map);
4423  }
4424 
4425  // Mark files as changed
4426  setInstance(mesh_.facesInstance());
4427 
4428  // Update face removal engine
4429  faceRemover_.updateMesh(map);
4430 
4431  // Clear cell shapes
4432  cellShapesPtr_.clear();
4433 }
4434 
4435 
4436 // Gets called after mesh subsetting. Maps are from new back to old.
4439  const labelList& pointMap,
4440  const labelList& faceMap,
4441  const labelList& cellMap
4442 )
4443 {
4444  // Update celllevel
4445  if (debug)
4446  {
4447  Pout<< "hexRef8::subset :"
4448  << " Updating various lists"
4449  << endl;
4450  }
4451 
4452  if (history_.active())
4453  {
4455  << "Subsetting will not work in combination with unrefinement."
4456  << nl
4457  << "Proceed at your own risk." << endl;
4458  }
4459 
4460 
4461  // Update celllevel
4462  {
4463  labelList newCellLevel(cellMap.size());
4464 
4465  forAll(cellMap, newCelli)
4466  {
4467  newCellLevel[newCelli] = cellLevel_[cellMap[newCelli]];
4468  }
4469 
4470  cellLevel_.transfer(newCellLevel);
4471 
4472  if (cellLevel_.found(-1))
4473  {
4475  << "Problem : "
4476  << "cellLevel_ contains illegal value -1 after mapping:"
4477  << cellLevel_
4478  << abort(FatalError);
4479  }
4480  }
4481 
4482  // Update pointlevel
4483  {
4484  labelList newPointLevel(pointMap.size());
4485 
4486  forAll(pointMap, newPointi)
4487  {
4488  newPointLevel[newPointi] = pointLevel_[pointMap[newPointi]];
4489  }
4490 
4491  pointLevel_.transfer(newPointLevel);
4492 
4493  if (pointLevel_.found(-1))
4494  {
4496  << "Problem : "
4497  << "pointLevel_ contains illegal value -1 after mapping:"
4498  << pointLevel_
4499  << abort(FatalError);
4500  }
4501  }
4502 
4503  // Update refinement tree
4504  if (history_.active())
4505  {
4506  history_.subset(pointMap, faceMap, cellMap);
4507  }
4508 
4509  // Mark files as changed
4510  setInstance(mesh_.facesInstance());
4511 
4512  // Nothing needs doing to faceRemover.
4513  //faceRemover_.subset(pointMap, faceMap, cellMap);
4514 
4515  // Clear cell shapes
4516  cellShapesPtr_.clear();
4517 }
4518 
4519 
4520 // Gets called after the mesh distribution
4522 {
4523  if (debug)
4524  {
4525  Pout<< "hexRef8::distribute :"
4526  << " Updating various lists"
4527  << endl;
4528  }
4529 
4530  // Update celllevel
4531  map.distributeCellData(cellLevel_);
4532  // Update pointlevel
4533  map.distributePointData(pointLevel_);
4534 
4535  // Update refinement tree
4536  if (history_.active())
4537  {
4538  history_.distribute(map);
4539  }
4540 
4541  // Update face removal engine
4542  faceRemover_.distribute(map);
4543 
4544  // Clear cell shapes
4545  cellShapesPtr_.clear();
4546 }
4547 
4548 
4550 {
4551  const scalar smallDim = 1e-6 * mesh_.bounds().mag();
4552 
4553  if (debug)
4554  {
4555  Pout<< "hexRef8::checkMesh : Using matching tolerance smallDim:"
4556  << smallDim << endl;
4557  }
4558 
4559  // Check owner on coupled faces.
4560  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4561 
4562  // There should be only one coupled face between two cells. Why? Since
4563  // otherwise mesh redistribution might cause multiple faces between two
4564  // cells
4565  {
4566  labelList nei(mesh_.nBoundaryFaces());
4567  forAll(nei, i)
4568  {
4569  nei[i] = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4570  }
4571 
4572  // Replace data on coupled patches with their neighbour ones.
4573  syncTools::swapBoundaryFaceList(mesh_, nei);
4574 
4575  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4576 
4577  forAll(patches, patchi)
4578  {
4579  const polyPatch& pp = patches[patchi];
4580 
4581  if (pp.coupled())
4582  {
4583  // Check how many faces between owner and neighbour.
4584  // Should be only one.
4585  labelPairLookup cellToFace(2*pp.size());
4586 
4587  label facei = pp.start();
4588 
4589  forAll(pp, i)
4590  {
4591  label own = mesh_.faceOwner()[facei];
4592  label bFacei = facei-mesh_.nInternalFaces();
4593 
4594  if (!cellToFace.insert(labelPair(own, nei[bFacei]), facei))
4595  {
4596  dumpCell(own);
4598  << "Faces do not seem to be correct across coupled"
4599  << " boundaries" << endl
4600  << "Coupled face " << facei
4601  << " between owner " << own
4602  << " on patch " << pp.name()
4603  << " and coupled neighbour " << nei[bFacei]
4604  << " has two faces connected to it:"
4605  << facei << " and "
4606  << cellToFace[labelPair(own, nei[bFacei])]
4607  << abort(FatalError);
4608  }
4609 
4610  facei++;
4611  }
4612  }
4613  }
4614  }
4615 
4616  // Check face areas.
4617  // ~~~~~~~~~~~~~~~~~
4618 
4619  {
4620  scalarField neiFaceAreas(mesh_.nBoundaryFaces());
4621  forAll(neiFaceAreas, i)
4622  {
4623  neiFaceAreas[i] = mag(mesh_.faceAreas()[i+mesh_.nInternalFaces()]);
4624  }
4625 
4626  // Replace data on coupled patches with their neighbour ones.
4627  syncTools::swapBoundaryFaceList(mesh_, neiFaceAreas);
4628 
4629  forAll(neiFaceAreas, i)
4630  {
4631  label facei = i+mesh_.nInternalFaces();
4632 
4633  const scalar magArea = mag(mesh_.faceAreas()[facei]);
4634 
4635  if (mag(magArea - neiFaceAreas[i]) > smallDim)
4636  {
4637  const face& f = mesh_.faces()[facei];
4638  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4639 
4640  dumpCell(mesh_.faceOwner()[facei]);
4641 
4643  << "Faces do not seem to be correct across coupled"
4644  << " boundaries" << endl
4645  << "Coupled face " << facei
4646  << " on patch " << patchi
4647  << " " << mesh_.boundaryMesh()[patchi].name()
4648  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4649  << " has face area:" << magArea
4650  << " (coupled) neighbour face area differs:"
4651  << neiFaceAreas[i]
4652  << " to within tolerance " << smallDim
4653  << abort(FatalError);
4654  }
4655  }
4656  }
4657 
4658 
4659  // Check number of points on faces.
4660  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4661  {
4662  labelList nVerts(mesh_.nBoundaryFaces());
4663 
4664  forAll(nVerts, i)
4665  {
4666  nVerts[i] = mesh_.faces()[i+mesh_.nInternalFaces()].size();
4667  }
4668 
4669  // Replace data on coupled patches with their neighbour ones.
4670  syncTools::swapBoundaryFaceList(mesh_, nVerts);
4671 
4672  forAll(nVerts, i)
4673  {
4674  label facei = i+mesh_.nInternalFaces();
4675 
4676  const face& f = mesh_.faces()[facei];
4677 
4678  if (f.size() != nVerts[i])
4679  {
4680  dumpCell(mesh_.faceOwner()[facei]);
4681 
4682  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4683 
4685  << "Faces do not seem to be correct across coupled"
4686  << " boundaries" << endl
4687  << "Coupled face " << facei
4688  << " on patch " << patchi
4689  << " " << mesh_.boundaryMesh()[patchi].name()
4690  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4691  << " has size:" << f.size()
4692  << " (coupled) neighbour face has size:"
4693  << nVerts[i]
4694  << abort(FatalError);
4695  }
4696  }
4697  }
4698 
4699 
4700  // Check points of face
4701  // ~~~~~~~~~~~~~~~~~~~~
4702  {
4703  // Anchor points.
4704  pointField anchorPoints(mesh_.nBoundaryFaces());
4705 
4706  forAll(anchorPoints, i)
4707  {
4708  label facei = i+mesh_.nInternalFaces();
4709  const point& fc = mesh_.faceCentres()[facei];
4710  const face& f = mesh_.faces()[facei];
4711  const vector anchorVec(mesh_.points()[f[0]] - fc);
4712 
4713  anchorPoints[i] = anchorVec;
4714  }
4715 
4716  // Replace data on coupled patches with their neighbour ones. Apply
4717  // rotation transformation (but not separation since is relative vector
4718  // to point on same face.
4719  syncTools::swapBoundaryFaceList(mesh_, anchorPoints);
4720 
4721  forAll(anchorPoints, i)
4722  {
4723  label facei = i+mesh_.nInternalFaces();
4724  const point& fc = mesh_.faceCentres()[facei];
4725  const face& f = mesh_.faces()[facei];
4726  const vector anchorVec(mesh_.points()[f[0]] - fc);
4727 
4728  if (mag(anchorVec - anchorPoints[i]) > smallDim)
4729  {
4730  dumpCell(mesh_.faceOwner()[facei]);
4731 
4732  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4733 
4735  << "Faces do not seem to be correct across coupled"
4736  << " boundaries" << endl
4737  << "Coupled face " << facei
4738  << " on patch " << patchi
4739  << " " << mesh_.boundaryMesh()[patchi].name()
4740  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4741  << " has anchor vector:" << anchorVec
4742  << " (coupled) neighbour face anchor vector differs:"
4743  << anchorPoints[i]
4744  << " to within tolerance " << smallDim
4745  << abort(FatalError);
4746  }
4747  }
4748  }
4749 
4750  if (debug)
4751  {
4752  Pout<< "hexRef8::checkMesh : Returning" << endl;
4753  }
4754 }
4755 
4756 
4759  const label maxPointDiff,
4760  const labelList& pointsToCheck
4761 ) const
4762 {
4763  if (debug)
4764  {
4765  Pout<< "hexRef8::checkRefinementLevels :"
4766  << " Checking 2:1 refinement level" << endl;
4767  }
4768 
4769  if
4770  (
4771  cellLevel_.size() != mesh_.nCells()
4772  || pointLevel_.size() != mesh_.nPoints()
4773  )
4774  {
4776  << "cellLevel size should be number of cells"
4777  << " and pointLevel size should be number of points."<< nl
4778  << "cellLevel:" << cellLevel_.size()
4779  << " mesh.nCells():" << mesh_.nCells() << nl
4780  << "pointLevel:" << pointLevel_.size()
4781  << " mesh.nPoints():" << mesh_.nPoints()
4782  << abort(FatalError);
4783  }
4784 
4785 
4786  // Check 2:1 consistency.
4787  // ~~~~~~~~~~~~~~~~~~~~~~
4788 
4789  {
4790  // Internal faces.
4791  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
4792  {
4793  label own = mesh_.faceOwner()[facei];
4794  label nei = mesh_.faceNeighbour()[facei];
4795 
4796  if (mag(cellLevel_[own] - cellLevel_[nei]) > 1)
4797  {
4798  dumpCell(own);
4799  dumpCell(nei);
4800 
4802  << "Celllevel does not satisfy 2:1 constraint." << nl
4803  << "On face " << facei << " owner cell " << own
4804  << " has refinement " << cellLevel_[own]
4805  << " neighbour cell " << nei << " has refinement "
4806  << cellLevel_[nei]
4807  << abort(FatalError);
4808  }
4809  }
4810 
4811  // Coupled faces. Get neighbouring value
4812  labelList neiLevel(mesh_.nBoundaryFaces());
4813 
4814  forAll(neiLevel, i)
4815  {
4816  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4817 
4818  neiLevel[i] = cellLevel_[own];
4819  }
4820 
4821  // No separation
4822  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
4823 
4824  forAll(neiLevel, i)
4825  {
4826  label facei = i+mesh_.nInternalFaces();
4827 
4828  label own = mesh_.faceOwner()[facei];
4829 
4830  if (mag(cellLevel_[own] - neiLevel[i]) > 1)
4831  {
4832  dumpCell(own);
4833 
4834  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4835 
4837  << "Celllevel does not satisfy 2:1 constraint."
4838  << " On coupled face " << facei
4839  << " on patch " << patchi << " "
4840  << mesh_.boundaryMesh()[patchi].name()
4841  << " owner cell " << own << " has refinement "
4842  << cellLevel_[own]
4843  << " (coupled) neighbour cell has refinement "
4844  << neiLevel[i]
4845  << abort(FatalError);
4846  }
4847  }
4848  }
4849 
4850 
4851  // Check pointLevel is synchronized
4852  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4853  {
4854  labelList syncPointLevel(pointLevel_);
4855 
4856  // Get min level
4858  (
4859  mesh_,
4860  syncPointLevel,
4861  minEqOp<label>(),
4862  labelMax
4863  );
4864 
4865 
4866  forAll(syncPointLevel, pointi)
4867  {
4868  if (pointLevel_[pointi] != syncPointLevel[pointi])
4869  {
4871  << "PointLevel is not consistent across coupled patches."
4872  << endl
4873  << "point:" << pointi << " coord:" << mesh_.points()[pointi]
4874  << " has level " << pointLevel_[pointi]
4875  << " whereas the coupled point has level "
4876  << syncPointLevel[pointi]
4877  << abort(FatalError);
4878  }
4879  }
4880  }
4881 
4882 
4883  // Check 2:1 across points (instead of faces)
4884  if (maxPointDiff != -1)
4885  {
4886  // Determine per point the max cell level.
4887  labelList maxPointLevel(mesh_.nPoints(), Zero);
4888 
4889  forAll(maxPointLevel, pointi)
4890  {
4891  const labelList& pCells = mesh_.pointCells(pointi);
4892 
4893  label& pLevel = maxPointLevel[pointi];
4894 
4895  forAll(pCells, i)
4896  {
4897  pLevel = max(pLevel, cellLevel_[pCells[i]]);
4898  }
4899  }
4900 
4901  // Sync maxPointLevel to neighbour
4903  (
4904  mesh_,
4905  maxPointLevel,
4906  maxEqOp<label>(),
4907  labelMin // null value
4908  );
4909 
4910  // Check 2:1 across boundary points
4911  forAll(pointsToCheck, i)
4912  {
4913  label pointi = pointsToCheck[i];
4914 
4915  const labelList& pCells = mesh_.pointCells(pointi);
4916 
4917  forAll(pCells, i)
4918  {
4919  label celli = pCells[i];
4920 
4921  if
4922  (
4923  mag(cellLevel_[celli]-maxPointLevel[pointi])
4924  > maxPointDiff
4925  )
4926  {
4927  dumpCell(celli);
4928 
4930  << "Too big a difference between"
4931  << " point-connected cells." << nl
4932  << "cell:" << celli
4933  << " cellLevel:" << cellLevel_[celli]
4934  << " uses point:" << pointi
4935  << " coord:" << mesh_.points()[pointi]
4936  << " which is also used by a cell with level:"
4937  << maxPointLevel[pointi]
4938  << abort(FatalError);
4939  }
4940  }
4941  }
4942  }
4943 
4944 
4945  //- Gives problems after first splitting off inside mesher.
4947  //{
4948  // // Any patches with points having only two edges.
4949  //
4950  // boolList isHangingPoint(mesh_.nPoints(), false);
4951  //
4952  // const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4953  //
4954  // forAll(patches, patchi)
4955  // {
4956  // const polyPatch& pp = patches[patchi];
4957  //
4958  // const labelList& meshPoints = pp.meshPoints();
4959  //
4960  // forAll(meshPoints, i)
4961  // {
4962  // label pointi = meshPoints[i];
4963  //
4964  // const labelList& pEdges = mesh_.pointEdges()[pointi];
4965  //
4966  // if (pEdges.size() == 2)
4967  // {
4968  // isHangingPoint[pointi] = true;
4969  // }
4970  // }
4971  // }
4972  //
4973  // syncTools::syncPointList
4974  // (
4975  // mesh_,
4976  // isHangingPoint,
4977  // andEqOp<bool>(), // only if all decide it is hanging point
4978  // true, // null
4979  // false // no separation
4980  // );
4981  //
4982  // //OFstream str(mesh_.time().path()/"hangingPoints.obj");
4983  //
4984  // label nHanging = 0;
4985  //
4986  // forAll(isHangingPoint, pointi)
4987  // {
4988  // if (isHangingPoint[pointi])
4989  // {
4990  // nHanging++;
4991  //
4992  // Pout<< "Hanging boundary point " << pointi
4993  // << " at " << mesh_.points()[pointi]
4994  // << endl;
4995  // //meshTools::writeOBJ(str, mesh_.points()[pointi]);
4996  // }
4997  // }
4998  //
4999  // if (returnReduce(nHanging, sumOp<label>()) > 0)
5000  // {
5001  // FatalErrorInFunction
5002  // << "Detected a point used by two edges only (hanging point)"
5003  // << nl << "This is not allowed"
5004  // << abort(FatalError);
5005  // }
5006  //}
5007 }
5008 
5009 
5011 {
5012  if (!cellShapesPtr_)
5013  {
5014  if (debug)
5015  {
5016  Pout<< "hexRef8::cellShapes() : calculating splitHex cellShapes."
5017  << " cellLevel:" << cellLevel_.size()
5018  << " pointLevel:" << pointLevel_.size()
5019  << endl;
5020  }
5021 
5022  const cellShapeList& meshShapes = mesh_.cellShapes();
5023  cellShapesPtr_.reset(new cellShapeList(meshShapes));
5024 
5025  label nSplitHex = 0;
5026  label nUnrecognised = 0;
5027 
5028  forAll(cellLevel_, celli)
5029  {
5030  if (meshShapes[celli].model().index() == 0)
5031  {
5032  label level = cellLevel_[celli];
5033 
5034  // Return true if we've found 6 quads
5035  DynamicList<face> quads;
5036  bool haveQuads = matchHexShape
5037  (
5038  celli,
5039  level,
5040  quads
5041  );
5042 
5043  if (haveQuads)
5044  {
5045  faceList faces(std::move(quads));
5046  cellShapesPtr_()[celli] = degenerateMatcher::match(faces);
5047  nSplitHex++;
5048  }
5049  else
5050  {
5051  nUnrecognised++;
5052  }
5053  }
5054  }
5055  if (debug)
5056  {
5057  Pout<< "hexRef8::cellShapes() :"
5058  << " nCells:" << mesh_.nCells() << " of which" << nl
5059  << " primitive:" << (mesh_.nCells()-nSplitHex-nUnrecognised)
5060  << nl
5061  << " split-hex:" << nSplitHex << nl
5062  << " poly :" << nUnrecognised << nl
5063  << endl;
5064  }
5065  }
5066  return *cellShapesPtr_;
5067 }
5068 
5069 
5071 {
5072  if (debug)
5073  {
5074  checkRefinementLevels(-1, labelList(0));
5075  }
5076 
5077  if (debug)
5078  {
5079  Pout<< "hexRef8::getSplitPoints :"
5080  << " Calculating unrefineable points" << endl;
5081  }
5082 
5083 
5084  if (!history_.active())
5085  {
5087  << "Only call if constructed with history capability"
5088  << abort(FatalError);
5089  }
5090 
5091  // Master cell
5092  // -1 undetermined
5093  // -2 certainly not split point
5094  // >= label of master cell
5095  labelList splitMaster(mesh_.nPoints(), -1);
5096  labelList splitMasterLevel(mesh_.nPoints(), Zero);
5097 
5098  // Unmark all with not 8 cells
5099  //const labelListList& pointCells = mesh_.pointCells();
5100 
5101  for (label pointi = 0; pointi < mesh_.nPoints(); pointi++)
5102  {
5103  const labelList& pCells = mesh_.pointCells(pointi);
5104 
5105  if (pCells.size() != 8)
5106  {
5107  splitMaster[pointi] = -2;
5108  }
5109  }
5110 
5111  // Unmark all with different master cells
5112  const labelList& visibleCells = history_.visibleCells();
5113 
5114  forAll(visibleCells, celli)
5115  {
5116  const labelList& cPoints = mesh_.cellPoints(celli);
5117 
5118  if (visibleCells[celli] != -1 && history_.parentIndex(celli) >= 0)
5119  {
5120  label parentIndex = history_.parentIndex(celli);
5121 
5122  // Check same master.
5123  forAll(cPoints, i)
5124  {
5125  label pointi = cPoints[i];
5126 
5127  label masterCelli = splitMaster[pointi];
5128 
5129  if (masterCelli == -1)
5130  {
5131  // First time visit of point. Store parent cell and
5132  // level of the parent cell (with respect to celli). This
5133  // is additional guarantee that we're referring to the
5134  // same master at the same refinement level.
5135 
5136  splitMaster[pointi] = parentIndex;
5137  splitMasterLevel[pointi] = cellLevel_[celli] - 1;
5138  }
5139  else if (masterCelli == -2)
5140  {
5141  // Already decided that point is not splitPoint
5142  }
5143  else if
5144  (
5145  (masterCelli != parentIndex)
5146  || (splitMasterLevel[pointi] != cellLevel_[celli] - 1)
5147  )
5148  {
5149  // Different masters so point is on two refinement
5150  // patterns
5151  splitMaster[pointi] = -2;
5152  }
5153  }
5154  }
5155  else
5156  {
5157  // Either not visible or is unrefined cell
5158  forAll(cPoints, i)
5159  {
5160  label pointi = cPoints[i];
5161 
5162  splitMaster[pointi] = -2;
5163  }
5164  }
5165  }
5166 
5167  // Unmark boundary faces
5168  for
5169  (
5170  label facei = mesh_.nInternalFaces();
5171  facei < mesh_.nFaces();
5172  facei++
5173  )
5174  {
5175  const face& f = mesh_.faces()[facei];
5176 
5177  forAll(f, fp)
5178  {
5179  splitMaster[f[fp]] = -2;
5180  }
5181  }
5182 
5183 
5184  // Collect into labelList
5185 
5186  label nSplitPoints = 0;
5187 
5188  forAll(splitMaster, pointi)
5189  {
5190  if (splitMaster[pointi] >= 0)
5191  {
5192  nSplitPoints++;
5193  }
5194  }
5195 
5196  labelList splitPoints(nSplitPoints);
5197  nSplitPoints = 0;
5198 
5199  forAll(splitMaster, pointi)
5200  {
5201  if (splitMaster[pointi] >= 0)
5202  {
5203  splitPoints[nSplitPoints++] = pointi;
5204  }
5205  }
5206 
5207  return splitPoints;
5208 }
5209 
5210 
5211 //void Foam::hexRef8::markIndex
5212 //(
5213 // const label maxLevel,
5214 // const label level,
5215 // const label index,
5216 // const label markValue,
5217 // labelList& indexValues
5218 //) const
5219 //{
5220 // if (level < maxLevel && indexValues[index] == -1)
5221 // {
5222 // // Mark
5223 // indexValues[index] = markValue;
5224 //
5225 // // Mark parent
5226 // const splitCell8& split = history_.splitCells()[index];
5227 //
5228 // if (split.parent_ >= 0)
5229 // {
5230 // markIndex
5231 // (
5232 // maxLevel, level+1, split.parent_, markValue, indexValues);
5233 // )
5234 // }
5235 // }
5236 //}
5237 //
5238 //
5243 //void Foam::hexRef8::markCellClusters
5244 //(
5245 // const label maxLevel,
5246 // labelList& cluster
5247 //) const
5248 //{
5249 // cluster.setSize(mesh_.nCells());
5250 // cluster = -1;
5251 //
5252 // const DynamicList<splitCell8>& splitCells = history_.splitCells();
5253 //
5254 // // Mark all splitCells down to level maxLevel with a cell originating from
5255 // // it.
5256 //
5257 // labelList indexLevel(splitCells.size(), -1);
5258 //
5259 // forAll(visibleCells, celli)
5260 // {
5261 // label index = visibleCells[celli];
5262 //
5263 // if (index >= 0)
5264 // {
5265 // markIndex(maxLevel, 0, index, celli, indexLevel);
5266 // }
5267 // }
5268 //
5269 // // Mark cells with splitCell
5270 //}
5271 
5272 
5275  const labelList& pointsToUnrefine,
5276  const bool maxSet
5277 ) const
5278 {
5279  if (debug)
5280  {
5281  Pout<< "hexRef8::consistentUnrefinement :"
5282  << " Determining 2:1 consistent unrefinement" << endl;
5283  }
5284 
5285  if (maxSet)
5286  {
5288  << "maxSet not implemented yet."
5289  << abort(FatalError);
5290  }
5291 
5292  // Loop, modifying pointsToUnrefine, until no more changes to due to 2:1
5293  // conflicts.
5294  // maxSet = false : unselect points to refine
5295  // maxSet = true: select points to refine
5296 
5297  // Maintain bitset for pointsToUnrefine and cellsToUnrefine
5298  bitSet unrefinePoint(mesh_.nPoints(), pointsToUnrefine);
5299 
5300  while (true)
5301  {
5302  // Construct cells to unrefine
5303  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5304 
5305  bitSet unrefineCell(mesh_.nCells());
5306 
5307  forAll(unrefinePoint, pointi)
5308  {
5309  if (unrefinePoint.test(pointi))
5310  {
5311  const labelList& pCells = mesh_.pointCells(pointi);
5312 
5313  unrefineCell.set(pCells);
5314  }
5315  }
5316 
5317 
5318  label nChanged = 0;
5319 
5320 
5321  // Check 2:1 consistency taking refinement into account
5322  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5323 
5324  // Internal faces.
5325  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
5326  {
5327  label own = mesh_.faceOwner()[facei];
5328  label nei = mesh_.faceNeighbour()[facei];
5329 
5330  label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5331  label neiLevel = cellLevel_[nei] - unrefineCell.get(nei);
5332 
5333  if (ownLevel < (neiLevel-1))
5334  {
5335  // Since was 2:1 this can only occur if own is marked for
5336  // unrefinement.
5337 
5338  if (maxSet)
5339  {
5340  unrefineCell.set(nei);
5341  }
5342  else
5343  {
5344  // could also combine with unset:
5345  // if (!unrefineCell.unset(own))
5346  // {
5347  // FatalErrorInFunction
5348  // << "problem cell already unset"
5349  // << abort(FatalError);
5350  // }
5351  if (!unrefineCell.test(own))
5352  {
5354  << "problem" << abort(FatalError);
5355  }
5356 
5357  unrefineCell.unset(own);
5358  }
5359  nChanged++;
5360  }
5361  else if (neiLevel < (ownLevel-1))
5362  {
5363  if (maxSet)
5364  {
5365  unrefineCell.set(own);
5366  }
5367  else
5368  {
5369  if (!unrefineCell.test(nei))
5370  {
5372  << "problem" << abort(FatalError);
5373  }
5374 
5375  unrefineCell.unset(nei);
5376  }
5377  nChanged++;
5378  }
5379  }
5380 
5381 
5382  // Coupled faces. Swap owner level to get neighbouring cell level.
5383  labelList neiLevel(mesh_.nBoundaryFaces());
5384 
5385  forAll(neiLevel, i)
5386  {
5387  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
5388 
5389  neiLevel[i] = cellLevel_[own] - unrefineCell.get(own);
5390  }
5391 
5392  // Swap to neighbour
5393  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
5394 
5395  forAll(neiLevel, i)
5396  {
5397  label facei = i+mesh_.nInternalFaces();
5398  label own = mesh_.faceOwner()[facei];
5399  label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5400 
5401  if (ownLevel < (neiLevel[i]-1))
5402  {
5403  if (!maxSet)
5404  {
5405  if (!unrefineCell.test(own))
5406  {
5408  << "problem" << abort(FatalError);
5409  }
5410 
5411  unrefineCell.unset(own);
5412  nChanged++;
5413  }
5414  }
5415  else if (neiLevel[i] < (ownLevel-1))
5416  {
5417  if (maxSet)
5418  {
5419  if (unrefineCell.test(own))
5420  {
5422  << "problem" << abort(FatalError);
5423  }
5424 
5425  unrefineCell.set(own);
5426  nChanged++;
5427  }
5428  }
5429  }
5430 
5431  reduce(nChanged, sumOp<label>());
5432 
5433  if (debug)
5434  {
5435  Pout<< "hexRef8::consistentUnrefinement :"
5436  << " Changed " << nChanged
5437  << " refinement levels due to 2:1 conflicts."
5438  << endl;
5439  }
5440 
5441  if (nChanged == 0)
5442  {
5443  break;
5444  }
5445 
5446 
5447  // Convert cellsToUnrefine back into points to unrefine
5448  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5449 
5450  // Knock out any point whose cell neighbour cannot be unrefined.
5451  forAll(unrefinePoint, pointi)
5452  {
5453  if (unrefinePoint.test(pointi))
5454  {
5455  const labelList& pCells = mesh_.pointCells(pointi);
5456 
5457  forAll(pCells, j)
5458  {
5459  if (!unrefineCell.test(pCells[j]))
5460  {
5461  unrefinePoint.unset(pointi);
5462  break;
5463  }
5464  }
5465  }
5466  }
5467  }
5468 
5469 
5470  // Convert back to labelList.
5471  label nSet = 0;
5472 
5473  forAll(unrefinePoint, pointi)
5474  {
5475  if (unrefinePoint.test(pointi))
5476  {
5477  nSet++;
5478  }
5479  }
5480 
5481  labelList newPointsToUnrefine(nSet);
5482  nSet = 0;
5483 
5484  forAll(unrefinePoint, pointi)
5485  {
5486  if (unrefinePoint.test(pointi))
5487  {
5488  newPointsToUnrefine[nSet++] = pointi;
5489  }
5490  }
5491 
5492  return newPointsToUnrefine;
5493 }
5494 
5495 
5498  const labelList& splitPointLabels,
5499  polyTopoChange& meshMod
5500 )
5501 {
5502  if (!history_.active())
5503  {
5505  << "Only call if constructed with history capability"
5506  << abort(FatalError);
5507  }
5508 
5509  if (debug)
5510  {
5511  Pout<< "hexRef8::setUnrefinement :"
5512  << " Checking initial mesh just to make sure" << endl;
5513 
5514  checkMesh();
5515 
5516  forAll(cellLevel_, celli)
5517  {
5518  if (cellLevel_[celli] < 0)
5519  {
5521  << "Illegal cell level " << cellLevel_[celli]
5522  << " for cell " << celli
5523  << abort(FatalError);
5524  }
5525  }
5526 
5527 
5528  // Write to sets.
5529  pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5530  pSet.write();
5531 
5532  cellSet cSet(mesh_, "splitPointCells", splitPointLabels.size());
5533 
5534  forAll(splitPointLabels, i)
5535  {
5536  const labelList& pCells = mesh_.pointCells(splitPointLabels[i]);
5537 
5538  cSet.insert(pCells);
5539  }
5540  cSet.write();
5541 
5542  Pout<< "hexRef8::setRefinement : Dumping " << pSet.size()
5543  << " points and "
5544  << cSet.size() << " cells for unrefinement to" << nl
5545  << " pointSet " << pSet.objectPath() << nl
5546  << " cellSet " << cSet.objectPath()
5547  << endl;
5548  }
5549 
5550 
5551  labelList cellRegion;
5552  labelList cellRegionMaster;
5553  labelList facesToRemove;
5554 
5555  {
5556  labelHashSet splitFaces(12*splitPointLabels.size());
5557 
5558  forAll(splitPointLabels, i)
5559  {
5560  const labelList& pFaces = mesh_.pointFaces()[splitPointLabels[i]];
5561 
5562  splitFaces.insert(pFaces);
5563  }
5564 
5565  // Check with faceRemover what faces will get removed. Note that this
5566  // can be more (but never less) than splitFaces provided.
5567  faceRemover_.compatibleRemoves
5568  (
5569  splitFaces.toc(), // pierced faces
5570  cellRegion, // per cell -1 or region it is merged into
5571  cellRegionMaster, // per region the master cell
5572  facesToRemove // new faces to be removed.
5573  );
5574 
5575  if (facesToRemove.size() != splitFaces.size())
5576  {
5577  // Dump current mesh
5578  {
5579  const_cast<polyMesh&>(mesh_).setInstance
5580  (
5581  mesh_.time().timeName()
5582  );
5583  mesh_.write();
5584  pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5585  pSet.write();
5586  faceSet fSet(mesh_, "splitFaces", splitFaces);
5587  fSet.write();
5588  faceSet removeSet(mesh_, "facesToRemove", facesToRemove);
5589  removeSet.write();
5590  }
5591 
5593  << "Ininitial set of split points to unrefine does not"
5594  << " seem to be consistent or not mid points of refined cells"
5595  << " splitPoints:" << splitPointLabels.size()
5596  << " splitFaces:" << splitFaces.size()
5597  << " facesToRemove:" << facesToRemove.size()
5598  << abort(FatalError);
5599  }
5600  }
5601 
5602  // Redo the region master so it is consistent with our master.
5603  // This will guarantee that the new cell (for which faceRemover uses
5604  // the region master) is already compatible with our refinement structure.
5605 
5606  forAll(splitPointLabels, i)
5607  {
5608  label pointi = splitPointLabels[i];
5609 
5610  // Get original cell label
5611 
5612  const labelList& pCells = mesh_.pointCells(pointi);
5613 
5614  // Check
5615  if (pCells.size() != 8)
5616  {
5618  << "splitPoint " << pointi
5619  << " should have 8 cells using it. It has " << pCells
5620  << abort(FatalError);
5621  }
5622 
5623 
5624  // Check that the lowest numbered pCells is the master of the region
5625  // (should be guaranteed by directRemoveFaces)
5626  //if (debug)
5627  {
5628  label masterCelli = min(pCells);
5629 
5630  forAll(pCells, j)
5631  {
5632  label celli = pCells[j];
5633 
5634  label region = cellRegion[celli];
5635 
5636  if (region == -1)
5637  {
5639  << "Ininitial set of split points to unrefine does not"
5640  << " seem to be consistent or not mid points"
5641  << " of refined cells" << nl
5642  << "cell:" << celli << " on splitPoint " << pointi
5643  << " has no region to be merged into"
5644  << abort(FatalError);
5645  }
5646 
5647  if (masterCelli != cellRegionMaster[region])
5648  {
5650  << "cell:" << celli << " on splitPoint:" << pointi
5651  << " in region " << region
5652  << " has master:" << cellRegionMaster[region]
5653  << " which is not the lowest numbered cell"
5654  << " among the pointCells:" << pCells
5655  << abort(FatalError);
5656  }
5657  }
5658  }
5659  }
5660 
5661  // Insert all commands to combine cells. Never fails so don't have to
5662  // test for success.
5663  faceRemover_.setRefinement
5664  (
5665  facesToRemove,
5666  cellRegion,
5667  cellRegionMaster,
5668  meshMod
5669  );
5670 
5671  // Remove the 8 cells that originated from merging around the split point
5672  // and adapt cell levels (not that pointLevels stay the same since points
5673  // either get removed or stay at the same position.
5674  forAll(splitPointLabels, i)
5675  {
5676  label pointi = splitPointLabels[i];
5677 
5678  const labelList& pCells = mesh_.pointCells(pointi);
5679 
5680  label masterCelli = min(pCells);
5681 
5682  forAll(pCells, j)
5683  {
5684  cellLevel_[pCells[j]]--;
5685  }
5686 
5687  history_.combineCells(masterCelli, pCells);
5688  }
5689 
5690  // Mark files as changed
5691  setInstance(mesh_.facesInstance());
5692 
5693  // history_.updateMesh will take care of truncating.
5694 }
5695 
5696 
5697 // Write refinement to polyMesh directory.
5698 bool Foam::hexRef8::write(const bool valid) const
5699 {
5700  bool writeOk =
5701  cellLevel_.write(valid)
5702  && pointLevel_.write(valid)
5703  && level0Edge_.write(valid);
5704 
5705  if (history_.active())
5706  {
5707  writeOk = writeOk && history_.write(valid);
5708  }
5709  else
5710  {
5712  }
5713 
5714  return writeOk;
5715 }
5716 
5717 
5719 {
5720  IOobject io
5721  (
5722  "dummy",
5723  mesh.facesInstance(),
5724  mesh.meshSubDir,
5725  mesh
5726  );
5727  fileName setsDir(io.path());
5728 
5729  if (topoSet::debug) DebugVar(setsDir);
5730 
5731  if (exists(setsDir/"cellLevel"))
5732  {
5733  rm(setsDir/"cellLevel");
5734  }
5735  if (exists(setsDir/"pointLevel"))
5736  {
5737  rm(setsDir/"pointLevel");
5738  }
5739  if (exists(setsDir/"level0Edge"))
5740  {
5741  rm(setsDir/"level0Edge");
5742  }
5744 }
5745 
5746 
5747 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::refinementHistory::visibleCells
const labelList & visibleCells() const
Definition: refinementHistory.H:268
Foam::HashTable::size
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
Foam::reverse
void reverse(UList< T > &list, const label n)
Definition: UListI.H:396
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:104
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:69
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:62
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:53
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:447
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:5070
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:329
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:5698
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:4236
Foam::syncTools::swapBoundaryFaceList
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:439
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:994
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
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:5718
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:5010
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:2255
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:724
Foam::sumOp
Definition: ops.H:213
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:390
Foam::FaceCellWave::setFaceInfo
void setFaceInfo(const label facei, const Type &faceInfo)
Set single initial changed face.
Definition: FaceCellWave.C:318
Foam::hexRef8::setRefinement
labelListList setRefinement(const labelList &cells, polyTopoChange &)
Insert refinement. All selected cells will be split into 8.
Definition: hexRef8.C:3195
labelPairHashes.H
A HashTable to objects of type <T> with a labelPair key. The hashing is based on labelPair (FixedList...
Foam::primitiveMesh::nCells
label nCells() const
Number of mesh cells.
Definition: primitiveMeshI.H:96
Foam::hexRef8::checkRefinementLevels
void checkRefinementLevels(const label maxPointDiff, const labelList &pointsToCheck) const
Debug: Check 2:1 consistency across faces.
Definition: hexRef8.C:4758
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
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]=cellShape(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::Field< vector >
Foam::regIOobject::write
virtual bool write(const bool valid=true) const
Write using setting from DB.
Definition: regIOobjectWrite.C:165
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:286
hexRef8.H
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
degenerateMatcher.H
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:107
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:474
Foam::syncTools::syncEdgeList
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh edges.
Definition: syncToolsTemplates.C:803
patchID
label patchID
Definition: boundaryProcessorFaPatchPoints.H:5
faceSet.H
Foam::List::transfer
void transfer(List< T > &list)
Definition: List.C:459
Foam::IOobject::READ_IF_PRESENT
Definition: IOobject.H:122
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:39
Foam::hexRef8::subset
void subset(const labelList &pointMap, const labelList &faceMap, const labelList &cellMap)
Update local numbering for subsetted mesh.
Definition: hexRef8.C:4438
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:2795
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:313
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:4209
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
refinementData.H
Foam::HashTable< label, labelPair, labelPair::Hash<> >
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:2311
Time.H
Foam::hexRef8::setUnrefinement
void setUnrefinement(const labelList &splitPointLabels, polyTopoChange &)
Remove some refinement. Needs to be supplied output of.
Definition: hexRef8.C:5497
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:381
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:2460
Foam::nl
constexpr char nl
Definition: Ostream.H:385
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::IOobject::readOpt
readOption readOpt() const
The read option.
Definition: IOobjectI.H:165
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::primitiveMesh::nPoints
label nPoints() const
Number of mesh points.
Definition: primitiveMeshI.H:37
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:115
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:325
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::hexRef8::distribute
void distribute(const mapDistributePolyMesh &)
Update local numbering for mesh redistribution.
Definition: hexRef8.C:4521
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
cellSet.H
Foam::hexRef8::checkMesh
void checkMesh() const
Debug: Check coupled mesh for correctness.
Definition: hexRef8.C:4549
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:5274
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:80
Foam::IOobject::objectPath
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:209
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::IOobject::NO_READ
Definition: IOobject.H:123
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:381
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::patchIdentifier::name
const word & name() const
The patch name.
Definition: patchIdentifier.H:134
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:303
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:372
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