11. module - 國立臺灣大學homepage.ntu.edu.tw/~wttsai/fortran/ppt/11.module.pdf · a major...
TRANSCRIPT
11. Module
12/6/2016
A Major Feature of the Modern Fortran
• Module was introduced in Fortran 90.
• It is a container capable of sharing variables, subroutines, functions, interfaces and other among program units.
• Also, there are extra benefits for sharing them with modules, such as the global scope for variables and explicit interfaces for procedures.
• Two main capabilities a module can do:
1. Sharing data between program units
2. Creating explicit interfaces for procedures
module
integer ::
program subroutine function
module
subroutine ( , )
program
call subroutine ( , )
Pass Fail
• Main program and subroutines/functions exchange data through argument list.
Sharing Data Using MODULE
subroutine fix(elev,dep,nx,ny) implicit none integer,intent(in) :: nx, ny real,intent(out) :: elev(nx,ny), dep(nx,ny) integer :: i, j do j = 1, ny do i = 1, nx elev(i,j)= elev(i,j) + 10.0 dep(i,j) = dep(i,j)/100.0 end do end do end subroutine
program main implicit none intger,parameter :: nx = 100, ny = 100 real :: elev(nx,ny), dep(nx,ny) integer :: i, j do i = 1, nx read(10,*) (elev(i,j), j=1,ny) read(11,*) (dep(i,j), j=1,ny) end do call fix(elev,dep,nx,ny) end program
subroutine fix use share implicit none integer :: i, j do j = 1, ny do i = 1, nx elev(i,j)= elev(i,j) + 10.0 dep(i,j) = dep(i,j)/100.0 end do end do end subroutine
program main use share implicit none integer :: i, j do i = 1, nx read(10,*) (elev(i,j), j=1,ny) read(11,*) (dep(i,j), j=1,ny) end do call fix end program
module share implicit none save integer,parameter :: nx=100, ny=100 real :: elev(nx,ny), dep(nx,ny) end module share
• They can also exchange data using modules.
subroutine fix use share implicit none integer :: i, j do j = 1, ny do i = 1, nx elev(i,j)= elev(i,j) + 10.0 dep(i,j) = dep(i,j)/100.0 end do end do end subroutine
program main use share implicit none integer :: i, j do i = 1, nx read(10,*) (elev(i,j), j=1,ny) read(11,*) (dep(i,j), j=1,ny) end do call fix end program
module share implicit none save integer,parameter :: nx=100, ny=100 real :: elev(nx,ny), dep(nx,ny) end module share
• USE module_name: must be above any other statements except the program or subroutine statement
• SAVE: all data and variables declared preserved in all program units
• module codes must be positioned & compiled before other codes which use it.
module share
program main
subroutine fix
share.mod
share.mod
old
new
• Module must be compiled before main program and subroutines/functions which use it.
> gfortran \ share.f90 main.f90 fix.f90
> gfortran \ main.f90 fix.f90 share.f90
share.mod and a.exe will be created.
module share
program main
subroutine fix
share.mod
new
If share.mod does not exist:
Fatal Error: Can't open module file 'share.mod' for reading at (1): No such file or directory
If share.mod already exists:
The old share.mod will be used in compiling, and a new share.mod will be created.
PROGRAM t_random0 ! Test the random number generator random0 and use of MODULE ! USE ran001 IMPLICIT NONE REAL :: avg, ran, sum INTEGER :: i, iseq ! ! Print out 10 random numbers. WRITE (*,*) '10 random numbers: ' DO i=1,10 CALL random0(ran) WRITE (*,'(3X,F16.6,I12)') ran, iseed END DO ! ! Average 5 consecutive 10000-value sequences. WRITE (*,*) 'Averages of 5 consecutive 10000-sample sequences:' DO iseq=1,5 sum=0. DO i=1,10000 CALL random0(ran) sum=sum+ran END DO avg=sum/10000. WRITE (*,'(3X,F16.6)') avg END DO ! END PROGRAM
MODULE ran001 ! To declare data shared between subs random0 and seed. ! An initial value of iseed is given IMPLICIT NONE INTEGER, SAVE :: iseed = 9876 END MODULE ran001
SUBROUTINE random0 (ran) ! Generate a pseudorandom number with a uniform ! distribution in the range 0. <= ran < 1.0. ! USE ran001 ! Shared seed IMPLICIT NONE REAL, INTENT(OUT) :: ran ! iseed = MOD(8121*iseed+28411, 134456) ! Next number ran = REAL(iseed)/134456. END SUBROUTINE random0
• In Fortran 77 programs, data sharing was implemented with common block.
Deprecated method to share data: common block
subroutine fix() implicit none integer,parameter :: n1 = 100, n2 = 100 real :: a(n1,n2), b(n1,n2) integer :: i, j common /hydro/ elev, dep do j = 1, n1 do i = 1, n2 elev(i,j)= elev(i,j) + 10.0 dep(i,j) = dep(i,j)/100.0 end do end do end subroutine
program main implicit none integer,parameter :: nx = 100, ny = 100 real :: elev(nx,ny), dep(nx,ny) integer :: i, j common /hydro/ elev, dep do i = 1, nx read(10,*) (elev(i,j), j=1,ny) read(11,*) (dep(i,j), j=1,ny) end do call fix() end program
Example:
Don't use it in your new program since it is not as flexible as sharing data through modules
Variable Passing in Fortran: the Pass-by-Reference Scheme
What passed to the subroutine are the pointers to the memory addresses containing the calling arguments, not the actual values.
program test
subroutine sub1
program test real :: a, b(2) integer :: n call sub1(a,b,n) end program
The Fortran compiler will not recognize if the arguments between the main program and the subroutine are mismatched, e.g., real to integer, scalar to array.
Errors like this are extremely difficult to find and debug.
subroutine sub1(x,y,i) real, intent(out) :: x real, intent(in) :: y(2) integer :: i end subroutine sub1
a b(1) b(2) n
x y(1) y(2) i
Memory 1 byte
Only these addresses are passed
4 bytes = 32 bits integer = 24+8 bits real
program bad_call ! To illustrate mismatch of calling argument implicit none real :: x=1. call bad_argument(x) end program bad_call
The Fortran compiler will not recognize if the arguments between the main program and the subroutine are mismatched, e.g., real to integer, scalar to array.
Errors like this are extremely difficult to find and debug.
Compile and execute using GNU Fortran:
> gfortran bad_call.f90
bad_call.f90:5.18: call bad_argument(x)1 Warning: Type mismatch in argument 'i' at (1); passed REAL(4) to INTEGER(4) > a.exe i= 2130567168
Compile and execute using Intel Fortran:
> ifort bad_call.f90 > a.out i= -1191408000
4 bytes = 32 bits integer = 24+8 bits real
subroutine bad_argument(i) implicit none integer :: i write(*,*) 'i=',i end subroutine bad_argument
Example:
Using Modules to Create Explicit Interfaces
MODULE my_subs CONTAINS subroutine bad_argument(i) implicit none integer :: i write(*,*) 'i=',i end subroutine bad_argument END MODULE my_subs program bad_call2 ! Use MODULE to detect mismatch of arguments ! USE my_subs implicit none real :: x=1. call bad_argument(x) end program bad_call2
module procedure
• Procedures in modules (called module procedure) have explicit interfaces automatically.
Example:
Compile and execute using Intel Fortran:
> ifort bad_call2.f90 bad_call2.f90(17): error #6633: The type of the actual argument differs from the type of the dummy argument. [X] call bad_argument(x) ------------------^ compilation aborted for bad_call2.f90 (code 1)
Compile and execute using GNU Fortran:
> gfortran bad_call2.f90 bad_call2.f90:17.18: call bad_argument(x) 1 Error: Type mismatch in argument 'i' at (1); passed REAL(4) to INTEGER(4)
Implicit interface
subroutine fix (elev,dep,nx,ny) implicit none integer,intent(in) :: nx, ny real,intent(out) :: elev(nx,ny), dep(nx,ny) integer :: i, j do j = 1, ny do i = 1, nx elev(i,j)= elev(i,j) + 10.0 dep(i,j) = dep(i,j)/100.0 end do end do end subroutine
program main implicit none intger,parameter :: nx = 100, ny = 100 real :: elev(nx,ny), dep(nx,ny) integer :: i, j do i = 1, nx read(10,*) (elev(i,j), j=1,ny) read(11,*) (dep(i,j), j=1,ny) end do call fix (elev,dep,nx,ny) end program
• Types of arguments are implicit between program units.
• Coders should check type mismatch themselves.
Example:
module my_subs contains subroutine fix (elev,dep,nx,ny) implicit none integer,intent(in) :: nx, ny real,intent(out) :: elev(nx,ny), dep(nx,ny) integer :: i, j do j = 1, ny do i = 1, nx elev(i,j)= elev(i,j) + 10.0 dep(i,j) = dep(i,j)/100.0 end do end do end subroutine end module
program main use my_subs implicit none integer,parameter :: nx = 100, ny = 100 real :: elev(nx,ny), dep(nx,ny) integer :: i, j do i = 1, nx read(10,*) (elev(i,j), j=1,ny) read(11,*) (dep(i,j), j=1,ny) end do call fix (elev,dep,nx,ny) end program
• Types of arguments are explicit between program units.
• Compiler can check type mismatch automatically.
Explicit interface
Example:
Keyword Arguments
• If a procedure's interface is explicit, then it is possible to use keyword arguments and optional arguments in the calling program to enhance flexibility.
module my_mod contains real function calc (first,second,third) implicit none real,intent(in) :: first, second, third calc = (third-first)/second end function end module
program t_keywords use my_mod implicit none write(*,*) calc(1.0,2.0,3.0) write(*,*) calc(first=1.0,second=2.0,third=3.0) write(*,*) calc(second=2.0,third=3.0,first=1.0) write(*,*) calc(1.0,third=3.0,second=2.0) end program
Example:
1.0000000 1.0000000 1.0000000 1.0000000
Execute:
• An optional argument is a dummy procedure argument that are not always be present. It is only possible in procedures with explicit interface.
module my_mod contains subroutine calc(first,second,third,ans) implicit none real,intent(inout) :: third real,intent(in) :: first, second real,intent(out),optional :: ans if (present(ans)) then ans = (third-first)/second else third = (third-first)/second end if end subroutine end module
program t_optional use my_mod implicit none real :: answer, one=1.0, two=2.0, three=3.0 call calc(second=two,third=three,first=one,ans=answer) write(*,*) answer call calc(second=two,third=three,first=one) write(*,*) three end program
Optional Arguments
Example:
1.0000000 1.0000000
Execute:
• There is still other way to define interface (in case you don't want to use modules).
program interface_example implicit none ! Declare interface to subroutine "sort" interface subroutine sort(a,n) implicit none real,dimension(:),intent(inout) :: a integer,intent(in) :: n end subroutine sort end interface ! Declare local variables real,dimension(6) :: array = & (/1.,5.,3.,2.,6.,4./) Integer :: nvals = 6 ! Call "sort" to sort data call sort(n=nvals,a=array) write(*,*) array end program
subroutine sort(a,n) implicit none real,dimension(:),intent(inout) :: a integer,intent(in) :: n real :: tmp integer :: i, j, n_right n_right = 0 do j = 1, n-1 do i = 2, n-n_right if (a(i-1) > a(i)) then tmp = a(i) a(i) = a(i-1) a(i-1) = tmp end if end do n_right = n_right + 1 end do end subroutine sort
Interface Block
The interface block can be put after the declaration section as well
Example:
Restricting Access of Module Data/Procedures
program restrict use my_mod, only: a, plus_two implicit none real :: b = 10.0 a = 100.0 call mult_two(a) write(*,*) a*b end program
module my_mod implicit none real :: a, b contains subroutine plus_two(x) implicit none real :: x x = x + 2.0 end subroutine subroutine mult_two(x) implicit none real :: x x = x * 2.0 end subroutine end module
> gfortran restrict.f90 restrict.f90: undefined reference to `mult_two_'
Compile:
• Variables, subroutines, and functions in modules can be partially invoked, using only in use statement.
• The purpose is to prevent naming conflicts
Example:
• Variables, subroutines, and functions in modules can be invoked as other names, using => in use statement.
• The purpose is to prevent naming conflicts
Renaming Module Data/Procedures
program rename use my_mod, money=>a, m2=>mult_two implicit none real :: a = 30.255 money = 10000.0 call m2(money) write(*,*) money*a end program
local_name=>module_name module my_mod implicit none real :: a, b contains subroutine plus_two(x) implicit none real :: x x = x + 2.0 end subroutine !------------------------ subroutine mult_two(x) real :: x x = x * 2.0 end subroutine end module
605100.00
Execute:
Example:
• Linear least-square approximation is a standard method to approximate over-determined systems.
• Consider time series of magnitude 𝑌𝑖 at time 𝑥𝑖, total 𝑁 data. If you want to approximate them with a linear curve 𝑦 = 𝑎𝑥 + 𝑏, the least-square approximation literally states that the summation of error 𝑌𝑖 − 𝑦𝑖
2 should be minimal:
Exercise : Linear Least-Square Approximation
𝑆 = 𝑌𝑖 − 𝑦𝑖2
𝑁
𝑖=1
= 𝑌𝑖 − 𝑎𝑥𝑖 − 𝑏2
𝑁
𝑖=1
𝑌𝑖
𝑦 = 𝑎𝑥 + 𝑏 𝑎 𝑥𝑖
2 + 𝑏 𝑥𝑖 = 𝑥𝑖𝑌𝑖
𝑎 𝑥𝑖 + 𝑏𝑁 = 𝑌𝑖
𝑐1𝑎 + 𝑐2𝑏 = 𝑐3
𝑐4𝑎 + 𝑐5𝑏 = 𝑐6
For the minimal 𝑆,
𝜕𝑆
𝜕𝑎= 0
𝜕𝑆
𝜕𝑏= 0
𝑎 =−𝑐3𝑐5 + 𝑐2𝑐6−𝑐1𝑐5 + 𝑐2𝑐4
𝑏 =𝑐3 − 𝑐1𝑎𝑐2
1. Read the data 𝑥𝑖 (first column) and 𝑌𝑖 (second column) in the data file xy.dat shown below. The total number of data 𝑁 is given in the first line.
2. Develop a subroutine leastsq_linear1(N, x, Y, a, b) in a module sub_module to calculate 𝑎 and 𝑏 of the linear curve.
3. Develop a subroutine leastsq_linear2() without any dummy arguments to calculate 𝑎 and 𝑏. It should be outside a module. Use a module data_module to share variables between the subroutine and the main program.
4. Both programs should print out 𝑎 and 𝑏.
module sub_module leastsq_linear1(N, x, Y, a, b) end module program (Read data) call leastsq_linear1(N, x, Y, a, b) write(*,*) a, b end program
module data_module (Declare N, x, Y, a, b) end module subroutine leastsq_linear2() ... end subroutine program (Read data) call leastsq_linear2() write(*,*) a, b end program
leastsq_linear1 leastsq_linear2
25 0.10000000 -1.3146429 0.20000000 -3.1990519 0.30000001 -0.10450792 0.40000001 -0.71243405 0.50000000 -2.2956548 0.60000002 -0.91617846 0.69999999 -2.6574748 0.80000001 -2.3678687 0.90000004 0.38248765 1.0000000 1.0534627 1.1000000 1.0077106 1.2000000 1.1989625 1.3000001 6.5031471 1.4000000 4.1205955 1.5000000 5.1728935 1.6000000 7.1715932 1.7000000 3.9966502 1.8000001 8.5051289 1.9000000 9.1784534 2.0000000 7.9379234 2.1000001 11.834155 2.2000000 9.8077221 2.3000000 9.3412457 2.4000001 14.611238 2.5000000 13.090397
xy.dat