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 |
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, n var , newp3df) IMPLICIT NONE INTEGER,INTENT(IN) :: ndatafiles, n var (:) CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: datafiles CHARACTER(LEN=*),INTENT(IN) :: newp3df INTEGER,POINTER,DIMENSION(:) :: ni,nj,nk INTEGER,INTENT( in ) :: nb ! local INTEGER n var s, tmpint, b, n, i,j,k,l INTEGER,POINTER,DIMENSION(:) :: offset, funit,shift REAL( 4 ),POINTER,DIMENSION(:,:,:,:) :: gdata n var s = SUM( n var ( 1 :ndatafiles) ) OPEN( 33 ,FILE=TRIM(newp3df),action= 'write' , form= 'unformatted' ) WRITE( 33 ) nb WRITE( 33 ) (ni(b),nj(b),nk(b),n var s, 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) + n var (n) ENDDO DO b= 1 , nb ALLOCATE( gdata(ni(b),nj(b),nk(b), n var s) ) 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 ,n var s ) 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),n var (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 get var names(ndatafiles, datafiles, var names, n var ) IMPLICIT NONE INTEGER,INTENT(OUT) :: ndatafiles INTEGER,DIMENSION(:), INTENT(OUT) :: n var CHARACTER(LEN=*),DIMENSION(:),INTENT(OUT) :: var names,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 n var (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 n var (n) = n var (n) + 1 i = i + 1 var names(i) = tmpstr WRITE(*,*) i, TRIM( var names(i) ) ELSE notend = .FALSE. ENDIF ENDDO CLOSE( 33 ) ENDDO !DO n= 1 ,i ! WRITE(*,*) TRIM( var names(n) ) !ENDDO !WRITE(*,*) n var ( 1 :ndatafiles) END SUBROUTINE SUBROUTINE mergename(ndata, n var , var names, namefile) INTEGER,INTENT(IN) :: ndata INTEGER,DIMENSION(:),INTENT(IN) :: n var CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: var names CHARACTER(LEN=*),INTENT(IN) :: namefile ! local INTEGER :: i,j,n OPEN( 33 ,FILE=TRIM(namefile)) j = 0 DO n= 1 , ndata DO i= 1 , n var (n) j=j+ 1 WRITE( 33 , *) TRIM( var names(j)) ENDDO ENDDO END SUBROUTINE END MODULE PROGRAM main USE mergep3d IMPLICIT NONE INTEGER :: ndata,n var ( 1024 ),nb,ierr INTEGER,POINTER,DIMENSION(:) :: ni,nj,nk CHARACTER(LEN= 64 ) :: fnames( 1024 ), var names( 1024 ),newp3df,newname CALL get var names(ndata, fnames, var names, n var ) 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, n var , TRIM(newp3df) ) CALL mergename(ndata, n var , var names, 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目录中关键的文件有
- make.inc,定义所有编译参数
- make_mod,专用于编译module
- make_f77,专用于编译fortran77代码
- make_clib,专用于编译c文件
- make_sub,用于编译其它src下子目录中fortran90代码
- 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 -fback trace 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会编译调试版本。