Mercurial > octave-nkf
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& |