Intrepid2
Intrepid2_PolylibDef.hpp
Go to the documentation of this file.
1 /*
2 // @HEADER
3 // *****************************************************************************
4 // Intrepid2 Package
5 //
6 // Copyright 2007 NTESS and the Intrepid2 contributors.
7 // SPDX-License-Identifier: BSD-3-Clause
8 // *****************************************************************************
9 // @HEADER
10 */
11 
13 //
14 // File: Intrepid_PolylibDef.hpp
15 //
16 // For more information, please see: http://www.nektar.info
17 //
18 // The MIT License
19 //
20 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
21 // Department of Aeronautics, Imperial College London (UK), and Scientific
22 // Computing and Imaging Institute, University of Utah (USA).
23 //
24 // License for the specific language governing rights and limitations under
25 // Permission is hereby granted, free of charge, to any person obtaining a
26 // copy of this software and associated documentation files (the "Software"),
27 // to deal in the Software without restriction, including without limitation
28 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
29 // and/or sell copies of the Software, and to permit persons to whom the
30 // Software is furnished to do so, subject to the following conditions:
31 //
32 // The above copyright notice and this permission notice shall be included
33 // in all copies or substantial portions of the Software.
34 //
35 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
36 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
40 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
41 // DEALINGS IN THE SOFTWARE.
42 //
43 // Description:
44 // This file is redistributed with the Intrepid package. It should be used
45 // in accordance with the above MIT license, at the request of the authors.
46 // This file is NOT covered by the usual Intrepid/Trilinos LGPL license.
47 //
48 // Origin: Nektar++ library, http://www.nektar.info, downloaded on
49 // March 10, 2009.
50 //
52 
53 
62 #ifndef __INTREPID2_POLYLIB_DEF_HPP__
63 #define __INTREPID2_POLYLIB_DEF_HPP__
64 
65 #if defined(_MSC_VER) || defined(_WIN32) && defined(__ICL)
66 // M_PI, M_SQRT2, etc. are hidden in MSVC by #ifdef _USE_MATH_DEFINES
67  #ifndef _USE_MATH_DEFINES
68  #define _USE_MATH_DEFINES
69  #endif
70  #include <math.h>
71 #endif
72 
73 namespace Intrepid2 {
74 
75  // -----------------------------------------------------------------------
76  // Points and Weights
77  // -----------------------------------------------------------------------
78 
79  template<>
80  template<typename zViewType,
81  typename wViewType>
82  KOKKOS_INLINE_FUNCTION
83  void
84  Polylib::Serial::Cubature<POLYTYPE_GAUSS>::
85  getValues( zViewType z,
86  wViewType w,
87  const ordinal_type np,
88  const double alpha,
89  const double beta) {
90  const double one = 1.0, two = 2.0, apb = alpha + beta;
91  double fac;
92 
93  JacobiZeros(z, np, alpha, beta);
94  JacobiPolynomialDerivative(np, z, w, np, alpha, beta);
95 
96  fac = pow(two, apb + one)*GammaFunction(alpha + np + one)*GammaFunction(beta + np + one);
97  fac /= GammaFunction((np + one))*GammaFunction(apb + np + one);
98 
99  for (ordinal_type i = 0; i < np; ++i)
100  w(i) = fac/(w(i)*w(i)*(one-z(i)*z(i)));
101  }
102 
103  template<>
104  template<typename zViewType,
105  typename wViewType>
106  KOKKOS_INLINE_FUNCTION
107  void
108  Polylib::Serial::Cubature<POLYTYPE_GAUSS_RADAU_LEFT>::
109  getValues( zViewType z,
110  wViewType w,
111  const ordinal_type np,
112  const double alpha,
113  const double beta) {
114  if (np == 1) {
115  z(0) = 0.0;
116  w(0) = 2.0;
117  } else {
118  const double one = 1.0, two = 2.0, apb = alpha + beta;
119  double fac;
120 
121  z(0) = -one;
122 
123  auto z_plus_1 = Kokkos::subview(z, Kokkos::pair<ordinal_type,ordinal_type>(1, z.extent(0)));
124  JacobiZeros(z_plus_1, np-1, alpha, beta+1);
125 
126  Kokkos::View<typename zViewType::value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged> null;
127  JacobiPolynomial(np, z, w, null, np-1, alpha, beta);
128 
129  fac = pow(two, apb)*GammaFunction(alpha + np)*GammaFunction(beta + np);
130  fac /= GammaFunction(np)*(beta + np)*GammaFunction(apb + np + 1);
131 
132  for (ordinal_type i = 0; i < np; ++i)
133  w(i) = fac*(1-z(i))/(w(i)*w(i));
134  w(0) *= (beta + one);
135  }
136  }
137 
138  template<>
139  template<typename zViewType,
140  typename wViewType>
141  KOKKOS_INLINE_FUNCTION
142  void
143  Polylib::Serial::Cubature<POLYTYPE_GAUSS_RADAU_RIGHT>::
144  getValues( zViewType z,
145  wViewType w,
146  const ordinal_type np,
147  const double alpha,
148  const double beta) {
149  if (np == 1) {
150  z(0) = 0.0;
151  w(0) = 2.0;
152  } else {
153  const double one = 1.0, two = 2.0, apb = alpha + beta;
154  double fac;
155 
156  JacobiZeros(z, np-1, alpha+1, beta);
157  z(np-1) = one;
158 
159  Kokkos::View<typename zViewType::value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged> null;
160  JacobiPolynomial(np, z, w, null, np-1, alpha, beta);
161 
162  fac = pow(two,apb)*GammaFunction(alpha + np)*GammaFunction(beta + np);
163  fac /= GammaFunction(np)*(alpha + np)*GammaFunction(apb + np + 1);
164 
165  for (ordinal_type i = 0; i < np; ++i)
166  w(i) = fac*(1+z(i))/(w(i)*w(i));
167  w(np-1) *= (alpha + one);
168  }
169  }
170 
171  template<>
172  template<typename zViewType,
173  typename wViewType>
174  KOKKOS_INLINE_FUNCTION
175  void
176  Polylib::Serial::Cubature<POLYTYPE_GAUSS_LOBATTO>::
177  getValues( zViewType z,
178  wViewType w,
179  const ordinal_type np,
180  const double alpha,
181  const double beta) {
182  if ( np == 1 ) {
183  z(0) = 0.0;
184  w(0) = 2.0;
185  } else {
186  const double one = 1.0, apb = alpha + beta, two = 2.0;
187  double fac;
188 
189  z(0) = -one;
190  z(np-1) = one;
191 
192  auto z_plus_1 = Kokkos::subview(z, Kokkos::pair<ordinal_type,ordinal_type>(1, z.extent(0)));
193  JacobiZeros(z_plus_1, np-2, alpha+one, beta+one);
194 
195  Kokkos::View<typename zViewType::value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged> null;
196  JacobiPolynomial(np, z, w, null, np-1, alpha, beta);
197 
198  fac = pow(two, apb + 1)*GammaFunction(alpha + np)*GammaFunction(beta + np);
199  fac /= (np-1)*GammaFunction(np)*GammaFunction(alpha + beta + np + one);
200 
201  for (ordinal_type i = 0; i < np; ++i)
202  w(i) = fac/(w(i)*w(i));
203 
204  w(0) *= (beta + one);
205  w(np-1) *= (alpha + one);
206  }
207  }
208 
209  // -----------------------------------------------------------------------
210  // Derivatives
211  // -----------------------------------------------------------------------
212 
213  template<>
214  template<typename DViewType,
215  typename zViewType>
216  KOKKOS_INLINE_FUNCTION
217  void
218  Polylib::Serial::Derivative<POLYTYPE_GAUSS>::
219  getValues( DViewType D,
220  const zViewType z,
221  const ordinal_type np,
222  const double alpha,
223  const double beta) {
224  if (np <= 0) {
225  D(0,0) = 0.0;
226  } else {
227  const double one = 1.0, two = 2.0;
228 
229  auto pd = Kokkos::subview(D, np-1, Kokkos::pair<int,int>(0,np));
230  JacobiPolynomialDerivative(np, z, pd, np, alpha, beta);
231 
232  // The temporary view pd is stored in the last row of the matrix D
233  // This loop is designed so that we do not overwrite pd entries before we read them
234  for (ordinal_type i = 0; i < np; ++i) {
235  const auto & pd_i = pd(i);
236  const auto & z_i = z(i);
237  for (ordinal_type j = 0; j < i; ++j) {
238  const auto & pd_j = pd(j);
239  const auto & z_j = z(j);
240  D(j,i) = pd_j/(pd_i*(z_j-z_i));
241  D(i,j) = pd_i/(pd_j*(z_i-z_j));
242  }
243  D(i,i) = (alpha - beta + (alpha + beta + two)*z_i) / (two*(one - z_i*z_i));
244  }
245  }
246  }
247 
248  template<>
249  template<typename DViewType,
250  typename zViewType>
251  KOKKOS_INLINE_FUNCTION
252  void
253  Polylib::Serial::Derivative<POLYTYPE_GAUSS_RADAU_LEFT>::
254  getValues( DViewType D,
255  const zViewType z,
256  const ordinal_type np,
257  const double alpha,
258  const double beta) {
259  if (np <= 0) {
260  D(0,0) = 0.0;
261  } else {
262  const double one = 1.0, two = 2.0;
263 
264  auto pd = Kokkos::subview(D, np-1, Kokkos::pair<int,int>(0,np));
265  pd(0) = pow(-one,np-1)*GammaFunction(np+beta+one) / (GammaFunction(np)*GammaFunction(beta+two));
266 
267  auto pd_plus_1 = Kokkos::subview(pd, Kokkos::pair<ordinal_type,ordinal_type>(1, pd.extent(0)));
268  auto z_plus_1 = Kokkos::subview( z, Kokkos::pair<ordinal_type,ordinal_type>(1, z.extent(0)));
269 
270  JacobiPolynomialDerivative(np-1, z_plus_1, pd_plus_1, np-1, alpha, beta+1);
271  for(ordinal_type i = 1; i < np; ++i)
272  pd(i) *= (1+z(i));
273 
274  // The temporary view pd is stored in the last row of the matrix D
275  // This loop is designed so that we do not overwrite pd entries before we read them
276  for (ordinal_type i = 0; i < np; ++i) {
277  const auto & pd_i = pd(i);
278  const auto & z_i = z(i);
279  for (ordinal_type j = 0; j < i; ++j) {
280  const auto & pd_j = pd(j);
281  const auto & z_j = z(j);
282  D(j,i) = pd_j/(pd_i*(z_j-z_i));
283  D(i,j) = pd_i/(pd_j*(z_i-z_j));
284  }
285  if (i == 0)
286  D(i,i) = -(np + alpha + beta + one)*(np - one) / (two*(beta + two));
287  else
288  D(i,i) = (alpha - beta + one + (alpha + beta + one)*z_i) / (two*(one - z_i*z_i));
289  }
290  }
291  }
292 
293  template<>
294  template<typename DViewType,
295  typename zViewType>
296  KOKKOS_INLINE_FUNCTION
297  void
298  Polylib::Serial::Derivative<POLYTYPE_GAUSS_RADAU_RIGHT>::
299  getValues( DViewType D,
300  const zViewType z,
301  const ordinal_type np,
302  const double alpha,
303  const double beta) {
304  if (np <= 0) {
305  D(0,0) = 0.0;
306  } else {
307  const double one = 1.0, two = 2.0;
308 
309  auto pd = Kokkos::subview(D, np-1, Kokkos::pair<int,int>(0,np));
310 
311  JacobiPolynomialDerivative(np-1, z, pd, np-1, alpha+1, beta);
312  for (ordinal_type i = 0; i < np-1; ++i)
313  pd(i) *= (1-z(i));
314 
315  pd(np-1) = -GammaFunction(np+alpha+one) / (GammaFunction(np)*GammaFunction(alpha+two));
316 
317  // The temporary view pd is stored in the last row of the matrix D
318  // This loop is designed so that we do not overwrite pd entries before we read them
319  for (ordinal_type i = 0; i < np; ++i) {
320  const auto & pd_i = pd(i);
321  const auto & z_i = z(i);
322  for (ordinal_type j = 0; j < i; ++j) {
323  const auto & pd_j = pd(j);
324  const auto & z_j = z(j);
325  D(j,i) = pd_j/(pd_i*(z_j-z_i));
326  D(i,j) = pd_i/(pd_j*(z_i-z_j));
327  }
328  if (i == np-1)
329  D(i,i) = (np + alpha + beta + one)*(np - one) / (two*(alpha + two));
330  else
331  D(i,i) = (alpha - beta - one + (alpha + beta + one)*z_i) / (two*(one - z_i*z_i));
332  }
333  }
334  }
335 
336  template<>
337  template<typename DViewType,
338  typename zViewType>
339  KOKKOS_INLINE_FUNCTION
340  void
341  Polylib::Serial::Derivative<POLYTYPE_GAUSS_LOBATTO>::
342  getValues( DViewType D,
343  const zViewType z,
344  const ordinal_type np,
345  const double alpha,
346  const double beta) {
347  if (np <= 0) {
348  D(0,0) = 0.0;
349  } else {
350  const double one = 1.0, two = 2.0;
351 
352  auto pd = Kokkos::subview(D, np-1, Kokkos::pair<int,int>(0,np));
353 
354  pd(0) = two*pow(-one,np)*GammaFunction(np + beta);
355  pd(0) /= GammaFunction(np - one)*GammaFunction(beta + two);
356 
357  auto pd_plus_1 = Kokkos::subview(pd, Kokkos::pair<ordinal_type,ordinal_type>(1, pd.extent(0)));
358  auto z_plus_1 = Kokkos::subview( z, Kokkos::pair<ordinal_type,ordinal_type>(1, z.extent(0)));
359 
360  JacobiPolynomialDerivative(np-2, z_plus_1, pd_plus_1, np-2, alpha+1, beta+1);
361  for (ordinal_type i = 1; i < np-1; ++i) {
362  const auto & z_i = z(i);
363  pd(i) *= (one-z_i*z_i);
364  }
365 
366  pd(np-1) = -two*GammaFunction(np + alpha);
367  pd(np-1) /= GammaFunction(np - one)*GammaFunction(alpha + two);
368 
369  // The temporary view pd is stored in the last row of the matrix D
370  // This loop is designed so that we do not overwrite pd entries before we read them
371  for (ordinal_type i = 0; i < np; ++i) {
372  const auto & pd_i = pd(i);
373  const auto & z_i = z(i);
374  for (ordinal_type j = 0; j < i; ++j) {
375  const auto & pd_j = pd(j);
376  const auto & z_j = z(j);
377  D(j,i) = pd_j/(pd_i*(z_j-z_i));
378  D(i,j) = pd_i/(pd_j*(z_i-z_j));
379  }
380  if (i == 0)
381  D(i,i) = (alpha - (np-1)*(np + alpha + beta))/(two*(beta+ two));
382  else if (i == np-1)
383  D(i,i) =-(beta - (np-1)*(np + alpha + beta))/(two*(alpha+ two));
384  else
385  D(i,i) = (alpha - beta + (alpha + beta)*z_i)/(two*(one - z_i*z_i));
386  }
387  }
388  }
389 
390  // -----------------------------------------------------------------------
391  // Lagrangian Interpolants
392  // -----------------------------------------------------------------------
393 
394  template<>
395  template<typename zViewType>
396  KOKKOS_INLINE_FUNCTION
397  typename zViewType::value_type
398  Polylib::Serial::LagrangianInterpolant<POLYTYPE_GAUSS>::
399  getValue(const ordinal_type i,
400  const typename zViewType::value_type z,
401  const zViewType zgj,
402  const ordinal_type np,
403  const double alpha,
404  const double beta) {
405  const double tol = tolerence();
406 
407  typedef typename zViewType::value_type value_type;
408  typedef typename zViewType::pointer_type pointer_type;
409 
410  value_type h, p_buf, pd_buf, zi_buf = zgj(i);
411  Kokkos::View<value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged>
412  p((pointer_type)&p_buf, 1), pd((pointer_type)&pd_buf, 1), zi((pointer_type)&zi_buf, 1),
413  zv(const_cast<pointer_type>(&z), 1), null;
414 
415  const auto dz = z - zi(0);
416  if (Util<value_type>::abs(dz) < tol)
417  return 1.0;
418 
419  JacobiPolynomialDerivative(1, zi, pd, np, alpha, beta);
420  JacobiPolynomial(1, zv, p, null , np, alpha, beta);
421 
422  h = p(0)/(pd(0)*dz);
423 
424  return h;
425  }
426 
427  template<>
428  template<typename zViewType>
429  KOKKOS_INLINE_FUNCTION
430  typename zViewType::value_type
431  Polylib::Serial::LagrangianInterpolant<POLYTYPE_GAUSS_RADAU_LEFT>::
432  getValue(const ordinal_type i,
433  const typename zViewType::value_type z,
434  const zViewType zgrj,
435  const ordinal_type np,
436  const double alpha,
437  const double beta) {
438  const double tol = tolerence();
439 
440  typedef typename zViewType::value_type value_type;
441  typedef typename zViewType::pointer_type pointer_type;
442 
443  value_type h, p_buf, pd_buf, zi_buf = zgrj(i);
444  Kokkos::View<value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged>
445  p((pointer_type)&p_buf, 1), pd((pointer_type)&pd_buf, 1), zi((pointer_type)&zi_buf, 1),
446  zv(const_cast<pointer_type>(&z), 1), null;
447 
448  const auto dz = z - zi(0);
449  if (Util<value_type>::abs(dz) < tol)
450  return 1.0;
451 
452  JacobiPolynomial(1, zi, p , null, np-1, alpha, beta + 1);
453 
454  // need to use this routine in case zi = -1 or 1
455  JacobiPolynomialDerivative(1, zi, pd, np-1, alpha, beta + 1);
456  h = (1.0 + zi(0))*pd(0) + p(0);
457 
458  JacobiPolynomial(1, zv, p, null, np-1, alpha, beta + 1);
459  h = (1.0 + z)*p(0)/(h*dz);
460 
461  return h;
462  }
463 
464 
465  template<>
466  template<typename zViewType>
467  KOKKOS_INLINE_FUNCTION
468  typename zViewType::value_type
469  Polylib::Serial::LagrangianInterpolant<POLYTYPE_GAUSS_RADAU_RIGHT>::
470  getValue(const ordinal_type i,
471  const typename zViewType::value_type z,
472  const zViewType zgrj,
473  const ordinal_type np,
474  const double alpha,
475  const double beta) {
476  const double tol = tolerence();
477 
478  typedef typename zViewType::value_type value_type;
479  typedef typename zViewType::pointer_type pointer_type;
480 
481  value_type h, p_buf, pd_buf, zi_buf = zgrj(i);
482  Kokkos::View<value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged>
483  p((pointer_type)&p_buf, 1), pd((pointer_type)&pd_buf, 1), zi((pointer_type)&zi_buf, 1),
484  zv(const_cast<pointer_type>(&z), 1), null;
485 
486  const auto dz = z - zi(0);
487  if (Util<value_type>::abs(dz) < tol)
488  return 1.0;
489 
490  JacobiPolynomial(1, zi, p , null, np-1, alpha+1, beta);
491 
492  // need to use this routine in case z = -1 or 1
493  JacobiPolynomialDerivative(1, zi, pd, np-1, alpha+1, beta);
494  h = (1.0 - zi(0))*pd(0) - p(0);
495 
496  JacobiPolynomial (1, zv, p, null, np-1, alpha+1, beta);
497  h = (1.0 - z)*p(0)/(h*dz);
498 
499  return h;
500  }
501 
502 
503  template<>
504  template<typename zViewType>
505  KOKKOS_INLINE_FUNCTION
506  typename zViewType::value_type
507  Polylib::Serial::LagrangianInterpolant<POLYTYPE_GAUSS_LOBATTO>::
508  getValue(const ordinal_type i,
509  const typename zViewType::value_type z,
510  const zViewType zglj,
511  const ordinal_type np,
512  const double alpha,
513  const double beta) {
514  const double one = 1.0, two = 2.0, tol = tolerence();
515 
516  typedef typename zViewType::value_type value_type;
517  typedef typename zViewType::pointer_type pointer_type;
518 
519  value_type h, p_buf, pd_buf, zi_buf = zglj(i);
520  Kokkos::View<value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged>
521  p((pointer_type)&p_buf, 1), pd((pointer_type)&pd_buf, 1), zi((pointer_type)&zi_buf, 1),
522  zv(const_cast<pointer_type>(&z), 1), null;
523 
524  const auto dz = z - zi(0);
525  if (Util<value_type>::abs(dz) < tol)
526  return 1.0;
527 
528  JacobiPolynomial(1, zi, p , null, np-2, alpha + one, beta + one);
529 
530  // need to use this routine in case z = -1 or 1
531  JacobiPolynomialDerivative(1, zi, pd, np-2, alpha + one, beta + one);
532  h = (one - zi(0)*zi(0))*pd(0) - two*zi(0)*p(0);
533 
534  JacobiPolynomial(1, zv, p, null, np-2, alpha + one, beta + one);
535  h = (one - z*z)*p(0)/(h*dz);
536 
537  return h;
538  }
539 
540  // -----------------------------------------------------------------------
541  // Interpolation Operator
542  // -----------------------------------------------------------------------
543 
544  template<EPolyType polyType>
545  template<typename imViewType,
546  typename zgrjViewType,
547  typename zmViewType>
548  KOKKOS_INLINE_FUNCTION
549  void
550  Polylib::Serial::InterpolationOperator<polyType>::
551  getMatrix( imViewType im,
552  const zgrjViewType zgrj,
553  const zmViewType zm,
554  const ordinal_type nz,
555  const ordinal_type mz,
556  const double alpha,
557  const double beta) {
558  for (ordinal_type i = 0; i < mz; ++i) {
559  const auto zp = zm(i);
560  for (ordinal_type j = 0; j < nz; ++j)
561  im(i, j) = LagrangianInterpolant<polyType>::getValue(j, zp, zgrj, nz, alpha, beta);
562  }
563  }
564 
565  // -----------------------------------------------------------------------
566 
567  template<typename zViewType,
568  typename polyiViewType,
569  typename polydViewType>
570  KOKKOS_INLINE_FUNCTION
571  void
573  JacobiPolynomial(const ordinal_type np,
574  const zViewType z,
575  polyiViewType polyi,
576  polydViewType polyd,
577  const ordinal_type n,
578  const double alpha,
579  const double beta) {
580  const double zero = 0.0, one = 1.0, two = 2.0;
581 
582  if (! np) {
583  return;
584  }
585 
586  if (n == 0) {
587  if (polyi.data())
588  for (ordinal_type i = 0; i < np; ++i)
589  polyi(i) = one;
590  if (polyd.data())
591  for (ordinal_type i = 0; i < np; ++i)
592  polyd(i) = zero;
593  } else if (n == 1) {
594  if (polyi.data())
595  for (ordinal_type i = 0; i < np; ++i)
596  polyi(i) = 0.5*(alpha - beta + (alpha + beta + two)*z(i));
597  if (polyd.data())
598  for (ordinal_type i = 0; i < np; ++i)
599  polyd(i) = 0.5*(alpha + beta + two);
600  } else {
601  INTREPID2_TEST_FOR_ABORT(polyd.data() && !polyd.data() ,
602  ">>> ERROR (Polylib::Serial::JacobiPolynomial): polyi view needed to compute polyd view.");
603  if(!polyi.data()) return;
604 
605  constexpr ordinal_type maxOrder = 2*MaxPolylibPoint-1;
606 
607  INTREPID2_TEST_FOR_ABORT(maxOrder < n,
608  ">>> ERROR (Polylib::Serial::JacobiPolynomial): Requested order exceeds maxOrder .");
609 
610  double a2[maxOrder-1]={}, a3[maxOrder-1]={}, a4[maxOrder-1]={};
611  double ad1(0.0), ad2(0.0), ad3(0.0);
612  const double apb = alpha + beta;
613  const double amb = alpha - beta;
614 
615 
616  for (auto k = 2; k <= n; ++k) {
617  double a1 = two*k*(k + apb)*(two*k + apb - two);
618  a2[k-2] = (two*k + apb - one)*(apb*amb)/a1;
619  a3[k-2] = (two*k + apb - two)*(two*k + apb - one)*(two*k + apb)/a1;
620  a4[k-2] = two*(k + alpha - one)*(k + beta - one)*(two*k + apb)/a1;
621  }
622 
623  if (polyd.data()) {
624  double ad4 = (two*n + alpha + beta);
625  ad1 = n*(alpha - beta)/ad4;
626  ad2 = n*(two*n + alpha + beta)/ad4;
627  ad3 = two*(n + alpha)*(n + beta)/ad4;
628  }
629 
630  typename polyiViewType::value_type polyn0, polyn1, polyn2;
631  for(ordinal_type i = 0; i < np; ++i) {
632  const auto & z_i = z(i);
633  polyn2 = one;
634  polyn1 = 0.5*(amb + (apb + two)*z_i);
635  polyn0 = (a2[0] + a3[0]*z_i)*polyn1 - a4[0]*polyn2;
636  for (ordinal_type k = 1; k < n-1; ++k) {
637  polyn2 = polyn1;
638  polyn1 = polyn0;
639  polyn0 = (a2[k] + a3[k]*z_i)*polyn1 - a4[k]*polyn2;
640  }
641  if (polyd.data()) {
642  polyd(i) = (ad1- ad2*z_i)*polyn0 + ad3*polyn1 / (one - z_i*z_i);
643  }
644  polyi(i) = polyn0;
645  }
646  }
647  }
648 
649  template<typename zViewType,
650  typename polydViewType>
651  KOKKOS_INLINE_FUNCTION
652  void
654  JacobiPolynomialDerivative(const ordinal_type np,
655  const zViewType z,
656  polydViewType polyd,
657  const ordinal_type n,
658  const double alpha,
659  const double beta) {
660  const double one = 1.0;
661  if (n == 0)
662  for(ordinal_type i = 0; i < np; ++i)
663  polyd(i) = 0.0;
664  else {
665  Kokkos::View<typename polydViewType::value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged> null;
666  JacobiPolynomial(np, z, polyd, null, n-1, alpha+one, beta+one);
667  for(ordinal_type i = 0; i < np; ++i)
668  polyd(i) *= 0.5*(alpha + beta + n + one);
669  }
670  }
671 
672  // -----------------------------------------------------------------------
673 
674  template<typename zViewType,
675  bool DeflationEnabled>
676  KOKKOS_INLINE_FUNCTION
677  void
679  JacobiZeros( zViewType z,
680  const ordinal_type n,
681  const double alpha,
682  const double beta) {
683  if (DeflationEnabled)
684  JacobiZerosPolyDeflation(z, n, alpha, beta);
685  else
686  JacobiZerosTriDiagonal(z, n, alpha, beta);
687  }
688 
689  template<typename zViewType>
690  KOKKOS_INLINE_FUNCTION
691  void
692  Polylib::Serial::
693  JacobiZerosPolyDeflation( zViewType z,
694  const ordinal_type n,
695  const double alpha,
696  const double beta) {
697  if(!n)
698  return;
699 
700  const double dth = M_PI/(2.0*n);
701  const double one = 1.0, two = 2.0;
702  const double tol = tolerence();
703 
704  typedef typename zViewType::value_type value_type;
705  typedef typename zViewType::pointer_type pointer_type;
706 
707  value_type r_buf, poly_buf, pder_buf;
708  Kokkos::View<value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged>
709  poly((pointer_type)&poly_buf, 1), pder((pointer_type)&pder_buf, 1), r((pointer_type)&r_buf, 1);
710 
711  value_type rlast = 0.0;
712  for (auto k = 0; k < n; ++k) {
713  r(0) = -cos((two*(double)k + one) * dth);
714  if (k)
715  r(0) = 0.5*(r(0) + rlast);
716 
717  for (ordinal_type j = 1; j < MaxPolylibIteration; ++j) {
718  JacobiPolynomial(1, r, poly, pder, n, alpha, beta);
719 
720  value_type sum = 0;
721  for (ordinal_type i = 0; i < k; ++i)
722  sum += one/(r(0) - z(i));
723 
724  const value_type delr = -poly(0) / (pder(0) - sum * poly(0));
725  r(0) += delr;
726 
727  if( Util<value_type>::abs(delr) < tol )
728  break;
729  }
730  z(k) = r(0);
731  rlast = r(0);
732  }
733  }
734 
735  template<typename aViewType>
736  KOKKOS_INLINE_FUNCTION
737  void
738  Polylib::Serial::
739  JacobiZerosTriDiagonal( aViewType a,
740  const ordinal_type n,
741  const double alpha,
742  const double beta) {
743  if(!n)
744  return;
745 
746  typedef typename aViewType::value_type value_type;
747  typedef typename aViewType::pointer_type pointer_type;
748 
749  value_type b_buf[MaxPolylibPoint];
750  Kokkos::View<value_type*,Kokkos::AnonymousSpace,Kokkos::MemoryUnmanaged>
751  b((pointer_type)&b_buf[0], MaxPolylibPoint);
752 
753  // generate normalised terms
754  const double apb = alpha + beta;
755  double apbi = 2.0 + apb;
756 
757  b(n-1) = pow(2.0,apb+1.0)*GammaFunction(alpha+1.0)*GammaFunction(beta+1.0)/GammaFunction(apbi);
758  a(0) = (beta-alpha)/apbi;
759  b(0) = sqrt(4.0*(1.0+alpha)*(1.0+beta)/((apbi+1.0)*apbi*apbi));
760 
761  const double a2b2 = beta*beta-alpha*alpha;
762  for (ordinal_type i = 1; i < n-1; ++i) {
763  apbi = 2.0*(i+1) + apb;
764  a(i) = a2b2/((apbi-2.0)*apbi);
765  b(i) = sqrt(4.0*(i+1)*(i+1+alpha)*(i+1+beta)*(i+1+apb)/
766  ((apbi*apbi-1)*apbi*apbi));
767  }
768 
769  apbi = 2.0*n + apb;
770  //a(n-1) = a2b2/((apbi-2.0)*apbi); // THIS IS A BUG!!!
771  if (n>1) a(n-1) = a2b2/((apbi-2.0)*apbi);
772 
773  // find eigenvalues
774  TriQL(a, b, n);
775  }
776 
777 
778  template<typename dViewType,
779  typename eViewType>
780  KOKKOS_INLINE_FUNCTION
781  void
783  TriQL( dViewType d,
784  eViewType e,
785  const ordinal_type n) {
786  ordinal_type m,l,iter,i,k;
787 
788  typedef typename dViewType::value_type value_type;
789  value_type s,r,p,g,f,dd,c,b;
790 
791  for (l=0; l<n; ++l) {
792  iter=0;
793  do {
794  for (m=l; m<n-1; ++m) {
796  if (Util<value_type>::abs(e(m))+dd == dd) break;
797  }
798  if (m != l) {
799  if (iter++ == MaxPolylibIteration) {
800  INTREPID2_TEST_FOR_ABORT(true,
801  ">>> ERROR (Polylib::Serial): Too many iterations in TQLI.");
802  }
803  g=(d(l+1)-d(l))/(2.0*e(l));
804  r=sqrt((g*g)+1.0);
805  //g=d(m)-d(l)+e(l)/(g+sign(r,g));
806  g=d(m)-d(l)+e(l)/(g+((g)<0 ? value_type(-Util<value_type>::abs(r)) : Util<value_type>::abs(r)));
807  s=c=1.0;
808  p=0.0;
809  for (i=m-1; i>=l; i--) {
810  f=s*e(i);
811  b=c*e(i);
813  c=g/f;
814  r=sqrt((c*c)+1.0);
815  e(i+1)=f*r;
816  c *= (s=1.0/r);
817  } else {
818  s=f/g;
819  r=sqrt((s*s)+1.0);
820  e(i+1)=g*r;
821  s *= (c=1.0/r);
822  }
823  g=d(i+1)-p;
824  r=(d(i)-g)*s+2.0*c*b;
825  p=s*r;
826  d(i+1)=g+p;
827  g=c*r-b;
828  }
829  d(l)=d(l)-p;
830  e(l)=g;
831  e(m)=0.0;
832  }
833  } while (m != l);
834  }
835 
836  // order eigenvalues
837  for (i = 0; i < n-1; ++i) {
838  k = i;
839  p = d(i);
840  for (l = i+1; l < n; ++l)
841  if (d(l) < p) {
842  k = l;
843  p = d(l);
844  }
845  d(k) = d(i);
846  d(i) = p;
847  }
848  }
849 
850  KOKKOS_INLINE_FUNCTION
851  double
853  GammaFunction(const double x) {
854  double gamma(0);
855 
856  if (x == -0.5) gamma = -2.0*sqrt(M_PI);
857  else if (x == 0.0) gamma = 1.0;
858  else if ((x-(ordinal_type)x) == 0.5) {
859  ordinal_type n = (ordinal_type) x;
860  auto tmp = x;
861 
862  gamma = sqrt(M_PI);
863  while (n--) {
864  tmp -= 1.0;
865  gamma *= tmp;
866  }
867  } else if ((x-(ordinal_type)x) == 0.0) {
868  ordinal_type n = (ordinal_type) x;
869  auto tmp = x;
870 
871  gamma = 1.0;
872  while (--n) {
873  tmp -= 1.0;
874  gamma *= tmp;
875  }
876  } else {
877  INTREPID2_TEST_FOR_ABORT(true,
878  ">>> ERROR (Polylib::Serial): Argument is not of integer or half order.");
879  }
880  return gamma;
881  }
882 
883 } // end of namespace Intrepid2
884 
885 #endif
small utility functions
static KOKKOS_INLINE_FUNCTION void JacobiPolynomialDerivative(const ordinal_type np, const zViewType z, polydViewType polyd, const ordinal_type n, const double alpha, const double beta)
Calculate the derivative of Jacobi polynomials.
static KOKKOS_INLINE_FUNCTION void JacobiPolynomial(const ordinal_type np, const zViewType z, polyiViewType poly_in, polydViewType polyd, const ordinal_type n, const double alpha, const double beta)
Routine to calculate Jacobi polynomials, , and their first derivative, .
static KOKKOS_INLINE_FUNCTION void JacobiZeros(zViewType z, const ordinal_type n, const double alpha, const double beta)
Calculate the n zeros, z, of the Jacobi polynomial, i.e. .
static KOKKOS_INLINE_FUNCTION double GammaFunction(const double x)
Calculate the Gamma function , , for integer values x and halves.
static KOKKOS_INLINE_FUNCTION void TriQL(dViewType d, eViewType e, const ordinal_type n)
QL algorithm for symmetric tridiagonal matrix.