1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
29 #include "wedgePolyPatch.H"
30 #include "symmetryPolyPatch.H"
31 #include "cyclicPolyPatch.H"
32 #include "processorPolyPatch.H"
33 #include "wallPolyPatch.H"
34 #include "transform.H"
36 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 template<class ParticleType>
39 void Foam::Particle<ParticleType>::findFaces
41 const vector& position,
42 DynamicList<label>& faceList
45 const polyMesh& mesh = cloud_.polyMesh_;
46 const labelList& faces = mesh.cells()[celli_];
47 const vector& C = mesh.cellCentres()[celli_];
52 label facei = faces[i];
53 scalar lam = lambda(C, position, facei);
55 if ((lam > 0) && (lam < 1.0))
57 faceList.append(facei);
63 template<class ParticleType>
64 void Foam::Particle<ParticleType>::findFaces
66 const vector& position,
68 const scalar stepFraction,
69 DynamicList<label>& faceList
72 const polyMesh& mesh = cloud_.pMesh();
73 const labelList& faces = mesh.cells()[celli];
74 const vector& C = mesh.cellCentres()[celli];
79 label facei = faces[i];
80 scalar lam = lambda(C, position, facei, stepFraction);
82 if ((lam > 0) && (lam < 1.0))
84 faceList.append(facei);
90 template<class ParticleType>
91 template<class TrackData>
92 void Foam::Particle<ParticleType>::prepareForParallelTransfer
98 // Convert the face index to be local to the processor patch
99 facei_ = patchFace(patchi, facei_);
103 template<class ParticleType>
104 template<class TrackData>
105 void Foam::Particle<ParticleType>::correctAfterParallelTransfer
111 const processorPolyPatch& ppp =
112 refCast<const processorPolyPatch>
113 (cloud_.pMesh().boundaryMesh()[patchi]);
115 celli_ = ppp.faceCells()[facei_];
119 if (ppp.forwardT().size() == 1)
121 const tensor& T = ppp.forwardT()[0];
122 transformPosition(T);
123 static_cast<ParticleType&>(*this).transformProperties(T);
127 const tensor& T = ppp.forwardT()[facei_];
128 transformPosition(T);
129 static_cast<ParticleType&>(*this).transformProperties(T);
132 else if (ppp.separated())
134 if (ppp.separation().size() == 1)
136 position_ -= ppp.separation()[0];
137 static_cast<ParticleType&>(*this).transformProperties
144 position_ -= ppp.separation()[facei_];
145 static_cast<ParticleType&>(*this).transformProperties
147 -ppp.separation()[facei_]
152 // Reset the face index for the next tracking operation
153 if (stepFraction_ > (1.0 - SMALL))
160 facei_ += ppp.start();
165 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
167 template<class ParticleType>
168 Foam::Particle<ParticleType>::Particle
170 const Cloud<ParticleType>& cloud,
171 const vector& position,
180 origProc_(Pstream::myProcNo()),
181 origId_(cloud_.getNewParticleID())
185 template<class ParticleType>
186 Foam::Particle<ParticleType>::Particle(const Particle<ParticleType>& p)
188 IDLList<ParticleType>::link(),
190 position_(p.position_),
193 stepFraction_(p.stepFraction_),
194 origProc_(p.origProc_),
199 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
201 template<class ParticleType>
202 template<class TrackData>
203 Foam::label Foam::Particle<ParticleType>::track
205 const vector& endPosition,
211 // Tracks to endPosition or stop on boundary
212 while(!onBoundary() && stepFraction_ < 1.0 - SMALL)
214 stepFraction_ += trackToFace(endPosition, td)*(1.0 - stepFraction_);
222 template<class ParticleType>
223 Foam::label Foam::Particle<ParticleType>::track(const vector& endPosition)
226 return track(endPosition, dummyTd);
229 template<class ParticleType>
230 template<class TrackData>
231 Foam::scalar Foam::Particle<ParticleType>::trackToFace
233 const vector& endPosition,
237 const polyMesh& mesh = cloud_.polyMesh_;
239 DynamicList<label>& faces = cloud_.labels_;
240 findFaces(endPosition, faces);
243 scalar trackFraction = 0.0;
245 if (faces.empty()) // inside cell
248 position_ = endPosition;
252 scalar lambdaMin = GREAT;
254 if (faces.size() == 1)
256 lambdaMin = lambda(position_, endPosition, faces[0], stepFraction_);
261 // If the particle has to cross more than one cell to reach the
262 // endPosition, we check which way to go.
263 // If one of the faces is a boundary face and the particle is
264 // outside, we choose the boundary face.
265 // The particle is outside if one of the lambda's is > 1 or < 0
269 lambda(position_, endPosition, faces[i], stepFraction_);
279 bool internalFace = cloud_.internalFace(facei_);
281 // For warped faces the particle can be 'outside' the cell.
282 // This will yield a lambda larger than 1, or smaller than 0
283 // For values < 0, the particle travels away from the cell
284 // and we don't move the particle, only change cell.
285 // For values larger than 1, we move the particle to endPosition only.
288 if (lambdaMin <= 1.0)
290 trackFraction = lambdaMin;
291 position_ += trackFraction*(endPosition - position_);
296 position_ = endPosition;
299 else if (static_cast<ParticleType&>(*this).softImpact())
301 // Soft-sphere particles can travel outside the domain
302 // but we don't use lambda since this the particle
303 // is going away from face
305 position_ = endPosition;
309 if (internalFace) // Internal face
311 if (celli_ == mesh.faceOwner()[facei_])
313 celli_ = mesh.faceNeighbour()[facei_];
315 else if (celli_ == mesh.faceNeighbour()[facei_])
317 celli_ = mesh.faceOwner()[facei_];
323 "Particle::trackToFace(const vector&, TrackData&)"
324 )<< "addressing failure" << nl
325 << abort(FatalError);
330 ParticleType& p = static_cast<ParticleType&>(*this);
332 // Soft-sphere algorithm ignores the boundary
336 position_ = endPosition;
339 label patchi = patch(facei_);
340 const polyPatch& patch = mesh.boundaryMesh()[patchi];
342 if (!p.hitPatch(patch, td, patchi))
344 if (isA<wedgePolyPatch>(patch))
348 static_cast<const wedgePolyPatch&>(patch), td
351 else if (isA<symmetryPolyPatch>(patch))
355 static_cast<const symmetryPolyPatch&>(patch), td
358 else if (isA<cyclicPolyPatch>(patch))
362 static_cast<const cyclicPolyPatch&>(patch), td
365 else if (isA<processorPolyPatch>(patch))
369 static_cast<const processorPolyPatch&>(patch), td
372 else if (isA<wallPolyPatch>(patch))
376 static_cast<const wallPolyPatch&>(patch), td
381 p.hitPatch(patch, td);
387 // If the trackFraction = 0 something went wrong.
388 // Either the particle is flipping back and forth across a face perhaps
389 // due to velocity interpolation errors or it is in a "hole" in the mesh
390 // caused by face warpage.
391 // In both cases resolve the positional ambiguity by moving the particle
392 // slightly towards the cell-centre.
393 if (trackFraction < SMALL)
395 position_ += 1.0e-3*(mesh.cellCentres()[celli_] - position_);
398 return trackFraction;
401 template<class ParticleType>
402 Foam::scalar Foam::Particle<ParticleType>::trackToFace
404 const vector& endPosition
408 return trackToFace(endPosition, dummyTd);
411 template<class ParticleType>
412 void Foam::Particle<ParticleType>::transformPosition(const tensor& T)
414 position_ = transform(T, position_);
418 template<class ParticleType>
419 void Foam::Particle<ParticleType>::transformProperties(const tensor&)
423 template<class ParticleType>
424 void Foam::Particle<ParticleType>::transformProperties(const vector&)
428 template<class ParticleType>
429 template<class TrackData>
430 bool Foam::Particle<ParticleType>::hitPatch
441 template<class ParticleType>
442 template<class TrackData>
443 void Foam::Particle<ParticleType>::hitWedgePatch
445 const wedgePolyPatch& wpp,
449 vector nf = wpp.faceAreas()[wpp.whichFace(facei_)];
452 static_cast<ParticleType&>(*this).transformProperties(I - 2.0*nf*nf);
456 template<class ParticleType>
457 template<class TrackData>
458 void Foam::Particle<ParticleType>::hitSymmetryPatch
460 const symmetryPolyPatch& spp,
464 vector nf = spp.faceAreas()[spp.whichFace(facei_)];
467 static_cast<ParticleType&>(*this).transformProperties(I - 2.0*nf*nf);
471 template<class ParticleType>
472 template<class TrackData>
473 void Foam::Particle<ParticleType>::hitCyclicPatch
475 const cyclicPolyPatch& cpp,
479 label patchFacei_ = cpp.whichFace(facei_);
481 facei_ = cpp.transformGlobalFace(facei_);
483 celli_ = cloud_.polyMesh_.faceOwner()[facei_];
487 const tensor& T = cpp.transformT(patchFacei_);
489 transformPosition(T);
490 static_cast<ParticleType&>(*this).transformProperties(T);
492 else if (cpp.separated())
494 position_ += cpp.separation(patchFacei_);
495 static_cast<ParticleType&>(*this).transformProperties
497 cpp.separation(patchFacei_)
503 template<class ParticleType>
504 template<class TrackData>
505 void Foam::Particle<ParticleType>::hitProcessorPatch
507 const processorPolyPatch& spp,
513 template<class ParticleType>
514 template<class TrackData>
515 void Foam::Particle<ParticleType>::hitWallPatch
517 const wallPolyPatch& spp,
523 template<class ParticleType>
524 template<class TrackData>
525 void Foam::Particle<ParticleType>::hitPatch
527 const polyPatch& spp,
533 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
535 #include "ParticleIO.C"
537 // ************************************************************************* //