I have an OpenMP paralelized loop. I would like to be able to replicate experiments everytime I run the program. The program calls a lot of random numbers. The issue is given the nature of parallelization I cannot replicate the experiments from one run to the next run. Is there anyway of doing this? I can see two options:
1) Call all the random numbers before executing the paralelized loop (I really would like to avoid this option as potentially the number of random numbers to be generated could be unknown at the time one enters the loop);
2) Have an option to fix the seeds for each thread. This is something that is possible in matlab very easily by setting a seed that depends on the index of the parallelized loop. E.g:
%% Matlab example
parfor k = 1:nsim
rng(k, 'twister');
end
Below a minimal working example of something similar to what I am running:
%% Fortran minimal working example
program mwe
use tools
implicit none
integer :: ind1, ind2, ind3
integer :: n1 = 1000, n2 = 750, n3 = 300
real :: mu, mu1=0.01, mu2=0.02, sigma, sigma1=0.20, sigma2=0.40
real :: aux
real, allocatable :: z(:,:,:)
allocate(z(n1, n2, n3))
!$omp parallel do default(private) shared(n1, n2, n3, z, mu1, mu2, sigma1, sigma2)
do ind1 = 1,n1
do ind2=1,n2
do ind3 = 1,n3
call RANDOM_NUMBER(aux)
if (aux .le. 0.5) then
mu = mu1
sigma = sigma1
else
mu = mu2
sigma = sigma2
end if
z(ind1,ind2,ind3) = normal(mu,sigma)
end do
end do
end do
!$omp end parallel do
ind1 = 1
end program
MODULE tools
contains
function ran1() !returns random number between 0 - 1
implicit none
real :: ran1,x
call random_number(x) ! built in fortran 90 random number function
ran1=x
end function ran1
function normal(mean,sigma) !returns a normal distribution
implicit none
real :: normal,tmp
real :: mean,sigma
integer flag
real :: fac,gsave,rsq,r1,r2
save flag,gsave
data flag /0/
if (flag.eq.0) then
rsq=2.0
do while(rsq.ge.1.0.or.rsq.eq.0.0) ! new from for do
r1=2.0*ran1()-1.0
r2=2.0*ran1()-1.0
rsq=r1*r1+r2*r2
enddo
fac=sqrt(-2.0*log(rsq)/rsq)
gsave=r1*fac
tmp=r2*fac
flag=1
else
tmp=gsave
flag=0
endif
normal=tmp*sigma+mean
return
end function normal
end module