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