File: fft.c

package info (click to toggle)
sprng 2.0a-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 3,076 kB
  • ctags: 2,031
  • sloc: ansic: 30,361; fortran: 1,618; makefile: 566; cpp: 58; sh: 5
file content (239 lines) | stat: -rw-r--r-- 8,638 bytes parent folder | download | duplicates (13)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/****************************************************************************/
/*  Note: This test is not in the regular SPRNG test format                 */
/*                                                                          */ 
/*                 _________ 2D FFT test _________                          */
/*                                                                          */
/* Type: make fft to compile this program; it is not automatically made     */
/*                                                                          */
/* The FFT routine is based on that on the Power Challenge array at NCSA    */
/* Please make changes on your machine. (routines dzfft*)                   */
/*                                                                          */
/* We fill a random array with 'n' numbers from 'nstreams' streams.         */
/* We then compute the 2D FFT for this array. The expected value for all    */
/* terms except the constant one is 0. The standard deviation too can be    */
/* determined theoretically. We check to see if most of the coefficients    */
/* are acceptable based on how far they are from the expected value. As     */
/* its output, this program prints the coeffieients that fall outside a     */
/* a certain acceptable range. We should alway expect a number of them      */
/* to fall outside the range. However, in repeated runs of this test, we    */
/* would expect that the same coefficients do not keep falling outside      */
/* the range each time.                                                     */
/*                                                                          */
/* Each column of the array consists of numbers from the same stream.       */
/* Note that we use a *** column major *** order, due to the requirements   */
/* of the SGI software. The Fourier coeffients are stored in place. This    */
/* can be done, even though the results are complex because only about half */
/* the coefficients are needed; the other half can be determined from the   */
/* ones computed. We need slightly more than 'n' rows, and the number of    */
/* rows needed for the coefficients is given by 'lda'.                      */
/****************************************************************************/

#include <stdio.h>
/*#if defined(SPRNG_MPI)
#include "mpi.h"
#endif*/
#if defined(SPRNG_MPI)
#undef SPRNG_MPI
#endif
#include "sprng.h"
#include <math.h>
#include <fft.h>


void Analyze(int nstreams, int nruns, int n);
void FFTCalc (int nstreams, int nruns, int n);


int **streams, lda;
double *means, *FFTcoeffs;

void main (int argc, char *argv[])
{

  int i, seed, param, nruns, nstreams, n, *stream, myid=0, nprocs=1;


#ifdef SPRNG_MPI
  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &myid);
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  if(myid != 0)			/* This is a sequential program currently  */
  {
    MPI_Finalize();
    exit(0);
  }
#endif

  /**************************** Initialization *****************************/

  if(argc != 8 || atoi(argv[2]) != 1 || atoi(argv[6]) != 0)
  {
    fprintf(stderr,"USAGE: %s nstreams 1 seed param nruns 0 n\n",
	    argv[0]);
    exit(-1);
  }
  else if(atoi(argv[1]) < 1 || atoi(argv[5]) < 1 || atoi(argv[7]) < 1 )
  {
    fprintf(stderr,"ERROR: nstreams, nruns, and n must be > 0\n");
    exit(-1);
  }
  
  nstreams = atoi(argv[1]);	/* number of streams                       */
  param = atoi(argv[4]);	/* parameter to the generator              */
  nruns = atoi(argv[5]);	/* number of runs to repeat                */
  n = atoi(argv[7]);		/* number of random numbers per stream     */

  if(n&1)			/* number of rows for Fourier coefficients */
    lda = n+1;
  else
    lda = n+2;
  
  FFTcoeffs = (double *) malloc(lda*nstreams*sizeof(double)); /* FFT coeffs */
  means = (double *) malloc(lda*nstreams*sizeof(double)); /* average coeffs */
  streams = (int **) malloc(nstreams*sizeof(int *)); /*random number streams*/
  
  for(i=0; i<lda*nstreams; i++)
    FFTcoeffs[i] = means[i] = 0.0;
  
  seed = make_sprng_seed();
  
  for (i=0; i<nstreams; i++)	/* initialize random number streams         */
    streams[i] = init_sprng(i,nstreams,seed,param);
  

  /***************************** Calculate FFTs *****************************/

  FFTCalc(nstreams,nruns,n);


  /************************* Analyze coefficients ***************************/

  Analyze(nstreams,nruns,n); 

  free(FFTcoeffs);
  free(means);
  free(streams);

#if defined(SPRNG_MPI)
     MPI_Finalize();
#endif

  
}


/* Analyze the output of the Fourier Transform. Check if coefficients are  */
/* within a "reasonable" distance of the expected values.                  */

void Analyze(int nstreams, int nruns, int n)
{
  int i, j, count;
  double StdDev1, StdDev2, mean1, mean2, StdDev, mult, percentile;
  
  /* The "reasonable" permitted distance from the expected value is some   */
  /* multiple of the standard deviation. We choose different multiples     */
  /* for different sample sizes; otherwise the output could be too large   */
  /* or too small. The percentile range corresponds to this multiple;      */
  /* but this value is approximate, especially for small values of 'nruns' */
  /* since the normality assumption may not hold otherwise.                */
  count = 0;
  if(nstreams*n <100)		/* percentile at which test fails.         */
  {				/* Different sizes have different          */
    mult = 1.0;			/* percentiles; otherwise the number       */
    percentile = 68.0;		/* of coefficients printed will be too     */
  }                             /* large. */
  else if(nstreams*n < 5000)
  {
    mult = 2.0;
    percentile = 95.0;
  }
  else if(nstreams*n < 20000)
  {
    mult = 3.0;
    percentile = 99.7;
  }
  else
  {
    mult = 3.9;
    percentile = 99.99;
  }
  
  mean1 = (double)nstreams*(double)n/2.0; /* Expected value of constant term*/
  mean2 = 0.0;			/* Expected values of all other terms       */
  StdDev1 = sqrt((double)nstreams*(double)n/(double)nruns/12.0);
  StdDev2 = sqrt((double)nstreams*(double)n/(double)nruns/24.0);

  if(fabs(means[0]-mean1) > mult*StdDev1) /* Check constant term            */
  {
    count++;
    printf("%d. (0,0) th coefficient exceeds ~ %g th percentile: Expected = %g, observed = %g, StdDev = %g\n\n", count, percentile, mean1, means[0], StdDev1);
  }
  
  for (j=0; j<nstreams; j++)  /*  Check each coefficient                    */
    for (i=0; i<lda/2; i++) 
    {
      if(i==0 && j==0)	      /* The constant term has already been checked */
	continue;
      else
      {
	if(nstreams%2 == 1 || j%(nstreams/2) != 0 || i%(n/2) != 0)
	  StdDev = StdDev2;
	else
	  StdDev = StdDev1;
      }
      
      if(fabs(means[2*i+j*lda]-mean2) > mult*StdDev) /* Real part of coeff. */
      {
	count++;
	printf("%d. Real part of (%d,%d) th coefficient exceeds ~ %g th percentile: Expected = %g, observed = %g, StdDev = %g\n\n", count, i, j, percentile, mean2, means[2*i+j*lda], StdDev);
      }
      
      if(fabs(means[2*i+j*lda+1]-mean2) > mult*StdDev) /* Imaginary part    */
      {
	count++;
	printf("%d. Complex part of (%d,%d) th coefficient exceeds ~ %g th percentile: Expected = %g, observed = %g, StdDev = %g\n\n", count, i, j, percentile, mean2, means[2*i+j*lda+1], StdDev);
      }
    }
  
  printf("No other coefficient exceeds %g th percentile\n\n", percentile);
  
  return;
}


/* Perform FFT on random arrays. Each column is from the same stream.       */
/* There are n rows per column, and nstream rows                            */

void FFTCalc(int nstreams, int nruns, int n) 
{
  int i,j,k;
  double *coeff;
  
  for(k=0; k<nruns; k++)	/* Repeat calculation 'nruns' times         */
  {
    for (j=0; j<nstreams; j++)  /*  fill array with random numbers          */
      for (i=0; i<n; i++) 
	FFTcoeffs[i+j*lda] = sprng(streams[j]); 
    
    coeff = dzfft2dui (n, nstreams, NULL); /*initialize FFT modules         */
    dzfft2du(1,n,nstreams,FFTcoeffs,lda, coeff); /* Compute FFT in place    */

    for (i=0; i<lda*nstreams; i++)  /*  Compute mean for each coefficient   */
	means[i] += FFTcoeffs[i]; 

#ifdef DEBUG	    /* Check if inverse transform yields original data      */
    zdfft2du (-1, n, nstreams, FFTcoeffs, lda, coeff); 
    dscal2d(n,nstreams,1.0/(double)(n*nstreams),FFTCoeffs,lda);
    for(i=0; i<(lda*nstreams); i++) 
      printf("array[%d] = %g\n", i, FFTcoeffs[i]); 
#endif
  } /*end loop for nruns                                                    */

  for (i=0; i<lda*nstreams; i++)  /*  Compute mean for each coefficient     */
    means[i] /= nruns; 
  
  return;
}