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