0% found this document useful (0 votes)
126 views

Computing With Fortran by Haselbacher PDF

This document provides an overview of a course on computing with Fortran. It discusses the structure of a simple Fortran program, including the declaration, executable, and termination sections. It also covers compiling and linking Fortran programs, as well as comments, formatting, and style guidelines. The course will cover intrinsic data types, operations, procedures, control flow, and input/output in Fortran. Programming exercises will take place each day to reinforce the concepts.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
126 views

Computing With Fortran by Haselbacher PDF

This document provides an overview of a course on computing with Fortran. It discusses the structure of a simple Fortran program, including the declaration, executable, and termination sections. It also covers compiling and linking Fortran programs, as well as comments, formatting, and style guidelines. The course will cover intrinsic data types, operations, procedures, control flow, and input/output in Fortran. Programming exercises will take place each day to reinforce the concepts.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 202

Computing with Fortran

Engineering Tool V
Spring 2015

Dr. Andreas Haselbacher


Institute of Energy Technology
Overview
• Course overview
• Structure of simple Fortran program
• Compiling and linking
• Intrinsic data types
• Operations
• Intrinsic procedures
• Control flow
• Input/output

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

• Students have fun programming!

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

END PROGRAM simple_program

11
Structure of Simple Fortran Program

PROGRAM simple_program

IMPLICIT NONE Declaration section

INTEGER :: i,j

i = 1
j = 2*i
Executable section

WRITE(*,*) i,j

END PROGRAM simple_program Termination section

12
Structure of Simple Fortran Program

PROGRAM simple_program Program name can consist of up to 31


letters, digits, and underscores, that is,
IMPLICIT NONE A-Z, a-z, 0-9, _

Program name must start with letter


INTEGER :: i,j
Fortran is case-insensitive! So
i = 1 simple_program
SIMPLE_PROGRAM
j = 2*i
sIMplE_pRoGRaM
are all equivalent
WRITE(*,*) i,j

END PROGRAM simple_program

13
Structure of Simple Fortran Program

PROGRAM simple_program

IMPLICIT NONE Don’t worry about this for now, we’ll


deal with it later
INTEGER :: i,j

i = 1
j = 2*i

WRITE(*,*) i,j

END PROGRAM simple_program

14
Structure of Simple Fortran Program

PROGRAM simple_program

IMPLICIT NONE

INTEGER :: i,j Fortran commands, variables, and


constants are also case-insensitive!
i = 1
Could just as well have written
j = 2*i integer :: I,J
InTEgEr :: I,j
WRITE(*,*) i,j
Recommend following convention:
• Fortran commands: uppercase
END PROGRAM simple_program
• Program names: mixed case
• Variable names: mixed case

Variable names must not coincide with


Fortran commands and procedures

15
Structure of Simple Fortran Program

PROGRAM simple_program

IMPLICIT NONE

INTEGER :: i,j Lines may be up to 132 characters long

i = 1 Recommendation: Restrict to smaller


number (say, 80) which can be printed
j = 2*i on A4 paper with normal font size

WRITE(*,*) i,j If line is longer than your maximum


length, use continuation character &
END PROGRAM simple_program and continue on next line

The maximum number of continuation


lines is 39

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

END PROGRAM simple_program

17
Structure of Simple Fortran Program

PROGRAM simple_program program simple_program


implicit none
IMPLICIT NONE integer :: i,j
i = 1
INTEGER :: i,j j = 2*i
write(*,*) i,j
i = 1 end program simple_program
j = 2*i

WRITE(*,*) i,j

END PROGRAM simple_program

18
Structure of Simple Fortran Program

PROGRAM simple_program
In a simple program like this one,
IMPLICIT NONE comments are not really necessary

But in more complicated ones,


INTEGER :: i,j
comments are very important

i = 1 In Fortran, comments start with !


j = 2*i

WRITE(*,*) i,j

END PROGRAM simple_program

19
Structure of Simple Fortran Program

PROGRAM simple_program
In a simple program like this one,
IMPLICIT NONE comments are not really necessary

But in more complicated ones,


INTEGER :: i,j
comments are very important

! Define i In Fortran, comments start with !


i = 1

j = 2*i ! Compute j Comments can be placed anywhere,


even on same line as statements
WRITE(*,*) i,j

END PROGRAM simple_program

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

simple_code.f90 Source code/source file

22
Compiling & Linking

simple_code.f90 Source code/source file

Compiling

simple_code.o Object code/object file

23
Compiling & Linking

simple_code.f90 Source code/source file

Compiling

simple_code.o Object code/object file

Linking

simple_code
Executable/executable file
simple_code.exe

24
Compiling & Linking

simple_code.f90

gfortran -c simple_code.f90 -o simple_code.o

simple_code.o

gfortran simple_code.o -o simple_code

simple_code

25
Compiling & Linking

simple_code.f90 Compiler option indicating


“compile only”

gfortran -c simple_code.f90 -o simple_code.o

simple_code.o Compiler option indicating


name of output

gfortran simple_code.o -o simple_code

simple_code Many additional compiler options are available


We’ll talk about some of them later

26
Compiling & Linking

simple_code.f90

gfortran simple_code.f90 -o simple_code

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/

Quote perfectly encapsulates two


central components of a program:
‣ Data (and how it is stored)
‣ Algorithms/methods/operations
that manipulate data

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

• Integer constants declared with:


INTEGER, PARAMETER :: NEDGES_MAX = 1000
• Constants (of any data type) often called named constants
• Constants (of any data type) cannot be changed after the
declaration

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

• Q: How to represent negative integers?


• A: Reserve one bit to represent sign
• Thus can represent numbers ranging from -2n-1 to 2n-1-1
• Fortran uses 32 bits for INTEGERs, thus can represent
numbers ranging from -2147483648 to 2147483647
• Very important: Range of representable numbers is limited
• Exceeding the range leads to integer overflow or underflow

34
Intrinsic Data Types: REAL
• Computers represent floating-point numbers:
132.857 =+0.132857E+3

Sign Mantissa Exponent


• Range of real numbers that can be represented depends on
numbers of bits used for mantissa and exponent
• Fortran uses 32 bits for REALs:
‣ 1 bit for sign
‣ 23 bits for mantissa
‣ 8 for exponent
• Most floating-point numbers are rounded, so not exact
• Largest number: 3.40282347E+38
• Machine precision: 1.19209290E-07

35
Intrinsic Data Types: DOUBLE PRECISION Program
example

• If REAL range too small or machine precision too large, need


DOUBLE PRECISION representation
• Fortran uses 64 bits for DOUBLE PRECISION:
‣ 1 bit for sign
‣ 52 bits for mantissa
‣ 11 for exponent

• Largest number: 1.7976931348623157E+308


• Machine precision: 2.2204460492503131E-016

36
Intrinsic Data Types: COMPLEX
• Convenient way to represent complex numbers:
COMPLEX :: c,d

c = (1.0,-2.0) Represents 1-2i


d = CMPLX(-3,4) Represents -3+4i

• Fortran provides intrinsic procedures for complex numbers,


such as magnitudes, complex conjugates, etc.

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 = ‘a’ Can initialise characters with


c = “b” single or double quotes

c = ‘&’

• Single characters are not, of course, very useful

39
Intrinsic Data Types: CHARACTER
• To represent words or phrases, use strings of characters
• Example of declaration of string:
CHARACTER(LEN=11) :: c

Ok to initialise to string with less than 11


c = “hello world” characters, but not more

• Careful with apostrophes:


c = ‘what’s up?’ Gives compiler error (unbalanced quotes)
c = “what’s up?”
Both ok
c = ‘what’’s up?’

• Can also use shorter declaration


CHARACTER(11) :: c

40
Intrinsic Data Types: CHARACTER
• Declaration of character string parameters:
CHARACTER(6), PARAMETER :: ERROR_MESSAGE = ‘ERROR!’
INTEGER :: i,j

WRITE(*,*) ‘Enter positive integer:’


READ(*,*) i
WRITE(*,*) ‘Enter negative integer:’
READ(*,*) 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

• Hence recommend that always use IMPLICIT NONE

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

• In general: leftmost subscript varies fastest


• This has important performance implications
• Maximum number of array dimensions: 7

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) Compile with


gfortran bounds1d.f90 -o bounds1d
END PROGRAM bounds1d
Compiler produces executable, but also
issues warning:
bounds1d.f90:10.15:

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/)

WRITE(*,*) 'Enter i:'


READ(*,*) i

WRITE(*,*) a(i) Compiler cannot issue warning, as index i


is unknown at compile time
END PROGRAM bounds1d

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

• Full list of warning options:


gfortran --help=warnings
• These options will slow down executable, ok during
development and testing

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

• Binary operations: • Careful when comparing


real numbers!
== equal to a == b

/= not equal to a /= b
> greater than a > b

>= greater than or a >= b


equal to
< smaller than a < b

<= smaller than or a <= b


equal to

• Precedence: Left to right

59
Logical Operations
• Can only be used with logical variables and constants
• Binary operations:

.AND. logical AND

.OR. logical OR

.EQV. logical equivalence

.NEQV. logical nonequivalence

• Unary operation:
.NOT. logical NOT

60
Logical Operations
• Truth table:
A B A .AND. B A .OR. B A .EQV. B A .NEQV. B

.FALSE. .FALSE. .FALSE. .FALSE. .TRUE. .FALSE.

.FALSE. .TRUE. .FALSE. .TRUE. .FALSE. .TRUE.

.TRUE. .FALSE. .FALSE. .TRUE. .FALSE. .TRUE.

.TRUE. .TRUE. .TRUE. .TRUE. .TRUE. .FALSE.

• Precedence (top to bottom):


.NOT. left to right
.AND. left to right .NEQV. is
.OR. equivalent to
left to right
“exclusive or”
.EQV.
.NEQV. left to right

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

TRIM(x) Remove 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)

which is equivalent to: i, i_beg, i_end must not be changed


in loop
i = i_beg
Fortran statement
i = i + i_inc
Fortran statement

i = i_end
Fortran statement
• Known as “iterative” or “counting” or “count-controlled” loop

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

IF ( flagReachedMaxCounter .EQV. .TRUE. ) THEN


WRITE(*,*) ‘WARNING! Maximum loop counter reached!’
END IF

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

Values and meaning of non-zero


variable compiler-dependent

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

Note apostrophes and


parentheses!
99
Output: To Screen with Formatting
• Following only covers most important edit descriptors
• For more information, see:
‣ Chapman (2008): 5.3 and 14.1
‣ Ellis et al. (1994): 8.2 and 15.2
‣ Metcalf et al. (2004): 9

100
Output: To Screen with Formatting
• For character variables and constants, use A edit descriptor:
Aw w = overall width

• Example code: • Output


PROGRAM editdescriptors

IMPLICIT NONE

INTEGER, PARAMETER :: MAX_CHAR_LEN = 80


CHARACTER(MAX_CHAR_LEN) :: c

c = 'We are testing edit descriptors!'

WRITE(*,*) LEN_TRIM(c) 32

WRITE(*,'(A10)') c We are tes


WRITE(*,'(A32)') c We are testing edit descriptors!
WRITE(*,'(A33)') c We are testing edit descriptors!

END PROGRAM editdescriptors


Output truncated if
width too small!

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

w = overall width ±mmm.nnnnnnn


Fw.d
d = number of decimal places <- d ->

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

WRITE(*,'(A,1X,E13.6)') 'E13.6 gives:',r E13.6 gives: -0.123457E+10


WRITE(*,'(A,1X,E10.3)') 'E10.3 gives:',r E10.3 gives: -0.123E+10
WRITE(*,'(A,1X,E9.3)') 'E9.3 gives:',r E9.3 gives: -.123E+10
WRITE(*,'(A,1X,E8.3)') 'E8.3 gives:',r E8.3 gives: ********
WRITE(*,'(A,1X,E7.3)') 'E7.3 gives:',r E7.3 gives: *******

END PROGRAM editdescriptors

Use nX edit descriptor to If overall width too small,


insert n empty spaces lose 0 and get *

103
Output: To Screen with Formatting
• Example code: • Output:

PROGRAM editdescriptors

IMPLICIT NONE

REAL :: r

r = -12345.0

WRITE(*,'(A,1X,F8.1)') ‘F8.1 gives:',r F8.1 gives: -12345.0


WRITE(*,’(A,1X,F9.2)') ‘F9.2 gives:',r F9.2 gives: -12345.00
WRITE(*,’(A,1X,F7.1)') ‘F7.1 gives:',r F7.1 gives: *******

END PROGRAM editdescriptors

If overall width too small,


get *

104
Output: To Screen with Formatting
• For integer variables and constants, use I edit descriptor:
Iw w = overall width

• For logical variables and constants, use L edit descriptor:


Lw 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)’)

• More complicated example:


WRITE(*,’(A,3X,A,2(1X,E23.16),2(1X,I9))') s1,s2,r1,r2,i1,i2

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

STATUS=fileStatus fileStatus is a string Permissible values of fileStatus:


• ‘NEW’ = File must not exist, causes
error if does exist
• ‘OLD’ = File must exist, causes error
if does not exist
• ‘REPLACE’ = Create file regardless
of whether it exists
• ‘UNKNOWN’ = File may exist,
behaviour is compiler-dependent
IOSTAT=errorFlag errorFlag is an integer Non-zero values of errorFlag indicate
that an error occurred on opening the
file. The values and meaning are
compiler-dependent.

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

STATUS=fileStatus fileStatus is a string Permissible values of fileStatus:


• ‘KEEP’ = File will not be deleted after
closing (default)
• ‘DELETE’ = File will be deleted after
closing
IOSTAT=errorFlag errorFlag is an integer Non-zero values of errorFlag indicate
that an error occurred on opening the
file. The values and meaning are
compiler-dependent.

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

Dr. Andreas Haselbacher


Institute of Energy Technology
Overview
• Structuring a program
• Functions
• Makefiles
• Subroutines
• Functions & subroutines: discussion
• Modules
• Arrays
‣ Dynamic memory allocation
‣ Arrays as arguments
• Additional topics

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 FUNCTION cbrt(x)

IMPLICIT NONE Declaration section

REAL, INTENT(IN) :: x

cbrt = EXP(LOG(x)/3.0) Executable section

END FUNCTION cbrt Termination section

6
Functions
• Example: Fortran provides intrinsic function to compute square
root, but not cube root
• Can address this problem by writing own function:

REAL FUNCTION cbrt(x) Name of function and dummy argument


Note: Can have more than one dummy
IMPLICIT NONE argument, name must not coincide with
Fortran commands, intrinsic procedures

REAL, INTENT(IN) :: x Declaration of dummy argument(s)

cbrt = EXP(LOG(x)/3.0) Compute result, must be assigned to


variable with same name as function
END FUNCTION cbrt End of function

• Will address INTENT(IN) attribute shortly…

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:

cbrt is internal procedure cbrt is external procedure

Put cbrt into same file as main,


Put cbrt and main into separate
use CONTAINS statement, and
files, compile separately, then link
compile as single file

9
Functions: Internal Procedure
• Example:
PROGRAM main Single file
IMPLICIT NONE
REAL :: x,r
x = 3.0
r = cbrt(x)
WRITE(*,*) r

CONTAINS

REAL FUNCTION cbrt(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x
cbrt = EXP(LOG(x)/3.0)
END FUNCTION cbrt

END PROGRAM main

10
Functions: Internal Procedure
• Example:
PROGRAM main
IMPLICIT NONE
REAL :: x,r
Main program
x = 3.0
r = cbrt(x)
WRITE(*,*) r

CONTAINS

REAL FUNCTION cbrt(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x
cbrt = EXP(LOG(x)/3.0)
END FUNCTION cbrt

END PROGRAM main

11
Functions: Internal Procedure
• Example:
PROGRAM main
IMPLICIT NONE
REAL :: x,r
x = 3.0
r = cbrt(x)
WRITE(*,*) r

CONTAINS CONTAINS statement

REAL FUNCTION cbrt(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x
cbrt = EXP(LOG(x)/3.0)
END FUNCTION cbrt

END PROGRAM main

12
Functions: Internal Procedure
• Example:
PROGRAM main
IMPLICIT NONE
REAL :: x,r
x = 3.0
r = cbrt(x)
WRITE(*,*) r

CONTAINS

REAL FUNCTION cbrt(x)


Function
IMPLICIT NONE
REAL, INTENT(IN) :: x
Note: Function appears after CONTAINS
cbrt = EXP(LOG(x)/3.0)
END FUNCTION cbrt
statement but before END PROGRAM statement

END PROGRAM main

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:

REAL FUNCTION cbrt(x)

IMPLICIT NONE

REAL :: x No INTENT(IN)attribute

x = LOG(x)/3.0 Statement changes x, but not cbrt

cbrt = EXP(x)

END FUNCTION cbrt


This function is said to have a side-effect:
It does not just return a result (main effect), but
also modifies the dummy argument
14
Functions: INTENT(IN) Attribute
• Effectively, functions with side effects have two (or more)
outputs
• Side effects are permitted in Fortran, but considered poor
programming practice

• Good programming practice: Write functions without side


effects, that is, functions that do not modify dummy arguments
• Recommendation: always use INTENT(IN) attribute for
dummy arguments in functions

• INTENT(IN) attribute is nothing but a sign to compiler to


check if your actions and intentions are consistent
• If variable with INTENT(IN) modified by mistake, compiler
issues error

15
Functions: INTENT(IN) Attribute
• Example:

REAL FUNCTION cbrt(x)

IMPLICIT NONE

REAL, INTENT(IN) :: x

Statement changes x and hence


x = LOG(x)/3.0
violates INTENT(IN) attribute

cbrt = EXP(x) Therefore, compiler will issue error

END FUNCTION cbrt

16
Functions: External Procedure
main.f90 cbrt.f90

PROGRAM main REAL FUNCTION cbrt(x)


IMPLICIT NONE IMPLICIT NONE
REAL, EXTERNAL :: cbrt REAL, INTENT(IN) :: x
REAL :: x,r cbrt = EXP(LOG(x)/3.0)
x = 3.0 END FUNCTION cbrt
r = cbrt(x)
WRITE(*,*) r
END PROGRAM main

Compiling
gfortran -g -Wall -c main.f90 -o main.o gfortran -g -Wall -c cbrt.f90 -o cbrt.o

main.o cbrt.o

Linking

gfortran main.o cbrt.o -o main

main

17
Functions: External Procedure
• Functions in files other than that containing main program
must be declared with the EXTERNAL attribute

• Advantage: Putting functions into separate files has advantage


of keeping size of main program manageable
• Disadvantage: Compiler cannot check whether function called
correctly (illustrated later)
• Later, will learn how to solve this problem

18
Functions: Alternative Form
• Example:

REAL FUNCTION cbrt(x)

IMPLICIT NONE

REAL, INTENT(IN) :: x

cbrt = EXP(LOG(x)/3.0)

END FUNCTION cbrt

19
Functions: Alternative Form
• Example:

FUNCTION cbrt(x) Can omit data type from FUNCTION


statement…
IMPLICIT NONE

REAL :: cbrt … provided it is declared


REAL, INTENT(IN) :: x
Note: This form is necessary with
functions that return user-defined data
cbrt = EXP(LOG(x)/3.0) types

END FUNCTION cbrt

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

### Source and object section ##################################################


SRCF90= ModSample.f90 main.f90 List source files (modules first)

### Pattern rules ##############################################################


%.o: %.f90
$(FC) $(FFLAGS) -c $< -o $@
Explain to make how to produce
object files from source files
OBJF90= $(SRCF90:.f90=.o)

### Target section #############################################################


$(EXEC): $(OBJF90)
$(FC) $(OBJF90) $(LDFLAGS) -o $@

Explain to make what to do


.PHONY: clean
clean:
$(RM) $(OBJF90) *.$(MODEXT) $(EXEC) $(RIFFRAFF)

### Dependencies section ####################################################### Explain to make how your files


main.o: ModSample.o
depend on each other

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)

### Target section #############################################################


$(EXEC): $(OBJF90)
$(FC) $(OBJF90) $(LDFLAGS) -o $@

.PHONY: clean
clean:
$(RM) $(OBJF90) *.$(MODEXT) $(EXEC) $(RIFFRAFF)

### Dependencies section ####################################################### If you add or remove source


main.o: ModSample.o files from your code, edit this list
accordingly

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

WRITE(*,*) ‘Enter a,b,c:’


READ(*,*) a,b,c
Get coefficients

CALL SolveQuadratic(a,b,c,r1,r2) Call subroutine to compute roots


WRITE(*,*) ‘Solutions:’,r1,r2 Write roots
END PROGRAM main

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, INTENT(IN) :: a,b,c


Declaration section
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) Executable section
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 Termination section

29
Subroutines
SUBROUTINE SolveQuadratic(a,b,c,r1,r2) Name of subroutine and
dummy arguments
IMPLICIT NONE

REAL, INTENT(IN) :: a,b,c Declaration of dummy


COMPLEX, INTENT(OUT) :: r1,r2 arguments
REAL :: d,q Declaration of local
variables
d = b**2 - 4.0*a*c
Recommendation:
IF ( d < 0.0 ) THEN
Separate declarations into
q = SQRT(-d)
r1 = CMPLX(-0.5*b/a, 0.5*q/a) • input arguments
r2 = CMPLX(-0.5*b/a,-0.5*q/a) • output arguments
ELSE • local variables
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 of subroutine

30
Subroutines: INTENT(OUT) Attribute
SUBROUTINE SolveQuadratic(a,b,c,r1,r2)

IMPLICIT NONE

REAL, INTENT(IN) :: a,b,c


COMPLEX, INTENT(OUT) :: r1,r2 INTENT(OUT) indicates
that these dummy
REAL :: d,q
arguments become
d = b**2 - 4.0*a*c undefined on entry

IF ( d < 0.0 ) THEN It does not mean that


q = SQRT(-d) compiler should check that
r1 = CMPLX(-0.5*b/a, 0.5*q/a) they will be set!
r2 = CMPLX(-0.5*b/a,-0.5*q/a)
ELSE
q = -0.5*(b + SIGN(1.0,b)*SQRT(d)) If these dummy arguments
r1 = CMPLX(q/a,0.0) are not set in the
r2 = CMPLX(c/q,0.0) subroutine, they will be
END IF ! d undefined on exit also!
END SUBROUTINE SolveQuadratic

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)

END SUBROUTINE SolveQuadratic

END PROGRAM main

33
Subroutines: Internal Procedure

PROGRAM main

IMPLICIT NONE

REAL :: a,b,c
COMPLEX :: r1,r2

WRITE(*,*) ‘Enter a,b,c:’


READ(*,*) a,b,c

CALL SolveQuadratic(a,b,c,r1,r2)

WRITE(*,*) ‘Solutions:’,r1,r2

CONTAINS CONTAINS statement


SUBROUTINE SolveQuadratic(a,b,c,r1,r2)

END SUBROUTINE SolveQuadratic

END PROGRAM main

34
Subroutines: Internal Procedure

PROGRAM main

IMPLICIT NONE

REAL :: a,b,c
COMPLEX :: r1,r2

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) Subroutine


END SUBROUTINE SolveQuadratic


Note: Subroutine appears before
END PROGRAM statement
END PROGRAM main

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

gfortran main.o SolveQuadratic.o -o main

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

• Advantages of writing modular programs:


‣ Program easier to understand
‣ Program easier to test/debug
‣ Parts of program can be reused/shared
‣ …
• With well-designed and documented interface, procedure
internals are not important

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:

• Argument is defined on entry to procedure


INTENT(IN) • Argument will not be changed in procedure
• Compiler will issue error if argument is changed
• Argument becomes undefined on entry to the procedure
• Argument will be undefined on exit unless it is set in the
INTENT(OUT) procedure
• It is up to you to set the value of the argument!
• The compiler may not warn you if the argument is not
defined!

INTENT(INOUT) • Argument is defined on entry to procedure


• Argument can be changed in procedure

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

• There is another, very important advantage to internal


procedures…
• Consider example on following slide

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, 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) Subroutine
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 MODULE ModSolvePoly End of module

51
Modules
• Accessing contents of module is known as use association:

PROGRAM main

USE ModSolvePoly USE statements must appear


IMPLICIT NONE immediately after PROGRAM,
FUNCTION, SUBROUTINE, or
REAL :: a,b,c
MODULE statement and before
COMPLEX :: r1,r2
IMPLICIT NONE
WRITE(*,*) 'Enter a,b,c:'
READ(*,*) a,b,c

CALL SolveQuadratic(a,b,c,r1,r2)

WRITE(*,*) 'Solutions:',r1,r2

END PROGRAM main

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

• Compilation of ModSolvePoly.f90 produces


ModSolvePoly.o
modsolvepoly.mod

• Modules must be compiled before files in which they are used,


otherwise get compiler error:
main.f90:4.6:

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

WRITE(*,*) 'Enter a,b,c:'


READ(*,*) a,b,c

CALL SolveQuadratic(a,b,r1,r2)

WRITE(*,*) 'Solutions:',r1,r2

END PROGRAM main

get compiler error:


main.f90:14.26:
CALL SolveQuadratic(a,b,r1,r2)
1
Error: Type mismatch in argument 'c' at (1); passed COMPLEX(4) to REAL(4)

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

REAL, PARAMETER :: PHYS_CONST_SP_G = 9.81


REAL, PARAMETER :: PHYS_CONST_SP_C0 = 299792458.0

END MODULE ModPhysicalConstantsSP

MODULE ModMathematicalConstantsSP

IMPLICIT NONE

REAL, PARAMETER :: MATH_CONST_SP_PI = 3.141593


REAL, PARAMETER :: MATH_CONST_SP_PHI = 1.618034

END ModMathematicalConstantsSP

• Could be used to get unique values anywhere in code


56
Modules
• More powerful to combine data and procedures:
PROGRAM main MODULE ModSample

USE ModSample INTEGER :: IntegerPublic

IMPLICIT NONE CONTAINS

INTEGER :: a SUBROUTINE DummySubroutine(a)

IntegerPublic = 2 IMPLICIT NONE

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

USE ModSample INTEGER :: IntegerPublic

IMPLICIT NONE CONTAINS

INTEGER :: a SUBROUTINE DummySubroutine(a)

IntegerPublic = 2 IMPLICIT NONE

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

• Therefore, IntegerPublic said to be public variable of


module ModSample
• Consequence: Must be careful with naming variables and
constants to avoid conflicts with public variables from modules

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

USE ModSample INTEGER :: IntegerPublic


INTEGER, PRIVATE :: IntegerPrivate
IMPLICIT NONE
CONTAINS
INTEGER :: a
SUBROUTINE DummySubroutine(a)
IntegerPublic = 2
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

END SUBROUTINE DummySubroutine

END MODULE ModSample

62
Modules
• Better (and recommended) solution: Private as default
PROGRAM main MODULE ModSample

USE ModSample PRIVATE


INTEGER :: IntegerPrivate,IntegerPublic
IMPLICIT NONE
PUBLIC :: IntegerPublic
INTEGER :: a PUBLIC :: DummySubroutine

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

END SUBROUTINE DummySubroutine

END MODULE ModSample


63
Modules
• Alternative declarations:
PROGRAM main MODULE ModSample

USE ModSample PRIVATE


INTEGER, PUBLIC :: IntegerPublic
IMPLICIT NONE
INTEGER :: IntegerPrivate
INTEGER :: a PUBLIC :: DummySubroutine

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

END SUBROUTINE DummySubroutine

END MODULE ModSample


64
Modules
• Note that if DummySubroutine not PUBLIC, that is:
PROGRAM main MODULE ModSample

USE ModSample PRIVATE


INTEGER :: IntegerPrivate,IntegerPublic
IMPLICIT NONE
PUBLIC :: IntegerPublic
INTEGER :: a CONTAINS

IntegerPublic = 2 SUBROUTINE DummySubroutine(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

END SUBROUTINE DummySubroutine

• Compiling this leads to… END MODULE ModSample

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

END MODULE ModIntersections

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

CALL IntersectLineCircle(line,circle,ipoint1,ipoint2) Call subroutine with derived


data types as arguments
WRITE(*,*) ‘Intersection point 1:’,ipoint1%x,ipoint1%1
WRITE(*,*) ‘Intersection point 1:’,ipoint2%x,ipoint2%y

END PROGRAM typedemo

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

ef is short for “error flag”

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

• Before allocation and after deallocation, array elements cannot


be accessed!
• Consider following example…

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

Compare this with next example…


75
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
At line 20 of file test.f90
ALLOCATE(a(m,n),STAT=ef)
IF ( ef /= 0 ) THEN Fortran runtime error: Index '5' of
dimension 1 of array 'a' above upper
WRITE(*,*) 'ERROR!'
bound of 4
STOP
END IF ! ef
a = 1.0
WRITE(*,*) a(m+1,n)
DEALLOCATE(a,STAT=ef)
IF ( ef /= 0 ) THEN
WRITE(*,*) 'ERROR!'
STOP
END IF ! ef
END PROGRAM test

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

• If unsure about dimensions of a, use LBOUND(a,i) and


UBOUND(a,i)

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

adjacent code be improved? IMPLICIT NONE


INTEGER :: ef,i,j,m,n
REAL, ALLOCATABLE :: a(:,:)
WRITE(*,*) 'Enter m,n:'
READ(*,*) m,n
ALLOCATE(a(m,n),STAT=ef)
IF ( ef /= 0 ) THEN
WRITE(*,*) 'ERROR!'
STOP
END IF ! ef
a = 1.0
DEALLOCATE(a,STAT=ef)
IF ( ef /= 0 ) THEN
WRITE(*,*) 'ERROR!'
STOP
END IF ! ef
END 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

Number of subscripts; each subscript has


Array dimension
lower and upper bound
Array rank Same as array dimension
Dimension extent Number of elements in that dimension
Array size Total number of elements in array
Array shape Determined by rank and dimension extents

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

Assumed-shape array Not given As dummy argument


provided procedure has
explicit interface, cannot
be used in main program
Automatic array Explicitly declared, at Not as dummy argument,
least one index bound cannot be used in main
not constant program
Deferred-shape array Not given, determined Not as dummy argument,
(Allocatable array) with ALLOCATE can be used as local
statement 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)

END SUBROUTINE arrayargs

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)

a = 1 • Output of code on left: Not


CALL sub(a) -3 2
4 5
CONTAINS

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

You might also like