Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Direct Access I/O

Ahmad_Falahatpisheh
1,074 Views
Hello,

I have a file containing an ID which is INTEGER*4 and three coordinates variables for that ID which are all REAL*8 like the following as an example (C:\\TEMP\\NODES.TXT):

227499, 0.658436716, 12.1055336, -2.70311999

Also I have another file which contains four INTEGER*4 variables like the following (C:\\TEMP\\ELEMENTS.TXT):

528594, 232407, 231854, 231853

I have used the following code to convert the sequential file to a DIRECT ACCESS file. The number of records are variable each time I run the code. Could you please let me know how I should choose the RECORD LENGTH for those two files? Even I set REC=10 it works perectly with like 500,000 records.

PROGRAM WRITE_AS_DIRECT
INTEGER*4 NODEID, I
INTEGER*4 ELEMID, NODEID1, NODEID2, NODEID3
REAL*8 X, Y, Z

OPEN(UNIT=1,FILE='C:\\TEMP\\NODES.TXT')
OPEN(UNIT=2,FILE='C:\\TEMP\\NODESDIRECT.TXT',
1 ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10,ACTION='WRITE')
I=1
DO WHILE (.NOT.EOF(1))
READ(1,*) NODEID, X, Y, Z
WRITE(2,REC=NODEID) X, Y, Z
I=I+1
ENDDO
CLOSE(1)
CLOSE(2)



OPEN(UNIT=1,FILE='C:\\TEMP\\ELEMENTS.TXT')
OPEN(UNIT=2,FILE='C:\\TEMP\\ELEMENTSDIRECT.TXT',
1 ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10,ACTION='WRITE')
I=1
DO WHILE (.NOT.EOF(1))
READ(1,*) ELEMID, NODEID1, NODEID2, NODEID3
WRITE(2,REC=ELEMID) NODEID1, NODEID2, NODEID3
I=I+1
ENDDO
CLOSE(1)
CLOSE(2)


END

Thanks,
Ahmad
0 Kudos
1 Solution
Jugoslav_Dujic
Valued Contributor II
1,074 Views
You are not using Fortran 77. Apparently, you are using Intel Fortran, which is a Fortran-95 (well, almost Fortran-2003) compiler. The proof of that is that you are already using direct unformatted files, which are a Fortran-90 feature.

You are using the fixed-form code, but it is not equal to "Fortran 77". Fixed-form is still valid Fortran-90, Fortran-95 and Fortran-2003. The standard to which the code conforms is dictated by features it uses, not by the source form.

By the way, this Jim's solution is not good in a general case:

[fortran]SIZEOF_RECORD_DATA = SIZEOF(X) + SIZEOF(Y) + SIZEOF(Z)  [/fortran]
Because of padding, you may potentially end up with a record smaller than required. Instead, use the Fortran feature specially designed for that:

[bash]INQUIRE(IOLENGTH=SIZEOF_RECORD_DATA) X, Y, Z[/bash]

View solution in original post

0 Kudos
6 Replies
GVautier
New Contributor II
1,074 Views
Hello

The record length must be set to the length of datas written in each record. In the first case, 3 real*8 implies a record length of 24, and in the second 3 integer*4 implies 12.
0 Kudos
Ahmad_Falahatpisheh
1,074 Views
Thanks. Does it matter if I set a bigger record length and use for example half of it (in case I switch REAL*8 to REAL)?
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,074 Views
Thanks. Does it matter if I set a bigger record length and use for example half of it (in case I switch REAL*8 to REAL)?


Compute the record length

[bash]PROGRAM WRITE_AS_DIRECT
    INTEGER*4 NODEID, I
    INTEGER*4 ELEMID, NODEID1, NODEID2, NODEID3
    ! RECORD DATA
    REAL*8 X, Y, Z
    ! END OF RECORD DATA
    INTEGER :: SIZEOF_RECORD_DATA
    
    SIZEOF_RECORD_DATA = SIZEOF(X) + SIZEOF(Y) + SIZEOF(Z)
    
    OPEN(UNIT=1,FILE='C:TEMPNODES.TXT')
    OPEN(UNIT=2, &
&       FILE='C:TEMPNODESDIRECT.TXT', &
&       ACCESS='DIRECT', &
&       FORM='UNFORMATTED', &
&       RECL=SIZEOF_RECORD_DATA, &
&       ACTION='WRITE')
    I=1      
    DO WHILE (.NOT.EOF(1))
     READ(1,*) NODEID, X, Y, Z
     WRITE(2,REC=NODEID) X, Y, Z   
     I=I+1 
    ENDDO
    CLOSE(1)
    CLOSE(2)


        
    OPEN(UNIT=1,FILE='C:TEMPELEMENTS.TXT')
    OPEN(   UNIT=2, &
&           FILE='C:TEMPELEMENTSDIRECT.TXT', &
&           ACCESS='DIRECT', &
&           FORM='UNFORMATTED', &
&           RECL=SIZEOF_RECORD_DATA, &
&           ACTION='WRITE')
    I=1      
    DO WHILE (.NOT.EOF(1))
     READ(1,*) ELEMID, NODEID1, NODEID2, NODEID3
     WRITE(2,REC=ELEMID) NODEID1, NODEID2, NODEID3
     I=I+1 
    ENDDO
    CLOSE(1)
    CLOSE(2)


END
[/bash]


It will be less error prone if you place the record data into a user defined type.

type iorec_t
real*8 :: X, Y, Z
end type iorec_t

type(iorec_t) :: iorec

OPEN(UNIT=1,FILE='C:\TEMP\NODES.TXT')
OPEN(UNIT=2, &
& FILE='C:\TEMP\NODESDIRECT.TXT', &
& ACCESS='DIRECT', &
& FORM='UNFORMATTED', &
& RECL=SIZEOF(iorec), &
& ACTION='WRITE')
I=1
DO WHILE (.NOT.EOF(1))
READ(1,*) NODEID, iorec%X, iorec%Y, iorec%Z
WRITE(2,REC=NODEID) iorec
I=I+1
ENDDO
...
0 Kudos
Ahmad_Falahatpisheh
1,074 Views
It really looks professional. Unfortunately, I am using FORTRAN77. Do you think I can pply the same concept?

Thanks,
Ahmad
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,075 Views
You are not using Fortran 77. Apparently, you are using Intel Fortran, which is a Fortran-95 (well, almost Fortran-2003) compiler. The proof of that is that you are already using direct unformatted files, which are a Fortran-90 feature.

You are using the fixed-form code, but it is not equal to "Fortran 77". Fixed-form is still valid Fortran-90, Fortran-95 and Fortran-2003. The standard to which the code conforms is dictated by features it uses, not by the source form.

By the way, this Jim's solution is not good in a general case:

[fortran]SIZEOF_RECORD_DATA = SIZEOF(X) + SIZEOF(Y) + SIZEOF(Z)  [/fortran]
Because of padding, you may potentially end up with a record smaller than required. Instead, use the Fortran feature specially designed for that:

[bash]INQUIRE(IOLENGTH=SIZEOF_RECORD_DATA) X, Y, Z[/bash]
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,074 Views
Jugoslav,

Thanks for pointing this out.

On this subject, and for clarification, if padding is involved in the I/O then wouldn't it also be dependent on the mode in which and machine on whicha file were opened? If so then wouldn't the INQUIRE also require an I/O unit? In the special case of the user's sample code reals were written and padds typically wouldn't have been used. Padd might appear when writing user defined type or LOGICAL or some CHARACTER variables, but then these would also cause portibility problems with the binary files (one system requiring machine word alignment the other not).

Jim
0 Kudos
Reply