meshSearch: Prevent hang in calculation of line-boundary intersections

This fix changes how the intersections loop ignores previously
intersected faces. It now marks them by their index so that subsequent
iterations ignore them.

Before this change, after an intersection was found the start point was
advanced by a small amount to move the past the intersection. The
problem with this was if multiple boundary faces or the end point were
in close proximity to the intersection then the move forward might span
them. This could lead to intersections being missed or counted multiple
times, in some cases indefinitely.

Based on a patch contributed by Mattijs Janssens
Resolves bug report https://bugs.openfoam.org/view.php?id=1147
This commit is contained in:
Will Bainbridge
2018-09-28 12:26:17 +01:00
committed by mattijs
parent b937a531bd
commit 911ea1087d
2 changed files with 92 additions and 61 deletions

View File

@ -2,8 +2,8 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation | Copyright 2015 OpenCFD Ltd. \\/ M anipulation | Copyright 2015-2018 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -38,6 +38,85 @@ namespace Foam
defineTypeNameAndDebug(meshSearch, 0); defineTypeNameAndDebug(meshSearch, 0);
scalar meshSearch::tol_ = 1e-3; scalar meshSearch::tol_ = 1e-3;
// Intersection operation that checks previous successful hits so that they
// are not duplicated
class findUniqueIntersectOp
:
public treeDataFace::findIntersectOp
{
public:
const indexedOctree<treeDataFace>& tree_;
const List<pointIndexHit>& hits_;
public:
//- Construct from components
findUniqueIntersectOp
(
const indexedOctree<treeDataFace>& tree,
const List<pointIndexHit>& hits
)
:
treeDataFace::findIntersectOp(tree),
tree_(tree),
hits_(hits)
{}
//- Calculate intersection of triangle with ray. Sets result
// accordingly
bool operator()
(
const label index,
const point& start,
const point& end,
point& intersectionPoint
) const
{
const primitiveMesh& mesh = tree_.shapes().mesh();
// Check whether this hit has already happened. If the new face
// index is the same as an existing hit then return no new hit. If
// the new face shares a point with an existing hit face and the
// line passes through both faces in the same direction, then this
// is also assumed to be a duplicate hit.
const label newFacei = tree_.shapes().faceLabels()[index];
const face& newFace = mesh.faces()[newFacei];
const scalar newDot = mesh.faceAreas()[newFacei] & (end - start);
forAll(hits_, hiti)
{
const label oldFacei = hits_[hiti].index();
const face& oldFace = mesh.faces()[oldFacei];
const scalar oldDot =
mesh.faceAreas()[oldFacei] & (end - start);
if
(
hits_[hiti].index() == newFacei
|| (
newDot*oldDot > 0
&& (labelHashSet(newFace) & labelHashSet(oldFace)).size()
)
)
{
return false;
}
}
const bool hit =
treeDataFace::findIntersectOp::operator()
(
index,
start,
end,
intersectionPoint
);
return hit;
}
};
} }
@ -466,25 +545,6 @@ Foam::label Foam::meshSearch::findNearestBoundaryFaceWalk
} }
Foam::vector Foam::meshSearch::offset
(
const point& bPoint,
const label bFacei,
const vector& dir
) const
{
// Get the neighbouring cell
label ownerCelli = mesh_.faceOwner()[bFacei];
const point& c = mesh_.cellCentres()[ownerCelli];
// Typical dimension: distance from point on face to cell centre
scalar typDim = mag(c - bPoint);
return tol_*typDim*dir;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::meshSearch::meshSearch Foam::meshSearch::meshSearch
@ -808,39 +868,19 @@ Foam::List<Foam::pointIndexHit> Foam::meshSearch::intersections
) const ) const
{ {
DynamicList<pointIndexHit> hits; DynamicList<pointIndexHit> hits;
findUniqueIntersectOp iop(boundaryTree(), hits);
const vector edgeVec = normalised(pEnd - pStart); while (true)
point pt = pStart;
pointIndexHit bHit;
do
{ {
bHit = intersection(pt, pEnd); // Get the next hit, or quit
pointIndexHit curHit = boundaryTree().findLine(pStart, pEnd, iop);
if (!curHit.hit()) break;
if (bHit.hit()) // Change index into octreeData into face label
{ curHit.setIndex(boundaryTree().shapes().faceLabels()[curHit.index()]);
hits.append(bHit);
const vector& area = mesh_.faceAreas()[bHit.index()];
scalar typDim = Foam::sqrt(mag(area));
if ((mag(bHit.hitPoint() - pEnd)/typDim) < SMALL)
{
break;
}
// Restart from hitPoint shifted a little bit in the direction
// of the destination
pt =
bHit.hitPoint()
+ offset(bHit.hitPoint(), bHit.index(), edgeVec);
}
} while (bHit.hit());
hits.append(curHit);
}
hits.shrink(); hits.shrink();

View File

@ -2,8 +2,8 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -135,15 +135,6 @@ class meshSearch
const label seedFacei const label seedFacei
) const; ) const;
//- Calculate offset vector in direction dir with as length a
// fraction of the cell size (of the cell straddling boundary face)
vector offset
(
const point& bPoint,
const label bFacei,
const vector& dir
) const;
//- No copy construct //- No copy construct
meshSearch(const meshSearch&) = delete; meshSearch(const meshSearch&) = delete;