我正在将一个旧的数学模型(1995年到2000年之间)移植到当前的linux机器上。为此,我调整了所有的makefile,如下所示:
FORTRAN = gfortran # f90 -f77 -ftrap=%none
OPTS = -O -u -lgfortran -g -fconvert="big-endian" # -O -u
NOOPT =
LOADER = gfortran #f90
LOADOPTS = #-lf77compat
和
SYSFFLAGS = -O0 -u -g -fconvert="big-endian" # -f77=input
SYSCFLAGS = -DX_WCHAR
SYSLDFLAGS =
SYSCPPFLAGS = -DSYS_UNIX -DCODE_ASCII -DCODE_IEEE # -DSYS_Sun
SYSAUTODBL = -fdefault-real-8 #-r8
SYSDEBUG = -g
SYSCHECK = -C
LINKOPT =
CPPOPT =
SHELL = /bin/sh
CC = cc
FC = gfortran # f90
LD = gfortran # f90
AR = ar vru
RM = rm -f
CP = cp
MV = mv -f
LN = ln -s
所以我替换了所有过时的编译器/选项,以便能够编译代码。之后,它生成没有错误的二进制文件。请注意,#符号后面的所有选项都是Makefile中的原始选项。
因此,在运行程序时,无法读取示例数据。 IMO在Sun机器上将这些文件创建为无格式序列模式。以下十六进制转储属于我需要阅读的文件。
0000000: 0000 0400 2020 2020 2020 2020 2020 2020 ....
0000010: 3930 3130 7465 7374 2d63 3031 2020 2020 9010test-c01
0000020: 2020 2020 4741 5520 2020 2020 2020 2020 GAU
0000030: 2020 2020 2020 2020 2020 2020 2020 2020
0000040: 2020 2020 2020 2020 2020 2020 2020 2020
0000050: 2020 2020 2020 2020 2020 2020 2020 2020
...
...
0000390: 2020 2020 2020 2020 2020 2020 2020 2020
00003a0: 2020 2020 2020 2020 2020 2020 2020 2020
00003b0: 2020 2020 3139 3936 3037 3232 2032 3030 19960722 200
00003c0: 3434 3920 4147 434d 352e 3420 2020 2020 449 AGCM5.4
00003d0: 2020 2020 3230 3030 3036 3134 2031 3230 20000614 120
00003e0: 3831 3720 6869 726f 2020 2020 2020 2020 817 hiro
00003f0: 2020 2020 2020 2020 2020 2020 2020 2034 4
0000400: 3039 3630 0000 0400 0002 8000 bef7 21f3 0960..........!.
0000410: bf3c 55ab bf7a 8f71 bf99 e26a bfb2 db4e .<U..z.q...j...N
0000420: bfc7 425f bfd6 64b1 bfdf d44f bfe3 6a43 ..B_..d....O..jC
分析代码后,它可以读取直到 0000410 行。标记 0002 8000 后无法继续。下面显示的源代码实际上是读取此文件。
...
* [INPUT]
INTEGER IFILE
CHARACTER HITEM *(*) !! name for identify
CHARACTER HDFMT *(*) !! data format
*
* [ENTRY INPUT]
REAL * 8 TIME1 !! time
REAL * 8 TIME2 !! time
REAL*8 DMIN
REAL*8 DMAX
REAL*8 DIVS
REAL*8 DIVL
INTEGER ISTYPE
INTEGER JFILE !! output file No.
INTEGER IMAXD
INTEGER JMAXD
*
* [WORK]
REAL * 8 DDATA ( NGDWRK )
REAL * 4 SDATA ( NGDWRK )
*
* [INTERNAL WORK]
INTEGER I, J, K, IJK, IJKNUM, IERR
...
...
READ ( IFILE, IOSTAT=IEOD ) HEAD
...
...
...
DO 2150 IJK = 1, IJKNUM
READ ( IFILE, END=2150 ) SDATA(IJK)
WRITE (6,*) ' IGTIO::GTZZRD: iteration=', IJK, SDATA(IJK)
2150 CONTINUE
为了轻松调试我替换上面的循环。原来是隐含的。
READ ( IFILE, IOSTAT=IEOD)
& (SDATA(IJK), IJK=1, IJKNUM )
循环的输出是:
IGTIO::GTZZRD: iteration= 1 -0.48268089
IGTIO::GTZZRD: iteration= 2 1.35631564E-19
IGTIO::GTZZRD: iteration= 3 -0.48142704
IGTIO::GTZZRD: iteration= 4 1.35631564E-19
IGTIO::GTZZRD: iteration= 5 244.25270
IGTIO::GTZZRD: iteration= 6 1.35631564E-19
IGTIO::GTZZRD: iteration= 7 983.87988
IGTIO::GTZZRD: iteration= 8 1.35631564E-19
IGTIO::GTZZRD: iteration= 9 1.59284362E-04
IGTIO::GTZZRD: iteration= 10 1.35631564E-19
IGTIO::GTZZRD: iteration= 11 0.0000000
---error here---
我绝对迷失在此,所以任何帮助都表示赞赏。
答案 0 :(得分:2)
以下是最新消息 - 首先,这绝对是一个Big Enfian文件。 前4个字节
00000400
是大端4字节整数1024,这是您第一条记录的长度。
这符合HEAD
的长度(每条评论)
现在请注意00000400
在字节位置1024 + 4处完全重复(十六进制转储行400),正如您对fortran无格式文件所期望的那样......到目前为止一直很好。
现在接下来的4个字节
0002 8000
开始第二条记录。 (编辑纠正错误)这是163840(2 * 16 ^ 4 + 8 * 16 ^ 3)您应该在十六进制转储中找到重复的位置1024 + 8 + 163840 + 4。 (我认为应该是028400行。)
问题出现了:在你的代码中,你正在将160千字节的记录读入一个4字节的变量,然后转到下一条记录。我猜您会看到交替10 ^ -19,因为每个其他记录都是类型字符。
在未格式化的fortran中,您必须一次性读取整个记录 - 尝试读取整个数组(没有循环..)
READ ( IFILE )SDATA
假设sdata的尺寸为当然保持160 kb。 (例如,真* 4(40960))
答案 1 :(得分:1)
您的问题的答案在我错过的编辑中。还要感谢乔治的算术 - 我没有费心去做。
我们可以有把握地说记录标题是正确的,并且您可以通过字节序转换来解决问题。
所以,问题是:使用隐含do循环的读取不等同于do循环内的读取。
即:read(unit) (i(j), j=1,5)
与
do j=1,5
read(unit) i(j)
end do
首先,读取五个值来自一个记录,第二个记录是从不同记录中读取的。
然后,您应该还原您的更改。但是,如果要进行相同的诊断,可以执行类似
的操作READ ( IFILE, IOSTAT=IEOD) (SDATA(IJK), IJK=1, IJKNUM )
WRITE (6, '("IGTIO::GTZZRD: iteration='", I0.0, F12.8)') (IJK, SDATA(IJK), IJK=1,IJKNUM)
答案 2 :(得分:0)
在此范围之外,由于某种原因,在1100循环中调用负责读取文件的深层方法。这导致读取文件的次数超过了必要的次数。在下面找到固定代码:
* 1100 CONTINUE
CALL GDREDX !! read data
O ( GDATA , IEOD ,
O HITEMD, HTITL , HUNIT , HDSET ,
O TIME , TDUR , KLEVS ,
I IFILE , HITEM , HDFMT ,
I IMAXD , JMAXD ,
I IDIMD , JDIMD , KDIMD )
IF ( IEOD .EQ. 0 ) THEN
WRITE (6,*) ' IRWGD.F::GDRDTS: TSEL0=', TSEL0
WRITE (6,*) ' IRWGD.F::GDRDTS: TSEL1=', TSEL1
WRITE (6,*) ' IRWGD.F::GDRDTS: TIME=', TIME
* IF ( ((TSEL0.GE.0).AND.(TIME.LT.TSEL0))
* & .OR.((TSEL1.GE.0).AND.(TIME.GT.TSEL1)) ) THEN
* GOTO 1100
* ENDIF
ENDIF
*
RETURN
END
这是误导我,以弄清楚发生了什么。