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