Intrepid
/usr/src/RPM/BUILD/trilinos10-10.6.4/packages/intrepid/src/Shared/Intrepid_PolylibDef.hpp
Go to the documentation of this file.
00001 
00002 //
00003 // File: Intrepid_PolylibDef.hpp
00004 //
00005 // For more information, please see: http://www.nektar.info
00006 //
00007 // The MIT License
00008 //
00009 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
00010 // Department of Aeronautics, Imperial College London (UK), and Scientific
00011 // Computing and Imaging Institute, University of Utah (USA).
00012 //
00013 // License for the specific language governing rights and limitations under
00014 // Permission is hereby granted, free of charge, to any person obtaining a
00015 // copy of this software and associated documentation files (the "Software"),
00016 // to deal in the Software without restriction, including without limitation
00017 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00018 // and/or sell copies of the Software, and to permit persons to whom the
00019 // Software is furnished to do so, subject to the following conditions:
00020 //
00021 // The above copyright notice and this permission notice shall be included
00022 // in all copies or substantial portions of the Software.
00023 //
00024 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00025 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00026 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00027 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00028 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00029 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00030 // DEALINGS IN THE SOFTWARE.
00031 //
00032 // Description:
00033 // This file is redistributed with the Intrepid package. It should be used
00034 // in accordance with the above MIT license, at the request of the authors.
00035 // This file is NOT covered by the usual Intrepid/Trilinos LGPL license.
00036 //
00037 // Origin: Nektar++ library, http://www.nektar.info, downloaded on
00038 //         March 10, 2009.
00039 //
00041 
00042 
00049 #ifdef _MSC_VER
00050 #include "winmath.h"
00051 #endif
00052 
00053 
00054 namespace Intrepid {
00055 
00057 #define INTREPID_POLYLIB_STOP 50 
00058 
00060 #define INTREPID_POLYLIB_POLYNOMIAL_DEFLATION 0
00061 
00062 #ifdef INTREPID_POLYLIB_POLYNOMIAL_DEFLATION
00063 
00064 #define jacobz(n,z,alpha,beta) Jacobz(n,z,alpha,beta)
00065 #else
00066 
00067 #define jacobz(n,z,alpha,beta) JacZeros(n,z,alpha,beta)
00068 #endif
00069 
00070 
00071 template <class Scalar>
00072 void IntrepidPolylib::zwgj (Scalar *z, Scalar *w, const int np, const Scalar alpha, const Scalar beta){
00073   register int i;
00074   Scalar fac, one = 1.0, two = 2.0, apb = alpha + beta;
00075 
00076   IntrepidPolylib::jacobz (np,z,alpha,beta);
00077   IntrepidPolylib::jacobd (np,z,w,np,alpha,beta);
00078 
00079   fac  = std::pow(two,apb + one)*IntrepidPolylib::gammaF(alpha + np + one)*IntrepidPolylib::gammaF(beta + np + one);
00080   fac /= IntrepidPolylib::gammaF((Scalar)(np + one))*IntrepidPolylib::gammaF(apb + np + one);
00081 
00082   for(i = 0; i < np; ++i) w[i] = fac/(w[i]*w[i]*(one-z[i]*z[i]));
00083 
00084   return;
00085 }
00086 
00087 
00088 template <class Scalar>
00089 void IntrepidPolylib::zwgrjm(Scalar *z, Scalar *w, const int np, const Scalar alpha, const Scalar beta){
00090 
00091   if(np == 1){
00092     z[0] = 0.0;
00093     w[0] = 2.0;
00094   }
00095   else{
00096     register int i;
00097     Scalar fac, one = 1.0, two = 2.0, apb = alpha + beta;
00098 
00099     z[0] = -one;
00100     IntrepidPolylib::jacobz  (np-1,z+1,alpha,beta+1);
00101     IntrepidPolylib::jacobfd (np,z,w,(Scalar*)0,np-1,alpha,beta);
00102 
00103     fac  = std::pow(two,apb)*IntrepidPolylib::gammaF(alpha + np)*IntrepidPolylib::gammaF(beta + np);
00104     fac /= IntrepidPolylib::gammaF((Scalar)np)*(beta + np)*IntrepidPolylib::gammaF(apb + np + 1);
00105 
00106     for(i = 0; i < np; ++i) w[i] = fac*(1-z[i])/(w[i]*w[i]);
00107     w[0] *= (beta + one);
00108   }
00109 
00110   return;
00111 }
00112 
00113 
00114 template <class Scalar>
00115 void IntrepidPolylib::zwgrjp(Scalar *z, Scalar *w, const int np, const Scalar alpha, const Scalar beta){
00116 
00117   if(np == 1){
00118     z[0] = 0.0;
00119     w[0] = 2.0;
00120   }
00121   else{
00122     register int i;
00123     Scalar fac, one = 1.0, two = 2.0, apb = alpha + beta;
00124 
00125     IntrepidPolylib::jacobz  (np-1,z,alpha+1,beta);
00126     z[np-1] = one;
00127     IntrepidPolylib::jacobfd (np,z,w,(Scalar*)0,np-1,alpha,beta);
00128 
00129     fac  = std::pow(two,apb)*IntrepidPolylib::gammaF(alpha + np)*IntrepidPolylib::gammaF(beta + np);
00130     fac /= IntrepidPolylib::gammaF((Scalar)np)*(alpha + np)*IntrepidPolylib::gammaF(apb + np + 1);
00131 
00132     for(i = 0; i < np; ++i) w[i] = fac*(1+z[i])/(w[i]*w[i]);
00133     w[np-1] *= (alpha + one);
00134   }
00135 
00136   return;
00137 }
00138 
00139 
00140 template <class Scalar>
00141 void IntrepidPolylib::zwglj(Scalar *z, Scalar *w, const int np, const Scalar alpha, const Scalar beta){
00142 
00143   if( np == 1 ){
00144     z[0] = 0.0;
00145     w[0] = 2.0;
00146   }
00147   else{
00148     register int i;
00149     Scalar   fac, one = 1.0, apb = alpha + beta, two = 2.0;
00150 
00151     z[0]    = -one;
00152     z[np-1] =  one;
00153     IntrepidPolylib::jacobz  (np-2,z + 1,alpha + one,beta + one);
00154     IntrepidPolylib::jacobfd (np,z,w,(Scalar*)0,np-1,alpha,beta);
00155 
00156     fac  = std::pow(two,apb + 1)*IntrepidPolylib::gammaF(alpha + np)*IntrepidPolylib::gammaF(beta + np);
00157     fac /= (np-1)*IntrepidPolylib::gammaF((Scalar)np)*IntrepidPolylib::gammaF(alpha + beta + np + one);
00158 
00159     for(i = 0; i < np; ++i) w[i] = fac/(w[i]*w[i]);
00160     w[0]    *= (beta  + one);
00161     w[np-1] *= (alpha + one);
00162   }
00163 
00164   return;
00165 }
00166 
00167 
00168 template <class Scalar>
00169 void IntrepidPolylib::Dgj(Scalar *D,  const Scalar *z, const int np, const Scalar alpha, const Scalar beta)
00170 {
00171 
00172     Scalar one = 1.0, two = 2.0;
00173 
00174     if (np <= 0){
00175         D[0] = 0.0;
00176     }
00177     else{
00178         register int i,j; 
00179         Scalar *pd;
00180 
00181         pd = (Scalar *)malloc(np*sizeof(Scalar));
00182         IntrepidPolylib::jacobd(np,z,pd,np,alpha,beta);
00183 
00184         for (i = 0; i < np; i++){
00185             for (j = 0; j < np; j++){
00186 
00187                 if (i != j) 
00188                     //D[i*np+j] = pd[j]/(pd[i]*(z[j]-z[i])); <--- This is either a bug, or the derivative matrix is not defined consistently.
00189                     D[i*np+j] = pd[i]/(pd[j]*(z[i]-z[j]));
00190                 else    
00191                     D[i*np+j] = (alpha - beta + (alpha + beta + two)*z[j])/
00192                     (two*(one - z[j]*z[j]));
00193             }
00194         }
00195         free(pd);
00196     }
00197     return;
00198 }
00199 
00200 
00201 template <class Scalar>
00202 void IntrepidPolylib::Dgrjm(Scalar *D, const Scalar *z, const int np, const Scalar alpha, const Scalar beta)
00203 {
00204 
00205     if (np <= 0){
00206         D[0] = 0.0;
00207     }
00208     else{
00209         register int i, j; 
00210         Scalar   one = 1.0, two = 2.0;
00211         Scalar   *pd;
00212 
00213         pd  = (Scalar *)malloc(np*sizeof(Scalar));
00214 
00215         pd[0] = std::pow(-one,np-1)*IntrepidPolylib::gammaF((Scalar)np+beta+one);
00216         pd[0] /= IntrepidPolylib::gammaF((Scalar)np)*IntrepidPolylib::gammaF(beta+two);
00217         IntrepidPolylib::jacobd(np-1,z+1,pd+1,np-1,alpha,beta+1);
00218         for(i = 1; i < np; ++i) pd[i] *= (1+z[i]);
00219 
00220         for (i = 0; i < np; i++) {
00221             for (j = 0; j < np; j++){
00222                 if (i != j) 
00223                     //D[i*np+j] = pd[j]/(pd[i]*(z[j]-z[i])); <--- This is either a bug, or the derivative matrix is not defined consistently.
00224                     D[i*np+j] = pd[i]/(pd[j]*(z[i]-z[j]));
00225                 else { 
00226                     if(j == 0)
00227                         D[i*np+j] = -(np + alpha + beta + one)*(np - one)/
00228                         (two*(beta + two));
00229                     else
00230                         D[i*np+j] = (alpha - beta + one + (alpha + beta + one)*z[j])/
00231                         (two*(one - z[j]*z[j]));
00232                 }
00233             }
00234         }
00235         free(pd);
00236     }
00237     return;
00238 }
00239 
00240 
00241 template <class Scalar>
00242 void IntrepidPolylib::Dgrjp(Scalar *D, const Scalar *z, const int np, const Scalar alpha, const Scalar beta)
00243 {
00244 
00245     if (np <= 0){
00246         D[0] = 0.0;
00247     }
00248     else{
00249         register int i, j; 
00250         Scalar   one = 1.0, two = 2.0;
00251         Scalar   *pd;
00252 
00253         pd  = (Scalar *)malloc(np*sizeof(Scalar));
00254 
00255 
00256         IntrepidPolylib::jacobd(np-1,z,pd,np-1,alpha+1,beta);
00257         for(i = 0; i < np-1; ++i) pd[i] *= (1-z[i]);
00258         pd[np-1] = -IntrepidPolylib::gammaF((Scalar)np+alpha+one);
00259         pd[np-1] /= IntrepidPolylib::gammaF((Scalar)np)*IntrepidPolylib::gammaF(alpha+two);
00260 
00261         for (i = 0; i < np; i++) {
00262             for (j = 0; j < np; j++){
00263                 if (i != j)
00264                     //D[i*np+j] = pd[j]/(pd[i]*(z[j]-z[i])); <--- This is either a bug, or the derivative matrix is not defined consistently.
00265                     D[i*np+j] = pd[i]/(pd[j]*(z[i]-z[j]));
00266                 else { 
00267                     if(j == np-1)
00268                         D[i*np+j] = (np + alpha + beta + one)*(np - one)/
00269                         (two*(alpha + two));
00270                     else
00271                         D[i*np+j] = (alpha - beta - one + (alpha + beta + one)*z[j])/
00272                         (two*(one - z[j]*z[j]));
00273                 }
00274             }
00275         }
00276         free(pd);
00277     }
00278     return;
00279 }
00280 
00281 
00282 template <class Scalar>
00283 void IntrepidPolylib::Dglj(Scalar *D, const Scalar *z, const int np, const Scalar alpha, const Scalar beta)
00284 {
00285 
00286     if (np <= 0){
00287         D[0] = 0.0;
00288     }
00289     else{
00290         register int i, j; 
00291         Scalar   one = 1.0, two = 2.0;
00292         Scalar   *pd;
00293 
00294         pd  = (Scalar *)malloc(np*sizeof(Scalar));
00295 
00296         pd[0]  = two*std::pow(-one,np)*IntrepidPolylib::gammaF((Scalar)np + beta);
00297         pd[0] /= IntrepidPolylib::gammaF((Scalar)np - one)*IntrepidPolylib::gammaF(beta + two);
00298         IntrepidPolylib::jacobd(np-2,z+1,pd+1,np-2,alpha+1,beta+1);
00299         for(i = 1; i < np-1; ++i) pd[i] *= (one-z[i]*z[i]);
00300         pd[np-1]  = -two*IntrepidPolylib::gammaF((Scalar)np + alpha);
00301         pd[np-1] /= IntrepidPolylib::gammaF((Scalar)np - one)*IntrepidPolylib::gammaF(alpha + two);
00302 
00303         for (i = 0; i < np; i++) {
00304             for (j = 0; j < np; j++){
00305                 if (i != j)
00306                     //D[i*np+j] = pd[j]/(pd[i]*(z[j]-z[i])); <--- This is either a bug, or the derivative matrix is not defined consistently.
00307                     D[i*np+j] = pd[i]/(pd[j]*(z[i]-z[j]));
00308                 else { 
00309                     if (j == 0)
00310                         D[i*np+j] = (alpha - (np-1)*(np + alpha + beta))/(two*(beta+ two));
00311                     else if (j == np-1)
00312                         D[i*np+j] =-(beta - (np-1)*(np + alpha + beta))/(two*(alpha+ two));
00313                     else
00314                         D[i*np+j] = (alpha - beta + (alpha + beta)*z[j])/
00315                         (two*(one - z[j]*z[j]));
00316                 }
00317             }
00318         }
00319         free(pd);
00320     }
00321     return;
00322 }
00323 
00324 
00325 template <class Scalar>
00326 Scalar IntrepidPolylib::hgj (const int i, const Scalar z, const Scalar *zgj,
00327                              const int np, const Scalar alpha, const Scalar beta)
00328 {
00329 
00330     Scalar zi, dz, p, pd, h;
00331 
00332     zi  = *(zgj+i);
00333     dz  = z - zi;
00334     if (std::abs(dz) < INTREPID_TOL) return 1.0;
00335 
00336     IntrepidPolylib::jacobd (1, &zi, &pd , np, alpha, beta);
00337     IntrepidPolylib::jacobfd(1, &z , &p, (Scalar*)0 , np, alpha, beta);
00338     h = p/(pd*dz);
00339 
00340     return h;
00341 }
00342 
00343 
00344 template <class Scalar>
00345 Scalar IntrepidPolylib::hgrjm (const int i, const Scalar z, const Scalar *zgrj,
00346                                const int np, const Scalar alpha, const Scalar beta)
00347 {
00348 
00349     Scalar zi, dz, p, pd, h;
00350 
00351     zi  = *(zgrj+i);
00352     dz  = z - zi;
00353     if (std::abs(dz) < INTREPID_TOL) return 1.0;
00354 
00355     IntrepidPolylib::jacobfd (1, &zi, &p , (Scalar*)0, np-1, alpha, beta + 1);
00356     // need to use this routine in case zi = -1 or 1
00357     IntrepidPolylib::jacobd  (1, &zi, &pd, np-1, alpha, beta + 1);
00358     h = (1.0 + zi)*pd + p;
00359     IntrepidPolylib::jacobfd (1, &z, &p, (Scalar*)0,  np-1, alpha, beta + 1);
00360     h = (1.0 + z )*p/(h*dz);
00361 
00362     return h;
00363 }
00364 
00365 
00366 template <class Scalar>
00367 Scalar IntrepidPolylib::hgrjp (const int i, const Scalar z, const Scalar *zgrj,
00368                                const int np, const Scalar alpha, const Scalar beta)
00369 {
00370 
00371     Scalar zi, dz, p, pd, h;
00372 
00373     zi  = *(zgrj+i);
00374     dz  = z - zi;
00375     if (std::abs(dz) < INTREPID_TOL) return 1.0;
00376 
00377     IntrepidPolylib::jacobfd (1, &zi, &p , (Scalar*)0, np-1, alpha+1, beta );
00378     // need to use this routine in case z = -1 or 1
00379     IntrepidPolylib::jacobd  (1, &zi, &pd, np-1, alpha+1, beta );
00380     h = (1.0 - zi)*pd - p;
00381     IntrepidPolylib::jacobfd (1, &z, &p, (Scalar*)0,  np-1, alpha+1, beta);
00382     h = (1.0 - z )*p/(h*dz);
00383 
00384     return h;
00385 }
00386 
00387 
00388 template <class Scalar>
00389 Scalar IntrepidPolylib::hglj (const int i, const Scalar z, const Scalar *zglj,
00390                               const int np, const Scalar alpha, const Scalar beta)
00391 {
00392     Scalar one = 1., two = 2.;
00393     Scalar zi, dz, p, pd, h;
00394 
00395     zi  = *(zglj+i);
00396     dz  = z - zi;
00397     if (std::abs(dz) < INTREPID_TOL) return 1.0;
00398 
00399     IntrepidPolylib::jacobfd(1, &zi, &p , (Scalar*)0, np-2, alpha + one, beta + one);
00400     // need to use this routine in case z = -1 or 1
00401     IntrepidPolylib::jacobd (1, &zi, &pd, np-2, alpha + one, beta + one);
00402     h = (one - zi*zi)*pd - two*zi*p;
00403     IntrepidPolylib::jacobfd(1, &z, &p, (Scalar*)0, np-2, alpha + one, beta + one);
00404     h = (one - z*z)*p/(h*dz);
00405 
00406     return h;
00407 }
00408 
00409 
00410 template <class Scalar>
00411 void IntrepidPolylib::Imgj(Scalar *im, const Scalar *zgj, const Scalar *zm, const int nz, 
00412                            const int mz, const Scalar alpha, const Scalar beta){
00413         Scalar zp;
00414         register int i, j;
00415 
00416         /* old Polylib code */
00417         for (i = 0; i < mz; ++i) {
00418             zp = zm[i];
00419             for (j = 0; j < nz; ++j) {
00420                 im[i*nz+j] = IntrepidPolylib::hgj(j, zp, zgj, nz, alpha, beta);
00421             }
00422         }
00423 
00424         /* original Nektar++ code: is this correct???
00425         for (i = 0; i < nz; ++i) {
00426             for (j = 0; j < mz; ++j)
00427             {
00428                 zp = zm[j];
00429                 im [i*mz+j] = IntrepidPolylib::hgj(i, zp, zgj, nz, alpha, beta);
00430             }
00431         }
00432         */
00433 
00434         return;
00435 }
00436 
00437 
00438 template <class Scalar>
00439 void IntrepidPolylib::Imgrjm(Scalar *im, const Scalar *zgrj, const Scalar *zm, const int nz,
00440                              const int mz, const Scalar alpha, const Scalar beta)
00441 {
00442     Scalar zp;
00443     register int i, j;
00444 
00445     for (i = 0; i < mz; i++) {
00446       zp = zm[i];
00447       for (j = 0; j < nz; j++) {
00448         im[i*nz+j] = IntrepidPolylib::hgrjm(j, zp, zgrj, nz, alpha, beta);
00449       }
00450     }
00451 
00452     /* original Nektar++ code: is this correct???
00453     for (i = 0; i < nz; i++) {
00454         for (j = 0; j < mz; j++)
00455         {
00456             zp = zm[j];
00457             im [i*mz+j] = IntrepidPolylib::hgrjm(i, zp, zgrj, nz, alpha, beta);
00458         }
00459     }
00460     */
00461 
00462     return;
00463 }
00464 
00465 
00466 template <class Scalar>
00467 void IntrepidPolylib::Imgrjp(Scalar *im, const Scalar *zgrj, const Scalar *zm, const int nz, 
00468                              const int mz, const Scalar alpha, const Scalar beta)
00469 {
00470         Scalar zp;
00471         register int i, j;
00472 
00473         for (i = 0; i < mz; i++) {
00474           zp = zm[i];
00475           for (j = 0; j < nz; j++) {
00476             im [i*nz+j] = IntrepidPolylib::hgrjp(j, zp, zgrj, nz, alpha, beta);
00477           }
00478         }
00479 
00480         /* original Nektar++ code: is this correct?
00481         for (i = 0; i < nz; i++) {
00482             for (j = 0; j < mz; j++)
00483             {
00484                 zp = zm[j];
00485                 im [i*mz+j] = IntrepidPolylib::hgrjp(i, zp, zgrj, nz, alpha, beta);
00486             }
00487         }
00488         */
00489 
00490         return;
00491 }
00492 
00493 
00494 template <class Scalar>
00495 void IntrepidPolylib::Imglj(Scalar *im, const Scalar *zglj, const Scalar *zm, const int nz, 
00496                             const int mz, const Scalar alpha, const Scalar beta)
00497 {
00498     Scalar zp;
00499     register int i, j;
00500 
00501     for (i = 0; i < mz; i++) {
00502       zp = zm[i];
00503       for (j = 0; j < nz; j++) {
00504         im[i*nz+j] = IntrepidPolylib::hglj(j, zp, zglj, nz, alpha, beta);
00505       }
00506     }
00507 
00508     /* original Nektar++ code: is this correct?
00509     for (i = 0; i < nz; i++) {
00510         for (j = 0; j < mz; j++)
00511         {
00512             zp = zm[j];
00513             im[i*mz+j] = IntrepidPolylib::hglj(i, zp, zglj, nz, alpha, beta);
00514         }
00515     }
00516     */
00517 
00518     return;
00519 }
00520 
00521 
00522 template <class Scalar>
00523 void IntrepidPolylib::jacobfd(const int np, const Scalar *z, Scalar *poly_in, Scalar *polyd,
00524                               const int n, const Scalar alpha, const Scalar beta){
00525   register int i;
00526   Scalar  zero = 0.0, one = 1.0, two = 2.0;
00527 
00528   if(!np)
00529     return;
00530 
00531   if(n == 0){
00532     if(poly_in)
00533       for(i = 0; i < np; ++i)
00534         poly_in[i] = one;
00535     if(polyd)
00536       for(i = 0; i < np; ++i)
00537         polyd[i] = zero;
00538   }
00539   else if (n == 1){
00540     if(poly_in)
00541       for(i = 0; i < np; ++i)
00542         poly_in[i] = 0.5*(alpha - beta + (alpha + beta + two)*z[i]);
00543     if(polyd)
00544       for(i = 0; i < np; ++i)
00545         polyd[i] = 0.5*(alpha + beta + two);
00546   }
00547   else{
00548     register int k;
00549     Scalar   a1,a2,a3,a4;
00550     Scalar   two = 2.0, apb = alpha + beta;
00551     Scalar   *poly, *polyn1,*polyn2;
00552 
00553     if(poly_in){ // switch for case of no poynomial function return
00554       polyn1 = (Scalar *)malloc(2*np*sizeof(Scalar));
00555       polyn2 = polyn1+np;
00556       poly   = poly_in;
00557     }
00558     else{
00559       polyn1 = (Scalar *)malloc(3*np*sizeof(Scalar));
00560       polyn2 = polyn1+np;
00561       poly   = polyn2+np;
00562     }
00563 
00564     for(i = 0; i < np; ++i){
00565       polyn2[i] = one;
00566       polyn1[i] = 0.5*(alpha - beta + (alpha + beta + two)*z[i]);
00567     }
00568 
00569     for(k = 2; k <= n; ++k){
00570       a1 =  two*k*(k + apb)*(two*k + apb - two);
00571       a2 = (two*k + apb - one)*(alpha*alpha - beta*beta);
00572       a3 = (two*k + apb - two)*(two*k + apb - one)*(two*k + apb);
00573       a4 =  two*(k + alpha - one)*(k + beta - one)*(two*k + apb);
00574 
00575       a2 /= a1;
00576       a3 /= a1;
00577       a4 /= a1;
00578 
00579       for(i = 0; i < np; ++i){
00580         poly  [i] = (a2 + a3*z[i])*polyn1[i] - a4*polyn2[i];
00581         polyn2[i] = polyn1[i];
00582         polyn1[i] = poly  [i];
00583       }
00584     }
00585 
00586     if(polyd){
00587       a1 = n*(alpha - beta);
00588       a2 = n*(two*n + alpha + beta);
00589       a3 = two*(n + alpha)*(n + beta);
00590       a4 = (two*n + alpha + beta);
00591       a1 /= a4;  a2 /= a4;   a3 /= a4;
00592 
00593       // note polyn2 points to polyn1 at end of poly iterations
00594       for(i = 0; i < np; ++i){
00595         polyd[i]  = (a1- a2*z[i])*poly[i] + a3*polyn2[i];
00596         polyd[i] /= (one - z[i]*z[i]);
00597       }
00598     }
00599 
00600     free(polyn1);
00601   }
00602 
00603   return;
00604 }
00605 
00606 
00607 template <class Scalar>
00608 void IntrepidPolylib::jacobd(const int np, const Scalar *z, Scalar *polyd, const int n,
00609                              const Scalar alpha, const Scalar beta)
00610 {
00611   register int i;
00612   Scalar one = 1.0;
00613   if(n == 0)
00614     for(i = 0; i < np; ++i) polyd[i] = 0.0;
00615   else{
00616     //jacobf(np,z,polyd,n-1,alpha+one,beta+one);
00617     IntrepidPolylib::jacobfd(np,z,polyd,(Scalar*)0,n-1,alpha+one,beta+one);
00618     for(i = 0; i < np; ++i) polyd[i] *= 0.5*(alpha + beta + (Scalar)n + one);
00619   }
00620   return;
00621 }
00622 
00623 
00624 template <class Scalar>
00625 void IntrepidPolylib::Jacobz(const int n, Scalar *z, const Scalar alpha, const Scalar beta){
00626     register int i,j,k;
00627     Scalar   dth = M_PI/(2.0*(Scalar)n);
00628     Scalar   poly,pder,rlast=0.0;
00629     Scalar   sum,delr,r;
00630     Scalar one = 1.0, two = 2.0;
00631 
00632     if(!n)
00633         return;
00634 
00635     for(k = 0; k < n; ++k){
00636         r = -std::cos((two*(Scalar)k + one) * dth);
00637         if(k) r = 0.5*(r + rlast);
00638 
00639         for(j = 1; j < INTREPID_POLYLIB_STOP; ++j){
00640             IntrepidPolylib::jacobfd(1,&r,&poly, &pder, n, alpha, beta);
00641 
00642             for(i = 0, sum = 0.0; i < k; ++i) sum += one/(r - z[i]);
00643 
00644             delr = -poly / (pder - sum * poly);
00645             r   += delr;
00646             if( std::abs(delr) < INTREPID_TOL ) break;
00647         }
00648         z[k]  = r;
00649         rlast = r;
00650     }
00651     return;
00652 }
00653 
00654 
00655 template <class Scalar>
00656 void IntrepidPolylib::JacZeros(const int n, Scalar *a, const Scalar alpha, const Scalar beta){
00657   int i;
00658   Scalar apb, apbi,a2b2;
00659   Scalar *b;
00660 
00661   if(!n)
00662     return;
00663 
00664   b = (Scalar *) malloc(n*sizeof(Scalar));
00665 
00666   // generate normalised terms
00667   apb  = alpha + beta;
00668   apbi = 2.0 + apb;
00669 
00670   b[n-1] = std::pow(2.0,apb+1.0)*IntrepidPolylib::gammaF(alpha+1.0)*IntrepidPolylib::gammaF(beta+1.0)/gammaF(apbi);
00671   a[0]   = (beta-alpha)/apbi;
00672   b[0]   = std::sqrt(4.0*(1.0+alpha)*(1.0+beta)/((apbi+1.0)*apbi*apbi));
00673 
00674   a2b2 = beta*beta-alpha*alpha;
00675   for(i = 1; i < n-1; ++i){
00676     apbi = 2.0*(i+1) + apb;
00677     a[i] = a2b2/((apbi-2.0)*apbi);
00678     b[i] = std::sqrt(4.0*(i+1)*(i+1+alpha)*(i+1+beta)*(i+1+apb)/
00679                      ((apbi*apbi-1)*apbi*apbi));
00680   }
00681 
00682   apbi   = 2.0*n + apb;
00683   //a[n-1] = a2b2/((apbi-2.0)*apbi); // THIS IS A BUG!!!
00684   if (n>1) a[n-1] = a2b2/((apbi-2.0)*apbi);
00685 
00686   // find eigenvalues
00687   IntrepidPolylib::TriQL(n, a, b);
00688 
00689   free(b);
00690   return;
00691 }
00692 
00693 
00694 template <class Scalar>
00695 void IntrepidPolylib::TriQL(const int n, Scalar *d,Scalar *e) {
00696   int m,l,iter,i,k;
00697   Scalar s,r,p,g,f,dd,c,b;
00698 
00699   for (l=0;l<n;l++) {
00700     iter=0;
00701     do {
00702       for (m=l;m<n-1;m++) {
00703         dd=std::abs(d[m])+std::abs(d[m+1]);
00704         if (std::abs(e[m])+dd == dd) break;
00705       }
00706       if (m != l) {
00707         if (iter++ == 50){
00708           TEST_FOR_EXCEPTION((1),
00709                              std::runtime_error,
00710                              ">>> ERROR (IntrepidPolylib): Too many iterations in TQLI.");
00711         }
00712         g=(d[l+1]-d[l])/(2.0*e[l]);
00713         r=std::sqrt((g*g)+1.0);
00714         //g=d[m]-d[l]+e[l]/(g+sign(r,g));
00715         g=d[m]-d[l]+e[l]/(g+((g)<0 ? -std::abs(r) : std::abs(r)));
00716         s=c=1.0;
00717         p=0.0;
00718         for (i=m-1;i>=l;i--) {
00719           f=s*e[i];
00720           b=c*e[i];
00721           if (std::abs(f) >= std::abs(g)) {
00722             c=g/f;
00723             r=std::sqrt((c*c)+1.0);
00724             e[i+1]=f*r;
00725             c *= (s=1.0/r);
00726           } else {
00727             s=f/g;
00728             r=std::sqrt((s*s)+1.0);
00729             e[i+1]=g*r;
00730             s *= (c=1.0/r);
00731           }
00732           g=d[i+1]-p;
00733           r=(d[i]-g)*s+2.0*c*b;
00734           p=s*r;
00735           d[i+1]=g+p;
00736           g=c*r-b;
00737         }
00738         d[l]=d[l]-p;
00739         e[l]=g;
00740         e[m]=0.0;
00741       }
00742     } while (m != l);
00743   }
00744 
00745   // order eigenvalues
00746   for(i = 0; i < n-1; ++i){
00747     k = i;
00748     p = d[i];
00749     for(l = i+1; l < n; ++l)
00750       if (d[l] < p) {
00751         k = l;
00752         p = d[l];
00753       }
00754     d[k] = d[i];
00755     d[i] = p;
00756   }
00757 }
00758 
00759 
00760 template <class Scalar>
00761 Scalar IntrepidPolylib::gammaF(const Scalar x){
00762   Scalar gamma = 1.0;
00763 
00764   if     (x == -0.5) gamma = -2.0*std::sqrt(M_PI);
00765   else if (!x) return gamma;
00766   else if ((x-(int)x) == 0.5){
00767     int n = (int) x;
00768     Scalar tmp = x;
00769 
00770     gamma = std::sqrt(M_PI);
00771     while(n--){
00772       tmp   -= 1.0;
00773       gamma *= tmp;
00774     }
00775   }
00776   else if ((x-(int)x) == 0.0){
00777     int n = (int) x;
00778     Scalar tmp = x;
00779 
00780     while(--n){
00781       tmp   -= 1.0;
00782       gamma *= tmp;
00783     }
00784   }
00785   else
00786     TEST_FOR_EXCEPTION((1),
00787                        std::invalid_argument,
00788                        ">>> ERROR (IntrepidPolylib): Argument is not of integer or half order.");
00789   return gamma;
00790 }
00791 
00792 } // end of namespace Intrepid
00793