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 = magSqr(e.vec(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::listCombineReduce(typEdgeLenSqr, minEqOp<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 = magSqr(e.vec(mesh_.points()));
472 
473  maxEdgeLenSqr[cLevel] = max(maxEdgeLenSqr[cLevel], edgeLenSqr);
474  }
475  }
476 
477  Pstream::listCombineReduce(maxEdgeLenSqr, maxEqOp<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  // From edge mid to anchor points
1202  Map<edge> midPointToAnchors(24);
1203  // From edge mid to face mids
1204  Map<edge> midPointToFaceMids(24);
1205 
1206  // Storage for on-the-fly addressing
1207  DynamicList<label> storage;
1208 
1209 
1210  // Running count of number of internal faces added so far.
1211  label nFacesAdded = 0;
1212 
1213  forAll(cFaces, i)
1214  {
1215  label facei = cFaces[i];
1216 
1217  const face& f = mesh_.faces()[facei];
1218  const labelList& fEdges = mesh_.faceEdges(facei, storage);
1219 
1220  // We are on the celli side of face f. The face will have 1 or 4
1221  // cLevel points and lots of higher numbered ones.
1222 
1223  label faceMidPointi = -1;
1224 
1225  label nAnchors = countAnchors(f, cLevel);
1226 
1227  if (nAnchors == 1)
1228  {
1229  // Only one anchor point. So the other side of the face has already
1230  // been split using cLevel+1 and cLevel+2 points.
1231 
1232  // Find the one anchor.
1233  label anchorFp = -1;
1234 
1235  forAll(f, fp)
1236  {
1237  if (pointLevel_[f[fp]] <= cLevel)
1238  {
1239  anchorFp = fp;
1240  break;
1241  }
1242  }
1243 
1244  // Now the face mid point is the second cLevel+1 point
1245  label edgeMid = findLevel
1246  (
1247  facei,
1248  f,
1249  f.fcIndex(anchorFp),
1250  true,
1251  cLevel+1
1252  );
1253  label faceMid = findLevel
1254  (
1255  facei,
1256  f,
1257  f.fcIndex(edgeMid),
1258  true,
1259  cLevel+1
1260  );
1261 
1262  faceMidPointi = f[faceMid];
1263  }
1264  else if (nAnchors == 4)
1265  {
1266  // There is no face middle yet but the face will be marked for
1267  // splitting.
1268 
1269  faceMidPointi = faceMidPoint[facei];
1270  }
1271  else
1272  {
1273  dumpCell(mesh_.faceOwner()[facei]);
1274  if (mesh_.isInternalFace(facei))
1275  {
1276  dumpCell(mesh_.faceNeighbour()[facei]);
1277  }
1278 
1280  << "nAnchors:" << nAnchors
1281  << " facei:" << facei
1282  << abort(FatalError);
1283  }
1284 
1285 
1286 
1287  // Now loop over all the anchors (might be just one) and store
1288  // the edge mids connected to it. storeMidPointInfo will collect
1289  // all the info and combine it all.
1290 
1291  forAll(f, fp0)
1292  {
1293  label point0 = f[fp0];
1294 
1295  if (pointLevel_[point0] <= cLevel)
1296  {
1297  // Anchor.
1298 
1299  // Walk forward
1300  // ~~~~~~~~~~~~
1301  // to cLevel+1 or edgeMidPoint of this level.
1302 
1303 
1304  label edgeMidPointi = -1;
1305 
1306  label fp1 = f.fcIndex(fp0);
1307 
1308  if (pointLevel_[f[fp1]] <= cLevel)
1309  {
1310  // Anchor. Edge will be split.
1311  label edgeI = fEdges[fp0];
1312 
1313  edgeMidPointi = edgeMidPoint[edgeI];
1314 
1315  if (edgeMidPointi == -1)
1316  {
1317  dumpCell(celli);
1318 
1319  const labelList& cPoints = mesh_.cellPoints(celli);
1320 
1322  << "cell:" << celli << " cLevel:" << cLevel
1323  << " cell points:" << cPoints
1324  << " pointLevel:"
1325  << labelUIndList(pointLevel_, cPoints)
1326  << " face:" << facei
1327  << " f:" << f
1328  << " pointLevel:"
1329  << labelUIndList(pointLevel_, f)
1330  << " faceAnchorLevel:" << faceAnchorLevel[facei]
1331  << " faceMidPoint:" << faceMidPoint[facei]
1332  << " faceMidPointi:" << faceMidPointi
1333  << " fp:" << fp0
1334  << abort(FatalError);
1335  }
1336  }
1337  else
1338  {
1339  // Search forward in face to clevel+1
1340  label edgeMid = findLevel(facei, f, fp1, true, cLevel+1);
1341 
1342  edgeMidPointi = f[edgeMid];
1343  }
1344 
1345  label newFacei = storeMidPointInfo
1346  (
1347  cellAnchorPoints,
1348  cellAddedCells,
1349  cellMidPoint,
1350  edgeMidPoint,
1351 
1352  celli,
1353  facei,
1354  true, // mid point after anchor
1355  edgeMidPointi, // edgemid
1356  point0, // anchor
1357  faceMidPointi,
1358 
1359  midPointToAnchors,
1360  midPointToFaceMids,
1361  meshMod
1362  );
1363 
1364  if (newFacei != -1)
1365  {
1366  nFacesAdded++;
1367 
1368  if (nFacesAdded == 12)
1369  {
1370  break;
1371  }
1372  }
1373 
1374 
1375 
1376  // Walk backward
1377  // ~~~~~~~~~~~~~
1378 
1379  label fpMin1 = f.rcIndex(fp0);
1380 
1381  if (pointLevel_[f[fpMin1]] <= cLevel)
1382  {
1383  // Anchor. Edge will be split.
1384  label edgeI = fEdges[fpMin1];
1385 
1386  edgeMidPointi = edgeMidPoint[edgeI];
1387 
1388  if (edgeMidPointi == -1)
1389  {
1390  dumpCell(celli);
1391 
1392  const labelList& cPoints = mesh_.cellPoints(celli);
1393 
1395  << "cell:" << celli << " cLevel:" << cLevel
1396  << " cell points:" << cPoints
1397  << " pointLevel:"
1398  << labelUIndList(pointLevel_, cPoints)
1399  << " face:" << facei
1400  << " f:" << f
1401  << " pointLevel:"
1402  << labelUIndList(pointLevel_, f)
1403  << " faceAnchorLevel:" << faceAnchorLevel[facei]
1404  << " faceMidPoint:" << faceMidPoint[facei]
1405  << " faceMidPointi:" << faceMidPointi
1406  << " fp:" << fp0
1407  << abort(FatalError);
1408  }
1409  }
1410  else
1411  {
1412  // Search back to clevel+1
1413  label edgeMid = findLevel
1414  (
1415  facei,
1416  f,
1417  fpMin1,
1418  false,
1419  cLevel+1
1420  );
1421 
1422  edgeMidPointi = f[edgeMid];
1423  }
1424 
1425  newFacei = storeMidPointInfo
1426  (
1427  cellAnchorPoints,
1428  cellAddedCells,
1429  cellMidPoint,
1430  edgeMidPoint,
1431 
1432  celli,
1433  facei,
1434  false, // mid point before anchor
1435  edgeMidPointi, // edgemid
1436  point0, // anchor
1437  faceMidPointi,
1438 
1439  midPointToAnchors,
1440  midPointToFaceMids,
1441  meshMod
1442  );
1443 
1444  if (newFacei != -1)
1445  {
1446  nFacesAdded++;
1447 
1448  if (nFacesAdded == 12)
1449  {
1450  break;
1451  }
1452  }
1453  } // done anchor
1454  } // done face
1455 
1456  if (nFacesAdded == 12)
1457  {
1458  break;
1459  }
1460  }
1461 }
1462 
1463 
1464 void Foam::hexRef8::walkFaceToMid
1465 (
1466  const labelList& edgeMidPoint,
1467  const label cLevel,
1468  const label facei,
1469  const label startFp,
1470  DynamicList<label>& faceVerts
1471 ) const
1472 {
1473  const face& f = mesh_.faces()[facei];
1474  const labelList& fEdges = mesh_.faceEdges(facei);
1475 
1476  label fp = startFp;
1477 
1478  // Starting from fp store all (1 or 2) vertices until where the face
1479  // gets split
1480 
1481  while (true)
1482  {
1483  if (edgeMidPoint[fEdges[fp]] >= 0)
1484  {
1485  faceVerts.append(edgeMidPoint[fEdges[fp]]);
1486  }
1487 
1488  fp = f.fcIndex(fp);
1489 
1490  if (pointLevel_[f[fp]] <= cLevel)
1491  {
1492  // Next anchor. Have already append split point on edge in code
1493  // above.
1494  return;
1495  }
1496  else if (pointLevel_[f[fp]] == cLevel+1)
1497  {
1498  // Mid level
1499  faceVerts.append(f[fp]);
1500 
1501  return;
1502  }
1503  else if (pointLevel_[f[fp]] == cLevel+2)
1504  {
1505  // Store and continue to cLevel+1.
1506  faceVerts.append(f[fp]);
1507  }
1508  }
1509 }
1510 
1511 
1512 // Same as walkFaceToMid but now walk back.
1513 void Foam::hexRef8::walkFaceFromMid
1514 (
1515  const labelList& edgeMidPoint,
1516  const label cLevel,
1517  const label facei,
1518  const label startFp,
1519  DynamicList<label>& faceVerts
1520 ) const
1521 {
1522  const face& f = mesh_.faces()[facei];
1523  const labelList& fEdges = mesh_.faceEdges(facei);
1524 
1525  label fp = f.rcIndex(startFp);
1526 
1527  while (true)
1528  {
1529  if (pointLevel_[f[fp]] <= cLevel)
1530  {
1531  // anchor.
1532  break;
1533  }
1534  else if (pointLevel_[f[fp]] == cLevel+1)
1535  {
1536  // Mid level
1537  faceVerts.append(f[fp]);
1538  break;
1539  }
1540  else if (pointLevel_[f[fp]] == cLevel+2)
1541  {
1542  // Continue to cLevel+1.
1543  }
1544  fp = f.rcIndex(fp);
1545  }
1546 
1547  // Store
1548  while (true)
1549  {
1550  if (edgeMidPoint[fEdges[fp]] >= 0)
1551  {
1552  faceVerts.append(edgeMidPoint[fEdges[fp]]);
1553  }
1554 
1555  fp = f.fcIndex(fp);
1556 
1557  if (fp == startFp)
1558  {
1559  break;
1560  }
1561  faceVerts.append(f[fp]);
1562  }
1563 }
1564 
1565 
1566 // Updates refineCell (cells marked for refinement) so across all faces
1567 // there will be 2:1 consistency after refinement.
1568 Foam::label Foam::hexRef8::faceConsistentRefinement
1569 (
1570  const bool maxSet,
1571  const labelUList& cellLevel,
1572  bitSet& refineCell
1573 ) const
1574 {
1575  label nChanged = 0;
1576 
1577  // Internal faces.
1578  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1579  {
1580  label own = mesh_.faceOwner()[facei];
1581  label ownLevel = cellLevel[own] + refineCell.get(own);
1582 
1583  label nei = mesh_.faceNeighbour()[facei];
1584  label neiLevel = cellLevel[nei] + refineCell.get(nei);
1585 
1586  if (ownLevel > (neiLevel+1))
1587  {
1588  if (maxSet)
1589  {
1590  refineCell.set(nei);
1591  }
1592  else
1593  {
1594  refineCell.unset(own);
1595  }
1596  nChanged++;
1597  }
1598  else if (neiLevel > (ownLevel+1))
1599  {
1600  if (maxSet)
1601  {
1602  refineCell.set(own);
1603  }
1604  else
1605  {
1606  refineCell.unset(nei);
1607  }
1608  nChanged++;
1609  }
1610  }
1611 
1612 
1613  // Coupled faces. Swap owner level to get neighbouring cell level.
1614  // (only boundary faces of neiLevel used)
1615  labelList neiLevel(mesh_.nBoundaryFaces());
1616 
1617  forAll(neiLevel, i)
1618  {
1619  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1620 
1621  neiLevel[i] = cellLevel[own] + refineCell.get(own);
1622  }
1623 
1624  // Swap to neighbour
1625  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
1626 
1627  // Now we have neighbour value see which cells need refinement
1628  forAll(neiLevel, i)
1629  {
1630  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1631  label ownLevel = cellLevel[own] + refineCell.get(own);
1632 
1633  if (ownLevel > (neiLevel[i]+1))
1634  {
1635  if (!maxSet)
1636  {
1637  refineCell.unset(own);
1638  nChanged++;
1639  }
1640  }
1641  else if (neiLevel[i] > (ownLevel+1))
1642  {
1643  if (maxSet)
1644  {
1645  refineCell.set(own);
1646  nChanged++;
1647  }
1648  }
1649  }
1650 
1651  return nChanged;
1652 }
1653 
1654 
1655 // Debug: check if wanted refinement is compatible with 2:1
1656 void Foam::hexRef8::checkWantedRefinementLevels
1657 (
1658  const labelUList& cellLevel,
1659  const labelList& cellsToRefine
1660 ) const
1661 {
1662  bitSet refineCell(mesh_.nCells(), cellsToRefine);
1663 
1664  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1665  {
1666  label own = mesh_.faceOwner()[facei];
1667  label ownLevel = cellLevel[own] + refineCell.get(own);
1668 
1669  label nei = mesh_.faceNeighbour()[facei];
1670  label neiLevel = cellLevel[nei] + refineCell.get(nei);
1671 
1672  if (mag(ownLevel-neiLevel) > 1)
1673  {
1674  dumpCell(own);
1675  dumpCell(nei);
1677  << "cell:" << own
1678  << " current level:" << cellLevel[own]
1679  << " level after refinement:" << ownLevel
1680  << nl
1681  << "neighbour cell:" << nei
1682  << " current level:" << cellLevel[nei]
1683  << " level after refinement:" << neiLevel
1684  << nl
1685  << "which does not satisfy 2:1 constraints anymore."
1686  << abort(FatalError);
1687  }
1688  }
1689 
1690  // Coupled faces. Swap owner level to get neighbouring cell level.
1691  // (only boundary faces of neiLevel used)
1692  labelList neiLevel(mesh_.nBoundaryFaces());
1693 
1694  forAll(neiLevel, i)
1695  {
1696  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1697 
1698  neiLevel[i] = cellLevel[own] + refineCell.get(own);
1699  }
1700 
1701  // Swap to neighbour
1702  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
1703 
1704  // Now we have neighbour value see which cells need refinement
1705  forAll(neiLevel, i)
1706  {
1707  label facei = i + mesh_.nInternalFaces();
1708 
1709  label own = mesh_.faceOwner()[facei];
1710  label ownLevel = cellLevel[own] + refineCell.get(own);
1711 
1712  if (mag(ownLevel - neiLevel[i]) > 1)
1713  {
1714  label patchi = mesh_.boundaryMesh().whichPatch(facei);
1715 
1716  dumpCell(own);
1718  << "Celllevel does not satisfy 2:1 constraint."
1719  << " On coupled face "
1720  << facei
1721  << " on patch " << patchi << " "
1722  << mesh_.boundaryMesh()[patchi].name()
1723  << " owner cell " << own
1724  << " current level:" << cellLevel[own]
1725  << " level after refinement:" << ownLevel
1726  << nl
1727  << " (coupled) neighbour cell will get refinement "
1728  << neiLevel[i]
1729  << abort(FatalError);
1730  }
1731  }
1732 }
1733 
1734 
1735 // Set instance for mesh files
1736 void Foam::hexRef8::setInstance(const fileName& inst)
1737 {
1738  if (debug)
1739  {
1740  Pout<< "hexRef8::setInstance(const fileName& inst) : "
1741  << "Resetting file instance to " << inst << endl;
1742  }
1743 
1744  cellLevel_.instance() = inst;
1745  pointLevel_.instance() = inst;
1746  level0Edge_.instance() = inst;
1747  history_.instance() = inst;
1748 }
1749 
1750 
1751 void Foam::hexRef8::collectLevelPoints
1752 (
1753  const labelList& f,
1754  const label level,
1755  DynamicList<label>& points
1756 ) const
1757 {
1758  forAll(f, fp)
1759  {
1760  if (pointLevel_[f[fp]] <= level)
1761  {
1762  points.append(f[fp]);
1763  }
1764  }
1765 }
1766 
1767 
1768 void Foam::hexRef8::collectLevelPoints
1769 (
1770  const labelList& meshPoints,
1771  const labelList& f,
1772  const label level,
1773  DynamicList<label>& points
1774 ) const
1775 {
1776  forAll(f, fp)
1777  {
1778  label pointi = meshPoints[f[fp]];
1779  if (pointLevel_[pointi] <= level)
1780  {
1781  points.append(pointi);
1782  }
1783  }
1784 }
1785 
1786 
1787 // Return true if we've found 6 quads. faces guaranteed to be outwards pointing.
1788 bool Foam::hexRef8::matchHexShape
1789 (
1790  const label celli,
1791  const label cellLevel,
1792  DynamicList<face>& quads
1793 ) const
1794 {
1795  const cell& cFaces = mesh_.cells()[celli];
1796 
1797  // Work arrays
1798  DynamicList<label> verts(4);
1799  quads.clear();
1800 
1801 
1802  // 1. pick up any faces with four cellLevel points
1803 
1804  forAll(cFaces, i)
1805  {
1806  label facei = cFaces[i];
1807  const face& f = mesh_.faces()[facei];
1808 
1809  verts.clear();
1810  collectLevelPoints(f, cellLevel, verts);
1811  if (verts.size() == 4)
1812  {
1813  if (mesh_.faceOwner()[facei] != celli)
1814  {
1815  reverse(verts);
1816  }
1817  quads.emplace_back(verts);
1818  }
1819  }
1820 
1821 
1822  if (quads.size() < 6)
1823  {
1824  Map<labelList> pointFaces(2*cFaces.size());
1825 
1826  forAll(cFaces, i)
1827  {
1828  label facei = cFaces[i];
1829  const face& f = mesh_.faces()[facei];
1830 
1831  // Pick up any faces with only one level point.
1832  // See if there are four of these where the common point
1833  // is a level+1 point. This common point is then the mid of
1834  // a split face.
1835 
1836  verts.clear();
1837  collectLevelPoints(f, cellLevel, verts);
1838  if (verts.size() == 1)
1839  {
1840  // Add to pointFaces for any level+1 point (this might be
1841  // a midpoint of a split face)
1842  for (const label pointi : f)
1843  {
1844  if (pointLevel_[pointi] == cellLevel+1)
1845  {
1846  pointFaces(pointi).push_uniq(facei);
1847  }
1848  }
1849  }
1850  }
1851 
1852  // 2. Check if we've collected any midPoints.
1853  forAllConstIters(pointFaces, iter)
1854  {
1855  const labelList& pFaces = iter.val();
1856 
1857  if (pFaces.size() == 4)
1858  {
1859  // Collect and orient.
1860  faceList fourFaces(pFaces.size());
1861  forAll(pFaces, pFacei)
1862  {
1863  label facei = pFaces[pFacei];
1864  const face& f = mesh_.faces()[facei];
1865  if (mesh_.faceOwner()[facei] == celli)
1866  {
1867  fourFaces[pFacei] = f;
1868  }
1869  else
1870  {
1871  fourFaces[pFacei] = f.reverseFace();
1872  }
1873  }
1874 
1875  primitivePatch bigFace
1876  (
1877  SubList<face>(fourFaces),
1878  mesh_.points()
1879  );
1880  const labelListList& edgeLoops = bigFace.edgeLoops();
1881 
1882  if (edgeLoops.size() == 1)
1883  {
1884  // Collect the 4 cellLevel points
1885  verts.clear();
1886  collectLevelPoints
1887  (
1888  bigFace.meshPoints(),
1889  bigFace.edgeLoops()[0],
1890  cellLevel,
1891  verts
1892  );
1893 
1894  if (verts.size() == 4)
1895  {
1896  quads.emplace_back(verts);
1897  }
1898  }
1899  }
1900  }
1901  }
1902 
1903  return (quads.size() == 6);
1904 }
1906 
1907 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1908 
1909 // Construct from mesh, read refinement data
1910 Foam::hexRef8::hexRef8(const polyMesh& mesh, const bool readHistory)
1911 :
1912  mesh_(mesh),
1913  cellLevel_
1914  (
1915  IOobject
1916  (
1917  "cellLevel",
1918  mesh_.facesInstance(),
1919  polyMesh::meshSubDir,
1920  mesh_,
1921  IOobject::READ_IF_PRESENT,
1922  IOobject::NO_WRITE
1923  ),
1924  labelList(mesh_.nCells(), Zero)
1925  ),
1926  pointLevel_
1927  (
1928  IOobject
1929  (
1930  "pointLevel",
1931  mesh_.facesInstance(),
1932  polyMesh::meshSubDir,
1933  mesh_,
1934  IOobject::READ_IF_PRESENT,
1935  IOobject::NO_WRITE
1936  ),
1937  labelList(mesh_.nPoints(), Zero)
1938  ),
1939  level0Edge_
1940  (
1941  IOobject
1942  (
1943  "level0Edge",
1944  mesh_.facesInstance(),
1945  polyMesh::meshSubDir,
1946  mesh_,
1947  IOobject::READ_IF_PRESENT,
1948  IOobject::NO_WRITE
1949  ),
1950  // Needs name:
1951  dimensionedScalar("level0Edge", dimLength, getLevel0EdgeLength())
1952  ),
1953  history_
1954  (
1955  IOobject
1956  (
1957  "refinementHistory",
1958  mesh_.facesInstance(),
1959  polyMesh::meshSubDir,
1960  mesh_,
1961  IOobject::NO_READ,
1962  IOobject::NO_WRITE
1963  ),
1964  // All cells visible if not read or readHistory = false
1965  (readHistory ? mesh_.nCells() : 0)
1966  ),
1967  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
1968  savedPointLevel_(0),
1969  savedCellLevel_(0)
1970 {
1971  if (readHistory)
1972  {
1974  if (history_.typeHeaderOk<refinementHistory>(true))
1975  {
1976  history_.read();
1977  }
1978  }
1979 
1980  if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
1981  {
1983  << "History enabled but number of visible cells "
1984  << history_.visibleCells().size() << " in "
1985  << history_.objectPath()
1986  << " is not equal to the number of cells in the mesh "
1987  << mesh_.nCells()
1988  << abort(FatalError);
1989  }
1990 
1991  if
1992  (
1993  cellLevel_.size() != mesh_.nCells()
1994  || pointLevel_.size() != mesh_.nPoints()
1995  )
1996  {
1998  << "Restarted from inconsistent cellLevel or pointLevel files."
1999  << endl
2000  << "cellLevel file " << cellLevel_.objectPath() << endl
2001  << "pointLevel file " << pointLevel_.objectPath() << endl
2002  << "Number of cells in mesh:" << mesh_.nCells()
2003  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2004  << "Number of points in mesh:" << mesh_.nPoints()
2005  << " does not equal size of pointLevel:" << pointLevel_.size()
2006  << abort(FatalError);
2007  }
2008 
2009 
2010  // Check refinement levels for consistency
2012 
2013 
2014  // Check initial mesh for consistency
2015 
2016  //if (debug)
2017  {
2018  checkMesh();
2019  }
2020 }
2021 
2022 
2023 Foam::hexRef8::hexRef8
2024 (
2025  const polyMesh& mesh,
2026  const labelList& cellLevel,
2027  const labelList& pointLevel,
2028  const refinementHistory& history,
2029  const scalar level0Edge
2030 )
2031 :
2032  mesh_(mesh),
2033  cellLevel_
2034  (
2035  IOobject
2036  (
2037  "cellLevel",
2038  mesh_.facesInstance(),
2039  polyMesh::meshSubDir,
2040  mesh_,
2041  IOobject::NO_READ,
2042  IOobject::NO_WRITE
2043  ),
2044  cellLevel
2045  ),
2046  pointLevel_
2047  (
2048  IOobject
2049  (
2050  "pointLevel",
2051  mesh_.facesInstance(),
2052  polyMesh::meshSubDir,
2053  mesh_,
2054  IOobject::NO_READ,
2055  IOobject::NO_WRITE
2056  ),
2057  pointLevel
2058  ),
2059  level0Edge_
2060  (
2061  IOobject
2062  (
2063  "level0Edge",
2064  mesh_.facesInstance(),
2065  polyMesh::meshSubDir,
2066  mesh_,
2067  IOobject::NO_READ,
2068  IOobject::NO_WRITE
2069  ),
2070  // Needs name:
2072  (
2073  "level0Edge",
2074  dimLength,
2075  (level0Edge >= 0 ? level0Edge : getLevel0EdgeLength())
2076  )
2077  ),
2078  history_
2079  (
2080  IOobject
2081  (
2082  "refinementHistory",
2083  mesh_.facesInstance(),
2084  polyMesh::meshSubDir,
2085  mesh_,
2086  IOobject::NO_READ,
2087  IOobject::NO_WRITE
2088  ),
2089  history
2090  ),
2091  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
2092  savedPointLevel_(0),
2093  savedCellLevel_(0)
2094 {
2095  if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
2096  {
2098  << "History enabled but number of visible cells in it "
2099  << history_.visibleCells().size()
2100  << " is not equal to the number of cells in the mesh "
2101  << mesh_.nCells() << abort(FatalError);
2102  }
2103 
2104  if
2105  (
2106  cellLevel_.size() != mesh_.nCells()
2107  || pointLevel_.size() != mesh_.nPoints()
2108  )
2109  {
2111  << "Incorrect cellLevel or pointLevel size." << endl
2112  << "Number of cells in mesh:" << mesh_.nCells()
2113  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2114  << "Number of points in mesh:" << mesh_.nPoints()
2115  << " does not equal size of pointLevel:" << pointLevel_.size()
2116  << abort(FatalError);
2117  }
2118 
2119  // Check refinement levels for consistency
2121 
2122 
2123  // Check initial mesh for consistency
2124 
2125  //if (debug)
2126  {
2127  checkMesh();
2128  }
2129 }
2130 
2131 
2132 Foam::hexRef8::hexRef8
2133 (
2134  const polyMesh& mesh,
2135  const labelList& cellLevel,
2136  const labelList& pointLevel,
2137  const scalar level0Edge
2138 )
2139 :
2140  mesh_(mesh),
2141  cellLevel_
2142  (
2143  IOobject
2144  (
2145  "cellLevel",
2146  mesh_.facesInstance(),
2147  polyMesh::meshSubDir,
2148  mesh_,
2149  IOobject::NO_READ,
2150  IOobject::NO_WRITE
2151  ),
2152  cellLevel
2153  ),
2154  pointLevel_
2155  (
2156  IOobject
2157  (
2158  "pointLevel",
2159  mesh_.facesInstance(),
2160  polyMesh::meshSubDir,
2161  mesh_,
2162  IOobject::NO_READ,
2163  IOobject::NO_WRITE
2164  ),
2165  pointLevel
2166  ),
2167  level0Edge_
2168  (
2169  IOobject
2170  (
2171  "level0Edge",
2172  mesh_.facesInstance(),
2173  polyMesh::meshSubDir,
2174  mesh_,
2175  IOobject::NO_READ,
2176  IOobject::NO_WRITE
2177  ),
2178  // Needs name:
2180  (
2181  "level0Edge",
2182  dimLength,
2183  (level0Edge >= 0 ? level0Edge : getLevel0EdgeLength())
2184  )
2185  ),
2186  history_
2187  (
2188  IOobject
2189  (
2190  "refinementHistory",
2191  mesh_.facesInstance(),
2192  polyMesh::meshSubDir,
2193  mesh_,
2194  IOobject::NO_READ,
2195  IOobject::NO_WRITE
2196  ),
2197  List<refinementHistory::splitCell8>(0),
2198  labelList(0),
2199  false
2200  ),
2201  faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
2202  savedPointLevel_(0),
2203  savedCellLevel_(0)
2204 {
2205  if
2206  (
2207  cellLevel_.size() != mesh_.nCells()
2208  || pointLevel_.size() != mesh_.nPoints()
2209  )
2210  {
2212  << "Incorrect cellLevel or pointLevel size." << endl
2213  << "Number of cells in mesh:" << mesh_.nCells()
2214  << " does not equal size of cellLevel:" << cellLevel_.size() << endl
2215  << "Number of points in mesh:" << mesh_.nPoints()
2216  << " does not equal size of pointLevel:" << pointLevel_.size()
2217  << abort(FatalError);
2218  }
2219 
2220  // Check refinement levels for consistency
2222 
2223  // Check initial mesh for consistency
2224 
2225  //if (debug)
2226  {
2227  checkMesh();
2228  }
2229 }
2231 
2232 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2233 
2235 (
2236  const labelUList& cellLevel,
2237  const labelList& cellsToRefine,
2238  const bool maxSet
2239 ) const
2240 {
2241  // Loop, modifying cellsToRefine, until no more changes to due to 2:1
2242  // conflicts.
2243  // maxSet = false : unselect cells to refine
2244  // maxSet = true : select cells to refine
2245 
2246  bitSet refineCell(mesh_.nCells(), cellsToRefine);
2247 
2248  while (true)
2249  {
2250  label nChanged = faceConsistentRefinement
2251  (
2252  maxSet,
2253  cellLevel,
2254  refineCell
2255  );
2256 
2257  reduce(nChanged, sumOp<label>());
2258 
2259  if (debug)
2260  {
2261  Pout<< "hexRef8::consistentRefinement : Changed " << nChanged
2262  << " refinement levels due to 2:1 conflicts."
2263  << endl;
2264  }
2265 
2266  if (nChanged == 0)
2267  {
2268  break;
2269  }
2270  }
2271 
2272  // Convert back to labelList.
2273  labelList newCellsToRefine(refineCell.toc());
2274 
2275  if (debug)
2276  {
2277  checkWantedRefinementLevels(cellLevel, newCellsToRefine);
2278  }
2279 
2280  return newCellsToRefine;
2281 }
2282 
2283 
2284 // Given a list of cells to refine determine additional cells to refine
2285 // such that the overall refinement:
2286 // - satisfies maxFaceDiff (e.g. 2:1) across neighbouring faces
2287 // - satisfies maxPointDiff (e.g. 4:1) across selected point connected
2288 // cells. This is used to ensure that e.g. cells on the surface are not
2289 // point connected to cells which are 8 times smaller.
2291 (
2292  const label maxFaceDiff,
2293  const labelList& cellsToRefine,
2294  const labelList& facesToCheck,
2295  const label maxPointDiff,
2296  const labelList& pointsToCheck
2297 ) const
2298 {
2299  const labelList& faceOwner = mesh_.faceOwner();
2300  const labelList& faceNeighbour = mesh_.faceNeighbour();
2301 
2302 
2303  if (maxFaceDiff <= 0)
2304  {
2306  << "Illegal maxFaceDiff " << maxFaceDiff << nl
2307  << "Value should be >= 1" << exit(FatalError);
2308  }
2309 
2310 
2311  // Bit tricky. Say we want a distance of three cells between two
2312  // consecutive refinement levels. This is done by using FaceCellWave to
2313  // transport out the new refinement level. It gets decremented by one
2314  // every cell it crosses so if we initialize it to maxFaceDiff
2315  // we will get a field everywhere that tells us whether an unselected cell
2316  // needs refining as well.
2317 
2318 
2319  // Initial information about (distance to) cellLevel on all cells
2320  List<refinementData> allCellInfo(mesh_.nCells());
2321 
2322  // Initial information about (distance to) cellLevel on all faces
2323  List<refinementData> allFaceInfo(mesh_.nFaces());
2324 
2325  forAll(allCellInfo, celli)
2326  {
2327  // maxFaceDiff since refinementData counts both
2328  // faces and cells.
2329  allCellInfo[celli] = refinementData
2330  (
2331  maxFaceDiff*(cellLevel_[celli]+1),// when cell is to be refined
2332  maxFaceDiff*cellLevel_[celli] // current level
2333  );
2334  }
2335 
2336  // Cells to be refined will have cellLevel+1
2337  forAll(cellsToRefine, i)
2338  {
2339  label celli = cellsToRefine[i];
2340 
2341  allCellInfo[celli].count() = allCellInfo[celli].refinementCount();
2342  }
2343 
2344 
2345  // Labels of seed faces
2346  DynamicList<label> seedFaces(mesh_.nFaces()/100);
2347  // refinementLevel data on seed faces
2348  DynamicList<refinementData> seedFacesInfo(mesh_.nFaces()/100);
2349 
2350  // Dummy additional info for FaceCellWave
2351  int dummyTrackData = 0;
2352 
2353 
2354  // Additional buffer layer thickness by changing initial count. Usually
2355  // this happens on boundary faces. Bit tricky. Use allFaceInfo to mark
2356  // off thus marked faces so they're skipped in the next loop.
2357  forAll(facesToCheck, i)
2358  {
2359  label facei = facesToCheck[i];
2360 
2361  if (allFaceInfo[facei].valid(dummyTrackData))
2362  {
2363  // Can only occur if face has already gone through loop below.
2365  << "Argument facesToCheck seems to have duplicate entries!"
2366  << endl
2367  << "face:" << facei << " occurs at positions "
2368  << findIndices(facesToCheck, facei)
2369  << abort(FatalError);
2370  }
2371 
2372 
2373  const refinementData& ownData = allCellInfo[faceOwner[facei]];
2374 
2375  label maxDataCount = ownData.count();
2376 
2377  if (mesh_.isInternalFace(facei))
2378  {
2379  // Seed face if neighbouring cell (after possible refinement)
2380  // will be refined one more than the current owner or neighbour.
2381 
2382  const refinementData& neiData = allCellInfo[faceNeighbour[facei]];
2383 
2384  if (maxDataCount < neiData.count())
2385  {
2386  maxDataCount = neiData.count();
2387  }
2388  }
2389 
2390  label faceCount = maxDataCount + maxFaceDiff;
2391  label faceRefineCount = faceCount + maxFaceDiff;
2392 
2393  seedFaces.push_back(facei);
2394  allFaceInfo[facei] =
2395  seedFacesInfo.emplace_back(faceRefineCount, faceCount);
2396  }
2397 
2398 
2399  // Just seed with all faces inbetween different refinement levels for now
2400  // (alternatively only seed faces on cellsToRefine but that gives problems
2401  // if no cells to refine)
2402  forAll(faceNeighbour, facei)
2403  {
2404  // Check if face already handled in loop above
2405  if (!allFaceInfo[facei].valid(dummyTrackData))
2406  {
2407  label own = faceOwner[facei];
2408  label nei = faceNeighbour[facei];
2409 
2410  // Seed face with transported data from highest cell.
2411 
2412  if (allCellInfo[own].count() > allCellInfo[nei].count())
2413  {
2414  allFaceInfo[facei].updateFace
2415  (
2416  mesh_,
2417  facei,
2418  own,
2419  allCellInfo[own],
2421  dummyTrackData
2422  );
2423  seedFaces.append(facei);
2424  seedFacesInfo.append(allFaceInfo[facei]);
2425  }
2426  else if (allCellInfo[own].count() < allCellInfo[nei].count())
2427  {
2428  allFaceInfo[facei].updateFace
2429  (
2430  mesh_,
2431  facei,
2432  nei,
2433  allCellInfo[nei],
2435  dummyTrackData
2436  );
2437  seedFaces.append(facei);
2438  seedFacesInfo.append(allFaceInfo[facei]);
2439  }
2440  }
2441  }
2442 
2443  // Seed all boundary faces with owner value. This is to make sure that
2444  // they are visited (probably only important for coupled faces since
2445  // these need to be visited from both sides)
2446  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
2447  {
2448  // Check if face already handled in loop above
2449  if (!allFaceInfo[facei].valid(dummyTrackData))
2450  {
2451  label own = faceOwner[facei];
2452 
2453  // Seed face with transported data from owner.
2454  refinementData faceData;
2455  faceData.updateFace
2456  (
2457  mesh_,
2458  facei,
2459  own,
2460  allCellInfo[own],
2462  dummyTrackData
2463  );
2464  seedFaces.append(facei);
2465  seedFacesInfo.append(faceData);
2466  }
2467  }
2468 
2469 
2470  // face-cell-face transport engine
2472  (
2473  mesh_,
2474  allFaceInfo,
2475  allCellInfo,
2476  dummyTrackData
2477  );
2478 
2479  while (true)
2480  {
2481  if (debug)
2482  {
2483  Pout<< "hexRef8::consistentSlowRefinement : Seeded "
2484  << seedFaces.size() << " faces between cells with different"
2485  << " refinement level." << endl;
2486  }
2487 
2488  // Set seed faces
2489  levelCalc.setFaceInfo(seedFaces.shrink(), seedFacesInfo.shrink());
2490  seedFaces.clear();
2491  seedFacesInfo.clear();
2492 
2493  // Iterate until no change. Now 2:1 face difference should be satisfied
2494  levelCalc.iterate(mesh_.globalData().nTotalFaces()+1);
2495 
2496 
2497  // Now check point-connected cells (face-connected cells already ok):
2498  // - get per point max of connected cells
2499  // - sync across coupled points
2500  // - check cells against above point max
2501 
2502  if (maxPointDiff == -1)
2503  {
2504  // No need to do any point checking.
2505  break;
2506  }
2507 
2508  // Determine per point the max cell level. (done as count, not
2509  // as cell level purely for ease)
2510  labelList maxPointCount(mesh_.nPoints(), Zero);
2511 
2512  forAll(maxPointCount, pointi)
2513  {
2514  label& pLevel = maxPointCount[pointi];
2515 
2516  const labelList& pCells = mesh_.pointCells(pointi);
2517 
2518  forAll(pCells, i)
2519  {
2520  pLevel = max(pLevel, allCellInfo[pCells[i]].count());
2521  }
2522  }
2523 
2524  // Sync maxPointCount to neighbour
2526  (
2527  mesh_,
2528  maxPointCount,
2529  maxEqOp<label>(),
2530  labelMin // null value
2531  );
2532 
2533  // Update allFaceInfo from maxPointCount for all points to check
2534  // (usually on boundary faces)
2535 
2536  // Per face the new refinement data
2537  Map<refinementData> changedFacesInfo(pointsToCheck.size());
2538 
2539  forAll(pointsToCheck, i)
2540  {
2541  label pointi = pointsToCheck[i];
2542 
2543  // Loop over all cells using the point and check whether their
2544  // refinement level is much less than the maximum.
2545 
2546  const labelList& pCells = mesh_.pointCells(pointi);
2547 
2548  forAll(pCells, pCelli)
2549  {
2550  label celli = pCells[pCelli];
2551 
2553 
2554  if
2555  (
2556  !cellInfo.isRefined()
2557  && (
2558  maxPointCount[pointi]
2559  > cellInfo.count() + maxFaceDiff*maxPointDiff
2560  )
2561  )
2562  {
2563  // Mark cell for refinement
2564  cellInfo.count() = cellInfo.refinementCount();
2565 
2566  // Insert faces of cell as seed faces.
2567  const cell& cFaces = mesh_.cells()[celli];
2568 
2569  forAll(cFaces, cFacei)
2570  {
2571  label facei = cFaces[cFacei];
2572 
2573  refinementData faceData;
2574  faceData.updateFace
2575  (
2576  mesh_,
2577  facei,
2578  celli,
2579  cellInfo,
2581  dummyTrackData
2582  );
2583 
2584  if (faceData.count() > allFaceInfo[facei].count())
2585  {
2586  changedFacesInfo.insert(facei, faceData);
2587  }
2588  }
2589  }
2590  }
2591  }
2592 
2593  label nChanged = changedFacesInfo.size();
2594  reduce(nChanged, sumOp<label>());
2595 
2596  if (nChanged == 0)
2597  {
2598  break;
2599  }
2600 
2601 
2602  // Transfer into seedFaces, seedFacesInfo
2603  seedFaces.setCapacity(changedFacesInfo.size());
2604  seedFacesInfo.setCapacity(changedFacesInfo.size());
2605 
2606  forAllConstIters(changedFacesInfo, iter)
2607  {
2608  seedFaces.append(iter.key());
2609  seedFacesInfo.append(iter.val());
2610  }
2611  }
2612 
2613 
2614  if (debug)
2615  {
2616  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
2617  {
2618  label own = mesh_.faceOwner()[facei];
2619  label ownLevel =
2620  cellLevel_[own]
2621  + (allCellInfo[own].isRefined() ? 1 : 0);
2622 
2623  label nei = mesh_.faceNeighbour()[facei];
2624  label neiLevel =
2625  cellLevel_[nei]
2626  + (allCellInfo[nei].isRefined() ? 1 : 0);
2627 
2628  if (mag(ownLevel-neiLevel) > 1)
2629  {
2630  dumpCell(own);
2631  dumpCell(nei);
2633  << "cell:" << own
2634  << " current level:" << cellLevel_[own]
2635  << " current refData:" << allCellInfo[own]
2636  << " level after refinement:" << ownLevel
2637  << nl
2638  << "neighbour cell:" << nei
2639  << " current level:" << cellLevel_[nei]
2640  << " current refData:" << allCellInfo[nei]
2641  << " level after refinement:" << neiLevel
2642  << nl
2643  << "which does not satisfy 2:1 constraints anymore." << nl
2644  << "face:" << facei << " faceRefData:" << allFaceInfo[facei]
2645  << abort(FatalError);
2646  }
2647  }
2648 
2649 
2650  // Coupled faces. Swap owner level to get neighbouring cell level.
2651  // (only boundary faces of neiLevel used)
2652 
2653  labelList neiLevel(mesh_.nBoundaryFaces());
2654  labelList neiCount(mesh_.nBoundaryFaces());
2655  labelList neiRefCount(mesh_.nBoundaryFaces());
2656 
2657  forAll(neiLevel, i)
2658  {
2659  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
2660  neiLevel[i] = cellLevel_[own];
2661  neiCount[i] = allCellInfo[own].count();
2662  neiRefCount[i] = allCellInfo[own].refinementCount();
2663  }
2664 
2665  // Swap to neighbour
2666  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
2667  syncTools::swapBoundaryFaceList(mesh_, neiCount);
2668  syncTools::swapBoundaryFaceList(mesh_, neiRefCount);
2669 
2670  // Now we have neighbour value see which cells need refinement
2671  forAll(neiLevel, i)
2672  {
2673  label facei = i+mesh_.nInternalFaces();
2674 
2675  label own = mesh_.faceOwner()[facei];
2676  label ownLevel =
2677  cellLevel_[own]
2678  + (allCellInfo[own].isRefined() ? 1 : 0);
2679 
2680  label nbrLevel =
2681  neiLevel[i]
2682  + ((neiCount[i] >= neiRefCount[i]) ? 1 : 0);
2683 
2684  if (mag(ownLevel - nbrLevel) > 1)
2685  {
2686  dumpCell(own);
2687  label patchi = mesh_.boundaryMesh().whichPatch(facei);
2688 
2690  << "Celllevel does not satisfy 2:1 constraint."
2691  << " On coupled face "
2692  << facei
2693  << " refData:" << allFaceInfo[facei]
2694  << " on patch " << patchi << " "
2695  << mesh_.boundaryMesh()[patchi].name() << nl
2696  << "owner cell " << own
2697  << " current level:" << cellLevel_[own]
2698  << " current count:" << allCellInfo[own].count()
2699  << " current refCount:"
2700  << allCellInfo[own].refinementCount()
2701  << " level after refinement:" << ownLevel
2702  << nl
2703  << "(coupled) neighbour cell"
2704  << " has current level:" << neiLevel[i]
2705  << " current count:" << neiCount[i]
2706  << " current refCount:" << neiRefCount[i]
2707  << " level after refinement:" << nbrLevel
2708  << abort(FatalError);
2709  }
2710  }
2711  }
2712 
2713  // Convert back to labelList of cells to refine.
2714 
2715  label nRefined = 0;
2716 
2717  forAll(allCellInfo, celli)
2718  {
2719  if (allCellInfo[celli].isRefined())
2720  {
2721  nRefined++;
2722  }
2723  }
2724 
2725  // Updated list of cells to refine
2726  labelList newCellsToRefine(nRefined);
2727  nRefined = 0;
2728 
2729  forAll(allCellInfo, celli)
2730  {
2731  if (allCellInfo[celli].isRefined())
2732  {
2733  newCellsToRefine[nRefined++] = celli;
2734  }
2735  }
2736 
2737  if (debug)
2738  {
2739  Pout<< "hexRef8::consistentSlowRefinement : From "
2740  << cellsToRefine.size() << " to " << newCellsToRefine.size()
2741  << " cells to refine." << endl;
2742  }
2743 
2744  return newCellsToRefine;
2745 }
2746 
2747 
2749 (
2750  const label maxFaceDiff,
2751  const labelList& cellsToRefine,
2752  const labelList& facesToCheck
2753 ) const
2754 {
2755  const labelList& faceOwner = mesh_.faceOwner();
2756  const labelList& faceNeighbour = mesh_.faceNeighbour();
2757 
2758  if (maxFaceDiff <= 0)
2759  {
2761  << "Illegal maxFaceDiff " << maxFaceDiff << nl
2762  << "Value should be >= 1" << exit(FatalError);
2763  }
2764 
2765  const scalar level0Size = 2*maxFaceDiff*level0EdgeLength();
2766 
2767 
2768  // Bit tricky. Say we want a distance of three cells between two
2769  // consecutive refinement levels. This is done by using FaceCellWave to
2770  // transport out the 'refinement shell'. Anything inside the refinement
2771  // shell (given by a distance) gets marked for refinement.
2772 
2773  // Initial information about (distance to) cellLevel on all cells
2774  List<refinementDistanceData> allCellInfo(mesh_.nCells());
2775 
2776  // Initial information about (distance to) cellLevel on all faces
2777  List<refinementDistanceData> allFaceInfo(mesh_.nFaces());
2778 
2779  // Dummy additional info for FaceCellWave
2780  int dummyTrackData = 0;
2781 
2782 
2783  // Mark cells with wanted refinement level
2784  forAll(cellsToRefine, i)
2785  {
2786  label celli = cellsToRefine[i];
2787 
2788  allCellInfo[celli] = refinementDistanceData
2789  (
2790  level0Size,
2791  mesh_.cellCentres()[celli],
2792  cellLevel_[celli]+1 // wanted refinement
2793  );
2794  }
2795  // Mark all others with existing refinement level
2796  forAll(allCellInfo, celli)
2797  {
2798  if (!allCellInfo[celli].valid(dummyTrackData))
2799  {
2800  allCellInfo[celli] = refinementDistanceData
2801  (
2802  level0Size,
2803  mesh_.cellCentres()[celli],
2804  cellLevel_[celli] // wanted refinement
2805  );
2806  }
2807  }
2808 
2809 
2810  //{
2811  // const fvMesh& fMesh = reinterpret_cast<const fvMesh&>(mesh_);
2812  //
2813  // // Dump origin level
2814  // volScalarField originLevel
2815  // (
2816  // IOobject
2817  // (
2818  // "originLevel_before_walk",
2819  // fMesh.time().timeName(),
2820  // fMesh,
2821  // IOobject::NO_READ,
2822  // IOobject::NO_WRITE,
2823  // IOobject::NO_REGISTER
2824  // ),
2825  // fMesh,
2826  // dimensionedScalar(dimless, Zero)
2827  // );
2828  //
2829  // forAll(originLevel, celli)
2830  // {
2831  // originLevel[celli] = allCellInfo[celli].originLevel();
2832  // }
2833  // Pout<< "Writing " << originLevel.objectPath() << endl;
2834  // originLevel.write();
2835  //}
2836  //{
2837  // const auto& cc = mesh_.cellCentres();
2838  //
2839  // mkDir(mesh_.time().timePath());
2840  // OBJstream os(mesh_.time().timePath()/"origin_before_walk.obj");
2841  // forAll(allCellInfo, celli)
2842  // {
2843  // os.write(linePointRef(cc[celli], allCellInfo[celli].origin()));
2844  // }
2845  //}
2846 
2847 
2848  // Labels of seed faces
2849  DynamicList<label> seedFaces(mesh_.nFaces()/100);
2850  // refinementLevel data on seed faces
2851  DynamicList<refinementDistanceData> seedFacesInfo(mesh_.nFaces()/100);
2852 
2853  const pointField& cc = mesh_.cellCentres();
2854  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2855 
2856  // Get neighbour boundary data:
2857  // - coupled faces : owner data
2858  // - non-coupled faces : owner level + 1 so we can treat
2859  pointField nbrCc(mesh_.nBoundaryFaces(), point::max);
2860  labelList nbrLevel(mesh_.nBoundaryFaces(), labelMax);
2861  bitSet isBoundary(mesh_.nFaces());
2862  {
2863  for (const polyPatch& pp : patches)
2864  {
2865  if (pp.coupled())
2866  {
2867  const auto& faceCells = pp.faceCells();
2868  forAll(faceCells, i)
2869  {
2870  const label own = faceCells[i];
2871  nbrCc[pp.offset()+i] = cc[own];
2872 
2873  const label ownLevel =
2874  (
2875  allCellInfo[own].valid(dummyTrackData)
2876  ? allCellInfo[own].originLevel()
2877  : cellLevel_[own]
2878  );
2879  nbrLevel[pp.offset()+i] = ownLevel;
2880  }
2881  }
2882  else
2883  {
2884  isBoundary.set(pp.range());
2885  }
2886  }
2887  syncTools::swapBoundaryFaceList(mesh_, nbrCc);
2888  syncTools::swapBoundaryFaceList(mesh_, nbrLevel);
2889  }
2890 
2891 
2892  for (const label facei : facesToCheck)
2893  {
2894  if (allFaceInfo[facei].valid(dummyTrackData))
2895  {
2896  // Can only occur if face has already gone through loop below.
2898  << "Argument facesToCheck seems to have duplicate entries!"
2899  << endl
2900  << "face:" << facei << " occurs at positions "
2901  << findIndices(facesToCheck, facei)
2902  << abort(FatalError);
2903  }
2904 
2905  const label own = faceOwner[facei];
2906  const label ownLevel =
2907  (
2908  allCellInfo[own].valid(dummyTrackData)
2909  ? allCellInfo[own].originLevel()
2910  : cellLevel_[own]
2911  );
2912  const point& ownCc = cc[own];
2913 
2914  if (isBoundary(facei))
2915  {
2916  // Do as if boundary face would have neighbour with one higher
2917  // refinement level.
2918  const point& fc = mesh_.faceCentres()[facei];
2919 
2920  refinementDistanceData neiData
2921  (
2922  level0Size,
2923  2*fc - cc[own], // est'd cell centre
2924  ownLevel+1
2925  );
2926 
2927  allFaceInfo[facei].updateFace
2928  (
2929  mesh_,
2930  facei,
2931  own, // not used (should be nei)
2932  neiData,
2934  dummyTrackData
2935  );
2936  }
2937  else
2938  {
2939  label neiLevel;
2940  point neiCc;
2941  if (mesh_.isInternalFace(facei))
2942  {
2943  const label nei = faceNeighbour[facei];
2944  neiLevel =
2945  (
2946  allCellInfo[nei].valid(dummyTrackData)
2947  ? allCellInfo[nei].originLevel()
2948  : cellLevel_[nei]
2949  );
2950  neiCc = cc[nei];
2951  }
2952  else
2953  {
2954  neiLevel = nbrLevel[facei-mesh_.nInternalFaces()];
2955  neiCc = nbrCc[facei-mesh_.nInternalFaces()];
2956  }
2957 
2958  if (ownLevel == neiLevel)
2959  {
2960  // Fake as if nei>own or own>nei (whichever one 'wins')
2961  allFaceInfo[facei].updateFace
2962  (
2963  mesh_,
2964  facei,
2965  own, // not used, should be nei
2966  refinementDistanceData(level0Size, neiCc, neiLevel+1),
2968  dummyTrackData
2969  );
2970  allFaceInfo[facei].updateFace
2971  (
2972  mesh_,
2973  facei,
2974  own, // not used
2975  refinementDistanceData(level0Size, ownCc, ownLevel+1),
2977  dummyTrackData
2978  );
2979  }
2980  else
2981  {
2982  // Difference in level anyway.
2983  allFaceInfo[facei].updateFace
2984  (
2985  mesh_,
2986  facei,
2987  own, // not used, should be nei
2988  refinementDistanceData(level0Size, neiCc, neiLevel),
2990  dummyTrackData
2991  );
2992  allFaceInfo[facei].updateFace
2993  (
2994  mesh_,
2995  facei,
2996  own, // not used
2997  refinementDistanceData(level0Size, ownCc, ownLevel),
2999  dummyTrackData
3000  );
3001  }
3002  }
3003  seedFaces.append(facei);
3004  seedFacesInfo.append(allFaceInfo[facei]);
3005  }
3006 
3007 
3008 
3009  // Create some initial seeds to start walking from. This is only if there
3010  // are no facesToCheck.
3011  // Just seed with all faces inbetween different refinement levels for now
3012  // Note: no need to handle coupled faces since FaceCellWave below
3013  // already swaps seedInfo upon start
3014  //forAll(faceNeighbour, facei)
3015  forAll(faceOwner, facei)
3016  {
3017  // Check if face already handled in loop above
3018  if (!allFaceInfo[facei].valid(dummyTrackData) && !isBoundary(facei))
3019  {
3020  const label own = faceOwner[facei];
3021  const label ownLevel =
3022  (
3023  allCellInfo[own].valid(dummyTrackData)
3024  ? allCellInfo[own].originLevel()
3025  : cellLevel_[own]
3026  );
3027  const point& ownCc = cc[own];
3028 
3029  label neiLevel;
3030  point neiCc;
3031  if (mesh_.isInternalFace(facei))
3032  {
3033  const label nei = faceNeighbour[facei];
3034  neiLevel =
3035  (
3036  allCellInfo[nei].valid(dummyTrackData)
3037  ? allCellInfo[nei].originLevel()
3038  : cellLevel_[nei]
3039  );
3040  neiCc = cc[nei];
3041  }
3042  else
3043  {
3044  neiLevel = nbrLevel[facei-mesh_.nInternalFaces()];
3045  neiCc = nbrCc[facei-mesh_.nInternalFaces()];
3046  }
3047 
3048  if (ownLevel > neiLevel)
3049  {
3050  // Set face to owner data. (since face not yet would be copy)
3051  seedFaces.append(facei);
3052  allFaceInfo[facei].updateFace
3053  (
3054  mesh_,
3055  facei,
3056  own,
3057  refinementDistanceData(level0Size, ownCc, ownLevel),
3059  dummyTrackData
3060  );
3061  seedFacesInfo.append(allFaceInfo[facei]);
3062  }
3063  else if (neiLevel > ownLevel)
3064  {
3065  seedFaces.append(facei);
3066  allFaceInfo[facei].updateFace
3067  (
3068  mesh_,
3069  facei,
3070  own, // not used, should be nei,
3071  refinementDistanceData(level0Size, neiCc, neiLevel),
3073  dummyTrackData
3074  );
3075  seedFacesInfo.append(allFaceInfo[facei]);
3076  }
3077  }
3078  }
3079 
3080  seedFaces.shrink();
3081  seedFacesInfo.shrink();
3082 
3083  // face-cell-face transport engine
3084  FaceCellWave<refinementDistanceData, int> levelCalc
3085  (
3086  mesh_,
3087  seedFaces,
3088  seedFacesInfo,
3089  allFaceInfo,
3090  allCellInfo,
3091  mesh_.globalData().nTotalCells()+1,
3092  dummyTrackData
3093  );
3094 
3095 
3096  //- noted: origin is different face (? or cell) between non-parallel
3097  // and parallel
3098  //{
3099  // const auto& cc = mesh_.cellCentres();
3100  //
3101  // mkDir(mesh_.time().timePath());
3102  // OBJstream os(mesh_.time().timePath()/"origin_after_walk.obj");
3103  // forAll(allCellInfo, celli)
3104  // {
3105  // os.write(linePointRef(cc[celli], allCellInfo[celli].origin()));
3106  // }
3107  //}
3108 
3109 
3110 
3111  //if (debug)
3112  //{
3113  // const fvMesh& fMesh = reinterpret_cast<const fvMesh&>(mesh_);
3114  //
3115  // // Dump origin level
3116  // volScalarField originLevel
3117  // (
3118  // IOobject
3119  // (
3120  // "originLevel_after_walk",
3121  // fMesh.time().timeName(),
3122  // fMesh,
3123  // IOobject::NO_READ,
3124  // IOobject::NO_WRITE,
3125  // IOobject::NO_REGISTER
3126  // ),
3127  // fMesh,
3128  // dimensionedScalar(dimless, Zero)
3129  // );
3130  //
3131  // forAll(originLevel, celli)
3132  // {
3133  // originLevel[celli] = allCellInfo[celli].originLevel();
3134  // }
3135  // // Dump wanted level
3136  // volScalarField wantedLevel
3137  // (
3138  // IOobject
3139  // (
3140  // "wantedLevel",
3141  // fMesh.time().timeName(),
3142  // fMesh,
3143  // IOobject::NO_READ,
3144  // IOobject::NO_WRITE,
3145  // IOobject::NO_REGISTER
3146  // ),
3147  // fMesh,
3148  // dimensionedScalar(dimless, Zero)
3149  // );
3150  //
3151  // forAll(wantedLevel, celli)
3152  // {
3153  // wantedLevel[celli] = allCellInfo[celli].wantedLevel(cc[celli]);
3154  // }
3155  //
3156  // Pout<< "Writing " << originLevel.objectPath() << endl;
3157  // //fMesh.write();
3158  // originLevel.write();
3159  // Pout<< "Writing " << wantedLevel.objectPath() << endl;
3160  // wantedLevel.write();
3161  //}
3162 
3163 
3164  // Convert back to labelList of cells to refine.
3165  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3166 
3167  // 1. Force original refinement cells to be picked up by setting the
3168  // originLevel of input cells to be a very large level (but within range
3169  // of 1<< shift inside refinementDistanceData::wantedLevel)
3170  forAll(cellsToRefine, i)
3171  {
3172  label celli = cellsToRefine[i];
3173 
3174  allCellInfo[celli].originLevel() = sizeof(label)*8-2;
3175  allCellInfo[celli].origin() = cc[celli];
3176  }
3177 
3178  // 2. Extend to 2:1. I don't understand yet why this is not done
3179  // 2. Extend to 2:1. For non-cube cells the scalar distance does not work
3180  // so make sure it at least provides 2:1.
3181  bitSet refineCell(mesh_.nCells());
3182  forAll(allCellInfo, celli)
3183  {
3184  label wanted = allCellInfo[celli].wantedLevel(cc[celli]);
3185 
3186  if (wanted > cellLevel_[celli]+1)
3187  {
3188  refineCell.set(celli);
3189  }
3190  }
3191  faceConsistentRefinement(true, cellLevel_, refineCell);
3192 
3193  while (true)
3194  {
3195  label nChanged = faceConsistentRefinement(true, cellLevel_, refineCell);
3196 
3197  reduce(nChanged, sumOp<label>());
3198 
3199  if (debug)
3200  {
3201  Pout<< "hexRef8::consistentSlowRefinement2 : Changed " << nChanged
3202  << " refinement levels due to 2:1 conflicts."
3203  << endl;
3204  }
3205 
3206  if (nChanged == 0)
3207  {
3208  break;
3209  }
3210  }
3211 
3212  // 3. Convert back to labelList.
3213  labelList newCellsToRefine(refineCell.toc());
3214 
3215  if (debug)
3216  {
3217  Pout<< "hexRef8::consistentSlowRefinement2 : From "
3218  << cellsToRefine.size() << " to " << newCellsToRefine.size()
3219  << " cells to refine." << endl;
3220 
3221  // Check that newCellsToRefine obeys at least 2:1.
3222 
3223  {
3224  cellSet cellsIn(mesh_, "cellsToRefineIn", cellsToRefine);
3225  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3226  << cellsIn.size() << " to cellSet "
3227  << cellsIn.objectPath() << endl;
3228  cellsIn.write();
3229  }
3230  {
3231  cellSet cellsOut(mesh_, "cellsToRefineOut", newCellsToRefine);
3232  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3233  << cellsOut.size() << " to cellSet "
3234  << cellsOut.objectPath() << endl;
3235  cellsOut.write();
3236  }
3237 
3238  // Extend to 2:1
3239  bitSet refineCell(mesh_.nCells(), newCellsToRefine);
3240 
3241  const bitSet savedRefineCell(refineCell);
3242  label nChanged = faceConsistentRefinement(true, cellLevel_, refineCell);
3243 
3244  {
3245  cellSet cellsOut2
3246  (
3247  mesh_, "cellsToRefineOut2", newCellsToRefine.size()
3248  );
3249  forAll(refineCell, celli)
3250  {
3251  if (refineCell.test(celli))
3252  {
3253  cellsOut2.insert(celli);
3254  }
3255  }
3256  Pout<< "hexRef8::consistentSlowRefinement2 : writing "
3257  << cellsOut2.size() << " to cellSet "
3258  << cellsOut2.objectPath() << endl;
3259  cellsOut2.write();
3260  }
3261 
3262  if (nChanged > 0)
3263  {
3264  forAll(refineCell, celli)
3265  {
3266  if (refineCell.test(celli) && !savedRefineCell.test(celli))
3267  {
3268  dumpCell(celli);
3270  << "Cell:" << celli << " cc:"
3271  << mesh_.cellCentres()[celli]
3272  << " was not marked for refinement but does not obey"
3273  << " 2:1 constraints."
3274  << abort(FatalError);
3275  }
3276  }
3277  }
3278  }
3279 
3280  return newCellsToRefine;
3281 }
3282 
3283 
3284 // Top level driver to insert topo changes to do all refinement.
3286 (
3287  const labelList& cellLabels,
3288  polyTopoChange& meshMod
3289 )
3290 {
3291  if (debug)
3292  {
3293  Pout<< "hexRef8::setRefinement :"
3294  << " Checking initial mesh just to make sure" << endl;
3295 
3296  checkMesh();
3297  // Cannot call checkRefinementlevels since hanging points might
3298  // get triggered by the mesher after subsetting.
3299  //checkRefinementLevels(-1, labelList(0));
3300  }
3301 
3302  // Clear any saved point/cell data.
3303  savedPointLevel_.clear();
3304  savedCellLevel_.clear();
3305 
3306 
3307  // New point/cell level. Copy of pointLevel for existing points.
3308  DynamicList<label> newCellLevel(cellLevel_.size());
3309  forAll(cellLevel_, celli)
3310  {
3311  newCellLevel.append(cellLevel_[celli]);
3312  }
3313  DynamicList<label> newPointLevel(pointLevel_.size());
3314  forAll(pointLevel_, pointi)
3315  {
3316  newPointLevel.append(pointLevel_[pointi]);
3317  }
3318 
3319 
3320  if (debug)
3321  {
3322  Pout<< "hexRef8::setRefinement :"
3323  << " Allocating " << cellLabels.size() << " cell midpoints."
3324  << endl;
3325  }
3326 
3327 
3328  // Mid point per refined cell.
3329  // -1 : not refined
3330  // >=0: label of mid point.
3331  labelList cellMidPoint(mesh_.nCells(), -1);
3332 
3333  forAll(cellLabels, i)
3334  {
3335  label celli = cellLabels[i];
3336 
3337  label anchorPointi = mesh_.faces()[mesh_.cells()[celli][0]][0];
3338 
3339  cellMidPoint[celli] = meshMod.setAction
3340  (
3341  polyAddPoint
3342  (
3343  mesh_.cellCentres()[celli], // point
3344  anchorPointi, // master point
3345  -1, // zone for point
3346  true // supports a cell
3347  )
3348  );
3349 
3350  newPointLevel(cellMidPoint[celli]) = cellLevel_[celli]+1;
3351  }
3352 
3353 
3354  if (debug)
3355  {
3356  cellSet splitCells(mesh_, "splitCells", cellLabels.size());
3357 
3358  forAll(cellMidPoint, celli)
3359  {
3360  if (cellMidPoint[celli] >= 0)
3361  {
3362  splitCells.insert(celli);
3363  }
3364  }
3365 
3366  Pout<< "hexRef8::setRefinement : Dumping " << splitCells.size()
3367  << " cells to split to cellSet " << splitCells.objectPath()
3368  << endl;
3369 
3370  splitCells.write();
3371  }
3372 
3373 
3374 
3375  // Split edges
3376  // ~~~~~~~~~~~
3377 
3378  if (debug)
3379  {
3380  Pout<< "hexRef8::setRefinement :"
3381  << " Allocating edge midpoints."
3382  << endl;
3383  }
3384 
3385  // Unrefined edges are ones between cellLevel or lower points.
3386  // If any cell using this edge gets split then the edge needs to be split.
3387 
3388  // -1 : no need to split edge
3389  // >=0 : label of introduced mid point
3390  labelList edgeMidPoint(mesh_.nEdges(), -1);
3391 
3392  // Note: Loop over cells to be refined or edges?
3393  forAll(cellMidPoint, celli)
3394  {
3395  if (cellMidPoint[celli] >= 0)
3396  {
3397  const labelList& cEdges = mesh_.cellEdges(celli);
3398 
3399  forAll(cEdges, i)
3400  {
3401  label edgeI = cEdges[i];
3402 
3403  const edge& e = mesh_.edges()[edgeI];
3404 
3405  if
3406  (
3407  pointLevel_[e[0]] <= cellLevel_[celli]
3408  && pointLevel_[e[1]] <= cellLevel_[celli]
3409  )
3410  {
3411  edgeMidPoint[edgeI] = 12345; // mark need for splitting
3412  }
3413  }
3414  }
3415  }
3416 
3417  // Synchronize edgeMidPoint across coupled patches. Take max so that
3418  // any split takes precedence.
3420  (
3421  mesh_,
3422  edgeMidPoint,
3423  maxEqOp<label>(),
3424  labelMin
3425  );
3426 
3427 
3428  // Introduce edge points
3429  // ~~~~~~~~~~~~~~~~~~~~~
3430 
3431  {
3432  // Phase 1: calculate midpoints and sync.
3433  // This needs doing for if people do not write binary and we slowly
3434  // get differences.
3435 
3436  pointField edgeMids(mesh_.nEdges(), point(-GREAT, -GREAT, -GREAT));
3437 
3438  forAll(edgeMidPoint, edgeI)
3439  {
3440  if (edgeMidPoint[edgeI] >= 0)
3441  {
3442  // Edge marked to be split.
3443  edgeMids[edgeI] = mesh_.edges()[edgeI].centre(mesh_.points());
3444  }
3445  }
3447  (
3448  mesh_,
3449  edgeMids,
3450  maxEqOp<vector>(),
3451  point(-GREAT, -GREAT, -GREAT)
3452  );
3453 
3454 
3455  // Phase 2: introduce points at the synced locations.
3456  forAll(edgeMidPoint, edgeI)
3457  {
3458  if (edgeMidPoint[edgeI] >= 0)
3459  {
3460  // Edge marked to be split. Replace edgeMidPoint with actual
3461  // point label.
3462 
3463  const edge& e = mesh_.edges()[edgeI];
3464 
3465  edgeMidPoint[edgeI] = meshMod.setAction
3466  (
3467  polyAddPoint
3468  (
3469  edgeMids[edgeI], // point
3470  e[0], // master point
3471  -1, // zone for point
3472  true // supports a cell
3473  )
3474  );
3475 
3476  newPointLevel(edgeMidPoint[edgeI]) =
3477  max
3478  (
3479  pointLevel_[e[0]],
3480  pointLevel_[e[1]]
3481  )
3482  + 1;
3483  }
3484  }
3485  }
3486 
3487  if (debug)
3488  {
3489  OFstream str(mesh_.time().path()/"edgeMidPoint.obj");
3490 
3491  forAll(edgeMidPoint, edgeI)
3492  {
3493  if (edgeMidPoint[edgeI] >= 0)
3494  {
3495  const edge& e = mesh_.edges()[edgeI];
3496 
3497  meshTools::writeOBJ(str, e.centre(mesh_.points()));
3498  }
3499  }
3500 
3501  Pout<< "hexRef8::setRefinement :"
3502  << " Dumping edge centres to split to file " << str.name() << endl;
3503  }
3504 
3505 
3506  // Calculate face level
3507  // ~~~~~~~~~~~~~~~~~~~~
3508  // (after splitting)
3509 
3510  if (debug)
3511  {
3512  Pout<< "hexRef8::setRefinement :"
3513  << " Allocating face midpoints."
3514  << endl;
3515  }
3516 
3517  // Face anchor level. There are guaranteed 4 points with level
3518  // <= anchorLevel. These are the corner points.
3519  labelList faceAnchorLevel(mesh_.nFaces());
3520 
3521  for (label facei = 0; facei < mesh_.nFaces(); facei++)
3522  {
3523  faceAnchorLevel[facei] = faceLevel(facei);
3524  }
3525 
3526  // -1 : no need to split face
3527  // >=0 : label of introduced mid point
3528  labelList faceMidPoint(mesh_.nFaces(), -1);
3529 
3530 
3531  // Internal faces: look at cells on both sides. Uniquely determined since
3532  // face itself guaranteed to be same level as most refined neighbour.
3533  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
3534  {
3535  if (faceAnchorLevel[facei] >= 0)
3536  {
3537  label own = mesh_.faceOwner()[facei];
3538  label ownLevel = cellLevel_[own];
3539  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3540 
3541  label nei = mesh_.faceNeighbour()[facei];
3542  label neiLevel = cellLevel_[nei];
3543  label newNeiLevel = neiLevel + (cellMidPoint[nei] >= 0 ? 1 : 0);
3544 
3545  if
3546  (
3547  newOwnLevel > faceAnchorLevel[facei]
3548  || newNeiLevel > faceAnchorLevel[facei]
3549  )
3550  {
3551  faceMidPoint[facei] = 12345; // mark to be split
3552  }
3553  }
3554  }
3555 
3556  // Coupled patches handled like internal faces except now all information
3557  // from neighbour comes from across processor.
3558  // Boundary faces are more complicated since the boundary face can
3559  // be more refined than its owner (or neighbour for coupled patches)
3560  // (does not happen if refining/unrefining only, but does e.g. when
3561  // refinining and subsetting)
3562 
3563  {
3564  labelList newNeiLevel(mesh_.nBoundaryFaces());
3565 
3566  forAll(newNeiLevel, i)
3567  {
3568  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
3569  label ownLevel = cellLevel_[own];
3570  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3571 
3572  newNeiLevel[i] = newOwnLevel;
3573  }
3574 
3575  // Swap.
3576  syncTools::swapBoundaryFaceList(mesh_, newNeiLevel);
3577 
3578  // So now we have information on the neighbour.
3579 
3580  forAll(newNeiLevel, i)
3581  {
3582  label facei = i+mesh_.nInternalFaces();
3583 
3584  if (faceAnchorLevel[facei] >= 0)
3585  {
3586  label own = mesh_.faceOwner()[facei];
3587  label ownLevel = cellLevel_[own];
3588  label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3589 
3590  if
3591  (
3592  newOwnLevel > faceAnchorLevel[facei]
3593  || newNeiLevel[i] > faceAnchorLevel[facei]
3594  )
3595  {
3596  faceMidPoint[facei] = 12345; // mark to be split
3597  }
3598  }
3599  }
3600  }
3601 
3602 
3603  // Synchronize faceMidPoint across coupled patches. (logical or)
3605  (
3606  mesh_,
3607  faceMidPoint,
3608  maxEqOp<label>()
3609  );
3610 
3611 
3612 
3613  // Introduce face points
3614  // ~~~~~~~~~~~~~~~~~~~~~
3615 
3616  {
3617  // Phase 1: determine mid points and sync. See comment for edgeMids
3618  // above
3619  pointField bFaceMids
3620  (
3621  mesh_.nBoundaryFaces(),
3622  point(-GREAT, -GREAT, -GREAT)
3623  );
3624 
3625  forAll(bFaceMids, i)
3626  {
3627  label facei = i+mesh_.nInternalFaces();
3628 
3629  if (faceMidPoint[facei] >= 0)
3630  {
3631  bFaceMids[i] = mesh_.faceCentres()[facei];
3632  }
3633  }
3635  (
3636  mesh_,
3637  bFaceMids,
3638  maxEqOp<vector>()
3639  );
3640 
3641  forAll(faceMidPoint, facei)
3642  {
3643  if (faceMidPoint[facei] >= 0)
3644  {
3645  // Face marked to be split. Replace faceMidPoint with actual
3646  // point label.
3647 
3648  const face& f = mesh_.faces()[facei];
3649 
3650  faceMidPoint[facei] = meshMod.setAction
3651  (
3652  polyAddPoint
3653  (
3654  (
3655  facei < mesh_.nInternalFaces()
3656  ? mesh_.faceCentres()[facei]
3657  : bFaceMids[facei-mesh_.nInternalFaces()]
3658  ), // point
3659  f[0], // master point
3660  -1, // zone for point
3661  true // supports a cell
3662  )
3663  );
3664 
3665  // Determine the level of the corner points and midpoint will
3666  // be one higher.
3667  newPointLevel(faceMidPoint[facei]) = faceAnchorLevel[facei]+1;
3668  }
3669  }
3670  }
3671 
3672  if (debug)
3673  {
3674  faceSet splitFaces(mesh_, "splitFaces", cellLabels.size());
3675 
3676  forAll(faceMidPoint, facei)
3677  {
3678  if (faceMidPoint[facei] >= 0)
3679  {
3680  splitFaces.insert(facei);
3681  }
3682  }
3683 
3684  Pout<< "hexRef8::setRefinement : Dumping " << splitFaces.size()
3685  << " faces to split to faceSet " << splitFaces.objectPath() << endl;
3686 
3687  splitFaces.write();
3688  }
3689 
3690 
3691  // Information complete
3692  // ~~~~~~~~~~~~~~~~~~~~
3693  // At this point we have all the information we need. We should no
3694  // longer reference the cellLabels to refine. All the information is:
3695  // - cellMidPoint >= 0 : cell needs to be split
3696  // - faceMidPoint >= 0 : face needs to be split
3697  // - edgeMidPoint >= 0 : edge needs to be split
3698 
3699 
3700 
3701  // Get the corner/anchor points
3702  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3703 
3704  if (debug)
3705  {
3706  Pout<< "hexRef8::setRefinement :"
3707  << " Finding cell anchorPoints (8 per cell)"
3708  << endl;
3709  }
3710 
3711  // There will always be 8 points on the hex that have were introduced
3712  // with the hex and will have the same or lower refinement level.
3713 
3714  // Per cell the 8 corner points.
3715  labelListList cellAnchorPoints(mesh_.nCells());
3716 
3717  {
3718  labelList nAnchorPoints(mesh_.nCells(), Zero);
3719 
3720  forAll(cellMidPoint, celli)
3721  {
3722  if (cellMidPoint[celli] >= 0)
3723  {
3724  cellAnchorPoints[celli].setSize(8);
3725  }
3726  }
3727 
3728  forAll(pointLevel_, pointi)
3729  {
3730  const labelList& pCells = mesh_.pointCells(pointi);
3731 
3732  forAll(pCells, pCelli)
3733  {
3734  label celli = pCells[pCelli];
3735 
3736  if
3737  (
3738  cellMidPoint[celli] >= 0
3739  && pointLevel_[pointi] <= cellLevel_[celli]
3740  )
3741  {
3742  if (nAnchorPoints[celli] == 8)
3743  {
3744  dumpCell(celli);
3746  << "cell " << celli
3747  << " of level " << cellLevel_[celli]
3748  << " uses more than 8 points of equal or"
3749  << " lower level" << nl
3750  << "Points so far:" << cellAnchorPoints[celli]
3751  << abort(FatalError);
3752  }
3753 
3754  cellAnchorPoints[celli][nAnchorPoints[celli]++] = pointi;
3755  }
3756  }
3757  }
3758 
3759  forAll(cellMidPoint, celli)
3760  {
3761  if (cellMidPoint[celli] >= 0)
3762  {
3763  if (nAnchorPoints[celli] != 8)
3764  {
3765  dumpCell(celli);
3766 
3767  const labelList& cPoints = mesh_.cellPoints(celli);
3768 
3770  << "cell " << celli
3771  << " of level " << cellLevel_[celli]
3772  << " does not seem to have 8 points of equal or"
3773  << " lower level" << endl
3774  << "cellPoints:" << cPoints << endl
3775  << "pointLevels:"
3776  << labelUIndList(pointLevel_, cPoints) << endl
3777  << abort(FatalError);
3778  }
3779  }
3780  }
3781  }
3782 
3783 
3784  // Add the cells
3785  // ~~~~~~~~~~~~~
3786 
3787  if (debug)
3788  {
3789  Pout<< "hexRef8::setRefinement :"
3790  << " Adding cells (1 per anchorPoint)"
3791  << endl;
3792  }
3793 
3794  // Per cell the 7 added cells (+ original cell)
3795  labelListList cellAddedCells(mesh_.nCells());
3796 
3797  forAll(cellAnchorPoints, celli)
3798  {
3799  const labelList& cAnchors = cellAnchorPoints[celli];
3800 
3801  if (cAnchors.size() == 8)
3802  {
3803  labelList& cAdded = cellAddedCells[celli];
3804  cAdded.setSize(8);
3805 
3806  // Original cell at 0
3807  cAdded[0] = celli;
3808 
3809  // Update cell level
3810  newCellLevel[celli] = cellLevel_[celli]+1;
3811 
3812 
3813  for (label i = 1; i < 8; i++)
3814  {
3815  cAdded[i] = meshMod.setAction
3816  (
3817  polyAddCell
3818  (
3819  -1, // master point
3820  -1, // master edge
3821  -1, // master face
3822  celli, // master cell
3823  mesh_.cellZones().whichZone(celli) // zone for cell
3824  )
3825  );
3826 
3827  newCellLevel(cAdded[i]) = cellLevel_[celli]+1;
3828  }
3829  }
3830  }
3831 
3832 
3833  // Faces
3834  // ~~~~~
3835  // 1. existing faces that get split (into four always)
3836  // 2. existing faces that do not get split but only edges get split
3837  // 3. existing faces that do not get split but get new owner/neighbour
3838  // 4. new internal faces inside split cells.
3839 
3840  if (debug)
3841  {
3842  Pout<< "hexRef8::setRefinement :"
3843  << " Marking faces to be handled"
3844  << endl;
3845  }
3846 
3847  // Get all affected faces.
3848  bitSet affectedFace(mesh_.nFaces());
3849 
3850  {
3851  forAll(cellMidPoint, celli)
3852  {
3853  if (cellMidPoint[celli] >= 0)
3854  {
3855  const cell& cFaces = mesh_.cells()[celli];
3856 
3857  affectedFace.set(cFaces);
3858  }
3859  }
3860 
3861  forAll(faceMidPoint, facei)
3862  {
3863  if (faceMidPoint[facei] >= 0)
3864  {
3865  affectedFace.set(facei);
3866  }
3867  }
3868 
3869  forAll(edgeMidPoint, edgeI)
3870  {
3871  if (edgeMidPoint[edgeI] >= 0)
3872  {
3873  const labelList& eFaces = mesh_.edgeFaces(edgeI);
3874 
3875  affectedFace.set(eFaces);
3876  }
3877  }
3878  }
3879 
3880 
3881  // 1. Faces that get split
3882  // ~~~~~~~~~~~~~~~~~~~~~~~
3883 
3884  if (debug)
3885  {
3886  Pout<< "hexRef8::setRefinement : Splitting faces" << endl;
3887  }
3888 
3889  forAll(faceMidPoint, facei)
3890  {
3891  if (faceMidPoint[facei] >= 0 && affectedFace.test(facei))
3892  {
3893  // Face needs to be split and hasn't yet been done in some way
3894  // (affectedFace - is impossible since this is first change but
3895  // just for completeness)
3896 
3897  const face& f = mesh_.faces()[facei];
3898 
3899  // Has original facei been used (three faces added, original gets
3900  // modified)
3901  bool modifiedFace = false;
3902 
3903  label anchorLevel = faceAnchorLevel[facei];
3904 
3905  face newFace(4);
3906 
3907  forAll(f, fp)
3908  {
3909  label pointi = f[fp];
3910 
3911  if (pointLevel_[pointi] <= anchorLevel)
3912  {
3913  // point is anchor. Start collecting face.
3914 
3915  DynamicList<label> faceVerts(4);
3916 
3917  faceVerts.append(pointi);
3918 
3919  // Walk forward to mid point.
3920  // - if next is +2 midpoint is +1
3921  // - if next is +1 it is midpoint
3922  // - if next is +0 there has to be edgeMidPoint
3923 
3924  walkFaceToMid
3925  (
3926  edgeMidPoint,
3927  anchorLevel,
3928  facei,
3929  fp,
3930  faceVerts
3931  );
3932 
3933  faceVerts.append(faceMidPoint[facei]);
3934 
3935  walkFaceFromMid
3936  (
3937  edgeMidPoint,
3938  anchorLevel,
3939  facei,
3940  fp,
3941  faceVerts
3942  );
3943 
3944  // Convert dynamiclist to face.
3945  newFace.transfer(faceVerts);
3946 
3947  //Pout<< "Split face:" << facei << " verts:" << f
3948  // << " into quad:" << newFace << endl;
3949 
3950  // Get new owner/neighbour
3951  label own, nei;
3952  getFaceNeighbours
3953  (
3954  cellAnchorPoints,
3955  cellAddedCells,
3956  facei,
3957  pointi, // Anchor point
3958 
3959  own,
3960  nei
3961  );
3962 
3963 
3964  if (debug)
3965  {
3966  if (mesh_.isInternalFace(facei))
3967  {
3968  label oldOwn = mesh_.faceOwner()[facei];
3969  label oldNei = mesh_.faceNeighbour()[facei];
3970 
3971  checkInternalOrientation
3972  (
3973  meshMod,
3974  oldOwn,
3975  facei,
3976  mesh_.cellCentres()[oldOwn],
3977  mesh_.cellCentres()[oldNei],
3978  newFace
3979  );
3980  }
3981  else
3982  {
3983  label oldOwn = mesh_.faceOwner()[facei];
3984 
3985  checkBoundaryOrientation
3986  (
3987  meshMod,
3988  oldOwn,
3989  facei,
3990  mesh_.cellCentres()[oldOwn],
3991  mesh_.faceCentres()[facei],
3992  newFace
3993  );
3994  }
3995  }
3996 
3997 
3998  if (!modifiedFace)
3999  {
4000  modifiedFace = true;
4001 
4002  modFace(meshMod, facei, newFace, own, nei);
4003  }
4004  else
4005  {
4006  addFace(meshMod, facei, newFace, own, nei);
4007  }
4008  }
4009  }
4010 
4011  // Mark face as having been handled
4012  affectedFace.unset(facei);
4013  }
4014  }
4015 
4016 
4017  // 2. faces that do not get split but use edges that get split
4018  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4019 
4020  if (debug)
4021  {
4022  Pout<< "hexRef8::setRefinement :"
4023  << " Adding edge splits to unsplit faces"
4024  << endl;
4025  }
4026 
4027  DynamicList<label> eFacesStorage;
4028  DynamicList<label> fEdgesStorage;
4029 
4030  forAll(edgeMidPoint, edgeI)
4031  {
4032  if (edgeMidPoint[edgeI] >= 0)
4033  {
4034  // Split edge. Check that face not already handled above.
4035 
4036  const labelList& eFaces = mesh_.edgeFaces(edgeI, eFacesStorage);
4037 
4038  forAll(eFaces, i)
4039  {
4040  label facei = eFaces[i];
4041 
4042  if (faceMidPoint[facei] < 0 && affectedFace.test(facei))
4043  {
4044  // Unsplit face. Add edge splits to face.
4045 
4046  const face& f = mesh_.faces()[facei];
4047  const labelList& fEdges = mesh_.faceEdges
4048  (
4049  facei,
4050  fEdgesStorage
4051  );
4052 
4053  DynamicList<label> newFaceVerts(f.size());
4054 
4055  forAll(f, fp)
4056  {
4057  newFaceVerts.append(f[fp]);
4058 
4059  label edgeI = fEdges[fp];
4060 
4061  if (edgeMidPoint[edgeI] >= 0)
4062  {
4063  newFaceVerts.append(edgeMidPoint[edgeI]);
4064  }
4065  }
4066 
4067  face newFace;
4068  newFace.transfer(newFaceVerts);
4069 
4070  // The point with the lowest level should be an anchor
4071  // point of the neighbouring cells.
4072  label anchorFp = findMinLevel(f);
4073 
4074  label own, nei;
4075  getFaceNeighbours
4076  (
4077  cellAnchorPoints,
4078  cellAddedCells,
4079  facei,
4080  f[anchorFp], // Anchor point
4081 
4082  own,
4083  nei
4084  );
4085 
4086 
4087  if (debug)
4088  {
4089  if (mesh_.isInternalFace(facei))
4090  {
4091  label oldOwn = mesh_.faceOwner()[facei];
4092  label oldNei = mesh_.faceNeighbour()[facei];
4093 
4094  checkInternalOrientation
4095  (
4096  meshMod,
4097  oldOwn,
4098  facei,
4099  mesh_.cellCentres()[oldOwn],
4100  mesh_.cellCentres()[oldNei],
4101  newFace
4102  );
4103  }
4104  else
4105  {
4106  label oldOwn = mesh_.faceOwner()[facei];
4107 
4108  checkBoundaryOrientation
4109  (
4110  meshMod,
4111  oldOwn,
4112  facei,
4113  mesh_.cellCentres()[oldOwn],
4114  mesh_.faceCentres()[facei],
4115  newFace
4116  );
4117  }
4118  }
4119 
4120  modFace(meshMod, facei, newFace, own, nei);
4121 
4122  // Mark face as having been handled
4123  affectedFace.unset(facei);
4124  }
4125  }
4126  }
4127  }
4128 
4129 
4130  // 3. faces that do not get split but whose owner/neighbour change
4131  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4132 
4133  if (debug)
4134  {
4135  Pout<< "hexRef8::setRefinement :"
4136  << " Changing owner/neighbour for otherwise unaffected faces"
4137  << endl;
4138  }
4139 
4140  forAll(affectedFace, facei)
4141  {
4142  if (affectedFace.test(facei))
4143  {
4144  const face& f = mesh_.faces()[facei];
4145 
4146  // The point with the lowest level should be an anchor
4147  // point of the neighbouring cells.
4148  label anchorFp = findMinLevel(f);
4149 
4150  label own, nei;
4151  getFaceNeighbours
4152  (
4153  cellAnchorPoints,
4154  cellAddedCells,
4155  facei,
4156  f[anchorFp], // Anchor point
4157 
4158  own,
4159  nei
4160  );
4161 
4162  modFace(meshMod, facei, f, own, nei);
4163 
4164  // Mark face as having been handled
4165  affectedFace.unset(facei);
4166  }
4167  }
4168 
4169 
4170  // 4. new internal faces inside split cells.
4171  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4172 
4173 
4174  // This is the hard one. We have to find the splitting points between
4175  // the anchor points. But the edges between the anchor points might have
4176  // been split (into two,three or four edges).
4177 
4178  if (debug)
4179  {
4180  Pout<< "hexRef8::setRefinement :"
4181  << " Create new internal faces for split cells"
4182  << endl;
4183  }
4184 
4185  forAll(cellMidPoint, celli)
4186  {
4187  if (cellMidPoint[celli] >= 0)
4188  {
4189  createInternalFaces
4190  (
4191  cellAnchorPoints,
4192  cellAddedCells,
4193  cellMidPoint,
4194  faceMidPoint,
4195  faceAnchorLevel,
4196  edgeMidPoint,
4197  celli,
4198  meshMod
4199  );
4200  }
4201  }
4202 
4203  // Extend pointLevels and cellLevels for the new cells. Could also be done
4204  // in updateMesh but saves passing cellAddedCells out of this routine.
4205 
4206  // Check
4207  if (debug)
4208  {
4209  label minPointi = labelMax;
4210  label maxPointi = labelMin;
4211 
4212  forAll(cellMidPoint, celli)
4213  {
4214  if (cellMidPoint[celli] >= 0)
4215  {
4216  minPointi = min(minPointi, cellMidPoint[celli]);
4217  maxPointi = max(maxPointi, cellMidPoint[celli]);
4218  }
4219  }
4220  forAll(faceMidPoint, facei)
4221  {
4222  if (faceMidPoint[facei] >= 0)
4223  {
4224  minPointi = min(minPointi, faceMidPoint[facei]);
4225  maxPointi = max(maxPointi, faceMidPoint[facei]);
4226  }
4227  }
4228  forAll(edgeMidPoint, edgeI)
4229  {
4230  if (edgeMidPoint[edgeI] >= 0)
4231  {
4232  minPointi = min(minPointi, edgeMidPoint[edgeI]);
4233  maxPointi = max(maxPointi, edgeMidPoint[edgeI]);
4234  }
4235  }
4236 
4237  if (minPointi != labelMax && minPointi != mesh_.nPoints())
4238  {
4240  << "Added point labels not consecutive to existing mesh points."
4241  << nl
4242  << "mesh_.nPoints():" << mesh_.nPoints()
4243  << " minPointi:" << minPointi
4244  << " maxPointi:" << maxPointi
4245  << abort(FatalError);
4246  }
4247  }
4248 
4249  pointLevel_.transfer(newPointLevel);
4250  cellLevel_.transfer(newCellLevel);
4251 
4252  // Mark files as changed
4253  setInstance(mesh_.facesInstance());
4254 
4255 
4256  // Update the live split cells tree.
4257  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4258 
4259  // New unrefinement structure
4260  if (history_.active())
4261  {
4262  if (debug)
4263  {
4264  Pout<< "hexRef8::setRefinement :"
4265  << " Updating refinement history to " << cellLevel_.size()
4266  << " cells" << endl;
4267  }
4268 
4269  // Extend refinement history for new cells
4270  history_.resize(cellLevel_.size());
4271 
4272  forAll(cellAddedCells, celli)
4273  {
4274  const labelList& addedCells = cellAddedCells[celli];
4275 
4276  if (addedCells.size())
4277  {
4278  // Cell was split.
4279  history_.storeSplit(celli, addedCells);
4280  }
4281  }
4282  }
4283 
4284  // Compact cellAddedCells.
4285 
4286  labelListList refinedCells(cellLabels.size());
4287 
4288  forAll(cellLabels, i)
4289  {
4290  label celli = cellLabels[i];
4291 
4292  refinedCells[i].transfer(cellAddedCells[celli]);
4293  }
4294 
4295  return refinedCells;
4296 }
4297 
4300 (
4301  const labelList& pointsToStore,
4302  const labelList& facesToStore,
4303  const labelList& cellsToStore
4304 )
4305 {
4306  savedPointLevel_.clear();
4307  savedPointLevel_.reserve(pointsToStore.size());
4308  forAll(pointsToStore, i)
4309  {
4310  label pointi = pointsToStore[i];
4311  savedPointLevel_.insert(pointi, pointLevel_[pointi]);
4312  }
4313 
4314  savedCellLevel_.clear();
4315  savedCellLevel_.reserve(cellsToStore.size());
4316  forAll(cellsToStore, i)
4317  {
4318  label celli = cellsToStore[i];
4319  savedCellLevel_.insert(celli, cellLevel_[celli]);
4320  }
4321 }
4322 
4323 
4324 // Gets called after the mesh change. setRefinement will already have made
4325 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4326 // only need to account for reordering.
4327 void Foam::hexRef8::updateMesh(const mapPolyMesh& map)
4328 {
4329  Map<label> dummyMap(0);
4330 
4331  updateMesh(map, dummyMap, dummyMap, dummyMap);
4332 }
4333 
4334 
4335 // Gets called after the mesh change. setRefinement will already have made
4336 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4337 // only need to account for reordering.
4339 (
4340  const mapPolyMesh& map,
4341  const Map<label>& pointsToRestore,
4342  const Map<label>& facesToRestore,
4343  const Map<label>& cellsToRestore
4344 )
4345 {
4346  // Update celllevel
4347  if (debug)
4348  {
4349  Pout<< "hexRef8::updateMesh :"
4350  << " Updating various lists"
4351  << endl;
4352  }
4353 
4354  {
4355  const labelList& reverseCellMap = map.reverseCellMap();
4356 
4357  if (debug)
4358  {
4359  Pout<< "hexRef8::updateMesh :"
4360  << " reverseCellMap:" << map.reverseCellMap().size()
4361  << " cellMap:" << map.cellMap().size()
4362  << " nCells:" << mesh_.nCells()
4363  << " nOldCells:" << map.nOldCells()
4364  << " cellLevel_:" << cellLevel_.size()
4365  << " reversePointMap:" << map.reversePointMap().size()
4366  << " pointMap:" << map.pointMap().size()
4367  << " nPoints:" << mesh_.nPoints()
4368  << " nOldPoints:" << map.nOldPoints()
4369  << " pointLevel_:" << pointLevel_.size()
4370  << endl;
4371  }
4372 
4373  if (reverseCellMap.size() == cellLevel_.size())
4374  {
4375  // Assume it is after hexRef8 that this routine is called.
4376  // Just account for reordering. We cannot use cellMap since
4377  // then cells created from cells would get cellLevel_ of
4378  // cell they were created from.
4379  reorder(reverseCellMap, mesh_.nCells(), -1, cellLevel_);
4380  }
4381  else
4382  {
4383  // Map data
4384  const labelList& cellMap = map.cellMap();
4385 
4386  labelList newCellLevel(cellMap.size());
4387  forAll(cellMap, newCelli)
4388  {
4389  label oldCelli = cellMap[newCelli];
4390 
4391  if (oldCelli == -1)
4392  {
4393  newCellLevel[newCelli] = -1;
4394  }
4395  else
4396  {
4397  newCellLevel[newCelli] = cellLevel_[oldCelli];
4398  }
4399  }
4400  cellLevel_.transfer(newCellLevel);
4401  }
4402 
4403  // See if any cells to restore. This will be for some new cells
4404  // the corresponding old cell.
4405  forAllConstIters(cellsToRestore, iter)
4406  {
4407  const label newCelli = iter.key();
4408  const label storedCelli = iter.val();
4409 
4410  const auto fnd = savedCellLevel_.cfind(storedCelli);
4411 
4412  if (!fnd.good())
4413  {
4415  << "Problem : trying to restore old value for new cell "
4416  << newCelli << " but cannot find old cell " << storedCelli
4417  << " in map of stored values " << savedCellLevel_
4418  << abort(FatalError);
4419  }
4420  cellLevel_[newCelli] = fnd.val();
4421  }
4422 
4423  //if (cellLevel_.found(-1))
4424  //{
4425  // WarningInFunction
4426  // << "Problem : "
4427  // << "cellLevel_ contains illegal value -1 after mapping
4428  // << " at cell " << cellLevel_.find(-1) << endl
4429  // << "This means that another program has inflated cells"
4430  // << " (created cells out-of-nothing) and hence we don't know"
4431  // << " their cell level. Continuing with illegal value."
4432  // << abort(FatalError);
4433  //}
4434  }
4435 
4436 
4437  // Update pointlevel
4438  {
4439  const labelList& reversePointMap = map.reversePointMap();
4440 
4441  if (reversePointMap.size() == pointLevel_.size())
4442  {
4443  // Assume it is after hexRef8 that this routine is called.
4444  reorder(reversePointMap, mesh_.nPoints(), -1, pointLevel_);
4445  }
4446  else
4447  {
4448  // Map data
4449  const labelList& pointMap = map.pointMap();
4450 
4451  labelList newPointLevel(pointMap.size());
4452 
4453  forAll(pointMap, newPointi)
4454  {
4455  const label oldPointi = pointMap[newPointi];
4456 
4457  if (oldPointi == -1)
4458  {
4459  //FatalErrorInFunction
4460  // << "Problem : point " << newPointi
4461  // << " at " << mesh_.points()[newPointi]
4462  // << " does not originate from another point"
4463  // << " (i.e. is inflated)." << nl
4464  // << "Hence we cannot determine the new pointLevel"
4465  // << " for it." << abort(FatalError);
4466  newPointLevel[newPointi] = -1;
4467  }
4468  else
4469  {
4470  newPointLevel[newPointi] = pointLevel_[oldPointi];
4471  }
4472  }
4473  pointLevel_.transfer(newPointLevel);
4474  }
4475 
4476  // See if any points to restore. This will be for some new points
4477  // the corresponding old point (the one from the call to storeData)
4478  forAllConstIters(pointsToRestore, iter)
4479  {
4480  const label newPointi = iter.key();
4481  const label storedPointi = iter.val();
4482 
4483  auto fnd = savedPointLevel_.find(storedPointi);
4484 
4485  if (!fnd.good())
4486  {
4488  << "Problem : trying to restore old value for new point "
4489  << newPointi << " but cannot find old point "
4490  << storedPointi
4491  << " in map of stored values " << savedPointLevel_
4492  << abort(FatalError);
4493  }
4494  pointLevel_[newPointi] = fnd.val();
4495  }
4496 
4497  //if (pointLevel_.found(-1))
4498  //{
4499  // WarningInFunction
4500  // << "Problem : "
4501  // << "pointLevel_ contains illegal value -1 after mapping"
4502  // << " at point" << pointLevel_.find(-1) << endl
4503  // << "This means that another program has inflated points"
4504  // << " (created points out-of-nothing) and hence we don't know"
4505  // << " their point level. Continuing with illegal value."
4506  // //<< abort(FatalError);
4507  //}
4508  }
4509 
4510  // Update refinement tree
4511  if (history_.active())
4512  {
4513  history_.updateMesh(map);
4514  }
4515 
4516  // Mark files as changed
4517  setInstance(mesh_.facesInstance());
4518 
4519  // Update face removal engine
4520  faceRemover_.updateMesh(map);
4521 
4522  // Clear cell shapes
4523  cellShapesPtr_.clear();
4524 }
4525 
4526 
4527 // Gets called after mesh subsetting. Maps are from new back to old.
4529 (
4530  const labelList& pointMap,
4531  const labelList& faceMap,
4532  const labelList& cellMap
4533 )
4534 {
4535  // Update celllevel
4536  if (debug)
4537  {
4538  Pout<< "hexRef8::subset :"
4539  << " Updating various lists"
4540  << endl;
4541  }
4542 
4543  if (history_.active())
4544  {
4546  << "Subsetting will not work in combination with unrefinement."
4547  << nl
4548  << "Proceed at your own risk." << endl;
4549  }
4550 
4551 
4552  // Update celllevel
4553  {
4554  labelList newCellLevel(cellMap.size());
4555 
4556  forAll(cellMap, newCelli)
4557  {
4558  newCellLevel[newCelli] = cellLevel_[cellMap[newCelli]];
4559  }
4560 
4561  cellLevel_.transfer(newCellLevel);
4562 
4563  if (cellLevel_.found(-1))
4564  {
4566  << "Problem : "
4567  << "cellLevel_ contains illegal value -1 after mapping:"
4568  << cellLevel_
4569  << abort(FatalError);
4570  }
4571  }
4572 
4573  // Update pointlevel
4574  {
4575  labelList newPointLevel(pointMap.size());
4576 
4577  forAll(pointMap, newPointi)
4578  {
4579  newPointLevel[newPointi] = pointLevel_[pointMap[newPointi]];
4580  }
4581 
4582  pointLevel_.transfer(newPointLevel);
4583 
4584  if (pointLevel_.found(-1))
4585  {
4587  << "Problem : "
4588  << "pointLevel_ contains illegal value -1 after mapping:"
4589  << pointLevel_
4590  << abort(FatalError);
4591  }
4592  }
4593 
4594  // Update refinement tree
4595  if (history_.active())
4596  {
4597  history_.subset(pointMap, faceMap, cellMap);
4598  }
4599 
4600  // Mark files as changed
4601  setInstance(mesh_.facesInstance());
4602 
4603  // Nothing needs doing to faceRemover.
4604  //faceRemover_.subset(pointMap, faceMap, cellMap);
4605 
4606  // Clear cell shapes
4607  cellShapesPtr_.clear();
4608 }
4609 
4611 // Gets called after the mesh distribution
4613 {
4614  if (debug)
4615  {
4616  Pout<< "hexRef8::distribute :"
4617  << " Updating various lists"
4618  << endl;
4619  }
4620 
4621  // Update celllevel
4622  map.distributeCellData(cellLevel_);
4623  // Update pointlevel
4624  map.distributePointData(pointLevel_);
4625 
4626  // Update refinement tree
4627  if (history_.active())
4628  {
4629  history_.distribute(map);
4630  }
4631 
4632  // Update face removal engine
4633  faceRemover_.distribute(map);
4634 
4635  // Clear cell shapes
4636  cellShapesPtr_.clear();
4637 }
4639 
4640 void Foam::hexRef8::checkMesh() const
4641 {
4642  const scalar smallDim = 1e-6 * mesh_.bounds().mag();
4643 
4644  if (debug)
4645  {
4646  Pout<< "hexRef8::checkMesh : Using matching tolerance smallDim:"
4647  << smallDim << endl;
4648  }
4649 
4650  // Check owner on coupled faces.
4651  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4652 
4653  // There should be only one coupled face between two cells. Why? Since
4654  // otherwise mesh redistribution might cause multiple faces between two
4655  // cells
4656  {
4657  labelList nei(mesh_.nBoundaryFaces());
4658  forAll(nei, i)
4659  {
4660  nei[i] = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4661  }
4662 
4663  // Replace data on coupled patches with their neighbour ones.
4664  syncTools::swapBoundaryFaceList(mesh_, nei);
4665 
4666  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4667 
4668  forAll(patches, patchi)
4669  {
4670  const polyPatch& pp = patches[patchi];
4671 
4672  if (pp.coupled())
4673  {
4674  // Check how many faces between owner and neighbour.
4675  // Should be only one.
4676  labelPairLookup cellToFace(2*pp.size());
4677 
4678  label facei = pp.start();
4679 
4680  forAll(pp, i)
4681  {
4682  label own = mesh_.faceOwner()[facei];
4683  label bFacei = facei-mesh_.nInternalFaces();
4684 
4685  if (!cellToFace.insert(labelPair(own, nei[bFacei]), facei))
4686  {
4687  dumpCell(own);
4689  << "Faces do not seem to be correct across coupled"
4690  << " boundaries" << endl
4691  << "Coupled face " << facei
4692  << " between owner " << own
4693  << " on patch " << pp.name()
4694  << " and coupled neighbour " << nei[bFacei]
4695  << " has two faces connected to it:"
4696  << facei << " and "
4697  << cellToFace[labelPair(own, nei[bFacei])]
4698  << abort(FatalError);
4699  }
4700 
4701  facei++;
4702  }
4703  }
4704  }
4705  }
4706 
4707  // Check face areas.
4708  // ~~~~~~~~~~~~~~~~~
4709 
4710  {
4711  scalarField neiFaceAreas(mesh_.nBoundaryFaces());
4712  forAll(neiFaceAreas, i)
4713  {
4714  neiFaceAreas[i] = mag(mesh_.faceAreas()[i+mesh_.nInternalFaces()]);
4715  }
4716 
4717  // Replace data on coupled patches with their neighbour ones.
4718  syncTools::swapBoundaryFaceList(mesh_, neiFaceAreas);
4719 
4720  forAll(neiFaceAreas, i)
4721  {
4722  label facei = i+mesh_.nInternalFaces();
4723 
4724  const scalar magArea = mag(mesh_.faceAreas()[facei]);
4725 
4726  if (mag(magArea - neiFaceAreas[i]) > smallDim)
4727  {
4728  const face& f = mesh_.faces()[facei];
4729  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4730 
4731  dumpCell(mesh_.faceOwner()[facei]);
4732 
4734  << "Faces do not seem to be correct across coupled"
4735  << " boundaries" << endl
4736  << "Coupled face " << facei
4737  << " on patch " << patchi
4738  << " " << mesh_.boundaryMesh()[patchi].name()
4739  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4740  << " has face area:" << magArea
4741  << " (coupled) neighbour face area differs:"
4742  << neiFaceAreas[i]
4743  << " to within tolerance " << smallDim
4744  << abort(FatalError);
4745  }
4746  }
4747  }
4748 
4749 
4750  // Check number of points on faces.
4751  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4752  {
4753  labelList nVerts(mesh_.nBoundaryFaces());
4754 
4755  forAll(nVerts, i)
4756  {
4757  nVerts[i] = mesh_.faces()[i+mesh_.nInternalFaces()].size();
4758  }
4759 
4760  // Replace data on coupled patches with their neighbour ones.
4761  syncTools::swapBoundaryFaceList(mesh_, nVerts);
4762 
4763  forAll(nVerts, i)
4764  {
4765  label facei = i+mesh_.nInternalFaces();
4766 
4767  const face& f = mesh_.faces()[facei];
4768 
4769  if (f.size() != nVerts[i])
4770  {
4771  dumpCell(mesh_.faceOwner()[facei]);
4772 
4773  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4774 
4776  << "Faces do not seem to be correct across coupled"
4777  << " boundaries" << endl
4778  << "Coupled face " << facei
4779  << " on patch " << patchi
4780  << " " << mesh_.boundaryMesh()[patchi].name()
4781  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4782  << " has size:" << f.size()
4783  << " (coupled) neighbour face has size:"
4784  << nVerts[i]
4785  << abort(FatalError);
4786  }
4787  }
4788  }
4789 
4790 
4791  // Check points of face
4792  // ~~~~~~~~~~~~~~~~~~~~
4793  {
4794  // Anchor points.
4795  pointField anchorPoints(mesh_.nBoundaryFaces());
4796 
4797  forAll(anchorPoints, i)
4798  {
4799  label facei = i+mesh_.nInternalFaces();
4800  const point& fc = mesh_.faceCentres()[facei];
4801  const face& f = mesh_.faces()[facei];
4802  const vector anchorVec(mesh_.points()[f[0]] - fc);
4803 
4804  anchorPoints[i] = anchorVec;
4805  }
4806 
4807  // Replace data on coupled patches with their neighbour ones. Apply
4808  // rotation transformation (but not separation since is relative vector
4809  // to point on same face.
4810  syncTools::swapBoundaryFaceList(mesh_, anchorPoints);
4811 
4812  forAll(anchorPoints, i)
4813  {
4814  label facei = i+mesh_.nInternalFaces();
4815  const point& fc = mesh_.faceCentres()[facei];
4816  const face& f = mesh_.faces()[facei];
4817  const vector anchorVec(mesh_.points()[f[0]] - fc);
4818 
4819  if (mag(anchorVec - anchorPoints[i]) > smallDim)
4820  {
4821  dumpCell(mesh_.faceOwner()[facei]);
4822 
4823  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4824 
4826  << "Faces do not seem to be correct across coupled"
4827  << " boundaries" << endl
4828  << "Coupled face " << facei
4829  << " on patch " << patchi
4830  << " " << mesh_.boundaryMesh()[patchi].name()
4831  << " coords:" << UIndirectList<point>(mesh_.points(), f)
4832  << " has anchor vector:" << anchorVec
4833  << " (coupled) neighbour face anchor vector differs:"
4834  << anchorPoints[i]
4835  << " to within tolerance " << smallDim
4836  << abort(FatalError);
4837  }
4838  }
4839  }
4840 
4841  if (debug)
4842  {
4843  Pout<< "hexRef8::checkMesh : Returning" << endl;
4844  }
4845 }
4846 
4849 (
4850  const label maxPointDiff,
4851  const labelList& pointsToCheck
4852 ) const
4853 {
4854  if (debug)
4855  {
4856  Pout<< "hexRef8::checkRefinementLevels :"
4857  << " Checking 2:1 refinement level" << endl;
4858  }
4859 
4860  if
4861  (
4862  cellLevel_.size() != mesh_.nCells()
4863  || pointLevel_.size() != mesh_.nPoints()
4864  )
4865  {
4867  << "cellLevel size should be number of cells"
4868  << " and pointLevel size should be number of points."<< nl
4869  << "cellLevel:" << cellLevel_.size()
4870  << " mesh.nCells():" << mesh_.nCells() << nl
4871  << "pointLevel:" << pointLevel_.size()
4872  << " mesh.nPoints():" << mesh_.nPoints()
4873  << abort(FatalError);
4874  }
4875 
4876 
4877  // Check 2:1 consistency.
4878  // ~~~~~~~~~~~~~~~~~~~~~~
4879 
4880  {
4881  // Internal faces.
4882  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
4883  {
4884  label own = mesh_.faceOwner()[facei];
4885  label nei = mesh_.faceNeighbour()[facei];
4886 
4887  if (mag(cellLevel_[own] - cellLevel_[nei]) > 1)
4888  {
4889  dumpCell(own);
4890  dumpCell(nei);
4891 
4893  << "Celllevel does not satisfy 2:1 constraint." << nl
4894  << "On face " << facei << " owner cell " << own
4895  << " has refinement " << cellLevel_[own]
4896  << " neighbour cell " << nei << " has refinement "
4897  << cellLevel_[nei]
4898  << abort(FatalError);
4899  }
4900  }
4901 
4902  // Coupled faces. Get neighbouring value
4903  labelList neiLevel(mesh_.nBoundaryFaces());
4904 
4905  forAll(neiLevel, i)
4906  {
4907  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4908 
4909  neiLevel[i] = cellLevel_[own];
4910  }
4911 
4912  // No separation
4913  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
4914 
4915  forAll(neiLevel, i)
4916  {
4917  label facei = i+mesh_.nInternalFaces();
4918 
4919  label own = mesh_.faceOwner()[facei];
4920 
4921  if (mag(cellLevel_[own] - neiLevel[i]) > 1)
4922  {
4923  dumpCell(own);
4924 
4925  label patchi = mesh_.boundaryMesh().whichPatch(facei);
4926 
4928  << "Celllevel does not satisfy 2:1 constraint."
4929  << " On coupled face " << facei
4930  << " on patch " << patchi << " "
4931  << mesh_.boundaryMesh()[patchi].name()
4932  << " owner cell " << own << " has refinement "
4933  << cellLevel_[own]
4934  << " (coupled) neighbour cell has refinement "
4935  << neiLevel[i]
4936  << abort(FatalError);
4937  }
4938  }
4939  }
4940 
4941 
4942  // Check pointLevel is synchronized
4943  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4944  {
4945  labelList syncPointLevel(pointLevel_);
4946 
4947  // Get min level
4949  (
4950  mesh_,
4951  syncPointLevel,
4952  minEqOp<label>(),
4953  labelMax
4954  );
4955 
4956 
4957  forAll(syncPointLevel, pointi)
4958  {
4959  if (pointLevel_[pointi] != syncPointLevel[pointi])
4960  {
4962  << "PointLevel is not consistent across coupled patches."
4963  << endl
4964  << "point:" << pointi << " coord:" << mesh_.points()[pointi]
4965  << " has level " << pointLevel_[pointi]
4966  << " whereas the coupled point has level "
4967  << syncPointLevel[pointi]
4968  << abort(FatalError);
4969  }
4970  }
4971  }
4972 
4973 
4974  // Check 2:1 across points (instead of faces)
4975  if (maxPointDiff != -1)
4976  {
4977  // Determine per point the max cell level.
4978  labelList maxPointLevel(mesh_.nPoints(), Zero);
4979 
4980  forAll(maxPointLevel, pointi)
4981  {
4982  const labelList& pCells = mesh_.pointCells(pointi);
4983 
4984  label& pLevel = maxPointLevel[pointi];
4985 
4986  forAll(pCells, i)
4987  {
4988  pLevel = max(pLevel, cellLevel_[pCells[i]]);
4989  }
4990  }
4991 
4992  // Sync maxPointLevel to neighbour
4994  (
4995  mesh_,
4996  maxPointLevel,
4997  maxEqOp<label>(),
4998  labelMin // null value
4999  );
5000 
5001  // Check 2:1 across boundary points
5002  forAll(pointsToCheck, i)
5003  {
5004  label pointi = pointsToCheck[i];
5005 
5006  const labelList& pCells = mesh_.pointCells(pointi);
5007 
5008  forAll(pCells, i)
5009  {
5010  label celli = pCells[i];
5011 
5012  if
5013  (
5014  mag(cellLevel_[celli]-maxPointLevel[pointi])
5015  > maxPointDiff
5016  )
5017  {
5018  dumpCell(celli);
5019 
5021  << "Too big a difference between"
5022  << " point-connected cells." << nl
5023  << "cell:" << celli
5024  << " cellLevel:" << cellLevel_[celli]
5025  << " uses point:" << pointi
5026  << " coord:" << mesh_.points()[pointi]
5027  << " which is also used by a cell with level:"
5028  << maxPointLevel[pointi]
5029  << abort(FatalError);
5030  }
5031  }
5032  }
5033  }
5034 
5035 
5036  //- Gives problems after first splitting off inside mesher.
5038  //{
5039  // // Any patches with points having only two edges.
5040  //
5041  // boolList isHangingPoint(mesh_.nPoints(), false);
5042  //
5043  // const polyBoundaryMesh& patches = mesh_.boundaryMesh();
5044  //
5045  // forAll(patches, patchi)
5046  // {
5047  // const polyPatch& pp = patches[patchi];
5048  //
5049  // const labelList& meshPoints = pp.meshPoints();
5050  //
5051  // forAll(meshPoints, i)
5052  // {
5053  // label pointi = meshPoints[i];
5054  //
5055  // const labelList& pEdges = mesh_.pointEdges()[pointi];
5056  //
5057  // if (pEdges.size() == 2)
5058  // {
5059  // isHangingPoint[pointi] = true;
5060  // }
5061  // }
5062  // }
5063  //
5064  // syncTools::syncPointList
5065  // (
5066  // mesh_,
5067  // isHangingPoint,
5068  // andEqOp<bool>(), // only if all decide it is hanging point
5069  // true, // null
5070  // false // no separation
5071  // );
5072  //
5073  // //OFstream str(mesh_.time().path()/"hangingPoints.obj");
5074  //
5075  // label nHanging = 0;
5076  //
5077  // forAll(isHangingPoint, pointi)
5078  // {
5079  // if (isHangingPoint[pointi])
5080  // {
5081  // nHanging++;
5082  //
5083  // Pout<< "Hanging boundary point " << pointi
5084  // << " at " << mesh_.points()[pointi]
5085  // << endl;
5086  // //meshTools::writeOBJ(str, mesh_.points()[pointi]);
5087  // }
5088  // }
5089  //
5090  // if (returnReduceOr(nHanging))
5091  // {
5092  // FatalErrorInFunction
5093  // << "Detected a point used by two edges only (hanging point)"
5094  // << nl << "This is not allowed"
5095  // << abort(FatalError);
5096  // }
5097  //}
5098 }
5099 
5100 
5103  if (!cellShapesPtr_)
5104  {
5105  if (debug)
5106  {
5107  Pout<< "hexRef8::cellShapes() : calculating splitHex cellShapes."
5108  << " cellLevel:" << cellLevel_.size()
5109  << " pointLevel:" << pointLevel_.size()
5110  << endl;
5111  }
5112 
5113  const cellShapeList& meshShapes = mesh_.cellShapes();
5114  cellShapesPtr_.reset(new cellShapeList(meshShapes));
5115 
5116  label nSplitHex = 0;
5117  label nUnrecognised = 0;
5118 
5119  forAll(cellLevel_, celli)
5120  {
5121  if (meshShapes[celli].model().index() == 0)
5122  {
5123  label level = cellLevel_[celli];
5124 
5125  // Return true if we've found 6 quads
5126  DynamicList<face> quads;
5127  bool haveQuads = matchHexShape
5128  (
5129  celli,
5130  level,
5131  quads
5132  );
5133 
5134  if (haveQuads)
5135  {
5136  faceList faces(std::move(quads));
5137  cellShapesPtr_()[celli] = degenerateMatcher::match(faces);
5138  nSplitHex++;
5139  }
5140  else
5141  {
5142  nUnrecognised++;
5143  }
5144  }
5145  }
5146  if (debug)
5147  {
5148  Pout<< "hexRef8::cellShapes() :"
5149  << " nCells:" << mesh_.nCells() << " of which" << nl
5150  << " primitive:" << (mesh_.nCells()-nSplitHex-nUnrecognised)
5151  << nl
5152  << " split-hex:" << nSplitHex << nl
5153  << " poly :" << nUnrecognised << nl
5154  << endl;
5155  }
5156  }
5157  return *cellShapesPtr_;
5158 }
5159 
5160 
5163  if (debug)
5164  {
5165  checkRefinementLevels(-1, labelList(0));
5166  }
5167 
5168  if (debug)
5169  {
5170  Pout<< "hexRef8::getSplitPoints :"
5171  << " Calculating unrefineable points" << endl;
5172  }
5173 
5174 
5175  if (!history_.active())
5176  {
5178  << "Only call if constructed with history capability"
5179  << abort(FatalError);
5180  }
5181 
5182  // Master cell
5183  // -1 undetermined
5184  // -2 certainly not split point
5185  // >= label of master cell
5186  labelList splitMaster(mesh_.nPoints(), -1);
5187  labelList splitMasterLevel(mesh_.nPoints(), Zero);
5188 
5189  // Unmark all with not 8 cells
5190  //const labelListList& pointCells = mesh_.pointCells();
5191 
5192  for (label pointi = 0; pointi < mesh_.nPoints(); pointi++)
5193  {
5194  const labelList& pCells = mesh_.pointCells(pointi);
5195 
5196  if (pCells.size() != 8)
5197  {
5198  splitMaster[pointi] = -2;
5199  }
5200  }
5201 
5202  // Unmark all with different master cells
5203  const labelList& visibleCells = history_.visibleCells();
5204 
5205  forAll(visibleCells, celli)
5206  {
5207  const labelList& cPoints = mesh_.cellPoints(celli);
5208 
5209  if (visibleCells[celli] != -1 && history_.parentIndex(celli) >= 0)
5210  {
5211  label parentIndex = history_.parentIndex(celli);
5212 
5213  // Check same master.
5214  forAll(cPoints, i)
5215  {
5216  label pointi = cPoints[i];
5217 
5218  label masterCelli = splitMaster[pointi];
5219 
5220  if (masterCelli == -1)
5221  {
5222  // First time visit of point. Store parent cell and
5223  // level of the parent cell (with respect to celli). This
5224  // is additional guarantee that we're referring to the
5225  // same master at the same refinement level.
5226 
5227  splitMaster[pointi] = parentIndex;
5228  splitMasterLevel[pointi] = cellLevel_[celli] - 1;
5229  }
5230  else if (masterCelli == -2)
5231  {
5232  // Already decided that point is not splitPoint
5233  }
5234  else if
5235  (
5236  (masterCelli != parentIndex)
5237  || (splitMasterLevel[pointi] != cellLevel_[celli] - 1)
5238  )
5239  {
5240  // Different masters so point is on two refinement
5241  // patterns
5242  splitMaster[pointi] = -2;
5243  }
5244  }
5245  }
5246  else
5247  {
5248  // Either not visible or is unrefined cell
5249  forAll(cPoints, i)
5250  {
5251  label pointi = cPoints[i];
5252 
5253  splitMaster[pointi] = -2;
5254  }
5255  }
5256  }
5257 
5258  // Unmark boundary faces
5259  for
5260  (
5261  label facei = mesh_.nInternalFaces();
5262  facei < mesh_.nFaces();
5263  facei++
5264  )
5265  {
5266  const face& f = mesh_.faces()[facei];
5267 
5268  forAll(f, fp)
5269  {
5270  splitMaster[f[fp]] = -2;
5271  }
5272  }
5273 
5274 
5275  // Collect into labelList
5276 
5277  label nSplitPoints = 0;
5278 
5279  forAll(splitMaster, pointi)
5280  {
5281  if (splitMaster[pointi] >= 0)
5282  {
5283  nSplitPoints++;
5284  }
5285  }
5286 
5287  labelList splitPoints(nSplitPoints);
5288  nSplitPoints = 0;
5289 
5290  forAll(splitMaster, pointi)
5291  {
5292  if (splitMaster[pointi] >= 0)
5293  {
5294  splitPoints[nSplitPoints++] = pointi;
5295  }
5296  }
5297 
5298  return splitPoints;
5299 }
5300 
5301 
5302 //void Foam::hexRef8::markIndex
5303 //(
5304 // const label maxLevel,
5305 // const label level,
5306 // const label index,
5307 // const label markValue,
5308 // labelList& indexValues
5309 //) const
5310 //{
5311 // if (level < maxLevel && indexValues[index] == -1)
5312 // {
5313 // // Mark
5314 // indexValues[index] = markValue;
5315 //
5316 // // Mark parent
5317 // const splitCell8& split = history_.splitCells()[index];
5318 //
5319 // if (split.parent_ >= 0)
5320 // {
5321 // markIndex
5322 // (
5323 // maxLevel, level+1, split.parent_, markValue, indexValues);
5324 // )
5325 // }
5326 // }
5327 //}
5328 //
5329 //
5334 //void Foam::hexRef8::markCellClusters
5335 //(
5336 // const label maxLevel,
5337 // labelList& cluster
5338 //) const
5339 //{
5340 // cluster.setSize(mesh_.nCells());
5341 // cluster = -1;
5342 //
5343 // const DynamicList<splitCell8>& splitCells = history_.splitCells();
5344 //
5345 // // Mark all splitCells down to level maxLevel with a cell originating from
5346 // // it.
5347 //
5348 // labelList indexLevel(splitCells.size(), -1);
5349 //
5350 // forAll(visibleCells, celli)
5351 // {
5352 // label index = visibleCells[celli];
5353 //
5354 // if (index >= 0)
5355 // {
5356 // markIndex(maxLevel, 0, index, celli, indexLevel);
5357 // }
5358 // }
5359 //
5360 // // Mark cells with splitCell
5361 //}
5362 
5363 
5365 (
5366  const labelList& pointsToUnrefine,
5367  const bool maxSet
5368 ) const
5369 {
5370  if (debug)
5371  {
5372  Pout<< "hexRef8::consistentUnrefinement :"
5373  << " Determining 2:1 consistent unrefinement" << endl;
5374  }
5375 
5376  if (maxSet)
5377  {
5379  << "maxSet not implemented yet."
5380  << abort(FatalError);
5381  }
5382 
5383  // Loop, modifying pointsToUnrefine, until no more changes to due to 2:1
5384  // conflicts.
5385  // maxSet = false : unselect points to refine
5386  // maxSet = true: select points to refine
5387 
5388  // Maintain bitset for pointsToUnrefine and cellsToUnrefine
5389  bitSet unrefinePoint(mesh_.nPoints(), pointsToUnrefine);
5390 
5391  while (true)
5392  {
5393  // Construct cells to unrefine
5394  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5395 
5396  bitSet unrefineCell(mesh_.nCells());
5397 
5398  forAll(unrefinePoint, pointi)
5399  {
5400  if (unrefinePoint.test(pointi))
5401  {
5402  const labelList& pCells = mesh_.pointCells(pointi);
5403 
5404  unrefineCell.set(pCells);
5405  }
5406  }
5407 
5408 
5409  label nChanged = 0;
5410 
5411 
5412  // Check 2:1 consistency taking refinement into account
5413  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5414 
5415  // Internal faces.
5416  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
5417  {
5418  label own = mesh_.faceOwner()[facei];
5419  label nei = mesh_.faceNeighbour()[facei];
5420 
5421  label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5422  label neiLevel = cellLevel_[nei] - unrefineCell.get(nei);
5423 
5424  if (ownLevel < (neiLevel-1))
5425  {
5426  // Since was 2:1 this can only occur if own is marked for
5427  // unrefinement.
5428 
5429  if (maxSet)
5430  {
5431  unrefineCell.set(nei);
5432  }
5433  else
5434  {
5435  // could also combine with unset:
5436  // if (!unrefineCell.unset(own))
5437  // {
5438  // FatalErrorInFunction
5439  // << "problem cell already unset"
5440  // << abort(FatalError);
5441  // }
5442  if (!unrefineCell.test(own))
5443  {
5445  << "problem" << abort(FatalError);
5446  }
5447 
5448  unrefineCell.unset(own);
5449  }
5450  nChanged++;
5451  }
5452  else if (neiLevel < (ownLevel-1))
5453  {
5454  if (maxSet)
5455  {
5456  unrefineCell.set(own);
5457  }
5458  else
5459  {
5460  if (!unrefineCell.test(nei))
5461  {
5463  << "problem" << abort(FatalError);
5464  }
5465 
5466  unrefineCell.unset(nei);
5467  }
5468  nChanged++;
5469  }
5470  }
5471 
5472 
5473  // Coupled faces. Swap owner level to get neighbouring cell level.
5474  labelList neiLevel(mesh_.nBoundaryFaces());
5475 
5476  forAll(neiLevel, i)
5477  {
5478  label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
5479 
5480  neiLevel[i] = cellLevel_[own] - unrefineCell.get(own);
5481  }
5482 
5483  // Swap to neighbour
5484  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
5485 
5486  forAll(neiLevel, i)
5487  {
5488  label facei = i+mesh_.nInternalFaces();
5489  label own = mesh_.faceOwner()[facei];
5490  label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5491 
5492  if (ownLevel < (neiLevel[i]-1))
5493  {
5494  if (!maxSet)
5495  {
5496  if (!unrefineCell.test(own))
5497  {
5499  << "problem" << abort(FatalError);
5500  }
5501 
5502  unrefineCell.unset(own);
5503  nChanged++;
5504  }
5505  }
5506  else if (neiLevel[i] < (ownLevel-1))
5507  {
5508  if (maxSet)
5509  {
5510  if (unrefineCell.test(own))
5511  {
5513  << "problem" << abort(FatalError);
5514  }
5515 
5516  unrefineCell.set(own);
5517  nChanged++;
5518  }
5519  }
5520  }
5521 
5522  reduce(nChanged, sumOp<label>());
5523 
5524  if (debug)
5525  {
5526  Pout<< "hexRef8::consistentUnrefinement :"
5527  << " Changed " << nChanged
5528  << " refinement levels due to 2:1 conflicts."
5529  << endl;
5530  }
5531 
5532  if (nChanged == 0)
5533  {
5534  break;
5535  }
5536 
5537 
5538  // Convert cellsToUnrefine back into points to unrefine
5539  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5540 
5541  // Knock out any point whose cell neighbour cannot be unrefined.
5542  forAll(unrefinePoint, pointi)
5543  {
5544  if (unrefinePoint.test(pointi))
5545  {
5546  const labelList& pCells = mesh_.pointCells(pointi);
5547 
5548  forAll(pCells, j)
5549  {
5550  if (!unrefineCell.test(pCells[j]))
5551  {
5552  unrefinePoint.unset(pointi);
5553  break;
5554  }
5555  }
5556  }
5557  }
5558  }
5559 
5560 
5561  // Convert back to labelList.
5562  label nSet = 0;
5563 
5564  forAll(unrefinePoint, pointi)
5565  {
5566  if (unrefinePoint.test(pointi))
5567  {
5568  nSet++;
5569  }
5570  }
5571 
5572  labelList newPointsToUnrefine(nSet);
5573  nSet = 0;
5574 
5575  forAll(unrefinePoint, pointi)
5576  {
5577  if (unrefinePoint.test(pointi))
5578  {
5579  newPointsToUnrefine[nSet++] = pointi;
5580  }
5581  }
5582 
5583  return newPointsToUnrefine;
5584 }
5585 
5586 
5588 (
5589  const labelList& splitPointLabels,
5590  polyTopoChange& meshMod
5591 )
5592 {
5593  if (!history_.active())
5594  {
5596  << "Only call if constructed with history capability"
5597  << abort(FatalError);
5598  }
5599 
5600  if (debug)
5601  {
5602  Pout<< "hexRef8::setUnrefinement :"
5603  << " Checking initial mesh just to make sure" << endl;
5604 
5605  checkMesh();
5606 
5607  forAll(cellLevel_, celli)
5608  {
5609  if (cellLevel_[celli] < 0)
5610  {
5612  << "Illegal cell level " << cellLevel_[celli]
5613  << " for cell " << celli
5614  << abort(FatalError);
5615  }
5616  }
5617 
5618 
5619  // Write to sets.
5620  pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5621  pSet.write();
5622 
5623  cellSet cSet(mesh_, "splitPointCells", splitPointLabels.size());
5624 
5625  forAll(splitPointLabels, i)
5626  {
5627  const labelList& pCells = mesh_.pointCells(splitPointLabels[i]);
5628 
5629  cSet.insert(pCells);
5630  }
5631  cSet.write();
5632 
5633  Pout<< "hexRef8::setRefinement : Dumping " << pSet.size()
5634  << " points and "
5635  << cSet.size() << " cells for unrefinement to" << nl
5636  << " pointSet " << pSet.objectPath() << nl
5637  << " cellSet " << cSet.objectPath()
5638  << endl;
5639  }
5640 
5641 
5642  labelList cellRegion;
5643  labelList cellRegionMaster;
5644  labelList facesToRemove;
5645 
5646  {
5647  labelHashSet splitFaces(12*splitPointLabels.size());
5648 
5649  forAll(splitPointLabels, i)
5650  {
5651  const labelList& pFaces = mesh_.pointFaces()[splitPointLabels[i]];
5652 
5653  splitFaces.insert(pFaces);
5654  }
5655 
5656  // Check with faceRemover what faces will get removed. Note that this
5657  // can be more (but never less) than splitFaces provided.
5658  faceRemover_.compatibleRemoves
5659  (
5660  splitFaces.toc(), // pierced faces
5661  cellRegion, // per cell -1 or region it is merged into
5662  cellRegionMaster, // per region the master cell
5663  facesToRemove // new faces to be removed.
5664  );
5665 
5666  if (facesToRemove.size() != splitFaces.size())
5667  {
5668  // Dump current mesh
5669  {
5670  const_cast<polyMesh&>(mesh_).setInstance
5671  (
5672  mesh_.time().timeName()
5673  );
5674  mesh_.write();
5675  pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5676  pSet.write();
5677  faceSet fSet(mesh_, "splitFaces", splitFaces);
5678  fSet.write();
5679  faceSet removeSet(mesh_, "facesToRemove", facesToRemove);
5680  removeSet.write();
5681  }
5682 
5684  << "Ininitial set of split points to unrefine does not"
5685  << " seem to be consistent or not mid points of refined cells"
5686  << " splitPoints:" << splitPointLabels.size()
5687  << " splitFaces:" << splitFaces.size()
5688  << " facesToRemove:" << facesToRemove.size()
5689  << abort(FatalError);
5690  }
5691  }
5692 
5693  // Redo the region master so it is consistent with our master.
5694  // This will guarantee that the new cell (for which faceRemover uses
5695  // the region master) is already compatible with our refinement structure.
5696 
5697  forAll(splitPointLabels, i)
5698  {
5699  label pointi = splitPointLabels[i];
5700 
5701  // Get original cell label
5702 
5703  const labelList& pCells = mesh_.pointCells(pointi);
5704 
5705  // Check
5706  if (pCells.size() != 8)
5707  {
5709  << "splitPoint " << pointi
5710  << " should have 8 cells using it. It has " << pCells
5711  << abort(FatalError);
5712  }
5713 
5714 
5715  // Check that the lowest numbered pCells is the master of the region
5716  // (should be guaranteed by directRemoveFaces)
5717  //if (debug)
5718  {
5719  label masterCelli = min(pCells);
5720 
5721  forAll(pCells, j)
5722  {
5723  label celli = pCells[j];
5724 
5725  label region = cellRegion[celli];
5726 
5727  if (region == -1)
5728  {
5730  << "Ininitial set of split points to unrefine does not"
5731  << " seem to be consistent or not mid points"
5732  << " of refined cells" << nl
5733  << "cell:" << celli << " on splitPoint " << pointi
5734  << " has no region to be merged into"
5735  << abort(FatalError);
5736  }
5737 
5738  if (masterCelli != cellRegionMaster[region])
5739  {
5741  << "cell:" << celli << " on splitPoint:" << pointi
5742  << " in region " << region
5743  << " has master:" << cellRegionMaster[region]
5744  << " which is not the lowest numbered cell"
5745  << " among the pointCells:" << pCells
5746  << abort(FatalError);
5747  }
5748  }
5749  }
5750  }
5751 
5752  // Insert all commands to combine cells. Never fails so don't have to
5753  // test for success.
5754  faceRemover_.setRefinement
5755  (
5756  facesToRemove,
5757  cellRegion,
5758  cellRegionMaster,
5759  meshMod
5760  );
5761 
5762  // Remove the 8 cells that originated from merging around the split point
5763  // and adapt cell levels (not that pointLevels stay the same since points
5764  // either get removed or stay at the same position.
5765  forAll(splitPointLabels, i)
5766  {
5767  label pointi = splitPointLabels[i];
5768 
5769  const labelList& pCells = mesh_.pointCells(pointi);
5770 
5771  label masterCelli = min(pCells);
5772 
5773  forAll(pCells, j)
5774  {
5775  cellLevel_[pCells[j]]--;
5776  }
5777 
5778  history_.combineCells(masterCelli, pCells);
5779  }
5780 
5781  // Mark files as changed
5782  setInstance(mesh_.facesInstance());
5783 
5784  // history_.updateMesh will take care of truncating.
5785 }
5786 
5787 
5788 // Write refinement to polyMesh directory.
5789 bool Foam::hexRef8::write(const bool writeOnProc) const
5791  bool writeOk =
5792  cellLevel_.write(writeOnProc)
5793  && pointLevel_.write(writeOnProc)
5794  && level0Edge_.write(writeOnProc);
5795 
5796  if (history_.active())
5797  {
5798  writeOk = writeOk && history_.write(writeOnProc);
5799  }
5800  else
5801  {
5803  }
5804 
5805  return writeOk;
5806 }
5807 
5808 
5811  IOobject io
5812  (
5813  "dummy",
5814  mesh.facesInstance(),
5816  mesh
5817  );
5818  fileName setsDir(io.path());
5819 
5820  if (topoSet::debug) DebugVar(setsDir);
5821 
5822  if (exists(setsDir/"cellLevel"))
5823  {
5824  rm(setsDir/"cellLevel");
5825  }
5826  if (exists(setsDir/"pointLevel"))
5827  {
5828  rm(setsDir/"pointLevel");
5829  }
5830  if (exists(setsDir/"level0Edge"))
5831  {
5832  rm(setsDir/"level0Edge");
5833  }
5835 }
5836 
5837 
5838 // ************************************************************************* //
void distribute(const mapDistributePolyMesh &)
Update local numbering for mesh redistribution.
Definition: hexRef8.C:4610
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:116
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
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:859
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:326
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:5589
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:521
bool active() const
Is there unrefinement history?
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
Definition: hexRef8.C:5810
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:493
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:411
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
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:4638
void storeData(const labelList &pointsToStore, const labelList &facesToStore, const labelList &cellsToStore)
Signal points/face/cells for which to store data.
Definition: hexRef8.C:4298
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:2744
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:3284
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:5366
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:284
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:78
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:4527
fileName path() const
The complete path for the object (with instance, local,...).
Definition: IOobject.C:480
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
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:90
void setInstance(const fileName &inst)
Definition: hexRef8.C:1731
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
void setSize(const label n)
Alias for resize()
Definition: List.H:320
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
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
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
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:2286
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:835
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
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:521
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:584
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.
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (respects is_globalIOobject trait) and check its info.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
void updateMesh(const mapPolyMesh &)
Update local numbering for changed mesh.
Definition: hexRef8.C:4325
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:51
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
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...
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
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:2230
void distributePointData(List< T > &values) const
Distribute list of point data.
static void removeFiles(const polyMesh &)
Helper: remove all sets files from mesh instance.
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:59
#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:496
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:5162
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:75
void checkRefinementLevels(const label maxPointDiff, const labelList &pointsToCheck) const
Debug: Check 2:1 consistency across faces.
Definition: hexRef8.C:4847
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:62
All refinement history. Used in unrefinement.
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
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:5790
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:97
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:180
List< wallPoints > allFaceInfo(mesh_.nFaces())
const cellShapeList & cellShapes() const
Utility: get hexes as cell shapes.
Definition: hexRef8.C:5102
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:303
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
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
A HashTable to objects of type <T> with a label key.
static void listCombineReduce(List< T > &values, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Combines List elements. After completion all processors have the same data.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: POSIX.C:1404
label setAction(const topoAction &action)
For compatibility with polyTopoChange: set topological action.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127