A Quick Fortran 77 CourseHans Petter Langtangen
Simula Research Laboratory
&
Dept. of Informatics, Univ. of Oslo
February 2004
A Quick Fortran 77 Course – p. 1
Advantages of Fortran 77
F77 is a very simple language
F77 is easy to learn
F77 was made for computing mathematical formulasand operating efficiently on plain arrays
F77 is still (and will forever be?) the dominatinglanguage for numerical computing
Lots of well tested and efficient F77 libraries exist
Compilers have 50 years of experience with optimizingF77 loops over arrays
Result: F77 is hard to beat when it comes to arrayoperations
A Quick Fortran 77 Course – p. 2
Disadvantages of Fortran 77
The basic variables types are primitive
No struct or class construct in F77
No dynamic memory allocation
Very primitive language for text processing, lists andmore complicated data structures
F77 codes are difficult to extend, maintain and re-use
F90/F95: extension of F77 with classes(but not virtual functions, templates etc.)
The efficiency of F90/F95 is still problematic, and F77programmers move very slowly to F90/F95
A Quick Fortran 77 Course – p. 3
My opinion
F77 is attractive for time-critical loops (array operations)
Make the rest of the program in a higher-level language:Python, C++, Java or F95
Python and F77 is an easy-to-use pair!
Note: integration of F77 with C++ or Java is notstraightforward
A Quick Fortran 77 Course – p. 4
Formatting rules
Lines starting with a character in column 1 arecomment lines
Program statements must begin in column 7 or later
A character in column 6 indicates continuation of theprevious line
Labels (for “go to”) appear as numbers in column 2-5
Only one statement per line
No use of semicolon after a statement
White space has no meaning (can be omitted)
A Quick Fortran 77 Course – p. 5
Example on source code file format
C lines starting with a char in column 1 are commentsC program statements start in column 7
C lines can be continued with a char in column 6:REAL R, S1,
& S2, S3
GO TO 100C label numbers (can be avoided) appear in column 2-5
10 CONTINUE100 CONTINUE
C only one statement can appear at each line
C Traditional F77 used upper-case chars and up to 6 charsC in variable names - most modern compilers allow much longerC variable names
C F77 is not case sensitive
A Quick Fortran 77 Course – p. 6
Basic variable types
INTEGER NREAL R
C array A of length N, indices from 1 to N:REAL A(N)
C other arrays:DOUBLE PRECISION B(N,N), Q(-1:N), P(0:N,3,2)
C array sizes: NxN N+2 (N+1)x3x2C array indices start at 1 unless explicitly specified
C boolean variables:LOGICAL ON, CONVGD
C Fortran has full support for complex numbers:COMPLEX Z, Y
C alternative floating-point types:REAL*4 VAR1, VAR2REAL*8 VAR2, BARR(N)
A Quick Fortran 77 Course – p. 7
Subroutines
Subroutine (no return value):SUBROUTINE MYFUNC2(F1, F2, N, M)
C first declare the variable types of the arguments:INTEGER N, MREAL*4 F1(N), F2(M,N)
C declare local variables in the routine:REAL*4 A, B, C
C computing statements:...RETURNEND
Example on call:INTEGER P, QREAL*8 A(P), A0(Q,P)...CALL MYFUNC(A, A0, Q, P)...
A Quick Fortran 77 Course – p. 8
Functions
Functions return a single value:REAL*8 FUNCTION PTCOOR(COOR, PT, DIR, N)INTEGER N, PT, DIRREAL*8 COOR(N,2)PTCOOR = COOR(PT,DIR)RETURN
C the PTCOOR variable (equals the name of the functionC is returned from this function
Example on call:INTEGER NREAL*8 C...C = PTCOOR(COOR, 8, 1, N)
All arguments to subroutines and functions aretransferred as “pointers” (call by reference) so anychange to COOR, PT, DIR or N above is visible in thecalling code
A Quick Fortran 77 Course – p. 9
No dynamic memory allocation
Arrays must be allocated with a length fixed at compiletime
INTEGER LENGTHPARAMETER (LENGTH=10000)
C array with fixed size at compile time:REAL*8 ARR(LENGTH)
CALL MYFUNC(ARR, LENGTH)...
C in a subroutine,C the array can have "variable" size:
SUBROUTINE MYFUNC(A, N)INTEGER NREAL*8 A(N)...
Ugly techniques exist for simulating dynamic memoryallocation
A Quick Fortran 77 Course – p. 10
Scratch arrays
If you need scratch arrays inside a routine, these mustbe allocated outside (with fixed length) and provided asarguments:
INTEGER NPARAMETER (N=390000)REAL*8 WORK1(N)...CALL MYFUNC3(Q1, Q2, N, WORK1)...
SUBROUTINE MYFUNC3(Q1, Q2, N, SCRATCH)INTEGER NREAL*8 Q1, Q2, SCRATCH(N)...
A Quick Fortran 77 Course – p. 11
Main program
The main program starts with PROGRAM:PROGRAM MYPROGINTEGER SIZEPARAMETER (SIZE=100000)REAL*8 COOR(SIZE,2), WORK1(SIZE), WORK2(SIZE)...CALL COMPUTE(COOR, WORK1, WORK2, N)...END
The rest of the code is subroutines or functions
A Quick Fortran 77 Course – p. 12
Loops over arrays
For-loops are called do-loops in F77:C i=1,3,5,7,...,N and j=1,2,3,...,N:
DO J = 1, NDO I = 1,N,2A(I,J) = SIN(I*DX + J*DY)
END DOEND DO
Arrays are stored column-wise in Fortran 77 (row-wisein C), so the first index should have the fastest variationin a loop!
A Quick Fortran 77 Course – p. 13
If-tests
C comparison operators:C .LT. .LE. .GT. .GE. .EQ.C < <= > >= ==
IF (A .GE. MAX) THENMAX = A
END IF
IF (Q2 .LT. Q1) THENQ2 = Q1
ELSE IF (Q2 .EQ. Q1) THENQ2 = 0.0
ELSEQ1 = 0.0
END IF
A Quick Fortran 77 Course – p. 14
Strings
C declare strings with fixed length:CHARACTER BUFFER*200CHARACTER FILENAME*30
CALL FILEREAD(FILENAME)...
SUBROUTINE FILEREAD(NAME)C strings in a subroutine (unknown length):
CHARACTER NAME*(*)..
A Quick Fortran 77 Course – p. 15
I/O, standard input/output
WRITE(*,*) ’computed A(’,I,’)=’,A(I,J)WRITE(*,*) ’Give two numbers:’READ(*,*) R1, R2
A Quick Fortran 77 Course – p. 16
I/O, files (1)
INFILE=20OPEN(INFILE, FILE=NAME, STATUS=’UNKNOWN’, IOSTAT=IERR,
& FORM=’FORMATTED’)IF (IERR .GT. 0) THEN
C unsuccessful opening of the fileWRITE(*,*) ’Could not open file’, NAME
END IF
READ(INFILE,*) NDO I = 1,NREAD(INFILE,*) A(I)
END DO
C try to read more...DO I = 1, 1.0E+20READ(INFILE, *, IOSTAT=IERR) A(N+I)IF (IERR .LT. 0) THEN
C end of fileAL = N+IGO TO 100
ELSE IF (IERR .GT. 0) THENWRITE(*,*) ’Read error...’
END IFEND DOCLOSE(INFILE)
A Quick Fortran 77 Course – p. 17
I/O, files (2)
100 CONTINUEOPEN(21, FILE=’sim.dat’, STATUS=’UNKNOWN’,
& FORM=’FORMATTED’)WRITE(21,*) NDO I = 1,NWRITE(21,*) A(I)
END DOCLOSE(21)
A Quick Fortran 77 Course – p. 18
Global variables
Global variables in F77 are stored in (named) commonblocks:INTEGER J1, MREAL*8 A(M)COMMON /DATA1/ J1, M, A
To use a global variable in a routine, the completecommon block must be declared
Most F77 compilers allow a keyword "include" forincluding a file with the definition of a common block(otherwise all declarations of a common block must beconsistent throughtout a program)
A Quick Fortran 77 Course – p. 19
Scientific Hello World
program helloworldreal*8 r, swrite(*,*) ’Give a number:’read(*,*) rs = sin(r)write(*,*) ’Hello, World! sin(’,r,’)=’,s
C with format string (A is text, F is float):write(*,1000) ’Hello, World! sin(’,r,’)=’,s
1000 format(A, F6.3, A, F11.8)end
A Quick Fortran 77 Course – p. 20
Compiling and using the code
Compiling and linking:g77 -O3 -c hw.f # produces hw.o object fileg77 -o tmp.app hw.o # links to executable tmp.app
Running the program:unix> ./tmp.appGive a number:
0.0001Hello, World! sin( 0.0001)= 9.99999998E-05
Hello, World! sin( 0.000)= 0.00010000
A Quick Fortran 77 Course – p. 21
A complete application
We shall show the complete F77 code for a programsolving the differential equation
md2y
dt2+ b
dy
dt+ cf(y) = A cosωt
numerically
Initial conditions:
y(0) = y0,dy
dt
∣
∣
∣
∣
t=0
= 0
Most solution methods require the equation to berewritten as a system of first-order differentialequations:
dy1
dt= y2
dy2
dt=
1
m(A cos ωt − by2 + cf(y1))
Solution methods: forward Euler and 2nd-orderRunge-Kutta
A Quick Fortran 77 Course – p. 22
Initialize parameters
subroutine scan2(m_, b_, c_, A_, w_, y0_, tstop_, dt_, func_)C Initialize the data needed in the solver, and store in aC common block /data/, from the arguments to this subroutine.
real*8 m_, b_, c_, A_, w_, y0_, tstop_, dt_character func_*(*)
real*8 m, b, c, A, w, y0, tstop, dtcharacter func*20common /data/ m, b, c, A, w, y0, tstop, dt, func
m = m_b = b_c = c_A = A_w = w_y0 = y0_tstop = tstop_dt = dt_func = func_returnend
A Quick Fortran 77 Course – p. 23
Initialize parameters from stdin
subroutine scan1()C Read input data (physical and numerical parameters)C from standard input. The data are stored in a common block.
real*8 m_, b_, c_, A_, w_, y0_, tstop_, dt_character func_*20read(*,*) m_, b_, c_, func_, A_, w_, y0_, tstop_, dt_call scan2(m_, b_, c_, A_, w_, y0_, tstop_, dt_, func_)returnend
A Quick Fortran 77 Course – p. 24
Step in forward Euler method
subroutine adv_fe(y, n, t, dt, scratch)C Advance the solution one time step using theC Forward Euler method.
integer n, ireal*8 y(n), t, dt, scratch(n)
call rhs(scratch, y, n, t)C Forward Euler scheme:
do 10 i = 1,ny(i) = y(i) + dt*scratch(i)
10 continuereturnend
A Quick Fortran 77 Course – p. 25
Step in 2nd-order Runge-Kutta method
subroutine adv_rk2(y, n, t, dt, scratch1, scratch2)C Advance the solution one time step using aC 2nd order Runge-Kutta method.
integer n, ireal*8 y(n), t, dt, scratch1(n), scratch2(n), t2
call rhs(scratch1, y, n, t)do 10 i = 1,n
scratch2(i) = y(i) + dt*scratch1(i)10 continue
t2 = t + dtcall rhs(scratch2, scratch2, n, t2)do 20 i = 1,n
y(i) = y(i) + 0.5*dt*(scratch1(i) + scratch2(i))20 continue
returnend
A Quick Fortran 77 Course – p. 26
Define equations to be solved
The numerical algorithm subroutines call a subroutinethat evaluates the right-hand side of the first-orderdifferential equation system
Code on next slide
A Quick Fortran 77 Course – p. 27
Define equations to be solved
subroutine rhs(f, y, n, t)C Define the right-hand side of the ODE system.
integer nreal*8 f(n), y(n), treal*8 cterm
real*8 m, b, c, A, w, y0, tstop, dtcharacter func*20common /data/ m, b, c, A, w, y0, tstop, dt, func
if (func .eq. ’y’) thencterm = y(1)
else if (func .eq. ’siny’) thencterm = sin(y(1))
else if (func .eq. ’y3’) thencterm = y(1) + (y(1)**3)/6.0
elsewrite(*,*) ’Error: spring-term ’,func,’ illegal’cterm = 0.0
endif
f(1) = y(2)f(2) = ( -b*y(2) - c*cterm + A*cos(w*t) )/mreturnend A Quick Fortran 77 Course – p. 28
Putting it all together
subroutine timeloop()C Integrate the ODEs in time by calling adv_fe orC adv_rk2 at every time step.
integer n, nmaxparameter (nmax=2)real*8 time, y(nmax), scratch1(nmax), scratch2(nmax)real*8 m, b, c, A, w, y0, tstop, dtcharacter func*20common /data/ m, b, c, A, w, y0, tstop, dt, func
n = 2C initial conditions:
y(1) = y0y(2) = 0.0
open(21, file=’sim.dat’, status=’unknown’, form=’formatted’)do 10 time = dt, tstop, dt
C call adv_fe (y, n, time, dt, scratch1)call adv_rk2 (y, n, time, dt, scratch1, scratch2)write(21,1000) time, y(1)
10 continueclose(21)return
1000 format(F12.4, F12.4)end A Quick Fortran 77 Course – p. 29
A main program
program oscillator
call scan1()call timeloop()end
A Quick Fortran 77 Course – p. 30