You are on page 1of 37

Advanced Finite Elements Methods

Eric Sonnendrücker, Ahmed Ratnani


Max-Planck-Institut für Plasmaphysik
und
Zentrum Mathematik, TU München

LESSONS NOTES
WINTERSEMESTER 2015/2016

October 14, 2015


2
Contents

1 Getting started with Fortran 7


1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1.1 Historical facts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1.2 General Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Basic Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.1 DO, WHILE statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.2 IF statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.3 SELECT statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.4 Interface procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4 Pointers and Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.5 Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.6 Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2 Modern Fortran: Object-Oriented Programming 19


2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2 Type extensions and parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3 Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4 The ASSOCIATE constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 The SELECT TYPE command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6 Type-Bound Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6.1 Prototype approach: using subroutine/functions pointers . . . . . . . . . . . . . . . . . . 22
2.6.2 Contract approach: ABSTRACT types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3 Project: A Finite Element Library 25


3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.1.1 The 1D case: code description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2 Code Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.1 First Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.2 Second specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.3 Third specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.3 A case study: A Finite Element Method Project . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

A Developper tools 27
A.1 Installation and Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
A.2 Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
A.3 Versioning: svn & git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
A.4 CMake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
A.5 Unit-tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
A.6 Calling Fortran codes from Python: f2py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
A.7 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3
4 CONTENTS

B Numerical Integration 29
B.1 Quadrature formulae . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

C Applied Linear Algebra 31


C.1 Kronecker algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
C.1.1 Kronecker sum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
C.1.2 Solving AX + XB = C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
C.1.3 Solving AXB
Pr = C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
C.1.4 Solving i=1 Ai XBi = C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
C.2 Sparse Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
C.3 Linear solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
C.3.1 Direct solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
C.3.2 Iterative solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Introduction

How to use this document


This document is not a reference manual for Fortran, there are many good books for that [7, 6, 2]. You will
not, and you don’t, need to learn all Fortran features or capabilities. However you will learn, step by step,
new concepts through some practical examples. Think of this document as a way to start writing clean codes.
Sometimes, we will intentionally write bad codes, as if we are writing them for the first time. We will give bad
naming for our variables, use some wrong design. But through these notes we will learn from our mistakes. We
will often refer to our commandments [3]. These notes are not finished yet and all remarks are welcome.

Getting and Compiling the source code


All Fortran codes that are presented in these notes can be found on github. If you have git already installed,
you can run the following lines in your Terminal :

1 git clone git@github.com:ratnania/lessons.git

this will create a directory lessons that contains a CMakeLists.txt and source codes for each chapter. Using
cmake, you need to create a build directory and run the following lines:

1 mkdir −p build
2 cd build
3 # cmake must points to the path of CMakeLists.txt file
4 cmake ..
5 make

5
6 CONTENTS
Chapter 1

Getting started with Fortran

1.1 Introduction
In this lecture, we will learn how to write Modern Fortran codes. By modern, we mean Object-Oriented
Programming. But why using an old language like Fortran, while we can use C++?
Many reasons for that. First of all

Legacy codes Through the years, the scientific community wrote a lot of good codes.
OOP What a mathematician or a physicist is asking from Fortran and the OOP, is not for sure what the C++
can offer!
In these notes, you will not learn all the features of Fortran. For more details about the language capabilities,
we refer the reader to the books [7, 2, 6, 1]. However, we will introduce, step by step, the features we need.
Remember to always keep it simple (and stupid).

1.1.1 Historical facts


Fortran was one of the first high level languages developed for computers. It stands for Mathematical FORmula
TRAN slating System. Fortran was started by John Backus at IBM in 1954. The first release of the compiler
was in 1957. Since then, many versions have been released: Fortran 66 (1966), Fortran 77 (1977), Fortran 90
(1991), Fortran 95 (1997), Fortran 2003 (2004) and finally Fortran 2008 (2010).

1.1.2 General Principles


Coding should be less important than modeling. The sustainability of a code depends on how it is well designed.
Usually, it’s not straitforward to get a good model (and not the best, if it exists). It also takes a lot of time.
However, it’s not a waste of time. In fact, once the code begins to get mature, it’s much more easy to extend it.
However, you should follow some rules, such as using a Test Driven Development approach, to test every little
part of it, in order to prevent from a regression.

7
8 CHAPTER 1. GETTING STARTED WITH FORTRAN

1.2 Getting started


Let’s start with the most classical example. Open your favorite EditorA.2 and copy paste the following lines:

1 PROGRAM E X _ 1
2 IMPLICIT NONE
3 PRINT ∗ , ’ H e l l o From F o r t r a n ! ’
4 END PROGRAM E X _ 1

You can compile the last example using:

1 gfortran ex_1.F90 −o ex_1.exe

You can also use the CMake tool. All our examples make use of it. Now let’s create a procedure/subroutine
that prints the previous message.

1 PROGRAM EX_2
2 IMPLICIT NONE
3 CALL MY_PRINT ( )
4 CONTAINS
5 SUBROUTINE MY_PRINT ( )
6 IMPLICIT NONE
7 PRINT ∗ , ’ H e l l o From F o r t r a n P r o c e d u r e ! ’
8 END SUBROUTINE MY_PRINT
9 END PROGRAM EX_2

Now let’s print some basic declarations. For the moment, we will only cover integers, reals, booleans, con-
stants and arrays.

1 PROGRAM EX_3
2 IMPLICIT NONE
3 CALL MY_PRINT_1 ( )
4 CALL MY_PRINT_2 ( )
5 CONTAINS
6 ! ...................................................
7 SUBROUTINE MY_PRINT_1 ( )
8 IMPLICIT NONE
9 INTEGER : : i
10 INTEGER , PARAMETER : : J = 1
11 REAL ( KIND=8) : : x
12 REAL ( KIND=4) : : y
13
14 PRINT ∗ , ”>>> E n t e r MY PRINT 1”
15
16 i = J + 1
17 x = 2.0 ∗ i
18 y = 2.0 ∗ i
19
20 PRINT ∗, ”J : ”, J
21 PRINT ∗, ”I : ”, i
22 PRINT ∗, ”X : ”, x
23 PRINT ∗, ”Y : ”, y
24
25 PRINT ∗ , ”<<< L e a v e MY PRINT 1”
26
27 END SUBROUTINE MY_PRINT_1
28 ! ...................................................
29
30 ! ...................................................
31 SUBROUTINE MY_PRINT_2 ( )
32 IMPLICIT NONE
33 INTEGER , PARAMETER : : N = 5
34 INTEGER : : i
35 INTEGER , DIMENSION ( 5 ) : : arr_i
36 REAL ( KIND=8) , DIMENSION ( N ) : : arr_x
37 REAL ( KIND=8) , DIMENSION ( N ) : : arr_y
38
39 PRINT ∗ , ”>>> E n t e r MY PRINT 2”
40
41 arr_i = 1
42
43 DO i = 1 , N
1.2. GETTING STARTED 9

44 arr_x ( i ) = i ∗ 1 . 0 d0 / N
45 arr_y ( i ) = i ∗ 1 . 0 / N
46 END DO
47
48 PRINT ∗ , ” ARR I : ” , arr_i
49 PRINT ∗ , ”ARR X : ” , arr_x
50 PRINT ∗ , ”ARR Y : ” , arr_y
51
52 PRINT ∗ , ”<<< L e a v e MY PRINT 2”
53
54 END SUBROUTINE MY_PRINT_2
55 ! ...................................................
56
57 END PROGRAM EX_3

Now, let’s consider the classical case when we want to model an unknown (temperature, pressure, . . . ). Usually,
for instance if we use a Galerkin-Ritz method, our unknown will live in a vectorial space and then, knowning
the basis, one only needs to have the expansion coefficients over it. For this purpose, we introduce the concept
of MODULE which plays the role of the C++ namespace. We introduce also how to construct a data structure
using the keyword TYPE. The following example describes a first attempt to model an unknown. We call it a
field and it relies on the use of the implicit constructor of Fortran.

1 ! ...................................................
2 MODULE MODULE_FIELD
3 IMPLICIT NONE
4 PRIVATE
5 PUBLIC : : FIELD , FIELD_DIMENSION , FIELD_PRINT
6
7 TYPE FIELD
8 INTEGER : : n_dim
9 INTEGER : : n_size
10 END TYPE FIELD
11
12 CONTAINS
13 ! ...................................................
14 FUNCTION F IE LD _D I ME NS IO N ( self ) RESULT( val )
15 IMPLICIT NONE
16 TYPE( FIELD ) , INTENT ( IN ) : : self
17 INTEGER : : val
18
19 val = self % n_dim
20 END FUNCTION F IE LD _ DI ME NS I ON
21 ! ...................................................
22
23 ! ...................................................
24 FUNCTION FIELD_SIZE ( self ) RESULT( val )
25 IMPLICIT NONE
26 TYPE( FIELD ) , INTENT ( IN ) : : self
27 INTEGER : : val
28
29 val = self % n_size
30 END FUNCTION FIELD_SIZE
31 ! ...................................................
32
33 ! ...................................................
34 SUBROUTINE FIELD_PRINT ( self )
35 IMPLICIT NONE
36 TYPE( FIELD ) , INTENT ( IN ) : : self
37
38 PRINT ∗ , ’ F i e l d : dim ’ , self % n_dim
39 PRINT ∗ , ’ size ’ , self % n_size
40 END SUBROUTINE FIELD_PRINT
41 ! ......................... ..........................
42 END MODULE MODULE_FIELD
43 ! ............................ .......................
44
45 ! ...................................................
46 PROGRAM EX_4
47 USE MODULE_FIELD
48 IMPLICIT NONE
49 TYPE( FIELD ) : : U
50
51 U = FIELD ( 1 , 1 0 ) ! Use t h e i m p l i c i t c o n s t r u c t o r
52 CALL FIELD_PRINT ( U ) ! Call a class subroutine
53
54 END PROGRAM EX_4
55 ! ...................................................
10 CHAPTER 1. GETTING STARTED WITH FORTRAN

Remark 1.2.1 Later, we will see how to add the allocation of the coefficients array directly through the implicit
constructor.

1.3 Basic Statements


Through this section, we will present some basic statements through modeling a matrix and the matrix-vector
product operation, in the context of Finite Differences.

1.3.1 DO, WHILE statements


Let consider a matrix M ∈ Mm,n (R) and vector x ∈ Rm . The following code implements the matrix-vector
product:

1 ! .............................. .....................
2 PROGRAM EX_5
3 IMPLICIT NONE
4 INTEGER , PARAMETER : : M = 5
5 INTEGER , PARAMETER : : N = 5
6 REAL( KIND=8) , DIMENSION ( M , N ) : : Mat
7 REAL( KIND=8) , DIMENSION ( N ) :: x
8 REAL( KIND=8) , DIMENSION ( M ) :: y
9 INTEGER : : i
10 INTEGER : : j
11
12 ! ...
13 Mat = 0 . 0
14 DO j = 1 , N
15 DO i = 1 , M
16 Mat ( i , j ) = ( i+j ) ∗ 1 . 0
17 END DO
18 END DO
19 ! ...
20
21 ! ...
22 x = 1.0
23 ! ...
24
25 ! ...
26 CALL M A T R I X _ P R O D U C T _ V E C T O R _ D E N S E ( Mat , x , y )
27 ! ...
28
29 PRINT ∗ , ” y = M x : ” , y
30
31 CONTAINS
32 ! ...................................................
33 SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ D E N S E ( A , x , y )
34 IMPLICIT NONE
35 REAL ( KIND=8) , DIMENSION ( : , : ) , INTENT ( IN ) : : A
36 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: x
37 REAL ( KIND=8) , DIMENSION ( : ) , INTENT (INOUT) :: y
38 ! LOCAL
39 INTEGER : : M
40 INTEGER : : N
41 INTEGER : : i
42 INTEGER : : j
43
44 M = SIZE ( A , 1 )
45 N = SIZE ( A , 2 )
46
47 ! ...
48 y = 0.0
49 DO i = 1 , M
50 DO j = 1 , N
51 y(i) = y(i) + A(i , j) ∗ x(j)
52 END DO
53 END DO
54 ! ...
55
56 END SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ D E N S E
57 ! ...................................................
58 END PROGRAM EX_5
59 ! ...................................................
1.3. BASIC STATEMENTS 11

Let us now consider the case of a sparse matrix in CSR format. The following code describes the matrix-vector
product:

1 ! ................................. ..................
2 PROGRAM EX_6
3 IMPLICIT NONE
4 INTEGER , PARAMETER :: N = 4
5 INTEGER , PARAMETER :: NNZ = 9
6 REAL( KIND=8) , DIMENSION ( N ) :: x
7 REAL( KIND=8) , DIMENSION ( N ) :: y
8 REAL( KIND=8) , DIMENSION ( NNZ ) :: A
9 INTEGER ( KIND=8) , DIMENSION ( NNZ ) :: JA
10 INTEGER ( KIND=4) , DIMENSION ( N+1) :: IA
11
12 ! ...
13 JA ( 1 ) = 1 ; A (1) = 1.0
14 JA ( 2 ) = 3 ; A (2) = 2.0
15 JA ( 3 ) = 4 ; A (3) = 3.0
16 JA ( 4 ) = 2 ; A (4) = 4.0
17 JA ( 5 ) = 2 ; A (5) = 5.0
18 JA ( 6 ) = 3 ; A (6) = 6.0
19 JA ( 7 ) = 2 ; A (7) = 7.0
20 JA ( 8 ) = 3 ; A (8) = 8.0
21 JA ( 9 ) = 4 ; A (9) = 9.0
22 ! ...
23
24 ! ...
25 IA ( 1 ) = 1
26 IA ( 2 ) = 4
27 IA ( 3 ) = 5
28 IA ( 4 ) = 7
29 IA ( 5 ) = 10
30 ! ...
31
32 ! ...
33 x = 1.0
34 ! ...
35
36 ! ...
37 CALL M A T R I X _ P R O D U C T _ V E C T O R _ C S R ( IA , JA , A , x , y )
38 ! ...
39
40 PRINT ∗ , ” y = M x : ” , y
41
42 CONTAINS
43 ! ........................................... ........
44 SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ C S R ( IA , JA , A , x , y)
45 IMPLICIT NONE
46 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: A
47 INTEGER ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) : : JA
48 INTEGER ( KIND=4) , DIMENSION ( : ) , INTENT ( IN ) : : IA
49 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: x
50 REAL ( KIND=8) , DIMENSION ( : ) , INTENT (INOUT) :: y
51 ! LOCAL
52 INTEGER : : N
53 INTEGER : : i
54 INTEGER : : k_max
55 INTEGER : : k_min
56
57 N = SIZE ( IA , 1 ) − 1
58
59 ! ...
60 y = 0.0
61 DO i = 1 , N
62 k_min = IA ( i )
63 k_max = IA ( i+1) − 1
64 PRINT ∗ , i , k_min , k_max
65 y ( i ) = DOT_PRODUCT ( A ( k_min : k_max ) , X ( JA ( k_min : k_max ) ) )
66 END DO
67 ! ...
68 END SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ C S R
69 ! ...................................................
70
71 END PROGRAM EX_6
72 ! ...................................................

more details can be found in [11].


12 CHAPTER 1. GETTING STARTED WITH FORTRAN

1.3.2 IF statements
We now implement the matrix that discretizes the Poisson problem in 1D using finite differences with homoge-
neous Dirichlet boundary conditions:

1 ! ...................................................
2 PROGRAM EX_7
3 IMPLICIT NONE
4 ! Example t h a t g e n e r a t e A L a p l a c i a n w i t h D i r i c h l e t BC and FD
5 !
6 ! The l a p l a c i a n l o o k s l i k e :
7 ! > 2 −1 ... 0
8 ! > −1 2 −1 0 ... 0
9 ! > 0 −1 2 −1 0 . . . 0
10 ! 1/ dx ˆ2 > ....
11 ! > ....
12 ! > 0 ... −1 2 −1
13 ! > 0 ... −1 2
14 !
15 INTEGER , PARAMETER : : N = 5
16 REAL( KIND=8) , DIMENSION ( N , N ) : : Mat
17 INTEGER : : i
18 REAL( KIND=8) : : dx
19
20 ! ...
21 dx = 1 . / N
22 ! ...
23
24 ! ...
25 Mat = 0 . 0
26 DO i = 1 , N
27 I F ( i == 1 ) THEN
28 Mat ( i , i ) = 2 . 0
29 Mat ( i , i+1) = −1.0
30 ELSEIF ( i == N ) THEN
31 Mat ( i , i−1) = −1.0
32 Mat ( i , i ) = 2 . 0
33 ELSE
34 Mat ( i , i−1) = −1.0
35 Mat ( i , i ) = 2 . 0
36 Mat ( i , i+1) = −1.0
37 END I F
38 END DO
39 Mat = ( 1 . / dx ∗ ∗2 ) ∗ Mat
40 ! ...
41
42 END PROGRAM EX_7
43 ! ...................................................

1.3.3 SELECT statements


Now, let’s go back to our matrix-vector product. We have implemented two subroutines:
MATRIX PRODUCT VECTOR DENSE and MATRIX PRODUCT VECTOR CSR for a dense and CSR matrix. A first at-
tempt to model a matrix will be to consider a data-structure that contains all data needed for a dense/CSR
matrix. The following code describes this data-structure and makes use of the SELECT keyword to take the right
matrix-vector product implementation depending on the matrix type.

1 ! ...................................................
2 MODULE M A T R I X _ U T I L I T I E S
3 IMPLICIT NONE
4 PRIVATE
5 PUBLIC : : MATRIX , &
6 & MATRIX_CREATE_DENSE , MATRIX_CREATE_CSR , &
7 & MATRIX_FREE_DENSE , MATRIX_FREE_CSR , &
8 & MATRIX_PRODUCT_VECTOR
9
10 TYPE MATRIX
11 INTEGER : : matrix_type
12 INTEGER : : N
13 INTEGER : : NNZ
14 REAL ( KIND=8) , DIMENSION ( : , : ) , ALLOCATABLE : : dense_A
15 REAL ( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : csr_A
16 INTEGER ( KIND=4) , DIMENSION ( : ) , ALLOCATABLE : : csr_IA
1.3. BASIC STATEMENTS 13

17 INTEGER ( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : csr_JA


18 END TYPE MATRIX
19
20 CONTAINS
21 ! ...................................................
22 SUBROUTINE M A T R I X _ C R E A T E _ D E N S E ( self , Mat )
23 IMPLICIT NONE
24 TYPE( MATRIX ) , INTENT (INOUT) : : self
25 REAL ( KIND=8) , DIMENSION ( : , : ) , INTENT ( IN ) : : Mat
26 ! LOCAL
27
28 I F ( SIZE ( Mat , 1 ) . NE . SIZE ( Mat , 2 ) ) THEN
29 STOP ’ Only s q u a r e m a t r i c e s can be u s e d ’
30 END I F
31
32 self % N = SIZE ( Mat , 1 )
33
34 ALLOCATE( self % dense_A ( self % N , self % N ) )
35
36 self % dense_A = Mat
37
38 self % matrix_type = 0
39
40 END SUBROUTINE M A T R I X _ C R E A T E _ D E N S E
41 ! ...................................................
42
43 ! ...................................................
44 SUBROUTINE M A T R I X _ F R E E _ D E N S E ( self )
45 IMPLICIT NONE
46 TYPE( MATRIX ) , INTENT (INOUT) : : self
47 ! LOCAL
48
49 DEALLOCATE( self % dense_A )
50
51 END SUBROUTINE M A T R I X _ F R E E _ D E N S E
52 ! ...................................................
53
54 ! ...................................................
55 SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ D E N S E ( A , x , y )
56 IMPLICIT NONE
57 REAL ( KIND=8) , DIMENSION ( : , : ) , INTENT ( IN ) : : A
58 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: x
59 REAL ( KIND=8) , DIMENSION ( : ) , INTENT (INOUT) :: y
60 ! LOCAL
61 INTEGER : : M
62 INTEGER : : N
63 INTEGER : : i
64 INTEGER : : j
65
66 M = SIZE ( A , 1 )
67 N = SIZE ( A , 2 )
68
69 ! ...
70 y = 0.0
71 DO i = 1 , M
72 DO j = 1 , N
73 y(i) = y(i) + A(i , j) ∗ x(j)
74 END DO
75 END DO
76 ! ...
77
78 END SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ D E N S E
79 ! ...................................................
80
81 ! ...................................................
82 SUBROUTINE M A T R I X _ C R E A T E _ C S R ( self , IA , JA , A )
83 IMPLICIT NONE
84 TYPE( MATRIX ) , INTENT (INOUT) : : self
85 INTEGER ( KIND=8) , DIMENSION ( : ) : : JA
86 INTEGER ( KIND=4) , DIMENSION ( : ) : : IA
87 REAL ( KIND=8) , DIMENSION ( : ) : : A
88 ! LOCAL
89
90 self % N = SIZE ( IA , 1 ) − 1
91 self % NNZ = SIZE ( JA , 1 )
92
93 ALLOCATE( self % csr_IA ( self % N + 1 ) )
94 ALLOCATE( self % csr_JA ( self % NNZ ) )
95 ALLOCATE( self % csr_A ( self % NNZ ) )
96
97 self % csr_IA = IA
98 self % csr_JA = JA
14 CHAPTER 1. GETTING STARTED WITH FORTRAN

99 self % csr_A = A
100
101 self % matrix_type = 1
102
103 END SUBROUTINE M A T R I X _ C R E A T E _ C S R
104 ! ...................................................
105
106 ! ...................................................
107 SUBROUTINE M AT RI X_ F RE E_ CS R ( self )
108 IMPLICIT NONE
109 TYPE( MATRIX ) , INTENT (INOUT) : : self
110 ! LOCAL
111
112 DEALLOCATE( self % csr_IA )
113 DEALLOCATE( self % csr_JA )
114 DEALLOCATE( self % csr_A )
115
116 END SUBROUTINE M AT RI X _F RE E_ C SR
117 ! ...................................................
118
119 ! ........................................... ........
120 SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ C S R ( IA , JA , A , x , y)
121 IMPLICIT NONE
122 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: A
123 INTEGER ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) : : JA
124 INTEGER ( KIND=4) , DIMENSION ( : ) , INTENT ( IN ) : : IA
125 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: x
126 REAL ( KIND=8) , DIMENSION ( : ) , INTENT (INOUT) :: y
127 ! LOCAL
128 INTEGER : : N
129 INTEGER : : i
130 INTEGER : : k_max
131 INTEGER : : k_min
132
133 N = SIZE ( IA , 1 ) − 1
134
135 ! ...
136 y = 0.0
137 DO i = 1 , N
138 k_min = IA ( i )
139 k_max = IA ( i+1) − 1
140 y ( i ) = DOT_PRODUCT ( A ( k_min : k_max ) , X ( JA ( k_min : k_max ) ) )
141 END DO
142 ! ...
143 END SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R _ C S R
144 ! ...................................................
145
146 ! ...................................................
147 SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R ( self , x , y )
148 IMPLICIT NONE
149 TYPE( MATRIX ) , INTENT ( IN ) : : self
150 REAL ( KIND=8) , DIMENSION ( : ) , INTENT ( IN ) :: x
151 REAL ( KIND=8) , DIMENSION ( : ) , INTENT (INOUT) :: y
152 ! LOCAL
153
154 SELECT CASE( self % matrix_type )
155 CASE ( 0 )
156 CALL M A T R I X _ P R O D U C T _ V E C T O R _ D E N S E ( self % dense_A , x , y )
157 CASE ( 1 )
158 CALL M A T R I X _ P R O D U C T _ V E C T O R _ C S R ( self % csr_IA , self % csr_JA , self % csr_A ←-
, x , y)
159 CASE DEFAULT
160 PRINT ∗ , ”MATRIX PRODUCT VECTOR : m a t r i x −t y p e n o t y e t i m p l e m e n t e d ”
161 END SELECT
162
163 END SUBROUTINE M A T R I X _ P R O D U C T _ V E C T O R
164 ! ...................................................
165
166 END MODULE M A T R I X _ U T I L I T I E S
167 ! ...................................................
168
169 ! ................................. ..................
170 PROGRAM EX_8
171 USE MATR I X _ U T I L I T I E S
172 IMPLICIT NONE
173 INTEGER , PARAMETER :: M = 5
174 INTEGER , PARAMETER :: N = 4
175 INTEGER , PARAMETER :: NNZ = 9
176 REAL( KIND=8) , DIMENSION ( NNZ ) :: A
177 INTEGER ( KIND=8) , DIMENSION ( NNZ ) :: JA
178 INTEGER ( KIND=4) , DIMENSION ( N+1) :: IA
179 REAL( KIND=8) , DIMENSION ( M , M ) :: Mat
1.3. BASIC STATEMENTS 15

180 REAL( KIND=8) , DIMENSION ( N ) :: x1


181 REAL( KIND=8) , DIMENSION ( N ) :: y1
182 REAL( KIND=8) , DIMENSION ( M ) :: x2
183 REAL( KIND=8) , DIMENSION ( M ) :: y2
184 INTEGER : : i
185 INTEGER : : j
186 TYPE( MATRIX ) : : csr
187 TYPE( MATRIX ) : : dense
188
189 ! ...
190 JA ( 1 ) = 1 ; A (1) = 1.0
191 JA ( 2 ) = 3 ; A (2) = 2.0
192 JA ( 3 ) = 4 ; A (3) = 3.0
193 JA ( 4 ) = 2 ; A (4) = 4.0
194 JA ( 5 ) = 2 ; A (5) = 5.0
195 JA ( 6 ) = 3 ; A (6) = 6.0
196 JA ( 7 ) = 2 ; A (7) = 7.0
197 JA ( 8 ) = 3 ; A (8) = 8.0
198 JA ( 9 ) = 4 ; A (9) = 9.0
199 ! ...
200
201 ! ...
202 IA ( 1 ) = 1
203 IA ( 2 ) = 4
204 IA ( 3 ) = 5
205 IA ( 4 ) = 7
206 IA ( 5 ) = 10
207 ! ...
208
209 ! ...
210 Mat = 0 . 0
211 DO j = 1 , N
212 DO i = 1 , M
213 Mat ( i , j ) = ( i+j ) ∗ 1 . 0
214 END DO
215 END DO
216 ! ...
217
218 ! ...
219 x1 = 1 . 0 ; x2 = 1 . 0
220 ! ...
221
222 ! ...
223 CALL M A T R I X _ C R E A T E _ C S R ( csr , IA , JA , A )
224 CALL M A T R I X _ P R O D U C T _ V E C T O R ( csr , x1 , y1 )
225 CALL M AT RI X_ F RE E_ C SR ( csr )
226 ! ...
227
228 ! ...
229 CALL M A T R I X _ C R E A T E _ D E N S E ( dense , Mat )
230 CALL M A T R I X _ P R O D U C T _ V E C T O R ( dense , x2 , y2 )
231 CALL M A T R I X _ F R E E _ D E N S E ( dense )
232 ! ...
233
234 PRINT ∗ , ” y2 = M2 x2 : ” , y2
235 PRINT ∗ , ” y1 = M1 x1 : ” , y1
236
237 END PROGRAM EX_8
238 ! ...................................................

1.3.4 Interface procedure

In order to enhance the readablity of our last code, we may want to have one single subroutine to create a
matrix object no matter what type it is. This can be done through the INTERFACE statement.

1 INTERFACE MATRIX_CREATE
2 MODULE PROCEDURE MATRIX_CREATE_DENSE , MATRIX_CREATE_CSR
3 END INTERFACE

Now depending on the actual arguments of your CALL, the compiler will pick the right subroutine.
16 CHAPTER 1. GETTING STARTED WITH FORTRAN

1.4 Pointers and Targets


Unlike the C language for which a pointer contains the object address, in Fortran a pointer is more an alias,
usually called reference, It is somehow a high level abstraction of the classical reference in the C language. A
Fortran pointer has one of the following states:

• Undefined

• Null

• Associated

1 REAL , POINTER : : p1
2 INTEGER , DIMENSION ( : ) , POINTER : : p2
3

4 TYPE box
5 INTEGER i_1
6 INTEGER i_2
7 END TYPE
8 TYPE ( box ) , POINTER : : p3

When a pointer is associated, it should give the reference of a Target. This leads to the following rules:

1 REAL , POINTER : : p1
2 REAL , POINTER : : p2
3 REAL , TARGET : : x
4

5 x = 2.0
6

7 p1 => x ! OK
8 p2 => p1 ! OK
9 ! x = p1 ! KO
10 x = 1.0
11

12 PRINT ∗ , p2

A pointer can be the reference or alias of more complex objects.

1 REAL , DIMENSION ( 1 0 , 2 0 ) , TARGET : : a


2 REAL , DIMENSION ( : ) , POINTER : : p
3 integer :: i
4

5 a = RESHAPE ( source =(/ ( i , i =1 , 2 0 0 ) / ) , shape =shape ( a ) )


6

7 READ ( ∗ , ∗ ) i
8 p = > a (i , 1:10:3)
9 ! p p o i n t s now t o a (1) , a (4) , a (7) , a (10)
10 PRINT ∗ , p (3)

♣ A pointer can also be allocated. A disctinction between non-allocated and allocated pointers should be
done, using for example the prefix ptr
.
1.5. INPUT/OUTPUT 17

1.5 Input/Output
1.6 Tips
Let’s go back to our dense matrix. The following example shows that you must pay attention to the order of
loops. Indeed, there is an overhead when setting nested loops. The loop range must be increasing from top to
down.

1 SUBROUTINE D O _ F A S T ( x , n , m )
2 IMPLICIT NONE
3 INTEGER, DIMENSION( n , m ) , INTENT(INOUT) :: x
4 INTEGER, INTENT( IN ) :: n
5 INTEGER, INTENT( IN ) :: m
6 ! LOCAL
7 INTEGER : : i , j
8
9 x = 0
10 DO j =1 , m
11 DO i =1 , n
12 x ( i , j ) = i+j
13 END DO
14 END DO
15
16 END SUBROUTINE D O _ F A S T
17
18 SUBROUTINE D O _ S L O W ( x , n , m )
19 IMPLICIT NONE
20 INTEGER, DIMENSION( n , m ) , INTENT(INOUT) :: x
21 INTEGER, INTENT( IN ) :: n
22 INTEGER, INTENT( IN ) :: m
23 ! LOCAL
24 INTEGER : : i , j
25
26 x = 0
27 DO i =1 , n
28 DO j =1 , m
29 x ( i , j ) = i+j
30 END DO
31 END DO
32
33 END SUBROUTINE D O _ S L O W
34
35 PROGRAM E X A M P L E
36 IMPLICIT NONE
37 INTEGER, PARAMETER : : n _ l o o p s = 10
38 INTEGER : : n
39 INTEGER : : m
40 INTEGER : : i
41 INTEGER, DIMENSION ( : , : ) , ALLOCATABLE : : x
42 REAL : : start , finish
43
44 n = 100000 ; m = 1000
45 ALLOCATE( x ( n , m ) )
46
47 CALL C P U _ T I M E ( s t a r t )
48 DO i =1 , n _ l o o p s
49 CALL D O _ F A S T ( x , n , m )
50 END DO
51 CALL C P U _ T I M E ( f i n i s h )
52 p r i n t ∗ , ”> Done w i t h f a s t . ”
53 p r i n t ’ ( ” Time = ” , f 6 . 3 , ” s e c o n d s . ” ) ’ , ( f i n i s h −s t a r t ) / n _ l o o p s
54
55 CALL C P U _ T I M E ( s t a r t )
56 DO i =1 , n _ l o o p s
57 CALL D O _ s l o w ( x , n , m )
58 END DO
59 CALL C P U _ T I M E ( f i n i s h )
60 p r i n t ∗ , ”> Done w i t h s l o w . ”
61 p r i n t ’ ( ” Time = ” , f 6 . 3 , ” s e c o n d s . ” ) ’ , ( f i n i s h −s t a r t ) / n _ l o o p s
62
63 END PROGRAM E X A M P L E

In this example, we clearly see the impact of the overhead when n > m:

1 ahmed $ gfortran ex_9.F90


18 CHAPTER 1. GETTING STARTED WITH FORTRAN

2 ahmed $ ./a.out
3 > Done with fast.
4 Time = 0.366 seconds.
5 > Done with slow.
6 Time = 0.794 seconds.

Let us now change the compilation options. First we use the option -O1

1 ahmed $ gfortran −O1 ex_9.F90


2 ahmed $ ./a.out
3 > Done with fast.
4 Time = 0.184 seconds.
5 > Done with slow.
6 Time = 0.434 seconds.

Using the option -O2

1 ahmed $ gfortran −O2 ex_9.F90


2 ahmed $ ./a.out
3 > Done with fast.
4 Time = 0.174 seconds.
5 > Done with slow.
6 Time = 0.430 seconds.

Using the option -O3

1 ahmed $ gfortran −O3 ex_9.F90


2 ahmed $ ./a.out
3 > Done with fast.
4 Time = 0.174 seconds.
5 > Done with slow.
6 Time = 0.251 seconds.

Nowdays compilers are smart enough to optimize our loops but not enough to get the best performance.
♣ Always pay attention to the range of nested loops
Chapter 2

Modern Fortran: Object-Oriented


Programming

2.1 Introduction
We will introduce the basic concepts of OOP through our matrix example. As we can notice in the last code
(see subsection 1.3.3), we have now two kinds of matrices: dense and CSR. Before going further, let’s start by
cleaning our code a little. We split the data-structure into two types: DENSE and CSR. This leads to the following
definitions:

1 TYPE MATRIX_DENSE
2 INTEGER : : N
3 REAL( KIND=8) , DIMENSION ( : , : ) , ALLOCATABLE : : A
4 END TYPE MATRIX_DENSE
5

6 TYPE MATRIX_CSR
7 INTEGER : : N
8 INTEGER : : NNZ
9 REAL( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : A
10 INTEGER ( KIND=4) , DIMENSION ( : ) , ALLOCATABLE : : IA
11 INTEGER ( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : JA
12 END TYPE MATRIX_CSR

The OOP paradigm relies on 3 (among others) fundamental ideas:


• Encapsulation
• Inheritance
• Polymorphism
These notions need the concept of an object or class rather than a structure/derived-type.

What is an object?
When you don’t want the external user to access or modify directly some private data in your structure then
using a data-structure is meaningless and it’s not the right way to implement your idea. Objects should hide
their data behind some abstractions and only expose functions or subroutines that operate on that data. This
is a part of what is called Programming by contract.

2.2 Type extensions and parameters


The first thing would be to create a MATRIX object and then make the dense and CSR matrices inherit from it:

19
20 CHAPTER 2. MODERN FORTRAN: OBJECT-ORIENTED PROGRAMMING

1 TYPE MATRIX
2 INTEGER : : N
3 END TYPE MATRIX
4

5 TYPE, EXTENDS( MATRIX ) : : MATRIX_DENSE


6 REAL( KIND=8) , DIMENSION ( : , : ) , ALLOCATABLE : : coefficients
7 END TYPE MATRIX_DENSE
8

9 TYPE, EXTENDS( MATRIX ) : : MATRIX_CSR


10 INTEGER : : NNZ
11 INTEGER ( KIND=4) , DIMENSION ( : ) , ALLOCATABLE : : IA
12 INTEGER ( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : JA
13 REAL( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : A
14 END TYPE MATRIX_CSR

Now, automatically, the objects MATRIX DENSE and MATRIX CSR will inherit the type parameter N which repre-
sents the number of rows and columns (we only consider square matrices).

Type parameters

2.3 Polymorphism
The idea behind the entension of the matrix type, is to collect objects that share some specific behavior for
example. In the case of a matrix, what we usually want to do is: matrix-vector product, solve a linear system,
compute some norms, . . . . Through polymorphism the data type of your variable may vary at run time. A
typical use would be the following:

1 TYPE( MATRIX_DENSE ) , TARGET : : dense


2 TYPE( MATRIX_CSR ) , TARGET : : csr
3 CLASS ( MATRIX ) , POINTER : : ptr_matrix
4

5 ! . . . t a k e t h e d e n s e m a t r i x and do some s t u f f
6 ptr_matrix => dense
7 ! ...
8

9 ! . . . c o n v e r s i o n t o c s r f o r m a t and t h e n do what you want


10 ptr_matrix => csr
11 ! ...

Remark 2.3.1 Two very important remarks:

• The use of the TARGET attribut for both DENSE and CSR variables,

• The variables DENSE and CSR are declared with the keyword TYPE while the matrix pointer, the polymorphic
variable, is defined with the keyword CLASS.

♣ Don’t put a CLASS object inside your data-structure.

Unlimited polymorphism

2.4 The ASSOCIATE constructor


To enhance the readablity of Fortran codes, we can use the ASSOCIATE construct that allows us to associate a
name with a variable or the value of an expression within the scope of the considered block.
2.5. THE SELECT TYPE COMMAND 21

♣ Be careful, blocks should be small, otherwise it will be painful to navigate through the file, specially if
there many ASSOCIATE blocks
.

2.5 The SELECT TYPE command


In order to make our code much more clear, we would like to have a single function/subroutine when the action
of the matrix object are the same, no matter if it is dense or csr. For this reason, we will use polymorphic
variables and in addition we will need to select the type dynamically. This can be done using the keyword
SELECT TYPE:

1 SUBROUTINE MATRIX_FREE ( self )


2 IMPLICIT NONE
3 CLASS ( MATRIX ) , INTENT(INOUT) : : self
4 ! LOCAL
5

6 SELECT TYPE ( self )


7 CLASS IS ( MATRIX_DENSE )
8 CALL MATRIX_FREE_DENSE ( self )
9 CLASS IS ( MATRIX_CSR )
10 CALL MATRIX_FREE_CSR ( self )
11 CLASS DEFAULT
12 STOP ’ MATRIX FREE : u n e x p e c t e d t y p e f o r s e l f o b j e c t ! ’
13 END SELECT
14

15 END SUBROUTINE MATRIX_FREE

The same strategy can be applied for the MATRIX PRODUCT VECTOR subroutine.
♣ This is straitforward when the involved subroutines/functions have the same signature. This is not the
case in general, and sometime, you may need to use opional arguments.

2.6 Type-Bound Procedures


Our code will be better, if we can associate a given procedure like CREATE, FREE or DOT for the matric-vector
product. In Fortran 2003 this is possible using the Type bounding procedures. It is obvious that the following
code is much more clear, also through the definition of our object, we can see what are its properties. It is
normal to ask a matrix object to provide subroutines to create, free and apply a matrix-vector product. This is
again a way of expressing the contract between the developper and the user.

1 TYPE MATRIX
2 INTEGER : : N
3 END TYPE MATRIX
4

5 TYPE, EXTENDS( MATRIX ) : : MATRIX_DENSE


6 REAL( KIND=8) , DIMENSION ( : , : ) , ALLOCATABLE : : coefficients
7 CONTAINS
8 PROCEDURE : : CREATE => MATRIX_CREATE_DENSE
9 PROCEDURE : : FREE => MATRIX_FREE_DENSE
10 PROCEDURE : : DOT => MATRIX_PRODUCT_VECTOR_DENSE
11 END TYPE MATRIX_DENSE
12

13 TYPE, EXTENDS( MATRIX ) : : MATRIX_CSR


14 INTEGER : : NNZ
15 INTEGER ( KIND=4) , DIMENSION ( : ) , ALLOCATABLE : : IA
22 CHAPTER 2. MODERN FORTRAN: OBJECT-ORIENTED PROGRAMMING

16 INTEGER ( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : JA


17 REAL( KIND=8) , DIMENSION ( : ) , ALLOCATABLE : : A
18 CONTAINS
19 PROCEDURE : : CREATE => MATRIX_CREATE_CSR
20 PROCEDURE : : FREE => MATRIX_FREE_CSR
21 PROCEDURE : : DOT => MATRIX_PRODUCT_VECTOR_CSR
22 END TYPE MATRIX_CSR

♣ Do not use the PASS statement. The resulting code is less clear.

2.6.1 Prototype approach: using subroutine/functions pointers


2.6.2 Contract approach: ABSTRACT types
Now that we decided that any matrix object must provide the subroutines to create, free and apply a matrix-
vector product, we can enforce it inside the definition of the parent object MATRIX. To do so, we need to add
the ABSTRACT argument in its definition. The following code implements these ideas. However, we still can not
add the CREATE subroutine into the ABSTRACT type.

1 TYPE, ABSTRACT : : MATRIX


2 INTEGER : : N
3 CONTAINS
4 PROCEDURE ( MATRIX_FREE ) , DEFERRED : : FREE
5 PROCEDURE ( MATRIX_PRODUCT_VECTOR ) , DEFERRED : : DOT
6 END TYPE MATRIX
7

8 ABSTRACT INTERFACE
9 SUBROUTINE MATRIX_FREE ( self )
10 IMPORT MATRIX
11 IMPLICIT NONE
12 CLASS ( MATRIX ) , INTENT(INOUT) : : self
13 END SUBROUTINE MATRIX_FREE
14 END INTERFACE
15

16 ABSTRACT INTERFACE
17 SUBROUTINE MATRIX_PRODUCT_VECTOR ( self , x , y )
18 IMPORT MATRIX
19 IMPLICIT NONE
20 CLASS ( MATRIX ) , INTENT( IN ) : : self
21 REAL( KIND=8) , DIMENSION ( : ) , INTENT( IN ) :: x
22 REAL( KIND=8) , DIMENSION ( : ) , INTENT(INOUT) :: y
23 END SUBROUTINE MATRIX_PRODUCT_VECTOR
24 END INTERFACE

♣ An ABSTRACT type is a derived type that cannot be instantiated.

2.7 Operators
The aim of this section is to make our code more clear through the definition of some basic operators: +, −, ∗, ==
, ! = and ask our objects to provide these operations. Before doing so, we need to ask ourselves some questions:

1. what do we mean by the matrix A is equal to the matrix B?


2.7. OPERATORS 23

2. although we understand what to do when adding two csr/dense matrices, can we add a csr matrix to a
dense matrix? what about the opposite?
24 CHAPTER 2. MODERN FORTRAN: OBJECT-ORIENTED PROGRAMMING
Chapter 3

Project: A Finite Element Library

3.1 Introduction
3.1.1 The 1D case: code description
We decribe here the initial Fortran code for our project. This code solves the 1D Poisson equation. It has two
files fem1d lagrange.F90 and main.F90. The first file contains the following routines:

FEM1D LAGRANGE STIFFNESS This subroutine assembles the stiffness and mass matrices and the load

LAGRANGE DERIVATIVE evaluates the Lagrange basis derivative.

LAGRANGE VALUE evaluates the Lagrange basis polynomials.

LAGRANGE SET sets abscissas and weights for Gauss-Legendre quadrature.

R8MAT FS factors and solves a system with one right hand side.

R8VEC LINSPACE creates a vector of linearly spaced values.

R8VEC PRINT prints an R8VEC.

while the second file contains the following ones:

MAIN the main program

LEGENDRE SET TEST tests LEGENDRE SET.

LAGRANGE VALUE TEST tests LAGRANGE VALUE.

LAGRANGE DERIVATIVE TEST tests LAGRANGE DERIVATIVE.

FEM1D LGRANGE STIFFNESS TEST tests FEM1D LAGRANGE STIFFNESS.

F the right hand side function.

EXACT the exact solution.

The original code can be found here.

25
26 CHAPTER 3. PROJECT: A FINITE ELEMENT LIBRARY

Compilation and execution


In order to compile these files, you need a Fortran compiler (gfortran, ifort, . . . ). If you are using gfortran, then
you can run the following commands:

1 gfortran −c fem1d_lagrange.F90
2 gfortran main.F90 fem1d_lagrange.o −o fem.exe

Execution can be done by

1 ./fem.exe

3.2 Code Design


Rather than presenting the specification of our final code, we will present and introduce them one by one, and
continuously change, update and redisgn our code. We want the reader to face a typical situation that we
encontour: we only keep writing and rewriting our codes!

3.2.1 First Specification


3.2.2 Second specification
3.2.3 Third specification

3.3 A case study: A Finite Element Method Project


Through this lecture, we will present the basic concepts from Object-Oriented Programming and apply them
to the implementation of a Finite Element Method Library. We decided to only consider the case of B-Splines
basis functions as they allow us to create different spaces with a minimal cost. The code can be extended easily
to treate other kind of basis functions.
The first notion we need is the Discrete Vectorial Functions Space. It is an abstrat notion that we
will extend later in the case of the well known spaces H 1 , H(div ), H(rot ), L2 .

1 TYPE DEF_ABSTRACT_SPACE
2 INTEGER : : oi_dim
3 END TYPE DEF_ABSTRACT_SPACE

A function that lives in the discrete space will be called a field. We can therefor define an abstract field as
well as specific fields depending on the spaces H 1 , H(div ), H(rot ), L2 .

1 TYPE DEF_ABSTRACT_FIELD
2 INTEGER : : oi_dim
3 END TYPE DEF_ABSTRACT_FIELD
Appendix A

Developper tools

A.1 Installation and Compilation


A.2 Editors
A.3 Versioning: svn & git
A.4 CMake
A.5 Unit-tests
A.6 Calling Fortran codes from Python: f2py
A.7 Documentation

27
28 APPENDIX A. DEVELOPPER TOOLS
Appendix B

Numerical Integration

B.1 Quadrature formulae


For more details, we refer the reader to the book [9]. In figure (Fig. B.1), we show the quadrature points
formulae for a mesh {x0 = 0, x1 = 14 , x2 = 12 , x3 = 43 , x4 = 1} for a quadratic polynomial degree.

1 1 3
Figure B.1: The quadrature points formulae for a mesh {x0 = 0, x1 = 4
, x2 = 2
, x3 = 4
, x4 = 1} for a quadratic polynomial
degree.

29
30 APPENDIX B. NUMERICAL INTEGRATION
Appendix C

Applied Linear Algebra

C.1 Kronecker algebra


In this section, we present an overview about an interesting subject, which is the Kronecker Algebra, and which
will be of a big interest in the Fast-IGA approach. Most of the presented results were taken from [4, 10].

Definition C.1.1 (The vec operator) Let A = (aij ) ∈ Mn×m , the vec operator is defined as,
 
A:,1
vecA =  ...  ∈ Rmn (C.1.1)
 

A:,m

which is simply a vector composed by stacking all the columns of A. Where we denote A:,j the j th column of A.
We also define the inverse operator of vec by,

A = vec−1 vecA (C.1.2)

Definition C.1.2 (Kronecker product) Let A = (aij ) ∈ Mm×n and B = (bij ) ∈ Mr×s be two matrices.
The Kronecker product of A and B, denoted by A ⊗ B ∈ Mmr×ns , defines the following matrix:
 
a11 B a12 B ··· a1n B
 a21 B a22 B ··· a2n B 
A⊗B = (C.1.3)
 
.. .. .. 
 . . . 
am1 B am2 B ··· amn B

Example

Let
   
a11 a12 b11 b12
A= , B=
a21 a22 b21 b22

then their Kronecker product is,


 
a11 b11 a11 b12 a12 b11 a12 b12
 a11 b21 a11 b22 a12 b21 a12 b22 
A⊗B =
 a21 b11
 (C.1.4)
a21 b12 a22 b11 a22 b12 
a21 b21 a21 b22 a22 b21 a22 b22

31
32 APPENDIX C. APPLIED LINEAR ALGEBRA

Properties
Proposition C.1.3 If α is a scalar, then
A ⊗ αB = αA ⊗ B (C.1.5)
Proposition C.1.4 We have,
(A + B) ⊗ C = A ⊗ C + B ⊗ C (C.1.6)
A ⊗ (B + C) = A ⊗ B + A ⊗ C (C.1.7)
Proposition C.1.5 (Associativity)
A ⊗ B ⊗ C = A ⊗ (B ⊗ C) = (A ⊗ B) ⊗ C (C.1.8)
Proposition C.1.6 (Mixed Product Rule)
(A ⊗ B)(C ⊗ D) = AC ⊗ BD (C.1.9)
and,
(A ⊗ B)p = Ap ⊗ B p , ∀p ∈ N (C.1.10)
Proposition C.1.7
(A ⊗ B)T = AT ⊗ B T (C.1.11)
Proposition C.1.8
(A ⊗ B)−1 = A−1 ⊗ B −1 (C.1.12)
Proposition C.1.9
vec(ABC) = (C T ⊗ A)vec(B) (C.1.13)
Proposition C.1.10
tr(A ⊗ B) = tr(B ⊗ A) = tr(A)tr(B) (C.1.14)
Proposition C.1.11 Let A ∈ Mn×n and B ∈ Mm×m , we have,
mspec(A ⊗ B) = {λµ, λ ∈ mspec(A), µ ∈ mspec(B)} (C.1.15)
Proposition C.1.12 Let A ∈ Mn×n and B ∈ Mm×m , we have,
det(A ⊗ B) = (detA)m (detB)n (C.1.16)
We deduce from C.1.15,
Proposition C.1.13 Let A ∈ Mn×n , we have,
ρ(A ⊗ A) = ρ(A)2 (C.1.17)
Proposition C.1.14 Let f be an analytic function, A ∈ Mn×n such that f (A) exists, then we have,
f (Im ⊗ A) = Im ⊗ f (A) (C.1.18)
f (A ⊗ Im ) = f (A) ⊗ Im (C.1.19)
Proposition C.1.15 Let X ∈ Rn and Y ∈ Rm , be two vectors. We have,
XY T = X ⊗ (Y T ) = (Y T ) ⊗ X (C.1.20)
moreover, we have,
vec(XY T ) = Y ⊗ X (C.1.21)
C.1. KRONECKER ALGEBRA 33

Definition C.1.16 (Kronecker permutation matrix) The Kronecker permutation matrix Pn,m ∈
Mnm×nm , is defined by,
n,m
X
Pn,m = Ei,j,n×m ⊗ Ej,i,m×n (C.1.22)
i,j=1

Proposition C.1.17 Let A ∈ Mm×n , we have,

vec(AT ) = Pm,n vec(A) (C.1.23)

Proposition C.1.18 Let us consider the Kronecker permutation matrix Pn,m ∈ Mnm×nm . Then we have,

• Pn,m
T −1
= Pn,m = Pm,n

• Pn,m is orthogonal,

• Pn,m Pm,n = Inm

• Pn,n is orthogonal, symmetric and involutory,

• Pn,n is a reflector,

• trPn,n = n,

• P1,m = Im , and Pn,1 = In

• if X ∈ Rn and Y ∈ Rm , then,

Pn,m (Y ⊗ X) = X ⊗ Y (C.1.24)

• if A ∈ Mn×m and B ∈ Mr×s , then

Pr,n (A ⊗ B)Pm,s = B ⊗ A (C.1.25)

• if A ∈ Mn×n and B ∈ Mm×m , then


−1
Pm,n (A ⊗ B)Pn,m = Pm,n (A ⊗ B)Pm,n =B⊗A (C.1.26)

Therefor, A ⊗ B and B ⊗ A are similar.

Proposition C.1.19 Let A ∈ Mn×n and B ∈ Mm×m , then we have the following properties,

• if A and B are diagonal, then A ⊗ B is diagonal,

• if A and B are upper triangular, then A ⊗ B is upper triangular,

• if A and B are lower triangular, then A ⊗ B is lower triangular,

Proposition C.1.20 Let A, C ∈ Mn×m and B, D ∈ Mr×s . If A is (left equivalent, right equivalent, equivalent)
to C, and assume that B is (left equivalent, right equivalent, equivalent) to D. Then, A ⊗ B is (left equivalent,
right equivalent, equivalent) to C ⊗ D.

Remark C.1.21 The use of Kronecker product preconditioners is well known [13, 8, 12, 5], it is based on
results of the form,

Minimizing, φA (B, C) = kA − B ⊗ Ck2 (C.1.27)

for a chosen norm.


34 APPENDIX C. APPLIED LINEAR ALGEBRA

C.1.1 Kronecker sum


Definition C.1.22 (Kronecker sum) Let A = (aij ) ∈ Mn×n and B = (bij ) ∈ Mm×m be two matrices. The
Kronecker sum of A and B, denoted by A ⊕ B ∈ Mmn×mn , defines the following matrix:
A ⊕ B = A ⊗ Im + In ⊗ B (C.1.28)
Proposition C.1.23 Let A ∈ Mn×n and B ∈ Mm×m , we have,
mspec(A ⊕ B) = {λ + µ, λ ∈ mspec(A), µ ∈ mspec(B)} (C.1.29)

C.1.2 Solving AX + XB = C
Let A ∈ Mn×n , B ∈ Mm×m and C ∈ Mn×m . The aim of this section, is to solve the equation:
AX + XB = C (C.1.30)
we can rewrite this equation in term of the Kronecker sum:
(B T ⊕ A)vecX = vecC (C.1.31)
or equivalently,
Gx = c (C.1.32)
where, G = (B T ⊕ A), x = vecX, and c = vecC.
Using the property C.1.29, we can easily check that C.1.30 has a unique solution if and only if G is nonsingular,
i.e λ + µ 6= 0, ∀λ ∈ mspec(A), ∀µ ∈ mspec(B), which can be written in the form,
mspec(A) ∩ mspec(−B) = ∅ (C.1.33)
Proposition C.1.24 If mspec(A)∩mspec(−B)
   ∅, then there
=  exists a unique matrix X ∈ Mn×m , satisfying
A C A 0
C.1.30. Moreover, the matrices and are similar and verify,
0 −B 0 −B
     
A C I X A 0 I −X
= . (C.1.34)
0 −B 0 I 0 −B 0 I

C.1.3 Solving AXB = C


Let A, B, C and X ∈ Mn×n . As seen previously, using C.1.13, the equation
AXB = C (C.1.35)
can be written in the form,
Hx = c (C.1.36)
where, H = (B T ⊗ A), x = vecX, and c = vecC.
Using the property C.1.15, we can easily check that C.1.35 has a unique solution if and only if H is nonsingular,
i.e λµ 6= 0, ∀λ ∈ mspec(A), ∀µ ∈ mspec(B), which is equivalent to, A and B are both nonsingular.
Pr
C.1.4 Solving i=1 Ai XBi = C
Let Ai , Bi , C, 1 ≤ i ≤ r and X ∈ Mn×n . Using, the previous result, it is easy to show that the solution of:
r
X
Ai XBi = C (C.1.37)
i=1

can be written in the form,


Hx = c (C.1.38)
Pr T
where, H = i=1 (Bi ⊗ Ai ), x = vecX, and c = vecC.
C.2. SPARSE MATRICES 35

C.2 Sparse Matrices


C.3 Linear solvers
C.3.1 Direct solvers
C.3.2 Iterative solvers
36 APPENDIX C. APPLIED LINEAR ALGEBRA
Bibliography

[1] Ed Akin. Object Oriented Programming Via FORTRAN 90/95. Cambridge University Press, New York,
NY, USA, 2003.
[2] N.S. Clerman and W. Spector. Modern Fortran: Style and Usage. Cambridge University Press, 2011.
[3] NMPP Division. Fortran programming guidelines. In progress.
[4] A. Graham. Kronecker products and matrix calculus with applications. 1981.

[5] Laura Grigori and Hua Xiang. Kronecker Product Approximation Preconditioners for Convection-diffusion
Model Problems. Technical Report RR-6536, INRIA, 2008.
[6] Arjen Markus. Modern Fortran in Practice. Cambridge University Press, 2012. Cambridge Books Online.
[7] Michael Metcalf, John Reid, and Malcolm Cohen. Modern Fortran Explained. Oxford University Press,
Inc., New York, NY, USA, 4th edition, 2011.
[8] Langville A. N. and Stewart W. J. A kronecker product approximate preconditioner for sans. Numerical
Linear Algebra with Applications, 11:723–752, 2004.
[9] Philip Rabinowitz and J. Davis Philip. Methods of numerical integration (second edition). Academic Press,
second edition, 1984.

[10] Bernstein D. S. Matrix Mathematics: Theory, Facts, and Formulas. PRINCETON UNIVERSITY PRESS,
second edition, 2009.
[11] Y. Saad. Iterative Methods for Sparse Linear Systems. Society for Industrial and Applied Mathematics,
Philadelphia, PA, USA, 2nd edition, 2003.

[12] Elisabeth Ullmann. A kronecker product preconditioner for stochastic galerkin finite element discretizations.
Siam Journal on Scientific Computing, 32:923–946, 2010.
[13] Charles F. van Loan. The ubiquitous kronecker product. J. Comput. Appl. Math., 123:85–100, November
2000.

37

You might also like