BUG: UListIO: byteSize overflowing on really big faceLists
[OpenFOAM-2.0.x.git] / src / mesh / autoMesh / autoHexMesh / meshRefinement / meshRefinementRefine.C
blob2664719b26057ba262ec76a5edf99989e0f44866
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
11     OpenFOAM is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by
13     the Free Software Foundation, either version 3 of the License, or
14     (at your option) any later version.
16     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
24 \*----------------------------------------------------------------------------*/
26 #include "meshRefinement.H"
27 #include "trackedParticle.H"
28 #include "syncTools.H"
29 #include "Time.H"
30 #include "refinementSurfaces.H"
31 #include "refinementFeatures.H"
32 #include "shellSurfaces.H"
33 #include "faceSet.H"
34 #include "decompositionMethod.H"
35 #include "fvMeshDistribute.H"
36 #include "polyTopoChange.H"
37 #include "mapDistributePolyMesh.H"
38 #include "featureEdgeMesh.H"
39 #include "Cloud.H"
40 //#include "globalIndex.H"
42 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
44 // Get faces (on the new mesh) that have in some way been affected by the
45 // mesh change. Picks up all faces but those that are between two
46 // unrefined faces. (Note that of an unchanged face the edge still might be
47 // split but that does not change any face centre or cell centre.
48 Foam::labelList Foam::meshRefinement::getChangedFaces
50     const mapPolyMesh& map,
51     const labelList& oldCellsToRefine
54     const polyMesh& mesh = map.mesh();
56     labelList changedFaces;
58     // For reporting: number of masterFaces changed
59     label nMasterChanged = 0;
60     PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh));
62     {
63         // Mark any face on a cell which has been added or changed
64         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65         // Note that refining a face changes the face centre (for a warped face)
66         // which changes the cell centre. This again changes the cellcentre-
67         // cellcentre edge across all faces of the cell.
68         // Note: this does not happen for unwarped faces but unfortunately
69         // we don't have this information.
71         const labelList& faceOwner = mesh.faceOwner();
72         const labelList& faceNeighbour = mesh.faceNeighbour();
73         const cellList& cells = mesh.cells();
74         const label nInternalFaces = mesh.nInternalFaces();
76         // Mark refined cells on old mesh
77         PackedBoolList oldRefineCell(map.nOldCells());
79         forAll(oldCellsToRefine, i)
80         {
81             oldRefineCell.set(oldCellsToRefine[i], 1u);
82         }
84         // Mark refined faces
85         PackedBoolList refinedInternalFace(nInternalFaces);
87         // 1. Internal faces
89         for (label faceI = 0; faceI < nInternalFaces; faceI++)
90         {
91             label oldOwn = map.cellMap()[faceOwner[faceI]];
92             label oldNei = map.cellMap()[faceNeighbour[faceI]];
94             if
95             (
96                 oldOwn >= 0
97              && oldRefineCell.get(oldOwn) == 0u
98              && oldNei >= 0
99              && oldRefineCell.get(oldNei) == 0u
100             )
101             {
102                 // Unaffected face since both neighbours were not refined.
103             }
104             else
105             {
106                 refinedInternalFace.set(faceI, 1u);
107             }
108         }
111         // 2. Boundary faces
113         boolList refinedBoundaryFace(mesh.nFaces()-nInternalFaces, false);
115         forAll(mesh.boundaryMesh(), patchI)
116         {
117             const polyPatch& pp = mesh.boundaryMesh()[patchI];
119             label faceI = pp.start();
121             forAll(pp, i)
122             {
123                 label oldOwn = map.cellMap()[faceOwner[faceI]];
125                 if (oldOwn >= 0 && oldRefineCell.get(oldOwn) == 0u)
126                 {
127                     // owner did exist and wasn't refined.
128                 }
129                 else
130                 {
131                     refinedBoundaryFace[faceI-nInternalFaces] = true;
132                 }
133                 faceI++;
134             }
135         }
137         // Synchronise refined face status
138         syncTools::syncBoundaryFaceList
139         (
140             mesh,
141             refinedBoundaryFace,
142             orEqOp<bool>()
143         );
146         // 3. Mark all faces affected by refinement. Refined faces are in
147         //    - refinedInternalFace
148         //    - refinedBoundaryFace
149         boolList changedFace(mesh.nFaces(), false);
151         forAll(refinedInternalFace, faceI)
152         {
153             if (refinedInternalFace.get(faceI) == 1u)
154             {
155                 const cell& ownFaces = cells[faceOwner[faceI]];
156                 forAll(ownFaces, ownI)
157                 {
158                     changedFace[ownFaces[ownI]] = true;
159                 }
160                 const cell& neiFaces = cells[faceNeighbour[faceI]];
161                 forAll(neiFaces, neiI)
162                 {
163                     changedFace[neiFaces[neiI]] = true;
164                 }
165             }
166         }
168         forAll(refinedBoundaryFace, i)
169         {
170             if (refinedBoundaryFace[i])
171             {
172                 const cell& ownFaces = cells[faceOwner[i+nInternalFaces]];
173                 forAll(ownFaces, ownI)
174                 {
175                     changedFace[ownFaces[ownI]] = true;
176                 }
177             }
178         }
180         syncTools::syncFaceList
181         (
182             mesh,
183             changedFace,
184             orEqOp<bool>()
185         );
188         // Now we have in changedFace marked all affected faces. Pack.
189         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191         changedFaces = findIndices(changedFace, true);
193         // Count changed master faces.
194         nMasterChanged = 0;
196         forAll(changedFace, faceI)
197         {
198             if (changedFace[faceI] && isMasterFace[faceI])
199             {
200                 nMasterChanged++;
201             }
202         }
204     }
206     if (debug)
207     {
208         Pout<< "getChangedFaces : Detected "
209             << " local:" << changedFaces.size()
210             << " global:" << returnReduce(nMasterChanged, sumOp<label>())
211             << " changed faces out of " << mesh.globalData().nTotalFaces()
212             << endl;
214         faceSet changedFacesSet(mesh, "changedFaces", changedFaces);
215         Pout<< "getChangedFaces : Writing " << changedFaces.size()
216             << " changed faces to faceSet " << changedFacesSet.name()
217             << endl;
218         changedFacesSet.write();
219     }
221     return changedFaces;
225 // Mark cell for refinement (if not already marked). Return false if
226 // refinelimit hit. Keeps running count (in nRefine) of cells marked for
227 // refinement
228 bool Foam::meshRefinement::markForRefine
230     const label markValue,
231     const label nAllowRefine,
233     label& cellValue,
234     label& nRefine
237     if (cellValue == -1)
238     {
239         cellValue = markValue;
240         nRefine++;
241     }
243     return nRefine <= nAllowRefine;
247 // Calculates list of cells to refine based on intersection with feature edge.
248 Foam::label Foam::meshRefinement::markFeatureRefinement
250     const point& keepPoint,
251     const label nAllowRefine,
253     labelList& refineCell,
254     label& nRefine
255 ) const
257     // We want to refine all cells containing a feature edge.
258     // - don't want to search over whole mesh
259     // - don't want to build octree for whole mesh
260     // - so use tracking to follow the feature edges
261     //
262     // 1. find non-manifold points on feature edges (i.e. start of feature edge
263     //    or 'knot')
264     // 2. seed particle starting at keepPoint going to this non-manifold point
265     // 3. track particles to their non-manifold point
266     //
267     // 4. track particles across their connected feature edges, marking all
268     //    visited cells with their level (through trackingData)
269     // 5. do 4 until all edges have been visited.
272     // Find all start cells of features. Is done by tracking from keepPoint.
273     Cloud<trackedParticle> cloud(mesh_, IDLList<trackedParticle>());
275     // Create particles on whichever processor holds the keepPoint.
276     label cellI = -1;
277     label tetFaceI = -1;
278     label tetPtI = -1;
280     mesh_.findCellFacePt(keepPoint, cellI, tetFaceI, tetPtI);
282     if (cellI != -1)
283     {
284         forAll(features_, featI)
285         {
286             const featureEdgeMesh& featureMesh = features_[featI];
287             const label featureLevel = features_.levels()[featI];
289             const labelListList& pointEdges = featureMesh.pointEdges();
291             forAll(pointEdges, pointI)
292             {
293                 if (pointEdges[pointI].size() != 2)
294                 {
295                     if (debug)
296                     {
297                         Pout<< "Adding particle from point:" << pointI
298                             << " coord:" << featureMesh.points()[pointI]
299                             << " pEdges:" << pointEdges[pointI]
300                             << endl;
301                     }
303                     // Non-manifold point. Create particle.
304                     cloud.addParticle
305                     (
306                         new trackedParticle
307                         (
308                             mesh_,
309                             keepPoint,
310                             cellI,
311                             tetFaceI,
312                             tetPtI,
313                             featureMesh.points()[pointI],   // endpos
314                             featureLevel,                   // level
315                             featI,                          // featureMesh
316                             pointI                          // end point
317                         )
318                     );
319                 }
320             }
321         }
322     }
325     // Largest refinement level of any feature passed through
326     labelList maxFeatureLevel(mesh_.nCells(), -1);
328     // Database to pass into trackedParticle::move
329     trackedParticle::trackingData td(cloud, maxFeatureLevel);
331     // Track all particles to their end position (= starting feature point)
332     cloud.move(td, GREAT);
334     // Reset level
335     maxFeatureLevel = -1;
337     // Whether edge has been visited.
338     List<PackedBoolList> featureEdgeVisited(features_.size());
340     forAll(features_, featI)
341     {
342         featureEdgeVisited[featI].setSize(features_[featI].edges().size());
343         featureEdgeVisited[featI] = 0u;
344     }
346     while (true)
347     {
348         label nParticles = 0;
350         // Make particle follow edge.
351         forAllIter(Cloud<trackedParticle>, cloud, iter)
352         {
353             trackedParticle& tp = iter();
355             label featI = tp.i();
356             label pointI = tp.j();
358             const featureEdgeMesh& featureMesh = features_[featI];
359             const labelList& pEdges = featureMesh.pointEdges()[pointI];
361             // Particle now at pointI. Check connected edges to see which one
362             // we have to visit now.
364             bool keepParticle = false;
366             forAll(pEdges, i)
367             {
368                 label edgeI = pEdges[i];
370                 if (featureEdgeVisited[featI].set(edgeI, 1u))
371                 {
372                     // Unvisited edge. Make the particle go to the other point
373                     // on the edge.
375                     const edge& e = featureMesh.edges()[edgeI];
376                     label otherPointI = e.otherVertex(pointI);
378                     tp.end() = featureMesh.points()[otherPointI];
379                     tp.j() = otherPointI;
380                     keepParticle = true;
381                     break;
382                 }
383             }
385             if (!keepParticle)
386             {
387                 // Particle at 'knot' where another particle already has been
388                 // seeded. Delete particle.
389                 cloud.deleteParticle(tp);
390             }
391             else
392             {
393                 // Keep particle
394                 nParticles++;
395             }
396         }
398         reduce(nParticles, sumOp<label>());
399         if (nParticles == 0)
400         {
401             break;
402         }
404         // Track all particles to their end position.
405         cloud.move(td, GREAT);
406     }
409     // See which cells to refine. maxFeatureLevel will hold highest level
410     // of any feature edge that passed through.
412     const labelList& cellLevel = meshCutter_.cellLevel();
414     label oldNRefine = nRefine;
416     forAll(maxFeatureLevel, cellI)
417     {
418         if (maxFeatureLevel[cellI] > cellLevel[cellI])
419         {
420             // Mark
421             if
422             (
423                !markForRefine
424                 (
425                     0,                      // surface (n/a)
426                     nAllowRefine,
427                     refineCell[cellI],
428                     nRefine
429                 )
430             )
431             {
432                 // Reached limit
433                 break;
434             }
435         }
436     }
438     if
439     (
440         returnReduce(nRefine, sumOp<label>())
441       > returnReduce(nAllowRefine, sumOp<label>())
442     )
443     {
444         Info<< "Reached refinement limit." << endl;
445     }
447     return returnReduce(nRefine-oldNRefine,  sumOp<label>());
451 // Mark cells for non-surface intersection based refinement.
452 Foam::label Foam::meshRefinement::markInternalRefinement
454     const label nAllowRefine,
456     labelList& refineCell,
457     label& nRefine
458 ) const
460     const labelList& cellLevel = meshCutter_.cellLevel();
461     const pointField& cellCentres = mesh_.cellCentres();
463     label oldNRefine = nRefine;
465     // Collect cells to test
466     pointField testCc(cellLevel.size()-nRefine);
467     labelList testLevels(cellLevel.size()-nRefine);
468     label testI = 0;
470     forAll(cellLevel, cellI)
471     {
472         if (refineCell[cellI] == -1)
473         {
474             testCc[testI] = cellCentres[cellI];
475             testLevels[testI] = cellLevel[cellI];
476             testI++;
477         }
478     }
480     // Do test to see whether cells is inside/outside shell with higher level
481     labelList maxLevel;
482     shells_.findHigherLevel(testCc, testLevels, maxLevel);
484     // Mark for refinement. Note that we didn't store the original cellID so
485     // now just reloop in same order.
486     testI = 0;
487     forAll(cellLevel, cellI)
488     {
489         if (refineCell[cellI] == -1)
490         {
491             if (maxLevel[testI] > testLevels[testI])
492             {
493                 bool reachedLimit = !markForRefine
494                 (
495                     maxLevel[testI],    // mark with any positive value
496                     nAllowRefine,
497                     refineCell[cellI],
498                     nRefine
499                 );
501                 if (reachedLimit)
502                 {
503                     if (debug)
504                     {
505                         Pout<< "Stopped refining internal cells"
506                             << " since reaching my cell limit of "
507                             << mesh_.nCells()+7*nRefine << endl;
508                     }
509                     break;
510                 }
511             }
512             testI++;
513         }
514     }
516     if
517     (
518         returnReduce(nRefine, sumOp<label>())
519       > returnReduce(nAllowRefine, sumOp<label>())
520     )
521     {
522         Info<< "Reached refinement limit." << endl;
523     }
525     return returnReduce(nRefine-oldNRefine, sumOp<label>());
529 // Collect faces that are intersected and whose neighbours aren't yet marked
530 // for refinement.
531 Foam::labelList Foam::meshRefinement::getRefineCandidateFaces
533     const labelList& refineCell
534 ) const
536     labelList testFaces(mesh_.nFaces());
538     label nTest = 0;
540     forAll(surfaceIndex_, faceI)
541     {
542         if (surfaceIndex_[faceI] != -1)
543         {
544             label own = mesh_.faceOwner()[faceI];
546             if (mesh_.isInternalFace(faceI))
547             {
548                 label nei = mesh_.faceNeighbour()[faceI];
550                 if (refineCell[own] == -1 || refineCell[nei] == -1)
551                 {
552                     testFaces[nTest++] = faceI;
553                 }
554             }
555             else
556             {
557                 if (refineCell[own] == -1)
558                 {
559                     testFaces[nTest++] = faceI;
560                 }
561             }
562         }
563     }
564     testFaces.setSize(nTest);
566     return testFaces;
570 // Mark cells for surface intersection based refinement.
571 Foam::label Foam::meshRefinement::markSurfaceRefinement
573     const label nAllowRefine,
574     const labelList& neiLevel,
575     const pointField& neiCc,
577     labelList& refineCell,
578     label& nRefine
579 ) const
581     const labelList& cellLevel = meshCutter_.cellLevel();
582     const pointField& cellCentres = mesh_.cellCentres();
584     label oldNRefine = nRefine;
586     // Use cached surfaceIndex_ to detect if any intersection. If so
587     // re-intersect to determine level wanted.
589     // Collect candidate faces
590     // ~~~~~~~~~~~~~~~~~~~~~~~
592     labelList testFaces(getRefineCandidateFaces(refineCell));
594     // Collect segments
595     // ~~~~~~~~~~~~~~~~
597     pointField start(testFaces.size());
598     pointField end(testFaces.size());
599     labelList minLevel(testFaces.size());
601     forAll(testFaces, i)
602     {
603         label faceI = testFaces[i];
605         label own = mesh_.faceOwner()[faceI];
607         if (mesh_.isInternalFace(faceI))
608         {
609             label nei = mesh_.faceNeighbour()[faceI];
611             start[i] = cellCentres[own];
612             end[i] = cellCentres[nei];
613             minLevel[i] = min(cellLevel[own], cellLevel[nei]);
614         }
615         else
616         {
617             label bFaceI = faceI - mesh_.nInternalFaces();
619             start[i] = cellCentres[own];
620             end[i] = neiCc[bFaceI];
621             minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
622         }
623     }
625     // Extend segments a bit
626     {
627         const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
628         start -= smallVec;
629         end += smallVec;
630     }
633     // Do test for higher intersections
634     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
636     labelList surfaceHit;
637     labelList surfaceMinLevel;
638     surfaces_.findHigherIntersection
639     (
640         start,
641         end,
642         minLevel,
644         surfaceHit,
645         surfaceMinLevel
646     );
649     // Mark cells for refinement
650     // ~~~~~~~~~~~~~~~~~~~~~~~~~
652     forAll(testFaces, i)
653     {
654         label faceI = testFaces[i];
656         label surfI = surfaceHit[i];
658         if (surfI != -1)
659         {
660             // Found intersection with surface with higher wanted
661             // refinement. Check if the level field on that surface
662             // specifies an even higher level. Note:this is weird. Should
663             // do the check with the surfaceMinLevel whilst intersecting the
664             // surfaces?
666             label own = mesh_.faceOwner()[faceI];
668             if (surfaceMinLevel[i] > cellLevel[own])
669             {
670                 // Owner needs refining
671                 if
672                 (
673                    !markForRefine
674                     (
675                         surfI,
676                         nAllowRefine,
677                         refineCell[own],
678                         nRefine
679                     )
680                 )
681                 {
682                     break;
683                 }
684             }
686             if (mesh_.isInternalFace(faceI))
687             {
688                 label nei = mesh_.faceNeighbour()[faceI];
689                 if (surfaceMinLevel[i] > cellLevel[nei])
690                 {
691                     // Neighbour needs refining
692                     if
693                     (
694                        !markForRefine
695                         (
696                             surfI,
697                             nAllowRefine,
698                             refineCell[nei],
699                             nRefine
700                         )
701                     )
702                     {
703                         break;
704                     }
705                 }
706             }
707         }
708     }
710     if
711     (
712         returnReduce(nRefine, sumOp<label>())
713       > returnReduce(nAllowRefine, sumOp<label>())
714     )
715     {
716         Info<< "Reached refinement limit." << endl;
717     }
719     return returnReduce(nRefine-oldNRefine, sumOp<label>());
723 // Checks if multiple intersections of a cell (by a surface with a higher
724 // max than the cell level) and if so if the normals at these intersections
725 // make a large angle.
726 // Returns false if the nRefine limit has been reached, true otherwise.
727 bool Foam::meshRefinement::checkCurvature
729     const scalar curvature,
730     const label nAllowRefine,
732     const label surfaceLevel,   // current intersection max level
733     const vector& surfaceNormal,// current intersection normal
735     const label cellI,
737     label& cellMaxLevel,        // cached max surface level for this cell
738     vector& cellMaxNormal,      // cached surface normal for this cell
740     labelList& refineCell,
741     label& nRefine
742 ) const
744     const labelList& cellLevel = meshCutter_.cellLevel();
746     // Test if surface applicable
747     if (surfaceLevel > cellLevel[cellI])
748     {
749         if (cellMaxLevel == -1)
750         {
751             // First visit of cell. Store
752             cellMaxLevel = surfaceLevel;
753             cellMaxNormal = surfaceNormal;
754         }
755         else
756         {
757             // Second or more visit. Check curvature.
758             if ((cellMaxNormal & surfaceNormal) < curvature)
759             {
760                 return markForRefine
761                 (
762                     surfaceLevel,   // mark with any non-neg number.
763                     nAllowRefine,
764                     refineCell[cellI],
765                     nRefine
766                 );
767             }
769             // Set normal to that of highest surface. Not really necessary
770             // over here but we reuse cellMax info when doing coupled faces.
771             if (surfaceLevel > cellMaxLevel)
772             {
773                 cellMaxLevel = surfaceLevel;
774                 cellMaxNormal = surfaceNormal;
775             }
776         }
777     }
779     // Did not reach refinement limit.
780     return true;
784 // Mark cells for surface curvature based refinement.
785 Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
787     const scalar curvature,
788     const label nAllowRefine,
789     const labelList& neiLevel,
790     const pointField& neiCc,
792     labelList& refineCell,
793     label& nRefine
794 ) const
796     const labelList& cellLevel = meshCutter_.cellLevel();
797     const pointField& cellCentres = mesh_.cellCentres();
799     label oldNRefine = nRefine;
801     // 1. local test: any cell on more than one surface gets refined
802     // (if its current level is < max of the surface max level)
804     // 2. 'global' test: any cell on only one surface with a neighbour
805     // on a different surface gets refined (if its current level etc.)
808     // Collect candidate faces (i.e. intersecting any surface and
809     // owner/neighbour not yet refined.
810     labelList testFaces(getRefineCandidateFaces(refineCell));
812     // Collect segments
813     pointField start(testFaces.size());
814     pointField end(testFaces.size());
815     labelList minLevel(testFaces.size());
817     forAll(testFaces, i)
818     {
819         label faceI = testFaces[i];
821         label own = mesh_.faceOwner()[faceI];
823         if (mesh_.isInternalFace(faceI))
824         {
825             label nei = mesh_.faceNeighbour()[faceI];
827             start[i] = cellCentres[own];
828             end[i] = cellCentres[nei];
829             minLevel[i] = min(cellLevel[own], cellLevel[nei]);
830         }
831         else
832         {
833             label bFaceI = faceI - mesh_.nInternalFaces();
835             start[i] = cellCentres[own];
836             end[i] = neiCc[bFaceI];
837             minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
838         }
839     }
841     // Extend segments a bit
842     {
843         const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
844         start -= smallVec;
845         end += smallVec;
846     }
849     // Test for all intersections (with surfaces of higher max level than
850     // minLevel) and cache per cell the max surface level and the local normal
851     // on that surface.
852     labelList cellMaxLevel(mesh_.nCells(), -1);
853     vectorField cellMaxNormal(mesh_.nCells(), vector::zero);
855     {
856         // Per segment the normals of the surfaces
857         List<vectorList> surfaceNormal;
858         // Per segment the list of levels of the surfaces
859         labelListList surfaceLevel;
861         surfaces_.findAllHigherIntersections
862         (
863             start,
864             end,
865             minLevel,           // max level of surface has to be bigger
866                                 // than min level of neighbouring cells
867             surfaceNormal,
868             surfaceLevel
869         );
870         // Clear out unnecessary data
871         start.clear();
872         end.clear();
873         minLevel.clear();
875         // Extract per cell information on the surface with the highest max
876         forAll(testFaces, i)
877         {
878             label faceI = testFaces[i];
879             label own = mesh_.faceOwner()[faceI];
881             const vectorList& fNormals = surfaceNormal[i];
882             const labelList& fLevels = surfaceLevel[i];
884             forAll(fLevels, hitI)
885             {
886                 checkCurvature
887                 (
888                     curvature,
889                     nAllowRefine,
891                     fLevels[hitI],
892                     fNormals[hitI],
894                     own,
895                     cellMaxLevel[own],
896                     cellMaxNormal[own],
898                     refineCell,
899                     nRefine
900                 );
901             }
903             if (mesh_.isInternalFace(faceI))
904             {
905                 label nei = mesh_.faceNeighbour()[faceI];
907                 forAll(fLevels, hitI)
908                 {
909                     checkCurvature
910                     (
911                         curvature,
912                         nAllowRefine,
914                         fLevels[hitI],
915                         fNormals[hitI],
917                         nei,
918                         cellMaxLevel[nei],
919                         cellMaxNormal[nei],
921                         refineCell,
922                         nRefine
923                     );
924                 }
925             }
926         }
927     }
929     // 2. Find out a measure of surface curvature and region edges.
930     // Send over surface region and surface normal to neighbour cell.
932     labelList neiBndMaxLevel(mesh_.nFaces()-mesh_.nInternalFaces());
933     vectorField neiBndMaxNormal(mesh_.nFaces()-mesh_.nInternalFaces());
935     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
936     {
937         label bFaceI = faceI-mesh_.nInternalFaces();
938         label own = mesh_.faceOwner()[faceI];
940         neiBndMaxLevel[bFaceI] = cellMaxLevel[own];
941         neiBndMaxNormal[bFaceI] = cellMaxNormal[own];
942     }
943     syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel);
944     syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal);
946     // Loop over all faces. Could only be checkFaces.. except if they're coupled
948     // Internal faces
949     for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
950     {
951         label own = mesh_.faceOwner()[faceI];
952         label nei = mesh_.faceNeighbour()[faceI];
954         if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1)
955         {
956             // Have valid data on both sides. Check curvature.
957             if ((cellMaxNormal[own] & cellMaxNormal[nei]) < curvature)
958             {
959                 // See which side to refine
960                 if (cellLevel[own] < cellMaxLevel[own])
961                 {
962                     if
963                     (
964                         !markForRefine
965                         (
966                             cellMaxLevel[own],
967                             nAllowRefine,
968                             refineCell[own],
969                             nRefine
970                         )
971                     )
972                     {
973                         if (debug)
974                         {
975                             Pout<< "Stopped refining since reaching my cell"
976                                 << " limit of " << mesh_.nCells()+7*nRefine
977                                 << endl;
978                         }
979                         break;
980                     }
981                 }
983                 if (cellLevel[nei] < cellMaxLevel[nei])
984                 {
985                     if
986                     (
987                         !markForRefine
988                         (
989                             cellMaxLevel[nei],
990                             nAllowRefine,
991                             refineCell[nei],
992                             nRefine
993                         )
994                     )
995                     {
996                         if (debug)
997                         {
998                             Pout<< "Stopped refining since reaching my cell"
999                                 << " limit of " << mesh_.nCells()+7*nRefine
1000                                 << endl;
1001                         }
1002                         break;
1003                     }
1004                 }
1005             }
1006         }
1007     }
1008     // Boundary faces
1009     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
1010     {
1011         label own = mesh_.faceOwner()[faceI];
1012         label bFaceI = faceI - mesh_.nInternalFaces();
1014         if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFaceI] != -1)
1015         {
1016             // Have valid data on both sides. Check curvature.
1017             if ((cellMaxNormal[own] & neiBndMaxNormal[bFaceI]) < curvature)
1018             {
1019                 if
1020                 (
1021                     !markForRefine
1022                     (
1023                         cellMaxLevel[own],
1024                         nAllowRefine,
1025                         refineCell[own],
1026                         nRefine
1027                     )
1028                 )
1029                 {
1030                     if (debug)
1031                     {
1032                         Pout<< "Stopped refining since reaching my cell"
1033                             << " limit of " << mesh_.nCells()+7*nRefine
1034                             << endl;
1035                     }
1036                     break;
1037                 }
1038             }
1039         }
1040     }
1042     if
1043     (
1044         returnReduce(nRefine, sumOp<label>())
1045       > returnReduce(nAllowRefine, sumOp<label>())
1046     )
1047     {
1048         Info<< "Reached refinement limit." << endl;
1049     }
1051     return returnReduce(nRefine-oldNRefine, sumOp<label>());
1055 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
1057 // Calculate list of cells to refine. Gets for any edge (start - end)
1058 // whether it intersects the surface. Does more accurate test and checks
1059 // the wanted level on the surface intersected.
1060 // Does approximate precalculation of how many cells can be refined before
1061 // hitting overall limit maxGlobalCells.
1062 Foam::labelList Foam::meshRefinement::refineCandidates
1064     const point& keepPoint,
1065     const scalar curvature,
1067     const bool featureRefinement,
1068     const bool internalRefinement,
1069     const bool surfaceRefinement,
1070     const bool curvatureRefinement,
1071     const label maxGlobalCells,
1072     const label maxLocalCells
1073 ) const
1075     label totNCells = mesh_.globalData().nTotalCells();
1077     labelList cellsToRefine;
1079     if (totNCells >= maxGlobalCells)
1080     {
1081         Info<< "No cells marked for refinement since reached limit "
1082             << maxGlobalCells << '.' << endl;
1083     }
1084     else
1085     {
1086         // Every cell I refine adds 7 cells. Estimate the number of cells
1087         // I am allowed to refine.
1088         // Assume perfect distribution so can only refine as much the fraction
1089         // of the mesh I hold. This prediction step prevents us having to do
1090         // lots of reduces to keep count of the total number of cells selected
1091         // for refinement.
1093         //scalar fraction = scalar(mesh_.nCells())/totNCells;
1094         //label myMaxCells = label(maxGlobalCells*fraction);
1095         //label nAllowRefine = (myMaxCells - mesh_.nCells())/7;
1096         ////label nAllowRefine = (maxLocalCells - mesh_.nCells())/7;
1097         //
1098         //Pout<< "refineCandidates:" << nl
1099         //    << "    total cells:" << totNCells << nl
1100         //    << "    local cells:" << mesh_.nCells() << nl
1101         //    << "    local fraction:" << fraction << nl
1102         //    << "    local allowable cells:" << myMaxCells << nl
1103         //    << "    local allowable refinement:" << nAllowRefine << nl
1104         //    << endl;
1106         //- Disable refinement shortcut. nAllowRefine is per processor limit.
1107         label nAllowRefine = labelMax / Pstream::nProcs();
1109         // Marked for refinement (>= 0) or not (-1). Actual value is the
1110         // index of the surface it intersects.
1111         labelList refineCell(mesh_.nCells(), -1);
1112         label nRefine = 0;
1115         // Swap neighbouring cell centres and cell level
1116         labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1117         pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
1118         calcNeighbourData(neiLevel, neiCc);
1122         // Cells pierced by feature lines
1123         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1125         if (featureRefinement)
1126         {
1127             label nFeatures = markFeatureRefinement
1128             (
1129                 keepPoint,
1130                 nAllowRefine,
1132                 refineCell,
1133                 nRefine
1134             );
1136             Info<< "Marked for refinement due to explicit features    : "
1137                 << nFeatures << " cells."  << endl;
1138         }
1140         // Inside refinement shells
1141         // ~~~~~~~~~~~~~~~~~~~~~~~~
1143         if (internalRefinement)
1144         {
1145             label nShell = markInternalRefinement
1146             (
1147                 nAllowRefine,
1149                 refineCell,
1150                 nRefine
1151             );
1152             Info<< "Marked for refinement due to refinement shells    : "
1153                 << nShell << " cells."  << endl;
1154         }
1156         // Refinement based on intersection of surface
1157         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1159         if (surfaceRefinement)
1160         {
1161             label nSurf = markSurfaceRefinement
1162             (
1163                 nAllowRefine,
1164                 neiLevel,
1165                 neiCc,
1167                 refineCell,
1168                 nRefine
1169             );
1170             Info<< "Marked for refinement due to surface intersection : "
1171                 << nSurf << " cells."  << endl;
1172         }
1174         // Refinement based on curvature of surface
1175         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1177         if
1178         (
1179             curvatureRefinement
1180          && (curvature >= -1 && curvature <= 1)
1181          && (surfaces_.minLevel() != surfaces_.maxLevel())
1182         )
1183         {
1184             label nCurv = markSurfaceCurvatureRefinement
1185             (
1186                 curvature,
1187                 nAllowRefine,
1188                 neiLevel,
1189                 neiCc,
1191                 refineCell,
1192                 nRefine
1193             );
1194             Info<< "Marked for refinement due to curvature/regions    : "
1195                 << nCurv << " cells."  << endl;
1196         }
1198         // Pack cells-to-refine
1199         // ~~~~~~~~~~~~~~~~~~~~
1201         cellsToRefine.setSize(nRefine);
1202         nRefine = 0;
1204         forAll(refineCell, cellI)
1205         {
1206             if (refineCell[cellI] != -1)
1207             {
1208                 cellsToRefine[nRefine++] = cellI;
1209             }
1210         }
1211     }
1213     return cellsToRefine;
1217 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::refine
1219     const labelList& cellsToRefine
1222     // Mesh changing engine.
1223     polyTopoChange meshMod(mesh_);
1225     // Play refinement commands into mesh changer.
1226     meshCutter_.setRefinement(cellsToRefine, meshMod);
1228     // Create mesh (no inflation), return map from old to new mesh.
1229     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false);
1231     // Update fields
1232     mesh_.updateMesh(map);
1234     // Optionally inflate mesh
1235     if (map().hasMotionPoints())
1236     {
1237         mesh_.movePoints(map().preMotionPoints());
1238     }
1239     else
1240     {
1241         // Delete mesh volumes.
1242         mesh_.clearOut();
1243     }
1245     // Reset the instance for if in overwrite mode
1246     mesh_.setInstance(timeName());
1248     // Update intersection info
1249     updateMesh(map, getChangedFaces(map, cellsToRefine));
1251     return map;
1255 // Do refinement of consistent set of cells followed by truncation and
1256 // load balancing.
1257 Foam::autoPtr<Foam::mapDistributePolyMesh>
1258 Foam::meshRefinement::refineAndBalance
1260     const string& msg,
1261     decompositionMethod& decomposer,
1262     fvMeshDistribute& distributor,
1263     const labelList& cellsToRefine,
1264     const scalar maxLoadUnbalance
1267     // Do all refinement
1268     refine(cellsToRefine);
1270     if (debug)
1271     {
1272         Pout<< "Writing refined but unbalanced " << msg
1273             << " mesh to time " << timeName() << endl;
1274         write
1275         (
1276             debug,
1277             mesh_.time().path()
1278            /timeName()
1279         );
1280         Pout<< "Dumped debug data in = "
1281             << mesh_.time().cpuTimeIncrement() << " s" << endl;
1283         // test all is still synced across proc patches
1284         checkData();
1285     }
1287     Info<< "Refined mesh in = "
1288         << mesh_.time().cpuTimeIncrement() << " s" << endl;
1289     printMeshInfo(debug, "After refinement " + msg);
1292     // Load balancing
1293     // ~~~~~~~~~~~~~~
1295     autoPtr<mapDistributePolyMesh> distMap;
1297     if (Pstream::nProcs() > 1)
1298     {
1299         scalar nIdealCells =
1300             mesh_.globalData().nTotalCells()
1301           / Pstream::nProcs();
1303         scalar unbalance = returnReduce
1304         (
1305             mag(1.0-mesh_.nCells()/nIdealCells),
1306             maxOp<scalar>()
1307         );
1309         if (unbalance <= maxLoadUnbalance)
1310         {
1311             Info<< "Skipping balancing since max unbalance " << unbalance
1312                 << " is less than allowable " << maxLoadUnbalance
1313                 << endl;
1314         }
1315         else
1316         {
1317             scalarField cellWeights(mesh_.nCells(), 1);
1319             distMap = balance
1320             (
1321                 false,  //keepZoneFaces
1322                 false,  //keepBaffles
1323                 cellWeights,
1324                 decomposer,
1325                 distributor
1326             );
1328             Info<< "Balanced mesh in = "
1329                 << mesh_.time().cpuTimeIncrement() << " s" << endl;
1331             printMeshInfo(debug, "After balancing " + msg);
1334             if (debug)
1335             {
1336                 Pout<< "Writing balanced " << msg
1337                     << " mesh to time " << timeName() << endl;
1338                 write
1339                 (
1340                     debug,
1341                     mesh_.time().path()/timeName()
1342                 );
1343                 Pout<< "Dumped debug data in = "
1344                     << mesh_.time().cpuTimeIncrement() << " s" << endl;
1346                 // test all is still synced across proc patches
1347                 checkData();
1348             }
1349         }
1350     }
1352     return distMap;
1356 // Do load balancing followed by refinement of consistent set of cells.
1357 Foam::autoPtr<Foam::mapDistributePolyMesh>
1358 Foam::meshRefinement::balanceAndRefine
1360     const string& msg,
1361     decompositionMethod& decomposer,
1362     fvMeshDistribute& distributor,
1363     const labelList& initCellsToRefine,
1364     const scalar maxLoadUnbalance
1367     labelList cellsToRefine(initCellsToRefine);
1369     //{
1370     //    globalIndex globalCells(mesh_.nCells());
1371     //
1372     //    Info<< "** Distribution before balancing/refining:" << endl;
1373     //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
1374     //    {
1375     //        Info<< "    " << procI << '\t'
1376     //            << globalCells.localSize(procI) << endl;
1377     //    }
1378     //    Info<< endl;
1379     //}
1380     //{
1381     //    globalIndex globalCells(cellsToRefine.size());
1382     //
1383     //    Info<< "** Cells to be refined:" << endl;
1384     //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
1385     //    {
1386     //        Info<< "    " << procI << '\t'
1387     //            << globalCells.localSize(procI) << endl;
1388     //    }
1389     //    Info<< endl;
1390     //}
1393     // Load balancing
1394     // ~~~~~~~~~~~~~~
1396     autoPtr<mapDistributePolyMesh> distMap;
1398     if (Pstream::nProcs() > 1)
1399     {
1400         // First check if we need to balance at all. Precalculate number of
1401         // cells after refinement and see what maximum difference is.
1402         scalar nNewCells = scalar(mesh_.nCells() + 7*cellsToRefine.size());
1403         scalar nIdealNewCells =
1404             returnReduce(nNewCells, sumOp<scalar>())
1405           / Pstream::nProcs();
1406         scalar unbalance = returnReduce
1407         (
1408             mag(1.0-nNewCells/nIdealNewCells),
1409             maxOp<scalar>()
1410         );
1412         if (unbalance <= maxLoadUnbalance)
1413         {
1414             Info<< "Skipping balancing since max unbalance " << unbalance
1415                 << " is less than allowable " << maxLoadUnbalance
1416                 << endl;
1417         }
1418         else
1419         {
1420             scalarField cellWeights(mesh_.nCells(), 1);
1421             forAll(cellsToRefine, i)
1422             {
1423                 cellWeights[cellsToRefine[i]] += 7;
1424             }
1426             distMap = balance
1427             (
1428                 false,  //keepZoneFaces
1429                 false,  //keepBaffles
1430                 cellWeights,
1431                 decomposer,
1432                 distributor
1433             );
1435             // Update cells to refine
1436             distMap().distributeCellIndices(cellsToRefine);
1438             Info<< "Balanced mesh in = "
1439                 << mesh_.time().cpuTimeIncrement() << " s" << endl;
1440         }
1442         //{
1443         //    globalIndex globalCells(mesh_.nCells());
1444         //
1445         //    Info<< "** Distribution after balancing:" << endl;
1446         //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
1447         //    {
1448         //        Info<< "    " << procI << '\t'
1449         //            << globalCells.localSize(procI) << endl;
1450         //    }
1451         //    Info<< endl;
1452         //}
1454         printMeshInfo(debug, "After balancing " + msg);
1456         if (debug)
1457         {
1458             Pout<< "Writing balanced " << msg
1459                 << " mesh to time " << timeName() << endl;
1460             write
1461             (
1462                 debug,
1463                 mesh_.time().path()/timeName()
1464             );
1465             Pout<< "Dumped debug data in = "
1466                 << mesh_.time().cpuTimeIncrement() << " s" << endl;
1468             // test all is still synced across proc patches
1469             checkData();
1470         }
1471     }
1474     // Refinement
1475     // ~~~~~~~~~~
1477     refine(cellsToRefine);
1479     if (debug)
1480     {
1481         Pout<< "Writing refined " << msg
1482             << " mesh to time " << timeName() << endl;
1483         write
1484         (
1485             debug,
1486             mesh_.time().path()
1487            /timeName()
1488         );
1489         Pout<< "Dumped debug data in = "
1490             << mesh_.time().cpuTimeIncrement() << " s" << endl;
1492         // test all is still synced across proc patches
1493         checkData();
1494     }
1496     Info<< "Refined mesh in = "
1497         << mesh_.time().cpuTimeIncrement() << " s" << endl;
1499     //{
1500     //    globalIndex globalCells(mesh_.nCells());
1501     //
1502     //    Info<< "** After refinement distribution:" << endl;
1503     //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
1504     //    {
1505     //        Info<< "    " << procI << '\t'
1506     //            << globalCells.localSize(procI) << endl;
1507     //    }
1508     //    Info<< endl;
1509     //}
1511     printMeshInfo(debug, "After refinement " + msg);
1513     return distMap;
1517 // ************************************************************************* //