Lagrangian: Enabled tracking through ACMI patches and minor code improvements

Particle collisions with ACMI patches are now handled. The hit detects
whether the location is within the overlap or the coupled region and
recurses, calling the hit routine appropriate for the region.

The low level tracking methods are now more consistently named. There is
now a distinction between tracking to a face and hitting it. Function
object side effects have been moved out of the base layer and into the
parcels on which they are meaningful.
This commit is contained in:
Will Bainbridge
2017-08-09 15:52:33 +01:00
parent a8b2e2a58e
commit adffa0f33d
12 changed files with 137 additions and 77 deletions

View File

@ -110,7 +110,7 @@ bool Foam::findCellParticle::move
while (td.keepParticle && !td.switchProcessor && stepFraction() < 1)
{
const scalar f = 1 - stepFraction();
trackToFace(f*(end_ - start_), f, td);
trackToAndHitFace(f*(end_ - start_), f, td);
}
if (stepFraction() == 1 || !td.keepParticle)

View File

@ -203,7 +203,7 @@ bool Foam::streamLineParticle::move
dt = maxDt;
}
trackToFace(dt*U, 0, td);
trackToAndHitFace(dt*U, 0, td);
if
(

View File

@ -59,7 +59,7 @@ bool Foam::DSMCParcel<ParcelType>::move(TrackData& td, const scalar trackTime)
meshTools::constrainDirection(mesh, mesh.solutionD(), Utracking);
const scalar f = 1 - p.stepFraction();
p.trackToFace(f*trackTime*Utracking, f, td);
p.trackToAndHitFace(f*trackTime*Utracking, f, td);
if (p.onBoundaryFace() && td.keepParticle)
{

View File

@ -344,6 +344,7 @@ void Foam::particle::changeFace(const label tetTriI)
{
const label newFaceI = mesh_.cells()[celli_][cellFaceI];
const class face& newFace = mesh_.faces()[newFaceI];
const label newOwner = mesh_.faceOwner()[newFaceI];
// Exclude the current face
if (tetFacei_ == newFaceI)
@ -351,21 +352,21 @@ void Foam::particle::changeFace(const label tetTriI)
continue;
}
// Loop over the edges, looking for the shared one
label edgeComp = 0;
// Loop over the edges, looking for the shared one. Note that we have to
// match the direction of the edge as well as the end points in order to
// avoid false positives when dealing with coincident ACMI faces.
const label edgeComp = newOwner == celli_ ? -1 : +1;
label edgeI = 0;
for (; edgeI < newFace.size(); ++ edgeI)
{
edgeComp = edge::compare(sharedEdge, newFace.faceEdge(edgeI));
if (edgeComp != 0)
{
break;
}
}
for
(
;
edgeI < newFace.size()
&& edge::compare(sharedEdge, newFace.faceEdge(edgeI)) != edgeComp;
++ edgeI
);
// If the face does not contain the edge, then move on to the next face
if (edgeComp == 0)
if (edgeI >= newFace.size())
{
continue;
}
@ -643,6 +644,17 @@ Foam::scalar Foam::particle::trackToFace
{
// The track has hit a face, so set the current face and return
facei_ = tetFacei_;
/*
if (!mesh_.isInternalFace(facei_))
{
const label patchi = mesh_.boundaryMesh().whichPatch(facei_);
const polyPatch& patch = mesh_.boundaryMesh()[patchi];
Info<< "Tet face is on " << patch.type() << " patch #" << patchi
<< endl << endl;
}
*/
return f;
}
else
@ -667,8 +679,8 @@ Foam::scalar Foam::particle::trackToStationaryTri
if (debug)
{
Info<< "Particle " << origId() << endl
<< "Tracking from " << x0 << " to " << x0 + x1 << endl;
Info<< "Particle " << origId() << endl << "Tracking from " << x0
<< " along " << x1 << " to " << x0 + x1 << endl;
}
// Get the tet geometry
@ -778,8 +790,8 @@ Foam::scalar Foam::particle::trackToMovingTri
if (debug)
{
Info<< "Particle " << origId() << endl
<< "Tracking from " << x0 << " to " << x0 + x1 << endl;
Info<< "Particle " << origId() << endl << "Tracking from " << x0
<< " along " << x1 << " to " << x0 + x1 << endl;
}
// Get the tet geometry

View File

@ -57,6 +57,8 @@ class particle;
class polyPatch;
class cyclicPolyPatch;
class cyclicAMIPolyPatch;
class cyclicACMIPolyPatch;
class processorPolyPatch;
class symmetryPlanePolyPatch;
class symmetryPolyPatch;
@ -294,10 +296,6 @@ protected:
// Patch interactions
//- Overridable function to handle the particle hitting a face
template<class TrackData>
void hitFace(TrackData& td);
//- Overridable function to handle the particle hitting a
// patch. Executed before other patch-hitting functions.
// trackFraction is passed in to allow mesh motion to
@ -343,6 +341,16 @@ protected:
const vector& direction
);
//- Overridable function to handle the particle hitting a
// cyclicACMIPatch
template<class TrackData>
void hitCyclicACMIPatch
(
const cyclicACMIPolyPatch&,
TrackData& td,
const vector& direction
);
//- Overridable function to handle the particle hitting a
// processorPatch
template<class TrackData>
@ -579,12 +587,21 @@ public:
label& tetTriI
);
//- As non-templated particle::trackToFace, but with additional
// boundary handling.
//- Hit the current face. If the current face is internal than this
// crosses into the next cell. If it is a boundary face then this will
// interact the particle with the relevant patch.
template<class TrackData>
void trackToFace
void hitFace
(
const vector& displacement,
const vector& direction,
TrackData& td
);
//- Convenience function. Cobines trackToFace and hitFace
template<class TrackData>
void trackToAndHitFace
(
const vector& direction,
const scalar fraction,
TrackData& td
);

View File

@ -27,6 +27,7 @@ License
#include "cyclicPolyPatch.H"
#include "cyclicAMIPolyPatch.H"
#include "cyclicACMIPolyPatch.H"
#include "processorPolyPatch.H"
#include "symmetryPlanePolyPatch.H"
#include "symmetryPolyPatch.H"
@ -163,38 +164,30 @@ void Foam::particle::writeFields(const CloudType& c)
template<class TrackData>
void Foam::particle::trackToFace
void Foam::particle::hitFace
(
const vector& displacement,
const scalar fraction,
const vector& direction,
TrackData& td
)
{
// Track
trackToFace(displacement, fraction);
// If the track is complete, return
if (!onFace())
{
return;
}
// Hit face/patch processing
typedef typename TrackData::cloudType::particleType particleType;
particleType& p = static_cast<particleType&>(*this);
p.hitFace(td);
if (onInternalFace())
else if (onInternalFace())
{
changeCell();
}
else
else if (onBoundaryFace())
{
label origFacei = facei_;
label patchi = mesh_.boundaryMesh().whichPatch(facei_);
typename TrackData::cloudType::particleType& p =
static_cast<typename TrackData::cloudType::particleType&>(*this);
// No action is taken for tetPti_ for tetFacei_ here. These are handled
// by the patch interaction call or later during processor transfer.
const label origFacei = facei_;
label patchi = mesh_.boundaryMesh().whichPatch(facei_);
const tetIndices faceHitTetIs(celli_, tetFacei_, tetPti_);
if
@ -245,13 +238,22 @@ void Foam::particle::trackToFace
static_cast<const cyclicPolyPatch&>(patch), td
);
}
else if (isA<cyclicACMIPolyPatch>(patch))
{
p.hitCyclicACMIPatch
(
static_cast<const cyclicACMIPolyPatch&>(patch),
td,
direction
);
}
else if (isA<cyclicAMIPolyPatch>(patch))
{
p.hitCyclicAMIPatch
(
static_cast<const cyclicAMIPolyPatch&>(patch),
td,
displacement
direction
);
}
else if (isA<processorPolyPatch>(patch))
@ -278,8 +280,16 @@ void Foam::particle::trackToFace
template<class TrackData>
void Foam::particle::hitFace(TrackData&)
{}
void Foam::particle::trackToAndHitFace
(
const vector& direction,
const scalar fraction,
TrackData& td
)
{
trackToFace(direction, fraction);
hitFace(direction, td);
}
template<class TrackData>
@ -455,6 +465,46 @@ void Foam::particle::hitCyclicAMIPatch
}
template<class TrackData>
void Foam::particle::hitCyclicACMIPatch
(
const cyclicACMIPolyPatch& cpp,
TrackData& td,
const vector& direction
)
{
const label localFacei = cpp.whichFace(facei_);
// If the mask is within the patch tolerance at either end, then we can
// assume an interaction with the appropriate part of the ACMI pair.
const scalar mask = cpp.mask()[localFacei];
bool couple = mask >= 1 - cpp.tolerance();
bool nonOverlap = mask <= cpp.tolerance();
// If the mask is an intermediate value, then we search for a location on
// the other side of the AMI. If we can't find a location, then we assume
// that we have hit the non-overlap patch.
if (!couple && !nonOverlap)
{
vector pos = position();
couple = cpp.pointFace(localFacei, direction, pos) >= 0;
nonOverlap = !couple;
}
if (couple)
{
hitCyclicAMIPatch(cpp, td, direction);
}
else
{
// Move to the face associated with the non-overlap patch and redo the
// face interaction.
tetFacei_ = facei_ = cpp.nonOverlapPatch().start() + localFacei;
hitFace(direction, td);
}
}
template<class TrackData>
void Foam::particle::hitProcessorPatch(const processorPolyPatch&, TrackData&)
{}

View File

@ -291,8 +291,8 @@ bool Foam::KinematicParcel<ParcelType>::move
f = min(f, maxCo*l/max(SMALL*l, mag(s)));
if (p.active())
{
// Track to the next face
p.trackToFace(f*s, f, td);
// Track to and hit the next face
p.trackToAndHitFace(f*s, f, td);
}
else
{
@ -304,7 +304,6 @@ bool Foam::KinematicParcel<ParcelType>::move
p.stepFraction() += f;
}
const scalar dt = (p.stepFraction() - sfrac)*trackTime;
// Avoid problems with extremely small timesteps
@ -331,6 +330,11 @@ bool Foam::KinematicParcel<ParcelType>::move
p.age() += dt;
if (p.onFace())
{
td.cloud().functions().postFace(p, p.face(), td.keepParticle);
}
td.cloud().functions().postMove(p, celli, dt, start, td.keepParticle);
}
@ -338,22 +342,6 @@ bool Foam::KinematicParcel<ParcelType>::move
}
template<class ParcelType>
template<class TrackData>
void Foam::KinematicParcel<ParcelType>::hitFace(TrackData& td)
{
typename TrackData::cloudType::parcelType& p =
static_cast<typename TrackData::cloudType::parcelType&>(*this);
td.cloud().functions().postFace(p, p.face(), td.keepParticle);
}
template<class ParcelType>
void Foam::KinematicParcel<ParcelType>::hitFace(int& td)
{}
template<class ParcelType>
template<class TrackData>
bool Foam::KinematicParcel<ParcelType>::hitPatch

View File

@ -577,14 +577,6 @@ public:
// Patch interactions
//- Overridable function to handle the particle hitting a face
// without trackData
void hitFace(int& td);
//- Overridable function to handle the particle hitting a face
template<class TrackData>
void hitFace(TrackData& td);
//- Overridable function to handle the particle hitting a patch
// Executed before other patch-hitting functions
template<class TrackData>

View File

@ -88,7 +88,7 @@ bool Foam::molecule::move(molecule::trackingData& td, const scalar trackTime)
while (td.keepParticle && !td.switchProcessor && stepFraction() < 1)
{
const scalar f = 1 - stepFraction();
trackToFace(f*trackTime*v_, f, td);
trackToAndHitFace(f*trackTime*v_, f, td);
}
}
else if (td.part() == 2)

View File

@ -58,7 +58,7 @@ bool Foam::solidParticle::move
const scalar sfrac = stepFraction();
const scalar f = 1 - stepFraction();
trackToFace(f*trackTime*U_, f, td);
trackToAndHitFace(f*trackTime*U_, f, td);
const scalar dt = (stepFraction() - sfrac)*trackTime;

View File

@ -144,7 +144,8 @@ bool Foam::trackedParticle::move
td.maxLevel_[cell()] = max(td.maxLevel_[cell()], level_);
const scalar f = 1 - stepFraction();
trackToFace(f*(end_ - start_), f, td);
const vector s = end_ - start_;
trackToAndHitFace(f*s, f, td);
}
}

View File

@ -62,7 +62,7 @@ bool Foam::faceOnlySet::trackToBoundary
{
point oldPoint = trackPt;
singleParticle.trackToFace(end_ - start_, 0, trackData);
singleParticle.trackToAndHitFace(end_ - start_, 0, trackData);
trackPt = singleParticle.position();