Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Read two-dimensional array

cmc
New Contributor I
2,445 Views

Hi,

I want to read a two-dimensional array. The array could be quite big, so I will rely on using a Do loop such as:

do i = 1, n_rows
   do j = 1, n_columns
      read(unit = 1, fmt = *, iostat = io) array(i,j)
   end do
end do

What I discovered is that no matter how I configure the do loops, it insists on reading column no. 1 first. And when it reach the maximum row number (n_rows), io becomes -1 (end of file statement) and the rest of values becomes 0. It is probably some dumb thing I'm doing wrong, but can anyone please help?

Cheers,
Carl

0 Kudos
1 Solution
David_Billinghurst
New Contributor III
2,445 Views

Carl,

Your data file has the data for each row on a single line.  By default each READ statement in Fortran starts a new record = new line.  Here are a couple of ways to read your data file.

Read a line at a time, like so. 

  do i = 1, n_rows
     read(1,*) (array(i,j), j=1, n_columns)
  end do

Read all the data in one go.  This method will just read the next n_rows*n_column numbers in the file, then discard the rest of a partially read line.

  read(1,*) ((array(i,j), j=1,n_columns), i=1,n_rows)

Here are the full programs

program io_2
  implicit none
  integer n_rows, n_columns, i, j
  real(kind=8), allocatable :: array(:,:)
  
  open(unit=1,file='file.dat',status='old')
  read(1,*) n_rows, n_columns
  allocate(array(n_rows, n_columns))
  do i = 1, n_rows
     read(1,*) (array(i,j), j=1, n_columns)
  end do

  write(*,*) array(1,1), array(1,n_columns)
  write(*,*) array(n_rows,1), array(n_rows,n_columns)

end program
program io_3
  implicit none
  integer n_rows, n_columns, i, j
  real(kind=8), allocatable :: array(:,:)
  
  open(unit=1,file='file.dat',status='old')
  read(1,*) n_rows, n_columns
  allocate(array(n_rows, n_columns))
  read(1,*) ((array(i,j), j=1,n_columns), i=1,n_rows)

  write(*,*) array(1,1), array(1,n_columns)
  write(*,*) array(n_rows,1), array(n_rows,n_columns)

end program

They generate identical output

$ ./io_2
   1.0000000000000000        42.740000000000002
   2016.0000000000000        28.890000000000001

 

View solution in original post

0 Kudos
4 Replies
David_Billinghurst
New Contributor III
2,445 Views

Carl,

Can you provide a self contained program and sample data file.  As is we can't see: the types of the variables; how the file is opened; how the data is arranged in the input.

As written, each READ statement consumes one record (one line).  It will read the first number on the line and discard the rest (if any).  Your code works for me with the appropriate input file.  If your data is in a different format your code will need to be modified to suit.

program io_1
  implicit none
  integer n_rows, n_columns, i, j, io
  integer, allocatable :: array(:,:)
  
  open(unit=1,file='io_1.dat',status='old')
  read(1,*) n_rows, n_columns
  allocate(array(n_rows, n_columns))
  do i = 1, n_rows
    do j = 1, n_columns
     read(unit=1,fmt=*,iostat=io) array(i,j)
    end do
  end do

  do i = 1, n_rows
    write(*,*) array(i,:)
  end do

end program

with data file 

2 2
1
2
3
4

generates

$ ./io_1
           1           2
           3           4

 

0 Kudos
cmc
New Contributor I
2,445 Views

Hi David,

I tried your approach, which is basically the same thing that I was already doing, and it did not work.

subroutine file(file_name)
  implicit none
  character(len=*), intent(in)  :: file_name
  integer(2)                    :: n_rows, n_columns, i, j, io
  real(8), allocatable          :: array(:,:)

  open(unit = 1, file = file_name, status = 'old')
  read(1,*) n_rows, n_columns
  allocate(array(n_rows, n_columns))

  do i = 1, n_rows
    do j = 1, n_columns
     read(unit = 1, fmt = *, iostat = io) array(i,j)
    end do
  end do
end subroutine

I have attached the file I'm trying to read. Hopefully you or someone else can figure it out.

Thanks,
Carl

 

0 Kudos
David_Billinghurst
New Contributor III
2,446 Views

Carl,

Your data file has the data for each row on a single line.  By default each READ statement in Fortran starts a new record = new line.  Here are a couple of ways to read your data file.

Read a line at a time, like so. 

  do i = 1, n_rows
     read(1,*) (array(i,j), j=1, n_columns)
  end do

Read all the data in one go.  This method will just read the next n_rows*n_column numbers in the file, then discard the rest of a partially read line.

  read(1,*) ((array(i,j), j=1,n_columns), i=1,n_rows)

Here are the full programs

program io_2
  implicit none
  integer n_rows, n_columns, i, j
  real(kind=8), allocatable :: array(:,:)
  
  open(unit=1,file='file.dat',status='old')
  read(1,*) n_rows, n_columns
  allocate(array(n_rows, n_columns))
  do i = 1, n_rows
     read(1,*) (array(i,j), j=1, n_columns)
  end do

  write(*,*) array(1,1), array(1,n_columns)
  write(*,*) array(n_rows,1), array(n_rows,n_columns)

end program
program io_3
  implicit none
  integer n_rows, n_columns, i, j
  real(kind=8), allocatable :: array(:,:)
  
  open(unit=1,file='file.dat',status='old')
  read(1,*) n_rows, n_columns
  allocate(array(n_rows, n_columns))
  read(1,*) ((array(i,j), j=1,n_columns), i=1,n_rows)

  write(*,*) array(1,1), array(1,n_columns)
  write(*,*) array(n_rows,1), array(n_rows,n_columns)

end program

They generate identical output

$ ./io_2
   1.0000000000000000        42.740000000000002
   2016.0000000000000        28.890000000000001

 

0 Kudos
cmc
New Contributor I
2,445 Views

Thank you so much :) That worked perfectly!

\Carl

0 Kudos
Reply