GIT: Initial state after latest Foundation merge

This commit is contained in:
Andrew Heather
2016-09-20 14:49:08 +01:00
4571 changed files with 115696 additions and 74609 deletions

View File

@ -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;
}
// ************************************************************************* //

View File

@ -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
// ************************************************************************* //

View File

@ -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();
}
// ************************************************************************* //

View File

@ -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;
}
// ************************************************************************* //

View File

@ -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
// ************************************************************************* //

View File

@ -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;
}
// ************************************************************************* //

View File

@ -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
// ************************************************************************* //

View File

@ -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)
{}
// ************************************************************************* //

View File

@ -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
// ************************************************************************* //