generating random numbers in a Fortran Module - random
Now I am facing the problem that in a module, with a seed I am generating random numbers to be used in a loop of a function but each time I call that function, the same random numbers are generated (because the seed is obviously the same) but it's supposed that it must continue the series or at least it must be different between calls. One solution could be that the main program gives a new seed to be used in the module but I think it there could be another elegant solution.
I am using Mersenne Twister generator by suggestion of many people.
Added
My function in my module (it is a package of functions) escentially makes such a Metropolis test using random numbers generated by a seed, for some reason compilation complains if I put
module mymod
uses mtmod
call sgrnd(4357)!<-- this line causes compilation error
contains
myfunc(args)
implicit none
// declarations etc
!call sgrnd(4357) <-- if I put this call here compilator says ok,
!but re-start random number series each time this function is called :(
....
!the following part is inside a loop
if (prob < grnd()) then
!grnd() is random number generated
return
else continue testing to the end of the loop cycle
end myfunc
But if I put that function in the contains of the main program (using mtmod too) and call sgrnd(4357) before contains section and the calls to myfunc, now everything compile and run nicely. For clarity, I didn't want to put that long function in the main program, it has 70 lines of code, but it seems I have no escape. Notice that so, the seed is once called. The simulations have now physical meanings but with that price payed.
I always used this subroutine (I'm running a MonteCarlo simulation), call it in the beginning of your main program and tis should do the job:
(Source: gfortran 4.6.1)
c initialize a random seed from the system clock at every run (fortran 95 code)
subroutine init_random_seed()
INTEGER :: i, n, clock
INTEGER, DIMENSION(:), ALLOCATABLE :: seed
CALL RANDOM_SEED(size = n)
ALLOCATE(seed(n))
CALL SYSTEM_CLOCK(COUNT=clock)
seed = clock + 37 * (/ (i - 1, i = 1, n) /)
CALL RANDOM_SEED(PUT = seed)
DEALLOCATE(seed)
end
You can find here a subroutine that uses system time to re-seed the random number generator. You shouldn't have to do this every time you call random_number(), just each time you re-start the program.
Honestly, it didn't take me more than ten minutes to find this with Google.
In order to recover my points taken, I was obliged to find my own answer, here it is (after one hour of tries)
main program is
program callrtmod
use mymod
implicit none
real::x
x=1.0
write(*,*) x+writerandnum()
write(*,*) x+writerandnum()
write(*,*) x+writerandnum()
end program callrtmod
here's my module
module mymod
implicit none
!-------------mt variables-------------
! Default seed
integer, parameter :: defaultsd = 4357
! Period parameters
integer, parameter :: N = 624, N1 = N + 1
! the array for the state vector
integer, save, dimension(0:N-1) :: mt
integer, save :: mti = N1
!--------------------------------------
contains
function writerandnum
implicit none
real(8)::writerandnum
writerandnum = grnd()
!if you please, you could perform a Metropolis test here too
end function writerandnum
!Initialization subroutine
subroutine sgrnd(seed)
implicit none
integer, intent(in) :: seed
mt(0) = iand(seed,-1)
do mti=1,N-1
mt(mti) = iand(69069 * mt(mti-1),-1)
enddo
!
return
end subroutine sgrnd
!---------------------------------------------------------------------------
!the function grnd was here
!---------------------------------------------------------------------------
subroutine mtsavef( fname, forma )
character(*), intent(in) :: fname
character, intent(in) :: forma
select case (forma)
case('u','U')
open(unit=10,file=trim(fname),status='UNKNOWN',form='UNFORMATTED', &
position='APPEND')
write(10)mti
write(10)mt
case default
open(unit=10,file=trim(fname),status='UNKNOWN',form='FORMATTED', &
position='APPEND')
write(10,*)mti
write(10,*)mt
end select
close(10)
return
end subroutine mtsavef
subroutine mtsaveu( unum, forma )
integer, intent(in) :: unum
character, intent(in) :: forma
select case (forma)
case('u','U')
write(unum)mti
write(unum)mt
case default
write(unum,*)mti
write(unum,*)mt
end select
return
end subroutine mtsaveu
subroutine mtgetf( fname, forma )
character(*), intent(in) :: fname
character, intent(in) :: forma
select case (forma)
case('u','U')
open(unit=10,file=trim(fname),status='OLD',form='UNFORMATTED')
read(10)mti
read(10)mt
case default
open(unit=10,file=trim(fname),status='OLD',form='FORMATTED')
read(10,*)mti
read(10,*)mt
end select
close(10)
return
end subroutine mtgetf
subroutine mtgetu( unum, forma )
integer, intent(in) :: unum
character, intent(in) :: forma
select case (forma)
case('u','U')
read(unum)mti
read(unum)mt
case default
read(unum,*)mti
read(unum,*)mt
end select
return
end subroutine mtgetu
!===============================================
!Random number generator
! real(8) function grnd()
function grnd !agregue yo
implicit integer(a-z)
real(8) grnd !agregue yo
! Period parameters
integer, parameter :: M = 397, MATA = -1727483681
! constant vector a
integer, parameter :: LMASK = 2147483647
! least significant r bits
integer, parameter :: UMASK = -LMASK - 1
! most significant w-r bits
! Tempering parameters
integer, parameter :: TMASKB= -1658038656, TMASKC= -272236544
dimension mag01(0:1)
data mag01/0, MATA/
save mag01
! mag01(x) = x * MATA for x=0,1
TSHFTU(y)=ishft(y,-11)
TSHFTS(y)=ishft(y,7)
TSHFTT(y)=ishft(y,15)
TSHFTL(y)=ishft(y,-18)
if(mti.ge.N) then
! generate N words at one time
if(mti.eq.N+1) then
! if sgrnd() has not been called,
call sgrnd( defaultsd )
! a default initial seed is used
endif
do kk=0,N-M-1
y=ior(iand(mt(kk),UMASK),iand(mt(kk+1),LMASK))
mt(kk)=ieor(ieor(mt(kk+M),ishft(y,-1)),mag01(iand(y,1)))
enddo
do kk=N-M,N-2
y=ior(iand(mt(kk),UMASK),iand(mt(kk+1),LMASK))
mt(kk)=ieor(ieor(mt(kk+(M-N)),ishft(y,-1)),mag01(iand(y,1)))
enddo
y=ior(iand(mt(N-1),UMASK),iand(mt(0),LMASK))
mt(N-1)=ieor(ieor(mt(M-1),ishft(y,-1)),mag01(iand(y,1)))
mti = 0
endif
y=mt(mti)
mti = mti + 1
y=ieor(y,TSHFTU(y))
y=ieor(y,iand(TSHFTS(y),TMASKB))
y=ieor(y,iand(TSHFTT(y),TMASKC))
y=ieor(y,TSHFTL(y))
if(y .lt. 0) then
grnd=(dble(y)+2.0d0**32)/(2.0d0**32-1.0d0)
else
grnd=dble(y)/(2.0d0**32-1.0d0)
endif
return
end function grnd
end module mymod
test my solution and vote me up ;) [of course, as you see, I modified mt.f90 code to be included conveniently in my module, so I can keep separately the main program from the randon numbers generation part, so I can do a Metropolis test aside the main program. The main program just wants to know if a trial was accepted or not. My solution does give more clarity to the main progam]
Related
Is it possible in Fortran to determine if two polymorphic objects are the same derived type?
Is it possible to take two polymorphic objects and determine if they are of the same derived type (or class)? The intention is to use it as a clean way to filter a generic linked list. Something like the following mock code. function isSameType(a, b) result(itIs) !arguments class(*), intent(in) :: a class(*), intent(in) :: b !output logical :: itIs !return true if a and b are both the same type !return false if a and b are not end function isSameType
The standard inquiry function same_type_as tests equality of dynamic type of two objects: program typetest implicit none type t1 end type t1 type t2 end type t2 class(*), allocatable :: a, b allocate(t1 :: a) allocate(t2 :: b) print *, SAME_TYPE_AS(a,b) ! False end program same_type_as does not test declared type (except where this is the same thing). It does not consider kind parameters: program partest implicit none type :: t1(n) integer, kind :: n end type t1 type(t1(1)) :: a type(t1(2)) :: b print *, SAME_TYPE_AS(a,b) ! True end program Further, to get a useful result you'll be wanting (at least) one of a and b to be of extensible dynamic type. While you can ask program intrinsictest implicit none class(*), allocatable :: a, b allocate(real :: a) allocate(double precision :: b) print *, SAME_TYPE_AS(a,b) ! ... end program the result is processor dependent (could be true or false).
Acessing MPI_WTIME in single precision
I need to get wall time in single precision. MPI_WTIME however returns the value in double precision. To work around this I try: subroutine wtime real(kind=8) :: t_now real :: wt t_now = MPI_WTIME() if ( t_now > 1e38 ) then wt = 1e30 else if ( t_now < 1e-38 ) then wt = 0 end if end subroutine wtime Is there a fortran equivalent of MPI_WTIME() that I can use instead to get wall time in single precision? I compile my code with the flag -real-size 32 so by default real is of kind 4.
Fortran syntax for assignments
The Fortran syntax is driving me mad! Can anyone explain how I can call the assignment (I'm pretty sure that is not the right terminology either...). I'm trying to assign a type according to the value type. I have the following: module test_module implicit none type :: mytype integer :: i real :: r logical :: l contains generic :: assignment(=) => mytype_to_type procedure, pass(me) :: mytype_to_type end type mytype contains subroutine mytype_to_type(t, me) implicit none class(*), intent(inout) :: t class(mytype), intent(in) :: me !.. process based on input type select type (t) type is (integer) t = me%i type is (real) t = me%r type is (logical) t = me%l class default stop "none" return end select end subroutine mytype_to_type end module test_module program test use test_module implicit none type(mytype) :: t_type integer :: i = 1 real :: r = 1. logical :: l = .true. t_type = i !! how is this supposed to work? select type(t_type) type is (integer) write(*,*) "is int" type is (real) write(*,*) "is real" type is (logical) write(*,*) "is logical" class default return end select end program test Would this even work? Could anyone help me with this? Thanks!
In a subroutine supporting defined assignment the two arguments are such that the first corresponds to the left-hand side of the assignment statement and the second the right-hand side.1 Here, then the subroutine you provide is assignment from a my_type expression to an unlimited polymorphic object. This isn't what you want, seeing t_type on the left. Instead, you should provide defined assignment to a my_type object. subroutine stuff_to_mytype(me,t) class(mytype), intent(out) :: me class(*), intent(in) :: t !.. process based on input type select type (t) type is (integer) me%i = t type is (real) me%r = t type is (logical) me%l = t class default stop "none" return end select end subroutine stuff_to_mytype That said, you could do this with a specific subroutine for each type you support, rather than an unlimited polymorphic right-hand side, with generic resolution. In this case you could also consider generic structure constructors (t_type=mytype(i)). 1 Precisely, the second argument is the right-hand side enclosed in parentheses.
OpenMP parameter sweep parallel
I am new to OpenMP. I want to solve a stiff ODE system for a range of parameter values using parallel do loops. I use the following code in Fortran given below. However, I do not know whether calling a stiff solver(as a subroutine) inside a parallel do loop is allowed or not? Also, I want to write the time series data into files with filenames such as "r_value_s__value.txt" in the subroutine before the return to the main program. Can anyone help. Below is the code and the error. I used gfortran with flags -fopenmp to compile. PROGRAM OPENMP_PARALLEL_STIFF USE omp_lib IMPLICIT NONE INTEGER :: I, J INTEGER, PARAMETER :: RTOT=10, STOT=15 INTEGER :: TID INTEGER, PARAMETER :: NUM_THREADS=8 DOUBLE PRECISION :: T_INITIAL, T_FINAL CALL OMP_SET_NUM_THREADS(NUM_THREADS) CALL CPU_TIME(T_INITIAL) PRINT*, "TIME INITIAL ",T_INITIAL !$OMP PARALLEL DO PRIVATE(I,J,TID) DO I=1,RTOT DO J=1,STOT TID=OMP_GET_THREAD_NUM() CALL STIFF_DRIVER(TID,I,J,RTOT,STOT) END DO END DO !$OMP END PARALLEL DO CALL CPU_TIME(T_FINAL) PRINT*, "TIME FINAL ",T_FINAL PRINT*, "TIME ELAPSED ",(T_FINAL-T_INITIAL)/NUM_THREADS END PROGRAM OPENMP_PARALLEL_STIFF SUBROUTINE STIFF_DRIVER(TID,II,JJ,RTOT,STOT) USE USEFUL_PARAMETERS_N_FUNC USE DVODE_F90_M ! Type declarations: IMPLICIT NONE ! Number of odes for the problem: INTEGER :: SERIAL_NUMBER, TID INTEGER :: II, JJ, RTOT, STOT, IND INTEGER :: J, NTOUT INTEGER :: ITASK, ISTATE, ISTATS, I ! parameters : declaration DOUBLE PRECISION, PARAMETER :: s0=0.450D0, dr=1.0D-4, ds=1.0D-2 DOUBLE PRECISION, DIMENSION(NEQ) :: Y, YOUT DOUBLE PRECISION :: ATOL, RTOL, RSTATS, T, TOUT, EPS, TFINAL, DELTAT DIMENSION :: RSTATS(22), ISTATS(31) DOUBLE PRECISION :: bb, cc, ba, ba1, eta CHARACTER(len=45) :: filename TYPE (VODE_OPTS) :: OPTIONS SERIAL_NUMBER=3011+II+(JJ-1)*RTOT IND=TID+3011+II+(JJ-1)*RTOT WRITE (*,12)SERIAL_NUMBER,TID 12 FORMAT ("SL. NO. ",I5," THREAD NO.",I3) r=(II-1)*dr s=s0+JJ*ds EPS = 1.0D-9 ! Open the output file: WRITE (filename,93)r,s 93 FORMAT ("r_",f6.4,"_s_",f4.2,".txt") OPEN (UNIT=IND,FILE=filename,STATUS='UNKNOWN',ACTION='WRITE') ! Parameters for the stiff ODE system q0 = 0.60D0; v = 3.0D0 Va = 20.0D-4; Vs = 1.0D-1 e1 = 1.0D-1; e2 = 1.10D-5; e3 = 2.3D-3; e4=3.0D-4 del = 1.7D-4; mu = 5.9D-4 al = 1.70D-4; be = 8.9D-4; ga = 2.5D-1 ! S and r dependent parameters e1s = e1/s; e2s = e2/(s**2); e3s = e3/s; e4s = e4/s dels = del*s; rs = r*s e1v = e1/v; e2v = e2/(v**2); e3v = e3/v; e4v = e4/v delv = del*v; rv = r*v ! SET INITIAL PARAMETERS for INTEGRATION ROUTINES T = 0.0D0 TFINAL = 200.0D0 DELTAT = 0.10D0 NTOUT = INT(TFINAL/DELTAT) RTOL = EPS ATOL = EPS ITASK = 1 ISTATE = 1 ! Set the initial conditions: USING MODULE USEFUL_PARAMETERS_N_FUNC CALL Y_INITIAL(NEQ,Y) ! Set the VODE_F90 options: OPTIONS = SET_OPTS(DENSE_J=.TRUE.,USER_SUPPLIED_JACOBIAN=.FALSE., & RELERR=RTOL,ABSERR=ATOL,MXSTEP=100000) ! Integration: DO I=1,NTOUT TOUT = (I-1)*DELTAT CALL DVODE_F90(F_FUNC,NEQ,Y,T,TOUT,ITASK,ISTATE,OPTIONS) ! Stop the integration in case of an error IF (ISTATE<0) THEN WRITE (*,*)"ISTATE ", ISTATE STOP END IF ! WRITE DATA TO FILE WRITE (IND,*) TOUT,T, Y(NEQ-2) END DO CLOSE(UNIT=IND) RETURN END SUBROUTINE STIFF_DRIVER At line ** of file openmp_parallel_stiff.f90 (unit = 3013) Fortran runtime error: File already opened in another unit
The issue is the format that you chose: f6.4 for r will overflow for r>=10. Then, the output will be six asterisks ****** (depending on the compiler) for all values of r>=10 on all threads. The same holds true for s. I would suggest to either limit/check the range of these values or extend the format to honor more digits. As #francescalus mentioned, another possibility is hit a combination of II and JJ where r and s are identical. Just for the fun of it - let's do the math: r=(II-1)*dr s=s0+JJ*ds From r=s follows (II-1)*dr = s0+JJ*ds or II = 1 + s0/dr + JJ*ds/dr Using the constants s0=0.450D0, dr=1.0D-4, ds=1.0D-2 yields II = 4501 + JJ*10 So, whenever this combination is true for two (or more) threads at a time, you run into the observed issue. Simple solution for this case: add the thread number to the file name.
A value sended by host not return correctly by device using CUDA Fortran
I took an example of data transfer between Host and Device for CUDA Fortran and found this: Host Code: program incTest use cudafor use simpleOps_m implicit none integer, parameter :: n = 256 integer :: a(n), b, i integer, device :: a_d(n) a = 1 b = 3 a_d = a call inc<<<1,n>>>(a_d, b) a = a_d if (all(a == 4)) then write(*,*) 'Success' endif end program incTest Device Code: module simpleOps_m contains attributes(global) subroutine inc(a, b) implicit none integer :: a(:) integer, value :: b integer :: i i = threadIdx%x a(i) = a(i)+b end subroutine inc end module simpleOps_m The expected outcome is the console presenting "Success", but this did not happen. Nothing appears in the screen, nothing errors or messages. This happen because don't enter in if, because a_d has the same value that before call inc subroutine. I'm using: OS: Linux - Ubuntu 16 Cuda 8 PGI to compile Commands to compile: pgf90 -Mcuda -c Device.cuf pgf90 -Mcuda -c Host.cuf pgf90 -Mcuda -o HostDevice Device.o Host.o ./HostDevice I tried other examples and they did not work too. I tried using simple Fortran (.f90) code with the same commands to compile and it works! How can I fix this problem?
What type of device are you using? (If you don't know, post the output from the "pgaccelinfo" utility). My best guess is that you have a Pascal based device in which case you need to compile with "-Mcuda=cc60". For example, if I add error checking to the example code, we see that we get an invalid device kernel error when running on a Pascal without the "cc60" as part of the compilation. % cat test.cuf module simpleOps_m contains attributes(global) subroutine inc(a, b) implicit none integer :: a(:) integer, value :: b integer :: i i = threadIdx%x a(i) = a(i)+b end subroutine inc end module simpleOps_m program incTest use cudafor use simpleOps_m implicit none integer, parameter :: n = 256 integer :: a(n), b, i, istat integer, device :: a_d(n) a = 1 b = 3 a_d = a call inc<<<1,n>>>(a_d, b) istat=cudaDeviceSynchronize() istat=cudaGetLastError() a = a_d if (all(a == 4)) then write(*,*) 'Success' else write(*,*) 'Error code:', cudaGetErrorString(istat) endif end program incTest % pgf90 test.cuf -Mcuda % a.out Error code: invalid device function % pgf90 test.cuf -Mcuda=cc60 % a.out Success