Silverfrost Forums

Welcome to our forums

Binary file in FORTRAN

4 Aug 2011 12:13 #8727

Are the binary files of software A readable?

Yes they are. You must know the OPEN and the WRITE statements that generated them and probably the compiler that generated the fortran code. It is then simply a matter of providing the OPEN and READ statements that suit what was written. You need to provide the READ statement that suits the WRITE. This should always be documented for other users. I would expect there should be a defined data structure to be used.

Binary and text files are very similar. You just need the appropriate OPEN, READ and WRITE to use them. Binary files are preferred as they retain maximum precision of the numbers being stored. They are more typically used. Text files can be simpler, as you can more easily look at the file (with NOTEPAD) and see what is in the file. I prefer text files, especially if I want to review what information is being transferred, or there will be a time lag between usage.

To open a binary sequential file use: OPEN ( UNIT=11, FILE='temporary_file', STATUS='UNKNOWN', & ACCESS='SEQUENTIAL', FORM='UNFORMATTED', & ACTION='READWRITE', IOSTAT=iostat) To open a sequential text file use: OPEN ( UNIT=11, FILE='temporary_file', STATUS='UNKNOWN', & ACCESS='SEQUENTIAL', FORM='FORMATTED', & ACTION='READWRITE', IOSTAT=iostat) To open a binary direct access file use: OPEN ( UNIT=11, FILE='temporary_file', STATUS='UNKNOWN', & ACCESS='DIRECT', FORM='UNFORMATTED', RECL=1000, & ACTION='READWRITE', IOSTAT=iostat)

The only problem is that files opened as sequential unformatted files also store extra information to identify the amount of information written by each WRITE statement, and this extra information differs between compilers. Direct access unformatted files do not have this problem. All comments about this problem assume that different fortran compilers have been used for program A and program B. Depending on which program you have access to ( A or B ) determines the approach you should take. If I was to approach this problem, I would use ACCESS='TRANSPARENT' and read or write the header and footer in the way the other program expected.

The style of your questions implies you are new to using binary files, although you have implied you have/had access to program A and have written the binary files. The proof of your work is how program B reads what you have written. If you don't have access to program B, you may need to use an approach Ian has recommended and convert the files to a 'record' structure that program B's compiler expects. Test it out !

John

4 Aug 2011 12:29 #8729

In addition to above;

Let me start with something simple;

(1) Let us say I have a 'MY FE PROGRAM'

I have;

subroutine ReadMyFEProgramData

call GetNodes !!I get number of nodes call GetNumberOFElements !!I get number of elements

end

(2) Now, I want to begin writing my binary file which ANOTHER (say program ''A'') program can read. I know that; the variables for number of nodes and number of elements in program 'A' are named as NNODES And NELMENTS respectively.

Number of words of NNODES And NELMENTS is 1 (each) and disk address is 10 and 11 respectively.

The word size id 4 bytes for single precision and 8 bytes for double precision.

The databases (i.e.binary file) are written as word addressable fixed length binary files. The actual length depends on the amount of data saved, but will always be a multiple of 512 words (4 or 8 bytes each). Since it is likely that the database cannot be contained in a single file of length, FEMLEN,the data will spread over several files known as a family of files. Having a set of files enables them to be handled more easily than a single very large file. The root name for a family is the name of the first file member.

With this information, can anyone please guide me how to write NNODES and NELMNTS to a binary file?

After writing, PROGRAM A understands the binary file I wrote and can do what it wants with the data in binary file.

4 Aug 2011 2:47 #8730

I've recommended you read the fortran documentation about Input/Output, as your grasp of the subject appears poor. A simple example of what you may need : ( you could improve much of it depending on other requirements) subroutine write_FE_info (num_nodes, XYZ, num_elem, elem_type, elem_connect) ! ! Routine to dump Model to binary file ! integer4 num_nodes, num_elem, elem_type(), elem_connect(10,) real8 XYZ(3,) ! character file_name40 integer4 iostat, i, j, node_count(6), nn data node_count / 2, 2, 4, 4, 8, 4 / ! file_name = 'transfer_file.bin' open (unit=21, file=file_name, form='UNFORMATTED', iostat=iostat) write (,*) ' File ',trim(file_name),' Opened for writing: iostat=', iostat ! write (21) num_nodes write (21) ((xyz(i,j),i=1,3),j=1,num_nodes) ! write (21) num_elem write (21) (elem_type(i),i=1,num_elem) do j = 1,num_elem if (elem_type(j) < 1) cycle nn = node_count(elem_type(j)) write (21) j, (elem_connect(i,j),i=1,nn) end do ! close (unit=21) ! end subroutine write_FE_info

      subroutine read_FE_info (num_nodes, XYZ, num_elem, elem_type, elem_connect)
!
!  Routine to read Model from binary file
!
      integer*4 num_nodes, num_elem, elem_type(*), elem_connect(10,*)
      real*8    XYZ(3,*)
!
      character file_name*40
      integer*4 iostat, i, j, k, node_count(6), nn
      data node_count / 2, 2, 4, 4, 8, 4 /
!
      file_name = 'transfer_file.bin'
      open (unit=21, file=file_name, form='UNFORMATTED', status='OLD', iostat=iostat)
        write (*,*) ' File ',trim(file_name),' Opened for reading: iostat=', iostat
!
      read (21, iostat=iostat) num_nodes
        write (*,*) num_nodes, ' nodes in model', iostat
      read (21, iostat=iostat) ((xyz(i,j),i=1,3),j=1,num_nodes)
        write (*,*) ' nodes read', iostat
!
      read (21, iostat=iostat) num_elem
        write (*,*) num_elem, ' elements in model', iostat
      read (21, iostat=iostat) (elem_type(i),i=1,num_elem)
        write (*,*) ' element type read', iostat
!
      do j = 1,num_elem
         elem_connect(:,j) = 0
         if (elem_type(j) < 1) cycle
         nn = node_count(elem_type(j))
         read (21, iostat=iostat) k, (elem_connect(i,j),i=1,nn)
         if (iostat /= 0 .or. j/=k) write (*,*) 'ERROR reading element',j,k
      end do
       write (*,*) 'elements read'
!
      close (unit=21)
!
      end subroutine read_FE_info

compiles but not tested !!

4 Aug 2011 5:49 #8731

If you want to cope with different record length formats, I've modified the program to demonstrate how you might control the record length header, using ACCESS='TRANSPARENT'. other compilers might use FORM='BINARY'

      subroutine write_FE_info (num_nodes, XYZ, num_elem, elem_type, elem_connect)
!
!  Routine to dump Model to binary file
!
      integer*4 num_nodes, num_elem, elem_type(*), elem_connect(10,*)
      real*8    XYZ(3,*)
!
      character file_name*40
      integer*4 iostat, j, node_count(6), nn, elist(0:10)
      data node_count / 2, 2, 4, 4, 8, 4 /
!
      file_name = 'transfer_file.bin'
      open (unit=21, file=file_name, form='UNFORMATTED', access='TRANSPARENT', iostat=iostat)
      write (*,*) ' File ',trim(file_name),' Opened for writing: iostat=', iostat
!
      call write_record (num_nodes, 4)
      call write_record (xyz, 3*num_nodes*8)
!
      call write_record (num_elem, 4)
      call write_record (elem_type, num_elem*4)
      do j = 1,num_elem
         if (elem_type(j) < 1) cycle
         nn = node_count(elem_type(j))
         elist(0) = j
         elist(1:10) = elem_connect(:,j)
         call write_record (elist, (nn+1)*4)
      end do
!
      close (unit=21)
!
      end subroutine write_FE_info

      subroutine read_FE_info (num_nodes, XYZ, num_elem, elem_type, elem_connect)
!
!  Routine to read Model from binary file
!
      integer*4 num_nodes, num_elem, elem_type(*), elem_connect(10,*)
      real*8    XYZ(3,*)
!
      character file_name*40
      integer*4 iostat, j, node_count(6), nn, elist(0:10)
      data node_count / 2, 2, 4, 4, 8, 4 /
!
      file_name = 'transfer_file.bin'
      open (unit=21, file=file_name, form='UNFORMATTED', access='TRANSPARENT', status='OLD', iostat=iostat)
      write (*,*) ' File ',trim(file_name),' Opened for reading: iostat=', iostat
!
      call read_record (num_nodes, iostat)
       write (*,*) num_nodes, ' nodes in model', iostat
      call read_record (xyz, iostat)
       write (*,*) ' nodes read', iostat
!
      call read_record (num_elem, iostat)
       write (*,*) num_elem, ' elements in model', iostat
      call read_record (elem_type, iostat)
       write (*,*) ' element type read', iostat
!
      do j = 1,num_elem
         elem_connect(:,j) = 0
         if (elem_type(j) < 1 .or. elem_type(j) > 6) cycle
         nn = node_count(elem_type(j))
         call read_record (elist, iostat)
         if (iostat < 0 .or. elist(0)/=j) write (*,*) 'ERROR reading element',j,elist(0)
         elem_connect(1:nn,j) = elist(1:nn)
      end do
!
      close (unit=21)
!
      end subroutine read_FE_info

      subroutine write_record (list, bytes)       ! write (21) num_nodes
!
!  Write record, assuming access=transparent
!
      integer*4 list(8), bytes, n
      n = bytes/4
      write (21) bytes
      write (21) list(1:n)
      write (21) bytes
      end
4 Aug 2011 5:51 #8732

the file I/O routines subroutine write_record (list, bytes) ! write (21) num_nodes ! ! Write record, assuming access=transparent ! integer*4 list(8), bytes, n n = bytes/4 write (21) bytes write (21) list(1:n) write (21) bytes end

      subroutine read_record (list, bytes)       ! read (21, iostat=iostat) num_nodes
!
!  Read record, assuming access=transparent
!
      integer*4 list(8), bytes, iostat,n,m
!
      read (21, iostat=iostat) bytes
       if (iostat/=0) then
          write (*,*) 'error reading header'
          goto 99
       end if
       if (bytes < 4 .or. mod(bytes,4)/=0) then
          write (*,*) 'invalid header for record'
          goto 99
       end if
!
      n = bytes/4
      read (21, iostat=iostat) list(1:n)
       if (iostat/=0) then
          write (*,*) 'error reading record'
          goto 99
       end if
!
      read (21, iostat=iostat) m
       if (iostat/=0) then
          write (*,*) 'error reading trailer'
          goto 99
       end if
       if (m/=bytes) then
          write (*,*)'inconsistent header and trailer for record'
          goto 99
       end if
!
      return
!
   99 bytes = -1
      end

Again, compiled but not tested !

Please login to reply.