1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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)
189 position_(p.position_),
192 stepFraction_(p.stepFraction_),
193 origProc_(p.origProc_),
198 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
200 template<class ParticleType>
201 template<class TrackData>
202 Foam::label Foam::Particle<ParticleType>::track
204 const vector& endPosition,
210 // Tracks to endPosition or stop on boundary
211 while(!onBoundary() && stepFraction_ < 1.0 - SMALL)
213 stepFraction_ += trackToFace(endPosition, td)*(1.0 - stepFraction_);
221 template<class ParticleType>
222 Foam::label Foam::Particle<ParticleType>::track(const vector& endPosition)
225 return track(endPosition, dummyTd);
228 template<class ParticleType>
229 template<class TrackData>
230 Foam::scalar Foam::Particle<ParticleType>::trackToFace
232 const vector& endPosition,
236 const polyMesh& mesh = cloud_.polyMesh_;
238 DynamicList<label>& faces = cloud_.labels_;
239 findFaces(endPosition, faces);
242 scalar trackFraction = 0.0;
244 if (faces.empty()) // inside cell
247 position_ = endPosition;
251 scalar lambdaMin = GREAT;
253 if (faces.size() == 1)
255 lambdaMin = lambda(position_, endPosition, faces[0], stepFraction_);
260 // If the particle has to cross more than one cell to reach the
261 // endPosition, we check which way to go.
262 // If one of the faces is a boundary face and the particle is
263 // outside, we choose the boundary face.
264 // The particle is outside if one of the lambda's is > 1 or < 0
268 lambda(position_, endPosition, faces[i], stepFraction_);
278 bool internalFace = cloud_.internalFace(facei_);
280 // For warped faces the particle can be 'outside' the cell.
281 // This will yield a lambda larger than 1, or smaller than 0
282 // For values < 0, the particle travels away from the cell
283 // and we don't move the particle, only change cell.
284 // For values larger than 1, we move the particle to endPosition only.
287 if (lambdaMin <= 1.0)
289 trackFraction = lambdaMin;
290 position_ += trackFraction*(endPosition - position_);
295 position_ = endPosition;
298 else if (static_cast<ParticleType&>(*this).softImpact())
300 // Soft-sphere particles can travel outside the domain
301 // but we don't use lambda since this the particle
302 // is going away from face
304 position_ = endPosition;
308 if (internalFace) // Internal face
310 if (celli_ == mesh.faceOwner()[facei_])
312 celli_ = mesh.faceNeighbour()[facei_];
314 else if (celli_ == mesh.faceNeighbour()[facei_])
316 celli_ = mesh.faceOwner()[facei_];
322 "Particle::trackToFace(const vector&, TrackData&)"
323 )<< "addressing failure" << nl
324 << abort(FatalError);
329 ParticleType& p = static_cast<ParticleType&>(*this);
331 // Soft-sphere algorithm ignores the boundary
335 position_ = endPosition;
338 label patchi = patch(facei_);
339 const polyPatch& patch = mesh.boundaryMesh()[patchi];
341 if (!p.hitPatch(patch, td, patchi))
343 if (isA<wedgePolyPatch>(patch))
347 static_cast<const wedgePolyPatch&>(patch), td
350 else if (isA<symmetryPolyPatch>(patch))
354 static_cast<const symmetryPolyPatch&>(patch), td
357 else if (isA<cyclicPolyPatch>(patch))
361 static_cast<const cyclicPolyPatch&>(patch), td
364 else if (isA<processorPolyPatch>(patch))
368 static_cast<const processorPolyPatch&>(patch), td
371 else if (isA<wallPolyPatch>(patch))
375 static_cast<const wallPolyPatch&>(patch), td
380 p.hitPatch(patch, td);
386 // If the trackFraction = 0 something went wrong.
387 // Either the particle is flipping back and forth across a face perhaps
388 // due to velocity interpolation errors or it is in a "hole" in the mesh
389 // caused by face warpage.
390 // In both cases resolve the positional ambiguity by moving the particle
391 // slightly towards the cell-centre.
392 if (trackFraction < SMALL)
394 position_ += 1.0e-3*(mesh.cellCentres()[celli_] - position_);
397 return trackFraction;
400 template<class ParticleType>
401 Foam::scalar Foam::Particle<ParticleType>::trackToFace
403 const vector& endPosition
407 return trackToFace(endPosition, dummyTd);
410 template<class ParticleType>
411 void Foam::Particle<ParticleType>::transformPosition(const tensor& T)
413 position_ = transform(T, position_);
417 template<class ParticleType>
418 void Foam::Particle<ParticleType>::transformProperties(const tensor&)
422 template<class ParticleType>
423 void Foam::Particle<ParticleType>::transformProperties(const vector&)
427 template<class ParticleType>
428 template<class TrackData>
429 bool Foam::Particle<ParticleType>::hitPatch
440 template<class ParticleType>
441 template<class TrackData>
442 void Foam::Particle<ParticleType>::hitWedgePatch
444 const wedgePolyPatch& wpp,
448 vector nf = wpp.faceAreas()[wpp.whichFace(facei_)];
451 static_cast<ParticleType&>(*this).transformProperties(I - 2.0*nf*nf);
455 template<class ParticleType>
456 template<class TrackData>
457 void Foam::Particle<ParticleType>::hitSymmetryPatch
459 const symmetryPolyPatch& spp,
463 vector nf = spp.faceAreas()[spp.whichFace(facei_)];
466 static_cast<ParticleType&>(*this).transformProperties(I - 2.0*nf*nf);
470 template<class ParticleType>
471 template<class TrackData>
472 void Foam::Particle<ParticleType>::hitCyclicPatch
474 const cyclicPolyPatch& cpp,
478 label patchFacei_ = cpp.whichFace(facei_);
480 facei_ = cpp.transformGlobalFace(facei_);
482 celli_ = cloud_.polyMesh_.faceOwner()[facei_];
486 const tensor& T = cpp.transformT(patchFacei_);
488 transformPosition(T);
489 static_cast<ParticleType&>(*this).transformProperties(T);
491 else if (cpp.separated())
493 position_ += cpp.separation(patchFacei_);
494 static_cast<ParticleType&>(*this).transformProperties
496 cpp.separation(patchFacei_)
502 template<class ParticleType>
503 template<class TrackData>
504 void Foam::Particle<ParticleType>::hitProcessorPatch
506 const processorPolyPatch& spp,
512 template<class ParticleType>
513 template<class TrackData>
514 void Foam::Particle<ParticleType>::hitWallPatch
516 const wallPolyPatch& spp,
522 template<class ParticleType>
523 template<class TrackData>
524 void Foam::Particle<ParticleType>::hitPatch
526 const polyPatch& spp,
532 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
534 #include "ParticleIO.C"
536 // ************************************************************************* //