Fortran - nf90_open - SIGSEGV - fortran

I am using an old fortran program given to me to open a netcdf file, read its contents, perform some calculations and interpolation, and write the data to another file format. I have very little experience in fortran, so please any help would be deeply appreciated.
The program is compiled successfully:
ifort -c -CB -CU -ftrapuv -par_report0 -vec_report0 -heap-arrays -O0 -stand f90 -check all -traceback -fstack-protector -assume protect_parens -implicitnone -debug -gen-interfaces -check arg_temp_created -ftrapuv -g -convert big_endian -I/opt/cray/netcdf/4.3.0/INTEL/130/include/ CAM_netcdf_to_WRF_intermediate.f90 ; ifort CAM_netcdf_to_WRF_intermediate.o -L/opt/cray/netcdf/4.3.0/INTEL/130/lib -lnetcdf -lnetcdff
The program crashes, running out of bounds while trying to read in the netcdf file:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7657d33 in nf_open_ (A1=0x18 <Address 0x18 out of bounds>, A2=0x4e04bc <__NLITPACK_19>,
A3=0x7fffffff90ec, C1=128) at fort-control.c:27
27 fort-control.c: No such file or directory.
Running GDB, using 'bt full':
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7657d33 in nf_open_ (A1=0x18 <Address 0x18 out of bounds>, A2=0x4e04bc <__NLITPACK_19>,
A3=0x7fffffff90ec, C1=128) at fort-control.c:27
27 fort-control.c: No such file or directory.
(gdb) bt full
#0 0x00007ffff7657d33 in nf_open_ (A1=0x18 <Address 0x18 out of bounds>,
A2=0x4e04bc <__NLITPACK_19>, A3=0x7fffffff90ec, C1=128) at fort-control.c:27
B1 = 0x0
B3 = 5113020
#1 0x00007ffff76630ac in NETCDF::nf90_open (
path=<error reading variable: Cannot access memory at address 0x18>, mode=0, ncid=-858993460,
chunksize=<error reading variable: Cannot access memory at address 0x0>,
cache_size=<error reading variable: Cannot access memory at address 0x0>,
cache_nelems=<error reading variable: Cannot access memory at address 0x0>,
cache_preemption=<error reading variable: Cannot access memory at address 0x0>,
comm=<error reading variable: Cannot access memory at address 0x0>,
info=<error reading variable: Cannot access memory at address 0x0>, .tmp.PATH.len_V$ffc=128)
at netcdf4_file.f90:64
nf90_open = -144388088
ret = 0
preemption_out = 0
nelems_out = -1
size_out = 0
preemption_in = 32767
nelems_in = -134664192
size_in = 32767
The program is below:
program CAM_netcdf_to_WRF_intermediate
use netcdf
implicit none
! Declarations:
integer, parameter :: outfile_diagnostics = 16
integer, parameter :: infile_CAM_files_and_dates = 15
character(len=24) :: HDATE
! dimensions:
integer, parameter :: nx_CAM=288,ny_CAM=192,nz_CAM=26 &
,nfields=5,nfields2d=9,nfields2d_to_read=5 &
,nz_soil=4,nz_CLM=1,nfields_soil=2
integer, parameter :: nz_WRF=38
character(len=128) :: netcdf_cam_filename,netcdf_clm_filename,netcdf_pop_filename
character(len=128) :: netcdf_ice_filename
integer :: iEOF
logical :: EOF
! open outpuf log file:
open(outfile_diagnostics,form='formatted',file="Output/CCSM2WRF.log")
! read the first date and netcdf file name from the input file:
open(infile_CAM_files_and_dates,form='formatted',file="Input/CCSM2WRF.input")
read(infile_CAM_files_and_dates,*,iostat=iEOF) netcdf_cam_filename,netcdf_clm_filename,&
netcdf_pop_filename,netcdf_ice_filename,hdate
if (iEOF<0) then;
print *, "EOF True"
EOF=.true.;
else;
print *, "EOF False"
EOF=.false.;
end if
call dummy_read(nz_WRF,hdate,outfile_diagnostics,netcdf_cam_filename &
,netcdf_clm_filename,netcdf_pop_filename &
,netcdf_ice_filename,nx_CAM,ny_CAM,nz_CAM)
stop
end program CAM_netcdf_to_WRF_intermediate
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SUBROUTINE HANDLE_ERR(STATUS)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
use netcdf
implicit none
INTEGER STATUS
IF (STATUS .NE. NF90_NOERR) THEN
PRINT *, NF90_STRERROR(STATUS)
STOP 'Stopped'
ENDIF
END SUBROUTINE HANDLE_ERR
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Subroutine dummy_read &
(nz_WRF,outfile_diagnostics,netcdf_cam_filename &
,netcdf_clm_filename,netcdf_pop_filename,netcdf_ice_filename &
,nx_CAM,ny_CAM,nz_CAM)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
use netcdf
implicit none
integer :: nz_WRF
integer :: nx_CAM,ny_CAM,nz_CAM
character(len=128) :: filename
character(len=24) :: HDATE
integer :: outfile_diagnostics
integer :: STATUS, NCID, NCID_clm, NCID_pop, NCID_ice
character(len=128) :: netcdf_cam_filename, netcdf_clm_filename, netcdf_pop_filename
character(len=128) :: netcdf_ice_filename
! open output files for metgrid in WRF/WPS intermediate format:
write(filename,'("Output/FILE:",A13)') hdate(1:13)
write(outfile_diagnostics,*) "output intermediate file filename=",filename
open(10,form='unformatted',file=filename)
write(filename,'("Output/SST:",A13)') hdate(1:13)
write(outfile_diagnostics,*) "output intermediate SST file filename=",filename
open(11,form='unformatted',file=filename)
STATUS = NF90_OPEN(netcdf_cam_filename, 0, NCID)
! STATUS = NF90_OPEN(path = "Inputdata/ind/cam_CCSM4_historical_197909-197912-1979090100.nc", mode= 0, ncid = NCID)
IF (STATUS .NE. NF90_NOERR) CALL HANDLE_ERR(STATUS)
print *, "first status conditional statement"
STATUS = NF90_OPEN(netcdf_clm_filename, 0, NCID_clm)
IF (STATUS .NE. NF90_NOERR) CALL HANDLE_ERR(STATUS)
STATUS = NF90_OPEN(netcdf_pop_filename, 0, NCID_pop)
IF (STATUS .NE. NF90_NOERR) CALL HANDLE_ERR(STATUS)
STATUS = NF90_OPEN(netcdf_ice_filename, 0, NCID_ice)
IF (STATUS .NE. NF90_NOERR) CALL HANDLE_ERR(STATUS)
status=NF90_CLOSE(NCID)
status=NF90_CLOSE(NCID_clm)
status=NF90_CLOSE(NCID_pop)
status=NF90_CLOSE(NCID_ice)
print *, "Leaving dummy, going to MAIN"
return
end Subroutine dummy_read
The open statement works if I hard-code the path of the netcdf file (see the commented out line within the dummy_read subroutine). Printing out the netcdf_cam_filename within main returns a valid string, however printing out the string within the dummy_read subroutine returns an empty string. I am uncertain why the netcdf_cam_filename string is not making it into the subroutine correctly.
Please ask if you need additional information. I only posted pieces of the code that I think applies to the error. Thanks in advance.

Your subroutine call is mismatched to the actual definition.
Your call to dummy_read is:
call dummy_read(nz_WRF,hdate,outfile_diagnostics,netcdf_cam_filename &
,netcdf_clm_filename,netcdf_pop_filename &
,netcdf_ice_filename,nx_CAM,ny_CAM,nz_CAM)
While your declaration of dummy_read is:
Subroutine dummy_read &
(nz_WRF,outfile_diagnostics,netcdf_cam_filename &
,netcdf_clm_filename,netcdf_pop_filename,netcdf_ice_filename &
,nx_CAM,ny_CAM,nz_CAM)
Or shown a different way:
call dummy_read(nz_WRF,hdate, outfile_diagnostics,netcdf_cam_filename,netcdf_clm_filename,netcdf_pop_filename,netcdf_ice_filename,nx_CAM,ny_CAM,nz_CAM)
Subroutine dummy_read(nz_WRF,outfile_diagnostics,netcdf_cam_filename,netcdf_clm_filename,netcdf_pop_filename,netcdf_ice_filename,nx_CAM, ny_CAM,nz_CAM)
Which results in an argument mismatch. The dummy argument outfile_diagnostics is associated with the actual argument hdate and so on. You are passing 10 arguments to a subroutine declared to take 9.
You might wonder why the compiler produced an executable in such a case rather than producing an error. This is because you are calling the procedure with an implicit interface and Fortran trusts you to do the right thing. Fortran can detect argument mismatches but to do so you need to provide an explicit interface. Aside from explicitly declaring the interface, the easiest ways to do this are to either make the procedure a module procedure (by putting the subroutine into a module) or an internal procedure (by putting the procedure in the main program after a contains statement).
You can also ask the compiler to provide high levels of warnings to avoid this problem. Compiling with gfortran with -Wall produces this warning with your code:
call dummy_read(nz_WRF,hdate,outfile_diagnostics,netcdf_cam_filename &
1
Warning: Type mismatch in argument 'outfile_diagnostics' at (1); passed CHARACTER(1) to INTEGER(4)
Adiitionally, ifort provides the option -gen-interfaces flag that will automatically generate modules to contain external procedures. I would however consider this a tool to help port code to newer language standards than something to rely on.

Related

Memory allocation error when reading multiple files

I'm trying to open 6 different files (at least) and then read the number of lines in each file, which should be about 20,000 lines each. I've read some posts on this forum about how to do that as I'm a newbie, and I've tried to implement it for my purposes.
I can do this individually without any problem, but when I try to read in all the files, I get an error message. I get either the "Killed: 9" error message or a malloc error:
malloc: *** mach_vm_map(size=63032829050880) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
What does this error mean regarding memory allocation? What am I doing wrong? How do I go about correcting this?
PROGRAM X
IMPLICIT NONE
INTEGER :: J,IO,NFILES,NLINES
CHARACTER (LEN=128) :: FILENAME
NFILES = 6
NLINES = 0
DO J = 0,NFILES-1
WRITE(FILENAME,'(A,I7.7,A)') 'data_',J*200,'.txt'
OPEN(1,FILE='FILENAME',FORM='FORMATTED')
DO
READ(1,*,IOSTAT=IO)
IF (IO/=0) EXIT
NLINES = NLINES + 1
END DO
WRITE(*,*) NLINES
CLOSE(1)
END DO
END PROGRAM X
I am using gfortran to compile.
UPDATE
I created 6 test files, data_0000000.txt, data_0000200.txt, ..., data_0001000.txt, each with less than 10 lines where there are less than 100 characters in each line. Unfortunately, I get the same error.
Obligatory disclaimer: If you just want to know the number of lines in a file, use wc -l <filename>. Don't reinvent the wheel if you don't have to.
I write this not necessarily because I think you didn't know that, but because someone else might come along, and think they need to write their own program to get the number of lines of files.
As for your question: I don't know why you get a malloc error. Maybe tell us which compiler and system you're using (including versions)? That said, there are three things that I noticed when reading your code:
You create a variable FILENAME, but then you don't use it. You're quoting it: FILE='FILENAME' which means that the open command looks for a file literally called FILENAME, not for a file with the name stored in the variable FILENAME. Remove the quotes:
OPEN(1, FILENAME=FILENAME, FORM='FORMATTED')
You use the unit number 1 -- that is dangerous. Different version of Fortran use specific unit numbers for specific uses. Use a handle far larger (at least 10, or more), or, even better, use the newunit descriptor in the open statement:
INTEGER :: u
OPEN(NEWUNIT=u, FILE=FILENAME, ACTION='READ', FORM='FORMATTED')
READ(u, *, IOSTAT=IO)
CLOSE(u)
You're not resetting the NLINES variable to 0 between files. The program will print a cumulative sum, not the number of lines for each file directly.
Adding to #chw21's response, if your sole purpose is to count the number of records (lines) in a file, here is a modular solution and a test program along with it (the counting is done inside subroutine getNumRecordInFile()):
module NumRecord_mod
implicit none
type :: Err_type
logical :: occurred = .false.
integer :: stat = -huge(0)
character(:), allocatable :: msg
end type Err_type
contains
! returns the number of lines in a file.
subroutine getNumRecordInFile(filePath,numRecord,Err)
implicit none
character(len=*), intent(in) :: filePath
integer, intent(out) :: numRecord
type(Err_type), intent(out) :: Err
character(len=8) :: record
integer :: fileUnit
logical :: fileExists, isOpen
integer :: iostat
character(*), parameter :: PROCEDURE_NAME = "#getNumRecordInFile()"
Err%occurred = .false.
Err%msg = ""
! Check if file exists
inquire( file=filePath, exist=fileExists, opened=isOpen, number=fileUnit, iostat=Err%stat )
if (Err%stat/=0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while inquiring the status of file='" // filePath // "'."
return
end if
if (.not.fileExists) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": The input file='" // filePath // "' does not exist."
return
end if
if (isOpen) close(unit=fileUnit,iostat=Err%stat)
if (Err%stat>0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while attempting to close the open input file='" // filePath // "'."
return
end if
open(newunit=fileUnit,file=filePath,status="old",iostat=Err%stat)
if (Err%stat>0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while opening input file='" // filePath // "'."
return
end if
numRecord = 0
do
read(fileUnit,'(A)',iostat=iostat) record
if(iostat==0) then
numRecord = numRecord + 1
cycle
elseif(is_iostat_end(iostat)) then
exit
else
Err%occurred = .true.
Err%stat = iostat
Err%msg = PROCEDURE_NAME // ": Error occurred while reading input file='" // filePath // "'."
return
end if
end do
close(fileUnit,iostat=Err%stat)
if (Err%stat>0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while attempting to close the open input file='" // &
filePath // "' after counting the number of records in file."
return
end if
end subroutine getNumRecordInFile
end module NumRecord_mod
program test_numRecord
use NumRecord_mod
implicit none
type(Err_type) :: Err
integer :: numRecord
character(:), allocatable :: filePath
filePath = "main.f95"
call getNumRecordInFile(filePath=filePath,numRecord=numRecord,Err=Err)
if (Err%occurred) then
write(*,*) Err%msg
write(*,*) Err%stat
error stop
else
write(*,*) "Total number of records in file='" // filePath // "': ", numRecord
end if
end program test_numRecord
Now if you put this code in a file named "main.f95" and compile it under Fortran 2008 standard, then it should output the number of lines in your "main.f95" file, which should be something like the following:
$gfortran -std=f2008 *.f95 -o main
$main
Total number of records in file='main.f95': 98
For testing, you can simply copy paste the entire code in the online Fortran compiler here: https://www.tutorialspoint.com/compile_fortran_online.php
But keep in mind to change the compile option -std=f95 to -std=f2008 by going to Project -> Compile Options before executing the code.
Try this change (declaration and read line), there was no variable specified where the line contents shall go, here insert now dummy...
character(len=1000) :: dummy
...
READ(u, '(a)' , IOSTAT=IO) dummy
....

I am trying to compile following code wrote in fortran but has many errors

I am trying to compile this following code in gfortran compiler:
do_cmd = .not. is_group
do while (.not. EOF(unit=100) .and. .not. flag_stop)
read (100, '(A)', iostat = ios) buf
if (buf(1:1)=="#") then
! comment line
elseif ((buf(1:2)=="v ") .and. do_cmd) then ! vertex
read(buf(2:), *, iostat=ios) p(1), p(2), p(3)
if (ios.ne.0) then
print "(/,2x,'Error of reading vertex position from obj-file (line #'(I3)');')", line_index
stop
end if
But I get these errors when the code is compiling:
do while (.not. EOF(unit=100) .and. .not. flag_stop)
1
Error: Keyword argument requires explicit interface for procedure ‘eof’ at (1)
and;
do while (.not. EOF(unit=100) .and. .not. flag_stop)
1
Error: Function ‘eof’ at (1) has no IMPLICIT type
I will be so grateful if anyone could help me.
edit:
I'm very new in fortran and couldn't find out how eof function works in gfortran.
What does it mean using unit=100 in argument?
And also Thought it is a logical function by default. How should I implicit its type?
As far as I know, EOF is not part of the Fortran Standard. At least I can't find it anywhere.
In most programming languages, EOF stands for "End of File", and it is fairly obvious to me that the EOF in your example is supposed to be a logical function that returns .TRUE. if and only if the read pointer associated with unit (in your case 100) points to the end of the file.
You can use the ios variable to check whether an EOF was encountered during the read. In that case, it will be -1. You can then use the exit statement to immediately quit the loop.
If you don't like the -1, and you use a Fortran 2003 compatible compiler, you might even use the module ISO_FORTRAN_ENV, which provides (amongst other things) the parameter IOSTAT_END.
Here's a very simple example:
program iso
use ISO_FORTRAN_ENV
implicit none
integer, parameter :: u = 100
character(len=80) :: buf
integer :: ios
open(unit=u, action='READ', status='OLD', file='data.dat')
read_loop : do
read(u, '(A)', iostat=ios) buf
if (ios == IOSTAT_END) exit read_loop ! EOF
if (buf(1:1) == '#') cycle read_loop ! This line is a comment
write(*, *) buf
end do read_loop
close(u)
end program iso
One note though: This code is meant as an example. It only exits the loop if it encounters an EOF -- not if the read fails for any other reason. (There are some other reasons that the the read would fail.) If that other error is persistent, then this will lead to an infinite loop.
It may be useful to try a user-defined EOF function (as shown below) to minimize the amount of code modifications; but because this function is rather inefficient, I guess it is probably better to rewrite the original code so as to utilize iostat in read statements directly (as suggested above)...
module eofmod !<-- please save this in a separate file, compile, and link with other programs
implicit none
contains
logical function EOF( unit )
integer, optional :: unit
integer :: ios
if ( .not. present( unit ) ) stop "no unit given"
read( unit, *, iostat=ios )
if ( ios == -1 ) then
EOF = .true.
else
EOF = .false. ; backspace( unit )
endif
end function
end module
program test
use eofmod !<-- needs to be inserted at the top of routines (or modules) where "EOF" is used
implicit none
character(200) :: buf
open(10, file="test.dat", status="old")
do while ( .not. EOF( unit=10 ) )
read( 10, "(a)" ) buf
print "(a)", trim( buf )
enddo
close(10)
end program

Why does Fortran HDF5's unlimited maximum dimension parameter (H5S_UNLIMITED_F) evaluate to zero instead of -1?

I'm try to compile a Fortran application to write HDF5 files. My compiler is gfortran 4.7.2. Specifically, I'm trying to create a dataspace with a certain set of current dimensions and maximum dimensions. I want the last dimension to have an unlimited maximum dimension. There isn't much documentation for Fortran HDF5, but I was able to figure out that this can be specified by setting that dimension in question to H5S_UNLIMITED_F. This value is supposed to evaluate to -1, but in my application it instead evaluates to 0, which causes a runtime error because 0 is less than the corresponding current dimension (in my case, 20). This is the error:
HDF5-DIAG: Error detected in HDF5 (1.8.11) thread 0:
#000: H5S.c line 1388 in H5Screate_simple(): maxdims is smaller than dims
major: Invalid arguments to routine
minor: Bad value
I compiled one of the Fortran examples that came with HDF5 that uses the same H5S_UNLIMITED_F parameter (h5_extend.f90), but for that application, the parameter evaluates to -1 and there is no problem.
What might I be doing wrong?
Below is a test program I wrote to replicate the problem seen in my project:
program simple_test
use hdf5
implicit none
integer :: irank, hdferr
integer(hsize_t) :: ny, nx, nz
real, dimension(:,:,:), allocatable :: dset
character (len = 256) :: hdf_file, dlab
integer(hid_t) :: file_handle, mem_space, file_space, dset_handle
integer(hsize_t), dimension(:), allocatable :: dim_array, max_array
irank = 3
ny = 10
nx = 15
nz = 20
allocate (dset(ny, nx, nz))
hdf_file = 'simple_test.hdf5'
dlab = 'simple_data'
allocate (dim_array(irank))
allocate (max_array(irank))
dim_array = (/ ny, nx, nz /)
max_array = (/ ny, nx, H5S_UNLIMITED_F /)
print *, 'h5s_unlimited_f: ', h5s_unlimited_f
print *, 'dim_array: ', dim_array
print *, 'max_array: ', max_array
call h5open_f(hdferr)
if (hdferr .eq. -1) then
print *, 'Error opening HDF5 Fortran interface.'
end if
! Create a new file.
call h5fcreate_f(hdf_file, H5F_ACC_TRUNC_F, file_handle, hdferr)
if (hdferr .eq. -1) then
print *, 'Error creating HDF5 file.'
end if
! Create memory dataspace.
call h5screate_simple_f(irank, dim_array, mem_space, hdferr, max_array)
if (hdferr .eq. -1) then
print *, 'Error creating HDF5 memory dataspace.'
end if
! Create the dataset.
call h5dcreate_f(file_handle, trim(dlab), H5T_IEEE_F32LE, mem_space, &
dset_handle, hdferr)
if (hdferr .eq. -1) then
print *, 'Error creating HDF5 dataset.'
end if
! Create file dataspace.
call h5screate_simple_f(irank, dim_array, file_space, hdferr, max_array)
if (hdferr .eq. -1) then
print *, 'Error creating HDF5 file dataspace.'
end if
call h5dwrite_f(dset_handle, H5T_IEEE_F32LE, dset, dim_array, hdferr, &
mem_space, file_space)
if (hdferr .eq. -1) then
print *, 'Error writing HDF5 dataset.'
end if
call h5close_f(hdferr)
if (hdferr .eq. -1) then
print *, 'Error closing HDF5 Fortran interface.'
end if
deallocate (dset)
deallocate (dim_array)
deallocate (max_array)
end program simple_test
The first call to h5s_create_simple_f is what fails. If I change the memory dataspace to not use the max_array parameter (since it is optional and in my case perhaps unnecessary), then I still get the same error on the second call to h5s_create_simple_f.
I'm compiling as follows:
gfortran -c simple_test.f90 -o simple_test.o -I<hdf5_include_path>
gfortran -o simple_test simple_test.o -L<hdf5_lib_path> -lhdf5_fortran -lhdf5hl_fortran
I've also tried setting max_array(irank) to -1, but that yields an entirely different error.
(The original issue was that H5S_UNLIMITED_F is a variable that is initialised by a call to H5open_f, referencing it before that initialization is not permitted.)
Are you sure that the call to H5S_create_simple_f is what fails? Your traceback indicates an error from the dataset portion of the library.
I would expect a failure from dataset creation, because for variable sized datasets you need to specify the chunk size. Create a property list using H5Pcreate_f, then set the chunk size using H5Pset_chunk_f, then provide that property list after the error argument in the call to H5Dcreate_f. Comment if that doesn't make sense and I'll dig out an example.

reading in large data set in Fortran

I am attempting read a large data file into Fortran it contains about 40960000 rows, I later convert it to a matrix so it would be 6400 * 6400. When I try my code using a much smaller data set it works fine. However, it tells me that there is a segmentation fault, when I use my larger dataset. I suspect that it is a memory allocation issue. Is there a way to allocate more memory or otherwise correct this problem.
program infectgrid
implicit none
integer :: i, individual, nedge,&
tempinfect_tim_err, dumnum_infalpha0, dumnum_infalpha1, alpha0counter, &
alpha1counter, obsrand, minvalshift
character (LEN = 50) :: parameterfilelabel, parameterfile, networkfilelabel, infectfilenamelabel, networkfile, infectfilename
!allocatable to allow for reading in of individuals and time periods
integer, dimension(:) , allocatable :: xcord, ycord, dummy3, recover_tim1, recover_tim2, &
recover_tim3, recover_tim4, recover_tim5, sampleadjshort, shortsamplecount, &
cov1dum, covlog, covvect1uni
character, dimension (:), allocatable :: rec
integer, dimension (:, :) , allocatable :: link
real, dimension(:) , allocatable :: alphavect
call random_seed
open(12, file = "filenamesinfection.txt", status = "old")
read(12, *) parameterfile, networkfile, infectfilename
close(12)
open(12, file = parameterfile, status = "old")
read(12, *) individualname, alpha0name, alpha1name
read(12, *) individual, alpha0, alpha1
nedge = individual*individual
allocate(rec(1:nedge))
allocate(xcord(1:nedge))
allocate(ycord(1:nedge))
allocate(dummy3(1:nedge))
allocate(sampleadjshort(1:nedge))
allocate(shortsamplecount(1:nedge))
allocate(covlog(1:nedge))
allocate(cov1dum(1:nedge))
allocate(link(1:individual, 1:individual))
link = 0
covlog = 0
print *, individual, alpha0, alpha1
print *, link(individual, individual)
print *, "test"
open(10, file = networkfile, status = "old")
print *, networkfile
print *, "test"
do i = 1, nedge
read ( 10, *) rec(i), xcord(i), ycord(i), dummy3(i), cov1dum(i), sampleadjshort(i), shortsamplecount(i)
if (dummy3(i) == 1) then
link(xcord(i), ycord(i)) = 1
end if
if (xcord(i) == ycord(i)) then
covlog(i) = 1
end if
end do
close(10)
covvect1uni = pack(cov1dum, covlog == 1)
print *, "xcord", xcord(nedge), "ycord", ycord(nedge)
print *, link(individual, individual)
print *, "test"
The file prints out the first and second "test" but does not print out the link statement nor the line starting with "xcord" and soon after gives me a segmentation fault i.e. Segmentation fault nohup ./swnetworkinfectrecoveralpha05covgeo2.out
as to compiler options, I think that I am using most of what is available: ifort -free -O2 -stand f03 -check bounds -traceback -warn all -fstack-protector -assume protect_parens -implicitnone -o swnetworkinfectrecoveralpha05covgeo2.out swnetworkinfectrecoveralpha05covgeo2.f90

HDF5 for data files written with fortran

The HDF5 data storage uses the C convention, i.e. if I am storing a matrix A(N,M,K) in a binary file, the fastest changing dimension of the stored data will have size N. Apparently when I use the Fortran wrapper of HDF5, HDF5 automatically transposes the matrix, to be consistent with C.
I have a data of size (256 by 128 by 256) stored in an unformatted binary file written by fortran. I am trying to convert it into h5 format by using a program given below. But the final output is giving me the dimensions of the stored matrix as (128,256,256). I have no idea what to do to make sure that the final hd5 file can be rightly visualized in the visualizing software (Paraview).
PROGRAM H5_RDWT
USE HDF5 ! This module contains all necessary modules
IMPLICIT NONE
CHARACTER(LEN=6), parameter :: out_file = "out.h5" ! File name
CHARACTER(LEN=6), parameter :: in_file = "in.dat" ! File name
CHARACTER(LEN=4), parameter :: dsetname = "vort"! Dataset name
CHARACTER(LEN=50) :: len
INTEGER(HID_T) :: in_file_id ! File identifier
INTEGER(HID_T) :: out_file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: dspace_id ! Dataspace identifier
INTEGER :: in_file_id = 23
INTEGER :: nx = 256, ny=128, nz=256
INTEGER(HSIZE_T), DIMENSION(3) :: dims ! Dataset dimensions
INTEGER :: rank = 3 ! Dataset rank
INTEGER :: error ! Error flag
INTEGER :: i, j, k, ii, jj, kk ! Indices
REAL, allocatable :: buff_r(:,:,:) ! buffer for reading from input file
dims(1) = nx
dims(2) = ny
dims(3) = nz
allocate(buff_r(nx,ny,nz))
! Read the input data.
open (in_file_id,FILE=in_file,form='unformatted',access='direct',recl=4*nx*ny*nz)
read (in_file_id,rec=1) buff_r
! Initialize FORTRAN interface of HDF5.
CALL h5open_f(error)
! Create a new file.
CALL h5fcreate_f (out_file, H5F_ACC_TRUNC_F, out_file_id, error)
! Create the dataspace.
CALL h5screate_simple_f(rank, dims, dspace_id, error)
! Create the dataset with default properties.
CALL h5dcreate_f(out_file_id, dsetname, H5T_NATIVE_REAL, dspace_id, &
dset_id, error)
! Write the dataset.
CALL h5dwrite_f(dset_id, H5T_NATIVE_REAL, buff_r, dims, error)
! End access to the dataset and release resources used by it.
CALL h5dclose_f(dset_id, error)
! Terminate access to the data space.
CALL h5sclose_f(dspace_id, error)
! Close the file.
CALL h5fclose_f(out_file_id, error)
! Close FORTRAN interface.
CALL h5close_f(error)
deallocate(buff_r)
END PROGRAM H5_RDWT
To illustrate what is happening, I am generating a sample data file using the following script:
program main
!-------- initialize variables -------------
character(8) :: fname
integer, parameter:: n = 32
real*8, dimension(n,n,2*n) :: re
integer i,j,k, recl
Inquire( iolength = recl ) re
!------ fill in the array with sample data ----
do k = 1, 2*n
do j = 1, n
do i = 1, n
re(i,j,k) = 1.0
end do
end do
end do
!------ write in data in a file -----------
write(fname, "(A)") "data.dat"
open (10, file=fname, form='unformatted', access='direct', recl=recl)
write(10,rec=1) re
close(10)
stop
end program main
I copy pasted the program by Ian Bush and changed the values of nx, ny and nz to 32, 32 and 64 respectively. I would expect the generated h5 file to have dimensions (32,32,64). But it is coming out to be (64,32,32). Here is what is happening in my machine:
[pradeep#laptop]$gfortran generate_data.f90
[pradeep#laptop]$./a.out
[pradeep#laptop]$ls -l data.dat
-rw-r--r-- 1 pradeep staff 524288 Mar 12 14:04 data.dat
[pradeep#laptop]$h5fc convert_to_h5.f90
[pradeep#laptop]$./a.out
[pradeep#laptop]$ls -l out.h5
-rw-r--r-- 1 pradeep staff 526432 Mar 12 14:05 out.h5
[pradeep#laptop]$h5dump -H out.h5
HDF5 "out.h5" {
GROUP "/" {
DATASET "data" {
DATATYPE H5T_IEEE_F64LE
DATASPACE SIMPLE { ( 64, 32, 32 ) / ( 64, 32, 32 ) }
}
}
}
Please confirm with me if you are seeing the same thing.
I have also run into trouble with viewing HDF5 files that I've written with a Fortran application. The basic issue is that Fortran and C store multidimensional arrays differently (Fortran is column-major, C is row-major), and since the Fortran HDF5 libraries are interfaces into the C HDF5 libraries, the Fortran wrapper transposes the dimensions before passing the data into the C code. Likewise, when a Fortran application reads an HDF5 file, the Fortran wrapper transposes the dimensions again.
So if you do all your writing and reading with Fortran applications, you shouldn't notice any discrepancies. If you write the file with a Fortran app and then read it with a C app (such as h5dump), the dimensions will appear transposed. That's not a bug, it's just how it works.
If you want to display the data correctly, either read the data with a Fortran application or use a C app and transpose the data first. (Or you could transpose the data before writing it in the first place.)
As already mentioned, this is all explained fairly well in section 7.3.2.5 of the documentation: http://www.hdfgroup.org/HDF5/doc/UG/UG_frame12Dataspaces.html
Long comment really rather than an answer ...
Can you clarify why you don't think it is working? Once I correct a couple of things in your code
1) in_file_id is declared twice with 2 different kinds
2) Recl for direct access files are not necessarily in terms of bytes - Inquire by output list is much more portable
I get the following which, having generated a dummy file with random data, seems to work:
ian#ian-pc:~/test/stack$ cat hdf5.f90
PROGRAM H5_RDWT
USE HDF5 ! This module contains all necessary modules
IMPLICIT NONE
CHARACTER(LEN=6), parameter :: out_file = "out.h5" ! File name
CHARACTER(LEN=6), parameter :: in_file = "in.dat" ! File name
CHARACTER(LEN=4), parameter :: dsetname = "vort"! Dataset name
CHARACTER(LEN=50) :: len
!!$ INTEGER(HID_T) :: in_file_id ! File identifier
INTEGER(HID_T) :: out_file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: dspace_id ! Dataspace identifier
INTEGER(HID_T) :: in_file_id = 23
INTEGER :: nx = 256, ny=128, nz=256
INTEGER(HSIZE_T), DIMENSION(3) :: dims ! Dataset dimensions
INTEGER :: rank = 3 ! Dataset rank
Integer :: recl
INTEGER :: error ! Error flag
INTEGER :: i, j, k, ii, jj, kk ! Indices
REAL, allocatable :: buff_r(:,:,:) ! buffer for reading from input file
dims(1) = nx
dims(2) = ny
dims(3) = nz
allocate(buff_r(nx,ny,nz))
Inquire( iolength = recl ) buff_r
! Read the input data.
open (in_file_id,FILE=in_file,form='unformatted',access='direct',recl=recl)
read (in_file_id,rec=1) buff_r
! Initialize FORTRAN interface of HDF5.
CALL h5open_f(error)
! Create a new file.
CALL h5fcreate_f (out_file, H5F_ACC_TRUNC_F, out_file_id, error)
! Create the dataspace.
CALL h5screate_simple_f(rank, dims, dspace_id, error)
! Create the dataset with default properties.
CALL h5dcreate_f(out_file_id, dsetname, H5T_NATIVE_REAL, dspace_id, &
dset_id, error)
! Write the dataset.
CALL h5dwrite_f(dset_id, H5T_NATIVE_REAL, buff_r, dims, error)
! End access to the dataset and release resources used by it.
CALL h5dclose_f(dset_id, error)
! Terminate access to the data space.
CALL h5sclose_f(dspace_id, error)
! Close the file.
CALL h5fclose_f(out_file_id, error)
! Close FORTRAN interface.
CALL h5close_f(error)
deallocate(buff_r)
END PROGRAM H5_RDWT
ian#ian-pc:~/test/stack$ h5fc hdf5.f90
ian#ian-pc:~/test/stack$ ./a.out
ian#ian-pc:~/test/stack$ ls -l out.h5
-rw-rw-r-- 1 ian ian 33556576 Mar 11 10:29 out.h5
ian#ian-pc:~/test/stack$ ncdump out.h5 | head
netcdf out {
dimensions:
phony_dim_0 = 256 ;
phony_dim_1 = 128 ;
variables:
float vort(phony_dim_0, phony_dim_1, phony_dim_0) ;
data:
vort =
0.9975595, 0.5668247, 0.9659153, 0.7479277, 0.3673909, 0.4806369,
ian#ian-pc:~/test/stack$
So why do you think there is a problem?
For safe reasons I would recommend you to disassemble matrices into vector form and store them as 1D datasets in HDF5 file. Then, while reading assemble them in the same manner. Use H5SSELECT_HYPERSLAB_F for writing/reading slices of your matrix.