1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*----------------------------------------------------------------------------*/
27 #include "meshRefinement.H"
29 #include "volFields.H"
30 #include "surfaceMesh.H"
31 #include "syncTools.H"
33 #include "refinementHistory.H"
34 #include "refinementSurfaces.H"
35 #include "decompositionMethod.H"
36 #include "regionSplit.H"
37 #include "fvMeshDistribute.H"
38 #include "indirectPrimitivePatch.H"
39 #include "polyTopoChange.H"
40 #include "removeCells.H"
41 #include "mapDistributePolyMesh.H"
42 #include "localPointRegion.H"
43 #include "pointMesh.H"
44 #include "pointFields.H"
45 #include "slipPointPatchFields.H"
46 #include "fixedValuePointPatchFields.H"
47 #include "globalPointPatchFields.H"
48 #include "calculatedPointPatchFields.H"
49 #include "processorPointPatch.H"
50 #include "globalIndex.H"
51 #include "meshTools.H"
54 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
58 defineTypeNameAndDebug(meshRefinement, 0);
61 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
63 void Foam::meshRefinement::calcNeighbourData
69 const labelList& cellLevel = meshCutter_.cellLevel();
70 const pointField& cellCentres = mesh_.cellCentres();
72 label nBoundaryFaces = mesh_.nFaces() - mesh_.nInternalFaces();
74 if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
76 FatalErrorIn("meshRefinement::calcNeighbour(..)") << "nBoundaries:"
77 << nBoundaryFaces << " neiLevel:" << neiLevel.size()
81 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
83 forAll(patches, patchI)
85 const polyPatch& pp = patches[patchI];
87 const unallocLabelList& faceCells = pp.faceCells();
88 const vectorField::subField faceCentres = pp.faceCentres();
90 label bFaceI = pp.start()-mesh_.nInternalFaces();
96 neiLevel[bFaceI] = cellLevel[faceCells[i]];
97 neiCc[bFaceI] = cellCentres[faceCells[i]];
105 neiLevel[bFaceI] = cellLevel[faceCells[i]];
106 neiCc[bFaceI] = faceCentres[i];
112 // Swap coupled boundaries. Apply separation to cc since is coordinate.
113 syncTools::swapBoundaryFaceList(mesh_, neiCc, true);
114 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
118 // Find intersections of edges (given by their two endpoints) with surfaces.
119 // Returns first intersection if there are more than one.
120 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
122 const pointField& cellCentres = mesh_.cellCentres();
124 label nTotEdges = returnReduce(surfaceIndex_.size(), sumOp<label>());
125 label nChangedFaces = returnReduce(changedFaces.size(), sumOp<label>());
127 Info<< "Edge intersection testing:" << nl
128 << " Number of edges : " << nTotEdges << nl
129 << " Number of edges to retest : " << nChangedFaces
132 // Get boundary face centre and level. Coupled aware.
133 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
134 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
135 calcNeighbourData(neiLevel, neiCc);
137 // Collect segments we want to test for
138 pointField start(changedFaces.size());
139 pointField end(changedFaces.size());
141 forAll(changedFaces, i)
143 label faceI = changedFaces[i];
144 label own = mesh_.faceOwner()[faceI];
146 start[i] = cellCentres[own];
147 if (mesh_.isInternalFace(faceI))
149 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
153 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
157 // Do tests in one go
158 labelList surfaceHit;
160 labelList surfaceLevel;
161 surfaces_.findHigherIntersection
165 labelList(start.size(), -1), // accept any intersection
171 // Keep just surface hit
172 forAll(surfaceHit, i)
174 surfaceIndex_[changedFaces[i]] = surfaceHit[i];
177 // Make sure both sides have same information. This should be
178 // case in general since same vectors but just to make sure.
179 syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>(), false);
181 label nHits = countHits();
182 label nTotHits = returnReduce(nHits, sumOp<label>());
184 Info<< " Number of intersected edges : " << nTotHits << endl;
186 // Set files to same time as mesh
187 setInstance(mesh_.facesInstance());
191 void Foam::meshRefinement::checkData()
193 Pout<< "meshRefinement::checkData() : Checking refinement structure."
195 meshCutter_.checkMesh();
197 Pout<< "meshRefinement::checkData() : Checking refinement levels."
199 meshCutter_.checkRefinementLevels(1, labelList(0));
202 Pout<< "meshRefinement::checkData() : Checking synchronization."
205 // Check face centres
207 // Boundary face centres
208 pointField::subList boundaryFc
211 mesh_.nFaces()-mesh_.nInternalFaces(),
212 mesh_.nInternalFaces()
215 // Get neighbouring face centres
216 pointField neiBoundaryFc(boundaryFc);
217 syncTools::swapBoundaryFaceList
225 testSyncBoundaryFaceList
228 "testing faceCentres : ",
233 // Check meshRefinement
235 // Get boundary face centre and level. Coupled aware.
236 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
237 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
238 calcNeighbourData(neiLevel, neiCc);
240 // Collect segments we want to test for
241 pointField start(mesh_.nFaces());
242 pointField end(mesh_.nFaces());
246 start[faceI] = mesh_.cellCentres()[mesh_.faceOwner()[faceI]];
248 if (mesh_.isInternalFace(faceI))
250 end[faceI] = mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]];
254 end[faceI] = neiCc[faceI-mesh_.nInternalFaces()];
258 // Do tests in one go
259 labelList surfaceHit;
261 labelList surfaceLevel;
262 surfaces_.findHigherIntersection
266 labelList(start.size(), -1), // accept any intersection
273 forAll(surfaceHit, faceI)
275 if (surfaceHit[faceI] != surfaceIndex_[faceI])
277 if (mesh_.isInternalFace(faceI))
279 WarningIn("meshRefinement::checkData()")
280 << "Internal face:" << faceI
281 << " fc:" << mesh_.faceCentres()[faceI]
282 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
283 << " current:" << surfaceHit[faceI]
285 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
287 << mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]]
292 WarningIn("meshRefinement::checkData()")
293 << "Boundary face:" << faceI
294 << " fc:" << mesh_.faceCentres()[faceI]
295 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
296 << " current:" << surfaceHit[faceI]
298 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
305 labelList::subList boundarySurface
308 mesh_.nFaces()-mesh_.nInternalFaces(),
309 mesh_.nInternalFaces()
312 labelList neiBoundarySurface(boundarySurface);
313 syncTools::swapBoundaryFaceList
321 testSyncBoundaryFaceList
324 "testing surfaceIndex() : ",
331 // Find duplicate faces
332 Pout<< "meshRefinement::checkData() : Counting duplicate faces."
335 labelList duplicateFace
337 localPointRegion::findDuplicateFaces
340 identity(mesh_.nFaces()-mesh_.nInternalFaces())
341 + mesh_.nInternalFaces()
349 forAll(duplicateFace, i)
351 if (duplicateFace[i] != -1)
356 nDup /= 2; // will have counted both faces of duplicate
357 Pout<< "meshRefinement::checkData() : Found " << nDup
358 << " duplicate pairs of faces." << endl;
363 void Foam::meshRefinement::setInstance(const fileName& inst)
365 meshCutter_.setInstance(inst);
366 surfaceIndex_.instance() = inst;
370 // Remove cells. Put exposedFaces (output of getExposedFaces(cellsToRemove))
371 // into exposedPatchIDs.
372 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells
374 const labelList& cellsToRemove,
375 const labelList& exposedFaces,
376 const labelList& exposedPatchIDs,
377 removeCells& cellRemover
380 polyTopoChange meshMod(mesh_);
382 // Arbitrary: put exposed faces into last patch.
383 cellRemover.setRefinement
391 // Change the mesh (no inflation)
392 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
395 mesh_.updateMesh(map);
397 // Move mesh (since morphing might not do this)
398 if (map().hasMotionPoints())
400 mesh_.movePoints(map().preMotionPoints());
404 // Delete mesh volumes. No other way to do this?
408 // Update local mesh data
409 cellRemover.updateMesh(map);
411 // Update intersections. Recalculate intersections for exposed faces.
412 labelList newExposedFaces = renumber
414 map().reverseFaceMap(),
418 //Pout<< "removeCells : updating intersections for "
419 // << newExposedFaces.size() << " newly exposed faces." << endl;
421 updateMesh(map, newExposedFaces);
427 // Determine for multi-processor regions the lowest numbered cell on the lowest
428 // numbered processor.
429 void Foam::meshRefinement::getRegionMaster
431 const boolList& blockedFace,
432 const regionSplit& globalRegion,
433 Map<label>& regionToMaster
436 globalIndex globalCells(mesh_.nCells());
438 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
440 forAll(patches, patchI)
442 const polyPatch& pp = patches[patchI];
444 if (isA<processorPolyPatch>(pp))
448 label faceI = pp.start()+i;
450 if (!blockedFace[faceI])
452 // Only if there is a connection to the neighbour
453 // will there be a multi-domain region; if not through
454 // this face then through another.
456 label cellI = mesh_.faceOwner()[faceI];
457 label globalCellI = globalCells.toGlobal(cellI);
459 Map<label>::iterator iter =
460 regionToMaster.find(globalRegion[cellI]);
462 if (iter != regionToMaster.end())
464 label master = iter();
465 iter() = min(master, globalCellI);
469 regionToMaster.insert
481 Pstream::mapCombineGather(regionToMaster, minEqOp<label>());
482 Pstream::mapCombineScatter(regionToMaster);
486 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
488 // Construct from components
489 Foam::meshRefinement::meshRefinement
492 const scalar mergeDistance,
493 const refinementSurfaces& surfaces,
494 const shellSurfaces& shells
498 mergeDistance_(mergeDistance),
509 mesh_.facesInstance(),
512 IOobject::READ_IF_PRESENT,
516 labelList(mesh_.nCells(), 0)
523 mesh_.facesInstance(),
526 IOobject::READ_IF_PRESENT,
530 labelList(mesh_.nPoints(), 0)
537 mesh_.facesInstance(),
544 List<refinementHistory::splitCell8>(0),
553 mesh_.facesInstance(),
560 labelList(mesh_.nFaces(), -1)
564 // recalculate intersections for all faces
565 updateIntersections(identity(mesh_.nFaces()));
569 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
571 Foam::label Foam::meshRefinement::countHits() const
575 forAll(surfaceIndex_, faceI)
577 if (surfaceIndex_[faceI] >= 0)
586 // Determine distribution to move connected regions onto one processor.
587 Foam::labelList Foam::meshRefinement::decomposeCombineRegions
589 const boolList& blockedFace,
590 const List<labelPair>& explicitConnections,
591 decompositionMethod& decomposer
594 // Determine global regions, separated by blockedFaces
595 regionSplit globalRegion(mesh_, blockedFace, explicitConnections);
597 // Now globalRegion has global region per cell. Problem is that
598 // the region might span multiple domains so we want to get
599 // a "region master" per domain. Note that multi-processor
600 // regions can only occur on cells on coupled patches.
603 // Determine per coupled region the master cell (lowest numbered cell
604 // on lowest numbered processor)
605 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
607 Map<label> regionToMaster(mesh_.nFaces()-mesh_.nInternalFaces());
608 getRegionMaster(blockedFace, globalRegion, regionToMaster);
611 // Global cell numbering engine
612 globalIndex globalCells(mesh_.nCells());
615 // Determine cell centre per region
616 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
617 // Now we can divide regions into
618 // - single-processor regions (almost all)
619 // - allocate local region + coordinate for it
620 // - multi-processor for which I am master
621 // - allocate local region + coordinate for it
622 // - multi-processor for which I am not master
623 // - do not allocate region.
624 // - but inherit new distribution from master.
626 Map<label> globalToLocalRegion(mesh_.nCells());
627 DynamicList<point> localCc(mesh_.nCells()/10);
629 forAll(globalRegion, cellI)
631 Map<label>::const_iterator fndMaster =
632 regionToMaster.find(globalRegion[cellI]);
634 if (fndMaster != regionToMaster.end())
636 // Multi-processor region.
637 if (globalCells.toGlobal(cellI) == fndMaster())
639 // I am master. Allocate region for me.
640 globalToLocalRegion.insert(globalRegion[cellI], localCc.size());
641 localCc.append(mesh_.cellCentres()[cellI]);
646 // Single processor region.
647 Map<label>::iterator iter =
648 globalToLocalRegion.find(globalRegion[cellI]);
650 if (iter == globalToLocalRegion.end())
652 globalToLocalRegion.insert(globalRegion[cellI], localCc.size());
653 localCc.append(mesh_.cellCentres()[cellI]);
658 pointField localPoints;
659 localPoints.transfer(localCc);
662 // Call decomposer on localCc
663 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
665 labelList localDistribution = decomposer.decompose(localPoints);
668 // Distribute the destination processor for coupled regions
669 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
671 Map<label> regionToDist(regionToMaster.size());
673 forAllConstIter(Map<label>, regionToMaster, iter)
675 if (globalCells.isLocal(iter()))
677 // Master cell is local.
681 localDistribution[globalToLocalRegion[iter.key()]]
686 // Master cell is not on this processor. Make sure it is overridden.
687 regionToDist.insert(iter.key(), labelMax);
690 Pstream::mapCombineGather(regionToDist, minEqOp<label>());
691 Pstream::mapCombineScatter(regionToDist);
694 // Convert region-based decomposition back to cell-based one
695 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
697 labelList distribution(mesh_.nCells());
699 forAll(globalRegion, cellI)
701 Map<label>::const_iterator fndMaster =
702 regionToDist.find(globalRegion[cellI]);
704 if (fndMaster != regionToDist.end())
707 distribution[cellI] = fndMaster();
711 // region is local to the processor.
712 label localRegionI = globalToLocalRegion[globalRegion[cellI]];
714 distribution[cellI] = localDistribution[localRegionI];
721 Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance
723 const bool keepZoneFaces,
724 const bool keepBaffles,
725 decompositionMethod& decomposer,
726 fvMeshDistribute& distributor
729 autoPtr<mapDistributePolyMesh> map;
731 if (Pstream::parRun())
734 // << "Doing final balancing" << nl
735 // << "---------------------" << nl
740 // const_cast<Time&>(mesh_.time())++;
743 // Wanted distribution
744 labelList distribution;
746 if (keepZoneFaces || keepBaffles)
748 // Faces where owner and neighbour are not 'connected' so can
749 // go to different processors.
750 boolList blockedFace(mesh_.nFaces(), true);
752 List<labelPair> couples;
756 label nNamed = surfaces().getNamedSurfaces().size();
758 Info<< "Found " << nNamed << " surfaces with faceZones."
759 << " Applying special decomposition to keep those together."
762 // Determine decomposition to keep/move surface zones
763 // on one processor. The reason is that snapping will make these
764 // into baffles, move and convert them back so if they were
765 // proc boundaries after baffling&moving the points might be no
766 // longer snychronised so recoupling will fail. To prevent this
767 // keep owner&neighbour of such a surface zone on the same
770 const wordList& fzNames = surfaces().faceZoneNames();
771 const faceZoneMesh& fZones = mesh_.faceZones();
773 // Get faces whose owner and neighbour should stay together,
774 // i.e. they are not 'blocked'.
778 forAll(fzNames, surfI)
780 if (fzNames[surfI].size() > 0)
783 label zoneI = fZones.findZoneID(fzNames[surfI]);
785 const faceZone& fZone = fZones[zoneI];
789 if (blockedFace[fZone[i]])
791 blockedFace[fZone[i]] = false;
797 Info<< "Found " << returnReduce(nZoned, sumOp<label>())
798 << " zoned faces to keep together."
804 // Get boundary baffles that need to stay together.
805 couples = getDuplicateFaces // all baffles
807 identity(mesh_.nFaces()-mesh_.nInternalFaces())
808 +mesh_.nInternalFaces()
811 Info<< "Found " << returnReduce(couples.size(), sumOp<label>())
812 << " baffles to keep together."
816 distribution = decomposeCombineRegions
823 labelList nProcCells(distributor.countCells(distribution));
824 Pstream::listCombineGather(nProcCells, plusEqOp<label>());
825 Pstream::listCombineScatter(nProcCells);
827 Info<< "Calculated decomposition:" << endl;
828 forAll(nProcCells, procI)
830 Info<< " " << procI << '\t' << nProcCells[procI] << endl;
836 // Normal decomposition
837 distribution = decomposer.decompose(mesh_.cellCentres());
842 Pout<< "Wanted distribution:"
843 << distributor.countCells(distribution)
846 // Do actual sending/receiving of mesh
847 map = distributor.distribute(distribution);
849 // Update numbering of meshRefiner
856 // Helper function to get intersected faces
857 Foam::labelList Foam::meshRefinement::intersectedFaces() const
859 // Mark all faces that will become baffles
861 label nBoundaryFaces = 0;
863 forAll(surfaceIndex_, faceI)
865 if (surfaceIndex_[faceI] != -1)
871 labelList surfaceFaces(nBoundaryFaces);
874 forAll(surfaceIndex_, faceI)
876 if (surfaceIndex_[faceI] != -1)
878 surfaceFaces[nBoundaryFaces++] = faceI;
885 // Helper function to get points used by faces
886 Foam::labelList Foam::meshRefinement::intersectedPoints
888 // const labelList& globalToPatch
891 const faceList& faces = mesh_.faces();
893 // Mark all points on faces that will become baffles
894 PackedList<1> isBoundaryPoint(mesh_.nPoints(), 0u);
895 label nBoundaryPoints = 0;
897 forAll(surfaceIndex_, faceI)
899 if (surfaceIndex_[faceI] != -1)
901 const face& f = faces[faceI];
905 if (isBoundaryPoint.set(f[fp], 1u))
913 //// Insert all meshed patches.
914 //forAll(globalToPatch, i)
916 // label patchI = globalToPatch[i];
920 // const polyPatch& pp = mesh_.boundaryMesh()[patchI];
922 // label faceI = pp.start();
926 // const face& f = faces[faceI];
930 // if (isBoundaryPoint.set(f[fp], 1u))
931 // nBoundaryPoints++;
941 labelList boundaryPoints(nBoundaryPoints);
943 forAll(isBoundaryPoint, pointI)
945 if (isBoundaryPoint.get(pointI) == 1u)
947 boundaryPoints[nBoundaryPoints++] = pointI;
951 return boundaryPoints;
955 Foam::labelList Foam::meshRefinement::addedPatches
957 const labelList& globalToPatch
960 labelList patchIDs(globalToPatch.size());
963 forAll(globalToPatch, i)
965 if (globalToPatch[i] != -1)
967 patchIDs[addedI++] = globalToPatch[i];
970 patchIDs.setSize(addedI);
976 //- Create patch from set of patches
977 Foam::autoPtr<Foam::indirectPrimitivePatch> Foam::meshRefinement::makePatch
979 const polyMesh& mesh,
980 const labelList& patchIDs
983 const polyBoundaryMesh& patches = mesh.boundaryMesh();
990 const polyPatch& pp = patches[patchIDs[i]];
996 labelList addressing(nFaces);
1001 const polyPatch& pp = patches[patchIDs[i]];
1003 label meshFaceI = pp.start();
1007 addressing[nFaces++] = meshFaceI++;
1011 return autoPtr<indirectPrimitivePatch>
1013 new indirectPrimitivePatch
1015 IndirectList<face>(mesh.faces(), addressing),
1022 // Construct pointVectorField with correct boundary conditions
1023 Foam::tmp<Foam::pointVectorField> Foam::meshRefinement::makeDisplacementField
1025 const pointMesh& pMesh,
1026 const labelList& adaptPatchIDs
1029 const polyMesh& mesh = pMesh();
1031 // Construct displacement field.
1032 const pointBoundaryMesh& pointPatches = pMesh.boundary();
1034 wordList patchFieldTypes
1036 pointPatches.size(),
1037 slipPointPatchVectorField::typeName
1040 forAll(adaptPatchIDs, i)
1042 patchFieldTypes[adaptPatchIDs[i]] =
1043 fixedValuePointPatchVectorField::typeName;
1046 forAll(pointPatches, patchI)
1048 if (isA<globalPointPatch>(pointPatches[patchI]))
1050 patchFieldTypes[patchI] = globalPointPatchVectorField::typeName;
1052 else if (isA<processorPointPatch>(pointPatches[patchI]))
1054 patchFieldTypes[patchI] = calculatedPointPatchVectorField::typeName;
1058 tmp<pointVectorField> tfld
1060 new pointVectorField
1064 "pointDisplacement",
1065 mesh.time().timeName(),
1068 IOobject::AUTO_WRITE
1071 dimensionedVector("displacement", dimLength, vector::zero),
1079 void Foam::meshRefinement::checkCoupledFaceZones(const polyMesh& mesh)
1081 const faceZoneMesh& fZones = mesh.faceZones();
1083 // Check any zones are present anywhere and in same order
1086 List<wordList> zoneNames(Pstream::nProcs());
1087 zoneNames[Pstream::myProcNo()] = fZones.names();
1088 Pstream::gatherList(zoneNames);
1089 Pstream::scatterList(zoneNames);
1090 // All have same data now. Check.
1091 forAll(zoneNames, procI)
1093 if (procI != Pstream::myProcNo())
1095 if (zoneNames[procI] != zoneNames[Pstream::myProcNo()])
1099 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1100 ) << "faceZones are not synchronised on processors." << nl
1101 << "Processor " << procI << " has faceZones "
1102 << zoneNames[procI] << nl
1103 << "Processor " << Pstream::myProcNo()
1104 << " has faceZones "
1105 << zoneNames[Pstream::myProcNo()] << nl
1106 << exit(FatalError);
1112 // Check that coupled faces are present on both sides.
1114 labelList faceToZone(mesh.nFaces()-mesh.nInternalFaces(), -1);
1116 forAll(fZones, zoneI)
1118 const faceZone& fZone = fZones[zoneI];
1122 label bFaceI = fZone[i]-mesh.nInternalFaces();
1126 if (faceToZone[bFaceI] == -1)
1128 faceToZone[bFaceI] = zoneI;
1130 else if (faceToZone[bFaceI] == zoneI)
1134 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1135 ) << "Face " << fZone[i] << " in zone "
1137 << " is twice in zone!"
1138 << abort(FatalError);
1144 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1145 ) << "Face " << fZone[i] << " in zone "
1147 << " is also in zone "
1148 << fZones[faceToZone[bFaceI]].name()
1149 << abort(FatalError);
1155 labelList neiFaceToZone(faceToZone);
1156 syncTools::swapBoundaryFaceList(mesh, neiFaceToZone, false);
1158 forAll(faceToZone, i)
1160 if (faceToZone[i] != neiFaceToZone[i])
1164 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1165 ) << "Face " << mesh.nInternalFaces()+i
1166 << " is in zone " << faceToZone[i]
1167 << ", its coupled face is in zone " << neiFaceToZone[i]
1168 << abort(FatalError);
1174 // Adds patch if not yet there. Returns patchID.
1175 Foam::label Foam::meshRefinement::addPatch
1178 const word& patchName,
1179 const word& patchType
1182 polyBoundaryMesh& polyPatches =
1183 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
1185 label patchI = polyPatches.findPatchID(patchName);
1188 if (polyPatches[patchI].type() == patchType)
1197 // "meshRefinement::addPatch(fvMesh&, const word&, const word&)"
1198 // ) << "Patch " << patchName << " already exists but with type "
1199 // << patchType << nl
1200 // << "Current patch names:" << polyPatches.names()
1201 // << exit(FatalError);
1206 label insertPatchI = polyPatches.size();
1207 label startFaceI = mesh.nFaces();
1209 forAll(polyPatches, patchI)
1211 const polyPatch& pp = polyPatches[patchI];
1213 if (isA<processorPolyPatch>(pp))
1215 insertPatchI = patchI;
1216 startFaceI = pp.start();
1222 // Below is all quite a hack. Feel free to change once there is a better
1223 // mechanism to insert and reorder patches.
1225 // Clear local fields and e.g. polyMesh parallelInfo.
1228 label sz = polyPatches.size();
1230 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
1232 // Add polyPatch at the end
1233 polyPatches.setSize(sz+1);
1247 fvPatches.setSize(sz+1);
1253 polyPatches[sz], // point to newly added polyPatch
1258 addPatchFields<volScalarField>
1261 calculatedFvPatchField<scalar>::typeName
1263 addPatchFields<volVectorField>
1266 calculatedFvPatchField<vector>::typeName
1268 addPatchFields<volSphericalTensorField>
1271 calculatedFvPatchField<sphericalTensor>::typeName
1273 addPatchFields<volSymmTensorField>
1276 calculatedFvPatchField<symmTensor>::typeName
1278 addPatchFields<volTensorField>
1281 calculatedFvPatchField<tensor>::typeName
1286 addPatchFields<surfaceScalarField>
1289 calculatedFvPatchField<scalar>::typeName
1291 addPatchFields<surfaceVectorField>
1294 calculatedFvPatchField<vector>::typeName
1296 addPatchFields<surfaceSphericalTensorField>
1299 calculatedFvPatchField<sphericalTensor>::typeName
1301 addPatchFields<surfaceSymmTensorField>
1304 calculatedFvPatchField<symmTensor>::typeName
1306 addPatchFields<surfaceTensorField>
1309 calculatedFvPatchField<tensor>::typeName
1312 // Create reordering list
1313 // patches before insert position stay as is
1314 labelList oldToNew(sz+1);
1315 for (label i = 0; i < insertPatchI; i++)
1319 // patches after insert position move one up
1320 for (label i = insertPatchI; i < sz; i++)
1324 // appended patch gets moved to insert position
1325 oldToNew[sz] = insertPatchI;
1327 // Shuffle into place
1328 polyPatches.reorder(oldToNew);
1329 fvPatches.reorder(oldToNew);
1331 reorderPatchFields<volScalarField>(mesh, oldToNew);
1332 reorderPatchFields<volVectorField>(mesh, oldToNew);
1333 reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
1334 reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
1335 reorderPatchFields<volTensorField>(mesh, oldToNew);
1336 reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
1337 reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
1338 reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
1339 reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
1340 reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
1342 return insertPatchI;
1346 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
1348 const point& keepPoint
1351 // Determine connected regions. regionSplit is the labelList with the
1353 regionSplit cellRegion(mesh_);
1357 label cellI = mesh_.findCell(keepPoint);
1361 regionI = cellRegion[cellI];
1364 reduce(regionI, maxOp<label>());
1370 "meshRefinement::splitMeshRegions(const point&)"
1371 ) << "Point " << keepPoint
1372 << " is not inside the mesh." << nl
1373 << "Bounding box of the mesh:" << mesh_.globalData().bb()
1374 << exit(FatalError);
1380 // Get cells to remove
1381 DynamicList<label> cellsToRemove(mesh_.nCells());
1382 forAll(cellRegion, cellI)
1384 if (cellRegion[cellI] != regionI)
1386 cellsToRemove.append(cellI);
1389 cellsToRemove.shrink();
1391 label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
1392 reduce(nCellsToKeep, sumOp<label>());
1394 Info<< "Keeping all cells in region " << regionI
1395 << " containing point " << keepPoint << endl
1396 << "Selected for keeping : "
1398 << " cells." << endl;
1402 removeCells cellRemover(mesh_);
1404 labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
1406 if (exposedFaces.size() > 0)
1410 "meshRefinement::splitMeshRegions(const point&)"
1411 ) << "Removing non-reachable cells should only expose boundary faces"
1413 << "ExposedFaces:" << exposedFaces << abort(FatalError);
1416 return doRemoveCells
1420 labelList(exposedFaces.size(),-1), // irrelevant since 0 size.
1426 void Foam::meshRefinement::distribute(const mapDistributePolyMesh& map)
1428 // mesh_ already distributed; distribute my member data
1430 // surfaceQueries_ ok.
1433 meshCutter_.distribute(map);
1435 // surfaceIndex is face data.
1436 map.distributeFaceData(surfaceIndex_);
1438 // maintainedFaces are indices of faces.
1439 forAll(userFaceData_, i)
1441 map.distributeFaceData(userFaceData_[i].second());
1446 void Foam::meshRefinement::updateMesh
1448 const mapPolyMesh& map,
1449 const labelList& changedFaces
1452 Map<label> dummyMap(0);
1454 updateMesh(map, changedFaces, dummyMap, dummyMap, dummyMap);
1458 void Foam::meshRefinement::storeData
1460 const labelList& pointsToStore,
1461 const labelList& facesToStore,
1462 const labelList& cellsToStore
1465 // For now only meshCutter has storable/retrievable data.
1466 meshCutter_.storeData
1475 void Foam::meshRefinement::updateMesh
1477 const mapPolyMesh& map,
1478 const labelList& changedFaces,
1479 const Map<label>& pointsToRestore,
1480 const Map<label>& facesToRestore,
1481 const Map<label>& cellsToRestore
1484 // For now only meshCutter has storable/retrievable data.
1486 // Update numbering of cells/vertices.
1487 meshCutter_.updateMesh
1495 // Update surfaceIndex
1496 updateList(map.faceMap(), -1, surfaceIndex_);
1498 // Update cached intersection information
1499 updateIntersections(changedFaces);
1501 // Update maintained faces
1502 forAll(userFaceData_, i)
1504 labelList& data = userFaceData_[i].second();
1506 if (userFaceData_[i].first() == KEEPALL)
1508 // extend list with face-from-face data
1509 updateList(map.faceMap(), -1, data);
1511 else if (userFaceData_[i].first() == MASTERONLY)
1514 labelList newFaceData(map.faceMap().size(), -1);
1516 forAll(newFaceData, faceI)
1518 label oldFaceI = map.faceMap()[faceI];
1520 if (oldFaceI >= 0 && map.reverseFaceMap()[oldFaceI] == faceI)
1522 newFaceData[faceI] = data[oldFaceI];
1525 data.transfer(newFaceData);
1529 // remove any face that has been refined i.e. referenced more than
1532 // 1. Determine all old faces that get referenced more than once.
1533 // These get marked with -1 in reverseFaceMap
1534 labelList reverseFaceMap(map.reverseFaceMap());
1536 forAll(map.faceMap(), faceI)
1538 label oldFaceI = map.faceMap()[faceI];
1542 if (reverseFaceMap[oldFaceI] != faceI)
1544 // faceI is slave face. Mark old face.
1545 reverseFaceMap[oldFaceI] = -1;
1550 // 2. Map only faces with intact reverseFaceMap
1551 labelList newFaceData(map.faceMap().size(), -1);
1552 forAll(newFaceData, faceI)
1554 label oldFaceI = map.faceMap()[faceI];
1558 if (reverseFaceMap[oldFaceI] == faceI)
1560 newFaceData[faceI] = data[oldFaceI];
1564 data.transfer(newFaceData);
1570 bool Foam::meshRefinement::write() const
1574 && meshCutter_.write()
1575 && surfaceIndex_.write();
1581 void Foam::meshRefinement::printMeshInfo(const bool debug, const string& msg)
1584 const globalMeshData& pData = mesh_.globalData();
1589 << " : cells(local):" << mesh_.nCells()
1590 << " faces(local):" << mesh_.nFaces()
1591 << " points(local):" << mesh_.nPoints()
1597 << " : cells:" << pData.nTotalCells()
1598 << " faces:" << pData.nTotalFaces()
1599 << " points:" << pData.nTotalPoints()
1606 const labelList& cellLevel = meshCutter_.cellLevel();
1608 labelList nCells(gMax(cellLevel)+1, 0);
1610 forAll(cellLevel, cellI)
1612 nCells[cellLevel[cellI]]++;
1615 Pstream::listCombineGather(nCells, plusEqOp<label>());
1616 Pstream::listCombineScatter(nCells);
1618 Info<< "Cells per refinement level:" << endl;
1619 forAll(nCells, levelI)
1621 Info<< " " << levelI << '\t' << nCells[levelI]
1628 void Foam::meshRefinement::dumpRefinementLevel() const
1630 volScalarField volRefLevel
1635 mesh_.time().timeName(),
1638 IOobject::AUTO_WRITE,
1642 dimensionedScalar("zero", dimless, 0)
1645 const labelList& cellLevel = meshCutter_.cellLevel();
1647 forAll(volRefLevel, cellI)
1649 volRefLevel[cellI] = cellLevel[cellI];
1652 volRefLevel.write();
1655 pointMesh pMesh(mesh_);
1657 pointScalarField pointRefLevel
1662 mesh_.time().timeName(),
1669 dimensionedScalar("zero", dimless, 0)
1672 const labelList& pointLevel = meshCutter_.pointLevel();
1674 forAll(pointRefLevel, pointI)
1676 pointRefLevel[pointI] = pointLevel[pointI];
1679 pointRefLevel.write();
1683 void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
1686 const pointField& cellCentres = mesh_.cellCentres();
1688 OFstream str(prefix + "_edges.obj");
1690 Pout<< "meshRefinement::dumpIntersections :"
1691 << " Writing cellcentre-cellcentre intersections to file "
1692 << str.name() << endl;
1695 // Redo all intersections
1696 // ~~~~~~~~~~~~~~~~~~~~~~
1698 // Get boundary face centre and level. Coupled aware.
1699 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1700 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
1701 calcNeighbourData(neiLevel, neiCc);
1703 labelList intersectionFaces(intersectedFaces());
1705 // Collect segments we want to test for
1706 pointField start(intersectionFaces.size());
1707 pointField end(intersectionFaces.size());
1709 forAll(intersectionFaces, i)
1711 label faceI = intersectionFaces[i];
1712 start[i] = cellCentres[mesh_.faceOwner()[faceI]];
1714 if (mesh_.isInternalFace(faceI))
1716 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
1720 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
1724 // Do tests in one go
1725 labelList surfaceHit;
1726 List<pointIndexHit> surfaceHitInfo;
1727 surfaces_.findAnyIntersection
1735 forAll(intersectionFaces, i)
1737 if (surfaceHit[i] != -1)
1739 meshTools::writeOBJ(str, start[i]);
1741 meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
1743 meshTools::writeOBJ(str, end[i]);
1745 str << "l " << vertI-2 << ' ' << vertI-1 << nl
1746 << "l " << vertI-1 << ' ' << vertI << nl;
1751 // Convert to vtk format
1754 "objToVTK " + prefix + "_edges.obj " + prefix + "_edges.vtk > /dev/null"
1756 system(cmd.c_str());
1762 void Foam::meshRefinement::write
1765 const fileName& prefix
1772 if (flag & SCALARLEVELS)
1774 dumpRefinementLevel();
1776 if (flag&OBJINTERSECTIONS && prefix.size()>0)
1778 dumpIntersections(prefix);
1783 // ************************************************************************* //