1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36 template<class ParticleType>
37 inline scalar Particle<ParticleType>::lambda
42 const scalar stepFraction
45 const polyMesh& mesh = cloud_.polyMesh_;
46 bool movingMesh = mesh.moving();
50 vector Sf = mesh.faceAreas()[facei];
52 vector Cf = mesh.faceCentres()[facei];
54 // move reference point for wall
55 if (!cloud_.internalFace(facei))
57 const vector& C = mesh.cellCentres()[celli_];
58 scalar CCf = mag((C - Cf) & Sf);
59 // check if distance between cell centre and face centre
60 // is larger than wallImpactDistance
64 > static_cast<const ParticleType&>(*this).wallImpactDistance(Sf)
67 Cf -= static_cast<const ParticleType&>(*this)
68 .wallImpactDistance(Sf)*Sf;
72 // for a moving mesh we need to reconstruct the old
73 // Sf and Cf from oldPoints (they aren't stored)
75 const vectorField& oldPoints = mesh.oldPoints();
77 vector Cf00 = mesh.faces()[facei].centre(oldPoints);
78 vector Cf0 = Cf00 + stepFraction*(Cf - Cf00);
80 vector Sf00 = mesh.faces()[facei].normal(oldPoints);
82 // for layer addition Sf00 = vector::zero and we use Sf
83 if (mag(Sf00) > SMALL)
92 scalar magSfDiff = mag(Sf - Sf00);
94 // check if the face is rotating
95 if (magSfDiff > SMALL)
97 vector Sf0 = Sf00 + stepFraction*(Sf - Sf00);
99 // find center of rotation
100 vector omega = Sf0 ^ Sf;
101 scalar magOmega = mag(omega);
102 omega /= magOmega + SMALL;
103 vector n0 = omega ^ Sf0;
104 scalar lam = ((Cf - Cf0) & Sf)/(n0 & Sf);
105 vector r0 = Cf0 + lam*n0;
107 // solve '(p - r0) & Sfp = 0', where
108 // p = from + lambda*(to - from)
109 // Sfp = Sf0 + lambda*(Sf - Sf0)
110 // which results in the quadratic eq.
111 // a*lambda^2 + b*lambda + c = 0
112 vector alpha = from - r0;
113 vector beta = to - from;
114 scalar a = beta & (Sf - Sf0);
115 scalar b = (alpha & (Sf - Sf0)) + (beta & Sf0);
116 scalar c = alpha & Sf0;
120 // solve the second order polynomial
123 scalar cp = ap*ap - 4.0*bp;
127 // imaginary roots only
132 scalar l1 = -0.5*(ap - ::sqrt(cp));
133 scalar l2 = -0.5*(ap + ::sqrt(cp));
135 // one root is around 0-1, while
136 // the other is very large in mag
137 if (mag(l1) < mag(l2))
149 // when a==0, solve the first order polynomial
155 vector alpha = from - Cf0;
156 vector beta = to - from - (Cf - Cf0);
157 scalar lambdaNominator = alpha & Sf;
158 scalar lambdaDenominator = beta & Sf;
160 // check if trajectory is parallel to face
161 if (mag(lambdaDenominator) < SMALL)
163 if (lambdaDenominator < 0.0)
165 lambdaDenominator = -SMALL;
169 lambdaDenominator = SMALL;
173 return (-lambdaNominator/lambdaDenominator);
178 // mesh is static and stepFraction is not needed
179 return lambda(from, to, facei);
184 template<class ParticleType>
185 inline scalar Particle<ParticleType>::lambda
192 const polyMesh& mesh = cloud_.polyMesh_;
194 vector Sf = mesh.faceAreas()[facei];
196 vector Cf = mesh.faceCentres()[facei];
198 // move reference point for wall
199 if (!cloud_.internalFace(facei))
201 const vector& C = mesh.cellCentres()[celli_];
202 scalar CCf = mag((C - Cf) & Sf);
203 // check if distance between cell centre and face centre
204 // is larger than wallImpactDistance
208 > static_cast<const ParticleType&>(*this).wallImpactDistance(Sf)
211 Cf -= static_cast<const ParticleType&>(*this)
212 .wallImpactDistance(Sf)*Sf;
216 scalar lambdaNominator = (Cf - from) & Sf;
217 scalar lambdaDenominator = (to - from) & Sf;
219 // check if trajectory is parallel to face
220 if (mag(lambdaDenominator) < SMALL)
222 if (lambdaDenominator < 0.0)
224 lambdaDenominator = -SMALL;
228 lambdaDenominator = SMALL;
232 return lambdaNominator/lambdaDenominator;
236 template<class ParticleType>
237 inline bool Particle<ParticleType>::inCell() const
239 labelList faces = findFaces(position_);
241 return (!faces.size());
245 template<class ParticleType>
246 inline bool Particle<ParticleType>::inCell
248 const vector& position,
250 const scalar stepFraction
253 labelList faces = findFaces(position, celli, stepFraction);
255 return (!faces.size());
259 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
261 template<class ParticleType>
262 inline Particle<ParticleType>::trackData::trackData
264 Cloud<ParticleType>& cloud
270 template<class ParticleType>
271 inline Cloud<ParticleType>& Particle<ParticleType>::trackData::cloud()
277 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
279 template<class ParticleType>
280 inline const Cloud<ParticleType>& Particle<ParticleType>::cloud() const
286 template<class ParticleType>
287 inline const vector& Particle<ParticleType>::position() const
293 template<class ParticleType>
294 inline vector& Particle<ParticleType>::position()
300 template<class ParticleType>
301 inline label Particle<ParticleType>::cell() const
306 template<class ParticleType>
307 inline label& Particle<ParticleType>::cell()
313 template<class ParticleType>
314 inline label Particle<ParticleType>::face() const
320 template<class ParticleType>
321 inline bool Particle<ParticleType>::onBoundary() const
323 return facei_ != -1 && facei_ >= cloud_.pMesh().nInternalFaces();
327 template<class ParticleType>
328 inline scalar& Particle<ParticleType>::stepFraction()
330 return stepFraction_;
334 template<class ParticleType>
335 inline scalar Particle<ParticleType>::stepFraction() const
337 return stepFraction_;
341 template<class ParticleType>
342 inline bool Particle<ParticleType>::softImpact() const
348 template<class ParticleType>
349 inline label Particle<ParticleType>::patch(const label facei) const
351 return cloud_.facePatch(facei);
355 template<class ParticleType>
356 inline label Particle<ParticleType>::patchFace
362 return cloud_.patchFace(patchi, facei);
366 template<class ParticleType>
367 inline scalar Particle<ParticleType>::wallImpactDistance(const vector&) const
373 template<class ParticleType>
374 inline label Particle<ParticleType>::faceInterpolation() const
380 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
382 } // End namespace Foam
384 // ************************************************************************* //