Nektar++
Polylib.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: Polylib.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description:
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include "Polylib.h"
36#include <cfloat>
37#include <cmath>
38#include <complex>
39#include <cstdio>
40
41#include <boost/core/ignore_unused.hpp>
42
44/// Maximum number of iterations in polynomial defalation routine Jacobz
45#define STOP 30
46/// Precision tolerance for two points to be similar
47#define EPS 100 * DBL_EPSILON
48/// return the sign(b)*a
49#define sign(a, b) ((b) < 0 ? -fabs(a) : fabs(a))
50
51namespace Polylib
52{
53
54/// The following function is used to circumvent/reduce "Subtractive
55/// Cancellation" The expression 1/dz is replaced by optinvsub(.,.) Added on 26
56/// April 2017
57double optdiff(double xl, double xr)
58{
59 double m_xln, m_xrn;
60 int m_expn;
61 int m_digits = static_cast<int>(fabs(floor(log10(DBL_EPSILON))) - 1);
62
63 if (fabs(xl - xr) < 1.e-4)
64 {
65
66 m_expn = static_cast<int>(floor(log10(fabs(xl - xr))));
67 m_xln = xl * powl(10.0L, -m_expn) -
68 floor(xl * powl(10.0L,
69 -m_expn)); // substract the digits overlap part
70 m_xrn =
71 xr * powl(10.0L, -m_expn) -
72 floor(xl *
73 powl(10.0L,
74 -m_expn)); // substract the common digits overlap part
75 m_xln =
76 round(m_xln * powl(10.0L, m_digits + m_expn)); // git rid of rubbish
77 m_xrn = round(m_xrn * powl(10.0L, m_digits + m_expn));
78
79 return powl(10.0L, -m_digits) * (m_xln - m_xrn);
80 }
81 else
82 {
83 return (xl - xr);
84 }
85}
86
87double laginterp(double z, int j, const double *zj, int np)
88{
89 double temp = 1.0;
90 for (int i = 0; i < np; i++)
91 {
92 if (j != i)
93 {
94 temp *= optdiff(z, zj[i]) / (zj[j] - zj[i]);
95 }
96 }
97 return temp;
98}
99
100double laginterpderiv(double z, int k, const double *zj, int np)
101{
102 double y = 0.0;
103 for (int j = 0; j < np; ++j)
104 {
105 if (j != k)
106 {
107 double tmp = 1.0;
108 for (int i = 0; i < np; ++i)
109 {
110 if (i != k)
111 {
112 if (i != j)
113 {
114 tmp *= (z - zj[i]);
115 }
116 tmp /= (zj[k] - zj[i]);
117 }
118 }
119 y += tmp;
120 }
121 }
122 return y;
123}
124
125/// Define whether to use polynomial deflation (1) or tridiagonal solver (0).
126#define POLYNOMIAL_DEFLATION 0
127
128#ifdef POLYNOMIAL_DEFLATION
129/// zero determination using Newton iteration with polynomial deflation
130#define jacobz(n, z, alpha, beta) Jacobz(n, z, alpha, beta)
131#else
132/// zero determination using eigenvalues of tridiagaonl matrix
133#define jacobz(n, z, alpha, beta) JacZeros(n, z, alpha, beta)
134#endif
135
136/* local functions */
137static void Jacobz(const int n, double *z, const double alpha,
138 const double beta);
139static void RecCoeff(const int, double *, double *, const double, const double);
140static void TriQL(const int, double *, double *, double **);
141void JKMatrix(int, double *, double *);
142void chri1(int, double *, double *, double *, double *, double);
143
144/**
145\brief Gauss-Jacobi zeros and weights.
146
147\li Generate \a np Gauss Jacobi zeros, \a z, and weights,\a w,
148associated with the Jacobi polynomial \f$ P^{\alpha,\beta}_{np}(z)
149\f$,
150
151\li Exact for polynomials of order \a 2np-1 or less
152*/
153
154void zwgj(double *z, double *w, const int np, const double alpha,
155 const double beta)
156{
157 int i;
158 double fac, one = 1.0, two = 2.0, apb = alpha + beta;
159
160 jacobz(np, z, alpha, beta);
161 jacobd(np, z, w, np, alpha, beta);
162
163 fac = pow(two, apb + one) * gammaFracGammaF(np + 1, alpha, np + 1, 0.0) *
164 gammaFracGammaF(np + 1, beta, np + 1, apb);
165
166 for (i = 0; i < np; ++i)
167 w[i] = fac / (w[i] * w[i] * (one - z[i] * z[i]));
168
169 return;
170}
171
172/**
173\brief Gauss-Radau-Jacobi zeros and weights with end point at \a z=-1.
174
175\li Generate \a np Gauss-Radau-Jacobi zeros, \a z, and weights,\a w,
176associated with the polynomial \f$(1+z) P^{\alpha,\beta+1}_{np-1}(z)
177\f$.
178
179\li Exact for polynomials of order \a 2np-2 or less
180*/
181
182void zwgrjm(double *z, double *w, const int np, const double alpha,
183 const double beta)
184{
185
186 if (np == 1)
187 {
188 z[0] = 0.0;
189 w[0] = 2.0;
190 }
191 else
192 {
193 int i;
194 double fac, one = 1.0, two = 2.0, apb = alpha + beta;
195
196 z[0] = -one;
197 jacobz(np - 1, z + 1, alpha, beta + 1);
198 jacobfd(np, z, w, NULL, np - 1, alpha, beta);
199
200 fac = pow(two, apb) * gammaFracGammaF(np, alpha, np, 0.0) *
201 gammaFracGammaF(np, beta, np + 1, apb);
202 fac /= (beta + np);
203
204 for (i = 0; i < np; ++i)
205 w[i] = fac * (1 - z[i]) / (w[i] * w[i]);
206 w[0] *= (beta + one);
207 }
208
209 return;
210}
211
212/**
213\brief Gauss-Radau-Jacobi zeros and weights with end point at \a z=1
214
215
216\li Generate \a np Gauss-Radau-Jacobi zeros, \a z, and weights,\a w,
217associated with the polynomial \f$(1-z) P^{\alpha+1,\beta}_{np-1}(z)
218\f$.
219
220\li Exact for polynomials of order \a 2np-2 or less
221*/
222
223void zwgrjp(double *z, double *w, const int np, const double alpha,
224 const double beta)
225{
226
227 if (np == 1)
228 {
229 z[0] = 0.0;
230 w[0] = 2.0;
231 }
232 else
233 {
234 int i;
235 double fac, one = 1.0, two = 2.0, apb = alpha + beta;
236
237 jacobz(np - 1, z, alpha + 1, beta);
238 z[np - 1] = one;
239 jacobfd(np, z, w, NULL, np - 1, alpha, beta);
240
241 fac = pow(two, apb) * gammaFracGammaF(np, alpha, np, 0.0) *
242 gammaFracGammaF(np, beta, np + 1, apb);
243 fac /= (alpha + np);
244
245 for (i = 0; i < np; ++i)
246 w[i] = fac * (1 + z[i]) / (w[i] * w[i]);
247 w[np - 1] *= (alpha + one);
248 }
249
250 return;
251}
252
253/**
254\brief Gauss-Lobatto-Jacobi zeros and weights with end point at \a z=-1,\a 1
255
256
257\li Generate \a np Gauss-Lobatto-Jacobi points, \a z, and weights, \a w,
258associated with polynomial \f$ (1-z)(1+z) P^{\alpha+1,\beta+1}_{np-2}(z) \f$
259\li Exact for polynomials of order \a 2np-3 or less
260*/
261
262void zwglj(double *z, double *w, const int np, const double alpha,
263 const double beta)
264{
265
266 if (np == 1)
267 {
268 z[0] = 0.0;
269 w[0] = 2.0;
270 }
271 else if (np == 2)
272 {
273 z[0] = -1.0;
274 z[1] = 1.0;
275
276 w[0] = 1.0;
277 w[1] = 1.0;
278 }
279 else
280 {
281 int i;
282 double fac, one = 1.0, apb = alpha + beta, two = 2.0;
283
284 z[0] = -one;
285 z[np - 1] = one;
286 jacobz(np - 2, z + 1, alpha + one, beta + one);
287 jacobfd(np, z, w, NULL, np - 1, alpha, beta);
288
289 fac = pow(two, apb + 1) * gammaFracGammaF(np, alpha, np, 0.0) *
290 gammaFracGammaF(np, beta, np + 1, apb);
291 fac /= (np - 1);
292
293 for (i = 0; i < np; ++i)
294 w[i] = fac / (w[i] * w[i]);
295 w[0] *= (beta + one);
296 w[np - 1] *= (alpha + one);
297 }
298
299 return;
300}
301
302/**
303\brief Gauss-Kronrod-Jacobi zeros and weights.
304
305\li Generate \a npt=2*np+1 Gauss-Kronrod Jacobi zeros, \a z, and weights,\a w,
306associated with the Jacobi polynomial \f$ P^{\alpha,\beta}_{np}(z)
307\f$,
308
309\li Exact for polynomials of order \a 3np+1 or less
310*/
311void zwgk(double *z, double *w, const int npt, const double alpha,
312 const double beta)
313{
314
315 int np = (npt - 1) / 2;
316
317 int i, j;
318
319 // number of kronrod points associated with the np gauss rule
320 int kpoints = 2 * np + 1;
321
322 // Define the number of required recurrence coefficents
323 int ncoeffs = (int)floor(3.0 * (np + 1) / 2);
324
325 // Define arrays for the recurrence coefficients
326 // We will use these arrays for the Kronrod results too, hence the
327 // reason for the size of the arrays
328 double *a = new double[kpoints];
329 double *b = new double[kpoints];
330
331 // Initialize a and b to zero
332 for (i = 0; i < kpoints; i++)
333 {
334 a[i] = 0.0;
335 b[i] = 0.0;
336 }
337
338 // Call the routine to calculate the recurrence coefficients
339 RecCoeff(ncoeffs, a, b, alpha, beta);
340
341 // Call the routine to caluclate the jacobi-Kronrod matrix
342 JKMatrix(np, a, b);
343
344 // Set up the identity matrix
345 double **zmatrix = new double *[kpoints];
346 for (i = 0; i < kpoints; i++)
347 {
348 zmatrix[i] = new double[kpoints];
349 for (j = 0; j < kpoints; j++)
350 {
351 zmatrix[i][j] = 0.0;
352 }
353 }
354 for (i = 0; i < kpoints; i++)
355 {
356 zmatrix[i][i] = 1.0;
357 }
358
359 // Calculte the points and weights
360 TriQL(kpoints, a, b, zmatrix);
361
362 for (i = 0; i < kpoints; i++)
363 {
364 z[i] = a[i];
365 w[i] = b[i];
366 }
367 delete[] a;
368 delete[] b;
369 for (i = 0; i < kpoints; i++)
370 {
371 delete[] zmatrix[i];
372 }
373 delete[] zmatrix;
374}
375
376/**
377\brief Gauss-Radau-Kronrod-Jacobi zeros and weights.
378
379\li Generate \a npt=2*np Radau-Kronrod Jacobi zeros, \a z, and weights,\a w,
380associated with the Jacobi polynomial \f$ P^{\alpha,\beta}_{np}(z)
381\f$,
382*/
383void zwrk(double *z, double *w, const int npt, const double alpha,
384 const double beta)
385{
386
387 int np = npt / 2;
388
389 if (np < 2)
390 {
391 fprintf(stderr, "too few points in formula\n");
392 return;
393 }
394
395 double end0 = -1;
396
397 int i, j;
398
399 // number of kronrod points associated with the np gauss rule
400 int kpoints = 2 * np;
401
402 // Define the number of required recurrence coefficents
403 int ncoeffs = (int)ceil(3.0 * np / 2);
404
405 // Define arrays for the recurrence coefficients
406 double *a = new double[ncoeffs + 1];
407 double *b = new double[ncoeffs + 1];
408
409 // Initialize a and b to zero
410 for (i = 0; i < ncoeffs + 1; i++)
411 {
412 a[i] = 0.0;
413 b[i] = 0.0;
414 }
415
416 // Call the routine to calculate the recurrence coefficients
417 RecCoeff(ncoeffs, a, b, alpha, beta);
418
419 double *a0 = new double[ncoeffs];
420 double *b0 = new double[ncoeffs];
421
422 chri1(ncoeffs, a, b, a0, b0, end0);
423
424 double s = b0[0] / fabs(b0[0]);
425 b0[0] = s * b0[0];
426
427 // Finding the 2*np-1 gauss-kronrod points
428 double *z1 = new double[2 * np - 1];
429 double *w1 = new double[2 * np - 1];
430 for (i = 0; i < ncoeffs; i++)
431 {
432 z1[i] = a0[i];
433 w1[i] = b0[i];
434 }
435 JKMatrix(np - 1, z1, w1);
436 // Set up the identity matrix
437 double **zmatrix = new double *[2 * np - 1];
438 for (i = 0; i < 2 * np - 1; i++)
439 {
440 zmatrix[i] = new double[2 * np - 1];
441 for (j = 0; j < 2 * np - 1; j++)
442 {
443 zmatrix[i][j] = 0.0;
444 }
445 }
446 for (i = 0; i < 2 * np - 1; i++)
447 {
448 zmatrix[i][i] = 1.0;
449 }
450
451 // Calculate the points and weights
452 TriQL(2 * np - 1, z1, w1, zmatrix);
453
454 double sumW1 = 0.0;
455 for (i = 0; i < 2 * np - 1; i++)
456 {
457 w1[i] = s * w1[i] / (z1[i] - end0);
458 sumW1 += w1[i];
459 }
460
461 z[0] = end0;
462 w[0] = b[0] - sumW1;
463 for (i = 1; i < kpoints; i++)
464 {
465 z[i] = z1[i - 1];
466 w[i] = w1[i - 1];
467 }
468
469 delete[] a;
470 delete[] b;
471 delete[] a0;
472 delete[] b0;
473 delete[] z1;
474 delete[] w1;
475 for (i = 0; i < 2 * np - 1; i++)
476 {
477 delete[] zmatrix[i];
478 }
479 delete[] zmatrix;
480}
481
482/**
483\brief Gauss-Lobatto-Kronrod-Jacobi zeros and weights.
484
485\li Generate \a npt=2*np-1 Lobatto-Kronrod Jacobi zeros, \a z, and weights,\a w,
486associated with the Jacobi polynomial \f$ P^{\alpha,\beta}_{np}(z)
487\f$,
488*/
489void zwlk(double *z, double *w, const int npt, const double alpha,
490 const double beta)
491{
492
493 int np = (npt + 1) / 2;
494
495 if (np < 4)
496 {
497 fprintf(stderr, "too few points in formula\n");
498 return;
499 }
500
501 double endl = -1;
502 double endr = 1;
503 int i, j;
504
505 // number of kronrod points associated with the np gauss rule
506 int kpoints = 2 * np - 1;
507
508 // Define the number of required recurrence coefficents
509 int ncoeffs = (int)ceil(3.0 * np / 2) - 1;
510
511 // Define arrays for the recurrence coefficients
512 double *a = new double[ncoeffs + 1];
513 double *b = new double[ncoeffs + 1];
514
515 // Initialize a and b to zero
516 for (i = 0; i < ncoeffs + 1; i++)
517 {
518 a[i] = 0.0;
519 b[i] = 0.0;
520 }
521
522 // Call the routine to calculate the recurrence coefficients
523 RecCoeff(ncoeffs, a, b, alpha, beta);
524
525 double *a0 = new double[ncoeffs];
526 double *b0 = new double[ncoeffs];
527
528 chri1(ncoeffs, a, b, a0, b0, endl);
529
530 double *a1 = new double[ncoeffs - 1];
531 double *b1 = new double[ncoeffs - 1];
532
533 chri1(ncoeffs - 1, a0, b0, a1, b1, endr);
534
535 double s = b1[0] / fabs(b1[0]);
536 b1[0] = s * b1[0];
537
538 // Finding the 2*np-1 gauss-kronrod points
539 double *z1 = new double[2 * np - 3];
540 double *w1 = new double[2 * np - 3];
541 for (i = 0; i < ncoeffs; i++)
542 {
543 z1[i] = a1[i];
544 w1[i] = b1[i];
545 }
546 JKMatrix(np - 2, z1, w1);
547 // Set up the identity matrix
548 double **zmatrix = new double *[2 * np - 3];
549 for (i = 0; i < 2 * np - 3; i++)
550 {
551 zmatrix[i] = new double[2 * np - 3];
552 for (j = 0; j < 2 * np - 3; j++)
553 {
554 zmatrix[i][j] = 0.0;
555 }
556 }
557 for (i = 0; i < 2 * np - 3; i++)
558 {
559 zmatrix[i][i] = 1.0;
560 }
561
562 // Calculate the points and weights
563 TriQL(2 * np - 3, z1, w1, zmatrix);
564
565 double sumW1 = 0.0;
566 double sumW1Z1 = 0.0;
567 for (i = 0; i < 2 * np - 3; i++)
568 {
569 w1[i] = s * w1[i] / (z1[i] - endl) / (z1[i] - endr);
570 sumW1 += w1[i];
571 sumW1Z1 += z1[i] * w1[i];
572 }
573
574 double c0 = b[0] - sumW1;
575 double c1 = a[0] * b[0] - sumW1Z1;
576
577 z[0] = endl;
578 z[2 * np - 2] = endr;
579 w[0] = (c0 * endr - c1) / (endr - endl);
580 w[2 * np - 2] = (c1 - c0 * endl) / (endr - endl);
581
582 for (i = 1; i < kpoints - 1; i++)
583 {
584 z[i] = z1[i - 1];
585 w[i] = w1[i - 1];
586 }
587 delete[] a;
588 delete[] b;
589 delete[] a0;
590 delete[] b0;
591 delete[] a1;
592 delete[] b1;
593 delete[] z1;
594 delete[] w1;
595 for (i = 0; i < 2 * np - 3; i++)
596 {
597 delete[] zmatrix[i];
598 }
599 delete[] zmatrix;
600}
601
602/**
603\brief Compute the Integration Matrix.
604*/
605void Qg(double *Q, const double *z, const int np)
606{
607
608 if (np <= 0)
609 {
610 Q[0] = 0.0;
611 }
612 else
613 {
614 int i, j, k;
615 double *pd;
616
617 pd = (double *)malloc(np * sizeof(double));
618
619 for (i = 0; i < np; i++)
620 {
621 polycoeffs(pd, z, i, np);
622 for (j = 0; j < np; j++)
623 {
624 Q[j * np + i] = 0.0;
625 for (k = 0; k < np; k++)
626 {
627 Q[j * np + i] += pd[k] / (k + 1) * pow(z[j], k + 1);
628 }
629 }
630 }
631 free(pd);
632 }
633 return;
634}
635
636/**
637\brief Compute the Derivative Matrix and its transpose associated
638with the Gauss-Jacobi zeros.
639
640\li Compute the derivative matrix, \a d, and its transpose, \a dt,
641associated with the n_th order Lagrangian interpolants through the
642\a np Gauss-Jacobi points \a z such that \n
643\f$ \frac{du}{dz}(z[i]) = \sum_{j=0}^{np-1} D[i*np+j] u(z[j]) \f$
644
645*/
646
647void Dgj(double *D, const double *z, const int np, const double alpha,
648 const double beta)
649{
650
651 double one = 1.0, two = 2.0;
652
653 if (np <= 0)
654 {
655 D[0] = 0.0;
656 }
657 else
658 {
659 int i, j;
660 double *pd;
661
662 pd = (double *)malloc(np * sizeof(double));
663 jacobd(np, z, pd, np, alpha, beta);
664
665 for (i = 0; i < np; i++)
666 {
667 for (j = 0; j < np; j++)
668 {
669
670 if (i != j)
671 D[i * np + j] = pd[j] / (pd[i] * (z[j] - z[i]));
672 else
673 D[i * np + j] =
674 (alpha - beta + (alpha + beta + two) * z[j]) /
675 (two * (one - z[j] * z[j]));
676 }
677 }
678 free(pd);
679 }
680 return;
681}
682
683/**
684\brief Compute the Derivative Matrix and its transpose associated
685with the Gauss-Radau-Jacobi zeros with a zero at \a z=-1.
686
687\li Compute the derivative matrix, \a d, associated with the n_th
688order Lagrangian interpolants through the \a np Gauss-Radau-Jacobi
689points \a z such that \n \f$ \frac{du}{dz}(z[i]) =
690\sum_{j=0}^{np-1} D[i*np+j] u(z[j]) \f$
691
692*/
693
694void Dgrjm(double *D, const double *z, const int np, const double alpha,
695 const double beta)
696{
697
698 if (np <= 0)
699 {
700 D[0] = 0.0;
701 }
702 else
703 {
704 int i, j;
705 double one = 1.0, two = 2.0;
706 double *pd;
707
708 pd = (double *)malloc(np * sizeof(double));
709
710 pd[0] = pow(-one, np - 1) * gammaFracGammaF(np + 1, beta, np, 0.0);
711 pd[0] /= gammaF(beta + two);
712 jacobd(np - 1, z + 1, pd + 1, np - 1, alpha, beta + 1);
713 for (i = 1; i < np; ++i)
714 pd[i] *= (1 + z[i]);
715
716 for (i = 0; i < np; i++)
717 {
718 for (j = 0; j < np; j++)
719 {
720 if (i != j)
721 D[i * np + j] = pd[j] / (pd[i] * (z[j] - z[i]));
722 else
723 {
724 if (j == 0)
725 D[i * np + j] = -(np + alpha + beta + one) *
726 (np - one) / (two * (beta + two));
727 else
728 D[i * np + j] =
729 (alpha - beta + one + (alpha + beta + one) * z[j]) /
730 (two * (one - z[j] * z[j]));
731 }
732 }
733 }
734 free(pd);
735 }
736
737 return;
738}
739
740/**
741\brief Compute the Derivative Matrix associated with the
742Gauss-Radau-Jacobi zeros with a zero at \a z=1.
743
744\li Compute the derivative matrix, \a d, associated with the n_th
745order Lagrangian interpolants through the \a np Gauss-Radau-Jacobi
746points \a z such that \n \f$ \frac{du}{dz}(z[i]) =
747\sum_{j=0}^{np-1} D[i*np+j] u(z[j]) \f$
748*/
749
750void Dgrjp(double *D, const double *z, const int np, const double alpha,
751 const double beta)
752{
753
754 if (np <= 0)
755 {
756 D[0] = 0.0;
757 }
758 else
759 {
760 int i, j;
761 double one = 1.0, two = 2.0;
762 double *pd;
763
764 pd = (double *)malloc(np * sizeof(double));
765
766 jacobd(np - 1, z, pd, np - 1, alpha + 1, beta);
767 for (i = 0; i < np - 1; ++i)
768 pd[i] *= (1 - z[i]);
769 pd[np - 1] = -gammaFracGammaF(np + 1, alpha, np, 0.0);
770 pd[np - 1] /= gammaF(alpha + two);
771
772 for (i = 0; i < np; i++)
773 {
774 for (j = 0; j < np; j++)
775 {
776 if (i != j)
777 D[i * np + j] = pd[j] / (pd[i] * (z[j] - z[i]));
778 else
779 {
780 if (j == np - 1)
781 D[i * np + j] = (np + alpha + beta + one) * (np - one) /
782 (two * (alpha + two));
783 else
784 D[i * np + j] =
785 (alpha - beta - one + (alpha + beta + one) * z[j]) /
786 (two * (one - z[j] * z[j]));
787 }
788 }
789 }
790 free(pd);
791 }
792
793 return;
794}
795
796/**
797\brief Compute the Derivative Matrix associated with the
798Gauss-Lobatto-Jacobi zeros.
799
800\li Compute the derivative matrix, \a d, associated with the n_th
801order Lagrange interpolants through the \a np
802Gauss-Lobatto-Jacobi points \a z such that \n \f$
803\frac{du}{dz}(z[i]) = \sum_{j=0}^{np-1} D[i*np+j] u(z[j]) \f$
804
805*/
806
807void Dglj(double *D, const double *z, const int np, const double alpha,
808 const double beta)
809{
810 if (np <= 1)
811 {
812 D[0] = 0.0;
813 }
814 else
815 {
816 int i, j;
817 double one = 1.0, two = 2.0;
818 double *pd;
819
820 pd = (double *)malloc(np * sizeof(double));
821
822 pd[0] = two * pow(-one, np) * gammaFracGammaF(np, beta, np - 1, 0.0);
823 pd[0] /= gammaF(beta + two);
824 jacobd(np - 2, z + 1, pd + 1, np - 2, alpha + 1, beta + 1);
825 for (i = 1; i < np - 1; ++i)
826 pd[i] *= (one - z[i] * z[i]);
827 pd[np - 1] = -two * gammaFracGammaF(np, alpha, np - 1, 0.0);
828 pd[np - 1] /= gammaF(alpha + two);
829
830 for (i = 0; i < np; i++)
831 {
832 for (j = 0; j < np; j++)
833 {
834 if (i != j)
835 D[i * np + j] = pd[j] / (pd[i] * (z[j] - z[i]));
836 else
837 {
838 if (j == 0)
839 D[i * np + j] =
840 (alpha - (np - 1) * (np + alpha + beta)) /
841 (two * (beta + two));
842 else if (j == np - 1)
843 D[i * np + j] =
844 -(beta - (np - 1) * (np + alpha + beta)) /
845 (two * (alpha + two));
846 else
847 D[i * np + j] = (alpha - beta + (alpha + beta) * z[j]) /
848 (two * (one - z[j] * z[j]));
849 }
850 }
851 }
852 free(pd);
853 }
854
855 return;
856}
857
858/**
859\brief Compute the value of the \a i th Lagrangian interpolant through
860the \a np Gauss-Jacobi points \a zgj at the arbitrary location \a z.
861
862\li \f$ -1 \leq z \leq 1 \f$
863
864\li Uses the defintion of the Lagrangian interpolant:\n
865%
866\f$ \begin{array}{rcl}
867h_j(z) = \left\{ \begin{array}{ll}
868\displaystyle \frac{P_{np}^{\alpha,\beta}(z)}
869{[P_{np}^{\alpha,\beta}(z_j)]^\prime
870(z-z_j)} & \mbox{if $z \ne z_j$}\\
871& \\
8721 & \mbox{if $z=z_j$}
873\end{array}
874\right.
875\end{array} \f$
876*/
877
878double hgj(const int i, const double z, const double *zgj, const int np,
879 const double alpha, const double beta)
880{
881 boost::ignore_unused(alpha, beta);
882 double zi, dz;
883
884 zi = *(zgj + i);
885 dz = z - zi;
886 if (fabs(dz) < EPS)
887 return 1.0;
888
889 return laginterp(z, i, zgj, np);
890}
891
892/**
893\brief Compute the value of the \a i th Lagrangian interpolant through the
894\a np Gauss-Radau-Jacobi points \a zgrj at the arbitrary location
895\a z. This routine assumes \a zgrj includes the point \a -1.
896
897\li \f$ -1 \leq z \leq 1 \f$
898
899\li Uses the defintion of the Lagrangian interpolant:\n
900%
901\f$ \begin{array}{rcl}
902h_j(z) = \left\{ \begin{array}{ll}
903\displaystyle \frac{(1+z) P_{np-1}^{\alpha,\beta+1}(z)}
904{((1+z_j) [P_{np-1}^{\alpha,\beta+1}(z_j)]^\prime +
905P_{np-1}^{\alpha,\beta+1}(z_j) ) (z-z_j)} & \mbox{if $z \ne z_j$}\\
906& \\
9071 & \mbox{if $z=z_j$}
908\end{array}
909\right.
910\end{array} \f$
911*/
912
913double hgrjm(const int i, const double z, const double *zgrj, const int np,
914 const double alpha, const double beta)
915{
916 boost::ignore_unused(alpha, beta);
917
918 double zi, dz;
919
920 zi = *(zgrj + i);
921 dz = z - zi;
922 if (fabs(dz) < EPS)
923 return 1.0;
924
925 return laginterp(z, i, zgrj, np);
926}
927
928/**
929\brief Compute the value of the \a i th Lagrangian interpolant through the
930\a np Gauss-Radau-Jacobi points \a zgrj at the arbitrary location
931\a z. This routine assumes \a zgrj includes the point \a +1.
932
933\li \f$ -1 \leq z \leq 1 \f$
934
935\li Uses the defintion of the Lagrangian interpolant:\n
936%
937\f$ \begin{array}{rcl}
938h_j(z) = \left\{ \begin{array}{ll}
939\displaystyle \frac{(1-z) P_{np-1}^{\alpha+1,\beta}(z)}
940{((1-z_j) [P_{np-1}^{\alpha+1,\beta}(z_j)]^\prime -
941P_{np-1}^{\alpha+1,\beta}(z_j) ) (z-z_j)} & \mbox{if $z \ne z_j$}\\
942& \\
9431 & \mbox{if $z=z_j$}
944\end{array}
945\right.
946\end{array} \f$
947*/
948
949double hgrjp(const int i, const double z, const double *zgrj, const int np,
950 const double alpha, const double beta)
951{
952 boost::ignore_unused(alpha, beta);
953 double zi, dz;
954
955 zi = *(zgrj + i);
956 dz = z - zi;
957 if (fabs(dz) < EPS)
958 return 1.0;
959
960 return laginterp(z, i, zgrj, np);
961}
962
963/**
964\brief Compute the value of the \a i th Lagrangian interpolant through the
965\a np Gauss-Lobatto-Jacobi points \a zgrj at the arbitrary location
966\a z.
967
968\li \f$ -1 \leq z \leq 1 \f$
969
970\li Uses the defintion of the Lagrangian interpolant:\n
971%
972\f$ \begin{array}{rcl}
973h_j(z) = \left\{ \begin{array}{ll}
974\displaystyle \frac{(1-z^2) P_{np-2}^{\alpha+1,\beta+1}(z)}
975{((1-z^2_j) [P_{np-2}^{\alpha+1,\beta+1}(z_j)]^\prime -
9762 z_j P_{np-2}^{\alpha+1,\beta+1}(z_j) ) (z-z_j)}&\mbox{if $z \ne z_j$}\\
977& \\
9781 & \mbox{if $z=z_j$}
979\end{array}
980\right.
981\end{array} \f$
982*/
983
984double hglj(const int i, const double z, const double *zglj, const int np,
985 const double alpha, const double beta)
986{
987 boost::ignore_unused(alpha, beta);
988
989 double zi, dz;
990
991 zi = *(zglj + i);
992 dz = z - zi;
993 if (fabs(dz) < EPS)
994 return 1.0;
995
996 return laginterp(z, i, zglj, np);
997}
998
999/**
1000\brief Interpolation Operator from Gauss-Jacobi points to an
1001arbitrary distribution at points \a zm
1002
1003\li Computes the one-dimensional interpolation matrix, \a im, to
1004interpolate a function from at Gauss-Jacobi distribution of \a nz
1005zeros \a zgrj to an arbitrary distribution of \a mz points \a zm, i.e.\n
1006\f$
1007u(zm[i]) = \sum_{j=0}^{nz-1} im[i*nz+j] \ u(zgj[j])
1008\f$
1009
1010*/
1011
1012void Imgj(double *im, const double *zgj, const double *zm, const int nz,
1013 const int mz, const double alpha, const double beta)
1014{
1015 double zp;
1016 int i, j;
1017
1018 for (i = 0; i < nz; ++i)
1019 {
1020 for (j = 0; j < mz; ++j)
1021 {
1022 zp = zm[j];
1023 im[i * mz + j] = hgj(i, zp, zgj, nz, alpha, beta);
1024 }
1025 }
1026
1027 return;
1028}
1029
1030/**
1031\brief Interpolation Operator from Gauss-Radau-Jacobi points
1032(including \a z=-1) to an arbitrary distrubtion at points \a zm
1033
1034\li Computes the one-dimensional interpolation matrix, \a im, to
1035interpolate a function from at Gauss-Radau-Jacobi distribution of
1036\a nz zeros \a zgrj (where \a zgrj[0]=-1) to an arbitrary
1037distribution of \a mz points \a zm, i.e.
1038\n
1039\f$ u(zm[i]) = \sum_{j=0}^{nz-1} im[i*nz+j] \ u(zgj[j]) \f$
1040
1041*/
1042
1043void Imgrjm(double *im, const double *zgrj, const double *zm, const int nz,
1044 const int mz, const double alpha, const double beta)
1045{
1046 double zp;
1047 int i, j;
1048
1049 for (i = 0; i < nz; i++)
1050 {
1051 for (j = 0; j < mz; j++)
1052 {
1053 zp = zm[j];
1054 im[i * mz + j] = hgrjm(i, zp, zgrj, nz, alpha, beta);
1055 }
1056 }
1057
1058 return;
1059}
1060
1061/**
1062\brief Interpolation Operator from Gauss-Radau-Jacobi points
1063(including \a z=1) to an arbitrary distrubtion at points \a zm
1064
1065\li Computes the one-dimensional interpolation matrix, \a im, to
1066interpolate a function from at Gauss-Radau-Jacobi distribution of
1067\a nz zeros \a zgrj (where \a zgrj[nz-1]=1) to an arbitrary
1068distribution of \a mz points \a zm, i.e.
1069\n
1070\f$ u(zm[i]) = \sum_{j=0}^{nz-1} im[i*nz+j] \ u(zgj[j]) \f$
1071
1072*/
1073
1074void Imgrjp(double *im, const double *zgrj, const double *zm, const int nz,
1075 const int mz, const double alpha, const double beta)
1076{
1077 double zp;
1078 int i, j;
1079
1080 for (i = 0; i < nz; i++)
1081 {
1082 for (j = 0; j < mz; j++)
1083 {
1084 zp = zm[j];
1085 im[i * mz + j] = hgrjp(i, zp, zgrj, nz, alpha, beta);
1086 }
1087 }
1088
1089 return;
1090}
1091
1092/**
1093\brief Interpolation Operator from Gauss-Lobatto-Jacobi points
1094to an arbitrary distrubtion at points \a zm
1095
1096\li Computes the one-dimensional interpolation matrix, \a im, to
1097interpolate a function from at Gauss-Lobatto-Jacobi distribution of
1098\a nz zeros \a zgrj (where \a zgrj[0]=-1) to an arbitrary
1099distribution of \a mz points \a zm, i.e.
1100\n
1101\f$ u(zm[i]) = \sum_{j=0}^{nz-1} im[i*nz+j] \ u(zgj[j]) \f$
1102
1103*/
1104
1105void Imglj(double *im, const double *zglj, const double *zm, const int nz,
1106 const int mz, const double alpha, const double beta)
1107{
1108 double zp;
1109 int i, j;
1110
1111 for (i = 0; i < nz; i++)
1112 {
1113 for (j = 0; j < mz; j++)
1114 {
1115 zp = zm[j];
1116 im[i * mz + j] = hglj(i, zp, zglj, nz, alpha, beta);
1117 }
1118 }
1119
1120 return;
1121}
1122
1123/**
1124\brief Compute the coefficients of Lagrange interpolation polynomials
1125
1126*/
1127
1128void polycoeffs(double *c, const double *z, const int i, const int np)
1129{
1130 int j, k, m;
1131
1132 // Compute denominator
1133 double d = 1.0;
1134 for (j = 0; j < np; j++)
1135 {
1136 if (i != j)
1137 {
1138 d *= z[i] - z[j];
1139 }
1140 c[j] = 0.0;
1141 }
1142
1143 // Compute coefficient
1144 c[0] = 1.0;
1145 m = 0;
1146 for (j = 0; j < np; j++)
1147 {
1148 if (i != j)
1149 {
1150 m += 1;
1151 c[m] = c[m - 1];
1152 for (k = m - 1; k > 0; k--)
1153 {
1154 c[k] *= -1.0 * z[j];
1155 c[k] += c[k - 1];
1156 }
1157 c[0] *= -1.0 * z[j];
1158 }
1159 }
1160 for (j = 0; j < np; j++)
1161 {
1162 c[j] /= d;
1163 }
1164}
1165
1166/**
1167\brief Routine to calculate Jacobi polynomials, \f$
1168P^{\alpha,\beta}_n(z) \f$, and their first derivative, \f$
1169\frac{d}{dz} P^{\alpha,\beta}_n(z) \f$.
1170
1171\li This function returns the vectors \a poly_in and \a poly_d
1172containing the value of the \f$ n^th \f$ order Jacobi polynomial
1173\f$ P^{\alpha,\beta}_n(z) \alpha > -1, \beta > -1 \f$ and its
1174derivative at the \a np points in \a z[i]
1175
1176- If \a poly_in = NULL then only calculate derivatice
1177
1178- If \a polyd = NULL then only calculate polynomial
1179
1180- To calculate the polynomial this routine uses the recursion
1181relationship (see appendix A ref [4]) :
1182\f$ \begin{array}{rcl}
1183P^{\alpha,\beta}_0(z) &=& 1 \\
1184P^{\alpha,\beta}_1(z) &=& \frac{1}{2} [ \alpha-\beta+(\alpha+\beta+2)z] \\
1185a^1_n P^{\alpha,\beta}_{n+1}(z) &=& (a^2_n + a^3_n z)
1186P^{\alpha,\beta}_n(z) - a^4_n P^{\alpha,\beta}_{n-1}(z) \\
1187a^1_n &=& 2(n+1)(n+\alpha + \beta + 1)(2n + \alpha + \beta) \\
1188a^2_n &=& (2n + \alpha + \beta + 1)(\alpha^2 - \beta^2) \\
1189a^3_n &=& (2n + \alpha + \beta)(2n + \alpha + \beta + 1)
1190(2n + \alpha + \beta + 2) \\
1191a^4_n &=& 2(n+\alpha)(n+\beta)(2n + \alpha + \beta + 2)
1192\end{array} \f$
1193
1194- To calculate the derivative of the polynomial this routine uses
1195the relationship (see appendix A ref [4]) :
1196\f$ \begin{array}{rcl}
1197b^1_n(z)\frac{d}{dz} P^{\alpha,\beta}_n(z)&=&b^2_n(z)P^{\alpha,\beta}_n(z)
1198+ b^3_n(z) P^{\alpha,\beta}_{n-1}(z) \hspace{2.2cm} \\
1199b^1_n(z) &=& (2n+\alpha + \beta)(1-z^2) \\
1200b^2_n(z) &=& n[\alpha - \beta - (2n+\alpha + \beta)z]\\
1201b^3_n(z) &=& 2(n+\alpha)(n+\beta)
1202\end{array} \f$
1203
1204- Note the derivative from this routine is only valid for -1 < \a z < 1.
1205*/
1206void jacobfd(const int np, const double *z, double *poly_in, double *polyd,
1207 const int n, const double alpha, const double beta)
1208{
1209 int i;
1210 double zero = 0.0, one = 1.0, two = 2.0;
1211
1212 if (!np)
1213 return;
1214
1215 if (n == 0)
1216 {
1217 if (poly_in)
1218 for (i = 0; i < np; ++i)
1219 poly_in[i] = one;
1220 if (polyd)
1221 for (i = 0; i < np; ++i)
1222 polyd[i] = zero;
1223 }
1224 else if (n == 1)
1225 {
1226 if (poly_in)
1227 for (i = 0; i < np; ++i)
1228 poly_in[i] = 0.5 * (alpha - beta + (alpha + beta + two) * z[i]);
1229 if (polyd)
1230 for (i = 0; i < np; ++i)
1231 polyd[i] = 0.5 * (alpha + beta + two);
1232 }
1233 else
1234 {
1235 int k;
1236 double a1, a2, a3, a4;
1237 double two = 2.0, apb = alpha + beta;
1238 double *poly, *polyn1, *polyn2;
1239
1240 if (poly_in)
1241 { // switch for case of no poynomial function return
1242 polyn1 = (double *)malloc(2 * np * sizeof(double));
1243 polyn2 = polyn1 + np;
1244 poly = poly_in;
1245 }
1246 else
1247 {
1248 polyn1 = (double *)malloc(3 * np * sizeof(double));
1249 polyn2 = polyn1 + np;
1250 poly = polyn2 + np;
1251 }
1252
1253 for (i = 0; i < np; ++i)
1254 {
1255 polyn2[i] = one;
1256 polyn1[i] = 0.5 * (alpha - beta + (alpha + beta + two) * z[i]);
1257 }
1258
1259 for (k = 2; k <= n; ++k)
1260 {
1261 a1 = two * k * (k + apb) * (two * k + apb - two);
1262 a2 = (two * k + apb - one) * (alpha * alpha - beta * beta);
1263 a3 =
1264 (two * k + apb - two) * (two * k + apb - one) * (two * k + apb);
1265 a4 = two * (k + alpha - one) * (k + beta - one) * (two * k + apb);
1266
1267 a2 /= a1;
1268 a3 /= a1;
1269 a4 /= a1;
1270
1271 for (i = 0; i < np; ++i)
1272 {
1273 poly[i] = (a2 + a3 * z[i]) * polyn1[i] - a4 * polyn2[i];
1274 polyn2[i] = polyn1[i];
1275 polyn1[i] = poly[i];
1276 }
1277 }
1278
1279 if (polyd)
1280 {
1281 a1 = n * (alpha - beta);
1282 a2 = n * (two * n + alpha + beta);
1283 a3 = two * (n + alpha) * (n + beta);
1284 a4 = (two * n + alpha + beta);
1285 a1 /= a4;
1286 a2 /= a4;
1287 a3 /= a4;
1288
1289 // note polyn2 points to polyn1 at end of poly iterations
1290 for (i = 0; i < np; ++i)
1291 {
1292 polyd[i] = (a1 - a2 * z[i]) * poly[i] + a3 * polyn2[i];
1293 polyd[i] /= (one - z[i] * z[i]);
1294 }
1295 }
1296
1297 free(polyn1);
1298 }
1299
1300 return;
1301}
1302
1303/**
1304\brief Calculate the derivative of Jacobi polynomials
1305
1306\li Generates a vector \a poly of values of the derivative of the
1307\a n th order Jacobi polynomial \f$ P^(\alpha,\beta)_n(z)\f$ at the
1308\a np points \a z.
1309
1310\li To do this we have used the relation
1311\n
1312\f$ \frac{d}{dz} P^{\alpha,\beta}_n(z)
1313= \frac{1}{2} (\alpha + \beta + n + 1) P^{\alpha,\beta}_n(z) \f$
1314
1315\li This formulation is valid for \f$ -1 \leq z \leq 1 \f$
1316
1317*/
1318void jacobd(const int np, const double *z, double *polyd, const int n,
1319 const double alpha, const double beta)
1320{
1321 int i;
1322 double one = 1.0;
1323 if (n == 0)
1324 for (i = 0; i < np; ++i)
1325 polyd[i] = 0.0;
1326 else
1327 {
1328 // jacobf(np,z,polyd,n-1,alpha+one,beta+one);
1329 jacobfd(np, z, polyd, NULL, n - 1, alpha + one, beta + one);
1330 for (i = 0; i < np; ++i)
1331 polyd[i] *= 0.5 * (alpha + beta + (double)n + one);
1332 }
1333 return;
1334}
1335
1336/**
1337\brief Calculate the Gamma function , \f$ \Gamma(n)\f$, for integer
1338values and halves.
1339
1340Determine the value of \f$\Gamma(n)\f$ using:
1341
1342\f$ \Gamma(n) = (n-1)! \mbox{ or } \Gamma(n+1/2) = (n-1/2)\Gamma(n-1/2)\f$
1343
1344where \f$ \Gamma(1/2) = \sqrt(\pi)\f$
1345*/
1346
1347double gammaF(const double x)
1348{
1349 double gamma = 1.0;
1350
1351 if (x == -0.5)
1352 gamma = -2.0 * sqrt(M_PI);
1353 else if (!x)
1354 return gamma;
1355 else if ((x - (int)x) == 0.5)
1356 {
1357 int n = (int)x;
1358 double tmp = x;
1359
1360 gamma = sqrt(M_PI);
1361 while (n--)
1362 {
1363 tmp -= 1.0;
1364 gamma *= tmp;
1365 }
1366 }
1367 else if ((x - (int)x) == 0.0)
1368 {
1369 int n = (int)x;
1370 double tmp = x;
1371
1372 while (--n)
1373 {
1374 tmp -= 1.0;
1375 gamma *= tmp;
1376 }
1377 }
1378 else
1379 fprintf(stderr, "%lf is not of integer or half order\n", x);
1380 return gamma;
1381}
1382
1383/**
1384\brief Calculate fraction of two Gamma functions, \f$
1385\Gamma(x+\alpha)/\Gamma(y+\beta) \f$, for integer values and halves.
1386
1387Determine the value of \f$\Gamma(n)\f$ using:
1388
1389\f$ \Gamma(n) = (n-1)! \mbox{ or } \Gamma(n+1/2) = (n-1/2)\Gamma(n-1/2)\f$
1390
1391where \f$ \Gamma(1/2) = \sqrt(\pi)\f$
1392
1393Attempts simplification in cases like \f$ \Gamma(x+1)/\Gamma(x-1) = x*(x-1) \f$
1394*/
1395
1396double gammaFracGammaF(const int x, const double alpha, const int y,
1397 const double beta)
1398{
1399 double gamma = 1.0;
1400 double halfa = fabs(alpha - int(alpha));
1401 double halfb = fabs(beta - int(beta));
1402 if (halfa == 0.0 && halfb == 0.0) // integer value
1403 {
1404 int X = x + alpha;
1405 int Y = y + beta;
1406 if (X > Y)
1407 {
1408 for (int tmp = X - 1; tmp > Y - 1; tmp -= 1)
1409 gamma *= tmp;
1410 }
1411 else if (Y > X)
1412 {
1413 for (int tmp = Y - 1; tmp > X - 1; tmp -= 1)
1414 gamma *= tmp;
1415 gamma = 1. / gamma;
1416 }
1417 }
1418 else if (halfa == 0.5 && halfb == 0.5) // both are halves
1419 {
1420 double X = x + alpha;
1421 double Y = y + beta;
1422 if (X > Y)
1423 {
1424 for (int tmp = int(X); tmp > int(Y); tmp -= 1)
1425 gamma *= tmp - 0.5;
1426 }
1427 else if (Y > X)
1428 {
1429 for (int tmp = int(Y); tmp > int(X); tmp -= 1)
1430 gamma *= tmp - 0.5;
1431 gamma = 1. / gamma;
1432 }
1433 }
1434 else
1435 {
1436 double X = x + alpha;
1437 double Y = y + beta;
1438 while (X > 1 || Y > 1)
1439 {
1440 if (X > 1)
1441 {
1442 gamma *= X - 1.;
1443 X -= 1.;
1444 }
1445 if (Y > 1)
1446 {
1447 gamma /= Y - 1.;
1448 Y -= 1.;
1449 }
1450 }
1451 if (X == 0.5)
1452 {
1453 gamma *= sqrt(M_PI);
1454 }
1455 else if (Y == 0.5)
1456 {
1457 gamma /= sqrt(M_PI);
1458 }
1459 else
1460 {
1461 fprintf(stderr, "%lf or %lf is not of integer or half order\n", X,
1462 Y);
1463 }
1464 }
1465
1466 return gamma;
1467}
1468
1469/**
1470
1471 \brief
1472
1473Calcualte the bessel function of the first kind with complex double input y.
1474Taken from Numerical Recipies in C
1475
1476Returns a complex double
1477*/
1478
1479std::complex<Nektar::NekDouble> ImagBesselComp(
1480 int n, std::complex<Nektar::NekDouble> y)
1481{
1482 std::complex<Nektar::NekDouble> z(1.0, 0.0);
1483 std::complex<Nektar::NekDouble> zbes(1.0, 0.0);
1484 std::complex<Nektar::NekDouble> zarg;
1485 Nektar::NekDouble tol = 1e-15;
1486 int maxit = 10000;
1487 int i = 1;
1488
1489 zarg = -0.25 * y * y;
1490
1491 while (abs(z) > tol && i <= maxit)
1492 {
1493 z = z * (1.0 / i / (i + n) * zarg);
1494 if (abs(z) <= tol)
1495 break;
1496 zbes = zbes + z;
1497 i++;
1498 }
1499 zarg = 0.5 * y;
1500 for (i = 1; i <= n; i++)
1501 {
1502 zbes = zbes * zarg;
1503 }
1504 return zbes;
1505}
1506
1507/**
1508\brief Calculate the \a n zeros, \a z, of the Jacobi polynomial, i.e.
1509\f$ P_n^{\alpha,\beta}(z) = 0 \f$
1510
1511This routine is only value for \f$( \alpha > -1, \beta > -1)\f$
1512and uses polynomial deflation in a Newton iteration
1513*/
1514
1515static void Jacobz(const int n, double *z, const double alpha,
1516 const double beta)
1517{
1518 int i, j, k;
1519 double dth = M_PI / (2.0 * (double)n);
1520 double poly, pder, rlast = 0.0;
1521 double sum, delr, r;
1522 double one = 1.0, two = 2.0;
1523
1524 if (!n)
1525 return;
1526
1527 for (k = 0; k < n; ++k)
1528 {
1529 r = -cos((two * (double)k + one) * dth);
1530 if (k)
1531 r = 0.5 * (r + rlast);
1532
1533 for (j = 1; j < STOP; ++j)
1534 {
1535 jacobfd(1, &r, &poly, &pder, n, alpha, beta);
1536
1537 for (i = 0, sum = 0.0; i < k; ++i)
1538 sum += one / (r - z[i]);
1539
1540 delr = -poly / (pder - sum * poly);
1541 r += delr;
1542 if (fabs(delr) < EPS)
1543 break;
1544 }
1545 z[k] = r;
1546 rlast = r;
1547 }
1548 return;
1549}
1550
1551/**
1552\brief Zero and Weight determination through the eigenvalues and eigenvectors of
1553a tridiagonal matrix from the three term recurrence relationship.
1554
1555Set up a symmetric tridiagonal matrix
1556
1557\f$ \left [ \begin{array}{ccccc}
1558a[0] & b[0] & & & \\
1559b[0] & a[1] & b[1] & & \\
15600 & \ddots & \ddots & \ddots & \\
1561& & \ddots & \ddots & b[n-2] \\
1562& & & b[n-2] & a[n-1] \end{array} \right ] \f$
1563
1564Where the coefficients a[n], b[n] come from the recurrence relation
1565
1566\f$ b_j p_j(z) = (z - a_j ) p_{j-1}(z) - b_{j-1} p_{j-2}(z) \f$
1567
1568where \f$ j=n+1\f$ and \f$p_j(z)\f$ are the Jacobi (normalized)
1569orthogonal polynomials \f$ \alpha,\beta > -1\f$( integer values and
1570halves). Since the polynomials are orthonormalized, the tridiagonal
1571matrix is guaranteed to be symmetric. The eigenvalues of this
1572matrix are the zeros of the Jacobi polynomial.
1573*/
1574
1575void JacZeros(const int n, double *a, double *b, const double alpha,
1576 const double beta)
1577{
1578
1579 int i, j;
1580 RecCoeff(n, a, b, alpha, beta);
1581
1582 double **z = new double *[n];
1583 for (i = 0; i < n; i++)
1584 {
1585 z[i] = new double[n];
1586 for (j = 0; j < n; j++)
1587 {
1588 z[i][j] = 0.0;
1589 }
1590 }
1591 for (i = 0; i < n; i++)
1592 {
1593 z[i][i] = 1.0;
1594 }
1595
1596 // find eigenvalues and eigenvectors
1597 TriQL(n, a, b, z);
1598
1599 delete[] z;
1600 return;
1601}
1602
1603/**
1604\brief The routine finds the recurrence coefficients \a a and
1605\a b of the orthogonal polynomials
1606*/
1607static void RecCoeff(const int n, double *a, double *b, const double alpha,
1608 const double beta)
1609{
1610
1611 int i;
1612 double apb, apbi, a2b2;
1613
1614 if (!n)
1615 return;
1616
1617 // generate normalised terms
1618 apb = alpha + beta;
1619 apbi = 2.0 + apb;
1620
1621 b[0] = pow(2.0, apb + 1.0) * gammaF(alpha + 1.0) * gammaF(beta + 1.0) /
1622 gammaF(apbi); // MuZero
1623 a[0] = (beta - alpha) / apbi;
1624 b[1] = (4.0 * (1.0 + alpha) * (1.0 + beta) / ((apbi + 1.0) * apbi * apbi));
1625
1626 a2b2 = beta * beta - alpha * alpha;
1627
1628 for (i = 1; i < n - 1; i++)
1629 {
1630 apbi = 2.0 * (i + 1) + apb;
1631 a[i] = a2b2 / ((apbi - 2.0) * apbi);
1632 b[i + 1] = (4.0 * (i + 1) * (i + 1 + alpha) * (i + 1 + beta) *
1633 (i + 1 + apb) / ((apbi * apbi - 1) * apbi * apbi));
1634 }
1635
1636 apbi = 2.0 * n + apb;
1637 a[n - 1] = a2b2 / ((apbi - 2.0) * apbi);
1638}
1639
1640/** \brief QL algorithm for symmetric tridiagonal matrix
1641
1642This subroutine is a translation of an algol procedure,
1643num. math. \b 12, 377-383(1968) by martin and wilkinson, as modified
1644in num. math. \b 15, 450(1970) by dubrulle. Handbook for
1645auto. comp., vol.ii-linear algebra, 241-248(1971). This is a
1646modified version from numerical recipes.
1647
1648This subroutine finds the eigenvalues and first components of the
1649eigenvectors of a symmetric tridiagonal matrix by the implicit QL
1650method.
1651
1652on input:
1653- n is the order of the matrix;
1654- d contains the diagonal elements of the input matrix;
1655- e contains the subdiagonal elements of the input matrix
1656in its first n-2 positions.
1657 - z is the n by n identity matrix
1658
1659on output:
1660
1661- d contains the eigenvalues in ascending order.
1662- e contains the weight values - modifications of the first component
1663 of normalised eigenvectors
1664*/
1665
1666static void TriQL(const int n, double *d, double *e, double **z)
1667{
1668 int m, l, iter, i, k;
1669 double s, r, p, g, f, dd, c, b;
1670
1671 double MuZero = e[0];
1672
1673 // Renumber the elements of e
1674 for (i = 0; i < n - 1; i++)
1675 {
1676 e[i] = sqrt(e[i + 1]);
1677 }
1678 e[n - 1] = 0.0;
1679
1680 for (l = 0; l < n; l++)
1681 {
1682 iter = 0;
1683 do
1684 {
1685 for (m = l; m < n - 1; m++)
1686 {
1687 dd = fabs(d[m]) + fabs(d[m + 1]);
1688 if (fabs(e[m]) + dd == dd)
1689 break;
1690 }
1691 if (m != l)
1692 {
1693 if (iter++ == STOP)
1694 {
1695 fprintf(stderr, "triQL: Too many iterations in TQLI");
1696 exit(1);
1697 }
1698 g = (d[l + 1] - d[l]) / (2.0 * e[l]);
1699 r = sqrt((g * g) + 1.0);
1700 g = d[m] - d[l] + e[l] / (g + sign(r, g));
1701 s = c = 1.0;
1702 p = 0.0;
1703 for (i = m - 1; i >= l; i--)
1704 {
1705 f = s * e[i];
1706 b = c * e[i];
1707 if (fabs(f) >= fabs(g))
1708 {
1709 c = g / f;
1710 r = sqrt((c * c) + 1.0);
1711 e[i + 1] = f * r;
1712 c *= (s = 1.0 / r);
1713 }
1714 else
1715 {
1716 s = f / g;
1717 r = sqrt((s * s) + 1.0);
1718 e[i + 1] = g * r;
1719 s *= (c = 1.0 / r);
1720 }
1721 g = d[i + 1] - p;
1722 r = (d[i] - g) * s + 2.0 * c * b;
1723 p = s * r;
1724 d[i + 1] = g + p;
1725 g = c * r - b;
1726
1727 // Calculate the eigenvectors
1728 for (k = 0; k < n; k++)
1729 {
1730 f = z[k][i + 1];
1731 z[k][i + 1] = s * z[k][i] + c * f;
1732 z[k][i] = c * z[k][i] - s * f;
1733 }
1734 }
1735 d[l] = d[l] - p;
1736 e[l] = g;
1737 e[m] = 0.0;
1738 }
1739 } while (m != l);
1740 }
1741
1742 // order eigenvalues
1743 // Since we only need the first component of the eigenvectors
1744 // to calcualte the weight, we only swap the first components
1745 for (i = 0; i < n - 1; ++i)
1746 {
1747 k = i;
1748 p = d[i];
1749 for (l = i + 1; l < n; ++l)
1750 if (d[l] < p)
1751 {
1752 k = l;
1753 p = d[l];
1754 }
1755 d[k] = d[i];
1756 d[i] = p;
1757
1758 double temp = z[0][k];
1759 z[0][k] = z[0][i];
1760 z[0][i] = temp;
1761 }
1762
1763 // Calculate the weights
1764 for (i = 0; i < n; i++)
1765 {
1766 e[i] = MuZero * z[0][i] * z[0][i];
1767 }
1768}
1769
1770/**
1771\brief Calcualtes the Jacobi-kronrod matrix by determining the
1772\a a and \b coefficients.
1773
1774The first \a 3n+1 coefficients are already known
1775
1776For more information refer to:
1777"Dirk P. Laurie, Calcualtion of Gauss-Kronrod quadrature rules"
1778*/
1779void JKMatrix(int n, double *a, double *b)
1780{
1781 int i, j, k, m;
1782 // Working storage
1783 int size = (int)floor(n / 2.0) + 2;
1784 double *s = new double[size];
1785 double *t = new double[size];
1786
1787 // Initialize s and t to zero
1788 for (i = 0; i < size; i++)
1789 {
1790 s[i] = 0.0;
1791 t[i] = 0.0;
1792 }
1793
1794 t[1] = b[n + 1];
1795 for (m = 0; m <= n - 2; m++)
1796 {
1797 double u = 0.0;
1798 for (k = (int)floor((m + 1) / 2.0); k >= 0; k--)
1799 {
1800 int l = m - k;
1801 u = u + (a[k + n + 1] - a[l]) * t[k + 1] + b[k + n + 1] * s[k] -
1802 b[l] * s[k + 1];
1803 s[k + 1] = u;
1804 }
1805
1806 // Swap the contents of s and t
1807 double *hold = s;
1808 s = t;
1809 t = hold;
1810 }
1811
1812 for (j = (int)floor(n / 2.0); j >= 0; j--)
1813 {
1814 s[j + 1] = s[j];
1815 }
1816
1817 for (m = n - 1; m <= 2 * n - 3; m++)
1818 {
1819 double u = 0;
1820 for (k = m + 1 - n; k <= floor((m - 1) / 2.0); k++)
1821 {
1822 int l = m - k;
1823 j = n - 1 - l;
1824 u = u - (a[k + n + 1] - a[l]) * t[j + 1] - b[k + n + 1] * s[j + 1] +
1825 b[l] * s[j + 2];
1826 s[j + 1] = u;
1827 }
1828
1829 if (m % 2 == 0)
1830 {
1831 k = m / 2;
1832 a[k + n + 1] =
1833 a[k] + (s[j + 1] - b[k + n + 1] * s[j + 2]) / t[j + 2];
1834 }
1835 else
1836 {
1837 k = (m + 1) / 2;
1838 b[k + n + 1] = s[j + 1] / s[j + 2];
1839 }
1840
1841 // Swap the contents of s and t
1842 double *hold = s;
1843 s = t;
1844 t = hold;
1845 }
1846
1847 a[2 * n] = a[n - 1] - b[2 * n] * s[1] / t[1];
1848}
1849
1850/**
1851\brief
1852Given a weight function \f$w(t)\f$ through the first \a n+1
1853coefficients \a a and \a b of its orthogonal polynomials
1854this routine generates the first \a n recurrence coefficients for the orthogonal
1855polynomials relative to the modified weight function \f$(t-z)w(t)\f$.
1856
1857The result will be placed in the array \a a0 and \a b0.
1858*/
1859
1860void chri1(int n, double *a, double *b, double *a0, double *b0, double z)
1861{
1862
1863 double q = ceil(3.0 * n / 2);
1864 int size = (int)q + 1;
1865 if (size < n + 1)
1866 {
1867 fprintf(stderr, "input arrays a and b are too short\n");
1868 }
1869 double *r = new double[n + 1];
1870 r[0] = z - a[0];
1871 r[1] = z - a[1] - b[1] / r[0];
1872 a0[0] = a[1] + r[1] - r[0];
1873 b0[0] = -r[0] * b[0];
1874
1875 if (n == 1)
1876 {
1877 delete[] r;
1878 return;
1879 }
1880 int k = 0;
1881 for (k = 1; k < n; k++)
1882 {
1883 r[k + 1] = z - a[k + 1] - b[k + 1] / r[k];
1884 a0[k] = a[k + 1] + r[k + 1] - r[k];
1885 b0[k] = b[k] * r[k] / r[k - 1];
1886 }
1887 delete[] r;
1888}
1889
1890} // namespace Polylib
#define jacobz(n, z, alpha, beta)
zero determination using Newton iteration with polynomial deflation
Definition: Polylib.cpp:130
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:49
#define EPS
Precision tolerance for two points to be similar.
Definition: Polylib.cpp:47
#define STOP
Maximum number of iterations in polynomial defalation routine Jacobz.
Definition: Polylib.cpp:45
@ beta
Gauss Radau pinned at x=-1,.
Definition: PointsType.h:61
std::vector< double > w(NPUPPER)
std::vector< double > z(NPUPPER)
std::vector< double > d(NPUPPER *NPUPPER)
std::vector< double > q(NPUPPER *NPUPPER)
double NekDouble
The namespace associated with the the Polylib library (Polylib introduction)
Definition: Polylib.cpp:52
double laginterpderiv(double z, int k, const double *zj, int np)
Definition: Polylib.cpp:100
double gammaF(const double x)
Calculate the Gamma function , , for integer values and halves.
Definition: Polylib.cpp:1347
void Dgj(double *D, const double *z, const int np, const double alpha, const double beta)
Compute the Derivative Matrix and its transpose associated with the Gauss-Jacobi zeros.
Definition: Polylib.cpp:647
void zwgrjm(double *z, double *w, const int np, const double alpha, const double beta)
Gauss-Radau-Jacobi zeros and weights with end point at z=-1.
Definition: Polylib.cpp:182
void JacZeros(const int n, double *a, double *b, const double alpha, const double beta)
Zero and Weight determination through the eigenvalues and eigenvectors of a tridiagonal matrix from t...
Definition: Polylib.cpp:1575
void zwgrjp(double *z, double *w, const int np, const double alpha, const double beta)
Gauss-Radau-Jacobi zeros and weights with end point at z=1.
Definition: Polylib.cpp:223
double laginterp(double z, int j, const double *zj, int np)
Definition: Polylib.cpp:87
void chri1(int, double *, double *, double *, double *, double)
Given a weight function through the first n+1 coefficients a and b of its orthogonal polynomials thi...
Definition: Polylib.cpp:1860
void Dglj(double *D, const double *z, const int np, const double alpha, const double beta)
Compute the Derivative Matrix associated with the Gauss-Lobatto-Jacobi zeros.
Definition: Polylib.cpp:807
void Imgrjp(double *im, const double *zgrj, const double *zm, const int nz, const int mz, const double alpha, const double beta)
Interpolation Operator from Gauss-Radau-Jacobi points (including z=1) to an arbitrary distrubtion at ...
Definition: Polylib.cpp:1074
void zwglj(double *z, double *w, const int np, const double alpha, const double beta)
Gauss-Lobatto-Jacobi zeros and weights with end point at z=-1,1.
Definition: Polylib.cpp:262
void zwgj(double *z, double *w, const int np, const double alpha, const double beta)
Gauss-Jacobi zeros and weights.
Definition: Polylib.cpp:154
void Imgj(double *im, const double *zgj, const double *zm, const int nz, const int mz, const double alpha, const double beta)
Interpolation Operator from Gauss-Jacobi points to an arbitrary distribution at points zm.
Definition: Polylib.cpp:1012
static void RecCoeff(const int, double *, double *, const double, const double)
The routine finds the recurrence coefficients a and b of the orthogonal polynomials.
Definition: Polylib.cpp:1607
double hgrjm(const int i, const double z, const double *zgrj, const int np, const double alpha, const double beta)
Compute the value of the i th Lagrangian interpolant through the np Gauss-Radau-Jacobi points zgrj at...
Definition: Polylib.cpp:913
void Qg(double *Q, const double *z, const int np)
Compute the Integration Matrix.
Definition: Polylib.cpp:605
double gammaFracGammaF(const int x, const double alpha, const int y, const double beta)
Calculate fraction of two Gamma functions, , for integer values and halves.
Definition: Polylib.cpp:1396
void polycoeffs(double *c, const double *z, const int i, const int np)
Compute the coefficients of Lagrange interpolation polynomials.
Definition: Polylib.cpp:1128
static void TriQL(const int, double *, double *, double **)
QL algorithm for symmetric tridiagonal matrix.
Definition: Polylib.cpp:1666
static void Jacobz(const int n, double *z, const double alpha, const double beta)
Calculate the n zeros, z, of the Jacobi polynomial, i.e. .
Definition: Polylib.cpp:1515
double hgj(const int i, const double z, const double *zgj, const int np, const double alpha, const double beta)
Compute the value of the i th Lagrangian interpolant through the np Gauss-Jacobi points zgj at the ar...
Definition: Polylib.cpp:878
void Imgrjm(double *im, const double *zgrj, const double *zm, const int nz, const int mz, const double alpha, const double beta)
Interpolation Operator from Gauss-Radau-Jacobi points (including z=-1) to an arbitrary distrubtion at...
Definition: Polylib.cpp:1043
void zwgk(double *z, double *w, const int npt, const double alpha, const double beta)
Gauss-Kronrod-Jacobi zeros and weights.
Definition: Polylib.cpp:311
void Dgrjm(double *D, const double *z, const int np, const double alpha, const double beta)
Compute the Derivative Matrix and its transpose associated with the Gauss-Radau-Jacobi zeros with a z...
Definition: Polylib.cpp:694
std::complex< Nektar::NekDouble > ImagBesselComp(int n, std::complex< Nektar::NekDouble > y)
Calcualte the bessel function of the first kind with complex double input y. Taken from Numerical Rec...
Definition: Polylib.cpp:1479
void Dgrjp(double *D, const double *z, const int np, const double alpha, const double beta)
Compute the Derivative Matrix associated with the Gauss-Radau-Jacobi zeros with a zero at z=1.
Definition: Polylib.cpp:750
double hgrjp(const int i, const double z, const double *zgrj, const int np, const double alpha, const double beta)
Compute the value of the i th Lagrangian interpolant through the np Gauss-Radau-Jacobi points zgrj at...
Definition: Polylib.cpp:949
void zwrk(double *z, double *w, const int npt, const double alpha, const double beta)
Gauss-Radau-Kronrod-Jacobi zeros and weights.
Definition: Polylib.cpp:383
double hglj(const int i, const double z, const double *zglj, const int np, const double alpha, const double beta)
Compute the value of the i th Lagrangian interpolant through the np Gauss-Lobatto-Jacobi points zgrj ...
Definition: Polylib.cpp:984
void Imglj(double *im, const double *zglj, const double *zm, const int nz, const int mz, const double alpha, const double beta)
Interpolation Operator from Gauss-Lobatto-Jacobi points to an arbitrary distrubtion at points zm.
Definition: Polylib.cpp:1105
void jacobd(const int np, const double *z, double *polyd, const int n, const double alpha, const double beta)
Calculate the derivative of Jacobi polynomials.
Definition: Polylib.cpp:1318
double optdiff(double xl, double xr)
The following function is used to circumvent/reduce "Subtractive Cancellation" The expression 1/dz is...
Definition: Polylib.cpp:57
void jacobfd(const int np, const double *z, double *poly_in, double *polyd, const int n, const double alpha, const double beta)
Routine to calculate Jacobi polynomials, , and their first derivative, .
Definition: Polylib.cpp:1206
void JKMatrix(int, double *, double *)
Calcualtes the Jacobi-kronrod matrix by determining the a and coefficients.
Definition: Polylib.cpp:1779
void zwlk(double *z, double *w, const int npt, const double alpha, const double beta)
Gauss-Lobatto-Kronrod-Jacobi zeros and weights.
Definition: Polylib.cpp:489
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294