1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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
29 Sliding interface, point projection
32 Hrvoje Jasak, Wikki Ltd. All rights reserved. Copyright Hrvoje Jasak.
34 \*---------------------------------------------------------------------------*/
36 #include "slidingInterface.H"
38 #include "primitiveMesh.H"
40 #include "triPointRef.H"
42 #include "polyTopoChanger.H"
44 #include "standAlonePatch.H"
46 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
48 const Foam::scalar Foam::slidingInterface::pointMergeTol_
50 debug::tolerances("slidingPointMergeTol", 0.2)
53 const Foam::scalar Foam::slidingInterface::edgeMergeTol_
55 debug::tolerances("slidingEdgeMergeTol", 0.05)
58 const Foam::scalar Foam::slidingInterface::integralAdjTol_
60 debug::tolerances("slidingIntegralAdjTol", 0.15)
63 const Foam::scalar Foam::slidingInterface::edgeMasterCatchFraction_
65 debug::tolerances("slidingEdgeMasterCatchFraction", 0.4)
68 const Foam::scalar Foam::slidingInterface::edgeEndCutoffTol_
70 debug::tolerances("slidingEdgeEndCutoffTol", 0.0001)
73 const Foam::label Foam::slidingInterface::nFacesPerSlaveEdge_ = 5;
75 // Increased limit for extreme 20-1 cutting. HJ, 19/Dec/2008
76 const Foam::label Foam::slidingInterface::edgeFaceEscapeLimit_ = 20;
78 // const Foam::scalar Foam::slidingInterface::pointMergeTol_ = 0.05;
79 // const Foam::scalar Foam::slidingInterface::edgeMergeTol_ = 0.01;
80 // const Foam::label Foam::slidingInterface::nFacesPerSlaveEdge_ = 5;
81 // const Foam::label Foam::slidingInterface::edgeFaceEscapeLimit_ = 10;
83 // const Foam::scalar Foam::slidingInterface::integralAdjTol_ = 0.05;
84 // const Foam::scalar Foam::slidingInterface::edgeMasterCatchFraction_ = 0.4;
85 // const Foam::scalar Foam::slidingInterface::edgeEndCutoffTol_ = 0.0001;
88 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
90 // Index of debug signs:
91 // a - integral match adjustment: point adjusted
92 // n - integral match adjustment: point not adjusted
93 // . - loop of the edge-to-face interaction detection
94 // x - reversal of direction in edge-to-face interaction detection
95 // + - complete edge-to-face interaction detection
96 // z - incomplete edge-to-face interaction detection. This may be OK for edges
97 // crossing from one to the other side of multiply connected master patch
98 // * - colinear triangle: adjusting projection with slave face normal
99 // m - master point inserted into the edge
101 bool Foam::slidingInterface::projectPoints() const
105 Pout<< "bool slidingInterface::projectPoints() for object "
107 << "Projecting slave points onto master surface using ";
109 if (debug::optimisationSwitch("nSquaredProjection", 0) > 0)
111 Pout<< "N-squared point projection" << endl;
115 Pout<< "optimised point projection" << endl;
120 // 1) Go through all the points of the master and slave patch and calculate
121 // minimum edge length coming from the point. Calculate the point
122 // merge tolerance as the fraction of mimimum edge length.
123 // 2) Project all the slave points onto the master patch
124 // in the normal direction.
125 // 3) If some points have missed and the match is integral, the
126 // points in question will be adjusted. Find the nearest face for
127 // those points and continue with the procedure.
128 // 4) For every point, check all the points of the face it has hit.
129 // For every pair of points find if their distance is smaller than
130 // both the master and slave merge tolerance. If so, the slave point
131 // is moved to the location of the master point. Remember the master
133 // 5) For every unmerged slave point, check its distance to all the
134 // edges of the face it has hit. If the distance is smaller than the
135 // edge merge tolerance, the point will be moved onto the edge.
136 // Remember the master edge index.
137 // 6) The remaning slave points will be projected into faces. Remember the
138 // master face index.
139 // 7) For the points that miss the master patch, grab the nearest face
140 // on the master and leave the slave point where it started
141 // from and the miss is recorded.
143 const polyMesh& mesh = topoChanger().mesh();
145 const primitiveFacePatch& masterPatch =
146 mesh.faceZones()[masterFaceZoneID_.index()]();
148 const primitiveFacePatch& slavePatch =
149 mesh.faceZones()[slaveFaceZoneID_.index()]();
153 Pout<< "Master patch size = " << masterPatch.size()
154 << " Slave patch size = " << slavePatch.size() << endl;
157 // Get references to local points, local edges and local faces
158 // for master and slave patch
159 // const labelList& masterMeshPoints = masterPatch.meshPoints();
160 const pointField& masterLocalPoints = masterPatch.localPoints();
161 const faceList& masterLocalFaces = masterPatch.localFaces();
162 const edgeList& masterEdges = masterPatch.edges();
163 const labelListList& masterEdgeFaces = masterPatch.edgeFaces();
164 const labelListList& masterFaceEdges = masterPatch.faceEdges();
165 const labelListList& masterFaceFaces = masterPatch.faceFaces();
166 // Pout<< "Master patch. Local points: " << masterLocalPoints << nl
167 // << "Master patch. Mesh points: " << masterPatch.meshPoints() << nl
168 // << "Local faces: " << masterLocalFaces << nl
169 // << "local edges: " << masterEdges
172 // const labelList& slaveMeshPoints = slavePatch.meshPoints();
173 const pointField& slaveLocalPoints = slavePatch.localPoints();
174 const edgeList& slaveEdges = slavePatch.edges();
175 const labelListList& slaveEdgeFaces = slavePatch.edgeFaces();
176 const vectorField& slavePointNormals = slavePatch.pointNormals();
177 // const vectorField& slaveFaceNormals = slavePatch.faceNormals();
178 // Pout<< "Slave patch. Local points: " << slaveLocalPoints << nl
179 // << "Slave patch. Mesh points: " << slavePatch.meshPoints() << nl
180 // << "Local faces: " << slavePatch.localFaces() << nl
181 // << "local edges: " << slaveEdges
184 // Calculate min edge distance for points and faces
186 // Calculate min edge length for the points and faces of master patch
187 scalarField minMasterPointLength(masterLocalPoints.size(), GREAT);
188 scalarField minMasterFaceLength(masterPatch.size(), GREAT);
190 forAll (masterEdges, edgeI)
192 const edge& curEdge = masterEdges[edgeI];
194 const scalar curLength =
195 masterEdges[edgeI].mag(masterLocalPoints);
198 minMasterPointLength[curEdge.start()] =
201 minMasterPointLength[curEdge.start()],
205 minMasterPointLength[curEdge.end()] =
208 minMasterPointLength[curEdge.end()],
213 const labelList& curFaces = masterEdgeFaces[edgeI];
215 forAll (curFaces, faceI)
217 minMasterFaceLength[curFaces[faceI]] =
220 minMasterFaceLength[curFaces[faceI]],
226 // Pout << "min length for master points: " << minMasterPointLength << endl
227 // << "min length for master faces: " << minMasterFaceLength << endl;
229 // Calculate min edge length for the points and faces of slave patch
230 scalarField minSlavePointLength(slaveLocalPoints.size(), GREAT);
231 scalarField minSlaveFaceLength(slavePatch.size(), GREAT);
233 forAll (slaveEdges, edgeI)
235 const edge& curEdge = slaveEdges[edgeI];
237 const scalar curLength =
238 slaveEdges[edgeI].mag(slaveLocalPoints);
241 minSlavePointLength[curEdge.start()] =
244 minSlavePointLength[curEdge.start()],
248 minSlavePointLength[curEdge.end()] =
251 minSlavePointLength[curEdge.end()],
256 const labelList& curFaces = slaveEdgeFaces[edgeI];
258 forAll (curFaces, faceI)
260 minSlaveFaceLength[curFaces[faceI]] =
263 minSlaveFaceLength[curFaces[faceI]],
269 // Pout << "min length for slave points: " << minSlavePointLength << endl
270 // << "min length for slave faces: " << minSlaveFaceLength << endl;
272 // Project slave points onto the master patch
274 // Face hit by the slave point
275 List<objectHit> slavePointFaceHits =
276 slavePatch.projectPoints
287 forAll (slavePointFaceHits, pointI)
289 if (slavePointFaceHits[pointI].hit())
295 Pout<< "Number of hits in point projection: " << nHits
296 << " out of " << slavePointFaceHits.size() << " points."
300 // Projected slave points are stored for mesh motion correction
301 if (projectedSlavePointsPtr_) delete projectedSlavePointsPtr_;
303 projectedSlavePointsPtr_ =
304 new pointField(slavePointFaceHits.size(), vector::zero);
305 pointField& projectedSlavePoints = *projectedSlavePointsPtr_;
307 // Adjust projection to type of match
309 label nAdjustedPoints = 0;
311 // If the match is integral and some points have missed,
312 // find nearest master face
313 if (matchType_ == INTEGRAL)
317 Pout<< "bool slidingInterface::projectPoints() for object "
319 << "Adjusting point projection for integral match: ";
322 forAll (slavePointFaceHits, pointI)
324 if (slavePointFaceHits[pointI].hit())
326 // Grab the hit point
327 projectedSlavePoints[pointI] =
329 [slavePointFaceHits[pointI].hitObject()].ray
331 slaveLocalPoints[pointI],
332 slavePointNormals[pointI],
339 // Check if point has been adjusted
340 bool adjusted = false;
342 if (slavePointFaceHits[pointI].hitObject() > -1)
344 // Grab the nearest point on the face (edge)
345 pointHit missAdjust =
347 [slavePointFaceHits[pointI].hitObject()].ray
349 slaveLocalPoints[pointI],
350 slavePointNormals[pointI],
355 const point nearPoint = missAdjust.missPoint();
356 const point missPoint =
357 slaveLocalPoints[pointI]
358 + slavePointNormals[pointI]*missAdjust.distance();
360 // Calculate the tolerance
361 const scalar mergeTol =
362 integralAdjTol_*minSlavePointLength[pointI];
365 if (mag(nearPoint - missPoint) < mergeTol)
372 // Pout<< "Moving slave point in integral adjustment "
373 // << pointI << " miss point: " << missPoint
374 // << " near point: " << nearPoint
375 // << " mergeTol: " << mergeTol
376 // << " dist: " << mag(nearPoint - missPoint)
377 // << " global point index: "
378 // << slavePatch.meshPoints()[pointI]
381 projectedSlavePoints[pointI] = nearPoint;
383 slavePointFaceHits[pointI] =
387 slavePointFaceHits[pointI].hitObject()
397 projectedSlavePoints[pointI] = slaveLocalPoints[pointI];
409 Pout << " done." << endl;
412 else if (matchType_ == PARTIAL)
414 forAll (slavePointFaceHits, pointI)
416 if (slavePointFaceHits[pointI].hit())
418 // Grab the hit point
419 projectedSlavePoints[pointI] =
421 [slavePointFaceHits[pointI].hitObject()].ray
423 slaveLocalPoints[pointI],
424 slavePointNormals[pointI],
431 // The point remains where it started from
432 projectedSlavePoints[pointI] = slaveLocalPoints[pointI];
440 "bool slidingInterface::projectPoints() const"
441 ) << "Problem in point projection. Unknown sliding match type "
442 << " for object " << name()
443 << abort(FatalError);
448 Pout<< "Number of adjusted points in projection: "
449 << nAdjustedPoints << endl;
451 // Check for zero-length edges in slave projection
452 scalar minEdgeLength = GREAT;
454 label nShortEdges = 0;
456 forAll (slaveEdges, edgeI)
458 el = slaveEdges[edgeI].mag(projectedSlavePoints);
462 Pout<< "Point projection problems for edge: "
463 << slaveEdges[edgeI] << ". Length = " << el
469 minEdgeLength = min(minEdgeLength, el);
476 "bool slidingInterface::projectPoints() const"
477 ) << "Problem in point projection. " << nShortEdges
478 << " short projected edges "
479 << "after adjustment for object " << name()
480 << abort(FatalError);
484 Pout << " ... projection OK." << endl;
487 // scalarField magDiffs(mag(slaveLocalPoints - projectedSlavePoints));
488 // Pout<< "Slave point face hits: " << slavePointFaceHits << nl
489 // << "slave points: " << slaveLocalPoints << nl
490 // << "Projected slave points: " << projectedSlavePoints
491 // << "diffs: " << magDiffs << endl;
493 // Merge projected points against master points
497 Info<< "Writing VTK files for raw projection"
498 << "Sliding interface " << name()
499 << " Master patch: " << masterPatchID_.name()
500 << " Slave patch: " << slavePatchID_.name()
503 fileName fvPath(mesh.time().path()/"VTK");
506 standAlonePatch::writeVTK
508 fvPath/fileName(masterFaceZoneID_.name() + "Master"),
509 masterPatch.localFaces(),
513 standAlonePatch::writeVTKNormals
515 fvPath/fileName(masterFaceZoneID_.name() + "MasterNormals"),
516 masterPatch.localFaces(),
520 standAlonePatch::writeVTK
522 fvPath/fileName(slaveFaceZoneID_.name() + "Slave"),
523 slavePatch.localFaces(),
527 standAlonePatch::writeVTKNormals
529 fvPath/fileName(slaveFaceZoneID_.name() + "SlaveNormals"),
530 slavePatch.localFaces(),
534 standAlonePatch::writeVTK
536 fvPath/fileName(slaveFaceZoneID_.name() + "RawProjectedSlave"),
537 slavePatch.localFaces(),
542 labelList slavePointPointHits(slaveLocalPoints.size(), -1);
543 labelList masterPointPointHits(masterLocalPoints.size(), -1);
545 // Go through all the slave points and compare them against all the points
546 // in the master face they hit. If the distance between the projected
547 // point and any of the master face points is smaller than
548 // both tolerances, merge the projected point by:
549 // 1) adjusting the projected point to coincide with the
550 // master point it merges with
551 // 2) remembering the hit master point index in slavePointPointHits
552 // 3) resetting the hit face to -1
553 // 4) If a master point has been hit directly, it cannot be merged
554 // into the edge. Mark it as used in the reverse list
556 label nMergedPoints = 0;
558 forAll (projectedSlavePoints, pointI)
560 if (slavePointFaceHits[pointI].hit())
562 // Taking a non-const reference so the point can be adjusted
563 point& curPoint = projectedSlavePoints[pointI];
566 const face& hitFace =
567 masterLocalFaces[slavePointFaceHits[pointI].hitObject()];
569 label mergePoint = -1;
570 scalar mergeDist = GREAT;
572 // Try all point before deciding on best fit.
573 forAll (hitFace, hitPointI)
576 mag(masterLocalPoints[hitFace[hitPointI]] - curPoint);
578 // Calculate the tolerance
579 const scalar mergeTol =
583 minSlavePointLength[pointI],
584 minMasterPointLength[hitFace[hitPointI]]
587 if (dist < mergeTol && dist < mergeDist)
589 mergePoint = hitFace[hitPointI];
592 // Pout<< "Merging slave point "
593 // << slavePatch.meshPoints()[pointI] << " at "
594 // << slaveLocalPoints[pointI] << " with master "
595 // << masterPatch.meshPoints()[mergePoint] << " at "
596 // << masterLocalPoints[mergePoint]
597 // << ". dist: " << mergeDist
598 // << " mergeTol: " << mergeTol << endl;
604 // Point is to be merged with master point
607 slavePointPointHits[pointI] = mergePoint;
608 curPoint = masterLocalPoints[mergePoint];
609 masterPointPointHits[mergePoint] = pointI;
614 // Pout<< "slavePointPointHits: " << slavePointPointHits << nl
615 // << "masterPointPointHits: " << masterPointPointHits << endl;
619 // Check for zero-length edges in slave projection
620 scalar minEdgeLength = GREAT;
623 forAll (slaveEdges, edgeI)
625 el = slaveEdges[edgeI].mag(projectedSlavePoints);
629 Pout<< "Point projection problems for edge: "
630 << slaveEdges[edgeI] << ". Length = " << el
634 minEdgeLength = min(minEdgeLength, el);
637 if (minEdgeLength < SMALL)
641 "bool slidingInterface::projectPoints() const"
642 ) << "Problem in point projection. Short projected edge "
643 << " after point merge for object " << name()
644 << abort(FatalError);
648 Pout << " ... point merge OK." << endl;
652 // Merge projected points against master edges
654 labelList slavePointEdgeHits(slaveLocalPoints.size(), -1);
656 label nMovedPoints = 0;
658 forAll (projectedSlavePoints, pointI)
660 // Eliminate the points merged into points
663 slavePointPointHits[pointI] < 0
664 && slavePointFaceHits[pointI].hit()
667 // Get current point position
668 point& curPoint = projectedSlavePoints[pointI];
671 const labelList& hitFaceEdges =
672 masterFaceEdges[slavePointFaceHits[pointI].hitObject()];
674 // Calculate the tolerance
675 const scalar mergeLength =
678 minSlavePointLength[pointI],
679 minMasterFaceLength[slavePointFaceHits[pointI].hitObject()]
682 const scalar mergeTol = pointMergeTol_*mergeLength;
684 scalar minDistance = GREAT;
686 forAll (hitFaceEdges, edgeI)
688 const edge& curEdge = masterEdges[hitFaceEdges[edgeI]];
691 curEdge.line(masterLocalPoints).nearestDist(curPoint);
696 mag(edgeHit.hitPoint() - projectedSlavePoints[pointI]);
698 if (dist < mergeTol && dist < minDistance)
700 // Point is to be moved onto master edge
703 slavePointEdgeHits[pointI] = hitFaceEdges[edgeI];
704 projectedSlavePoints[pointI] = edgeHit.hitPoint();
708 // Pout<< "Moving slave point "
709 // << slavePatch.meshPoints()[pointI]
711 // << ") at " << slaveLocalPoints[pointI]
712 // << " onto master edge " << hitFaceEdges[edgeI]
715 // << masterLocalPoints[curEdge.start()] << " "
716 // << masterLocalPoints[curEdge.end()]
717 // << " ) hit: " << edgeHit.hitPoint()
718 // << ". dist: " << dist
719 // << " mergeTol: " << mergeTol << endl;
722 } // end of hit face edges
724 if (slavePointEdgeHits[pointI] > -1)
726 // Projected slave point has moved. Re-attempt merge with
727 // master points of the edge
728 point& curPoint = projectedSlavePoints[pointI];
730 const edge& hitMasterEdge =
731 masterEdges[slavePointEdgeHits[pointI]];
733 label mergePoint = -1;
734 scalar mergeDist = GREAT;
736 forAll (hitMasterEdge, hmeI)
739 mag(masterLocalPoints[hitMasterEdge[hmeI]] - curPoint);
741 // Calculate the tolerance
742 const scalar mergeTol =
746 minSlavePointLength[pointI],
747 minMasterPointLength[hitMasterEdge[hmeI]]
750 if (hmeDist < mergeTol && hmeDist < mergeDist)
752 mergePoint = hitMasterEdge[hmeI];
755 // Pout<< "Merging slave point; SECOND TRY "
756 // << slavePatch.meshPoints()[pointI] << " local "
757 // << pointI << " at "
758 // << slaveLocalPoints[pointI] << " with master "
759 // << masterPatch.meshPoints()[mergePoint] << " at "
760 // << masterLocalPoints[mergePoint]
761 // << ". hmeDist: " << mergeDist
762 // << " mergeTol: " << mergeTol << endl;
768 // Point is to be merged with master point
769 slavePointPointHits[pointI] = mergePoint;
770 curPoint = masterLocalPoints[mergePoint];
771 masterPointPointHits[mergePoint] = pointI;
773 slavePointFaceHits[pointI] =
774 objectHit(true, slavePointFaceHits[pointI].hitObject());
777 // Disable edge merge
778 slavePointEdgeHits[pointI] = -1;
786 Pout<< "Number of merged master points: " << nMergedPoints << nl
787 << "Number of adjusted slave points: " << nMovedPoints << endl;
789 // Check for zero-length edges in slave projection
790 scalar minEdgeLength = GREAT;
793 forAll (slaveEdges, edgeI)
795 el = slaveEdges[edgeI].mag(projectedSlavePoints);
799 Pout<< "Point projection problems for edge: "
800 << slaveEdges[edgeI] << ". Length = " << el
804 minEdgeLength = min(minEdgeLength, el);
807 if (minEdgeLength < SMALL)
811 "bool slidingInterface::projectPoints() const"
812 ) << "Problem in point projection. Short projected edge "
813 << " after correction for object " << name()
814 << abort(FatalError);
818 // Pout << "slavePointEdgeHits: " << slavePointEdgeHits << endl;
820 // Insert the master points into closest slave edge if appropriate
823 // The face potentially interacts with all the points of the
824 // faces covering the path between its two ends. Since we are
825 // examining an arbitrary shadow of the edge on a non-Euclidian
826 // surface, it is typically quite hard to do a geometric point
827 // search (under a shadow of a straight line). Therefore, the
828 // search will be done topologically.
830 // I) Point collection
831 // -------------------
832 // 1) Grab the master faces to which the end points of the edge
833 // have been projected.
834 // 2) Starting from the face containing the edge start, grab all
835 // its points and put them into the point lookup map. Put the
836 // face onto the face lookup map.
837 // 3) If the face of the end point is on the face lookup, complete
838 // the point collection step (this is checked during insertion.
839 // 4) Start a new round of insertion. Visit all faces in the face
840 // lookup and add their neighbours which are not already on the
841 // map. Every time the new neighbour is found, add its points to
842 // the point lookup. If the face of the end point is inserted,
843 // continue with the current roundof insertion and stop the
848 // Grab all the points from the point collection and check them
849 // against the current edge. If the edge-to-point distance is
850 // smaller than the smallest tolerance in the game (min of
851 // master point tolerance and left and right slave face around
852 // the edge tolerance) and the nearest point hits the edge, the
853 // master point will break the slave edge. Check the actual
854 // distance of the original master position from the edge. If
855 // the distance is smaller than a fraction of slave edge
856 // length, the hit is considered valid. Store the slave edge
857 // index for every master point.
859 labelList masterPointEdgeHits(masterLocalPoints.size(), -1);
860 scalarField masterPointEdgeDist(masterLocalPoints.size(), GREAT);
862 // Note. "Processing slave edges" code is repeated twice in the
863 // sliding intergace coupling in order to allow the point
864 // projection to be done separately from the actual cutting.
865 // Please change consistently with coupleSlidingInterface.C
869 Pout << "Processing slave edges " << endl;
872 // Create a map of faces the edge can interact with
873 labelHashSet curFaceMap
875 nFacesPerSlaveEdge_*primitiveMesh::edgesPerFace_
878 labelHashSet addedFaces(2*primitiveMesh::edgesPerFace_);
880 forAll (slaveEdges, edgeI)
882 const edge& curEdge = slaveEdges[edgeI];
886 slavePointFaceHits[curEdge.start()].hit()
887 || slavePointFaceHits[curEdge.end()].hit()
894 // Grab the faces for start and end points
895 const label startFace =
898 slavePointFaceHits[curEdge.start()].hitObject(),
899 slavePointFaceHits[curEdge.end()].hitObject()
901 const label endFace =
904 slavePointFaceHits[curEdge.start()].hitObject(),
905 slavePointFaceHits[curEdge.end()].hitObject()
908 // Pout<< "Doing edge " << edgeI << " or " << curEdge
910 // << slavePointFaceHits[curEdge.start()].hitObject()
912 // << slavePointFaceHits[curEdge.end()].hitObject()
915 // If the end face is on the list, the face collection is finished
917 bool completed = false;
919 while (nSweeps < edgeFaceEscapeLimit_)
923 if (addedFaces.found(endFace))
928 // Add all face neighbours of face in the map
929 const labelList cf = addedFaces.toc();
934 const labelList& curNbrs = masterFaceFaces[cf[cfI]];
936 forAll (curNbrs, nbrI)
938 if (!curFaceMap.found(curNbrs[nbrI]))
940 curFaceMap.insert(curNbrs[nbrI]);
941 addedFaces.insert(curNbrs[nbrI]);
946 if (completed) break;
961 // It is impossible to reach the end from the start, probably
962 // due to disconnected domain. Do search in opposite direction
964 label nReverseSweeps = 0;
967 curFaceMap.insert(endFace);
968 addedFaces.insert(endFace);
970 while (nReverseSweeps < edgeFaceEscapeLimit_)
974 if (addedFaces.found(startFace))
979 // Add all face neighbours of face in the map
980 const labelList cf = addedFaces.toc();
985 const labelList& curNbrs = masterFaceFaces[cf[cfI]];
987 forAll (curNbrs, nbrI)
989 if (!curFaceMap.found(curNbrs[nbrI]))
991 curFaceMap.insert(curNbrs[nbrI]);
992 addedFaces.insert(curNbrs[nbrI]);
997 if (completed) break;
1021 // Collect the points
1023 // Create a map of points the edge can interact with
1024 labelHashSet curPointMap
1026 nFacesPerSlaveEdge_*primitiveMesh::pointsPerFace_
1029 const labelList curFaces = curFaceMap.toc();
1030 // Pout << "curFaces: " << curFaces << endl;
1031 forAll (curFaces, faceI)
1033 const face& f = masterLocalFaces[curFaces[faceI]];
1037 curPointMap.insert(f[pointI]);
1041 const labelList curMasterPoints = curPointMap.toc();
1043 // Check all the points against the edge.
1045 linePointRef edgeLine = curEdge.line(projectedSlavePoints);
1047 const vector edgeVec = edgeLine.vec();
1048 const scalar edgeMag = edgeLine.mag();
1050 // Calculate actual distance involved in projection. This
1051 // is used to reject master points out of reach.
1052 // Calculated as a combination of travel distance in projection and
1054 scalar slaveCatchDist =
1055 edgeMasterCatchFraction_*edgeMag
1060 projectedSlavePoints[curEdge.start()]
1061 - slaveLocalPoints[curEdge.start()]
1065 projectedSlavePoints[curEdge.end()]
1066 - slaveLocalPoints[curEdge.end()]
1070 // The point merge distance needs to be measured in the
1071 // plane of the slave edge. The unit vector is calculated
1072 // as a cross product of the edge vector and the edge
1073 // projection direction. When checking for the distance
1074 // in plane, a minimum of the master-to-edge and
1075 // projected-master-to-edge distance is used, to avoid
1076 // problems with badly defined master planes. HJ,
1078 vector edgeNormalInPlane =
1081 slavePointNormals[curEdge.start()]
1082 + slavePointNormals[curEdge.end()]
1085 edgeNormalInPlane /= mag(edgeNormalInPlane);
1087 forAll (curMasterPoints, pointI)
1089 const label cmp = curMasterPoints[pointI];
1091 // Skip the current point if the edge start or end has
1092 // been adjusted onto in
1095 slavePointPointHits[curEdge.start()] == cmp
1096 || slavePointPointHits[curEdge.end()] == cmp
1097 || masterPointPointHits[cmp] > -1
1100 // Pout << "Edge already snapped to point. Skipping." << endl;
1104 // Check if the point actually hits the edge within bounds
1105 pointHit edgeLineHit =
1106 edgeLine.nearestDist(masterLocalPoints[cmp]);
1108 if (edgeLineHit.hit())
1110 // If the distance to the line is smaller than
1111 // the tolerance the master point needs to be
1112 // inserted into the edge
1114 // Strict checking of slave cut to avoid capturing
1117 ((edgeLineHit.hitPoint() - edgeLine.start()) & edgeVec)
1120 scalar distInEdgePlane =
1123 edgeLineHit.distance(),
1127 masterLocalPoints[cmp]
1128 - edgeLineHit.hitPoint()
1133 // Pout << "master point: " << cmp
1134 // << " cutOnSlave " << cutOnSlave
1135 // << " distInEdgePlane: " << distInEdgePlane
1136 // << " tol1: " << pointMergeTol_*edgeMag
1137 // << " hitDist: " << edgeLineHit.distance()
1142 // masterPointEdgeDist[cmp]
1145 // Not a point hit, check for edge
1148 cutOnSlave > edgeEndCutoffTol_
1149 && cutOnSlave < 1.0 - edgeEndCutoffTol_ // check edge cut
1150 && distInEdgePlane < edgeMergeTol_*edgeMag // merge plane
1151 && edgeLineHit.distance()
1155 masterPointEdgeDist[cmp]
1161 if (masterPointEdgeHits[cmp] == -1)
1173 // Snap to point onto edge
1174 masterPointEdgeHits[cmp] = edgeI;
1175 masterPointEdgeDist[cmp] = edgeLineHit.distance();
1177 // Pout<< "Inserting master point "
1178 // << masterPatch.meshPoints()[cmp]
1180 // << ") at " << masterLocalPoints[cmp]
1181 // << " into slave edge " << edgeI
1182 // << " " << curEdge
1183 // << " cutOnSlave: " << cutOnSlave
1184 // << " distInEdgePlane: " << distInEdgePlane
1185 // << ". dist: " << edgeLineHit.distance()
1187 // << edgeMergeTol_*edgeMag
1188 // << " other tol: " <<
1192 // masterPointEdgeDist[cmp]
1198 } // End if both ends missing
1199 } // End all slave edges
1205 // Pout << "masterPointEdgeHits: " << masterPointEdgeHits << endl;
1209 fileName fvPath(mesh.time().path()/"VTK");
1211 standAlonePatch::writeVTK
1213 fvPath/fileName(slaveFaceZoneID_.name() + "ProjectedAdjustedSlave"),
1214 slavePatch.localFaces(),
1215 projectedSlavePoints
1218 Pout<< "bool slidingInterface::projectPoints() for object "
1220 << "Finished projecting points. Topology = ";
1223 // Pout<< "slavePointPointHits: " << slavePointPointHits << nl
1224 // << "slavePointEdgeHits: " << slavePointEdgeHits << nl
1225 // << "slavePointFaceHits: " << slavePointFaceHits << nl
1226 // << "masterPointEdgeHits: " << masterPointEdgeHits << endl;
1229 // - slavePointPointHits
1230 // - slavePointEdgeHits
1231 // - slavePointFaceHits
1232 // - masterPointEdgeHits
1233 // define how the two patches will be merged topologically.
1234 // If the lists have not changed since the last merge, the
1235 // sliding interface changes only geometrically and simple mesh
1236 // motion will suffice. Otherwise, a topological change is
1239 // Compare the result with the current state
1242 // The mesh needs to change topologically
1245 // Store the addressing arrays and projected points
1246 deleteDemandDrivenData(slavePointPointHitsPtr_);
1247 slavePointPointHitsPtr_ = new labelList(slavePointPointHits);
1249 deleteDemandDrivenData(slavePointEdgeHitsPtr_);
1250 slavePointEdgeHitsPtr_ = new labelList(slavePointEdgeHits);
1252 deleteDemandDrivenData(slavePointFaceHitsPtr_);
1253 slavePointFaceHitsPtr_ = new List<objectHit>(slavePointFaceHits);
1255 deleteDemandDrivenData(masterPointEdgeHitsPtr_);
1256 masterPointEdgeHitsPtr_ = new labelList(masterPointEdgeHits);
1260 Pout << "(Detached interface) changing." << endl;
1265 // Compare the lists against the stored lists. If any of them
1266 // has changed, topological change will be executed.
1271 !slavePointPointHitsPtr_
1272 || !slavePointEdgeHitsPtr_
1273 || !slavePointFaceHitsPtr_
1274 || !masterPointEdgeHitsPtr_
1277 // Must be restart. Force topological change.
1278 deleteDemandDrivenData(slavePointPointHitsPtr_);
1279 slavePointPointHitsPtr_ = new labelList(slavePointPointHits);
1281 deleteDemandDrivenData(slavePointEdgeHitsPtr_);
1282 slavePointEdgeHitsPtr_ = new labelList(slavePointEdgeHits);
1284 deleteDemandDrivenData(slavePointFaceHitsPtr_);
1285 slavePointFaceHitsPtr_ = new List<objectHit>(slavePointFaceHits);
1287 deleteDemandDrivenData(masterPointEdgeHitsPtr_);
1288 masterPointEdgeHitsPtr_ = new labelList(masterPointEdgeHits);
1292 Pout << "(Attached interface restart) changing." << endl;
1299 if (slavePointPointHits != (*slavePointPointHitsPtr_))
1303 Pout << "(Point projection) ";
1309 if (slavePointEdgeHits != (*slavePointEdgeHitsPtr_))
1313 Pout << "(Edge projection) ";
1319 // Comparison for face hits needs to exclude points that have hit
1320 // another point or edge
1321 bool faceHitsDifferent = false;
1323 const List<objectHit>& oldPointFaceHits = *slavePointFaceHitsPtr_;
1325 forAll (slavePointFaceHits, pointI)
1329 slavePointPointHits[pointI] < 0
1330 && slavePointEdgeHits[pointI] < 0
1333 // This is a straight face hit
1334 if (slavePointFaceHits[pointI] != oldPointFaceHits[pointI])
1336 // Two lists are different
1337 faceHitsDifferent = true;
1343 if (faceHitsDifferent)
1347 Pout << "(Face projection) ";
1354 if (masterPointEdgeHits != (*masterPointEdgeHitsPtr_))
1358 Pout << "(Master point projection) ";
1368 deleteDemandDrivenData(slavePointPointHitsPtr_);
1369 slavePointPointHitsPtr_ = new labelList(slavePointPointHits);
1371 deleteDemandDrivenData(slavePointEdgeHitsPtr_);
1372 slavePointEdgeHitsPtr_ = new labelList(slavePointEdgeHits);
1374 deleteDemandDrivenData(slavePointFaceHitsPtr_);
1375 slavePointFaceHitsPtr_ = new List<objectHit>(slavePointFaceHits);
1377 deleteDemandDrivenData(masterPointEdgeHitsPtr_);
1378 masterPointEdgeHitsPtr_ = new labelList(masterPointEdgeHits);
1382 Pout << "changing." << endl;
1389 Pout << "preserved." << endl;
1398 void Foam::slidingInterface::clearPointProjection() const
1400 deleteDemandDrivenData(slavePointPointHitsPtr_);
1401 deleteDemandDrivenData(slavePointEdgeHitsPtr_);
1402 deleteDemandDrivenData(slavePointFaceHitsPtr_);
1403 deleteDemandDrivenData(masterPointEdgeHitsPtr_);
1405 deleteDemandDrivenData(projectedSlavePointsPtr_);
1409 // ************************************************************************* //