34 const Foam::label Foam::particle::maxNTracksBehind_ = 48;
46 void Foam::particle::stationaryTetReverseTransform
55 const vector ab = A.b() - A.a();
56 const vector ac = A.c() - A.a();
57 const vector ad = A.d() - A.a();
58 const vector bc = A.c() - A.b();
59 const vector bd = A.d() - A.b();
63 detA = ab & (ac ^ ad);
75 void Foam::particle::movingTetReverseTransform
77 const scalar fraction,
79 FixedList<scalar, 4>& detA,
80 FixedList<barycentricTensor, 3>& T
83 Pair<barycentricTensor> A = movingTetTransform(fraction);
85 const Pair<vector> ab(A[0].
b() - A[0].a(), A[1].
b() - A[1].a());
86 const Pair<vector> ac(A[0].
c() - A[0].a(), A[1].
c() - A[1].a());
87 const Pair<vector> ad(A[0].d() - A[0].a(), A[1].d() - A[1].a());
88 const Pair<vector> bc(A[0].
c() - A[0].
b(), A[1].
c() - A[1].
b());
89 const Pair<vector> bd(A[0].d() - A[0].
b(), A[1].d() - A[1].
b());
94 detA[0] = ab[0] & (ac[0] ^ ad[0]);
96 (ab[1] & (ac[0] ^ ad[0]))
97 + (ab[0] & (ac[1] ^ ad[0]))
98 + (ab[0] & (ac[0] ^ ad[1]));
100 (ab[0] & (ac[1] ^ ad[1]))
101 + (ab[1] & (ac[0] ^ ad[1]))
102 + (ab[1] & (ac[1] ^ ad[0]));
103 detA[3] = ab[1] & (ac[1] ^ ad[1]);
114 (bd[0] ^ bc[1]) + (bd[1] ^ bc[0]),
115 (ac[0] ^ ad[1]) + (ac[1] ^ ad[0]),
116 (ad[0] ^ ab[1]) + (ad[1] ^ ab[0]),
117 (ab[0] ^ ac[1]) + (ab[1] ^ ac[0])
129 void Foam::particle::reflect()
131 Swap(coordinates_.c(), coordinates_.d());
135 void Foam::particle::rotate(
const bool reverse)
139 scalar temp = coordinates_.b();
140 coordinates_.b() = coordinates_.c();
141 coordinates_.c() = coordinates_.d();
142 coordinates_.d() = temp;
146 scalar temp = coordinates_.d();
147 coordinates_.d() = coordinates_.c();
148 coordinates_.c() = coordinates_.b();
149 coordinates_.b() = temp;
154 void Foam::particle::changeTet(
const label tetTriI)
161 const bool isOwner = mesh_.faceOwner()[tetFacei_] == celli_;
163 const label firstTetPtI = 1;
164 const label lastTetPtI = mesh_.faces()[tetFacei_].size() - 2;
170 else if (tetTriI == 2)
174 if (tetPti_ == lastTetPtI)
186 if (tetPti_ == firstTetPtI)
197 else if (tetTriI == 3)
201 if (tetPti_ == firstTetPtI)
213 if (tetPti_ == lastTetPtI)
227 <<
"Changing tet without changing cell should only happen when the " 228 <<
"track is on triangle 1, 2 or 3." 234 void Foam::particle::changeFace(
const label tetTriI)
242 const triFace triOldIs(currentTetIndices().faceTriIs(mesh_));
248 sharedEdge = edge(triOldIs[1], triOldIs[2]);
250 else if (tetTriI == 2)
252 sharedEdge = edge(triOldIs[2], triOldIs[0]);
254 else if (tetTriI == 3)
256 sharedEdge = edge(triOldIs[0], triOldIs[1]);
261 <<
"Changing face without changing cell should only happen when the" 262 <<
" track is on triangle 1, 2 or 3." 265 sharedEdge = edge(-1, -1);
271 forAll(mesh_.cells()[celli_], cellFaceI)
273 const label newFaceI = mesh_.cells()[celli_][cellFaceI];
274 const class face& newFace = mesh_.faces()[newFaceI];
275 const label newOwner = mesh_.faceOwner()[newFaceI];
278 if (tetFacei_ == newFaceI)
284 const label edgeComp = newOwner == celli_ ? -1 : +1;
289 edgeI < newFace.size()
290 &&
edge::compare(sharedEdge, newFace.faceEdge(edgeI)) != edgeComp;
295 if (edgeI >= newFace.size())
301 const label newBaseI =
max(0, mesh_.tetBasePtIs()[newFaceI]);
302 edgeI = (edgeI - newBaseI + newFace.size()) % newFace.size();
307 edgeI =
min(
max(1, edgeI), newFace.size() - 2);
310 tetFacei_ = newFaceI;
320 <<
"The search for an edge-connected face and tet-point failed." 325 if (sharedEdge.otherVertex(triOldIs[1]) == -1)
329 else if (sharedEdge.otherVertex(triOldIs[2]) == -1)
335 const triFace triNewIs = currentTetIndices().faceTriIs(mesh_);
341 if (sharedEdge.otherVertex(triNewIs[1]) == -1)
345 else if (sharedEdge.otherVertex(triNewIs[2]) == -1)
352 void Foam::particle::changeCell()
360 const label ownerCellI = mesh_.faceOwner()[tetFacei_];
361 const bool isOwner = celli_ == ownerCellI;
362 celli_ = isOwner ? mesh_.faceNeighbour()[tetFacei_] : ownerCellI;
369 void Foam::particle::locate
373 const bool boundaryFail,
374 const string boundaryMsg
385 celli = mesh_.cellTree().findInside(position);
390 <<
"Cell not found for particle position " << position <<
"." 396 const vector displacement = position - mesh_.cellCentres()[celli_];
401 const class cell& c = mesh_.cells()[celli_];
402 scalar minF = vGreat;
403 label minTetFacei = -1, minTetPti = -1;
406 const class face& f = mesh_.faces()[c[cellTetFacei]];
407 for (
label tetPti = 1; tetPti < f.size() - 1; ++ tetPti)
410 tetFacei_ = c[cellTetFacei];
416 const scalar f = trackToTri(displacement, 0, tetTriI);
426 minTetFacei = tetFacei_;
435 tetFacei_ = minTetFacei;
440 track(displacement, 0);
453 static label nWarnings = 0;
454 static const label maxNWarnings = 100;
455 if (nWarnings < maxNWarnings)
460 if (nWarnings == maxNWarnings)
463 <<
"Suppressing any further warnings about particles being " 464 <<
"located outside of the mesh." <<
endl;
478 const label tetFacei,
483 coordinates_(coordinates),
489 stepFractionBehind_(0),
492 origId_(getNewParticleID())
504 coordinates_(- vGreat, - vGreat, - vGreat, - vGreat),
510 stepFractionBehind_(0),
513 origId_(getNewParticleID())
520 "Particle initialised with a location outside of the mesh." 528 coordinates_(p.coordinates_),
530 tetFacei_(p.tetFacei_),
533 stepFraction_(p.stepFraction_),
534 stepFractionBehind_(p.stepFractionBehind_),
535 nTracksBehind_(p.nTracksBehind_),
536 origProc_(p.origProc_),
544 coordinates_(p.coordinates_),
546 tetFacei_(p.tetFacei_),
549 stepFraction_(p.stepFraction_),
550 stepFractionBehind_(p.stepFractionBehind_),
551 nTracksBehind_(p.nTracksBehind_),
552 origProc_(p.origProc_),
561 const vector& displacement,
562 const scalar fraction
585 const vector& displacement,
586 const scalar fraction
594 const scalar f =
trackToFace(displacement, fraction);
607 const vector& displacement,
608 const scalar fraction
623 while (nTracksBehind_ < maxNTracksBehind_)
625 f *=
trackToTri(f*displacement, f*fraction, tetTriI);
632 else if (tetTriI == 0)
647 <<
"Particle #" << origId_ <<
" got stuck at " <<
position() <<
endl;
649 stepFraction_ += f*fraction;
651 stepFractionBehind_ = 0;
660 const vector& displacement,
661 const scalar fraction,
666 const vector x1 = displacement;
672 <<
" along " << x1 <<
" to " << x0 + x1 <<
endl;
679 stationaryTetReverseTransform(centre, detA, T);
684 stationaryTetGeometry(o, b, v1, v2);
685 Info<<
"Tet points o=" << o <<
", b=" << b
686 <<
", v1=" << v1 <<
", v2=" << v2 <<
endl 687 <<
"Tet determinant = " << detA <<
endl 688 <<
"Start local coordinates = " << y0 <<
endl;
696 Info<<
"Local displacement = " << Tx1 <<
"/" << detA <<
endl;
701 scalar muH = detA > vSmall ? 1/detA : vGreat;
702 for (
label i = 0; i < 4; ++ i)
704 if (Tx1[i] < - vSmall && Tx1[i] < -
mag(detA)*small)
706 scalar
mu = - y0[i]/Tx1[i];
710 Info<<
"Hit on tet face " << i <<
" at local coordinate " 711 << y0 + mu*Tx1 <<
", " << mu*detA*100 <<
"% of the " 712 <<
"way along the track" <<
endl;
715 if (0 <= mu && mu < muH)
726 if (iH == -1 && muH == vGreat)
728 stepFraction_ += fraction;
736 for (
label i = 0; i < 4; ++ i)
752 stepFraction_ += fraction*muH*detA;
758 Info<<
"Track hit tet face " << iH <<
" first" <<
endl;
762 Info<<
"Track hit no tet faces" <<
endl;
764 Info<<
"End local coordinates = " << yH <<
endl 766 <<
"Tracking displacement = " <<
position() - x0 <<
endl 767 << muH*detA*100 <<
"% of the step from " 768 << stepFraction_ - fraction*muH*detA <<
" to " 769 << stepFraction_ - fraction*muH*detA + fraction
774 if (muH*detA < small || nTracksBehind_ > 0)
776 stepFractionBehind_ += (fraction != 0 ? fraction : 1)*muH*detA;
778 if (stepFractionBehind_ > rootSmall)
780 stepFractionBehind_ = 0;
789 return iH != -1 ? 1 - muH*detA : 0;
795 const vector& displacement,
796 const scalar fraction,
801 const vector x1 = displacement;
807 <<
" along " << x1 <<
" to " << x0 + x1 <<
endl;
814 movingTetReverseTransform(fraction, centre, detA, T);
819 movingTetGeometry(fraction, o, b, v1, v2);
820 Info<<
"Tet points o=" << o[0] <<
", b=" << b[0]
821 <<
", v1=" << v1[0] <<
", v2=" << v2[0] <<
endl 822 <<
"Tet determinant = " << detA[0] <<
endl 823 <<
"Start local coordinates = " << y0[0] <<
endl;
827 const vector x0Rel = x0 - centre[0];
828 const vector x1Rel = x1 - centre[1];
831 cubicEqn detAEqn(
sqr(detA[0])*detA[3], detA[0]*detA[2], detA[1], 1);
834 ((x1Rel & T[2]) + detA[3]*yC)*
sqr(detA[0]);
836 ((x1Rel & T[1]) + (x0Rel & T[2]) + detA[2]*yC)*detA[0];
838 ((x1Rel & T[0]) + (x0Rel & T[1]) + detA[1]*yC);
843 hitEqn[i] =
cubicEqn(hitEqnA[i], hitEqnB[i], hitEqnC[i], hitEqnD[i]);
848 for (
label i = 0; i < 4; ++ i)
850 Info<< (i ?
" " :
"Hit equation ") << i <<
" = " 851 << hitEqn[i] <<
endl;
853 Info<<
" DetA equation = " << detA <<
endl;
858 scalar muH = detA[0] > vSmall ? 1/detA[0] : vGreat;
859 for (
label i = 0; i < 4; ++ i)
863 for (
label j = 0; j < 3; ++ j)
868 && hitEqn[i].derivative(mu[j]) < - vSmall
869 && hitEqn[i].derivative(mu[j]) < -
mag(detA[0])*small
876 hitEqn[0].value(mu[j]),
877 hitEqn[1].value(mu[j]),
878 hitEqn[2].value(mu[j]),
879 hitEqn[3].value(mu[j])
881 const scalar detAH = detAEqn.
value(mu[j]);
883 Info<<
"Hit on tet face " << i <<
" at local coordinate " 884 << (
mag(detAH) > vSmall ?
name(yH/detAH) :
"???")
885 <<
", " << mu[j]*detA[0]*100 <<
"% of the " 886 <<
"way along the track" <<
endl;
889 if (0 <= mu[j] && mu[j] < muH)
901 if (iH == -1 && muH == vGreat)
903 stepFraction_ += fraction;
910 hitEqn[0].value(muH),
911 hitEqn[1].value(muH),
912 hitEqn[2].value(muH),
922 const scalar detAH = detAEqn.
value(muH);
923 if (
mag(detAH) < vSmall)
926 <<
"A moving tet collapsed onto a particle. This is not supported. " 927 <<
"The mesh is too poor, or the motion too severe, for particle " 933 for (
label i = 0; i < 4; ++ i)
949 stepFraction_ += fraction*muH*detA[0];
955 Info<<
"Track hit tet face " << iH <<
" first" <<
endl;
959 Info<<
"Track hit no tet faces" <<
endl;
961 Info<<
"End local coordinates = " << yH <<
endl 963 <<
"Tracking displacement = " <<
position() - x0 <<
endl 964 << muH*detA[0]*100 <<
"% of the step from " 965 << stepFraction_ - fraction*muH*detA[0] <<
" to " 966 << stepFraction_ - fraction*muH*detA[0] + fraction
971 if (muH*detA[0] < small || nTracksBehind_ > 0)
973 stepFractionBehind_ += (fraction != 0 ? fraction : 1)*muH*detA[0];
975 if (stepFractionBehind_ > rootSmall)
977 stepFractionBehind_ = 0;
986 return iH != -1 ? 1 - muH*detA[0] : 0;
992 const vector& displacement,
993 const scalar fraction,
997 if (mesh_.
moving() && (stepFraction_ != 1 || fraction != 0))
1051 if (isA<processorPolyPatch>(pp))
1055 else if (isA<nonConformalCyclicPolyPatch>(pp))
1062 <<
"Transfer patch type not recognised" 1087 facei_ += ppp.
start();
1094 tetPti_ = mesh_.
faces()[tetFacei_].
size() - 1 - tetPti_;
1108 const label sendFromPatch,
1109 const label sendToPatchFace
1128 facei_ = sendToPatchFace;
1140 const label sendToPatch
1161 "Particle crossed between " + nonConformalCyclicPolyPatch::typeName +
1163 " to a location outside of the mesh." 1199 const vector pos(coordinates_.
b(), coordinates_.
c(), coordinates_.
d());
1203 tetFacei_ = mesh_.
cells()[celli_][0];
1213 if (mesh_.
moving() && stepFraction_ != 1)
1218 movingTetReverseTransform(0, centre, detA, T);
1219 coordinates_ += (
pos - centre[0]) & T[0]/detA[0];
1226 stationaryTetReverseTransform(centre, detA, T);
1227 coordinates_ += (
pos - centre) & T/detA;
1235 const label procCell,
1236 const label procTetFace
1245 (mesh_.
faceOwner()[tetFacei_] == celli_)
1246 == (procMesh.
faceOwner()[procTetFace] == procCell)
1253 return procMesh.
faces()[procTetFace].
size() - 1 - tetPti_;
1269 "Particle mapped to a location outside of the mesh."
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
label origProc() const
Return the originating processor ID.
#define forAll(list, i)
Loop across all elements in list.
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
const word & name() const
Return name.
vector deviationFromMeshCentre() const
Get the displacement from the mesh centre. Used to correct the.
bool moving() const
Is mesh moving.
errorManipArg< error, int > exit(error &err, const int errNo=1)
void prepareForProcessorTransfer(trackingData &td)
Make changes prior to a transfer across a processor boundary.
A 1D vector of objects of type <T> with a fixed size <Size>.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
label procTetPt(const polyMesh &procMesh, const label procCell, const label procTetFace) const
Return the tet point appropriate for decomposition or reconstruction.
void correctAfterParallelTransfer(trackingData &td)
Make changes following a parallel transfer. Runs either processor.
void correctAfterNonConformalCyclicTransfer(const label sendToPatch)
Make changes following a transfer across a non conformal cyclic.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
scalar trackToFace(const vector &displacement, const scalar fraction)
As particle::track, but stops when a face is hit.
void size(const label)
Override size to be inconsistent with allocated storage.
static int compare(const edge &, const edge &)
Compare edges.
scalar trackToTri(const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToFace, but stops when a tet triangle is hit. On.
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Cmpt cmptSum(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
void autoMap(const vector &position, const polyTopoChangeMap &mapper)
Map after a topology change.
const dimensionedScalar b
Wien displacement law constant: default SI units: [m K].
Ostream & endl(Ostream &os)
Add newline and flush stream.
dimensionedScalar y0(const dimensionedScalar &ds)
Templated storage for the roots of polynomial equations, plus flags to indicate the nature of the roo...
const cellList & cells() const
virtual const transformer & transform() const
Return transformation between the coupled patches.
Vector< scalar > vector
A scalar version of the templated Vector.
Barycentric< scalar > barycentric
A scalar version of the templated Barycentric.
void replace(const direction, const Cmpt &)
scalar trackToCell(const vector &displacement, const scalar fraction)
As particle::track, but stops when a new cell is reached.
label sendFromPatch
Patch from which to send the particle.
virtual void transformProperties(const transformer &)
Transform the physical properties of the particle.
const dimensionedScalar c
Speed of light in a vacuum.
Neighbour processor patch.
const Vector< label > & geometricD() const
Return the vector of geometric directions in mesh.
dimensionedScalar pos(const dimensionedScalar &ds)
Cubic equation of the form a*x^3 + b*x^2 + c*x + d = 0.
void prepareForInteractionListReferral(const transformer &transform)
Break the topology and store the cartesian position so that the.
An ordered pair of two objects of type <T> with first() and second() elements.
const labelUList & faceCells() const
Return face-cell addressing.
tmp< fvMatrix< Type > > operator==(const fvMatrix< Type > &, const fvMatrix< Type > &)
void prepareForParallelTransfer(trackingData &td)
Make changes prior to a parallel transfer. Runs either processor or.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
particle(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label tetFacei, const label tetPti)
Construct from components.
void correctAfterInteractionListReferral(const label celli)
Correct the topology after referral. Locates the particle relative.
virtual const labelList & faceOwner() const
Return face owner.
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
virtual const faceList & faces() const
Return raw faces.
label origId() const
Return the particle ID on the originating processor.
const dimensionedScalar mu
Atomic mass unit.
bool onFace() const
Is the particle on a face?
defineTypeNameAndDebug(combustionModel, 0)
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
const labelList & reverseCellMap() const
Reverse cell map.
BarycentricTensor< scalar > barycentricTensor
A scalar version of the templated BarycentricTensor.
word name(const complex &)
Return a string representation of a complex.
scalar trackToMovingTri(const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToTri, but for moving meshes.
virtual const transformer & transform() const
Return null transform between processor patches.
label sendToPatch
Patch to which to send the particle.
void correctAfterProcessorTransfer(trackingData &td)
Make changes following a transfer across a processor boundary.
#define WarningInFunction
Report a warning using Foam::Warning.
label start() const
Return start label of this patch in the polyMesh face list.
Templated 4x3 tensor derived from VectorSpace. Has 12 components. Can represent a barycentric transfo...
dimensioned< scalar > mag(const dimensioned< Type > &)
void prepareForNonConformalCyclicTransfer(const label sendToPatch, const label sendToPatchFace)
Make changes prior to a transfer across a non conformal cyclic.
bool onInternalFace() const
Is the particle on an internal face?
Mesh consisting of general polyhedral cells.
scalar trackToStationaryTri(const vector &displacement, const scalar fraction, label &tetTriI)
As particle::trackToTri, but for stationary meshes.
A patch is a list of labels that address the faces in the global face list.
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
scalar track(const vector &displacement, const scalar fraction)
Track along the displacement for a given fraction of the overall.
bool operator!=(const particle &, const particle &)
scalar value(const scalar x) const
Evaluate at x.
vector position() const
Return current particle position.
static const Vector< scalar > zero
label patch() const
Return the index of patch that the particle is on.
void type(const direction i, const rootType t)
Set the type of the i-th root.
label sendToPatchFace
Patch face to which to send the particle.