Computing With Fortran by Haselbacher PDF
Computing With Fortran by Haselbacher PDF
Engineering Tool V
Spring 2015
2
Course Overview
• Course is about computing, not programming with Fortran
• Programming is means to an end, not the end itself
• Therefore, need to be effective and efficient programmer
3
Course Overview
• Computers are fast but stupid: Once told what to do, they can
do it quickly many times
• Fundamentally, programming is nothing but explaining actions
to computer
• Consequences:
‣ You need to understand action before you can explain it
‣ Programming forces you to understand what you do
‣ If computer does not do what you want, it’s your fault
4
Course Overview
• Course focus on Fortran 90 (called Fortran for simplicity)
• Changes in later versions (mostly) not important for us
‣ Fortran 95: Minor revision of Fortran 90
‣ Fortran 2003: Major additions to Fortran 95
‣ Fortran 2008: Minor revision of Fortran 2003
• gfortran compiler:
‣ Fortran 95: Completely supported
‣ Fortran 2003: Partially supported
‣ Fortran 2008: Partially supported
5
Course Overview: Scope & Structure
• Cannot cover all of Fortran in 12 hours
• Course will only cover what I view as most important parts
• Cannot cover debuggers, unfortunately
• Planned structure:
Day 1 Day 2 Day 3
Lecture/ Lecture/
Lecture 1 Programming
programming programming
Lecture/ Lecture/
Lecture 2 Programming
programming programming
Lecture/ Lecture/
Lecture 3 Programming
programming programming
Lecture 4 Programming Programming Programming
6
Course Overview: Goals
• Students know important Fortran commands and concepts
• Students write well-structured Fortran programs
• Students use compiler effectively
7
Course Overview: Administrative Matters
• Course grade: Pass/fail
• Determination of grade based on program submitted after end
of lectures on day 3
8
Course Overview: Recommended Books
• Fortran:
‣ S. J. Chapman, Fortran 95/2003 for Scientists and
Engineers, 3rd ed., McGraw-Hill, 2008
‣ T. M. R. Ellis, I. R. Philips, and T. M. Lahey, Fortran 90
Programming, Addison-Wesley, 1994
‣ M. Metcalf, J. Reid, and M. Cohen, Fortran 95/2003
Explained, 3rd ed., 2004
• Programming in general:
‣ B. W. Kernighan and R. Pike, The Practice of Programming,
Addison-Wesley, 1999
‣ S. McConnell, Code Complete, 2nd ed., Microsoft Press,
2004
9
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
10
Structure of Simple Fortran Program
PROGRAM simple_program
IMPLICIT NONE
INTEGER :: i,j
i = 1
j = 2*i
WRITE(*,*) i,j
11
Structure of Simple Fortran Program
PROGRAM simple_program
INTEGER :: i,j
i = 1
j = 2*i
Executable section
WRITE(*,*) i,j
12
Structure of Simple Fortran Program
13
Structure of Simple Fortran Program
PROGRAM simple_program
i = 1
j = 2*i
WRITE(*,*) i,j
14
Structure of Simple Fortran Program
PROGRAM simple_program
IMPLICIT NONE
15
Structure of Simple Fortran Program
PROGRAM simple_program
IMPLICIT NONE
16
Structure of Simple Fortran Program
PROGRAM simple_program
Fortran ignores empty lines
IMPLICIT NONE
Recommendation: Use them to make
your programs more readable
INTEGER :: i,j
i = 1
j = 2*i
WRITE(*,*) i,j
17
Structure of Simple Fortran Program
WRITE(*,*) i,j
18
Structure of Simple Fortran Program
PROGRAM simple_program
In a simple program like this one,
IMPLICIT NONE comments are not really necessary
WRITE(*,*) i,j
19
Structure of Simple Fortran Program
PROGRAM simple_program
In a simple program like this one,
IMPLICIT NONE comments are not really necessary
20
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
21
Compiling & Linking
22
Compiling & Linking
Compiling
23
Compiling & Linking
Compiling
Linking
simple_code
Executable/executable file
simple_code.exe
24
Compiling & Linking
simple_code.f90
simple_code.o
simple_code
25
Compiling & Linking
26
Compiling & Linking
simple_code.f90
simple_code
27
Algorithms + Data Structures = Programs
Niklaus Wirth (*1934)
• Swiss computer scientist
• Degree from ETH in 1959
• Professor at ETH from
1968-1999
http://www.heidelberg-laureate-forum.org/blog/laureate/niklaus-e-wirth/
28
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
29
Intrinsic Data Types
• Fortran provides six intrinsic data types:
‣ INTEGER
‣ REAL
‣ DOUBLE PRECISION
‣ COMPLEX
‣ LOGICAL
‣ CHARACTER
• Each can be used to declare variables or constants
• Can also define your own data types
30
Intrinsic Data Types: INTEGER
• Integer variables declared with:
INTEGER :: i,j,k
Recommendation:
Use uppercase names
i = 1 for PARAMETERs
j = 2 Use underscores to
k = i + j separate words
31
Intrinsic Data Types: INTEGER
• Q: Why use named constants?
32
Intrinsic Data Types: INTEGER
• Computers represent data as strings of bits using binary
number system
• Each bit assumes values 0 or 1
• Number of bits in string therefore determines range of values
that can be represented
• Assuming 8-bit representation:
00000010 = 1*2^1 + 0*2^0 = 22
00100011 = 1*2^5 + 1*2^1 + 1*2^0 = 352
• Minimum and maximum number that could be represented:
00000000 = 02
11111111 = 2552
‣ With n bits, can represent numbers ranging from 0 to 2n-1
33
Intrinsic Data Types: INTEGER Program
example
34
Intrinsic Data Types: REAL
• Computers represent floating-point numbers:
132.857 =+0.132857E+3
35
Intrinsic Data Types: DOUBLE PRECISION Program
example
36
Intrinsic Data Types: COMPLEX
• Convenient way to represent complex numbers:
COMPLEX :: c,d
37
Intrinsic Data Types: LOGICAL
• Logical variables declared with:
LOGICAL :: testPassed,resultNegative
• Logical variables and constants can only take two values:
testPassed = .TRUE. Periods important!
resultNegative = .FALSE.
• Logical constants can be declared with:
LOGICAL, PARAMETER :: flagTrue = .TRUE.
• Use of logical constants limited
38
Intrinsic Data Types: CHARACTER
• Single characters are declared with
CHARACTER :: c
c = ‘&’
39
Intrinsic Data Types: CHARACTER
• To represent words or phrases, use strings of characters
• Example of declaration of string:
CHARACTER(LEN=11) :: c
40
Intrinsic Data Types: CHARACTER
• Declaration of character string parameters:
CHARACTER(6), PARAMETER :: ERROR_MESSAGE = ‘ERROR!’
INTEGER :: i,j
IF ( i < 0 ) THEN
WRITE(*,*) ERROR_MESSAGE
STOP Definition of character string
END IF parameter useful if used
repeatedly
IF ( j > 0 ) THEN
WRITE(*,*) ERROR_MESSAGE If string needs to be
STOP changed, only one change
END IF is necessary
41
Intrinsic Data Types: IMPLICIT NONE
• In older versions of Fortran, implicit declaration possible:
‣ Variables starting with i, j, k, l, m, n were integers by
default
‣ All other variables were real variables by default
‣ Backward compatibility means can still be used
• Now considered dangerous because it masks typing mistakes:
SUBROUTINE MakeVectorUnitVector(b)
REAL, INTENT(INOUT) :: b(2)
REAL :: length This mistake could
be caught be
length = SQRT(b(1)*b(1)+b(2)*b(2)) compiler options,
b(1) = b(1)/lngth more later
b(2) = b(2)/lngth
END SUBROUTINE MakeVectorUnitVector
42
Intrinsic Data Types
• Single variables are not very useful
• Often collection of variables in arrays convenient/needed
• Examples:
‣ Solution of linear system of equations
‣ Finite-difference/volume/element solutions of PDEs
‣ …
43
Intrinsic Data Types: INTEGER Arrays
• Declaration and initialization of 1d INTEGER arrays:
INTEGER :: a(4) Equivalent declarations
INTEGER, DIMENSION(4) :: b of one-dimensional array
with 4 elements
a(1) = 1
a(2) = -4 Equivalent initializations
a(3) = 37 of array a
a(4) = -121
a = (/1,-4,37,-121/)
b(1:4) = 0
44
Intrinsic Data Types: INTEGER Arrays
• By default, Fortran array elements are indexed 1, 2, …
• Can be changed by suitable declaration and initialization:
INTEGER :: a(-1:2)
INTEGER, DIMENSION(0:3) :: b
a(-1) = 1
a( 0) = -4 Equivalent initializations
of array a
a( 1) = 37
a( 2) = -121
a = (/1,-4,37,-121/)
This initialization to a
b(:) = 0 constant value works for
any numbering
45
Intrinsic Data Types: INTEGER Arrays
• Declaration and initialization of 2d INTEGER arrays is similar:
INTEGER :: a(2,3)
INTEGER, DIMENSION(4,2) :: b
a(1,1) = 1
a(2,1) = -4
a(1,2) = 37
a(2,2) = -121
a(1,3) = 456
a(2,3) = -17
b(:,:) = 0
46
Intrinsic Data Types: INTEGER Arrays
• Fortran stores multi-dimensional arrays in column-major order:
INTEGER :: a(2,3) Address Value
0 a(1,1)= 1
a(1,1) = 1
1 a(2,1)= -4
a(2,1) = -4 1 37 456 2 a(1,2)= 37
a(1,2) = 37
-4 -121 -17 3 a(2,2)=-121
a(2,2) = -121
a(1,3) = 456 4 a(1,3)= 456
a(2,3) = -17 5 a(2,3)= -17
47
Intrinsic Data Types: Other Arrays
• Arrays for other intrinsic data types defined similarly
• Careful with arrays of character strings:
CHARACTER(20) :: a(80)
An array of 80 strings, each of which is 20 characters long
48
Arrays: Stepping Out-of-Bounds
• Stepping out of bounds of an array is common mistake:
PROGRAM bounds1d
INTEGER :: a(4)
a = (/1,-4,37,-121/)
WRITE(*,*) a(0)
1
Warning: Array reference at (1) is
out of bounds (0 < 1) in dimension 1
49
Arrays: Stepping Out-of-Bounds
• What about following program?
PROGRAM bounds1d
IMPLICIT NONE
INTEGER :: i
INTEGER :: a(4)
a = (/1,-4,37,-121/)
50
Arrays: Stepping Out-of-Bounds
• What happens when you run this program?
i a(i)
-2 0
-1 0 Undefined behaviour if i < 1 or i > 4
0 0
“Undefined” means that behaviour may be
1 1 different on different machines, with
different compilers, and different each time
2 -4 you run program (even on same machine
3 37 and with same compiler)
4 -121
5 1475824016
6 32767
51
Arrays: Stepping Out-of-Bounds
• Compiler can help you avoid this problem
• By compiling with
gfortran -fbounds-check bounds1d.f90 -o bounds1d
get following behavior:
Enter i:
0
At line 14 of file bounds1d.f90
Fortran runtime error: Index '0' of dimension 1 of array 'a'
below lower bound of 1
• Bottom line: Compiler can help you detect and find mistakes
• But you need to tell compiler to do so with appropriate options
52
Recommended Compiler Options
• Recommendation: while developing program, turn on all
compiler options that help detect and find mistakes
• For example:
Option Effect
-g Produce information for debugger
-Wall -Wextra Issue (lots of) warnings
-fbounds-check Check stepping out of bounds of arrays
Produce list of procedures called when
-fbacktrace
program crashes
Trap division by zero, overflow, underflow,
-ffpe-trap=zero,overflow,underflow,invalid
invalid operations
53
Recommended Compiler Options
• Once program working correctly, use compiler options to
speed up execution:
gfortran -On code.f90 -o code
where n is number from 0 (no optimization) to 3 (most
aggressive optimization)
• Check that optimization does not influence results
• Bottom line:
‣ Compiler great help in code development; make use of it
‣ Familiarize yourself with options of your compiler(s)
54
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
55
Arithmetic Operations
• Binary operations: • Precedence (top to bottom):
a = b ** left to right
= Assignment
i = i + 1
* / left to right
+ Addition a + b
+ - left to right
- Subtraction a - b
/ Division a/b
• Use parentheses to influence
* Multiplication a*b precedence:
** Exponentiation a**b a = (a+b)**n/(c*(a-b/(e+f)))
• Unary operations:
+ ? a = +b
- Negation a = -b
56
Arithmetic Operations: Integer/Mixed Arithmetic
• Careful with Fortran’s integer arithmetic, i.e., arithmetic
involving only integers
• Fortran’s integer arithmetic always produces integer result by
truncating fractional part
• Examples:
3/4 = 0
4/3 = 1
5/3 = 1
6/3 = 2
• Looks like major inconvenience, but can be useful at times
57
Arithmetic Operations: Integer/Mixed Arithmetic
• To divide two integers, change at least one to real number to
get real result:
3/4 = 0
3.0/4 = 0.75
3/4.0 = 0.75
or
i/REAL(j) i/DBLE(j)
REAL(i)/j DBLE(i)/j
• In mixed (or mixed-mode) arithmetic, Fortran converts integers
to real numbers:
1 + 3/4 = 1
1 + 3.0/4 = 1.75
1.0 + 3/4 = 1.0
• Recommendation: Avoid mixed arithmetic by converting
integers yourself using REAL and DBLE intrinsic procedures
58
Program
Relational Operations example
/= not equal to a /= b
> greater than a > b
59
Logical Operations
• Can only be used with logical variables and constants
• Binary operations:
.OR. logical OR
• Unary operation:
.NOT. logical NOT
60
Logical Operations
• Truth table:
A B A .AND. B A .OR. B A .EQV. B A .NEQV. B
61
Logical Operations: Example of a Mistake
• What I wanted the program to be:
IF ( (flag1 .EQV. .FALSE.) .AND. (flag2 .EQV. .FALSE.) ) THEN
Fortran statements
END IF
• What I actually typed:
IF ( flag1 .EQV. .FALSE. .AND. flag2 .EQV. .FALSE. ) THEN
Fortran statements
END IF
• Precedence rules mean this is equivalent to:
IF ( (flag1 .EQV. (.FALSE. .AND. flag2)) .EQV. .FALSE. ) THEN
Fortran statements
END IF Desired Actual
flag1 flag2
expression expression
.FALSE. .FALSE. .TRUE. .FALSE.
.FALSE. .TRUE. .FALSE. .FALSE.
.TRUE. .FALSE. .FALSE. .TRUE.
.TRUE. .TRUE. .FALSE. .TRUE.
62
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
63
Intrinsic procedures
• Fortran provides 108 intrinsic procedures to operate on data
• These include trigonometric procedures, for example
• We will later learn how to write our own procedures
• Following covers only most important intrinsic procedures
• For complete list, see:
‣ Chapman (2008), Appendix B
‣ Ellis et al. (1994), Appendix A
‣ Metcalf et al. (2004), Appendix A
64
Intrinsic procedures: Integer data
ABS(x) Absolute value of x
Converts x to double-precision
DBLE(x)
floating-point value
MAX(a,b) Picks the larger of a and b
MIN(a,b) Picks the smaller of a and b
MOD(a,b) Remainder (modulo) function
Converts x to single-precision
REAL(x)
floating-point value
65
Intrinsic procedures: Floating-point data
ABS(x) Absolute value of x
ACOS(x) Inverse cosine of x result in radians
ACOSH(x) Inverse hyperbolic cosine of x
ASIN(x) Inverse sine of x result in radians
ASINH(x) Inverse hyperbolic sine of x
ATAN(x) Inverse tangent of x result in radians, -π/2 to π/2
ATAN2(y,x) Inverse tangent of y/x result in radians, -π to π
ATANH(x) Inverse hyperbolic tangent of x
Convert a,b to complex number
CMPLX(a,b)
a+bi
COS(x) Cosine of x x in radians
COSH(x) Hyperbolic cosine of x
EXP(x) Exponential of x
INT(x) Truncates x to integer
66
Intrinsic procedures: Floating-point data
LOG(x) Natural logarithm of x x>0
LOG10(x) Base-10 logarithm of x x>0
MAX(a,b) Picks the larger of a and b
MIN(a,b) Picks the smaller of a and b
MOD(a,b) Remainder (modulo) function
NINT(x) Nearest integer to x
SIGN(a,b) Value of a with sign of b
SIN(x) Sine of x x in radians
SINH(x) Hyperbolic sine of x
SQRT(x) Square root of x x≥0
TAN(x) Tangent of x x in radians
TANH(x) Hyperbolic tangent of x
67
Intrinsic procedures: Complex data
ABS(x) Magnitude of x
AIMAG(x) Imaginary part of x
CONJG(x) Complex conjugate of x
REAL(x) Real part of x
68
Intrinsic procedures: Character string data
LEN(x) Length of x
Length of x, not counting
LEN_TRIM(x)
trailing blank characters
69
Intrinsic procedures: Arrays
a and b must be
DOT_PRODUCT(a,b) Dot product of vectors a and b
conforming
LBOUND(a,i) Lower bound of ith dimension of a
a and b must be
MATMUL(a,b) Matrix product of a and b
conforming
Location of first element of See any of the books
MAXLOC(a,m)
maximum value in a given mask m for more information
Maximum value of elements in a See any of the books
MAXVAL(a,m)
given mask m for more information
Location of first element of See any of the books
MINLOC(a,m)
minimum value in a given mask m for more information
Minimum value of elements in a See any of the books
MINVAL(a,m)
given mask m for more information
SIZE(a,i) Size of a along ith dimension
70
Intrinsic procedures: Arrays
Sum of elements in a along See any of the books
SUM(a,i,m)
dimension i given mask m for more information
TRANSPOSE(a) Transpose of a
UBOUND(a,i) Upper bound of ith dimension of a
71
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
72
Control Flow
• Often necessary to:
‣ Take action in response to data
‣ Repeat actions multiple times
• Both amount to “controlling the flow” in the program
73
Control Flow: IF Statements
• General case (“block IF”):
IF ( logical_expression ) THEN There can be any number
Fortran statements of ELSE IF statements
ELSE IF ( logical_expression ) THEN (including none)
Fortran statements
Important: First true
ELSE IF ( logical_expression ) THEN expression is taken
Fortran statements
ELSE
There can be at most one
Fortran statements
ELSE statement
END IF
It must appear after the
ELSE IF statements (if
there are any)
• Special case (“logical IF”):
IF ( logical_expression ) Fortran statement
74
Control Flow: IF Statements
• IF statements can be nested:
IF ( logical_expression ) THEN
IF ( logical_expression ) THEN
Fortran statements
ELSE IF
IF ( logical_expression ) THEN
Fortran statements
ELSE
Fortran statements
END IF
END IF
ELSE IF ( logical_expression ) THEN
Fortran statements
ELSE
Fortran statements
END IF
75
Control Flow: IF Statements
• IF statements can be nested:
outerIF: IF ( logical_expression ) THEN
middleIF: IF ( logical_expression ) THEN
Fortran statements
ELSE IF
innerIF: IF ( logical_expression ) THEN
Fortran statements
ELSE Fortran 95 allows you to
Fortran statements name IF statements
END IF innerIF
END IF middleIF Benefits:
ELSE IF ( logical_expression ) THEN 1. Easier for people to
understand nested IFs
Fortran statements
2. If you accidentally delete
ELSE an IF or END IF, compiler
Fortran statements can treat is as an error
END IF outerIF
76
Control Flow: SELECT CASE Statement
There must be at least one CASE
statement
If there is more than one CASE
SELECT CASE ( case_expression )
statement, the case_selectors
CASE ( case_selector_1 ) must be mutually exclusive
Fortran statements
The case selectors must be
CASE ( case_selector_2 )
constants (integer, character, or
Fortran statements logical)
CASE ( case_selector_3 )
Fortran statements The statements under CASE
CASE DEFAULT DEFAULT are executed if none of
Fortran statements the other CASE statements are
END SELECT executed
The CASE DEFAULT statement is
not required
It is recommended that you include
it to catch programming mistakes
77
Control Flow: SELECT CASE Statement
Example:
SELECT CASE( TRIM(line) )
CASE ('# BC_FARF')
CALL RFLU_ReadBcFarfSection(pRegion)
CASE ('# BC_INFLOW_TOTANG')
CALL RFLU_ReadBcInflowTotAngSection(pRegion)
CASE ('# BC_INFLOW_VELTEMP')
CALL RFLU_ReadBcInflowVelTempSection(pRegion)
CASE ('# BC_INJECT')
CALL RFLU_ReadBcInjectSection(pRegion)
…
CASE DEFAULT
CALL ErrorStop(global,ERR_REACHED_DEFAULT)
END SELECT ! TRIM(line)
78
Control Flow: SELECT CASE Statement
Example:
SELECT CASE ( flag )
CASE ( 1,2 ) case_selector can
DO iPatch = 1,pGrid%nPatches consist of more than one
pPatch => pRegion%patches(iPatch) value, separated by
commas
…
END DO ! iPatch case_selector can
CASE ( 3 ) also specify range of
DO iPatch = 1,pGrid%nPatches values:
pPatch => pRegion%patches(iPatch) CASE ( val_min:val_max )
…
END DO ! iPatch
CASE DEFAULT
CALL ErrorStop(global,ERR_REACHED_DEFAULT)
END SELECT ! flag
79
Control Flow: SELECT CASE or IF?
IF SELECT CASE
logical_expression case_selector must
may involve variables only involve constants
Order of ELSE IFs does Order of CASEs does not
matter matter
80
Defensive Programming
• Recommendation: always include CASE DEFAULT statement
• If it should not be reached, write error message if reached
• Example of defensive programming
81
Defensive Programming
• McConnell (2004, p. 187):
“The idea is based on defensive driving. In defensive driving, you adopt
the mind-set that you’re never sure what other drivers are going to do.
That way, you make sure that if they do something dangerous you won’t
be hurt. You take responsibility for protecting yourself even when it
might be the other driver’s fault. In defensive programming, the main
idea is that if a routine is passed bad data, it won’t be hurt, even if the
bad data is another routine’s fault. More generally, it is the recognition
that programs will have problems and modifications, and that a smart
programming will develop code accordingly.”
• My take:
‣ Anticipate problems (Murphy’s law…)
‣ Write code to handle problems (not to fix them)
‣ Write error messages to let you know problem occurred
82
KISS Principle
• KISS = Keep it simple, stupid
• Simple programs are easier to write, debug, and modify
• Often bad idea to use elegant code that is hard to understand
• Not uncommon to have difficulty understanding code that was
written only a couple of weeks/months ago
• Bottom line: Write simple programs
• Does not mean that simple programs are inefficient
83
Control Flow: DO Statements
• DO-loops are used to repeat operations
• First form of DO-loop: i “loop counter”, must be integer
DO i = i_beg,i_end,i_inc i_beg must be integer expression
Fortran statements i_end must be integer expression
END DO i_inc “loop increment” (1 if not specified)
84
Control Flow: DO Statements
• Sometimes, need to repeat statements until condition is met,
but number of repetitions is not known
• Second form of DO-loop:
DO
Fortran statements
IF ( logical expression ) THEN
Fortran statements
EXIT Causes control to be transferred to
END IF first statement after END DO
Fortran statements
END DO
• Sometimes referred to as “while” loop
• Note that if logical expression is never true, get so-called
infinite loop…
85
Defensive Programming
• Avoid infinite loops by introducing loop counters:
INTEGER, PARAMETER :: MAX_LOOP_COUNTER = 1000
loopCounter = 0
DO Maximum value of
loopCounter = loopCounter + 1 loop counter must be
Fortran statements chosen large enough
IF ( logical expression ) THEN
Fortran statements
EXIT
END IF
IF ( loopCounter == MAX_LOOP_COUNTER ) THEN
EXIT
END IF
Fortran statements
END DO
86
Defensive Programming
• Problem: Do not why loop was exited
• Checking loopCounter is a possible solution
• Another solution shown on next slide…
87
Defensive Programming
• Solution:
LOGICAL :: flagReachedMaxCounter
DO
loopCounter = loopCounter + 1
Fortran statements
IF ( logical expression ) THEN
Fortran statements
flagReachedMaxCounter = .FALSE.
EXIT
END IF
IF ( loopCounter == MAX_LOOP_COUNTER ) THEN
flagReachedMaxCounter = .TRUE.
EXIT
END IF
Fortran statements
END DO
88
Defensive Programming
• Introduce check after loop:
…
IF ( loopCounter == MAX_LOOP_COUNTER ) THEN
flagReachedMaxCounter = .TRUE.
EXIT
END IF
Fortran statements
END DO
89
Control Flow: DO Statements
• Fortran allows DO loops to be named:
LOGICAL :: flagReachedMaxCounter
whileLoop: DO
loopCounter = loopCounter + 1
Fortran statements
IF ( logical expression ) THEN
Fortran statements
flagReachedMaxCounter = .FALSE.
EXIT whileLoop
END IF
IF ( loopCounter == MAX_LOOP_COUNTER ) THEN
flagReachedMaxCounter = .TRUE.
EXIT
END IF whileLoop
Fortran statements
END DO whileLoop
9090
Control Flow: DO Statements
• Already discussed EXIT statement, which transfer control to
first statement after END DO
• There is also the CYCLE statement, which transfers control to
END DO statement (and possibly back to DO statement)
Program
example:
Column-major
ordering and
performance
91
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output
92
Input/Output
• Programs require input data and generate output data
• Four possibilites:
Screen File
Read Read from screen Read from file
Write Write to screen Write to file
93
Screen File
Output: To Screen Read
Write
• Writing an integer to screen is accomplished by:
INTEGER :: i
i = 5
WRITE(*,*) i The significance of *,* will be
explained soon
• Similar for floating-point variables
• Writing character string accomplished by:
INTEGER, PARAMETER :: MAX_CHAR_LEN = 80
CHARACTER(MAX_CHAR_LEN) :: c
c = ‘Hello!’
WRITE(*,*) c
• This writes whole string, including trailing blank spaces
• This can be avoided with intrinsic procedure TRIM:
WRITE(*,*) TRIM(c)
94
Output: To Screen
• Can combine writing of data types:
INTEGER, PARAMETER :: MAX_CHAR_LEN = 80
INTEGER :: i
CHARACTER(MAX_CHAR_LEN) :: c
i = 5
c = ‘Hello!’
WRITE(*,*) TRIM(c),i
or
WRITE(*,*) ‘i=‘,i
WRITE(*,*) ‘c=‘,TRIM(c)
95
Screen File
Input: From Screen Read
Write
• Reading an integer from screen is accomplished by:
INTEGER :: i
READ(*,*) i
• Similarly, a single-precision floating-point variable is read by:
REAL :: r
READ(*,*) r
• Finally, a character string is read by:
INTEGER, PARAMETER :: MAX_CHAR_LEN = 80
CHARACTER(MAX_CHAR_LEN) :: c
READ(*,*) c
96
Input: From Screen
• Can also read several variables together:
INTEGER, PARAMETER :: MAX_CHAR_LEN = 80
INTEGER :: i
CHARACTER(MAX_CHAR_LEN) :: c
WRITE(*,*) ‘Enter integer and string:’
READ(*,*) i,c Can enter one value at a time,
separated by <return>
WRITE(*,*) i,TRIM(c)
• Get run-time error if data that does not match data type:
Enter integer and string:
17.0 3
At line 11 of file readmixed.f90 (unit = 5, file = 'stdin')
Fortran runtime error: Bad integer for item 1 in list input
97
Defensive Programming
• Better way is to check for invalid input using IOSTAT specifier:
INTEGER :: ef
READ(*,*,IOSTAT=ef) i,c
IF ( ef /= 0 ) THEN
WRITE(*,*) ‘ERROR - Invalid input!’
STOP
END IF ! ef
giving IOSTAT returns an integer status
Enter integer and string: variable
17.0 3
Non-zero status variable indicates
ERROR - Invalid input! READ statement was unsuccessful
98
Screen File
Output: To Screen with Formatting Read
Write
• Often desire to influence how output is formatted
• For example, want to write certain number of decimal places,
pi = 3.141593
instead of
pi = 3.141592653589793238462643383279
or use engineering notation,
p = 1.01325E+5
instead of
p = 101325.0
• This can be achieved using edit descriptors
• They are used in place of second * in WRITE statement:
WRITE(*,’(edit descriptors)’) something
100
Output: To Screen with Formatting
• For character variables and constants, use A edit descriptor:
Aw w = overall width
IMPLICIT NONE
WRITE(*,*) LEN_TRIM(c) 32
101
Output: To Screen with Formatting
• For real and double-precision variables and constants:
±0.nnnnnnnE±ee
123<- d ->4567
w = overall width w ≥ d + 7
Ew.d
d = number of decimal places
For example:
E10.3, E13.6, E16.9
102
Output: To Screen with Formatting
• Example code: • Output:
Combine edit
descriptors
PROGRAM editdescriptors separated by
IMPLICIT NONE
commas,
Must match!
REAL :: r
r = -1234567890.987654321
103
Output: To Screen with Formatting
• Example code: • Output:
PROGRAM editdescriptors
IMPLICIT NONE
REAL :: r
r = -12345.0
104
Output: To Screen with Formatting
• For integer variables and constants, use I edit descriptor:
Iw w = overall width
105
Output: To Screen with Formatting
• Any edit descriptor can be prefaced to indicate repetition
• For example, to write out 2 integers of width 4:
WRITE(*,’(2I4)’)
106
Screen File
Output: To File Read
Write
• To write to file, replace first * in WRITE statement:
WRITE(fileUnit,’(edit descriptors)’) something
where fileUnit is an integer
• Following will only cover most important aspects of writing to
(and reading from) files
• For more information, see:
‣ Chapman (2008): 5.5
‣ Ellis et al. (1994): 9
‣ Metcalf et al. (2004): 10
• File must (should) be opened before can write to it
• Once opened, can write data to file in same way as writing to
screen
107
Input/Output: File Handling
• Files are opened with
OPEN(list of specifiers)
• Specifiers include:
UNIT=fileUnit fileUnit is a positive integer • fileUnit values 0, 5, and 6 are
reserved
• The maximum value of fileUnit is
compiler-dependent (often 99)
FILE=fileName fileName is a string
108
Input/Output: File Handling
• The INQUIRE statement can be used to find out more about
particular fileUnit
• Here only illustrate use to determine whether file exists:
INQUIRE(UNIT=fileUnit,EXIST=existFlag, &
IOSTAT=errorFlag)
• If the file exists, existFlag is set to .TRUE., otherwise
to .FALSE.
• There are many additional specifiers, see, for example,
Chapman (2008, 14.3.3)
• Can be used as follows...
109
Defensive Programming
Opening file in Fortran:
INQUIRE(UNIT=fileUnit,EXIST=existFlag,IOSTAT=errorFlag)
IF ( errorFlag /= 0 ) THEN May not always be
WRITE(*,*) ‘ERROR - INQUIRE returned non-zero IOSTAT!’ appropriate option...
STOP
ELSE
IF ( existFlag .EQV. .TRUE. ) THEN
OPEN(UNIT=fileUnit,FILE=TRIM(fileName),STATUS=‘REPLACE’,IOSTAT=errorFlag)
ELSE
OPEN(UNIT=fileUnit,FILE=TRIM(fileName),STATUS=‘NEW’,IOSTAT=errorFlag)
END IF ! existFlag
IF ( errorFlag /= 0 ) THEN
WRITE(*,*) ‘ERROR - Could not open file!’
STOP
END IF ! errorFlag
END IF ! errorFlag
110
Input/Output: File Handling
• Closing files is considerably easier:
CLOSE(list of specifiers)
• Specifiers include:
UNIT=fileUnit fileUnit is a positive integer
111
Defensive Programming
Closing file in Fortran:
CLOSE(FILE=fileUnit,IOSTAT=errorFlag)
IF ( errorFlag /= 0 ) THEN
WRITE(*,*) ‘ERROR - Could not close file!’
STOP
END IF ! errorFlag
112
Screen File
Input: From File Read
Write
• File must (should) be opened before can read from it
• Once opened, can read data from file in same way as reading
from screen
113
Input/Output: File Handling
• Dirty little secret about Fortran file output:
‣ If file with unit fileUnit not opened before writing to it,
Fortran will write to file called fort.fileUnit
‣ This can be very useful while developing or debugging
‣ This behavior is compiler-dependent, so not portable and
should not be used in general
114
Computing with Fortran
Engineering Tool V
Spring 2015
2
Structuring a Program
• Can write complex programs with material already covered
• However, these programs will consist of one single routine
• They will be hard to understand, test, change, share…
• … which is everything we do not want programs to be
3
Structuring a Program
• Good approach of tackling complex problems:
‣ Subdivide into smaller and simpler parts (analysis)
‣ Work on smaller and simpler parts
‣ Put smaller and simpler parts back together (synthesis)
• Fortran provides several ways of using this approach:
‣ Procedures: Functions and subroutines
‣ Modules: Data and procedures
• Functions and subroutines are important part of programming
method called structured or modular programming
4
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
5
Functions
• Example: Fortran provides intrinsic function to compute square
root, but not cube root
• Can address this problem by writing own function:
REAL, INTENT(IN) :: x
6
Functions
• Example: Fortran provides intrinsic function to compute square
root, but not cube root
• Can address this problem by writing own function:
7
Functions
• This function could now be used as follows:
PROGRAM main
IMPLICIT NONE
REAL :: x,y,r
x = 3.0
y = 3.0
Used in assignment statement (or in
r = cbrt(x)
other operations)
WRITE(*,*) r,cbrt(y) Used in WRITE statement
END PROGRAM main
Note: In the above, x and y are actual
arguments
• Two problems:
• Small problem: what should be improved in cbrt?
• Bigger problem: this program will not compile because
main does not “know” what cbrt is/does
8
Functions
• Two basic ways of “telling” main about cbrt:
9
Functions: Internal Procedure
• Example:
PROGRAM main Single file
IMPLICIT NONE
REAL :: x,r
x = 3.0
r = cbrt(x)
WRITE(*,*) r
CONTAINS
10
Functions: Internal Procedure
• Example:
PROGRAM main
IMPLICIT NONE
REAL :: x,r
Main program
x = 3.0
r = cbrt(x)
WRITE(*,*) r
CONTAINS
11
Functions: Internal Procedure
• Example:
PROGRAM main
IMPLICIT NONE
REAL :: x,r
x = 3.0
r = cbrt(x)
WRITE(*,*) r
12
Functions: Internal Procedure
• Example:
PROGRAM main
IMPLICIT NONE
REAL :: x,r
x = 3.0
r = cbrt(x)
WRITE(*,*) r
CONTAINS
13
Functions: INTENT(IN) Attribute
• Background: Fortran uses “call by reference”, so addresses of
arguments rather than argument values are passed
• Could have written cbrt as:
IMPLICIT NONE
REAL :: x No INTENT(IN)attribute
cbrt = EXP(x)
15
Functions: INTENT(IN) Attribute
• Example:
IMPLICIT NONE
REAL, INTENT(IN) :: x
16
Functions: External Procedure
main.f90 cbrt.f90
Compiling
gfortran -g -Wall -c main.f90 -o main.o gfortran -g -Wall -c cbrt.f90 -o cbrt.o
main.o cbrt.o
Linking
main
17
Functions: External Procedure
• Functions in files other than that containing main program
must be declared with the EXTERNAL attribute
18
Functions: Alternative Form
• Example:
IMPLICIT NONE
REAL, INTENT(IN) :: x
cbrt = EXP(LOG(x)/3.0)
19
Functions: Alternative Form
• Example:
20
Functions: Summary
• Functions are Fortran procedures that return a single result
• Non-intrinsic functions are sometimes called user-defined
functions
21
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
22
Makefiles
• Manually compiling and linking of codes consisting of multiple
files is tedious
• Makefiles can be used to automate compilation and linking
• Use/adapt the simple Makefile provided
23
Makefiles
### Macros #####################################################################
SHELL= /bin/sh
EXEC= mycode
FC= gfortran
FFLAGS= -g -Wall -Wextra -fbounds-check
Define macros for later use
#FFLAGS= -O3
MODEXT= mod
RIFFRAFF= *.bak *.bck *.ckp *.dSYM
RM= rm -rf
24
Makefiles
### Macros #####################################################################
SHELL= /bin/sh
EXEC= mycode Specify executable name
FC= gfortran Specify compiler
FFLAGS= -g -Wall -Wextra -fbounds-check Specify compiler options
#FFLAGS= -O3
MODEXT= mod
RIFFRAFF= *.bak *.bck *.ckp *.dSYM
RM= rm -rf If you add or remove source
files from your code, edit this list
### Source and object section ##################################################
SRCF90= ModSample.f90 main.f90
accordingly. If you need more
lines, terminate a line with \
### Pattern rules ############################################################## and continue with a tab on the
%.o: %.f90 next line
$(FC) $(FFLAGS) -c $< -o $@
OBJF90= $(SRCF90:.f90=.o)
.PHONY: clean
clean:
$(RM) $(OBJF90) *.$(MODEXT) $(EXEC) $(RIFFRAFF)
25
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
26
Subroutines
• Dummy argument(s) to functions should not be modified
• Hence functions are limited to returning single result
• To avoid this restriction, use subroutines
• Example: Computing roots of quadratic function
PROGRAM main
IMPLICIT NONE
REAL :: a,b,c
COMPLEX :: r1,r2
27
Subroutines
• As with cbrt function discussed earlier, can treat
SolveQuadratic as internal or external procedure
• First, take closer look at SolveQuadratic
28
Subroutines
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
IMPLICIT NONE
REAL :: d,q
d = b**2 - 4.0*a*c
29
Subroutines
SUBROUTINE SolveQuadratic(a,b,c,r1,r2) Name of subroutine and
dummy arguments
IMPLICIT NONE
30
Subroutines: INTENT(OUT) Attribute
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
IMPLICIT NONE
31
Subroutines
• Now, let’s take a look at how we can “tell” the main program
about SolveQuadratic
• Discussed two options earlier:
‣ Internal procedure: Use CONTAINS statement
‣ External procedure: Separate files
32
Subroutines: Internal Procedure
PROGRAM main
IMPLICIT NONE
REAL :: a,b,c
COMPLEX :: r1,r2
Main program
WRITE(*,*) ‘Enter a,b,c:’
READ(*,*) a,b,c
CALL SolveQuadratic(a,b,c,r1,r2)
WRITE(*,*) ‘Solutions:’,r1,r2
CONTAINS
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
33
Subroutines: Internal Procedure
PROGRAM main
IMPLICIT NONE
REAL :: a,b,c
COMPLEX :: r1,r2
CALL SolveQuadratic(a,b,c,r1,r2)
WRITE(*,*) ‘Solutions:’,r1,r2
34
Subroutines: Internal Procedure
PROGRAM main
IMPLICIT NONE
REAL :: a,b,c
COMPLEX :: r1,r2
CALL SolveQuadratic(a,b,c,r1,r2)
WRITE(*,*) ‘Solutions:’,r1,r2
CONTAINS
35
Subroutines: External Procedure
main.f90 SolveQuadratic.f90
PROGRAM main SUBROUTINE …
IMPLICIT NONE
…
REAL :: a,b,c
COMPLEX :: r1,r2 END SUBROUTINE …
…
CALL SolveQuadratic(…)
…
END PROGRAM main
Compiling
gfortran -g -Wall -c
gfortran -g -Wall -c main.f90 -o main.o SolveQuadratic.f90 -o SolveQuadratic.o
main.o SolveQuadratic.o
Linking
main
36
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
37
Functions & Subroutines: Discussion
• Functions and subroutines are indispensable for writing
modular programs: Use them extensively
• Guidelines for writing one or the other:
Write a FUNCTION when… … you have one result/output
Write a SUBROUTINE when… … you have more than one result/output
38
Functions & Subroutines: Discussion
• Personal recommendations:
‣ Keep function names short (like SIN, SQRT) to keep
expressions short
‣ Choose subroutine names that clearly indicate objective:
SolveQuadratic
SolveCubic
ComputeFluxes
ComputeSolutionError
IterateJacobi
IterateGaussSeidel
‣ Above all, use a consistent naming scheme!
39
Functions & Subroutines: Discussion
• Keep in mind the following about INTENT attributes:
40
Functions & Subroutines: Discussion
• What are advantages/disadvantages of internal and external
procedures?
Advantages Disadvantages
Internal procedure • Simplicity: no need to • Single-file program may
(with CONTAINS compile and link multiple become long
statement) files
External procedure • Separate files easier to • Need to compile and link
(separate files) keep short and easy to multiple files
understand
41
Functions & Subroutines: Discussion
PROGRAM main
IMPLICIT NONE • Consider first case of internal
REAL :: a,b,c
COMPLEX :: r1,r2 procedure as shown on left
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c • Compiles and runs successfully
CALL SolveQuadratic(a,b,c,r1,r2)
WRITE(*,*) 'Solutions:',r1,r2
CONTAINS
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
IMPLICIT NONE
REAL, INTENT(IN) :: a,b,c
COMPLEX, INTENT(OUT) :: r1,r2
REAL :: d,q
d = b**2 - 4.0*a*c
IF ( d < 0.0 ) THEN
q = SQRT(-d)
r1 = CMPLX(-0.5*b/a, 0.5*q/a)
r2 = CMPLX(-0.5*b/a,-0.5*q/a)
ELSE
q = -0.5*(b + SIGN(1.0,b)*SQRT(d))
r1 = CMPLX(q/a,0.0)
r2 = CMPLX(c/q,0.0)
END IF ! d
END SUBROUTINE SolveQuadratic
END PROGRAM main
42
Functions & Subroutines: Discussion
PROGRAM main
IMPLICIT NONE • Now assume we made mistake
REAL :: a,b,c
COMPLEX :: r1,r2 and accidentally forgot to pass
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c
third argument
CALL SolveQuadratic(a,b,c,r1,r2) • Very common mistake!
WRITE(*,*) 'Solutions:',r1,r2
CONTAINS
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
IMPLICIT NONE
REAL, INTENT(IN) :: a,b,c
COMPLEX, INTENT(OUT) :: r1,r2
REAL :: d,q
d = b**2 - 4.0*a*c
IF ( d < 0.0 ) THEN
q = SQRT(-d)
r1 = CMPLX(-0.5*b/a, 0.5*q/a)
r2 = CMPLX(-0.5*b/a,-0.5*q/a)
ELSE
q = -0.5*(b + SIGN(1.0,b)*SQRT(d))
r1 = CMPLX(q/a,0.0)
r2 = CMPLX(c/q,0.0)
END IF ! d
END SUBROUTINE SolveQuadratic
END PROGRAM main
43
Functions & Subroutines: Discussion
PROGRAM main
IMPLICIT NONE • This is clearly wrong because
REAL :: a,b,c
COMPLEX :: r1,r2 argument lists do not match
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c
CALL SolveQuadratic(a,b,r1,r2)
WRITE(*,*) 'Solutions:',r1,r2
CONTAINS
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
IMPLICIT NONE
REAL, INTENT(IN) :: a,b,c
COMPLEX, INTENT(OUT) :: r1,r2
REAL :: d,q
d = b**2 - 4.0*a*c
IF ( d < 0.0 ) THEN
q = SQRT(-d)
r1 = CMPLX(-0.5*b/a, 0.5*q/a)
r2 = CMPLX(-0.5*b/a,-0.5*q/a)
ELSE
q = -0.5*(b + SIGN(1.0,b)*SQRT(d))
r1 = CMPLX(q/a,0.0)
r2 = CMPLX(c/q,0.0)
END IF ! d
END SUBROUTINE SolveQuadratic
END PROGRAM main
44
Functions & Subroutines: Discussion
PROGRAM main
IMPLICIT NONE • Because procedure is internal,
REAL :: a,b,c
COMPLEX :: r1,r2 compiler can compare
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c
arguments lists
CALL SolveQuadratic(a,b,r1,r2) • Inconsistent argument lists lead
WRITE(*,*) 'Solutions:',r1,r2
CONTAINS
to compiler error:
SUBROUTINE SolveQuadratic(a,b,c,r1,r2) gfortran -g -Wall main.f90 -o main
IMPLICIT NONE main.f90:12.26:
REAL, INTENT(IN) :: a,b,c
COMPLEX, INTENT(OUT) :: r1,r2
REAL :: d,q CALL SolveQuadratic(a,b,r1,r2)
d = b**2 - 4.0*a*c 1
IF ( d < 0.0 ) THEN Error: Type mismatch in argument 'c'
q = SQRT(-d)
r1 = CMPLX(-0.5*b/a, 0.5*q/a) at (1); passed COMPLEX(4) to REAL(4)
r2 = CMPLX(-0.5*b/a,-0.5*q/a)
ELSE
q = -0.5*(b + SIGN(1.0,b)*SQRT(d))
r1 = CMPLX(q/a,0.0)
r2 = CMPLX(c/q,0.0)
END IF ! d
END SUBROUTINE SolveQuadratic
END PROGRAM main
45
Functions & Subroutines: Discussion
PROGRAM main
IMPLICIT NONE • Now consider case of external
REAL :: a,b,c
COMPLEX :: r1,r2 procedure
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c • Compiler cannot compare
CALL SolveQuadratic(a,b,r1,r2) argument lists
WRITE(*,*) 'Solutions:',r1,r2
END PROGRAM main • Code compiles successfully and
SUBROUTINE SolveQuadratic(a,b,c,r1,r2) gives wrong answer!
IMPLICIT NONE
REAL, INTENT(IN) :: a,b,c
COMPLEX, INTENT(OUT) :: r1,r2
REAL :: d,q
• Problem is implicit interface of
d = b**2 - 4.0*a*c procedure
IF ( d < 0.0 ) THEN
q = SQRT(-d)
r1 = CMPLX(-0.5*b/a, 0.5*q/a)
r2 = CMPLX(-0.5*b/a,-0.5*q/a)
ELSE
q = -0.5*(b + SIGN(1.0,b)*SQRT(d))
r1 = CMPLX(q/a,0.0)
r2 = CMPLX(c/q,0.0)
END IF ! d
END SUBROUTINE SolveQuadratic
46
Functions & Subroutines: Discussion
PROGRAM main
IMPLICIT NONE • Problem can be solved by
INTERFACE
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
providing explicit interface
REAL, INTENT(IN) :: a,b,c • Inconsistent argument lists lead
COMPLEX, INTENT(OUT) :: r1,r2
END SUBROUTINE SolveQuadratic
to compiler error:
END INTERFACE gfortran -g -Wall -c main.f90 -o main.o
REAL :: a,b,c main.f90:19.26:
COMPLEX :: r1,r2
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c CALL SolveQuadratic(a,b,r1,r2)
CALL SolveQuadratic(a,b,r1,r2) 1
WRITE(*,*) 'Solutions:',r1,r2 Error: Type mismatch in argument 'c' at
END PROGRAM main (1); passed COMPLEX(4) to REAL(4)
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)
IMPLICIT NONE
REAL, INTENT(IN) :: a,b,c
• Will not discuss explicit
COMPLEX, INTENT(OUT) :: r1,r2
…
interfaces in detail here since
… there exists a better way…
…
END SUBROUTINE SolveQuadratic
47
Functions & Subroutines: Discussion
• What are advantages/disadvantages of internal and external
procedures?
Advantages Disadvantages
Internal procedure • Simplicity: no need to • Single-file program may
(with CONTAINS compile and link multiple become long
statement) files • Inconvenient for sharing
• Interfaces are always
explicit
External procedure • Separate files easier to • Need to compile and link
(separate files) keep short and easy to multiple files
understand • Explicit interfaces must
• Easy to share be provided
48
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
49
Modules
• Modules collect variables, data-type definitions, and
procedures
• Advantages:
‣ Simplify writing of modular programs
‣ Module procedures automatically have explicit interfaces
‣ …
50
Modules
MODULE ModSolvePoly Name of module (up to 31 characters)
CONTAINS CONTAINS statement indicates
SUBROUTINE SolveQuadratic(a,b,c,r1,r2) that procedures follow
IMPLICIT NONE
REAL :: d,q
d = b**2 - 4.0*a*c
51
Modules
• Accessing contents of module is known as use association:
PROGRAM main
CALL SolveQuadratic(a,b,c,r1,r2)
WRITE(*,*) 'Solutions:',r1,r2
52
Modules
• Modules are compiled like other Fortran source files:
gfortran -g -Wall -c ModSolvePoly.f90 -o ModSolvePoly.o
gfortran -g -Wall -c main.f90 -o main.o
gfortran -g -Wall main.o ModSolvePoly.o -o main
USE ModSolvePoly
1
Fatal Error: Can't open module file 'modsolvepoly.mod' for reading at (1): No
such file or directory
53
Modules
• Key point: By placing procedure SolveQuadratic in module,
it automatically acquires explicit interface
• Therefore, if use incorrect argument list, such as
PROGRAM main
USE ModSolvePoly
IMPLICIT NONE
REAL :: a,b,c
COMPLEX :: r1,r2
CALL SolveQuadratic(a,b,r1,r2)
WRITE(*,*) 'Solutions:',r1,r2
54
Modules
• Modules give flexibility of splitting program into several files
without having to specify explicit interfaces
• ModSolvePoly.f90 could be made more useful by including
additional routines:
‣ SolveCubic(a,b,c,d,r1,r2,r3)
‣ SolveQuartic(a,b,c,d,e,r1,r2,r3,r4)
‣ Versions with double-precision arithmetic
‣ Versions with complex coefficients a, b, and c
‣ …
55
Modules
• So far, only placed procedures in modules
• But modules can also contain variables and constants
• Simple examples:
MODULE ModPhysicalConstantsSP
IMPLICIT NONE
MODULE ModMathematicalConstantsSP
IMPLICIT NONE
END ModMathematicalConstantsSP
INTEGER, INTENT(INOUT) :: a
a = 10
WRITE(*,*) IntegerPublic,a
CALL DummySubroutine(a)
a = IntegerPublic*a
WRITE(*,*) a
END SUBROUTINE DummySubroutine
END PROGRAM main
END MODULE ModSample
• Output:
2 10
20
57
Modules
• More powerful to combine data and procedures:
PROGRAM main MODULE ModSample
INTEGER, INTENT(INOUT) :: a
a = 10
WRITE(*,*) IntegerPublic,a
CALL DummySubroutine(a)
a = IntegerPublic*a
WRITE(*,*) a
END SUBROUTINE DummySubroutine
END PROGRAM main
END MODULE ModSample
• Output:
2 10
20
58
Modules
• IntegerPublic accessible to:
‣ All procedures in ModSample and
‣ All procedures that use-associate ModSample
59
Modules
• For example, variable called IntegerPublic in main would
conflict with IntegerPublic in ModSample…
• … and have led to compiler error:
main.f90:8.29:
INTEGER :: a,IntegerPublic
1
main.f90:4.6:
USE ModSample
2
Error: Symbol 'integerpublic' at (1) conflicts with symbol
from module 'modsample', use-associated at (2)
60
Modules
• To avoid conflicts:
‣ Careful naming of variables and constants in procedures that
use-associate variables and constants from modules
‣ Restricting access to variables and constants in modules
where possible: Make variables public only if necessary
• Fortran enables this with PUBLIC and PRIVATE attributes for
variables and constants declared in modules: data hiding
61
Modules
• One solution: Public as default
PROGRAM main MODULE ModSample
62
Modules
• Better (and recommended) solution: Private as default
PROGRAM main MODULE ModSample
IntegerPublic = 2 CONTAINS
SUBROUTINE DummySubroutine(a)
a = 10
IMPLICIT NONE
CALL DummySubroutine(a)
INTEGER, INTENT(INOUT) :: a
WRITE(*,*) a
WRITE(*,*) IntegerPublic,a
END PROGRAM main
IntegerPrivate = 20
a = IntegerPublic*IntegerPrivate*a
IntegerPublic = 2 CONTAINS
SUBROUTINE DummySubroutine(a)
a = 10
IMPLICIT NONE
CALL DummySubroutine(a)
INTEGER, INTENT(INOUT) :: a
WRITE(*,*) a
WRITE(*,*) IntegerPublic,a
END PROGRAM main
IntegerPrivate = 20
a = IntegerPublic*IntegerPrivate*a
IMPLICIT NONE
a = 10
INTEGER, INTENT(INOUT) :: a
CALL DummySubroutine(a)
WRITE(*,*) IntegerPublic,a
WRITE(*,*) a
IntegerPrivate = 20
END PROGRAM main
a = IntegerPublic*IntegerPrivate*a
65
Modules
• Compiling this leads to:
gfortran -g -Wall -c ModSample.f90 -o ModSample.o
ModSample.f90:10:0: warning: 'dummysubroutine' defined but
not used [-Wunused-function]
gfortran -g -Wall -c main.f90 -o main.o
gfortran ModSample.o main.o -o main
Undefined symbols for architecture x86_64:
"_dummysubroutine_", referenced from:
_MAIN__ in main.o
ld: symbol(s) not found for architecture x86_64
66
Modules: Examples
• Module for vectors:
‣ Define vector
‣ Multiply vector by scalar
‣ Scalar product
‣ Vector product
‣ Angle between vectors
‣ Rotation of vector
‣ …
• Module for intersections:
‣ Two lines
‣ Line and circle
‣ Two circles
‣ …
67
Modules: Examples
68
Modules
• Fortran allows definition of new data types: derived data types
• Examples:
TYPE :: t_point Recommendation: Use _t prefix or postfix to
REAL :: x,y distinguish type definition from variables/constants
END TYPE t_point
TYPE :: t_line
REAL :: intercept,slope
END TYPE t_line
TYPE :: t_circle
REAL :: radius
REAL :: origin(2)
END TYPE t_circle
• Modules are well suited to contain derived data types and the
procedures to manipulate them
• Otherwise, would need type definition in every procedure that
needs them
69
Modules
• Example module:
MODULE ModIntersections
IMPLICIT NONE
SUBROUTINE IntersectLineCircle(line,circle,point1,point2)
TYPE :: t_point IMPLICIT NONE
REAL :: x,y
END TYPE t_point TYPE(t_circle), INTENT(IN) :: circle
TYPE(t_line), INTENT(IN) :: line
TYPE :: t_line TYPE(t_point), INTENT(OUT) :: point1,point2
REAL :: intercept,slope …
END TYPE t_line
END SUBROUTINE IntersectLineCircle
TYPE :: t_circle
REAL :: radius
REAL :: origin(2)
END TYPE t_circle
CONTAINS
SUBROUTINE IntersectLineCircle(line,circle,point1,point2)
…
END SUBROUTINE IntersectLineCircle
70
Modules
• The example definitions could be used as follows:
PROGRAM typedemo
Contains derived data type
USE ModIntersections
definition and procedures
IMPLICIT NONE
TYPE(t_point) :: ipoint1,ipoint2
Declaration with derived data
TYPE(t_line) :: line
type definition
TYPE(t_circle) :: circle
line%intercept = 1.05
line%slope = -2.31
Set components of derived
circle%origin(1) = -0.72 data types using %
circle%origin(2) = 0.59
circle%radius = 2.17
71
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
72
Arrays: Dynamic Memory Allocation
• Previously discussed arrays with known dimensions
• In practice, array dimensions usually problem-dependent
• Such arrays are declared with
REAL, ALLOCATABLE :: a(:,:)
or
REAL, DIMENSION(:,:), ALLOCATABLE :: a
• Once dimensions known, can allocate memory:
ALLOCATE(a(m,n),STAT=ef) ALLOCATE returns an integer status
IF ( ef /= 0 ) THEN variable
WRITE(*,*) ‘ERROR!’
Non-zero status variable indicates
STOP
memory allocation was unsuccessful
END IF ! ef
Values and meaning of non-zero
status variable compiler-dependent
73
Arrays: Dynamic Memory Allocation
• If array no longer needed, can be deallocated:
DEALLOCATE(a,STAT=ef) DEALLOCATE returns an integer status
IF ( ef /= 0 ) THEN variable
WRITE(*,*) ‘ERROR!’
Non-zero status variable indicates
STOP
memory deallocation was unsuccessful
END IF ! ef
Values and meaning of non-zero status
variable compiler-dependent
74
Arrays: Dynamic Memory Allocation
PROGRAM test Stepping out-of-bounds leads to
IMPLICIT NONE
run-time error:
INTEGER :: ef,m,n
Enter m,n:
REAL, ALLOCATABLE :: a(:,:)
4
WRITE(*,*) 'Enter m,n:'
2
READ(*,*) m,n
ALLOCATE(a(m,n),STAT=ef) Program received signal SIGSEGV:
IF ( ef /= 0 ) THEN Segmentation fault - invalid memory
WRITE(*,*) 'ERROR!' reference.
STOP Backtrace for this error:
END IF ! ef
#0 0x104d492d2
a = 1.0 #1 0x104d49a8e
DEALLOCATE(a,STAT=ef) #2 0x7fff875c1f19
IF ( ef /= 0 ) THEN
#3 0x104e1db4a
WRITE(*,*) 'ERROR!'
STOP #4 0x104e20514
END IF ! ef #5 0x104e2104e
WRITE(*,*) a(1,1) #6 0x104d40d87
#7 0x104d40dce
END PROGRAM test
Segmentation fault: 11
76
Arrays: Dynamic Memory Allocation
• If unsure whether a allocated, use ALLOCATED(a) function:
‣ Returns logical variable, set to true if a allocated, false
otherwise
‣ Can only be used if a declared with ALLOCATABLE attribute
77
Arrays: Dynamic Memory Allocation
• Good programming practice:
‣ Always check status variables
‣ Write helpful error messages
78
Arrays: Dynamic Memory Allocation
• How could error handling in PROGRAM allocdealloc
79
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics
80
Arrays as Arguments: Background
81
Arrays as Arguments: Background
Dimension/ Dimension
Array Shape Size
Rank extents
a(2,3) 2 2,3 6
b(0:1,-1:1) 2 2,3 6
c(-1:1,0:3) 2 3,4 12
e(5) 1 5 5
f(-3:1) 1 5 5
82
Arrays as Arguments
• Four types of arrays in Fortran:
Shape Use
Explicit-shape array Explicitly declared As dummy argument or
as local variable
83
Arrays as Arguments
SUBROUTINE arrayargs(m,n,a,b)
IMPLICIT NONE
! Arguments
INTEGER, INTENT(IN) :: m,n
REAL, INTENT(INOUT) :: a(m,n) ! Explicit-shape array
REAL, INTENT(INOUT) :: b(:,:) ! Assumed-shape array
! Locals
INTEGER :: r,s
REAL :: c(m,n),d(5,n) ! Automatic arrays
REAL :: e(5) ! Explicit-shape array
REAL, ALLOCATABLE :: f(:,:,:) ! Deferred-shape array
! Allocate memory
r = …
s = …
ALLOCATE(f(3,r,s),STAT=ef)
…
DEALLOCATE(f,STAT=ef)
…
84
Arrays as Arguments
SUBROUTINE arrayargs(m,n,a,b)
IMPLICIT NONE
! Arguments
INTEGER, INTENT(IN) :: m,n
REAL, INTENT(INOUT) :: a(m,n) ! Explicit-shape array
REAL, INTENT(INOUT) :: b(:,:) ! Assumed-shape array
! Locals
INTEGER :: r,s
REAL :: c(m,n),d(5,n) ! Automatic arrays
REAL :: e(5) ! Explicit-shape array
REAL, ALLOCATABLE :: f(:,:,:) ! Deferred-shape array
! Allocate memory
r = … Assumed-shape array can only be
s = … dummy argument in procedure with
ALLOCATE(f(3,r,s),STAT=ef) explicit interface, so either
… 1. calling routine includes explicit
DEALLOCATE(f,STAT=ef) interface for arrayargs, or
… 2. arrayargs is placed in MODULE
END SUBROUTINE arrayargs and USEd in calling routine
85
Arrays as Arguments
PROGRAM arrayexpshape
• Careful when passing array
IMPLICIT NONE
with non-unity lower bounds!
INTEGER :: a(-3:2,4:5)
SUBROUTINE sub(b)
but
1 6
INTEGER, INTENT(IN) :: b(:,:)
1 2
WRITE(*,*) LBOUND(b,1),UBOUND(b,1)
WRITE(*,*) LBOUND(b,2),UBOUND(b,2) • Q: Can you think of a work-
END SUBROUTINE sub around?
END PROGRAM arrayexpshape
86
Additional Topics
Topic Brief description Additional information
Whole-array operations Perform operations on Chapman (2008): 6.3
whole arrays
Namelist input/output Simplified input/output Chapman (2008): 14.4
of group of variables Ellis et al. (1994): 15.7
Binary files Faster reading/writing, Chapman (2008): 14.3
smaller file sizes
Recursion Enable procedures to Chapman (2008): 13.2
call themselves Ellis et al. (1994): 11.5
Object-oriented Enhanced modularity, Chapman (2008): 16
programming (a little in flexibility, abstraction
Fortran 90/95, but
mostly in Fortran 2003)
Command-line Access to command- Chapman (2008): 13.11
arguments (Fortran line arguments
2003)
87
Additional Topics
Topic Brief description Additional information
Parameterized data Change representation Chapman (2008): 11
types of data Ellis et al. (1994): 10.2,
14
Optional arguments Do not pass all Chapman (2008): 13.3
arguments to Ellis et al. (1994): 11.1
procedures
Procedures as Pass procedure Chapman (2008): 7.5
arguments names as arguments
to procedures
Generic procedures Procedures for Chapman (2008): 13.5
different data types Ellis et al. (1994): 11.6
88