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