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