su2hmc
Loading...
Searching...
No Matches
random.c
Go to the documentation of this file.
1
6#include "coord.h"
7#ifdef __NVCC__
8#include <curand.h>
9#endif
10#include "errorcodes.h"
11#ifdef __INTEL_MKL__
12#include <mkl.h>
13#include <mkl_vsl.h>
14//Bad practice? Yes but it is convenient
15#endif
16#include "par_mpi.h"
17#include "random.h"
18#include "sizes.h"
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <time.h>
23
24//Declaring external variables
25#if (defined USE_RAN2||(!defined __INTEL_MKL__&&!defined __RANLUX__))
27long seed;
28#elif defined __RANLUX__
30gsl_rng *ranlux_instd;
32unsigned long seed;
33#elif defined __INTEL_MKL__
35unsigned int seed;
37VSLStreamStatePtr stream;
38#endif
39#ifndef M_PI
41#define M_PI acos(-1)
42#endif
43
44#ifdef __RANLUX__
45/*
46 * @brief Seed the ranlux generator from GSL
47 *
48 * @param *seed pointer to seed
49 *
50 * @see gsl_rng_alloc(), gsl_rng_set()
51 *
52 * @return 0
53 */
54inline int ranset(unsigned long *seed)
55#elif (defined __INTEL_MKL__&&!defined USE_RAN2)
56/*
57 * @brief Seed the Intel Mersenne twister generator
58 *
59 * @param *seed pointer to seed
60 *
61 * @see vslNewStream()
62 *
63 * @return 0
64 */
65inline int ranset(unsigned int *seed)
66#else
67/*
68 * @brief Dummy seed the ran2 generator
69 *
70 * @param seed pointer to seed
71 *
72 * @return 0
73 */
74inline int ranset(long *seed)
75#endif
76{
77#ifdef __RANLUX__
78 ranlux_instd=gsl_rng_alloc(gsl_rng_ranlxd2);
79 gsl_rng_set(ranlux_instd,*seed);
80 return 0;
81#elif (defined __INTEL_MKL__&& !defined USE_RAN2)
82 vslNewStream( &stream, VSL_BRNG_MT19937, *seed );
83 return 0;
84#else
85 return 0;
86#endif
87}
88int Par_ranread(char *filename, double *ranval){
89 /*
90 * @brief Reads ps from a file
91 * Since this function is very similar to Par_sread, I'm not really going to comment it
92 * check there if you are confused about things.
93 *
94 * @param *filename: The name of the file we're reading from
95 * @param ps: The destination for the file's contents
96 *
97 * @return Zero on success, integer error code otherwise
98 */
99 const char *funcname = "Par_psread";
100 FILE *dest;
101 if(!rank){
102 if(!(dest = fopen(filename, "rb"))){
103 fprintf(stderr, "Error %i in %s: Failed to open %s.\nExiting...\n\n", OPENERROR, funcname, filename);
104#if(nproc>1)
105 MPI_Abort(comm,OPENERROR);
106#else
107 exit(OPENERROR);
108#endif
109
110 }
111 fread(&ranval, sizeof(ranval), 1, dest);
112 fclose(dest);
113 }
114#if(nproc>1)
115 Par_dcopy(ranval);
116#endif
117 return 0;
118}
119#if (defined USE_RAN2||(!defined __INTEL_MKL__&&!defined __RANLUX__))
120 /*
121 * @brief Uses the rank to get a new seed.
122 * Copying from the FORTRAN description here
123 * c create new seeds in range seed to 9*seed
124 * c having a range of 0*seed gave an unfortunate pattern
125 * c in the underlying value of ds(1) (it was always 10 times bigger
126 * c on the last processor). This does not appear to happen with 9.
127 *
128 * @param *seed: The seed from the rank in question.
129 * @param iread: Do we read from file or not. Don't remember why it's here as it's not used
130 *
131 * @see ranset() (used to initialise the stream for MKL at the moment. Legacy from Fortran)
132 *
133 * @return Zero on success, integer error code otherwise
134 */
135int Par_ranset(long *seed,int iread)
136#elif defined __RANLUX__
137 /*
138 * @brief Uses the rank to get a new seed.
139 * Copying from the FORTRAN description here
140 * c create new seeds in range seed to 9*seed
141 * c having a range of 0*seed gave an unfortunate pattern
142 * c in the underlying value of ds(1) (it was always 10 times bigger
143 * c on the last processor). This does not appear to happen with 9.
144 *
145 * @param *seed: The seed from the rank in question.
146 * @param iread: Do we read from file or not. Don't remember why it's here as it's not used
147 *
148 * @see ranset() (used to initialise the stream for MKL at the moment. Legacy from Fortran)
149 *
150 * @return Zero on success, integer error code otherwise
151 */
152int Par_ranset(unsigned long *seed,int iread)
153#elif (defined __INTEL_MKL__||defined __RANLUX__)
154 /*
155 * @brief Uses the rank to get a new seed.
156 * Copying from the FORTRAN description here
157 * c create new seeds in range seed to 9*seed
158 * c having a range of 0*seed gave an unfortunate pattern
159 * c in the underlying value of ds(1) (it was always 10 times bigger
160 * c on the last processor). This does not appear to happen with 9.
161 *
162 * @param *seed: The seed from the rank in question.
163 * @param iread: Do we read from file or not. Don't remember why it's here as it's not used
164 *
165 * @see ranset() (used to initialise the stream for MKL at the moment. Legacy from Fortran)
166 *
167 * @return Zero on success, integer error code otherwise
168 */
169int Par_ranset(unsigned int *seed,int iread)
170#endif
171{
172 const char *funcname = "Par_ranset";
173 //If we're not using the master thread, we need to change the seed
174#ifdef _DEBUG
175 printf("Master seed: %i\t",*seed);
176#endif
177 if(rank)
178 *seed *= 1.0f+8.0f*(float)rank/(float)(size-1);
179#ifdef _DEBUG
180 printf("Rank: %i\tSeed %i\n",rank, *seed);
181#endif
182 //Next we set the seed using ranset
183 //This is one of the really weird FORTRAN 66-esque functions with ENTRY points, so good luck!
184#if (defined __INTEL_MKL__||defined __RANLUX__)
185 return ranset(seed);
186#else
187 return 0;
188#endif
189}
190double Par_granf(){
191 /*
192 * @brief Generates a random double which is then sent to the other ranks
193 *
194 * @see ran2(), par_dcopy(), gsl_rng_uniform(), vdRngUniform()
195 *
196 * @return the random number generated
197 */
198 const char *funcname = "Par_granf";
199 double ran_val=0;
200 if(!rank){
201#if (defined USE_RAN2||(!defined __INTEL_MKL__&&!defined __RANLUX__))
202 ran_val = ran2(&seed);
203#elif defined __RANLUX__
204 ran_val = gsl_rng_uniform(ranlux_instd);
205#else
206 vdRngUniform(VSL_RNG_METHOD_UNIFORM_STD_ACCURATE, stream, 1, &ran_val, 0,1);
207#endif
208 }
209#if(nproc>1)
210 Par_dcopy(&ran_val);
211#endif
212 return ran_val;
213}
214int Gauss_z(Complex *ps, unsigned int n, const Complex mu, const double sigma){
215 /*
216 * @brief Generates a vector of normally distributed random double precision complex numbers using the Box-Muller Method
217 *
218 * @param ps: The output array
219 * @param n: The array length
220 * @param mu: mean
221 * @param sigma: variance
222 *
223 * @see ran2(), par_dcopy(), gsl_rng_uniform(), vdRngUniform()
224 *
225 * @return Zero on success integer error code otherwise
226 */
227 const char *funcname = "Gauss_z";
228 if(n<=0){
229 fprintf(stderr, "Error %i in %s: Array cannot have length %i.\nExiting...\n\n",
230 ARRAYLEN, funcname, n);
231#if(nproc>1)
232 MPI_Abort(comm,ARRAYLEN);
233#else
234 exit(ARRAYLEN);
235#endif
236 }
237#pragma unroll
238 for(int i=0;i<n;i++){
239 /* Marsaglia Method for fun
240 do{
241 u=sfmt_genrand_real1(sfmt);
242 v=sfmt_genrand_real1(sfmt);
243 r=u*u+v*v;
244 }while(0<r & r<1);
245 r=sqrt(r);
246 r=sqrt(-2.0*log(r)/r)*sigma;
247 ps[i] = mu+u*r + I*(mu+v*r);
248 */
249#ifdef __RANLUX__
250 double r =sigma*sqrt(-2*log(gsl_rng_uniform(ranlux_instd)));
251 double theta=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
252#else
253 double r =sigma*sqrt(-2*log(ran2(&seed)));
254 double theta=2.0*M_PI*ran2(&seed);
255#endif
256 ps[i]=r*(cos(theta)+sin(theta)*I)+mu;
257 }
258 return 0;
259}
260int Gauss_c(Complex_f *ps, unsigned int n, const Complex_f mu, const float sigma){
261 /*
262 * @brief Generates a vector of normally distributed random single precision complex numbers using the Box-Muller Method
263 *
264 * @param ps: The output array
265 * @param n: The array length
266 * @param mu: mean
267 * @param sigma: variance
268 *
269 * @see ran2(), par_dcopy(), gsl_rng_uniform(), vdRngUniform()
270 *
271 * @return Zero on success integer error code otherwise
272 */
273 const char *funcname = "Gauss_z";
274 if(n<=0){
275 fprintf(stderr, "Error %i in %s: Array cannot have length %i.\nExiting...\n\n",
276 ARRAYLEN, funcname, n);
277#if(nproc>1)
278 MPI_Abort(comm,ARRAYLEN);
279#else
280 exit(ARRAYLEN);
281#endif
282 }
283#pragma unroll
284 for(int i=0;i<n;i++){
285 /* Marsaglia Method for fun
286 do{
287 u=sfmt_genrand_real1(sfmt);
288 v=sfmt_genrand_real1(sfmt);
289 r=u*u+v*v;
290 }while(0<r & r<1);
291 r=sqrt(r);
292 r=sqrt(-2.0*log(r)/r)*sigma;
293 ps[i] = mu+u*r + I*(mu+v*r);
294 */
295#ifdef __RANLUX__
296 float r =sigma*sqrt(-2*log(gsl_rng_uniform(ranlux_instd)));
297 float theta=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
298#else
299 float r =sigma*sqrt(-2*log(ran2(&seed)));
300 float theta=2.0*M_PI*ran2(&seed);
301#endif
302 ps[i]=r*(cos(theta)+mu+sin(theta)*I)+mu;
303 }
304 return 0;
305}
306int Gauss_d(double *ps, unsigned int n, const double mu, const double sigma){
307 /*
308 * @brief Generates a vector of normally distributed random double precision numbers using the Box-Muller Method
309 *
310 * @param ps: The output array
311 * @param n: The array length
312 * @param mu: mean
313 * @param sigma: variance
314 *
315 * @see ran2(), par_dcopy(), gsl_rng_uniform(), vdRngUniform()
316 *
317 * @return Zero on success integer error code otherwise
318 */
319 const char *funcname = "Gauss_z";
320 //The FORTRAN Code had two different Gauss Routines. gaussp having unit
321 //mean and variance and gauss0 where the variance would appear to be 1/sqrt(2)
322 //(Since we multiply by sqrt(-ln(r)) instead of sqrt(-2ln(r)) )
323 if(n<=0){
324 fprintf(stderr, "Error %i in %s: Array cannot have length %i.\nExiting...\n\n",
325 ARRAYLEN, funcname, n);
326#if(nproc>1)
327 MPI_Abort(comm,ARRAYLEN);
328#else
329 exit(ARRAYLEN);
330#endif
331 }
332 int i;
333 double r, u, v;
334 //If n is odd we calculate the last index seperately and the rest in pairs
335 if(n%2==1){
336 n--;
337#ifdef __RANLUX__
338 r=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
339 ps[n]=sqrt(-2*log(gsl_rng_uniform(ranlux_instd)))*cos(r);
340#else
341 r=2.0*M_PI*ran2(&seed);
342 ps[n]=sqrt(-2*log(ran2(&seed)))*cos(r);
343#endif
344 }
345 for(i=0;i<n;i+=2){
346 /* Marsaglia Method for fun
347 do{
348 u=sfmt_genrand_real1(sfmt);
349 v=sfmt_genrand_real1(sfmt);
350 r=u*u+v*v;
351 }while(0<r & r<1);
352 r=sqrt(r);
353 r=sqrt(-2.0*log(r)/r)*sigma;
354 ps[i] = mu+u*r;
355 ps[i+1]=mu+v*r;
356 */
357#ifdef __RANLUX__
358 u=sqrt(-2*log(gsl_rng_uniform(ranlux_instd)))*sigma;
359 r=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
360#else
361 u=sqrt(-2*log(ran2(&seed)))*sigma;
362 r=2.0*M_PI*ran2(&seed);
363#endif
364 ps[i]=u*cos(r)+mu;
365 ps[i+1]=u*sin(r)+mu;
366 }
367 return 0;
368}
369int Gauss_f(float *ps, unsigned int n, const float mu, const float sigma){
370 /*
371 * @brief Generates a vector of normally distributed random single precision numbers using the Box-Muller Method
372 *
373 * @param ps: The output array
374 * @param n: The array length
375 * @param mu: mean
376 * @param sigma: variance
377 *
378 * @see ran2(), par_dcopy(), gsl_rng_uniform(), vdRngUniform()
379 *
380 * @return Zero on success integer error code otherwise
381 */
382 const char *funcname = "Gauss_z";
383 //The FORTRAN Code had two different Gauss Routines. gaussp having unit
384 //mean and variance and gauss0 where the variance would appear to be 1/sqrt(2)
385 //(Since we multiply by sqrt(-ln(r)) instead of sqrt(-2ln(r)) )
386 if(n<=0){
387 fprintf(stderr, "Error %i in %s: Array cannot have length %i.\nExiting...\n\n",
388 ARRAYLEN, funcname, n);
389#if(nproc>1)
390 MPI_Abort(comm,ARRAYLEN);
391#else
392 exit(ARRAYLEN);
393#endif
394 }
395 int i;
396 float r, u, v;
397 //If n is odd we calculate the last index seperately and the rest in pairs
398 if(n%2==1){
399 n--;
400#ifdef __RANLUX__
401 r=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
402 ps[n]=sqrt(-2*log(gsl_rng_uniform(ranlux_instd)))*cos(r);
403#else
404 r=2.0*M_PI*ran2(&seed);
405 ps[n]=sqrt(-2*log(ran2(&seed)))*cos(r);
406#endif
407 }
408#ifdef __RANLUX__
409 r=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
410 ps[n]=sqrt(-2*log(gsl_rng_uniform(ranlux_instd)))*cos(r);
411#else
412 r=2.0*M_PI*ran2(&seed);
413 ps[n]=sqrt(-2*log(ran2(&seed)))*cos(r);
414#endif
415 for(i=0;i<n;i+=2){
416 /* Marsaglia Method for fun
417 do{
418 u=sfmt_genrand_real1(sfmt);
419 v=sfmt_genrand_real1(sfmt);
420 r=u*u+v*v;
421 }while(0<r & r<1);
422 r=sqrt(r);
423 r=sqrt(-2.0*log(r)/r)*sigma;
424 ps[i] = mu+u*r;
425 ps[i+1]=mu+v*r;
426 */
427#ifdef __RANLUX__
428 u=sqrt(-2*log(gsl_rng_uniform(ranlux_instd)))*sigma;
429 r=2.0*M_PI*gsl_rng_uniform(ranlux_instd);
430#else
431 u=sqrt(-2*log(ran2(&seed)))*sigma;
432 r=2.0*M_PI*ran2(&seed);
433#endif
434 ps[i]=u*cos(r)+mu;
435 ps[i+1]=u*sin(r)+mu;
436 }
437 return 0;
438}
439#ifndef __RANLUX__
440double ran2(long *idum) {
441 /*
442 * @brief Generates uniformly distributed random double between zero and one as
443 * described in numerical recipes. It's also thread-safe for different seeds.
444 *
445 * @param idum: Pointer to the seed
446 *
447 * @return The random double between zero and one
448 *
449 */
450 long k;
451 int j;
452 static long idum2=123456789;
453 static long iy=0;
454 static long iv[NTAB];
456#pragma omp threadprivate(idum2, iy, iv)
457 //No worries
458 double temp;
459
460 if (*idum <= 0) {
461 if (-(*idum) < 1) *idum=1;
462 else *idum = -(*idum);
463 {
464 idum2=(*idum);
465
466 for(j=NTAB+7;j>=0;j--) {
467 k=(*idum)/IQ1;
468 *idum=IA1*(*idum-k*IQ1)-k*IR1;
469 if (*idum < 0) *idum += IM1;
470 if (j < NTAB)
471 iv[j] = *idum;
472 }
473 iy=iv[0];
474 }
475 }
476 k=(*idum)/IQ1;
477 *idum=IA1*(*idum-k*IQ1)-k*IR1;
478 if (*idum < 0) *idum += IM1;
479 k=idum2/IQ2;
480 idum2=IA2*(idum2-k*IQ2)-k*IR2;
481
482 if (idum2 < 0) idum2 += IM2; j=iy/NDIV;
483 iy=iv[j]-idum2;
484 iv[j] = *idum;
485 if (iy < 1) iy += IMM1;
486 if ((temp=AM*iy) > RNMX)
487 return RNMX;
488
489 else return temp;
490
491}
492#endif
493
494/*
495 int ran_test(){
496 const char *funcname ="ran_test";
497 const double mu = 0.3;
498 const double sigma = 2;
499 const float mu_f = 0.7;
500 const float sigma_f = 1.6;
501 long seed = 10;
502 ranset(&seed);
503 Complex *z_arr=(Complex *)malloc(1024*1024*sizeof(Complex));
504 FILE *z_out=fopen("z_ran.out","w");
505 Gauss_z(z_arr,1024*1024,mu,sigma);
506 for(int i =0; i<1024*1024;i++)
507 fprintf(z_out, "%f\t%f\n", creal(z_arr[i]), cimag(z_arr[i]));
508 fclose(z_out);
509 free(z_arr);
510 Complex_f *c_arr=(Complex_f *)malloc(1024*1024*sizeof(Complex_f));
511 Gauss_c(c_arr,1024*1024,mu_f,sigma_f);
512 FILE *c_out=fopen("c_ran.out","w");
513 free(c_arr);
514 for(int i =0; i<1024*1024;i++)
515 fprintf(c_out,"%f\t%f\n", creal(c_arr[i]), cimag(c_arr[i]));
516 fclose(c_out);
517 double *d_arr=(double *)malloc(1024*1024*sizeof(double));
518 Gauss_d(d_arr,1024*1024,mu,sigma);
519 FILE *d_out=fopen("d_ran.out","w");
520 for(int i =0; i<1024*1024;i++)
521 fprintf(d_out,"%f\n", d_arr[i]);
522 fclose(d_out);
523 free(d_arr);
524 float *f_arr=(float *)malloc(1024*1024*sizeof(float));
525 Gauss_f(f_arr,1024*1024,mu_f,sigma_f);
526 FILE *f_out=fopen("f_ran.out","w");
527 for(int i =0; i<1024*1024;i++)
528 fprintf(f_out,"%f\n", f_arr[i]);
529 fclose(f_out);
530 free(f_arr);
531 return 0;
532 }
533 */
Header for routines related to lattice sites.
This header is intended to be a useful reference for error codes and their meanings.
MPI headers.
int size
The number of MPI ranks in total.
Definition par_mpi.c:22
int Par_dcopy(double *dval)
Broadcasts a double to the other processes.
int rank
The MPI rank.
Definition par_mpi.c:22
int Gauss_f(float *ps, unsigned int n, const float mu, const float sigma)
Generates a vector of normally distributed random single precision numbers using the Box-Muller Metho...
Definition random.c:369
int ranset(long *seed)
Dummy seed the ran2 generator.
Definition random.c:74
int Par_ranread(char *filename, double *ranval)
Reads ps from a file Since this function is very similar to Par_sread, I'm not really going to commen...
Definition random.c:88
int Gauss_z(Complex *ps, unsigned int n, const Complex mu, const double sigma)
Generates a vector of normally distributed random double precision complex numbers using the Box-Mull...
Definition random.c:214
int Gauss_c(Complex_f *ps, unsigned int n, const Complex_f mu, const float sigma)
Generates a vector of normally distributed random single precision complex numbers using the Box-Mull...
Definition random.c:260
int Gauss_d(double *ps, unsigned int n, const double mu, const double sigma)
Generates a vector of normally distributed random double precision numbers using the Box-Muller Metho...
Definition random.c:306
int Par_ranset(long *seed, int iread)
Uses the rank to get a new seed. Copying from the FORTRAN description here c create new seeds in rang...
Definition random.c:135
#define M_PI
if not defined elsewhere
Definition random.c:41
double Par_granf()
Generates a random double which is then sent to the other ranks.
Definition random.c:190
double ran2(long *idum)
Generates uniformly distributed random double between zero and one as described in numerical recipes....
Definition random.c:440
long seed
RAN2 seed.
Definition random.c:27
Header for random number configuration.
Defines the constants of the code and other parameters for loop dimensions. Each subroutine includes ...
#define Complex
Double precision complex number.
Definition sizes.h:58
#define Complex_f
Single precision complex number.
Definition sizes.h:56