Implicit None
常用:类型( 属性 ) , 形容词 , 形容词 … :: 变量名(数组外形)= 值 , 变量名2(数组外形)= 值
定义多个变量用,
隔开,用空格不行
整型(Integer)
实型(Real)
复数Complex 类型(本质上是real)
字符型(Character)
派生(type)类型
Real(Kind=8) , parameter , private :: rVar = 20.0d0
Character(Len=32) , Intent( IN ) :: cStr(5,8)
Integer , save :: n = 30 , m = 40
Integer m
complex :: com
#如果( , )构造复数报错,可以使用cmplx(real,image)函数
yc(i)=cmplx(yr(i),yi(i))
数值型kind
用于解决不同编译器默认表达范围不一致问题
整形最大可表示i位示例
! k = Selected_Int_Kind( i ) 可以用这个函数来选择能满足要求的Kind
! i 表示需要最大的十进制位数
! k 表示返回的能满足范围的最小的Kind值
! Selected_Int_Kind( i )函数可以放在声明语句里
integer , parameter :: KI=selected_int_kind(10)
integer(kind=KI) :: i1 i2 i3
! k = Selected_Real_Kind( r , p ) 可以用这个函数来选择能满足要求的Kind
! r 表示需要最大的十进制位数 , p 表示最小的有效位数 p位*E^r
! k 表示返回的能满足范围的最小的Kind值
integer , parameter :: DP=selected_real_kind(r=50,p=14)
real(kind=DP) :: r1 r2
双精准度 - 使用两个双精准浮点数
complex(kind=8) a ! F90新增作法
complex(8) a !
COMPLEX*16 a ! F77传统作法
在数值后面加kind数值,表明数值类型,如siesta
! Initialize some variables(Double precision:dp=8)
DUext = 0.0_dp
Eharrs = 0.0_dp
Eharrs1 = 0.0_dp
若一个函数要求输入双精度实数,要传递xxx.xx_dp
给这个函数,否则会结果异常,如
call Pdgemm("N","N",2,8,2,1.0_dp,A,1,1,DESCA,B,1,1,DESCB,0.0_dp,C,1,1,DESCC)
平方根函数要求sqrt()
输入为实数或复数,因此sqrt(2)
会报错,而sqrt(2.0)
才是正确的
complex与实数kind一样
字符型len
kind默认为1(ASCII码格式),也可通过Selected_Char_Kind( ‘ASCII’ )确定
len表示长度
character(len=32) :: str
parameter 常量
syslab=" ---abc==="
write(*,*) "adjustl"//adjustl(syslab)//"end"
write(*,*) "adjustr"//adjustr(syslab)//"end"
write(*,*) "trim"//trim(syslab)//"end"
write(*,*) "trim(adjustl)"//trim(adjustl(syslab))//"end"
# |< >!
adjustl---abc=== end
adjustr ---abc===end
trim ---abc===end
trim(adjustl)---abc===end
INDEX示例
str="hello,world"
WRITE(*,*) INDEX(str,"llo") !返回结果为3,即str中第3个元素及之后是llo
类型,形容词 :: 数组名(n1,n2,n3...维度)
类型,形容词 :: 数组名(n0:n1,m0:m1,...) 也可以,n0,m0也可从负数开始
加上allocatable
形容词
类型,allocatable,其他形容词 :: 数组名(:,:,:....) !用:
!分配大小
allocate(array(N))
!释放空间
deallocate(array)
ALLOCATE分配的数据边界可以是正数,负数,0
参考数组赋值与运算
可用在倒格失的定义当中如qe的FFTXlib/stick_base.f90
文件
ALLOCATE(array(lb:ub))
ALLOCATE(b(-4:4))
DO i = -4,4
b(i) = i
ENDDO
WRITE(*,*) "b(-2:0)",b(-2:0)
b(-2:0) -2 -1 0
内存中的存储顺序为array(1,1,1)->array(2,1,1)->array(3,1,1)->array(1,2,1)
所以do r=1,n1 sum=sum+array(r,1,1)
比do r=1,n1 sum=sum+array(1,1,r)
的语法就是最快的
同理,不建议高维数组
data
只能用来赋初值,已赋值后,调用无效
data
的顺序
data((A(i,j),i=1,2),j=1,3) /1,2,3,4,5,6/
1.00000000 3.00000000 5.00000000
2.00000000 4.00000000 6.00000000
integer :: array(5),A(2,3)
!使用data赋值,后面的值要和前面的一一对应
array(1)=1
array(2:5)=3
data array /1,2,3,4,5/
data array /5*5/ !*表重复 /5,5,5,5,5/
data((A(i,j),i=1,2),j=1,3) /1,2,3,4,5,6/
!(f(I),i=1,5)就代表一组循环,i从1到5,输出f(i),例如
A=(/(I*I,I=1,6)/)
!可直接进行调用或赋值
array(n,m)
array(n,:)
array(:)
A(:,:)
array(:,n)
与array(n,:)
都视为一行矩阵,可以互相赋值,即列和行可以互相赋值
+-*/function()
都是对应元素操作,不是数学矩阵操作
> <
返回逻辑值,也是对应元素比较
可以 b=2*a
等价于b(i)=2*a(i)
,加减乘除都行
也可以a*b
不过是matlab中的点乘
2.1.15 数组查询函数
default return value of ubound and lbound
MAXVAL
WRITE(*,"(A,I1,A,I4)") "max is a(",MAXLOC(a),"), which is",MAXVAL(a)
WRITE(*,"(A,I1,A,I4)") "min is a(",MINLOC(a),"), which is",MINVAL(a)
注意MAXLOC
返回的是数组,即使a是一维的,a(MAXLOC(a))
只有一个数,也要用数组变量去接受最大值
用ANY
判断数组元素
RESULT = ANY(MASK [, DIM])
ANY( (/.true., .false., .true./) )
可以返回是否有成立值,应该不仅可以用来判断整数,逻辑数组都可以,如
IF( ANY( a .EQ. 0 ) ) WRITE(*,*) "At least one 0 in a"
IF( .NOT. ANY( a > 90 ) ) WRITE(*,*) "No one > 90 in a"
结构体 TYPE
结构体,type内只有变量
type内含有方法(函数)时,就是类了->面向对象编程了
定义结构体类型
TYPE ,形容词 :: 结构体名
变量表(声明语句)
END TYPE
将结构体实体化,也可实体化为数组
TYPE(结构体名) :: 变量名
type :: student
character :: nickname,address
integer :: num,score
end type
type(student) :: xiaoming
结构体名%成员名 !优先使用
结构体名.成员名 !gfortran好像不支持
xiaoming%nickname
xiaoming.num
TYPE(student)::xiaoming=student (“xiaoming","china",1,90), S2, S3
xiaoming.score=95
类是在结构体的基础上,面向对象的拓展
指针POINTER
属性
被指针指向的变量TARGET属性
指向变量p1=>t1
,检查是否指向TARGET变量ASSOCIATED(POINTER,[TARGET])
,示例
PROGRAM pointer_
IMPLICIT NONE
INTEGER,POINTER :: p1
INTEGER,TARGET :: i1,i2
NULLIFY(p1)
i1=1; i2=2
p1=>i1 ; WRITE(*,*) p1,ASSOCIATED(p1),ASSOCIATED(p1,i1),ASSOCIATED(p1,i2)
p1=>i1 ; WRITE(*,*) p1,ASSOCIATED(p1),ASSOCIATED(p1,i1),ASSOCIATED(p1,i2)
NULLIFY(p1) ; WRITE(*,*) p1,ASSOCIATED(p1),ASSOCIATED(p1,i1),ASSOCIATED(p1,i2)
END PROGRAM
cndaqiang@girl:~/code/test$ gfortran point.f90 ; ./a.out
1 T T F
1 T T F
0 F F F
数据类型转换
!1,数字转字符
write(str1,"(i4.4)") num ! 如有需要,不足四位前面补零
print*,str1
!2,字符转数字
read(str1,"(i2)") num
print*,str1
流程控制 IF SELECT
IF(条件) 执行语句
IF (条件) THEN
ELSE IF (条件) THEN
ELSE IF (条件) THEN
END IF
!ELSE IF与ELSE可不写
SELECT
SELECT case (表达式)
case(A)
case(B)
END SELECT
!好像表达式结果只能为整数或字符串,A,B...也要对应
CYCLE 进入下一循环
EXIT 结束循环
DO i=start,end [,step]
!步长step默认为1,可设置为正,负
!不写i=1,end 无穷循环
END DO
结束后i=end+1
DO WHILE()
DO WHILE(条件)
END DO
FORALL屏蔽赋值
数组赋值与运算
FORALL是F95的新增功能。它是数组屏蔽赋值(WHERE语句和构造)功能的一对一元素的推广,其方式有FORALL语句和FORALL构造。
FORALL语句的一般形式为:FORALL(循环三元下标[,循环三元下标]…[,屏蔽表达式]) 赋值语句
FORALL构造的一般形式为:
[构造名:] FORALL(循环三元下标[,循环三元下标]…[,屏蔽表达式])
END FORALL [构造名]
屏蔽表达式是数组逻辑表达式,缺省值为.TRUE.。块是赋值语句,或为WHERE语句或构造,或为FORALL语句或构造。
循环三元下标的形式为:循环变量=下界:上界[:步长]。循环变量是整型的。步长不能为0,缺省值为1。
PROGRAM forallT
INTEGER :: a(10),b(10)
INTEGER :: i
DO i=1,10
a(i) = i
ENDDO
b=0
FORALL(i=1:10,a(i)>5) b(i)=6
WRITE(*,*) b
END PROGRAM
cndaqiang@girl:~/code/test$ gfortran forall.f90 ; ./a.out
0 0 0 0 0
6 6 6 6 6
WHERE
可以找到数组中符合条件的项,然后操作另一数组中相同的项,如
PROGRAM whereT
INTEGER :: a(10),b(10)
INTEGER :: i
DO i=1,10
a(i) = i
ENDDO
b=0
WHERE(a>5)
b=6
ELSEWHERE(a>3)
b=4
ELSEWHERE
b=1
ENDWHERE
WRITE(*,*) b
WHERE(a>5) a=0
WRITE(*,*) a
END PROGRAM
cndaqiang@girl:~/code/test$ gfortran where.f90 ; ./a.out
1 1 1 4 4
6 6 6 6 6
1 2 3 4 5
0 0 0 0 0
格式化输入输出
READ(unit=设备号/字符串名称,fmt=格式或行号) 格式化输入
读取一行数据,且存到矩阵
read(unit,*) ika, ((eig(ib,is), ib = 1, nband), is = 1, nspin)
#此处先进行ib循环,再进行is循环
WRITE(unit=设备号/字符串名称,fmt=格式) 格式化输出
默认设备是键盘,用5
或*
表示,还可以是外部文件(open文件时指定设备号)
输入输出为字符串时,等价于将字符串视为文件,称为内部文件
实现整数/实数<=>字符串
格式适合一次控制,"格式内容"
行号可以在很多次输出都采用统一格式时,减少书写量
READ(设备号,格式行号)
也可以
READ(*,*)
*
分别表示默认键盘和不指定格式
READ(*,*) a,b,c
一次读取多个数据赋值给a,b,c
格式化输出控制
默认WRITE后会换行,设置advance="no"
取消换行,如
注意:ifort有bug,还要再加上一个FLUSH,不然也会出现随机换行事件
WRITE(funit,9035,advance="no")
FLUSH(funit) #ifort要用这个确保不会换行
FMT=*
读写
WRITE(unit,FMT=*) var
时, 会根据var
的内容进行写,有些编译器(ifort)会写成多行,gfortran一般写成一行
如果写到了第n
行, 再次调用WRITE
时, 从n+1
行开始写
READ(unit,FMT=*) var
时, 会根据var
的内容进行读, 如果当前行的数据不够, 会读取下面几行
如果读到了第n
行, 再次调用READ
时,从n+1
行开始读
针对这些特点, 我们读写的数据如果不是给人看的, 按照数组下标,或者直接将一个数组WRITE(unit,FMT=*)
即可, 而且不同编译器之间都可以互相读写
给人看的时候才要考虑格式化输出
输出未知数目的数时
先计算出FMT并保存到字符串中,再用这个字符串作为FMT输出
real :: a(10)
write(s,fmt="(a3,i3,a6)") "(a,",UBOUND(a,1),"f12.6)"
write(*,fmt=s) a
当变量比格式多时,会重复格式进行输入,如
REAL(8) :: b(10)
b=1.0
write(*,10) b
10 FORMAT(1X,2E20.8)
write(*,"(1X,3E20.8)") b
b会按照格式每行输出2/3个,直到输出完毕为止
函数与主程序program并列
主程序和函数无先后次序
function 与subroutine除了返回值,和声明方式,没有区别
函数都是传址调用
function
[形容词][,返回类型] function 名称([虚参列表])
[虚参声明]
[局部变量定义]
名称=返回值
[return]
End [function [名称]]
用前要声明
external
interface
contains
包含在程序单元内
用module
引入
返回变量=名称([实参列表])
调用外部函数function,要在变量定义区指明,子程序subroutine不用
CHARACTER(len=6), EXTERNAL :: int_to_char
Error: Function ‘int_to_char’ at (1) has no IMPLICIT type
td_analysis.f90:90:89:
subroutine
[形容词] subroutine 名称([虚参列表])
[虚参声明][局部变量定义]
名称=返回值
[return]
End [subroutine [名称]]
直接call
call 名称([实参列表])
使用前的声明
使用function前用external
声明,或使用interface
声明
program externalOrinterface
implicit none
real :: x,y
real ,external :: fun !函数要声明
x=1.0
y=fun(x)
write(*,*) y
call sub(x)
end program externalOrinterface
real function fun(x)
real :: x
fun=x*x+1.0
end function fun
subroutine sub(x)
real :: x,y
y=x*x+1.0
write(*,*) y
end subroutine sub
interface
fun也可使用interface
代替external
,有些特殊用法需要用interface声明
interface
real function fun(x)
real :: x
end function fun
end interface
使用以下用法时,必须使用 interface:
• 函数返回值是数组、指针
• 参数为假定形状数组
• 参数具有 intent、value 属性
• 参数有可选参数、改变参数顺序
以下用法时,虽然不强制要求,但也推荐使用 interface
• 函数名作为虚参和虚参
实际上,我们建议在任何函数调用时,都使用接口!
每个程序单元调用其他函数时都要interface,用module可以减少书写那么多interface
interface同名函数重构
使用interface
和module procedure
定义同名函数,会根据函数输入变量类型自动匹配
(python27) ~/code/TDQE/Fortran/module_interface $ cat main.f90
program main
use m_interface
integer :: aa(5),bb(5)
call my_sum(aa(1),bb(1))
call my_sum(aa,bb)
end program(python27) ~/code/TDQE/Fortran/module_interface $ cat module.f90
module m_interface
interface my_sum
module procedure my_sum_integer
module procedure my_sum_array
end interface
contains
subroutine my_sum_integer(a,b)
INTEGER :: a,b
write(*,*) "my_sum_integer:",a+b
end subroutine
subroutine my_sum_array(a,b)
INTEGER ::a(:),b(:)
write(*,*) "my_sum_array",a+b
end subroutine
end module
mpif90 -c -g -O2 -ffree-line-length-none module.f90
mpif90 -c -g -O2 -ffree-line-length-none main.f90
mpif90 -g -O2 -ffree-line-length-none -o interface main.o module.o
./interface
my_sum_integer: 3
my_sum_array 3 3 3 3 3
contains
在程序单元(主程序,function,subroutine)内使用contains
,contains后面跟的函数,仅可以被此程序单元调用,且不用声明
module
内部的函数也用contains
,use module_name
后,可以调用
contains
后面的函数可以直接调用程序单元和module
里的变量
real function fun(x)
implicit none
real ::x,y
y=23.0
fun=x*3.0
fun=two(fun)
contains !使用contains
real function two(x)
real ::x
two=x*2.0+y !可以直接调用程序单元或module里的变量
end function two
end function fun
module 内部函数互相调用不用声明
参数传递:在函数内解释参数
传递字符串
声明时len=*
,siesta得代码中常见
program strsub
implicit none
character(len=20)::str
str="hello,world!"
call sub(str)
contains
subroutine sub(strr)
implicit none
character(len=*) :: strr
write(*,*) trim(strr)
end subroutine sub
end program strsub
传递数组-数组地址维度大小都会传过来
program pro
implicit none
real :: array(10),total
integer I
array=(/(I,I=1,10)/)
total=sum(array(2:3))
write(*,*) total
end program pro
real function sum(a)
real::a(:) !多维时a(:,:),传入参数的下标变为1,2,3...,size(a,dim=n),上限自动计算,下线也可指定
!real::a(n)取出传过来的数组的前n个元素作为一个数组
integer :: i
sum=0
do i=1,size(a,dim=1)
sum=sum+a(i)
end do
end function sum
也可以把数组维度作为参数传入
也有用real :: a(*)
,老程序中有,会将输入数组变为1维,适合于不同维度的矩阵运算,如不同维度矩阵相加
module m_matradd
implicit none
contains
subroutine matradd(m,n,A,B,C,lds)
implicit none
integer :: m,n,i,j,lds
real:: A(*),B(*),C(*)
!其实fortran直接 C=A+B 就可以
!C(1:m*n)=A(1:m*n)+B(1:m*n)
DO j=0,n-1
DO i=1,m
C(i+j*lds)=A(i+j*lds)+B(i+j*lds)
end DO
end DO
end subroutine matradd
end module m_matrad
传递结构体-用module
主程序和子程序需使用同一个结构体定义,使用module
modele里面include
mpif.h后,调用该module的程序不用include了**
**module里面
inplicit none`后,对调用该module的程序无影响
module typedef
implicit none
type :: student
character(len=10) :: nickname
integer :: num,score
end type
end module typedef
program cndaqiang
use typedef
!use module名 要在其他语句之前
implicit none
type(student)::xiaoming
xiaoming%nickname="xiaoming"
xiaoming%num=1
xiaoming%score=95
call sub(xiaoming)
end program
subroutine sub(who)
use typedef
implicit none
type(student)::who
write(*,*) who%nickname(:),who%num
end subroutine
在函数体内用interface
声明传入参数的类型
module mod_fun
!real :: x,y
contains
real function fun(test,x)
implicit none
interface !函数作为参数时,要用interface声明(解释)函数类型
real function test(x)
real ::x
end function
end interface
real :: x
fun=test(x)+x
end function fun
real function test(x)
implicit none
real :: x
test=x*x+x
end function test
end module mod_fun
program inter
use mod_fun !使用module导入的函数,不用声明
implicit none
real :: x,y
x=3.0
y=fun(test,x)
write(*,*) y
end program inter
save属性
函数执行完后,空间不释放,下次执行该函数时作为初值
Integer , save :: var
Integer :: var = 0 !// 虽然没有书写 save ,但定义时初始化值,有具有 save 属性
虚参的 Intent 属性(需要 Interface)
明确指定虚参的目的:输入参数、输出参数、中性参数
!//输入参数,在子程序内部不允许改变
Integer , Intent( IN ) :: input_arg
!//输出参数,子程序返回前必须改变(对应实参不能是常数,也不能是表达式)
Integer , Intent( OUT ) :: output_arg
!//中性参数
Integer , Intent( INOUT ) :: neuter_arg
Integer :: neuter_arg !// 未指定 Intent 则为中性
请注意:Intent 的检查是在编译时进行,而非运行时检查
建议对每一个虚参都指定 Intent 属性!
虚参的 value 属性(需要 Interface)
指定该参数为传值参数,而非传址参数。
!//传值参数,只能作为输入参数。改变后不影响实参。
Integer , value :: by_value_arg
请注意:除混编之外,一般不使用 value 属性
可选参数optional(