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

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

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

w=w1

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

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

 

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

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模式编译没有问题。但是优化编译后出错。最后改为

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文件,这导致我计算出的速度数据文件和压强数据文件以及涡量数据文件没法在一个图中操作显示。

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

使用方法

 

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

 

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的子目录即可。一个例子如下

 

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

 

# 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

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

 

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

 

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

 

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

 

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