1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 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
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"
27 #include <finiteVolume/volMesh.H>
28 #include <finiteVolume/volFields.H>
29 #include <finiteVolume/surfaceMesh.H>
30 #include <OpenFOAM/syncTools.H>
31 #include <OpenFOAM/Time.H>
32 #include <dynamicMesh/refinementHistory.H>
33 #include <autoMesh/refinementSurfaces.H>
34 #include <decompositionMethods/decompositionMethod.H>
35 #include <meshTools/regionSplit.H>
36 #include <dynamicMesh/fvMeshDistribute.H>
37 #include <OpenFOAM/indirectPrimitivePatch.H>
38 #include <dynamicMesh/polyTopoChange.H>
39 #include <dynamicMesh/removeCells.H>
40 #include <OpenFOAM/mapDistributePolyMesh.H>
41 #include <dynamicMesh/localPointRegion.H>
42 #include <OpenFOAM/pointMesh.H>
43 #include <OpenFOAM/pointFields.H>
44 #include <OpenFOAM/slipPointPatchFields.H>
45 #include <OpenFOAM/fixedValuePointPatchFields.H>
46 #include <OpenFOAM/globalPointPatchFields.H>
47 #include <OpenFOAM/calculatedPointPatchFields.H>
48 #include <OpenFOAM/processorPointPatch.H>
49 #include <OpenFOAM/globalIndex.H>
50 #include <meshTools/meshTools.H>
51 #include <OpenFOAM/OFstream.H>
52 #include <decompositionMethods/geomDecomp.H>
53 #include <OpenFOAM/Random.H>
54 #include <meshTools/searchableSurfaces.H>
55 #include <meshTools/treeBoundBox.H>
56 #include <finiteVolume/zeroGradientFvPatchFields.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 labelHashSet addedPatchIDSet = meshedPatches();
89 forAll(patches, patchI)
91 const polyPatch& pp = patches[patchI];
93 const unallocLabelList& faceCells = pp.faceCells();
94 const vectorField::subField faceCentres = pp.faceCentres();
95 const vectorField::subField faceAreas = pp.faceAreas();
97 label bFaceI = pp.start()-mesh_.nInternalFaces();
103 neiLevel[bFaceI] = cellLevel[faceCells[i]];
104 neiCc[bFaceI] = cellCentres[faceCells[i]];
108 else if (addedPatchIDSet.found(patchI))
110 // Face was introduced from cell-cell intersection. Try to
111 // reconstruct other side cell(centre). Three possibilities:
112 // - cells same size.
113 // - preserved cell smaller. Not handled.
114 // - preserved cell larger.
117 // Extrapolate the face centre.
118 vector fn = faceAreas[i];
119 fn /= mag(fn)+VSMALL;
121 label own = faceCells[i];
122 label ownLevel = cellLevel[own];
123 label faceLevel = meshCutter_.getAnchorLevel(pp.start()+i);
125 // Normal distance from face centre to cell centre
126 scalar d = ((faceCentres[i] - cellCentres[own]) & fn);
127 if (faceLevel > ownLevel)
129 // Other cell more refined. Adjust normal distance
132 neiLevel[bFaceI] = cellLevel[ownLevel];
133 // Calculate other cell centre by extrapolation
134 neiCc[bFaceI] = faceCentres[i] + d*fn;
142 neiLevel[bFaceI] = cellLevel[faceCells[i]];
143 neiCc[bFaceI] = faceCentres[i];
149 // Swap coupled boundaries. Apply separation to cc since is coordinate.
150 syncTools::swapBoundaryFaceList(mesh_, neiCc, true);
151 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
155 // Find intersections of edges (given by their two endpoints) with surfaces.
156 // Returns first intersection if there are more than one.
157 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
159 const pointField& cellCentres = mesh_.cellCentres();
161 // Stats on edges to test. Count proc faces only once.
162 PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
165 label nMasterFaces = 0;
166 forAll(isMasterFace, faceI)
168 if (isMasterFace.get(faceI) == 1)
173 reduce(nMasterFaces, sumOp<label>());
175 label nChangedFaces = 0;
176 forAll(changedFaces, i)
178 if (isMasterFace.get(changedFaces[i]) == 1)
183 reduce(nChangedFaces, sumOp<label>());
185 Info<< "Edge intersection testing:" << nl
186 << " Number of edges : " << nMasterFaces << nl
187 << " Number of edges to retest : " << nChangedFaces
192 // Get boundary face centre and level. Coupled aware.
193 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
194 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
195 calcNeighbourData(neiLevel, neiCc);
197 // Collect segments we want to test for
198 pointField start(changedFaces.size());
199 pointField end(changedFaces.size());
201 forAll(changedFaces, i)
203 label faceI = changedFaces[i];
204 label own = mesh_.faceOwner()[faceI];
206 start[i] = cellCentres[own];
207 if (mesh_.isInternalFace(faceI))
209 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
213 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
217 // Do tests in one go
218 labelList surfaceHit;
220 labelList surfaceLevel;
221 surfaces_.findHigherIntersection
225 labelList(start.size(), -1), // accept any intersection
231 // Keep just surface hit
232 forAll(surfaceHit, i)
234 surfaceIndex_[changedFaces[i]] = surfaceHit[i];
237 // Make sure both sides have same information. This should be
238 // case in general since same vectors but just to make sure.
239 syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>(), false);
241 label nHits = countHits();
242 label nTotHits = returnReduce(nHits, sumOp<label>());
244 Info<< " Number of intersected edges : " << nTotHits << endl;
246 // Set files to same time as mesh
247 setInstance(mesh_.facesInstance());
251 void Foam::meshRefinement::checkData()
253 Pout<< "meshRefinement::checkData() : Checking refinement structure."
255 meshCutter_.checkMesh();
257 Pout<< "meshRefinement::checkData() : Checking refinement levels."
259 meshCutter_.checkRefinementLevels(1, labelList(0));
262 label nBnd = mesh_.nFaces()-mesh_.nInternalFaces();
264 Pout<< "meshRefinement::checkData() : Checking synchronization."
267 // Check face centres
269 // Boundary face centres
270 pointField::subList boundaryFc
274 mesh_.nInternalFaces()
277 // Get neighbouring face centres
278 pointField neiBoundaryFc(boundaryFc);
279 syncTools::swapBoundaryFaceList
287 testSyncBoundaryFaceList
290 "testing faceCentres : ",
295 // Check meshRefinement
297 // Get boundary face centre and level. Coupled aware.
298 labelList neiLevel(nBnd);
299 pointField neiCc(nBnd);
300 calcNeighbourData(neiLevel, neiCc);
302 // Collect segments we want to test for
303 pointField start(mesh_.nFaces());
304 pointField end(mesh_.nFaces());
308 start[faceI] = mesh_.cellCentres()[mesh_.faceOwner()[faceI]];
310 if (mesh_.isInternalFace(faceI))
312 end[faceI] = mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]];
316 end[faceI] = neiCc[faceI-mesh_.nInternalFaces()];
320 // Do tests in one go
321 labelList surfaceHit;
323 labelList surfaceLevel;
324 surfaces_.findHigherIntersection
328 labelList(start.size(), -1), // accept any intersection
333 // Get the coupled hit
340 mesh_.nInternalFaces()
343 syncTools::swapBoundaryFaceList(mesh_, neiHit, false);
346 forAll(surfaceHit, faceI)
348 if (surfaceIndex_[faceI] != surfaceHit[faceI])
350 if (mesh_.isInternalFace(faceI))
352 WarningIn("meshRefinement::checkData()")
353 << "Internal face:" << faceI
354 << " fc:" << mesh_.faceCentres()[faceI]
355 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
356 << " current:" << surfaceHit[faceI]
358 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
360 << mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]]
366 != neiHit[faceI-mesh_.nInternalFaces()]
369 WarningIn("meshRefinement::checkData()")
370 << "Boundary face:" << faceI
371 << " fc:" << mesh_.faceCentres()[faceI]
372 << " cached surfaceIndex_:" << surfaceIndex_[faceI]
373 << " current:" << surfaceHit[faceI]
375 << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
376 << " end:" << end[faceI]
383 labelList::subList boundarySurface
386 mesh_.nFaces()-mesh_.nInternalFaces(),
387 mesh_.nInternalFaces()
390 labelList neiBoundarySurface(boundarySurface);
391 syncTools::swapBoundaryFaceList
399 testSyncBoundaryFaceList
402 "testing surfaceIndex() : ",
409 // Find duplicate faces
410 Pout<< "meshRefinement::checkData() : Counting duplicate faces."
413 labelList duplicateFace
415 localPointRegion::findDuplicateFaces
418 identity(mesh_.nFaces()-mesh_.nInternalFaces())
419 + mesh_.nInternalFaces()
427 forAll(duplicateFace, i)
429 if (duplicateFace[i] != -1)
434 nDup /= 2; // will have counted both faces of duplicate
435 Pout<< "meshRefinement::checkData() : Found " << nDup
436 << " duplicate pairs of faces." << endl;
441 void Foam::meshRefinement::setInstance(const fileName& inst)
443 meshCutter_.setInstance(inst);
444 surfaceIndex_.instance() = inst;
448 // Remove cells. Put exposedFaces (output of getExposedFaces(cellsToRemove))
449 // into exposedPatchIDs.
450 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells
452 const labelList& cellsToRemove,
453 const labelList& exposedFaces,
454 const labelList& exposedPatchIDs,
455 removeCells& cellRemover
458 polyTopoChange meshMod(mesh_);
460 // Arbitrary: put exposed faces into last patch.
461 cellRemover.setRefinement
469 // Change the mesh (no inflation)
470 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
473 mesh_.updateMesh(map);
475 // Move mesh (since morphing might not do this)
476 if (map().hasMotionPoints())
478 mesh_.movePoints(map().preMotionPoints());
482 // Delete mesh volumes. No other way to do this?
488 mesh_.setInstance(oldInstance_);
491 // Update local mesh data
492 cellRemover.updateMesh(map);
494 // Update intersections. Recalculate intersections for exposed faces.
495 labelList newExposedFaces = renumber
497 map().reverseFaceMap(),
501 //Pout<< "removeCells : updating intersections for "
502 // << newExposedFaces.size() << " newly exposed faces." << endl;
504 updateMesh(map, newExposedFaces);
510 // Determine for multi-processor regions the lowest numbered cell on the lowest
511 // numbered processor.
512 void Foam::meshRefinement::getCoupledRegionMaster
514 const globalIndex& globalCells,
515 const boolList& blockedFace,
516 const regionSplit& globalRegion,
517 Map<label>& regionToMaster
520 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
522 forAll(patches, patchI)
524 const polyPatch& pp = patches[patchI];
526 if (isA<processorPolyPatch>(pp))
530 label faceI = pp.start()+i;
532 if (!blockedFace[faceI])
534 // Only if there is a connection to the neighbour
535 // will there be a multi-domain region; if not through
536 // this face then through another.
538 label cellI = mesh_.faceOwner()[faceI];
539 label globalCellI = globalCells.toGlobal(cellI);
541 Map<label>::iterator iter =
542 regionToMaster.find(globalRegion[cellI]);
544 if (iter != regionToMaster.end())
546 label master = iter();
547 iter() = min(master, globalCellI);
551 regionToMaster.insert
563 Pstream::mapCombineGather(regionToMaster, minEqOp<label>());
564 Pstream::mapCombineScatter(regionToMaster);
568 void Foam::meshRefinement::calcLocalRegions
570 const globalIndex& globalCells,
571 const labelList& globalRegion,
572 const Map<label>& coupledRegionToMaster,
573 const scalarField& cellWeights,
575 Map<label>& globalToLocalRegion,
576 pointField& localPoints,
577 scalarField& localWeights
580 globalToLocalRegion.resize(globalRegion.size());
581 DynamicList<point> localCc(globalRegion.size()/2);
582 DynamicList<scalar> localWts(globalRegion.size()/2);
584 forAll(globalRegion, cellI)
586 Map<label>::const_iterator fndMaster =
587 coupledRegionToMaster.find(globalRegion[cellI]);
589 if (fndMaster != coupledRegionToMaster.end())
591 // Multi-processor region.
592 if (globalCells.toGlobal(cellI) == fndMaster())
594 // I am master. Allocate region for me.
595 globalToLocalRegion.insert(globalRegion[cellI], localCc.size());
596 localCc.append(mesh_.cellCentres()[cellI]);
597 localWts.append(cellWeights[cellI]);
602 // Single processor region.
603 if (globalToLocalRegion.insert(globalRegion[cellI], localCc.size()))
605 localCc.append(mesh_.cellCentres()[cellI]);
606 localWts.append(cellWeights[cellI]);
611 localPoints.transfer(localCc);
612 localWeights.transfer(localWts);
614 if (localPoints.size() != globalToLocalRegion.size())
616 FatalErrorIn("calcLocalRegions(..)")
617 << "localPoints:" << localPoints.size()
618 << " globalToLocalRegion:" << globalToLocalRegion.size()
624 Foam::label Foam::meshRefinement::getShiftedRegion
626 const globalIndex& indexer,
627 const Map<label>& globalToLocalRegion,
628 const Map<label>& coupledRegionToShifted,
629 const label globalRegion
632 Map<label>::const_iterator iter =
633 globalToLocalRegion.find(globalRegion);
635 if (iter != globalToLocalRegion.end())
637 // Region is 'owned' locally. Convert local region index into global.
638 return indexer.toGlobal(iter());
642 return coupledRegionToShifted[globalRegion];
647 // Add if not yet present
648 void Foam::meshRefinement::addUnique(const label elem, labelList& lst)
650 if (findIndex(lst, elem) == -1)
652 label sz = lst.size();
659 void Foam::meshRefinement::calcRegionRegions
661 const labelList& globalRegion,
662 const Map<label>& globalToLocalRegion,
663 const Map<label>& coupledRegionToMaster,
664 labelListList& regionRegions
667 // Global region indexing since we now know the shifted regions.
668 globalIndex shiftIndexer(globalToLocalRegion.size());
670 // Redo the coupledRegionToMaster to be in shifted region indexing.
671 Map<label> coupledRegionToShifted(coupledRegionToMaster.size());
672 forAllConstIter(Map<label>, coupledRegionToMaster, iter)
674 label region = iter.key();
676 Map<label>::const_iterator fndRegion = globalToLocalRegion.find(region);
678 if (fndRegion != globalToLocalRegion.end())
680 // A local cell is master of this region. Get its shifted region.
681 coupledRegionToShifted.insert
684 shiftIndexer.toGlobal(fndRegion())
687 Pstream::mapCombineGather(coupledRegionToShifted, minEqOp<label>());
688 Pstream::mapCombineScatter(coupledRegionToShifted);
692 // Determine region-region connectivity.
693 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
694 // This is for all my regions (so my local ones or the ones I am master
695 // of) the neighbouring region indices.
699 PtrList<HashSet<edge, Hash<edge> > > regionConnectivity(Pstream::nProcs());
700 forAll(regionConnectivity, procI)
702 if (procI != Pstream::myProcNo())
704 regionConnectivity.set
707 new HashSet<edge, Hash<edge> >
709 coupledRegionToShifted.size()
717 // Connectivity. For all my local regions the connected regions.
718 regionRegions.setSize(globalToLocalRegion.size());
720 // Add all local connectivity to regionRegions; add all non-local
721 // to the transferlists.
722 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
724 label ownRegion = globalRegion[mesh_.faceOwner()[faceI]];
725 label neiRegion = globalRegion[mesh_.faceNeighbour()[faceI]];
727 if (ownRegion != neiRegion)
729 label shiftOwnRegion = getShiftedRegion
733 coupledRegionToShifted,
736 label shiftNeiRegion = getShiftedRegion
740 coupledRegionToShifted,
745 // Connection between two regions. Send to owner of region.
746 // - is ownRegion 'owned' by me
747 // - is neiRegion 'owned' by me
749 if (shiftIndexer.isLocal(shiftOwnRegion))
751 label localI = shiftIndexer.toLocal(shiftOwnRegion);
752 addUnique(shiftNeiRegion, regionRegions[localI]);
756 label masterProc = shiftIndexer.whichProcID(shiftOwnRegion);
757 regionConnectivity[masterProc].insert
759 edge(shiftOwnRegion, shiftNeiRegion)
763 if (shiftIndexer.isLocal(shiftNeiRegion))
765 label localI = shiftIndexer.toLocal(shiftNeiRegion);
766 addUnique(shiftOwnRegion, regionRegions[localI]);
770 label masterProc = shiftIndexer.whichProcID(shiftNeiRegion);
771 regionConnectivity[masterProc].insert
773 edge(shiftOwnRegion, shiftNeiRegion)
781 forAll(regionConnectivity, procI)
783 if (procI != Pstream::myProcNo())
785 OPstream str(Pstream::blocking, procI);
786 str << regionConnectivity[procI];
790 forAll(regionConnectivity, procI)
792 if (procI != Pstream::myProcNo())
794 IPstream str(Pstream::blocking, procI);
795 str >> regionConnectivity[procI];
799 // Add to addressing.
800 forAll(regionConnectivity, procI)
802 if (procI != Pstream::myProcNo())
806 HashSet<edge, Hash<edge> >::const_iterator iter =
807 regionConnectivity[procI].begin();
808 iter != regionConnectivity[procI].end();
812 const edge& e = iter.key();
814 bool someLocal = false;
815 if (shiftIndexer.isLocal(e[0]))
817 label localI = shiftIndexer.toLocal(e[0]);
818 addUnique(e[1], regionRegions[localI]);
821 if (shiftIndexer.isLocal(e[1]))
823 label localI = shiftIndexer.toLocal(e[1]);
824 addUnique(e[0], regionRegions[localI]);
830 FatalErrorIn("calcRegionRegions(..)")
831 << "Received from processor " << procI
832 << " connection " << e
833 << " where none of the elements is local to me."
834 << abort(FatalError);
842 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
844 // Construct from components
845 Foam::meshRefinement::meshRefinement
848 const scalar mergeDistance,
849 const bool overwrite,
850 const refinementSurfaces& surfaces,
851 const shellSurfaces& shells
855 mergeDistance_(mergeDistance),
856 overwrite_(overwrite),
857 oldInstance_(mesh.pointsInstance()),
868 mesh_.facesInstance(),
871 IOobject::READ_IF_PRESENT,
875 labelList(mesh_.nCells(), 0)
882 mesh_.facesInstance(),
885 IOobject::READ_IF_PRESENT,
889 labelList(mesh_.nPoints(), 0)
896 mesh_.facesInstance(),
903 List<refinementHistory::splitCell8>(0),
912 mesh_.facesInstance(),
919 labelList(mesh_.nFaces(), -1)
923 // recalculate intersections for all faces
924 updateIntersections(identity(mesh_.nFaces()));
928 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
930 Foam::label Foam::meshRefinement::countHits() const
932 // Stats on edges to test. Count proc faces only once.
933 PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
937 forAll(surfaceIndex_, faceI)
939 if (surfaceIndex_[faceI] >= 0 && isMasterFace.get(faceI) == 1)
948 // Determine distribution to move connected regions onto one processor.
949 Foam::labelList Foam::meshRefinement::decomposeCombineRegions
951 const scalarField& cellWeights,
952 const boolList& blockedFace,
953 const List<labelPair>& explicitConnections,
954 decompositionMethod& decomposer
957 // Determine global regions, separated by blockedFaces
958 regionSplit globalRegion(mesh_, blockedFace, explicitConnections);
960 // Now globalRegion has global region per cell. Problem is that
961 // the region might span multiple domains so we want to get
962 // a "region master" per domain. Note that multi-processor
963 // regions can only occur on cells on coupled patches.
964 // Note: since the number of regions does not change by this the
965 // process can be seen as just a shift of a region onto a single
969 // Global cell numbering engine
970 globalIndex globalCells(mesh_.nCells());
973 // Determine per coupled region the master cell (lowest numbered cell
974 // on lowest numbered processor)
975 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
976 // (does not determine master for non-coupled=fully-local regions)
978 Map<label> coupledRegionToMaster(mesh_.nFaces()-mesh_.nInternalFaces());
979 getCoupledRegionMaster
984 coupledRegionToMaster
987 // Determine my regions
988 // ~~~~~~~~~~~~~~~~~~~~
989 // These are the fully local ones or the coupled ones of which I am master.
991 Map<label> globalToLocalRegion;
992 pointField localPoints;
993 scalarField localWeights;
998 coupledRegionToMaster,
1001 globalToLocalRegion,
1008 // Find distribution for regions
1009 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1011 labelList regionDistribution;
1013 if (isA<geomDecomp>(decomposer))
1015 regionDistribution = decomposer.decompose(localPoints, localWeights);
1019 labelListList regionRegions;
1023 globalToLocalRegion,
1024 coupledRegionToMaster,
1029 regionDistribution = decomposer.decompose
1039 // Convert region-based decomposition back to cell-based one
1040 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1042 // Transfer destination processor back to all. Use global reduce for now.
1043 Map<label> regionToDist(coupledRegionToMaster.size());
1044 forAllConstIter(Map<label>, coupledRegionToMaster, iter)
1046 label region = iter.key();
1048 Map<label>::const_iterator regionFnd = globalToLocalRegion.find(region);
1050 if (regionFnd != globalToLocalRegion.end())
1052 // Master cell is local. Store my distribution.
1053 regionToDist.insert(iter.key(), regionDistribution[regionFnd()]);
1057 // Master cell is not on this processor. Make sure it is overridden.
1058 regionToDist.insert(iter.key(), labelMax);
1061 Pstream::mapCombineGather(regionToDist, minEqOp<label>());
1062 Pstream::mapCombineScatter(regionToDist);
1065 // Determine destination for all cells
1066 labelList distribution(mesh_.nCells());
1068 forAll(globalRegion, cellI)
1070 Map<label>::const_iterator fndRegion =
1071 regionToDist.find(globalRegion[cellI]);
1073 if (fndRegion != regionToDist.end())
1075 distribution[cellI] = fndRegion();
1079 // region is local to the processor.
1080 label localRegionI = globalToLocalRegion[globalRegion[cellI]];
1082 distribution[cellI] = regionDistribution[localRegionI];
1086 return distribution;
1090 Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance
1092 const bool keepZoneFaces,
1093 const bool keepBaffles,
1094 const scalarField& cellWeights,
1095 decompositionMethod& decomposer,
1096 fvMeshDistribute& distributor
1099 autoPtr<mapDistributePolyMesh> map;
1101 if (Pstream::parRun())
1105 // const_cast<Time&>(mesh_.time())++;
1108 // Wanted distribution
1109 labelList distribution;
1111 if (keepZoneFaces || keepBaffles)
1113 // Faces where owner and neighbour are not 'connected' so can
1114 // go to different processors.
1115 boolList blockedFace(mesh_.nFaces(), true);
1116 label nUnblocked = 0;
1118 List<labelPair> couples;
1122 // Determine decomposition to keep/move surface zones
1123 // on one processor. The reason is that snapping will make these
1124 // into baffles, move and convert them back so if they were
1125 // proc boundaries after baffling&moving the points might be no
1126 // longer snychronised so recoupling will fail. To prevent this
1127 // keep owner&neighbour of such a surface zone on the same
1130 const wordList& fzNames = surfaces().faceZoneNames();
1131 const faceZoneMesh& fZones = mesh_.faceZones();
1133 // Get faces whose owner and neighbour should stay together,
1134 // i.e. they are not 'blocked'.
1136 forAll(fzNames, surfI)
1138 if (fzNames[surfI].size())
1141 label zoneI = fZones.findZoneID(fzNames[surfI]);
1143 const faceZone& fZone = fZones[zoneI];
1147 if (blockedFace[fZone[i]])
1149 blockedFace[fZone[i]] = false;
1157 // If the faceZones are not synchronised the blockedFace
1158 // might not be synchronised. If you are sure the faceZones
1159 // are synchronised remove below check.
1160 syncTools::syncFaceList
1164 andEqOp<bool>(), // combine operator
1168 reduce(nUnblocked, sumOp<label>());
1172 Info<< "Found " << nUnblocked
1173 << " zoned faces to keep together." << endl;
1178 // Get boundary baffles that need to stay together.
1179 couples = getDuplicateFaces // all baffles
1181 identity(mesh_.nFaces()-mesh_.nInternalFaces())
1182 +mesh_.nInternalFaces()
1185 label nCouples = returnReduce(couples.size(), sumOp<label>());
1189 Info<< "Found " << nCouples << " baffles to keep together."
1193 if (nUnblocked > 0 || nCouples > 0)
1195 Info<< "Applying special decomposition to keep baffles"
1196 << " and zoned faces together." << endl;
1198 distribution = decomposeCombineRegions
1206 labelList nProcCells(distributor.countCells(distribution));
1207 Pstream::listCombineGather(nProcCells, plusEqOp<label>());
1208 Pstream::listCombineScatter(nProcCells);
1210 Info<< "Calculated decomposition:" << endl;
1211 forAll(nProcCells, procI)
1213 Info<< " " << procI << '\t' << nProcCells[procI] << endl;
1219 // Normal decomposition
1220 distribution = decomposer.decompose
1222 mesh_.cellCentres(),
1229 // Normal decomposition
1230 distribution = decomposer.decompose
1232 mesh_.cellCentres(),
1239 labelList nProcCells(distributor.countCells(distribution));
1240 Pout<< "Wanted distribution:" << nProcCells << endl;
1242 Pstream::listCombineGather(nProcCells, plusEqOp<label>());
1243 Pstream::listCombineScatter(nProcCells);
1245 Pout<< "Wanted resulting decomposition:" << endl;
1246 forAll(nProcCells, procI)
1248 Pout<< " " << procI << '\t' << nProcCells[procI] << endl;
1252 // Do actual sending/receiving of mesh
1253 map = distributor.distribute(distribution);
1255 // Update numbering of meshRefiner
1262 // Helper function to get intersected faces
1263 Foam::labelList Foam::meshRefinement::intersectedFaces() const
1265 label nBoundaryFaces = 0;
1267 forAll(surfaceIndex_, faceI)
1269 if (surfaceIndex_[faceI] != -1)
1275 labelList surfaceFaces(nBoundaryFaces);
1278 forAll(surfaceIndex_, faceI)
1280 if (surfaceIndex_[faceI] != -1)
1282 surfaceFaces[nBoundaryFaces++] = faceI;
1285 return surfaceFaces;
1289 // Helper function to get points used by faces
1290 Foam::labelList Foam::meshRefinement::intersectedPoints() const
1292 const faceList& faces = mesh_.faces();
1294 // Mark all points on faces that will become baffles
1295 PackedBoolList isBoundaryPoint(mesh_.nPoints());
1296 label nBoundaryPoints = 0;
1298 forAll(surfaceIndex_, faceI)
1300 if (surfaceIndex_[faceI] != -1)
1302 const face& f = faces[faceI];
1306 if (isBoundaryPoint.set(f[fp], 1u))
1314 //// Insert all meshed patches.
1315 //labelList adaptPatchIDs(meshedPatches());
1316 //forAll(adaptPatchIDs, i)
1318 // label patchI = adaptPatchIDs[i];
1320 // if (patchI != -1)
1322 // const polyPatch& pp = mesh_.boundaryMesh()[patchI];
1324 // label faceI = pp.start();
1328 // const face& f = faces[faceI];
1332 // if (isBoundaryPoint.set(f[fp], 1u))
1333 // nBoundaryPoints++;
1343 labelList boundaryPoints(nBoundaryPoints);
1344 nBoundaryPoints = 0;
1345 forAll(isBoundaryPoint, pointI)
1347 if (isBoundaryPoint.get(pointI) == 1u)
1349 boundaryPoints[nBoundaryPoints++] = pointI;
1353 return boundaryPoints;
1357 //- Create patch from set of patches
1358 Foam::autoPtr<Foam::indirectPrimitivePatch> Foam::meshRefinement::makePatch
1360 const polyMesh& mesh,
1361 const labelList& patchIDs
1364 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1371 const polyPatch& pp = patches[patchIDs[i]];
1373 nFaces += pp.size();
1377 labelList addressing(nFaces);
1382 const polyPatch& pp = patches[patchIDs[i]];
1384 label meshFaceI = pp.start();
1388 addressing[nFaces++] = meshFaceI++;
1392 return autoPtr<indirectPrimitivePatch>
1394 new indirectPrimitivePatch
1396 IndirectList<face>(mesh.faces(), addressing),
1403 // Construct pointVectorField with correct boundary conditions
1404 Foam::tmp<Foam::pointVectorField> Foam::meshRefinement::makeDisplacementField
1406 const pointMesh& pMesh,
1407 const labelList& adaptPatchIDs
1410 const polyMesh& mesh = pMesh();
1412 // Construct displacement field.
1413 const pointBoundaryMesh& pointPatches = pMesh.boundary();
1415 wordList patchFieldTypes
1417 pointPatches.size(),
1418 slipPointPatchVectorField::typeName
1421 forAll(adaptPatchIDs, i)
1423 patchFieldTypes[adaptPatchIDs[i]] =
1424 fixedValuePointPatchVectorField::typeName;
1427 forAll(pointPatches, patchI)
1429 if (isA<globalPointPatch>(pointPatches[patchI]))
1431 patchFieldTypes[patchI] = globalPointPatchVectorField::typeName;
1433 else if (isA<processorPointPatch>(pointPatches[patchI]))
1435 patchFieldTypes[patchI] = calculatedPointPatchVectorField::typeName;
1439 tmp<pointVectorField> tfld
1441 new pointVectorField
1445 "pointDisplacement",
1446 mesh.time().timeName(), //timeName(),
1449 IOobject::AUTO_WRITE
1452 dimensionedVector("displacement", dimLength, vector::zero),
1461 void Foam::meshRefinement::checkCoupledFaceZones(const polyMesh& mesh)
1463 const faceZoneMesh& fZones = mesh.faceZones();
1465 // Check any zones are present anywhere and in same order
1468 List<wordList> zoneNames(Pstream::nProcs());
1469 zoneNames[Pstream::myProcNo()] = fZones.names();
1470 Pstream::gatherList(zoneNames);
1471 Pstream::scatterList(zoneNames);
1472 // All have same data now. Check.
1473 forAll(zoneNames, procI)
1475 if (procI != Pstream::myProcNo())
1477 if (zoneNames[procI] != zoneNames[Pstream::myProcNo()])
1481 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1482 ) << "faceZones are not synchronised on processors." << nl
1483 << "Processor " << procI << " has faceZones "
1484 << zoneNames[procI] << nl
1485 << "Processor " << Pstream::myProcNo()
1486 << " has faceZones "
1487 << zoneNames[Pstream::myProcNo()] << nl
1488 << exit(FatalError);
1494 // Check that coupled faces are present on both sides.
1496 labelList faceToZone(mesh.nFaces()-mesh.nInternalFaces(), -1);
1498 forAll(fZones, zoneI)
1500 const faceZone& fZone = fZones[zoneI];
1504 label bFaceI = fZone[i]-mesh.nInternalFaces();
1508 if (faceToZone[bFaceI] == -1)
1510 faceToZone[bFaceI] = zoneI;
1512 else if (faceToZone[bFaceI] == zoneI)
1516 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1517 ) << "Face " << fZone[i] << " in zone "
1519 << " is twice in zone!"
1520 << abort(FatalError);
1526 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1527 ) << "Face " << fZone[i] << " in zone "
1529 << " is also in zone "
1530 << fZones[faceToZone[bFaceI]].name()
1531 << abort(FatalError);
1537 labelList neiFaceToZone(faceToZone);
1538 syncTools::swapBoundaryFaceList(mesh, neiFaceToZone, false);
1540 forAll(faceToZone, i)
1542 if (faceToZone[i] != neiFaceToZone[i])
1546 "meshRefinement::checkCoupledFaceZones(const polyMesh&)"
1547 ) << "Face " << mesh.nInternalFaces()+i
1548 << " is in zone " << faceToZone[i]
1549 << ", its coupled face is in zone " << neiFaceToZone[i]
1550 << abort(FatalError);
1556 // Adds patch if not yet there. Returns patchID.
1557 Foam::label Foam::meshRefinement::addPatch
1560 const word& patchName,
1561 const word& patchType
1564 polyBoundaryMesh& polyPatches =
1565 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
1567 label patchI = polyPatches.findPatchID(patchName);
1570 if (polyPatches[patchI].type() == patchType)
1579 // "meshRefinement::addPatch(fvMesh&, const word&, const word&)"
1580 // ) << "Patch " << patchName << " already exists but with type "
1581 // << patchType << nl
1582 // << "Current patch names:" << polyPatches.names()
1583 // << exit(FatalError);
1588 label insertPatchI = polyPatches.size();
1589 label startFaceI = mesh.nFaces();
1591 forAll(polyPatches, patchI)
1593 const polyPatch& pp = polyPatches[patchI];
1595 if (isA<processorPolyPatch>(pp))
1597 insertPatchI = patchI;
1598 startFaceI = pp.start();
1604 // Below is all quite a hack. Feel free to change once there is a better
1605 // mechanism to insert and reorder patches.
1607 // Clear local fields and e.g. polyMesh parallelInfo.
1610 label sz = polyPatches.size();
1612 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
1614 // Add polyPatch at the end
1615 polyPatches.setSize(sz+1);
1629 fvPatches.setSize(sz+1);
1635 polyPatches[sz], // point to newly added polyPatch
1640 addPatchFields<volScalarField>
1643 calculatedFvPatchField<scalar>::typeName
1645 addPatchFields<volVectorField>
1648 calculatedFvPatchField<vector>::typeName
1650 addPatchFields<volSphericalTensorField>
1653 calculatedFvPatchField<sphericalTensor>::typeName
1655 addPatchFields<volSymmTensorField>
1658 calculatedFvPatchField<symmTensor>::typeName
1660 addPatchFields<volTensorField>
1663 calculatedFvPatchField<tensor>::typeName
1668 addPatchFields<surfaceScalarField>
1671 calculatedFvPatchField<scalar>::typeName
1673 addPatchFields<surfaceVectorField>
1676 calculatedFvPatchField<vector>::typeName
1678 addPatchFields<surfaceSphericalTensorField>
1681 calculatedFvPatchField<sphericalTensor>::typeName
1683 addPatchFields<surfaceSymmTensorField>
1686 calculatedFvPatchField<symmTensor>::typeName
1688 addPatchFields<surfaceTensorField>
1691 calculatedFvPatchField<tensor>::typeName
1694 // Create reordering list
1695 // patches before insert position stay as is
1696 labelList oldToNew(sz+1);
1697 for (label i = 0; i < insertPatchI; i++)
1701 // patches after insert position move one up
1702 for (label i = insertPatchI; i < sz; i++)
1706 // appended patch gets moved to insert position
1707 oldToNew[sz] = insertPatchI;
1709 // Shuffle into place
1710 polyPatches.reorder(oldToNew);
1711 fvPatches.reorder(oldToNew);
1713 reorderPatchFields<volScalarField>(mesh, oldToNew);
1714 reorderPatchFields<volVectorField>(mesh, oldToNew);
1715 reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
1716 reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
1717 reorderPatchFields<volTensorField>(mesh, oldToNew);
1718 reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
1719 reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
1720 reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
1721 reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
1722 reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
1724 return insertPatchI;
1728 Foam::label Foam::meshRefinement::addMeshedPatch
1734 label meshedI = findIndex(meshedPatches_, name);
1738 // Already there. Get corresponding polypatch
1739 return mesh_.boundaryMesh().findPatchID(name);
1744 label patchI = addPatch(mesh_, name, type);
1747 label sz = meshedPatches_.size();
1748 meshedPatches_.setSize(sz+1);
1749 meshedPatches_[sz] = name;
1756 Foam::labelList Foam::meshRefinement::meshedPatches() const
1758 labelList patchIDs(meshedPatches_.size());
1759 forAll(meshedPatches_, i)
1761 patchIDs[i] = mesh_.boundaryMesh().findPatchID(meshedPatches_[i]);
1763 if (patchIDs[i] == -1)
1765 FatalErrorIn("meshRefinement::meshedPatches() const")
1766 << "Problem : did not find patch " << meshedPatches_[i]
1767 << abort(FatalError);
1775 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
1777 const point& keepPoint
1780 // Determine connected regions. regionSplit is the labelList with the
1782 regionSplit cellRegion(mesh_);
1786 label cellI = mesh_.findCell(keepPoint);
1790 regionI = cellRegion[cellI];
1793 reduce(regionI, maxOp<label>());
1799 "meshRefinement::splitMeshRegions(const point&)"
1800 ) << "Point " << keepPoint
1801 << " is not inside the mesh." << nl
1802 << "Bounding box of the mesh:" << mesh_.globalData().bb()
1803 << exit(FatalError);
1809 // Get cells to remove
1810 DynamicList<label> cellsToRemove(mesh_.nCells());
1811 forAll(cellRegion, cellI)
1813 if (cellRegion[cellI] != regionI)
1815 cellsToRemove.append(cellI);
1818 cellsToRemove.shrink();
1820 label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
1821 reduce(nCellsToKeep, sumOp<label>());
1823 Info<< "Keeping all cells in region " << regionI
1824 << " containing point " << keepPoint << endl
1825 << "Selected for keeping : "
1827 << " cells." << endl;
1831 removeCells cellRemover(mesh_);
1833 labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
1835 if (exposedFaces.size())
1839 "meshRefinement::splitMeshRegions(const point&)"
1840 ) << "Removing non-reachable cells should only expose boundary faces"
1842 << "ExposedFaces:" << exposedFaces << abort(FatalError);
1845 return doRemoveCells
1849 labelList(exposedFaces.size(),-1), // irrelevant since 0 size.
1855 void Foam::meshRefinement::distribute(const mapDistributePolyMesh& map)
1857 // mesh_ already distributed; distribute my member data
1859 // surfaceQueries_ ok.
1862 meshCutter_.distribute(map);
1864 // surfaceIndex is face data.
1865 map.distributeFaceData(surfaceIndex_);
1867 // maintainedFaces are indices of faces.
1868 forAll(userFaceData_, i)
1870 map.distributeFaceData(userFaceData_[i].second());
1873 // Redistribute surface and any fields on it.
1875 Random rndGen(653213);
1877 // Get local mesh bounding box. Single box for now.
1878 List<treeBoundBox> meshBb(1);
1879 treeBoundBox& bb = meshBb[0];
1880 bb = treeBoundBox(mesh_.points());
1881 bb = bb.extend(rndGen, 1E-4);
1883 // Distribute all geometry (so refinementSurfaces and shellSurfaces)
1884 searchableSurfaces& geometry =
1885 const_cast<searchableSurfaces&>(surfaces_.geometry());
1889 autoPtr<mapDistribute> faceMap;
1890 autoPtr<mapDistribute> pointMap;
1891 geometry[i].distribute
1894 false, // do not keep outside triangles
1899 if (faceMap.valid())
1901 // (ab)use the instance() to signal current modification time
1902 geometry[i].instance() = geometry[i].time().timeName();
1912 void Foam::meshRefinement::updateMesh
1914 const mapPolyMesh& map,
1915 const labelList& changedFaces
1918 Map<label> dummyMap(0);
1920 updateMesh(map, changedFaces, dummyMap, dummyMap, dummyMap);
1924 void Foam::meshRefinement::storeData
1926 const labelList& pointsToStore,
1927 const labelList& facesToStore,
1928 const labelList& cellsToStore
1931 // For now only meshCutter has storable/retrievable data.
1932 meshCutter_.storeData
1941 void Foam::meshRefinement::updateMesh
1943 const mapPolyMesh& map,
1944 const labelList& changedFaces,
1945 const Map<label>& pointsToRestore,
1946 const Map<label>& facesToRestore,
1947 const Map<label>& cellsToRestore
1950 // For now only meshCutter has storable/retrievable data.
1952 // Update numbering of cells/vertices.
1953 meshCutter_.updateMesh
1961 // Update surfaceIndex
1962 updateList(map.faceMap(), -1, surfaceIndex_);
1964 // Update cached intersection information
1965 updateIntersections(changedFaces);
1967 // Update maintained faces
1968 forAll(userFaceData_, i)
1970 labelList& data = userFaceData_[i].second();
1972 if (userFaceData_[i].first() == KEEPALL)
1974 // extend list with face-from-face data
1975 updateList(map.faceMap(), -1, data);
1977 else if (userFaceData_[i].first() == MASTERONLY)
1980 labelList newFaceData(map.faceMap().size(), -1);
1982 forAll(newFaceData, faceI)
1984 label oldFaceI = map.faceMap()[faceI];
1986 if (oldFaceI >= 0 && map.reverseFaceMap()[oldFaceI] == faceI)
1988 newFaceData[faceI] = data[oldFaceI];
1991 data.transfer(newFaceData);
1995 // remove any face that has been refined i.e. referenced more than
1998 // 1. Determine all old faces that get referenced more than once.
1999 // These get marked with -1 in reverseFaceMap
2000 labelList reverseFaceMap(map.reverseFaceMap());
2002 forAll(map.faceMap(), faceI)
2004 label oldFaceI = map.faceMap()[faceI];
2008 if (reverseFaceMap[oldFaceI] != faceI)
2010 // faceI is slave face. Mark old face.
2011 reverseFaceMap[oldFaceI] = -1;
2016 // 2. Map only faces with intact reverseFaceMap
2017 labelList newFaceData(map.faceMap().size(), -1);
2018 forAll(newFaceData, faceI)
2020 label oldFaceI = map.faceMap()[faceI];
2024 if (reverseFaceMap[oldFaceI] == faceI)
2026 newFaceData[faceI] = data[oldFaceI];
2030 data.transfer(newFaceData);
2036 bool Foam::meshRefinement::write() const
2040 && meshCutter_.write()
2041 && surfaceIndex_.write();
2044 // Make sure that any distributed surfaces (so ones which probably have
2045 // been changed) get written as well.
2046 // Note: should ideally have some 'modified' flag to say whether it
2047 // has been changed or not.
2048 searchableSurfaces& geometry =
2049 const_cast<searchableSurfaces&>(surfaces_.geometry());
2053 searchableSurface& s = geometry[i];
2055 // Check if instance() of surface is not constant or system.
2056 // Is good hint that surface is distributed.
2059 s.instance() != s.time().system()
2060 && s.instance() != s.time().caseSystem()
2061 && s.instance() != s.time().constant()
2062 && s.instance() != s.time().caseConstant()
2065 // Make sure it gets written to current time, not constant.
2066 s.instance() = s.time().timeName();
2067 writeOk = writeOk && s.write();
2075 void Foam::meshRefinement::printMeshInfo(const bool debug, const string& msg)
2078 const globalMeshData& pData = mesh_.globalData();
2083 << " : cells(local):" << mesh_.nCells()
2084 << " faces(local):" << mesh_.nFaces()
2085 << " points(local):" << mesh_.nPoints()
2091 << " : cells:" << pData.nTotalCells()
2092 << " faces:" << pData.nTotalFaces()
2093 << " points:" << pData.nTotalPoints()
2100 const labelList& cellLevel = meshCutter_.cellLevel();
2102 labelList nCells(gMax(cellLevel)+1, 0);
2104 forAll(cellLevel, cellI)
2106 nCells[cellLevel[cellI]]++;
2109 Pstream::listCombineGather(nCells, plusEqOp<label>());
2110 Pstream::listCombineScatter(nCells);
2112 Info<< "Cells per refinement level:" << endl;
2113 forAll(nCells, levelI)
2115 Info<< " " << levelI << '\t' << nCells[levelI]
2122 //- Return either time().constant() or oldInstance
2123 Foam::word Foam::meshRefinement::timeName() const
2125 if (overwrite_ && mesh_.time().timeIndex() == 0)
2127 return oldInstance_;
2131 return mesh_.time().timeName();
2136 void Foam::meshRefinement::dumpRefinementLevel() const
2138 volScalarField volRefLevel
2146 IOobject::AUTO_WRITE,
2150 dimensionedScalar("zero", dimless, 0),
2151 zeroGradientFvPatchScalarField::typeName
2154 const labelList& cellLevel = meshCutter_.cellLevel();
2156 forAll(volRefLevel, cellI)
2158 volRefLevel[cellI] = cellLevel[cellI];
2161 volRefLevel.write();
2164 const pointMesh& pMesh = pointMesh::New(mesh_);
2166 pointScalarField pointRefLevel
2178 dimensionedScalar("zero", dimless, 0)
2181 const labelList& pointLevel = meshCutter_.pointLevel();
2183 forAll(pointRefLevel, pointI)
2185 pointRefLevel[pointI] = pointLevel[pointI];
2188 pointRefLevel.write();
2192 void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
2195 const pointField& cellCentres = mesh_.cellCentres();
2197 OFstream str(prefix + "_edges.obj");
2199 Pout<< "meshRefinement::dumpIntersections :"
2200 << " Writing cellcentre-cellcentre intersections to file "
2201 << str.name() << endl;
2204 // Redo all intersections
2205 // ~~~~~~~~~~~~~~~~~~~~~~
2207 // Get boundary face centre and level. Coupled aware.
2208 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2209 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2210 calcNeighbourData(neiLevel, neiCc);
2212 labelList intersectionFaces(intersectedFaces());
2214 // Collect segments we want to test for
2215 pointField start(intersectionFaces.size());
2216 pointField end(intersectionFaces.size());
2218 forAll(intersectionFaces, i)
2220 label faceI = intersectionFaces[i];
2221 start[i] = cellCentres[mesh_.faceOwner()[faceI]];
2223 if (mesh_.isInternalFace(faceI))
2225 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
2229 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
2233 // Do tests in one go
2234 labelList surfaceHit;
2235 List<pointIndexHit> surfaceHitInfo;
2236 surfaces_.findAnyIntersection
2244 forAll(intersectionFaces, i)
2246 if (surfaceHit[i] != -1)
2248 meshTools::writeOBJ(str, start[i]);
2250 meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
2252 meshTools::writeOBJ(str, end[i]);
2254 str << "l " << vertI-2 << ' ' << vertI-1 << nl
2255 << "l " << vertI-1 << ' ' << vertI << nl;
2260 // Convert to vtk format
2263 "objToVTK " + prefix + "_edges.obj " + prefix + "_edges.vtk > /dev/null"
2265 system(cmd.c_str());
2271 void Foam::meshRefinement::write
2274 const fileName& prefix
2281 if (flag & SCALARLEVELS)
2283 dumpRefinementLevel();
2285 if (flag & OBJINTERSECTIONS && prefix.size())
2287 dumpIntersections(prefix);
2292 // ************************ vim: set sw=4 sts=4 et: ************************ //