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 <autoMesh/meshRefinement.H>
28 #include <finiteVolume/volMesh.H>
29 #include <finiteVolume/volFields.H>
30 #include <finiteVolume/surfaceMesh.H>
31 #include <OpenFOAM/syncTools.H>
32 #include <OpenFOAM/Time.H>
33 #include <dynamicMesh/refinementHistory.H>
34 #include <autoMesh/refinementSurfaces.H>
35 #include <decompositionMethods/decompositionMethod.H>
36 #include <meshTools/regionSplit.H>
37 #include <dynamicMesh/fvMeshDistribute.H>
38 #include <OpenFOAM/indirectPrimitivePatch.H>
39 #include <dynamicMesh/polyTopoChange.H>
40 #include <dynamicMesh/removeCells.H>
41 #include <OpenFOAM/mapDistributePolyMesh.H>
42 #include <dynamicMesh/localPointRegion.H>
43 #include <OpenFOAM/pointMesh.H>
44 #include <OpenFOAM/pointFields.H>
45 #include <OpenFOAM/slipPointPatchFields.H>
46 #include <OpenFOAM/fixedValuePointPatchFields.H>
47 #include <OpenFOAM/globalPointPatchFields.H>
48 #include <OpenFOAM/calculatedPointPatchFields.H>
49 #include <OpenFOAM/processorPointPatch.H>
50 #include <OpenFOAM/globalIndex.H>
51 #include <meshTools/meshTools.H>
52 #include <OpenFOAM/OFstream.H>
53 #include <decompositionMethods/geomDecomp.H>
54 #include <OpenFOAM/Random.H>
55 #include <meshTools/searchableSurfaces.H>
56 #include <meshTools/treeBoundBox.H>
58 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
62 defineTypeNameAndDebug(meshRefinement, 0);
65 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
67 void Foam::meshRefinement::calcNeighbourData
73 const labelList& cellLevel = meshCutter_.cellLevel();
74 const pointField& cellCentres = mesh_.cellCentres();
76 label nBoundaryFaces = mesh_.nFaces() - mesh_.nInternalFaces();
78 if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
80 FatalErrorIn("meshRefinement::calcNeighbour(..)") << "nBoundaries:"
81 << nBoundaryFaces << " neiLevel:" << neiLevel.size()
85 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
87 forAll(patches, patchI)
89 const polyPatch& pp = patches[patchI];
91 const unallocLabelList& faceCells = pp.faceCells();
92 const vectorField::subField faceCentres = pp.faceCentres();
94 label bFaceI = pp.start()-mesh_.nInternalFaces();
100 neiLevel[bFaceI] = cellLevel[faceCells[i]];
101 neiCc[bFaceI] = cellCentres[faceCells[i]];
109 neiLevel[bFaceI] = cellLevel[faceCells[i]];
110 neiCc[bFaceI] = faceCentres[i];
116 // Swap coupled boundaries. Apply separation to cc since is coordinate.
117 syncTools::swapBoundaryFaceList(mesh_, neiCc, true);
118 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
122 // Find intersections of edges (given by their two endpoints) with surfaces.
123 // Returns first intersection if there are more than one.
124 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
126 const pointField& cellCentres = mesh_.cellCentres();
128 label nTotEdges = returnReduce(surfaceIndex_.size(), sumOp<label>());
129 label nChangedFaces = returnReduce(changedFaces.size(), sumOp<label>());
131 Info<< "Edge intersection testing:" << nl
132 << " Number of edges : " << nTotEdges << nl
133 << " Number of edges to retest : " << nChangedFaces
136 // Get boundary face centre and level. Coupled aware.
137 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
138 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
139 calcNeighbourData(neiLevel, neiCc);
141 // Collect segments we want to test for
142 pointField start(changedFaces.size());
143 pointField end(changedFaces.size());
145 forAll(changedFaces, i)
147 label faceI = changedFaces[i];
148 label own = mesh_.faceOwner()[faceI];
150 start[i] = cellCentres[own];
151 if (mesh_.isInternalFace(faceI))
153 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
157 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
161 // Do tests in one go
162 labelList surfaceHit;
164 labelList surfaceLevel;
165 surfaces_.findHigherIntersection
169 labelList(start.size(), -1), // accept any intersection
175 // Keep just surface hit
176 forAll(surfaceHit, i)
178 surfaceIndex_[changedFaces[i]] = surfaceHit[i];
181 // Make sure both sides have same information. This should be
182 // case in general since same vectors but just to make sure.
183 syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>(), false);
185 label nHits = countHits();
186 label nTotHits = returnReduce(nHits, sumOp<label>());
188 Info<< " Number of intersected edges : " << nTotHits << endl;
190 // Set files to same time as mesh
191 setInstance(mesh_.facesInstance());
195 void Foam::meshRefinement::checkData()
197 Pout<< "meshRefinement::checkData() : Checking refinement structure."
199 meshCutter_.checkMesh();
201 Pout<< "meshRefinement::checkData() : Checking refinement levels."
203 meshCutter_.checkRefinementLevels(1, labelList(0));
206 Pout<< "meshRefinement::checkData() : Checking synchronization."
209 // Check face centres
211 // Boundary face centres
212 pointField::subList boundaryFc
215 mesh_.nFaces()-mesh_.nInternalFaces(),
216 mesh_.nInternalFaces()
219 // Get neighbouring face centres
220 pointField neiBoundaryFc(boundaryFc);
221 syncTools::swapBoundaryFaceList
229 testSyncBoundaryFaceList
232 "testing faceCentres : ",
237 // Check meshRefinement
239 // Get boundary face centre and level. Coupled aware.
240 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
241 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
242 calcNeighbourData(neiLevel, neiCc);
244 // Collect segments we want to test for
245 pointField start(mesh_.nFaces());
246 pointField end(mesh_.nFaces());
250 start[faceI] = mesh_.cellCentres()[mesh_.faceOwner()[faceI]];
252 if (mesh_.isInternalFace(faceI))
254 end[faceI] = mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]];
258 end[faceI] = neiCc[faceI-mesh_.nInternalFaces()];
262 // Do tests in one go
263 labelList surfaceHit;
265 labelList surfaceLevel;
266 surfaces_.findHigherIntersection
270 labelList(start.size(), -1), // accept any intersection
277 forAll(surfaceHit, faceI)
279 if (surfaceHit[faceI] != surfaceIndex_[faceI])
281 if (mesh_.isInternalFace(faceI))
283 WarningIn("meshRefinement::checkData()")
284 << "Internal face:" << faceI
285 << " fc:" << mesh_.faceCentres()[faceI]
286 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
287 << " current:" << surfaceHit[faceI]
289 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
291 << mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]]
296 WarningIn("meshRefinement::checkData()")
297 << "Boundary face:" << faceI
298 << " fc:" << mesh_.faceCentres()[faceI]
299 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
300 << " current:" << surfaceHit[faceI]
302 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
309 labelList::subList boundarySurface
312 mesh_.nFaces()-mesh_.nInternalFaces(),
313 mesh_.nInternalFaces()
316 labelList neiBoundarySurface(boundarySurface);
317 syncTools::swapBoundaryFaceList
325 testSyncBoundaryFaceList
328 "testing surfaceIndex() : ",
335 // Find duplicate faces
336 Pout<< "meshRefinement::checkData() : Counting duplicate faces."
339 labelList duplicateFace
341 localPointRegion::findDuplicateFaces
344 identity(mesh_.nFaces()-mesh_.nInternalFaces())
345 + mesh_.nInternalFaces()
353 forAll(duplicateFace, i)
355 if (duplicateFace[i] != -1)
360 nDup /= 2; // will have counted both faces of duplicate
361 Pout<< "meshRefinement::checkData() : Found " << nDup
362 << " duplicate pairs of faces." << endl;
367 void Foam::meshRefinement::setInstance(const fileName& inst)
369 meshCutter_.setInstance(inst);
370 surfaceIndex_.instance() = inst;
374 // Remove cells. Put exposedFaces (output of getExposedFaces(cellsToRemove))
375 // into exposedPatchIDs.
376 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells
378 const labelList& cellsToRemove,
379 const labelList& exposedFaces,
380 const labelList& exposedPatchIDs,
381 removeCells& cellRemover
384 polyTopoChange meshMod(mesh_);
386 // Arbitrary: put exposed faces into last patch.
387 cellRemover.setRefinement
395 // Change the mesh (no inflation)
396 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
399 mesh_.updateMesh(map);
401 // Move mesh (since morphing might not do this)
402 if (map().hasMotionPoints())
404 mesh_.movePoints(map().preMotionPoints());
408 // Delete mesh volumes. No other way to do this?
412 // Update local mesh data
413 cellRemover.updateMesh(map);
415 // Update intersections. Recalculate intersections for exposed faces.
416 labelList newExposedFaces = renumber
418 map().reverseFaceMap(),
422 //Pout<< "removeCells : updating intersections for "
423 // << newExposedFaces.size() << " newly exposed faces." << endl;
425 updateMesh(map, newExposedFaces);
431 // Determine for multi-processor regions the lowest numbered cell on the lowest
432 // numbered processor.
433 void Foam::meshRefinement::getRegionMaster
435 const boolList& blockedFace,
436 const regionSplit& globalRegion,
437 Map<label>& regionToMaster
440 globalIndex globalCells(mesh_.nCells());
442 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
444 forAll(patches, patchI)
446 const polyPatch& pp = patches[patchI];
448 if (isA<processorPolyPatch>(pp))
452 label faceI = pp.start()+i;
454 if (!blockedFace[faceI])
456 // Only if there is a connection to the neighbour
457 // will there be a multi-domain region; if not through
458 // this face then through another.
460 label cellI = mesh_.faceOwner()[faceI];
461 label globalCellI = globalCells.toGlobal(cellI);
463 Map<label>::iterator iter =
464 regionToMaster.find(globalRegion[cellI]);
466 if (iter != regionToMaster.end())
468 label master = iter();
469 iter() = min(master, globalCellI);
473 regionToMaster.insert
485 Pstream::mapCombineGather(regionToMaster, minEqOp<label>());
486 Pstream::mapCombineScatter(regionToMaster);
490 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
492 // Construct from components
493 Foam::meshRefinement::meshRefinement
496 const scalar mergeDistance,
497 const refinementSurfaces& surfaces,
498 const shellSurfaces& shells
502 mergeDistance_(mergeDistance),
513 mesh_.facesInstance(),
516 IOobject::READ_IF_PRESENT,
520 labelList(mesh_.nCells(), 0)
527 mesh_.facesInstance(),
530 IOobject::READ_IF_PRESENT,
534 labelList(mesh_.nPoints(), 0)
541 mesh_.facesInstance(),
548 List<refinementHistory::splitCell8>(0),
557 mesh_.facesInstance(),
564 labelList(mesh_.nFaces(), -1)
568 // recalculate intersections for all faces
569 updateIntersections(identity(mesh_.nFaces()));
573 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
575 Foam::label Foam::meshRefinement::countHits() const
579 forAll(surfaceIndex_, faceI)
581 if (surfaceIndex_[faceI] >= 0)
590 // Determine distribution to move connected regions onto one processor.
591 Foam::labelList Foam::meshRefinement::decomposeCombineRegions
593 const boolList& blockedFace,
594 const List<labelPair>& explicitConnections,
595 decompositionMethod& decomposer
598 // Determine global regions, separated by blockedFaces
599 regionSplit globalRegion(mesh_, blockedFace, explicitConnections);
601 // Now globalRegion has global region per cell. Problem is that
602 // the region might span multiple domains so we want to get
603 // a "region master" per domain. Note that multi-processor
604 // regions can only occur on cells on coupled patches.
607 // Determine per coupled region the master cell (lowest numbered cell
608 // on lowest numbered processor)
609 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
611 Map<label> regionToMaster(mesh_.nFaces()-mesh_.nInternalFaces());
612 getRegionMaster(blockedFace, globalRegion, regionToMaster);
615 // Global cell numbering engine
616 globalIndex globalCells(mesh_.nCells());
619 // Determine cell centre per region
620 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
621 // Now we can divide regions into
622 // - single-processor regions (almost all)
623 // - allocate local region + coordinate for it
624 // - multi-processor for which I am master
625 // - allocate local region + coordinate for it
626 // - multi-processor for which I am not master
627 // - do not allocate region.
628 // - but inherit new distribution from master.
630 Map<label> globalToLocalRegion(mesh_.nCells());
631 DynamicList<point> localCc(mesh_.nCells()/10);
633 forAll(globalRegion, cellI)
635 Map<label>::const_iterator fndMaster =
636 regionToMaster.find(globalRegion[cellI]);
638 if (fndMaster != regionToMaster.end())
640 // Multi-processor region.
641 if (globalCells.toGlobal(cellI) == fndMaster())
643 // I am master. Allocate region for me.
644 globalToLocalRegion.insert(globalRegion[cellI], localCc.size());
645 localCc.append(mesh_.cellCentres()[cellI]);
650 // Single processor region.
651 Map<label>::iterator iter =
652 globalToLocalRegion.find(globalRegion[cellI]);
654 if (iter == globalToLocalRegion.end())
656 globalToLocalRegion.insert(globalRegion[cellI], localCc.size());
657 localCc.append(mesh_.cellCentres()[cellI]);
662 pointField localPoints;
663 localPoints.transfer(localCc);
666 // Call decomposer on localCc
667 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
669 labelList localDistribution = decomposer.decompose(localPoints);
672 // Distribute the destination processor for coupled regions
673 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
675 Map<label> regionToDist(regionToMaster.size());
677 forAllConstIter(Map<label>, regionToMaster, iter)
679 if (globalCells.isLocal(iter()))
681 // Master cell is local.
685 localDistribution[globalToLocalRegion[iter.key()]]
690 // Master cell is not on this processor. Make sure it is overridden.
691 regionToDist.insert(iter.key(), labelMax);
694 Pstream::mapCombineGather(regionToDist, minEqOp<label>());
695 Pstream::mapCombineScatter(regionToDist);
698 // Convert region-based decomposition back to cell-based one
699 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
701 labelList distribution(mesh_.nCells());
703 forAll(globalRegion, cellI)
705 Map<label>::const_iterator fndMaster =
706 regionToDist.find(globalRegion[cellI]);
708 if (fndMaster != regionToDist.end())
711 distribution[cellI] = fndMaster();
715 // region is local to the processor.
716 label localRegionI = globalToLocalRegion[globalRegion[cellI]];
718 distribution[cellI] = localDistribution[localRegionI];
725 Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance
727 const bool keepZoneFaces,
728 const bool keepBaffles,
729 decompositionMethod& decomposer,
730 fvMeshDistribute& distributor
733 autoPtr<mapDistributePolyMesh> map;
735 if (Pstream::parRun())
739 // const_cast<Time&>(mesh_.time())++;
742 // Wanted distribution
743 labelList distribution;
745 if (keepZoneFaces || keepBaffles)
747 // Faces where owner and neighbour are not 'connected' so can
748 // go to different processors.
749 boolList blockedFace(mesh_.nFaces(), true);
751 List<labelPair> couples;
755 label nNamed = surfaces().getNamedSurfaces().size();
757 Info<< "Found " << nNamed << " surfaces with faceZones."
758 << " Applying special decomposition to keep those together."
761 // Determine decomposition to keep/move surface zones
762 // on one processor. The reason is that snapping will make these
763 // into baffles, move and convert them back so if they were
764 // proc boundaries after baffling&moving the points might be no
765 // longer snychronised so recoupling will fail. To prevent this
766 // keep owner&neighbour of such a surface zone on the same
769 const wordList& fzNames = surfaces().faceZoneNames();
770 const faceZoneMesh& fZones = mesh_.faceZones();
772 // Get faces whose owner and neighbour should stay together,
773 // i.e. they are not 'blocked'.
777 forAll(fzNames, surfI)
779 if (fzNames[surfI].size() > 0)
782 label zoneI = fZones.findZoneID(fzNames[surfI]);
784 const faceZone& fZone = fZones[zoneI];
788 if (blockedFace[fZone[i]])
790 blockedFace[fZone[i]] = false;
796 Info<< "Found " << returnReduce(nZoned, sumOp<label>())
797 << " zoned faces to keep together."
803 // Get boundary baffles that need to stay together.
804 couples = getDuplicateFaces // all baffles
806 identity(mesh_.nFaces()-mesh_.nInternalFaces())
807 +mesh_.nInternalFaces()
810 Info<< "Found " << returnReduce(couples.size(), sumOp<label>())
811 << " baffles to keep together."
815 distribution = decomposeCombineRegions
822 labelList nProcCells(distributor.countCells(distribution));
823 Pstream::listCombineGather(nProcCells, plusEqOp<label>());
824 Pstream::listCombineScatter(nProcCells);
826 Info<< "Calculated decomposition:" << endl;
827 forAll(nProcCells, procI)
829 Info<< " " << procI << '\t' << nProcCells[procI] << endl;
835 // Normal decomposition
836 distribution = decomposer.decompose(mesh_.cellCentres());
841 Pout<< "Wanted distribution:"
842 << distributor.countCells(distribution)
845 // Do actual sending/receiving of mesh
846 map = distributor.distribute(distribution);
848 // Update numbering of meshRefiner
855 // Helper function to get intersected faces
856 Foam::labelList Foam::meshRefinement::intersectedFaces() const
858 // Mark all faces that will become baffles
860 label nBoundaryFaces = 0;
862 forAll(surfaceIndex_, faceI)
864 if (surfaceIndex_[faceI] != -1)
870 labelList surfaceFaces(nBoundaryFaces);
873 forAll(surfaceIndex_, faceI)
875 if (surfaceIndex_[faceI] != -1)
877 surfaceFaces[nBoundaryFaces++] = faceI;
884 // Helper function to get points used by faces
885 Foam::labelList Foam::meshRefinement::intersectedPoints
887 // const labelList& globalToPatch
890 const faceList& faces = mesh_.faces();
892 // Mark all points on faces that will become baffles
893 PackedList<1> isBoundaryPoint(mesh_.nPoints(), 0u);
894 label nBoundaryPoints = 0;
896 forAll(surfaceIndex_, faceI)
898 if (surfaceIndex_[faceI] != -1)
900 const face& f = faces[faceI];
904 if (isBoundaryPoint.set(f[fp], 1u))
912 //// Insert all meshed patches.
913 //forAll(globalToPatch, i)
915 // label patchI = globalToPatch[i];
919 // const polyPatch& pp = mesh_.boundaryMesh()[patchI];
921 // label faceI = pp.start();
925 // const face& f = faces[faceI];
929 // if (isBoundaryPoint.set(f[fp], 1u))
930 // nBoundaryPoints++;
940 labelList boundaryPoints(nBoundaryPoints);
942 forAll(isBoundaryPoint, pointI)
944 if (isBoundaryPoint.get(pointI) == 1u)
946 boundaryPoints[nBoundaryPoints++] = pointI;
950 return boundaryPoints;
954 Foam::labelList Foam::meshRefinement::addedPatches
956 const labelList& globalToPatch
959 labelList patchIDs(globalToPatch.size());
962 forAll(globalToPatch, i)
964 if (globalToPatch[i] != -1)
966 patchIDs[addedI++] = globalToPatch[i];
969 patchIDs.setSize(addedI);
975 //- Create patch from set of patches
976 Foam::autoPtr<Foam::indirectPrimitivePatch> Foam::meshRefinement::makePatch
978 const polyMesh& mesh,
979 const labelList& patchIDs
982 const polyBoundaryMesh& patches = mesh.boundaryMesh();
989 const polyPatch& pp = patches[patchIDs[i]];
995 labelList addressing(nFaces);
1000 const polyPatch& pp = patches[patchIDs[i]];
1002 label meshFaceI = pp.start();
1006 addressing[nFaces++] = meshFaceI++;
1010 return autoPtr<indirectPrimitivePatch>
1012 new indirectPrimitivePatch
1014 IndirectList<face>(mesh.faces(), addressing),
1021 // Construct pointVectorField with correct boundary conditions
1022 Foam::tmp<Foam::pointVectorField> Foam::meshRefinement::makeDisplacementField
1024 const pointMesh& pMesh,
1025 const labelList& adaptPatchIDs
1028 const polyMesh& mesh = pMesh();
1030 // Construct displacement field.
1031 const pointBoundaryMesh& pointPatches = pMesh.boundary();
1033 wordList patchFieldTypes
1035 pointPatches.size(),
1036 slipPointPatchVectorField::typeName
1039 forAll(adaptPatchIDs, i)
1041 patchFieldTypes[adaptPatchIDs[i]] =
1042 fixedValuePointPatchVectorField::typeName;
1045 forAll(pointPatches, patchI)
1047 if (isA<globalPointPatch>(pointPatches[patchI]))
1049 patchFieldTypes[patchI] = globalPointPatchVectorField::typeName;
1051 else if (isA<processorPointPatch>(pointPatches[patchI]))
1053 patchFieldTypes[patchI] = calculatedPointPatchVectorField::typeName;
1057 tmp<pointVectorField> tfld
1059 new pointVectorField
1063 "pointDisplacement",
1064 mesh.time().timeName(),
1067 IOobject::AUTO_WRITE
1070 dimensionedVector("displacement", dimLength, vector::zero),
1078 void Foam::meshRefinement::checkCoupledFaceZones(const polyMesh& mesh)
1080 const faceZoneMesh& fZones = mesh.faceZones();
1082 // Check any zones are present anywhere and in same order
1085 List<wordList> zoneNames(Pstream::nProcs());
1086 zoneNames[Pstream::myProcNo()] = fZones.names();
1087 Pstream::gatherList(zoneNames);
1088 Pstream::scatterList(zoneNames);
1089 // All have same data now. Check.
1090 forAll(zoneNames, procI)
1092 if (procI != Pstream::myProcNo())
1094 if (zoneNames[procI] != zoneNames[Pstream::myProcNo()])
1098 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1099 ) << "faceZones are not synchronised on processors." << nl
1100 << "Processor " << procI << " has faceZones "
1101 << zoneNames[procI] << nl
1102 << "Processor " << Pstream::myProcNo()
1103 << " has faceZones "
1104 << zoneNames[Pstream::myProcNo()] << nl
1105 << exit(FatalError);
1111 // Check that coupled faces are present on both sides.
1113 labelList faceToZone(mesh.nFaces()-mesh.nInternalFaces(), -1);
1115 forAll(fZones, zoneI)
1117 const faceZone& fZone = fZones[zoneI];
1121 label bFaceI = fZone[i]-mesh.nInternalFaces();
1125 if (faceToZone[bFaceI] == -1)
1127 faceToZone[bFaceI] = zoneI;
1129 else if (faceToZone[bFaceI] == zoneI)
1133 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1134 ) << "Face " << fZone[i] << " in zone "
1136 << " is twice in zone!"
1137 << abort(FatalError);
1143 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1144 ) << "Face " << fZone[i] << " in zone "
1146 << " is also in zone "
1147 << fZones[faceToZone[bFaceI]].name()
1148 << abort(FatalError);
1154 labelList neiFaceToZone(faceToZone);
1155 syncTools::swapBoundaryFaceList(mesh, neiFaceToZone, false);
1157 forAll(faceToZone, i)
1159 if (faceToZone[i] != neiFaceToZone[i])
1163 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1164 ) << "Face " << mesh.nInternalFaces()+i
1165 << " is in zone " << faceToZone[i]
1166 << ", its coupled face is in zone " << neiFaceToZone[i]
1167 << abort(FatalError);
1173 // Adds patch if not yet there. Returns patchID.
1174 Foam::label Foam::meshRefinement::addPatch
1177 const word& patchName,
1178 const word& patchType
1181 polyBoundaryMesh& polyPatches =
1182 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
1184 label patchI = polyPatches.findPatchID(patchName);
1187 if (polyPatches[patchI].type() == patchType)
1196 // "meshRefinement::addPatch(fvMesh&, const word&, const word&)"
1197 // ) << "Patch " << patchName << " already exists but with type "
1198 // << patchType << nl
1199 // << "Current patch names:" << polyPatches.names()
1200 // << exit(FatalError);
1205 label insertPatchI = polyPatches.size();
1206 label startFaceI = mesh.nFaces();
1208 forAll(polyPatches, patchI)
1210 const polyPatch& pp = polyPatches[patchI];
1212 if (isA<processorPolyPatch>(pp))
1214 insertPatchI = patchI;
1215 startFaceI = pp.start();
1221 // Below is all quite a hack. Feel free to change once there is a better
1222 // mechanism to insert and reorder patches.
1224 // Clear local fields and e.g. polyMesh parallelInfo.
1227 label sz = polyPatches.size();
1229 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
1231 // Add polyPatch at the end
1232 polyPatches.setSize(sz+1);
1246 fvPatches.setSize(sz+1);
1252 polyPatches[sz], // point to newly added polyPatch
1257 addPatchFields<volScalarField>
1260 calculatedFvPatchField<scalar>::typeName
1262 addPatchFields<volVectorField>
1265 calculatedFvPatchField<vector>::typeName
1267 addPatchFields<volSphericalTensorField>
1270 calculatedFvPatchField<sphericalTensor>::typeName
1272 addPatchFields<volSymmTensorField>
1275 calculatedFvPatchField<symmTensor>::typeName
1277 addPatchFields<volTensorField>
1280 calculatedFvPatchField<tensor>::typeName
1285 addPatchFields<surfaceScalarField>
1288 calculatedFvPatchField<scalar>::typeName
1290 addPatchFields<surfaceVectorField>
1293 calculatedFvPatchField<vector>::typeName
1295 addPatchFields<surfaceSphericalTensorField>
1298 calculatedFvPatchField<sphericalTensor>::typeName
1300 addPatchFields<surfaceSymmTensorField>
1303 calculatedFvPatchField<symmTensor>::typeName
1305 addPatchFields<surfaceTensorField>
1308 calculatedFvPatchField<tensor>::typeName
1311 // Create reordering list
1312 // patches before insert position stay as is
1313 labelList oldToNew(sz+1);
1314 for (label i = 0; i < insertPatchI; i++)
1318 // patches after insert position move one up
1319 for (label i = insertPatchI; i < sz; i++)
1323 // appended patch gets moved to insert position
1324 oldToNew[sz] = insertPatchI;
1326 // Shuffle into place
1327 polyPatches.reorder(oldToNew);
1328 fvPatches.reorder(oldToNew);
1330 reorderPatchFields<volScalarField>(mesh, oldToNew);
1331 reorderPatchFields<volVectorField>(mesh, oldToNew);
1332 reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
1333 reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
1334 reorderPatchFields<volTensorField>(mesh, oldToNew);
1335 reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
1336 reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
1337 reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
1338 reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
1339 reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
1341 return insertPatchI;
1345 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
1347 const point& keepPoint
1350 // Determine connected regions. regionSplit is the labelList with the
1352 regionSplit cellRegion(mesh_);
1356 label cellI = mesh_.findCell(keepPoint);
1360 regionI = cellRegion[cellI];
1363 reduce(regionI, maxOp<label>());
1369 "meshRefinement::splitMeshRegions(const point&)"
1370 ) << "Point " << keepPoint
1371 << " is not inside the mesh." << nl
1372 << "Bounding box of the mesh:" << mesh_.globalData().bb()
1373 << exit(FatalError);
1379 // Get cells to remove
1380 DynamicList<label> cellsToRemove(mesh_.nCells());
1381 forAll(cellRegion, cellI)
1383 if (cellRegion[cellI] != regionI)
1385 cellsToRemove.append(cellI);
1388 cellsToRemove.shrink();
1390 label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
1391 reduce(nCellsToKeep, sumOp<label>());
1393 Info<< "Keeping all cells in region " << regionI
1394 << " containing point " << keepPoint << endl
1395 << "Selected for keeping : "
1397 << " cells." << endl;
1401 removeCells cellRemover(mesh_);
1403 labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
1405 if (exposedFaces.size() > 0)
1409 "meshRefinement::splitMeshRegions(const point&)"
1410 ) << "Removing non-reachable cells should only expose boundary faces"
1412 << "ExposedFaces:" << exposedFaces << abort(FatalError);
1415 return doRemoveCells
1419 labelList(exposedFaces.size(),-1), // irrelevant since 0 size.
1425 void Foam::meshRefinement::distribute(const mapDistributePolyMesh& map)
1427 // mesh_ already distributed; distribute my member data
1429 // surfaceQueries_ ok.
1432 meshCutter_.distribute(map);
1434 // surfaceIndex is face data.
1435 map.distributeFaceData(surfaceIndex_);
1437 // maintainedFaces are indices of faces.
1438 forAll(userFaceData_, i)
1440 map.distributeFaceData(userFaceData_[i].second());
1445 void Foam::meshRefinement::updateMesh
1447 const mapPolyMesh& map,
1448 const labelList& changedFaces
1451 Map<label> dummyMap(0);
1453 updateMesh(map, changedFaces, dummyMap, dummyMap, dummyMap);
1457 void Foam::meshRefinement::storeData
1459 const labelList& pointsToStore,
1460 const labelList& facesToStore,
1461 const labelList& cellsToStore
1464 // For now only meshCutter has storable/retrievable data.
1465 meshCutter_.storeData
1474 void Foam::meshRefinement::updateMesh
1476 const mapPolyMesh& map,
1477 const labelList& changedFaces,
1478 const Map<label>& pointsToRestore,
1479 const Map<label>& facesToRestore,
1480 const Map<label>& cellsToRestore
1483 // For now only meshCutter has storable/retrievable data.
1485 // Update numbering of cells/vertices.
1486 meshCutter_.updateMesh
1494 // Update surfaceIndex
1495 updateList(map.faceMap(), -1, surfaceIndex_);
1497 // Update cached intersection information
1498 updateIntersections(changedFaces);
1500 // Update maintained faces
1501 forAll(userFaceData_, i)
1503 labelList& data = userFaceData_[i].second();
1505 if (userFaceData_[i].first() == KEEPALL)
1507 // extend list with face-from-face data
1508 updateList(map.faceMap(), -1, data);
1510 else if (userFaceData_[i].first() == MASTERONLY)
1513 labelList newFaceData(map.faceMap().size(), -1);
1515 forAll(newFaceData, faceI)
1517 label oldFaceI = map.faceMap()[faceI];
1519 if (oldFaceI >= 0 && map.reverseFaceMap()[oldFaceI] == faceI)
1521 newFaceData[faceI] = data[oldFaceI];
1524 data.transfer(newFaceData);
1528 // remove any face that has been refined i.e. referenced more than
1531 // 1. Determine all old faces that get referenced more than once.
1532 // These get marked with -1 in reverseFaceMap
1533 labelList reverseFaceMap(map.reverseFaceMap());
1535 forAll(map.faceMap(), faceI)
1537 label oldFaceI = map.faceMap()[faceI];
1541 if (reverseFaceMap[oldFaceI] != faceI)
1543 // faceI is slave face. Mark old face.
1544 reverseFaceMap[oldFaceI] = -1;
1549 // 2. Map only faces with intact reverseFaceMap
1550 labelList newFaceData(map.faceMap().size(), -1);
1551 forAll(newFaceData, faceI)
1553 label oldFaceI = map.faceMap()[faceI];
1557 if (reverseFaceMap[oldFaceI] == faceI)
1559 newFaceData[faceI] = data[oldFaceI];
1563 data.transfer(newFaceData);
1569 bool Foam::meshRefinement::write() const
1573 && meshCutter_.write()
1574 && surfaceIndex_.write();
1580 void Foam::meshRefinement::printMeshInfo(const bool debug, const string& msg)
1583 const globalMeshData& pData = mesh_.globalData();
1588 << " : cells(local):" << mesh_.nCells()
1589 << " faces(local):" << mesh_.nFaces()
1590 << " points(local):" << mesh_.nPoints()
1596 << " : cells:" << pData.nTotalCells()
1597 << " faces:" << pData.nTotalFaces()
1598 << " points:" << pData.nTotalPoints()
1605 const labelList& cellLevel = meshCutter_.cellLevel();
1607 labelList nCells(gMax(cellLevel)+1, 0);
1609 forAll(cellLevel, cellI)
1611 nCells[cellLevel[cellI]]++;
1614 Pstream::listCombineGather(nCells, plusEqOp<label>());
1615 Pstream::listCombineScatter(nCells);
1617 Info<< "Cells per refinement level:" << endl;
1618 forAll(nCells, levelI)
1620 Info<< " " << levelI << '\t' << nCells[levelI]
1627 void Foam::meshRefinement::dumpRefinementLevel() const
1629 volScalarField volRefLevel
1634 mesh_.time().timeName(),
1637 IOobject::AUTO_WRITE,
1641 dimensionedScalar("zero", dimless, 0)
1644 const labelList& cellLevel = meshCutter_.cellLevel();
1646 forAll(volRefLevel, cellI)
1648 volRefLevel[cellI] = cellLevel[cellI];
1651 volRefLevel.write();
1654 pointMesh pMesh(mesh_);
1656 pointScalarField pointRefLevel
1661 mesh_.time().timeName(),
1668 dimensionedScalar("zero", dimless, 0)
1671 const labelList& pointLevel = meshCutter_.pointLevel();
1673 forAll(pointRefLevel, pointI)
1675 pointRefLevel[pointI] = pointLevel[pointI];
1678 pointRefLevel.write();
1682 void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
1685 const pointField& cellCentres = mesh_.cellCentres();
1687 OFstream str(prefix + "_edges.obj");
1689 Pout<< "meshRefinement::dumpIntersections :"
1690 << " Writing cellcentre-cellcentre intersections to file "
1691 << str.name() << endl;
1694 // Redo all intersections
1695 // ~~~~~~~~~~~~~~~~~~~~~~
1697 // Get boundary face centre and level. Coupled aware.
1698 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1699 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
1700 calcNeighbourData(neiLevel, neiCc);
1702 labelList intersectionFaces(intersectedFaces());
1704 // Collect segments we want to test for
1705 pointField start(intersectionFaces.size());
1706 pointField end(intersectionFaces.size());
1708 forAll(intersectionFaces, i)
1710 label faceI = intersectionFaces[i];
1711 start[i] = cellCentres[mesh_.faceOwner()[faceI]];
1713 if (mesh_.isInternalFace(faceI))
1715 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
1719 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
1723 // Do tests in one go
1724 labelList surfaceHit;
1725 List<pointIndexHit> surfaceHitInfo;
1726 surfaces_.findAnyIntersection
1734 forAll(intersectionFaces, i)
1736 if (surfaceHit[i] != -1)
1738 meshTools::writeOBJ(str, start[i]);
1740 meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
1742 meshTools::writeOBJ(str, end[i]);
1744 str << "l " << vertI-2 << ' ' << vertI-1 << nl
1745 << "l " << vertI-1 << ' ' << vertI << nl;
1750 // Convert to vtk format
1753 "objToVTK " + prefix + "_edges.obj " + prefix + "_edges.vtk > /dev/null"
1755 system(cmd.c_str());
1761 void Foam::meshRefinement::write
1764 const fileName& prefix
1771 if (flag & SCALARLEVELS)
1773 dumpRefinementLevel();
1775 if (flag&OBJINTERSECTIONS && prefix.size()>0)
1777 dumpIntersections(prefix);
1782 // ************************ vim: set sw=4 sts=4 et: ************************ //