1

Is there any way to condense this code?

.
.
real*4 a4,e4,inc4,capom4,omega4,capm4
integer*2 id2
real*8 array(1e7,8)
.
.
row=0
do n=1,nleft+nbod2-1
 row=row+1
 read(iu) id2,a4,e4,inc4,capom4,omega4,capm4    
 array(row,1)=id2
 array(row,2)=a4
 array(row,3)=e4
 array(row,4)=inc4
 array(row,5)=capom4
 array(row,6)=omega4
 array(row,7)=capm4
end do
.
.

I've tried about five different ways starting with an implied DO loop and all result in "forrtl: severe (67): input statement requires too much data...".

0

3 Answers 3

2

The reason you cannot condense

 read(iu) id2,a4,e4,inc4,capom4,omega4,capm4    
 array(row,1)=id2
 array(row,2)=a4
 array(row,3)=e4
 array(row,4)=inc4
 array(row,5)=capom4
 array(row,6)=omega4
 array(row,7)=capm4

into

read(iu) (array(row,i), i=1:7)

is because this is causes a mismatch of your data file to your read arguments. In the source provided in the comments below you have these variables declared as:

real*4 ttmp,a4,e4,inc4,capom4,omega4,capm4
integer*2 nleft,nbod2,id2
real*8 array(1e7,8)

This means your read call read(iu) id2,a4,e4,inc4,capom4,omega4,capm4 is requesting 26 bytes (1*2 bytes + 6*4 bytes) and this corresponds to the record size in the unformatted file provided in the comments.

When you change the read to:

read(iu) (array(row,i), i=1:7)

which is completely valid on its own, it no longer matches the binary file and the read fails. This read requests 56 bytes (7*8 bytes) and produces the fatal runtime error you are reporting (you are requesting 56 bytes from a 26 byte record). The temporary variables used in the read are necessary so that you can read a 2 byte integer and 4 byte floats and then assign them to 8 byte real variables. The read cannot accomplish this directly because the underlying binary data in your file are not 8 byte reals.


So what can you do?

In your code you posted below your read is slightly different

  read(iu) id2,a4,e4,inc4,capom4,omega4,capm4

  array(row,1)=id2
  array(row,2)=ttmp
  array(row,3)=a4
  array(row,4)=e4
  array(row,5)=inc4
  array(row,6)=capom4
  array(row,7)=omega4
  array(row,8)=capm4

You could do away with the 6 named temporary variables and instead use an array of 6 reals for this. e.g.

real*4 :: readtemp(6)
.
.
do n=1,nleft+nbod2-1
  read(iu) id2,readtemp 
  array(n,1)=id2
  array(n,2)=ttmp
  array(n,3:8)= readtemp
end do

This lets you get rid of 6 individual reals in exchange for one array and condenses 6 of the assignments to just 1 assignment. Not a total collapse of the read/assign combo as in the other answer, but this does avoid needing to define a type to accomplish it.

Sign up to request clarification or add additional context in comments.

3 Comments

OK, the full code, runtime error messages and data file are posted at dl.dropboxusercontent.com/u/26040666/bin_tyc.dat and dl.dropboxusercontent.com/u/26040666/Code.txt Linux: Ubuntu 14.04 Intel Fortran compiler: Intel® Parallel Studio XE 2015 (compiler 15.0). No compiler errors.
@user94858 see my edit. You cannot condense the code because the types provided to read are completely different.
@casey Thanks. I have read his code and, hmm, integer*2 ... I will post another trial.
0

Since the OP's code involves mixed data types including integer*2, direct use of read(iu) array( n, 1:7 ) seems not working. So I made another two trials to condense the code. The first one is

read(iu) id2, a4, e4, inc4, capom4, omega4, capm4
array( n, : ) = [ real*8 :: id2, a4, e4, inc4, capom4, omega4, capm4 ]

which saves some lines of code, but still a bit lengthy. So the second trial is

type dat_t
    sequence
    integer*2 :: id2
    real*4    :: a4, e4, inc4, capom4, omega4, capm4
endtype

type(dat_t) :: dat( 10000 )   !! or allocate() if necessary

and read the unformated file as

do n = 1, nleft + nbod2 - 1
    read(iu) dat( n )
enddo

The obtained data can be used as usual, e.g., dat( n )% a4. Here it is important to put the keyword sequence to ensure contiguous arrangement of variables in memory. Otherwise the same error occurs as in the OP's case...

I have tested this with a code below (using gfortran4.8 and ifort14.0)

program main
    integer, parameter :: dp = 8

    type dat_t
        sequence                                                                   
        character(5) :: s
        integer      :: k
        real(dp)     :: x, y
    endtype

    type(dat_t) :: d( 500 )
    real(dp)    :: a( 100 )

    !! write test data                                                              
    open( 10, file="test.dat", form="unformatted" )
    write( 10 ) "hello", 100, 777.0_dp, 888.0_dp
    close( 10 )

    !! read test data                                                               
    open( 20, file="test.dat", form="unformatted", status="old" )

    read( 20 ) d( 50 )
    print *, d( 50 )

    a( 1:3 ) = [ real(dp) :: d( 50 )% k, d( 50 )% x, d( 50 )% y ]
    print *, a( 1:3 )

    close( 20 )
end

Comments

0

You haven't really shown us enough to offer very good advice. Leaving that to one side, this might work:

Replace the block

row=0
do n=1,nleft+nbod2-1
 row=row+1
 read(iu) id2,a4,e4,inc4,capom4,omega4,capm4    
 array(row,1)=id2
 array(row,2)=a4
 array(row,3)=e4
 array(row,4)=inc4
 array(row,5)=capom4
 array(row,6)=omega4
 array(row,7)=capm4
end do

with

do n=1,nleft+nbod2-1
 read(iu) array(n,1:7)    
end do

In any further questions post exactly the code you are having trouble with, and exactly the errors reported by your compiler or at run-time.

1 Comment

First variant I tried. Doesn't work. Error message: forrtl: severe (67): input statement requires too much data, unit 20, file /home/name/testprogs/bin_tyc.dat Happy to give you the complete program once I've cleaned out the debugging statements. You'll also need the input file - how does one upload something like this to this site?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.