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