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;
212 // Protect any points on faces that would collapse down to nothing
213 // No particular intelligence so might protect too many points
214 forAll(mesh_.faces(), faceI)
216 const face& f = mesh_.faces()[faceI];
221 if (pointCanBeDeleted[f[fp]])
227 if ((f.size() - nCollapse) < 3)
229 // Just unmark enough points
232 if (pointCanBeDeleted[f[fp]])
234 pointCanBeDeleted[f[fp]] = false;
246 // Point can be deleted only if all processors want to delete it
247 syncTools::syncPointList
253 false // no separation
256 return returnReduce(nDeleted, sumOp<label>());
260 void Foam::removePoints::setRefinement
262 const boolList& pointCanBeDeleted,
263 polyTopoChange& meshMod
266 // Count deleted points
268 forAll(pointCanBeDeleted, pointI)
270 if (pointCanBeDeleted[pointI])
276 // Faces (in mesh face labels) affected by points removed. Will hopefully
278 labelHashSet facesAffected(4*nDeleted);
281 // Undo: from global mesh point to index in savedPoint_
282 Map<label> pointToSaved;
287 savedPoints_.setSize(nDeleted);
288 pointToSaved.resize(2*nDeleted);
297 forAll(pointCanBeDeleted, pointI)
299 if (pointCanBeDeleted[pointI])
303 pointToSaved.insert(pointI, nDeleted);
304 savedPoints_[nDeleted++] = mesh_.points()[pointI];
306 meshMod.setAction(polyRemovePoint(pointI));
308 // Store faces affected
309 const labelList& pFaces = mesh_.pointFaces()[pointI];
313 facesAffected.insert(pFaces[i]);
326 savedFaceLabels_.setSize(facesAffected.size());
327 savedFaces_.setSize(facesAffected.size());
331 forAllConstIter(labelHashSet, facesAffected, iter)
333 label faceI = iter.key();
335 const face& f = mesh_.faces()[faceI];
337 face newFace(f.size());
343 label pointI = f[fp];
345 if (!pointCanBeDeleted[pointI])
347 newFace[newI++] = pointI;
350 newFace.setSize(newI);
352 // Actually change the face to the new vertices
353 modifyFace(faceI, newFace, meshMod);
355 // Save the face. Negative indices are into savedPoints_
358 savedFaceLabels_[nSaved] = faceI;
360 face& savedFace = savedFaces_[nSaved++];
361 savedFace.setSize(f.size());
365 label pointI = f[fp];
367 if (pointCanBeDeleted[pointI])
369 savedFace[fp] = -pointToSaved[pointI]-1;
373 savedFace[fp] = pointI;
381 // DEBUG: Compare the stored faces with the current ones.
384 forAll(savedFaceLabels_, saveI)
386 // Points from the mesh
387 List<point> meshPoints
392 mesh_.faces()[savedFaceLabels_[saveI]] // mesh face
396 // Points from the saved face
397 List<point> keptPoints
399 BiIndirectList<point>
403 savedFaces_[saveI] // saved face
407 if (meshPoints != keptPoints)
409 FatalErrorIn("setRefinement")
410 << "faceI:" << savedFaceLabels_[saveI] << nl
411 << "meshPoints:" << meshPoints << nl
412 << "keptPoints:" << keptPoints << nl
413 << abort(FatalError);
421 void Foam::removePoints::updateMesh(const mapPolyMesh& map)
425 forAll(savedFaceLabels_, localI)
427 if (savedFaceLabels_[localI] >= 0)
429 label newFaceI = map.reverseFaceMap()[savedFaceLabels_[localI]];
435 "removePoints::updateMesh(const mapPolyMesh&)"
436 ) << "Old face " << savedFaceLabels_[localI]
437 << " seems to have dissapeared."
438 << abort(FatalError);
440 savedFaceLabels_[localI] = newFaceI;
445 // Renumber mesh vertices (indices >=0). Leave saved vertices
447 forAll(savedFaces_, i)
449 face& f = savedFaces_[i];
453 label pointI = f[fp];
457 f[fp] = map.reversePointMap()[pointI];
463 "removePoints::updateMesh(const mapPolyMesh&)"
464 ) << "Old point " << pointI
465 << " seems to have dissapeared."
466 << abort(FatalError);
473 // DEBUG: Compare the stored faces with the current ones.
476 forAll(savedFaceLabels_, saveI)
478 if (savedFaceLabels_[saveI] >= 0)
480 const face& f = mesh_.faces()[savedFaceLabels_[saveI]];
482 // Get kept points of saved faces.
483 const face& savedFace = savedFaces_[saveI];
485 face keptFace(savedFace.size());
488 forAll(savedFace, fp)
490 label pointI = savedFace[fp];
494 keptFace[keptFp++] = pointI;
497 keptFace.setSize(keptFp);
499 // Compare as faces (since f might have rotated and
500 // face::operator== takes care of this)
503 FatalErrorIn("setRefinement")
504 << "faceI:" << savedFaceLabels_[saveI] << nl
505 << "face:" << f << nl
506 << "keptFace:" << keptFace << nl
508 << BiIndirectList<point>
514 << abort(FatalError);
523 // Given list of faces to undo picks up the local indices of the faces
524 // to restore. Additionally it also picks up all the faces that use
525 // any of the deleted points.
526 void Foam::removePoints::getUnrefimentSet
528 const labelList& undoFaces,
529 labelList& localFaces,
530 labelList& localPoints
537 "removePoints::getUnrefimentSet(const labelList&"
538 ", labelList&, labelList&) const"
539 ) << "removePoints not constructed with"
540 << " unrefinement capability."
541 << abort(FatalError);
547 faceSet undoFacesSet(mesh_, "undoFacesSet", undoFaces);
548 label sz = undoFacesSet.size();
550 undoFacesSet.sync(mesh_);
551 if (sz != undoFacesSet.size())
555 "removePoints::getUnrefimentSet(const labelList&"
556 ", labelList&, labelList&) const"
557 ) << "undoFaces not synchronised across coupled faces." << endl
558 << "Size before sync:" << sz
559 << " after sync:" << undoFacesSet.size()
560 << abort(FatalError);
565 // Problem: input undoFaces are synced. But e.g.
566 // two faces, A (uncoupled) and B(coupled) share a deleted point. A gets
567 // passed in to be restored. Now picking up the deleted point and the
568 // original faces using it picks up face B. But not its coupled neighbour!
569 // Problem is that we cannot easily synchronise the deleted points
570 // (e.g. syncPointList) since they're not in the mesh anymore - only the
571 // faces are. So we have to collect the points-to-restore as indices
572 // in the faces (which is information we can synchronise)
576 // Mark points-to-restore
577 labelHashSet localPointsSet(undoFaces.size());
580 // Create set of faces to be restored
581 labelHashSet undoFacesSet(undoFaces);
583 forAll(savedFaceLabels_, saveI)
585 if (savedFaceLabels_[saveI] < 0)
589 "removePoints::getUnrefimentSet(const labelList&"
590 ", labelList&, labelList&) const"
591 ) << "Illegal face label " << savedFaceLabels_[saveI]
592 << " at index " << saveI
593 << abort(FatalError);
596 if (undoFacesSet.found(savedFaceLabels_[saveI]))
598 const face& savedFace = savedFaces_[saveI];
600 forAll(savedFace, fp)
602 if (savedFace[fp] < 0)
604 label savedPointI = -savedFace[fp]-1;
606 if (savedPoints_[savedPointI] == wallPoint::greatPoint)
610 "removePoints::getUnrefimentSet"
611 "(const labelList&, labelList&, labelList&)"
613 ) << "Trying to restore point " << savedPointI
614 << " from mesh face " << savedFaceLabels_[saveI]
615 << " saved face:" << savedFace
616 << " which has already been undone."
617 << abort(FatalError);
620 localPointsSet.insert(savedPointI);
627 // Per boundary face, per index in face whether the point needs
628 // restoring. Note that this is over all saved faces, not just over
629 // the ones in undoFaces.
631 boolListList faceVertexRestore(mesh_.nFaces()-mesh_.nInternalFaces());
633 // Populate with my local points-to-restore.
634 forAll(savedFaces_, saveI)
636 label bFaceI = savedFaceLabels_[saveI] - mesh_.nInternalFaces();
640 const face& savedFace = savedFaces_[saveI];
642 boolList& fRestore = faceVertexRestore[bFaceI];
644 fRestore.setSize(savedFace.size());
647 forAll(savedFace, fp)
649 if (savedFace[fp] < 0)
651 label savedPointI = -savedFace[fp]-1;
653 if (localPointsSet.found(savedPointI))
662 syncTools::syncBoundaryFaceList
666 faceEqOp<bool, orEqOp>(), // special operator to handle faces
667 false // no separation
670 // So now if any of the points-to-restore is used by any coupled face
671 // anywhere the corresponding index in faceVertexRestore will be set.
673 // Now combine the localPointSet and the (sychronised)
674 // boundary-points-to-restore.
676 forAll(savedFaces_, saveI)
678 label bFaceI = savedFaceLabels_[saveI] - mesh_.nInternalFaces();
682 const boolList& fRestore = faceVertexRestore[bFaceI];
684 const face& savedFace = savedFaces_[saveI];
688 // Does neighbour require point restored?
691 if (savedFace[fp] >= 0)
695 "removePoints::getUnrefimentSet"
696 "(const labelList&, labelList&, labelList&)"
698 ) << "Problem: on coupled face:"
699 << savedFaceLabels_[saveI]
701 << mesh_.faceCentres()[savedFaceLabels_[saveI]]
703 << " my neighbour tries to restore the vertex"
704 << " at index " << fp
705 << " whereas my saved face:" << savedFace
706 << " does not indicate a deleted vertex"
707 << " at that position."
708 << abort(FatalError);
711 label savedPointI = -savedFace[fp]-1;
713 localPointsSet.insert(savedPointI);
720 localPoints = localPointsSet.toc();
723 // Collect all saved faces using any localPointsSet
724 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
726 labelHashSet localFacesSet(2*undoFaces.size());
728 forAll(savedFaces_, saveI)
730 const face& savedFace = savedFaces_[saveI];
732 forAll(savedFace, fp)
734 if (savedFace[fp] < 0)
736 label savedPointI = -savedFace[fp]-1;
738 if (localPointsSet.found(savedPointI))
740 localFacesSet.insert(saveI);
745 localFaces = localFacesSet.toc();
748 // Note that at this point the localFaces to restore can contain points
749 // that are not going to be restored! The localFaces though will
750 // be guaranteed to be all the ones affected by the restoration of the
755 void Foam::removePoints::setUnrefinement
757 const labelList& localFaces,
758 const labelList& localPoints,
759 polyTopoChange& meshMod
766 "removePoints::setUnrefinement(const labelList&"
767 ", labelList&, polyTopoChange&)"
768 ) << "removePoints not constructed with"
769 << " unrefinement capability."
770 << abort(FatalError);
774 // Per savedPoint -1 or the restored point label
775 labelList addedPoints(savedPoints_.size(), -1);
777 forAll(localPoints, i)
779 label localI = localPoints[i];
781 if (savedPoints_[localI] == wallPoint::greatPoint)
785 "removePoints::setUnrefinement(const labelList&"
786 ", labelList&, polyTopoChange&)"
787 ) << "Saved point " << localI << " already restored!"
788 << abort(FatalError);
791 addedPoints[localI] = meshMod.setAction
795 savedPoints_[localI], // point
797 -1, // zone for point
798 true // supports a cell
802 // Mark the restored points so they are not restored again.
803 savedPoints_[localI] = wallPoint::greatPoint;
806 forAll(localFaces, i)
808 label saveI = localFaces[i];
810 // Modify indices into saved points (so < 0) to point to the
812 face& savedFace = savedFaces_[saveI];
814 face newFace(savedFace.size());
817 bool hasSavedPoints = false;
819 forAll(savedFace, fp)
821 if (savedFace[fp] < 0)
823 label addedPointI = addedPoints[-savedFace[fp]-1];
825 if (addedPointI != -1)
827 savedFace[fp] = addedPointI;
828 newFace[newFp++] = addedPointI;
832 hasSavedPoints = true;
837 newFace[newFp++] = savedFace[fp];
840 newFace.setSize(newFp);
842 modifyFace(savedFaceLabels_[saveI], newFace, meshMod);
846 // Face fully restored. Mark for compaction later on
847 savedFaceLabels_[saveI] = -1;
848 savedFaces_[saveI].clear();
853 // Compact face labels
856 forAll(savedFaceLabels_, saveI)
858 if (savedFaceLabels_[saveI] != -1)
860 if (newSaveI != saveI)
862 savedFaceLabels_[newSaveI] = savedFaceLabels_[saveI];
863 savedFaces_[newSaveI].transfer(savedFaces_[saveI]);
869 savedFaceLabels_.setSize(newSaveI);
870 savedFaces_.setSize(newSaveI);
873 // Check that all faces have been restored that use any restored points
876 forAll(savedFaceLabels_, saveI)
878 const face& savedFace = savedFaces_[saveI];
880 forAll(savedFace, fp)
882 if (savedFace[fp] < 0)
884 label addedPointI = addedPoints[-savedFace[fp]-1];
886 if (addedPointI != -1)
888 FatalErrorIn("setUnrefinement")
889 << "Face:" << savedFaceLabels_[saveI]
890 << " savedVerts:" << savedFace
891 << " uses restored point:" << -savedFace[fp]-1
892 << " with new pointlabel:" << addedPointI
893 << abort(FatalError);
902 // ************************************************************************* //