meshRefinementRefine.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) 2015-2022 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 "meshRefinement.H"
30#include "trackedParticle.H"
31#include "syncTools.H"
32#include "Time.H"
33#include "refinementSurfaces.H"
34#include "refinementFeatures.H"
35#include "shellSurfaces.H"
36#include "faceSet.H"
37#include "decompositionMethod.H"
38#include "fvMeshDistribute.H"
39#include "polyTopoChange.H"
41#include "Cloud.H"
42//#include "globalIndex.H"
43#include "OBJstream.H"
44#include "cellSet.H"
45#include "treeDataCell.H"
46
47#include "cellCuts.H"
48#include "refineCell.H"
49#include "hexCellLooper.H"
50#include "meshCutter.H"
51
52// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
53
54namespace Foam
55{
56 //- To compare normals
57 static bool less(const vector& x, const vector& y)
58 {
59 for (direction i = 0; i < vector::nComponents; i++)
60 {
61 if (x[i] < y[i])
62 {
63 return true;
64 }
65 else if (x[i] > y[i])
66 {
67 return false;
68 }
69 }
70 // All components the same
71 return false;
72 }
73
74
75 //- To compare normals
77 {
78 const vectorList& values_;
79
80 public:
81
82 normalLess(const vectorList& values)
83 :
84 values_(values)
85 {}
86
87 bool operator()(const label a, const label b) const
88 {
89 return less(values_[a], values_[b]);
90 }
91 };
92
93
94 //- Template specialization for pTraits<labelList> so we can have fields
95 template<>
97 {
98
99 public:
100
101 //- Component type
103 };
104
105 //- Template specialization for pTraits<labelList> so we can have fields
106 template<>
108 {
109
110 public:
111
112 //- Component type
114 };
115}
116
117
118// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
119
120// Get faces (on the new mesh) that have in some way been affected by the
121// mesh change. Picks up all faces but those that are between two
122// unrefined faces. (Note that of an unchanged face the edge still might be
123// split but that does not change any face centre or cell centre.
124Foam::labelList Foam::meshRefinement::getChangedFaces
125(
126 const mapPolyMesh& map,
127 const labelList& oldCellsToRefine
128)
129{
130 const polyMesh& mesh = map.mesh();
131
132 labelList changedFaces;
133
134 // For reporting: number of masterFaces changed
135 label nMasterChanged = 0;
136 bitSet isMasterFace(syncTools::getMasterFaces(mesh));
137
138 {
139 // Mark any face on a cell which has been added or changed
140 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141 // Note that refining a face changes the face centre (for a warped face)
142 // which changes the cell centre. This again changes the cellcentre-
143 // cellcentre edge across all faces of the cell.
144 // Note: this does not happen for unwarped faces but unfortunately
145 // we don't have this information.
146
147 const labelList& faceOwner = mesh.faceOwner();
148 const labelList& faceNeighbour = mesh.faceNeighbour();
149 const cellList& cells = mesh.cells();
150 const label nInternalFaces = mesh.nInternalFaces();
151
152 // Mark refined cells on old mesh
153 bitSet oldRefineCell(map.nOldCells(), oldCellsToRefine);
154
155 // Mark refined faces
156 bitSet refinedInternalFace(nInternalFaces);
157
158 // 1. Internal faces
159
160 for (label faceI = 0; faceI < nInternalFaces; faceI++)
161 {
162 label oldOwn = map.cellMap()[faceOwner[faceI]];
163 label oldNei = map.cellMap()[faceNeighbour[faceI]];
164
165 if
166 (
167 oldOwn >= 0 && !oldRefineCell.test(oldOwn)
168 && oldNei >= 0 && !oldRefineCell.test(oldNei)
169 )
170 {
171 // Unaffected face since both neighbours were not refined.
172 }
173 else
174 {
175 refinedInternalFace.set(faceI);
176 }
177 }
178
179
180 // 2. Boundary faces
181
182 boolList refinedBoundaryFace(mesh.nBoundaryFaces(), false);
183
184 forAll(mesh.boundaryMesh(), patchI)
185 {
186 const polyPatch& pp = mesh.boundaryMesh()[patchI];
187
188 label faceI = pp.start();
189
190 forAll(pp, i)
191 {
192 label oldOwn = map.cellMap()[faceOwner[faceI]];
193
194 if (oldOwn >= 0 && !oldRefineCell.test(oldOwn))
195 {
196 // owner did exist and wasn't refined.
197 }
198 else
199 {
200 refinedBoundaryFace[faceI-nInternalFaces] = true;
201 }
202 faceI++;
203 }
204 }
205
206 // Synchronise refined face status
208 (
209 mesh,
210 refinedBoundaryFace,
211 orEqOp<bool>()
212 );
213
214
215 // 3. Mark all faces affected by refinement. Refined faces are in
216 // - refinedInternalFace
217 // - refinedBoundaryFace
218 boolList changedFace(mesh.nFaces(), false);
219
220 forAll(refinedInternalFace, faceI)
221 {
222 if (refinedInternalFace.test(faceI))
223 {
224 const cell& ownFaces = cells[faceOwner[faceI]];
225 forAll(ownFaces, ownI)
226 {
227 changedFace[ownFaces[ownI]] = true;
228 }
229 const cell& neiFaces = cells[faceNeighbour[faceI]];
230 forAll(neiFaces, neiI)
231 {
232 changedFace[neiFaces[neiI]] = true;
233 }
234 }
235 }
236
237 forAll(refinedBoundaryFace, i)
238 {
239 if (refinedBoundaryFace[i])
240 {
241 const cell& ownFaces = cells[faceOwner[i+nInternalFaces]];
242 forAll(ownFaces, ownI)
243 {
244 changedFace[ownFaces[ownI]] = true;
245 }
246 }
247 }
248
250 (
251 mesh,
252 changedFace,
253 orEqOp<bool>()
254 );
255
256
257 // Now we have in changedFace marked all affected faces. Pack.
258 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
259
260 changedFaces = findIndices(changedFace, true);
261
262 // Count changed master faces.
263 nMasterChanged = 0;
264
265 forAll(changedFace, faceI)
266 {
267 if (changedFace[faceI] && isMasterFace.test(faceI))
268 {
269 nMasterChanged++;
270 }
271 }
272
273 }
274
275 if (debug&meshRefinement::MESH)
276 {
277 Pout<< "getChangedFaces : Detected "
278 << " local:" << changedFaces.size()
279 << " global:" << returnReduce(nMasterChanged, sumOp<label>())
280 << " changed faces out of " << mesh.globalData().nTotalFaces()
281 << endl;
282
283 faceSet changedFacesSet(mesh, "changedFaces", changedFaces);
284 Pout<< "getChangedFaces : Writing " << changedFaces.size()
285 << " changed faces to faceSet " << changedFacesSet.name()
286 << endl;
287 changedFacesSet.write();
288 }
289
290 return changedFaces;
291}
292
293
294// Mark cell for refinement (if not already marked). Return false if
295// refinelimit hit. Keeps running count (in nRefine) of cells marked for
296// refinement
297bool Foam::meshRefinement::markForRefine
298(
299 const label markValue,
300 const label nAllowRefine,
301
302 label& cellValue,
303 label& nRefine
304)
305{
306 if (cellValue == -1)
307 {
308 cellValue = markValue;
309 nRefine++;
310 }
311
312 return nRefine <= nAllowRefine;
313}
314
315
316void Foam::meshRefinement::markFeatureCellLevel
317(
318 const pointField& keepPoints,
319 labelList& maxFeatureLevel
320) const
321{
322 // We want to refine all cells containing a feature edge.
323 // - don't want to search over whole mesh
324 // - don't want to build octree for whole mesh
325 // - so use tracking to follow the feature edges
326 //
327 // 1. find non-manifold points on feature edges (i.e. start of feature edge
328 // or 'knot')
329 // 2. seed particle starting at keepPoint going to this non-manifold point
330 // 3. track particles to their non-manifold point
331 //
332 // 4. track particles across their connected feature edges, marking all
333 // visited cells with their level (through trackingData)
334 // 5. do 4 until all edges have been visited.
335
336
337 // Find all start cells of features. Is done by tracking from keepPoint.
338 Cloud<trackedParticle> startPointCloud
339 (
340 mesh_,
341 "startPointCloud",
342 IDLList<trackedParticle>()
343 );
344
345
346 // Features are identical on all processors. Number them so we know
347 // what to seed. Do this on only the processor that
348 // holds the keepPoint.
349
350 for (const point& keepPoint : keepPoints)
351 {
352 const label celli = mesh_.cellTree().findInside(keepPoint);
353
354 if (celli != -1)
355 {
356 // I am the processor that holds the keepPoint
357
358 forAll(features_, feati)
359 {
360 const edgeMesh& featureMesh = features_[feati];
361 const label featureLevel = features_.levels()[feati][0];
362 const labelListList& pointEdges = featureMesh.pointEdges();
363
364 // Find regions on edgeMesh
365 labelList edgeRegion;
366 label nRegions = featureMesh.regions(edgeRegion);
367
368
369 bitSet regionVisited(nRegions);
370
371
372 // 1. Seed all 'knots' in edgeMesh
373
374
375 forAll(pointEdges, pointi)
376 {
377 if (pointEdges[pointi].size() != 2)
378 {
380 {
381 Pout<< "Adding particle from point:" << pointi
382 << " coord:" << featureMesh.points()[pointi]
383 << " since number of emanating edges:"
384 << pointEdges[pointi].size()
385 << endl;
386 }
387
388 // Non-manifold point. Create particle.
389 startPointCloud.addParticle
390 (
391 new trackedParticle
392 (
393 mesh_,
394 keepPoint,
395 celli,
396 featureMesh.points()[pointi], // endpos
397 featureLevel, // level
398 feati, // featureMesh
399 pointi, // end point
400 -1 // feature edge
401 )
402 );
403
404 // Mark
405 if (pointEdges[pointi].size() > 0)
406 {
407 label e0 = pointEdges[pointi][0];
408 label regioni = edgeRegion[e0];
409 regionVisited.set(regioni);
410 }
411 }
412 }
413
414
415 // 2. Any regions that have not been visited at all? These can
416 // only be circular regions!
417 forAll(featureMesh.edges(), edgei)
418 {
419 if (regionVisited.set(edgeRegion[edgei]))
420 {
421 const edge& e = featureMesh.edges()[edgei];
422 label pointi = e.start();
424 {
425 Pout<< "Adding particle from point:" << pointi
426 << " coord:" << featureMesh.points()[pointi]
427 << " on circular region:" << edgeRegion[edgei]
428 << endl;
429 }
430
431 // Non-manifold point. Create particle.
432 startPointCloud.addParticle
433 (
434 new trackedParticle
435 (
436 mesh_,
437 keepPoint,
438 celli,
439 featureMesh.points()[pointi], // endpos
440 featureLevel, // level
441 feati, // featureMesh
442 pointi, // end point
443 -1 // feature edge
444 )
445 );
446 }
447 }
448 }
449 }
450 }
451
452
453 // Largest refinement level of any feature passed through
454 maxFeatureLevel = labelList(mesh_.nCells(), -1);
455
456 // Whether edge has been visited.
457 List<bitSet> featureEdgeVisited(features_.size());
458
459 forAll(features_, featI)
460 {
461 featureEdgeVisited[featI].setSize(features_[featI].edges().size());
462 featureEdgeVisited[featI] = false;
463 }
464
465 // Database to pass into trackedParticle::move
466 trackedParticle::trackingData td
467 (
468 startPointCloud,
469 maxFeatureLevel,
470 featureEdgeVisited
471 );
472
473
474 // Track all particles to their end position (= starting feature point)
475 // Note that the particle might have started on a different processor
476 // so this will transfer across nicely until we can start tracking proper.
477 scalar maxTrackLen = 2.0*mesh_.bounds().mag();
478
480 {
481 Pout<< "Tracking " << startPointCloud.size()
482 << " particles over distance " << maxTrackLen
483 << " to find the starting cell" << endl;
484 }
485 startPointCloud.move(startPointCloud, td, maxTrackLen);
486
487
488 // Reset levels
489 maxFeatureLevel = -1;
490 forAll(features_, featI)
491 {
492 featureEdgeVisited[featI] = false;
493 }
494
495
496 Cloud<trackedParticle> cloud
497 (
498 mesh_,
499 "featureCloud",
500 IDLList<trackedParticle>()
501 );
502
504 {
505 Pout<< "Constructing cloud for cell marking" << endl;
506 }
507
508 for (const trackedParticle& startTp : startPointCloud)
509 {
510 const label featI = startTp.i();
511 const label pointI = startTp.j();
512
513 const edgeMesh& featureMesh = features_[featI];
514 const labelList& pEdges = featureMesh.pointEdges()[pointI];
515
516 // Now shoot particles down all pEdges.
517 forAll(pEdges, pEdgeI)
518 {
519 label edgeI = pEdges[pEdgeI];
520
521 if (featureEdgeVisited[featI].set(edgeI))
522 {
523 // Unvisited edge. Make the particle go to the other point
524 // on the edge.
525
526 const edge& e = featureMesh.edges()[edgeI];
527 label otherPointi = e.otherVertex(pointI);
528
529 trackedParticle* tp(new trackedParticle(startTp));
530 tp->start() = tp->position();
531 tp->end() = featureMesh.points()[otherPointi];
532 tp->j() = otherPointi;
533 tp->k() = edgeI;
534
536 {
537 Pout<< "Adding particle for point:" << pointI
538 << " coord:" << tp->position()
539 << " feature:" << featI
540 << " to track to:" << tp->end()
541 << endl;
542 }
543
544 cloud.addParticle(tp);
545 }
546 }
547 }
548
549 startPointCloud.clear();
550
551
552 while (true)
553 {
554 // Track all particles to their end position.
556 {
557 Pout<< "Tracking " << cloud.size()
558 << " particles over distance " << maxTrackLen
559 << " to mark cells" << endl;
560 }
561 cloud.move(cloud, td, maxTrackLen);
562
563 // Make particle follow edge.
564 for (trackedParticle& tp : cloud)
565 {
566 const label featI = tp.i();
567 const label pointI = tp.j();
568
569 const edgeMesh& featureMesh = features_[featI];
570 const labelList& pEdges = featureMesh.pointEdges()[pointI];
571
572 // Particle now at pointI. Check connected edges to see which one
573 // we have to visit now.
574
575 bool keepParticle = false;
576
577 forAll(pEdges, i)
578 {
579 label edgeI = pEdges[i];
580
581 if (featureEdgeVisited[featI].set(edgeI))
582 {
583 // Unvisited edge. Make the particle go to the other point
584 // on the edge.
585
586 const edge& e = featureMesh.edges()[edgeI];
587 label otherPointi = e.otherVertex(pointI);
588
589 tp.start() = tp.position();
590 tp.end() = featureMesh.points()[otherPointi];
591 tp.j() = otherPointi;
592 tp.k() = edgeI;
593 keepParticle = true;
594 break;
595 }
596 }
597
598 if (!keepParticle)
599 {
600 // Particle at 'knot' where another particle already has been
601 // seeded. Delete particle.
602 cloud.deleteParticle(tp);
603 }
604 }
605
606
608 {
609 Pout<< "Remaining particles " << cloud.size() << endl;
610 }
611
612 if (returnReduce(cloud.size(), sumOp<label>()) == 0)
613 {
614 break;
615 }
616 }
617
618
619
620 //if (debug&meshRefinement::FEATURESEEDS)
621 //{
622 // forAll(maxFeatureLevel, cellI)
623 // {
624 // if (maxFeatureLevel[cellI] != -1)
625 // {
626 // Pout<< "Feature went through cell:" << cellI
627 // << " coord:" << mesh_.cellCentres()[cellI]
628 // << " level:" << maxFeatureLevel[cellI]
629 // << endl;
630 // }
631 // }
632 //}
633}
634
635
636// Calculates list of cells to refine based on intersection with feature edge.
637Foam::label Foam::meshRefinement::markFeatureRefinement
638(
639 const pointField& keepPoints,
640 const label nAllowRefine,
641
642 labelList& refineCell,
643 label& nRefine
644) const
645{
646 // Largest refinement level of any feature passed through
647 labelList maxFeatureLevel;
648 markFeatureCellLevel(keepPoints, maxFeatureLevel);
649
650 // See which cells to refine. maxFeatureLevel will hold highest level
651 // of any feature edge that passed through.
652
653 const labelList& cellLevel = meshCutter_.cellLevel();
654
655 label oldNRefine = nRefine;
656
657 forAll(maxFeatureLevel, cellI)
658 {
659 if (maxFeatureLevel[cellI] > cellLevel[cellI])
660 {
661 // Mark
662 if
663 (
664 !markForRefine
665 (
666 0, // surface (n/a)
667 nAllowRefine,
668 refineCell[cellI],
669 nRefine
670 )
671 )
672 {
673 // Reached limit
674 break;
675 }
676 }
677 }
678
679 if
680 (
681 returnReduce(nRefine, sumOp<label>())
682 > returnReduce(nAllowRefine, sumOp<label>())
683 )
684 {
685 Info<< "Reached refinement limit." << endl;
686 }
687
688 return returnReduce(nRefine-oldNRefine, sumOp<label>());
689}
690
691
692// Mark cells for distance-to-feature based refinement.
693Foam::label Foam::meshRefinement::markInternalDistanceToFeatureRefinement
694(
695 const label nAllowRefine,
696
697 labelList& refineCell,
698 label& nRefine
699) const
700{
701 const labelList& cellLevel = meshCutter_.cellLevel();
702 const pointField& cellCentres = mesh_.cellCentres();
703
704 // Detect if there are any distance shells
705 if (features_.maxDistance() <= 0.0)
706 {
707 return 0;
708 }
709
710 label oldNRefine = nRefine;
711
712 // Collect cells to test
713 pointField testCc(cellLevel.size()-nRefine);
714 labelList testLevels(cellLevel.size()-nRefine);
715 label testI = 0;
716
717 forAll(cellLevel, cellI)
718 {
719 if (refineCell[cellI] == -1)
720 {
721 testCc[testI] = cellCentres[cellI];
722 testLevels[testI] = cellLevel[cellI];
723 testI++;
724 }
725 }
726
727 // Do test to see whether cells are inside/outside shell with higher level
728 labelList maxLevel;
729 features_.findHigherLevel(testCc, testLevels, maxLevel);
730
731 // Mark for refinement. Note that we didn't store the original cellID so
732 // now just reloop in same order.
733 testI = 0;
734 forAll(cellLevel, cellI)
735 {
736 if (refineCell[cellI] == -1)
737 {
738 if (maxLevel[testI] > testLevels[testI])
739 {
740 bool reachedLimit = !markForRefine
741 (
742 maxLevel[testI], // mark with any positive value
743 nAllowRefine,
744 refineCell[cellI],
745 nRefine
746 );
747
748 if (reachedLimit)
749 {
750 if (debug)
751 {
752 Pout<< "Stopped refining internal cells"
753 << " since reaching my cell limit of "
754 << mesh_.nCells()+7*nRefine << endl;
755 }
756 break;
757 }
758 }
759 testI++;
760 }
761 }
762
763 if
764 (
765 returnReduce(nRefine, sumOp<label>())
766 > returnReduce(nAllowRefine, sumOp<label>())
767 )
768 {
769 Info<< "Reached refinement limit." << endl;
770 }
771
772 return returnReduce(nRefine-oldNRefine, sumOp<label>());
773}
774
775
776// Mark cells for non-surface intersection based refinement.
777Foam::label Foam::meshRefinement::markInternalRefinement
778(
779 const label nAllowRefine,
780
781 labelList& refineCell,
782 label& nRefine
783) const
784{
785 const labelList& cellLevel = meshCutter_.cellLevel();
786 const pointField& cellCentres = mesh_.cellCentres();
787
788 label oldNRefine = nRefine;
789
790 // Collect cells to test
791 pointField testCc(cellLevel.size()-nRefine);
792 labelList testLevels(cellLevel.size()-nRefine);
793 label testI = 0;
794
795 forAll(cellLevel, cellI)
796 {
797 if (refineCell[cellI] == -1)
798 {
799 testCc[testI] = cellCentres[cellI];
800 testLevels[testI] = cellLevel[cellI];
801 testI++;
802 }
803 }
804
805 // Do test to see whether cells are inside/outside shell with higher level
806 labelList maxLevel;
807 shells_.findHigherLevel(testCc, testLevels, maxLevel);
808
809 // Mark for refinement. Note that we didn't store the original cellID so
810 // now just reloop in same order.
811 testI = 0;
812 forAll(cellLevel, cellI)
813 {
814 if (refineCell[cellI] == -1)
815 {
816 if (maxLevel[testI] > testLevels[testI])
817 {
818 bool reachedLimit = !markForRefine
819 (
820 maxLevel[testI], // mark with any positive value
821 nAllowRefine,
822 refineCell[cellI],
823 nRefine
824 );
825
826 if (reachedLimit)
827 {
828 if (debug)
829 {
830 Pout<< "Stopped refining internal cells"
831 << " since reaching my cell limit of "
832 << mesh_.nCells()+7*nRefine << endl;
833 }
834 break;
835 }
836 }
837 testI++;
838 }
839 }
840
841 if
842 (
843 returnReduce(nRefine, sumOp<label>())
844 > returnReduce(nAllowRefine, sumOp<label>())
845 )
846 {
847 Info<< "Reached refinement limit." << endl;
848 }
849
850 return returnReduce(nRefine-oldNRefine, sumOp<label>());
851}
852
853
854Foam::label Foam::meshRefinement::unmarkInternalRefinement
855(
856 labelList& refineCell,
857 label& nRefine
858) const
859{
860 const labelList& cellLevel = meshCutter_.cellLevel();
861 const pointField& cellCentres = mesh_.cellCentres();
862
863 label oldNRefine = nRefine;
864
865 // Collect cells to test
866 pointField testCc(nRefine);
867 labelList testLevels(nRefine);
868 label testI = 0;
869
870 forAll(cellLevel, cellI)
871 {
872 if (refineCell[cellI] >= 0)
873 {
874 testCc[testI] = cellCentres[cellI];
875 testLevels[testI] = cellLevel[cellI];
876 testI++;
877 }
878 }
879
880 // Do test to see whether cells are inside/outside shell with higher level
881 labelList levelShell;
882 limitShells_.findLevel(testCc, testLevels, levelShell);
883
884 // Mark for refinement. Note that we didn't store the original cellID so
885 // now just reloop in same order.
886 testI = 0;
887 forAll(cellLevel, cellI)
888 {
889 if (refineCell[cellI] >= 0)
890 {
891 if (levelShell[testI] != -1)
892 {
893 refineCell[cellI] = -1;
894 nRefine--;
895 }
896 testI++;
897 }
898 }
899
900 return returnReduce(oldNRefine-nRefine, sumOp<label>());
901}
902
903
904// Collect faces that are intersected and whose neighbours aren't yet marked
905// for refinement.
906Foam::labelList Foam::meshRefinement::getRefineCandidateFaces
907(
908 const labelList& refineCell
909) const
910{
911 labelList testFaces(mesh_.nFaces());
912
913 label nTest = 0;
914
915 const labelList& surfIndex = surfaceIndex();
916
917 labelList boundaryRefineCell;
918 syncTools::swapBoundaryCellList(mesh_, refineCell, boundaryRefineCell);
919
920 forAll(surfIndex, faceI)
921 {
922 if (surfIndex[faceI] != -1)
923 {
924 label own = mesh_.faceOwner()[faceI];
925
926 if (mesh_.isInternalFace(faceI))
927 {
928 label nei = mesh_.faceNeighbour()[faceI];
929
930 if (refineCell[own] == -1 || refineCell[nei] == -1)
931 {
932 testFaces[nTest++] = faceI;
933 }
934 }
935 else
936 {
937 const label bFacei = faceI - mesh_.nInternalFaces();
938 if (refineCell[own] == -1 || boundaryRefineCell[bFacei] == -1)
939 {
940 testFaces[nTest++] = faceI;
941 }
942 }
943 }
944 }
945 testFaces.setSize(nTest);
946
947 return testFaces;
948}
949
950
951// Mark cells for surface intersection based refinement.
952Foam::label Foam::meshRefinement::markSurfaceRefinement
953(
954 const label nAllowRefine,
955 const labelList& neiLevel,
956 const pointField& neiCc,
957
958 labelList& refineCell,
959 label& nRefine
960) const
961{
962 const labelList& cellLevel = meshCutter_.cellLevel();
963
964 label oldNRefine = nRefine;
965
966 // Use cached surfaceIndex_ to detect if any intersection. If so
967 // re-intersect to determine level wanted.
968
969 // Collect candidate faces
970 // ~~~~~~~~~~~~~~~~~~~~~~~
971
972 labelList testFaces(getRefineCandidateFaces(refineCell));
973
974 // Collect segments
975 // ~~~~~~~~~~~~~~~~
976
977 pointField start(testFaces.size());
978 pointField end(testFaces.size());
979 labelList minLevel(testFaces.size());
980
981 calcCellCellRays
982 (
983 neiCc,
984 neiLevel,
985 testFaces,
986 start,
987 end,
988 minLevel
989 );
990
991
992 // Do test for higher intersections
993 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
994
995 labelList surfaceHit;
996 labelList surfaceMinLevel;
997 surfaces_.findHigherIntersection
998 (
999 shells_,
1000 start,
1001 end,
1002 minLevel,
1003
1004 surfaceHit,
1005 surfaceMinLevel
1006 );
1007
1008
1009 // Mark cells for refinement
1010 // ~~~~~~~~~~~~~~~~~~~~~~~~~
1011
1012 forAll(testFaces, i)
1013 {
1014 label faceI = testFaces[i];
1015
1016 label surfI = surfaceHit[i];
1017
1018 if (surfI != -1)
1019 {
1020 // Found intersection with surface with higher wanted
1021 // refinement. Check if the level field on that surface
1022 // specifies an even higher level. Note:this is weird. Should
1023 // do the check with the surfaceMinLevel whilst intersecting the
1024 // surfaces?
1025
1026 label own = mesh_.faceOwner()[faceI];
1027
1028 if (surfaceMinLevel[i] > cellLevel[own])
1029 {
1030 // Owner needs refining
1031 if
1032 (
1033 !markForRefine
1034 (
1035 surfI,
1036 nAllowRefine,
1037 refineCell[own],
1038 nRefine
1039 )
1040 )
1041 {
1042 break;
1043 }
1044 }
1045
1046 if (mesh_.isInternalFace(faceI))
1047 {
1048 label nei = mesh_.faceNeighbour()[faceI];
1049 if (surfaceMinLevel[i] > cellLevel[nei])
1050 {
1051 // Neighbour needs refining
1052 if
1053 (
1054 !markForRefine
1055 (
1056 surfI,
1057 nAllowRefine,
1058 refineCell[nei],
1059 nRefine
1060 )
1061 )
1062 {
1063 break;
1064 }
1065 }
1066 }
1067 }
1068 }
1069
1070 if
1071 (
1072 returnReduce(nRefine, sumOp<label>())
1073 > returnReduce(nAllowRefine, sumOp<label>())
1074 )
1075 {
1076 Info<< "Reached refinement limit." << endl;
1077 }
1078
1079 return returnReduce(nRefine-oldNRefine, sumOp<label>());
1080}
1081
1082
1083// Count number of matches of first argument in second argument
1084Foam::label Foam::meshRefinement::countMatches
1085(
1086 const List<point>& normals1,
1087 const List<point>& normals2,
1088 const scalar tol
1089) const
1090{
1091 label nMatches = 0;
1092
1093 forAll(normals1, i)
1094 {
1095 const vector& n1 = normals1[i];
1096
1097 forAll(normals2, j)
1098 {
1099 const vector& n2 = normals2[j];
1100
1101 if (magSqr(n1-n2) < tol)
1102 {
1103 nMatches++;
1104 break;
1105 }
1106 }
1107 }
1108
1109 return nMatches;
1110}
1111
1112
1113// Mark cells for surface curvature based refinement.
1114Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
1115(
1116 const scalar curvature,
1117 const label nAllowRefine,
1118 const labelList& neiLevel,
1119 const pointField& neiCc,
1120
1121 labelList& refineCell,
1122 label& nRefine
1123) const
1124{
1125 const labelList& cellLevel = meshCutter_.cellLevel();
1126 const pointField& cellCentres = mesh_.cellCentres();
1127
1128 label oldNRefine = nRefine;
1129
1130 // 1. local test: any cell on more than one surface gets refined
1131 // (if its current level is < max of the surface max level)
1132
1133 // 2. 'global' test: any cell on only one surface with a neighbour
1134 // on a different surface gets refined (if its current level etc.)
1135
1136
1137 const bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
1138
1139
1140 // Collect candidate faces (i.e. intersecting any surface and
1141 // owner/neighbour not yet refined.
1142 labelList testFaces(getRefineCandidateFaces(refineCell));
1143
1144 // Collect segments
1145 pointField start(testFaces.size());
1146 pointField end(testFaces.size());
1147 labelList minLevel(testFaces.size());
1148
1149 // Note: uses isMasterFace otherwise could be call to calcCellCellRays
1150 forAll(testFaces, i)
1151 {
1152 label faceI = testFaces[i];
1153
1154 label own = mesh_.faceOwner()[faceI];
1155
1156 if (mesh_.isInternalFace(faceI))
1157 {
1158 label nei = mesh_.faceNeighbour()[faceI];
1159
1160 start[i] = cellCentres[own];
1161 end[i] = cellCentres[nei];
1162 minLevel[i] = min(cellLevel[own], cellLevel[nei]);
1163 }
1164 else
1165 {
1166 label bFaceI = faceI - mesh_.nInternalFaces();
1167
1168 start[i] = cellCentres[own];
1169 end[i] = neiCc[bFaceI];
1170
1171 if (!isMasterFace[faceI])
1172 {
1173 std::swap(start[i], end[i]);
1174 }
1175
1176 minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
1177 }
1178 }
1179
1180 // Extend segments a bit
1181 {
1182 const vectorField smallVec(ROOTSMALL*(end-start));
1183 start -= smallVec;
1184 end += smallVec;
1185 }
1186
1187
1188 // Test for all intersections (with surfaces of higher max level than
1189 // minLevel) and cache per cell the interesting inter
1190 labelListList cellSurfLevels(mesh_.nCells());
1191 List<vectorList> cellSurfNormals(mesh_.nCells());
1192
1193 {
1194 // Per segment the normals of the surfaces
1195 List<vectorList> surfaceNormal;
1196 // Per segment the list of levels of the surfaces
1197 labelListList surfaceLevel;
1198
1199 surfaces_.findAllIntersections
1200 (
1201 start,
1202 end,
1203 minLevel, // max level of surface has to be bigger
1204 // than min level of neighbouring cells
1205
1206 labelList(surfaces_.maxLevel().size(), 0), // min level
1207 surfaces_.maxLevel(),
1208
1209 surfaceNormal,
1210 surfaceLevel
1211 );
1212
1213
1214 // Sort the data according to surface location. This will guarantee
1215 // that on coupled faces both sides visit the intersections in
1216 // the same order so will decide the same
1217 labelList visitOrder;
1218 forAll(surfaceNormal, pointI)
1219 {
1220 vectorList& pNormals = surfaceNormal[pointI];
1221 labelList& pLevel = surfaceLevel[pointI];
1222
1223 sortedOrder(pNormals, visitOrder, normalLess(pNormals));
1224
1225 pNormals = List<point>(pNormals, visitOrder);
1226 pLevel = labelUIndList(pLevel, visitOrder);
1227 }
1228
1229 // Clear out unnecessary data
1230 start.clear();
1231 end.clear();
1232 minLevel.clear();
1233
1234 // Convert face-wise data to cell.
1235 forAll(testFaces, i)
1236 {
1237 label faceI = testFaces[i];
1238 label own = mesh_.faceOwner()[faceI];
1239
1240 const vectorList& fNormals = surfaceNormal[i];
1241 const labelList& fLevels = surfaceLevel[i];
1242
1243 forAll(fNormals, hitI)
1244 {
1245 if (fLevels[hitI] > cellLevel[own])
1246 {
1247 cellSurfLevels[own].append(fLevels[hitI]);
1248 cellSurfNormals[own].append(fNormals[hitI]);
1249 }
1250
1251 if (mesh_.isInternalFace(faceI))
1252 {
1253 label nei = mesh_.faceNeighbour()[faceI];
1254 if (fLevels[hitI] > cellLevel[nei])
1255 {
1256 cellSurfLevels[nei].append(fLevels[hitI]);
1257 cellSurfNormals[nei].append(fNormals[hitI]);
1258 }
1259 }
1260 }
1261 }
1262 }
1263
1264
1265
1266 // Bit of statistics
1267 if (debug)
1268 {
1269 label nSet = 0;
1270 label nNormals = 9;
1271 forAll(cellSurfNormals, cellI)
1272 {
1273 const vectorList& normals = cellSurfNormals[cellI];
1274 if (normals.size())
1275 {
1276 nSet++;
1277 nNormals += normals.size();
1278 }
1279 }
1280 reduce(nSet, sumOp<label>());
1281 reduce(nNormals, sumOp<label>());
1282 Info<< "markSurfaceCurvatureRefinement :"
1283 << " cells:" << mesh_.globalData().nTotalCells()
1284 << " of which with normals:" << nSet
1285 << " ; total normals stored:" << nNormals
1286 << endl;
1287 }
1288
1289
1290
1291 bool reachedLimit = false;
1292
1293
1294 // 1. Check normals per cell
1295 // ~~~~~~~~~~~~~~~~~~~~~~~~~
1296
1297 for
1298 (
1299 label cellI = 0;
1300 !reachedLimit && cellI < cellSurfNormals.size();
1301 cellI++
1302 )
1303 {
1304 const vectorList& normals = cellSurfNormals[cellI];
1305 const labelList& levels = cellSurfLevels[cellI];
1306
1307 // n^2 comparison of all normals in a cell
1308 for (label i = 0; !reachedLimit && i < normals.size(); i++)
1309 {
1310 for (label j = i+1; !reachedLimit && j < normals.size(); j++)
1311 {
1312 if ((normals[i] & normals[j]) < curvature)
1313 {
1314 label maxLevel = max(levels[i], levels[j]);
1315
1316 if (cellLevel[cellI] < maxLevel)
1317 {
1318 if
1319 (
1320 !markForRefine
1321 (
1322 maxLevel,
1323 nAllowRefine,
1324 refineCell[cellI],
1325 nRefine
1326 )
1327 )
1328 {
1329 if (debug)
1330 {
1331 Pout<< "Stopped refining since reaching my cell"
1332 << " limit of " << mesh_.nCells()+7*nRefine
1333 << endl;
1334 }
1335 reachedLimit = true;
1336 break;
1337 }
1338 }
1339 }
1340 }
1341 }
1342 }
1343
1344
1345
1346 // 2. Find out a measure of surface curvature
1347 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1348 // Look at normals between neighbouring surfaces
1349 // Loop over all faces. Could only be checkFaces, except if they're coupled
1350
1351 // Internal faces
1352 for
1353 (
1354 label faceI = 0;
1355 !reachedLimit && faceI < mesh_.nInternalFaces();
1356 faceI++
1357 )
1358 {
1359 label own = mesh_.faceOwner()[faceI];
1360 label nei = mesh_.faceNeighbour()[faceI];
1361
1362 const vectorList& ownNormals = cellSurfNormals[own];
1363 const labelList& ownLevels = cellSurfLevels[own];
1364 const vectorList& neiNormals = cellSurfNormals[nei];
1365 const labelList& neiLevels = cellSurfLevels[nei];
1366
1367
1368 // Special case: owner normals set is a subset of the neighbour
1369 // normals. Do not do curvature refinement since other cell's normals
1370 // do not add any information. Avoids weird corner extensions of
1371 // refinement regions.
1372 bool ownIsSubset =
1373 countMatches(ownNormals, neiNormals)
1374 == ownNormals.size();
1375
1376 bool neiIsSubset =
1377 countMatches(neiNormals, ownNormals)
1378 == neiNormals.size();
1379
1380
1381 if (!ownIsSubset && !neiIsSubset)
1382 {
1383 // n^2 comparison of between ownNormals and neiNormals
1384 for (label i = 0; !reachedLimit && i < ownNormals.size(); i++)
1385 {
1386 for (label j = 0; !reachedLimit && j < neiNormals.size(); j++)
1387 {
1388 // Have valid data on both sides. Check curvature.
1389 if ((ownNormals[i] & neiNormals[j]) < curvature)
1390 {
1391 // See which side to refine.
1392 if (cellLevel[own] < ownLevels[i])
1393 {
1394 if
1395 (
1396 !markForRefine
1397 (
1398 ownLevels[i],
1399 nAllowRefine,
1400 refineCell[own],
1401 nRefine
1402 )
1403 )
1404 {
1405 if (debug)
1406 {
1407 Pout<< "Stopped refining since reaching"
1408 << " my cell limit of "
1409 << mesh_.nCells()+7*nRefine << endl;
1410 }
1411 reachedLimit = true;
1412 break;
1413 }
1414 }
1415 if (cellLevel[nei] < neiLevels[j])
1416 {
1417 if
1418 (
1419 !markForRefine
1420 (
1421 neiLevels[j],
1422 nAllowRefine,
1423 refineCell[nei],
1424 nRefine
1425 )
1426 )
1427 {
1428 if (debug)
1429 {
1430 Pout<< "Stopped refining since reaching"
1431 << " my cell limit of "
1432 << mesh_.nCells()+7*nRefine << endl;
1433 }
1434 reachedLimit = true;
1435 break;
1436 }
1437 }
1438 }
1439 }
1440 }
1441 }
1442 }
1443
1444
1445 // Send over surface normal to neighbour cell.
1446 List<vectorList> neiSurfaceNormals;
1447 syncTools::swapBoundaryCellList(mesh_, cellSurfNormals, neiSurfaceNormals);
1448
1449 // Boundary faces
1450 for
1451 (
1452 label faceI = mesh_.nInternalFaces();
1453 !reachedLimit && faceI < mesh_.nFaces();
1454 faceI++
1455 )
1456 {
1457 label own = mesh_.faceOwner()[faceI];
1458 label bFaceI = faceI - mesh_.nInternalFaces();
1459
1460 const vectorList& ownNormals = cellSurfNormals[own];
1461 const labelList& ownLevels = cellSurfLevels[own];
1462 const vectorList& neiNormals = neiSurfaceNormals[bFaceI];
1463
1464 // Special case: owner normals set is a subset of the neighbour
1465 // normals. Do not do curvature refinement since other cell's normals
1466 // do not add any information. Avoids weird corner extensions of
1467 // refinement regions.
1468 bool ownIsSubset =
1469 countMatches(ownNormals, neiNormals)
1470 == ownNormals.size();
1471
1472 bool neiIsSubset =
1473 countMatches(neiNormals, ownNormals)
1474 == neiNormals.size();
1475
1476
1477 if (!ownIsSubset && !neiIsSubset)
1478 {
1479 // n^2 comparison of between ownNormals and neiNormals
1480 for (label i = 0; !reachedLimit && i < ownNormals.size(); i++)
1481 {
1482 for (label j = 0; !reachedLimit && j < neiNormals.size(); j++)
1483 {
1484 // Have valid data on both sides. Check curvature.
1485 if ((ownNormals[i] & neiNormals[j]) < curvature)
1486 {
1487 if (cellLevel[own] < ownLevels[i])
1488 {
1489 if
1490 (
1491 !markForRefine
1492 (
1493 ownLevels[i],
1494 nAllowRefine,
1495 refineCell[own],
1496 nRefine
1497 )
1498 )
1499 {
1500 if (debug)
1501 {
1502 Pout<< "Stopped refining since reaching"
1503 << " my cell limit of "
1504 << mesh_.nCells()+7*nRefine
1505 << endl;
1506 }
1507 reachedLimit = true;
1508 break;
1509 }
1510 }
1511 }
1512 }
1513 }
1514 }
1515 }
1516
1517
1518 if
1519 (
1520 returnReduce(nRefine, sumOp<label>())
1521 > returnReduce(nAllowRefine, sumOp<label>())
1522 )
1523 {
1524 Info<< "Reached refinement limit." << endl;
1525 }
1526
1527 return returnReduce(nRefine-oldNRefine, sumOp<label>());
1528}
1529
1530
1532(
1533 const scalar planarCos,
1534 const vector& point0,
1535 const vector& normal0,
1536
1537 const vector& point1,
1538 const vector& normal1
1539) const
1540{
1541 //- Hits differ and angles are oppositeish and
1542 // hits have a normal distance
1543 vector d = point1-point0;
1544 scalar magD = mag(d);
1545
1546 if (magD > mergeDistance())
1547 {
1548 scalar cosAngle = (normal0 & normal1);
1549
1550 vector avg = Zero;
1551 if (cosAngle < (-1+planarCos))
1552 {
1553 // Opposite normals
1554 avg = 0.5*(normal0-normal1);
1555 }
1556 else if (cosAngle > (1-planarCos))
1557 {
1558 avg = 0.5*(normal0+normal1);
1559 }
1560
1561 if (avg != vector::zero)
1562 {
1563 avg /= mag(avg);
1564
1565 // Check normal distance of intersection locations
1566 if (mag(avg&d) > mergeDistance())
1567 {
1568 return true;
1569 }
1570 }
1571 }
1572
1573 return false;
1574}
1575
1576
1577// Mark small gaps
1579(
1580 const scalar planarCos,
1581 const label level0,
1582 const vector& point0,
1583 const vector& normal0,
1584
1585 const label level1,
1586 const vector& point1,
1587 const vector& normal1
1588) const
1589{
1590 //const scalar edge0Len = meshCutter_.level0EdgeLength();
1591
1592 //- Hits differ and angles are oppositeish and
1593 // hits have a normal distance
1594 vector d = point1-point0;
1595 scalar magD = mag(d);
1596
1597 if (magD > mergeDistance())
1598 {
1599 scalar cosAngle = (normal0 & normal1);
1600
1601 vector avgNormal = Zero;
1602 if (cosAngle < (-1+planarCos))
1603 {
1604 // Opposite normals
1605 avgNormal = 0.5*(normal0-normal1);
1606 }
1607 else if (cosAngle > (1-planarCos))
1608 {
1609 avgNormal = 0.5*(normal0+normal1);
1610 }
1611
1612 if (avgNormal != vector::zero)
1613 {
1614 avgNormal /= mag(avgNormal);
1615
1616 //scalar normalDist = mag(d&avgNormal);
1617 //const scalar avgCellSize = edge0Len/pow(2.0, 0.5*(level0+level1));
1618 //if (normalDist > 1*avgCellSize)
1619 //{
1620 // Pout<< "** skipping large distance " << endl;
1621 // return false;
1622 //}
1623
1624 // Check average normal with respect to intersection locations
1625 if (mag(avgNormal&d/magD) > Foam::cos(degToRad(45.0)))
1626 {
1627 return true;
1628 }
1629 }
1630 }
1631
1632 return false;
1633}
1634
1635
1636bool Foam::meshRefinement::checkProximity
1637(
1638 const scalar planarCos,
1639 const label nAllowRefine,
1640
1641 const label surfaceLevel, // current intersection max level
1642 const vector& surfaceLocation, // current intersection location
1643 const vector& surfaceNormal, // current intersection normal
1644
1645 const label cellI,
1646
1647 label& cellMaxLevel, // cached max surface level for this cell
1648 vector& cellMaxLocation, // cached surface location for this cell
1649 vector& cellMaxNormal, // cached surface normal for this cell
1650
1652 label& nRefine
1653) const
1654{
1655 const labelList& cellLevel = meshCutter_.cellLevel();
1656
1657 // Test if surface applicable
1658 if (surfaceLevel > cellLevel[cellI])
1659 {
1660 if (cellMaxLevel == -1)
1661 {
1662 // First visit of cell. Store
1663 cellMaxLevel = surfaceLevel;
1664 cellMaxLocation = surfaceLocation;
1665 cellMaxNormal = surfaceNormal;
1666 }
1667 else
1668 {
1669 // Second or more visit.
1670 // Check if
1671 // - different location
1672 // - opposite surface
1673
1674 bool closeSurfaces = isNormalGap
1675 (
1676 planarCos,
1677 cellLevel[cellI], //cellMaxLevel,
1678 cellMaxLocation,
1679 cellMaxNormal,
1680 cellLevel[cellI], //surfaceLevel,
1681 surfaceLocation,
1682 surfaceNormal
1683 );
1684
1685 // Set normal to that of highest surface. Not really necessary
1686 // over here but we reuse cellMax info when doing coupled faces.
1687 if (surfaceLevel > cellMaxLevel)
1688 {
1689 cellMaxLevel = surfaceLevel;
1690 cellMaxLocation = surfaceLocation;
1691 cellMaxNormal = surfaceNormal;
1692 }
1693
1694
1695 if (closeSurfaces)
1696 {
1697 //Pout<< "Found gap:" << nl
1698 // << " location:" << surfaceLocation
1699 // << "\tnormal :" << surfaceNormal << nl
1701 // << "\tnormal :" << cellMaxNormal << nl
1702 // << "\tcos :" << (surfaceNormal&cellMaxNormal) << nl
1703 // << endl;
1704
1705 return markForRefine
1706 (
1707 surfaceLevel, // mark with any non-neg number.
1708 nAllowRefine,
1709 refineCell[cellI],
1710 nRefine
1711 );
1712 }
1713 }
1714 }
1715
1716 // Did not reach refinement limit.
1717 return true;
1718}
1719
1720
1721Foam::label Foam::meshRefinement::markProximityRefinement
1722(
1723 const scalar planarCos,
1724
1725 const labelList& surfaceMinLevel,
1726 const labelList& surfaceMaxLevel,
1727
1728 const label nAllowRefine,
1729 const labelList& neiLevel,
1730 const pointField& neiCc,
1731
1732 labelList& refineCell,
1733 label& nRefine
1734) const
1735{
1736 const labelList& cellLevel = meshCutter_.cellLevel();
1737
1738 label oldNRefine = nRefine;
1739
1740 // 1. local test: any cell on more than one surface gets refined
1741 // (if its current level is < max of the surface max level)
1742
1743 // 2. 'global' test: any cell on only one surface with a neighbour
1744 // on a different surface gets refined (if its current level etc.)
1745
1746
1747 // Collect candidate faces (i.e. intersecting any surface and
1748 // owner/neighbour not yet refined.
1749 const labelList testFaces(getRefineCandidateFaces(refineCell));
1750
1751 // Collect segments
1752 pointField start(testFaces.size());
1753 pointField end(testFaces.size());
1754 labelList minLevel(testFaces.size());
1755
1756 calcCellCellRays
1757 (
1758 neiCc,
1759 neiLevel,
1760 testFaces,
1761 start,
1762 end,
1763 minLevel
1764 );
1765
1766
1767 // Test for all intersections (with surfaces of higher gap level than
1768 // minLevel) and cache per cell the max surface level and the local normal
1769 // on that surface.
1770 labelList cellMaxLevel(mesh_.nCells(), -1);
1771 vectorField cellMaxNormal(mesh_.nCells(), Zero);
1772 pointField cellMaxLocation(mesh_.nCells(), Zero);
1773
1774 {
1775 // Per segment the normals of the surfaces
1776 List<vectorList> surfaceLocation;
1777 List<vectorList> surfaceNormal;
1778 // Per segment the list of levels of the surfaces
1779 labelListList surfaceLevel;
1780
1781 surfaces_.findAllIntersections
1782 (
1783 start,
1784 end,
1785 minLevel, // gap level of surface has to be bigger
1786 // than min level of neighbouring cells
1787
1788 surfaceMinLevel,
1789 surfaceMaxLevel,
1790
1791 surfaceLocation,
1792 surfaceNormal,
1793 surfaceLevel
1794 );
1795 // Clear out unnecessary data
1796 start.clear();
1797 end.clear();
1798 minLevel.clear();
1799
1801 //OBJstream str
1802 //(
1803 // mesh_.time().path()
1804 // / "findAllIntersections_"
1805 // + mesh_.time().timeName()
1806 // + ".obj"
1807 //);
1809 //OBJstream str2
1810 //(
1811 // mesh_.time().path()
1812 // / "findAllIntersections2_"
1813 // + mesh_.time().timeName()
1814 // + ".obj"
1815 //);
1816
1817 forAll(testFaces, i)
1818 {
1819 label faceI = testFaces[i];
1820 label own = mesh_.faceOwner()[faceI];
1821
1822 const labelList& fLevels = surfaceLevel[i];
1823 const vectorList& fPoints = surfaceLocation[i];
1824 const vectorList& fNormals = surfaceNormal[i];
1825
1826 forAll(fLevels, hitI)
1827 {
1828 checkProximity
1829 (
1830 planarCos,
1831 nAllowRefine,
1832
1833 fLevels[hitI],
1834 fPoints[hitI],
1835 fNormals[hitI],
1836
1837 own,
1838 cellMaxLevel[own],
1839 cellMaxLocation[own],
1840 cellMaxNormal[own],
1841
1842 refineCell,
1843 nRefine
1844 );
1845 }
1846
1847 if (mesh_.isInternalFace(faceI))
1848 {
1849 label nei = mesh_.faceNeighbour()[faceI];
1850
1851 forAll(fLevels, hitI)
1852 {
1853 checkProximity
1854 (
1855 planarCos,
1856 nAllowRefine,
1857
1858 fLevels[hitI],
1859 fPoints[hitI],
1860 fNormals[hitI],
1861
1862 nei,
1863 cellMaxLevel[nei],
1864 cellMaxLocation[nei],
1865 cellMaxNormal[nei],
1866
1867 refineCell,
1868 nRefine
1869 );
1870 }
1871 }
1872 }
1873 }
1874
1875 // 2. Find out a measure of surface curvature and region edges.
1876 // Send over surface region and surface normal to neighbour cell.
1877
1878 labelList neiBndMaxLevel(mesh_.nBoundaryFaces());
1879 pointField neiBndMaxLocation(mesh_.nBoundaryFaces());
1880 vectorField neiBndMaxNormal(mesh_.nBoundaryFaces());
1881
1882 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
1883 {
1884 label bFaceI = faceI-mesh_.nInternalFaces();
1885 label own = mesh_.faceOwner()[faceI];
1886
1887 neiBndMaxLevel[bFaceI] = cellMaxLevel[own];
1888 neiBndMaxLocation[bFaceI] = cellMaxLocation[own];
1889 neiBndMaxNormal[bFaceI] = cellMaxNormal[own];
1890 }
1891 syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel);
1892 syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLocation);
1893 syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal);
1894
1895 // Loop over all faces. Could only be checkFaces.. except if they're coupled
1896
1897 // Internal faces
1898 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1899 {
1900 label own = mesh_.faceOwner()[faceI];
1901 label nei = mesh_.faceNeighbour()[faceI];
1902
1903 if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1)
1904 {
1905 // Have valid data on both sides. Check planarCos.
1906 if
1907 (
1908 isNormalGap
1909 (
1910 planarCos,
1911 cellLevel[own], //cellMaxLevel[own],
1912 cellMaxLocation[own],
1913 cellMaxNormal[own],
1914 cellLevel[nei], //cellMaxLevel[nei],
1915 cellMaxLocation[nei],
1916 cellMaxNormal[nei]
1917 )
1918 )
1919 {
1920 // See which side to refine
1921 if (cellLevel[own] < cellMaxLevel[own])
1922 {
1923 if
1924 (
1925 !markForRefine
1926 (
1927 cellMaxLevel[own],
1928 nAllowRefine,
1929 refineCell[own],
1930 nRefine
1931 )
1932 )
1933 {
1934 if (debug)
1935 {
1936 Pout<< "Stopped refining since reaching my cell"
1937 << " limit of " << mesh_.nCells()+7*nRefine
1938 << endl;
1939 }
1940 break;
1941 }
1942 }
1943
1944 if (cellLevel[nei] < cellMaxLevel[nei])
1945 {
1946 if
1947 (
1948 !markForRefine
1949 (
1950 cellMaxLevel[nei],
1951 nAllowRefine,
1952 refineCell[nei],
1953 nRefine
1954 )
1955 )
1956 {
1957 if (debug)
1958 {
1959 Pout<< "Stopped refining since reaching my cell"
1960 << " limit of " << mesh_.nCells()+7*nRefine
1961 << endl;
1962 }
1963 break;
1964 }
1965 }
1966 }
1967 }
1968 }
1969 // Boundary faces
1970 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
1971 {
1972 label own = mesh_.faceOwner()[faceI];
1973 label bFaceI = faceI - mesh_.nInternalFaces();
1974
1975 if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFaceI] != -1)
1976 {
1977 // Have valid data on both sides. Check planarCos.
1978 if
1979 (
1980 isNormalGap
1981 (
1982 planarCos,
1983 cellLevel[own], //cellMaxLevel[own],
1984 cellMaxLocation[own],
1985 cellMaxNormal[own],
1986 neiLevel[bFaceI], //neiBndMaxLevel[bFaceI],
1987 neiBndMaxLocation[bFaceI],
1988 neiBndMaxNormal[bFaceI]
1989 )
1990 )
1991 {
1992 if
1993 (
1994 !markForRefine
1995 (
1996 cellMaxLevel[own],
1997 nAllowRefine,
1998 refineCell[own],
1999 nRefine
2000 )
2001 )
2002 {
2003 if (debug)
2004 {
2005 Pout<< "Stopped refining since reaching my cell"
2006 << " limit of " << mesh_.nCells()+7*nRefine
2007 << endl;
2008 }
2009 break;
2010 }
2011 }
2012 }
2013 }
2014
2015 if
2016 (
2017 returnReduce(nRefine, sumOp<label>())
2018 > returnReduce(nAllowRefine, sumOp<label>())
2019 )
2020 {
2021 Info<< "Reached refinement limit." << endl;
2022 }
2023
2024 return returnReduce(nRefine-oldNRefine, sumOp<label>());
2025}
2026
2027
2028// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2029
2030// Calculate list of cells to refine. Gets for any edge (start - end)
2031// whether it intersects the surface. Does more accurate test and checks
2032// the wanted level on the surface intersected.
2033// Does approximate precalculation of how many cells can be refined before
2034// hitting overall limit maxGlobalCells.
2036(
2037 const pointField& keepPoints,
2038 const scalar curvature,
2039 const scalar planarAngle,
2040
2041 const bool featureRefinement,
2042 const bool featureDistanceRefinement,
2043 const bool internalRefinement,
2044 const bool surfaceRefinement,
2045 const bool curvatureRefinement,
2046 const bool smallFeatureRefinement,
2047 const bool gapRefinement,
2048 const bool bigGapRefinement,
2049 const bool spreadGapSize,
2050 const label maxGlobalCells,
2051 const label maxLocalCells
2052) const
2053{
2054 label totNCells = mesh_.globalData().nTotalCells();
2055
2056 labelList cellsToRefine;
2057
2058 if (totNCells >= maxGlobalCells)
2059 {
2060 Info<< "No cells marked for refinement since reached limit "
2061 << maxGlobalCells << '.' << endl;
2062 }
2063 else
2064 {
2065 // Every cell I refine adds 7 cells. Estimate the number of cells
2066 // I am allowed to refine.
2067 // Assume perfect distribution so can only refine as much the fraction
2068 // of the mesh I hold. This prediction step prevents us having to do
2069 // lots of reduces to keep count of the total number of cells selected
2070 // for refinement.
2071
2072 //scalar fraction = scalar(mesh_.nCells())/totNCells;
2073 //label myMaxCells = label(maxGlobalCells*fraction);
2074 //label nAllowRefine = (myMaxCells - mesh_.nCells())/7;
2076 //
2077 //Pout<< "refineCandidates:" << nl
2078 // << " total cells:" << totNCells << nl
2079 // << " local cells:" << mesh_.nCells() << nl
2080 // << " local fraction:" << fraction << nl
2081 // << " local allowable cells:" << myMaxCells << nl
2082 // << " local allowable refinement:" << nAllowRefine << nl
2083 // << endl;
2084
2085 //- Disable refinement shortcut. nAllowRefine is per processor limit.
2086 label nAllowRefine = labelMax / Pstream::nProcs();
2087
2088 // Marked for refinement (>= 0) or not (-1). Actual value is the
2089 // index of the surface it intersects / shell it is inside.
2090 labelList refineCell(mesh_.nCells(), -1);
2091 label nRefine = 0;
2092
2093
2094 // Swap neighbouring cell centres and cell level
2095 labelList neiLevel(mesh_.nBoundaryFaces());
2096 pointField neiCc(mesh_.nBoundaryFaces());
2097 calcNeighbourData(neiLevel, neiCc);
2098
2099
2100 const scalar planarCos = Foam::cos(degToRad(planarAngle));
2101
2102
2103 // Cells pierced by feature lines
2104 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2105
2106 if (featureRefinement)
2107 {
2108 label nFeatures = markFeatureRefinement
2109 (
2110 keepPoints,
2111 nAllowRefine,
2112
2113 refineCell,
2114 nRefine
2115 );
2116
2117 Info<< "Marked for refinement due to explicit features "
2118 << ": " << nFeatures << " cells." << endl;
2119 }
2120
2121 // Inside distance-to-feature shells
2122 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2123
2124 if (featureDistanceRefinement)
2125 {
2126 label nShell = markInternalDistanceToFeatureRefinement
2127 (
2128 nAllowRefine,
2129
2130 refineCell,
2131 nRefine
2132 );
2133 Info<< "Marked for refinement due to distance to explicit features "
2134 ": " << nShell << " cells." << endl;
2135 }
2136
2137 // Inside refinement shells
2138 // ~~~~~~~~~~~~~~~~~~~~~~~~
2139
2140 if (internalRefinement)
2141 {
2142 label nShell = markInternalRefinement
2143 (
2144 nAllowRefine,
2145
2146 refineCell,
2147 nRefine
2148 );
2149 Info<< "Marked for refinement due to refinement shells "
2150 << ": " << nShell << " cells." << endl;
2151 }
2152
2153 // Refinement based on intersection of surface
2154 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2155
2156 if (surfaceRefinement)
2157 {
2158 label nSurf = markSurfaceRefinement
2159 (
2160 nAllowRefine,
2161 neiLevel,
2162 neiCc,
2163
2164 refineCell,
2165 nRefine
2166 );
2167 Info<< "Marked for refinement due to surface intersection "
2168 << ": " << nSurf << " cells." << endl;
2169
2170 // Refine intersected-cells only inside gaps. See
2171 // markInternalGapRefinement to refine all cells inside gaps.
2172 if
2173 (
2174 planarCos >= -1
2175 && planarCos <= 1
2176 && max(shells_.maxGapLevel()) > 0
2177 )
2178 {
2179 label nGapSurf = markSurfaceGapRefinement
2180 (
2181 planarCos,
2182 nAllowRefine,
2183 neiLevel,
2184 neiCc,
2185
2186 refineCell,
2187 nRefine
2188 );
2189 Info<< "Marked for refinement due to surface intersection"
2190 << " (at gaps)"
2191 << ": " << nGapSurf << " cells." << endl;
2192 }
2193 }
2194
2195 // Refinement based on curvature of surface
2196 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2197
2198 if
2199 (
2200 curvatureRefinement
2201 && (curvature >= -1 && curvature <= 1)
2202 && (surfaces_.minLevel() != surfaces_.maxLevel())
2203 )
2204 {
2205 label nCurv = markSurfaceCurvatureRefinement
2206 (
2207 curvature,
2208 nAllowRefine,
2209 neiLevel,
2210 neiCc,
2211
2212 refineCell,
2213 nRefine
2214 );
2215 Info<< "Marked for refinement due to curvature/regions "
2216 << ": " << nCurv << " cells." << endl;
2217 }
2218
2219
2220 // Refinement based on features smaller than cell size
2221 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2222
2223 if
2224 (
2225 smallFeatureRefinement
2226 && (planarCos >= -1 && planarCos <= 1)
2227 && max(shells_.maxGapLevel()) > 0
2228 )
2229 {
2230 label nGap = markSmallFeatureRefinement
2231 (
2232 planarCos,
2233 nAllowRefine,
2234 neiLevel,
2235 neiCc,
2236
2237 refineCell,
2238 nRefine
2239 );
2240 Info<< "Marked for refinement due to close opposite surfaces "
2241 << ": " << nGap << " cells." << endl;
2242 }
2243
2244
2245 // Refinement based on gap (only neighbouring cells)
2246 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2247
2248 const labelList& surfaceGapLevel = surfaces_.gapLevel();
2249
2250 if
2251 (
2252 gapRefinement
2253 && (planarCos >= -1 && planarCos <= 1)
2254 && (max(surfaceGapLevel) > -1)
2255 )
2256 {
2257 Info<< "Specified gap level : " << max(surfaceGapLevel)
2258 << ", planar angle " << planarAngle << endl;
2259
2260 label nGap = markProximityRefinement
2261 (
2262 planarCos,
2263
2264 labelList(surfaceGapLevel.size(), -1), // surface min level
2265 surfaceGapLevel, // surface max level
2266
2267 nAllowRefine,
2268 neiLevel,
2269 neiCc,
2270
2271 refineCell,
2272 nRefine
2273 );
2274 Info<< "Marked for refinement due to close opposite surfaces "
2275 << ": " << nGap << " cells." << endl;
2276 }
2277
2278
2279 // Refinement based on gaps larger than cell size
2280 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2281
2282 if
2283 (
2284 bigGapRefinement
2285 && (planarCos >= -1 && planarCos <= 1)
2286 && max(shells_.maxGapLevel()) > 0
2287 )
2288 {
2289 // Refine based on gap information provided by shell and nearest
2290 // surface
2291 labelList numGapCells;
2292 scalarField gapSize;
2293 label nGap = markInternalGapRefinement
2294 (
2295 planarCos,
2296 spreadGapSize,
2297 nAllowRefine,
2298
2299 refineCell,
2300 nRefine,
2301 numGapCells,
2302 gapSize
2303 );
2304 Info<< "Marked for refinement due to opposite surfaces"
2305 << " "
2306 << ": " << nGap << " cells." << endl;
2307 }
2308
2309
2310 // Limit refinement
2311 // ~~~~~~~~~~~~~~~~
2312
2313 if (limitShells_.shells().size())
2314 {
2315 label nUnmarked = unmarkInternalRefinement(refineCell, nRefine);
2316 if (nUnmarked > 0)
2317 {
2318 Info<< "Unmarked for refinement due to limit shells"
2319 << " : " << nUnmarked << " cells." << endl;
2320 }
2321 }
2322
2323
2324
2325 // Pack cells-to-refine
2326 // ~~~~~~~~~~~~~~~~~~~~
2327
2328 cellsToRefine.setSize(nRefine);
2329 nRefine = 0;
2330
2331 forAll(refineCell, cellI)
2332 {
2333 if (refineCell[cellI] != -1)
2334 {
2335 cellsToRefine[nRefine++] = cellI;
2336 }
2337 }
2338 }
2339
2340 return cellsToRefine;
2341}
2342
2343
2345(
2346 const labelList& cellsToRefine
2347)
2348{
2349 // Mesh changing engine.
2350 polyTopoChange meshMod(mesh_);
2351
2352 // Play refinement commands into mesh changer.
2353 meshCutter_.setRefinement(cellsToRefine, meshMod);
2354
2355 // Remove any unnecessary fields
2356 mesh_.clearOut();
2357 mesh_.moving(false);
2358
2359 // Create mesh (no inflation), return map from old to new mesh.
2360 autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false);
2361 mapPolyMesh& map = *mapPtr;
2362
2363 // Update fields
2364 mesh_.updateMesh(map);
2365
2366 // Optionally inflate mesh
2367 if (map.hasMotionPoints())
2368 {
2369 mesh_.movePoints(map.preMotionPoints());
2370 }
2371 else
2372 {
2373 // Delete mesh volumes.
2374 mesh_.clearOut();
2375 }
2376
2377 // Reset the instance for if in overwrite mode
2378 mesh_.setInstance(timeName());
2379
2380 // Update intersection info
2381 updateMesh(map, getChangedFaces(map, cellsToRefine));
2382
2383 return mapPtr;
2384}
2385
2386
2387// Do refinement of consistent set of cells followed by truncation and
2388// load balancing.
2391(
2392 const string& msg,
2393 decompositionMethod& decomposer,
2394 fvMeshDistribute& distributor,
2395 const labelList& cellsToRefine,
2396 const scalar maxLoadUnbalance
2397)
2398{
2399 // Do all refinement
2400 refine(cellsToRefine);
2401
2402 if (debug&meshRefinement::MESH)
2403 {
2404 Pout<< "Writing refined but unbalanced " << msg
2405 << " mesh to time " << timeName() << endl;
2406 write
2407 (
2408 debugType(debug),
2409 writeType(writeLevel() | WRITEMESH),
2410 mesh_.time().path()/timeName()
2411 );
2412 Pout<< "Dumped debug data in = "
2413 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2414
2415 // test all is still synced across proc patches
2416 checkData();
2417 }
2418
2419 Info<< "Refined mesh in = "
2420 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2421 printMeshInfo(debug, "After refinement " + msg);
2422
2423
2424 // Load balancing
2425 // ~~~~~~~~~~~~~~
2426
2428
2429 if (Pstream::nProcs() > 1)
2430 {
2431 scalar nIdealCells =
2432 mesh_.globalData().nTotalCells()
2433 / Pstream::nProcs();
2434
2435 scalar unbalance = returnReduce
2436 (
2437 mag(1.0-mesh_.nCells()/nIdealCells),
2439 );
2440
2441 if (unbalance <= maxLoadUnbalance)
2442 {
2443 Info<< "Skipping balancing since max unbalance " << unbalance
2444 << " is less than allowable " << maxLoadUnbalance
2445 << endl;
2446 }
2447 else
2448 {
2449 scalarField cellWeights(mesh_.nCells(), 1);
2450
2451 distMap = balance
2452 (
2453 false, //keepZoneFaces
2454 false, //keepBaffles
2455 cellWeights,
2456 decomposer,
2457 distributor
2458 );
2459
2460 Info<< "Balanced mesh in = "
2461 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2462
2463 printMeshInfo(debug, "After balancing " + msg);
2464
2465
2466 if (debug&meshRefinement::MESH)
2467 {
2468 Pout<< "Writing balanced " << msg
2469 << " mesh to time " << timeName() << endl;
2470 write
2471 (
2472 debugType(debug),
2473 writeType(writeLevel() | WRITEMESH),
2474 mesh_.time().path()/timeName()
2475 );
2476 Pout<< "Dumped debug data in = "
2477 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2478
2479 // test all is still synced across proc patches
2480 checkData();
2481 }
2482 }
2483 }
2484
2485 return distMap;
2486}
2487
2488
2489// Do load balancing followed by refinement of consistent set of cells.
2492(
2493 const string& msg,
2494 decompositionMethod& decomposer,
2495 fvMeshDistribute& distributor,
2496 const labelList& initCellsToRefine,
2497 const scalar maxLoadUnbalance
2498)
2499{
2500 labelList cellsToRefine(initCellsToRefine);
2501
2502 //{
2503 // globalIndex globalCells(mesh_.nCells());
2504 //
2505 // Info<< "** Distribution before balancing/refining:" << endl;
2506 // for (const int procI : Pstream::allProcs())
2507 // {
2508 // Info<< " " << procI << '\t'
2509 // << globalCells.localSize(procI) << endl;
2510 // }
2511 // Info<< endl;
2512 //}
2513 //{
2514 // globalIndex globalCells(cellsToRefine.size());
2515 //
2516 // Info<< "** Cells to be refined:" << endl;
2517 // for (const int procI : Pstream::allProcs())
2518 // {
2519 // Info<< " " << procI << '\t'
2520 // << globalCells.localSize(procI) << endl;
2521 // }
2522 // Info<< endl;
2523 //}
2524
2525
2526 // Load balancing
2527 // ~~~~~~~~~~~~~~
2528
2530
2531 if (Pstream::nProcs() > 1)
2532 {
2533 // First check if we need to balance at all. Precalculate number of
2534 // cells after refinement and see what maximum difference is.
2535 scalar nNewCells = scalar(mesh_.nCells() + 7*cellsToRefine.size());
2536 scalar nIdealNewCells =
2537 returnReduce(nNewCells, sumOp<scalar>())
2538 / Pstream::nProcs();
2539 scalar unbalance = returnReduce
2540 (
2541 mag(1.0-nNewCells/nIdealNewCells),
2543 );
2544
2545 if (unbalance <= maxLoadUnbalance)
2546 {
2547 Info<< "Skipping balancing since max unbalance " << unbalance
2548 << " is less than allowable " << maxLoadUnbalance
2549 << endl;
2550 }
2551 else
2552 {
2553 scalarField cellWeights(mesh_.nCells(), 1);
2554 forAll(cellsToRefine, i)
2555 {
2556 cellWeights[cellsToRefine[i]] += 7;
2557 }
2558
2559 distMap = balance
2560 (
2561 false, //keepZoneFaces
2562 false, //keepBaffles
2563 cellWeights,
2564 decomposer,
2565 distributor
2566 );
2567
2568 // Update cells to refine
2569 distMap().distributeCellIndices(cellsToRefine);
2570
2571 Info<< "Balanced mesh in = "
2572 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2573 }
2574
2575 //{
2576 // globalIndex globalCells(mesh_.nCells());
2577 //
2578 // Info<< "** Distribution after balancing:" << endl;
2579 // for (const int procI : Pstream::allProcs())
2580 // {
2581 // Info<< " " << procI << '\t'
2582 // << globalCells.localSize(procI) << endl;
2583 // }
2584 // Info<< endl;
2585 //}
2586
2587 printMeshInfo(debug, "After balancing " + msg);
2588
2589 if (debug&meshRefinement::MESH)
2590 {
2591 Pout<< "Writing balanced " << msg
2592 << " mesh to time " << timeName() << endl;
2593 write
2594 (
2595 debugType(debug),
2596 writeType(writeLevel() | WRITEMESH),
2597 mesh_.time().path()/timeName()
2598 );
2599 Pout<< "Dumped debug data in = "
2600 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2601
2602 // test all is still synced across proc patches
2603 checkData();
2604 }
2605 }
2606
2607
2608 // Refinement
2609 // ~~~~~~~~~~
2610
2611 refine(cellsToRefine);
2612
2613 if (debug&meshRefinement::MESH)
2614 {
2615 Pout<< "Writing refined " << msg
2616 << " mesh to time " << timeName() << endl;
2617 write
2618 (
2619 debugType(debug),
2620 writeType(writeLevel() | WRITEMESH),
2621 mesh_.time().path()/timeName()
2622 );
2623 Pout<< "Dumped debug data in = "
2624 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2625
2626 // test all is still synced across proc patches
2627 checkData();
2628 }
2629
2630 Info<< "Refined mesh in = "
2631 << mesh_.time().cpuTimeIncrement() << " s" << endl;
2632
2633 //{
2634 // globalIndex globalCells(mesh_.nCells());
2635 //
2636 // Info<< "** After refinement distribution:" << endl;
2637 // for (const int procI : Pstream::allProcs())
2638 // {
2639 // Info<< " " << procI << '\t'
2640 // << globalCells.localSize(procI) << endl;
2641 // }
2642 // Info<< endl;
2643 //}
2644
2645 printMeshInfo(debug, "After refinement " + msg);
2646
2647 return distMap;
2648}
2649
2650
2652(
2653 const label maxGlobalCells,
2654 const label maxLocalCells,
2655 const labelList& currentLevel,
2656 const direction dir
2657) const
2658{
2659 const labelList& cellLevel = meshCutter_.cellLevel();
2660 const pointField& cellCentres = mesh_.cellCentres();
2661
2662 label totNCells = mesh_.globalData().nTotalCells();
2663
2664 labelList cellsToRefine;
2665
2666 if (totNCells >= maxGlobalCells)
2667 {
2668 Info<< "No cells marked for refinement since reached limit "
2669 << maxGlobalCells << '.' << endl;
2670 }
2671 else
2672 {
2673 // Disable refinement shortcut. nAllowRefine is per processor limit.
2674 label nAllowRefine = labelMax / Pstream::nProcs();
2675
2676 // Marked for refinement (>= 0) or not (-1). Actual value is the
2677 // index of the surface it intersects / shell it is inside
2678 labelList refineCell(mesh_.nCells(), -1);
2679 label nRefine = 0;
2680
2681 // Find cells inside the shells with directional levels
2682 labelList insideShell;
2683 shells_.findDirectionalLevel
2684 (
2685 cellCentres,
2686 cellLevel,
2687 currentLevel, // current directional level
2688 dir,
2689 insideShell
2690 );
2691
2692 // Mark for refinement
2693 forAll(insideShell, celli)
2694 {
2695 if (insideShell[celli] >= 0)
2696 {
2697 bool reachedLimit = !markForRefine
2698 (
2699 insideShell[celli], // mark with any positive value
2700 nAllowRefine,
2701 refineCell[celli],
2702 nRefine
2703 );
2704
2705 if (reachedLimit)
2706 {
2707 if (debug)
2708 {
2709 Pout<< "Stopped refining cells"
2710 << " since reaching my cell limit of "
2711 << mesh_.nCells()+nAllowRefine << endl;
2712 }
2713 break;
2714 }
2715 }
2716 }
2717
2718 // Limit refinement
2719 // ~~~~~~~~~~~~~~~~
2720
2721 {
2722 label nUnmarked = unmarkInternalRefinement(refineCell, nRefine);
2723 if (nUnmarked > 0)
2724 {
2725 Info<< "Unmarked for refinement due to limit shells"
2726 << " : " << nUnmarked << " cells." << endl;
2727 }
2728 }
2729
2730
2731
2732 // Pack cells-to-refine
2733 // ~~~~~~~~~~~~~~~~~~~~
2734
2735 cellsToRefine.setSize(nRefine);
2736 nRefine = 0;
2737
2738 forAll(refineCell, cellI)
2739 {
2740 if (refineCell[cellI] != -1)
2741 {
2742 cellsToRefine[nRefine++] = cellI;
2743 }
2744 }
2745 }
2746
2747 return cellsToRefine;
2748}
2749
2750
2752(
2753 const string& msg,
2754 const direction cmpt,
2755 const labelList& cellsToRefine
2756)
2757{
2758 // Set splitting direction
2759 vector refDir(Zero);
2760 refDir[cmpt] = 1;
2761 List<refineCell> refCells(cellsToRefine.size());
2762 forAll(cellsToRefine, i)
2763 {
2764 refCells[i] = refineCell(cellsToRefine[i], refDir);
2765 }
2766
2767 // How to walk circumference of cells
2768 hexCellLooper cellWalker(mesh_);
2769
2770 // Analyse cuts
2771 cellCuts cuts(mesh_, cellWalker, refCells);
2772
2773 // Cell cutter
2774 Foam::meshCutter meshRefiner(mesh_);
2775
2776 polyTopoChange meshMod(mesh_);
2777
2778 // Insert mesh refinement into polyTopoChange.
2779 meshRefiner.setRefinement(cuts, meshMod);
2780
2781 // Remove any unnecessary fields
2782 mesh_.clearOut();
2783 mesh_.moving(false);
2784
2785 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh_, false);
2786
2787 // Update fields
2788 mesh_.updateMesh(*morphMap);
2789
2790 // Move mesh (since morphing does not do this)
2791 if (morphMap().hasMotionPoints())
2792 {
2793 mesh_.movePoints(morphMap().preMotionPoints());
2794 }
2795 else
2796 {
2797 // Delete mesh volumes.
2798 mesh_.clearOut();
2799 }
2800
2801 // Reset the instance for if in overwrite mode
2802 mesh_.setInstance(timeName());
2803
2804 // Update stored refinement pattern
2805 meshRefiner.updateMesh(*morphMap);
2806
2807 // Update intersection info
2808 updateMesh(*morphMap, getChangedFaces(*morphMap, cellsToRefine));
2809
2810 return morphMap;
2811}
2812
2813
2814// ************************************************************************* //
scalar y
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
virtual const fileName & name() const
Get the name of the stream.
Definition: OSstream.H:107
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition: UListI.H:350
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
Description of cuts across cells.
Definition: cellCuts.H:113
Abstract base class for domain decomposition.
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
label nTotalFaces() const noexcept
Return total number of faces in decomposed mesh. Not.
Implementation of cellLooper.
Definition: hexCellLooper.H:65
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
const pointField & preMotionPoints() const
Pre-motion point positions.
Definition: mapPolyMesh.H:613
bool hasMotionPoints() const
Has valid preMotionPoints?
Definition: mapPolyMesh.H:619
Cuts (splits) cells.
Definition: meshCutter.H:141
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: meshCutter.C:995
void setRefinement(const cellCuts &cuts, polyTopoChange &meshMod)
Do actual cutting with cut description. Inserts mesh changes.
Definition: meshCutter.C:522
autoPtr< mapDistributePolyMesh > balanceAndRefine(const string &msg, decompositionMethod &decomposer, fvMeshDistribute &distributor, const labelList &cellsToRefine, const scalar maxLoadUnbalance)
Balance before refining some cells.
writeType
Enumeration for what to write. Used as a bit-pattern.
labelList refineCandidates(const pointField &keepPoints, const scalar curvature, const scalar planarAngle, const bool featureRefinement, const bool featureDistanceRefinement, const bool internalRefinement, const bool surfaceRefinement, const bool curvatureRefinement, const bool smallFeatureRefinement, const bool gapRefinement, const bool bigGapRefinement, const bool spreadGapSize, const label maxGlobalCells, const label maxLocalCells) const
Calculate list of cells to refine.
debugType
Enumeration for what to debug. Used as a bit-pattern.
bool isNormalGap(const scalar planarCos, const label level0, const vector &point0, const vector &normal0, const label level1, const vector &point1, const vector &normal1) const
Is local topology a small gap normal to the test vector.
const fvMesh & mesh() const
Reference to mesh.
bool isGap(const scalar, const vector &, const vector &, const vector &, const vector &) const
Is local topology a small gap?
autoPtr< mapDistributePolyMesh > refineAndBalance(const string &msg, decompositionMethod &decomposer, fvMeshDistribute &distributor, const labelList &cellsToRefine, const scalar maxLoadUnbalance)
Refine some cells and rebalance.
autoPtr< mapPolyMesh > directionalRefine(const string &msg, const direction cmpt, const labelList &cellsToRefine)
Directionally refine in direction cmpt.
autoPtr< mapPolyMesh > refine(const labelList &cellsToRefine)
Refine some cells.
labelList directionalRefineCandidates(const label maxGlobalCells, const label maxLocalCells, const labelList &currentLevel, const direction dir) const
Calculate list of cells to directionally refine.
To compare normals.
normalLess(const vectorList &values)
bool operator()(const label a, const label b) const
static constexpr direction nComponents
Number of components in bool is 1.
Definition: bool.H:98
labelList cmptType
Component type.
vectorList cmptType
Component type.
A traits class, which is primarily used for primitives.
Definition: pTraits.H:59
label start() const noexcept
The start label of boundary faces in the polyMesh face list.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1310
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
Direct mesh changes based on v1.3 polyTopoChange syntax.
autoPtr< mapPolyMesh > changeMesh(polyMesh &mesh, const labelUList &patchMap, const bool inflate, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
label nInternalFaces() const noexcept
Number of internal faces.
label nFaces() const noexcept
Number of mesh faces.
const cellList & cells() const
Container with cells to refine. Refinement given as single direction.
Definition: refineCell.H:57
Contains information about location on a triSurface.
static bitSet getMasterFaces(const polyMesh &mesh)
Definition: syncTools.C:126
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:396
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:445
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
static void syncBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const TransformOp &top, const bool parRun=Pstream::parRun())
Synchronize values on boundary faces only.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
const cellShapeList & cells
word timeName
Definition: getTimeIndex.H:3
void set(List< bool > &bools, const labelUList &locations)
Set the listed locations (assign 'true').
Definition: BitOps.C:38
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
List< label > labelList
A List of labels.
Definition: List.H:66
List< cell > cellList
A List of cells.
Definition: cellListFwd.H:47
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
constexpr label labelMax
Definition: label.H:61
List< vector > vectorList
A List of vectors.
Definition: vectorList.H:64
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
static bool less(const vector &x, const vector &y)
To compare normals.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Field< vector > vectorField
Specialisation of Field<T> for vector.
uint8_t direction
Definition: direction.H:56
List< bool > boolList
A List of bools.
Definition: List.H:64
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
label checkData(const fvMesh &mesh, const instantList &timeDirs, wordList &objectNames)
Check if fields are good to use (available at all times)
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
labelList findIndices(const ListType &input, typename ListType::const_reference val, label start=0)
Linear search to find all occurrences of given element.
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:68
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar cos(const dimensionedScalar &ds)
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:158
runTime write()
volScalarField & b
Definition: createFields.H:27
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
A non-counting (dummy) refCount.
Definition: refCount.H:59