fortran - 悲催的科学匠人 - 冷水's blog

我被硬特fortran编译器坑的事迹

最早先,gfortran下没有问题的代码在硬特编译后出现segment fault。结果发现数组整体赋值出了问题,比如

1
w=w1

只要数组w和w1特别大,就fault了。只好遇到比较大的数组,就把用循环。

1
2
3
DO k=0,kb
  w(:,:,:,k)=w1(:,:,:,k)
ENDDO

 

最近又被坑了一次,而且完全与上面这个经验相反。

1
2
3
4
5
6
7
8
9
id=1
DO n=1,num
  ! get i,j,k
  ...
  DO l=ivs,ivt
    buff(id)=w(l,i,j,k)
    id = id +1
  ENDDO
ENDDO

这个片段是将w中的元素按照给定的顺序填充到一维数组buff中。

按照debug模式编译没有问题。但是优化编译后出错。最后改为

1
2
3
4
5
6
7
8
9
id=1
ncmp = ivt-ivs+1
DO n=1,num
  ! get i,j,k
  ...
  buff(id:id+ncmp-1)=w1(ivs:ivt,i,j,k)
  id = id + ncmp
 
ENDDO
就没有问题了。
原因没法知道,只能是硬特fortran的优化有问题。
 
 
上述问题都是在11.x版本上出现的。第二个问题在后来版本的编译器上没有了。我想这看来就是硬特家以前一直有非商业的免费版fortran编译器的原因吧。不过听说最近没有了,看来不再需要小白鼠了。
 
现在gfortran的性能不比ifort差多少,但是因为天河-1A上的标准配置就是ifort 11.1,所以不得不跳这些坑了。
 
 
 

gfortran的类型绑定方法还是没法用

至少在 gfortran 4.5上还不行

本来希望能够采用类似C++那样的成员函数调用方式

CALL obja%fun1(arg1, arg2, arg3)

 

结果不太行

 

只好改回老式的

CALL fun1(obja, arg1, arg2, arg3 )

 

可能在新版上可以,或者intel fortran

不过不想换编译器了

 

合并plot3d function文件

tecplot不支持导入多个function文件,这导致我计算出的速度数据文件和压强数据文件以及涡量数据文件没法在一个图中操作显示。

没法,写个小玩意克服一下

使用方法

 

1
$ mergep3df  newp3df newname  p3df1 name1  p3df2  name2 p3df3 name3 ...

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
MODULE mergep3d
CONTAINS
 
 
SUBROUTINE mergep3dfunc(ndatafiles, datafiles, &
                        nb,ni,nj,nk,  nvar,  newp3df)
  IMPLICIT NONE
  INTEGER,INTENT(IN) :: ndatafiles, nvar(:)
  CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: datafiles
  CHARACTER(LEN=*),INTENT(IN) :: newp3df
  INTEGER,POINTER,DIMENSION(:) :: ni,nj,nk
  INTEGER,INTENT(in) :: nb
  ! local
  INTEGER nvars, tmpint, b, n, i,j,k,l
  INTEGER,POINTER,DIMENSION(:) :: offset, funit,shift
  REAL(4),POINTER,DIMENSION(:,:,:,:) :: gdata
   
  nvars = SUM( nvar(1:ndatafiles) )
  OPEN(33,FILE=TRIM(newp3df),action='write', form='unformatted')
  WRITE(33) nb 
  WRITE(33) (ni(b),nj(b),nk(b),nvars, b=1,nb)
   
  ALLOCATE( offset(ndatafiles), funit(ndatafiles), shift(ndatafiles) )
  offset=0
  shift = 0
  DO n=1, ndatafiles
    funit(n) = 1000 + n
    OPEN(UNIT=funit(n),FILE=TRIM(datafiles(n)),action='read', form='unformatted')
    READ(funit(n)) tmpint
    READ(funit(n)) (tmpint,tmpint,tmpint,tmpint, b=1,nb) 
    offset(n) = FTELL(funit(n))
     
    shift(n+1) = shift(n) + nvar(n)
  ENDDO
   
   
  DO b=1, nb
    ALLOCATE( gdata(ni(b),nj(b),nk(b), nvars) )
    DO n=1, ndatafiles
      READ(funit(n)) (( ((gdata(i,j,k,l),i=1,ni(b)),j=1,nj(b)),k=1,nk(b)  ), &
                          l=shift(n)+1,shift(n+1) )     
    ENDDO
    WRITE(33) (( ((gdata(i,j,k,l),i=1,ni(b)),j=1,nj(b)),k=1,nk(b)  ),   l=1,nvars )
  ENDDO
   
   
 
END SUBROUTINE
 
 
SUBROUTINE checkp3dfunc(ndatafiles, datafiles,  &
                        nb, ni, nj, nk, ierr)
  IMPLICIT NONE
  INTEGER,INTENT(IN) :: ndatafiles
  CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: datafiles
  INTEGER,POINTER,DIMENSION(:) :: ni,nj,nk
  INTEGER,INTENT(OUT) :: nb,  ierr
   
  ! local
  INTEGER :: n,b,db,nfunc,dfunc
  INTEGER,DIMENSION(:),POINTER :: di,dj,dk
   
  OPEN(33,FILE=TRIM(datafiles(1)),action='read', form='unformatted')
  READ(33) nb;  WRITE(*,*) 'nblock=',nb
  ALLOCATE(ni(nb),nj(nb),nk(nb),   &
           di(nb),dj(nb),dk(nb),    )
  READ(33) (ni(b),nj(b),nk(b),nfunc, b=1,nb)
  WRITE(*,*) 'done read'
  !DO n=1,nb
  !  WRITE(*,*) ni(n),nj(n),nk(n),nvar(n)
  !ENDDO
  CLOSE(33)
   
  ierr = 0
  DO n=1,ndatafiles
    OPEN(33,FILE=TRIM(datafiles(n)),action='read', form='unformatted')
    READ(33) db
    IF(db /= nb) THEN
      ierr = 1
      CLOSE(33)
      RETURN
    ENDIF
     
    READ(33) (di(b),dj(b),dk(b),dfunc, b=1,nb)
    DO b=1,nb
      IF(di(b) /= ni(b) .OR. dj(b) /= nj(b) .OR. dk(b) /= nk(b) ) THEN
       
        WRITE(*,*) 'block ',b, di(b),dj(b),dk(b), ni(b),nj(b),nk(b)
        ierr = 2
        CLOSE(33)
        RETURN
      ENDIF
    ENDDO
     
     
     
    CLOSE(33)
  ENDDO
END SUBROUTINE
 
 
SUBROUTINE getvarnames(ndatafiles, datafiles,varnames, nvar)
  IMPLICIT NONE
  INTEGER,INTENT(OUT) :: ndatafiles
  INTEGER,DIMENSION(:), INTENT(OUT) :: nvar
  CHARACTER(LEN=*),DIMENSION(:),INTENT(OUT) :: varnames,datafiles
   
  ! local
  CHARACTER(LEN=128) :: tmpstr
   
  INTEGER :: IO, argn,n,i
  LOGICAL :: notend
   
  argn = command_argument_count()
  ndatafiles = (argn - 2)/2
  WRITE(*,*) 'argn=',argn,'ndatafiles =',ndatafiles
   
  i=0
  DO n=1,ndatafiles
    nvar(n)=0
    CALL get_command_argument(n+n+1,  datafiles(n))
    CALL get_command_argument(n+n+2,  tmpstr)
    !WRITE(*,*) tmpstr
    OPEN(33,FILE=TRIM(tmpstr))
     
    notend = .TRUE.
    DO WHILE (notend)
      READ(33, *, IOSTAT = IO ) tmpstr
      IF(IO>=0) THEN
        nvar(n) = nvar(n) + 1
        i = i + 1
        varnames(i) = tmpstr
        WRITE(*,*) i, TRIM( varnames(i) )
      ELSE
        notend = .FALSE.
      ENDIF
    ENDDO
    CLOSE(33
     
  ENDDO
  !DO n=1,i
  !  WRITE(*,*) TRIM(  varnames(n)  )
  !ENDDO
  !WRITE(*,*) nvar(1:ndatafiles)
END SUBROUTINE
 
SUBROUTINE mergename(ndata, nvar, varnames, namefile)
  INTEGER,INTENT(IN) :: ndata
  INTEGER,DIMENSION(:),INTENT(IN) :: nvar
  CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: varnames
  CHARACTER(LEN=*),INTENT(IN) :: namefile
  ! local
  INTEGER :: i,j,n
  OPEN(33,FILE=TRIM(namefile))
   
  j = 0
  DO n=1, ndata
  DO i=1, nvar(n)
      j=j+1
      WRITE(33, *) TRIM(varnames(j))
  ENDDO   
  ENDDO
 
END SUBROUTINE
END MODULE
 
 
PROGRAM main
  USE mergep3d
  IMPLICIT NONE
  INTEGER :: ndata,nvar(1024),nb,ierr
  INTEGER,POINTER,DIMENSION(:) :: ni,nj,nk
  CHARACTER(LEN=64) :: fnames(1024),varnames(1024),newp3df,newname
   
  CALL getvarnames(ndata, fnames, varnames, nvar)
  CALL checkp3dfunc(ndata, fnames,  nb,ni,nj,nk,  ierr)
  WRITE(*,*) 'ierr=',ierr
 
  CALL get_command_argument(2,newp3df)
  CALL get_command_argument(3,newname)
 
  CALL mergep3dfunc(ndata, fnames,  nb,ni,nj,nk,  nvar,  TRIM(newp3df) )
   
  CALL mergename(ndata, nvar, varnames, TRIM(newname) )
END

【轮子DIY】一个比较通用的fortran90程序make系统

一个项目中的副产品,目的是为fotran90项目构造简单的make系统

 

目录结构是主目录下必须包含bin,src和make目录。make目录下是一些makefile,而src就是源代码了。由于fortran的module特殊性,如果有module,src必须包含一个mod目录。如果包含fortran77代码,我也专门开辟一个f77目录包含这些文件,当然叶可以采用其它办法。此外,如果包含混编的c代码,我放入anisc目录。其它代码那找类别分别创建src的子目录即可。一个例子如下

 

1
2
3
4
5
6
7
8
poject
+---bin
+---make
+---src
    +---mod
    +---f77
    +---anisc
    +---main

 

make目录中关键的文件有

  1. make.inc,定义所有编译参数
  2. make_mod,专用于编译module
  3. make_f77,专用于编译fortran77代码
  4. make_clib,专用于编译c文件
  5. make_sub,用于编译其它src下子目录中fortran90代码
  6. Makefile,主make文件

 

make.inc

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# CMODE
 
# options:
# gnu,  
# pgi,
# intel
 
COMPILER=gnu
 
# path
PROJECT_HOME=..
SRCDIR=$(PROJECT_HOME)/src
OBJDIR=$(PROJECT_HOME)/obj_$(COMPILER)/$(CMODE)
MODDIR=$(PROJECT_HOME)/mod
BINDIR=$(PROJECT_HOME)/bin
 
 
 
# PGI fortran and C
ifeq ($(COMPILER),pgi)
  FC=mpif90
  LINK=mpif90
  CC=pgcc
 
  ifeq ($(CMODE),debug)
    FFLAGS0 = -module $(OBJDIR) -g -r8  -Kieee  -C
  else
    CMODE = release
    FFLAGS0 = -module $(OBJDIR) -O2 -r8  -Kieee
  endif
  ARCH = ar
  ARCHFLAG = cr
endif
 
 
 
 
# Intel fortran and C
ifeq ($(COMPILER),intel)
   FC=mpif90
   LINK=mpif90
   CC=icc
  
   ifeq ($(CMODE),debug)
     FFLAGS0 = -module $(OBJDIR) -g -r8  -check all
   else
     CMODE = release
     FFLAGS0 = -module $(OBJDIR) -O2 -r8 
   endif
  ARCH = ar
  ARCHFLAG = cr
endif
 
 
# GNU fortran and C
ifeq ($(COMPILER),gnu)
  FC=mpif90
  LINK=mpif90
  CC=gcc
 
  ifeq ($(CMODE),debug)
    FFLAGS0 = -J$(OBJDIR) -fdefault-real-8  -frecord-marker=4  -g -fcheck=all -fbacktrace
  else
    CMODE = release
    FFLAGS0 = -J$(OBJDIR) -O2 -fdefault-real-8  -frecord-marker=4
  endif
 
  ARCH = ar
  ARCHFLAG = cr
endif
 
 
 
FFLAGS = $(FFLAGS0)
 
# LIB dir 这里加入必要的库和路径
LIBDIR= #-L$(BLASDIR) -L$(LAPACKDIR)
LIBS   =  #
 
 
 
# output exe file, 你可以修改run为其它名称
EXE=$(BINDIR)/run_$(COMPILER)_$(CMODE)

 

 

make_f77

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include make.inc
 
MYSRC= $(wildcard $(SRCDIR)/$(SUB)/*.f)
MYTMP= $(patsubst %.f,%.o, $(MYSRC))
MYOBJ= $(patsubst $(SRCDIR)/$(SUB)%,$(OBJDIR)%, $(MYTMP))
all: $(MYOBJ)
 
 
$(MYOBJ): $(OBJDIR)/%.o: $(SRCDIR)/$(SUB)/%.f
    $(FC) -c $(FFLAGS)  $< -o $@
 
clean:
    rm -f $(MYOBJ)
 
submit:
    

 

make_clib

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include make.inc
 
MYSRC= $(wildcard $(SRCDIR)/$(SUB)/*.c)
MYTMP= $(patsubst %.c,%.o, $(MYSRC))
MYOBJ= $(patsubst $(SRCDIR)/$(SUB)%,$(OBJDIR)%, $(MYTMP))
all: $(MYOBJ)
 
 
$(MYOBJ): $(OBJDIR)/%.o: $(SRCDIR)/$(SUB)/%.c
    $(CC) -c  $< -o $@
 
clean:
    rm -f $(MYOBJ)
 
submit:
    

 

make_sub

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include make.inc
 
MYSRC= $(wildcard $(SRCDIR)/$(SUB)/*.f90)
MYTMP= $(patsubst %.f90,%.o, $(MYSRC))
MYOBJ= $(patsubst $(SRCDIR)/$(SUB)/%,$(OBJDIR)/$(DEST)/%, $(MYTMP))
all: $(MYOBJ)
 
 
$(MYOBJ): $(OBJDIR)/$(DEST)/%.o: $(SRCDIR)/$(SUB)/%.f90
    $(FC) -c $(FFLAGS)  $< -o $@
 
clean:
    rm -f $(MYOBJ)
 
submit:
    

 

make_mod

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include make.inc
SUB=mod
# 这里必须按照一定顺序填写module源代码文件
MYSRC = $(SRCDIR)/$(SUB)/mod1.f90 \
        $(SRCDIR)/$(SUB)/mod2.f90 \
    $(SRCDIR)/$(SUB)/mod3.f90
 
MYTMP= $(patsubst %.f90,%.o, $(MYSRC))
MYOBJ= $(patsubst $(SRCDIR)/$(SUB)%,$(OBJDIR)%, $(MYTMP))
all: $(MYOBJ)
 
$(MYOBJ): $(OBJDIR)/%.o: $(SRCDIR)/$(SUB)/%.f90
    $(FC) -c $(FFLAGS)  $< -o $@
 
clean:
    rm -f $(MYOBJ)

 

Makefile

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
include make.inc
 
TMPLIB = $(OBJDIR)/../libmytmp_$(CMODE).a
 
 
all: objs main
 
main: $(TMPLIB)
    $(LINK)   $(TMPLIB)  $(LIBDIR) $(LIBS) $(FFLAGS) -o $(EXE)
 
 
#编译所有obj文件并构造库,在make_mod后列出所有src子目录的编译命令  make -f make_sub "SUB=子目录名称"
objs:
    make -f make_mod
    make -f make_sub "SUB=main"
    make -f make_f77 "SUB=f77"
    make -f make_clib "SUB=anis_c"
    $(ARCH) $(ARCHFLAG) $(OBJDIR)/../libmytmp_$(CMODE).a  $(OBJDIR)/*.o
 
     
#删除所有obj文件、mod文件和库,在make_mod后列出所有src子目录的编译命令  make -f make_sub "SUB=子目录名称" clean 来清理给定类别的obj文件
#这里只是举例说明可以指定clean一部分文件,在某些场合下可以采用这个方法进行较为精确的clean控制
cleanall:
    make -f make_mod  clean
    make -f make_sub "SUB=main"  clean
    make -f make_f77 "SUB=f77" clean
    make -f make_clib "SUB=anis_c" clean
    rm -f $(OBJDIR)/../libmytmp_$(CMODE).a
    rm -f $(OBJDIR)/*.mod
 
#粗暴的删除所有编译生成的文件,
clean:
    rm -f $(OBJDIR)/../libmytmp_$(CMODE).a
    rm -f $(OBJDIR)/*.mod
    rm -f $(OBJDIR)/*.o
#创建obj文件目录
dir:
    mkdir  ../obj_$(COMPILER)
    mkdir  ../obj_$(COMPILER)/debug
    mkdir  ../obj_$(COMPILER)/release

 

具体使用时,只需要为module手工填写文件名,其它非module的代码一律自动寻找。第一次编译,需要先 make dir创建目录,而后再make。默认编译优化版本,使用make CMODE=debug会编译调试版本。

 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee