I am trying to write an attribute in my HDF file, my code manages to write the proper value for the attribute if it is of type integer, but not for reals. This is the code
! Number of processes is assumed to be 4
! PROGRAM DATASET_BY_CHUNK
USE HDF5 ! This module contains all necessary modules
! USE MPI
IMPLICIT NONE
include 'mpif.h'
CHARACTER(LEN=7), PARAMETER :: filename = "test.h5" ! File name
CHARACTER(LEN=9), PARAMETER :: dsetname = "data_test" ! Dataset name
INTEGER(HSIZE_T), DIMENSION(1) :: data_dims
INTEGER(HID_T) :: file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: filespace ! Dataspace identifier in file
INTEGER(HID_T) :: memspace ! Dataspace identifier in memory
INTEGER(HID_T) :: plist_id ! Property list identifier
INTEGER(HID_T) :: attr_id ! Attribute identifier
INTEGER(HID_T) :: aspace_id ! Attribute Dataspace identifier
INTEGER(HID_T) :: atype_id ! Attribute Dataspace identifier
INTEGER(HSIZE_T), DIMENSION(2) :: dimsf = (/4,8/) ! Dataset dimensions
! in the file.
! INTEGER, DIMENSION(7) :: dimsfi = (/4,8,0,0,0,0,0/)
INTEGER(HSIZE_T), DIMENSION (2) :: dimsfi = (/4,8/)
INTEGER(HSIZE_T), DIMENSION(2) :: chunk_dims = (/2,4/) ! Chunks dimensions
INTEGER(HSIZE_T), DIMENSION(2) :: count
INTEGER(HSSIZE_T), DIMENSION(2) :: offset
INTEGER(HSIZE_T), DIMENSION(2) :: stride
INTEGER(HSIZE_T), DIMENSION(2) :: block
INTEGER(HSIZE_T), DIMENSION(1) :: adims ! Attribute dimension
INTEGER :: arank = 1 ! Attribure rank
INTEGER(SIZE_T) :: attrlen ! Length of the attribute string
CHARACTER(LEN=80) :: attr_data ! Attribute data
INTEGER, ALLOCATABLE :: data (:,:) ! Data to write
INTEGER :: rank = 2 ! Dataset rank
real re
INTEGER :: error, error_n ! Error flags
!
! MPI definitions and calls.
!
INTEGER :: mpierror ! MPI error flag
INTEGER :: comm, info
INTEGER :: mpi_size, mpi_rank
comm = MPI_COMM_WORLD
info = MPI_INFO_NULL
CALL MPI_INIT(mpierror)
CALL MPI_COMM_SIZE(comm, mpi_size, mpierror)
CALL MPI_COMM_RANK(comm, mpi_rank, mpierror)
! Quit if mpi_size is not 4
if (mpi_size .NE. 4) then
write(*,*) 'This example is set up to use only 4 processes'
write(*,*) 'Quitting....'
goto 100
endif
attr_data = "Dataset character attribute"
!
! Initialize HDF5 library and Fortran interfaces.
!
CALL h5open_f(error)
!
! Setup file access property list with parallel I/O access.
!
CALL h5pcreate_f(H5P_FILE_ACCESS_F, plist_id, error)
CALL h5pset_fapl_mpio_f(plist_id, comm, info, error)
!
! Create the file collectively.
!
CALL h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, error, access_prp = plist_id)
CALL h5pclose_f(plist_id, error)
!
! Create some attribute
!
re = 20.0
!
! Create scalar data space for the attribute.
!
call h5screate_f(H5S_SCALAR_F,aspace_id,error)
adims=80
! -----------------------------
! Reynolds number
CALL h5acreate_f(file_id,'Re',H5T_NATIVE_DOUBLE,aspace_id, &
attr_id, error)
CALL h5awrite_f(attr_id,H5T_NATIVE_DOUBLE,re,adims,error)
CALL h5aclose_f(attr_id, error)
!
! Terminate access to the data space.
!
CALL h5sclose_f(aspace_id, error)
!
! Create the data space for the dataset.
!
CALL h5screate_simple_f(rank, dimsf, filespace, error)
CALL h5screate_simple_f(rank, chunk_dims, memspace, error)
!
! Create chunked dataset.
!
CALL h5pcreate_f(H5P_DATASET_CREATE_F, plist_id, error)
CALL h5pset_chunk_f(plist_id, rank, chunk_dims, error)
CALL h5dcreate_f(file_id, dsetname, H5T_NATIVE_INTEGER, filespace, &
dset_id, error, plist_id)
CALL h5sclose_f(filespace, error)
!
! Each process defines dataset in memory and writes it to the hyperslab
! in the file.
!
stride(1) = 1
stride(2) = 1
count(1) = 1
count(2) = 1
block(1) = chunk_dims(1)
block(2) = chunk_dims(2)
if (mpi_rank .EQ. 0) then
offset(1) = 0
offset(2) = 0
endif
if (mpi_rank .EQ. 1) then
offset(1) = chunk_dims(1)
offset(2) = 0
endif
if (mpi_rank .EQ. 2) then
offset(1) = 0
offset(2) = chunk_dims(2)
endif
if (mpi_rank .EQ. 3) then
offset(1) = chunk_dims(1)
offset(2) = chunk_dims(2)
endif
!
! Select hyperslab in the file.
!
CALL h5dget_space_f(dset_id, filespace, error)
CALL h5sselect_hyperslab_f (filespace, H5S_SELECT_SET_F, offset, count, error, &
stride, block)
!
! Initialize data buffer with trivial data.
!
ALLOCATE (data(chunk_dims(1),chunk_dims(2)))
data = mpi_rank + 1
!
! Create property list for collective dataset write
!
CALL h5pcreate_f(H5P_DATASET_XFER_F, plist_id, error)
CALL h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, error)
!
! Write the dataset collectively.
!
CALL h5dwrite_f(dset_id, H5T_NATIVE_INTEGER, data, dimsfi, error, &
file_space_id = filespace, mem_space_id = memspace, xfer_prp = plist_id)
!
! Write the dataset independently.
!
! CALL h5dwrite_f(dset_id, H5T_NATIVE_INTEGER, data, dimsfi,error, &
! file_space_id = filespace, mem_space_id = memspace)
!
! Deallocate data buffer.
!
DEALLOCATE(data)
!
! Close dataspaces.
!
CALL h5sclose_f(filespace, error)
CALL h5sclose_f(memspace, error)
!
! Close the dataset.
!
CALL h5dclose_f(dset_id, error)
!
! Close the property list.
!
CALL h5pclose_f(plist_id, error)
!
! Close the file.
!
CALL h5fclose_f(file_id, error)
!
! Close FORTRAN interfaces and HDF5 library.
!
CALL h5close_f(error)
100 continue
CALL MPI_FINALIZE(mpierror)
END PROGRAM DATASET_BY_CHUNK
The program runs satisfactorily, but when checking in Matlab with h5disp, I get that:
Attributes:
'Re': 0.000000
Any suggestions about how to fix it would be great! Thanks a lot
A Minimal, Complete, and Verifiable example (MCVE) would help both yourself (to spot your mistake) and us to figure out what you are really doing.
So in saying that, here's one. Please note there is no error checking, this is bad, bad, bad.
program fa
use hdf5
implicit none
character(len=8), parameter :: filename = "test.h5"
integer(hid_t) :: file_id
integer(hid_t) :: attr_id
integer(hid_t) :: aspace_id
integer(size_t), dimension(1) :: adims = (/0/)
integer :: ierr
real :: re
re = 20.0
call h5open_f(ierr)
call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, ierr)
call h5screate_f(H5S_SCALAR_F, aspace_id, ierr)
call h5acreate_f(file_id, 'Reynolds number', H5T_NATIVE_REAL, &
aspace_id, attr_id, ierr)
call h5awrite_f(attr_id, H5T_NATIVE_REAL, re, adims, ierr)
call h5aclose_f(attr_id, ierr)
call h5sclose_f(aspace_id, ierr)
call h5fclose_f(file_id, ierr)
call h5close_f(ierr)
end program fa
If you compile, run then dump the file:
$ h5fc -o fa fa.f90
$ ./fa
$ h5dump test.h5
HDF5 "test.h5" {
GROUP "/" {
ATTRIBUTE "Reynolds number" {
DATATYPE H5T_IEEE_F32LE
DATASPACE SCALAR
DATA {
(0): 20
}
}
}
}
Now the question I have to ask about your code is why is adims set to 80?
I would highly suggest three things
A MCVE.
Error checking.
In regards to using MPI you should always get a serial version (within reason) working then parallelize it. Yes, I know this might near be impossible, but if you do go this route it will make your life easier (at least to begin with).
Related
I'm doing a little project using Fortran. A part of the code is designed to check the PC's mac address. Currently, I'm using call system command as follows:
CALL SYSTEM("ipconfig -all >result.tmp")
Above code will invoke the windows ipconfig-all command and output the information to an external file result.tmp. Later this file will be read to check the mac address.
https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-fo...
I tried that solution, it works fine for the system command "ipconfig -all", but I did not figure out how to output the result to an external file. Does anyone can give me some hints on how to achieve that ?
Above works, except one annoying thing. The Fortran code will be compiled as a DLL and used by another C# program. The annoying thing is, whenever above code is executed in the C# program, a console window will be prompted shortly and then closed. I searched the forum to find if there is some way to disable the window prompt, it turns out there is some solution in the following link:
You also posted this at the Intel forum and user Paul Curtis replied with an example of how to get the MAC address directly using the Windows API.
Since StackOverflow prefers answers that aren't just links, I've included the code below.
MODULE MAC
USE ifwinty
USE charfunc
IMPLICIT NONE
PUBLIC GetMacInfo !, PortExists
PRIVATE
SAVE
INTEGER, PARAMETER :: MAX_ADAPTER_DESCRIPTION_LENGTH = 128
INTEGER, PARAMETER :: MAX_ADAPTER_NAME_LENGTH = 256
INTEGER, PARAMETER :: MAX_ADAPTER_ADDRESS_LENGTH = 8
INTEGER, PARAMETER :: MIB_IF_TYPE_ETHERNET = 6 ! Ipifcons.h
TYPE IP_ADDRESS_STRING
CHARACTER(LEN=16) :: String
END TYPE IP_ADDRESS_STRING
TYPE IP_MASK_STRING
CHARACTER(LEN=16) :: String
END TYPE IP_MASK_STRING
TYPE t_IP_ADDR_STRING
INTEGER (LPLONG) :: pNext
TYPE (IP_ADDRESS_STRING) :: IpAddress
TYPE (IP_MASK_STRING) :: IpMask
INTEGER (DWORD) :: Context
END TYPE t_IP_ADDR_STRING
TYPE t_IP_ADAPTER_INFO
INTEGER(LPLONG) :: pNext
INTEGER(DWORD) :: ComboIndex
CHARACTER(LEN=MAX_ADAPTER_NAME_LENGTH+4) :: AdapterName
CHARACTER(LEN=MAX_ADAPTER_DESCRIPTION_LENGTH+4) :: Description
INTEGER(UINT) :: AddressLength
INTEGER(BYTE) :: Address(MAX_ADAPTER_ADDRESS_LENGTH)
INTEGER(DWORD) :: Index
INTEGER(ULONG) :: iType
INTEGER(ULONG) :: DhcpEnabled
INTEGER(LPLONG) :: pCurrentIpAddress
TYPE(t_IP_ADDR_STRING) :: IpAddressList
TYPE(t_IP_ADDR_STRING) :: GatewayList
TYPE(t_IP_ADDR_STRING) :: DhcpServer
INTEGER(BOOL) :: HaveWins
TYPE(t_IP_ADDR_STRING) :: PrimaryWinsServer
TYPE(t_IP_ADDR_STRING) :: SecondaryWinsServer
INTEGER(ULONG) :: LeaseObtained
INTEGER(ULONG) :: LeaseExpires
END TYPE t_IP_ADAPTER_INFO
! must link with IpHlpApi.lib to access this API function;
! this interface is not included in ifwinty
INTERFACE
INTEGER(BOOL) FUNCTION GetAdaptersInfo (arg1, arg2)
USE ifwinty
!DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'GetAdaptersInfo' :: GetAdaptersInfo
INTEGER(LPLONG) :: arg1
INTEGER(LPLONG) :: arg2
END FUNCTION
END INTERFACE
CONTAINS
SUBROUTINE GetMacInfo (hwnd, id)
USE contwrap
IMPLICIT NONE
! dialog window handle and set of static-text IDs for display
INTEGER(HANDLE), INTENT(IN) :: hwnd
INTEGER, INTENT(IN), DIMENSION(4) :: id
CHARACTER(LEN=200) :: msg
INTEGER :: i, nc, count
INTEGER, PARAMETER :: acount = 16
TYPE(t_IP_ADAPTER_INFO),ALLOCATABLE :: ai(:)
count = 0
! allow for multiple adapters
ALLOCATE (ai(acount))
nc = SIZEOF(ai)
IF (GetAdaptersInfo(LOC(ai), LOC(nc)) == 0) THEN
DO i = 1, acount
SELECT CASE (ai(i)%iType)
CASE (MIB_IF_TYPE_ETHERNET)
! line 1: description and MAC address
!nc = INDEX(ai(i)%Description, CHAR(0)) - 1
!WRITE (msg, '(A,", ",5(Z2.2,"-"),Z2.2)') &
! ai(i)%Description(1:nc), &
! ai(i)%Address(1:ai(i)%AddressLength)
nc = INDEX(ai(i)%Description, CHAR(0))
msg = ai(i)%Description(1:nc)
count = count + 1
CALL StaticSetText (hwnd, id(count), msg)
CALL ControlSetVisible (hwnd, id(count), .TRUE.)
! line 2: IP and Gateway addresses
WRITE (msg, '("IP Addr: ",A," Gateway: ",A)') &
ai(i)%IpAddressList%IpAddress%string, &
ai(i)%GatewayList%IpAddress%string
CALL remove_nulls (msg)
count = count + 1
CALL StaticSetText (hwnd, id(count), msg)
CALL ControlSetVisible (hwnd, id(count), .TRUE.)
IF (count >= 4) EXIT
END SELECT
IF (ai(i)%pNext == NULL) EXIT
END DO
END IF
DEALLOCATE (ai)
END SUBROUTINE GetMacInfo
END MODULE MAC
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.
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
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]
I'm trying to do something that should be fairly common. Write an array of a compound datatype out to an hdf5 file, extend the file and write the new values of the array out and so on. I want to do this inside a loop. I initialize my dataset to have zero length and then extend it as needed in the loop.
If the loop is 1 trip it works fine:
HDF5 "mydata_1trip.h5" {
GROUP "/" {
DATASET "MYDATA" {
DATATYPE H5T_COMPOUND {
H5T_STD_I32LE "i4_name";
H5T_STD_I16LE "i21_name";
H5T_STD_I16LE "i22_name";
H5T_IEEE_F64LE "r8_name";
}
DATASPACE SIMPLE { ( 2 ) / ( H5S_UNLIMITED ) }
DATA {
(0): {
-100,
-1,
0,
1e+06
},
(1): {
-100,
-1,
0,
1e+06
} } } } }
With a 2 trip loop the dataset is correctly extended, but the 2nd write
overwrites the original data (and puts garbage in the 2nd dataset). So the problem would appear to be with the offset?
HDF5 "mydata_2trip.h5" {
GROUP "/" {
DATASET "MYDATA" {
DATATYPE H5T_COMPOUND {
H5T_STD_I32LE "i4_name";
H5T_STD_I16LE "i21_name";
H5T_STD_I16LE "i22_name";
H5T_IEEE_F64LE "r8_name";
}
DATASPACE SIMPLE { ( 4 ) / ( H5S_UNLIMITED ) }
DATA {
(0): {
-200,
-2,
0,
2e+06
},
(1): {
-200,
-2,
0,
2e+06
},
(2): {
107382520,
1,
0,
0
},
(3): {
107375576,
1,
0,
4.94066e-324
}
}
}
}
}
Here is the code
program read_test
USE hdf5
USE ISO_C_BINDING
implicit none
KIND parameters
INTEGER, PARAMETER :: int_k1 = SELECTED_INT_KIND(1) ! This should map to INTEGER*1 on most modern processors
INTEGER, PARAMETER :: int_k2 = SELECTED_INT_KIND(4) ! This should map to INTEGER*2 on most modern processors
INTEGER, PARAMETER :: int_k4 = SELECTED_INT_KIND(8) ! This should map to INTEGER*4 on most modern processors
INTEGER, PARAMETER :: int_k8 = SELECTED_INT_KIND(16) ! This should map to INTEGER*8 on most modern processors
INTEGER, PARAMETER :: r_k4 = SELECTED_REAL_KIND(5) ! This should map to REAL*4 on most modern processors
INTEGER, PARAMETER :: r_k8 = SELECTED_REAL_KIND(10) ! This should map to REAL*8 on most modern processors
FILES
CHARACTER(LEN=*), PARAMETER ::
& H5FILE_NAME="mydata.h5"
CHARACTER(LEN=*), PARAMETER :: DATASETNAME = "MYDATA"
type my_data
sequence
integer(kind=int_k4) :: i4
integer(kind=int_k2) :: i1_2,i2_2
real (kind=r_k8) :: r8
end type
integer(kind=int_k4) :: nsize=2,i
type(my_data),allocatable :: iblock(:)
INTEGER, PARAMETER :: RANK = 1
TYPE(my_data), pointer :: s1(:)
INTEGER(hid_t) :: s1_tid ! File datatype identifier
INTEGER(HID_T) :: file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: dataspace ! Dataspace identifier
INTEGER(HID_T) :: memspace ! Memory dataspace identifier
INTEGER(HID_T) :: crp_list ! Dataset creation property identifier
INTEGER(hsize_t) :: DIMS(1) ! Dataspace dimensions
INTEGER(SIZE_T) :: type_size ! Size of the datatype
INTEGER(SIZE_T) :: compound_offset, sizeof_compound
INTEGER(HSIZE_T), DIMENSION(1) :: chunk_dims,size
INTEGER :: hdferr
TYPE(C_PTR) :: f_ptr
Maximum dimensions
INTEGER(HSIZE_T), DIMENSION(1) :: maxdims
INTEGER(HSIZE_T), DIMENSION(1) :: offset
INTEGER(HSIZE_T), DIMENSION(1) :: count
allocate the buffers:
allocate(iblock(nsize))
dims(1) = nsize
allocate(s1(dims(1)))
Initialize FORTRAN interface.
CALL h5open_f(hdferr)
Create a new file using default properties.
CALL h5fcreate_f(h5file_name, H5F_ACC_TRUNC_F, file_id, hdferr)
We set it initially to 0. We
can extend the dataset at each step.
maxdims = (/H5S_UNLIMITED_F/)
dims(1) = 0
write(*,*)" dims = ",dims
Create the data space with unlimited dimensions.
CALL H5Screate_simple_f(RANK, dims, dataspace, hdferr,maxdims)
Then create a dataset creation property list. The layout of the dataset
have to be chunked when using unlimited dimensions. The choice of the
chunk size affects performances, both in time and disk space. If the
chunks are very small, you will have a lot of overhead. If they are
too large, you might allocate space that you don't need and your files
might end up being too large. This is a toy example so we will choose
chunks of one line.
Modify dataset creation properties, i.e. enable chunking
CALL h5pcreate_f(H5P_DATASET_CREATE_F, crp_list, hdferr)
chunk_dims(1) = nsize
CALL h5pset_chunk_f(crp_list, RANK, chunk_dims, hdferr)
Create the memory data type.
CALL H5Tcreate_f(H5T_COMPOUND_F, H5OFFSETOF(C_LOC(s1(1)),
& C_LOC(s1(2))), s1_tid, hdferr)
CALL H5Tinsert_f(s1_tid, "i4_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%i4)),
& h5kind_to_type(int_k4,H5_INTEGER_KIND), hdferr)
CALL H5Tinsert_f(s1_tid, "i21_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%i1_2)),
& h5kind_to_type(int_k2,H5_INTEGER_KIND), hdferr)
CALL H5Tinsert_f(s1_tid, "i22_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%i2_2)),
& h5kind_to_type(int_k2,H5_INTEGER_KIND), hdferr)
CALL H5Tinsert_f(s1_tid, "r8_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%r8)),
& h5kind_to_type(r_k8,H5_REAL_KIND), hdferr)
Create the dataset.
CALL H5Dcreate_f(file_id, datasetname, s1_tid, dataspace,
& dset_id, hdferr,crp_list)
Close resources. The dataset is now created so we don't need the
property list anymore. We don't need the file dataspace anymore because
when the dataset will be extended, it will become invalid as it will
still hold the previous extent. So we will have to grab the updated
file dataspace anyway.
call h5pclose_f(crp_list,hdferr)
CALL h5sclose_f(dataspace, hdferr)
We create a memory dataspace to indicate the size of our buffer in
memory.
dims(1) = nsize
CALL h5screate_simple_f(RANK, dims, dataspace, hdferr)
setup the input data
do i=1,2
iblock(:)%i4 = -100*i
iblock(:)%i1_2 = i
iblock(:)%i2_2 = -i
iblock(:)%r8 = 1.d6*i
Write data to memtype
s1(:) = iblock(:)
We create a memory dataspace to indicate the size of our buffer in
memory.
dims(1) is already nsize
We now need to extend the dataset. We set the initial size of the
dataset to 0, we thus need to extend it first. Note that we extend
the dataset itself, not its dataspace.
size(1) = i*nsize
CALL h5dset_extent_f(dset_id, size, hdferr)
dims(1) = nsize
CALL h5screate_simple_f (rank, dims, memspace, hdferr)
CALL h5dget_space_f(dset_id, dataspace, hdferr)
offset(1) = (i-1)*nsize ! if this is in chunks
count(1) = nsize
CALL h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F,
& offset, count, hdferr)
Write data array to dataset
f_ptr = C_LOC(s1(1))
CALL H5Dwrite_f(dset_id, s1_tid, f_ptr, hdferr)
CALL h5sclose_f(dataspace,hdferr)
enddo
Release resources
CALL H5Tclose_f(s1_tid, hdferr)
CALL h5sclose_f(memspace, hdferr)
CALL h5dclose_f(dset_id, hdferr)
CALL h5fclose_f(file_id, hdferr)
end program read_test