Alessandro Peca
Alessandro Peca

Reputation: 923

Why are incorrect values printed outside of the Fortran loop?

I read 3 arrays (X_halo, Y_halo, Z_halo) from an input file. If I write the values loaded within the DO cycle I can print them correctly, but out of the loop no. And if I try to print the values of X_halo(i) incorrect values are printed.

How can I do it?

program columns
  IMPLICIT NONE

  INTEGER,SAVE :: lun
  INTEGER, PARAMETER :: ARRAYLEN=1044  
  CHARACTER(120) :: filename
  DOUBLE PRECISION, DIMENSION (ARRAYLEN) :: X_halo, Y_halo, Z_halo
  INTEGER :: i, istat

  lun=1
  filename = 'xyz.dat'

  OPEN (UNIT=10, FILE=filename, STATUS='old', ACTION='read', IOSTAT=istat)

    DO i=1,ARRAYLEN
     READ (10, *, iostat=istat) X_halo(i), Y_halo(i), Z_halo(i)
!    print*, 'id:', i, 'X= ', X_halo(i), 'Y= ', Y_halo(i), 'Z= ', Z_halo(i)
    END DO

  DO i=1,ARRAYLEN
  print*, X_halo(i)
  END DO

  CLOSE (10)

end program columns

For example the first lines of the first column of the file xyz.dat are:

 281.0788
 189.8768
 669.2193
 720.7653

But the code returns:

6.9532597489392050E-310
2.2310395176993305E-314
6.9532121310250636E-310
6.9532238136146167E-310

Second problem: If you want to have ARRAYLEN as free variable to use the program for all the files in put, how can I do it?

Upvotes: 1

Views: 526

Answers (1)

Steve
Steve

Reputation: 1587

Not sure why you're receiving an error due to istat or why your values aren't printing correctly - they're fine for me, will need a minimal complete verifiable example with error messages to get feedback on that.

With regards to reading fewer lines than ARRAYLEN, as discussed in the comments in your previous question and outlined in the comments above, you want to check if istat < 0 then break from the loop, with

IF ( istat < 0 ) THEN
  EXIT
END IF

One way of having X_halo to be the length of lines read (I doubt this is the best way) is to save the entries to temporary vectors, check how many entries were read in with i, ALLOCATE your halo vectors, then copy from the temporary vectors.

PROGRAM columns
  IMPLICIT NONE

  INTEGER,SAVE :: lun
  INTEGER, PARAMETER :: ARRAYLEN=1044
  CHARACTER(120) :: filename
  ! Read data into tempory arrays of length up to ARRAYLEN
  DOUBLE PRECISION, DIMENSION (ARRAYLEN) :: X_tmp, Y_tmp, Z_tmp
  ! And these will be where we put the data when we know how many lines
  DOUBLE PRECISION, ALLOCATABLE, DIMENSION (:) :: X_halo, Y_halo, Z_halo
  INTEGER :: i, istat

  lun = 1
  filename = 'xyz.dat'

  OPEN (UNIT=10, FILE=filename, STATUS='old', ACTION='read', IOSTAT=istat)

  DO i=1,ARRAYLEN
    ! Read data in to the temporary vectors
    READ (10, *, IOSTAT=istat) X_tmp(i), Y_tmp(i), Z_tmp(i)
    IF ( istat < 0 ) THEN
      ! Then last READ failed with an EOF
      EXIT
    END IF
  END DO

  ! Last READ returned EOF, so i-1 lines were read
  i = i-1

  ALLOCATE(X_halo(i))
  ALLOCATE(Y_halo(i))
  ALLOCATE(Z_halo(i))
  ! Copy i entries in to the allocated vectors
  X_halo = X_tmp(1:i)
  Y_halo = Y_tmp(1:i)
  Z_halo = Z_tmp(1:i)

  PRINT*, X_halo

  CLOSE (10)

END PROGRAM columns

Running this with file xyz.dat as

281.0788 1.3 111
189.8768 2.3 222
669.2193 3.3 333
720.7653 4.3 444

returns

   281.07880000000000        189.87680000000000        669.21929999999998        720.76530000000002 

Another approach would be to READ through the file not saving the output just to get the number of lines i, then ALLOCATE your vectors, REWIND and READ in each line. See How to read number of lines in Fortran 90 from a text file?

Upvotes: 2

Related Questions