coef_cheb_fft.C

00001 /*
00002  * Chebyshev transform via a FFT 
00003  *
00004  */
00005 
00006 /*
00007  *   Copyright (c) 2005 Eric Gourgoulhon & Jerome Novak
00008  *
00009  *   This file is part of LORENE.
00010  *
00011  *   LORENE is free software; you can redistribute it and/or modify
00012  *   it under the terms of the GNU General Public License as published by
00013  *   the Free Software Foundation; either version 2 of the License, or
00014  *   (at your option) any later version.
00015  *
00016  *   LORENE is distributed in the hope that it will be useful,
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *   GNU General Public License for more details.
00020  *
00021  *   You should have received a copy of the GNU General Public License
00022  *   along with LORENE; if not, write to the Free Software
00023  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  */
00026 
00027 /*
00028  * $Id: coef_cheb_fft.C,v 1.2 2005/11/14 14:12:10 e_gourgoulhon Exp $
00029  * $Log: coef_cheb_fft.C,v $
00030  * Revision 1.2  2005/11/14 14:12:10  e_gourgoulhon
00031  * Added include <assert.h>
00032  *
00033  * Revision 1.1  2005/11/14 01:56:58  e_gourgoulhon
00034  * First version
00035  *
00036  *
00037  * $Header: /cvsroot/Lorene/School05/Monday/coef_cheb_fft.C,v 1.2 2005/11/14 14:12:10 e_gourgoulhon Exp $
00038  *
00039  */
00040 
00041 
00042 #include <iostream>
00043 
00044 using namespace std ;
00045 
00046 #include <stdlib.h>
00047 #include <math.h>
00048 #include <assert.h>
00049 #include <fftw3.h>
00050 
00051 fftw_plan prepare_fft(int n, double*& pg) {
00052 
00053     static const int nmax = 50 ; //Maximal number of FFT sizes 
00054     static int nworked = 0 ;
00055     static double* tab_tab[nmax] ;
00056     static fftw_plan plan_fft[nmax] ;
00057     static int nb_fft[nmax] ;
00058 
00059   int index = -1 ;
00060   for (int i=0; ((i<nworked) && (index<0)); i++) 
00061     if (nb_fft[i] == n) index = i ; //Has the plan already been estimated?
00062 
00063   if (index <0) { //New plan needed
00064     index = nworked ;
00065     if (index >= nmax) {
00066       cout << "prepare_fft: " << endl ;
00067       cout << "too many plans!" << endl ;
00068       abort() ;
00069     }
00070         
00071     double* tab = new double[n] ;
00072     tab_tab[index] = tab ; 
00073 
00074     plan_fft[index] = 
00075       fftw_plan_r2r_1d(n, tab, tab, FFTW_R2HC, FFTW_MEASURE) ;
00076       
00077     nb_fft[index] = n ;
00078     nworked++ ;
00079   }
00080   assert((index>=0)&&(index<nmax)) ;
00081   pg = tab_tab[index] ;
00082   return plan_fft[index] ;
00083 }
00084 
00085 
00086 double* cheb_ini(int n) {
00087 
00088     const int nmax = 30 ; /* Nombre maximun de dimensions differentes */
00089     static  double* table_sin[nmax] ;   /* Tableau des pointeurs sur les tableaux */
00090     static  int nwork = 0 ;     /* Nombre de tableaux deja initialises */
00091     static  int tbn[nmax] ;     /* Tableau des points deja initialises */
00092 
00093     // Ce nombre de points a-t-il deja ete utilise ?
00094     int indice = -1 ;
00095     for (int i=0 ; i < nwork ; i++ ) {
00096         if ( tbn[i] == n ) indice = i ;
00097     }
00098 
00099     // Initialisation
00100     if (indice == -1) {         /* Il faut une nouvelle initialisation */
00101         if ( nwork >= nmax ) {
00102             cout << "cheb_ini : nwork >= nmax !" << endl ; 
00103             abort() ; 
00104         }
00105         indice = nwork ; nwork++ ; tbn[indice] = n ;
00106 
00107         int nm1s2 = (n-1) / 2 ;         
00108         table_sin[indice] = new double[nm1s2] ; 
00109 
00110         double xx = M_PI / double(n-1);
00111         for (int i = 0; i < nm1s2 ; i++ ) {
00112             table_sin[indice][i] = sin( xx * i );
00113         }
00114     }
00115 
00116     return table_sin[indice] ;
00117 }
00118 
00119 
00120 void coef_cheb_fft(int nr, const double* ff, double* cf) {
00121 
00122     // Nombre de points pour la FFT:
00123     int nm1 = nr - 1;
00124     int nm1s2 = nm1 / 2;
00125 
00126     // Recherche des tables pour la FFT:
00127     double* pg = 0x0 ;
00128     fftw_plan p = prepare_fft(nm1, pg) ;
00129     double* g = pg ;
00130 
00131     // Recherche de la table des sin(psi) :
00132     double* sinp = cheb_ini(nr);        
00133 
00134 /*
00135  * NB: dans les commentaires qui suivent, psi designe la variable de [0, pi]
00136  *     reliee a x par  x = - cos(psi)   et F(psi) = f(x(psi)).  
00137  */
00138  
00139     // Valeur en psi=0 de la partie antisymetrique de F, F_ :
00140     double fmoins0 = 0.5 * ( ff[0] - ff[nm1] );
00141 
00142 // Fonction G(psi) = F+(psi) + F_(psi) sin(psi) 
00143 //---------------------------------------------
00144             for (int i = 1; i < nm1s2 ; i++ ) {
00145 // ... indice du pt symetrique de psi par rapport a pi/2:
00146     int isym = nm1 - i ; 
00147 // ... F+(psi)  
00148     double fp = 0.5 * ( ff[i] + ff[isym] ) ;    
00149 // ... F_(psi) sin(psi)
00150     double fms = 0.5 * ( ff[i] - ff[isym] ) * sinp[i] ; 
00151     g[i] = fp + fms ;
00152     g[isym] = fp - fms ;
00153             }
00154 //... cas particuliers:
00155     g[0] = 0.5 * ( ff[0] + ff[nm1] );
00156     g[nm1s2] = ff[nm1s2];
00157 
00158 // Developpement de G en series de Fourier par une FFT
00159 //----------------------------------------------------
00160 
00161     fftw_execute(p) ;
00162 
00163 // Coefficients pairs du developmt. de Tchebyshev de f
00164 //----------------------------------------------------
00165 //  Ces coefficients sont egaux aux coefficients en cosinus du developpement
00166 //  de G en series de Fourier (le facteur 2/nm1 vient de la normalisation
00167 //  de fftw) :
00168 
00169         double fac = 2./double(nm1) ;
00170         cf[0] = g[0] / double(nm1) ;
00171         for (int i=2; i<nm1; i += 2) cf[i] = fac*g[i/2] ;
00172         cf[nm1] = g[nm1s2] / double(nm1) ;
00173 
00174 // Coefficients impairs du developmt. de Tchebyshev de f
00175 //------------------------------------------------------
00176 // 1. Coef. c'_k (recurrence amorcee a partir de zero):
00177 //    NB: Le 4/nm1 en facteur de g(i) est du a la normalisation de fftw
00178 //  (si fftw donnait reellement les coef. en sinus, il faudrait le
00179 //   remplacer par un +2.) 
00180         fac *= -2. ;
00181             cf[1] = 0 ;
00182             double som = 0;
00183             for (int i = 3; i < nr; i += 2 ) {
00184           cf[i] = cf[i-2] + fac * g[nm1-i/2] ;
00185             som += cf[i] ;
00186             }
00187 
00188 // 2. Calcul de c_1 :
00189         double c1 = - ( fmoins0 + som ) / nm1s2 ;
00190 
00191 // 3. Coef. c_k avec k impair:  
00192             cf[1] = c1 ;
00193             for (int i = 3; i < nr; i += 2 ) cf[i] += c1 ;
00194 
00195 }

Generated on Tue Dec 6 14:48:44 2011 for POLYNOM by  doxygen 1.4.6