ENH: streamLine: add bidirectional tracking. Fixes #1466.

This commit is contained in:
mattijs
2019-10-23 16:52:27 +01:00
committed by Andrew Heather
parent 88ebf110ff
commit fb7698f6a1
10 changed files with 184 additions and 46 deletions

View File

@ -56,18 +56,35 @@ void Foam::functionObjects::streamLine::track()
const sampledSet& seedPoints = sampledSetPoints(); const sampledSet& seedPoints = sampledSetPoints();
forAll(seedPoints, i) forAll(seedPoints, seedi)
{ {
particles.addParticle particles.addParticle
( (
new streamLineParticle new streamLineParticle
( (
mesh_, mesh_,
seedPoints[i], seedPoints[seedi],
seedPoints.cells()[i], seedPoints.cells()[seedi],
(trackDir_ == trackDirType::FORWARD),
lifeTime_ lifeTime_
) )
); );
if (trackDir_ == trackDirType::BIDIRECTIONAL)
{
// Add additional particle for the forward bit of the track
particles.addParticle
(
new streamLineParticle
(
mesh_,
seedPoints[seedi],
seedPoints.cells()[seedi],
true,
lifeTime_
)
);
}
} }
label nSeeds = returnReduce(particles.size(), sumOp<label>()); label nSeeds = returnReduce(particles.size(), sumOp<label>());
@ -99,7 +116,6 @@ void Foam::functionObjects::streamLine::track()
vsInterp, vsInterp,
vvInterp, vvInterp,
UIndex, // index of U in vvInterp UIndex, // index of U in vvInterp
trackForward_, // track in +u direction?
nSubCycle_, // automatic track control:step through cells in steps? nSubCycle_, // automatic track control:step through cells in steps?
trackLength_, // fixed track length trackLength_, // fixed track length

View File

@ -45,7 +45,8 @@ Usage
setFormat vtk; setFormat vtk;
U U; U U;
trackForward yes; //Deprecated: trackForward yes;
direction bidirectional; // or forward/backward
fields fields
( (
@ -77,6 +78,7 @@ Usage
setFormat | Output data type | yes | setFormat | Output data type | yes |
U | Tracking velocity field name | no | U U | Tracking velocity field name | no | U
fields | Fields to sample | yes | fields | Fields to sample | yes |
direction | Direction to track | yes |
lifetime | Maximum number of particle tracking steps | yes | lifetime | Maximum number of particle tracking steps | yes |
trackLength | Tracking segment length | no | trackLength | Tracking segment length | no |
nSubCycle | Number of tracking steps per cell | no| nSubCycle | Number of tracking steps per cell | no|

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd.
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
| Copyright (C) 2015 OpenFOAM Foundation | Copyright (C) 2015 OpenFOAM Foundation
@ -47,6 +47,18 @@ namespace functionObjects
} }
const Foam::Enum
<
Foam::functionObjects::streamLineBase::trackDirType
>
Foam::functionObjects::streamLineBase::trackDirTypeNames
({
{ trackDirType::FORWARD, "forward" },
{ trackDirType::BACKWARD, "backward" },
{ trackDirType::BIDIRECTIONAL, "bidirectional" }
});
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
const Foam::word& const Foam::word&
@ -886,7 +898,27 @@ bool Foam::functionObjects::streamLineBase::read(const dictionary& dict)
Info<< " Employing velocity field " << UName_ << endl; Info<< " Employing velocity field " << UName_ << endl;
dict.readEntry("trackForward", trackForward_); bool trackForward;
if (dict.readIfPresent("trackForward", trackForward))
{
trackDir_ =
(
trackForward
? trackDirType::FORWARD
: trackDirType::BACKWARD
);
if (dict.found("direction"))
{
FatalIOErrorInFunction(dict) << "Cannot specify both "
<< "\"trackForward\" and \"direction\""
<< exit(FatalIOError);
}
}
else
{
trackDir_ = trackDirTypeNames.get("direction", dict);
}
dict.readEntry("lifeTime", lifeTime_); dict.readEntry("lifeTime", lifeTime_);
if (lifeTime_ < 1) if (lifeTime_ < 1)
{ {

View File

@ -45,6 +45,7 @@ SourceFiles
#include "writer.H" #include "writer.H"
#include "indirectPrimitivePatch.H" #include "indirectPrimitivePatch.H"
#include "interpolation.H" #include "interpolation.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -65,6 +66,22 @@ class streamLineBase
: :
public fvMeshFunctionObject public fvMeshFunctionObject
{ {
public:
// Public data types
//- Enumeration defining the track direction
enum trackDirType : char
{
FORWARD,
BACKWARD,
BIDIRECTIONAL
};
//- Names for the trackDir
static const Enum<trackDirType> trackDirTypeNames;
protected: protected:
//- Seed set engine //- Seed set engine
@ -85,8 +102,8 @@ protected:
//- Interpolation scheme to use //- Interpolation scheme to use
word interpolationScheme_; word interpolationScheme_;
//- Whether to use +u or -u //- Whether to use +u or -u or both
bool trackForward_; trackDirType trackDir_;
//- Maximum lifetime (= number of cells) of particle //- Maximum lifetime (= number of cells) of particle
label lifeTime_; label lifeTime_;

View File

@ -86,10 +86,12 @@ Foam::streamLineParticle::streamLineParticle
const polyMesh& mesh, const polyMesh& mesh,
const vector& position, const vector& position,
const label celli, const label celli,
const bool trackForward,
const label lifeTime const label lifeTime
) )
: :
particle(mesh, position, celli), particle(mesh, position, celli),
trackForward_(trackForward),
lifeTime_(lifeTime) lifeTime_(lifeTime)
{} {}
@ -98,17 +100,19 @@ Foam::streamLineParticle::streamLineParticle
( (
const polyMesh& mesh, const polyMesh& mesh,
Istream& is, Istream& is,
bool readFields bool readFields,
bool newFormat
) )
: :
particle(mesh, is, readFields) particle(mesh, is, readFields, newFormat)
{ {
if (readFields) if (readFields)
{ {
List<scalarList> sampledScalars; List<scalarList> sampledScalars;
List<vectorList> sampledVectors; List<vectorList> sampledVectors;
is >> lifeTime_ >> sampledPositions_ >> sampledScalars is >> trackForward_ >> lifeTime_
>> sampledPositions_ >> sampledScalars
>> sampledVectors; >> sampledVectors;
sampledScalars_.setSize(sampledScalars.size()); sampledScalars_.setSize(sampledScalars.size());
@ -133,9 +137,11 @@ Foam::streamLineParticle::streamLineParticle
) )
: :
particle(p), particle(p),
trackForward_(p.trackForward_),
lifeTime_(p.lifeTime_), lifeTime_(p.lifeTime_),
sampledPositions_(p.sampledPositions_), sampledPositions_(p.sampledPositions_),
sampledScalars_(p.sampledScalars_) sampledScalars_(p.sampledScalars_),
sampledVectors_(p.sampledVectors_)
{} {}
@ -168,7 +174,7 @@ bool Foam::streamLineParticle::move
sampledPositions_.append(position()); sampledPositions_.append(position());
vector U = interpolateFields(td, position(), cell(), face()); vector U = interpolateFields(td, position(), cell(), face());
if (!td.trackForward_) if (!trackForward_)
{ {
U = -U; U = -U;
} }
@ -366,11 +372,7 @@ void Foam::streamLineParticle::hitWallPatch
void Foam::streamLineParticle::readFields(Cloud<streamLineParticle>& c) void Foam::streamLineParticle::readFields(Cloud<streamLineParticle>& c)
{ {
// if (!c.size()) const bool valid = c.size();
// {
// return;
// }
bool valid = c.size();
particle::readFields(c); particle::readFields(c);
@ -433,6 +435,7 @@ void Foam::streamLineParticle::writeFields(const Cloud<streamLineParticle>& c)
Foam::Ostream& Foam::operator<<(Ostream& os, const streamLineParticle& p) Foam::Ostream& Foam::operator<<(Ostream& os, const streamLineParticle& p)
{ {
os << static_cast<const particle&>(p) os << static_cast<const particle&>(p)
<< token::SPACE << p.trackForward_
<< token::SPACE << p.lifeTime_ << token::SPACE << p.lifeTime_
<< token::SPACE << p.sampledPositions_ << token::SPACE << p.sampledPositions_
<< token::SPACE << p.sampledScalars_ << token::SPACE << p.sampledScalars_

View File

@ -79,8 +79,6 @@ public:
const label UIndex_; const label UIndex_;
const bool trackForward_;
const label nSubCycle_; const label nSubCycle_;
const scalar trackLength_; const scalar trackLength_;
@ -101,7 +99,6 @@ public:
const PtrList<interpolation<scalar>>& vsInterp, const PtrList<interpolation<scalar>>& vsInterp,
const PtrList<interpolation<vector>>& vvInterp, const PtrList<interpolation<vector>>& vvInterp,
const label UIndex, const label UIndex,
const bool trackForward,
const label nSubCycle, const label nSubCycle,
const scalar trackLength, const scalar trackLength,
DynamicList<List<point>>& allPositions, DynamicList<List<point>>& allPositions,
@ -113,7 +110,6 @@ public:
vsInterp_(vsInterp), vsInterp_(vsInterp),
vvInterp_(vvInterp), vvInterp_(vvInterp),
UIndex_(UIndex), UIndex_(UIndex),
trackForward_(trackForward),
nSubCycle_(nSubCycle), nSubCycle_(nSubCycle),
trackLength_(trackLength), trackLength_(trackLength),
allPositions_(allPositions), allPositions_(allPositions),
@ -127,6 +123,9 @@ private:
// Private data // Private data
//- Whether particle transports with +U or -U
bool trackForward_;
//- Lifetime of particle. Particle dies when reaches 0. //- Lifetime of particle. Particle dies when reaches 0.
label lifeTime_; label lifeTime_;
@ -162,6 +161,7 @@ public:
const polyMesh& c, const polyMesh& c,
const vector& position, const vector& position,
const label celli, const label celli,
const bool trackForward,
const label lifeTime const label lifeTime
); );
@ -170,7 +170,8 @@ public:
( (
const polyMesh& c, const polyMesh& c,
Istream& is, Istream& is,
bool readFields = true bool readFields = true,
bool newFormat = true
); );
//- Construct copy //- Construct copy

View File

@ -51,7 +51,8 @@ namespace functionObjects
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet Foam::Tuple2<Foam::tetIndices, Foam::point>
Foam::functionObjects::wallBoundedStreamLine::findNearestTet
( (
const bitSet& isWallPatch, const bitSet& isWallPatch,
const point& seedPt, const point& seedPt,
@ -63,6 +64,7 @@ Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet
label minFacei = -1; label minFacei = -1;
label minTetPti = -1; label minTetPti = -1;
scalar minDistSqr = sqr(GREAT); scalar minDistSqr = sqr(GREAT);
point nearestPt(GREAT, GREAT, GREAT);
for (label facei : cFaces) for (label facei : cFaces)
{ {
@ -76,14 +78,17 @@ Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet
for (label i = 2; i < f.size(); i++) for (label i = 2; i < f.size(); i++)
{ {
const point& thisPoint = mesh_.points()[f[fp]]; const point& thisPoint = mesh_.points()[f[fp]];
label nextFp = f.fcIndex(fp); const label nextFp = f.fcIndex(fp);
const point& nextPoint = mesh_.points()[f[nextFp]]; const point& nextPoint = mesh_.points()[f[nextFp]];
const triPointRef tri(basePoint, thisPoint, nextPoint); const triPointRef tri(basePoint, thisPoint, nextPoint);
scalar d2 = magSqr(tri.centre() - seedPt); //const scalar d2 = magSqr(tri.centre() - seedPt);
const pointHit nearInfo(tri.nearestPoint(seedPt));
const scalar d2 = nearInfo.distance();
if (d2 < minDistSqr) if (d2 < minDistSqr)
{ {
nearestPt = nearInfo.rawPoint();
minDistSqr = d2; minDistSqr = d2;
minFacei = facei; minFacei = facei;
minTetPti = i-1; minTetPti = i-1;
@ -93,16 +98,37 @@ Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet
} }
} }
// Put particle in tet // Return tet and nearest point on wall triangle
return tetIndices return Tuple2<Foam::tetIndices, Foam::point>
(
tetIndices
( (
celli, celli,
minFacei, minFacei,
minTetPti minTetPti
),
nearestPt
); );
} }
Foam::point Foam::functionObjects::wallBoundedStreamLine::pushIn
(
const triPointRef& tri,
const point& pt
) const
{
//pointHit nearPt(tri.nearestPoint(pt));
//if (nearPt.distance() > ROOTSMALL)
//{
// FatalErrorInFunction << "tri:" << tri
// << " seed:" << pt << exit(FatalError);
//}
return (1.0-ROOTSMALL)*pt+ROOTSMALL*tri.centre();
}
void Foam::functionObjects::wallBoundedStreamLine::track() void Foam::functionObjects::wallBoundedStreamLine::track()
{ {
// Determine the 'wall' patches // Determine the 'wall' patches
@ -130,14 +156,18 @@ void Foam::functionObjects::wallBoundedStreamLine::track()
const sampledSet& seedPoints = sampledSetPoints(); const sampledSet& seedPoints = sampledSetPoints();
forAll(seedPoints, i) forAll(seedPoints, seedi)
{ {
const label celli = seedPoints.cells()[i]; const label celli = seedPoints.cells()[seedi];
if (celli != -1) if (celli != -1)
{ {
const point& seedPt = seedPoints[i]; const point& seedPt = seedPoints[seedi];
tetIndices ids(findNearestTet(isWallPatch, seedPt, celli)); Tuple2<tetIndices, point> nearestId
(
findNearestTet(isWallPatch, seedPt, celli)
);
const tetIndices& ids = nearestId.first();
if (ids.face() != -1 && isWallPatch[ids.face()]) if (ids.face() != -1 && isWallPatch[ids.face()])
{ {
@ -154,15 +184,38 @@ void Foam::functionObjects::wallBoundedStreamLine::track()
new wallBoundedStreamLineParticle new wallBoundedStreamLineParticle
( (
mesh_, mesh_,
ids.faceTri(mesh_).centre(), // Perturb seed point to be inside triangle
pushIn(ids.faceTri(mesh_), nearestId.second()),
ids.cell(), ids.cell(),
ids.face(), // tetFace ids.face(), // tetFace
ids.tetPt(), ids.tetPt(),
-1, // not on a mesh edge -1, // not on a mesh edge
-1, // not on a diagonal edge -1, // not on a diagonal edge
(trackDir_ == trackDirType::FORWARD), // forward?
lifeTime_ // lifetime lifeTime_ // lifetime
) )
); );
if (trackDir_ == trackDirType::BIDIRECTIONAL)
{
// Additional particle for other half of track
particles.addParticle
(
new wallBoundedStreamLineParticle
(
mesh_,
// Perturb seed point to be inside triangle
pushIn(ids.faceTri(mesh_), nearestId.second()),
ids.cell(),
ids.face(), // tetFace
ids.tetPt(),
-1, // not on a mesh edge
-1, // not on a diagonal edge
true, // forward
lifeTime_ // lifetime
)
);
}
} }
else else
{ {
@ -173,7 +226,7 @@ void Foam::functionObjects::wallBoundedStreamLine::track()
} }
} }
label nSeeds = returnReduce(particles.size(), sumOp<label>()); const label nSeeds = returnReduce(particles.size(), sumOp<label>());
Log << type() << " : seeded " << nSeeds << " particles." << endl; Log << type() << " : seeded " << nSeeds << " particles." << endl;
@ -204,7 +257,6 @@ void Foam::functionObjects::wallBoundedStreamLine::track()
vsInterp, vsInterp,
vvInterp, vvInterp,
UIndex, // index of U in vvInterp UIndex, // index of U in vvInterp
trackForward_, // track in +u direction?
trackLength_, // fixed track length trackLength_, // fixed track length
isWallPatch, // which faces are to follow isWallPatch, // which faces are to follow

View File

@ -46,7 +46,8 @@ Usage
setFormat vtk; setFormat vtk;
U UNear; U UNear;
trackForward yes; //Deprecated: trackForward yes;
direction bidirectional; // or forward/backward
fields fields
( (
@ -76,6 +77,7 @@ Usage
setFormat | Output data type | yes | setFormat | Output data type | yes |
U | Tracking velocity field name | yes | U | Tracking velocity field name | yes |
fields | Fields to sample | yes | fields | Fields to sample | yes |
direction | Direction to track | yes |
lifetime | Maximum number of particle tracking steps | yes | lifetime | Maximum number of particle tracking steps | yes |
trackLength | Tracking segment length | no | trackLength | Tracking segment length | no |
nSubCycle | Number of tracking steps per cell | no| nSubCycle | Number of tracking steps per cell | no|
@ -139,13 +141,21 @@ protected:
// Protected Member Functions // Protected Member Functions
//- Find wall tet on cell //- Find wall tet on cell
tetIndices findNearestTet Tuple2<tetIndices, point> findNearestTet
( (
const bitSet& isWallPatch, const bitSet& isWallPatch,
const point& seedPt, const point& seedPt,
const label celli const label celli
) const; ) const;
//- Push a point a tiny bit towards the centre of the triangle it is in
// to avoid tracking problems
point pushIn
(
const triPointRef& tri,
const point& pt
) const;
public: public:

View File

@ -96,7 +96,7 @@ Foam::vector Foam::wallBoundedStreamLineParticle::sample
{ {
vector U = interpolateFields(td, localPosition_, cell(), face()); vector U = interpolateFields(td, localPosition_, cell(), face());
if (!td.trackForward_) if (!trackForward_)
{ {
U = -U; U = -U;
} }
@ -127,6 +127,7 @@ Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
const label tetPti, const label tetPti,
const label meshEdgeStart, const label meshEdgeStart,
const label diagEdge, const label diagEdge,
const bool trackForward,
const label lifeTime const label lifeTime
) )
: :
@ -140,6 +141,7 @@ Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
meshEdgeStart, meshEdgeStart,
diagEdge diagEdge
), ),
trackForward_(trackForward),
lifeTime_(lifeTime) lifeTime_(lifeTime)
{} {}
@ -159,7 +161,7 @@ Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
List<scalarList> sampledScalars; List<scalarList> sampledScalars;
List<vectorList> sampledVectors; List<vectorList> sampledVectors;
is >> lifeTime_ is >> trackForward_ >> lifeTime_
>> sampledPositions_ >> sampledScalars >> sampledVectors; >> sampledPositions_ >> sampledScalars >> sampledVectors;
sampledScalars_.setSize(sampledScalars.size()); sampledScalars_.setSize(sampledScalars.size());
@ -184,6 +186,7 @@ Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
) )
: :
wallBoundedParticle(p), wallBoundedParticle(p),
trackForward_(p.trackForward_),
lifeTime_(p.lifeTime_), lifeTime_(p.lifeTime_),
sampledPositions_(p.sampledPositions_), sampledPositions_(p.sampledPositions_),
sampledScalars_(p.sampledScalars_), sampledScalars_(p.sampledScalars_),
@ -269,6 +272,7 @@ Foam::Ostream& Foam::operator<<
) )
{ {
os << static_cast<const wallBoundedParticle&>(p) os << static_cast<const wallBoundedParticle&>(p)
<< token::SPACE << p.trackForward_
<< token::SPACE << p.lifeTime_ << token::SPACE << p.lifeTime_
<< token::SPACE << p.sampledPositions_ << token::SPACE << p.sampledPositions_
<< token::SPACE << p.sampledScalars_ << token::SPACE << p.sampledScalars_

View File

@ -82,7 +82,6 @@ public:
const PtrList<interpolation<scalar>>& vsInterp_; const PtrList<interpolation<scalar>>& vsInterp_;
const PtrList<interpolation<vector>>& vvInterp_; const PtrList<interpolation<vector>>& vvInterp_;
const label UIndex_; const label UIndex_;
const bool trackForward_;
const scalar trackLength_; const scalar trackLength_;
DynamicList<vectorList>& allPositions_; DynamicList<vectorList>& allPositions_;
@ -99,7 +98,6 @@ public:
const PtrList<interpolation<scalar>>& vsInterp, const PtrList<interpolation<scalar>>& vsInterp,
const PtrList<interpolation<vector>>& vvInterp, const PtrList<interpolation<vector>>& vvInterp,
const label UIndex, const label UIndex,
const bool trackForward,
const scalar trackLength, const scalar trackLength,
const bitSet& isWallPatch, const bitSet& isWallPatch,
@ -116,7 +114,6 @@ public:
vsInterp_(vsInterp), vsInterp_(vsInterp),
vvInterp_(vvInterp), vvInterp_(vvInterp),
UIndex_(UIndex), UIndex_(UIndex),
trackForward_(trackForward),
trackLength_(trackLength), trackLength_(trackLength),
allPositions_(allPositions), allPositions_(allPositions),
@ -132,6 +129,9 @@ protected:
// Protected data // Protected data
//- Track with +U or -U
bool trackForward_;
//- Lifetime of particle. Particle dies when reaches 0. //- Lifetime of particle. Particle dies when reaches 0.
label lifeTime_; label lifeTime_;
@ -172,6 +172,7 @@ public:
const label tetPti, const label tetPti,
const label meshEdgeStart, const label meshEdgeStart,
const label diagEdge, const label diagEdge,
const bool trackForward,
const label lifeTime const label lifeTime
); );