1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "BiIndirectList.H"
28 #include "removePoints.H"
29 #include "PstreamReduceOps.H"
31 #include "polyTopoChange.H"
32 #include "polyRemovePoint.H"
33 #include "polyAddPoint.H"
34 #include "polyModifyFace.H"
35 #include "syncTools.H"
36 #include "wallPoint.H" // only to use 'greatPoint'
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 defineTypeNameAndDebug(removePoints, 0);
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 // Change the vertices of the face whilst keeping everything else the same.
51 void Foam::removePoints::modifyFace
55 polyTopoChange& meshMod
58 // Get other face data.
60 label owner = mesh_.faceOwner()[faceI];
63 if (mesh_.isInternalFace(faceI))
65 neighbour = mesh_.faceNeighbour()[faceI];
69 patchI = mesh_.boundaryMesh().whichPatch(faceI);
72 label zoneID = mesh_.faceZones().whichZone(faceI);
74 bool zoneFlip = false;
78 const faceZone& fZone = mesh_.faceZones()[zoneID];
80 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
87 newFace, // modified face
88 faceI, // label of face being modified
90 neighbour, // neighbour
92 patchI, // patch for face
93 false, // remove from zone
94 zoneID, // zone for face
95 zoneFlip // face flip in zone
101 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
103 // Construct from mesh
104 Foam::removePoints::removePoints
106 const polyMesh& mesh,
115 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
117 Foam::label Foam::removePoints::countPointUsage
120 boolList& pointCanBeDeleted
123 // Containers to store two edges per point:
126 // -2 : more than two edges for point
127 labelList edge0(mesh_.nPoints(), -1);
128 labelList edge1(mesh_.nPoints(), -1);
130 const edgeList& edges = mesh_.edges();
134 const edge& e = edges[edgeI];
138 label pointI = e[eI];
140 if (edge0[pointI] == -2)
142 // Already too many edges
144 else if (edge0[pointI] == -1)
146 // Store first edge using point
147 edge0[pointI] = edgeI;
151 // Already one edge using point. Check second container.
153 if (edge1[pointI] == -1)
155 // Store second edge using point
156 edge1[pointI] = edgeI;
160 // Third edge using point. Mark.
169 // Check the ones used by only 2 edges that these are sufficiently in line.
170 const pointField& points = mesh_.points();
172 pointCanBeDeleted.setSize(mesh_.nPoints());
173 pointCanBeDeleted = false;
176 forAll(edge0, pointI)
178 if (edge0[pointI] >= 0 && edge1[pointI] >= 0)
180 // Point used by two edges exactly
182 const edge& e0 = edges[edge0[pointI]];
183 const edge& e1 = edges[edge1[pointI]];
185 label common = e0.commonVertex(e1);
186 label vLeft = e0.otherVertex(common);
187 label vRight = e1.otherVertex(common);
189 vector e0Vec = points[common] - points[vLeft];
190 e0Vec /= mag(e0Vec) + VSMALL;
192 vector e1Vec = points[vRight] - points[common];
193 e1Vec /= mag(e1Vec) + VSMALL;
195 if ((e0Vec & e1Vec) > minCos)
197 pointCanBeDeleted[pointI] = true;
201 else if (edge0[pointI] == -1)
203 // point not used at all
204 pointCanBeDeleted[pointI] = true;
213 // Point can be deleted only if all processors want to delete it
214 syncTools::syncPointList
220 false // no separation
223 return returnReduce(nDeleted, sumOp<label>());
227 void Foam::removePoints::setRefinement
229 const boolList& pointCanBeDeleted,
230 polyTopoChange& meshMod
233 // Count deleted points
235 forAll(pointCanBeDeleted, pointI)
237 if (pointCanBeDeleted[pointI])
243 // Faces (in mesh face labels) affected by points removed. Will hopefully
245 labelHashSet facesAffected(4*nDeleted);
248 // Undo: from global mesh point to index in savedPoint_
249 Map<label> pointToSaved;
254 savedPoints_.setSize(nDeleted);
255 pointToSaved.resize(2*nDeleted);
264 forAll(pointCanBeDeleted, pointI)
266 if (pointCanBeDeleted[pointI])
270 pointToSaved.insert(pointI, nDeleted);
271 savedPoints_[nDeleted++] = mesh_.points()[pointI];
273 meshMod.setAction(polyRemovePoint(pointI));
275 // Store faces affected
276 const labelList& pFaces = mesh_.pointFaces()[pointI];
280 facesAffected.insert(pFaces[i]);
293 savedFaceLabels_.setSize(facesAffected.size());
294 savedFaces_.setSize(facesAffected.size());
298 forAllConstIter(labelHashSet, facesAffected, iter)
300 label faceI = iter.key();
302 const face& f = mesh_.faces()[faceI];
304 face newFace(f.size());
310 label pointI = f[fp];
312 if (!pointCanBeDeleted[pointI])
314 newFace[newI++] = pointI;
317 newFace.setSize(newI);
319 // Actually change the face to the new vertices
320 modifyFace(faceI, newFace, meshMod);
322 // Save the face. Negative indices are into savedPoints_
325 savedFaceLabels_[nSaved] = faceI;
327 face& savedFace = savedFaces_[nSaved++];
328 savedFace.setSize(f.size());
332 label pointI = f[fp];
334 if (pointCanBeDeleted[pointI])
336 savedFace[fp] = -pointToSaved[pointI]-1;
340 savedFace[fp] = pointI;
348 // DEBUG: Compare the stored faces with the current ones.
351 forAll(savedFaceLabels_, saveI)
353 // Points from the mesh
354 List<point> meshPoints
359 mesh_.faces()[savedFaceLabels_[saveI]] // mesh face
363 // Points from the saved face
364 List<point> keptPoints
366 BiIndirectList<point>
370 savedFaces_[saveI] // saved face
374 if (meshPoints != keptPoints)
376 FatalErrorIn("setRefinement")
377 << "faceI:" << savedFaceLabels_[saveI] << nl
378 << "meshPoints:" << meshPoints << nl
379 << "keptPoints:" << keptPoints << nl
380 << abort(FatalError);
388 void Foam::removePoints::updateMesh(const mapPolyMesh& map)
392 forAll(savedFaceLabels_, localI)
394 if (savedFaceLabels_[localI] >= 0)
396 label newFaceI = map.reverseFaceMap()[savedFaceLabels_[localI]];
402 "removePoints::updateMesh(const mapPolyMesh&)"
403 ) << "Old face " << savedFaceLabels_[localI]
404 << " seems to have dissapeared."
405 << abort(FatalError);
407 savedFaceLabels_[localI] = newFaceI;
412 // Renumber mesh vertices (indices >=0). Leave saved vertices
414 forAll(savedFaces_, i)
416 face& f = savedFaces_[i];
420 label pointI = f[fp];
424 f[fp] = map.reversePointMap()[pointI];
430 "removePoints::updateMesh(const mapPolyMesh&)"
431 ) << "Old point " << pointI
432 << " seems to have dissapeared."
433 << abort(FatalError);
440 // DEBUG: Compare the stored faces with the current ones.
443 forAll(savedFaceLabels_, saveI)
445 if (savedFaceLabels_[saveI] >= 0)
447 const face& f = mesh_.faces()[savedFaceLabels_[saveI]];
449 // Get kept points of saved faces.
450 const face& savedFace = savedFaces_[saveI];
452 face keptFace(savedFace.size());
455 forAll(savedFace, fp)
457 label pointI = savedFace[fp];
461 keptFace[keptFp++] = pointI;
464 keptFace.setSize(keptFp);
466 // Compare as faces (since f might have rotated and
467 // face::operator== takes care of this)
470 FatalErrorIn("setRefinement")
471 << "faceI:" << savedFaceLabels_[saveI] << nl
472 << "face:" << f << nl
473 << "keptFace:" << keptFace << nl
475 << BiIndirectList<point>
481 << abort(FatalError);
490 // Given list of faces to undo picks up the local indices of the faces
491 // to restore. Additionally it also picks up all the faces that use
492 // any of the deleted points.
493 void Foam::removePoints::getUnrefimentSet
495 const labelList& undoFaces,
496 labelList& localFaces,
497 labelList& localPoints
504 "removePoints::getUnrefimentSet(const labelList&"
505 ", labelList&, labelList&) const"
506 ) << "removePoints not constructed with"
507 << " unrefinement capability."
508 << abort(FatalError);
514 faceSet undoFacesSet(mesh_, "undoFacesSet", undoFaces);
515 label sz = undoFacesSet.size();
517 undoFacesSet.sync(mesh_);
518 if (sz != undoFacesSet.size())
522 "removePoints::getUnrefimentSet(const labelList&"
523 ", labelList&, labelList&) const"
524 ) << "undoFaces not synchronised across coupled faces." << endl
525 << "Size before sync:" << sz
526 << " after sync:" << undoFacesSet.size()
527 << abort(FatalError);
532 // Problem: input undoFaces are synced. But e.g.
533 // two faces, A (uncoupled) and B(coupled) share a deleted point. A gets
534 // passed in to be restored. Now picking up the deleted point and the
535 // original faces using it picks up face B. But not its coupled neighbour!
536 // Problem is that we cannot easily synchronise the deleted points
537 // (e.g. syncPointList) since they're not in the mesh anymore - only the
538 // faces are. So we have to collect the points-to-restore as indices
539 // in the faces (which is information we can synchronise)
543 // Mark points-to-restore
544 labelHashSet localPointsSet(undoFaces.size());
547 // Create set of faces to be restored
548 labelHashSet undoFacesSet(undoFaces);
550 forAll(savedFaceLabels_, saveI)
552 if (savedFaceLabels_[saveI] < 0)
556 "removePoints::getUnrefimentSet(const labelList&"
557 ", labelList&, labelList&) const"
558 ) << "Illegal face label " << savedFaceLabels_[saveI]
559 << " at index " << saveI
560 << abort(FatalError);
563 if (undoFacesSet.found(savedFaceLabels_[saveI]))
565 const face& savedFace = savedFaces_[saveI];
567 forAll(savedFace, fp)
569 if (savedFace[fp] < 0)
571 label savedPointI = -savedFace[fp]-1;
573 if (savedPoints_[savedPointI] == wallPoint::greatPoint)
577 "removePoints::getUnrefimentSet"
578 "(const labelList&, labelList&, labelList&)"
580 ) << "Trying to restore point " << savedPointI
581 << " from mesh face " << savedFaceLabels_[saveI]
582 << " saved face:" << savedFace
583 << " which has already been undone."
584 << abort(FatalError);
587 localPointsSet.insert(savedPointI);
594 // Per boundary face, per index in face whether the point needs
595 // restoring. Note that this is over all saved faces, not just over
596 // the ones in undoFaces.
598 boolListList faceVertexRestore(mesh_.nFaces()-mesh_.nInternalFaces());
600 // Populate with my local points-to-restore.
601 forAll(savedFaces_, saveI)
603 label bFaceI = savedFaceLabels_[saveI] - mesh_.nInternalFaces();
607 const face& savedFace = savedFaces_[saveI];
609 boolList& fRestore = faceVertexRestore[bFaceI];
611 fRestore.setSize(savedFace.size());
614 forAll(savedFace, fp)
616 if (savedFace[fp] < 0)
618 label savedPointI = -savedFace[fp]-1;
620 if (localPointsSet.found(savedPointI))
629 syncTools::syncBoundaryFaceList
633 faceEqOp<bool, orEqOp>(), // special operator to handle faces
634 false // no separation
637 // So now if any of the points-to-restore is used by any coupled face
638 // anywhere the corresponding index in faceVertexRestore will be set.
640 // Now combine the localPointSet and the (sychronised)
641 // boundary-points-to-restore.
643 forAll(savedFaces_, saveI)
645 label bFaceI = savedFaceLabels_[saveI] - mesh_.nInternalFaces();
649 const boolList& fRestore = faceVertexRestore[bFaceI];
651 const face& savedFace = savedFaces_[saveI];
655 // Does neighbour require point restored?
658 if (savedFace[fp] >= 0)
662 "removePoints::getUnrefimentSet"
663 "(const labelList&, labelList&, labelList&)"
665 ) << "Problem: on coupled face:"
666 << savedFaceLabels_[saveI]
668 << mesh_.faceCentres()[savedFaceLabels_[saveI]]
670 << " my neighbour tries to restore the vertex"
671 << " at index " << fp
672 << " whereas my saved face:" << savedFace
673 << " does not indicate a deleted vertex"
674 << " at that position."
675 << abort(FatalError);
678 label savedPointI = -savedFace[fp]-1;
680 localPointsSet.insert(savedPointI);
687 localPoints = localPointsSet.toc();
690 // Collect all saved faces using any localPointsSet
691 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
693 labelHashSet localFacesSet(2*undoFaces.size());
695 forAll(savedFaces_, saveI)
697 const face& savedFace = savedFaces_[saveI];
699 forAll(savedFace, fp)
701 if (savedFace[fp] < 0)
703 label savedPointI = -savedFace[fp]-1;
705 if (localPointsSet.found(savedPointI))
707 localFacesSet.insert(saveI);
712 localFaces = localFacesSet.toc();
715 // Note that at this point the localFaces to restore can contain points
716 // that are not going to be restored! The localFaces though will
717 // be guaranteed to be all the ones affected by the restoration of the
722 void Foam::removePoints::setUnrefinement
724 const labelList& localFaces,
725 const labelList& localPoints,
726 polyTopoChange& meshMod
733 "removePoints::setUnrefinement(const labelList&"
734 ", labelList&, polyTopoChange&)"
735 ) << "removePoints not constructed with"
736 << " unrefinement capability."
737 << abort(FatalError);
741 // Per savedPoint -1 or the restored point label
742 labelList addedPoints(savedPoints_.size(), -1);
744 forAll(localPoints, i)
746 label localI = localPoints[i];
748 if (savedPoints_[localI] == wallPoint::greatPoint)
752 "removePoints::setUnrefinement(const labelList&"
753 ", labelList&, polyTopoChange&)"
754 ) << "Saved point " << localI << " already restored!"
755 << abort(FatalError);
758 addedPoints[localI] = meshMod.setAction
762 savedPoints_[localI], // point
764 -1, // zone for point
765 true // supports a cell
769 // Mark the restored points so they are not restored again.
770 savedPoints_[localI] = wallPoint::greatPoint;
773 forAll(localFaces, i)
775 label saveI = localFaces[i];
777 // Modify indices into saved points (so < 0) to point to the
779 face& savedFace = savedFaces_[saveI];
781 face newFace(savedFace.size());
784 bool hasSavedPoints = false;
786 forAll(savedFace, fp)
788 if (savedFace[fp] < 0)
790 label addedPointI = addedPoints[-savedFace[fp]-1];
792 if (addedPointI != -1)
794 savedFace[fp] = addedPointI;
795 newFace[newFp++] = addedPointI;
799 hasSavedPoints = true;
804 newFace[newFp++] = savedFace[fp];
807 newFace.setSize(newFp);
809 modifyFace(savedFaceLabels_[saveI], newFace, meshMod);
813 // Face fully restored. Mark for compaction later on
814 savedFaceLabels_[saveI] = -1;
815 savedFaces_[saveI].clear();
820 // Compact face labels
823 forAll(savedFaceLabels_, saveI)
825 if (savedFaceLabels_[saveI] != -1)
827 if (newSaveI != saveI)
829 savedFaceLabels_[newSaveI] = savedFaceLabels_[saveI];
830 savedFaces_[newSaveI].transfer(savedFaces_[saveI]);
836 savedFaceLabels_.setSize(newSaveI);
837 savedFaces_.setSize(newSaveI);
840 // Check that all faces have been restored that use any restored points
843 forAll(savedFaceLabels_, saveI)
845 const face& savedFace = savedFaces_[saveI];
847 forAll(savedFace, fp)
849 if (savedFace[fp] < 0)
851 label addedPointI = addedPoints[-savedFace[fp]-1];
853 if (addedPointI != -1)
855 FatalErrorIn("setUnrefinement")
856 << "Face:" << savedFaceLabels_[saveI]
857 << " savedVerts:" << savedFace
858 << " uses restored point:" << -savedFace[fp]-1
859 << " with new pointlabel:" << addedPointI
860 << abort(FatalError);
869 // ************************************************************************* //