1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
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
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"
28 #include "volFields.H"
29 #include "surfaceMesh.H"
30 #include "syncTools.H"
32 #include "refinementHistory.H"
33 #include "refinementSurfaces.H"
34 #include "refinementFeatures.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 "calculatedPointPatchFields.H"
48 #include "cyclicSlipPointPatchFields.H"
49 #include "processorPointPatch.H"
50 #include "globalIndex.H"
51 #include "meshTools.H"
53 #include "geomDecomp.H"
55 #include "searchableSurfaces.H"
56 #include "treeBoundBox.H"
57 #include "zeroGradientFvPatchFields.H"
59 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
63 defineTypeNameAndDebug(meshRefinement, 0);
66 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
68 void Foam::meshRefinement::calcNeighbourData
74 const labelList& cellLevel = meshCutter_.cellLevel();
75 const pointField& cellCentres = mesh_.cellCentres();
77 label nBoundaryFaces = mesh_.nFaces() - mesh_.nInternalFaces();
79 if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
81 FatalErrorIn("meshRefinement::calcNeighbour(..)") << "nBoundaries:"
82 << nBoundaryFaces << " neiLevel:" << neiLevel.size()
86 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
88 labelHashSet addedPatchIDSet(meshedPatches());
90 forAll(patches, patchI)
92 const polyPatch& pp = patches[patchI];
94 const labelUList& faceCells = pp.faceCells();
95 const vectorField::subField faceCentres = pp.faceCentres();
96 const vectorField::subField faceAreas = pp.faceAreas();
98 label bFaceI = pp.start()-mesh_.nInternalFaces();
104 neiLevel[bFaceI] = cellLevel[faceCells[i]];
105 neiCc[bFaceI] = cellCentres[faceCells[i]];
109 else if (addedPatchIDSet.found(patchI))
111 // Face was introduced from cell-cell intersection. Try to
112 // reconstruct other side cell(centre). Three possibilities:
113 // - cells same size.
114 // - preserved cell smaller. Not handled.
115 // - preserved cell larger.
118 // Extrapolate the face centre.
119 vector fn = faceAreas[i];
120 fn /= mag(fn)+VSMALL;
122 label own = faceCells[i];
123 label ownLevel = cellLevel[own];
124 label faceLevel = meshCutter_.getAnchorLevel(pp.start()+i);
126 // Normal distance from face centre to cell centre
127 scalar d = ((faceCentres[i] - cellCentres[own]) & fn);
128 if (faceLevel > ownLevel)
130 // Other cell more refined. Adjust normal distance
133 neiLevel[bFaceI] = cellLevel[ownLevel];
134 // Calculate other cell centre by extrapolation
135 neiCc[bFaceI] = faceCentres[i] + d*fn;
143 neiLevel[bFaceI] = cellLevel[faceCells[i]];
144 neiCc[bFaceI] = faceCentres[i];
150 // Swap coupled boundaries. Apply separation to cc since is coordinate.
151 syncTools::swapBoundaryFacePositions(mesh_, neiCc);
152 syncTools::swapBoundaryFaceList(mesh_, neiLevel);
156 // Find intersections of edges (given by their two endpoints) with surfaces.
157 // Returns first intersection if there are more than one.
158 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
160 const pointField& cellCentres = mesh_.cellCentres();
162 // Stats on edges to test. Count proc faces only once.
163 PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
166 label nMasterFaces = 0;
167 forAll(isMasterFace, faceI)
169 if (isMasterFace.get(faceI) == 1)
174 reduce(nMasterFaces, sumOp<label>());
176 label nChangedFaces = 0;
177 forAll(changedFaces, i)
179 if (isMasterFace.get(changedFaces[i]) == 1)
184 reduce(nChangedFaces, sumOp<label>());
186 Info<< "Edge intersection testing:" << nl
187 << " Number of edges : " << nMasterFaces << nl
188 << " Number of edges to retest : " << nChangedFaces
193 // Get boundary face centre and level. Coupled aware.
194 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
195 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
196 calcNeighbourData(neiLevel, neiCc);
198 // Collect segments we want to test for
199 pointField start(changedFaces.size());
200 pointField end(changedFaces.size());
202 forAll(changedFaces, i)
204 label faceI = changedFaces[i];
205 label own = mesh_.faceOwner()[faceI];
207 start[i] = cellCentres[own];
208 if (mesh_.isInternalFace(faceI))
210 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
214 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
218 // Extend segments a bit
220 const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
226 // Do tests in one go
227 labelList surfaceHit;
229 labelList surfaceLevel;
230 surfaces_.findHigherIntersection
234 labelList(start.size(), -1), // accept any intersection
240 // Keep just surface hit
241 forAll(surfaceHit, i)
243 surfaceIndex_[changedFaces[i]] = surfaceHit[i];
246 // Make sure both sides have same information. This should be
247 // case in general since same vectors but just to make sure.
248 syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>());
250 label nHits = countHits();
251 label nTotHits = returnReduce(nHits, sumOp<label>());
253 Info<< " Number of intersected edges : " << nTotHits << endl;
255 // Set files to same time as mesh
256 setInstance(mesh_.facesInstance());
260 void Foam::meshRefinement::checkData()
262 Pout<< "meshRefinement::checkData() : Checking refinement structure."
264 meshCutter_.checkMesh();
266 Pout<< "meshRefinement::checkData() : Checking refinement levels."
268 meshCutter_.checkRefinementLevels(1, labelList(0));
271 label nBnd = mesh_.nFaces()-mesh_.nInternalFaces();
273 Pout<< "meshRefinement::checkData() : Checking synchronization."
276 // Check face centres
278 // Boundary face centres
279 pointField::subList boundaryFc
283 mesh_.nInternalFaces()
286 // Get neighbouring face centres
287 pointField neiBoundaryFc(boundaryFc);
288 syncTools::syncBoundaryFacePositions
296 testSyncBoundaryFaceList
299 "testing faceCentres : ",
304 // Check meshRefinement
306 // Get boundary face centre and level. Coupled aware.
307 labelList neiLevel(nBnd);
308 pointField neiCc(nBnd);
309 calcNeighbourData(neiLevel, neiCc);
311 // Collect segments we want to test for
312 pointField start(mesh_.nFaces());
313 pointField end(mesh_.nFaces());
317 start[faceI] = mesh_.cellCentres()[mesh_.faceOwner()[faceI]];
319 if (mesh_.isInternalFace(faceI))
321 end[faceI] = mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]];
325 end[faceI] = neiCc[faceI-mesh_.nInternalFaces()];
329 // Extend segments a bit
331 const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
337 // Do tests in one go
338 labelList surfaceHit;
340 labelList surfaceLevel;
341 surfaces_.findHigherIntersection
345 labelList(start.size(), -1), // accept any intersection
350 // Get the coupled hit
357 mesh_.nInternalFaces()
360 syncTools::swapBoundaryFaceList(mesh_, neiHit);
363 forAll(surfaceHit, faceI)
365 if (surfaceIndex_[faceI] != surfaceHit[faceI])
367 if (mesh_.isInternalFace(faceI))
369 WarningIn("meshRefinement::checkData()")
370 << "Internal face:" << faceI
371 << " fc:" << mesh_.faceCentres()[faceI]
372 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
373 << " current:" << surfaceHit[faceI]
375 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
377 << mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]]
383 != neiHit[faceI-mesh_.nInternalFaces()]
386 WarningIn("meshRefinement::checkData()")
387 << "Boundary face:" << faceI
388 << " fc:" << mesh_.faceCentres()[faceI]
389 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
390 << " current:" << surfaceHit[faceI]
392 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
393 << " end:" << end[faceI]
400 labelList::subList boundarySurface
403 mesh_.nFaces()-mesh_.nInternalFaces(),
404 mesh_.nInternalFaces()
407 labelList neiBoundarySurface(boundarySurface);
408 syncTools::swapBoundaryFaceList
415 testSyncBoundaryFaceList
418 "testing surfaceIndex() : ",
425 // Find duplicate faces
426 Pout<< "meshRefinement::checkData() : Counting duplicate faces."
429 labelList duplicateFace
431 localPointRegion::findDuplicateFaces
434 identity(mesh_.nFaces()-mesh_.nInternalFaces())
435 + mesh_.nInternalFaces()
443 forAll(duplicateFace, i)
445 if (duplicateFace[i] != -1)
450 nDup /= 2; // will have counted both faces of duplicate
451 Pout<< "meshRefinement::checkData() : Found " << nDup
452 << " duplicate pairs of faces." << endl;
457 void Foam::meshRefinement::setInstance(const fileName& inst)
459 meshCutter_.setInstance(inst);
460 surfaceIndex_.instance() = inst;
464 // Remove cells. Put exposedFaces (output of getExposedFaces(cellsToRemove))
465 // into exposedPatchIDs.
466 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells
468 const labelList& cellsToRemove,
469 const labelList& exposedFaces,
470 const labelList& exposedPatchIDs,
471 removeCells& cellRemover
474 polyTopoChange meshMod(mesh_);
476 // Arbitrary: put exposed faces into last patch.
477 cellRemover.setRefinement
485 // Change the mesh (no inflation)
486 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
489 mesh_.updateMesh(map);
491 // Move mesh (since morphing might not do this)
492 if (map().hasMotionPoints())
494 mesh_.movePoints(map().preMotionPoints());
498 // Delete mesh volumes. No other way to do this?
502 // Reset the instance for if in overwrite mode
503 mesh_.setInstance(timeName());
504 setInstance(mesh_.facesInstance());
506 // Update local mesh data
507 cellRemover.updateMesh(map);
509 // Update intersections. Recalculate intersections for exposed faces.
510 labelList newExposedFaces = renumber
512 map().reverseFaceMap(),
516 //Pout<< "removeCells : updating intersections for "
517 // << newExposedFaces.size() << " newly exposed faces." << endl;
519 updateMesh(map, newExposedFaces);
525 // Determine for multi-processor regions the lowest numbered cell on the lowest
526 // numbered processor.
527 void Foam::meshRefinement::getCoupledRegionMaster
529 const globalIndex& globalCells,
530 const boolList& blockedFace,
531 const regionSplit& globalRegion,
532 Map<label>& regionToMaster
535 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
537 forAll(patches, patchI)
539 const polyPatch& pp = patches[patchI];
541 if (isA<processorPolyPatch>(pp))
545 label faceI = pp.start()+i;
547 if (!blockedFace[faceI])
549 // Only if there is a connection to the neighbour
550 // will there be a multi-domain region; if not through
551 // this face then through another.
553 label cellI = mesh_.faceOwner()[faceI];
554 label globalCellI = globalCells.toGlobal(cellI);
556 Map<label>::iterator iter =
557 regionToMaster.find(globalRegion[cellI]);
559 if (iter != regionToMaster.end())
561 label master = iter();
562 iter() = min(master, globalCellI);
566 regionToMaster.insert
578 Pstream::mapCombineGather(regionToMaster, minEqOp<label>());
579 Pstream::mapCombineScatter(regionToMaster);
583 void Foam::meshRefinement::calcLocalRegions
585 const globalIndex& globalCells,
586 const labelList& globalRegion,
587 const Map<label>& coupledRegionToMaster,
588 const scalarField& cellWeights,
590 Map<label>& globalToLocalRegion,
591 pointField& localPoints,
592 scalarField& localWeights
595 globalToLocalRegion.resize(globalRegion.size());
596 DynamicList<point> localCc(globalRegion.size()/2);
597 DynamicList<scalar> localWts(globalRegion.size()/2);
599 forAll(globalRegion, cellI)
601 Map<label>::const_iterator fndMaster =
602 coupledRegionToMaster.find(globalRegion[cellI]);
604 if (fndMaster != coupledRegionToMaster.end())
606 // Multi-processor region.
607 if (globalCells.toGlobal(cellI) == fndMaster())
609 // I am master. Allocate region for me.
610 globalToLocalRegion.insert(globalRegion[cellI], localCc.size());
611 localCc.append(mesh_.cellCentres()[cellI]);
612 localWts.append(cellWeights[cellI]);
617 // Single processor region.
618 if (globalToLocalRegion.insert(globalRegion[cellI], localCc.size()))
620 localCc.append(mesh_.cellCentres()[cellI]);
621 localWts.append(cellWeights[cellI]);
626 localPoints.transfer(localCc);
627 localWeights.transfer(localWts);
629 if (localPoints.size() != globalToLocalRegion.size())
631 FatalErrorIn("calcLocalRegions(..)")
632 << "localPoints:" << localPoints.size()
633 << " globalToLocalRegion:" << globalToLocalRegion.size()
639 Foam::label Foam::meshRefinement::getShiftedRegion
641 const globalIndex& indexer,
642 const Map<label>& globalToLocalRegion,
643 const Map<label>& coupledRegionToShifted,
644 const label globalRegion
647 Map<label>::const_iterator iter =
648 globalToLocalRegion.find(globalRegion);
650 if (iter != globalToLocalRegion.end())
652 // Region is 'owned' locally. Convert local region index into global.
653 return indexer.toGlobal(iter());
657 return coupledRegionToShifted[globalRegion];
662 // Add if not yet present
663 void Foam::meshRefinement::addUnique(const label elem, labelList& lst)
665 if (findIndex(lst, elem) == -1)
667 label sz = lst.size();
674 void Foam::meshRefinement::calcRegionRegions
676 const labelList& globalRegion,
677 const Map<label>& globalToLocalRegion,
678 const Map<label>& coupledRegionToMaster,
679 labelListList& regionRegions
682 // Global region indexing since we now know the shifted regions.
683 globalIndex shiftIndexer(globalToLocalRegion.size());
685 // Redo the coupledRegionToMaster to be in shifted region indexing.
686 Map<label> coupledRegionToShifted(coupledRegionToMaster.size());
687 forAllConstIter(Map<label>, coupledRegionToMaster, iter)
689 label region = iter.key();
691 Map<label>::const_iterator fndRegion = globalToLocalRegion.find(region);
693 if (fndRegion != globalToLocalRegion.end())
695 // A local cell is master of this region. Get its shifted region.
696 coupledRegionToShifted.insert
699 shiftIndexer.toGlobal(fndRegion())
702 Pstream::mapCombineGather(coupledRegionToShifted, minEqOp<label>());
703 Pstream::mapCombineScatter(coupledRegionToShifted);
707 // Determine region-region connectivity.
708 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
709 // This is for all my regions (so my local ones or the ones I am master
710 // of) the neighbouring region indices.
714 PtrList<HashSet<edge, Hash<edge> > > regionConnectivity(Pstream::nProcs());
715 forAll(regionConnectivity, procI)
717 if (procI != Pstream::myProcNo())
719 regionConnectivity.set
722 new HashSet<edge, Hash<edge> >
724 coupledRegionToShifted.size()
732 // Connectivity. For all my local regions the connected regions.
733 regionRegions.setSize(globalToLocalRegion.size());
735 // Add all local connectivity to regionRegions; add all non-local
736 // to the transferlists.
737 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
739 label ownRegion = globalRegion[mesh_.faceOwner()[faceI]];
740 label neiRegion = globalRegion[mesh_.faceNeighbour()[faceI]];
742 if (ownRegion != neiRegion)
744 label shiftOwnRegion = getShiftedRegion
748 coupledRegionToShifted,
751 label shiftNeiRegion = getShiftedRegion
755 coupledRegionToShifted,
760 // Connection between two regions. Send to owner of region.
761 // - is ownRegion 'owned' by me
762 // - is neiRegion 'owned' by me
764 if (shiftIndexer.isLocal(shiftOwnRegion))
766 label localI = shiftIndexer.toLocal(shiftOwnRegion);
767 addUnique(shiftNeiRegion, regionRegions[localI]);
771 label masterProc = shiftIndexer.whichProcID(shiftOwnRegion);
772 regionConnectivity[masterProc].insert
774 edge(shiftOwnRegion, shiftNeiRegion)
778 if (shiftIndexer.isLocal(shiftNeiRegion))
780 label localI = shiftIndexer.toLocal(shiftNeiRegion);
781 addUnique(shiftOwnRegion, regionRegions[localI]);
785 label masterProc = shiftIndexer.whichProcID(shiftNeiRegion);
786 regionConnectivity[masterProc].insert
788 edge(shiftOwnRegion, shiftNeiRegion)
796 forAll(regionConnectivity, procI)
798 if (procI != Pstream::myProcNo())
800 OPstream str(Pstream::blocking, procI);
801 str << regionConnectivity[procI];
805 forAll(regionConnectivity, procI)
807 if (procI != Pstream::myProcNo())
809 IPstream str(Pstream::blocking, procI);
810 str >> regionConnectivity[procI];
814 // Add to addressing.
815 forAll(regionConnectivity, procI)
817 if (procI != Pstream::myProcNo())
821 HashSet<edge, Hash<edge> >::const_iterator iter =
822 regionConnectivity[procI].begin();
823 iter != regionConnectivity[procI].end();
827 const edge& e = iter.key();
829 bool someLocal = false;
830 if (shiftIndexer.isLocal(e[0]))
832 label localI = shiftIndexer.toLocal(e[0]);
833 addUnique(e[1], regionRegions[localI]);
836 if (shiftIndexer.isLocal(e[1]))
838 label localI = shiftIndexer.toLocal(e[1]);
839 addUnique(e[0], regionRegions[localI]);
845 FatalErrorIn("calcRegionRegions(..)")
846 << "Received from processor " << procI
847 << " connection " << e
848 << " where none of the elements is local to me."
849 << abort(FatalError);
857 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
859 // Construct from components
860 Foam::meshRefinement::meshRefinement
863 const scalar mergeDistance,
864 const bool overwrite,
865 const refinementSurfaces& surfaces,
866 const refinementFeatures& features,
867 const shellSurfaces& shells
871 mergeDistance_(mergeDistance),
872 overwrite_(overwrite),
873 oldInstance_(mesh.pointsInstance()),
885 mesh_.facesInstance(),
888 IOobject::READ_IF_PRESENT,
892 labelList(mesh_.nCells(), 0)
899 mesh_.facesInstance(),
902 IOobject::READ_IF_PRESENT,
906 labelList(mesh_.nPoints(), 0)
913 mesh_.facesInstance(),
920 List<refinementHistory::splitCell8>(0),
929 mesh_.facesInstance(),
936 labelList(mesh_.nFaces(), -1)
940 // recalculate intersections for all faces
941 updateIntersections(identity(mesh_.nFaces()));
945 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
947 Foam::label Foam::meshRefinement::countHits() const
949 // Stats on edges to test. Count proc faces only once.
950 PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
954 forAll(surfaceIndex_, faceI)
956 if (surfaceIndex_[faceI] >= 0 && isMasterFace.get(faceI) == 1)
965 // Determine distribution to move connected regions onto one processor.
966 Foam::labelList Foam::meshRefinement::decomposeCombineRegions
968 const scalarField& cellWeights,
969 const boolList& blockedFace,
970 const List<labelPair>& explicitConnections,
971 decompositionMethod& decomposer
974 // Determine global regions, separated by blockedFaces
975 regionSplit globalRegion(mesh_, blockedFace, explicitConnections);
977 // Now globalRegion has global region per cell. Problem is that
978 // the region might span multiple domains so we want to get
979 // a "region master" per domain. Note that multi-processor
980 // regions can only occur on cells on coupled patches.
981 // Note: since the number of regions does not change by this the
982 // process can be seen as just a shift of a region onto a single
986 // Global cell numbering engine
987 globalIndex globalCells(mesh_.nCells());
990 // Determine per coupled region the master cell (lowest numbered cell
991 // on lowest numbered processor)
992 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
993 // (does not determine master for non-coupled=fully-local regions)
995 Map<label> coupledRegionToMaster(mesh_.nFaces()-mesh_.nInternalFaces());
996 getCoupledRegionMaster
1001 coupledRegionToMaster
1004 // Determine my regions
1005 // ~~~~~~~~~~~~~~~~~~~~
1006 // These are the fully local ones or the coupled ones of which I am master.
1008 Map<label> globalToLocalRegion;
1009 pointField localPoints;
1010 scalarField localWeights;
1015 coupledRegionToMaster,
1018 globalToLocalRegion,
1025 // Find distribution for regions
1026 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1028 labelList regionDistribution;
1030 if (isA<geomDecomp>(decomposer))
1032 regionDistribution = decomposer.decompose(localPoints, localWeights);
1036 labelListList regionRegions;
1040 globalToLocalRegion,
1041 coupledRegionToMaster,
1046 regionDistribution = decomposer.decompose
1056 // Convert region-based decomposition back to cell-based one
1057 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1059 // Transfer destination processor back to all. Use global reduce for now.
1060 Map<label> regionToDist(coupledRegionToMaster.size());
1061 forAllConstIter(Map<label>, coupledRegionToMaster, iter)
1063 label region = iter.key();
1065 Map<label>::const_iterator regionFnd = globalToLocalRegion.find(region);
1067 if (regionFnd != globalToLocalRegion.end())
1069 // Master cell is local. Store my distribution.
1070 regionToDist.insert(iter.key(), regionDistribution[regionFnd()]);
1074 // Master cell is not on this processor. Make sure it is overridden.
1075 regionToDist.insert(iter.key(), labelMax);
1078 Pstream::mapCombineGather(regionToDist, minEqOp<label>());
1079 Pstream::mapCombineScatter(regionToDist);
1082 // Determine destination for all cells
1083 labelList distribution(mesh_.nCells());
1085 forAll(globalRegion, cellI)
1087 Map<label>::const_iterator fndRegion =
1088 regionToDist.find(globalRegion[cellI]);
1090 if (fndRegion != regionToDist.end())
1092 distribution[cellI] = fndRegion();
1096 // region is local to the processor.
1097 label localRegionI = globalToLocalRegion[globalRegion[cellI]];
1099 distribution[cellI] = regionDistribution[localRegionI];
1103 return distribution;
1107 Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance
1109 const bool keepZoneFaces,
1110 const bool keepBaffles,
1111 const scalarField& cellWeights,
1112 decompositionMethod& decomposer,
1113 fvMeshDistribute& distributor
1116 autoPtr<mapDistributePolyMesh> map;
1118 if (Pstream::parRun())
1122 // const_cast<Time&>(mesh_.time())++;
1125 // Wanted distribution
1126 labelList distribution;
1128 if (keepZoneFaces || keepBaffles)
1130 // Faces where owner and neighbour are not 'connected' so can
1131 // go to different processors.
1132 boolList blockedFace(mesh_.nFaces(), true);
1133 label nUnblocked = 0;
1135 List<labelPair> couples;
1139 // Determine decomposition to keep/move surface zones
1140 // on one processor. The reason is that snapping will make these
1141 // into baffles, move and convert them back so if they were
1142 // proc boundaries after baffling&moving the points might be no
1143 // longer snychronised so recoupling will fail. To prevent this
1144 // keep owner&neighbour of such a surface zone on the same
1147 const wordList& fzNames = surfaces().faceZoneNames();
1148 const faceZoneMesh& fZones = mesh_.faceZones();
1149 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
1151 // Get faces whose owner and neighbour should stay together,
1152 // i.e. they are not 'blocked'.
1154 forAll(fzNames, surfI)
1156 if (fzNames[surfI].size())
1159 const faceZone& fZone = fZones[fzNames[surfI]];
1163 label faceI = fZone[i];
1164 if (blockedFace[faceI])
1168 mesh_.isInternalFace(faceI)
1169 || pbm[pbm.whichPatch(faceI)].coupled()
1172 blockedFace[faceI] = false;
1181 // If the faceZones are not synchronised the blockedFace
1182 // might not be synchronised. If you are sure the faceZones
1183 // are synchronised remove below check.
1184 syncTools::syncFaceList
1188 andEqOp<bool>() // combine operator
1191 reduce(nUnblocked, sumOp<label>());
1195 Info<< "Found " << nUnblocked
1196 << " zoned faces to keep together." << endl;
1201 // Get boundary baffles that need to stay together.
1202 couples = getDuplicateFaces // all baffles
1204 identity(mesh_.nFaces()-mesh_.nInternalFaces())
1205 +mesh_.nInternalFaces()
1208 label nCouples = returnReduce(couples.size(), sumOp<label>());
1212 Info<< "Found " << nCouples << " baffles to keep together."
1216 if (nUnblocked > 0 || nCouples > 0)
1218 Info<< "Applying special decomposition to keep baffles"
1219 << " and zoned faces together." << endl;
1221 distribution = decomposeCombineRegions
1229 labelList nProcCells(distributor.countCells(distribution));
1230 Pstream::listCombineGather(nProcCells, plusEqOp<label>());
1231 Pstream::listCombineScatter(nProcCells);
1233 Info<< "Calculated decomposition:" << endl;
1234 forAll(nProcCells, procI)
1236 Info<< " " << procI << '\t' << nProcCells[procI] << endl;
1242 // Normal decomposition
1243 distribution = decomposer.decompose
1246 mesh_.cellCentres(),
1253 // Normal decomposition
1254 distribution = decomposer.decompose
1257 mesh_.cellCentres(),
1264 labelList nProcCells(distributor.countCells(distribution));
1265 Pout<< "Wanted distribution:" << nProcCells << endl;
1267 Pstream::listCombineGather(nProcCells, plusEqOp<label>());
1268 Pstream::listCombineScatter(nProcCells);
1270 Pout<< "Wanted resulting decomposition:" << endl;
1271 forAll(nProcCells, procI)
1273 Pout<< " " << procI << '\t' << nProcCells[procI] << endl;
1277 // Do actual sending/receiving of mesh
1278 map = distributor.distribute(distribution);
1280 // Update numbering of meshRefiner
1283 // Set correct instance (for if overwrite)
1284 mesh_.setInstance(timeName());
1285 setInstance(mesh_.facesInstance());
1291 // Helper function to get intersected faces
1292 Foam::labelList Foam::meshRefinement::intersectedFaces() const
1294 label nBoundaryFaces = 0;
1296 forAll(surfaceIndex_, faceI)
1298 if (surfaceIndex_[faceI] != -1)
1304 labelList surfaceFaces(nBoundaryFaces);
1307 forAll(surfaceIndex_, faceI)
1309 if (surfaceIndex_[faceI] != -1)
1311 surfaceFaces[nBoundaryFaces++] = faceI;
1314 return surfaceFaces;
1318 // Helper function to get points used by faces
1319 Foam::labelList Foam::meshRefinement::intersectedPoints() const
1321 const faceList& faces = mesh_.faces();
1323 // Mark all points on faces that will become baffles
1324 PackedBoolList isBoundaryPoint(mesh_.nPoints());
1325 label nBoundaryPoints = 0;
1327 forAll(surfaceIndex_, faceI)
1329 if (surfaceIndex_[faceI] != -1)
1331 const face& f = faces[faceI];
1335 if (isBoundaryPoint.set(f[fp], 1u))
1343 //// Insert all meshed patches.
1344 //labelList adaptPatchIDs(meshedPatches());
1345 //forAll(adaptPatchIDs, i)
1347 // label patchI = adaptPatchIDs[i];
1349 // if (patchI != -1)
1351 // const polyPatch& pp = mesh_.boundaryMesh()[patchI];
1353 // label faceI = pp.start();
1357 // const face& f = faces[faceI];
1361 // if (isBoundaryPoint.set(f[fp], 1u))
1362 // nBoundaryPoints++;
1372 labelList boundaryPoints(nBoundaryPoints);
1373 nBoundaryPoints = 0;
1374 forAll(isBoundaryPoint, pointI)
1376 if (isBoundaryPoint.get(pointI) == 1u)
1378 boundaryPoints[nBoundaryPoints++] = pointI;
1382 return boundaryPoints;
1386 //- Create patch from set of patches
1387 Foam::autoPtr<Foam::indirectPrimitivePatch> Foam::meshRefinement::makePatch
1389 const polyMesh& mesh,
1390 const labelList& patchIDs
1393 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1400 const polyPatch& pp = patches[patchIDs[i]];
1402 nFaces += pp.size();
1406 labelList addressing(nFaces);
1411 const polyPatch& pp = patches[patchIDs[i]];
1413 label meshFaceI = pp.start();
1417 addressing[nFaces++] = meshFaceI++;
1421 return autoPtr<indirectPrimitivePatch>
1423 new indirectPrimitivePatch
1425 IndirectList<face>(mesh.faces(), addressing),
1432 // Construct pointVectorField with correct boundary conditions
1433 Foam::tmp<Foam::pointVectorField> Foam::meshRefinement::makeDisplacementField
1435 const pointMesh& pMesh,
1436 const labelList& adaptPatchIDs
1439 const polyMesh& mesh = pMesh();
1441 // Construct displacement field.
1442 const pointBoundaryMesh& pointPatches = pMesh.boundary();
1444 wordList patchFieldTypes
1446 pointPatches.size(),
1447 slipPointPatchVectorField::typeName
1450 forAll(adaptPatchIDs, i)
1452 patchFieldTypes[adaptPatchIDs[i]] =
1453 fixedValuePointPatchVectorField::typeName;
1456 forAll(pointPatches, patchI)
1458 if (isA<processorPointPatch>(pointPatches[patchI]))
1460 patchFieldTypes[patchI] = calculatedPointPatchVectorField::typeName;
1462 else if (isA<cyclicPointPatch>(pointPatches[patchI]))
1464 patchFieldTypes[patchI] = cyclicSlipPointPatchVectorField::typeName;
1468 // Note: time().timeName() instead of meshRefinement::timeName() since
1469 // postprocessable field.
1470 tmp<pointVectorField> tfld
1472 new pointVectorField
1476 "pointDisplacement",
1477 mesh.time().timeName(),
1480 IOobject::AUTO_WRITE
1483 dimensionedVector("displacement", dimLength, vector::zero),
1491 void Foam::meshRefinement::checkCoupledFaceZones(const polyMesh& mesh)
1493 const faceZoneMesh& fZones = mesh.faceZones();
1495 // Check any zones are present anywhere and in same order
1498 List<wordList> zoneNames(Pstream::nProcs());
1499 zoneNames[Pstream::myProcNo()] = fZones.names();
1500 Pstream::gatherList(zoneNames);
1501 Pstream::scatterList(zoneNames);
1502 // All have same data now. Check.
1503 forAll(zoneNames, procI)
1505 if (procI != Pstream::myProcNo())
1507 if (zoneNames[procI] != zoneNames[Pstream::myProcNo()])
1511 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1512 ) << "faceZones are not synchronised on processors." << nl
1513 << "Processor " << procI << " has faceZones "
1514 << zoneNames[procI] << nl
1515 << "Processor " << Pstream::myProcNo()
1516 << " has faceZones "
1517 << zoneNames[Pstream::myProcNo()] << nl
1518 << exit(FatalError);
1524 // Check that coupled faces are present on both sides.
1526 labelList faceToZone(mesh.nFaces()-mesh.nInternalFaces(), -1);
1528 forAll(fZones, zoneI)
1530 const faceZone& fZone = fZones[zoneI];
1534 label bFaceI = fZone[i]-mesh.nInternalFaces();
1538 if (faceToZone[bFaceI] == -1)
1540 faceToZone[bFaceI] = zoneI;
1542 else if (faceToZone[bFaceI] == zoneI)
1546 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1547 ) << "Face " << fZone[i] << " in zone "
1549 << " is twice in zone!"
1550 << abort(FatalError);
1556 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1557 ) << "Face " << fZone[i] << " in zone "
1559 << " is also in zone "
1560 << fZones[faceToZone[bFaceI]].name()
1561 << abort(FatalError);
1567 labelList neiFaceToZone(faceToZone);
1568 syncTools::swapBoundaryFaceList(mesh, neiFaceToZone);
1570 forAll(faceToZone, i)
1572 if (faceToZone[i] != neiFaceToZone[i])
1576 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1577 ) << "Face " << mesh.nInternalFaces()+i
1578 << " is in zone " << faceToZone[i]
1579 << ", its coupled face is in zone " << neiFaceToZone[i]
1580 << abort(FatalError);
1586 Foam::label Foam::meshRefinement::appendPatch
1589 const label insertPatchI,
1590 const word& patchName,
1591 const dictionary& patchDict
1594 // Clear local fields and e.g. polyMesh parallelInfo.
1597 polyBoundaryMesh& polyPatches =
1598 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
1599 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
1601 label patchI = polyPatches.size();
1603 // Add polyPatch at the end
1604 polyPatches.setSize(patchI+1);
1616 fvPatches.setSize(patchI+1);
1622 polyPatches[patchI], // point to newly added polyPatch
1627 addPatchFields<volScalarField>
1630 calculatedFvPatchField<scalar>::typeName
1632 addPatchFields<volVectorField>
1635 calculatedFvPatchField<vector>::typeName
1637 addPatchFields<volSphericalTensorField>
1640 calculatedFvPatchField<sphericalTensor>::typeName
1642 addPatchFields<volSymmTensorField>
1645 calculatedFvPatchField<symmTensor>::typeName
1647 addPatchFields<volTensorField>
1650 calculatedFvPatchField<tensor>::typeName
1655 addPatchFields<surfaceScalarField>
1658 calculatedFvPatchField<scalar>::typeName
1660 addPatchFields<surfaceVectorField>
1663 calculatedFvPatchField<vector>::typeName
1665 addPatchFields<surfaceSphericalTensorField>
1668 calculatedFvPatchField<sphericalTensor>::typeName
1670 addPatchFields<surfaceSymmTensorField>
1673 calculatedFvPatchField<symmTensor>::typeName
1675 addPatchFields<surfaceTensorField>
1678 calculatedFvPatchField<tensor>::typeName
1684 // Adds patch if not yet there. Returns patchID.
1685 Foam::label Foam::meshRefinement::addPatch
1688 const word& patchName,
1689 const dictionary& patchInfo
1692 polyBoundaryMesh& polyPatches =
1693 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
1694 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
1696 const label patchI = polyPatches.findPatchID(patchName);
1704 label insertPatchI = polyPatches.size();
1705 label startFaceI = mesh.nFaces();
1707 forAll(polyPatches, patchI)
1709 const polyPatch& pp = polyPatches[patchI];
1711 if (isA<processorPolyPatch>(pp))
1713 insertPatchI = patchI;
1714 startFaceI = pp.start();
1719 dictionary patchDict(patchInfo);
1720 patchDict.set("nFaces", 0);
1721 patchDict.set("startFace", startFaceI);
1723 // Below is all quite a hack. Feel free to change once there is a better
1724 // mechanism to insert and reorder patches.
1726 label addedPatchI = appendPatch(mesh, insertPatchI, patchName, patchDict);
1729 // Create reordering list
1730 // patches before insert position stay as is
1731 labelList oldToNew(addedPatchI+1);
1732 for (label i = 0; i < insertPatchI; i++)
1736 // patches after insert position move one up
1737 for (label i = insertPatchI; i < addedPatchI; i++)
1741 // appended patch gets moved to insert position
1742 oldToNew[addedPatchI] = insertPatchI;
1744 // Shuffle into place
1745 polyPatches.reorder(oldToNew);
1746 fvPatches.reorder(oldToNew);
1748 reorderPatchFields<volScalarField>(mesh, oldToNew);
1749 reorderPatchFields<volVectorField>(mesh, oldToNew);
1750 reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
1751 reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
1752 reorderPatchFields<volTensorField>(mesh, oldToNew);
1753 reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
1754 reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
1755 reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
1756 reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
1757 reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
1759 return insertPatchI;
1763 Foam::label Foam::meshRefinement::addMeshedPatch
1766 const dictionary& patchInfo
1769 label meshedI = findIndex(meshedPatches_, name);
1773 // Already there. Get corresponding polypatch
1774 return mesh_.boundaryMesh().findPatchID(name);
1779 label patchI = addPatch(mesh_, name, patchInfo);
1782 label sz = meshedPatches_.size();
1783 meshedPatches_.setSize(sz+1);
1784 meshedPatches_[sz] = name;
1791 Foam::labelList Foam::meshRefinement::meshedPatches() const
1793 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1795 DynamicList<label> patchIDs(meshedPatches_.size());
1796 forAll(meshedPatches_, i)
1798 label patchI = patches.findPatchID(meshedPatches_[i]);
1802 FatalErrorIn("meshRefinement::meshedPatches() const")
1803 << "Problem : did not find patch " << meshedPatches_[i]
1804 << endl << "Valid patches are " << patches.names()
1805 << abort(FatalError);
1807 if (!polyPatch::constraintType(patches[patchI].type()))
1809 patchIDs.append(patchI);
1817 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
1819 const point& keepPoint
1822 // Determine connected regions. regionSplit is the labelList with the
1824 regionSplit cellRegion(mesh_);
1828 label cellI = mesh_.findCell(keepPoint);
1832 regionI = cellRegion[cellI];
1835 reduce(regionI, maxOp<label>());
1841 "meshRefinement::splitMeshRegions(const point&)"
1842 ) << "Point " << keepPoint
1843 << " is not inside the mesh." << nl
1844 << "Bounding box of the mesh:" << mesh_.bounds()
1845 << exit(FatalError);
1851 // Get cells to remove
1852 DynamicList<label> cellsToRemove(mesh_.nCells());
1853 forAll(cellRegion, cellI)
1855 if (cellRegion[cellI] != regionI)
1857 cellsToRemove.append(cellI);
1860 cellsToRemove.shrink();
1862 label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
1863 reduce(nCellsToKeep, sumOp<label>());
1865 Info<< "Keeping all cells in region " << regionI
1866 << " containing point " << keepPoint << endl
1867 << "Selected for keeping : "
1869 << " cells." << endl;
1873 removeCells cellRemover(mesh_);
1875 labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
1877 if (exposedFaces.size())
1881 "meshRefinement::splitMeshRegions(const point&)"
1882 ) << "Removing non-reachable cells should only expose boundary faces"
1884 << "ExposedFaces:" << exposedFaces << abort(FatalError);
1887 return doRemoveCells
1891 labelList(exposedFaces.size(),-1), // irrelevant since 0 size.
1897 void Foam::meshRefinement::distribute(const mapDistributePolyMesh& map)
1899 // mesh_ already distributed; distribute my member data
1901 // surfaceQueries_ ok.
1904 meshCutter_.distribute(map);
1906 // surfaceIndex is face data.
1907 map.distributeFaceData(surfaceIndex_);
1909 // maintainedFaces are indices of faces.
1910 forAll(userFaceData_, i)
1912 map.distributeFaceData(userFaceData_[i].second());
1915 // Redistribute surface and any fields on it.
1917 Random rndGen(653213);
1919 // Get local mesh bounding box. Single box for now.
1920 List<treeBoundBox> meshBb(1);
1921 treeBoundBox& bb = meshBb[0];
1922 bb = treeBoundBox(mesh_.points());
1923 bb = bb.extend(rndGen, 1E-4);
1925 // Distribute all geometry (so refinementSurfaces and shellSurfaces)
1926 searchableSurfaces& geometry =
1927 const_cast<searchableSurfaces&>(surfaces_.geometry());
1931 autoPtr<mapDistribute> faceMap;
1932 autoPtr<mapDistribute> pointMap;
1933 geometry[i].distribute
1936 false, // do not keep outside triangles
1941 if (faceMap.valid())
1943 // (ab)use the instance() to signal current modification time
1944 geometry[i].instance() = geometry[i].time().timeName();
1954 // Update local data for a mesh change
1955 void Foam::meshRefinement::updateMesh
1957 const mapPolyMesh& map,
1958 const labelList& changedFaces
1961 Map<label> dummyMap(0);
1963 updateMesh(map, changedFaces, dummyMap, dummyMap, dummyMap);
1967 void Foam::meshRefinement::storeData
1969 const labelList& pointsToStore,
1970 const labelList& facesToStore,
1971 const labelList& cellsToStore
1974 // For now only meshCutter has storable/retrievable data.
1975 meshCutter_.storeData
1984 void Foam::meshRefinement::updateMesh
1986 const mapPolyMesh& map,
1987 const labelList& changedFaces,
1988 const Map<label>& pointsToRestore,
1989 const Map<label>& facesToRestore,
1990 const Map<label>& cellsToRestore
1993 // For now only meshCutter has storable/retrievable data.
1995 // Update numbering of cells/vertices.
1996 meshCutter_.updateMesh
2004 // Update surfaceIndex
2005 updateList(map.faceMap(), -1, surfaceIndex_);
2007 // Update cached intersection information
2008 updateIntersections(changedFaces);
2010 // Update maintained faces
2011 forAll(userFaceData_, i)
2013 labelList& data = userFaceData_[i].second();
2015 if (userFaceData_[i].first() == KEEPALL)
2017 // extend list with face-from-face data
2018 updateList(map.faceMap(), -1, data);
2020 else if (userFaceData_[i].first() == MASTERONLY)
2023 labelList newFaceData(map.faceMap().size(), -1);
2025 forAll(newFaceData, faceI)
2027 label oldFaceI = map.faceMap()[faceI];
2029 if (oldFaceI >= 0 && map.reverseFaceMap()[oldFaceI] == faceI)
2031 newFaceData[faceI] = data[oldFaceI];
2034 data.transfer(newFaceData);
2038 // remove any face that has been refined i.e. referenced more than
2041 // 1. Determine all old faces that get referenced more than once.
2042 // These get marked with -1 in reverseFaceMap
2043 labelList reverseFaceMap(map.reverseFaceMap());
2045 forAll(map.faceMap(), faceI)
2047 label oldFaceI = map.faceMap()[faceI];
2051 if (reverseFaceMap[oldFaceI] != faceI)
2053 // faceI is slave face. Mark old face.
2054 reverseFaceMap[oldFaceI] = -1;
2059 // 2. Map only faces with intact reverseFaceMap
2060 labelList newFaceData(map.faceMap().size(), -1);
2061 forAll(newFaceData, faceI)
2063 label oldFaceI = map.faceMap()[faceI];
2067 if (reverseFaceMap[oldFaceI] == faceI)
2069 newFaceData[faceI] = data[oldFaceI];
2073 data.transfer(newFaceData);
2079 bool Foam::meshRefinement::write() const
2083 && meshCutter_.write()
2084 && surfaceIndex_.write();
2087 // Make sure that any distributed surfaces (so ones which probably have
2088 // been changed) get written as well.
2089 // Note: should ideally have some 'modified' flag to say whether it
2090 // has been changed or not.
2091 searchableSurfaces& geometry =
2092 const_cast<searchableSurfaces&>(surfaces_.geometry());
2096 searchableSurface& s = geometry[i];
2098 // Check if instance() of surface is not constant or system.
2099 // Is good hint that surface is distributed.
2102 s.instance() != s.time().system()
2103 && s.instance() != s.time().caseSystem()
2104 && s.instance() != s.time().constant()
2105 && s.instance() != s.time().caseConstant()
2108 // Make sure it gets written to current time, not constant.
2109 s.instance() = s.time().timeName();
2110 writeOk = writeOk && s.write();
2118 void Foam::meshRefinement::printMeshInfo(const bool debug, const string& msg)
2121 const globalMeshData& pData = mesh_.globalData();
2126 << " : cells(local):" << mesh_.nCells()
2127 << " faces(local):" << mesh_.nFaces()
2128 << " points(local):" << mesh_.nPoints()
2133 PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
2134 label nMasterFaces = 0;
2135 forAll(isMasterFace, i)
2137 if (isMasterFace[i])
2143 PackedBoolList isMasterPoint(syncTools::getMasterPoints(mesh_));
2144 label nMasterPoints = 0;
2145 forAll(isMasterPoint, i)
2147 if (isMasterPoint[i])
2154 << " : cells:" << pData.nTotalCells()
2155 << " faces:" << returnReduce(nMasterFaces, sumOp<label>())
2156 << " points:" << returnReduce(nMasterPoints, sumOp<label>())
2163 const labelList& cellLevel = meshCutter_.cellLevel();
2165 labelList nCells(gMax(cellLevel)+1, 0);
2167 forAll(cellLevel, cellI)
2169 nCells[cellLevel[cellI]]++;
2172 Pstream::listCombineGather(nCells, plusEqOp<label>());
2173 Pstream::listCombineScatter(nCells);
2175 Info<< "Cells per refinement level:" << endl;
2176 forAll(nCells, levelI)
2178 Info<< " " << levelI << '\t' << nCells[levelI]
2185 //- Return either time().constant() or oldInstance
2186 Foam::word Foam::meshRefinement::timeName() const
2188 if (overwrite_ && mesh_.time().timeIndex() == 0)
2190 return oldInstance_;
2194 return mesh_.time().timeName();
2199 void Foam::meshRefinement::dumpRefinementLevel() const
2201 // Note: use time().timeName(), not meshRefinement::timeName()
2202 // so as to dump the fields to 0, not to constant.
2203 volScalarField volRefLevel
2208 mesh_.time().timeName(),
2211 IOobject::AUTO_WRITE,
2215 dimensionedScalar("zero", dimless, 0),
2216 zeroGradientFvPatchScalarField::typeName
2219 const labelList& cellLevel = meshCutter_.cellLevel();
2221 forAll(volRefLevel, cellI)
2223 volRefLevel[cellI] = cellLevel[cellI];
2226 volRefLevel.write();
2229 const pointMesh& pMesh = pointMesh::New(mesh_);
2231 pointScalarField pointRefLevel
2236 mesh_.time().timeName(),
2243 dimensionedScalar("zero", dimless, 0)
2246 const labelList& pointLevel = meshCutter_.pointLevel();
2248 forAll(pointRefLevel, pointI)
2250 pointRefLevel[pointI] = pointLevel[pointI];
2253 pointRefLevel.write();
2257 void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
2260 const pointField& cellCentres = mesh_.cellCentres();
2262 OFstream str(prefix + "_edges.obj");
2264 Pout<< "meshRefinement::dumpIntersections :"
2265 << " Writing cellcentre-cellcentre intersections to file "
2266 << str.name() << endl;
2269 // Redo all intersections
2270 // ~~~~~~~~~~~~~~~~~~~~~~
2272 // Get boundary face centre and level. Coupled aware.
2273 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2274 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2275 calcNeighbourData(neiLevel, neiCc);
2277 labelList intersectionFaces(intersectedFaces());
2279 // Collect segments we want to test for
2280 pointField start(intersectionFaces.size());
2281 pointField end(intersectionFaces.size());
2283 forAll(intersectionFaces, i)
2285 label faceI = intersectionFaces[i];
2286 start[i] = cellCentres[mesh_.faceOwner()[faceI]];
2288 if (mesh_.isInternalFace(faceI))
2290 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
2294 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
2298 // Extend segments a bit
2300 const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
2306 // Do tests in one go
2307 labelList surfaceHit;
2308 List<pointIndexHit> surfaceHitInfo;
2309 surfaces_.findAnyIntersection
2317 forAll(intersectionFaces, i)
2319 if (surfaceHit[i] != -1)
2321 meshTools::writeOBJ(str, start[i]);
2323 meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
2325 meshTools::writeOBJ(str, end[i]);
2327 str << "l " << vertI-2 << ' ' << vertI-1 << nl
2328 << "l " << vertI-1 << ' ' << vertI << nl;
2333 // Convert to vtk format
2336 "objToVTK " + prefix + "_edges.obj " + prefix + "_edges.vtk > /dev/null"
2338 system(cmd.c_str());
2344 void Foam::meshRefinement::write
2347 const fileName& prefix
2354 if (flag & SCALARLEVELS)
2356 dumpRefinementLevel();
2358 if (flag & OBJINTERSECTIONS && prefix.size())
2360 dumpIntersections(prefix);
2365 // ************************************************************************* //