Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clarifying a fortran implied loop

I used FORTRAN a little, many years ago, and have recently been tasked to maintain an old FORTRAN program (F77). The following code was unfamiliar:

      READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS,  
   .    ( BUFFER(BIX), BIX=1, NUM_WORDS )  

Reviewing some on-line forums revealed that the part that was confusing me, the continuation line, is an implied loop. Since my program is giving me trouble right here, I want to convert this to a conventional DO-loop. Converting it might also help the next poor slob that picks this thing up cold 5 years from now! Anyway, my best guess at the DO-loop equivalent is

  READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS  
  DO BIX=1, NUM_WORDS  
    READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) BUFFER(BIX)  
  ENDDO  

But when I made only this change, test cases which were working stopped working. I still felt that what was going on here was two different READs (the first to get NUM_WORDS, and the second to loop through the data), so I tried a less drastic change, converting it to two statements but retaining the implied loop:

  READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS  
  READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) ( BUFFER(BIX), BIX=1, NUM_WORDS )  

But just this change also causes the good test cases to fail. In both of my alterations, the value of NUM_WORDS was coming through as expected, so it seems that the loop is where it is failing.

So, what is the equivalent DO-loop for the original implied loop? Or am I on the wrong track altogether?
Thanks

like image 574
user3617977 Avatar asked Oct 21 '22 08:10

user3617977


1 Answers

How is the file opened? I.e. is it ACCESS='sequential', access='direct', or access='stream' (well, the last is unlikely as it's a F2003 addition). Secondly, is it formatted or unformatted? I'm going to assume it's unformatted sequential since there is no REC= specifier nor a format specifier in your read statements.

The reason why what you're trying to fails is that each read statement reads a separate record. Prior to the introduction of access='stream' in F2003, Fortran I/O was completely record based, which is slightly alien to those of us used to stream type files as seen in most other languages.

Records for unformatted sequential files are typically separated by "record markers" at each end of the record, typically 4 bytes specifying the length of the record. So the record (on disk) likely looks something like

| length (4 bytes) | num_words (4 bytes?) | buffer(1) | buffer(2) | ... | length |

Now if you try to read, say, num_words with one READ statement, it will correctly read num_words from the file, THEN it will skip forward until the start of the next record. And when you then try to read buffer with a separate READ statement you're already too far ahead in the file.

If you cheat a bit and use F90+ array syntax, you might get away with

READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS, BUFFER(1:NUM_WORDS)

(though I'm not sure if you're allowed to reference num_words in the same statement where it's being written to)

like image 103
janneb Avatar answered Dec 29 '22 21:12

janneb