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"
27 #include "combineFaces.H"
28 #include "polyTopoChange.H"
29 #include "removePoints.H"
32 #include "motionSmoother.H"
33 #include "syncTools.H"
35 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
37 //// Merge faces that are in-line.
38 //Foam::label Foam::meshRefinement::mergePatchFaces
40 // const scalar minCos,
41 // const scalar concaveCos,
42 // const labelList& patchIDs
45 // // Patch face merging engine
46 // combineFaces faceCombiner(mesh_);
48 // const polyBoundaryMesh& patches = mesh_.boundaryMesh();
50 // // Pick up all candidate cells on boundary
51 // labelHashSet boundaryCells(mesh_.nFaces()-mesh_.nInternalFaces());
53 // forAll(patchIDs, i)
55 // label patchI = patchIDs[i];
57 // const polyPatch& patch = patches[patchI];
59 // if (!patch.coupled())
63 // boundaryCells.insert(mesh_.faceOwner()[patch.start()+i]);
68 // // Get all sets of faces that can be merged
69 // labelListList mergeSets
71 // faceCombiner.getMergeSets
79 // label nFaceSets = returnReduce(mergeSets.size(), sumOp<label>());
81 // Info<< "mergePatchFaces : Merging " << nFaceSets
82 // << " sets of faces." << endl;
86 // // Topology changes container
87 // polyTopoChange meshMod(mesh_);
89 // // Merge all faces of a set into the first face of the set. Remove
91 // faceCombiner.setRefinement(mergeSets, meshMod);
93 // // Change the mesh (no inflation)
94 // autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
97 // mesh_.updateMesh(map);
99 // // Move mesh (since morphing does not do this)
100 // if (map().hasMotionPoints())
102 // mesh_.movePoints(map().preMotionPoints());
106 // // Delete mesh volumes. No other way to do this?
111 // // Reset the instance for if in overwrite mode
112 // mesh_.setInstance(timeName());
114 // faceCombiner.updateMesh(map);
116 // // Get the kept faces that need to be recalculated.
117 // // Merging two boundary faces might shift the cell centre
118 // // (unless the faces are absolutely planar)
119 // labelHashSet retestFaces(6*mergeSets.size());
121 // forAll(mergeSets, setI)
123 // label oldMasterI = mergeSets[setI][0];
125 // label faceI = map().reverseFaceMap()[oldMasterI];
127 // // faceI is always uncoupled boundary face
128 // const cell& cFaces = mesh_.cells()[mesh_.faceOwner()[faceI]];
132 // retestFaces.insert(cFaces[i]);
135 // updateMesh(map, retestFaces.toc());
143 //// Remove points not used by any face or points used by only two faces where
144 //// the edges are in line
145 //Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::mergeEdges
147 // const scalar minCos
150 // // Point removal analysis engine
151 // removePoints pointRemover(mesh_);
153 // // Count usage of points
154 // boolList pointCanBeDeleted;
155 // label nRemove = pointRemover.countPointUsage(minCos, pointCanBeDeleted);
157 // Info<< "Removing " << nRemove
158 // << " straight edge points." << endl;
160 // autoPtr<mapPolyMesh> map;
164 // // Save my local faces that will change. These changed faces might
165 // // cause a shift in the cell centre which needs to be retested.
166 // // Have to do this before changing mesh since point will be removed.
167 // labelHashSet retestOldFaces(nRemove / Pstream::nProcs());
170 // const faceList& faces = mesh_.faces();
172 // forAll(faces, faceI)
174 // const face& f = faces[faceI];
178 // if (pointCanBeDeleted[f[fp]])
180 // retestOldFaces.insert(faceI);
187 // // Topology changes container
188 // polyTopoChange meshMod(mesh_);
190 // pointRemover.setRefinement(pointCanBeDeleted, meshMod);
192 // // Change the mesh (no inflation)
193 // map = meshMod.changeMesh(mesh_, false, true);
196 // mesh_.updateMesh(map);
198 // // Move mesh (since morphing does not do this)
199 // if (map().hasMotionPoints())
201 // mesh_.movePoints(map().preMotionPoints());
205 // // Delete mesh volumes. No other way to do this?
209 // // Reset the instance for if in overwrite mode
210 // mesh_.setInstance(timeName());
212 // pointRemover.updateMesh(map);
214 // // Get the kept faces that need to be recalculated.
215 // labelHashSet retestFaces(6*retestOldFaces.size());
217 // const cellList& cells = mesh_.cells();
219 // forAllConstIter(labelHashSet, retestOldFaces, iter)
221 // label faceI = map().reverseFaceMap()[iter.key()];
223 // const cell& ownFaces = cells[mesh_.faceOwner()[faceI]];
225 // forAll(ownFaces, i)
227 // retestFaces.insert(ownFaces[i]);
230 // if (mesh_.isInternalFace(faceI))
232 // const cell& neiFaces = cells[mesh_.faceNeighbour()[faceI]];
234 // forAll(neiFaces, i)
236 // retestFaces.insert(neiFaces[i]);
240 // updateMesh(map, retestFaces.toc());
247 Foam::label Foam::meshRefinement::mergePatchFacesUndo
250 const scalar concaveCos,
251 const labelList& patchIDs,
252 const dictionary& motionDict
255 // Patch face merging engine
256 combineFaces faceCombiner(mesh_, true);
258 // Pick up all candidate cells on boundary
259 labelHashSet boundaryCells(mesh_.nFaces()-mesh_.nInternalFaces());
262 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
266 label patchI = patchIDs[i];
268 const polyPatch& patch = patches[patchI];
270 if (!patch.coupled())
274 boundaryCells.insert(mesh_.faceOwner()[patch.start()+i]);
280 // Get all sets of faces that can be merged. Since only faces on the same
281 // patch get merged there is no risk of e.g. patchID faces getting merged
282 // with original patches (or even processor patches). There is a risk
283 // though of original patchfaces getting merged if they make a small
284 // angle. Would be pretty weird starting mesh though.
285 labelListList allFaceSets
287 faceCombiner.getMergeSets
295 label nFaceSets = returnReduce(allFaceSets.size(), sumOp<label>());
297 Info<< "Merging " << nFaceSets << " sets of faces." << nl << endl;
303 faceSet allSets(mesh_, "allFaceSets", allFaceSets.size());
304 forAll(allFaceSets, setI)
306 forAll(allFaceSets[setI], i)
308 allSets.insert(allFaceSets[setI][i]);
311 Pout<< "Writing all faces to be merged to set "
312 << allSets.objectPath() << endl;
313 allSets.instance() = timeName();
316 const_cast<Time&>(mesh_.time())++;
320 // Topology changes container
321 polyTopoChange meshMod(mesh_);
323 // Merge all faces of a set into the first face of the set.
324 faceCombiner.setRefinement(allFaceSets, meshMod);
326 // Experimental: store data for all the points that have been deleted
329 faceCombiner.savedPointLabels(), // points to store
330 labelList(0), // faces to store
331 labelList(0) // cells to store
334 // Change the mesh (no inflation)
335 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
338 mesh_.updateMesh(map);
340 // Move mesh (since morphing does not do this)
341 if (map().hasMotionPoints())
343 mesh_.movePoints(map().preMotionPoints());
347 // Delete mesh volumes.
351 // Reset the instance for if in overwrite mode
352 mesh_.setInstance(timeName());
354 faceCombiner.updateMesh(map);
356 // Get the kept faces that need to be recalculated.
357 // Merging two boundary faces might shift the cell centre
358 // (unless the faces are absolutely planar)
359 labelHashSet retestFaces(2*allFaceSets.size());
361 forAll(allFaceSets, setI)
363 label oldMasterI = allFaceSets[setI][0];
364 retestFaces.insert(map().reverseFaceMap()[oldMasterI]);
366 updateMesh(map, growFaceCellFace(retestFaces));
371 Pout<< "Checking sync after initial merging " << nFaceSets
372 << " faces." << endl;
375 Pout<< "Writing initial merged-faces mesh to time "
376 << timeName() << nl << endl;
380 for (label iteration = 0; iteration < 100; iteration++)
383 << "Undo iteration " << iteration << nl
384 << "----------------" << endl;
387 // Check mesh for errors
388 // ~~~~~~~~~~~~~~~~~~~~~
394 mesh_.nFaces()-mesh_.nInternalFaces()
396 bool hasErrors = motionSmoother::checkMesh
404 //if (checkEdgeConnectivity)
406 // Info<< "Checking edge-face connectivity (duplicate faces"
407 // << " or non-consecutive shared vertices)" << endl;
409 // label nOldSize = errorFaces.size();
412 // mesh_.checkFaceFaces
419 // Info<< "Detected additional "
422 // errorFaces.size() - nOldSize,
425 // << " faces with illegal face-face connectivity"
437 errorFaces.instance() = timeName();
438 Pout<< "Writing all faces in error to faceSet "
439 << errorFaces.objectPath() << nl << endl;
444 // Check any master cells for using any of the error faces
445 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
447 DynamicList<label> mastersToRestore(allFaceSets.size());
449 forAll(allFaceSets, setI)
451 label masterFaceI = faceCombiner.masterFace()[setI];
453 if (masterFaceI != -1)
455 label masterCellII = mesh_.faceOwner()[masterFaceI];
457 const cell& cFaces = mesh_.cells()[masterCellII];
461 if (errorFaces.found(cFaces[i]))
463 mastersToRestore.append(masterFaceI);
469 mastersToRestore.shrink();
471 label nRestore = returnReduce
473 mastersToRestore.size(),
477 Info<< "Masters that need to be restored:"
482 faceSet restoreSet(mesh_, "mastersToRestore", mastersToRestore);
483 restoreSet.instance() = timeName();
484 Pout<< "Writing all " << mastersToRestore.size()
485 << " masterfaces to be restored to set "
486 << restoreSet.objectPath() << endl;
502 const_cast<Time&>(mesh_.time())++;
505 // Topology changes container
506 polyTopoChange meshMod(mesh_);
508 // Merge all faces of a set into the first face of the set.
509 // Experimental:mark all points/faces/cells that have been restored.
510 Map<label> restoredPoints(0);
511 Map<label> restoredFaces(0);
512 Map<label> restoredCells(0);
514 faceCombiner.setUnrefinement
523 // Change the mesh (no inflation)
524 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
527 mesh_.updateMesh(map);
529 // Move mesh (since morphing does not do this)
530 if (map().hasMotionPoints())
532 mesh_.movePoints(map().preMotionPoints());
536 // Delete mesh volumes.
541 // Reset the instance for if in overwrite mode
542 mesh_.setInstance(timeName());
544 faceCombiner.updateMesh(map);
546 // Renumber restore maps
547 inplaceMapKey(map().reversePointMap(), restoredPoints);
548 inplaceMapKey(map().reverseFaceMap(), restoredFaces);
549 inplaceMapKey(map().reverseCellMap(), restoredCells);
552 // Get the kept faces that need to be recalculated.
553 // Merging two boundary faces might shift the cell centre
554 // (unless the faces are absolutely planar)
555 labelHashSet retestFaces(2*restoredFaces.size());
557 forAllConstIter(Map<label>, restoredFaces, iter)
559 retestFaces.insert(iter.key());
562 // Experimental:restore all points/face/cells in maps
566 growFaceCellFace(retestFaces),
575 Pout<< "Checking sync after restoring " << retestFaces.size()
576 << " faces." << endl;
579 Pout<< "Writing merged-faces mesh to time "
580 << timeName() << nl << endl;
589 Info<< "No faces merged ..." << endl;
596 // Remove points. pointCanBeDeleted is parallel synchronised.
597 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemovePoints
599 removePoints& pointRemover,
600 const boolList& pointCanBeDeleted
603 // Topology changes container
604 polyTopoChange meshMod(mesh_);
606 pointRemover.setRefinement(pointCanBeDeleted, meshMod);
608 // Change the mesh (no inflation)
609 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
612 mesh_.updateMesh(map);
614 // Move mesh (since morphing does not do this)
615 if (map().hasMotionPoints())
617 mesh_.movePoints(map().preMotionPoints());
621 // Delete mesh volumes.
625 // Reset the instance for if in overwrite mode
626 mesh_.setInstance(timeName());
628 pointRemover.updateMesh(map);
631 // Retest all affected faces and all the cells using them
632 labelHashSet retestFaces(pointRemover.savedFaceLabels().size());
633 forAll(pointRemover.savedFaceLabels(), i)
635 label faceI = pointRemover.savedFaceLabels()[i];
638 retestFaces.insert(faceI);
641 updateMesh(map, growFaceCellFace(retestFaces));
646 Pout<< "Checking sync after removing points." << endl;
654 // Restore faces (which contain removed points)
655 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRestorePoints
657 removePoints& pointRemover,
658 const labelList& facesToRestore
661 // Topology changes container
662 polyTopoChange meshMod(mesh_);
664 // Determine sets of points and faces to restore
665 labelList localFaces, localPoints;
666 pointRemover.getUnrefimentSet
673 // Undo the changes on the faces that are in error.
674 pointRemover.setUnrefinement
681 // Change the mesh (no inflation)
682 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
685 mesh_.updateMesh(map);
687 // Move mesh (since morphing does not do this)
688 if (map().hasMotionPoints())
690 mesh_.movePoints(map().preMotionPoints());
694 // Delete mesh volumes.
698 // Reset the instance for if in overwrite mode
699 mesh_.setInstance(timeName());
701 pointRemover.updateMesh(map);
703 labelHashSet retestFaces(2*facesToRestore.size());
704 forAll(facesToRestore, i)
706 label faceI = map().reverseFaceMap()[facesToRestore[i]];
709 retestFaces.insert(faceI);
712 updateMesh(map, growFaceCellFace(retestFaces));
717 Pout<< "Checking sync after restoring points on "
718 << facesToRestore.size() << " faces." << endl;
726 // Collect all faces that are both in candidateFaces and in the set.
727 // If coupled face also collects the coupled face.
728 Foam::labelList Foam::meshRefinement::collectFaces
730 const labelList& candidateFaces,
731 const labelHashSet& set
734 // Has face been selected?
735 boolList selected(mesh_.nFaces(), false);
737 forAll(candidateFaces, i)
739 label faceI = candidateFaces[i];
741 if (set.found(faceI))
743 selected[faceI] = true;
746 syncTools::syncFaceList
750 orEqOp<bool>() // combine operator
753 labelList selectedFaces(findIndices(selected, true));
755 return selectedFaces;
759 // Pick up faces of cells of faces in set.
760 Foam::labelList Foam::meshRefinement::growFaceCellFace
762 const labelHashSet& set
765 boolList selected(mesh_.nFaces(), false);
767 forAllConstIter(faceSet, set, iter)
769 label faceI = iter.key();
771 label own = mesh_.faceOwner()[faceI];
773 const cell& ownFaces = mesh_.cells()[own];
774 forAll(ownFaces, ownFaceI)
776 selected[ownFaces[ownFaceI]] = true;
779 if (mesh_.isInternalFace(faceI))
781 label nbr = mesh_.faceNeighbour()[faceI];
783 const cell& nbrFaces = mesh_.cells()[nbr];
784 forAll(nbrFaces, nbrFaceI)
786 selected[nbrFaces[nbrFaceI]] = true;
790 syncTools::syncFaceList
794 orEqOp<bool>() // combine operator
796 return findIndices(selected, true);
800 // Remove points not used by any face or points used by only two faces where
801 // the edges are in line
802 Foam::label Foam::meshRefinement::mergeEdgesUndo
805 const dictionary& motionDict
809 << "Merging all points on surface that" << nl
810 << "- are used by only two boundary faces and" << nl
811 << "- make an angle with a cosine of more than " << minCos
812 << "." << nl << endl;
814 // Point removal analysis engine with undo
815 removePoints pointRemover(mesh_, true);
817 // Count usage of points
818 boolList pointCanBeDeleted;
819 label nRemove = pointRemover.countPointUsage(minCos, pointCanBeDeleted);
823 Info<< "Removing " << nRemove
824 << " straight edge points ..." << nl << endl;
829 doRemovePoints(pointRemover, pointCanBeDeleted);
832 for (label iteration = 0; iteration < 100; iteration++)
835 << "Undo iteration " << iteration << nl
836 << "----------------" << endl;
839 // Check mesh for errors
840 // ~~~~~~~~~~~~~~~~~~~~~
846 mesh_.nFaces()-mesh_.nInternalFaces()
848 bool hasErrors = motionSmoother::checkMesh
855 //if (checkEdgeConnectivity)
857 // Info<< "Checking edge-face connectivity (duplicate faces"
858 // << " or non-consecutive shared vertices)" << endl;
860 // label nOldSize = errorFaces.size();
863 // mesh_.checkFaceFaces
870 // Info<< "Detected additional "
871 // << returnReduce(errorFaces.size()-nOldSize,sumOp<label>())
872 // << " faces with illegal face-face connectivity"
883 errorFaces.instance() = timeName();
884 Pout<< "**Writing all faces in error to faceSet "
885 << errorFaces.objectPath() << nl << endl;
889 labelList masterErrorFaces
893 pointRemover.savedFaceLabels(),
898 label n = returnReduce(masterErrorFaces.size(), sumOp<label>());
900 Info<< "Detected " << n
901 << " error faces on boundaries that have been merged."
902 << " These will be restored to their original faces." << nl
910 << returnReduce(errorFaces.size(), sumOp<label>())
911 << " error faces in mesh."
912 << " Restoring neighbours of faces in error." << nl
915 labelList expandedErrorFaces
923 doRestorePoints(pointRemover, expandedErrorFaces);
929 doRestorePoints(pointRemover, masterErrorFaces);
934 const_cast<Time&>(mesh_.time())++;
935 Pout<< "Writing merged-edges mesh to time "
936 << timeName() << nl << endl;
942 Info<< "No straight edges simplified and no points removed ..." << endl;
949 // ************************************************************************* //