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