mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-12-28 03:37:59 +00:00
GIT: Initial state after latest Foundation merge
This commit is contained in:
@ -0,0 +1,415 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "wallBoundedParticle.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
const std::size_t Foam::wallBoundedParticle::sizeofFields_
|
||||
(
|
||||
sizeof(wallBoundedParticle) - sizeof(particle)
|
||||
);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::edge Foam::wallBoundedParticle::currentEdge() const
|
||||
{
|
||||
if ((meshEdgeStart_ != -1) == (diagEdge_ != -1))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Particle:"
|
||||
<< info()
|
||||
<< "cannot both be on a mesh edge and a face-diagonal edge."
|
||||
<< " meshEdgeStart_:" << meshEdgeStart_
|
||||
<< " diagEdge_:" << diagEdge_
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
const Foam::face& f = mesh_.faces()[tetFace()];
|
||||
|
||||
if (meshEdgeStart_ != -1)
|
||||
{
|
||||
return edge(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
|
||||
}
|
||||
else
|
||||
{
|
||||
label faceBasePtI = mesh_.tetBasePtIs()[tetFace()];
|
||||
label diagPtI = (faceBasePtI+diagEdge_)%f.size();
|
||||
|
||||
return edge(f[faceBasePtI], f[diagPtI]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::wallBoundedParticle::crossEdgeConnectedFace
|
||||
(
|
||||
const edge& meshEdge
|
||||
)
|
||||
{
|
||||
// Update tetFace, tetPt
|
||||
particle::crossEdgeConnectedFace(cell(), tetFace(), tetPt(), meshEdge);
|
||||
|
||||
// Update face to be same as tracking one
|
||||
face() = tetFace();
|
||||
|
||||
// And adapt meshEdgeStart_.
|
||||
const Foam::face& f = mesh_.faces()[tetFace()];
|
||||
label fp = findIndex(f, meshEdge[0]);
|
||||
|
||||
if (f.nextLabel(fp) == meshEdge[1])
|
||||
{
|
||||
meshEdgeStart_ = fp;
|
||||
}
|
||||
else
|
||||
{
|
||||
label fpMin1 = f.rcIndex(fp);
|
||||
|
||||
if (f[fpMin1] == meshEdge[1])
|
||||
{
|
||||
meshEdgeStart_ = fpMin1;
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Problem :"
|
||||
<< " particle:"
|
||||
<< info()
|
||||
<< "face:" << tetFace()
|
||||
<< " verts:" << f
|
||||
<< " meshEdge:" << meshEdge
|
||||
<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
diagEdge_ = -1;
|
||||
|
||||
// Check that still on same mesh edge
|
||||
const edge eNew(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
|
||||
if (eNew != meshEdge)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Problem" << abort(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::wallBoundedParticle::crossDiagonalEdge()
|
||||
{
|
||||
if (diagEdge_ == -1)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Particle:"
|
||||
<< info()
|
||||
<< "not on a diagonal edge" << abort(FatalError);
|
||||
}
|
||||
if (meshEdgeStart_ != -1)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Particle:"
|
||||
<< info()
|
||||
<< "meshEdgeStart_:" << meshEdgeStart_ << abort(FatalError);
|
||||
}
|
||||
|
||||
const Foam::face& f = mesh_.faces()[tetFace()];
|
||||
|
||||
// tetPtI starts from 1, goes up to f.size()-2
|
||||
|
||||
if (tetPt() == diagEdge_)
|
||||
{
|
||||
tetPt() = f.rcIndex(tetPt());
|
||||
}
|
||||
else
|
||||
{
|
||||
label nextTetPt = f.fcIndex(tetPt());
|
||||
if (diagEdge_ == nextTetPt)
|
||||
{
|
||||
tetPt() = nextTetPt;
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Particle:"
|
||||
<< info()
|
||||
<< "tetPt:" << tetPt()
|
||||
<< " diagEdge:" << diagEdge_ << abort(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
meshEdgeStart_ = -1;
|
||||
}
|
||||
|
||||
|
||||
Foam::scalar Foam::wallBoundedParticle::trackFaceTri
|
||||
(
|
||||
const vector& endPosition,
|
||||
label& minEdgeI
|
||||
)
|
||||
{
|
||||
// Track p from position to endPosition
|
||||
const triFace tri(currentTetIndices().faceTriIs(mesh_));
|
||||
vector n = tri.normal(mesh_.points());
|
||||
n /= mag(n)+VSMALL;
|
||||
|
||||
// Check which edge intersects the trajectory.
|
||||
// Project trajectory onto triangle
|
||||
minEdgeI = -1;
|
||||
scalar minS = 1; // end position
|
||||
|
||||
edge currentE(-1, -1);
|
||||
if (meshEdgeStart_ != -1 || diagEdge_ != -1)
|
||||
{
|
||||
currentE = currentEdge();
|
||||
}
|
||||
|
||||
// Determine path along line position+s*d to see where intersections are.
|
||||
forAll(tri, i)
|
||||
{
|
||||
label j = tri.fcIndex(i);
|
||||
|
||||
const point& pt0 = mesh_.points()[tri[i]];
|
||||
const point& pt1 = mesh_.points()[tri[j]];
|
||||
|
||||
if (edge(tri[i], tri[j]) == currentE)
|
||||
{
|
||||
// Do not check particle is on
|
||||
continue;
|
||||
}
|
||||
|
||||
// Outwards pointing normal
|
||||
vector edgeNormal = (pt1-pt0)^n;
|
||||
|
||||
edgeNormal /= mag(edgeNormal)+VSMALL;
|
||||
|
||||
// Determine whether position and end point on either side of edge.
|
||||
scalar sEnd = (endPosition-pt0)&edgeNormal;
|
||||
if (sEnd >= 0)
|
||||
{
|
||||
// endPos is outside triangle. position() should always be
|
||||
// inside.
|
||||
scalar sStart = (position()-pt0)&edgeNormal;
|
||||
if (mag(sEnd-sStart) > VSMALL)
|
||||
{
|
||||
scalar s = sStart/(sStart-sEnd);
|
||||
|
||||
if (s >= 0 && s < minS)
|
||||
{
|
||||
minS = s;
|
||||
minEdgeI = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minEdgeI != -1)
|
||||
{
|
||||
position() += minS*(endPosition-position());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did not hit any edge so tracked to the end position. Set position
|
||||
// without any calculation to avoid truncation errors.
|
||||
position() = endPosition;
|
||||
minS = 1.0;
|
||||
}
|
||||
|
||||
// Project position() back onto plane of triangle
|
||||
const point& triPt = mesh_.points()[tri[0]];
|
||||
position() -= ((position()-triPt)&n)*n;
|
||||
|
||||
return minS;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::wallBoundedParticle::isTriAlongTrack
|
||||
(
|
||||
const point& endPosition
|
||||
) const
|
||||
{
|
||||
const triFace triVerts(currentTetIndices().faceTriIs(mesh_));
|
||||
const edge currentE = currentEdge();
|
||||
|
||||
if
|
||||
(
|
||||
currentE[0] == currentE[1]
|
||||
|| findIndex(triVerts, currentE[0]) == -1
|
||||
|| findIndex(triVerts, currentE[1]) == -1
|
||||
)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Edge " << currentE << " not on triangle " << triVerts
|
||||
<< info()
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
|
||||
const vector dir = endPosition-position();
|
||||
|
||||
// Get normal of currentE
|
||||
vector n = triVerts.normal(mesh_.points());
|
||||
n /= mag(n);
|
||||
|
||||
forAll(triVerts, i)
|
||||
{
|
||||
label j = triVerts.fcIndex(i);
|
||||
const point& pt0 = mesh_.points()[triVerts[i]];
|
||||
const point& pt1 = mesh_.points()[triVerts[j]];
|
||||
|
||||
if (edge(triVerts[i], triVerts[j]) == currentE)
|
||||
{
|
||||
vector edgeNormal = (pt1-pt0)^n;
|
||||
return (dir&edgeNormal) < 0;
|
||||
}
|
||||
}
|
||||
|
||||
FatalErrorInFunction
|
||||
<< "Problem" << abort(FatalError);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::wallBoundedParticle::wallBoundedParticle
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const vector& position,
|
||||
const label celli,
|
||||
const label tetFacei,
|
||||
const label tetPtI,
|
||||
const label meshEdgeStart,
|
||||
const label diagEdge
|
||||
)
|
||||
:
|
||||
particle(mesh, position, celli, tetFacei, tetPtI),
|
||||
meshEdgeStart_(meshEdgeStart),
|
||||
diagEdge_(diagEdge)
|
||||
{}
|
||||
|
||||
|
||||
Foam::wallBoundedParticle::wallBoundedParticle
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
Istream& is,
|
||||
bool readFields
|
||||
)
|
||||
:
|
||||
particle(mesh, is, readFields)
|
||||
{
|
||||
if (readFields)
|
||||
{
|
||||
if (is.format() == IOstream::ASCII)
|
||||
{
|
||||
is >> meshEdgeStart_ >> diagEdge_;
|
||||
}
|
||||
else
|
||||
{
|
||||
is.read(reinterpret_cast<char*>(&meshEdgeStart_), sizeofFields_);
|
||||
}
|
||||
}
|
||||
|
||||
// Check state of Istream
|
||||
is.check
|
||||
(
|
||||
"wallBoundedParticle::wallBoundedParticle"
|
||||
"(const Cloud<wallBoundedParticle>&, Istream&, bool)"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Foam::wallBoundedParticle::wallBoundedParticle
|
||||
(
|
||||
const wallBoundedParticle& p
|
||||
)
|
||||
:
|
||||
particle(p),
|
||||
meshEdgeStart_(p.meshEdgeStart_),
|
||||
diagEdge_(p.diagEdge_)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
|
||||
|
||||
Foam::Ostream& Foam::operator<<
|
||||
(
|
||||
Ostream& os,
|
||||
const wallBoundedParticle& p
|
||||
)
|
||||
{
|
||||
if (os.format() == IOstream::ASCII)
|
||||
{
|
||||
os << static_cast<const particle&>(p)
|
||||
<< token::SPACE << p.meshEdgeStart_
|
||||
<< token::SPACE << p.diagEdge_;
|
||||
}
|
||||
else
|
||||
{
|
||||
os << static_cast<const particle&>(p);
|
||||
os.write
|
||||
(
|
||||
reinterpret_cast<const char*>(&p.meshEdgeStart_),
|
||||
wallBoundedParticle::sizeofFields_
|
||||
);
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
Foam::Ostream& Foam::operator<<
|
||||
(
|
||||
Ostream& os,
|
||||
const InfoProxy<wallBoundedParticle>& ip
|
||||
)
|
||||
{
|
||||
const wallBoundedParticle& p = ip.t_;
|
||||
|
||||
tetPointRef tpr(p.currentTet());
|
||||
|
||||
os << " " << static_cast<const particle&>(p) << nl
|
||||
<< " tet:" << nl;
|
||||
os << " ";
|
||||
meshTools::writeOBJ(os, tpr.a());
|
||||
os << " ";
|
||||
meshTools::writeOBJ(os, tpr.b());
|
||||
os << " ";
|
||||
meshTools::writeOBJ(os, tpr.c());
|
||||
os << " ";
|
||||
meshTools::writeOBJ(os, tpr.d());
|
||||
os << " l 1 2" << nl
|
||||
<< " l 1 3" << nl
|
||||
<< " l 1 4" << nl
|
||||
<< " l 2 3" << nl
|
||||
<< " l 2 4" << nl
|
||||
<< " l 3 4" << nl;
|
||||
os << " ";
|
||||
meshTools::writeOBJ(os, p.position());
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,355 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::wallBoundedParticle
|
||||
|
||||
Description
|
||||
Particle class that tracks on triangles of boundary faces. Use
|
||||
trackToEdge similar to trackToFace on particle.
|
||||
|
||||
SourceFiles
|
||||
wallBoundedParticle.C
|
||||
wallBoundedParticleTemplates.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef wallBoundedParticle_H
|
||||
#define wallBoundedParticle_H
|
||||
|
||||
#include "particle.H"
|
||||
#include "autoPtr.H"
|
||||
#include "InfoProxy.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward declaration of friend functions and operators
|
||||
|
||||
class wallBoundedParticle;
|
||||
|
||||
Ostream& operator<<(Ostream&, const wallBoundedParticle&);
|
||||
Ostream& operator<<(Ostream&, const InfoProxy<wallBoundedParticle>&);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class wallBoundedParticle Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class wallBoundedParticle
|
||||
:
|
||||
public particle
|
||||
{
|
||||
// Private data
|
||||
|
||||
//- Size in bytes of the fields
|
||||
static const std::size_t sizeofFields_;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Class used to pass tracking data to the trackToFace function
|
||||
template<class CloudType>
|
||||
class TrackingData
|
||||
:
|
||||
public particle::TrackingData<CloudType>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
const PackedBoolList& isWallPatch_;
|
||||
|
||||
// Constructors
|
||||
|
||||
inline TrackingData
|
||||
(
|
||||
CloudType& cloud,
|
||||
const PackedBoolList& isWallPatch
|
||||
)
|
||||
:
|
||||
particle::TrackingData<CloudType>
|
||||
(
|
||||
cloud
|
||||
),
|
||||
isWallPatch_(isWallPatch)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected data
|
||||
|
||||
//- Particle is on mesh edge:
|
||||
// const face& f = mesh.faces()[tetFace()]
|
||||
// const edge e(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
|
||||
// Note that this real edge
|
||||
// is also one of the edges of the face-triangle (from
|
||||
// tetFace()+tetPt()).
|
||||
label meshEdgeStart_;
|
||||
|
||||
//- Particle is on diagonal edge:
|
||||
// const face& f = mesh.faces()[tetFace()]
|
||||
// label faceBasePtI = mesh.tetBasePtIs()[facei];
|
||||
// label diagPtI = (faceBasePtI+diagEdge_)%f.size();
|
||||
// const edge e(f[faceBasePtI], f[diagPtI]);
|
||||
label diagEdge_;
|
||||
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Construct current edge
|
||||
edge currentEdge() const;
|
||||
|
||||
//- Cross mesh edge into different face on same cell
|
||||
void crossEdgeConnectedFace(const edge& meshEdge);
|
||||
|
||||
//- Cross diagonal edge into different triangle on same face,cell
|
||||
void crossDiagonalEdge();
|
||||
|
||||
//- Track through single triangle
|
||||
scalar trackFaceTri(const vector& endPosition, label& minEdgeI);
|
||||
|
||||
//- Is current triangle in the track direction
|
||||
bool isTriAlongTrack(const point& endPosition) const;
|
||||
|
||||
|
||||
// Patch interactions
|
||||
|
||||
//- Do all patch interaction
|
||||
template<class TrackData>
|
||||
void patchInteraction(TrackData& td, const scalar trackFraction);
|
||||
|
||||
//- Overridable function to handle the particle hitting a patch
|
||||
// Executed before other patch-hitting functions
|
||||
template<class TrackData>
|
||||
bool hitPatch
|
||||
(
|
||||
const polyPatch&,
|
||||
TrackData& td,
|
||||
const label patchi,
|
||||
const scalar trackFraction,
|
||||
const tetIndices& tetIs
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a wedge
|
||||
template<class TrackData>
|
||||
void hitWedgePatch
|
||||
(
|
||||
const wedgePolyPatch&,
|
||||
TrackData& td
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a
|
||||
// symmetry plane
|
||||
template<class TrackData>
|
||||
void hitSymmetryPlanePatch
|
||||
(
|
||||
const symmetryPlanePolyPatch&,
|
||||
TrackData& td
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a
|
||||
// symmetry patch
|
||||
template<class TrackData>
|
||||
void hitSymmetryPatch
|
||||
(
|
||||
const symmetryPolyPatch&,
|
||||
TrackData& td
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a cyclic
|
||||
template<class TrackData>
|
||||
void hitCyclicPatch
|
||||
(
|
||||
const cyclicPolyPatch&,
|
||||
TrackData& td
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a
|
||||
//- processorPatch
|
||||
template<class TrackData>
|
||||
void hitProcessorPatch
|
||||
(
|
||||
const processorPolyPatch&,
|
||||
TrackData& td
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a wallPatch
|
||||
template<class TrackData>
|
||||
void hitWallPatch
|
||||
(
|
||||
const wallPolyPatch&,
|
||||
TrackData& td,
|
||||
const tetIndices&
|
||||
);
|
||||
|
||||
//- Overridable function to handle the particle hitting a polyPatch
|
||||
template<class TrackData>
|
||||
void hitPatch
|
||||
(
|
||||
const polyPatch&,
|
||||
TrackData& td
|
||||
);
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from components
|
||||
wallBoundedParticle
|
||||
(
|
||||
const polyMesh& c,
|
||||
const vector& position,
|
||||
const label celli,
|
||||
const label tetFacei,
|
||||
const label tetPtI,
|
||||
const label meshEdgeStart,
|
||||
const label diagEdge
|
||||
);
|
||||
|
||||
//- Construct from Istream
|
||||
wallBoundedParticle
|
||||
(
|
||||
const polyMesh& c,
|
||||
Istream& is,
|
||||
bool readFields = true
|
||||
);
|
||||
|
||||
//- Construct copy
|
||||
wallBoundedParticle(const wallBoundedParticle& p);
|
||||
|
||||
//- Construct and return a clone
|
||||
autoPtr<particle> clone() const
|
||||
{
|
||||
return autoPtr<particle>(new wallBoundedParticle(*this));
|
||||
}
|
||||
|
||||
//- Factory class to read-construct particles used for
|
||||
// parallel transfer
|
||||
class iNew
|
||||
{
|
||||
const polyMesh& mesh_;
|
||||
|
||||
public:
|
||||
|
||||
iNew(const polyMesh& mesh)
|
||||
:
|
||||
mesh_(mesh)
|
||||
{}
|
||||
|
||||
autoPtr<wallBoundedParticle> operator()
|
||||
(
|
||||
Istream& is
|
||||
) const
|
||||
{
|
||||
return autoPtr<wallBoundedParticle>
|
||||
(
|
||||
new wallBoundedParticle(mesh_, is, true)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// Access
|
||||
|
||||
//- -1 or label of mesh edge
|
||||
inline label meshEdgeStart() const
|
||||
{
|
||||
return meshEdgeStart_;
|
||||
}
|
||||
|
||||
//- -1 or diagonal edge
|
||||
inline label diagEdge() const
|
||||
{
|
||||
return diagEdge_;
|
||||
}
|
||||
|
||||
|
||||
// Track
|
||||
|
||||
//- Equivalent of trackToFace
|
||||
template<class TrackData>
|
||||
scalar trackToEdge
|
||||
(
|
||||
TrackData& td,
|
||||
const vector& endPosition
|
||||
);
|
||||
|
||||
|
||||
// Info
|
||||
|
||||
//- Return info proxy.
|
||||
// Used to print particle information to a stream
|
||||
inline InfoProxy<wallBoundedParticle> info() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// I-O
|
||||
|
||||
//- Read
|
||||
template<class CloudType>
|
||||
static void readFields(CloudType&);
|
||||
|
||||
//- Write
|
||||
template<class CloudType>
|
||||
static void writeFields(const CloudType&);
|
||||
|
||||
|
||||
// Ostream Operator
|
||||
|
||||
friend Ostream& operator<<
|
||||
(
|
||||
Ostream&,
|
||||
const wallBoundedParticle&
|
||||
);
|
||||
|
||||
friend Ostream& operator<<
|
||||
(
|
||||
Ostream&,
|
||||
const InfoProxy<wallBoundedParticle>&
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#ifdef NoRepository
|
||||
#include "wallBoundedParticleTemplates.C"
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,559 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "wallBoundedParticle.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::patchInteraction
|
||||
(
|
||||
TrackData& td,
|
||||
const scalar trackFraction
|
||||
)
|
||||
{
|
||||
typedef typename TrackData::cloudType::particleType particleType;
|
||||
|
||||
particleType& p = static_cast<particleType&>(*this);
|
||||
p.hitFace(td);
|
||||
|
||||
if (!internalFace(facei_))
|
||||
{
|
||||
label origFacei = facei_;
|
||||
label patchi = patch(facei_);
|
||||
|
||||
// No action taken for tetPti_ for tetFacei_ here, handled by
|
||||
// patch interaction call or later during processor transfer.
|
||||
|
||||
|
||||
// Dummy tet indices. What to do here?
|
||||
tetIndices faceHitTetIs;
|
||||
|
||||
if
|
||||
(
|
||||
!p.hitPatch
|
||||
(
|
||||
mesh_.boundaryMesh()[patchi],
|
||||
td,
|
||||
patchi,
|
||||
trackFraction,
|
||||
faceHitTetIs
|
||||
)
|
||||
)
|
||||
{
|
||||
// Did patch interaction model switch patches?
|
||||
// Note: recalculate meshEdgeStart_, diagEdge_!
|
||||
if (facei_ != origFacei)
|
||||
{
|
||||
patchi = patch(facei_);
|
||||
}
|
||||
|
||||
const polyPatch& patch = mesh_.boundaryMesh()[patchi];
|
||||
|
||||
if (isA<wedgePolyPatch>(patch))
|
||||
{
|
||||
p.hitWedgePatch
|
||||
(
|
||||
static_cast<const wedgePolyPatch&>(patch), td
|
||||
);
|
||||
}
|
||||
else if (isA<symmetryPlanePolyPatch>(patch))
|
||||
{
|
||||
p.hitSymmetryPlanePatch
|
||||
(
|
||||
static_cast<const symmetryPlanePolyPatch&>(patch), td
|
||||
);
|
||||
}
|
||||
else if (isA<symmetryPolyPatch>(patch))
|
||||
{
|
||||
p.hitSymmetryPatch
|
||||
(
|
||||
static_cast<const symmetryPolyPatch&>(patch), td
|
||||
);
|
||||
}
|
||||
else if (isA<cyclicPolyPatch>(patch))
|
||||
{
|
||||
p.hitCyclicPatch
|
||||
(
|
||||
static_cast<const cyclicPolyPatch&>(patch), td
|
||||
);
|
||||
}
|
||||
else if (isA<processorPolyPatch>(patch))
|
||||
{
|
||||
p.hitProcessorPatch
|
||||
(
|
||||
static_cast<const processorPolyPatch&>(patch), td
|
||||
);
|
||||
}
|
||||
else if (isA<wallPolyPatch>(patch))
|
||||
{
|
||||
p.hitWallPatch
|
||||
(
|
||||
static_cast<const wallPolyPatch&>(patch), td, faceHitTetIs
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.hitPatch(patch, td);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
template<class TrackData>
|
||||
Foam::scalar Foam::wallBoundedParticle::trackToEdge
|
||||
(
|
||||
TrackData& td,
|
||||
const vector& endPosition
|
||||
)
|
||||
{
|
||||
// Track particle to a given position and returns 1.0 if the
|
||||
// trajectory is completed without hitting a face otherwise
|
||||
// stops at the face and returns the fraction of the trajectory
|
||||
// completed.
|
||||
// on entry 'stepFraction()' should be set to the fraction of the
|
||||
// time-step at which the tracking starts.
|
||||
|
||||
// Are we on a track face? If not we do a topological walk.
|
||||
|
||||
// Particle:
|
||||
// - cell_ always set
|
||||
// - tetFace_, tetPt_ always set (these identify tet particle is in)
|
||||
// - optionally meshEdgeStart_ or diagEdge_ set (edge particle is on)
|
||||
|
||||
//checkInside();
|
||||
//checkOnTriangle(position());
|
||||
//if (meshEdgeStart_ != -1 || diagEdge_ != -1)
|
||||
//{
|
||||
// checkOnEdge();
|
||||
//}
|
||||
|
||||
scalar trackFraction = 0.0;
|
||||
|
||||
if (!td.isWallPatch_[tetFace()])
|
||||
{
|
||||
// Don't track across face. Just walk in cell. Particle is on
|
||||
// mesh edge (as indicated by meshEdgeStart_).
|
||||
const edge meshEdge(currentEdge());
|
||||
|
||||
// If internal face check whether to go to neighbour cell or just
|
||||
// check to the other internal tet on the edge.
|
||||
if (mesh_.isInternalFace(tetFace()))
|
||||
{
|
||||
label nbrCelli =
|
||||
(
|
||||
celli_ == mesh_.faceOwner()[facei_]
|
||||
? mesh_.faceNeighbour()[facei_]
|
||||
: mesh_.faceOwner()[facei_]
|
||||
);
|
||||
// Check angle to nbrCell tet. Is it in the direction of the
|
||||
// endposition? I.e. since volume of nbr tet is positive the
|
||||
// tracking direction should be into the tet.
|
||||
tetIndices nbrTi(nbrCelli, tetFacei_, tetPti_, mesh_);
|
||||
if ((nbrTi.faceTri(mesh_).normal() & (endPosition-position())) < 0)
|
||||
{
|
||||
// Change into nbrCell. No need to change tetFace, tetPt.
|
||||
//Pout<< " crossed from cell:" << celli_
|
||||
// << " into " << nbrCelli << endl;
|
||||
celli_ = nbrCelli;
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Walk to other face on edge. Changes tetFace, tetPt but not
|
||||
// cell.
|
||||
crossEdgeConnectedFace(meshEdge);
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Walk to other face on edge. This might give loop since
|
||||
// particle should have been removed?
|
||||
crossEdgeConnectedFace(meshEdge);
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're inside a tet on the wall. Check if the current tet is
|
||||
// the one to cross. If not we cross into the neighbouring triangle.
|
||||
|
||||
if (mesh_.isInternalFace(tetFace()))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Can only track on boundary faces."
|
||||
<< " Face:" << tetFace()
|
||||
<< " at:" << mesh_.faceCentres()[tetFace()]
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
point projectedEndPosition = endPosition;
|
||||
// Remove normal component
|
||||
{
|
||||
const triFace tri(currentTetIndices().faceTriIs(mesh_));
|
||||
vector n = tri.normal(mesh_.points());
|
||||
n /= mag(n);
|
||||
const point& basePt = mesh_.points()[tri[0]];
|
||||
projectedEndPosition -= ((projectedEndPosition-basePt)&n)*n;
|
||||
}
|
||||
|
||||
|
||||
bool doTrack = false;
|
||||
if (meshEdgeStart_ == -1 && diagEdge_ == -1)
|
||||
{
|
||||
// We're starting and not yet on an edge.
|
||||
doTrack = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// See if the current triangle has got a point on the
|
||||
// correct side of the edge.
|
||||
doTrack = isTriAlongTrack(projectedEndPosition);
|
||||
}
|
||||
|
||||
|
||||
if (doTrack)
|
||||
{
|
||||
// Track across triangle. Return triangle edge crossed.
|
||||
label triEdgeI = -1;
|
||||
trackFraction = trackFaceTri(projectedEndPosition, triEdgeI);
|
||||
|
||||
if (triEdgeI == -1)
|
||||
{
|
||||
// Reached endpoint
|
||||
//checkInside();
|
||||
diagEdge_ = -1;
|
||||
meshEdgeStart_ = -1;
|
||||
return trackFraction;
|
||||
}
|
||||
|
||||
const tetIndices ti(currentTetIndices());
|
||||
|
||||
// Triangle (faceTriIs) gets constructed from
|
||||
// f[faceBasePtI_],
|
||||
// f[facePtAI_],
|
||||
// f[facePtBI_]
|
||||
//
|
||||
// So edge indices are:
|
||||
// 0 : edge between faceBasePtI_ and facePtAI_
|
||||
// 1 : edge between facePtAI_ and facePtBI_ (is always a real edge)
|
||||
// 2 : edge between facePtBI_ and faceBasePtI_
|
||||
|
||||
const Foam::face& f = mesh_.faces()[ti.face()];
|
||||
const label fp0 = ti.faceBasePt();
|
||||
|
||||
if (triEdgeI == 0)
|
||||
{
|
||||
if (ti.facePtA() == f.fcIndex(fp0))
|
||||
{
|
||||
//Pout<< "Real edge." << endl;
|
||||
diagEdge_ = -1;
|
||||
meshEdgeStart_ = fp0;
|
||||
//checkOnEdge();
|
||||
crossEdgeConnectedFace(currentEdge());
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else if (ti.facePtA() == f.rcIndex(fp0))
|
||||
{
|
||||
//Note: should not happen since boundary face so owner
|
||||
//Pout<< "Real edge." << endl;
|
||||
FatalErrorInFunction
|
||||
<< abort(FatalError);
|
||||
|
||||
diagEdge_ = -1;
|
||||
meshEdgeStart_ = f.rcIndex(fp0);
|
||||
//checkOnEdge();
|
||||
crossEdgeConnectedFace(currentEdge());
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get index of triangle on other side of edge.
|
||||
diagEdge_ = ti.facePtA()-fp0;
|
||||
if (diagEdge_ < 0)
|
||||
{
|
||||
diagEdge_ += f.size();
|
||||
}
|
||||
meshEdgeStart_ = -1;
|
||||
//checkOnEdge();
|
||||
crossDiagonalEdge();
|
||||
}
|
||||
}
|
||||
else if (triEdgeI == 1)
|
||||
{
|
||||
//Pout<< "Real edge." << endl;
|
||||
diagEdge_ = -1;
|
||||
meshEdgeStart_ = ti.facePtA();
|
||||
//checkOnEdge();
|
||||
crossEdgeConnectedFace(currentEdge());
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else // if (triEdgeI == 2)
|
||||
{
|
||||
if (ti.facePtB() == f.rcIndex(fp0))
|
||||
{
|
||||
//Pout<< "Real edge." << endl;
|
||||
diagEdge_ = -1;
|
||||
meshEdgeStart_ = ti.facePtB();
|
||||
//checkOnEdge();
|
||||
crossEdgeConnectedFace(currentEdge());
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else if (ti.facePtB() == f.fcIndex(fp0))
|
||||
{
|
||||
//Note: should not happen since boundary face so owner
|
||||
//Pout<< "Real edge." << endl;
|
||||
FatalErrorInFunction
|
||||
<< abort(FatalError);
|
||||
|
||||
diagEdge_ = -1;
|
||||
meshEdgeStart_ = fp0;
|
||||
//checkOnEdge();
|
||||
crossEdgeConnectedFace(currentEdge());
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Pout<< "Triangle edge." << endl;
|
||||
// Get index of triangle on other side of edge.
|
||||
diagEdge_ = ti.facePtB()-fp0;
|
||||
if (diagEdge_ < 0)
|
||||
{
|
||||
diagEdge_ += f.size();
|
||||
}
|
||||
meshEdgeStart_ = -1;
|
||||
//checkOnEdge();
|
||||
crossDiagonalEdge();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Current tet is not the right one. Check the neighbour tet.
|
||||
|
||||
if (meshEdgeStart_ != -1)
|
||||
{
|
||||
// Particle is on mesh edge so change into other face on cell
|
||||
crossEdgeConnectedFace(currentEdge());
|
||||
//checkOnEdge();
|
||||
patchInteraction(td, trackFraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Particle is on diagonal edge so change into the other
|
||||
// triangle.
|
||||
crossDiagonalEdge();
|
||||
//checkOnEdge();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//checkInside();
|
||||
|
||||
return trackFraction;
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
bool Foam::wallBoundedParticle::hitPatch
|
||||
(
|
||||
const polyPatch&,
|
||||
TrackData& td,
|
||||
const label patchi,
|
||||
const scalar trackFraction,
|
||||
const tetIndices& tetIs
|
||||
)
|
||||
{
|
||||
// Disable generic patch interaction
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitWedgePatch
|
||||
(
|
||||
const wedgePolyPatch& pp,
|
||||
TrackData& td
|
||||
)
|
||||
{
|
||||
// Remove particle
|
||||
td.keepParticle = false;
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitSymmetryPlanePatch
|
||||
(
|
||||
const symmetryPlanePolyPatch& pp,
|
||||
TrackData& td
|
||||
)
|
||||
{
|
||||
// Remove particle
|
||||
td.keepParticle = false;
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitSymmetryPatch
|
||||
(
|
||||
const symmetryPolyPatch& pp,
|
||||
TrackData& td
|
||||
)
|
||||
{
|
||||
// Remove particle
|
||||
td.keepParticle = false;
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitCyclicPatch
|
||||
(
|
||||
const cyclicPolyPatch& pp,
|
||||
TrackData& td
|
||||
)
|
||||
{
|
||||
// Remove particle
|
||||
td.keepParticle = false;
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitProcessorPatch
|
||||
(
|
||||
const processorPolyPatch& pp,
|
||||
TrackData& td
|
||||
)
|
||||
{
|
||||
// Switch particle
|
||||
td.switchProcessor = true;
|
||||
|
||||
// Adapt edgeStart_ for other side.
|
||||
// E.g. if edgeStart_ is 1 then the edge is between vertex 1 and 2 so
|
||||
// on the other side between 2 and 3 so edgeStart_ should be
|
||||
// f.size()-edgeStart_-1.
|
||||
|
||||
const Foam::face& f = mesh_.faces()[face()];
|
||||
|
||||
if (meshEdgeStart_ != -1)
|
||||
{
|
||||
meshEdgeStart_ = f.size()-meshEdgeStart_-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// diagEdge_ is relative to faceBasePt
|
||||
diagEdge_ = f.size()-diagEdge_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitWallPatch
|
||||
(
|
||||
const wallPolyPatch& wpp,
|
||||
TrackData& td,
|
||||
const tetIndices&
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
template<class TrackData>
|
||||
void Foam::wallBoundedParticle::hitPatch
|
||||
(
|
||||
const polyPatch& wpp,
|
||||
TrackData& td
|
||||
)
|
||||
{
|
||||
// Remove particle
|
||||
td.keepParticle = false;
|
||||
}
|
||||
|
||||
|
||||
template<class CloudType>
|
||||
void Foam::wallBoundedParticle::readFields(CloudType& c)
|
||||
{
|
||||
if (!c.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
particle::readFields(c);
|
||||
|
||||
IOField<label> meshEdgeStart
|
||||
(
|
||||
c.fieldIOobject("meshEdgeStart", IOobject::MUST_READ)
|
||||
);
|
||||
|
||||
IOField<label> diagEdge
|
||||
(
|
||||
c.fieldIOobject("diagEdge_", IOobject::MUST_READ)
|
||||
);
|
||||
c.checkFieldIOobject(c, diagEdge);
|
||||
|
||||
label i = 0;
|
||||
forAllIter(typename CloudType, c, iter)
|
||||
{
|
||||
iter().meshEdgeStart_ = meshEdgeStart[i];
|
||||
iter().diagEdge_ = diagEdge[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class CloudType>
|
||||
void Foam::wallBoundedParticle::writeFields(const CloudType& c)
|
||||
{
|
||||
particle::writeFields(c);
|
||||
|
||||
label np = c.size();
|
||||
|
||||
IOField<label> meshEdgeStart
|
||||
(
|
||||
c.fieldIOobject("meshEdgeStart", IOobject::NO_READ),
|
||||
np
|
||||
);
|
||||
IOField<label> diagEdge
|
||||
(
|
||||
c.fieldIOobject("diagEdge", IOobject::NO_READ),
|
||||
np
|
||||
);
|
||||
|
||||
label i = 0;
|
||||
forAllConstIter(typename CloudType, c, iter)
|
||||
{
|
||||
meshEdgeStart[i] = iter().meshEdgeStart_;
|
||||
diagEdge[i] = iter().diagEdge_;
|
||||
i++;
|
||||
}
|
||||
|
||||
meshEdgeStart.write();
|
||||
diagEdge.write();
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,328 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation | Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "wallBoundedStreamLine.H"
|
||||
#include "wallBoundedStreamLineParticleCloud.H"
|
||||
#include "sampledSet.H"
|
||||
#include "faceSet.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
namespace functionObjects
|
||||
{
|
||||
defineTypeNameAndDebug(wallBoundedStreamLine, 0);
|
||||
|
||||
addToRunTimeSelectionTable
|
||||
(
|
||||
functionObject,
|
||||
wallBoundedStreamLine,
|
||||
dictionary
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet
|
||||
(
|
||||
const PackedBoolList& isWallPatch,
|
||||
const point& seedPt,
|
||||
const label celli
|
||||
) const
|
||||
{
|
||||
const cell& cFaces = mesh_.cells()[celli];
|
||||
|
||||
label minFacei = -1;
|
||||
label minTetPtI = -1;
|
||||
scalar minDistSqr = sqr(GREAT);
|
||||
|
||||
forAll(cFaces, cFacei)
|
||||
{
|
||||
label facei = cFaces[cFacei];
|
||||
|
||||
if (isWallPatch[facei])
|
||||
{
|
||||
const face& f = mesh_.faces()[facei];
|
||||
const label fp0 = mesh_.tetBasePtIs()[facei];
|
||||
const point& basePoint = mesh_.points()[f[fp0]];
|
||||
|
||||
label fp = f.fcIndex(fp0);
|
||||
for (label i = 2; i < f.size(); i++)
|
||||
{
|
||||
const point& thisPoint = mesh_.points()[f[fp]];
|
||||
label nextFp = f.fcIndex(fp);
|
||||
const point& nextPoint = mesh_.points()[f[nextFp]];
|
||||
|
||||
const triPointRef tri(basePoint, thisPoint, nextPoint);
|
||||
|
||||
scalar d2 = magSqr(tri.centre() - seedPt);
|
||||
if (d2 < minDistSqr)
|
||||
{
|
||||
minDistSqr = d2;
|
||||
minFacei = facei;
|
||||
minTetPtI = i-1;
|
||||
}
|
||||
fp = nextFp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put particle in tet
|
||||
return tetIndices
|
||||
(
|
||||
celli,
|
||||
minFacei,
|
||||
minTetPtI,
|
||||
mesh_
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void Foam::functionObjects::wallBoundedStreamLine::track()
|
||||
{
|
||||
// Determine the 'wall' patches
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// These are the faces that need to be followed
|
||||
|
||||
autoPtr<indirectPrimitivePatch> boundaryPatch(wallPatch());
|
||||
PackedBoolList isWallPatch(mesh_.nFaces());
|
||||
forAll(boundaryPatch().addressing(), i)
|
||||
{
|
||||
isWallPatch[boundaryPatch().addressing()[i]] = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Find nearest wall particle for the seedPoints
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
IDLList<wallBoundedStreamLineParticle> initialParticles;
|
||||
wallBoundedStreamLineParticleCloud particles
|
||||
(
|
||||
mesh_,
|
||||
cloudName_,
|
||||
initialParticles
|
||||
);
|
||||
|
||||
{
|
||||
// Get the seed points
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
const sampledSet& seedPoints = sampledSetPtr_();
|
||||
|
||||
|
||||
forAll(seedPoints, i)
|
||||
{
|
||||
const point& seedPt = seedPoints[i];
|
||||
label celli = seedPoints.cells()[i];
|
||||
|
||||
tetIndices ids(findNearestTet(isWallPatch, seedPt, celli));
|
||||
|
||||
if (ids.face() != -1 && isWallPatch[ids.face()])
|
||||
{
|
||||
//Pout<< "Seeding particle :" << nl
|
||||
// << " seedPt:" << seedPt << nl
|
||||
// << " face :" << ids.face() << nl
|
||||
// << " at :" << mesh_.faceCentres()[ids.face()] << nl
|
||||
// << " cell :" << mesh_.cellCentres()[ids.cell()] << nl
|
||||
// << endl;
|
||||
|
||||
particles.addParticle
|
||||
(
|
||||
new wallBoundedStreamLineParticle
|
||||
(
|
||||
mesh_,
|
||||
ids.faceTri(mesh_).centre(),
|
||||
ids.cell(),
|
||||
ids.face(), // tetFace
|
||||
ids.tetPt(),
|
||||
-1, // not on a mesh edge
|
||||
-1, // not on a diagonal edge
|
||||
lifeTime_ // lifetime
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pout<< type() << " : ignoring seed " << seedPt
|
||||
<< " since not in wall cell." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label nSeeds = returnReduce(particles.size(), sumOp<label>());
|
||||
|
||||
Log << type() << " : seeded " << nSeeds << " particles." << endl;
|
||||
|
||||
|
||||
|
||||
// Read or lookup fields
|
||||
PtrList<volScalarField> vsFlds;
|
||||
PtrList<interpolation<scalar>> vsInterp;
|
||||
PtrList<volVectorField> vvFlds;
|
||||
PtrList<interpolation<vector>> vvInterp;
|
||||
|
||||
label UIndex = -1;
|
||||
|
||||
initInterpolations
|
||||
(
|
||||
nSeeds,
|
||||
UIndex,
|
||||
vsFlds,
|
||||
vsInterp,
|
||||
vvFlds,
|
||||
vvInterp
|
||||
);
|
||||
|
||||
// Additional particle info
|
||||
wallBoundedStreamLineParticle::trackingData td
|
||||
(
|
||||
particles,
|
||||
vsInterp,
|
||||
vvInterp,
|
||||
UIndex, // index of U in vvInterp
|
||||
trackForward_, // track in +u direction?
|
||||
trackLength_, // fixed track length
|
||||
isWallPatch, // which faces are to follow
|
||||
|
||||
allTracks_,
|
||||
allScalars_,
|
||||
allVectors_
|
||||
);
|
||||
|
||||
|
||||
// Set very large dt. Note: cannot use GREAT since 1/GREAT is SMALL
|
||||
// which is a trigger value for the tracking...
|
||||
const scalar trackTime = Foam::sqrt(GREAT);
|
||||
|
||||
// Track
|
||||
particles.move(td, trackTime);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::functionObjects::wallBoundedStreamLine::wallBoundedStreamLine
|
||||
(
|
||||
const word& name,
|
||||
const Time& runTime,
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
streamLineBase(name, runTime, dict)
|
||||
{
|
||||
read(dict_);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::functionObjects::wallBoundedStreamLine::~wallBoundedStreamLine()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::functionObjects::wallBoundedStreamLine::read(const dictionary& dict)
|
||||
{
|
||||
if (streamLineBase::read(dict))
|
||||
{
|
||||
Info<< type() << " " << name() << ":" << nl;
|
||||
|
||||
|
||||
// Make sure that the mesh is trackable
|
||||
if (debug)
|
||||
{
|
||||
// 1. Positive volume decomposition tets
|
||||
faceSet faces(mesh_, "lowQualityTetFaces", mesh_.nFaces()/100+1);
|
||||
if
|
||||
(
|
||||
polyMeshTetDecomposition::checkFaceTets
|
||||
(
|
||||
mesh_,
|
||||
polyMeshTetDecomposition::minTetQuality,
|
||||
true,
|
||||
&faces
|
||||
)
|
||||
)
|
||||
{
|
||||
label nFaces = returnReduce(faces.size(), sumOp<label>());
|
||||
|
||||
WarningInFunction
|
||||
<< "Found " << nFaces
|
||||
<<" faces with low quality or negative volume "
|
||||
<< "decomposition tets. Writing to faceSet " << faces.name()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// 2. All edges on a cell having two faces
|
||||
EdgeMap<label> numFacesPerEdge;
|
||||
forAll(mesh_.cells(), celli)
|
||||
{
|
||||
const cell& cFaces = mesh_.cells()[celli];
|
||||
|
||||
numFacesPerEdge.clear();
|
||||
|
||||
forAll(cFaces, cFacei)
|
||||
{
|
||||
label facei = cFaces[cFacei];
|
||||
const face& f = mesh_.faces()[facei];
|
||||
forAll(f, fp)
|
||||
{
|
||||
const edge e(f[fp], f.nextLabel(fp));
|
||||
EdgeMap<label>::iterator eFnd =
|
||||
numFacesPerEdge.find(e);
|
||||
if (eFnd != numFacesPerEdge.end())
|
||||
{
|
||||
eFnd()++;
|
||||
}
|
||||
else
|
||||
{
|
||||
numFacesPerEdge.insert(e, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forAllConstIter(EdgeMap<label>, numFacesPerEdge, iter)
|
||||
{
|
||||
if (iter() != 2)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "problem cell:" << celli
|
||||
<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,183 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation | Copyright (C) 2015-2016 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::functionObjects::wallBoundedStreamLine
|
||||
|
||||
Group
|
||||
grpFieldFunctionObjects
|
||||
|
||||
Description
|
||||
Generates streamline data by sampling a set of user-specified fields along a
|
||||
particle track, transported by a user-specified velocity field, constrained
|
||||
to a patch.
|
||||
|
||||
Example of function object specification:
|
||||
\verbatim
|
||||
wallBoundedStreamLine1
|
||||
{
|
||||
type wallBoundedStreamLine;
|
||||
libs ("libfieldFunctionObjects.so");
|
||||
|
||||
writeControl writeTime;
|
||||
|
||||
setFormat vtk;
|
||||
U UNear;
|
||||
trackForward yes;
|
||||
|
||||
fields
|
||||
(
|
||||
UNear
|
||||
p
|
||||
);
|
||||
|
||||
lifeTime 10000;
|
||||
trackLength 1e-3;
|
||||
bounds (0.2 -10 -10)(0.22 10 10);
|
||||
cloudName particleTracks;
|
||||
|
||||
seedSampleSet patchSeed;
|
||||
patchSeedCoeffs
|
||||
{
|
||||
type patchSeed;
|
||||
patches (wall);
|
||||
axis x;
|
||||
maxPoints 20000;
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Usage
|
||||
\table
|
||||
Property | Description | Required | Default value
|
||||
type | Type name: wallBoundedStreamLine| yes |
|
||||
setFormat | Output data type | yes |
|
||||
U | Tracking velocity field name | yes |
|
||||
fields | Fields to sample | yes |
|
||||
lifetime | Maximum number of particle tracking steps | yes |
|
||||
trackLength | Tracking segment length | no |
|
||||
nSubCycle | Number of tracking steps per cell | no|
|
||||
cloudName | Cloud name to use | yes |
|
||||
bounds | Bounding box to trim tracks | no | greatBox
|
||||
seedSampleSet| Seeding method (see below)| yes |
|
||||
\endtable
|
||||
|
||||
Where \c seedSampleSet is typically one of
|
||||
\plaintable
|
||||
uniform | uniform particle seeding
|
||||
cloud | cloud of points
|
||||
patchSeed | seeding via patch faces
|
||||
triSurfaceMeshPointSet | points according to a tri-surface mesh
|
||||
\endplaintable
|
||||
|
||||
Note
|
||||
When specifying the track resolution, the \c trackLength OR \c nSubCycle
|
||||
option should be used
|
||||
|
||||
See also
|
||||
Foam::functionObjects::streamLineBase
|
||||
|
||||
SourceFiles
|
||||
wallBoundedStreamLine.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef functionObjects_wallBoundedStreamLine_H
|
||||
#define functionObjects_wallBoundedStreamLine_H
|
||||
|
||||
#include "streamLineBase.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
namespace functionObjects
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class wallBoundedStreamLine Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class wallBoundedStreamLine
|
||||
:
|
||||
public streamLineBase
|
||||
{
|
||||
// Private Member Functions
|
||||
|
||||
//- Find wall tet on cell
|
||||
tetIndices findNearestTet
|
||||
(
|
||||
const PackedBoolList& isWallPatch,
|
||||
const point& seedPt,
|
||||
const label celli
|
||||
) const;
|
||||
|
||||
//- Disallow default bitwise copy construct
|
||||
wallBoundedStreamLine(const wallBoundedStreamLine&) = delete;
|
||||
|
||||
//- Disallow default bitwise assignment
|
||||
void operator=(const wallBoundedStreamLine&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("wallBoundedStreamLine");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from Time and dictionary
|
||||
wallBoundedStreamLine
|
||||
(
|
||||
const word& name,
|
||||
const Time& runTime,
|
||||
const dictionary& dict
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~wallBoundedStreamLine();
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Read settings
|
||||
virtual bool read(const dictionary&);
|
||||
|
||||
//- Do the actual tracking to fill the track data
|
||||
virtual void track();
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace functionObjects
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,435 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "wallBoundedStreamLineParticle.H"
|
||||
#include "vectorFieldIOField.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::vector Foam::wallBoundedStreamLineParticle::interpolateFields
|
||||
(
|
||||
const trackingData& td,
|
||||
const point& position,
|
||||
const label celli,
|
||||
const label facei
|
||||
)
|
||||
{
|
||||
if (celli == -1)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Cell:" << celli << abort(FatalError);
|
||||
}
|
||||
|
||||
const tetIndices ti = currentTetIndices();
|
||||
|
||||
const vector U = td.vvInterp_[td.UIndex_].interpolate
|
||||
(
|
||||
position,
|
||||
ti, //celli,
|
||||
facei
|
||||
);
|
||||
|
||||
// Check if at different position
|
||||
if
|
||||
(
|
||||
!sampledPositions_.size()
|
||||
|| magSqr(sampledPositions_.last()-position) > Foam::sqr(SMALL)
|
||||
)
|
||||
{
|
||||
// Store the location
|
||||
sampledPositions_.append(position);
|
||||
|
||||
// Store the scalar fields
|
||||
sampledScalars_.setSize(td.vsInterp_.size());
|
||||
forAll(td.vsInterp_, scalarI)
|
||||
{
|
||||
sampledScalars_[scalarI].append
|
||||
(
|
||||
td.vsInterp_[scalarI].interpolate
|
||||
(
|
||||
position,
|
||||
ti, //celli,
|
||||
facei
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Store the vector fields
|
||||
sampledVectors_.setSize(td.vvInterp_.size());
|
||||
forAll(td.vvInterp_, vectorI)
|
||||
{
|
||||
vector positionU;
|
||||
if (vectorI == td.UIndex_)
|
||||
{
|
||||
positionU = U;
|
||||
}
|
||||
else
|
||||
{
|
||||
positionU = td.vvInterp_[vectorI].interpolate
|
||||
(
|
||||
position,
|
||||
ti, //celli,
|
||||
facei
|
||||
);
|
||||
}
|
||||
sampledVectors_[vectorI].append(positionU);
|
||||
}
|
||||
}
|
||||
|
||||
return U;
|
||||
}
|
||||
|
||||
|
||||
Foam::vector Foam::wallBoundedStreamLineParticle::sample
|
||||
(
|
||||
trackingData& td
|
||||
)
|
||||
{
|
||||
vector U = interpolateFields(td, position(), cell(), tetFace());
|
||||
|
||||
if (!td.trackForward_)
|
||||
{
|
||||
U = -U;
|
||||
}
|
||||
|
||||
scalar magU = mag(U);
|
||||
|
||||
if (magU < SMALL)
|
||||
{
|
||||
// Stagnant particle. Might as well stop
|
||||
lifeTime_ = 0;
|
||||
}
|
||||
|
||||
U /= magU;
|
||||
|
||||
return U;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const vector& position,
|
||||
const label celli,
|
||||
const label tetFacei,
|
||||
const label tetPtI,
|
||||
const label meshEdgeStart,
|
||||
const label diagEdge,
|
||||
const label lifeTime
|
||||
)
|
||||
:
|
||||
wallBoundedParticle
|
||||
(
|
||||
mesh,
|
||||
position,
|
||||
celli,
|
||||
tetFacei,
|
||||
tetPtI,
|
||||
meshEdgeStart,
|
||||
diagEdge
|
||||
),
|
||||
lifeTime_(lifeTime)
|
||||
{}
|
||||
|
||||
|
||||
Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
Istream& is,
|
||||
bool readFields
|
||||
)
|
||||
:
|
||||
wallBoundedParticle(mesh, is, readFields)
|
||||
{
|
||||
if (readFields)
|
||||
{
|
||||
List<scalarList> sampledScalars;
|
||||
List<vectorList> sampledVectors;
|
||||
|
||||
is >> lifeTime_
|
||||
>> sampledPositions_ >> sampledScalars >> sampledVectors;
|
||||
|
||||
sampledScalars_.setSize(sampledScalars.size());
|
||||
forAll(sampledScalars, i)
|
||||
{
|
||||
sampledScalars_[i].transfer(sampledScalars[i]);
|
||||
}
|
||||
sampledVectors_.setSize(sampledVectors.size());
|
||||
forAll(sampledVectors, i)
|
||||
{
|
||||
sampledVectors_[i].transfer(sampledVectors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check state of Istream
|
||||
is.check
|
||||
(
|
||||
"wallBoundedStreamLineParticle::wallBoundedStreamLineParticle"
|
||||
"(const Cloud<wallBoundedStreamLineParticle>&, Istream&, bool)"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
|
||||
(
|
||||
const wallBoundedStreamLineParticle& p
|
||||
)
|
||||
:
|
||||
wallBoundedParticle(p),
|
||||
lifeTime_(p.lifeTime_),
|
||||
sampledPositions_(p.sampledPositions_),
|
||||
sampledScalars_(p.sampledScalars_),
|
||||
sampledVectors_(p.sampledVectors_)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::wallBoundedStreamLineParticle::move
|
||||
(
|
||||
trackingData& td,
|
||||
const scalar trackTime
|
||||
)
|
||||
{
|
||||
wallBoundedStreamLineParticle& p = static_cast
|
||||
<
|
||||
wallBoundedStreamLineParticle&
|
||||
>(*this);
|
||||
|
||||
|
||||
// Check position is inside tet
|
||||
//checkInside();
|
||||
|
||||
td.switchProcessor = false;
|
||||
td.keepParticle = true;
|
||||
|
||||
scalar tEnd = (1.0 - stepFraction())*trackTime;
|
||||
scalar maxDt = mesh_.bounds().mag();
|
||||
|
||||
while
|
||||
(
|
||||
td.keepParticle
|
||||
&& !td.switchProcessor
|
||||
&& lifeTime_ > 0
|
||||
)
|
||||
{
|
||||
// set the lagrangian time-step
|
||||
scalar dt = maxDt;
|
||||
|
||||
--lifeTime_;
|
||||
|
||||
// Get sampled velocity and fields. Store if position changed.
|
||||
vector U = sample(td);
|
||||
|
||||
// !user parameter!
|
||||
if (dt < SMALL)
|
||||
{
|
||||
// Force removal
|
||||
lifeTime_ = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (td.trackLength_ < GREAT)
|
||||
{
|
||||
dt = td.trackLength_;
|
||||
}
|
||||
|
||||
|
||||
scalar fraction = trackToEdge(td, position() + dt*U);
|
||||
dt *= fraction;
|
||||
|
||||
tEnd -= dt;
|
||||
stepFraction() = 1.0 - tEnd/trackTime;
|
||||
|
||||
|
||||
if (tEnd <= ROOTVSMALL)
|
||||
{
|
||||
// Force removal
|
||||
lifeTime_ = 0;
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
!td.keepParticle
|
||||
|| td.switchProcessor
|
||||
|| lifeTime_ == 0
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!td.keepParticle || lifeTime_ == 0)
|
||||
{
|
||||
if (lifeTime_ == 0)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "wallBoundedStreamLineParticle :"
|
||||
<< " Removing stagnant particle:"
|
||||
<< p.position()
|
||||
<< " sampled positions:" << sampledPositions_.size()
|
||||
<< endl;
|
||||
}
|
||||
td.keepParticle = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal exit. Store last position and fields
|
||||
sample(td);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "wallBoundedStreamLineParticle : Removing particle:"
|
||||
<< p.position()
|
||||
<< " sampled positions:" << sampledPositions_.size()
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer particle data into trackingData.
|
||||
{
|
||||
//td.allPositions_.append(sampledPositions_);
|
||||
td.allPositions_.append(vectorList());
|
||||
vectorList& top = td.allPositions_.last();
|
||||
top.transfer(sampledPositions_);
|
||||
}
|
||||
|
||||
forAll(sampledScalars_, i)
|
||||
{
|
||||
//td.allScalars_[i].append(sampledScalars_[i]);
|
||||
td.allScalars_[i].append(scalarList());
|
||||
scalarList& top = td.allScalars_[i].last();
|
||||
top.transfer(sampledScalars_[i]);
|
||||
}
|
||||
forAll(sampledVectors_, i)
|
||||
{
|
||||
//td.allVectors_[i].append(sampledVectors_[i]);
|
||||
td.allVectors_[i].append(vectorList());
|
||||
vectorList& top = td.allVectors_[i].last();
|
||||
top.transfer(sampledVectors_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return td.keepParticle;
|
||||
}
|
||||
|
||||
|
||||
void Foam::wallBoundedStreamLineParticle::readFields
|
||||
(
|
||||
Cloud<wallBoundedStreamLineParticle>& c
|
||||
)
|
||||
{
|
||||
if (!c.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wallBoundedParticle::readFields(c);
|
||||
|
||||
IOField<label> lifeTime
|
||||
(
|
||||
c.fieldIOobject("lifeTime", IOobject::MUST_READ)
|
||||
);
|
||||
c.checkFieldIOobject(c, lifeTime);
|
||||
|
||||
vectorFieldIOField sampledPositions
|
||||
(
|
||||
c.fieldIOobject("sampledPositions", IOobject::MUST_READ)
|
||||
);
|
||||
c.checkFieldIOobject(c, sampledPositions);
|
||||
|
||||
label i = 0;
|
||||
forAllIter(Cloud<wallBoundedStreamLineParticle>, c, iter)
|
||||
{
|
||||
iter().lifeTime_ = lifeTime[i];
|
||||
iter().sampledPositions_.transfer(sampledPositions[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::wallBoundedStreamLineParticle::writeFields
|
||||
(
|
||||
const Cloud<wallBoundedStreamLineParticle>& c
|
||||
)
|
||||
{
|
||||
wallBoundedParticle::writeFields(c);
|
||||
|
||||
label np = c.size();
|
||||
|
||||
IOField<label> lifeTime
|
||||
(
|
||||
c.fieldIOobject("lifeTime", IOobject::NO_READ),
|
||||
np
|
||||
);
|
||||
vectorFieldIOField sampledPositions
|
||||
(
|
||||
c.fieldIOobject("sampledPositions", IOobject::NO_READ),
|
||||
np
|
||||
);
|
||||
|
||||
label i = 0;
|
||||
forAllConstIter(Cloud<wallBoundedStreamLineParticle>, c, iter)
|
||||
{
|
||||
lifeTime[i] = iter().lifeTime_;
|
||||
sampledPositions[i] = iter().sampledPositions_;
|
||||
i++;
|
||||
}
|
||||
|
||||
lifeTime.write();
|
||||
sampledPositions.write();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
|
||||
|
||||
Foam::Ostream& Foam::operator<<
|
||||
(
|
||||
Ostream& os,
|
||||
const wallBoundedStreamLineParticle& p
|
||||
)
|
||||
{
|
||||
os << static_cast<const wallBoundedParticle&>(p)
|
||||
<< token::SPACE << p.lifeTime_
|
||||
<< token::SPACE << p.sampledPositions_
|
||||
<< token::SPACE << p.sampledScalars_
|
||||
<< token::SPACE << p.sampledVectors_;
|
||||
|
||||
// Check state of Ostream
|
||||
os.check
|
||||
(
|
||||
"Ostream& operator<<(Ostream&, const wallBoundedStreamLineParticle&)"
|
||||
);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,260 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::wallBoundedStreamLineParticle
|
||||
|
||||
Description
|
||||
Particle class that samples fields as it passes through. Used in streamline
|
||||
calculation.
|
||||
|
||||
SourceFiles
|
||||
wallBoundedStreamLineParticle.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef wallBoundedStreamLineParticle_H
|
||||
#define wallBoundedStreamLineParticle_H
|
||||
|
||||
#include "wallBoundedParticle.H"
|
||||
#include "autoPtr.H"
|
||||
#include "interpolation.H"
|
||||
#include "vectorList.H"
|
||||
#include "InfoProxy.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
class wallBoundedStreamLineParticleCloud;
|
||||
|
||||
|
||||
// Forward declaration of friend functions and operators
|
||||
|
||||
class wallBoundedStreamLineParticle;
|
||||
|
||||
Ostream& operator<<(Ostream&, const wallBoundedStreamLineParticle&);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class wallBoundedStreamLineParticle Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class wallBoundedStreamLineParticle
|
||||
:
|
||||
public wallBoundedParticle
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//- Class used to pass tracking data to the trackToEdge function
|
||||
class trackingData
|
||||
:
|
||||
public wallBoundedParticle::TrackingData
|
||||
<
|
||||
Cloud<wallBoundedStreamLineParticle>
|
||||
>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
|
||||
const PtrList<interpolation<scalar>>& vsInterp_;
|
||||
const PtrList<interpolation<vector>>& vvInterp_;
|
||||
const label UIndex_;
|
||||
const bool trackForward_;
|
||||
const scalar trackLength_;
|
||||
|
||||
DynamicList<vectorList>& allPositions_;
|
||||
List<DynamicList<scalarList>>& allScalars_;
|
||||
List<DynamicList<vectorList>>& allVectors_;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
trackingData
|
||||
(
|
||||
Cloud<wallBoundedStreamLineParticle>& cloud,
|
||||
const PtrList<interpolation<scalar>>& vsInterp,
|
||||
const PtrList<interpolation<vector>>& vvInterp,
|
||||
const label UIndex,
|
||||
const bool trackForward,
|
||||
const scalar trackLength,
|
||||
const PackedBoolList& isWallPatch,
|
||||
|
||||
DynamicList<List<point>>& allPositions,
|
||||
List<DynamicList<scalarList>>& allScalars,
|
||||
List<DynamicList<vectorList>>& allVectors
|
||||
)
|
||||
:
|
||||
wallBoundedParticle::TrackingData
|
||||
<
|
||||
Cloud<wallBoundedStreamLineParticle>
|
||||
>
|
||||
(
|
||||
cloud,
|
||||
isWallPatch
|
||||
),
|
||||
vsInterp_(vsInterp),
|
||||
vvInterp_(vvInterp),
|
||||
UIndex_(UIndex),
|
||||
trackForward_(trackForward),
|
||||
trackLength_(trackLength),
|
||||
|
||||
allPositions_(allPositions),
|
||||
allScalars_(allScalars),
|
||||
allVectors_(allVectors)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Private data
|
||||
|
||||
//- Lifetime of particle. Particle dies when reaches 0.
|
||||
label lifeTime_;
|
||||
|
||||
//- Sampled positions
|
||||
DynamicList<point> sampledPositions_;
|
||||
|
||||
//- Sampled scalars
|
||||
List<DynamicList<scalar>> sampledScalars_;
|
||||
|
||||
//- Sampled vectors
|
||||
List<DynamicList<vector>> sampledVectors_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
vector interpolateFields
|
||||
(
|
||||
const trackingData& td,
|
||||
const point& position,
|
||||
const label celli,
|
||||
const label facei
|
||||
);
|
||||
|
||||
vector sample(trackingData& td);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from components
|
||||
wallBoundedStreamLineParticle
|
||||
(
|
||||
const polyMesh& c,
|
||||
const vector& position,
|
||||
const label celli,
|
||||
const label tetFacei,
|
||||
const label tetPtI,
|
||||
const label meshEdgeStart,
|
||||
const label diagEdge,
|
||||
const label lifeTime
|
||||
);
|
||||
|
||||
//- Construct from Istream
|
||||
wallBoundedStreamLineParticle
|
||||
(
|
||||
const polyMesh& c,
|
||||
Istream& is,
|
||||
bool readFields = true
|
||||
);
|
||||
|
||||
//- Construct copy
|
||||
wallBoundedStreamLineParticle(const wallBoundedStreamLineParticle& p);
|
||||
|
||||
//- Construct and return a clone
|
||||
autoPtr<particle> clone() const
|
||||
{
|
||||
return autoPtr<particle>(new wallBoundedStreamLineParticle(*this));
|
||||
}
|
||||
|
||||
//- Factory class to read-construct particles used for
|
||||
// parallel transfer
|
||||
class iNew
|
||||
{
|
||||
const polyMesh& mesh_;
|
||||
|
||||
public:
|
||||
|
||||
iNew(const polyMesh& mesh)
|
||||
:
|
||||
mesh_(mesh)
|
||||
{}
|
||||
|
||||
autoPtr<wallBoundedStreamLineParticle> operator()
|
||||
(
|
||||
Istream& is
|
||||
) const
|
||||
{
|
||||
return autoPtr<wallBoundedStreamLineParticle>
|
||||
(
|
||||
new wallBoundedStreamLineParticle(mesh_, is, true)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// Tracking
|
||||
|
||||
//- Track all particles to their end point
|
||||
bool move(trackingData&, const scalar trackTime);
|
||||
|
||||
|
||||
// I-O
|
||||
|
||||
//- Read
|
||||
static void readFields(Cloud<wallBoundedStreamLineParticle>&);
|
||||
|
||||
//- Write
|
||||
static void writeFields
|
||||
(
|
||||
const Cloud<wallBoundedStreamLineParticle>&
|
||||
);
|
||||
|
||||
|
||||
// Ostream Operator
|
||||
|
||||
friend Ostream& operator<<
|
||||
(
|
||||
Ostream&,
|
||||
const wallBoundedStreamLineParticle&
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "wallBoundedStreamLineParticleCloud.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTemplateTypeNameAndDebug(Cloud<wallBoundedStreamLineParticle>, 0);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::wallBoundedStreamLineParticleCloud::wallBoundedStreamLineParticleCloud
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const word& cloudName,
|
||||
bool readFields
|
||||
)
|
||||
:
|
||||
Cloud<wallBoundedStreamLineParticle>(mesh, cloudName, false)
|
||||
{
|
||||
if (readFields)
|
||||
{
|
||||
wallBoundedStreamLineParticle::readFields(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::wallBoundedStreamLineParticleCloud::wallBoundedStreamLineParticleCloud
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const word& cloudName,
|
||||
const IDLList<wallBoundedStreamLineParticle>& particles
|
||||
)
|
||||
:
|
||||
Cloud<wallBoundedStreamLineParticle>(mesh, cloudName, particles)
|
||||
{}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,99 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::wallBoundedStreamLineParticleCloud
|
||||
|
||||
Description
|
||||
A Cloud of streamLine particles
|
||||
|
||||
SourceFiles
|
||||
streamLineCloud.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef streamLineCloud_H
|
||||
#define streamLineCloud_H
|
||||
|
||||
#include "Cloud.H"
|
||||
#include "wallBoundedStreamLineParticle.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class streamLineCloud Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class wallBoundedStreamLineParticleCloud
|
||||
:
|
||||
public Cloud<wallBoundedStreamLineParticle>
|
||||
{
|
||||
// Private Member Functions
|
||||
|
||||
//- Disallow default bitwise copy construct
|
||||
wallBoundedStreamLineParticleCloud
|
||||
(
|
||||
const wallBoundedStreamLineParticleCloud&
|
||||
);
|
||||
|
||||
//- Disallow default bitwise assignment
|
||||
void operator=(const wallBoundedStreamLineParticleCloud&);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Type of parcel the cloud was instantiated for
|
||||
typedef wallBoundedStreamLineParticle parcelType;
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct given mesh
|
||||
wallBoundedStreamLineParticleCloud
|
||||
(
|
||||
const polyMesh&,
|
||||
const word& cloudName = "defaultCloud",
|
||||
bool readFields = true
|
||||
);
|
||||
|
||||
//- Construct from mesh, cloud name, and a list of particles
|
||||
wallBoundedStreamLineParticleCloud
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const word& cloudName,
|
||||
const IDLList<wallBoundedStreamLineParticle>& particles
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user