GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
CollocWt.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cmath>
31
32#include <limits>
33#include <ostream>
34
35#include "Array.h"
36#include "CollocWt.h"
37#include "lo-error.h"
38#include "lo-mappers.h"
39
40// The following routines jcobi, dif, and dfopr are based on the code
41// found in Villadsen, J. and M. L. Michelsen, Solution of Differential
42// Equation Models by Polynomial Approximation, Prentice-Hall (1978)
43// pages 418-420.
44//
45// Translated to C++ by jwe.
46
48
49// Compute the first three derivatives of the node polynomial.
50//
51// n0 (alpha,beta) n1
52// p (x) = (x) * p (x) * (1 - x)
53// nt n
54//
55// at the interpolation points. Each of the parameters n0 and n1
56// may be given the value 0 or 1. The total number of points
57// nt = n + n0 + n1
58//
59// The values of root must be known before a call to dif is possible.
60// They may be computed using jcobi.
61
62static void dif (octave_idx_type nt, double *root, double *dif1,
63 double *dif2, double *dif3)
64{
65 // Evaluate derivatives of node polynomial using recursion formulas.
66
67 for (octave_idx_type i = 0; i < nt; i++)
68 {
69 double x = root[i];
70
71 dif1[i] = 1.0;
72 dif2[i] = 0.0;
73 dif3[i] = 0.0;
74
75 for (octave_idx_type j = 0; j < nt; j++)
76 {
77 if (j != i)
78 {
79 double y = x - root[j];
80
81 dif3[i] = y * dif3[i] + 3.0 * dif2[i];
82 dif2[i] = y * dif2[i] + 2.0 * dif1[i];
83 dif1[i] = y * dif1[i];
84 }
85 }
86 }
87}
88
89// Compute the zeros of the Jacobi polynomial.
90//
91// (alpha,beta)
92// p (x)
93// n
94//
95// Use dif to compute the derivatives of the node
96// polynomial
97//
98// n0 (alpha,beta) n1
99// p (x) = (x) * p (x) * (1 - x)
100// nt n
101//
102// at the interpolation points.
103//
104// See Villadsen and Michelsen, pages 131-132 and 418.
105//
106// Input parameters:
107//
108// nd : the dimension of the vectors dif1, dif2, dif3, and root
109//
110// n : the degree of the jacobi polynomial, (i.e., the number
111// of interior interpolation points)
112//
113// n0 : determines whether x = 0 is included as an
114// interpolation point
115//
116// n0 = 0 ==> x = 0 is not included
117// n0 = 1 ==> x = 0 is included
118//
119// n1 : determines whether x = 1 is included as an
120// interpolation point
121//
122// n1 = 0 ==> x = 1 is not included
123// n1 = 1 ==> x = 1 is included
124//
125// alpha : the value of alpha in the description of the jacobi
126// polynomial
127//
128// beta : the value of beta in the description of the jacobi
129// polynomial
130//
131// For a more complete explanation of alpha an beta, see Villadsen
132// and Michelsen, pages 57 to 59.
133//
134// Output parameters:
135//
136// root : one dimensional vector containing on exit the
137// n + n0 + n1 zeros of the node polynomial used in the
138// interpolation routine
139//
140// dif1 : one dimensional vector containing the first derivative
141// of the node polynomial at the zeros
142//
143// dif2 : one dimensional vector containing the second derivative
144// of the node polynomial at the zeros
145//
146// dif3 : one dimensional vector containing the third derivative
147// of the node polynomial at the zeros
148
149static bool
151 double alpha, double beta, double *dif1, double *dif2,
152 double *dif3, double *root)
153{
154 liboctave_panic_unless (n0 == 0 || n0 == 1);
155 liboctave_panic_unless (n1 == 0 || n1 == 1);
156
157 octave_idx_type nt = n + n0 + n1;
158
159 liboctave_panic_unless (nt >= 1);
160
161 // -- first evaluation of coefficients in recursion formulas.
162 // -- recursion coefficients are stored in dif1 and dif2.
163
164 double ab = alpha + beta;
165 double ad = beta - alpha;
166 double ap = beta * alpha;
167
168 dif1[0] = (ad / (ab + 2.0) + 1.0) / 2.0;
169 dif2[0] = 0.0;
170
171 if (n >= 2)
172 {
173 for (octave_idx_type i = 1; i < n; i++)
174 {
175 double z1 = i;
176 double z = ab + 2 * z1;
177
178 dif1[i] = (ab * ad / z / (z + 2.0) + 1.0) / 2.0;
179
180 if (i == 1)
181 dif2[i] = (ab + ap + z1) / z / z / (z + 1.0);
182 else
183 {
184 z *= z;
185 double y = z1 * (ab + z1);
186 y *= (ap + y);
187 dif2[i] = y / z / (z - 1.0);
188 }
189 }
190 }
191
192 // Root determination by Newton method with suppression of previously
193 // determined roots.
194
195 double x = 0.0;
196
197 for (octave_idx_type i = 0; i < n; i++)
198 {
199 bool done = false;
200
201 int k = 0;
202
203 while (! done)
204 {
205 double xd = 0.0;
206 double xn = 1.0;
207 double xd1 = 0.0;
208 double xn1 = 0.0;
209
210 for (octave_idx_type j = 0; j < n; j++)
211 {
212 double xp = (dif1[j] - x) * xn - dif2[j] * xd;
213 double xp1 = (dif1[j] - x) * xn1 - dif2[j] * xd1 - xn;
214
215 xd = xn;
216 xd1 = xn1;
217 xn = xp;
218 xn1 = xp1;
219 }
220
221 double zc = 1.0;
222 double z = xn / xn1;
223
224 if (i != 0)
225 {
226 for (octave_idx_type j = 1; j <= i; j++)
227 zc -= z / (x - root[j-1]);
228 }
229
230 z /= zc;
231 x -= z;
232
233 // Famous last words: 100 iterations should be more than
234 // enough in all cases.
235
236 if (++k > 100 || math::isnan (z))
237 return false;
238
239 if (std::abs (z) <= 100 * std::numeric_limits<double>::epsilon ())
240 done = true;
241 }
242
243 root[i] = x;
244 x += std::sqrt (std::numeric_limits<double>::epsilon ());
245 }
246
247 // Add interpolation points at x = 0 and/or x = 1.
248
249 if (n0 != 0)
250 {
251 for (octave_idx_type i = n; i > 0; i--)
252 root[i] = root[i-1];
253
254 root[0] = 0.0;
255 }
256
257 if (n1 != 0)
258 root[nt-1] = 1.0;
259
260 dif (nt, root, dif1, dif2, dif3);
261
262 return true;
263}
264
265// Compute derivative weights for orthogonal collocation.
266//
267// See Villadsen and Michelsen, pages 133-134, 419.
268//
269// Input parameters:
270//
271// nd : the dimension of the vectors dif1, dif2, dif3, and root
272//
273// n : the degree of the jacobi polynomial, (i.e., the number
274// of interior interpolation points)
275//
276// n0 : determines whether x = 0 is included as an
277// interpolation point
278//
279// n0 = 0 ==> x = 0 is not included
280// n0 = 1 ==> x = 0 is included
281//
282// n1 : determines whether x = 1 is included as an
283// interpolation point
284//
285// n1 = 0 ==> x = 1 is not included
286// n1 = 1 ==> x = 1 is included
287//
288// i : the index of the node for which the weights are to be
289// calculated
290//
291// id : indicator
292//
293// id = 1 ==> first derivative weights are computed
294// id = 2 ==> second derivative weights are computed
295// id = 3 ==> gaussian weights are computed (in this
296// case, the value of i is irrelevant)
297//
298// Output parameters:
299//
300// dif1 : one dimensional vector containing the first derivative
301// of the node polynomial at the zeros
302//
303// dif2 : one dimensional vector containing the second derivative
304// of the node polynomial at the zeros
305//
306// dif3 : one dimensional vector containing the third derivative
307// of the node polynomial at the zeros
308//
309// vect : one dimensional vector of computed weights
310
311static void
313 octave_idx_type i, octave_idx_type id, double *dif1,
314 double *dif2, double *dif3, double *root, double *vect)
315{
316 liboctave_panic_unless (n0 == 0 || n0 == 1);
317 liboctave_panic_unless (n1 == 0 || n1 == 1);
318
319 octave_idx_type nt = n + n0 + n1;
320
321 liboctave_panic_unless (nt >= 1);
322
323 liboctave_panic_unless (id == 1 || id == 2 || id == 3);
324
325 if (id != 3)
326 liboctave_panic_unless (i >= 0 && i < nt);
327
328 // Evaluate discretization matrices and Gaussian quadrature weights.
329 // Quadrature weights are normalized to sum to one.
330
331 if (id != 3)
332 {
333 for (octave_idx_type j = 0; j < nt; j++)
334 {
335 if (j == i)
336 {
337 if (id == 1)
338 vect[i] = dif2[i] / dif1[i] / 2.0;
339 else
340 vect[i] = dif3[i] / dif1[i] / 3.0;
341 }
342 else
343 {
344 double y = root[i] - root[j];
345
346 vect[j] = dif1[i] / dif1[j] / y;
347
348 if (id == 2)
349 vect[j] = vect[j] * (dif2[i] / dif1[i] - 2.0 / y);
350 }
351 }
352 }
353 else
354 {
355 double y = 0.0;
356
357 for (octave_idx_type j = 0; j < nt; j++)
358 {
359 double x = root[j];
360
361 double ax = x * (1.0 - x);
362
363 if (n0 == 0)
364 ax = ax / x / x;
365
366 if (n1 == 0)
367 ax = ax / (1.0 - x) / (1.0 - x);
368
369 vect[j] = ax / (dif1[j] * dif1[j]);
370
371 y += vect[j];
372 }
373
374 for (octave_idx_type j = 0; j < nt; j++)
375 vect[j] = vect[j] / y;
376 }
377}
378
379// Error handling.
380
381void
382CollocWt::error (const char *msg)
383{
384 (*current_liboctave_error_handler) ("CollocWt: fatal error '%s'", msg);
385}
386
389{
390 if (val >= m_rb)
391 error ("CollocWt: left bound greater than right bound");
392
393 m_lb = val;
394 m_initialized = 0;
395 return *this;
396}
397
400{
401 if (val <= m_lb)
402 error ("CollocWt: right bound less than left bound");
403
404 m_rb = val;
405 m_initialized = 0;
406 return *this;
407}
408
409void
411{
412 // Check for possible errors.
413
414 double wid = m_rb - m_lb;
415 if (wid <= 0.0)
416 {
417 error ("CollocWt: width less than or equal to zero");
418 }
419
421
422 if (nt < 0)
423 error ("CollocWt: total number of collocation points less than zero");
424 else if (nt == 0)
425 return;
426
427 Array<double> dif1 (dim_vector (nt, 1));
428 double *pdif1 = dif1.rwdata ();
429
430 Array<double> dif2 (dim_vector (nt, 1));
431 double *pdif2 = dif2.rwdata ();
432
433 Array<double> dif3 (dim_vector (nt, 1));
434 double *pdif3 = dif3.rwdata ();
435
436 Array<double> vect (dim_vector (nt, 1));
437 double *pvect = vect.rwdata ();
438
439 m_r.resize (nt, 1);
440 m_q.resize (nt, 1);
441 m_A.resize (nt, nt);
442 m_B.resize (nt, nt);
443
444 double *pr = m_r.rwdata ();
445
446 // Compute roots.
447
448 if (! jcobi (m_n, m_inc_left, m_inc_right, m_alpha, m_beta, pdif1,
449 pdif2, pdif3, pr))
450 error ("jcobi: newton iteration failed");
451
453
454 // First derivative weights.
455
456 id = 1;
457 for (octave_idx_type i = 0; i < nt; i++)
458 {
459 dfopr (m_n, m_inc_left, m_inc_right, i, id, pdif1, pdif2, pdif3,
460 pr, pvect);
461
462 for (octave_idx_type j = 0; j < nt; j++)
463 m_A(i, j) = vect(j);
464 }
465
466 // Second derivative weights.
467
468 id = 2;
469 for (octave_idx_type i = 0; i < nt; i++)
470 {
471 dfopr (m_n, m_inc_left, m_inc_right, i, id, pdif1, pdif2, pdif3,
472 pr, pvect);
473
474 for (octave_idx_type j = 0; j < nt; j++)
475 m_B(i, j) = vect(j);
476 }
477
478 // Gaussian quadrature weights.
479
480 id = 3;
481 double *pq = m_q.rwdata ();
482 dfopr (m_n, m_inc_left, m_inc_right, id, id, pdif1, pdif2, pdif3, pr, pq);
483
484 m_initialized = 1;
485}
486
487std::ostream&
488operator << (std::ostream& os, const CollocWt& a)
489{
490 if (a.left_included ())
491 os << "left boundary is included\n";
492 else
493 os << "left boundary is not included\n";
494
495 if (a.right_included ())
496 os << "right boundary is included\n";
497 else
498 os << "right boundary is not included\n";
499
500 os << "\n";
501
502 os << a.m_alpha << ' ' << a.m_beta << "\n\n"
503 << a.m_r << "\n\n"
504 << a.m_q << "\n\n"
505 << a.m_A << "\n"
506 << a.m_B << "\n";
507
508 return os;
509}
510
511OCTAVE_END_NAMESPACE(octave)
std::ostream & operator<<(std::ostream &os, const CollocWt &a)
Definition CollocWt.cc:488
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
T * rwdata()
Size of the specified dimension.
ColumnVector m_q
Definition CollocWt.h:198
Matrix m_A
Definition CollocWt.h:200
octave_idx_type left_included() const
Definition CollocWt.h:137
ColumnVector m_r
Definition CollocWt.h:197
Matrix m_B
Definition CollocWt.h:201
void init()
Definition CollocWt.cc:410
double m_rb
Definition CollocWt.h:192
octave_idx_type m_inc_left
Definition CollocWt.h:188
void error(const char *msg)
Definition CollocWt.cc:382
double m_alpha
Definition CollocWt.h:194
octave_idx_type m_inc_right
Definition CollocWt.h:189
bool m_initialized
Definition CollocWt.h:203
double m_lb
Definition CollocWt.h:191
double m_beta
Definition CollocWt.h:195
octave_idx_type right_included() const
Definition CollocWt.h:138
CollocWt & set_left(double val)
Definition CollocWt.cc:388
octave_idx_type m_n
Definition CollocWt.h:186
CollocWt & set_right(double val)
Definition CollocWt.cc:399
void resize(octave_idx_type n, const double &rfv=0)
Definition dColVector.h:112
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition dMatrix.h:156
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define liboctave_panic_unless(cond)
Definition lo-error.h:102
F77_RET_T const F77_DBLE * x