I/O of finite length

I/O of finite length

Suppose that I have a type real array of 25 elements, and at some point within my code I have the following two statements

open(unit=30,file='data.txt',status='unknown')
write(30,*)(real_array(j), j =1, 25)

Upon compilation (with ifort10.1) and execution the file data.txt does not contain one long line with 25 elements on it, but 7 lines 6 of which have 4 values in each and the last line containing one element of the array.

How can I force ifort to put all of the elements of the array onto one line in the output file?

18 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Within limits, which you may be exceeding, you have better control over the number of fields per line when you use an explicit record length and format, rather than list directed.
open(30,file='data.txt',recl=204)
write(30,'(2x,25f8.2)')real_array(1:25)

Quoting - tim18
Within limits, which you may be exceeding, you have better control over the number of fields per line when you use an explicit record length and format, rather than list directed.
open(30,file='data.txt',recl=204)
write(30,'(2x,25f8.2)')real_array(1:25)

more portable would be:

integer :: recsize

inquire(iolenght=recsize) real_array(1:25)
open(30,file='data.txt',recl=recsize)

(but I really don't understand why you are getting that behaviours. did you try with diferent compiler/version?)

Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

1. You haven't stated why you need all 25 values on one line. You certainly don't need this if the 25 values will be read back by a Fortran list-directed READ, because a list-directed READ will read from multiple lines if necessary. Of course, if the line will be read by a program written in some other language, you may be stuck with whatever requirements the other language imposes.

2. You might be able to get the numbers written on one line by doing nothing more than increasing the maximum record length for that file. Many Fortran implementations decide when to switch to a new line based on that maximum. Note, however, that an implementation is not required to do this, and that, in any case, the number of characters produced by list-directed output varies among implementations (thus varying the maximum output record length), so doing this is not portable from implementation to implementation or even from release to release of a given implementation.

3. If you want control and portability, take Tim's suggestion. My only quibble with his post is that 2+25*8 is 202, so he made the maximum record length two characters longer than necessary. Of course, if F8.2 isn't adequate for your values, you will have to use a different edit descriptor and may need to adjust your maximum record length accordingly.

4. Ignore Ricardo's suggestion. INQUIRE(IOLENGTH=var)list returns the size of an unformatted (i.e., binary) record, which has no portable conncection to the size of list-directed output.

-Kurt

Quoting - hirchert

4. Ignore Ricardo's suggestion. INQUIRE(IOLENGTH=var)list returns the size of an unformatted (i.e., binary) record, which has no portable conncection to the size of list-directed output.

It's reasonable to guess there might be a connection, in the contrived case where the data type is known to occupy the same number of bytes as the width specified in the format, and the byterecl option or equivalent has been selected. It won't work if the data type is default real, occupying 4 bytes, nor, in ifort, without the byterecl option. I'd agree with Kurt on the lack of portability.

Quoting - hirchert
4. Ignore Ricardo's suggestion. INQUIRE(IOLENGTH=var)list returns the size of an unformatted (i.e., binary) record, which has no portable conncection to the size of list-directed output.

thanks for the correction. I was just think there should be a more portable way to specify reclenght without just writing a "magic number"...

Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

Quoting - tim18
Within limits, which you may be exceeding, you have better control over the number of fields per line when you use an explicit record length and format, rather than list directed.
open(30,file='data.txt',recl=204)
write(30,'(2x,25f8.2)')real_array(1:25)

I do not think it is actually necessary to specify that recl value in the open statement. I never do that and I often need to write more than 25 numbers in one line. There should not be any problem with it. Out of curiosity, I have just checked this with 2000 (not 25) real numbers -- no problem at all, all numbers stayed in one line (note: some text editors may actually split the line into several lines when showing it -- don't get confused about it).

In case when 25 is not a fixed predetermined number (let's say it is a variable "n") you can replace the write statement with a loop like this:

do i=1,n
write(30, '(2x,f8.2)',advance='no') real_array(i)
enddo

Quoting - bubin

In case when 25 is not a fixed predetermined number (let's say it is a variable "n") you can replace the write statement with a loop like this:

do i=1,n
write(30, '(2x,f8.2)',advance='no') real_array(i)
enddo

Shouldn't this

do i=1,n
write(30, '(2x,f8.2)',advance='no') real_array(i)
enddo

and this

write(30, '(2x,f8.2)',advance='no') real_array(1:n)

give the same result? The first one outputs a single line, the second a number per line. I've tested in ifort and gfortran. Am I missing something?


Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

Quoting - rreis

Shouldn't this

do i=1,n
write(30, '(2x,f8.2)',advance='no') real_array(i)
enddo

and this

write(30, '(2x,f8.2)',advance='no') real_array(1:n)

give the same result? The first one outputs a single line, the second a number per line. I've tested in ifort and gfortran. Am I missing something?


I wonder whether a more useful suggestion might have been
write(30, '(2x,(f8.2))') real_array(1:n)

Quoting - tim18

I wonder whether a more useful suggestion might have been
write(30, '(2x,(f8.2))') real_array(1:n)

Tim's almost got it, but still not quite.

The issue is "format reversion" - what happens when a value is to be transmitted but you've reached the end of the format. What the standard says is that you begin a new record and then "revert" back to the matching left parenthesis, or the beginning of the format if none. In the original format, there is no matching left paren so you go back to the 2x and repeat this for each element in the array, each in a new record. With Tim's version, the reversion is back to the f8.2, but still a new record.

In Fortran 2003, the typical way to do this is with a large repeat count, for example:

'(2x,1000f8.2)'

As long as the number of elements is 1000 or less, you'll get all one record. One could also use the Variable Format Expression extension, like this:

'(2x,f8.2)'

but that should be a last resort.

Fortran 2008 adds an "unlimited format item" so you could have this:

'(2x,*(f8.2))'

and get exactly what is wanted here. This is not supported by Intel Fortran at this time.

As a side note, please don't use "real_array(1:n)" where just "real_array" would do.

Steve - Intel Developer Support

Quoting - Steve Lionel (Intel)

As long as the number of elements is 1000 or less, you'll get all one record. One could also use the Variable Format Expression extension, like this:

'(2x,f8.2)'

but that should be a last resort.

As a side note, please don't use "real_array(1:n)" where just "real_array" would do.

Indeed, this should be a last resort (read: you are absolutely sure that in the future you will never need to compile your code with a non-intel compiler). Variable format is not a part of fortran standard. Been there, did that, learned it the hard way... I can testify that it is absolutely not fun to manually correct every first write statement in a large program... :-). In fact, because of that I now tend to do most of input/output by calling a small number of my own elementary routines, which can be modified easily if needed. That is particularly useful when the precision or real numbers (double, extended double, quadruple) is a parameter in the code and when one needs to write several (but not a predetemined quantity) such real numbers in a single line.

Sorry to be insistent but I still don't understand why this

do i=1,n
write(30, '(2x,f8.2)',advance='no') real_array(i)
enddo

gives different results from this?

write(30, '(2x,f8.2)',advance='no') real_array

especially if

"ADVANCE= (Fortran 90 only)

ADVANCE='NO' tells a READ or WRITE not to advance the file position pointer to the next record when done. The effect for a READ is that the next READ will continue picking information off of the current record, or the next WRITE will write to the same record (line on the screen) starting at the position where the last READ or WRITE stopped. To use this option you must have a specific format, either labeled FORMAT statement, or format specifications in a character string (variable or constant). This will not work with a list-directed (*) format.

probably I'm missing something quite basic, my apologies.

Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

ADVANCE= specifies what happens at the end of the I/O statement - is the record completed or not? It does not affect new records started by format reversion or an explicit / format item.

Steve - Intel Developer Support

Quoting - Steve Lionel (Intel)
ADVANCE= specifies what happens at the end of the I/O statement - is the record completed or not? It does not affect new records started by format reversion or an explicit / format item.

how do I know (if the record is completed)?

from my little understanding I would expect full compatibility between having an explicit do loop

do i=1,n
write(idx, '(format)') array(i)
enddo

and its "vector expression"write(idx, '(format)') array(1:n)

more than the advance=no this is what I would like to understand. why the two expressions differ on their results...

the simpler things sometimes are the difficult to grok so I beg your patience on this...

Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

Quoting - rreis

do i=1,n
write(idx, '(format)') array(i)
enddo

and its "vector expression"write(idx, '(format)') array(1:n)

more than the advance=no this is what I would like to understand. why the two expressions differ on their results...

The latter is exactly equivalent to write(idx, '(format)') (array(i),i=1,n) .
Without advance=no, the first version will start a new line from the beginning of the format for each array element.

Quoting - tim18

The latter is exactly equivalent to write(idx, '(format)') (array(i),i=1,n) .
Without advance=no, the first version will start a new line from the beginning of the format for each array element.

ah, many thanks. A light bulb just flashed in my head. I was also thinking that

write(idx, '(format)')
(array(i),i=1,n)

would be equivalent to

do i=1,n
write(idx, '(format)')
array(i)
enddo

which, indeed, it ain't. This way of writing makes it more clear. I'm happy now. The only approach that gives me a full line is the do i=1,n loop.

Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

That's not the only way - I gave you a standard-conforming way to do this in a single write.

Steve - Intel Developer Support

Quoting - Steve Lionel (Intel)
That's not the only way - I gave you a standard-conforming way to do this in a single write.

oh, yes, Steve, you are right am sorry, I was only looking at those.

Just that F2008 is very far away, and I don't think there is a compiler that is fully F2003. I also don't like using "magic numbers", like in '(2x,1000f8.2)' . Off course I could write something with format to place a string "n" inside but it seems cumbersome.

I have never heard of "Variable Format Expression" before (just googled it now), but has you wrote it is an extension my mind dumped it as non-standard... So, I still think doing do Do loop would be the most portable approach to the problem. But, off course, it's a personal choice.

Ricardo Reis 'Non Serviam' @ http://www.lasef.ist.utl.pt @ http://www.radiozero.pt @ http://rreis.tumblr.com @ http://www.flickr.com/photos/rreis

Leave a Comment

Please sign in to add a comment. Not a member? Join today