/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see .
\*---------------------------------------------------------------------------*/
#include "slidingInterface.H"
#include "polyMesh.H"
#include "line.H"
#include "polyTopoChanger.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::scalar Foam::slidingInterface::pointMergeTolDefault_ = 0.05;
const Foam::scalar Foam::slidingInterface::edgeMergeTolDefault_ = 0.01;
const Foam::label Foam::slidingInterface::nFacesPerSlaveEdgeDefault_ = 5;
const Foam::label Foam::slidingInterface::edgeFaceEscapeLimitDefault_ = 10;
const Foam::scalar Foam::slidingInterface::integralAdjTolDefault_ = 0.05;
const Foam::scalar
Foam::slidingInterface::edgeMasterCatchFractionDefault_ = 0.4;
const Foam::scalar Foam::slidingInterface::edgeEndCutoffTolDefault_ = 0.0001;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Index of debug signs:
// a - integral match adjustment: point adjusted
// n - integral match adjustment: point not adjusted
// . - loop of the edge-to-face interaction detection
// x - reversal of direction in edge-to-face interaction detection
// + - complete edge-to-face interaction detection
// z - incomplete edge-to-face interaction detection. This may be OK for edges
// crossing from one to the other side of multiply connected master patch
// * - colinear triangle: adjusting projection with slave face normal
// m - master point inserted into the edge
bool Foam::slidingInterface::projectPoints() const
{
if (debug)
{
Pout<< FUNCTION_NAME << nl
<< ": for object " << name() << " : "
<< "Projecting slave points onto master surface." << endl;
}
// Algorithm:
// 1) Go through all the points of the master and slave patch and calculate
// minimum edge length coming from the point. Calculate the point
// merge tolerance as the fraction of minimum edge length.
// 2) Project all the slave points onto the master patch
// in the normal direction.
// 3) If some points have missed and the match is integral, the
// points in question will be adjusted. Find the nearest face for
// those points and continue with the procedure.
// 4) For every point, check all the points of the face it has hit.
// For every pair of points find if their distance is smaller than
// both the master and slave merge tolerance. If so, the slave point
// is moved to the location of the master point. Remember the master
// point index.
// 5) For every unmerged slave point, check its distance to all the
// edges of the face it has hit. If the distance is smaller than the
// edge merge tolerance, the point will be moved onto the edge.
// Remember the master edge index.
// 6) The remaning slave points will be projected into faces. Remember the
// master face index.
// 7) For the points that miss the master patch, grab the nearest face
// on the master and leave the slave point where it started
// from and the miss is recorded.
const polyMesh& mesh = topoChanger().mesh();
const primitiveFacePatch& masterPatch =
mesh.faceZones()[masterFaceZoneID_.index()]();
const primitiveFacePatch& slavePatch =
mesh.faceZones()[slaveFaceZoneID_.index()]();
// Get references to local points, local edges and local faces
// for master and slave patch
// const labelList& masterMeshPoints = masterPatch.meshPoints();
const pointField& masterLocalPoints = masterPatch.localPoints();
const faceList& masterLocalFaces = masterPatch.localFaces();
const edgeList& masterEdges = masterPatch.edges();
const labelListList& masterEdgeFaces = masterPatch.edgeFaces();
const labelListList& masterFaceEdges = masterPatch.faceEdges();
const labelListList& masterFaceFaces = masterPatch.faceFaces();
// Pout<< "Master patch. Local points: " << masterLocalPoints << nl
// << "Master patch. Mesh points: " << masterPatch.meshPoints() << nl
// << "Local faces: " << masterLocalFaces << nl
// << "local edges: " << masterEdges << endl;
// const labelList& slaveMeshPoints = slavePatch.meshPoints();
const pointField& slaveLocalPoints = slavePatch.localPoints();
const edgeList& slaveEdges = slavePatch.edges();
const labelListList& slaveEdgeFaces = slavePatch.edgeFaces();
const vectorField& slavePointNormals = slavePatch.pointNormals();
// const vectorField& slaveFaceNormals = slavePatch.faceNormals();
// Pout<< "Slave patch. Local points: " << slaveLocalPoints << nl
// << "Slave patch. Mesh points: " << slavePatch.meshPoints() << nl
// << "Local faces: " << slavePatch.localFaces() << nl
// << "local edges: " << slaveEdges << endl;
// Calculate min edge distance for points and faces
// Calculate min edge length for the points and faces of master patch
scalarField minMasterPointLength(masterLocalPoints.size(), GREAT);
scalarField minMasterFaceLength(masterPatch.size(), GREAT);
forAll(masterEdges, edgei)
{
const edge& curEdge = masterEdges[edgei];
const scalar curLength = curEdge.mag(masterLocalPoints);
// Do points
minMasterPointLength[curEdge.start()] =
min
(
minMasterPointLength[curEdge.start()],
curLength
);
minMasterPointLength[curEdge.end()] =
min
(
minMasterPointLength[curEdge.end()],
curLength
);
// Do faces
const labelList& curFaces = masterEdgeFaces[edgei];
for (const label facei : curFaces)
{
minMasterFaceLength[facei] =
min
(
minMasterFaceLength[facei],
curLength
);
}
}
// Pout<< "min length for master points: " << minMasterPointLength << endl
// << "min length for master faces: " << minMasterFaceLength << endl;
// Calculate min edge length for the points and faces of slave patch
scalarField minSlavePointLength(slaveLocalPoints.size(), GREAT);
scalarField minSlaveFaceLength(slavePatch.size(), GREAT);
forAll(slaveEdges, edgei)
{
const edge& curEdge = slaveEdges[edgei];
const scalar curLength = curEdge.mag(slaveLocalPoints);
// Do points
minSlavePointLength[curEdge.start()] =
min
(
minSlavePointLength[curEdge.start()],
curLength
);
minSlavePointLength[curEdge.end()] =
min
(
minSlavePointLength[curEdge.end()],
curLength
);
// Do faces
const labelList& curFaces = slaveEdgeFaces[edgei];
for (const label facei : curFaces)
{
minSlaveFaceLength[facei] =
min
(
minSlaveFaceLength[facei],
curLength
);
}
}
// Pout<< "min length for slave points: " << minSlavePointLength << endl
// << "min length for slave faces: " << minSlaveFaceLength << endl;
// Project slave points onto the master patch
// Face hit by the slave point
List slavePointFaceHits =
slavePatch.projectPoints
(
masterPatch,
slavePointNormals,
projectionAlgo_
);
if (debug)
{
label nHits = 0;
for (const auto& hit : slavePointFaceHits)
{
if (hit.hit())
{
++nHits;
}
}
Pout<< "Number of hits in point projection: " << nHits
<< " out of " << slavePointFaceHits.size() << " points."
<< endl;
}
// Projected slave points are stored for mesh motion correction
projectedSlavePointsPtr_.reset
(
new pointField(slavePointFaceHits.size(), Zero)
);
auto& projectedSlavePoints = *projectedSlavePointsPtr_;
// Adjust projection to type of match
label nAdjustedPoints = 0;
// If the match is integral and some points have missed,
// find nearest master face
if (matchType_ == INTEGRAL)
{
if (debug)
{
Pout<< "bool slidingInterface::projectPoints() for object "
<< name() << " : "
<< "Adjusting point projection for integral match: ";
}
forAll(slavePointFaceHits, pointi)
{
if (slavePointFaceHits[pointi].hit())
{
// Grab the hit point
projectedSlavePoints[pointi] =
masterLocalFaces
[slavePointFaceHits[pointi].hitObject()].ray
(
slaveLocalPoints[pointi],
slavePointNormals[pointi],
masterLocalPoints,
projectionAlgo_
).hitPoint();
}
else
{
// Grab the nearest point on the face (edge)
pointHit missAdjust =
masterLocalFaces[slavePointFaceHits[pointi].hitObject()].ray
(
slaveLocalPoints[pointi],
slavePointNormals[pointi],
masterLocalPoints,
projectionAlgo_
);
const point nearPoint = missAdjust.missPoint();
const point missPoint =
slaveLocalPoints[pointi]
+ slavePointNormals[pointi]*missAdjust.distance();
// Calculate the tolerance
const scalar mergeTol =
integralAdjTol_*minSlavePointLength[pointi];
// Adjust the hit
if (nearPoint.dist(missPoint) < mergeTol)
{
if (debug)
{
Pout<< "a";
}
// Pout<< "Moving slave point in integral adjustment "
// << pointi << " miss point: " << missPoint
// << " near point: " << nearPoint
// << " mergeTol: " << mergeTol
// << " dist: " << nearPoint.dist(missPoint) << endl;
projectedSlavePoints[pointi] = nearPoint;
slavePointFaceHits[pointi] =
objectHit(true, slavePointFaceHits[pointi].hitObject());
nAdjustedPoints++;
}
else
{
projectedSlavePoints[pointi] = slaveLocalPoints[pointi];
if (debug)
{
Pout<< "n";
}
}
}
}
if (debug)
{
Pout<< " done." << endl;
}
}
else if (matchType_ == PARTIAL)
{
forAll(slavePointFaceHits, pointi)
{
if (slavePointFaceHits[pointi].hit())
{
// Grab the hit point
projectedSlavePoints[pointi] =
masterLocalFaces
[slavePointFaceHits[pointi].hitObject()].ray
(
slaveLocalPoints[pointi],
slavePointNormals[pointi],
masterLocalPoints,
projectionAlgo_
).hitPoint();
}
else
{
// The point remains where it started from
projectedSlavePoints[pointi] = slaveLocalPoints[pointi];
}
}
}
else
{
FatalErrorInFunction
<< " for object " << name()
<< abort(FatalError);
}
if (debug)
{
Pout<< "Number of adjusted points in projection: "
<< nAdjustedPoints << endl;
// Check for zero-length edges in slave projection
scalar minEdgeLength = GREAT;
label nShortEdges = 0;
for (const edge& e : slaveEdges)
{
const scalar len = e.mag(projectedSlavePoints);
minEdgeLength = min(minEdgeLength, len);
if (len < SMALL)
{
Pout<< "Point projection problems for edge: "
<< e << ". Length = " << len
<< endl;
nShortEdges++;
}
}
if (nShortEdges > 0)
{
FatalErrorInFunction
<< nShortEdges << " short projected edges "
<< "after adjustment for object " << name()
<< abort(FatalError);
}
else
{
Pout<< " ... projection OK." << endl;
}
}
// scalarField magDiffs(mag(slaveLocalPoints - projectedSlavePoints));
// Pout<< "Slave point face hits: " << slavePointFaceHits << nl
// << "slave points: " << slaveLocalPoints << nl
// << "Projected slave points: " << projectedSlavePoints
// << "diffs: " << magDiffs << endl;
// Merge projected points against master points
labelList slavePointPointHits(slaveLocalPoints.size(), -1);
labelList masterPointPointHits(masterLocalPoints.size(), -1);
// Go through all the slave points and compare them against all the points
// in the master face they hit. If the distance between the projected point
// and any of the master face points is smaller than both tolerances,
// merge the projected point by:
// 1) adjusting the projected point to coincide with the
// master point it merges with
// 2) remembering the hit master point index in slavePointPointHits
// 3) resetting the hit face to -1
// 4) If a master point has been hit directly, it cannot be merged
// into the edge. Mark it as used in the reverse list
label nMergedPoints = 0;
forAll(projectedSlavePoints, pointi)
{
if (slavePointFaceHits[pointi].hit())
{
// Use non-const reference so the point can be adjusted
point& curPoint = projectedSlavePoints[pointi];
// Get the hit face (on master)
const face& hitFace =
masterLocalFaces[slavePointFaceHits[pointi].hitObject()];
label mergePoint = -1;
scalar mergeDist = GREAT;
// Try all point before deciding on best fit.
for (const label hitPointi : hitFace)
{
const scalar dist =
mag(masterLocalPoints[hitPointi] - curPoint);
// Calculate the tolerance
const scalar mergeTol =
pointMergeTol_*
min
(
minSlavePointLength[pointi],
minMasterPointLength[hitPointi]
);
if (dist < mergeTol && dist < mergeDist)
{
mergePoint = hitPointi;
mergeDist = dist;
// Pout<< "Merging slave point "
// << slavePatch.meshPoints()[pointi] << " at "
// << slaveLocalPoints[pointi] << " with master "
// << masterPatch.meshPoints()[mergePoint] << " at "
// << masterLocalPoints[mergePoint]
// << ". dist: " << mergeDist
// << " mergeTol: " << mergeTol << endl;
}
}
if (mergePoint > -1)
{
// Slave point is to be merged with master point.
// This may also include a false positive when the two points
// already point to the same global point, but this will need
// to be addressed by the caller.
nMergedPoints++;
slavePointPointHits[pointi] = mergePoint;
masterPointPointHits[mergePoint] = pointi;
// Adjust (snap) slave point
curPoint = masterLocalPoints[mergePoint];
}
}
}
// Pout<< "slavePointPointHits: " << slavePointPointHits << nl
// << "masterPointPointHits: " << masterPointPointHits << endl;
if (debug)
{
// Check for zero-length edges in slave projection
scalar minEdgeLength = GREAT;
for (const edge& e : slaveEdges)
{
const scalar len = e.mag(projectedSlavePoints);
minEdgeLength = min(minEdgeLength, len);
if (len < SMALL)
{
Pout<< "Point projection problems for edge: "
<< e << ". Length = " << len
<< endl;
}
}
if (minEdgeLength < SMALL)
{
FatalErrorInFunction
<< " after point merge for object " << name()
<< abort(FatalError);
}
else
{
Pout<< " ... point merge OK." << endl;
}
}
// Merge projected points against master edges
labelList slavePointEdgeHits(slaveLocalPoints.size(), -1);
label nMovedPoints = 0;
forAll(projectedSlavePoints, pointi)
{
// Eliminate the points merged into points
if (slavePointPointHits[pointi] < 0)
{
// Get current point position
point& curPoint = projectedSlavePoints[pointi];
// Get the hit face
const labelList& hitFaceEdges =
masterFaceEdges[slavePointFaceHits[pointi].hitObject()];
// Calculate the tolerance
const scalar mergeLength =
min
(
minSlavePointLength[pointi],
minMasterFaceLength[slavePointFaceHits[pointi].hitObject()]
);
const scalar mergeTol = pointMergeTol_*mergeLength;
scalar minDistance = GREAT;
for (const label edgei : hitFaceEdges)
{
const edge& curEdge = masterEdges[edgei];
pointHit edgeHit =
curEdge.line(masterLocalPoints).nearestDist(curPoint);
if (edgeHit.hit())
{
const scalar dist =
edgeHit.point().dist(projectedSlavePoints[pointi]);
if (dist < mergeTol && dist < minDistance)
{
// Point is to be moved onto master edge
nMovedPoints++;
slavePointEdgeHits[pointi] = edgei;
projectedSlavePoints[pointi] = edgeHit.point();
minDistance = dist;
// Pout<< "Moving slave point "
// << slavePatch.meshPoints()[pointi]
// << " (" << pointi
// << ") at " << slaveLocalPoints[pointi]
// << " onto master edge " << edgei
// << " or ("
// << masterLocalPoints[curEdge.start()]
// << masterLocalPoints[curEdge.end()]
// << ") hit: " << edgeHit.point()
// << ". dist: " << dist
// << " mergeTol: " << mergeTol << endl;
}
}
} // end of hit face edges
if (slavePointEdgeHits[pointi] > -1)
{
// Projected slave point has moved. Re-attempt merge with
// master points of the edge
point& curPoint = projectedSlavePoints[pointi];
const edge& hitMasterEdge =
masterEdges[slavePointEdgeHits[pointi]];
label mergePoint = -1;
scalar mergeDist = GREAT;
forAll(hitMasterEdge, hmeI)
{
const scalar hmeDist =
mag(masterLocalPoints[hitMasterEdge[hmeI]] - curPoint);
// Calculate the tolerance
const scalar mergeTol =
pointMergeTol_*
min
(
minSlavePointLength[pointi],
minMasterPointLength[hitMasterEdge[hmeI]]
);
if (hmeDist < mergeTol && hmeDist < mergeDist)
{
mergePoint = hitMasterEdge[hmeI];
mergeDist = hmeDist;
// Pout<< "Merging slave point; SECOND TRY "
// << slavePatch.meshPoints()[pointi] << " local "
// << pointi << " at "
// << slaveLocalPoints[pointi] << " with master "
// << masterPatch.meshPoints()[mergePoint] << " at "
// << masterLocalPoints[mergePoint]
// << ". hmeDist: " << mergeDist
// << " mergeTol: " << mergeTol << endl;
}
}
if (mergePoint > -1)
{
// Point is to be merged with master point
slavePointPointHits[pointi] = mergePoint;
curPoint = masterLocalPoints[mergePoint];
masterPointPointHits[mergePoint] = pointi;
slavePointFaceHits[pointi] =
objectHit(true, slavePointFaceHits[pointi].hitObject());
// Disable edge merge
slavePointEdgeHits[pointi] = -1;
}
}
}
}
if (debug)
{
Pout<< "Number of merged master points: " << nMergedPoints << nl
<< "Number of adjusted slave points: " << nMovedPoints << endl;
// Check for zero-length edges in slave projection
scalar minEdgeLength = GREAT;
for (const edge& e : slaveEdges)
{
const scalar len = e.mag(projectedSlavePoints);
minEdgeLength = min(minEdgeLength, len);
if (len < SMALL)
{
Pout<< "Point projection problems for edge: "
<< e << ". Length = " << len
<< endl;
}
}
if (minEdgeLength < SMALL)
{
FatalErrorInFunction
<< " after correction for object " << name()
<< abort(FatalError);
}
}
// Pout<< "slavePointEdgeHits: " << slavePointEdgeHits << endl;
// Insert the master points into closest slave edge if appropriate
// Algorithm:
// The face potentially interacts with all the points of the
// faces covering the path between its two ends. Since we are
// examining an arbitrary shadow of the edge on a non-Euclidian
// surface, it is typically quite hard to do a geometric point
// search (under a shadow of a straight line). Therefore, the
// search will be done topologically.
//
// I) Point collection
// -------------------
// 1) Grab the master faces to which the end points of the edge
// have been projected.
// 2) Starting from the face containing the edge start, grab all
// its points and put them into the point lookup map. Put the
// face onto the face lookup map.
// 3) If the face of the end point is on the face lookup, complete
// the point collection step (this is checked during insertion.
// 4) Start a new round of insertion. Visit all faces in the face
// lookup and add their neighbours which are not already on the
// map. Every time the new neighbour is found, add its points to
// the point lookup. If the face of the end point is inserted,
// continue with the current roundof insertion and stop the
// algorithm.
//
// II) Point check
// ---------------
// Grab all the points from the point collection and check them
// against the current edge. If the edge-to-point distance is
// smaller than the smallest tolerance in the game (min of
// master point tolerance and left and right slave face around
// the edge tolerance) and the nearest point hits the edge, the
// master point will break the slave edge. Check the actual
// distance of the original master position from the edge. If
// the distance is smaller than a fraction of slave edge
// length, the hit is considered valid. Store the slave edge
// index for every master point.
labelList masterPointEdgeHits(masterLocalPoints.size(), -1);
scalarField masterPointEdgeDist(masterLocalPoints.size(), GREAT);
// Note. "Processing slave edges" code is repeated twice in the
// sliding intergace coupling in order to allow the point
// projection to be done separately from the actual cutting.
// Please change consistently with coupleSlidingInterface.C
//
if (debug)
{
Pout<< "Processing slave edges " << endl;
}
// Create a map of faces the edge can interact with
labelHashSet curFaceMap
(
nFacesPerSlaveEdge_*primitiveMesh::edgesPerFace_
);
labelHashSet addedFaces(2*primitiveMesh::edgesPerFace_);
forAll(slaveEdges, edgei)
{
const edge& curEdge = slaveEdges[edgei];
{
// Grab the faces for start and end points
const label startFace =
slavePointFaceHits[curEdge.start()].hitObject();
const label endFace =
slavePointFaceHits[curEdge.end()].hitObject();
// Pout<< "Doing edge " << edgei
// << " or " << curEdge
// << " start: "
// << slavePointFaceHits[curEdge.start()].hitObject()
// << " end "
// << slavePointFaceHits[curEdge.end()].hitObject()
// << endl;
// If the end face is on the list, the face collection is finished
bool completed = false;
if (!completed)
{
// Forward sweep
// Clear the maps
curFaceMap.clear();
addedFaces.clear();
// Insert the start face into the list
curFaceMap.insert(startFace);
addedFaces.insert(startFace);
for
(
label nSweeps = 0;
nSweeps < edgeFaceEscapeLimit_;
++nSweeps
)
{
completed = addedFaces.found(endFace);
// Add all face neighbours of face in the map
const labelList cf(addedFaces.toc());
addedFaces.clear();
for (const label cfi : cf)
{
const labelList& curNbrs = masterFaceFaces[cfi];
for (const label nbri : curNbrs)
{
if (curFaceMap.insert(nbri))
{
addedFaces.insert(nbri);
}
}
}
if (completed) break;
if (debug)
{
Pout<< ".";
}
}
}
if (!completed)
{
// Reverse sweep
if (debug)
{
Pout<< "x";
}
// It is impossible to reach the end from the start, probably
// due to disconnected domain. Do search in opposite direction
addedFaces.clear();
curFaceMap.insert(endFace);
addedFaces.insert(endFace);
for
(
label nSweeps = 0;
nSweeps < edgeFaceEscapeLimit_;
++nSweeps
)
{
completed = addedFaces.found(startFace);
// Add all face neighbours of face in the map
const labelList cf(addedFaces.toc());
addedFaces.clear();
for (const label cfi : cf)
{
const labelList& curNbrs = masterFaceFaces[cfi];
for (const label nbri : curNbrs)
{
if (curFaceMap.insert(nbri))
{
addedFaces.insert(nbri);
}
}
}
if (completed) break;
if (debug)
{
Pout<< ".";
}
}
}
if (completed)
{
if (debug)
{
Pout<< "+ ";
}
}
else
{
if (debug)
{
Pout<< "z ";
}
}
// Collect the points
// Create a map of points the edge can interact with
labelHashSet curPointMap
(
nFacesPerSlaveEdge_*primitiveMesh::pointsPerFace_
);
for (const label facei : curFaceMap)
{
const face& f = masterLocalFaces[facei];
curPointMap.insert(f); // Insert all face points
}
const labelList curMasterPoints = curPointMap.toc();
// Check all the points against the edge.
linePointRef edgeLine = curEdge.line(projectedSlavePoints);
const vector edgeVec = edgeLine.vec();
const scalar edgeMag = edgeLine.mag();
// Calculate actual distance involved in projection. This
// is used to reject master points out of reach.
// Calculated as a combination of travel distance in projection and
// edge length
const scalar slaveCatchDist =
edgeMasterCatchFraction_*edgeMag
+ 0.5*
(
mag
(
projectedSlavePoints[curEdge.start()]
- slaveLocalPoints[curEdge.start()]
)
+ mag
(
projectedSlavePoints[curEdge.end()]
- slaveLocalPoints[curEdge.end()]
)
);
// The point merge distance needs to be measured in the
// plane of the slave edge. The unit vector is calculated
// as a cross product of the edge vector and the edge
// projection direction. When checking for the distance
// in plane, a minimum of the master-to-edge and
// projected-master-to-edge distance is used, to avoid
// problems with badly defined master planes. HJ,
// 17/Oct/2004
const vector edgeNormalInPlane =
normalised
(
edgeVec
^ (
slavePointNormals[curEdge.start()]
+ slavePointNormals[curEdge.end()]
)
);
for (const label cmp : curMasterPoints)
{
// Skip the current point if the edge start or end has
// been adjusted onto in
if
(
slavePointPointHits[curEdge.start()] == cmp
|| slavePointPointHits[curEdge.end()] == cmp
|| masterPointPointHits[cmp] > -1
)
{
// Pout<< "Edge already snapped to point. Skipping." << endl;
continue;
}
// Check if the point actually hits the edge within bounds
pointHit edgeLineHit =
edgeLine.nearestDist(masterLocalPoints[cmp]);
if (edgeLineHit.hit())
{
// If the distance to the line is smaller than
// the tolerance the master point needs to be
// inserted into the edge
// Strict checking of slave cut to avoid capturing
// end points.
const scalar cutOnSlave =
((edgeLineHit.point() - edgeLine.start()) & edgeVec)
/sqr(edgeMag);
const scalar distInEdgePlane =
min
(
edgeLineHit.distance(),
mag
(
(
masterLocalPoints[cmp]
- edgeLineHit.point()
)
& edgeNormalInPlane
)
);
// Pout<< "master point: " << cmp
// << " cutOnSlave " << cutOnSlave
// << " distInEdgePlane: " << distInEdgePlane
// << " tol1: " << pointMergeTol_*edgeMag
// << " hitDist: " << edgeLineHit.distance()
// << " tol2: " <<
// min
// (
// slaveCatchDist,
// masterPointEdgeDist[cmp]
// ) << endl;
// Not a point hit, check for edge
if
(
cutOnSlave > edgeEndCutoffTol_
&& cutOnSlave < 1.0 - edgeEndCutoffTol_ // check edge cut
&& distInEdgePlane < edgeMergeTol_*edgeMag // merge plane
&& edgeLineHit.distance()
< min
(
slaveCatchDist,
masterPointEdgeDist[cmp]
)
)
{
if (debug)
{
if (masterPointEdgeHits[cmp] == -1)
{
// First hit
Pout<< "m";
}
else
{
// Repeat hit
Pout<< "M";
}
}
// Snap to point onto edge
masterPointEdgeHits[cmp] = edgei;
masterPointEdgeDist[cmp] = edgeLineHit.distance();
// Pout<< "Inserting master point "
// << masterPatch.meshPoints()[cmp]
// << " (" << cmp
// << ") at " << masterLocalPoints[cmp]
// << " into slave edge " << edgei
// << " " << curEdge
// << " cutOnSlave: " << cutOnSlave
// << " distInEdgePlane: " << distInEdgePlane
// << ". dist: " << edgeLineHit.distance()
// << " mergeTol: "
// << edgeMergeTol_*edgeMag
// << " other tol: " <<
// min
// (
// slaveCatchDist,
// masterPointEdgeDist[cmp]
// )
// << endl;
}
}
}
} // End if both ends missing
} // End all slave edges
if (debug)
{
Pout<< endl;
}
// Pout<< "masterPointEdgeHits: " << masterPointEdgeHits << endl;
if (debug)
{
Pout<< "bool slidingInterface::projectPoints() for object "
<< name() << " : "
<< "Finished projecting points. Topology = ";
}
// Pout<< "slavePointPointHits: " << slavePointPointHits << nl
// << "slavePointEdgeHits: " << slavePointEdgeHits << nl
// << "slavePointFaceHits: " << slavePointFaceHits << nl
// << "masterPointEdgeHits: " << masterPointEdgeHits << endl;
// The four lists:
// - slavePointPointHits
// - slavePointEdgeHits
// - slavePointFaceHits
// - masterPointEdgeHits
// define how the two patches will be merged topologically.
// If the lists have not changed since the last merge, the
// sliding interface changes only geometrically and simple mesh
// motion will suffice. Otherwise, a topological change is
// required.
// Compare the result with the current state
if (!attached_)
{
// The mesh needs to change topologically
trigger_ = true;
// Store the addressing arrays and projected points
slavePointPointHitsPtr_.reset
(
new labelList(std::move(slavePointPointHits))
);
slavePointEdgeHitsPtr_.reset
(
new labelList(std::move(slavePointEdgeHits))
);
slavePointFaceHitsPtr_.reset
(
new List(std::move(slavePointFaceHits))
);
masterPointEdgeHitsPtr_.reset
(
new labelList(std::move(masterPointEdgeHits))
);
if (debug)
{
Pout<< "(Detached interface) changing." << endl;
}
}
else
{
// Compare the lists against the stored lists. If any of them
// has changed, topological change will be executed.
trigger_ = false;
if
(
!slavePointPointHitsPtr_
|| !slavePointEdgeHitsPtr_
|| !slavePointFaceHitsPtr_
|| !masterPointEdgeHitsPtr_
)
{
// Must be restart. Force topological change.
slavePointPointHitsPtr_.reset
(
new labelList(slavePointPointHits)
);
slavePointEdgeHitsPtr_.reset
(
new labelList(std::move(slavePointEdgeHits))
);
slavePointFaceHitsPtr_.reset
(
new List(std::move(slavePointFaceHits))
);
masterPointEdgeHitsPtr_.reset
(
new labelList(std::move(masterPointEdgeHits))
);
if (debug)
{
Pout<< "(Attached interface restart) changing." << endl;
}
trigger_ = true;
return trigger_;
}
if (slavePointPointHits != *slavePointPointHitsPtr_)
{
if (debug)
{
Pout<< "(Point projection) ";
}
trigger_ = true;
}
if (slavePointEdgeHits != *slavePointEdgeHitsPtr_)
{
if (debug)
{
Pout<< "(Edge projection) ";
}
trigger_ = true;
}
// Comparison for face hits needs to exclude points that have hit
// another point or edge
bool faceHitsDifferent = false;
const List& oldPointFaceHits = *slavePointFaceHitsPtr_;
forAll(slavePointFaceHits, pointi)
{
if
(
slavePointPointHits[pointi] < 0
&& slavePointEdgeHits[pointi] < 0
)
{
// This is a straight face hit
if (slavePointFaceHits[pointi] != oldPointFaceHits[pointi])
{
// Two lists are different
faceHitsDifferent = true;
break;
}
}
}
if (faceHitsDifferent)
{
if (debug)
{
Pout<< "(Face projection) ";
}
trigger_ = true;
}
if (masterPointEdgeHits != *masterPointEdgeHitsPtr_)
{
if (debug)
{
Pout<< "(Master point projection) ";
}
trigger_ = true;
}
if (trigger_)
{
// Grab new data
slavePointPointHitsPtr_.reset
(
new labelList(std::move(slavePointPointHits))
);
slavePointEdgeHitsPtr_.reset
(
new labelList(std::move(slavePointEdgeHits))
);
slavePointFaceHitsPtr_.reset
(
new List(std::move(slavePointFaceHits))
);
masterPointEdgeHitsPtr_.reset
(
new labelList(std::move(masterPointEdgeHits))
);
if (debug)
{
Pout<< "changing." << endl;
}
}
else
{
if (debug)
{
Pout<< "preserved." << endl;
}
}
}
return trigger_;
}
void Foam::slidingInterface::clearPointProjection() const
{
slavePointPointHitsPtr_.reset(nullptr);
slavePointEdgeHitsPtr_.reset(nullptr);
slavePointFaceHitsPtr_.reset(nullptr);
masterPointEdgeHitsPtr_.reset(nullptr);
projectedSlavePointsPtr_.reset(nullptr);
}
// ************************************************************************* //