35 const Foam::label Foam::particle::maxNTracksBehind_ = 48;
47 void Foam::particle::stationaryTetReverseTransform
65 detA = ab & (ac ^ ad);
77 void Foam::particle::movingTetReverseTransform
80 const scalar fraction,
82 FixedList<scalar, 4>& detA,
83 FixedList<barycentricTensor, 3>&
T
86 Pair<barycentricTensor>
A = movingTetTransform(mesh, fraction);
88 const Pair<vector> ab(
A[0].
b() -
A[0].a(),
A[1].
b() -
A[1].a());
89 const Pair<vector> ac(
A[0].
c() -
A[0].a(),
A[1].
c() -
A[1].a());
90 const Pair<vector> ad(
A[0].d() -
A[0].a(),
A[1].d() -
A[1].a());
91 const Pair<vector> bc(
A[0].
c() -
A[0].
b(),
A[1].
c() -
A[1].
b());
92 const Pair<vector> bd(
A[0].d() -
A[0].
b(),
A[1].d() -
A[1].
b());
97 detA[0] = ab[0] & (ac[0] ^ ad[0]);
99 (ab[1] & (ac[0] ^ ad[0]))
100 + (ab[0] & (ac[1] ^ ad[0]))
101 + (ab[0] & (ac[0] ^ ad[1]));
103 (ab[0] & (ac[1] ^ ad[1]))
104 + (ab[1] & (ac[0] ^ ad[1]))
105 + (ab[1] & (ac[1] ^ ad[0]));
106 detA[3] = ab[1] & (ac[1] ^ ad[1]);
117 (bd[0] ^ bc[1]) + (bd[1] ^ bc[0]),
118 (ac[0] ^ ad[1]) + (ac[1] ^ ad[0]),
119 (ad[0] ^ ab[1]) + (ad[1] ^ ab[0]),
120 (ab[0] ^ ac[1]) + (ab[1] ^ ac[0])
132 void Foam::particle::reflect()
134 Swap(coordinates_.c(), coordinates_.d());
138 void Foam::particle::rotate(
const bool reverse)
142 scalar temp = coordinates_.b();
143 coordinates_.b() = coordinates_.c();
144 coordinates_.c() = coordinates_.d();
145 coordinates_.d() = temp;
149 scalar temp = coordinates_.d();
150 coordinates_.d() = coordinates_.c();
151 coordinates_.c() = coordinates_.b();
152 coordinates_.b() = temp;
157 void Foam::particle::changeTet(
const polyMesh& mesh,
const label tetTriI)
164 const bool isOwner = mesh.faceOwner()[tetFacei_] == celli_;
166 const label firstTetPtI = 1;
167 const label lastTetPtI = mesh.faces()[tetFacei_].size() - 2;
171 changeFace(mesh, tetTriI);
173 else if (tetTriI == 2)
177 if (tetPti_ == lastTetPtI)
179 changeFace(mesh, tetTriI);
189 if (tetPti_ == firstTetPtI)
191 changeFace(mesh, tetTriI);
200 else if (tetTriI == 3)
204 if (tetPti_ == firstTetPtI)
206 changeFace(mesh, tetTriI);
216 if (tetPti_ == lastTetPtI)
218 changeFace(mesh, tetTriI);
230 <<
"Changing tet without changing cell should only happen when the "
231 <<
"track is on triangle 1, 2 or 3."
237 void Foam::particle::changeFace(
const polyMesh& mesh,
const label tetTriI)
245 const triFace triOldIs(currentTetIndices(mesh).faceTriIs(mesh));
251 sharedEdge = edge(triOldIs[1], triOldIs[2]);
253 else if (tetTriI == 2)
255 sharedEdge = edge(triOldIs[2], triOldIs[0]);
257 else if (tetTriI == 3)
259 sharedEdge = edge(triOldIs[0], triOldIs[1]);
264 <<
"Changing face without changing cell should only happen when the"
265 <<
" track is on triangle 1, 2 or 3."
268 sharedEdge = edge(-1, -1);
274 forAll(mesh.cells()[celli_], cellFaceI)
276 const label newFaceI = mesh.cells()[celli_][cellFaceI];
277 const class face& newFace = mesh.faces()[newFaceI];
278 const label newOwner = mesh.faceOwner()[newFaceI];
281 if (tetFacei_ == newFaceI)
287 const label edgeComp = newOwner == celli_ ? -1 : +1;
292 edgeI < newFace.size()
293 &&
edge::compare(sharedEdge, newFace.faceEdge(edgeI)) != edgeComp;
298 if (edgeI >= newFace.size())
304 const label newBaseI =
max(0, mesh.tetBasePtIs()[newFaceI]);
305 edgeI = (edgeI - newBaseI + newFace.size()) % newFace.size();
310 edgeI =
min(
max(1, edgeI), newFace.size() - 2);
313 tetFacei_ = newFaceI;
323 <<
"The search for an edge-connected face and tet-point failed."
328 if (sharedEdge.otherVertex(triOldIs[1]) == -1)
332 else if (sharedEdge.otherVertex(triOldIs[2]) == -1)
338 const triFace triNewIs = currentTetIndices(mesh).faceTriIs(mesh);
344 if (sharedEdge.otherVertex(triNewIs[1]) == -1)
348 else if (sharedEdge.otherVertex(triNewIs[2]) == -1)
355 void Foam::particle::changeCell(
const polyMesh& mesh)
363 const label ownerCellI = mesh.faceOwner()[tetFacei_];
364 const bool isOwner = celli_ == ownerCellI;
365 celli_ = isOwner ? mesh.faceNeighbour()[tetFacei_] : ownerCellI;
372 void Foam::particle::locate
374 const polyMesh& mesh,
377 const bool boundaryFail,
378 const string boundaryMsg
389 celli = mesh.cellTree().findInside(position);
394 <<
"Cell not found for particle position " << position <<
"."
400 const vector displacement = position - mesh.cellCentres()[celli_];
405 const class cell&
c = mesh.cells()[celli_];
406 scalar minF = vGreat;
407 label minTetFacei = -1, minTetPti = -1;
410 const class face&
f = mesh.faces()[
c[cellTetFacei]];
411 for (
label tetPti = 1; tetPti <
f.
size() - 1; ++ tetPti)
414 tetFacei_ =
c[cellTetFacei];
420 const scalar
f = trackToTri(mesh, displacement, 0, tetTriI);
430 minTetFacei = tetFacei_;
439 tetFacei_ = minTetFacei;
444 track(mesh, displacement, 0);
457 static label nWarnings = 0;
458 static const label maxNWarnings = 100;
459 if (nWarnings < maxNWarnings)
464 if (nWarnings == maxNWarnings)
467 <<
"Suppressing any further warnings about particles being "
468 <<
"located outside of the mesh." <<
endl;
482 const label tetFacei,
487 coordinates_(coordinates),
493 stepFractionBehind_(0),
495 origProc_(
Pstream::myProcNo()),
496 origId_(getNewParticleID())
507 coordinates_(- vGreat, - vGreat, - vGreat, - vGreat),
513 stepFractionBehind_(0),
515 origProc_(
Pstream::myProcNo()),
516 origId_(getNewParticleID())
524 "Particle initialised with a location outside of the mesh."
531 coordinates_(
p.coordinates_),
533 tetFacei_(
p.tetFacei_),
536 stepFraction_(
p.stepFraction_),
537 stepFractionBehind_(
p.stepFractionBehind_),
538 nTracksBehind_(
p.nTracksBehind_),
539 origProc_(
p.origProc_),
549 const vector& displacement,
550 const scalar fraction
558 scalar
f = trackToFace(mesh, displacement, fraction);
560 while (onInternalFace(mesh))
564 f *= trackToFace(mesh,
f*displacement,
f*fraction);
574 const vector& displacement,
575 const scalar fraction
583 const scalar
f = trackToFace(mesh, displacement, fraction);
585 if (onInternalFace(mesh))
597 const vector& displacement,
598 const scalar fraction
608 label tetTriI = onFace() ? 0 : -1;
613 while (nTracksBehind_ < maxNTracksBehind_)
615 f *= trackToTri(mesh,
f*displacement,
f*fraction, tetTriI);
622 else if (tetTriI == 0)
631 changeTet(mesh, tetTriI);
637 <<
"Particle #" << origId_ <<
" got stuck at " << position(mesh)
640 stepFraction_ +=
f*fraction;
642 stepFractionBehind_ = 0;
652 const vector& displacement,
653 const scalar fraction,
657 const vector x0 = position(mesh);
658 const vector x1 = displacement;
663 Info<<
"Particle " << origId() <<
endl <<
"Tracking from " << x0
664 <<
" along " << x1 <<
" to " << x0 + x1 <<
endl;
671 stationaryTetReverseTransform(mesh, centre, detA,
T);
676 stationaryTetGeometry(mesh, o,
b, v1, v2);
677 Info<<
"Tet points o=" << o <<
", b=" <<
b
678 <<
", v1=" << v1 <<
", v2=" << v2 <<
endl
679 <<
"Tet determinant = " << detA <<
endl
680 <<
"Start local coordinates = " <<
y0 <<
endl;
688 Info<<
"Local displacement = " << Tx1 <<
"/" << detA <<
endl;
693 scalar muH = detA > vSmall ? 1/detA : vGreat;
694 for (
label i = 0; i < 4; ++ i)
696 if (Tx1[i] < - vSmall && Tx1[i] < -
mag(detA)*small)
698 scalar
mu = -
y0[i]/Tx1[i];
702 Info<<
"Hit on tet face " << i <<
" at local coordinate "
703 <<
y0 +
mu*Tx1 <<
", " <<
mu*detA*100 <<
"% of the "
704 <<
"way along the track" <<
endl;
707 if (0 <=
mu &&
mu < muH)
718 if (iH == -1 && muH == vGreat)
720 stepFraction_ += fraction;
728 for (
label i = 0; i < 4; ++ i)
744 stepFraction_ += fraction*muH*detA;
750 Info<<
"Track hit tet face " << iH <<
" first" <<
endl;
754 Info<<
"Track hit no tet faces" <<
endl;
756 Info<<
"End local coordinates = " << yH <<
endl
757 <<
"End global coordinates = " << position(mesh) <<
endl
758 <<
"Tracking displacement = " << position(mesh) - x0 <<
endl
759 << muH*detA*100 <<
"% of the step from "
760 << stepFraction_ - fraction*muH*detA <<
" to "
761 << stepFraction_ - fraction*muH*detA + fraction
766 if (muH*detA < small || nTracksBehind_ > 0)
768 stepFractionBehind_ += (fraction != 0 ? fraction : 1)*muH*detA;
770 if (stepFractionBehind_ > rootSmall)
772 stepFractionBehind_ = 0;
781 return iH != -1 ? 1 - muH*detA : 0;
788 const vector& displacement,
789 const scalar fraction,
793 const vector x0 = position(mesh);
794 const vector x1 = displacement;
799 Info<<
"Particle " << origId() <<
endl <<
"Tracking from " << x0
800 <<
" along " << x1 <<
" to " << x0 + x1 <<
endl;
807 movingTetReverseTransform(mesh, fraction, centre, detA,
T);
812 movingTetGeometry(mesh, fraction, o,
b, v1, v2);
813 Info<<
"Tet points o=" << o[0] <<
", b=" <<
b[0]
814 <<
", v1=" << v1[0] <<
", v2=" << v2[0] <<
endl
815 <<
"Tet determinant = " << detA[0] <<
endl
816 <<
"Start local coordinates = " <<
y0[0] <<
endl;
820 const vector x0Rel = x0 - centre[0];
821 const vector x1Rel = x1 - centre[1];
824 cubicEqn detAEqn(
sqr(detA[0])*detA[3], detA[0]*detA[2], detA[1], 1);
827 ((x1Rel &
T[2]) + detA[3]*yC)*
sqr(detA[0]);
829 ((x1Rel &
T[1]) + (x0Rel &
T[2]) + detA[2]*yC)*detA[0];
831 ((x1Rel &
T[0]) + (x0Rel &
T[1]) + detA[1]*yC);
836 hitEqn[i] =
cubicEqn(hitEqnA[i], hitEqnB[i], hitEqnC[i], hitEqnD[i]);
841 for (
label i = 0; i < 4; ++ i)
843 Info<< (i ?
" " :
"Hit equation ") << i <<
" = "
844 << hitEqn[i] <<
endl;
846 Info<<
" DetA equation = " << detA <<
endl;
851 scalar muH = detA[0] > vSmall ? 1/detA[0] : vGreat;
852 for (
label i = 0; i < 4; ++ i)
856 for (
label j = 0; j < 3; ++ j)
861 && hitEqn[i].derivative(
mu[j]) < - vSmall
862 && hitEqn[i].derivative(
mu[j]) < -
mag(detA[0])*small
869 hitEqn[0].value(
mu[j]),
870 hitEqn[1].value(
mu[j]),
871 hitEqn[2].value(
mu[j]),
872 hitEqn[3].value(
mu[j])
874 const scalar detAH = detAEqn.
value(
mu[j]);
876 Info<<
"Hit on tet face " << i <<
" at local coordinate "
877 << (
mag(detAH) > vSmall ?
name(yH/detAH) :
"???")
878 <<
", " <<
mu[j]*detA[0]*100 <<
"% of the "
879 <<
"way along the track" <<
endl;
882 if (0 <=
mu[j] &&
mu[j] < muH)
894 if (iH == -1 && muH == vGreat)
896 stepFraction_ += fraction;
903 hitEqn[0].value(muH),
904 hitEqn[1].value(muH),
905 hitEqn[2].value(muH),
915 const scalar detAH = detAEqn.
value(muH);
916 if (
mag(detAH) < vSmall)
919 <<
"A moving tet collapsed onto a particle. This is not supported. "
920 <<
"The mesh is too poor, or the motion too severe, for particle "
926 for (
label i = 0; i < 4; ++ i)
942 stepFraction_ += fraction*muH*detA[0];
948 Info<<
"Track hit tet face " << iH <<
" first" <<
endl;
952 Info<<
"Track hit no tet faces" <<
endl;
954 Info<<
"End local coordinates = " << yH <<
endl
955 <<
"End global coordinates = " << position(mesh) <<
endl
956 <<
"Tracking displacement = " << position(mesh) - x0 <<
endl
957 << muH*detA[0]*100 <<
"% of the step from "
958 << stepFraction_ - fraction*muH*detA[0] <<
" to "
959 << stepFraction_ - fraction*muH*detA[0] + fraction
964 if (muH*detA[0] < small || nTracksBehind_ > 0)
966 stepFractionBehind_ += (fraction != 0 ? fraction : 1)*muH*detA[0];
968 if (stepFractionBehind_ > rootSmall)
970 stepFractionBehind_ = 0;
979 return iH != -1 ? 1 - muH*detA[0] : 0;
986 const vector& displacement,
987 const scalar fraction,
991 if (mesh.
moving() && (stepFraction_ != 1 || fraction != 0))
993 return trackToMovingTri(mesh, displacement, fraction, tetTriI);
997 return trackToStationaryTri(mesh, displacement, fraction, tetTriI);
1034 refCast<const processorPolyPatch>
1046 facei_ += ppp.
start();
1068 const label sendFromPatch,
1069 const label sendToPatchFace
1091 facei_ = sendToPatchFace;
1104 const label sendToPatch
1128 "Particle crossed between " + nonConformalCyclicPolyPatch::typeName +
1130 " to a location outside of the mesh."
1171 const vector pos(coordinates_.b(), coordinates_.c(), coordinates_.d());
1175 tetFacei_ = mesh.
cells()[celli_][0];
1185 if (mesh.
moving() && stepFraction_ != 1)
1190 movingTetReverseTransform(mesh, 0, centre, detA,
T);
1191 coordinates_ += (
pos - centre[0]) &
T[0]/detA[0];
1198 stationaryTetReverseTransform(mesh, centre, detA,
T);
1199 coordinates_ += (
pos - centre) &
T/detA;
1208 const label procCell,
1209 const label procTetFace
1219 == (procMesh.
faceOwner()[procTetFace] == procCell)
1226 return procMesh.
faces()[procTetFace].
size() - 1 - tetPti_;
1244 "Particle mapped to a location outside of the mesh."
static const Foam::dimensionedScalar A("A", Foam::dimPressure, 611.21)
#define forAll(list, i)
Loop across all elements in list.
Templated 4x3 tensor derived from VectorSpace. Has 12 components. Can represent a barycentric transfo...
A 1D vector of objects of type <T> with a fixed size <Size>.
void size(const label)
Override size to be inconsistent with allocated storage.
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 replace(const direction, const Cmpt &)
Cubic equation of the form a*x^3 + b*x^2 + c*x + d = 0.
scalar value(const scalar x) const
Evaluate at x.
static int compare(const edge &, const edge &)
Compare edges.
label sendToPatch
Patch to which to send the particle.
const polyMesh & mesh
Reference to the mesh.
label sendToPatchFace
Patch face to which to send the particle.
label origProc() const
Return the originating processor ID.
scalar trackToCell(const polyMesh &mesh, const vector &displacement, const scalar fraction)
As particle::track, but stops when a new cell is reached.
void prepareForNonConformalCyclicTransfer(const polyMesh &mesh, const label sendToPatch, const label sendToPatchFace)
Make changes prior to a transfer across a non conformal cyclic.
void prepareForProcessorTransfer(trackingData &td)
Make changes prior to a transfer across a processor boundary.
particle(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label tetFacei, const label tetPti, const label facei)
Construct from components.
void correctAfterInteractionListReferral(const polyMesh &mesh, const label celli)
Correct the topology after referral. Locates the particle.
scalar track(const polyMesh &mesh, const vector &displacement, const scalar fraction)
Track along the displacement for a given fraction of the overall.
scalar trackToFace(const polyMesh &mesh, const vector &displacement, const scalar fraction)
As particle::track, but stops when a face is hit.
void prepareForInteractionListReferral(const polyMesh &mesh, const transformer &transform)
Break the topology and store the cartesian position so that the.
scalar trackToTri(const polyMesh &mesh, const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToFace, but stops when a tet triangle is hit.
scalar trackToMovingTri(const polyMesh &mesh, const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToTri, but for moving meshes.
vector deviationFromMeshCentre(const polyMesh &mesh) const
Get the displacement from the mesh centre. Used to correct the.
void correctAfterNonConformalCyclicTransfer(const polyMesh &mesh, const label sendToPatch)
Make changes following a transfer across a non conformal cyclic.
static label particleCount_
Cumulative particle counter - used to provide unique ID.
void correctAfterProcessorTransfer(trackingData &td)
Make changes following a transfer across a processor boundary.
void map(const polyMesh &mesh, const point &position, const label celli)
Map after a mesh change.
label procTetPt(const polyMesh &mesh, const polyMesh &procMesh, const label procCell, const label procTetFace) const
Return the tet point appropriate for decomposition or.
vector position(const polyMesh &mesh) const
Return current particle position.
scalar trackToStationaryTri(const polyMesh &mesh, const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToTri, but for stationary meshes.
virtual void transformProperties(const transformer &)
Transform the physical properties of the particle.
label origId() const
Return the particle ID on the originating processor.
const word & name() const
Return name.
Mesh consisting of general polyhedral cells.
virtual const faceList & faces() const
Return raw faces.
virtual const labelList & faceOwner() const
Return face owner.
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
bool moving() const
Is mesh moving.
const Vector< label > & geometricD() const
Return the vector of geometric directions in mesh.
label start() const
Return start label of this patch in the polyMesh face list.
const labelUList & faceCells() const
Return face-cell addressing.
const cellList & cells() const
Neighbour processor patch.
virtual const transformer & transform() const
Return null transform between processor patches.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar mu
Atomic mass unit.
const dimensionedScalar c
Speed of light in a vacuum.
errorManipArg< error, int > exit(error &err, const int errNo=1)
dimensionedScalar pos(const dimensionedScalar &ds)
bool operator!=(const particle &, const particle &)
Barycentric< scalar > barycentric
A scalar version of the templated Barycentric.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
tmp< fvMatrix< Type > > operator==(const fvMatrix< Type > &, const fvMatrix< Type > &)
Ostream & endl(Ostream &os)
Add newline and flush stream.
dimensionedScalar y0(const dimensionedScalar &ds)
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
void reverse(UList< T > &, const label n)
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
Vector< scalar > vector
A scalar version of the templated Vector.
dimensionSet transform(const dimensionSet &)
dimensioned< scalar > mag(const dimensioned< Type > &)
defineTypeNameAndDebug(combustionModel, 0)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
BarycentricTensor< scalar > barycentricTensor
A scalar version of the templated BarycentricTensor.
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
Cmpt cmptSum(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
word name(const complex &)
Return a string representation of a complex.
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)