43const Foam::label Foam::particle::maxNBehind_ = 10;
56 "writeLagrangianPositions",
64void Foam::particle::stationaryTetReverseTransform
81 detA = ab & (ac ^ ad);
93void Foam::particle::movingTetReverseTransform
95 const scalar fraction,
109 centre[0] =
A[0].a();
110 centre[1] =
A[1].a();
112 detA[0] = ab[0] & (ac[0] ^ ad[0]);
114 (ab[1] & (ac[0] ^ ad[0]))
115 + (ab[0] & (ac[1] ^ ad[0]))
116 + (ab[0] & (ac[0] ^ ad[1]));
118 (ab[0] & (ac[1] ^ ad[1]))
119 + (ab[1] & (ac[0] ^ ad[1]))
120 + (ab[1] & (ac[1] ^ ad[0]));
121 detA[3] = ab[1] & (ac[1] ^ ad[1]);
132 (bd[0] ^ bc[1]) + (bd[1] ^ bc[0]),
133 (ac[0] ^ ad[1]) + (ac[1] ^ ad[0]),
134 (ad[0] ^ ab[1]) + (ad[1] ^ ab[0]),
135 (ab[0] ^ ac[1]) + (ab[1] ^ ac[0])
147void Foam::particle::reflect()
149 std::swap(coordinates_.c(), coordinates_.d());
153void Foam::particle::rotate(
const bool reverse)
157 scalar temp = coordinates_.b();
158 coordinates_.b() = coordinates_.c();
159 coordinates_.c() = coordinates_.d();
160 coordinates_.d() = temp;
164 scalar temp = coordinates_.d();
165 coordinates_.d() = coordinates_.c();
166 coordinates_.c() = coordinates_.b();
167 coordinates_.b() = temp;
172void Foam::particle::changeTet(
const label tetTriI)
174 const bool isOwner = mesh_.faceOwner()[tetFacei_] == celli_;
176 const label firstTetPtI = 1;
177 const label lastTetPtI = mesh_.faces()[tetFacei_].size() - 2;
183 else if (tetTriI == 2)
187 if (tetPti_ == lastTetPtI)
199 if (tetPti_ == firstTetPtI)
210 else if (tetTriI == 3)
214 if (tetPti_ == firstTetPtI)
226 if (tetPti_ == lastTetPtI)
240 <<
"Changing tet without changing cell should only happen when the "
241 <<
"track is on triangle 1, 2 or 3."
247void Foam::particle::changeFace(
const label tetTriI)
250 const triFace triOldIs(currentTetIndices().faceTriIs(mesh_));
256 sharedEdge =
edge(triOldIs[1], triOldIs[2]);
258 else if (tetTriI == 2)
260 sharedEdge =
edge(triOldIs[2], triOldIs[0]);
262 else if (tetTriI == 3)
264 sharedEdge =
edge(triOldIs[0], triOldIs[1]);
269 <<
"Changing face without changing cell should only happen when the"
270 <<
" track is on triangle 1, 2 or 3."
273 sharedEdge =
edge(-1, -1);
279 for (
const label newFaceI : mesh_.cells()[celli_])
281 const Foam::face& newFace = mesh_.faces()[newFaceI];
282 const label newOwner = mesh_.faceOwner()[newFaceI];
285 if (tetFacei_ == newFaceI)
293 const label edgeComp = newOwner == celli_ ? -1 : +1;
298 edgeI < newFace.
size()
304 if (edgeI >= newFace.
size())
310 const label newBaseI =
max(0, mesh_.tetBasePtIs()[newFaceI]);
311 edgeI = (edgeI - newBaseI + newFace.
size()) % newFace.
size();
316 edgeI =
min(
max(1, edgeI), newFace.
size() - 2);
319 tetFacei_ = newFaceI;
329 <<
"The search for an edge-connected face and tet-point failed."
334 if (sharedEdge.otherVertex(triOldIs[1]) == -1)
338 else if (sharedEdge.otherVertex(triOldIs[2]) == -1)
344 const triFace triNewIs = currentTetIndices().faceTriIs(mesh_);
350 if (sharedEdge.otherVertex(triNewIs[1]) == -1)
354 else if (sharedEdge.otherVertex(triNewIs[2]) == -1)
361void Foam::particle::changeCell()
364 const label ownerCellI = mesh_.faceOwner()[tetFacei_];
365 const bool isOwner = celli_ == ownerCellI;
366 celli_ = isOwner ? mesh_.faceNeighbour()[tetFacei_] : ownerCellI;
372void Foam::particle::changeToMasterPatch()
374 label thisPatch =
patch();
376 for (
const label otherFaceI : mesh_.cells()[celli_])
379 if (facei_ == otherFaceI || mesh_.isInternalFace(otherFaceI))
387 const Foam::face& thisFace = mesh_.faces()[facei_];
388 const Foam::face&
otherFace = mesh_.faces()[otherFaceI];
391 const label otherPatch =
392 mesh_.boundaryMesh().whichPatch(otherFaceI);
393 if (thisPatch > otherPatch)
396 thisPatch = otherPatch;
405void Foam::particle::locate
410 const bool boundaryFail,
411 const string& boundaryMsg
424 celli_ = mesh_.cellTree().findInside(position);
428 <<
"Cell not found for particle position " << position <<
"."
435 const vector displacement =
437 - mesh_.cellCentres()[celli_]
438 +
vector(VSMALL, VSMALL, VSMALL);
443 const Foam::cell&
c = mesh_.cells()[celli_];
444 scalar minF = VGREAT;
445 label minTetFacei = -1, minTetPti = -1;
448 const Foam::face&
f = mesh_.faces()[
c[cellTetFacei]];
449 for (label tetPti = 1; tetPti <
f.
size() - 1; ++tetPti)
452 tetFacei_ =
c[cellTetFacei];
457 const scalar
f = trackToTri(displacement, 0, tetTriI);
467 minTetFacei = tetFacei_;
476 tetFacei_ = minTetFacei;
479 track(displacement, 0);
492 static label nWarnings = 0;
493 static const label maxNWarnings = 100;
494 if ((nWarnings < maxNWarnings) && boundaryFail)
499 if (nWarnings == maxNWarnings)
502 <<
"Suppressing any further warnings about particles being "
503 <<
"located outside of the mesh." <<
endl;
515 const polyMesh&
mesh,
518 const label tetFacei,
531 origProc_(
Pstream::myProcNo()),
544 coordinates_(-VGREAT, -VGREAT, -VGREAT, -VGREAT),
552 origProc_(
Pstream::myProcNo()),
553 origId_(getNewParticleID())
561 "Particle initialised with a location outside of the mesh"
571 const label tetFacei,
577 coordinates_(-VGREAT, -VGREAT, -VGREAT, -VGREAT),
585 origProc_(
Pstream::myProcNo()),
586 origId_(getNewParticleID())
596 "Particle initialised with a location outside of the mesh"
605 coordinates_(
p.coordinates_),
607 tetFacei_(
p.tetFacei_),
610 stepFraction_(
p.stepFraction_),
612 nBehind_(
p.nBehind_),
613 origProc_(
p.origProc_),
628 const vector& displacement,
629 const scalar fraction
632 scalar
f = trackToFace(displacement, fraction);
634 while (onInternalFace())
647 const vector& displacement,
648 const scalar fraction
653 label tetTriI = onFace() ? 0 : -1;
658 while (nBehind_ < maxNBehind_)
660 f *= trackToTri(
f*displacement,
f*fraction, tetTriI);
667 else if (tetTriI == 0)
681 static label stuckID = -1, stuckProc = -1;
682 if (origId_ != stuckID && origProc_ != stuckProc)
685 <<
"Particle #" << origId_ <<
" got stuck at " << position()
690 stuckProc = origProc_;
692 stepFraction_ +=
f*fraction;
703 const vector& displacement,
704 const scalar fraction,
708 const vector x0 = position();
709 const vector x1 = displacement;
714 Pout<<
"Particle " << origId() <<
endl <<
"Tracking from " << x0
715 <<
" along " << x1 <<
" to " << x0 + x1 <<
endl;
722 stationaryTetReverseTransform(centre, detA,
T);
726 Pout<<
"Tet points: " << currentTetIndices().tet(mesh_) <<
endl
727 <<
"Tet determinant = " << detA <<
endl
728 <<
"Start local coordinates = " <<
y0 <<
endl;
736 Pout<<
"Local displacement = " << Tx1 <<
"/" << detA <<
endl;
741 scalar muH = detA <= 0 ? VGREAT : 1/detA;
742 for (label i = 0; i < 4; ++ i)
744 if (Tx1[i] < - detA*SMALL)
746 scalar
mu = -
y0[i]/Tx1[i];
750 Pout<<
"Hit on tet face " << i <<
" at local coordinate "
751 <<
y0 +
mu*Tx1 <<
", " <<
mu*detA*100 <<
"% of the "
752 <<
"way along the track" <<
endl;
755 if (0 <=
mu &&
mu < muH)
767 for (label i = 0; i < 4; ++ i)
769 yH.replace(i, i == iH ? 0 :
max(0, yH[i]));
786 Pout<<
"Track hit tet face " << iH <<
" first" <<
endl;
790 Pout<<
"Track hit no tet faces" <<
endl;
792 Pout<<
"End local coordinates = " << yH <<
endl
793 <<
"End global coordinates = " << position() <<
endl
794 <<
"Tracking displacement = " << position() - x0 <<
endl
795 << muH*detA*100 <<
"% of the step from " << stepFraction_ <<
" to "
796 << stepFraction_ + fraction <<
" completed" <<
endl <<
endl;
800 stepFraction_ += fraction*muH*detA;
804 Pout <<
"Step Fraction : " << stepFraction_ <<
endl;
805 Pout <<
"fraction*muH*detA : " << fraction*muH*detA <<
endl;
806 Pout <<
"static muH : " << muH <<
endl;
807 Pout <<
"origId() : " << origId() <<
endl;
811 if (detA <= 0 || nBehind_ > 0)
813 behind_ += muH*detA*
mag(displacement);
826 return iH != -1 ? 1 - muH*detA : 0;
832 const vector& displacement,
833 const scalar fraction,
837 const vector x0 = position();
838 const vector x1 = displacement;
843 Pout<<
"Particle " << origId() <<
endl <<
"Tracking from " << x0
844 <<
" along " << x1 <<
" to " << x0 + x1 <<
endl;
851 movingTetReverseTransform(fraction, centre, detA,
T);
856 movingTetGeometry(fraction, o,
b, v1, v2);
857 Pout<<
"Tet points o=" << o[0] <<
", b=" <<
b[0]
858 <<
", v1=" << v1[0] <<
", v2=" << v2[0] <<
endl
859 <<
"Tet determinant = " << detA[0] <<
endl
860 <<
"Start local coordinates = " <<
y0[0] <<
endl;
865 const vector x0Rel = x0 - centre[0];
866 const vector x1Rel = x1 - centre[1];
869 cubicEqn detAEqn(
sqr(detA[0])*detA[3], detA[0]*detA[2], detA[1], 1);
872 ((x1Rel &
T[2]) + detA[3]*yC)*
sqr(detA[0]);
874 ((x1Rel &
T[1]) + (x0Rel &
T[2]) + detA[2]*yC)*detA[0];
876 ((x1Rel &
T[0]) + (x0Rel &
T[1]) + detA[1]*yC);
881 hitEqn[i] =
cubicEqn(hitEqnA[i], hitEqnB[i], hitEqnC[i], hitEqnD[i]);
886 for (label i = 0; i < 4; ++ i)
888 Pout<< (i ?
" " :
"Hit equation ") << i <<
" = "
889 << hitEqn[i] <<
endl;
891 Pout<<
" DetA equation = " << detA <<
endl;
896 scalar muH = detA[0] <= 0 ? VGREAT : 1/detA[0];
897 for (label i = 0; i < 4; ++i)
901 for (label j = 0; j < 3; ++j)
906 && hitEqn[i].derivative(
mu[j]) < - detA[0]*SMALL
913 hitEqn[0].value(
mu[j]),
914 hitEqn[1].value(
mu[j]),
915 hitEqn[2].value(
mu[j]),
916 hitEqn[3].value(
mu[j])
918 const scalar detAH = detAEqn.value(
mu[j]);
920 Pout<<
"Hit on tet face " << i <<
" at local coordinate "
921 << (std::isnormal(detAH) ?
name(yH/detAH) :
"???")
922 <<
", " <<
mu[j]*detA[0]*100 <<
"% of the "
923 <<
"way along the track" <<
endl;
925 Pout<<
"derivative : " << hitEqn[i].derivative(
mu[j]) <<
nl
926 <<
" coord " << j <<
" mu[j]: " <<
mu[j] <<
nl
927 <<
" hitEq " << i <<
endl;
930 if (0 <=
mu[j] &&
mu[j] < muH)
942 hitEqn[0].value(muH),
943 hitEqn[1].value(muH),
944 hitEqn[2].value(muH),
954 const scalar detAH = detAEqn.value(muH);
955 if (!std::isnormal(detAH))
958 <<
"A moving tet collapsed onto a particle. This is not supported. "
959 <<
"The mesh is too poor, or the motion too severe, for particle "
965 for (label i = 0; i < 4; ++ i)
967 yH.replace(i, i == iH ? 0 :
max(0, yH[i]));
980 scalar advance = muH*detA[0];
983 stepFraction_ += fraction*advance;
986 if (detA[0] <= 0 || nBehind_ > 0)
988 behind_ += muH*detA[0]*
mag(displacement);
1005 Pout<<
"Track hit tet face " << iH <<
" first" <<
endl;
1009 Pout<<
"Track hit no tet faces" <<
endl;
1020 return iH != -1 ? 1 - muH*detA[0] : 0;
1026 const vector& displacement,
1027 const scalar fraction,
1031 if ((mesh_.moving() && (stepFraction_ != 1 || fraction != 0)))
1033 return trackToMovingTri(displacement, fraction, tetTriI);
1044 if (
cmptMin(mesh_.geometricD()) == -1)
1068 facei_ = mesh_.boundaryMesh()[
patch()].whichFace(facei_);
1089 transformProperties(
T);
1099 transformProperties(-
s);
1104 facei_ += ppp.
start();
1109 tetPti_ = mesh_.faces()[tetFacei_].size() - 1 - tetPti_;
1150 const vector pos(coordinates_.b(), coordinates_.c(), coordinates_.d());
1154 tetFacei_ = mesh_.cells()[celli_][0];
1165 if (mesh_.moving() && stepFraction_ != 1)
1167 Pair<vector> centre;
1168 FixedList<scalar, 4> detA;
1169 FixedList<barycentricTensor, 3>
T;
1170 movingTetReverseTransform(0, centre, detA,
T);
1171 coordinates_ += (
pos - centre[0]) &
T[0]/detA[0];
1178 stationaryTetReverseTransform(centre, detA,
T);
1179 coordinates_ += (
pos - centre) &
T/detA;
1186 const polyMesh& procMesh,
1187 const label procCell,
1188 const label procTetFace
1197 (mesh_.faceOwner()[tetFacei_] == celli_)
1198 == (procMesh.faceOwner()[procTetFace] == procCell)
1205 return procMesh.faces()[procTetFace].size() - 1 - tetPti_;
1213 const mapPolyMesh& mapper
1220 mapper.reverseCellMap()[celli_],
1222 "Particle mapped to a location outside of the mesh"
1235 "Particle mapped to a location outside of the mesh"
static const Foam::dimensionedScalar A("", Foam::dimPressure, 611.21)
A 1D vector of objects of type <T> with a fixed length <N>.
An ordered pair of two objects of type <T> with first() and second() elements.
Inter-processor communications stream.
Templated storage for the roots of polynomial equations, plus flags to indicate the nature of the roo...
void size(const label n)
Older name for setAddressableSize.
void replace(const direction, const Cmpt &)
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
virtual bool separated() const
Are the planes separated.
virtual bool parallel() const
Are the cyclic planes parallel.
virtual const vectorField & separation() const
If the planes are separated the separation vector.
virtual const tensorField & forwardT() const
Return face transformation tensor.
Container to encapsulate various operations for cubic equation of the forms with real coefficients:
scalar value(const scalar x) const
Evaluate the cubic equation at x.
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
static int compare(const edge &a, const edge &b)
Compare edges.
Foam::edge edge(const label edgei) const
Return i-th face edge (forward walk order).
static int compare(const face &a, const face &b)
Compare faces.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseCellMap() const noexcept
Reverse cell map.
void correctAfterInteractionListReferral(const label celli)
Correct the topology after referral. The particle may still be.
virtual void transformProperties(const tensor &T)
Transform the physical properties of the particle.
label procTetPt(const polyMesh &procMesh, const label procCell, const label procTetFace) const
Return the tet point appropriate for decomposition or reconstruction.
tetIndices currentTetIndices() const noexcept
Return indices of the current tet that the particle occupies.
vector deviationFromMeshCentre() const
Get the displacement from the mesh centre. Used to correct the.
scalar trackToStationaryTri(const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToTri, but for stationary meshes.
void correctAfterParallelTransfer(const label patchi, trackingData &td)
Convert processor patch addressing to the global equivalents.
scalar trackToFace(const vector &displacement, const scalar fraction)
As particle::track, but also stops on internal faces.
vector position() const
Return current particle position.
void prepareForInteractionListReferral(const vectorTensorTransform &transform)
Break the topology and store the particle position so that the.
bool onFace() const noexcept
Is the particle on a face?
const polyMesh & mesh() const noexcept
Return the mesh database.
void autoMap(const vector &position, const mapPolyMesh &mapper)
Map after a topology change.
const barycentric & coordinates() const noexcept
Return current particle coordinates.
scalar trackToMovingTri(const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToTri, but for moving meshes.
label patch() const
Return the index of patch that the particle is on.
void prepareForParallelTransfer()
Convert global addressing to the processor patch local equivalents.
static label particleCount_
Cumulative particle counter - used to provide unique ID.
static bool writeLagrangianPositions
Write particle positions file (v1706 format and earlier) Default is true (disable in etc/controlDict)...
scalar track(const vector &displacement, const scalar fraction)
Track along the displacement for a given fraction of the overall.
bool onInternalFace() const noexcept
Is the particle on an internal face?
label getNewParticleID() const
Get unique particle creation id.
label origId() const noexcept
Return the particle ID on the originating processor.
particle(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label tetFacei, const label tetPti)
Construct from components.
void relocate(const point &position, const label celli=-1)
Set the addressing based on the provided position.
scalar trackToTri(const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToFace, but also stops on tet triangles. On.
static bool writeLagrangianCoordinates
Write particle coordinates file (v1712 and later) Default is true.
label origProc() const noexcept
Return the originating processor ID.
Mesh consisting of general polyhedral cells.
virtual const faceList & faces() const
Return raw faces.
virtual const labelList & faceOwner() const
Return face owner.
label start() const noexcept
Return start label of this patch in the polyMesh face list.
const labelUList & faceCells() const
Return face-cell addressing.
A triangular face using a FixedList of labels corresponding to mesh vertices.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
PtrList< coordinateSystem > coordinates(solidRegions.size())
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
wallPoints::trackData td(isBlockedFace, regionToBlockSize)
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
Namespace for handling debugging switches.
int infoSwitch(const char *name, const int deflt=0)
Lookup info switch or add default value.
const std::string patch
OpenFOAM patch number as a std::string.
bool operator!=(const eddy &a, const eddy &b)
dimensionedScalar pos(const dimensionedScalar &ds)
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
dimensionedScalar y0(const dimensionedScalar &ds)
void reverse(UList< T > &list, const label n)
Reverse the first n elements of the list.
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
refinementData transform(const tensor &, const refinementData val)
No-op rotational transform for base types.
Cmpt cmptSum(const SphericalTensor< Cmpt > &st)
Return the sum of components of a SphericalTensor.
Ostream & endl(Ostream &os)
Add newline and flush stream.
tmp< faMatrix< Type > > operator==(const faMatrix< Type > &, const faMatrix< Type > &)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
vector point
Point is a vector.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
Barycentric< scalar > barycentric
A scalar version of the templated Barycentric.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
errorManipArg< error, int > exit(error &err, const int errNo=1)
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
BarycentricTensor< scalar > barycentricTensor
A scalar version of the templated BarycentricTensor.
constexpr char nl
The newline '\n' character (0x0a).
#define registerInfoSwitch(Name, Type, SwitchVar)
#define forAll(list, i)
Loop across all elements in list.