Loading [MathJax]/extensions/TeX/AMSsymbols.js
LAL 7.7.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
RealFFTTest.c
Go to the documentation of this file.
1/*
2* Copyright (C) 2007 Duncan Brown, Jolien Creighton
3*
4* This program is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License as published by
6* the Free Software Foundation; either version 2 of the License, or
7* (at your option) any later version.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12* GNU General Public License for more details.
13*
14* You should have received a copy of the GNU General Public License
15* along with with program; see the file COPYING. If not, write to the
16* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17* MA 02110-1301 USA
18*/
19
20/**
21 * \file
22 * \ingroup RealFFT_h
23 *
24 * \brief Tests the routines in \ref RealFFT.h.
25 *
26 * ### Usage ###
27 *
28 * \code
29 * RealFFTTest [options]
30 * Options:
31 * -h print this message
32 * -q quiet: run silently
33 * -v verbose: print extra information
34 * -d level set lalDebugLevel to level
35 * -m trials set number of random trials
36 * -n size set size of FFTs
37 * \endcode
38 *
39 * Use the <tt>-n</tt> option to specify the size of the test transform and
40 * the <tt>-m</tt> option to specify the number of test transforms of that size.
41 * (Default is to test transforms of size 1 to 128 in unit steps and then
42 * powers of two up to 65536.)
43 *
44 * ### Exit codes ###
45 *
46 * <table><tr><th>Code</th><th>Explanation</th></tr>
47 * <tr><td>0</td><td>Success, normal exit.</td></tr>
48 * <tr><td>1</td><td>Subroutine failed.</td></tr>
49 * </table>
50 *
51 * ### Uses ###
52 *
53 *
54 * ### Notes ###
55 *
56 */
57
58/** \cond DONT_DOXYGEN */
59#include <config.h>
60
61#include <complex.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <math.h>
65
66#include <lal/LALStdlib.h>
67#include <lal/LALgetopt.h>
68#include <lal/LALConstants.h>
69#include <lal/SeqFactories.h>
70#include <lal/RealFFT.h>
71#include <lal/VectorOps.h>
72#include <config.h>
73
74#define CODES_(x) #x
75#define CODES(x) CODES_(x)
76
77int verbose = 0;
78UINT4 m_ = 1; /* number of random trials */
79UINT4 n_ = 0; /* size of each transform */
80
81static void
82Usage( const char *program, int exitflag );
83
84static void
85ParseOptions( int argc, char *argv[] );
86
87static void
88TestStatus( LALStatus *status, const char *expectedCodes, int exitCode );
89
90void LALForwardRealDFT(
93 REAL4Vector *input
94 );
95
96int main( int argc, char *argv[] )
97{
98 static LALStatus status;
99
100 RealFFTPlan *fwd = NULL;
101 RealFFTPlan *rev = NULL;
102 REAL4Vector *dat = NULL;
103 REAL4Vector *rfft = NULL;
104 REAL4Vector *ans = NULL;
105 COMPLEX8Vector *dft = NULL;
106 COMPLEX8Vector *fft = NULL;
107#if LAL_CUDA_ENABLED
108 /* The test itself should pass at 1e-4, but it might fail at
109 * some rare cases where accuracy is bad for some numbers. */
110 REAL8 eps = 3e-4;
111#else
112 /* very conservative floating point precision */
113 REAL8 eps = 1e-6;
114#endif
115 REAL8 lbn;
116 REAL8 ssq;
117 REAL8 var;
118 REAL8 tol;
119
120 UINT4 nmax;
121 UINT4 m;
122 UINT4 n;
123 UINT4 i;
124 UINT4 j;
125 UINT4 k;
126 UINT4 s = 0;
127
128 FILE *fp;
129
130
131 ParseOptions( argc, argv );
132 m = m_;
133 n = n_;
134
135 fp = verbose ? stdout : NULL ;
136
137 if ( n == 0 )
138 {
139 nmax = 65536;
140 }
141 else
142 {
143 nmax = n--;
144 }
145
146 while ( n < nmax )
147 {
148 if ( n < 128 )
149 {
150 ++n;
151 }
152 else
153 {
154 n *= 2;
155 }
156
157 LALSCreateVector( &status, &dat, n );
158 TestStatus( &status, CODES( 0 ), 1 );
159 LALSCreateVector( &status, &rfft, n );
160 TestStatus( &status, CODES( 0 ), 1 );
161 LALSCreateVector( &status, &ans, n );
162 TestStatus( &status, CODES( 0 ), 1 );
163 LALCCreateVector( &status, &dft, n / 2 + 1 );
164 TestStatus( &status, CODES( 0 ), 1 );
165 LALCCreateVector( &status, &fft, n / 2 + 1 );
166 TestStatus( &status, CODES( 0 ), 1 );
167 fwd = XLALCreateForwardREAL4FFTPlan( n, 0 );
168 rev = XLALCreateReverseREAL4FFTPlan( n, 0 );
169 TestStatus( &status, CODES( 0 ), 1 );
170
171 /*
172 *
173 * Do m trials of random data.
174 *
175 */
176 for ( i = 0; i < m; ++i )
177 {
178 srand( s++ ); /* seed the random number generator */
179
180 /*
181 *
182 * Create data and compute error tolerance.
183 *
184 * Reference: Kaneko and Liu,
185 * "Accumulation of round-off error in fast fourier tranforms"
186 * J. Asssoc. Comp. Mach, Vol 17 (No 4) 637-654, October 1970.
187 *
188 */
189 srand( i ); /* seed the random number generator */
190 ssq = 0;
191 for ( j = 0; j < n; ++j )
192 {
193 dat->data[j] = 20.0 * rand() / (REAL4)( RAND_MAX + 1.0 ) - 10.0;
194 ssq += dat->data[j] * dat->data[j];
195 fp ? fprintf( fp, "%e\n", dat->data[j] ) : 0;
196 }
197 lbn = log( n ) / log( 2 );
198 var = 2.5 * lbn * eps * eps * ssq / n;
199 tol = 5 * sqrt( var ); /* up to 5 sigma excursions */
200 fp ? fprintf( fp, "\neps = %e \ntol = %e\n", eps, tol ) : 0;
201
202 /*
203 *
204 * Perform forward FFT and DFT (only if n < 100).
205 *
206 */
207 XLALREAL4ForwardFFT( fft, dat, fwd );
208 XLALREAL4VectorFFT( rfft, dat, fwd );
209 XLALREAL4VectorFFT( ans, rfft, rev );
210 fp ? fprintf( fp, "rfft()\t\trfft(rfft())\trfft(rfft())\n\n" ) : 0;
211 for ( j = 0; j < n; ++j )
212 {
213 fp ? fprintf( fp, "%e\t%e\t%e\n",
214 rfft->data[j], ans->data[j], ans->data[j] / n ) : 0;
215 }
216 if ( n < 128 )
217 {
218 LALForwardRealDFT( &status, dft, dat );
219 TestStatus( &status, CODES( 0 ), 1 );
220
221 /*
222 *
223 * Check accuracy of FFT vs DFT.
224 *
225 */
226 fp ? fprintf( fp, "\nfftre\t\tfftim\t\t" ) : 0;
227 fp ? fprintf( fp, "dtfre\t\tdftim\n" ) : 0;
228 for ( k = 0; k <= n / 2; ++k )
229 {
230 REAL8 fftre = creal(fft->data[k]);
231 REAL8 fftim = cimag(fft->data[k]);
232 REAL8 dftre = creal(dft->data[k]);
233 REAL8 dftim = cimag(dft->data[k]);
234 REAL8 errre = fabs( dftre - fftre );
235 REAL8 errim = fabs( dftim - fftim );
236 REAL8 avere = fabs( dftre + fftre ) / 2 + eps;
237 REAL8 aveim = fabs( dftim + fftim ) / 2 + eps;
238 REAL8 ferre = errre / avere;
239 REAL8 ferim = errim / aveim;
240 fp ? fprintf( fp, "%e\t%e\t", fftre, fftim ) : 0;
241 fp ? fprintf( fp, "%e\t%e\n", dftre, dftim ) : 0;
242 /* fp ? fprintf( fp, "%e\t%e\t", errre, errim ) : 0; */
243 /* fp ? fprintf( fp, "%e\t%e\n", ferre, ferim ) : 0; */
244 if ( ferre > eps && errre > tol )
245 {
246 fputs( "FAIL: Incorrect result from forward transform\n", stderr );
247 fprintf( stderr, "\tdifference = %e\n", errre );
248 fprintf( stderr, "\ttolerance = %e\n", tol );
249 fprintf( stderr, "\tfrac error = %e\n", ferre );
250 fprintf( stderr, "\tprecision = %e\n", eps );
251 return 1;
252 }
253 if ( ferim > eps && errim > tol )
254 {
255 fputs( "FAIL: Incorrect result from forward transform\n", stderr );
256 fprintf( stderr, "\tdifference = %e\n", errim );
257 fprintf( stderr, "\ttolerance = %e\n", tol );
258 fprintf( stderr, "\tfrac error = %e\n", ferim );
259 fprintf( stderr, "\tprecision = %e\n", eps );
260 return 1;
261 }
262 }
263 }
264
265 /*
266 *
267 * Perform reverse FFT and check accuracy vs original data.
268 *
269 */
270 XLALREAL4ReverseFFT( ans, fft, rev );
271 TestStatus( &status, CODES( 0 ), 1 );
272 fp ? fprintf( fp, "\ndat->data[j]\tans->data[j] / n\n" ) : 0;
273 for ( j = 0; j < n; ++j )
274 {
275 REAL8 err = fabs( dat->data[j] - ans->data[j] / n );
276 REAL8 ave = fabs( dat->data[j] + ans->data[j] / n ) / 2 + eps;
277 REAL8 fer = err / ave;
278 fp ? fprintf( fp, "%e\t%e\n", dat->data[j], ans->data[j] / n ) : 0;
279 /* fp ? fprintf( fp, "%e\t%e\n", err, fer ) : 0; */
280 if ( fer > eps && err > tol )
281 {
282 fputs( "FAIL: Incorrect result after reverse transform\n", stderr );
283 fprintf( stderr, "\tdifference = %e\n", err );
284 fprintf( stderr, "\ttolerance = %e\n", tol );
285 fprintf( stderr, "\tfrac error = %e\n", fer );
286 fprintf( stderr, "\tprecision = %e\n", eps );
287 return 1;
288 }
289 }
290 }
291
292 LALSDestroyVector( &status, &dat );
293 TestStatus( &status, CODES( 0 ), 1 );
294 LALSDestroyVector( &status, &rfft );
295 TestStatus( &status, CODES( 0 ), 1 );
296 LALSDestroyVector( &status, &ans );
297 TestStatus( &status, CODES( 0 ), 1 );
298 LALCDestroyVector( &status, &dft );
299 TestStatus( &status, CODES( 0 ), 1 );
300 LALCDestroyVector( &status, &fft );
301 TestStatus( &status, CODES( 0 ), 1 );
304
305 /* Null pointers should be a no-op */
306 rev = NULL;
307 fwd = NULL;
310
311 TestStatus( &status, CODES( 0 ), 1 );
312 }
313
315 return 0;
316}
317
318/*
319 * TestStatus()
320 *
321 * Routine to check that the status code status->statusCode agrees with one of
322 * the codes specified in the space-delimited string ignored; if not,
323 * exit to the system with code exitcode.
324 *
325 */
326static void
327TestStatus( LALStatus *status, const char *ignored, int exitcode )
328{
329 char str[64];
330 char *tok;
331
332 if ( verbose )
333 {
335 }
336
337 if ( strncpy( str, ignored, sizeof( str ) ) )
338 {
339 if ( (tok = strtok( str, " " ) ) )
340 {
341 do
342 {
343 if ( status->statusCode == atoi( tok ) )
344 {
345 return;
346 }
347 }
348 while ( ( tok = strtok( NULL, " " ) ) );
349 }
350 else
351 {
352 if ( status->statusCode == atoi( str ) )
353 {
354 return;
355 }
356 }
357 }
358
359 fprintf( stderr, "\nExiting to system with code %d\n", exitcode );
360 exit( exitcode );
361}
362
363/*
364 *
365 * Usage()
366 *
367 * Prints a usage message for program program and exits with code exitcode.
368 *
369 */
370static void
371Usage( const char *program, int exitcode )
372{
373 fprintf( stderr, "Usage: %s [options]\n", program );
374 fprintf( stderr, "Options:\n" );
375 fprintf( stderr, " -h print this message\n" );
376 fprintf( stderr, " -q quiet: run silently\n" );
377 fprintf( stderr, " -v verbose: print extra information\n" );
378 fprintf( stderr, " -d level set lalDebugLevel to level\n" );
379 fprintf( stderr, " -m trials set number of random trials\n" );
380 fprintf( stderr, " -n size set size of FFTs\n" );
381 exit( exitcode );
382}
383
384
385/*
386 * ParseOptions()
387 *
388 * Parses the argc - 1 option strings in argv[].
389 *
390 */
391static void
392ParseOptions( int argc, char *argv[] )
393{
394 FILE *fp;
395
396 while ( 1 )
397 {
398 int c = -1;
399
400 c = LALgetopt( argc, argv, "hqvd:m:n:" );
401 if ( c == -1 )
402 {
403 break;
404 }
405
406 switch ( c )
407 {
408 case 'n': /* set FFT size */
409 n_ = atoi( LALoptarg );
410 break;
411
412 case 'm': /* set number of trials */
413 m_ = atoi( LALoptarg );
414 break;
415
416 case 'd': /* set debug level */
417 break;
418
419 case 'v': /* verbose */
420 ++verbose;
421 break;
422
423 case 'q': /* quiet: run silently (ignore error messages) */
424 fp = freopen( "/dev/null", "w", stderr );
425 if (fp == NULL)
426 {
427 fprintf(stderr, "Error: Unable to open /dev/null\n");
428 exit(1);
429 }
430 fp = freopen( "/dev/null", "w", stdout );
431 if (fp == NULL)
432 {
433 fprintf(stderr, "Error: Unable to open /dev/null\n");
434 exit(1);
435 }
436 break;
437
438 case 'h':
439 Usage( argv[0], 0 );
440 break;
441
442 default:
443 Usage( argv[0], 1 );
444 }
445
446 }
447
448 if ( LALoptind < argc )
449 {
450 Usage( argv[0], 1 );
451 }
452
453 return;
454}
455
456
457static void
458LALDFT(
461 COMPLEX8Vector *input,
462 INT4 sign
463 )
464{
465 UINT4 n;
466 UINT4 j;
467 UINT4 k;
468
470
471 n = output->length;
472
473 for ( k = 0; k < n; ++k )
474 {
475 REAL8 sre = 0;
476 REAL8 sim = 0;
477 for ( j = 0; j < n; ++j )
478 {
479 REAL8 phi = sign * LAL_TWOPI * (REAL8)(j) * (REAL8)(k) / (REAL8)(n);
480 REAL8 c = cos( phi );
481 REAL8 s = sin( phi );
482 REAL8 re = creal(input->data[j]);
483 REAL8 im = cimag(input->data[j]);
484 sre += c * re - s * im;
485 sim += c * im + s * re;
486 }
487 output->data[k] = sre;
488 output->data[k] += I * sim;
489 }
490
491 RETURN( status );
492}
493
494void LALForwardRealDFT(
497 REAL4Vector *input
498 )
499{
500 COMPLEX8Vector *a = NULL;
501 COMPLEX8Vector *b = NULL;
502 UINT4 n;
503 UINT4 j;
504 UINT4 k;
505
508
509 n = input->length;
510
511 TRY( LALCCreateVector( status->statusPtr, &a, n ), status );
512 TRY( LALCCreateVector( status->statusPtr, &b, n ), status );
513
514 for ( j = 0; j < n; ++j )
515 a->data[j] = input->data[j];
516
517 TRY( LALDFT( status->statusPtr, b, a, -1 ), status );
518
519 for ( k = 0; k <= n / 2; ++k )
520 output->data[k] = b->data[k];
521
522 TRY( LALCDestroyVector( status->statusPtr, &a ), status );
523 TRY( LALCDestroyVector( status->statusPtr, &b ), status );
524
526 RETURN( status );
527}
528
529/** \endcond */
const char * program
void REPORTSTATUS(LALStatus *status)
Definition: LALError.c:322
void LALCheckMemoryLeaks(void)
Definition: LALMalloc.c:784
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
static int sign(int s)
Definition: LALStringTest.c:27
int LALgetopt(int argc, char *const *argv, const char *optstring)
Definition: LALgetopt.c:172
int LALoptind
Definition: LALgetopt.c:79
char * LALoptarg
Definition: LALgetopt.c:64
#define fprintf
static void Usage(const char *program, int exitcode)
Definition: XLALChisqTest.c:70
static void ParseOptions(int argc, char *argv[])
Definition: XLALChisqTest.c:88
int main(int argc, char *argv[])
Definition: cache.c:25
#define LAL_TWOPI
2*pi is circumference of a circle divided by its radius
Definition: LALConstants.h:180
double REAL8
Double precision real floating-point number (8 bytes).
uint32_t UINT4
Four-byte unsigned integer.
int32_t INT4
Four-byte signed integer.
float REAL4
Single precision real floating-point number (4 bytes).
static const INT4 m
Definition: Random.c:80
static const REAL4 eps
Definition: Random.c:84
static const INT4 a
Definition: Random.c:79
#define RealFFTPlan
Definition: RealFFT.h:195
REAL4FFTPlan * XLALCreateReverseREAL4FFTPlan(UINT4 size, int measurelvl)
Returns a new REAL4FFTPlan for a reverse transform.
Definition: CudaRealFFT.c:130
REAL4FFTPlan * XLALCreateForwardREAL4FFTPlan(UINT4 size, int measurelvl)
Returns a new REAL4FFTPlan for a forward transform.
Definition: CudaRealFFT.c:120
void XLALDestroyREAL4FFTPlan(REAL4FFTPlan *plan)
Destroys a REAL4FFTPlan.
Definition: CudaRealFFT.c:140
int XLALREAL4VectorFFT(REAL4Vector *_LAL_RESTRICT_ output, const REAL4Vector *_LAL_RESTRICT_ input, const REAL4FFTPlan *plan)
Perform a REAL4Vector to REAL4Vector FFT.
Definition: CudaRealFFT.c:233
int XLALREAL4ReverseFFT(REAL4Vector *output, const COMPLEX8Vector *input, const REAL4FFTPlan *plan)
Performs a reverse FFT of REAL4 data.
Definition: CudaRealFFT.c:198
int XLALREAL4ForwardFFT(COMPLEX8Vector *output, const REAL4Vector *input, const REAL4FFTPlan *plan)
Performs a forward FFT of REAL4 data.
Definition: CudaRealFFT.c:161
void LALCCreateVector(LALStatus *, COMPLEX8Vector **, UINT4)
void LALCDestroyVector(LALStatus *, COMPLEX8Vector **)
void LALSDestroyVector(LALStatus *, REAL4Vector **)
void LALSCreateVector(LALStatus *, REAL4Vector **, UINT4)
Vector of type COMPLEX8, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:163
COMPLEX8 * data
Pointer to the data array.
Definition: LALDatatypes.h:168
LAL status structure, see The LALStatus structure for more details.
Definition: LALDatatypes.h:947
Vector of type REAL4, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:145
REAL4 * data
Pointer to the data array.
Definition: LALDatatypes.h:150
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:149
int verbose
Definition: tconvert.c:103
FILE * fp
Definition: tconvert.c:105
void output(int gps_sec, int output_type)
Definition: tconvert.c:440