comparison liboctave/CollocWt.cc @ 10603:d909c4c14b63

convert villad functions to C++
author John W. Eaton <jwe@octave.org>
date Tue, 04 May 2010 13:00:00 -0400
parents 12884915a8e4
children fd0a3ac60b0e
comparison
equal deleted inserted replaced
10602:38eae0c3a003 10603:d909c4c14b63
25 #include <config.h> 25 #include <config.h>
26 #endif 26 #endif
27 27
28 #include <iostream> 28 #include <iostream>
29 29
30 #include <cfloat>
31
30 #include "CollocWt.h" 32 #include "CollocWt.h"
31 #include "f77-fcn.h" 33 #include "f77-fcn.h"
32 #include "lo-error.h" 34 #include "lo-error.h"
33 35
34 extern "C" 36 // The following routines jcobi, dif, and dfopr are based on the code
35 { 37 // found in Villadsen, J. and M. L. Michelsen, Solution of Differential
36 F77_RET_T 38 // Equation Models by Polynomial Approximation, Prentice-Hall (1978)
37 F77_FUNC (jcobi, JCOBI) (octave_idx_type&, octave_idx_type&, octave_idx_type&, octave_idx_type&, double&, 39 // pages 418-420.
38 double&, double*, double*, double*, 40 //
39 double*); 41 // Translated to C++ by jwe.
40 42
41 F77_RET_T 43 // Compute the first three derivatives of the node polynomial.
42 F77_FUNC (dfopr, DFOPR) (octave_idx_type&, octave_idx_type&, octave_idx_type&, octave_idx_type&, octave_idx_type&, octave_idx_type&, 44 //
43 double*, double*, double*, double*, 45 // n0 (alpha,beta) n1
44 double*); 46 // p (x) = (x) * p (x) * (1 - x)
47 // nt n
48 //
49 // at the interpolation points. Each of the parameters n0 and n1
50 // may be given the value 0 or 1. The total number of points
51 // nt = n + n0 + n1
52 //
53 // The values of root must be known before a call to dif is possible.
54 // They may be computed using jcobi.
55
56 static void
57 dif (octave_idx_type nt, double *root, double *dif1, double *dif2,
58 double *dif3)
59 {
60 // Evaluate derivatives of node polynomial using recursion formulas.
61
62 for (octave_idx_type i = 0; i < nt; i++)
63 {
64 double x = root[i];
65
66 dif1[i] = 1.0;
67 dif2[i] = 0.0;
68 dif3[i] = 0.0;
69
70 for (octave_idx_type j = 0; j < nt; j++)
71 {
72 if (j != i)
73 {
74 double y = x - root[j];
75
76 dif3[i] = y * dif3[i] + 3.0 * dif2[i];
77 dif2[i] = y * dif2[i] + 2.0 * dif1[i];
78 dif1[i] = y * dif1[i];
79 }
80 }
81 }
82 }
83
84 // Compute the zeros of the Jacobi polynomial.
85 //
86 // (alpha,beta)
87 // p (x)
88 // n
89 //
90 // Use dif to compute the derivatives of the node
91 // polynomial
92 //
93 // n0 (alpha,beta) n1
94 // p (x) = (x) * p (x) * (1 - x)
95 // nt n
96 //
97 // at the interpolation points.
98 //
99 // See Villadsen and Michelsen, pages 131-132 and 418.
100 //
101 // Input parameters:
102 //
103 // nd : the dimension of the vectors dif1, dif2, dif3, and root
104 //
105 // n : the degree of the jacobi polynomial, (i.e. the number
106 // of interior interpolation points)
107 //
108 // n0 : determines whether x = 0 is included as an
109 // interpolation point
110 //
111 // n0 = 0 ==> x = 0 is not included
112 // n0 = 1 ==> x = 0 is included
113 //
114 // n1 : determines whether x = 1 is included as an
115 // interpolation point
116 //
117 // n1 = 0 ==> x = 1 is not included
118 // n1 = 1 ==> x = 1 is included
119 //
120 // alpha : the value of alpha in the description of the jacobi
121 // polynomial
122 //
123 // beta : the value of beta in the description of the jacobi
124 // polynomial
125 //
126 // For a more complete explanation of alpha an beta, see Villadsen
127 // and Michelsen, pages 57 to 59.
128 //
129 // Output parameters:
130 //
131 // root : one dimensional vector containing on exit the
132 // n + n0 + n1 zeros of the node polynomial used in the
133 // interpolation routine
134 //
135 // dif1 : one dimensional vector containing the first derivative
136 // of the node polynomial at the zeros
137 //
138 // dif2 : one dimensional vector containing the second derivative
139 // of the node polynomial at the zeros
140 //
141 // dif3 : one dimensional vector containing the third derivative
142 // of the node polynomial at the zeros
143
144 static bool
145 jcobi (octave_idx_type n, octave_idx_type n0, octave_idx_type n1,
146 double alpha, double beta, double *dif1, double *dif2,
147 double *dif3, double *root)
148 {
149 assert (n0 == 0 || n0 == 1);
150 assert (n1 == 0 || n1 == 1);
151
152 octave_idx_type nt = n + n0 + n1;
153
154 assert (nt > 1);
155
156 // -- first evaluation of coefficients in recursion formulas.
157 // -- recursion coefficients are stored in dif1 and dif2.
158
159 double ab = alpha + beta;
160 double ad = beta - alpha;
161 double ap = beta * alpha;
162
163 dif1[0] = (ad / (ab + 2.0) + 1.0) / 2.0;
164 dif2[0] = 0.0;
165
166 if (n >= 2)
167 {
168 for (octave_idx_type i = 1; i < n; i++)
169 {
170 double z1 = i;
171 double z = ab + 2 * z1;
172
173 dif1[i] = (ab * ad / z / (z + 2.0) + 1.0) / 2.0;
174
175 if (i == 1)
176 dif2[i] = (ab + ap + z1) / z / z / (z + 1.0);
177 else
178 {
179 z = z * z;
180 double y = z1 * (ab + z1);
181 y = y * (ap + y);
182 dif2[i] = y / z / (z - 1.0);
183 }
184 }
185 }
186
187 // Root determination by Newton method with suppression of previously
188 // determined roots.
189
190 double x = 0.0;
191
192 for (octave_idx_type i = 0; i < n; i++)
193 {
194 bool done = false;
195
196 int k = 0;
197
198 while (! done)
199 {
200 double xd = 0.0;
201 double xn = 1.0;
202 double xd1 = 0.0;
203 double xn1 = 0.0;
204
205 for (octave_idx_type j = 0; j < n; j++)
206 {
207 double xp = (dif1[j] - x) * xn - dif2[j] * xd;
208 double xp1 = (dif1[j] - x) * xn1 - dif2[j] * xd1 - xn;
209
210 xd = xn;
211 xd1 = xn1;
212 xn = xp;
213 xn1 = xp1;
214 }
215
216 double zc = 1.0;
217 double z = xn / xn1;
218
219 if (i != 0)
220 {
221 for (octave_idx_type j = 1; j <= i; j++)
222 zc = zc - z / (x - root[j-1]);
223 }
224
225 z = z / zc;
226 x = x - z;
227
228 // Famous last words: 100 iterations should be more than
229 // enough in all cases.
230
231 if (++k > 100 || xisnan (z))
232 return false;
233
234 if (std::abs (z) <= 100 * DBL_EPSILON)
235 done = true;
236 }
237
238 root[i] = x;
239 x = x + sqrt (DBL_EPSILON);
240 }
241
242 // Add interpolation points at x = 0 and/or x = 1.
243
244 if (n0 != 0)
245 {
246 for (octave_idx_type i = n; i > 0; i--)
247 root[i] = root[i-1];
248
249 root[0] = 0.0;
250 }
251
252 if (n1 != 0)
253 root[nt-1] = 1.0;
254
255 dif (nt, root, dif1, dif2, dif3);
256
257 return true;
258 }
259
260 // Compute derivative weights for orthogonal collocation.
261 //
262 // See Villadsen and Michelsen, pages 133-134, 419.
263 //
264 // Input parameters:
265 //
266 // nd : the dimension of the vectors dif1, dif2, dif3, and root
267 //
268 // n : the degree of the jacobi polynomial, (i.e. the number
269 // of interior interpolation points)
270 //
271 // n0 : determines whether x = 0 is included as an
272 // interpolation point
273 //
274 // n0 = 0 ==> x = 0 is not included
275 // n0 = 1 ==> x = 0 is included
276 //
277 // n1 : determines whether x = 1 is included as an
278 // interpolation point
279 //
280 // n1 = 0 ==> x = 1 is not included
281 // n1 = 1 ==> x = 1 is included
282 //
283 // i : the index of the node for which the weights are to be
284 // calculated
285 //
286 // id : indicator
287 //
288 // id = 1 ==> first derivative weights are computed
289 // id = 2 ==> second derivative weights are computed
290 // id = 3 ==> gaussian weights are computed (in this
291 // case, the value of i is irrelevant)
292 //
293 // Output parameters:
294 //
295 // dif1 : one dimensional vector containing the first derivative
296 // of the node polynomial at the zeros
297 //
298 // dif2 : one dimensional vector containing the second derivative
299 // of the node polynomial at the zeros
300 //
301 // dif3 : one dimensional vector containing the third derivative
302 // of the node polynomial at the zeros
303 //
304 // vect : one dimensional vector of computed weights
305
306 static void
307 dfopr (octave_idx_type n, octave_idx_type n0, octave_idx_type n1,
308 octave_idx_type i, octave_idx_type id, double *dif1,
309 double *dif2, double *dif3, double *root, double *vect)
310 {
311 assert (n0 == 0 || n0 == 1);
312 assert (n1 == 0 || n1 == 1);
313
314 octave_idx_type nt = n + n0 + n1;
315
316 assert (nt > 1);
317
318 assert (id == 1 || id == 2 || id == 3);
319
320 if (id != 3)
321 assert (i >= 0 && i < nt);
322
323 // Evaluate discretization matrices and Gaussian quadrature weights.
324 // Quadrature weights are normalized to sum to one.
325
326 if (id != 3)
327 {
328 for (octave_idx_type j = 0; j < nt; j++)
329 {
330 if (j == i)
331 {
332 if (id == 1)
333 vect[i] = dif2[i] / dif1[i] / 2.0;
334 else
335 vect[i] = dif3[i] / dif1[i] / 3.0;
336 }
337 else
338 {
339 double y = root[i] - root[j];
340
341 vect[j] = dif1[i] / dif1[j] / y;
342
343 if (id == 2)
344 vect[j] = vect[j] * (dif2[i] / dif1[i] - 2.0 / y);
345 }
346 }
347 }
348 else
349 {
350 double y = 0.0;
351
352 for (octave_idx_type j = 0; j < nt; j++)
353 {
354 double x = root[j];
355
356 double ax = x * (1.0 - x);
357
358 if (n0 == 0)
359 ax = ax / x / x;
360
361 if (n1 == 0)
362 ax = ax / (1.0 - x) / (1.0 - x);
363
364 vect[j] = ax / (dif1[j] * dif1[j]);
365
366 y = y + vect[j];
367 }
368
369 for (octave_idx_type j = 0; j < nt; j++)
370 vect[j] = vect[j] / y;
371 }
45 } 372 }
46 373
47 // Error handling. 374 // Error handling.
48 375
49 void 376 void
121 448
122 double *pr = r.fortran_vec (); 449 double *pr = r.fortran_vec ();
123 450
124 // Compute roots. 451 // Compute roots.
125 452
126 F77_FUNC (jcobi, JCOBI) (nt, n, inc_left, inc_right, Alpha, Beta, 453 if (! jcobi (n, inc_left, inc_right, Alpha, Beta, pdif1, pdif2, pdif3, pr))
127 pdif1, pdif2, pdif3, pr); 454 {
455 error ("jcobi: newton iteration failed");
456 return;
457 }
128 458
129 octave_idx_type id; 459 octave_idx_type id;
130 460
131 // First derivative weights. 461 // First derivative weights.
132 462
133 id = 1; 463 id = 1;
134 for (octave_idx_type i = 1; i <= nt; i++) 464 for (octave_idx_type i = 0; i < nt; i++)
135 { 465 {
136 F77_FUNC (dfopr, DFOPR) (nt, n, inc_left, inc_right, i, id, pdif1, 466 dfopr (n, inc_left, inc_right, i, id, pdif1, pdif2, pdif3, pr, pvect);
137 pdif2, pdif3, pr, pvect);
138 467
139 for (octave_idx_type j = 0; j < nt; j++) 468 for (octave_idx_type j = 0; j < nt; j++)
140 A (i-1, j) = vect.elem (j); 469 A(i,j) = vect(j);
141 } 470 }
142 471
143 // Second derivative weights. 472 // Second derivative weights.
144 473
145 id = 2; 474 id = 2;
146 for (octave_idx_type i = 1; i <= nt; i++) 475 for (octave_idx_type i = 0; i < nt; i++)
147 { 476 {
148 F77_FUNC (dfopr, DFOPR) (nt, n, inc_left, inc_right, i, id, pdif1, 477 dfopr (n, inc_left, inc_right, i, id, pdif1, pdif2, pdif3, pr, pvect);
149 pdif2, pdif3, pr, pvect);
150 478
151 for (octave_idx_type j = 0; j < nt; j++) 479 for (octave_idx_type j = 0; j < nt; j++)
152 B (i-1, j) = vect.elem (j); 480 B(i,j) = vect(j);
153 } 481 }
154 482
155 // Gaussian quadrature weights. 483 // Gaussian quadrature weights.
156 484
157 id = 3; 485 id = 3;
158 double *pq = q.fortran_vec (); 486 double *pq = q.fortran_vec ();
159 F77_FUNC (dfopr, DFOPR) (nt, n, inc_left, inc_right, id, id, pdif1, 487 dfopr (n, inc_left, inc_right, id, id, pdif1, pdif2, pdif3, pr, pq);
160 pdif2, pdif3, pr, pq);
161 488
162 initialized = 1; 489 initialized = 1;
163 } 490 }
164 491
165 std::ostream& 492 std::ostream&