Browning, Robert S IV ERDC-RDE-GSL-MS CIV
2018-10-12 20:10:11 UTC
I am needing to read in a text file that contains numerical data separated by keywords. Because of the keywords, I need to read each line in as text first and test if itâs a keyword, and then call the appropriate subroutine based on the keyword value. Within the subroutines I also need to read each line as text first so I can stop the subroutine when the next keyword is found.
Â
The numerical data can be in either fixed format or comma-separated-value (CSV) format. In the CSV data, a zero could be represented by a pair of commas with no number between them.
Â
The issue I have encountered is that the read statement appears to behave differently when it is reading from a character string than when it is reading directly from the input file. If I were able to read directly from the input file, then a simple formatted read statement does everything I need. But if I am reading from a string, then things get a bit more complicated.
Â
I have constructed an example program that demonstrates the inconsistencies. I have also run this program using Intelâs ifort compiler and it works like I expected, which makes me think that this is a bug in gfortran.Â
Â
I have copied the text of my code (read_csv.f90), an input file (input.txt), and my results from execution (results.txt) to the bottom of this email.
Â
My code consists of three test cases:
Â
Case 1: Reads values from the input file directly into the assigned variables. This works as I expected and is the behavior desired. However, in my actual program I canât read directly from the input file because I need to first check for keywords.
Â
Case 2: Reads a line into a character string variable, and then attempts to read from the string into the numerical variables in the same fashion as Case 1. This approach completely fails for all CSV data.
Â
Case 3: Same as Case 2 but this approach explicitly calls a list-directed read command on the string if iostat /= 0. However, this still produces different results than Case 1. Here, instead of missing values being read in as zero, they are completely skipped and the initial value of the variable is unchanged. I can see value in both options, but it seems like the read statement should do the same thing regardless of where itâs reading from.
Â
Here is the content contained in the attached files:
Â
!main program => read_csv.f90Â
program read_csv
implicit none
integer, parameter :: dbl = selected_real_kind(p=14, r=99)
integer :: iost=0
integer :: I1, I2, I3
real(dbl) :: R1, R2, R3
character(80) :: text
character(90) :: line="------------------------------------------------------------------------------------------"
Â
!Character formats
1Â format (A)
2Â format (/A/)
3Â format (A/)
4Â format (/A)
!Combined format
10 format (I8,3ES16.8,2I8)
Â
open (unit=1, status="old", file="input.txt", action="read")
Â
print 4, line
print 3, "CASE 1"
print 3, "Read numbers from file into int/real variables:"
print 1, "Results:"
print 1, "Â Â Â Â Â I1Â Â Â Â Â Â Â Â Â Â Â Â Â R1Â Â Â Â Â Â Â Â Â Â Â Â Â R2Â Â Â Â Â Â Â Â Â Â Â Â Â R3Â Â Â Â Â I2Â Â Â Â Â I3"
read_loop_1: do
 I1=-99;      I2=-99;      I3=-99
 R1=-99._DBL; R2=-99._DBL; R3=-99._DBL
 read(1,10,iostat=iost) I1, R1, R2, R3, I2, I3
 if ( iost /= 0 ) then
   if ( iost < 0 ) then
     print 4, "End Of File Reached"
     print 3, line
   else if ( iost > 0 ) then
     print *, "ERROR reading in CASE 1: iost = ", iost
   end if
   exit read_loop_1
 else
   print 10, I1, R1, R2, R3, I2, I3
 end if
end do read_loop_1
Â
rewind (1)
Â
print 4, line
print 3, "CASE 2"
print 3, "Read numbers from file into string and then read from string into int/real variables:"
print 1, "Results:"
print 1, "Â Â Â Â Â I1Â Â Â Â Â Â Â Â Â Â Â Â Â R1Â Â Â Â Â Â Â Â Â Â Â Â Â R2Â Â Â Â Â Â Â Â Â Â Â Â Â R3Â Â Â Â Â I2Â Â Â Â Â I3"
read_loop_2: do
 I1=-99;      I2=-99;      I3=-99
 R1=-99._DBL; R2=-99._DBL; R3=-99._DBL
 read(1,1,iostat=iost) text
 if ( iost /= 0 ) then
   if ( iost < 0 ) then
     print 4, "End Of File Reached"
     print 3, line
   else if ( iost > 0 ) then
     print *, "ERROR reading in CASE 2: iost = ", iost
   end if
   exit read_loop_2
 else
   read(text,10,iostat=iost) I1, R1, R2, R3, I2, I3
   print 10, I1, R1, R2, R3, I2, I3
 end if
end do read_loop_2
Â
rewind (1)
Â
print 4, line
print 3, "CASE 3"
print 3, "Read numbers from file into string and then read from string into int/real variables:"
print 3, "Add condition that if formatted read fails, then do list-directed read using *"
print 1, "Results:"
print 1, "Â Â Â Â Â I1Â Â Â Â Â Â Â Â Â Â Â Â Â R1Â Â Â Â Â Â Â Â Â Â Â Â Â R2Â Â Â Â Â Â Â Â Â Â Â Â Â R3Â Â Â Â Â I2Â Â Â Â Â I3"
read_loop_3: do
 I1=-99;      I2=-99;      I3=-99
 R1=-99._DBL; R2=-99._DBL; R3=-99._DBL
 read(1,1,iostat=iost) text
 if ( iost /= 0 ) then
   if ( iost < 0 ) then
     print 4, "End Of File Reached"
     print 3, line
   else if ( iost > 0 ) then
     print *, "ERROR reading in CASE 3: iost = ", iost
   end if
   exit read_loop_3
 else
   read(text,10,iostat=iost) I1, R1, R2, R3, I2, I3
   if ( iost /= 0 ) then
     read(text,*,iostat=iost) I1, R1, R2, R3, I2, I3
   end if
   print 10, I1, R1, R2, R3, I2, I3
 end if
end do read_loop_3
Â
print 2, "NORMAL TERMINATION"
Â
close (1)
end program read_csv
Â
!input data in input.txt
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00                 3.00000000E+00              7
         1.00000000E+00                 3.00000000E+00
101,1.,2.,3.,7,7
102,1.,,3.,,7
,1.,,3.,,
Â
!results using gfortran
browning$ gfortran read_csv.f90
browning$ ./a.out
Â
------------------------------------------------------------------------------------------
CASE 1
Â
Read numbers from file into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 2
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    -99 -9.90000000E+01 -9.90000000E+01 -9.90000000E+01    -99    -99
    -99 -9.90000000E+01 -9.90000000E+01 -9.90000000E+01    -99    -99
    -99 -9.90000000E+01 -9.90000000E+01 -9.90000000E+01    -99    -99
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 3
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Add condition that if formatted read fails, then do list-directed read using *
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 -9.90000000E+01 3.00000000E+00    -99      7
    -99 1.00000000E+00 -9.90000000E+01 3.00000000E+00    -99    -99
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
NORMAL TERMINATION
Â
!results using ifort
browning$ ifort read_csv.f90
browning$ ./a.out
Â
------------------------------------------------------------------------------------------
CASE 1
Â
Read numbers from file into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 2
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 3
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Add condition that if formatted read fails, then do list-directed read using *
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
NORMAL TERMINATION
Â
Â
Â
Â
-Bob
Â
___________________________________________________
Robert S. Browning IV
Research Structural Engineer
Structural Mechanics Branch
Geotechnical and Structures Laboratory
U.S. Army Engineer Research and Development Center
3909 Halls Ferry Road, Vicksburg, MSÂ 39180-6199
ATTN: CEERD-GSM, BLDG 5008
Â
Office:Â 601-634-5228
iPhone:Â 601-630-7276
Fax: Â 601-634-2309 (email preferred)
Email:Â Â mailto:***@usace.army.mil
Â
The numerical data can be in either fixed format or comma-separated-value (CSV) format. In the CSV data, a zero could be represented by a pair of commas with no number between them.
Â
The issue I have encountered is that the read statement appears to behave differently when it is reading from a character string than when it is reading directly from the input file. If I were able to read directly from the input file, then a simple formatted read statement does everything I need. But if I am reading from a string, then things get a bit more complicated.
Â
I have constructed an example program that demonstrates the inconsistencies. I have also run this program using Intelâs ifort compiler and it works like I expected, which makes me think that this is a bug in gfortran.Â
Â
I have copied the text of my code (read_csv.f90), an input file (input.txt), and my results from execution (results.txt) to the bottom of this email.
Â
My code consists of three test cases:
Â
Case 1: Reads values from the input file directly into the assigned variables. This works as I expected and is the behavior desired. However, in my actual program I canât read directly from the input file because I need to first check for keywords.
Â
Case 2: Reads a line into a character string variable, and then attempts to read from the string into the numerical variables in the same fashion as Case 1. This approach completely fails for all CSV data.
Â
Case 3: Same as Case 2 but this approach explicitly calls a list-directed read command on the string if iostat /= 0. However, this still produces different results than Case 1. Here, instead of missing values being read in as zero, they are completely skipped and the initial value of the variable is unchanged. I can see value in both options, but it seems like the read statement should do the same thing regardless of where itâs reading from.
Â
Here is the content contained in the attached files:
Â
!main program => read_csv.f90Â
program read_csv
implicit none
integer, parameter :: dbl = selected_real_kind(p=14, r=99)
integer :: iost=0
integer :: I1, I2, I3
real(dbl) :: R1, R2, R3
character(80) :: text
character(90) :: line="------------------------------------------------------------------------------------------"
Â
!Character formats
1Â format (A)
2Â format (/A/)
3Â format (A/)
4Â format (/A)
!Combined format
10 format (I8,3ES16.8,2I8)
Â
open (unit=1, status="old", file="input.txt", action="read")
Â
print 4, line
print 3, "CASE 1"
print 3, "Read numbers from file into int/real variables:"
print 1, "Results:"
print 1, "Â Â Â Â Â I1Â Â Â Â Â Â Â Â Â Â Â Â Â R1Â Â Â Â Â Â Â Â Â Â Â Â Â R2Â Â Â Â Â Â Â Â Â Â Â Â Â R3Â Â Â Â Â I2Â Â Â Â Â I3"
read_loop_1: do
 I1=-99;      I2=-99;      I3=-99
 R1=-99._DBL; R2=-99._DBL; R3=-99._DBL
 read(1,10,iostat=iost) I1, R1, R2, R3, I2, I3
 if ( iost /= 0 ) then
   if ( iost < 0 ) then
     print 4, "End Of File Reached"
     print 3, line
   else if ( iost > 0 ) then
     print *, "ERROR reading in CASE 1: iost = ", iost
   end if
   exit read_loop_1
 else
   print 10, I1, R1, R2, R3, I2, I3
 end if
end do read_loop_1
Â
rewind (1)
Â
print 4, line
print 3, "CASE 2"
print 3, "Read numbers from file into string and then read from string into int/real variables:"
print 1, "Results:"
print 1, "Â Â Â Â Â I1Â Â Â Â Â Â Â Â Â Â Â Â Â R1Â Â Â Â Â Â Â Â Â Â Â Â Â R2Â Â Â Â Â Â Â Â Â Â Â Â Â R3Â Â Â Â Â I2Â Â Â Â Â I3"
read_loop_2: do
 I1=-99;      I2=-99;      I3=-99
 R1=-99._DBL; R2=-99._DBL; R3=-99._DBL
 read(1,1,iostat=iost) text
 if ( iost /= 0 ) then
   if ( iost < 0 ) then
     print 4, "End Of File Reached"
     print 3, line
   else if ( iost > 0 ) then
     print *, "ERROR reading in CASE 2: iost = ", iost
   end if
   exit read_loop_2
 else
   read(text,10,iostat=iost) I1, R1, R2, R3, I2, I3
   print 10, I1, R1, R2, R3, I2, I3
 end if
end do read_loop_2
Â
rewind (1)
Â
print 4, line
print 3, "CASE 3"
print 3, "Read numbers from file into string and then read from string into int/real variables:"
print 3, "Add condition that if formatted read fails, then do list-directed read using *"
print 1, "Results:"
print 1, "Â Â Â Â Â I1Â Â Â Â Â Â Â Â Â Â Â Â Â R1Â Â Â Â Â Â Â Â Â Â Â Â Â R2Â Â Â Â Â Â Â Â Â Â Â Â Â R3Â Â Â Â Â I2Â Â Â Â Â I3"
read_loop_3: do
 I1=-99;      I2=-99;      I3=-99
 R1=-99._DBL; R2=-99._DBL; R3=-99._DBL
 read(1,1,iostat=iost) text
 if ( iost /= 0 ) then
   if ( iost < 0 ) then
     print 4, "End Of File Reached"
     print 3, line
   else if ( iost > 0 ) then
     print *, "ERROR reading in CASE 3: iost = ", iost
   end if
   exit read_loop_3
 else
   read(text,10,iostat=iost) I1, R1, R2, R3, I2, I3
   if ( iost /= 0 ) then
     read(text,*,iostat=iost) I1, R1, R2, R3, I2, I3
   end if
   print 10, I1, R1, R2, R3, I2, I3
 end if
end do read_loop_3
Â
print 2, "NORMAL TERMINATION"
Â
close (1)
end program read_csv
Â
!input data in input.txt
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00                 3.00000000E+00              7
         1.00000000E+00                 3.00000000E+00
101,1.,2.,3.,7,7
102,1.,,3.,,7
,1.,,3.,,
Â
!results using gfortran
browning$ gfortran read_csv.f90
browning$ ./a.out
Â
------------------------------------------------------------------------------------------
CASE 1
Â
Read numbers from file into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 2
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    -99 -9.90000000E+01 -9.90000000E+01 -9.90000000E+01    -99    -99
    -99 -9.90000000E+01 -9.90000000E+01 -9.90000000E+01    -99    -99
    -99 -9.90000000E+01 -9.90000000E+01 -9.90000000E+01    -99    -99
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 3
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Add condition that if formatted read fails, then do list-directed read using *
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 -9.90000000E+01 3.00000000E+00    -99      7
    -99 1.00000000E+00 -9.90000000E+01 3.00000000E+00    -99    -99
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
NORMAL TERMINATION
Â
!results using ifort
browning$ ifort read_csv.f90
browning$ ./a.out
Â
------------------------------------------------------------------------------------------
CASE 1
Â
Read numbers from file into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 2
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
------------------------------------------------------------------------------------------
CASE 3
Â
Read numbers from file into string and then read from string into int/real variables:
Â
Add condition that if formatted read fails, then do list-directed read using *
Â
Results:
     I1             R1             R2             R3     I2     I3
      1 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
      2 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
    101 1.00000000E+00 2.00000000E+00 3.00000000E+00      7      7
    102 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      7
      0 1.00000000E+00 0.00000000E+00 3.00000000E+00      0      0
Â
End Of File Reached
------------------------------------------------------------------------------------------
Â
Â
NORMAL TERMINATION
Â
Â
Â
Â
-Bob
Â
___________________________________________________
Robert S. Browning IV
Research Structural Engineer
Structural Mechanics Branch
Geotechnical and Structures Laboratory
U.S. Army Engineer Research and Development Center
3909 Halls Ferry Road, Vicksburg, MSÂ 39180-6199
ATTN: CEERD-GSM, BLDG 5008
Â
Office:Â 601-634-5228
iPhone:Â 601-630-7276
Fax: Â 601-634-2309 (email preferred)
Email:Â Â mailto:***@usace.army.mil