Search code examples
multidimensional-arrayfortranbinaryfilesfile-read

Binary file data reading incorrectly in Fortran 90


I'm reading in a binary file written in a different program. The open & read statements seem to be successful, I had help in a previous post. However, the data read in does not match the file. I've initialized the 2D array but after reading in the file, the array does not hold the data but looks to be an uninitialized array. I've posted the code below for the read and the print out of the array. Any thoughts?

       allocate(dummy(imax,jmax))

       dummy = 0.0
       open(unit=io, file=trim(input), access='direct', iostat=ioer, &
            status='old', action='READ', recl=imax*jmax*4)

       if(ioer/=0) then
        print*, 'Cannot open file'
       else
        print*,'success opening file'
       end if

       j=0
       k=0
       read(unit=io,rec=1,iostat=ioer) dummy!(j,k)
       if(ioer/=0) then
         print*, 'Cannot open file'
       else
         print*,'success opening file'
       end if

       size: do j=1, imax
           do k=1, jmax
             if(dummy(j,k) > 0.) print*,'i-',j,'j-',k,'frp-',dummy(j,k)
           end do 
       end do size
       print*,'j-',j,'k-',k

Here is the original write:

  out_file = trim(output_dir)//'SEVIRI_FRP_.08deg_'//trim(season)//'.bin'

  print*, out_file
  print*, i_max,' i_max,',j_max,' j_max'

  open (io, file = out_file, access = 'direct', status = 'replace', recl = i_max*j_max*4)

  write(io, rec = 1) sev_frp
  write(io, rec = 2) count_sev_frp
  write(io, rec = 3) sum_sev_frp

This is what is a portion of what is printing out:

  i-         600 j-         213 frp-  4.1759680E-08
  i-         600 j-         220 frp-  8.8314310E-18
  i-         600 j-         221 frp-  2.7975964E-36
  i-         600 j-         246 frp-   461506.1    
  i-         600 j-         254 frp-   19.79016    
  i-         600 j-         255 frp-  2.0032716E-22
  i-         600 j-         260 frp-  1.0871451E+24
  j-         601 k-         401

This is the same portion of what it should be:

  i-         600 j-         213 frp-   13.6999998    
  i-         600 j-         218 frp-   63.2000008    
  i-         600 j-         220 frp-   29.1416683    
  i-         600 j-         221 frp-   31.8032303    
  i-         600 j-         229 frp-   39.5000000    
  i-         600 j-         232 frp-   55.4714279    
  i-         600 j-         246 frp-   54.2200012    
  i-         600 j-         254 frp-   13.1636362    
  i-         600 j-         255 frp-   10.9028578    
  i-         600 j-         258 frp-   24.6888885    
  i-         600 j-         259 frp-   13.5619040    
  i-         600 j-         260 frp-   11.4000006    
  n-         601 m-         401

The declaration/allocation statements:

 real, allocatable, dimension(:,:) :: dummy

 allocate(dummy(imax,jmax))

 dummy = 0.0

These are the same in both the write/read & imax is 600 jmax is 400


Solution

  • As M.S.B suggests in a comment, this is an endianess issue between the machine that is writing the file and the machine that is reading.

    To see this, look at the differences in these values at the same array index:

    i-         600 j-         213 frp-  4.1759680E-08
    i-         600 j-         213 frp-   13.6999998 
    

    If the first value 4.1759680E-08 is little endian, its hex representation is 33 33 5B 41. When this exact representation is read on a big endian machine, it reads as 13.6999998. If the first value is big endian and second little endian, the problem is the same except the hex representation is 41 5B 33 33 instead. To fix the problem you need to determine the endianess of the machine that writes the file.

    Both gfortran and Intel Fortran (and possible others) provide extensions that allow you to specify the byte ordering of an unformatted input file. If the machine that wrote the file is big endian, add this to your open statement when reading:

    convert='big_endian'
    

    If the machine that wrote the file is little endian, add this to the open statement when reading:

    convert='little_endian'
    

    You indicated you are writing on a little endian machine so in order to read this on the big endian machine, open it as:

    open(unit=io, file=trim(input), access='direct', iostat=ioer, &
            status='old', action='READ', recl=imax*jmax*4, &
            convert='little_endian')
    

    and your read should work properly.