1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
25 Calculation of shape function product for a tetrahedron
27 \*---------------------------------------------------------------------------*/
29 #include "tetrahedron.H"
30 #include "triPointRef.H"
31 #include "scalarField.H"
33 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
35 // (Probably very inefficient) minimum containment sphere calculation.
36 // From http://www.imr.sandia.gov/papers/imr11/shewchuk2.pdf:
37 // Sphere ctr is smallest one of
39 // - triangle circumcentre
41 template<class Point, class PointRef>
42 Foam::pointHit Foam::tetrahedron<Point, PointRef>::containmentSphere
47 const scalar fac = 1 + tol;
49 // Halve order of tolerance for comparisons of sqr.
50 const scalar facSqr = Foam::sqrt(fac);
53 // 1. Circumcentre itself.
55 pointHit pHit(circumCentre());
57 scalar minRadiusSqr = magSqr(pHit.rawPoint() - a_);
60 // 2. Try circumcentre of tet triangles. Create circumcircle for triFace and
61 // check if 4th point is inside.
64 point ctr = triPointRef(a_, b_, c_).circumCentre();
65 scalar radiusSqr = magSqr(ctr - a_);
69 radiusSqr < minRadiusSqr
70 && Foam::magSqr(d_-ctr) <= facSqr*radiusSqr
75 minRadiusSqr = radiusSqr;
79 point ctr = triPointRef(a_, b_, d_).circumCentre();
80 scalar radiusSqr = magSqr(ctr - a_);
84 radiusSqr < minRadiusSqr
85 && Foam::magSqr(c_-ctr) <= facSqr*radiusSqr
90 minRadiusSqr = radiusSqr;
94 point ctr = triPointRef(a_, c_, d_).circumCentre();
95 scalar radiusSqr = magSqr(ctr - a_);
99 radiusSqr < minRadiusSqr
100 && Foam::magSqr(b_-ctr) <= facSqr*radiusSqr
105 minRadiusSqr = radiusSqr;
109 point ctr = triPointRef(b_, c_, d_).circumCentre();
110 scalar radiusSqr = magSqr(ctr - b_);
114 radiusSqr < minRadiusSqr
115 && Foam::magSqr(a_-ctr) <= facSqr*radiusSqr
120 minRadiusSqr = radiusSqr;
125 // 3. Try midpoints of edges
129 point ctr = 0.5*(a_ + b_);
130 scalar radiusSqr = magSqr(a_ - ctr);
131 scalar testRadSrq = facSqr*radiusSqr;
135 radiusSqr < minRadiusSqr
136 && magSqr(c_-ctr) <= testRadSrq
137 && magSqr(d_-ctr) <= testRadSrq)
141 minRadiusSqr = radiusSqr;
147 point ctr = 0.5*(a_ + c_);
148 scalar radiusSqr = magSqr(a_ - ctr);
149 scalar testRadSrq = facSqr*radiusSqr;
153 radiusSqr < minRadiusSqr
154 && magSqr(b_-ctr) <= testRadSrq
155 && magSqr(d_-ctr) <= testRadSrq
160 minRadiusSqr = radiusSqr;
166 point ctr = 0.5*(a_ + d_);
167 scalar radiusSqr = magSqr(a_ - ctr);
168 scalar testRadSrq = facSqr*radiusSqr;
172 radiusSqr < minRadiusSqr
173 && magSqr(b_-ctr) <= testRadSrq
174 && magSqr(c_-ctr) <= testRadSrq
179 minRadiusSqr = radiusSqr;
185 point ctr = 0.5*(b_ + c_);
186 scalar radiusSqr = magSqr(b_ - ctr);
187 scalar testRadSrq = facSqr*radiusSqr;
191 radiusSqr < minRadiusSqr
192 && magSqr(a_-ctr) <= testRadSrq
193 && magSqr(d_-ctr) <= testRadSrq
198 minRadiusSqr = radiusSqr;
204 point ctr = 0.5*(b_ + d_);
205 scalar radiusSqr = magSqr(b_ - ctr);
206 scalar testRadSrq = facSqr*radiusSqr;
210 radiusSqr < minRadiusSqr
211 && magSqr(a_-ctr) <= testRadSrq
212 && magSqr(c_-ctr) <= testRadSrq)
216 minRadiusSqr = radiusSqr;
222 point ctr = 0.5*(c_ + d_);
223 scalar radiusSqr = magSqr(c_ - ctr);
224 scalar testRadSrq = facSqr*radiusSqr;
228 radiusSqr < minRadiusSqr
229 && magSqr(a_-ctr) <= testRadSrq
230 && magSqr(b_-ctr) <= testRadSrq
235 minRadiusSqr = radiusSqr;
240 pHit.setDistance(sqrt(minRadiusSqr));
246 template<class Point, class PointRef>
247 void Foam::tetrahedron<Point, PointRef>::gradNiSquared
252 // Change of sign between face area vector and gradient
253 // does not matter because of square
255 // Warning: Added a mag to produce positive coefficients even if
256 // the tetrahedron is twisted inside out. This is pretty
257 // dangerous, but essential for mesh motion.
258 scalar magVol = Foam::mag(mag());
260 buffer[0] = (1.0/9.0)*magSqr(Sa())/magVol;
261 buffer[1] = (1.0/9.0)*magSqr(Sb())/magVol;
262 buffer[2] = (1.0/9.0)*magSqr(Sc())/magVol;
263 buffer[3] = (1.0/9.0)*magSqr(Sd())/magVol;
267 template<class Point, class PointRef>
268 void Foam::tetrahedron<Point, PointRef>::gradNiDotGradNj
273 // Warning. Ordering of edges needs to be the same for a tetrahedron
274 // class, a tetrahedron cell shape model and a tetCell
276 // Warning: Added a mag to produce positive coefficients even if
277 // the tetrahedron is twisted inside out. This is pretty
278 // dangerous, but essential for mesh motion.
280 // Double change of sign between face area vector and gradient
282 scalar magVol = Foam::mag(mag());
288 buffer[0] = (1.0/9.0)*(sa & sb)/magVol;
289 buffer[1] = (1.0/9.0)*(sa & sc)/magVol;
290 buffer[2] = (1.0/9.0)*(sa & sd)/magVol;
291 buffer[3] = (1.0/9.0)*(sd & sb)/magVol;
292 buffer[4] = (1.0/9.0)*(sb & sc)/magVol;
293 buffer[5] = (1.0/9.0)*(sd & sc)/magVol;
297 template<class Point, class PointRef>
298 void Foam::tetrahedron<Point, PointRef>::gradNiGradNi
303 // Change of sign between face area vector and gradient
304 // does not matter because of square
306 scalar magVol = Foam::mag(mag());
308 buffer[0] = (1.0/9.0)*sqr(Sa())/magVol;
309 buffer[1] = (1.0/9.0)*sqr(Sb())/magVol;
310 buffer[2] = (1.0/9.0)*sqr(Sc())/magVol;
311 buffer[3] = (1.0/9.0)*sqr(Sd())/magVol;
315 template<class Point, class PointRef>
316 void Foam::tetrahedron<Point, PointRef>::gradNiGradNj
321 // Warning. Ordering of edges needs to be the same for a tetrahedron
322 // class, a tetrahedron cell shape model and a tetCell
324 // Double change of sign between face area vector and gradient
326 scalar magVol = Foam::mag(mag());
332 buffer[0] = (1.0/9.0)*(sa * sb)/magVol;
333 buffer[1] = (1.0/9.0)*(sa * sc)/magVol;
334 buffer[2] = (1.0/9.0)*(sa * sd)/magVol;
335 buffer[3] = (1.0/9.0)*(sd * sb)/magVol;
336 buffer[4] = (1.0/9.0)*(sb * sc)/magVol;
337 buffer[5] = (1.0/9.0)*(sd * sc)/magVol;
341 // ************************************************************************* //