RealFFTTest.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Duncan Brown, Jolien Creighton
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /**** <lalVerbatim file="RealFFTTestCV">
00021  * $Id: RealFFTTest.c,v 1.12 2007/06/08 14:41:44 bema Exp $
00022  **** </lalVerbatim> */
00023 
00024 /**** <lalLaTeX>
00025  * 
00026  * \subsection{Program \texttt{RealFFTTest.c}}
00027  * \label{ss:RealFFTTest.c}
00028  * 
00029  * Tests the routines in \verb+RealFFT.h+.
00030  * 
00031  * \subsection*{Usage}
00032  * \begin{verbatim}
00033  * RealFFTTest [options]
00034  * Options:
00035  *   -h         print this message
00036  *   -q         quiet: run silently
00037  *   -v         verbose: print extra information
00038  *   -d level   set lalDebugLevel to level
00039  *   -m trials  set number of random trials
00040  *   -n size    set size of FFTs
00041  * \end{verbatim}
00042  * 
00043  * Use the \verb+-n+ option to specify the size of the test transform and
00044  * the \verb+-m+ option to specify the number of test transforms of that size.
00045  * (Default is to test transforms of size 1 to 128 in unit steps and then
00046  * powers of two up to 65536.)
00047  * 
00048  * \subsubsection*{Description}
00049  * \subsubsection*{Exit codes}
00050  * \begin{tabular}{|c|l|}
00051  * \hline
00052  * Code & Explanation                   \\
00053  * \hline
00054  * \tt 0 & Success, normal exit.         \\
00055  * \tt 1 & Subroutine failed.            \\
00056  * \hline
00057  * \end{tabular}
00058  * 
00059  * \subsubsection*{Uses}
00060  * \subsubsection*{Notes}
00061  * 
00062  * \vfill{\footnotesize\input{RealFFTTestCV}}
00063  * 
00064  **** </lalLaTeX> */
00065 
00066 #include <stdio.h>
00067 #include <stdlib.h>
00068 #include <math.h>
00069 #include <lal/LALConfig.h>
00070 
00071 #ifdef HAVE_UNISTD_H
00072 #include <unistd.h>
00073 #endif
00074 
00075 #ifdef HAVE_GETOPT_H
00076 #include <getopt.h>
00077 #endif
00078 
00079 #include <lal/LALStdlib.h>
00080 #include <lal/LALConstants.h>
00081 #include <lal/SeqFactories.h>
00082 #include <lal/RealFFT.h>
00083 #include <lal/VectorOps.h>
00084 
00085 #define CODES_(x) #x
00086 #define CODES(x) CODES_(x)
00087 
00088 NRCSID( MAIN, "$Id: RealFFTTest.c,v 1.12 2007/06/08 14:41:44 bema Exp $" );
00089 
00090 extern char *optarg;
00091 extern int   optind;
00092 
00093 int lalDebugLevel = 0;
00094 int verbose       = 0;
00095 UINT4 m_ = 1; /* number of random trials */
00096 UINT4 n_ = 0; /* size of each transform  */
00097 
00098 static void
00099 Usage( const char *program, int exitflag );
00100 
00101 static void
00102 ParseOptions( int argc, char *argv[] );
00103 
00104 static void
00105 TestStatus( LALStatus *status, const char *expectedCodes, int exitCode );
00106 
00107 static void
00108 ClearStatus( LALStatus *status );
00109 
00110 void LALForwardRealDFT(
00111     LALStatus      *status,
00112     COMPLEX8Vector *output,
00113     REAL4Vector    *input
00114     );
00115 
00116 int main( int argc, char *argv[] )
00117 {
00118   static LALStatus status; 
00119 
00120   RealFFTPlan    *fwd = NULL;
00121   RealFFTPlan    *rev = NULL;
00122   REAL4Vector    *dat = NULL;
00123   REAL4Vector    *rfft = NULL;
00124   REAL4Vector    *ans = NULL;
00125   COMPLEX8Vector *dft = NULL;
00126   COMPLEX8Vector *fft = NULL;
00127   REAL8           eps = 1e-6; /* very conservative floating point precision */
00128   REAL8           lbn;
00129   REAL8           ssq;
00130   REAL8           var;
00131   REAL8           tol;
00132 
00133   UINT4 nmax;
00134   UINT4 m;
00135   UINT4 n;
00136   UINT4 i;
00137   UINT4 j;
00138   UINT4 k;
00139   UINT4 s = 0;
00140 
00141   FILE *fp;
00142 
00143   ParseOptions( argc, argv );
00144   m = m_;
00145   n = n_;
00146 
00147   fp = verbose ? stdout : NULL ;  
00148 
00149   if ( n == 0 )
00150   {
00151     nmax = 65536;
00152   }
00153   else
00154   {
00155     nmax = n--;
00156   }
00157 
00158   while ( n < nmax )
00159   {
00160     if ( n < 128 )
00161     {
00162       ++n;
00163     }
00164     else
00165     {
00166       n *= 2;
00167     }
00168 
00169     LALSCreateVector( &status, &dat, n );
00170     TestStatus( &status, CODES( 0 ), 1 );
00171     LALSCreateVector( &status, &rfft, n );
00172     TestStatus( &status, CODES( 0 ), 1 );
00173     LALSCreateVector( &status, &ans, n );
00174     TestStatus( &status, CODES( 0 ), 1 );
00175     LALCCreateVector( &status, &dft, n / 2 + 1 );
00176     TestStatus( &status, CODES( 0 ), 1 );
00177     LALCCreateVector( &status, &fft, n / 2 + 1 );
00178     TestStatus( &status, CODES( 0 ), 1 );
00179     LALCreateForwardRealFFTPlan( &status, &fwd, n, 0 );
00180     TestStatus( &status, CODES( 0 ), 1 );
00181     LALCreateReverseRealFFTPlan( &status, &rev, n, 0 );
00182     TestStatus( &status, CODES( 0 ), 1 );
00183 
00184     /*
00185      *
00186      * Do m trials of random data.
00187      *
00188      */
00189     for ( i = 0; i < m; ++i )
00190     {
00191       srand( s++ ); /* seed the random number generator */
00192 
00193       /* 
00194        *
00195        * Create data and compute error tolerance.
00196        *
00197        * Reference: Kaneko and Liu,
00198        * "Accumulation of round-off error in fast fourier tranforms"
00199        * J. Asssoc. Comp. Mach, Vol 17 (No 4) 637-654, October 1970.
00200        *
00201        */
00202       srand( i ); /* seed the random number generator */
00203       ssq = 0;
00204       for ( j = 0; j < n; ++j )
00205       {
00206         dat->data[j] = 20.0 * rand() / (REAL4)( RAND_MAX + 1.0 ) - 10.0;
00207         ssq += dat->data[j] * dat->data[j];
00208         fp ? fprintf( fp, "%e\n", dat->data[j] ) : 0;
00209       }
00210       lbn = log( n ) / log( 2 );
00211       var = 2.5 * lbn * eps * eps * ssq / n;
00212       tol = 5 * sqrt( var ); /* up to 5 sigma excursions */
00213       fp ? fprintf( fp, "\neps = %e \ntol = %e\n", eps, tol ) : 0;
00214 
00215       /*
00216        *
00217        * Perform forward FFT and DFT (only if n < 100).
00218        *
00219        */
00220       LALForwardRealFFT( &status, fft, dat, fwd );
00221       TestStatus( &status, CODES( 0 ), 1 );
00222       LALREAL4VectorFFT( &status, rfft, dat, fwd );
00223       TestStatus( &status, CODES( 0 ), 1 );
00224       LALREAL4VectorFFT( &status, ans, rfft, rev );
00225       TestStatus( &status, CODES( 0 ), 1 );
00226       fp ?  fprintf( fp, "rfft()\t\trfft(rfft())\trfft(rfft())\n\n"  ) : 0;
00227       for ( j = 0; j < n; ++j )
00228       {
00229         fp ? fprintf( fp, "%e\t%e\t%e\n", 
00230             rfft->data[j], ans->data[j], ans->data[j] / n ) : 0;
00231       }
00232       if ( n < 128 )
00233       {
00234         LALForwardRealDFT( &status, dft, dat );
00235         TestStatus( &status, CODES( 0 ), 1 );
00236 
00237         /*
00238          *
00239          * Check accuracy of FFT vs DFT.
00240          *
00241          */
00242         fp ? fprintf( fp, "\nfftre\t\tfftim\t\t" ) : 0;
00243         fp ? fprintf( fp, "dtfre\t\tdftim\n" ) : 0;
00244         for ( k = 0; k <= n / 2; ++k )
00245         {
00246           REAL8 fftre = fft->data[k].re;
00247           REAL8 fftim = fft->data[k].im;
00248           REAL8 dftre = dft->data[k].re;
00249           REAL8 dftim = dft->data[k].im;
00250           REAL8 errre = fabs( dftre - fftre );
00251           REAL8 errim = fabs( dftim - fftim );
00252           REAL8 avere = fabs( dftre + fftre ) / 2 + eps;
00253           REAL8 aveim = fabs( dftim + fftim ) / 2 + eps;
00254           REAL8 ferre = errre / avere;
00255           REAL8 ferim = errim / aveim;
00256           fp ? fprintf( fp, "%e\t%e\t", fftre, fftim ) : 0;
00257           fp ? fprintf( fp, "%e\t%e\n", dftre, dftim ) : 0;
00258           /* fp ? fprintf( fp, "%e\t%e\t", errre, errim ) : 0; */
00259           /* fp ? fprintf( fp, "%e\t%e\n", ferre, ferim ) : 0; */
00260           if ( ferre > eps && errre > tol )
00261           {
00262             fputs( "FAIL: Incorrect result from forward transform\n", stderr );
00263             fprintf( stderr, "\tdifference = %e\n", errre );
00264             fprintf( stderr, "\ttolerance  = %e\n", tol );
00265             fprintf( stderr, "\tfrac error = %e\n", ferre );
00266             fprintf( stderr, "\tprecision  = %e\n", eps );
00267             return 1;
00268           }
00269           if ( ferim > eps && errim > tol )
00270           {
00271             fputs( "FAIL: Incorrect result from forward transform\n", stderr );
00272             fprintf( stderr, "\tdifference = %e\n", errim );
00273             fprintf( stderr, "\ttolerance  = %e\n", tol );
00274             fprintf( stderr, "\tfrac error = %e\n", ferim );
00275             fprintf( stderr, "\tprecision  = %e\n", eps );
00276             return 1;
00277           }
00278         }
00279       }
00280 
00281       /*
00282        *
00283        * Perform reverse FFT and check accuracy vs original data.
00284        *
00285        */
00286       LALReverseRealFFT( &status, ans, fft, rev );
00287       TestStatus( &status, CODES( 0 ), 1 );
00288       fp ? fprintf( fp, "\ndat->data[j]\tans->data[j] / n\n" ) : 0;
00289       for ( j = 0; j < n; ++j )
00290       {
00291         REAL8 err = fabs( dat->data[j] - ans->data[j] / n );
00292         REAL8 ave = fabs( dat->data[j] + ans->data[j] / n ) / 2 + eps;
00293         REAL8 fer = err / ave;
00294         fp ? fprintf( fp, "%e\t%e\n", dat->data[j], ans->data[j] / n ) : 0;
00295         /* fp ? fprintf( fp, "%e\t%e\n", err, fer ) : 0; */
00296         if ( fer > eps && err > tol )
00297         {
00298           fputs( "FAIL: Incorrect result after reverse transform\n", stderr );
00299           fprintf( stderr, "\tdifference = %e\n", err );
00300           fprintf( stderr, "\ttolerance  = %e\n", tol );
00301           fprintf( stderr, "\tfrac error = %e\n", fer );
00302           fprintf( stderr, "\tprecision  = %e\n", eps );
00303           return 1;
00304         }
00305       }
00306     }
00307 
00308     LALSDestroyVector( &status, &dat );
00309     TestStatus( &status, CODES( 0 ), 1 );
00310     LALSDestroyVector( &status, &rfft );
00311     TestStatus( &status, CODES( 0 ), 1 );
00312     LALSDestroyVector( &status, &ans );
00313     TestStatus( &status, CODES( 0 ), 1 );
00314     LALCDestroyVector( &status, &dft );
00315     TestStatus( &status, CODES( 0 ), 1 );
00316     LALCDestroyVector( &status, &fft );
00317     TestStatus( &status, CODES( 0 ), 1 );
00318     LALDestroyRealFFTPlan( &status, &fwd );
00319     TestStatus( &status, CODES( 0 ), 1 );
00320     LALDestroyRealFFTPlan( &status, &rev );
00321     TestStatus( &status, CODES( 0 ), 1 );
00322   }
00323 
00324   LALCheckMemoryLeaks();
00325   return 0;
00326 }
00327 
00328 /*
00329  * TestStatus()
00330  *
00331  * Routine to check that the status code status->statusCode agrees with one of
00332  * the codes specified in the space-delimited string ignored; if not,
00333  * exit to the system with code exitcode.
00334  *
00335  */
00336 static void
00337 TestStatus( LALStatus *status, const char *ignored, int exitcode )
00338 {
00339   char  str[64];
00340   char *tok;
00341 
00342   if ( verbose )
00343   {
00344     REPORTSTATUS( status );
00345   }
00346 
00347   if ( strncpy( str, ignored, sizeof( str ) ) )
00348   {
00349     if ( (tok = strtok( str, " " ) ) )
00350     {
00351       do
00352       {
00353         if ( status->statusCode == atoi( tok ) )
00354         {
00355           return;
00356         }
00357       }
00358       while ( ( tok = strtok( NULL, " " ) ) );
00359     }
00360     else
00361     {
00362       if ( status->statusCode == atoi( tok ) )
00363       {
00364         return;
00365       }
00366     }
00367   }
00368 
00369   fprintf( stderr, "\nExiting to system with code %d\n", exitcode );
00370   exit( exitcode );
00371 }
00372 
00373 
00374 /*
00375  *
00376  * ClearStatus()
00377  *
00378  * Recursively applies DETATCHSTATUSPTR() to status structure to destroy
00379  * linked list of statuses.
00380  *
00381  */
00382 void
00383 ClearStatus( LALStatus *status )
00384 {
00385   if ( status->statusPtr )
00386   {
00387     ClearStatus( status->statusPtr );
00388     DETATCHSTATUSPTR( status );
00389   }
00390 }
00391 
00392 
00393 /*
00394  *
00395  * Usage()
00396  *
00397  * Prints a usage message for program program and exits with code exitcode.
00398  *
00399  */
00400 static void
00401 Usage( const char *program, int exitcode )
00402 {
00403   fprintf( stderr, "Usage: %s [options]\n", program );
00404   fprintf( stderr, "Options:\n" );
00405   fprintf( stderr, "  -h         print this message\n" );
00406   fprintf( stderr, "  -q         quiet: run silently\n" );
00407   fprintf( stderr, "  -v         verbose: print extra information\n" );
00408   fprintf( stderr, "  -d level   set lalDebugLevel to level\n" );
00409   fprintf( stderr, "  -m trials  set number of random trials\n" );
00410   fprintf( stderr, "  -n size    set size of FFTs\n" );
00411   exit( exitcode );
00412 }
00413 
00414 
00415 /*
00416  * ParseOptions()
00417  *
00418  * Parses the argc - 1 option strings in argv[].
00419  *
00420  */
00421 static void
00422 ParseOptions( int argc, char *argv[] )
00423 {
00424   while ( 1 )
00425   {
00426     int c = -1;
00427 
00428     c = getopt( argc, argv, "hqvd:m:n:" );
00429     if ( c == -1 )
00430     {
00431       break;
00432     }
00433 
00434     switch ( c )
00435     {
00436       case 'n': /* set FFT size */
00437         n_ = atoi( optarg );
00438         break;
00439 
00440       case 'm': /* set number of trials */
00441         m_ = atoi( optarg );
00442         break;
00443 
00444       case 'd': /* set debug level */
00445         lalDebugLevel = atoi( optarg );
00446         break;
00447 
00448       case 'v': /* verbose */
00449         ++verbose;
00450         break;
00451 
00452       case 'q': /* quiet: run silently (ignore error messages) */
00453         freopen( "/dev/null", "w", stderr );
00454         freopen( "/dev/null", "w", stdout );
00455         break;
00456 
00457       case 'h':
00458         Usage( argv[0], 0 );
00459         break;
00460 
00461       default:
00462         Usage( argv[0], 1 );
00463     }
00464 
00465   }
00466 
00467   if ( optind < argc )
00468   {
00469     Usage( argv[0], 1 );
00470   }
00471 
00472   return;
00473 }
00474 
00475 
00476 static void
00477 LALDFT(
00478     LALStatus      *status,
00479     COMPLEX8Vector *output,
00480     COMPLEX8Vector *input,
00481     INT4            sign
00482     )
00483 {
00484   UINT4 n;
00485   UINT4 j;
00486   UINT4 k;
00487 
00488   INITSTATUS( status, "DFT", MAIN );
00489 
00490   n = output->length;
00491 
00492   for ( k = 0; k < n; ++k )
00493   {
00494     REAL8 sre = 0;
00495     REAL8 sim = 0;
00496     for ( j = 0; j < n; ++j )
00497     {
00498       REAL8 phi = sign * LAL_TWOPI * (REAL8)(j) * (REAL8)(k) / (REAL8)(n);
00499       REAL8 c   = cos( phi );
00500       REAL8 s   = sin( phi );
00501       REAL8 re  = input->data[j].re;
00502       REAL8 im  = input->data[j].im;
00503       sre += c * re - s * im;
00504       sim += c * im + s * re;
00505     }
00506     output->data[k].re = sre;
00507     output->data[k].im = sim;
00508   }
00509 
00510   RETURN( status );
00511 }
00512 
00513 void LALForwardRealDFT(
00514     LALStatus      *status,
00515     COMPLEX8Vector *output,
00516     REAL4Vector    *input
00517     )
00518 {
00519   COMPLEX8Vector *a = NULL;
00520   COMPLEX8Vector *b = NULL;
00521   UINT4 n;
00522   UINT4 j;
00523   UINT4 k;
00524 
00525   INITSTATUS( status, "LALForwardRealDFT", MAIN );
00526   ATTATCHSTATUSPTR( status );
00527 
00528   n = input->length;
00529 
00530   TRY( LALCCreateVector( status->statusPtr, &a, n ), status );
00531   TRY( LALCCreateVector( status->statusPtr, &b, n ), status );
00532 
00533   for ( j = 0; j < n; ++j )
00534   {
00535     a->data[j].re = input->data[j];
00536     a->data[j].im = 0;
00537   }
00538 
00539   TRY( LALDFT( status->statusPtr, b, a, -1 ), status );
00540 
00541   for ( k = 0; k <= n / 2; ++k )
00542   {
00543     output->data[k].re = b->data[k].re;
00544     output->data[k].im = b->data[k].im;
00545   }
00546 
00547   TRY( LALCDestroyVector( status->statusPtr, &a ), status );
00548   TRY( LALCDestroyVector( status->statusPtr, &b ), status );
00549 
00550   DETATCHSTATUSPTR( status );
00551   RETURN( status );
00552 }
00553 

Generated on Sat Aug 30 03:13:07 2008 for LAL by  doxygen 1.5.2