0
votes

Let's say I have a 5 x 5 array of floating points in a file array.txt:

1.0 1.1 0.0 0.0 0.0
1.2 1.3 1.4 0.0 0.0
0.0 1.5 1.6 1.7 0.0
0.0 0.0 1.8 1.9 1.0
0.0 0.0 0.0 1.1 1.2

I know this is probably a strange thing to do, but I'm just trying to learn the read statements better: I want to create two 3x3 arrays in Fortran, i.e. real, dimension(3,3) :: array1, array2 and try reading in the first 9 values by row into array1 and the following 9 values into array2. That is, I would like arrays to have the form

array1 = 1.0 1.1 0.0
         0.0 0.0 1.2
         1.3 1.4 0.0

array2 = 0.0 0.0 1.5
         1.6 1.7 0.0
         0.0 0.0 1.8

Next I want to try to do the same by columns:

array1 = 1.0 1.2 0.0
         0.0 0.0 1.1
         1.3 1.5 0.0

array2 = 0.0 0.0 1.4
         1.6 1.8 0.0
         0.0 0.0 1.7

My "closest" attempt for row-wise:

program scratch
  implicit none

  real, dimension(3,3) :: array1, array2
  integer :: i

  open(12, file="array.txt")

 !read in values                                                 
  do i = 1,3
        read(12,'(3F4.1)', advance="no") array1(i,:)
  end do

end program scratch

My questions:

A. How to advance to next record when at the end?

B. How to do the same for reading in column-wise?

C. Why is '(3F4.1)' needed, as opposed to '(3F3.1)'?

2

2 Answers

0
votes

Reading by line is easy :

READ(12,*) ((array1(i,j),j=1,3),i=1,3),((array2(i,j),j=1,3),i=1,3)

"advance='no'" is necessary only if you use 2 read statements instead of 1 (and only on the first READ). But this works only with explicit format ...

Reading a file by column is not so obvious, especially because reading a file is usually an expensive task. I suggest you read the file in a larger table and then you distribute the values into your two arrays. For instance :

real :: table(5,5)
integer :: i,j,ii,jj,k
..
read(12,*) ((table(i,j),j=1,5),i=1,5)
k=0
do j=1,3
   do i=1,3
      k=k+1
      jj=(k-1)/5+1
      ii=k-(jj-1)*5
      array1(i,j)=table(ii,jj)
   enddo
enddo
do j=1,3
   do i=1,3
      k=k+1
      jj=(k-1)/5+1
      ii=k-(jj-1)*5
      array2(i,j)=table(ii,jj)
   enddo
enddo

(3F4.1) is better than (3F3.1) because each number occupies 4 bytes in fact (3 for the digits and 1 for the space between numbers). But as you see, I have used * which avoids to think about such detail.

0
votes

because of the requirement to "assign by columns" i would advise reading the whole works into a 5x5 array:

 real tmp(5,5)
 read(unit,*)tmp

(note no format specification required)

Then do the assignments you need using array operations.

for this small array, the simplest thing to do seems to be:

real tmp(5,5),flat(25),array1(3,3),array2(3,3)
read(unit,*)tmp
flat=reshape(tmp,shape(flat))
array1=reshape(flat(:9),shape(array1))
array2=reshape(flat(10:18),shape(array2))

then the transposed version is simply:

flat=reshape(transpose(tmp),shape(flat))
array1=reshape(flat(:9),shape(array1))
array2=reshape(flat(10:18),shape(array2))

If it was a really big array I'd think of a way that avoided making an extra copy of the data.

Note you can wrap each of those assignments in transpose if needed depending on how you really want the data represented, eg.

     array1=transpose(reshape(flat(:9),shape(array1)))