1 /*
2 XLiFE++ is an extended library of finite elements written in C++
3 Copyright (C) 2014 Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 /*!
18 \file LagrangeSegment.cpp
19 \authors D. Martin, N. Kielbasiewicz
20 \since 17 dec 2002
21 \date 6 aug 2012
22
23 \brief Implementation of xlifepp::LagrangeSegment class members and related functions
24 */
25
26 #include "LagrangeSegment.hpp"
27 #include "../Interpolation.hpp"
28 #include "utils.h"
29 #include "mathsResources.h"
30
31 #include <iostream>
32
33 namespace xlifepp
34 {
35
36 //! LagrangeSegment constructor for Lagrange reference elements
LagrangeSegment(const Interpolation * interp_p)37 LagrangeSegment::LagrangeSegment(const Interpolation* interp_p)
38 : RefSegment(interp_p)
39 {
40 name_ += "_Lagrange";
41 trace_p->push("LagrangeSegment::LagrangeSegment (" + name_ + ")");
42 // build element interpolation data
43 interpolationData();
44 // local numbering of points on sides
45 sideNumbering();
46 // Reference Element on edges
47 sideRefElement();
48 maxDegree = interpolation_p->numtype;
49
50 trace_p->pop();
51 }
52
~LagrangeSegment()53 LagrangeSegment::~LagrangeSegment() {}
54
55 //! interpolationData defines Lagrange Reference Element interpolation data
interpolationData()56 void LagrangeSegment::interpolationData()
57 {
58 trace_p->push("LagrangeSegment::interpolationData");
59 number_t kd = interpolation_p->numtype;
60
61 switch (kd)
62 {
63 case 0: nbDofs_ = nbInternalDofs_ = 1; break;
64 case 1: nbDofs_ = nbDofsOnVertices_ = 2; break;
65 default: // Lagrange segment of degree > 1
66 nbDofs_ = kd + 1;
67 nbInternalDofs_ = kd - 1;
68 nbDofsOnVertices_ = 2;
69 break;
70 }
71
72 // creating D.o.F of reference element
73 // in Lagrange standard elements only vertices are sharable
74 refDofs.reserve(nbDofs_);
75 lagrangeRefDofs(1, nbDofsOnVertices_, nbInternalDofs_);
76 //lagrangeRefDofs(1, nbDofsOnVertices_, nbDofs_ - nbInternalDofs_, 1); //old method
77
78 // allocate storage for shape functions
79 shapeValues.resize(*this, 1);
80 nbPts_ = nbDofs_;
81 trace_p->pop();
82 }
83
84 //! create standard Lagrange numbering on sides
sideNumbering()85 void LagrangeSegment::sideNumbering()
86 {
87 number_t nbSides = geomRefElem_p->nbSides();
88 sideDofNumbers_.resize(nbSides);
89 sideDofNumbers_[0].resize(1);
90 sideDofNumbers_[1].resize(1);
91
92 sideDofNumbers_[0][0] = geomRefElem_p->sideVertexNumber(1, 1);
93 sideDofNumbers_[1][0] = geomRefElem_p->sideVertexNumber(1, 2);
94 }
95
96 //! return nodes numbers of first order segment elements when splitting current element
splitP1() const97 std::vector<std::vector<number_t> > LagrangeSegment::splitP1() const {
98 std::vector<std::vector<number_t> > splitnum;
99 std::vector<number_t> pair(2,0);
100 number_t k=interpolation_p->numtype;
101 switch (k) {
102 case 0:
103 case 1:
104 pair[0]=1; pair[1]=2;
105 splitnum.push_back(pair);
106 return splitnum;
107 case 2:
108 pair[0]=1; pair[1]=3;
109 splitnum.push_back(pair);
110 pair[0]=3; pair[1]=2;
111 splitnum.push_back(pair);
112 return splitnum;
113 case 3:
114 pair[0]=1; pair[1]=3;
115 splitnum.push_back(pair);
116 pair[0]=3; pair[1]=4;
117 splitnum.push_back(pair);
118 pair[0]=4; pair[1]=2;
119 splitnum.push_back(pair);
120 return splitnum;
121 case 4:
122 pair[0]=1; pair[1]=3;
123 splitnum.push_back(pair);
124 pair[0]=3; pair[1]=4;
125 splitnum.push_back(pair);
126 pair[0]=4; pair[1]=5;
127 splitnum.push_back(pair);
128 pair[0]=5; pair[1]=2;
129 splitnum.push_back(pair);
130 return splitnum;
131 case 5:
132 pair[0]=1; pair[1]=3;
133 splitnum.push_back(pair);
134 pair[0]=3; pair[1]=4;
135 splitnum.push_back(pair);
136 pair[0]=4; pair[1]=5;
137 splitnum.push_back(pair);
138 pair[0]=5; pair[1]=6;
139 splitnum.push_back(pair);
140 pair[0]=6; pair[1]=2;
141 splitnum.push_back(pair);
142 return splitnum;
143 default:
144 pair[0]=1; pair[1]=3;
145 splitnum.push_back(pair);
146 for (number_t i=0; i<k-2; i++) {
147 pair[0]=i+3; pair[1]=i+4;
148 splitnum.push_back(pair);
149 }
150 pair[0]=k+1; pair[1]=2;
151 splitnum.push_back(pair);
152 return splitnum;
153 }
154 return splitnum;
155 }
156
157 //! return nodes numbers of first order segment elements when splitting current element
splitO1() const158 splitvec_t LagrangeSegment::splitO1() const
159 {
160 splitvec_t splitnum;
161 std::vector<std::vector<number_t> > buf;
162 buf=this->splitP1();
163 for (number_t i=0; i< buf.size(); i++)
164 {
165 splitnum.push_back(std::make_pair(_segment, buf[i]));
166 }
167 return splitnum;
168 }
169
170 //! output of Lagrange D.o.f's numbers on underlying P1 D.o.f's
outputAsP1(std::ofstream & os,const int refNum,const std::vector<number_t> & ranks) const171 void LagrangeSegment::outputAsP1(std::ofstream& os, const int refNum, const std::vector<number_t>& ranks) const
172 {
173 number_t kd = interpolation_p->numtype;
174 switch (kd)
175 {
176 case 0: noSuchFunction("outputAsP1"); break;
177 case 1: simplexVertexOutput(os, refNum, ranks[0], ranks[1]); break;
178 default:
179 simplexVertexOutput(os, refNum, ranks[0], ranks[2]);
180 for (number_t i = 2; i < kd; i++)
181 {
182 simplexVertexOutput(os, refNum, ranks[i], ranks[i + 1]);
183 }
184 simplexVertexOutput(os, refNum, ranks[kd], ranks[1]);
185 }
186 }
187
188 //! Lagrange segment Reference Element for Pk interpolation at equidistant nodes
LagrangeStdSegment(const Interpolation * interp_p)189 LagrangeStdSegment::LagrangeStdSegment(const Interpolation* interp_p)
190 : LagrangeSegment(interp_p)
191 {
192 name_ += "_" + tostring(interp_p->numtype);
193 // local coordinates of points supporting D.o.F
194 pointCoordinates();
195 // build O1 splitting scheme
196 splitO1Scheme = splitO1();
197 }
198
199 /*!
200 pointCoordinates defines Lagrange Reference Element point coordinates
201
202 Local numbering of Lagrange Pk 1D elements
203 \verbatim
204 --1-- 2---1 2---3---1 2---4---3---1 2---5---4---3---1 2---6---5---4---3---1
205 k=0 k=1 k=2 k=3 k=4 k=5
206 \endverbatim
207 */
pointCoordinates()208 void LagrangeStdSegment::pointCoordinates()
209 {
210 number_t kd = interpolation_p->numtype;
211 std::vector<RefDof*>::iterator it_rd(refDofs.begin());
212 real_t x=1.;
213 real_t unsurk=1./kd;
214
215 switch (kd)
216 {
217 case 0: // Lagrange [Std] segment of order kd=0
218 (*it_rd)->coords(.5);
219 break;
220 case 1: // Lagrange [Std] segment of order kd=1
221 (*it_rd++)->coords(1.);
222 (*it_rd++)->coords(0.);
223 break;
224 case 2: // Lagrange [Std] segment of order kd=2
225 (*it_rd++)->coords(1.);
226 (*it_rd++)->coords(0.);
227 (*it_rd++)->coords(0.5);
228 break;
229 default: // Lagrange [Std] segment of order kd > 2
230 (*it_rd++)->coords(1.);
231 (*it_rd++)->coords(0.);
232 while (it_rd != refDofs.end())
233 {
234 x -= unsurk;
235 (*it_rd++)->coords(x);
236 }
237 break;
238 }
239 }
240
241 /*!
242 shapeFunctions defines Lagrange Reference Element shape functions
243
244 Shape functions (Lagrange polynomials at \f$n_0=1, n_1=0, n_2=1-1/n, n_3=1-2/n, \ldots n_n=1/n\f$)
245 with \f$w_i(n_j)=\delta_{ij} \; (0 <= i,j <= n)\f$, are given by
246
247 \f$\begin{array}{rl}
248 w_0 & \displaystyle = \frac{n^{n-1}}{(n-1)!} x \prod_{j=1,n-1} (x-j/n) \\
249 & \displaystyle = \frac{x}{(n-1)!} \prod_{j=1,n-1} (nx-j) \\
250 w_1 & \displaystyle = (-1)^n n^{n-1}C_n^n (x-1)\frac{x-1/n}{1}\ldots\frac{x-(n-1)/n}{n-1} \\
251 & \displaystyle = (-1)^n \frac{n^{n-1}}{(n-1)!} (x-1) \prod_{j=1,n-1} (x-j/n) \\
252 & \displaystyle = (-1)^n \frac{x-1}{(n-1)!} \prod_{j=1,n-1} (nx-j) \\
253 w_2 & \displaystyle = (-1) n^{n-1} C_n^1 x(x-1)\frac{(x-1/n)}{1}\ldots\frac{(x-(j-1)/n)}{(j-1)}\frac{(x-j)/n)}{j}*\frac{(x-(j+1)/n)}{(j+1)}\ldots\frac{(x-(n-2)/n)}{(n-2)} \\
254 & \displaystyle = (-1) \frac{n^{n-1}}{(n-1)!} \frac{n!}{((n-2)2!)} \prod_{j=0,n \& j!= n-1} (x-j/n) \\
255 & \displaystyle = (-1) \frac{nx(x-1)}{((n-2)2!)} \prod_{j=1,n-2} (nx-j) \\
256 \forall i=3,n \; w_i & \displaystyle = (-1)^{i-1} n^{n-1} C_n^{i-1} x(x-1)\frac{(x-1/n)}{1}\ldots\frac{(x-(k-1)/n)}{(k-1)}\frac{(x-(k+1)/n)}{(k+1)}\ldots\frac{(x-(n-1)/n)}{(n-1)} \\
257 & \displaystyle = (-1)^{i-1} \frac{n^{n-1}}{(n-1)!} \frac{n!}{((n-i)i!)} \prod_{j=1,n-1 \& j!=k} (x-j/n) \\
258 & \displaystyle = (-1)^{i-1} \frac{n*x(x-1)}{((n-i)i!)} \prod_{j=1,n-1 \& j!=k} (n*x-j)
259 \end{array}\f$
260
261 where \f$k=n+1-i\f$ and \f$\displaystyle C_n^j=\frac{n!}{(n-j)! j!}\f$ are Pascal's triangle binomial coefficients.
262
263 Examples :
264 - n=1
265 - \f$ w_0 = 1*1^0 x = x\f$
266 - \f$ w_1 = -1*1^(x-1) = 1-x\f$
267 - n=2
268 - \f$ w_0 = 1*2^1/1 \;x (x-1/2) = x *(2x-1)\f$
269 - \f$ w_1 = 1*2^1/1 \;(x-1)(x-1/2) = (x-1)*(2x-1)\f$
270 - \f$ w_2 = -2*2^1/1 \;x(x-1) = -4x(x-1)\f$
271 - n=3
272 - \f$ w_0 = 1*3^2/2 \; x(x-1/3)(x-2/3) = 1/2 \; x(3x-1)(3x-2)\f$
273 - \f$ w_1 = -1*3^2/2 \; (x-1)(x-1/3)(x-2/3) = -1/2 \; (x-1)(3x-1)(3x-2)\f$
274 - \f$ w_2 = -3*3^2/2 \; x(x-1)(x-1/3) = -9/2 \; x(x-1)(3x-1)\f$
275 - \f$ w_3 = 3*3^2/2 \; x(x-1)(x-2/3)= 9/2 \; x(x-1)(3x-2)\f$
276 */
computeShapeValues(std::vector<real_t>::const_iterator it_pt,ShapeValues & shv,const bool withDeriv) const277 void LagrangeStdSegment::computeShapeValues(std::vector<real_t>::const_iterator it_pt, ShapeValues& shv, const bool withDeriv) const
278 {
279 // Lagrange standard shape function computation for any order kd >= 0
280 // kd : interpolation order
281 int kd = interpolation_p->numtype, kp1_i;
282 real_t x = *it_pt, kdx = kd * x, tmp;
283 std::vector<real_t>::iterator it_w(shv.w.begin());
284 std::vector<std::vector<real_t> >::iterator it_dw(shv.dw.begin());
285 std::vector<real_t>::iterator it_dwi((*it_dw).begin());
286 switch (kd)
287 {
288 case 0: // w_0=1
289 *it_w = 1.;
290 if (withDeriv) {*it_dwi = 0.;}
291 break;
292 case 1: // w_0=x , w_1=1-x
293 *it_w++ = x;
294 *it_w = 1. - x;
295 if (withDeriv)
296 {
297 *it_dwi++ = 1.;
298 *it_dwi = -1.;
299 }
300 break;
301 case 2: // w_0=x*(2x-1) , w_1=(x-1)*(2x-1) , w_2=-4x(x-1)
302 *it_w++ = x * (kdx - 1.);
303 *it_w++ = (x - 1.) * (kdx - 1.);
304 *it_w = -4.*x * (x - 1.);
305 if (withDeriv)
306 {
307 *it_dwi++ = 4 * x - 1.;
308 *it_dwi++ = 4 * x - 3.;
309 *it_dwi = -8 * x + 4.;
310 }
311 break;
312 default:
313 // shape function general computation
314 //
315 // NOTE : Below we have x_0=1, x_1=0, xl=1-(l-1)/k=(k+1-l)/k for l=2..k
316 //
317 // w_0=(x-0)/(1-0) * Prod_{l=2, k} (x-xl)/(1-xl) with w_0(1)=1.
318 // =x * Prod_{l=2..k} (kx -(k+1-l))/(k -(k+1-l))
319 *it_w = x;
320 for (int j = 1; j < kd; j++) {*it_w *= (kdx - j) / (kd - j);}
321 // w_1=(x-1)/(0-1) * Prod_{l=2..k} (x-xl)/(-xl) with w_1(0)=1.
322 it_w++;
323 *it_w = 1. - x;
324 for (int j = 1; j < kd; j++) {*it_w *= -(kdx - j) / j;}
325 // shape functions w_i, i=2..k
326 kp1_i = kd - 1;
327 for (it_w = shv.w.begin() + 2; it_w != shv.w.end(); kp1_i--, it_w++)
328 {
329 // w_i=(x-1/xi-1) * (x-0/xi-0) * Prod_{l=2..k, l!=i} (x-xl)/(xi-xl)
330 *it_w = 1.;
331 for (int l = 0; l < kp1_i; l++) {*it_w *= (kdx - l) / (kp1_i - l);}
332 for (int l = kp1_i + 1; l <= kd; l++) {*it_w *= (kdx - l) / (kp1_i - l);}
333 }
334
335 if (withDeriv)
336 {
337 // First derivative of shape functions
338 //
339 // derivative of shape functions w_i, i=0, k+1
340 // compute product of values (x-xl / xi-xl) for l=0..k+1, l!=i,j
341 // then multiply by (1 / xi-xj) then make sum on j's
342
343 // derivative of shape function dw_0
344 *it_dwi = 0.;
345 for (int j = 0; j < kd; j++)
346 {
347 tmp = 1.;
348 for (int l = 0; l < j; l++) {tmp *= (kdx - l) / (kd - l);}
349 for (int l = j + 1; l < kd; l++) {tmp *= (kdx - l) / (kd - l);}
350 *it_dwi += tmp * kd / (kd - j);
351 }
352
353 // derivative of shape function dw_1
354 it_dwi++;
355 *it_dwi = 0.;
356 for (int j = 1; j <= kd; j++)
357 {
358 tmp = 1.;
359 for (int l = 1; l < j; l++) {tmp *= -(kdx - l) / l;}
360 for (int l = j + 1; l <= kd; l++) {tmp *= -(kdx - l) / l;}
361 *it_dwi -= tmp * kd / j;
362 }
363
364 // derivative of shape functions dw_i (0 <i <= kd)
365 kp1_i = kd - 1;
366 for (it_dwi = (*it_dw).begin() + 2; it_dwi != (*it_dw).end(); kp1_i--, it_dwi++)
367 {
368 *it_dwi = 0.;
369 for (int j = 0; j < kp1_i; j++)
370 {
371 tmp = 1.;
372 for (int l = 0; l < j; l++) {tmp *= (kdx - l) / (kp1_i - l);}
373 for (int l = j + 1; l < kp1_i; l++) {tmp *= (kdx - l) / (kp1_i - l);}
374 for (int l = kp1_i + 1; l <= kd; l++) {tmp *= (kdx - l) / (kp1_i - l);}
375 *it_dwi += tmp * kd / (kp1_i - j);
376 }
377 for (int j = kp1_i + 1; j <= kd; j++)
378 {
379 tmp = 1.;
380 for (int l = 0; l < kp1_i; l++) {tmp *= (kdx - l) / (kp1_i - l);}
381 for (int l = kp1_i + 1; l < j; l++) {tmp *= (kdx - l) / (kp1_i - l);}
382 for (int l = j + 1; l <= kd; l++) {tmp *= (kdx - l) / (kp1_i - l);}
383 *it_dwi += tmp * kd / (kp1_i - j);
384 }
385 }
386 }
387 }
388 }
389
390 //! compute shape functions as polynomials using general algorithm
391 // not used by default
computeShapeFunctions()392 void LagrangeStdSegment::computeShapeFunctions()
393 {
394 //compute Matrix Lij=pj(ni) for all pi in Vk, ni nodes
395 number_t k=interpolation_p->numtype;
396 Matrix<real_t> L(nbDofs_,nbDofs_);
397 PolynomialBasis Pk(_Pk,1,k); //Pk[X] space equipped with canonical basis
398 std::vector<RefDof*>::iterator itd=refDofs.begin();
399 for (number_t i = 1; i <= nbDofs_; ++i, ++itd) //loop on nodes
400 {
401 std::vector<real_t>::const_iterator itpt=(*itd)->coords();
402 PolynomialBasis::iterator itp = Pk.begin();
403 for (number_t j=1; j<=nbDofs_; ++j, ++itp) L(i,j)=itp->eval(*itpt); //loop on monomials
404 }
405 //compute coefficients of shape functions by solving linear systems
406 Matrix<real_t> sf(nbDofs_,_idMatrix);
407 real_t eps=theZeroThreshold;
408 number_t r;
409 bool ok=gaussMultipleSolver(L, sf, nbDofs_, eps, r);
410 if (!ok)
411 {
412 where("LagrangeTrianglePk::computeShapeFunctions()");
413 error("mat_noinvert");
414 }
415 sf.roundToZero();
416 Matrix<real_t>::iterator itm=sf.begin();
417 Vector<real_t> v(nbDofs_);
418 Vector<real_t>::iterator itv;
419 Wk.dimVar=1; Wk.dimVec=1;
420 Wk.name="P"+tostring(k);
421 for (number_t i=0; i<nbDofs_; i++)
422 {
423 for (itv=v.begin(); itv!=v.end(); ++itv, ++itm) *itv=*itm;
424 Wk.add(combine(Pk,v));
425 }
426 //Wk.clean(0.000001);
427 dWk.resize(2);
428 dWk[0]=dx(Wk); dWk[1]=dy(Wk);
429 }
430
431 //! Lagrange segment Reference Element for Pk interpolation at Gauss-Lobatto nodes
LagrangeGLSegment(const Interpolation * interp_p)432 LagrangeGLSegment::LagrangeGLSegment(const Interpolation* interp_p)
433 : LagrangeSegment(interp_p)
434 {
435 name_ += "_Gauss-Lobatto_" + tostring(interp_p->numtype);
436 // local coordinates of points supporting D.o.F
437 pointCoordinates();
438 // build O1 splitting scheme
439 splitO1Scheme = splitO1();
440 }
441
442 //! pointCoordinates defines Lagrange Reference Element point coordinates
pointCoordinates()443 void LagrangeGLSegment::pointCoordinates()
444 {
445 number_t kd(interpolation_p->numtype);
446 std::vector<RefDof*>::iterator it_rd(refDofs.begin());
447 std::vector<real_t> coord1d;
448
449 switch (kd)
450 {
451 case 0: // Lagrange Gauss-Lobatto segment of order kd=0 (unavailable)
452 break;
453 case 1: // Lagrange [Gauss-Lobatto=Std] segment of order kd=1
454 (*it_rd++)->coords(1.);
455 (*it_rd++)->coords(0.);
456 break;
457 case 2: // Lagrange [Gauss-Lobatto=Std] segment of order kd=2
458 (*it_rd++)->coords(1.);
459 (*it_rd++)->coords(0.);
460 (*it_rd++)->coords(0.5);
461 break;
462 default: // Lagrange Gauss-Lobatto segment of order kd > 2
463 coord1d.resize((nbDofs_ + 1) / 2);
464 gaussLobattoPoints(nbDofs_, coord1d);
465 (*it_rd++)->coords(1.);
466 (*it_rd++)->coords(0.);
467 // GaussLobattoPoints(n) returns the first (n+1)/2 non-negative points
468 // of Gauss-Lobatto computed on [-1,1] in ascending order,
469 // including middle point of abscissa 0 for n odd and end point of abscissa 1.
470 // build point 3 up to (n+1)/2, for n > 3
471 for (std::vector<real_t>::reverse_iterator c1d = coord1d.rbegin() + 1; c1d != coord1d.rend(); c1d++) {(*it_rd++)->coords((1. + *c1d) / 2);}
472 // build points (n+3)/2 up to n
473 for (std::vector<real_t>::const_iterator c1d = coord1d.begin() + nbDofs_ % 2; c1d != coord1d.end() - 1; c1d++) {(*it_rd++)->coords((1. - *c1d) / 2);}
474 break;
475 }
476 }
477
478 //! shapeFunctions defines Lagrange Reference Element shape functions
computeShapeValues(std::vector<real_t>::const_iterator it_pt,ShapeValues & shv,const bool withDeriv) const479 void LagrangeGLSegment::computeShapeValues(std::vector<real_t>::const_iterator it_pt, ShapeValues& shv, const bool withDeriv) const
480 {
481 // Lagrange Gauss-Lobatto shape function computation for order kd > 0
482 real_t x(*it_pt), xi, xj, xl, tmp;
483 std::vector<RefDof*>::const_iterator it_rdb(refDofs.begin()), it_rde(refDofs.end()), it_rdi, it_rdl, it_rdj;
484 std::vector<real_t>::iterator it_w(shv.w.begin());
485 // shape function general computation
486 //
487 // NOTE : Below we have x_0=1, x_1=0 and xl (l=2..k) are the other Gauss-Lobatto
488 // points in ]0,1[ ordered by decreasing abscissa.
489 //
490 // w_0=(x-0)/(1-0) * Prod_{l=2..k} (x-xl)/(1-xl) with w_0(1)=1.
491 *it_w = x;
492 for (it_rdl = it_rdb + 2; it_rdl != it_rde; it_rdl++) {xl = *((*it_rdl)->coords()); *it_w *= (x - xl) / (1. - xl);}
493 // w_1=(x-1)/(0-1) * Prod_{l=2..k} (x-xl)/(-xl) with w_1(0)=1.
494 it_w++;
495 *it_w = 1. - x;
496 for (it_rdl = it_rdb + 2; it_rdl != it_rde; it_rdl++) {xl = *((*it_rdl)->coords()); *it_w *= -(x - xl) / xl;}
497 // shape functions w_i, i=2..k
498 it_rdi = it_rdb + 2;
499 for (it_w = shv.w.begin() + 2; it_w != shv.w.end(); it_rdi++, it_w++)
500 {
501 // w_i=(x-1)(xi-1) * (x-0/xi-0) * Prod_{l=2..k, l!=i} (x-xl)/(xi-xl)
502 xi = *((*it_rdi)->coords());
503 // compute (x-1)(xi-1) * (x-0/xi-0)
504 *it_w = ((x - 1.) / (xi - 1.)) * (x / xi);
505 // then multiply by Prod_{l=2..k, l!=i} (x-xl)/(xi-xl)
506 for (it_rdl = it_rdb + 2; it_rdl != it_rdi; it_rdl++) {xl = *((*it_rdl)->coords()); *it_w *= (x - xl) / (xi - xl);}
507 for (it_rdl = it_rdi + 1; it_rdl != it_rde; it_rdl++) {xl = *((*it_rdl)->coords()); *it_w *= (x - xl) / (xi - xl);}
508 }
509
510 if (withDeriv)
511 {
512 // Derivative of shape functions
513 //
514 // derivative of shape functions w_i, i=0..k
515 // compute product of values (x-xl / xi-xl) for l=0..k, l!=i,j
516 // multiply by (1 / xi-xj) then sum on j's
517 std::vector<std::vector<real_t> >::iterator it_dw(shv.dw.begin());
518 std::vector<real_t>::iterator it_dwi;
519 // loop on i=0..kd (all shape functions)
520 it_rdi = it_rdb;
521
522 for (std::vector<real_t>::iterator it_dwi = (*it_dw).begin(); it_dwi != (*it_dw).end(); it_rdi++, it_dwi++)
523 {
524 *it_dwi = 0.;
525 xi = *((*it_rdi)->coords());
526 // loop on j=0..i-1
527 for (it_rdj = it_rdb; it_rdj != it_rdi; it_rdj++)
528 {
529 xj = *((*it_rdj)->coords());
530 tmp = 1.;
531 // loops on l=0..kd , l!=j , l!=i (j <i)
532 for (it_rdl = it_rdb; it_rdl != it_rdj; it_rdl++) {xl = *((*it_rdl)->coords()); tmp *= (x - xl) / (xi - xl);}
533 for (it_rdl = it_rdj + 1; it_rdl != it_rdi; it_rdl++) {xl = *((*it_rdl)->coords()); tmp *= (x - xl) / (xi - xl);}
534 for (it_rdl = it_rdi + 1; it_rdl != it_rde; it_rdl++) {xl = *((*it_rdl)->coords()); tmp *= (x - xl) / (xi - xl);}
535 *it_dwi += tmp / (xi - xj);
536 }
537
538 // loop on j=i+1..kd
539 for (it_rdj = it_rdi + 1; it_rdj != it_rde; it_rdj++)
540 {
541 xj = *((*it_rdj)->coords());
542 tmp = 1.;
543 // loops on l=0..kd , l!=i , l!=j (j > i)
544 for (it_rdl = it_rdb; it_rdl != it_rdi; it_rdl++) {xl = *((*it_rdl)->coords()); tmp *= (x - xl) / (xi - xl);}
545 for (it_rdl = it_rdi + 1; it_rdl != it_rdj; it_rdl++) {xl = *((*it_rdl)->coords()); tmp *= (x - xl) / (xi - xl);}
546 for (it_rdl = it_rdj + 1; it_rdl != it_rde; it_rdl++) {xl = *((*it_rdl)->coords()); tmp *= (x - xl) / (xi - xl);}
547 *it_dwi += tmp / (xi - xj);
548 }
549 }
550 }
551 }
552
553 } // end of namespace xlifepp
554