Freefem++Doc

March 28, 2018 | Author: Martino Ermacora | Category: Matrix (Mathematics), Mac Os, Command Line Interface, Software, Areas Of Computer Science


Comments



Description

Third Edition, Version 3.18 http://www.freefem.org/ff++ F. Hecht, O. Pironneau A. Le Hyaric, K. Ohtsuka Laboratoire Jacques-Louis Lions, Universit´e Pierre et Marie Curie, Paris FreeFem++ Third Edition, Version 3.18 http://www.freefem.org/ff++ Fr´ed´eric Hecht 1,4 mailto:[email protected] http://www.ann.jussieu.fr/ ˜ hecht In collaboration with: • Olivier Pironneau, mailto:[email protected], http://www. ann.jussieu.fr/pironneau Olivier Pironneau is a professor of numerical analysis at the university of Paris VI and at LJLL. His scientific contributions are in numerical methods for fluids. He is a member of the Institut Universitaire de France and of the French Academy of Sciences • Jacques Morice, mailto:[email protected]. Jacaues Morice is a Post-Doct at LJLL. His doing is Thesis in University of Bordeaux I on fast multi- pole method (FMM). In this version, he do all three dimensions mesh generation and coupling with medit software. • Antoine Le Hyaric, mailto:[email protected], http://www. ann.jussieu.fr/ ˜ lehyaric/ Antoine Le Hyaric is a research engineer from the ”Centre National de la Recherche Scientifique” (CNRS) at LJLL . He is an expert in software engineering for scientific applications. He has applied his skills mainly to electromagnetics simulation, parallel computing and three-dimensional visualization. • Kohji Ohtsuka,mailto:[email protected], http://www.comfos.org/ Kohji Ohtsuka is a professor at the Hiroshima Kokusai Gakuin University, Japan and chairman of the World Scientific and Engineering academy and Society, Japan chapter. His research is in fracture dynamics, modeling and computing. Acknowledgments We are very grateful to l’ ´ Ecole Polytechnique (Palaiseau, France) for printing the second edition of this manual (http://www.polytechnique.fr ), and to l’Agence Nationale de la Recherche (Paris, France) for funding of the extension of FreeFem++ to a parallel tridimensional version (http://www.agence-nationale-recherche.fr) R´ef´erence : ANR-07-CIS7-002- 01. iv Contents 1 Introduction 1 1.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.1 For everyone: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.2 For the pros: Installation from sources . . . . . . . . . . . . . . . . . 3 1.2 How to use FreeFem++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.3 Environment variables, and the init file . . . . . . . . . . . . . . . . . . . . . 8 1.4 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2 Getting Started 11 2.0.1 FEM by FreeFem++ : how does it work? . . . . . . . . . . . . . . . 12 2.0.2 Some Features of FreeFem++ . . . . . . . . . . . . . . . . . . . . . 17 2.1 The Development Cycle: Edit–Run/Visualize–Revise . . . . . . . . . . . . . 17 3 Learning by Examples 19 3.1 Membranes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2 Heat Exchanger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.3 Acoustics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.4 Thermal Conduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.4.1 Axisymmetry: 3D Rod with circular section . . . . . . . . . . . . . . 29 3.4.2 A Nonlinear Problem : Radiation . . . . . . . . . . . . . . . . . . . . 30 3.5 Irrotational Fan Blade Flow and Thermal effects . . . . . . . . . . . . . . . . 30 3.5.1 Heat Convection around the airfoil . . . . . . . . . . . . . . . . . . . 32 3.6 Pure Convection : The Rotating Hill . . . . . . . . . . . . . . . . . . . . . . 33 3.7 A Projection Algorithm for the Navier-Stokes equations . . . . . . . . . . . 37 3.8 The System of elasticity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.9 The System of Stokes for Fluids . . . . . . . . . . . . . . . . . . . . . . . . . 42 3.10 A Large Fluid Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.11 An Example with Complex Numbers . . . . . . . . . . . . . . . . . . . . . . 46 3.12 Optimal Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.13 A Flow with Shocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.14 Classification of the equations . . . . . . . . . . . . . . . . . . . . . . . . . . 52 4 Syntax 55 4.1 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.2 List of major types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 4.3 Global Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 4.4 System Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 i ii CONTENTS 4.5 Arithmetics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.6 string expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.7 Functions of one Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 4.8 Functions of two Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 4.8.1 Formula . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 4.8.2 FE-functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 4.9 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 4.9.1 Arrays with two integer indices versus matrices . . . . . . . . . . . . 70 4.9.2 Matrix construction and setting . . . . . . . . . . . . . . . . . . . . . 72 4.9.3 Matrix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.9.4 Other arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 4.10 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 4.11 Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 4.11.1 Script arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.12 preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.13 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 5 Mesh Generation 85 5.1 Commands for Mesh Generation . . . . . . . . . . . . . . . . . . . . . . . . . 85 5.1.1 Square . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 5.1.2 Border . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 5.1.3 Data Structures and Read/Write Statements for a Mesh . . . . . . . 89 5.1.4 Mesh Connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 5.1.5 The keyword ”triangulate” . . . . . . . . . . . . . . . . . . . . . . . . 94 5.2 Boundary FEM Spaces Built as Empty Meshes . . . . . . . . . . . . . . . . 95 5.3 Remeshing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 5.3.1 Movemesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 5.4 Regular Triangulation: hTriangle . . . . . . . . . . . . . . . . . . . . . . . 98 5.5 Adaptmesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 5.6 Trunc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 5.7 Splitmesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 5.8 Meshing Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 5.9 How to change the label of elements and border elements of a mesh . . . . . 110 5.10 Mesh in three dimensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 5.10.1 Read/Write Statements for a Mesh in 3D . . . . . . . . . . . . . . . . 111 5.10.2 TeGen: A tetrahedral mesh generator . . . . . . . . . . . . . . . . . 112 5.10.3 Reconstruct/Refine a three dimensional mesh with TetGen . . . . . . 116 5.10.4 Moving mesh in three dimensions . . . . . . . . . . . . . . . . . . . . 117 5.10.5 Layer mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 5.11 Meshing examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 5.11.1 Build a 3d mesh of a cube with a balloon . . . . . . . . . . . . . . . . 124 5.12 The output solution formats .sol and .solb . . . . . . . . . . . . . . . . . . . 126 5.13 medit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 5.14 Mshmet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 5.15 FreeYams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 5.16 mmg3d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 5.17 A first 3d isotope mesh adaptation process . . . . . . . . . . . . . . . . . . . 138 CONTENTS iii 6 Finite Elements 139 6.1 Use of “fespace” in 2d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 6.2 Use of fespace in 3d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 6.3 Lagrangian Finite Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 6.3.1 P0-element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 6.3.2 P1-element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 6.3.3 P2-element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 6.4 P1 Nonconforming Element . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 6.5 Other FE-space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 6.6 Vector valued FE-function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 6.6.1 Raviart-Thomas element . . . . . . . . . . . . . . . . . . . . . . . . . 149 6.7 A Fast Finite Element Interpolator . . . . . . . . . . . . . . . . . . . . . . . 151 6.8 Keywords: Problem and Solve . . . . . . . . . . . . . . . . . . . . . . . . . . 153 6.8.1 Weak form and Boundary Condition . . . . . . . . . . . . . . . . . . 154 6.9 Parameters affecting solve and problem . . . . . . . . . . . . . . . . . . . 155 6.10 Problem definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 6.11 Numerical Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 6.12 Variational Form, Sparse Matrix, PDE Data Vector . . . . . . . . . . . . . . 161 6.13 Interpolation matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 6.14 Finite elements connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 7 Visualization 169 7.1 Plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 7.2 link with gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 7.3 link with medit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 8 Algorithms 175 8.1 conjugate Gradient/GMRES . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 8.2 Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 8.2.1 Example of utilization for BFGS or CMAES . . . . . . . . . . . . . . 178 8.2.2 The nlOpt optimizers . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 8.2.3 Optimization with MPI . . . . . . . . . . . . . . . . . . . . . . . . . 186 9 Mathematical Models 187 9.1 Static Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 9.1.1 Soap Film . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 9.1.2 Electrostatics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 9.1.3 Aerodynamics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 9.1.4 Error estimation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 9.1.5 Periodic Boundary Conditions . . . . . . . . . . . . . . . . . . . . . 194 9.1.6 Poisson Problems with mixed boundary condition . . . . . . . . . . . 197 9.1.7 Poisson with mixte finite element . . . . . . . . . . . . . . . . . . . . 199 9.1.8 Metric Adaptation and residual error indicator . . . . . . . . . . . . . 200 9.1.9 Adaptation using residual error indicator . . . . . . . . . . . . . . . . 202 9.2 Elasticity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 9.2.1 Fracture Mechanics . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 9.3 Nonlinear Static Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 iv CONTENTS 9.3.1 Newton-Raphson algorithm . . . . . . . . . . . . . . . . . . . . . . . 212 9.4 Eigenvalue Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 9.5 Evolution Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 9.5.1 Mathematical Theory on Time Difference Approximations. . . . . . . 218 9.5.2 Convection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 9.5.3 2D Black-Scholes equation for an European Put option . . . . . . . . 222 9.6 Navier-Stokes Equation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 9.6.1 Stokes and Navier-Stokes . . . . . . . . . . . . . . . . . . . . . . . . . 224 9.6.2 Uzawa Algorithm and Conjugate Gradients . . . . . . . . . . . . . . . 228 9.6.3 NSUzawaCahouetChabart.edp . . . . . . . . . . . . . . . . . . . . . . 230 9.7 Variational inequality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 9.8 Domain decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 9.8.1 Schwarz Overlap Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 234 9.8.2 Schwarz non Overlap Scheme . . . . . . . . . . . . . . . . . . . . . . 236 9.8.3 Schwarz-gc.edp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 9.9 Fluid/Structures Coupled Problem . . . . . . . . . . . . . . . . . . . . . . . 239 9.10 Transmission Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 9.11 Free Boundary Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 9.12 Non linear Elasticity (nolinear-elas.edp) . . . . . . . . . . . . . . . . . . . . . 248 9.13 Compressible Neo-Hookean Materials: Computational Solutions . . . . . . . 251 9.13.1 Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 9.13.2 A Neo-Hookean Compressible Material . . . . . . . . . . . . . . . . . 252 9.13.3 An Approach to Implementation in FreeFem++ . . . . . . . . . . . . 253 10 MPI Parallel version 255 10.1 MPI keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 10.2 MPI constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 10.3 MPI Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 10.4 MPI functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 10.5 MPI communicator operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 10.6 Schwarz example in parallel . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 10.6.1 True parallel Schwarz example . . . . . . . . . . . . . . . . . . . . . . 259 11 Parallel sparse solvers 265 11.1 Using parallel sparse solvers in FreeFem++ . . . . . . . . . . . . . . . . . 265 11.2 Sparse direct solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 11.2.1 MUMPS solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 11.2.2 SuperLU distributed solver . . . . . . . . . . . . . . . . . . . . . . . . 271 11.2.3 Pastix solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 11.3 Parallel sparse iterative solver . . . . . . . . . . . . . . . . . . . . . . . . . . 274 11.3.1 pARMS solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 11.3.2 Interfacing with HIPS . . . . . . . . . . . . . . . . . . . . . . . . . . 277 11.3.3 Interfacing with HYPRE . . . . . . . . . . . . . . . . . . . . . . . . . 283 11.3.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 11.4 Domain decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 11.4.1 Communicators and groups . . . . . . . . . . . . . . . . . . . . . . . 287 11.4.2 Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 CONTENTS v 11.4.3 Points to Points communicators . . . . . . . . . . . . . . . . . . . . . 289 11.4.4 Global operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 12 Mesh Files 295 12.1 File mesh data structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 12.2 bb File type for Store Solutions . . . . . . . . . . . . . . . . . . . . . . . . . 296 12.3 BB File Type for Store Solutions . . . . . . . . . . . . . . . . . . . . . . . . 296 12.4 Metric File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 12.5 List of AM FMT, AMDBA Meshes . . . . . . . . . . . . . . . . . . . . . . . 297 13 Addition of a new finite element 301 13.1 Some notations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 13.2 Which class to add? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 A Table of Notations 307 A.1 Generalities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 A.2 Sets, Mappings, Matrices, Vectors . . . . . . . . . . . . . . . . . . . . . . . . 307 A.3 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 A.4 Differential Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 A.5 Meshes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 A.6 Finite Element Spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 B Grammar 311 B.1 The bison grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 B.2 The Types of the languages, and cast . . . . . . . . . . . . . . . . . . . . . . 315 B.3 All the operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 C Dynamical link 321 C.1 A first example myfunction.cpp . . . . . . . . . . . . . . . . . . . . . . . . . 321 C.2 Example: Discrete Fast Fourier Transform . . . . . . . . . . . . . . . . . . . 324 C.3 Load Module for Dervieux’ P0-P1 Finite Volume Method . . . . . . . . . . . 326 C.4 More on Adding a new finite element . . . . . . . . . . . . . . . . . . . . . . 329 C.5 Add a new sparse solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 D Keywords 343 vi CONTENTS Preface Fruit of a long maturing process, freefem, in its last avatar, FreeFem++, is a high level inte- grated development environment (IDE) for numerically solving partial differential equations (PDE). It is the ideal tool for teaching the finite element method but it is also perfect for research to quickly test new ideas or multi-physics and complex applications. FreeFem++ has an advanced automatic mesh generator, capable of a posteriori mesh adap- tation; it has a general purpose elliptic solver interfaced with fast algorithms such as the multi-frontal method UMFPACK, SuperLU . Hyperbolic and parabolic problems are solved by iterative algorithms prescribed by the user with the high level language of FreeFem++. It has several triangular finite elements, including discontinuous elements. Finally every- thing is there in FreeFem++ to prepare research quality reports: color display online with zooming and other features and postscript printouts. This manual is meant for students at Master level, for researchers at any level, and for engineers (including financial engineering) with some understanding of variational methods for partial differential equations. vii viii CONTENTS Chapter 1 Introduction A partial differential equation is a relation between a function of several variables and its (partial) derivatives. Many problems in physics, engineering, mathematics and even banking are modeled by one or several partial differential equations. FreeFem++ is a software to solve these equations numerically. As its name implies, it is a free software (see the copyrights for full detail) based on the Finite Element Method; it is not a package, it is an integrated product with its own high level programming language. This software runs on all UNIX OS (with g++ 3.3 or later, and X11R6) , on Window 2000, NT, XP, Vista and 7 and on MacOS 10 (powerpc, intel) Moreover FreeFem++ is highly adaptive. Many phenomena involve several coupled sys- tems, for example: fluid-structure interactions, Lorentz forces for aluminium casting and ocean-atmosphere problems are three such systems. These require different finite element approximations and polynomial degrees, possibly on different meshes. Some algorithms like Schwarz’ domain decomposition method also require data interpolation on multiple meshes within one program. FreeFem++ can handle these difficulties, i.e. arbitrary finite element spaces on arbitrary unstructured and adapted bi-dimensional meshes. The characteristics of FreeFem++ are: • Problem description (real or complex valued) by their variational formulations, with access to the internal vectors and matrices if needed. • Multi-variables, multi-equations, bi-dimensional and three-dimensional static or time dependent, linear or nonlinear coupled systems; however the user is required to describe the iterative procedures which reduce the problem to a set of linear problems. • Easy geometric input by analytic description of boundaries by pieces; however this part is not a CAD system; for instance when two boundaries intersect, the user must specify the intersection points. • Automatic mesh generator, based on the Delaunay-Voronoi algorithm; the inner point density is proportional to the density of points on the boundaries [7]. 1 2 CHAPTER 1. INTRODUCTION • Metric-based anisotropic mesh adaptation. The metric can be computed automatically from the Hessian of any FreeFem++ function [9]. • High level user friendly typed input language with an algebra of analytic and finite element functions. • Multiple finite element meshes within one application with automatic interpolation of data on different meshes and possible storage of the interpolation matrices. • A large variety of triangular finite elements : linear, quadratic Lagrangian elements and more, discontinuous P1 and Raviart-Thomas elements, elements of a non-scalar type, the mini-element,. . . (but no quadrangles). • Tools to define discontinuous Galerkin finite element formulations P0, P1dc, P2dc and keywords: jump, mean, intalledges. • A large variety of linear direct and iterative solvers (LU, Cholesky, Crout, CG, GMRES, UMFPACK) and eigenvalue and eigenvector solvers. • Near optimal execution speed (compared with compiled C++ implementations pro- grammed directly). • Online graphics, generation of ,.txt,.eps,.gnu, mesh files for further manipu- lations of input and output data. • Many examples and tutorials: elliptic, parabolic and hyperbolic problems, Navier- Stokes flows, elasticity, Fluid structure interactions, Schwarz’s domain decomposition method, eigenvalue problem, residual error indicator, ... • A parallel version using mpi 1.1 Installation 1.1.1 For everyone: First open the following web page http://www.freefem.org/ff++/ And choose your platform: Linux, Windows, MacOS X, or go to the end of the page to get the full list of downloads. Remark 1 : Binaries are available for Microsoft Windows, Apple Mac OS X and some Linux systems. Install by double click on the appropriate file. 1.1. INSTALLATION 3 Windows binaries install First download the windows installation executable, then double click it. to install FreeFem++. In most cases just answer yes (or typr return) to all questions. Otherwise in the Additional Task windows, check the box ”Add application directory to your system path your system path .” This is required otherwise the program ffglut.exe will not be found. By now you should have two new icons on your desktop: • FreeFem++ (VERSION).exe the FreeFem++ application. • FreeFem++ (VERSION) Examples a link to the FreeFem++ folder of examples. where (VERSION) is the version of the files (for example 3.3-0-P4). By default, the installed files are in C:\Programs Files\FreeFem++ In this directory, you have all the .dll files and other applications: FreeFem++-nw.exe,ffglut.exe, ... the FreeFem++ application without graphic windows. The syntax for the command-line tools are the same as those of FreeFem.exe. MacOS X binaries install Download the MacOS X binary version file, extract all the files with a double click on the icon of the file, go the the directory and put the FreeFem+.app application in the /Applications directory. If you want a terminal access to FreeFem++ just copy the file FreeFem++ in a directory of your $PATH shell environment variable. If you want to automatically launch the FreeFem++.app, double click on a .edp file icon. Under the finder pick a .edp in directory examples++-tutorial for example, select menu File -> Get Info an change Open with: (choose FreeFem++.app) and click on button change All.... Where to go from here An integrated environment called FreeFem++-cs, written by An- toine Le Hyaric, is provided with FreeFem++ . Unless you wish to profile now your own de- velopment environment, you may proceed to the next paragraph ”How to use FreeFem++”. 1.1.2 For the pros: Installation from sources This section is for those who for some reason do not wish to use the binaries and hence need to recompile FreeFem++ or install it from the source code: The documentation archive : The documentation is also open source; to regenerate it you need a L A T E X environment capable of compiling a CVS archive; under MS-Windows you will have to use cygwin http://www.cygwin.com and under MacOS X we have used Apple’s Developer Tools ”Xcode” and L A T E X from http: //www.ctan.org/system/mac/texmac. 4 CHAPTER 1. INTRODUCTION The C++ archive : FreeFem++ must be compiled from the source archive, as indicated in http://www.freefem.org/ff++/index.htm To extract files from the compressed archive freefem++-(VERSION).tar.gz to a direc- tory called freefem++-(VERSION) enter the following commands in a shell window : tar zxvf freefem++-(VERSION).tar.gz cd freefem++-(VERSION) To compile and install FreeFem++ , just follow the INSTALL and README files. The following programs are produced, depending on the system you are running : 1. FreeFem++, standard version, with a graphical interface based on GLUT/OpenGL (use ffglut visualization tool) or not just add -nw parameter. 2. ffglut the visualization tools through a pipe of freefem++ (remark: if ffglut is not in the system path, you will have no plot) 3. FreeFem++-nw, postscript plot output only (batch version, no graphics windows via ffglut ) 4. FreeFem++-mpi, parallel version, postscript output only 5. /Applications/FreeFem++.app, the Drag and Drop CoCoa MacOSX Applica- tion 6. bamg , the bamg mesh generator 7. cvmsh2 , a mesh file convertor 8. drawbdmesh , a mesh file viewer 9. ffmedit the freefem++ version of medit software (thanks to P. Frey) The FreeFem++ parameter command: Brochet-2:˜ hecht$ FreeFem++ Syntaxe: FreeFem++ [ -v verbosity ] [ -fglut filepath ] [ -glut command ] [ -nw] [ -f] filename -v verbosity : 0 -- 1000000 level of freefem output -fglut filepath : the file name of save all plots (replot with ffglut command ) -glut command : change the command ffglut -gff command : change the command ffglut with space quotting -nowait : nowait at the end on window -wait : wait at the end on window -nw : no ffglut (=> no graphics windows) -ne : no edp script output -cd : Change directory to script dir with default ffglut : ffglut 1.1. INSTALLATION 5 Remark 2 In most cases you can set the level of output (verbosity) to value nn by adding the parameters -v nn on the command line. As an installation test, under unix: go into the directory examples++-tutorial and run FreeFem++ on the example script LaplaceP1.edp with the command : FreeFem++ LaplaceP1.edp If you are using nedit as your text editor, do one time nedit -import edp.nedit to have coloring syntax for your .edp files. The syntax of tools FreeFem++,FreeFem++-nw on the command-line are • FreeFem++ [-?] [-vnn] [-fglut file1] [-glut file2] [-f] edpfilepath where the • or FreeFem++-nw -? [-vnn] [-fglut file1] [-glut file2] [-f] edpfilepath where the -? show the usage. -fglut filename to store all the data for graphic in file filename, and to replay do ffglut filename. -glut ffglutprogam to change the visualisator program’s. -nw no call to ffglut -v nn set the level of verbosity to nn before execution of the script. if no file path then you get a dialog box to choose the edp file on windows systeme. The notation [] means ”optional”. Link with other text editors notepad++ at http://notepad-plus.sourceforge.net/uk/site.htm • Open Notepad++ and Enter F5 • In the new window enter the command FreeFem++ "$(FULL_CURRENT_PATH)" • Click on Save, and enter FreeFem++ in the box ”Name”, now choose the short cut key to launch directly FreeFem++ (for example alt+shift+R) • To add Color Syntax Compatible with FreeFem++ In Notepad++, – In Menu "Parameters"->"Configuration of the Color Syntax" proceed as follows: – In the list "Language" select C++ – Add ”edp” in the field "add ext" – Select "INSTRUCTION WORD" in the list "Description" and in the field "supple mentary key word", cut and past the following list: P0 P1 P2 P3 P4 P5 P1dc P2dc P3dc P4dc P5dc RT0 RT1 RT2 RT3 RT4 RT5 macro plot int1d int2d solve movemesh adaptmesh trunc checkmovemesh on func buildmesh square Eigenvalue min max imag exec LinearCG NLCG Newton BFGS LinearGMRES catch try intalledges jump average mean load savemesh convect abs sin cos tan atan asin acos cotan sinh cosh tanh cotanh atanh asinh acosh pow exp log log10 sqrt dx dy endl cout 6 CHAPTER 1. INTRODUCTION – Select ”TYPE WORD” in the list ”Description” and ... ” ”supplementary key word”, cut and past the following list mesh real fespace varf matrix problem string border complex ifstream of- stream – Click on Save & Close. Now nodepad++ is configured. Crimson Editor availble at http://www.crimsoneditor.com/ and adapted as follows: • Go to the Tools/Preferences/File association menu and add the .edp ex- tension set • In the same panel in Tools/User Tools, add a FreeFem++ item (1st line) with the path to freefem++.exe on the second line and $(FilePath) and $(FileDir) on third and fourth lines. Tick the 8.3 box. • for color syntax, extract file from crimson-freefem.zip and put files in the corresponding sub-folder of Crimson folder (C:\Program Files\Crimson Editor ). winedt for Windows : this is the best but it could be tricky to set up. Download it from http://www.winedt.com this is a multipurpose text editor with advanced features such as syntax coloring; a macro is available on www.freefem.org to localize winedt to FreeFem++ without disturbing the winedt functional mode for LateX, TeX, C, etc. However winedt is not free after the trial period. TeXnicCenter for Windows: this is the easiest and will be the best once we find a volunteer to program the color syntax. Download it from http://www.texniccenter.org/ It is also an editor for TeX/LaTeX. It has a ”‘tool”’ menu which can be configured to launch FreeFem++ programs as in: • Select the Tools/Customize item which will bring up a dialog box. • Select the Tools tab and create a new item: call it freefem. • in the 3 lines below, 1. search for FreeFem++.exe 2. select Main file with further option then Full path and click also on the 8.3 box 3. select main file full directory path with 8.3 nedit on the Mac OS, Cygwin/Xfree and linux, to import the color syntax do nedit -import edp.nedit 1.2. HOW TO USE FREEFEM++ 7 Smultron on the Mac, available at http://smultron.sourceforge.net. It comes ready with color syntax for .edp file. To teach it to launch FreeFem++ files, do a ”command B” (i.e. the menu Tools/Handle Command/new command) and create a command which does /usr/local/bin/FreeFem++-CoCoa %%p Figure 1.1: Integrated environment for FreeFem++ development with Windows 1.2 How to use FreeFem++ 8 CHAPTER 1. INTRODUCTION Under MacOS X with Graphic Interfaces To test an .edp file, just drag and drop the file icon on the MacOS application icon FreeFem++.app. You can also launch this application and use the menu: File →Open. One of the best ways however on the Mac is to use a text editor like Smultron.app (see above). Figure 1.2: The 3 panels of the integrated environment built with the Smultron Editor with FreeFem++ in action. The Tools menu has an item to launch FreeFem++ by a Ctrl+1 command. In Terminal mode Choose the type of application from FreeFem++, FreeFem++-nw, FreeFem++-mpi, . . . according to your needs. Add at least the path name; for example FreeFem++ your-edp-file-path 1.3 Environment variables, and the init file FreeFem++ reads a user’s init file named freefem++.pref to initialize global variables: verbosity, includepath, loadpath. Remark 3 The variable verbosity changes the level of internal printing (0, nothing (un- less there are syntax errors), 1 few, 10 lots, etc. ...), the default value is 2. The include files are searched from the includepath list and the load files are searched from loadpath list. 1.4. HISTORY 9 The syntax of the file is: verbosity= 5 loadpath += "/Library/FreeFem++/lib" loadpath += "/Users/hecht/Library/FreeFem++/lib" includepath += "/Library/FreeFem++/edp" includepath += "/Users/hecht/Library/FreeFem++/edp" # comment load += "funcTemplate" load += "myfunction" The possible paths for this file are • under unix and MacOs /etc/freefem++.pref $(HOME)/.freefem++.pref freefem++.pref • under windows freefem++.pref We can also use shell environment variable to change verbosity and the search rule before the init files. export FF_VERBOSITY=50 export FF_INCLUDEPATH="dir;;dir2" export FF_LOADPATH="dir;;dir3"" Remark: the separator between directories must be ”;” and not ”:” because ”:” is used under Windows. Remark, to show the list of init of freefem++, do export FF_VERBOSITY=100; ./FreeFem++-nw -- verbosity is set to 100 insert init-files /etc/freefem++.pref $ ... 1.4 History The project has evolved from MacFem, PCfem, written in Pascal. The first C version lead to freefem 3.4; it offered mesh adaptativity on a single mesh only. A thorough rewriting in C++ led to freefem+ (freefem+ 1.2.10 was its last release), which included interpolation over multiple meshes (functions defined on one mesh can be used on any other mesh); this software is no longer maintained but still in use because it 10 CHAPTER 1. INTRODUCTION handles a problem description using the strong form of the PDEs. Implementing the inter- polation from one unstructured mesh to another was not easy because it had to be fast and non-diffusive; for each point, one had to find the containing triangle. This is one of the basic problems of computational geometry (see Preparata & Shamos[18] for example). Doing it in a minimum number of operations was the challenge. Our implementation is O(nlog n) and based on a quadtree. This version also grew out of hand because of the evolution of the template syntax in C++. We have been working for a few years now on FreeFem++ , entirely re-written again in C++ with a thorough usage of template and generic programming for coupled systems of unknown size at compile time. Like all versions of freefem it has a high level user friendly input language which is not too far from the mathematical writing of the problems. The freefem language allows for a quick specification of any partial differential system of equations. The language syntax of FreeFem++ is the result of a new design which makes use of the STL [26], templates and bison for its implementation; more detail can be found in [12]. The outcome is a versatile software in which any new finite element can be included in a few hours; but a recompilation is then necessary. Therefore the library of finite elements available in FreeFem++ will grow with the version number and with the number of users who program more new elements. So far we have discontinuous P 0 elements,linear P 1 and quadratic P 2 Lagrangian elements, discontinuous P 1 and Raviart-Thomas elements and a few others like bubble elements. Chapter 2 Getting Started To illustrate with an example, let us explain how FreeFem++ solves Poisson’s equation: for a given function f(x, y), find a function u(x, y) satisfying −∆u(x, y) = f(x, y) for all (x, y) ∈ Ω, (2.1) u(x, y) = 0 for all (x, y) on ∂Ω, . (2.2) Here ∂Ω is the boundary of the bounded open set Ω ⊂ R 2 and ∆u = ∂ 2 u ∂x 2 + ∂ 2 u ∂y 2 . The following is a FreeFem++ program which computes u when f(x, y) = xy and Ω is the unit disk. The boundary C = ∂Ω is C = ¦(x, y)[ x = cos(t), y = sin(t), 0 ≤ t ≤ 2π¦ Note that in FreeFem++ the domain Ω is assumed to described by its boundary that is on the left side of its boundary oriented by the parameter. As illustrated in Fig. 2.2, we can see the isovalue of u by using plot (see line 13 below). Figure 2.1: mesh Th by build(C(50)) Figure 2.2: isovalue by plot(u) Example 2.1 // defining the boundary 1: border C(t=0,2 * pi){x=cos(t); y=sin(t);} 11 12 CHAPTER 2. GETTING STARTED // the triangulated domain Th is on the left side of its boundary 2: mesh Th = buildmesh (C(50)); // the finite element space defined over Th is called here Vh 3; fespace Vh(Th,P1); 4: Vh u,v; // defines u and v as piecewise-P1 continuous functions 5: func f= x * y; // definition of a called f function 6: real cpu=clock(); // get the clock in second 7: solve Poisson(u,v,solver=LU) = // defines the PDE 8: int2d(Th)(dx(u) * dx(v) + dy(u) * dy(v)) // bilinear part 9: - int2d(Th)( f * v) // right hand side 10: + on(C,u=0) ; // Dirichlet boundary condition 11: plot(u); 12: cout << " CPU time = " << clock()-cpu << endl; Note that the qualifier solver=LU is not required and by default a multi-frontal LU would have been used. Note also that the lines containing clock are equally not required. Finally note how close to the mathematics FreeFem++ input language is. Line 8 and 9 correspond to the mathematical variational equation T h ( ∂u ∂x ∂v ∂x + ∂u ∂y ∂v ∂y )dxdy = T h fvdxdy for all v which are in the finite element space V h and zero on the boundary C. Exercise : Change P1 into P2 and run the program. 2.0.1 FEM by FreeFem++ : how does it work? This first example shows how FreeFem++ executes with no effort all the usual steps re- quired by the finite element method (FEM). Let us go through them one by one. 1st line: the boundary Γ is described analytically by a parametric equation for x and for y. When Γ = ¸ J j=0 Γ j then each curve Γ j , must be specified and crossings of Γ j are not allowed except at end points . The keyword “label” can be added to define a group of boundaries for later use (boundary conditions for instance). Hence the circle could also have been described as two half circle with the same label: border Gamma1(t=0,pi) {x=cos(t); y=sin(t); label=C} border Gamma2(t=pi,2 * pi){x=cos(t); y=sin(t); label=C} Boundaries can be referred to either by name ( Gamma1 for example) or by label ( C here) or even by its internal number here 1 for the first half circle and 2 for the second (more examples are in Section 5.8). 2nd line: the triangulation T h of Ω is automatically generated by buildmesh(C(50)) using 50 points on C as in Fig. 2.1. The domain is assumed to be on the left side of the boundary which is implicitly oriented by the parametrization. So an elliptic hole can be added by 13 border C(t=2 * pi,0){x=0.1+0.3 * cos(t); y=0.5 * sin(t);} If by mistake one had written border C(t=0,2 * pi){x=0.1+0.3 * cos(t); y=0.5 * sin(t);} then the inside of the ellipse would be triangulated as well as the outside. Automatic mesh generation is based on the Delaunay-Voronoi algorithm. Refinement of the mesh are done by increasing the number of points on Γ, for example, buildmesh(C(100)), because inner vertices are determined by the density of points on the boundary. Mesh adaptation can be performed also against a given function f by calling adaptmesh(Th,f). Now the name T h (Th in FreeFem++ ) refers to the family ¦T k ¦ k=1,··· ,n t of triangles shown in figure 2.1. Traditionally h refers to the mesh size, n t to the number of triangles in T h and n v to the number of vertices, but it is seldom that we will have to use them explicitly. If Ω is not a polygonal domain, a “skin” remains between the exact domain Ω and its approximation Ω h = ∪ n t k=1 T k . However, we notice that all corners of Γ h = ∂Ω h are on Γ. 3rd line: A finite element space is, usually, a space of polynomial functions on elements, triangles here only, with certain matching properties at edges, vertices etc. Here fespace Vh(Th,P1) defines V h to be the space of continuous functions which are affine in x, y on each triangle of T h . As it is a linear vector space of finite dimension, basis can be found. The canonical basis is made of functions, called the hat functions φ k which are continuous piecewise affine and are equal to 1 on one vertex and 0 on all others. A typical hat function is shown on figure 2.4 1 . Then V h (T h , P 1 ) = w(x, y) w(x, y) = M ¸ k=1 w k φ k (x, y), w k are real numbers ¸ (2.3) where M is the dimension of V h , i.e. the number of vertices. The w k are called the degree of freedom of w and M the number of the degree of freedom. It is said also that the nodes of this finite element method are the vertices. Currently FreeFem++ implements the following elements in 2d, (see section 6 for the full description) P0 piecewise constant, P1 continuous piecewise linear, P2 continuous piecewise quadratic, P3 continuous piecewise cubic, (need load "Element_P3") P4 continuous piecewise quartic,(need load "Element_P4") RT0 Raviart-Thomas piecewise constant, 1 The easiest way to define φ k is by making use of the barycentric coordinates λ i (x, y), i = 1, 2, 3 of a point q = (x, y) ∈ T, defined by ¸ i λ i = 1, ¸ i λ i q i = q where q i , i = 1, 2, 3 are the 3 vertices of T. Then it is easy to see that the restriction of φ k on T is precisely λ k . 14 CHAPTER 2. GETTING STARTED # & % " ! $ $ % # ! " Figure 2.3: mesh Th ! " % & # ! " & % Figure 2.4: Graph of φ 1 (left) and φ 6 RT1 Raviart-Thomas degree 1 piecewise constant (need load "Element_Mixte") BDM1 Brezzi-Douglas-Marini degree 1 piecewise constant (need load "Element_Mixte") RT0Ortho Nedelec type 1 degree 0 piecewise constant RT1Ortho Nedelec type 1 degree 1 piecewise constant (need load "Element_Mixte") BDM1Ortho Brezzi-Douglas-Marini degree 1 piecewise constant (need load "Element_Mixte") P1nc piecewise linear non-conforming, P1dc piecewise linear discontinuous, P2dc piecewise quadratic discontinuous, P2h quadratic homogene continuous (without P1) P3dc piecewise cubic discontinuous,(need load "Element_P3dc") P4dc piecewise quartic discontinuous,(need load "Element_P4dc") P1b piecewise linear continuous plus bubble, P2b piecewise quadratic continuous plus bubble. Morley Morley finite element (need load "Morley") P2BR P2 Bernardi-Raugel finite element (need load "BernadiRaugel.cpp") P0edge a finite element constant per edge P1edge to P5edge a finite element polynomial on edge (need load "Element_PkEdge") ... Currently FreeFem++ implements the following elements in 3d, (see section 6 for the full description) P03d piecewise constant, P13d continuous piecewise linear, P23d continuous piecewise quadratic, RT03d Raviart-Thomas piecewise constant, Edge03d The Nedelec Edge element P1b3d piecewise linear continuous plus bubble, ... To get the full list, in a unix terminal, in directory examples++-tutorial do FreeFem++ dumptable.edp grep TypeOfFE lestables Note that other elements can be added fairly easily. 15 Step3: Setting the problem 4th line: Vh u,v declares that u and v are approximated as above, namely u(x, y) · u h (x, y) = M−1 ¸ k=0 u k φ k (x, y) (2.4) 5th line: the right hand side f is defined analytically using the keyword func. 7th–9th lines: defines the bilinear form of equation (2.1) and its Dirichlet boundary condi- tions (2.2). This variational formulation is derived by multiplying (2.1) by v(x, y) and integrating the result over Ω: − Ω v∆udxdy = Ω vf dxdy Then, by Green’s formula, the problem is converted into finding u such that a(u, v) −(f, v) = 0 ∀v satisfying v = 0 on ∂Ω. (2.5) with a(u, v) = Ω ∇u ∇v dxdy, (f, v) = Ω fv dxdy (2.6) In FreeFem++ the Poisson problem can be declared only as in Vh u,v; problem Poisson(u,v) = and solved later as in ... Poisson; // the problem is solved here ... or declared and solved at the same time as in Vh u,v; solve Poisson(u,v) =int(... and (2.5) is written with dx(u) = ∂u/∂x, dy(u) = ∂u/∂y and Ω ∇u ∇v dxdy −→ int2d(Th)( dx(u) * dx(v) + dy(u) * dy(v) ) Ω fv dxdy −→ int2d(Th)( f * v ) (Notice here, u is unused) In FreeFem++ bilinear terms and linear terms should not be under the same integral; indeed to construct the linear systems FreeFem++ finds out which integral contributes to the bilinear form by checking if both terms , the unknown (here u) and test functions (here v) are present. Step4: Solution and visualization 6th line: The current time in seconds is stored into the real-valued variable cpu. 7th line The problem is solved. 16 CHAPTER 2. GETTING STARTED 11th line: The visualization is done as illustrated in Fig. 2.2 (see Section 7.1 for zoom, postscript and other commands). 12th line: The computing time (not counting graphics) is written on the console Notice the C++-like syntax; the user needs not study C++ for using FreeFem++ , but it helps to guess what is allowed in the language. Access to matrices and vectors Internally FreeFem++ will solve a linear system of the type M−1 ¸ j=0 A ij u j −F i = 0, i = 0, , M −1; F i = Ω fφ i dxdy (2.7) which is found by using (2.4) and replacing v by φ i in (2.5). And the Dirichlet conditions are implemented by penalty, namely by setting A ii = 10 30 and F i = 10 30 ∗ 0 if i is a boundary degree of freedom. Note, that the number 10 30 is called tgv (tr`es grande valeur) and it is generally possible to change this value , see the index item solve!tgv=. The matrix A = (A ij ) is called stiffness matrix . If the user wants to access A directly he can do so by using (see section 6.12 page 162 for details) varf a(u,v) = int2d(Th)( dx(u) * dx(v) + dy(u) * dy(v)) + on(C,u=0) ; matrix A=a(Vh,Vh); // stiffness matrix, The vector F in (2.7) can also be constructed manually varf l(unused,v) = int2d(Th)(f * v)+on(C,unused=0); Vh F; F[] = l(0,Vh); // F[] is the vector associated to the function F The problem can then be solved by u[]=Aˆ-1 * F[]; // u[] is the vector associated to the function u Note 2.1 Here u and F are finite element function, and u[] and F[] give the array of value associated ( u[]≡ (u i ) i=0,...,M−1 and F[]≡ (F i ) i=0,...,M−1 ). So we have u(x, y) = M−1 ¸ i=0 u[][i]φ i (x, y), F(x, y) = M−1 ¸ i=0 F[][i]φ i (x, y) where φ i , i = 0..., , M − 1 are the basis functions of Vh like in equation (2.3), and M = Vh.ndof is the number of degree of freedom (i.e. the dimension of the space Vh). The linear system (2.7) is solved by UMFPACK unless another option is mentioned specifically as in Vh u,v; problem Poisson(u,v,solver=CG) = int2d(... meaning that Poisson is declared only here and when it is called (by simply writing Poisson; ) then (2.7) will be solved by the Conjugate Gradient method. 2.1. THE DEVELOPMENT CYCLE: EDIT–RUN/VISUALIZE–REVISE 17 2.0.2 Some Features of FreeFem++ The language of FreeFem++ is typed, polymorphic and reentrant with macro generation (see 9.12). Every variable must be typed and declared in a statement each statement sepa- rated from the next by a semicolon ”;”. The syntax is that of C++ by default augmented with something that is more akin to T E X. For the specialist, one key guideline is that FreeFem++ rarely generates an internal finite element array; this was adopted for speed and consequently FreeFem++ could be hard to beat in terms of execution speed, except for the time lost in the interpretation of the language (which can be reduced by a systematic usage of varf and matrices instead of problem. 2.1 The Development Cycle: Edit–Run/Visualize–Revise An integrated environment is provided with FreeFem++ by A. Le Hyaric; Many examples and tutorials are also given along with this documentation and it is best to study them and learn by example. Explanations for some of these examples are given in this documentation in the next chapter. If you are a FEM beginner, you may also have to read a book on variational formulations. The development cycle will have the following steps: Modeling: From strong forms of PDE to weak forms, one must know the variational for- mulation to use FreeFem++ ; one should also have an eye on the reusability of the variational formulation so as to keep the same internal matrices; a typical example is the time dependent heat equation with an implicit time scheme: the internal matrix can be factorized only once and FreeFem++ can be taught to do so. Programming: Write the code in FreeFem++ language using a text editor such as the one provided in the integrated environment. Run: Run the code (here written in file mycode.edp). note that this can also be done in terminal mode by : % FreeFem++ mycode.edp Visualization: Use the keyword plot to display functions while FreeFem++ is running. Use the plot-parameter wait=1 to stop the program at each plot. Use the plot- parameter ps="toto.eps" to generate a postscript file to archive the results. Debugging: A global variable ”debug” (for example) can help as in wait=true to wait=false. bool debug = true; border a(t=0,2 * pi){ x=cos(t); y=sin(t);label=1;} border b(t=0,2 * pi){ x=0.8+0.3 * cos(t); y=0.3 * sin(t);label=2;} plot(a(50)+b(-30),wait=debug); // plot the borders to see the intersection // (so change (0.8 in 0.3 in b) then needs a mouse click mesh Th = buildmesh(a(50)+b(-30)); plot(Th,wait=debug); // plot Th then needs a mouse click fespace Vh(Th,P2); Vh f = sin(pi * x) * cos(pi * y); plot(f,wait=debug); // plot the function f 18 CHAPTER 2. GETTING STARTED Vh g = sin(pi * x + cos(pi * y)); plot(g,wait=debug); // plot the function g Changing debug to false will make the plots flow continuously; watching the flow of graphs on the screen (while drinking coffee) can then become a pleasant experience. Error messages are displayed in the console window. They are not always very explicit because of the template structure of the C++ code, (we did our best)! Nevertheless they are displayed at the right place. For example, if you forget parenthesis as in bool debug = true; mesh Th = square(10,10; plot(Th); then you will get the following message from FreeFem++, 2 : mesh Th = square(10,10; Error line number 2, in file bb.edp, before token ; parse error current line = 2 Compile error : parse error line number :2, ; error Compile error : parse error line number :2, ; code = 1 If you use the same symbol twice as in real aaa =1; real aaa; then you will get the message 2 : real aaa; The identifier aaa exists the existing type is <Pd> the new type is <Pd> If you find that the program isn’t doing what you want you may also use cout to display in text format on the console window the value of variables, just as you would do in C++. The following example works: ...; fespace Vh...; Vh u;... cout<<u;... matrix A=a(Vh,Vh);... cout<<A; Another trick is to comment in and out by using the“ //” as in C++. For example real aaa =1; // real aaa; Chapter 3 Learning by Examples This chapter is for those, like us, who don’t like to read manuals. A number of simple examples cover a good deal of the capacity of FreeFem++ and are self-explanatory. For the modeling part this chapter continues at Chapter 9 where some PDEes of physics, engineering and finance are studied in greater depth. 3.1 Membranes Summary Here we shall learn how to solve a Dirichlet and/or mixed Dirichlet Neumann problem for the Laplace operator with application to the equilibrium of a membrane under load. We shall also check the accuracy of the method and interface with other graphics pack- ages. An elastic membrane Ω is attached to a planar rigid support Γ, and a force f(x)dx is exerted on each surface element dx = dx 1 dx 2 . The vertical membrane displacement, ϕ(x), is obtained by solving Laplace’s equation: −∆ϕ = f in Ω. As the membrane is fixed to its planar support, one has: ϕ[ Γ = 0. If the support wasn’t planar but at an elevation z(x 1 , x 2 ) then the boundary conditions would be of non-homogeneous Dirichlet type. ϕ[ Γ = z. If a part Γ 2 of the membrane border Γ is not fixed to the support but is left hanging, then due to the membrane’s rigidity the angle with the normal vector n is zero; thus the boundary conditions are ϕ[ Γ 1 = z, ∂ϕ ∂n [ Γ 2 = 0 where Γ 1 = Γ −Γ 2 ; recall that ∂ϕ ∂n = ∇ϕ n. Let us recall also that the Laplace operator ∆ is defined by: ∆ϕ = ∂ 2 ϕ ∂x 2 1 + ∂ 2 ϕ ∂x 2 2 . 19 20 CHAPTER 3. LEARNING BY EXAMPLES With such ”mixed boundary conditions” the problem has a unique solution (see (1987), Dautray-Lions (1988), Strang (1986) and Raviart-Thomas (1983)); the easiest proof is to notice that ϕ is the state of least energy, i.e. E(φ) = min ϕ−z∈V E(v), with E(v) = Ω ( 1 2 [∇v[ 2 −fv) and where V is the subspace of the Sobolev space H 1 (Ω) of functions which have zero trace on Γ 1 . Recall that (x ∈ R d , d = 2 here) H 1 (Ω) = ¦u ∈ L 2 (Ω) : ∇u ∈ (L 2 (Ω)) d ¦ Calculus of variation shows that the minimum must satisfy, what is known as the weak form of the PDE or its variational formulation (also known here as the theorem of virtual work) Ω ∇ϕ ∇w = Ω fw ∀w ∈ V Next an integration by parts (Green’s formula) will show that this is equivalent to the PDE when second derivatives exist. WARNING Unlike freefem+ which had both weak and strong forms, FreeFem++ im- plements only weak formulations. It is not possible to go further in using this software if you don’t know the weak form (i.e. variational formulation) of your problem: either you read a book, or ask help form a colleague or drop the matter. Now if you want to solve a system of PDE like A(u, v) = 0, B(u, v) = 0 don’t close this manual, because in weak form it is Ω (A(u, v)w 1 + B(u, v)w 2 ) = 0 ∀w 1 , w 2 ... Example Let an ellipse have the length of the semimajor axis a = 2, and unitary the semiminor axis Let the surface force be f = 1. Programming this case with FreeFem++ gives: Example 3.1 (membrane.edp) // file membrane.edp real theta=4. * pi/3.; real a=2.,b=1.; // the length of the semimajor axis and semiminor axis func z=x; border Gamma1(t=0,theta) { x = a * cos(t); y = b * sin(t); } border Gamma2(t=theta,2 * pi) { x = a * cos(t); y = b * sin(t); } mesh Th=buildmesh(Gamma1(100)+Gamma2(50)); fespace Vh(Th,P2); // P2 conforming triangular FEM Vh phi,w, f=1; solve Laplace(phi,w)=int2d(Th)(dx(phi) * dx(w) + dy(phi) * dy(w)) - int2d(Th)(f * w) + on(Gamma1,phi=z); plot(phi,wait=true, ps="membrane.eps"); // Plot phi plot(Th,wait=true, ps="membraneTh.eps"); // Plot Th savemesh(Th,"Th.msh"); 3.1. MEMBRANES 21 -2 -1.5 -1 -0.5 0 0.5 1 1.5 2 -2 -1.5 -1 -0.5 0 0.5 1 1.5 2 -1 -0.8 -0.6 -0.4 -0.2 0 0.2 0.4 0.6 0.8 1 -2 -1.5 -1 -0.5 0 0.5 1 1.5 2 "phi.txt" Figure 3.1: Mesh and level lines of the membrane deformation. Below: the same in 3D drawn by gnuplot from a file generated by FreeFem++ . 22 CHAPTER 3. LEARNING BY EXAMPLES A triangulation is built by the keyword buildmesh. This keyword calls a triangulation subroutine based on the Delaunay test, which first triangulates with only the boundary points, then adds internal points by subdividing the edges. How fine the triangulation becomes is controlled by the size of the closest boundary edges. The PDE is then discretized using the triangular second order finite element method on the triangulation; as was briefly indicated in the previous chapter, a linear system is derived from the discrete formulation whose size is the number of vertices plus the number of mid- edges in the triangulation. The system is solved by a multi-frontal Gauss LU factorization implemented in the package UMFPACK. The keyword plot will display both T h and ϕ (remove Th if ϕ only is desired) and the qualifier fill=true replaces the default option (colored level lines) by a full color display. Results are on figure 3.1. plot(phi,wait=true,fill=true); // Plot phi with full color display Next we would like to check the results! One simple way is to adjust the parameters so as to know the solutions. For instance on the unit circle a=1 , ϕ e = sin(x 2 + y 2 −1) solves the problem when z = 0, f = −4(cos(x 2 + y 2 −1) −(x 2 + y 2 ) sin(x 2 + y 2 −1)) except that on Γ 2 ∂ n ϕ = 2 instead of zero. So we will consider a non-homogeneous Neumann condition and solve Ω (∇ϕ ∇w = Ω fw + Γ 2 2w ∀w ∈ V We will do that with two triangulations, compute the L 2 error: = Ω [ϕ −ϕ e [ 2 and print the error in both cases as well as the log of their ratio an indication of the rate of convergence. Example 3.2 (membranerror.edp) // file membranerror.edp verbosity =0; // to remove all default output real theta=4. * pi/3.; real a=1.,b=1.; // the length of the semimajor axis and semiminor axis border Gamma1(t=0,theta) { x = a * cos(t); y = b * sin(t); } border Gamma2(t=theta,2 * pi) { x = a * cos(t); y = b * sin(t); } func f=-4 * (cos(xˆ2+yˆ2-1) -(xˆ2+yˆ2) * sin(xˆ2+yˆ2-1)); func phiexact=sin(xˆ2+yˆ2-1); real[int] L2error(2); // an array two values for(int n=0;n<2;n++) { mesh Th=buildmesh(Gamma1(20 * (n+1))+Gamma2(10 * (n+1))); fespace Vh(Th,P2); Vh phi,w; solve laplace(phi,w)=int2d(Th)(dx(phi) * dx(w) + dy(phi) * dy(w)) - int2d(Th)(f * w) - int1d(Th,Gamma2)(2 * w)+ on(Gamma1,phi=0); 3.1. MEMBRANES 23 plot(Th,phi,wait=true,ps="membrane.eps"); // Plot Th and phi L2error[n]= sqrt(int2d(Th)((phi-phiexact)ˆ2)); } for(int n=0;n<2;n++) cout << " L2error " << n << " = "<< L2error[n] <<endl; cout <<" convergence rate = "<< log(L2error[0]/L2error[1])/log(2.) <<endl; the output is L2error 0 = 0.00462991 L2error 1 = 0.00117128 convergence rate = 1.9829 times: compile 0.02s, execution 6.94s We find a rate of 1.93591, which is not close enough to the 3 predicted by the theory. The Geometry is always a polygon so we lose one order due to the geometry approximation in O(h 2 ) Now if you are not satisfied with the .eps plot generated by FreeFem++ and you want to use other graphic facilities, then you must store the solution in a file very much like in C++. It will be useless if you don’t save the triangulation as well, consequently you must do { ofstream ff("phi.txt"); ff << phi[]; } savemesh(Th,"Th.msh"); For the triangulation the name is important: it is the extension that determines the format. Still that may not take you where you want. Here is an interface with gnuplot to produce the right part of figure 3.2. // to build a gnuplot data file { ofstream ff("graph.txt"); for (int i=0;i<Th.nt;i++) { for (int j=0; j <3; j++) ff<<Th[i][j].x << " "<< Th[i][j].y<< " "<<phi[][Vh(i,j)]<<endl; ff<<Th[i][0].x << " "<< Th[i][0].y<< " "<<phi[][Vh(i,0)]<<"\n\n\n" } } We use the finite element numbering, where Wh(i,j) is the global index of j Th degrees of freedom of triangle number i. Then open gnuplot and do set palette rgbformulae 30,31,32 splot "graph.txt" w l pal This works with P2 and P1, but not with P1nc because the 3 first degrees of freedom of P2 or P2 are on vertices and not with P1nc. 24 CHAPTER 3. LEARNING BY EXAMPLES 3.2 Heat Exchanger Summary Here we shall learn more about geometry input and triangulation files, as well as read and write operations. The problem Let ¦C i ¦ 1,2 , be 2 thermal conductors within an enclosure C 0 . The first one is held at a constant temperature u 1 the other one has a given thermal conductivity κ 2 5 times larger than the one of C 0 . We assume that the border of enclosure C 0 is held at temperature 20 ◦ C and that we have waited long enough for thermal equilibrium. In order to know u(x) at any point x of the domain Ω, we must solve ∇ (κ∇u) = 0 in Ω, u |Γ = g where Ω is the interior of C 0 minus the conductors C 1 and Γ is the boundary of Ω, that is C 0 ∪C 1 Here g is any function of x equal to u i on C i . The second equation is a reduced form for: u = u i on C i , i = 0, 1. The variational formulation for this problem is in the subspace H 1 0 (Ω) ⊂ H 1 (Ω) of functions which have zero traces on Γ. u −g ∈ H 1 0 (Ω) : Ω ∇u∇v = 0 ∀v ∈ H 1 0 (Ω) Let us assume that C 0 is a circle of radius 5 centered at the origin, C i are rectangles, C 1 being at the constant temperature u 1 = 60 ◦ C. Example 3.3 (heatex.edp) // file heatex.edp int C1=99, C2=98; // could be anything such that = 0 and C1 = C2 border C0(t=0,2 * pi){x=5 * cos(t); y=5 * sin(t);} border C11(t=0,1){ x=1+t; y=3; label=C1;} border C12(t=0,1){ x=2; y=3-6 * t; label=C1;} border C13(t=0,1){ x=2-t; y=-3; label=C1;} border C14(t=0,1){ x=1; y=-3+6 * t; label=C1;} border C21(t=0,1){ x=-2+t; y=3; label=C2;} border C22(t=0,1){ x=-1; y=3-6 * t; label=C2;} border C23(t=0,1){ x=-1-t; y=-3; label=C2;} border C24(t=0,1){ x=-2; y=-3+6 * t; label=C2;} plot( C0(50) // to see the border of the domain + C11(5)+C12(20)+C13(5)+C14(20) + C21(-5)+C22(-20)+C23(-5)+C24(-20), wait=true, ps="heatexb.eps"); mesh Th=buildmesh( C0(50) + C11(5)+C12(20)+C13(5)+C14(20) + C21(-5)+C22(-20)+C23(-5)+C24(-20)); plot(Th,wait=1); 3.2. HEAT EXCHANGER 25 fespace Vh(Th,P1); Vh u,v; Vh kappa=1+2 * (x<-1) * (x>-2) * (y<3) * (y>-3); solve a(u,v)= int2d(Th)(kappa * (dx(u) * dx(v)+dy(u) * dy(v))) +on(C0,u=20)+on(C1,u=60); plot(u,wait=true, value=true, fill=true, ps="heatex.eps"); Note the following: • C0 is oriented counterclockwise by t, while C1 is oriented clockwise and C2 is oriented counterclockwise. This is why C1 is viewed as a hole by buildmesh. • C1 and C2 are built by joining pieces of straight lines. To group them in the same logical unit to input the boundary conditions in a readable way we assigned a label on the boundaries. As said earlier, borders have an internal number corresponding to their order in the program (check it by adding a cout<<C22; above). This is essential to understand how a mesh can be output to a file and re-read (see below). • As usual the mesh density is controlled by the number of vertices assigned to each boundary. It is not possible to change the (uniform) distribution of vertices but a piece of boundary can always be cut in two or more parts, for instance C12 could be replaced by C121+C122: // border C12(t=0,1) x=2; y=3-6 * t; label=C1; border C121(t=0,0.7){ x=2; y=3-6 * t; label=C1;} border C122(t=0.7,1){ x=2; y=3-6 * t; label=C1;} ... buildmesh(.../ * C12(20) * / + C121(12)+C122(8)+...); IsoValue 15.7895 22.1053 26.3158 30.5263 34.7368 38.9474 43.1579 47.3684 51.5789 55.7895 60 64.2105 68.4211 72.6316 76.8421 81.0526 85.2632 89.4737 93.6842 104.211 Figure 3.2: The heat exchanger Exercise Use the symmetry of the problem with respect to the axes; triangulate only one half of the domain, and set Dirichlet conditions on the vertical axis, and Neumann conditions on the horizontal axis. 26 CHAPTER 3. LEARNING BY EXAMPLES Writing and reading triangulation files Suppose that at the end of the previous program we added the line savemesh(Th,"condensor.msh"); and then later on we write a similar program but we wish to read the mesh from that file. Then this is how the condenser should be computed: mesh Sh=readmesh("condensor.msh"); fespace Wh(Sh,P1); Wh us,vs; solve b(us,vs)= int2d(Sh)(dx(us) * dx(vs)+dy(us) * dy(vs)) +on(1,us=0)+on(99,us=1)+on(98,us=-1); plot(us); Note that the names of the boundaries are lost but either their internal number (in the case of C0) or their label number (for C1 and C2) are kept. 3.3 Acoustics Summary Here we go to grip with ill posed problems and eigenvalue problems Pressure variations in air at rest are governed by the wave equation: ∂ 2 u ∂t 2 −c 2 ∆u = 0. When the solution wave is monochromatic (and that depend on the boundary and initial conditions), u is of the form u(x, t) = Re(v(x)e ikt ) where v is a solution of Helmholtz’s equation: k 2 v + c 2 ∆v = 0 in Ω, ∂v ∂n [ Γ = g. (3.1) where g is the source. Note the “+” sign in front of the Laplace operator and that k > 0 is real. This sign may make the problem ill posed for some values of c k , a phenomenon called “resonance”. At resonance there are non-zero solutions even when g = 0. So the following program may or may not work: Example 3.4 (sound.edp) // file sound.edp real kc2=1; func g=y * (1-y); border a0(t=0,1) { x= 5; y= 1+2 * t ;} border a1(t=0,1) { x=5-2 * t; y= 3 ;} border a2(t=0,1) { x= 3-2 * t; y=3-2 * t ;} border a3(t=0,1) { x= 1-t; y= 1 ;} border a4(t=0,1) { x= 0; y= 1-t ;} border a5(t=0,1) { x= t; y= 0 ;} border a6(t=0,1) { x= 1+4 * t; y= t ;} 3.4. THERMAL CONDUCTION 27 mesh Th=buildmesh( a0(20) + a1(20) + a2(20) + a3(20) + a4(20) + a5(20) + a6(20)); fespace Vh(Th,P1); Vh u,v; solve sound(u,v)=int2d(Th)(u * v * kc2 - dx(u) * dx(v) - dy(u) * dy(v)) - int1d(Th,a4)(g * v); plot(u, wait=1, ps="sound.eps"); Results are on Figure 3.3. But when kc2 is an eigenvalue of the problem, then the solution is not unique: if u e = 0 is an eigen state, then for any given solution u + u e is another a solution. To find all the u e one can do the following real sigma = 20; // value of the shift // OP = A - sigma B ; // the shifted matrix varf op(u1,u2)= int2d(Th)( dx(u1) * dx(u2) + dy(u1) * dy(u2) - sigma * u1 * u2 ); varf b([u1],[u2]) = int2d(Th)( u1 * u2 ) ; // no Boundary condition see note 9.1 matrix OP= op(Vh,Vh,solver=Crout,factorize=1); matrix B= b(Vh,Vh,solver=CG,eps=1e-20); int nev=2; // number of requested eigenvalues near sigma real[int] ev(nev); // to store the nev eigenvalue Vh[int] eV(nev); // to store the nev eigenvector int k=EigenValue(OP,B,sym=true,sigma=sigma,value=ev,vector=eV, tol=1e-10,maxit=0,ncv=0); cout<<ev(0)<<" 2 eigen values "<<ev(1)<<endl; v=eV[0]; plot(v,wait=1,ps="eigen.eps"); 3.4 Thermal Conduction Summary Here we shall learn how to deal with a time dependent parabolic problem. We shall also show how to treat an axisymmetric problem and show also how to deal with a nonlinear problem. How air cools a plate We seek the temperature distribution in a plate (0, Lx) (0, Ly) (0, Lz) of rectangular cross section Ω = (0, 6) (0, 1); the plate is surrounded by air at temperature u e and initially at temperature u = u 0 + x L u 1 . In the plane perpendicular to the plate at z = Lz/2, the temperature varies little with the coordinate z; as a first approximation the problem is 2D. We must solve the temperature equation in Ω in a time interval (0,T). ∂ t u −∇ (κ∇u) = 0 in Ω (0, T), u(x, y, 0) = u 0 + xu 1 κ ∂u ∂n + α(u −u e ) = 0 on Γ (0, T). (3.2) 28 CHAPTER 3. LEARNING BY EXAMPLES Figure 3.3: Left:Amplitude of an acoustic signal coming from the left vertical wall. Right: first eigen state (λ = (k/c) 2 = 19.4256) close to 20 of eigenvalue problem :−∆ϕ = λϕ and ∂ϕ ∂n = 0 on Γ Here the diffusion κ will take two values, one below the middle horizontal line and ten times less above, so as to simulate a thermostat. The term α(u − u e ) accounts for the loss of temperature by convection in air. Mathematically this boundary condition is of Fourier (or Robin, or mixed) type. The variational formulation is in L 2 (0, T; H 1 (Ω)); in loose terms and after applying an implicit Euler finite difference approximation in time; we shall seek u n (x, y) satisfying for all w ∈ H 1 (Ω): Ω ( u n −u n−1 δt w + κ∇u n ∇w) + Γ α(u n −u u e)w = 0 func u0 =10+90 * x/6; func k = 1.8 * (y<0.5)+0.2; real ue = 25, alpha=0.25, T=5, dt=0.1 ; mesh Th=square(30,5,[6 * x,y]); fespace Vh(Th,P1); Vh u=u0,v,uold; problem thermic(u,v)= int2d(Th)(u * v/dt + k * (dx(u) * dx(v) + dy(u) * dy(v))) + int1d(Th,1,3)(alpha * u * v) - int1d(Th,1,3)(alpha * ue * v) - int2d(Th)(uold * v/dt) + on(2,4,u=u0); ofstream ff("thermic.dat"); for(real t=0;t<T;t+=dt){ uold=u; // uold ≡ u n−1 = u n ≡u thermic; // here solve the thermic problem ff<<u(3,0.5)<<endl; 3.4. THERMAL CONDUCTION 29 plot(u); } Notice that we must separate by hand the bilinear part from the linear one. Notice also that the way we store the temperature at point (3,0.5) for all times in file thermic.dat. Should a one dimensional plot be required, the same procedure can be used. For instance to print x → ∂u ∂y (x, 0.9) one would do for(int i=0;i<20;i++) cout<<dy(u)(6.0 * i/20.0,0.9)<<endl; Results are shown on Figure 3.4. 34 36 38 40 42 44 46 48 50 52 54 56 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 "thermic.dat" Figure 3.4: Temperature at T=4.9. Right: decay of temperature versus time at x=3, y=0.5 3.4.1 Axisymmetry: 3D Rod with circular section Let us now deal with a cylindrical rod instead of a flat plate. For simplicity we take κ = 1. In cylindrical coordinates, the Laplace operator becomes (r is the distance to the axis, z is the distance along the axis, θ polar angle in a fixed plane perpendicular to the axis): ∆u = 1 r ∂ r (r∂ r u) + 1 r 2 ∂ 2 θθ u + ∂ 2 zz . Symmetry implies that we loose the dependence with respect to θ; so the domain Ω is again a rectangle ]0, R[]0, [[ . We take the convention of numbering of the edges as in square() (1 for the bottom horizontal ...); the problem is now: r∂ t u −∂ r (r∂ r u) −∂ z (r∂ z u) = 0 in Ω, u(t = 0) = u 0 + z L z (u 1 −u) u[ Γ 4 = u 0 , u[ Γ 2 = u 1 , α(u −u e ) + ∂u ∂n [ Γ 1 ∪Γ 3 = 0. (3.3) 30 CHAPTER 3. LEARNING BY EXAMPLES Note that the PDE has been multiplied by r. After discretization in time with an implicit scheme, with time steps dt, in the FreeFem++ syntax r becomes x and z becomes y and the problem is: problem thermaxi(u,v)=int2d(Th)((u * v/dt + dx(u) * dx(v) + dy(u) * dy(v)) * x) + int1d(Th,3)(alpha * x * u * v) - int1d(Th,3)(alpha * x * ue * v) - int2d(Th)(uold * v * x/dt) + on(2,4,u=u0); Notice that the bilinear form degenerates at x = 0. Still one can prove existence and uniqueness for u and because of this degeneracy no boundary conditions need to be imposed on Γ 1 . 3.4.2 A Nonlinear Problem : Radiation Heat loss through radiation is a loss proportional to the absolute temperature to the fourth power (Stefan’s Law). This adds to the loss by convection and gives the following boundary condition: κ ∂u ∂n + α(u −u e ) + c[(u + 273) 4 −(u e + 273) 4 ] = 0 The problem is nonlinear, and must be solved iteratively. If m denotes the iteration index, a semi-linearization of the radiation condition gives ∂u m+1 ∂n + α(u m+1 −u e ) + c(u m+1 −u e )(u m + u e + 546)((u m + 273) 2 + (u e + 273) 2 ) = 0, because we have the identity a 4 − b 4 = (a − b)(a + b)(a 2 + b 2 ). The iterative process will work with v = u −u e . ... fespace Vh(Th,P1); // finite element space real rad=1e-8, uek=ue+273; // def of the physical constants Vh vold,w,v=u0-ue,b; problem thermradia(v,w) = int2d(Th)(v * w/dt + k * (dx(v) * dx(w) + dy(v) * dy(w))) + int1d(Th,1,3)(b * v * w) - int2d(Th)(vold * w/dt) + on(2,4,v=u0-ue); for(real t=0;t<T;t+=dt){ vold=v; for(int m=0;m<5;m++){ b= alpha + rad * (v + 2 * uek) * ((v+uek)ˆ2 + uekˆ2); thermradia; } } vold=v+ue; plot(vold); 3.5 Irrotational Fan Blade Flow and Thermal effects Summary Here we will learn how to deal with a multi-physics system of PDEs on a Complex geometry, with multiple meshes within one problem. We also learn how to manipulate the region indicator and see how smooth is the projection operator from one mesh to another. 3.5. IRROTATIONAL FAN BLADE FLOW AND THERMAL EFFECTS 31 Incompressible flow Without viscosity and vorticity incompressible flows have a velocity given by: u = ∂ψ ∂x 2 − ∂ψ ∂x 1 , where ψ is solution of ∆ψ = 0 This equation expresses both incompressibility (∇u = 0) and absence of vortex (∇u = 0). As the fluid slips along the walls, normal velocity is zero, which means that ψ satisfies: ψ constant on the walls. One can also prescribe the normal velocity at an artificial boundary, and this translates into non constant Dirichlet data for ψ. Airfoil Let us consider a wing profile S in a uniform flow. Infinity will be represented by a large circle C where the flow is assumed to be of uniform velocity; one way to model this problem is to write ∆ψ = 0 in Ω, ψ[ S = 0, ψ[ C = u ∞ y, (3.4) where ∂Ω = C ∪ S The NACA0012 Airfoil An equation for the upper surface of a NACA0012 (this is a clas- sical wing profile in aerodynamics) is: y = 0.17735 √ x −0.075597x −0.212836x 2 + 0.17363x 3 −0.06254x 4 . Example 3.5 (potential.edp) // file potential.edp real S=99; border C(t=0,2 * pi) { x=5 * cos(t); y=5 * sin(t);} border Splus(t=0,1){ x = t; y = 0.17735 * sqrt(t)-0.075597 * t - 0.212836 * (tˆ2)+0.17363 * (tˆ3)-0.06254 * (tˆ4); label=S;} border Sminus(t=1,0){ x =t; y= -(0.17735 * sqrt(t)-0.075597 * t -0.212836 * (tˆ2)+0.17363 * (tˆ3)-0.06254 * (tˆ4)); label=S;} mesh Th= buildmesh(C(50)+Splus(70)+Sminus(70)); fespace Vh(Th,P2); Vh psi,w; solve potential(psi,w)=int2d(Th)(dx(psi) * dx(w)+dy(psi) * dy(w))+ on(C,psi = y) + on(S,psi=0); plot(psi,wait=1); A zoom of the streamlines are shown on Figure 3.5. 32 CHAPTER 3. LEARNING BY EXAMPLES IsoValue -10.9395 -3.12159 2.09037 7.30233 12.5143 17.7262 22.9382 28.1502 33.3621 38.5741 43.7861 48.998 54.21 59.4219 64.6339 69.8459 75.0578 80.2698 85.4817 98.5116 Figure 3.5: Zoom around the NACA0012 airfoil showing the streamlines (curve ψ = con- stant). To obtain such a plot use the interactive graphic command: “+” and p. Right: temperature distribution at time T=25 (now the maximum is at 90 instead of 120). Note that an incidence angle has been added here (see Chapter 9). 3.5.1 Heat Convection around the airfoil Now let us assume that the airfoil is hot and that air is there to cool it. Much like in the previous section the heat equation for the temperature v is ∂ t v −∇ (κ∇v) + u ∇v = 0, v(t = 0) = v 0 , ∂v ∂n [ C = 0 But now the domain is outside AND inside S and κ takes a different value in air and in steel. Furthermore there is convection of heat by the flow, hence the term u ∇v above. Consider the following, to be plugged at the end of the previous program: ... border D(t=0,2){x=1+t;y=0;} // added to have a fine mesh at trail mesh Sh = buildmesh(C(25)+Splus(-90)+Sminus(-90)+D(200)); fespace Wh(Sh,P1); Wh v,vv; int steel=Sh(0.5,0).region, air=Sh(-1,0).region; fespace W0(Sh,P0); W0 k=0.01 * (region==air)+0.1 * (region==steel); W0 u1=dy(psi) * (region==air), u2=-dx(psi) * (region==air); Wh vold = 120 * (region==steel); real dt=0.05, nbT=50; int i; problem thermic(v,vv,init=i,solver=LU)= int2d(Sh)(v * vv/dt + k * (dx(v) * dx(vv) + dy(v) * dy(vv)) + 10 * (u1 * dx(v)+u2 * dy(v)) * vv)- int2d(Sh)(vold * vv/dt); for(i=0;i<nbT;i++){ v=vold; thermic; 3.6. PURE CONVECTION : THE ROTATING HILL 33 plot(v); } Notice here • how steel and air are identified by the mesh parameter region which is defined when buildmesh is called and takes an integer value corresponding to each connected com- ponent of Ω; • how the convection terms are added without upwinding. Upwinding is necessary when the Pecley number [u[L/κ is large (here is a typical length scale), The factor 10 in front of the convection terms is a quick way of multiplying the velocity by 10 (else it is too slow to see something). • The solver is Gauss’ LU factorization and when init= 0 the LU decomposition is reused so it is much faster after the first iteration. 3.6 Pure Convection : The Rotating Hill Summary Here we will present two methods for upwinding for the simplest convection problem. We will learn about Characteristics-Galerkin and Discontinuous-Galerkin Finite Element Methods. Let Ω be the unit disk centered at 0; consider the rotation vector field u = [u1, u2], u 1 = y, u 2 = −x. Pure convection by u is ∂ t c +u.∇c = 0 in Ω (0, T) c(t = 0) = c 0 in Ω. The exact solution c(x t , t) at time t en point x t is given by c(x t , t) = c 0 (x, 0) where x t is the particle path in the flow starting at point x at time 0. So x t are solutions of ˙ x t = u(x t ), , x t=0 = x, where ˙ x t = d(t →x t ) dt The ODE are reversible and we want the solution at point x at time t ( not at point x t ) the initial point is x −t , and we have c(x, t) = c 0 (x −t , 0) The game consists in solving the equation until T = 2π, that is for a full revolution and to compare the final solution with the initial one; they should be equal. 34 CHAPTER 3. LEARNING BY EXAMPLES Solution by a Characteristics-Galerkin Method In FreeFem++ there is an operator called convect([u1,u2],dt,c) which compute c ◦ X with X is the convect field defined by X(x) = x dt and where x τ is particule path in the steady state velocity field u = [u1, u2] starting at point x at time τ = 0, so x τ is solution of the following ODE: ˙ x τ = u(x τ ), x τ=0 = x. When u is piecewise constant; this is possible because x τ is then a polygonal curve which can be computed exactly and the solution exists always when u is divergence free; convect returns c(x df ) = C ◦ X. Example 3.6 (convects.edp) // file convects.edp border C(t=0, 2 * pi) { x=cos(t); y=sin(t); }; mesh Th = buildmesh(C(100)); fespace Uh(Th,P1); Uh cold, c = exp(-10 * ((x-0.3)ˆ2 +(y-0.3)ˆ2)); real dt = 0.17,t=0; Uh u1 = y, u2 = -x; for (int m=0; m<2 * pi/dt ; m++) { t += dt; cold=c; c=convect([u1,u2],-dt,cold); plot(c,cmm=" t="+t + ", min=" + c[].min + ", max=" + c[].max); } Remark 4 3D plots can be done by adding the qualifyer ”dim=3” to the plot instruction. The method is very powerful but has two limitations: a/ it is not conservative, b/ it may diverge in rare cases when [u[ is too small due to quadrature error. Solution by Discontinuous-Galerkin FEM Discontinuous Galerkin methods take advantage of the discontinuities of c at the edges to build upwinding. There are may formulations possible. We shall implement here the so-called dual-P DC 1 formulation (see Ern[11]): Ω ( c n+1 −c n δt + u ∇c)w + E (α[n u[ − 1 2 n u)[c]w = E − Γ [n u[cw ∀w where E is the set of inner edges and E − Γ is the set of boundary edges where u n < 0 (in our case there is no such edges). Finally [c] is the jump of c across an edge with the convention that c + refers to the value on the right of the oriented edge. Example 3.7 (convects end.edp) // file convects.edp ... fespace Vh(Th,P1dc); Vh w, ccold, v1 = y, v2 = -x, cc = exp(-10 * ((x-0.3)ˆ2 +(y-0.3)ˆ2)); real u, al=0.5; dt = 0.05; 3.6. PURE CONVECTION : THE ROTATING HILL 35 macro n() (N.x * v1+N.y * v2) // Macro without parameter problem Adual(cc,w) = int2d(Th)((cc/dt+(v1 * dx(cc)+v2 * dy(cc))) * w) + intalledges(Th)((1-nTonEdge) * w * (al * abs(n)-n/2) * jump(cc)) // - int1d(Th,C)((n<0) * abs(n) * cc * w) // unused because cc=0 on ∂Ω − - int2d(Th)(ccold * w/dt); for ( t=0; t< 2 * pi ; t+=dt) { ccold=cc; Adual; plot(cc,fill=1,cmm="t="+t + ", min=" + cc[].min + ", max=" + cc[].max); }; real [int] viso=[-0.2,-0.1,0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1.1]; plot(c,wait=1,fill=1,ps="convectCG.eps",viso=viso); plot(c,wait=1,fill=1,ps="convectDG.eps",viso=viso); Notice the new keywords, intalledges to integrate on all edges of all triangles intalledges(Th) ≡ ¸ T∈Th ∂T (3.5) (so all internal edges are see two times ), nTonEdge which is one if the triangle has a boundary edge and zero otherwise, jump to implement [c]. Results of both methods are shown on Figure 3.6 with identical levels for the level line; this is done with the plot-modifier viso. Notice also the macro where the parameter u is not used (but the syntax needs one) and which ends with a //; it simply replaces the name n by (N.x * v1+N.y * v2). As easily guessed N.x,N.y is the normal to the edge. IsoValue -0.1 0 0.5 0.1 0.5 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.9 1 IsoValue -0.1 0 0.5 0.1 0.5 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.9 1 Figure 3.6: The rotated hill after one revolution, left with Characteristics-Galerkin, on the right with Discontinuous P 1 Galerkin FEM. Now if you think that DG is too slow try this 36 CHAPTER 3. LEARNING BY EXAMPLES // the same DG very much faster varf aadual(cc,w) = int2d(Th)((cc/dt+(v1 * dx(cc)+v2 * dy(cc))) * w) + intalledges(Th)((1-nTonEdge) * w * (al * abs(n)-n/2) * jump(cc)); varf bbdual(ccold,w) = - int2d(Th)(ccold * w/dt); matrix AA= aadual(Vh,Vh); matrix BB = bbdual(Vh,Vh); set (AA,init=t,solver=sparsesolver); Vh rhs=0; for ( t=0; t< 2 * pi ; t+=dt) { ccold=cc; rhs[] = BB * ccold[]; cc[] = AAˆ-1 * rhs[]; plot(cc,fill=0,cmm="t="+t + ", min=" + cc[].min + ", max=" + cc[].max); }; Notice the new keyword set to specify a solver in this framework; the modifier init is used to tel the solver that the matrix has not changed (init=true), and the name parameter are the same that in problem definition (see. 6.9) . Finite Volume Methods can also be handled with FreeFem++ but it requires program- ming. For instance the P 0 − P 1 Finite Volume Method of Dervieux et al associates to each P 0 function c 1 a P 0 function c 0 with constant value around each vertex q i equal to c 1 (q i ) on the cell σ i made by all the medians of all triangles having q i as vertex. Then upwinding is done by taking left or right values at the median: σ i 1 δt (c 1 n+1 −c 1 n ) + ∂σ i u nc − = 0 ∀i It can be programmed as load "mat_dervieux"; // external module in C++ must be loaded border a(t=0, 2 * pi){ x = cos(t); y = sin(t); } mesh th = buildmesh(a(100)); fespace Vh(th,P1); Vh vh,vold,u1 = y, u2 = -x; Vh v = exp(-10 * ((x-0.3)ˆ2 +(y-0.3)ˆ2)), vWall=0, rhs =0; real dt = 0.025; // qf1pTlump means mass lumping is used problem FVM(v,vh) = int2d(th,qft=qf1pTlump)(v * vh/dt) - int2d(th,qft=qf1pTlump)(vold * vh/dt) + int1d(th,a)(((u1 * N.x+u2 * N.y)<0) * (u1 * N.x+u2 * N.y) * vWall * vh) + rhs[] ; matrix A; MatUpWind0(A,th,vold,[u1,u2]); for ( int t=0; t< 2 * pi ; t+=dt){ vold=v; rhs[] = A * vold[] ; FVM; 3.7. A PROJECTION ALGORITHM FOR THE NAVIER-STOKES EQUATIONS 37 plot(v,wait=0); }; the mass lumping parameter forces a quadrature formula with Gauss points at the vertices so as to make the mass matrix diagonal; the linear system solved by a conjugate gradient method for instance will then converge in one or two iterations. The right hand side rhs is computed by an external C++ function MatUpWind0(...) which is programmed as // computes matrix a on a triangle for the Dervieux FVM int fvmP1P0(double q[3][2], // the 3 vertices of a triangle T double u[2], // convection velocity on T double c[3], // the P1 function on T double a[3][3], // output matrix double where[3] ) // where>0 means we’re on the boundary { for(int i=0;i<3;i++) for(int j=0;j<3;j++) a[i][j]=0; for(int i=0;i<3;i++){ int ip = (i+1)%3, ipp =(ip+1)%3; double unL =-((q[ip][1]+q[i][1]-2 * q[ipp][1]) * u[0] -(q[ip][0]+q[i][0]-2 * q[ipp][0]) * u[1])/6; if(unL>0) { a[i][i] += unL; a[ip][i]-=unL;} else{ a[i][ip] += unL; a[ip][ip]-=unL;} if(where[i]&&where[ip]){ // this is a boundary edge unL=((q[ip][1]-q[i][1]) * u[0] -(q[ip][0]-q[i][0]) * u[1])/2; if(unL>0) { a[i][i]+=unL; a[ip][ip]+=unL;} } } return 1; } It must be inserted into a larger .cpp file, shown in Appendix A, which is the load module linked to FreeFem++ . 3.7 A Projection Algorithm for the Navier-Stokes equations Summary Fluid flows require good algorithms and good triangultions. We show here an example of a complex algorithm and or first example of mesh adaptation. An incompressible viscous fluid satisfies: ∂ t u + u ∇u +∇p −ν∆u = 0, ∇ u = 0 in Ω]0, T[, u[ t=0 = u 0 , u[ Γ = u Γ . A possible algorithm, proposed by Chorin, is 1 δt [u m+1 −u m oX m ] +∇p m −ν∆u m = 0, u[ Γ = u Γ , −∆p m+1 = −∇ u m oX m , ∂ n p m+1 = 0, 38 CHAPTER 3. LEARNING BY EXAMPLES where uoX(x) = u(x −u(x)δt) since ∂ t u +u ∇u is approximated by the method of charac- teristics, as in the previous section. An improvement over Chorin’s algorithm, given by Rannacher, is to compute a correction, q, to the pressure (the overline denotes the mean over Ω) −∆q = ∇ u −∇ u and define u m+1 = ˜ u +∇qδt, p m+1 = p m −q −p m −q where ˜ u is the (u m+1 , v m+1 ) of Chorin’s algorithm. The backward facing step The geometry is that of a channel with a backward facing step so that the inflow section is smaller than the outflow section. This geometry produces a fluid recirculation zone that must be captured correctly. This can only be done if the triangulation is sufficiently fine, or well adapted to the flow. Remark (FH), The are a technical difficulty is the example, the discret flow flux must be 0 and in the previous version this is not the case, the correction is not so simple. Example 3.8 (NSprojection.edp) // file NSprojection.edp border a0(t=1,0){ x=0; y=t; label=1;} border a1(t=0,1){ x=2 * t; y=0; label=2;} border a2(t=0,1){ x=2; y=-t/2; label=2;} border a3(t=0,1){ x=2+18 * tˆ1.2; y=-0.5; label=2;} border a4(t=0,1){ x=20; y=-0.5+1.5 * t; label=3;} border a5(t=1,0){ x=20 * t; y=1; label=4;} int n=1; mesh Th= buildmesh(a0(3 * n)+a1(20 * n)+a2(10 * n)+a3(150 * n)+a4(5 * n)+a5(100 * n)); plot(Th); fespace Vh(Th,P1); real nu = 0.0025, dt = 0.2; // Reynolds=200 func uBCin = 4 * y * (1-y) * (y>0) * (x<2) ; func uBCout = 4./1.5 * (y+0.5) * (1-y) * (x>19); Vh w,u = uBCin, v =0, p = 0, q=0; real area= int2d(Th)(1.); Vh ubc = uBCin + uBCout; real influx0 = int1d(Th,1) (ubc * N.x), // FH add outflux0 = int1d(Th,3) (ubc * N.x); // FH add verbosity=1; for(int n=0;n<300;n++){ Vh uold = u, vold = v, pold=p; Vh f=convect([uold,vold],-dt,uold); real outflux = int1d(Th,3) (f * N.x); // FH add f = f - (influx0+outflux)/outflux0 * uBCout; // FH add outflux = int1d(Th,3) (f * N.x); // FH add assert( abs(influx0+outflux) < 1e-10); // WARNING the flux must be 0 .. solve pb4u(u,w,init=n,solver=LU) =int2d(Th)(u * w/dt +nu * (dx(u) * dx(w)+dy(u) * dy(w))) 3.7. A PROJECTION ALGORITHM FOR THE NAVIER-STOKES EQUATIONS 39 -int2d(Th)((convect([uold,vold],-dt,uold)/dt-dx(p)) * w) + on(1,u = 4 * y * (1-y)) + on(2,4,u = 0) + on(3,u=f); plot(u); solve pb4v(v,w,init=n,solver=LU) = int2d(Th)(v * w/dt +nu * (dx(v) * dx(w)+dy(v) * dy(w))) -int2d(Th)((convect([uold,vold],-dt,vold)/dt-dy(p)) * w) +on(1,2,3,4,v = 0); real meandiv = int2d(Th)(dx(u)+dy(v))/area; solve pb4p(q,w,init=n,solver=LU)= int2d(Th)(dx(q) * dx(w)+dy(q) * dy(w)) - int2d(Th)((dx(u)+ dy(v)-meandiv) * w/dt)+ on(3,q=0); real meanpq = int2d(Th)(pold - q)/area; if(n%50==49){ Th = adaptmesh(Th,[u,v],q,err=0.04,nbvx=100000); plot(Th, wait=true); ubc = uBCin + uBCout; // reinterpolate B.C. influx0 = int1d(Th,1) (ubc * N.x); // FH add outflux0 = int1d(Th,3) (ubc * N.x); // FH add } p = pold-q-meanpq; u = u + dx(q) * dt; v = v + dy(q) * dt; real err = sqrt(int2d(Th)(square(u-uold)+square(v-vold))/Th.area) ; cout << " iter " << n << " Err L2 = " << err << endl; if(err < 1e-3) break; } plot(p,wait=1,ps="NSprojP.eps"); plot(u,wait=1,ps="NSprojU.eps"); Figure 3.7: Rannacher’s projection algorithm: result on an adapted mesh (top) showing the pressure (middle) and the horizontal velocity u at Reynolds 400. We show in figure 3.7 the numerical results obtained for a Reynolds number of 400 where mesh adaptation is done after 50 iterations on the first mesh. 40 CHAPTER 3. LEARNING BY EXAMPLES 3.8 The System of elasticity Elasticity Solid objects deform under the action of applied forces: a point in the solid, originally at (x, y, z) will come to (X, Y, Z) after some time; the vector u = (u 1 , u 2 , u 3 ) = (X − x, Y − y, Z − z) is called the displacement. When the displacement is small and the solid is elastic, Hooke’s law gives a relationship between the stress tensor σ(u) = (σ ij (u)) and the strain tensor (u) = ij (u) σ ij (u) = λδ ij ∇.u + 2µ ij (u), where the Kronecker symbol δ ij = 1 if i = j, 0 otherwise, with ij (u) = 1 2 ( ∂u i ∂x j + ∂u j ∂x i ), and where λ, µ are two constants that describe the mechanical properties of the solid, and are themselves related to the better known constants E, Young’s modulus, and ν, Poisson’s ratio: µ = E 2(1 + ν) , λ = Eν (1 + ν)(1 −2ν) . Lam´e’s system Let us consider a beam with axis Oz and with perpendicular section Ω. The components along x and y of the strain u(x) in a section Ω subject to forces f perpendicular to the axis are governed by −µ∆u −(µ + λ)∇(∇.u) = f in Ω, where λ, µ are the Lam´e coefficients introduced above. Remark, we do not used this equation because the associated variationnal form does not give the right boundary condition, we simply use −div(σ) = f inΩ where the corresponding variationnal form is: Ω σ(u) : (v) dx − Ω vf dx = 0; where : denote the tensor scalar product, i.e. a : b = ¸ i,j a ij b ij . So the variationnal form can be written as : Ω λ∇.u∇.v + 2µ(u) : (v) dx − Ω vf dx = 0; Example Consider elastic plate with the undeformed rectangle shape [0, 20] [−1, 1]. The body force is the gravity force f and the boundary force g is zero on lower, upper and right sides. The left vertical sides of the beam is fixed. The boundary conditions are σ.n = g = 0 on Γ 1 , Γ 4 , Γ 3 , u = 0 on Γ 2 3.8. THE SYSTEM OF ELASTICITY 41 Here u = (u, v) has two components. The above two equations are strongly coupled by their mixed derivatives, and thus any iterative solution on each of the components is risky. One should rather use FreeFem++ ’s system approach and write: Example 3.9 (lame.edp) // file lame.edp mesh Th=square(10,10,[20 * x,2 * y-1]); fespace Vh(Th,P2); Vh u,v,uu,vv; real sqrt2=sqrt(2.); macro epsilon(u1,u2) [dx(u1),dy(u2),(dy(u1)+dx(u2))/sqrt2] // EOM // the sqrt2 is because we want: epsilon(u1,u2)’ * epsilon(v1,v2) == (u) : (v) macro div(u,v) ( dx(u)+dy(v) ) // EOM real E = 21e5, nu = 0.28, mu= E/(2 * (1+nu)); real lambda = E * nu/((1+nu) * (1-2 * nu)), f = -1; // solve lame([u,v],[uu,vv])= int2d(Th)( lambda * div(u,v) * div(uu,vv) +2. * mu * ( epsilon(u,v)’ * epsilon(uu,vv) ) ) - int2d(Th)(f * vv) + on(4,u=0,v=0); real coef=100; plot([u,v],wait=1,ps="lamevect.eps",coef=coef); mesh th1 = movemesh(Th, [x+u * coef, y+v * coef]); plot(th1,wait=1,ps="lamedeform.eps"); real dxmin = u[].min; real dymin = v[].min; cout << " - dep. max x = "<< dxmin<< " y=" << dymin << endl; cout << " dep. (20,0) = " << u(20,0) << " " << v(20,0) << endl; The numerical results are shown on figure 3.8 and the output is: -- square mesh : nb vertices =121 , nb triangles = 200 , nb boundary edges 40 -- Solve : min -0.00174137 max 0.00174105 min -0.0263154 max 1.47016e-29 - dep. max x = -0.00174137 y=-0.0263154 dep. (20,0) = -1.8096e-07 -0.0263154 times: compile 0.010219s, execution 1.5827s 42 CHAPTER 3. LEARNING BY EXAMPLES Figure 3.8: Solution of Lam´e’s equations for elasticity for a 2D beam deflected by its own weight and clamped by its left vertical side; result are shown with a amplification factor equal to 100. Remark: the size of the arrow is automatically bound, but the color gives the real length 3.9 The System of Stokes for Fluids In the case of a flow invariant with respect to the third coordinate (two-dimensional flow), flows at low Reynolds number (for instance micro-organisms) satisfy, −∆u +∇p = 0 ∇ u = 0 where u = (u 1 , u 2 ) is the fluid velocity and p its pressure. The driven cavity is a standard test. It is a box full of liquid with its lid moving horizontally at speed one. The pressure and the velocity must be discretized in compatible fintie element spaces for the LBB conditions to be satisfied: sup p∈P h (u, ∇p) [p[ ≥ β[u[ ∀u ∈ U h // file stokes.edp int n=3; mesh Th=square(10 * n,10 * n); fespace Uh(Th,P1b); Uh u,v,uu,vv; fespace Ph(Th,P1); Ph p,pp; solve stokes([u,v,p],[uu,vv,pp]) = int2d(Th)(dx(u) * dx(uu)+dy(u) * dy(uu) + dx(v) * dx(vv)+ dy(v) * dy(vv) + dx(p) * uu + dy(p) * vv + pp * (dx(u)+dy(v)) - 1e-10*p*pp) 3.10. A LARGE FLUID PROBLEM 43 + on(1,2,4,u=0,v=0) + on(3,u=1,v=0); plot([u,v],p,wait=1); Remark, we add a stabilization term -10e-10*p*pp to fixe the constant part of the pressure. Figure 3.9: Solution of Stokes’ equations for the driven cavity problem, showing the velocity field and the pressure level lines. Results are shown on figure 3.9 3.10 A Large Fluid Problem A friend of one of us in Auroville-India was building a ramp to access an air conditioned room. As I was visiting the construction site he told me that he expected to cool air escaping by the door to the room to slide down the ramp and refrigerate the feet of the coming visitors. I told him ”no way” and decided to check numerically. The results are on the front page of this book. The fluid velocity and pressure are solution of the Navier-Stokes equations with varying density function of the temperature. The geometry is trapezoidal with prescribed inflow made of cool air at the bottom and warm air above and so are the initial conditions; there is free outflow, slip velocity at the top (artificial) boundary and no-slip at the bottom. However the Navier-Stokes cum temperature equations have a RANS k − model and a Boussinesq approximation for the buoyancy. This comes to ∂ t θ + u∇θ −∇ (κ m T ∇θ) = 0 ∂ t u + u∇u −∇ (µ T ∇u) +∇p + e(θ −θ 0 )e 2 , ∇ u = 0 µ T = c µ k 2 , κ T = κµ T ∂ t k + u∇k + −∇ (µ T ∇k) = µ T 2 [∇u +∇u T [ 2 44 CHAPTER 3. LEARNING BY EXAMPLES ∂ t + u∇ + c 2 2 k − c c µ ∇ (µ T ∇) = c 1 2 k[∇u +∇u T [ 2 = 0 (3.6) We use a time discretization which preserves positivity and uses the method of characteristics (X m (x) ≈ x −u m (x)δt) 1 δt (θ m+1 −θ m ◦ X m ) −∇ (κ m T ∇θ m+1 ) = 0 1 δt (u m+1 −u m ◦ X m ) −∇ (µ m T ∇u m+1 ) +∇p m+1 + e(θ m+1 −θ 0 )e 2 , ∇ u m+1 = 0 1 δt (k m+1 −k m ◦ X m ) + k m+1 m k m −∇ (µ m T ∇k m+1 ) = µ m T 2 [∇u m +∇u mT [ 2 1 δt ( m+1 − m ◦ X m ) + c 2 m+1 m k m − c c µ ∇ ˙ (µ m T ∇ m+1 ) = c 1 2 k m [∇u m +∇u mT [ 2 µ m+1 T = c µ k m+1 2 m+1 , κ m+1 T = κµ m+1 T (3.7) In variational form and with appropriated boundary conditions the problem is: real L=6; border aa(t=0,1){x=t; y=0 ;} border bb(t=0,14){x=1+t; y= - 0.1 * t ;} border cc(t=-1.4,L){x=15; y=t ;} border dd(t=15,0){x= t ; y = L;} border ee(t=L,0.5){ x=0; y=t ;} border ff(t=0.5,0){ x=0; y=t ;} int n=8; mesh Th=buildmesh(aa(n)+bb(9 * n) + cc(4 * n) + dd(10 * n)+ee(6 * n) + ff(n)); real s0=clock(); fespace Vh2(Th,P1b); // velocity space fespace Vh(Th,P1); // pressure space fespace V0h(Th,P0); // for gradients Vh2 u2,v2,up1=0,up2=0; Vh2 u1,v1; Vh u1x=0,u1y,u2x,u2y, vv; real reylnods=500; // cout << " Enter the reynolds number :"; cin >> reylnods; assert(reylnods>1 && reylnods < 100000); up1=0; up2=0; func g=(x) * (1-x) * 4; // inflow Vh p=0,q, temp1,temp=35, k=0.001,k1,ep=0.0001,ep1; V0h muT=1,prodk,prode, kappa=0.25e-4, stress; real alpha=0, eee=9.81/303, c1m = 1.3/0.09 ; real nu=1, numu=nu/sqrt( 0.09), nuep=pow(nu,1.5)/4.1; int i=0,iter=0; real dt=0; problem TEMPER(temp,q) = // temperature equation int2d(Th)( alpha * temp * q + kappa * ( dx(temp) * dx(q) + dy(temp) * dy(q) )) // + int1d(Th,aa,bb)(temp * q * 0.1) + int2d(Th) ( -alpha * convect([up1,up2],-dt,temp1) * q ) + on(ff,temp=25) 3.10. A LARGE FLUID PROBLEM 45 + on(aa,bb,temp=35) ; problem kine(k,q)= // get the kinetic turbulent energy int2d(Th)( (ep1/k1+alpha) * k * q + muT * ( dx(k) * dx(q) + dy(k) * dy(q) )) // + int1d(Th,aa,bb)(temp * q * 0.1) + int2d(Th) ( prodk * q-alpha * convect([up1,up2],-dt,k1) * q ) + on(ff,k=0.0001) + on(aa,bb,k=numu * stress) ; problem viscturb(ep,q)= // get the rate of turbulent viscous energy int2d(Th)( (1.92 * ep1/k1+alpha) * ep * q + c1m * muT * ( dx(ep) * dx(q) + dy(ep) * dy(q) )) // + int1d(Th,aa,bb)(temp * q * 0.1) + int2d(Th) ( prode * q-alpha * convect([up1,up2],-dt,ep1) * q ) + on(ff,ep= 0.0001) + on(aa,bb,ep=nuep * pow(stress,1.5)) ; solve NS ([u1,u2,p],[v1,v2,q]) = // Navier-Stokes k-epsilon and Boussinesq int2d(Th)( alpha * ( u1 * v1 + u2 * v2) + muT * (dx(u1) * dx(v1)+dy(u1) * dy(v1)+dx(u2) * dx(v2)+dy(u2) * dy(v2)) // ( 2 * dx(u1) * dx(v1) + 2 * dy(u2) * dy(v2)+(dy(u1)+dx(u2)) * (dy(v1)+dx(v2))) + p * q * (0.000001) - p * dx(v1) - p * dy(v2) - dx(u1) * q - dy(u2) * q ) + int1d(Th,aa,bb,dd)(u1 * v1 * 0.1) + int2d(Th) (eee * (temp-35) * v1 -alpha * convect([up1,up2],-dt,up1) * v1 -alpha * convect([up1,up2],-dt,up2) * v2 ) + on(ff,u1=3,u2=0) + on(ee,u1=0,u2=0) + on(aa,dd,u2=0) + on(bb,u2= -up1 * N.x/N.y) + on(cc,u2=0) ; plot(coef=0.2,cmm=" [u1,u2] et p ",p,[u1,u2],ps="StokesP2P1.eps",value=1,wait=1); { real[int] xx(21),yy(21),pp(21); for (int i=0;i<21;i++) { yy[i]=i/20.; xx[i]=u1(0.5,i/20.); pp[i]=p(i/20.,0.999); } cout << " " << yy << endl; // plot([xx,yy],wait=1,cmm="u1 x=0.5 cup"); // plot([yy,pp],wait=1,cmm="pressure y=0.999 cup"); } dt = 0.05; int nbiter = 3; real coefdt = 0.25ˆ(1./nbiter); real coefcut = 0.25ˆ(1./nbiter) , cut=0.01; real tol=0.5,coeftol = 0.5ˆ(1./nbiter); nu=1./reylnods; 46 CHAPTER 3. LEARNING BY EXAMPLES for (iter=1;iter<=nbiter;iter++) { cout << " dt = " << dt << " ------------------------ " << endl; alpha=1/dt; for (i=0;i<=500;i++) { up1=u1; up2=u2; temp1=max(temp,25); temp1=min(temp1,35); k1=k; ep1=ep; muT=0.09 * k * k/ep; NS; plot([u1,u2],wait=1); // Solves Navier-Stokes prode =0.126 * k * (pow(2 * dx(u1),2)+pow(2 * dy(u2),2)+2 * pow(dx(u2)+dy(u1),2))/2; prodk= prode * k/ep * 0.09/0.126; kappa=muT/0.41; stress=abs(dy(u1)); kine; plot(k,wait=1); viscturb; plot(ep,wait=1); TEMPER; // solves temperature equation if ( !(i % 5)){ plot(temp,value=1,fill=true,ps="temp_"+iter+"_"+i+".ps"); plot(coef=0.2,cmm=" [u1,u2] et p ",p,[u1,u2],ps="plotNS_"+iter+"_"+i+".ps"); } cout << "CPU " << clock()-s0 << "s " << endl; } if (iter>= nbiter) break; Th=adaptmesh(Th,[dx(u1),dy(u1),dx(u1),dy(u2)],splitpbedge=1, abserror=0,cutoff=cut,err=tol, inquire=0,ratio=1.5,hmin=1./1000); plot(Th,ps="ThNS.eps"); dt = dt * coefdt; tol = tol * coeftol; cut = cut * coefcut; } cout << "CPU " <<clock()-s0 << "s " << endl; 3.11 An Example with Complex Numbers In a microwave oven heat comes from molecular excitation by an electromagnetic field. For a plane monochromatic wave, amplitude is given by Helmholtz’s equation: βv + ∆v = 0. We consider a rectangular oven where the wave is emitted by part of the upper wall. So the boundary of the domain is made up of a part Γ 1 where v = 0 and of another part Γ 2 = [c, d] where for instance v = sin(π y−c c−d ). Within an object to be cooked, denoted by B, the heat source is proportional to v 2 . At equilibrium, one has −∆θ = v 2 I B , θ Γ = 0 where I B is 1 in the object and 0 elsewhere. 3.11. AN EXAMPLE WITH COMPLEX NUMBERS 47 Figure 3.10: A microwave oven: real (left) and imaginary (middle) parts of wave and tem- perature (right). Results are shown on figure 3.10 In the program below β = 1/(1 −I/2) in the air and 2/(1 −I/2) in the object (i = √ −1): Example 3.10 (muwave.edp) // file muwave.edp real a=20, b=20, c=15, d=8, e=2, l=12, f=2, g=2; border a0(t=0,1) {x=a * t; y=0;label=1;} border a1(t=1,2) {x=a; y= b * (t-1);label=1;} border a2(t=2,3) { x=a * (3-t);y=b;label=1;} border a3(t=3,4){x=0;y=b-(b-c) * (t-3);label=1;} border a4(t=4,5){x=0;y=c-(c-d) * (t-4);label=2;} border a5(t=5,6){ x=0; y= d * (6-t);label=1;} border b0(t=0,1) {x=a-f+e * (t-1);y=g; label=3;} border b1(t=1,4) {x=a-f; y=g+l * (t-1)/3; label=3;} border b2(t=4,5) {x=a-f-e * (t-4); y=l+g; label=3;} border b3(t=5,8) {x=a-e-f; y= l+g-l * (t-5)/3; label=3;} int n=2; mesh Th = buildmesh(a0(10 * n)+a1(10 * n)+a2(10 * n)+a3(10 * n) +a4(10 * n)+a5(10 * n)+b0(5 * n)+b1(10 * n)+b2(5 * n)+b3(10 * n)); plot(Th,wait=1); fespace Vh(Th,P1); real meat = Th(a-f-e/2,g+l/2).region, air= Th(0.01,0.01).region; Vh R=(region-air)/(meat-air); Vh<complex> v,w; solve muwave(v,w) = int2d(Th)(v * w * (1+R) -(dx(v) * dx(w)+dy(v) * dy(w)) * (1-0.5i)) + on(1,v=0) + on(2, v=sin(pi * (y-c)/(c-d))); Vh vr=real(v), vi=imag(v); plot(vr,wait=1,ps="rmuonde.ps", fill=true); plot(vi,wait=1,ps="imuonde.ps", fill=true); fespace Uh(Th,P1); Uh u,uu, ff=1e5 * (vrˆ2 + viˆ2) * R; solve temperature(u,uu)= int2d(Th)(dx(u) * dx(uu)+ dy(u) * dy(uu)) - int2d(Th)(ff * uu) + on(1,2,u=0); 48 CHAPTER 3. LEARNING BY EXAMPLES plot(u,wait=1,ps="tempmuonde.ps", fill=true); 3.12 Optimal Control Thanks to the function BFGS it is possible to solve complex nonlinear optimization problem within FreeFem++. For example consider the following inverse problem min b,c,d∈R J = E (u −u d ) 2 : −∇(κ(b, c, d) ∇u) = 0, u[ Γ = u Γ where the desired state u d , the boundary data u Γ and the observation set E ⊂ Ω are all given. Furthermore let us assume that κ(x) = 1 + bI B (x) + cI C (x) + dI D (x) ∀x ∈ Ω where B, C, D are separated subsets of Ω. To solve this problem by the quasi-Newton BFGS method we need the derivatives of J with respect to b, c, d. We self explanatory notations, if δb, δc, δd are variations of b, c, d we have δJ ≈ 2 E (u −u d )δu, −∇(κ ∇δu) ≈ ∇(δκ ∇u) δu[ Γ = 0 Obviously J b is equal to δJ when δb = 1, δc = 0, δd = 0, and so on for J c and J d . All this is implemented in the following program // file optimcontrol.edp border aa(t=0, 2 * pi) { x = 5 * cos(t); y = 5 * sin(t); }; border bb(t=0, 2 * pi) { x = cos(t); y = sin(t); }; border cc(t=0, 2 * pi) { x = -3+cos(t); y = sin(t); }; border dd(t=0, 2 * pi) { x = cos(t); y = -3+sin(t); }; mesh th = buildmesh(aa(70)+bb(35)+cc(35)+dd(35)); fespace Vh(th,P1); Vh Ib=((xˆ2+yˆ2)<1.0001), Ic=(((x+3)ˆ2+ yˆ2)<1.0001), Id=((xˆ2+(y+3)ˆ2)<1.0001), Ie=(((x-1)ˆ2+ yˆ2)<=4), ud,u,uh,du; real[int] z(3); problem A(u,uh) =int2d(th)((1+z[0] * Ib+z[1] * Ic+z[2] * Id) * (dx(u) * dx(uh) +dy(u) * dy(uh))) + on(aa,u=xˆ3-yˆ3); z[0]=2; z[1]=3; z[2]=4; A; ud=u; ofstream f("J.txt"); func real J(real[int] & Z) { for (int i=0;i<z.n;i++)z[i]=Z[i]; A; real s= int2d(th)(Ie * (u-ud)ˆ2); f<<s<<" "; return s; } 3.12. OPTIMAL CONTROL 49 real[int] dz(3), dJdz(3); problem B(du,uh) =int2d(th)((1+z[0] * Ib+z[1] * Ic+z[2] * Id) * (dx(du) * dx(uh)+dy(du) * dy(uh))) +int2d(th)((dz[0] * Ib+dz[1] * Ic+dz[2] * Id) * (dx(u) * dx(uh)+dy(u) * dy(uh))) +on(aa,du=0); func real[int] DJ(real[int] &Z) { for(int i=0;i<z.n;i++) { for(int j=0;j<dz.n;j++) dz[j]=0; dz[i]=1; B; dJdz[i]= 2 * int2d(th)(Ie * (u-ud) * du); } return dJdz; } real[int] Z(3); for(int j=0;j<z.n;j++) Z[j]=1; BFGS(J,DJ,Z,eps=1.e-6,nbiter=15,nbiterline=20); cout << "BFGS: J(z) = " << J(Z) << endl; for(int j=0;j<z.n;j++) cout<<z[j]<<endl; plot(ud,value=1,ps="u.eps"); In this example the sets B, C, D, E are circles of boundaries bb, cc, dd, ee are the domain Ω is the circle of boundary aa. The desired state u d is the solution of the PDE for b = 2, c = 3, d = 4. The unknowns are packed into array z. Notice that it is necessary to recopy Z into z because one is a local variable while the other one is global. The program found b = 2.00125, c = 3.00109, d = 4.00551. Figure 3.11 shows u at convergence and the successive function evaluations of J. Note that an adjoint state could have been used. Define p by IsoValue -118.75 -106.25 -93.75 -81.25 -68.75 -56.25 -43.75 -31.25 -18.75 -6.25 6.25 18.75 31.25 43.75 56.25 68.75 81.25 93.75 106.25 118.75 0 5 10 15 20 25 30 35 40 45 0 5 10 15 20 25 30 35 "J.txt" Figure 3.11: On the left the level lines of u. On the right the successive evaluations of J by BFGS (5 values above 500 have been removed for readability) −∇ (κ∇p) = 2I E (u −u d ), p[ Γ = 0 Consequently δJ = − Ω (∇ (κ∇p))δu 50 CHAPTER 3. LEARNING BY EXAMPLES = Ω (κ∇p ∇δu) = − Ω (δκ∇p ∇u) (3.8) Then the derivatives are found by setting δb = 1, δc = δd = 0 and so on: J b = − B ∇p ∇u, J c = − C ∇p ∇u, J d = − D ∇p ∇u Remark As BFGS stores an M M matrix where M is the number of unknowns, it is dangerously expensive to use this method when the unknown x is a Finite Element Function. One should use another optimizer such as the NonLinear Conjugate Gradient NLCG (also a key word of FreeFem++). See the file algo.edp in the examples folder. 3.13 A Flow with Shocks Compressible Euler equations should be discretized with Finite Volumes or FEM with flux up-winding scheme but these are not implemented in FreeFem++ . Nevertheless acceptable results can be obtained with the method of characteristics provided that the mean values ¯ f = 1 2 (f + + f − ) are used at shocks in the scheme, and finally mesh adaptation . ∂ t ρ + ¯ u∇ρ + ¯ ρ∇ u = 0 ¯ ρ(∂ t u + ρu ¯ ρ ∇u +∇p = 0 ∂ t p + ¯ u∇p + (γ −1)¯ p∇ u = 0 (3.9) One possibility is to couple u, p and then update ρ, i.e. 1 (γ −1)δt¯ p m (p m+1 −p m ◦ X m ) +∇ u m+1 = 0 ¯ ρ m δt (u m+1 −u m ◦ ˜ X m ) +∇p m+1 = 0 ρ m+1 = ρ m ◦ X m + ¯ ρ m (γ −1)¯ p m (p m+1 −p m ◦ X m ) (3.10) A numerical result is given on Figure 3.12 and the FreeFem++ script is verbosity=1; int anew=1; real x0=0.5,y0=0, rr=0.2; border ccc(t=0,2){x=2-t;y=1;}; border ddd(t=0,1){x=0;y=1-t;}; border aaa1(t=0,x0-rr){x=t;y=0;}; border cercle(t=pi,0){ x=x0+rr * cos(t);y=y0+rr * sin(t);} border aaa2(t=x0+rr,2){x=t;y=0;}; border bbb(t=0,1){x=2;y=t;}; int m=5; mesh Th; if(anew) Th = buildmesh (ccc(5 * m) +ddd(3 * m) + aaa1(2 * m) + cercle(5 * m) + aaa2(5 * m) + bbb(2 * m) ); else Th = readmesh("Th_circle.mesh"); plot(Th,wait=0); 3.13. A FLOW WITH SHOCKS 51 IsoValue 0.0714186 0.212634 0.35385 0.495066 0.636282 0.777498 0.918714 1.05993 1.20115 1.34236 1.48358 1.62479 1.76601 1.90722 2.04844 2.18966 2.33087 2.47209 2.6133 2.75452 Figure 3.12: Pressure for a Euler flow around a disk at Mach 2 computed by (3.10) real dt=0.01, u0=2, err0=0.00625, pena=2; fespace Wh(Th,P1); fespace Vh(Th,P1); Wh u,v,u1,v1,uh,vh; Vh r,rh,r1; macro dn(u) (N.x * dx(u)+N.y * dy(u) ) // def the normal derivative if(anew){ u1= u0; v1= 0; r1 = 1;} else { ifstream g("u.txt");g>>u1[]; ifstream gg("v.txt");gg>>v1[]; ifstream ggg("r.txt");ggg>>r1[]; plot(u1,ps="eta.eps", value=1,wait=1); err0=err0/10; dt = dt/10; } problem eul(u,v,r,uh,vh,rh) = int2d(Th)( (u * uh+v * vh+r * rh)/dt + ((dx(r) * uh+ dy(r) * vh) - (dx(rh) * u + dy(rh) * v)) ) + int2d(Th)(-(rh * convect([u1,v1],-dt,r1) + uh * convect([u1,v1],-dt,u1) + vh * convect([u1,v1],-dt,v1))/dt) +int1d(Th,6)(rh * u) // +int1d(Th,1)(rh * v) + on(2,r=0) + on(2,u=u0) + on(2,v=0); int j=80; for(int k=0;k<3;k++) { 52 CHAPTER 3. LEARNING BY EXAMPLES if(k==20){ err0=err0/10; dt = dt/10; j=5;} for(int i=0;i<j;i++){ eul; u1=u; v1=v; r1=abs(r); cout<<"k="<<k<<" E="<<int2d(Th)(uˆ2+vˆ2+r)<<endl; plot(r,wait=0,value=1); } Th = adaptmesh (Th,r, nbvx=40000,err=err0, abserror=1,nbjacoby=2, omega=1.8,ratio=1.8, nbsmooth=3, splitpbedge=1, maxsubdiv=5,rescaling=1) ; plot(Th,wait=0); u=u;v=v;r=r; savemesh(Th,"Th_circle.mesh"); ofstream f("u.txt");f<<u[]; ofstream ff("v.txt");ff<<v[]; ofstream fff("r.txt");fff<<r[]; r1 = sqrt(u * u+v * v); plot(r1,ps="mach.eps", value=1); r1=r; } 3.14 Classification of the equations Summary It is usually not easy to determine the type of a system. Yet the approximations and algorithms suited to the problem depend on its type: • Finite Elements compatible (LBB conditions) for elliptic systems • Finite difference on the parabolic variable and a time loop on each elliptic subsystem of parabolic systems; better stability diagrams when the schemes are implicit in time. • Upwinding, Petrov-Galerkin, Characteristics-Galerkin, Discontinuous-Galerkin, Finite Volumes for hyperbolic systems plus, possibly, a time loop. When the system changes type, then expect difficulties (like shock discontinuities)! Elliptic, parabolic and hyperbolic equations A partial differential equation (PDE) is a relation between a function of several variables and its derivatives. F(ϕ(x), ∂ϕ ∂x 1 (x), , ∂ϕ ∂x d (x), ∂ 2 ϕ ∂x 2 1 (x), , ∂ m ϕ ∂x m d (x)) = 0 ∀x ∈ Ω ⊂ { d . The range of x over which the equation is taken, here Ω, is called the domain of the PDE. The highest derivation index, here m, is called the order. If F and ϕ are vector valued functions, then the PDE is actually a system of PDEs. Unless indicated otherwise, here by convention one PDE corresponds to one scalar valued F and ϕ. If F is linear with respect to its arguments, then the PDE is said to be linear. The general form of a second order, linear scalar PDE is ∂ 2 ϕ ∂x i ∂x j and A : B means ¸ d i,j=1 a ij b ij . αϕ + a ∇ϕ + B : ∇(∇ϕ) = f in Ω ⊂ { d , 3.14. CLASSIFICATION OF THE EQUATIONS 53 where f(x), α(x) ∈ {, a(x) ∈ { d , B(x) ∈ { d×d are the PDE coefficients. If the coefficients are independent of x, the PDE is said to have constant coefficients. To a PDE we associate a quadratic form, by replacing ϕ by 1, ∂ϕ/∂x i by z i and ∂ 2 ϕ/∂x i ∂x j by z i z j , where z is a vector in { d : α + a z + z T Bz = f. If it is the equation of an ellipse (ellipsoid if d ≥ 2), the PDE is said to be elliptic; if it is the equation of a parabola or a hyperbola, the PDE is said to be parabolic or hyperbolic. If A ≡ 0, the degree is no longer 2 but 1, and for reasons that will appear more clearly later, the PDE is still said to be hyperbolic. These concepts can be generalized to systems, by studying whether or not the polynomial system P(z) associated with the PDE system has branches at infinity (ellipsoids have no branches at infinity, paraboloids have one, and hyperboloids have several). If the PDE is not linear, it is said to be non linear. Those are said to be locally elliptic, parabolic, or hyperbolic according to the type of the linearized equation. For example, for the non linear equation ∂ 2 ϕ ∂t 2 − ∂ϕ ∂x ∂ 2 ϕ ∂x 2 = 1, we have d = 2, x 1 = t, x 2 = x and its linearized form is: ∂ 2 u ∂t 2 − ∂u ∂x ∂ 2 ϕ ∂x 2 − ∂ϕ ∂x ∂ 2 u ∂x 2 = 0, which for the unknown u is locally elliptic if ∂ϕ ∂x < 0 and locally hyperbolic if ∂ϕ ∂x > 0. Examples Laplace’s equation is elliptic: ∆ϕ ≡ ∂ 2 ϕ ∂x 2 1 + ∂ 2 ϕ ∂x 2 2 + + ∂ 2 ϕ ∂x 2 d = f, ∀x ∈ Ω ⊂ { d . The heat equation is parabolic in Q = Ω]0, T[⊂ { d+1 : ∂ϕ ∂t −µ∆ϕ = f ∀x ∈ Ω ⊂ { d , ∀t ∈]0, T[. If µ > 0, the wave equation is hyperbolic: ∂ 2 ϕ ∂t 2 −µ∆ϕ = f in Q. The convection diffusion equation is parabolic if µ = 0 and hyperbolic otherwise: ∂ϕ ∂t + a∇ϕ −µ∆ϕ = f. The biharmonic equation is elliptic: ∆(∆ϕ) = f in Ω. 54 CHAPTER 3. LEARNING BY EXAMPLES Boundary conditions A relation between a function and its derivatives is not sufficient to define the function. Additional information on the boundary Γ = ∂Ω of Ω, or on part of Γ is necessary. Such information is called a boundary condition. For example, ϕ(x) given, ∀x ∈ Γ, is called a Dirichlet boundary condition. The Neumann condition is ∂ϕ ∂n (x) given on Γ (or n B∇ϕ, given on Γ for a general second order PDE) where n is the normal at x ∈ Γ directed towards the exterior of Ω (by definition ∂ϕ ∂n = ∇ϕ n). Another classical condition, called a Robin (or Fourier) condition is written as: ϕ(x) + β(x) ∂ϕ ∂n (x) given on Γ. Finding a set of boundary conditions that defines a unique ϕ is a difficult art. In general, an elliptic equation is well posed (i.e. ϕ is unique) with one Dirichlet, Neumann or Robin conditions on the whole boundary. Thus, Laplace’s equations is well posed with a Dirichlet or Neumann condition but also with ϕ given on Γ 1 , ∂ϕ ∂n given on Γ 2 , Γ 1 ∪ Γ 2 = Γ, ˙ Γ 1 ∩ ˙ Γ 2 = ∅. Parabolic and hyperbolic equations rarely require boundary conditions on all of Γ]0, T[. For instance, the heat equation is well posed with ϕ given at t = 0 and Dirichlet or Neumann or mixed conditions on ∂Ω. Here t is time so the first condition is called an initial condition. The whole set of conditions are also called Cauchy conditions. The wave equation is well posed with ϕ and ∂ϕ ∂t given at t = 0 and Dirichlet or Neumann or mixed conditions on ∂Ω. Chapter 4 Syntax 4.1 Data Types In essence FreeFem++ is a compiler: its language is typed, polymorphic, with excep- tion and reentrant. Every variable must be declared of a certain type, in a declarative statement; each statement are separated from the next by a semicolon ‘;’. The language allows the manipulation of basic types integers (int), reals (real), strings (string), ar- rays (example: real[int]), bidimensional (2D) finite element meshes (mesh), 2D finite element spaces (fespace) , analytical functions (func), arrays of finite element functions (func[basic type]), linear and bilinear operators, sparse matrices, vectors , etc. For instance int i,n=20; // i, n are integer. real[int] xx(n),yy(n); // two array of size n for (i=0;i<=20;i++) // which can be used in statements such as { xx[i]= cos(i * pi/10); yy[i]= sin(i * pi/10); } The life of a variable is the current block ¦. . .¦, except the fespace variable, and the variables local to a block are destroyed at the end of the block as follows. Example 4.1 real r= 0.01; mesh Th=square(10,10); // unit square mesh fespace Vh(Th,P1); // P1 lagrange finite element space Vh u = x+ exp(y); func f = z * x + r * log(y); plot(u,wait=true); { // new block real r = 2; // not the same r fespace Vh(Th,P1); // error because Vh is a global name } // end of block // here r back to 0.01 The type declarations are compulsory in FreeFem++ ; in the end this feature is an asset because it is easy to make bugs in a language with many implicit types. The variable name is just an alphanumeric string, the underscore character “ ” is not allowed, because it will be used as an operator in the future. 55 56 CHAPTER 4. SYNTAX 4.2 List of major types bool is used for logical expression and flow-control. The result of a comparison is a boolean type as in bool fool=(1<2); which makes fool to be true. Similar examples can be built with ==, <=, >=, <, >, ! =. int declares an integer. string declare the variable to store a text enclosed within double quotes, such as: "This is a string in double quotes." real declares the variable to store a number such as “12.345”. complex Complex numbers, such as 1 + 2i, FreeFem++ understand that i = √ −1. complex a = 1i, b = 2 + 3i; cout << "a + b = " << a + b << endl; cout << "a - b = " << a + b << endl; cout << "a * b = " << a * b << endl; cout << "a / b = " << a / b << endl; Here’s the output; a + b = (2,4) a - b = (-2,-2) a * b = (-3,2) a / b = (0.230769,0.153846) ofstream to declare an output file . ifstream to declare an input file . real[int ] declares a variable that stores multiple real numbers with integer index. real[int] a(5); a[0] = 1; a[1] = 2; a[2] = 3.3333333; a[3] = 4; a[4] = 5; cout << "a = " << a << endl; This produces the output; a = 5 : 1 2 3.33333 4 5 real[string ] declares a variable that store multiple real numbers with string index. string[string ] declares a variable that store multiple strings with string index. 4.3. GLOBAL VARIABLES 57 func defines a function without argument, if independent variables are x, y. For example func f=cos(x)+sin(y) ; Remark that the function’s type is given by the expression’s type. Raising functions to a numerical power is done, for instance, by xˆ1, yˆ0.23. mesh creates the triangulation, see Section 5. fespace defines a new type of finite element space, see Section Section 6. problem declares the weak form of a partial differential problem without solving it. solve declares a problem and solves it. varf defines a full variational form. matrix defines a sparse matrix. 4.3 Global Variables The names x,y,z,label,region,P,N,nu_triangle... are reserved words used to link the language to the finite element tools: x is the x coordinate of the current point (real value) y is the y coordinate of the current point (real value) z is the z coordinate of the current point (real value) label contains the label number of a boundary if the current point is on a boundary, 0 otherwise (int value). region returns the region number of the current point (x,y) (int value). P gives the current point (R 2 value. ). By P.x, P.y, we can get the x, y components of P . Also P.z is reserved and can be used in 3D. N gives the outward unit normal vector at the current point if it is on a curve defined by border (R 3 value). N.x and N.y are x and y components of the normal vector. N.z is reserved. . lenEdge gives the length of the current edge lenEdge = [q i −q j [ if the current edge is [q i , q j ] hTriangle gives the size of the current triangle nuTriangle gives the index of the current triangle (int value). 58 CHAPTER 4. SYNTAX nuEdge gives the index of the current edge in the triangle (int value). nTonEdge gives the number of adjacent triangle of the current edge (integer ). area give the area of the current triangle (real value). volume give the volume of the current tetrahedra (real value). cout is the standard output device (default is console). On MS-Windows, the standard output is only the console, at this time. ostream cin is the standard input device (default is keyboard). (istreamvalue). endl adds an ”end of line” to the input/output flow. true means “true” in bool value. false means “false” in bool value. pi is the realvalue approximation value of π. 4.4 System Commands Here is how to show all the types, and all the operator and functions of a FreeFem++ program: dumptable(cout); To execute a system command in the string (not implemented on Carbon MacOS), which return the value of the system call. system("shell command"); // after version 3.12-1 exec("shell command"); This is useful to launch another executable from within FreeFem++ . On MS-Windows, the full path of the executable. For example, if there is the command “ls.exe” in the subdirectory “c:\cygwin\bin\”, then we must write exec("c:\\cygwin\\bin\\ls.exe"); Another useful system command is assert() to make sure something is true. assert(version>=1.40); 4.5. ARITHMETICS 59 4.5 Arithmetics On integers , +, −, ∗ are the usual arithmetic summation (plus), subtraction (minus) and multiplication (times), respectively,The operators / and % yield the quotient and the remainder from the division of the first expression by the second. If the second number of / or % is zero the behavior is undefined. The maximum or minimum of two integers a, b are obtained by max(a,b) or min(a,b). The power a b of two integers a, b is calculated by writing aˆb. The classical C++ ”arithmetical if” expression a ? b : c is equal to the value of expression b if the value of expression a is true otherwise is equal to value of expression c. Example 4.2 Computations with the integers int a = 12, b = 5; cout <<"plus, minus of "<<a<<" and "<<b<<" are "<<a+b<<", "<<a-b<<endl; cout <<"multiplication, quotient of them are "<<a * b<<", "<<a/b<<endl; cout <<"remainder from division of "<<a<<" by "<<b<<" is "<<a%b<<endl; cout <<"the minus of "<<a<<" is "<< -a << endl; cout <<a<<" plus -"<<b<<" need bracket:"<<a<<"+(-"<<b<<")="<<a+(-b)<<endl; cout <<"max and min of "<<a<<" and "<<b<<" is "<<max(a,b)<<","<<min(a,b)<< endl; cout <<b<<"th power of "<<a<<" is "<<aˆb<< endl; cout << " min == (a < b ? a : b ) is " << (a < b ? a : b) << endl; b=0; cout <<a<<"/0"<<" is "<< a/b << endl; cout <<a<<"%0"<<" is "<< a%b << endl; produce the following result: plus, minus of 12 and 5 are 17, 7 multiplication, quotient of them are 60, 2 remainder from division of 12 by 5 is 2 the minus of 12 is -12 12 plus -5 need bracket :12+(-5)=7 max and min of 12 and 5 is 12,5 5th power of 12 is 248832 min == (a < b ? a : b) is 5 12/0 : long long long Fatal error : ExecError Div by 0 at exec line 9 Exec error : exit By the relation integer ⊂ real, the operators “+, −, ∗, /, %” and “ max, min, ˆ” are extended to real numbers or variables. However, % calculates the remainder of the integer parts of two real numbers. The following are examples similar to Example 4.2 real a=sqrt(2.), b = pi; cout <<"plus, minus of "<<a<<" and "<<pi<<" are "<< a+b <<", "<< a-b << endl; cout <<"multiplication, quotient of them are "<<a * b<<", "<<a/b<< endl; cout <<"remainder from division of "<<a<<" by "<<b<<" is "<< a%b << endl; cout <<"the minus of "<<a<<" is "<< -a << endl; cout <<a<<" plus -"<<b<<" need bracket :"<<a<<"+(-"<<b<<")="<<a + (-b) << endl; 60 CHAPTER 4. SYNTAX It gives the following output: plus, minus of 1.41421 and 3.14159 are 4.55581, -1.72738 multiplication, quotient of them are 4.44288, 0.450158 remainder from division of 1.41421 by 3.14159 is 1 the minus of 1.41421 is -1.41421 1.41421 plus -3.14159 need bracket :1.41421+(-3.14159)=-1.72738 By the relation bool ⊂ int ⊂ real ⊂ complex, the operators “+, −, ∗, /” and “ ˆ” are also applicable on complex-typed variables, but “%, max, min” cannot be used. Complex numbers such as 5+9i, i= √ −1, are valid expressions. With real variables a=2.45, b=5.33,complex numbers like a +i b and a +i √ 2.0 must be declared by complex z1 = a+b * 1i, z2=a+sqrt(2.0) * 1i; The imaginary and real parts of a complex number z can be obtained with imag and real. The conjugate of a + bi (a, b are reals) is defined by a − bi, which can also be computed with the operator ”conj”, by conj(a+b * 1i) in FreeFem++ . Internally the complex number z = a+ib is considered as the pair (a, b) of real numbers a, b. We can attach to it the point (a, b) in the Cartesian plane where the x-axis is for the real part and the y-axis for the imaginary part. The same point (a, b) has a representation with polar coordinate (r, φ), So z his also z = r(cos φ+i sin φ), r = √ a 2 + b 2 and φ = tan −1 (b/a); r is called the modulus and φ the argument of z. In the following example, we shall show them using FreeFem++ programming, and de Moivre’s formula z n = r n (cos nφ+i sin nφ). Example 4.3 real a=2.45, b=5.33; complex z1=a+b * 1i, z2 = a+sqrt(2.) * 1i; func string pc(complex z) // printout complex to (real)+i(imaginary) { string r = "("+real(z); if (imag(z)>=0) r = r+"+"; return r+imag(z)+"i)"; } // printout complex to |z| * (cos(arg(z))+i * sin(arg(z))) func string toPolar(complex z) { return abs(z)+" * (cos("+arg(z)+")+i * sin("+arg(z)+"))"; } cout <<"Standard output of the complex "<<pc(z1)<<" is the pair " <<z1<<endl; cout <<"Plus, minus of "<<pc(z1)<<" and "<<pc(z2)<<" are "<< pc(z1+z2) <<", "<< pc(z1-z2) << endl; cout <<"Multiplication, quotient of them are "<<pc(z1 * z2)<<", " <<pc(z1/z2)<< endl; cout <<"Real/imaginary part of "<<pc(z1)<<" is "<<real(z1)<<", " <<imag(z1)<<endl; cout <<"Absolute of "<<pc(z1)<<" is "<<abs(z1)<<endl; cout <<pc(z2)<<" = "<<toPolar(z2)<<endl; cout <<" and polar("<<abs(z2)<<","<<arg(z2)<<") = " 4.6. STRING EXPRESSION 61 << pc(polar(abs(z2),arg(z2)))<<endl; cout <<"de Moivre’s formula: "<<pc(z2)<<"ˆ3 = "<<toPolar(z2ˆ3)<<endl; cout <<"conjugate of "<<pc(z2)<<" is "<<pc(conj(z2))<<endl; cout <<pc(z1)<<"ˆ"<<pc(z2)<<" is "<< pc(z1ˆz2) << endl; Here’s the output from Example 4.3 Standard output of the complex (2.45+5.33i) is the pair (2.45,5.33) Plus, minus of (2.45+5.33i) and (2.45+1.41421i) are (4.9+6.74421i), (0+3.91579i) Multiplication, quotient of them are (-1.53526+16.5233i), (1.692+1.19883i) Real/imaginary part of (2.45+5.33i) is 2.45, 5.33 Absolute of (2.45+5.33i) is 5.86612 (2.45+1.41421i) = 2.82887 * (cos(0.523509)+i * sin(0.523509)) and polar(2.82887,0.523509) = (2.45+1.41421i) de Moivre’s formula: (2.45+1.41421i)ˆ3 = 22.638 * (cos(1.57053)+i * sin(1.57053)) conjugate of (2.45+1.41421i) is (2.45-1.41421i) (2.45+5.33i)ˆ(2.45+1.41421i) is (8.37072-12.7078i) 4.6 string expression In the following example you some example string expression string tt="toto1"+1+" -- 77"; // string concatenation string t1="0123456789"; string t2; // new operator t2 ="12340005678"; t2(4:3) = "abcdefghijk-"; string t55=t2(4:3); // t2 = "12340abcdefghijk-005678"; cout << t2 << endl; cout << " find abc " << t2.find("abc") << endl; cout << "r find abc " << t2.rfind("abc") << endl; cout << " find abc from 10 " << t2.find("abc",10) << endl; cout << " ffind abc from 10 " <<t2.rfind("abc",10) << endl; cout << " " << string("abcc").length << endl; cout << " t55 " << t55 << endl; { // add getline version 3.0-6 jan 2009 FH string s; ifstream toto("xyf"); for (int i=0;i<10;++i) { getline(toto,s); cout << i << " : " << s << endl; } } 62 CHAPTER 4. SYNTAX 4.7 Functions of one Variable Fundamental functions are built into FreeFem++ as well as The power function xˆ y = pow(x,y)= x y ;, the exponent function exp(x) (= e x ), the logarithmic func- tion log(x)(= ln x) or log10(x) (= log 10 x); the trigonometric functions sin(x), cos(x), tan(x) assume angles measured in radians; the inverse of sin x, cos x, tan x (called circular function or inverse trigonometric function ) asin(x)(=arcsin x), acos(x)(=arccos x), atan(x)(=arctan x) are also implemented; the atan2(x,y) function computes the principal value of the arc tangent of y/x, using the signs of both arguments to determine the quadrant of the return value; the hyperbolic functions, sinh x = e x −e −x /2, cosh x = e x + e −x /2. and tanh x = sinh x/ cosh x called by sinh(x), cosh(x), tanh(x), asinh(x), acosh(x) and atanh(x). sinh −1 x = ln x + √ x 2 + 1 , cosh −1 x = ln x + √ x 2 −1 . The real function which rounds a real to an integer floor(x) rounds to largest integral value not greater than x, ceil(x) round to smallest integral value not less than x; similarly rint(x) returns the integral value nearest to x (according to the prevailing rounding mode) in floating-point format).. Elementary Functions denotes for us the class of functions presented above (polyno- mials, exponential, logarithmic, trigonometric, circular) and the functions obtained from those by the four arithmetic operations f(x) + g(x), f(x) −g(x), f(x)g(x), f(x)/g(x) and by composition f(g(x)), each applied a finite number of times. In FreeFem++ , all elementary functions can thus be created. The derivative of an elementary func- tion is also an elementary function; however, the indefinite integral of an elementary function cannot always be expressed in terms of elementary functions. Example 4.4 The following is an example where an elementary function is used to build the border of a domain. Cardioid real b = 1.; real a = b; func real phix(real t) { return (a+b) * cos(t)-b * cos(t * (a+b)/b); } func real phiy(real t) { return (a+b) * sin(t)-b * sin(t * (a+b)/b); } border C(t=0,2 * pi) { x=phix(t); y=phiy(t); } mesh Th = buildmesh(C(50)); 4.7. FUNCTIONS OF ONE VARIABLE 63 Taking the principal value, we can define log z for z = 0 by ln z = ln [z[ + i arg z. Using FreeFem++ , we calculated exp(1+4i), sin(pi+1i), cos(pi/2-1i) and log(1+2i), we then have −1.77679 −2.0572i, 1.8896710 −16 −1.1752i, 9.4483310 −17 + 1.1752i, 0.804719 + 1.10715i. Random Functions can be define as FreeFem++ has a Mersenne Twister function (see page http://www.math.sci.hiroshima-u.ac.jp/ ˜ m-mat/MT/emt.html for full detail). It is a very fast and accurate random number generator Of period 2 219937 −1, and the functions which calls it are: • randint32() generates unsigned 32-bit integers. • randint31() generates unsigned 31-bit integers. • randreal1() generates uniform real in [0, 1] (32-bit resolution). • randreal2() generates uniform real in [0, 1) (32-bit resolution). • randreal3() generates uniform real in (0, 1) (32-bit resolution). • randres53() generates uniform real in [0, 1) with 53-bit resolution. • randinit(seed ) initializes the state vector by using one 32-bit integer ”seed”, which may be zero. Library Functions form the mathematical library (version 2.17). • the functions j0(x), j1(x), jn(n,x), y0(x), y1(x), yn(n,x) are the Bessel functions of first and second kind. The functions j0(x) and j1(x) compute the Bessel function of the first kind of the order 0 and the order 1, respectively; the function jn(n, x) computes the Bessel function of the first kind of the integer order n. The functions y0(x) and y1(x) compute the linearly independent Bessel func- tion of the second kind of the order 0 and the order 1, respectively, for the positive integer value x (expressed as a real); the function yn(n, x) computes the Bessel function of the second kind for the integer order n for the positive integer value x (expressed as a real). • the function tgamma(x) calculates the Γ function of x. lgamma(x) calculates the natural logorithm of the absolute value of the Γ function of x. • The erf(x) function calculates the error function, where erf(x) = 2 √ (pi) x 0 exp(−t 2 )dt. The erfc(x) = function calculates the complementary error function of x, i.e. erfc(x) = 1 −erf(x). 64 CHAPTER 4. SYNTAX 4.8 Functions of two Variables 4.8.1 Formula The general form of real functions of two independent variables a, b is usually written as c = f(a, b). In FreeFem++ , x, y and z are reserved word as explained in in Section 4.3. So when the two variables of the function are x and y, we may define the function without its argument, for example func f=cos(x)+sin(y) ; Remark that the function type is given by the expression type. The power operator can be used in functions such as xˆ1, yˆ0.23. In func, we can write an elementary function as follows func f = sin(x) * cos(y); func g = (xˆ2+3 * yˆ2) * exp(1-xˆ2-yˆ2); func h = max(-0.5,0.1 * log(fˆ2+gˆ2)); Complex valued function create functions with 2 variables x, y as follows, mesh Th=square(20,20,[-pi+2 * pi * x,-pi+2 * pi * y]); // ] −π, π[ 2 fespace Vh(Th,P2); func z=x+y * 1i; // z = x +iy func f=imag(sqrt(z)); // f = · √ z func g=abs( sin(z/10) * exp(zˆ2/10) ); // g = [ sin z/10 exp z 2 /10[ Vh fh = f; plot(fh); // contour lines of f Vh gh = g; plot(gh); // contour lines of g We call also construct elementary functions of two variables from elementary functions f(x) or g(y) by the four arithmetic operations plus composition applied a finite number of times. 4.8.2 FE-functions Finite element functions are also constructed like elementary functions by an arithmetic for- mula involving elementary functions. The difference is that they are evaluated at declaration time and FreeFem++ stores the array of its values at the places associated with he degree of freedom of the finite element type. By opposition elementary functions are evaluated only when needed. Hence FE-functions are not defined only by their formula but also by the mesh and the finite element which enter in their definitions. If the value of a FE-function is requested at a point which is not a degree of freedom, an interpolation is used, leading to an interpolation error, while by contrast, an elementary function can be evaluated at any point exactly. func f=xˆ2 * (1+y)ˆ3+yˆ2; mesh Th = square(20,20,[-2+2 * x,-2+2 * y]); // square ] −2, 2[ 2 fespace Vh(Th,P1); Vh fh=f; // fh is the projection of f to Vh (real value) func zf=(xˆ2 * (1+y)ˆ3+yˆ2) * exp(x+1i * y); Vh<complex> zh = zf; // zh is the projection of zf // to complex value Vh space The construction of fh (=f h ) is explained in Section 6. 4.9. ARRAYS 65 Note 4.1 The command plot applies only for real or complex FE-functions (2d or 3d) and not to elementary functions. Complex valued functions create functions with 2 variables x, y as follows, mesh Th=square(20,20,[-pi+2 * pi * x,-pi+2 * pi * y]); // ] −π, π[ 2 fespace Vh(Th,P2); func z=x+y * 1i; // z = x +iy func f=imag(sqrt(z)); // f = · √ z func g=abs( sin(z/10) * exp(zˆ2/10) ); // g = [ sin z/10 exp z 2 /10[ Vh fh = f; plot(fh); // Fig. 4.1 isovalue of f Vh gh = g; plot(gh); // Fig. 4.2 isovalue of g Figure 4.1: · √ z has branch Figure 4.2: [ sin(z/10) exp(z 2 /10)[ 4.9 Arrays An array stores multiple objects, and there are 2 kinds of arrays: The first is similar to vector, i.e. arrays with with integer indices and the second type is arrays with string indices. In the first case, the size of the array must be known at execution time, and implementation is done with the KN<> class and all the vector operator of KN<> are implemented. For instance real [int] tab(10), tab1(10); // 2 array of 10 real real [int] tab2; // bug array with no size tab = 1.03; // set all the array to 1.03 tab[1]=2.15; cout << tab[1] << " " << tab[9] << " size of tab = " << tab.n << " min: " << tab.min << " max:" << tab.max << " sum : " << tab.sum << endl; // tab.resize(12); // change the size of array tab // to 12 with preserving first value tab(10:11)=3.14; // set unset value cout <<" resize tab: " << tab << endl; real [string] tt; tt["+"]=1.5; 66 CHAPTER 4. SYNTAX cout<<tt["a"]<<" "<<tt["+"]<<endl; real[int] a(5),b(5),c(5),d(5); a = 1; b = 2; c = 3; a[2]=0; d = ( a ? b : c ); // for i = 0, n-1 : d[i] = a[i] ? b[i] : c[i] , cout << " d = ( a ? b : c ) is " << d << endl; d = ( a ? 1 : c ); // for i = 0, n-1: d[i] = a[i] ? 1 : c[i] , (v2.23-1) d = ( a ? b : 0 ); // for i = 0, n-1: d[i] = a[i] ? b[i] : 0 , (v2.23-1) d = ( a ? 1 : 0 ); // for i = 0, n-1: d[i] = a[i] ? 0 : 1 , (v2.23-1) tab.sort ; // sort the array tab (version 2.18) cout << " tab (after sort) " << tab << endl; int[int] ii(0:d.n-1); // set array ii to 0,1, ..., d.n-1 (v3.2) d=-1:-5; // set d to -1,-2, .. -5 (v3.2) sort(d,ii); // sort array d and ii in parallel cout << " d " << d << "\n ii = " << ii << endl; produces the output 2.15 1.03 size of tab = 10 min: 1.03 max:2.15 sum : 11.42 resize tab: 12 1.03 2.15 1.03 1.03 1.03 1.03 1.03 1.03 1.03 1.03 3.14 3.14 0 1.5 d = ( a ? b : c ) is 5 3 3 2 3 3 tab (after sort) 12 1.03 1.03 1.03 1.03 1.03 1.03 1.03 1.03 1.03 2.15 3.14 3.14 d 5 -5 -4 -3 -2 -1 ii = 5 4 3 2 1 0 Arrays can be set like in matlab or scilab with the operator ::, the array generator of a:c is equivalent to a:1:c, and the array set by a:b:c is set to size [(b −a)/c[ + 1| and the value i is set by a + i(b −a)/c. There are int,real, complex arrays with, in the third case, two operators (.in, .re) to generate the real and imaginary real array from the complex array (without copy) : // version 3.2 mai 2009 // like matlab. and scilab { int[int] tt(2:10); // 2,3,4,5,6,7,8,9,10 int[int] t1(2:3:10); // 2,5,8, cout << " tt(2:10)= " << tt << endl; cout << " t1(2:3:10)= " << t1 << endl; tt=1:2:5; cout << " 1.:2:5 => " << tt << endl; } 4.9. ARRAYS 67 { real[int] tt(2:10); // 2,3,4,5,6,7,8,9,10 real[int] t1(2.:3:10.); // 2,5,8, cout << " tt(2:10)= " << tt << endl; cout << " t1(2:3:10)= " << t1 << endl; tt=1.:0.5:3.999; cout << " 1.:0.5:3.999 => " << tt << endl; } { complex[int] tt(2.+0i:10.+0i); // 2,3,4,5,6,7,8,9,10 complex[int] t1(2.:3.:10.); // 2,5,8, cout << " tt(2.+0i:10.+0i)= " << tt << endl; cout << " t1(2.:3.:10.)= " << t1 << endl; cout << " tt.re real part array " << tt.re << endl ; // the real part array of the complex array cout << " tt.im imag part array " << tt.im << endl ; // the imag part array of the complex array } The output is : tt(2:10)= 9 2 3 4 5 6 7 8 9 10 t1(2:3:10)= 3 2 5 8 1.:2:5 => 3 1 3 5 tt(2:10) = = 9 2 3 4 5 6 7 8 9 10 t1(2.:3:10.)= 3 2 5 8 1.:0.5:3.999 => 6 1 1.5 2 2.5 3 3.5 tt(2.+0i:10.+0i)= 9 (2,0) (3,0) (4,0) (5,0) (6,0) (7,0) (8,0) (9,0) (10,0) t1(2.:3.:10.);= 3 (2,0) (5,0) (8,0) tt.re real part array 9 2 3 4 5 6 7 8 9 10 tt.im imag part array 9 0 0 0 0 0 0 0 0 0 2 the all integer array operators are : { 68 CHAPTER 4. SYNTAX int N=5; real[int] a(N),b(N),c(N); a =1; a(0:4:2) = 2; a(3:4) = 4; cout <<" a = " << a << endl; b = a+ a; cout <<" b = a+a : " << b << endl; b += a; cout <<" b += a : " << b << endl; b += 2 * a; cout <<" b += 2 * a : " << b << endl; b /= 2; cout <<" b /= 2 : " << b << endl; b * = a; // same b = b . * a cout << "b * =a; b =" << b << endl; b /= a; // same b = b ./ a cout << "b/=a; b =" << b << endl; c = a+b; cout << " c =a+b : c=" << c << endl; c = 2 * a+4 * b; cout << " c =2 * a+4b : c= " << c << endl; c = a+4 * b; cout << " c =a+4b : c= " << c << endl; c = -a+4 * b; cout << " c =-a+4b : c= " << c << endl; c = -a-4 * b; cout << " c =-a-4b : c= " << c << endl; c = -a-b; cout << " c =-a-b : c= " << c << endl; c = a . * b; cout << " c =a. * b : c= " << c << endl; c = a ./ b; cout << " c =a./b : c= " << c << endl; c = 2 * b; cout << " c =2 * b : c= " << c << endl; c = b * 2 ; cout << " c =b * 2 : c= " << c << endl; / * this operator do not exist c = b/2 ; cout << " c =b/2 : c= " << c << endl; * / // ---- the methods -- cout << " ||a||_1 = " << a.l1 << endl; // cout << " ||a||_2 = " << a.l2 << endl; // cout << " ||a||_infty = " << a.linfty << endl; // cout << " sum a_i = " << a.sum << endl; // cout << " max a_i = " << a.max << endl; // cout << " min a_i = " << a.min << endl; // cout << " a’ * a = " << (a’ * a) << endl; // cout << " a quantile 0.2 = " << a.quantile(0.2) << endl; // } produce the output 4.9. ARRAYS 69 5 3 3 2 3 3 == 3 3 2 3 3 a = 5 2 1 2 4 4 b = a+a : 5 4 2 4 8 8 b += a : 5 6 3 6 12 12 b += 2 * a : 5 10 5 10 20 20 b /= 2 : 5 5 2.5 5 10 10 b * =a; b =5 10 2.5 10 40 40 b/=a; b =5 5 2.5 5 10 10 c =a+b : c=5 7 3.5 7 14 14 c =2 * a+4b : c= 5 24 12 24 48 48 c =a+4b : c= 5 22 11 22 44 44 c =-a+4b : c= 5 18 9 18 36 36 c =-a-4b : c= 5 -22 -11 -22 -44 -44 c =-a-b : c= 5 -7 -3.5 -7 -14 -14 c =a. * b : c= 5 10 2.5 10 40 40 c =a./b : c= 5 0.4 0.4 0.4 0.4 0.4 c =2 * b : c= 5 10 5 10 20 20 c =b * 2 : c= 5 10 5 10 20 20 70 CHAPTER 4. SYNTAX ||a||_1 = 13 ||a||_2 = 6.403124237 ||a||_infty = 4 sum a_i = 13 max a_i = 4 min a_i = 1 a’ * a = 41 a quantile 0.2 = 2 Note 4.2 Quantiles are points taken at regular intervals from the cumulative distribution function of a random variable. Here the array values are random. This statisticial function a.quantile(q) computes v from an array a of size n for a given number q ∈]0, 1[ such that #¦i/a[i] < v¦ ∼ q ∗ n ; it is equivalent to v = a[q ∗ n] when the array a is sorted. Example of array with renumbering (version 2.3 or better) . The renumbering is always given by an integer array, and if a value in the array is negative, the mapping is not imaged, so the value is not set. int[int] I=[2,3,4,-1,0]; // the integer mapping to set the renumbering b=c=-3; b= a(I); // for( i=0;i<b.n;i++) if(I[i] >=0) b[i]=a[I[i]]; c(I)= a; // for( i=0;i<I.n;i++) if(I[i] >=0) C(I[i])=a[i]; cout << " b = a(I) : " << b << "\n c(I) = a " << c << endl; The output is b = a(I) : 5 2 4 4 -3 2 c(I) = a 5 4 -3 2 1 2 4.9.1 Arrays with two integer indices versus matrices Some example are given below to transform full matrices into sparse matrices. int N=3,M=4; real[int,int] A(N,M); real[int] b(N),c(M); b=[1,2,3]; c=[4,5,6,7]; complex[int,int] C(N,M); complex[int] cb=[1,2,3],cc=[10i,20i,30i,40i]; 4.9. ARRAYS 71 b=[1,2,3]; int [int] I=[2,0,1]; int [int] J=[2,0,1,3]; A=1; // set the all matrix A(2,:) = 4; // the full line 2 A(:,1) = 5; // the full column 1 A(0:N-1,2) = 2; // set the column 2 A(1,0:2) = 3; // set the line 1 from 0 to 2 cout << " A = " << A << endl; // outer product C = cb * cc’; C += 3 * cb * cc’; C -= 5i * cb * cc’; cout << " C = " << C << endl; // this transforms an array into a sparse matrix matrix B; B = A; B=A(I,J); // B(i,j)= A(I(i),J(j)) B=A(Iˆ-1,Jˆ-1); // B(I(i),J(j))= A(i,j) A = 2. * b * c’; // outer product cout << " A = " << A << endl; B = b * c’; // outer product B(i,j) = b(i) * c(j) B = b * c’; // outer product B(i,j) = b(i) * c(j) B = (2 * b * c’)(I,J); // outer product B(i,j) = b(I(i)) * c(J(j)) B = (3. * b * c’)(Iˆ-1,Jˆ-1); // outer product B(I(i),J(j)) = b(i) * c(j) cout << "B = (3. * b * c’)(Iˆ-1,Jˆ-1) = " << B << endl; the output is b = a(I) : 5 2 4 4 -3 2 c(I) = a 5 4 -3 2 1 2 A = 3 4 1 5 2 1 3 3 3 1 4 5 2 4 C = 3 4 (-50,-40) (-100,-80) (-150,-120) (-200,-160) (-100,-80) (-200,-160) (-300,-240) (-400,-320) (-150,-120) (-300,-240) (-450,-360) (-600,-480) A = 3 4 8 10 12 14 16 20 24 28 24 30 36 42 72 CHAPTER 4. SYNTAX 4.9.2 Matrix construction and setting • To change the linear system solver associated to a matrix do set(M,solver=sparsesolver); The default solver is GMRES. • from a variational form: (see section 6.12 page 162 for details) varf vDD(u,v) = int2d(Thm)(u * v * 1e-10); matrix DD=vDD(Lh,Lh); • To set from a constant matrix matrix A = [[ 0, 1, 0, 10], [ 0, 0, 2, 0], [ 0, 0, 0, 3], [ 4,0 , 0, 0]]; • To set from a block matrix matrix M=[ [ Asd[0] ,0 ,0 ,0 ,Csd[0] ], [ 0 ,Asd[1] ,0 ,0 ,Csd[1] ], [ 0 ,0 ,Asd[2] ,0 ,Csd[2] ], [ 0 ,0 ,0 ,Asd[3] ,Csd[3] ], [ Csd[0]’,Csd[1]’,Csd[2]’,Csd[3]’,DD ] ]; // to now to pack the right hand side real[int] bb =[rhssd[0][], rhssd[1][],rhssd[2][],rhssd[3][],rhsl[] ]; set(M,solver=sparsesolver); xx = Mˆ-1 * bb; [usd[0][],usd[1][],usd[2][],usd[3][],lh[]] = xx; // to dispatch // the solution on each part. where Asd and Csd are arrays of matrices (from example mortar-DN-4.edp of examples++-tuturial). • To set or get all the indices and coefficients of the sparse matrix A, let I,J,C be respectively two int[int] arrays and a real[int] array. The three arrays define the matrix as follows A = ¸ k C[k]M I[k],J[k] where M ab = (δ ia δ jb ) ij one has: M ab a basic matrix with the only non zero term m ab = 1. One can write [I,J,C]=A ; to get all the term of the matrix A (the arrays are automatically resized), and A=[I,J,C] ; to change all the term matrices. Note 4.9. ARRAYS 73 that the size of the matrix is with n= I.max and m=J.max. Remark that I,J is forgotten to build a diagonal matrix, and similarly for the n, m of the matrix. • matrix renumbering int[int] I(15),J(15); // two array for renumbering // // the aim is to transform a matrix into a sparse matrix matrix B; B = A; // copie matrix A B=A(I,J); // B(i,j) = A(I(i),J(j)) B=A(Iˆ-1,Jˆ-1); // B(I(i),J(j))= A(i,j) B.resize(10,20); // resize the sparse matrix and remove out of bound terms where A is a given matrix. 4.9.3 Matrix Operations The multiplicative operators *, /, and % group left to right. • ’ is the (unary) right transposition for arrays, the matrix in real cases and Hermitian transpose in complex cases. • . * is the term to term multiply operator. • ./ is the term to term divide operator. there are some compound operators also: • ˆ-1 is for solving the linear system (example: b = Aˆ-1 x) • ’ * is the compound of transposition and matrix product, so it is the dot product (ex- ample real DotProduct=a’ * b) , in complex case you get the Hermitian product, so mathematically we have a’ * b= a T b . • a * b’ is the outer product (example matrix B=a’ * b ) Example 4.5 mesh Th = square(2,1); fespace Vh(Th,P1); Vh f,g; f = x * y; g = sin(pi * x); Vh<complex> ff,gg; // a complex valued finite element function ff= x * (y+1i); gg = exp(pi * x * 1i); varf mat(u,v) = int2d(Th)(1 * dx(u) * dx(v)+2 * dx(u) * dy(v)+3 * dy(u) * dx(v)+4 * dy(u) * dy(v)) + on(1,2,3,4,u=1); varf mati(u,v) = 74 CHAPTER 4. SYNTAX int2d(Th)(1 * dx(u) * dx(v)+2i * dx(u) * dy(v)+3 * dy(u) * dx(v)+4 * dy(u) * dy(v)) + on(1,2,3,4,u=1); matrix A = mat(Vh,Vh); matrix<complex> AA = mati(Vh,Vh); // a complex sparse matrix Vh m0; m0[] = A * f[]; Vh m01; m01[] = A’ * f[]; Vh m1; m1[] = f[]. * g[]; Vh m2; m2[] = f[]./g[]; cout << "f = " << f[] << endl; cout << "g = " << g[] << endl; cout << "A = " << A << endl; cout << "m0 = " << m0[] << endl; cout << "m01 = " << m01[] << endl; cout << "m1 = "<< m1[] << endl; cout << "m2 = "<< m2[] << endl; cout << "dot Product = "<< f[]’ * g[] << endl; cout << "hermitien Product = "<< ff[]’ * gg[] << endl; cout << "outer Product = "<< (A=ff[] * gg[]’) << endl; cout << "hermitien outer Product = "<< (AA=ff[] * gg[]’) << endl; real[int] diagofA(A.n); diagofA = A.diag; // get the diagonal of the matrix A.diag = diagofA ; // set the diagonal of the matrix // version 2.17 or better --- int[int] I(1),J(1); real[int] C(1); [I,J,C]=A; // get of the sparse term of the matrix A (the array are resized) cout << " I= " << I << endl; cout << " J= " << J << endl; cout << " C= " << C << endl; A=[I,J,C]; // set a new matrix matrix D=[diagofA] ; // set a diagonal matrix D from the array diagofA. cout << " D = " << D << endl; The resizing of a sparse matrix A is also allowed: A.resize(10,100); Note that the new size can be greater or smaller than the previous size; all new term are set to zero. 4.9. ARRAYS 75 On the triangulation of Figure 2.4 this produces the following: A = 10 30 0.5 0. 30. −2.5 0. 0. 10 30 0.5 0. 0.5 −2.5 0. 0. 10 30 0. 0. 0.5 0.5 0. 0. 10 30 0. 0. −2.5 0.5 0. 0.5 10 30 0. 0. −2.5 0. 0. 0.5 10 30 ¸ ¸ ¸ ¸ ¸ ¸ ¸ ¸ ¦v¦ = f[] = 0 0 0 0 0.5 1 T ¦w¦ = g[] = 0 1 1.2 10 −16 0 1 1.2 10 −16 A * f[] = −1.25 −2.25 0.5 0 5 10 29 10 30 T (= A¦v¦) A’ * f[] = −1.25 −2.25 0 0.25 5 10 29 10 30 T (= A T ¦v¦) f[]. * g[] = 0 0 0 0 0.5 1.2 10 −16 T = (v 1 w 1 v M w M ) T f[]./g[] = −NaN 0 0 −NaN 0.5 8.1 10 15 T = (v 1 /w 1 v M /w M ) T f[]’ * g[] = 0.5 (= ¦v¦ T ¦w¦ = ¦v¦ ¦w¦) The output of the I, J, C array: I= 18 0 0 0 1 1 1 1 2 2 3 3 4 4 4 4 5 5 5 J= 18 0 1 4 1 2 4 5 2 5 0 3 0 1 3 4 1 4 5 C= 18 1e+30 0.5 -2.5 1e+30 0.5 0.5 -2.5 1e+30 0.5 0.5 1e+30 -2.5 0.5 0.5 1e+30 -2.5 0.5 1e+30 The output of a diagonal sparse matrix D (Warning du to fortran interface the indices start on the output at one, but in FreeFem++ in index as in C begin at zero); D = # Sparce Matrix (Morse) # first line: n m (is symmetic) nbcoef # after for each nonzero coefficient: i j a_ij where (i,j) \in {1,...,n}x{1,...,m} 6 6 1 6 1 1 1.0000000000000000199e+30 2 2 1.0000000000000000199e+30 3 3 1.0000000000000000199e+30 4 4 1.0000000000000000199e+30 5 5 1.0000000000000000199e+30 6 6 1.0000000000000000199e+30 Note 4.3 The operators ˆ-1 cannot be used to create a matrix; the following gives an error matrix AAA = Aˆ-1; 76 CHAPTER 4. SYNTAX In examples++-load/lapack.edp a full matrix is inverted using the lapack library and this small dynamic link interface (see for more detail section C page 321). load "lapack" load "fflapack" int n=5; real[int,int] A(n,n),A1(n,n),B(n,n); for(int i=0;i<n;++i) for(int j=0;j<n;++j) A(i,j)= (i==j) ? n+1 : 1; cout << A << endl; A1=Aˆ-1; // def in load "lapack" cout << A1 << endl; B=0; for(int i=0;i<n;++i) for(int j=0;j<n;++j) for(int k=0;k<n;++k) B(i,j) +=A(i,k) * A1(k,j); cout << B << endl; // A1+Aˆ-1; attention ne marche pas inv(A1); // def in load "fflapack" cout << A1 << endl; and the output is: 5 5 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 error: dgesv_ 0 5 5 0.18 -0.02 -0.02 -0.02 -0.02 -0.02 0.18 -0.02 -0.02 -0.02 -0.02 -0.02 0.18 -0.02 -0.02 -0.02 -0.02 -0.02 0.18 -0.02 -0.02 -0.02 -0.02 -0.02 0.18 5 5 1 -1.387778781e-17 -1.040834086e-17 3.469446952e-17 0 -1.040834086e-17 1 -1.040834086e-17 -2.081668171e-17 0 3.469446952e-18 -5.551115123e-17 1 -2.081668171e-17 -2.775557562e-17 1.387778781e-17 -4.510281038e-17 -4.857225733e-17 1 -2.775557562e-17 -1.387778781e-17 -9.714451465e-17 -5.551115123e-17 -4.163336342e-17 1 5 5 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 4.9. ARRAYS 77 to compile lapack.cpp or fflapack.cpp you must have the library lapack on you system and try in directory examples++-load ff-c++ lapack.cpp -llapack ff-c++ fflapack.cpp -llapack 4.9.4 Other arrays It is also possible to make an array of FE functions, with the same syntax, and we can treat them as vector valued function if we need them. Example 4.6 In the following example, Poisson’s equation is solved for 3 different given functions f = 1, sin(πx) cos(πy), [x−1[[y −1[, whose solutions are stored in an array of FE function. mesh Th=square(20,20,[2 * x,2 * y]); fespace Vh(Th,P1); Vh u, v, f; problem Poisson(u,v) = int2d(Th)( dx(u) * dx(v) + dy(u) * dy(v)) + int2d(Th)( -f * v ) + on(1,2,3,4,u=0) ; Vh[int] uu(3); // an array of FE function f=1; // problem1 Poisson; uu[0] = u; f=sin(pi * x) * cos(pi * y); // problem2 Poisson; uu[1] = u; f=abs(x-1) * abs(y-1); // problem3 Poisson; uu[2] = u; for (int i=0; i<3; i++) // plots all solutions plot(uu[i], wait=true); For the second case, it is just a map of the STL 1 [26] so no operations on vector are allowed, except the selection of an item . The transpose or Hermitian conjugation operator is ’ as in Matlab or Scilab, so the way to compute the dot product of two array a,b is real ab= a’ * b. int i; real [int] tab(10), tab1(10); // 2 array of 10 real real [int] tab2; // Error: array with no size tab = 1; // set all the array to 1 tab[1]=2; cout << tab[1] << " " << tab[9] << " size of tab = " << tab.n << " " << tab.min << " " << tab.max << " " << endl; tab1=tab; tab=tab+tab1; tab=2 * tab+tab1 * 5; tab1=2 * tab-tab1 * 5; tab+=tab; cout << " dot product " << tab’ * tab << endl; // t tab tab cout << tab << endl; cout << tab[1] << " " << tab[9] << endl; real[string] map; // a dynamic array for (i=0;i<10;i=i+1) { tab[i] = i * i; 1 Standard template Library, now part of standard C++ 78 CHAPTER 4. SYNTAX cout << i << " " << tab[i] << "\n"; }; map["1"]=2.0; map[2]=3.0; // 2 is automatically cast to the string "2" cout << " map[\"1\"] = " << map["1"] << "; "<< endl; cout << " map[2] = " << map[2] << "; "<< endl; 4.10 Loops The for and while loops are implemented in FreeFem++ together with break and continue keywords. In for-loop, there are three parameters; the INITIALIZATION of a control variable, the CONDITION to continue, the CHANGE of the control variable. While CONDITION is true, for-loop continue. for (INITIALIZATION; CONDITION; CHANGE) { BLOCK of calculations } An example below shows a sum from 1 to 10 with result is in sum, int sum=0; for (int i=1; i<=10; i++) sum += i; The while-loop while (CONDITION) { BLOCK of calculations or change of control variables } is executed repeatedly until CONDITION become false. The sum from 1 to 10 can also be computed by while as follows, int i=1, sum=0; while (i<=10) { sum += i; i++; } We can exit from a loop in midstream by break. The continue statement will pass the part from continue to the end of the loop. Example 4.7 for (int i=0;i<10;i=i+1) cout << i << "\n"; real eps=1; while (eps>1e-5) { eps = eps/2; if( i++ <100) break; cout << eps << endl;} 4.11. INPUT/OUTPUT 79 for (int j=0; j<20; j++) { if (j<10) continue; cout << "j = " << j << endl; } 4.11 Input/Output The syntax of input/output statements is similar to C++ syntax. It uses cout, cin, endl, <<,>>. To write to (resp. read from) a file, declare a new variable ofstream ofile("filename"); or ofstream ofile("filename",append); (resp. ifstream ifile("filename"); ) and use ofile (resp. ifile) as cout (resp. cin). The word append in ofstream ofile("filename",append); means openning a file in append mode. Note 4.4 The file is closed at the exit of the enclosing block, Example 4.8 int i; cout << " std-out" << endl; cout << " enter i= ? "; cin >> i ; { ofstream f("toto.txt"); f << i << "coucou’\n"; }; // close the file f because the variable f is delete { ifstream f("toto.txt"); f >> i; } { ofstream f("toto.txt",append); // to append to the existing file "toto.txt" f << i << "coucou’\n"; }; // close the file f because the variable f is delete cout << i << endl; Some functions are available to format the output. • int nold=f.precision(n) Sets the number of digits printed to the right of the decimal point. This applies to all subsequent floating point numbers written to that output stream. However, this won’t make floating-point ”integers” print with a decimal point. It’s necessary to use fixed for that effect. • f.scientific Formats floating-point numbers in scientific notation ( d.dddEdd ) • f.fixed Used fixed point notation ( d.ddd ) for floating-point numbers. Opposite of scientific. 80 CHAPTER 4. SYNTAX • f.showbase Converts insertions to an external form that can be read according to the C++ lexical conventions for integral constants. By default, showbase is not set. • f.noshowbase unset showbase flags • f.showpos inserts a plus sign (+) into a decimal conversion of a positive integral value. • f.noshowpos unset showpos flags • f.default reset all the previous flags (fmtflags) to the default expect precision. Where f is output stream descriptor, for example cout. Remark, all these methods except the first return the stream f, so they can be chained as in cout.scientific.showpos << 3 << endl; 4.11.1 Script arguments There is a very useful predefined array in Freefem++ ARGV that contains all the arguments of the script used in the command line. The following code prints out the first three of these arguments: // version 3.8-1 for(int i=0;i<ARGV.n;++i) { cout << ARGV[i] << endl; } And to get argument unused in getARGV.idp include script file, getARGV(n,defaultvalue) // get the nth parameter unused if exist (n = 1, ...) getARGV(after,defaultvalue) // get the arg after the string after if exist The type of default value can be int, real, string, 4.12 preprocessor The preprocessor handles directives for source file inclusion (include ”script-name.idp”), macro definitions. There are two types of macros, object-like and function-like. Object-like macros do not take parameters; function-like macros do. The generic syntax for declaring an identifier as a macro of each type is, respectively, macro <identifier>() <replacement token list> // EOM a // comment to end the macro macro <identifier>(<parameter list>) <replacement token list> // EOM An example of macro without parameter macro xxx() {real i=0;int j=0;cout << i << " " << j << endl;} // 4.12. PREPROCESSOR 81 xxx / * replace xxx by the <replacement token list> * / The freefem++ code associated: 1 : // macro without parameter 2 : macro xxx {real i=0;int j=0;cout << i << " " << j << endl;}// 3 : 4 : {real i=0;int j=0;cout << i << " " << j << endl;} An example of macro parameter macro toto(i) i // // quoting parameter the ¦¦ are remove toto({real i=0;int j=0;cout << i << " " << j << endl;}) // and only one level of ¦¦ are remove toto({{real i=0;int j=0;cout << i << " " << j << endl;}}) The freefem++ code created : 6 : macro toto(i ) i // 8 : // quoting parameter the \{\} are remove 9 : real i=0;int j=0;cout << i << " " << j << endl; 10 : // and only one level of \{\} are remove 11 : {real i=0;int j=0;cout << i << " " << j << endl;} Use a macro as parameter of macro to transforme full matrix in formal array like in : real[int,int] CC(7,7),EE(6,3),EEps(4,4); macro VIL6(v,i) [ v(1,i), v(2,i),v(4,i), v(5,i),v(6,i) ] // EOM macro VIL3(v,i) [ v(1,i), v(2,i) ] // EOM // apply v on array element : macro VV6(v,vv) [ v(vv,1), v(vv,2), v(vv,4), v(vv,5), v(vv,6) ] // EOM macro VV3(v,vv) [ v(vv,1), v(vv,2) ] // EOM // so formal matrix to build problem.. func C5x5 = VV6(VIL6,CC); func E5x2 = VV6(VIL3,EE); func Eps = VV3(VIL3,EEps); The freefem++ code created : 16 : real[int,int] CC(7,7),EE(6,3),EEps(4,4); 17 : 18 : macro VIL6(v,i ) [ v(1,i), v(2,i),v(4,i), v(5,i),v(6,i) ] // EOM 19 : macro VIL3(v,i ) [ v(1,i), v(2,i) ] // EOM 20 : // apply v on array element : 21 : macro VV6(v,vv ) [ v(vv,1), v(vv,2), 22 : v(vv,4), v(vv,5), v(vv,6) ] // EOM 23 : macro VV3(v,vv ) [ v(vv,1), v(vv,2) ] // EOM 24 : // so formal matrix to build problem.. 25 : func C5x5 = 1 : [ [ CC(1,1), CC(2,1),CC(4,1), CC(5,1),CC(6,1) ] , 82 CHAPTER 4. SYNTAX [ CC(1,2), CC(2,2),CC(4,2), CC(5,2),CC(6,2) ] , 1 : [ CC(1,4), CC(2,4),CC(4,4), CC(5,4),CC(6,4) ] , [ CC(1,5), CC(2,5),CC(4,5), CC(5,5),CC(6,5) ] , [ CC(1,6), CC(2,6),CC(4,6), CC(5,6),CC(6,6) ] ] ; 26 : func E5x2 = 1 : [ [ EE(1,1), EE(2,1) ] , [ EE(1,2), EE(2,2) ] , 1 : [ EE(1,4), EE(2,4) ] , [ EE(1,5), EE(2,5) ] , [ EE(1,6), EE(2,6) ] ] ; 27 : func Eps = [ [ EEps(1,1), EEps(2,1) ] , [ EEps(1,2), EEps(2,2) ] ] ; 28 : finally the operator # to do concatenation of parameter: to build vectorial operation, like in macro div(u) (dx(u#1)+ dy(u#2)) // EOM mesh Th=square(2,2); fespace Vh(Th,P1); Vh v1=x,v2=y; cout << int2d(Th)(div(v)) << endl; The freefem++ code created : 31 : macro div(u ) (dx(u#1)+ dy(u#2)) //EOM 32 : mesh Th=square(2,2); fespace Vh(Th,P1); 33 : Vh v1=x,v2=y; 34 : cout << int2d(Th)( (dx(v1)+ dy(v2)) ) << endl; And to finish a amazing test to verified the quoting : macro foo(i,j,k) i j k // EOM foo(,,) // empty line foo( {int [}, {int] a(10},{);}) the result: 36 : macro foo(i,j,k ) i j k//EOM 37 : // empty line 38 : int [ int] a(10 ); To defined macro in a macro you can use the two new word NewMacro , EndMacro key word to set and and claose de macro definition (version 3.11, and not well tested). 4.13 Exception handling In the version 2.3 of FreeFem++, exception handing was added as in C++. But today only the C++ exceptions are caught. Note that in C++ all the errors attached to ExecError, assert, exit, ... call exceptions too so it may be hard to find the cause of the error. The exceptions handle all ExecError: 4.13. EXCEPTION HANDLING 83 Example 4.9 A simple example: catch a division by zero: real a; try { a=1./0.; } catch (...) // in versions > 2.3 all exceptions can be caught { cout << " Catch an ExecError " << endl; a =0; } The output is 1/0 : d d d current line = 3 Exec error : Div by 0 -- number :1 Try:: catch (...) exception Catch an ExecError Example 4.10 : a more realistic example with a none invertible matrix: int nn=5 ; mesh Th=square(nn,nn); verbosity=5; fespace Vh(Th,P1); // P1 FE space Vh uh,vh; // unkown and test function. func f=1; // right hand side function func g=0; // boundary condition function real cpu=clock(); problem laplace(uh,vh,solver=Cholesky,tolpivot=1e-6) = // definion of the problem int2d(Th)( dx(uh) * dx(vh) + dy(uh) * dy(vh) ) // bilinear form + int2d(Th)( -f * vh ) // linear form ; try { cout << " Try Cholesky \n"; laplace; // solve the problem plot(uh); // to see the result cout << "-- lap Cholesky " << nn << "x" << nn << " : " << -cpu+clock() << " s, max =" << uh[].max << endl; } catch(...) { // catch all cout << " Catch cholesky PB " << endl; } The output is 84 CHAPTER 4. SYNTAX -- square mesh : nb vertices =36 , nb triangles = 50 ... Nb of edges on Mortars = 0 Nb of edges on Boundary = 20, neb = 20 Nb Mortars 0 number of real boundary edges 20 Number of Edges = 85 Number of Boundary Edges = 20 neb = 20 Number of Mortars Edges = 0 Nb Of Mortars with Paper Def = 0 Nb Of Mortars = 0 ... Nb Of Nodes = 36 Nb of DF = 36 Try Cholesky -- Change of Mesh 0 0x312e9e8 Problem(): initmat 1 VF (discontinuous Galerkin) = 0 -- SizeOfSkyline =210 -- size of Matrix 196 Bytes skyline =1 -- discontinous Galerkin =0 size of Mat =196 Bytes -- int in Optimized = 1, ... all -- boundary int Optimized = 1, all ERREUR choleskypivot (35)= -1.23124e-13 < 1e-06 current line = 28 Exec error : FATAL ERREUR dans ../femlib/MatriceCreuse_tpl.hpp cholesky line: -- number :545 catch an erreur in solve => set sol = 0 !!!!!!! Try:: catch (...) exception Catch cholesky PB Chapter 5 Mesh Generation 5.1 Commands for Mesh Generation Let us begin with the two important keywords border and buildmesh All examples in this section come from the files mesh.edp and tablefunction.edp. 5.1.1 Square The command“square” triangulates the unit square. The following mesh Th = square(4,5); generates a 4 5 grid in the unit square [0, 1] 2 . The labels of the boundaries are shown in Fig. 5.1. To construct a n m grid in the rectangle [x 0 , x 1 ] [y 0 , y 1 ], proceeds as follows: l abel =4 l abel =1 l abel =3 l abel =2 Figure 5.1: Boundary labels of the mesh by square(10,10) write real x0=1.2,x1=1.8; real y0=0,y1=1; int n=5,m=20; mesh Th=square(n,m,[x0+(x1-x0) * x,y0+(y1-y0) * y]); 85 86 CHAPTER 5. MESH GENERATION Note 5.1 Adding the named parameter flags=icase with icase: 0 will produce a mesh where all quads are split with diagonal x −y = cte 1 will produce Union Jack flag type of mesh. 2 will produce a mesh where all quads are split with diagonal x + y = cte (v 3.8) 3 same as case 0 except in two corners such that no triangle with 3 vertices on boundary (v 3.8) 4 same as case 2 except in two corners such that no triangle with 3 vertices on boundary (v 3.8) mesh Th=square(n,m,[x0+(x1-x0) * x,y0+(y1-y0) * y],flags=icase); Adding the named parameter label=labs will change the 4 default label numbers to labs[i-1], for example int[int] labs=[11,12,13,14], and adding the named parameter region=10 will change the region number to 10, for instance (v 3.8). To see all these fags at work, try the file examples++/square-mesh.edp : for (int i=0;i<5;++i) { int[int] labs=[11,12,13,14]; mesh Th=square(3,3,flags=i,label=labs,region=10); plot(Th,wait=1,cmm=" square flags = "+i ); } 5.1.2 Border Boundaries are defined piecewise by parametrized curves. The pieces can only intersect at their endpoints, but it is possible to join more than two endpoints. This can be used to structure the mesh if an area thouches a border and create new regions by dividing larger ones: int upper = 1; int others = 2; int inner = 3; border C01(t=0,1){x = 0; y = -1+t; label = upper;} border C02(t=0,1){x = 1.5-1.5 * t; y = -1; label = upper;} border C03(t=0,1){x = 1.5; y = -t; label = upper;} border C04(t=0,1){x = 1+0.5 * t; y = 0; label = others;} border C05(t=0,1){x = 0.5+0.5 * t; y = 0; label = others;} border C06(t=0,1){x = 0.5 * t; y = 0; label = others;} border C11(t=0,1){x = 0.5; y = -0.5 * t; label = inner;} border C12(t=0,1){x = 0.5+0.5 * t; y = -0.5; label = inner;} 5.1. COMMANDS FOR MESH GENERATION 87 border C13(t=0,1){x = 1; y = -0.5+0.5 * t; label = inner;} int n = 10; plot(C01(-n)+C02(-n)+C03(-n)+C04(-n)+C05(-n)+C06(-n)+ C11(n)+C12(n)+C13(n), wait=true); mesh Th = buildmesh(C01(-n)+C02(-n)+C03(-n)+C04(-n)+C05(-n)+C06(-n)+ C11(n)+C12(n)+C13(n)); plot(Th, wait=true); // figure 5.3 cout << "Part 1 has region number " << Th(0.75, -0.25).region << endl; cout << "Part 2 has redion number " << Th(0.25, -0.25).region << endl; Figure 5.2: Multiple border ends intersect Figure 5.3: Generated mesh Triangulation keywords assume that the domain is defined as being on the left (resp right) of its oriented parameterized boundary Γ j = ¦(x, y) [ x = ϕ x (t), y = ϕ y (t), a j ≤ t ≤ b j ¦ To check the orientation plot t → (ϕ x (t), ϕ y (t)), t 0 ≤ t ≤ t 1 . If it is as in Fig. 5.4, then the domain lies on the shaded area, otherwise it lies on the opposite side The general expression to define a triangulation with buildmesh is mesh Mesh_Name = buildmesh(Γ 1 (m 1 ) + + Γ J (m j ) OptionalParameter); where m j are positive or negative numbers to indicate how many vertices should be on Γ j , Γ = ∪ J j=1 Γ J , and the optional parameter (separed with comma) can be nbvx=<int value> , to set the maximal number of vertices in the mesh. fixeborder=<bool value> , to say if the mesh generator can change the boundary mesh or not (by default the boundary mesh can change; beware that with periodic boundary conditions (see. 6), it can be dangerous . 88 CHAPTER 5. MESH GENERATION G j t = t 0 t = t 1 (x = j x (t), y = j y (t)) (dj x (t)/dt, dj y (t)/dt) (x = t, y = t) (x = t, y = -t) t = t 0 t = t 1 t = t 1 t = t 0 Figure 5.4: Orientation of the boundary defined by (φ x (t), φ y (t)) The orientation of boundaries can be changed by changing the sign of m j . The following example shows how to change the orientation. The example generates the unit disk with a small circular hole, and assign “1” to the unit disk (“2” to the circle inside). The boundary label must be non-zero, but it can also be omitted. 1: border a(t=0,2 * pi){ x=cos(t); y=sin(t);label=1;} 2: border b(t=0,2 * pi){ x=0.3+0.3 * cos(t); y=0.3 * sin(t);label=2;} 3: plot(a(50)+b(+30)) ; // to see a plot of the border mesh 4: mesh Thwithouthole= buildmesh(a(50)+b(+30)); 5: mesh Thwithhole = buildmesh(a(50)+b(-30)); 6: plot(Thwithouthole,wait=1,ps="Thwithouthole.eps"); // figure 5.5 7: plot(Thwithhole,wait=1,ps="Thwithhole.eps"); // figure 5.6 Note 5.2 Notice that the orientation is changed by “b(-30)” in 5th line. In 7th line, ps="fileName" is used to generate a postscript file with identification shown on the figure. Figure 5.5: mesh without hole Figure 5.6: mesh with hole Note 5.3 Borders are evaluated only at the time plot or buildmesh is called so the global variable are defined at this time andhere since r is changed between the two border calls the following code will not work because the first border will be computed with r=0.3: 5.1. COMMANDS FOR MESH GENERATION 89 real r=1; border a(t=0,2 * pi){ x=r * cos(t); y=r * sin(t);label=1;} r=0.3 ; border b(t=0,2 * pi){ x=r * cos(t); y=r * sin(t);label=1;} mesh Thwithhole = buildmesh(a(50)+b(-30)); // bug (a trap) because // the two circle have the same radius = 0.3 5.1.3 Data Structures and Read/Write Statements for a Mesh Users who want to read a triangulation made elsewhere should see the structure of the file generated below: border C(t=0,2 * pi) { x=cos(t); y=sin(t); } mesh Th = buildmesh(C(10)); savemesh("mesh_sample.msh"); the mesh is shown on Fig. 5.7. The informations about Th are saved in the file “mesh sample.msh”. whose structure is shown on Table 5.1. There n v denotes the number of vertices, n t number of triangles and n s the number of edges on boundary. For each vertex q i , i = 1, , n v , denote by (q i x , q i y ) the x-coordinate and y-coordinate. Each triangle T k , k = 1, , 10 has three vertices q k 1 , q k 2 , q k 3 that are oriented counterclock- wise. The boundary consists of 10 lines L i , i = 1, , 10 whose end points are q i 1 , q i 2 . 1 2 1 1 3 1 3 5 4 5 3 8 9 7 1 1 8 1 2 1 4 1 3 1 0 6 9 2 1 3 1 4 1 0 1 5 1 4 6 7 1 2 Figure 5.7: mesh by buildmesh(C(10)) In the left figure, we have the following. n v = 14, n t = 16, n s = 10 q 1 = (−0.309016994375, 0.951056516295) . . . . . . . . . q 14 = (−0.309016994375, −0.951056516295) The vertices of T 1 are q 9 , q 12 , q 10 . . . . . . . . . . The vertices of T 16 are q 9 , q 10 , q 6 . The edge of 1st side L 1 are q 6 , q 5 . . . . . . . . . . The edge of 10th side L 10 are q 10 , q 6 . In FreeFem++ there are many mesh file formats available for communication with other tools such as emc2, modulef.. (see Section 12), The extension of a file implies its format. More details can be found on the file format .msh in the article by F. Hecht ”bamg : a bidimentional anisotropic mesh generator” (downloadable from the FreeFem web site. ) 90 CHAPTER 5. MESH GENERATION Content of the file Explanation 14 16 10 n v n t n e -0.309016994375 0.951056516295 1 q 1 x q 1 y boundary label=1 0.309016994375 0.951056516295 1 q 2 x q 2 y boundary label=1 . . . -0.309016994375 -0.951056516295 1 q 14 x q 14 y boundary label=1 9 12 10 0 1 1 1 2 1 3 region label=0 5 9 6 0 2 1 2 2 2 3 region label=0 9 10 6 0 16 1 16 2 16 3 region label=0 6 5 1 1 1 1 2 boundary label=1 5 2 1 2 1 2 2 boundary label=1 10 6 1 10 1 10 2 boundary label=1 Table 5.1: The structure of “mesh sample.msh” A mesh file can be read into FreeFem++ except that the names of the borders are lost and only their reference numbers are kept. So these borders have to be referenced by the number which corresponds to their order of appearance in the program, unless this number is overwritten by the keyword ”label”. Here are some examples: border floor(t=0,1){ x=t; y=0; label=1;}; // the unit square border right(t=0,1){ x=1; y=t; label=5;}; border ceiling(t=1,0){ x=t; y=1; label=5;}; border left(t=1,0){ x=0; y=t; label=5;}; int n=10; mesh th= buildmesh(floor(n)+right(n)+ceiling(n)+left(n)); savemesh(th,"toto.am_fmt"); // "formatted Marrocco" format savemesh(th,"toto.Th"); // "bamg"-type mesh savemesh(th,"toto.msh"); // freefem format savemesh(th,"toto.nopo"); // modulef format see [10] mesh th2 = readmesh("toto.msh"); // read the mesh Example 5.1 (Readmesh.edp) border floor(t=0,1){ x=t; y=0; label=1;}; // the unit square border right(t=0,1){ x=1; y=t; label=5;}; border ceiling(t=1,0){ x=t; y=1; label=5;}; border left(t=1,0){ x=0; y=t; label=5;}; int n=10; mesh th= buildmesh(floor(n)+right(n)+ceiling(n)+left(n)); savemesh(th,"toto.am_fmt"); // format "formated Marrocco" savemesh(th,"toto.Th"); // format database db mesh "bamg" savemesh(th,"toto.msh"); // format freefem savemesh(th,"toto.nopo"); // modulef format see [10] mesh th2 = readmesh("toto.msh"); fespace femp1(th,P1); femp1 f = sin(x) * cos(y),g; 5.1. COMMANDS FOR MESH GENERATION 91 { // save solution ofstream file("f.txt"); file << f[] << endl; } // close the file (end block) { // read ifstream file("f.txt"); file >> g[] ; } // close reading file (end block) fespace Vh2(th2,P1); Vh2 u,v; plot(g); // find u such that // u + ∆u = g in Ω , // u = 0 on Γ 1 and ∂u ∂n = g on Γ 2 solve pb(u,v) = int2d(th)( u * v - dx(u) * dx(v)-dy(u) * dy(v) ) + int2d(th)(-g * v) + int1d(th,5)( g * v) // ∂u ∂n = g on Γ 2 + on(1,u=0) ; plot (th2,u); 5.1.4 Mesh Connectivity The following example explains methods to obtain mesh information. { // get mesh information (version 1.37) mesh Th=square(2,2); // get data of the mesh int nbtriangles=Th.nt; cout << " nb of Triangles = " << nbtriangles << endl; for (int i=0;i<nbtriangles;i++) for (int j=0; j <3; j++) cout << i << " " << j << " Th[i][j] = " << Th[i][j] << " x = "<< Th[i][j].x << " , y= "<< Th[i][j].y << ", label=" << Th[i][j].label << endl; // Th(i) return the vextex i of Th // Th[k] return the triangle k of Th fespace femp1(Th,P1); femp1 Thx=x,Thy=y; // hack of get vertex coordinates // get vertices information : int nbvertices=Th.nv; cout << " nb of vertices = " << nbvertices << endl; for (int i=0;i<nbvertices;i++) cout << "Th(" <<i << ") : " // << endl; << Th(i).x << " " << Th(i).y << " " << Th(i).label // v 2.19 << " old method: " << Thx[][i] << " " << Thy[][i] << endl; // method to find information of point (0.55,0.6) int it00 = Th(0.55,0.6).nuTriangle; // then triangle number int nr00 = Th(0.55,0.6).region; // 92 CHAPTER 5. MESH GENERATION // info of a triangle real area00 = Th[it00].area; // new in version 2.19 real nrr00 = Th[it00].region; // new in version 2.19 real nll00 = Th[it00].label; // same as region in this case. // Hack to get a triangle containing point x,y // or region number (old method) // ------------------------------------------------------- fespace femp0(Th,P0); femp0 nuT; // a P0 function to get triangle numbering for (int i=0;i<Th.nt;i++) nuT[][i]=i; femp0 nuReg=region; // a P0 function to get the region number // inquire int it0=nuT(0.55,0.6); // number of triangle Th’s containing (0.55,0,6); int nr0=nuReg(0.55,0.6);// number of region of Th’s containing (0.55,0,6); // dump // ------------------------------------------------------- cout << " point (0.55,0,6) :triangle number " << it00 << " " << it00 << ", region = " << nr0 << " == " << nr00 << ", area K " << area00 << endl; // new method to get boundary information and mesh adjacent int k=0,l=1,e=1; Th.nbe ; // return the number of boundary element Th.be(k); // return the boundary element k ∈ ¦0, ..., Th.nbe −1¦ Th.be(k)[l]; // return the vertices l ∈ ¦0, 1¦ of boundary elmt k Th.be(k).Element ; // return the triangle containing the boundary elmt k Th.be(k).whoinElement ; // return the edge number of triangle containing // the boundary elmt k Th[k].adj(e) ; // return adjacent triangle to k by edge e, and change // the value of e to the corresponding edge in the adjacent triangle Th[k] == Th[k].adj(e) // non adjacent triangle return the same Th[k] != Th[k].adj(e) // true adjacent triangle cout << " print mesh connectivity " << endl; int nbelement = Th.nt; for (int k=0;k<nbelement;++k) cout << k << " : " << int(Th[k][0]) << " " << int(Th[k][1]) << " " << int(Th[k][2]) << " , label " << Th[k].label << endl; // for (int k=0;k<nbelement;++k) for (int e=0,ee;e<3;++e) // remark FH hack: set ee to e, and ee is change by method adj, // in () to make difference with named parameters. cout << k << " " << e << " <=> " << int(Th[k].adj((ee=e))) << " " << ee << " adj: " << ( Th[k].adj((ee=e)) != Th[k]) << endl; // note : if k == int(Th[k].adj(ee=e)) not adjacent element 5.1. COMMANDS FOR MESH GENERATION 93 int nbboundaryelement = Th.nbe; for (int k=0;k<nbboundaryelement;++k) cout << k << " : " << Th.be(k)[0] << " " << Th.be(k)[1] << " , label " << Th.be(k).label << " tria " << int(Th.be(k).Element) << " " << Th.be(k).whoinElement << endl; } the output is: -- square mesh : nb vertices =9 , nb triangles = 8 , nb boundary edges 8 Nb of Vertices 9 , Nb of Triangles 8 Nb of edge on user boundary 8 , Nb of edges on true boundary 8 number of real boundary edges 8 nb of Triangles = 8 0 0 Th[i][j] = 0 x = 0 , y= 0, label=4 0 1 Th[i][j] = 1 x = 0.5 , y= 0, label=1 0 2 Th[i][j] = 4 x = 0.5 , y= 0.5, label=0 ... 6 0 Th[i][j] = 4 x = 0.5 , y= 0.5, label=0 6 1 Th[i][j] = 5 x = 1 , y= 0.5, label=2 6 2 Th[i][j] = 8 x = 1 , y= 1, label=3 7 0 Th[i][j] = 4 x = 0.5 , y= 0.5, label=0 7 1 Th[i][j] = 8 x = 1 , y= 1, label=3 7 2 Th[i][j] = 7 x = 0.5 , y= 1, label=3 Nb Of Nodes = 9 Nb of DF = 9 -- vector function’s bound 0 1 -- vector function’s bound 0 1 nb of vertices = 9 Th(0) : 0 0 4 old method: 0 0 Th(1) : 0.5 0 1 old method: 0.5 0 ... Th(7) : 0.5 1 3 old method: 0.5 1 Th(8) : 1 1 3 old method: 1 1 Nb Of Nodes = 8 Nb of DF = 8 print mesh connectivity 0 : 0 1 4 , label 0 1 : 0 4 3 , label 0 ... 6 : 4 5 8 , label 0 7 : 4 8 7 , label 0 0 0 <=> 3 1 adj: 1 0 1 <=> 1 2 adj: 1 0 2 <=> 0 2 adj: 0 ... 6 2 <=> 3 0 adj: 1 7 0 <=> 7 0 adj: 0 7 1 <=> 4 0 adj: 1 7 2 <=> 6 1 adj: 1 0 : 0 1 , label 1 tria 0 2 94 CHAPTER 5. MESH GENERATION 1 : 1 2 , label 1 tria 2 2 ... 6 : 0 3 , label 4 tria 1 1 7 : 3 6 , label 4 tria 5 1 5.1.5 The keyword ”triangulate” FreeFem++ is able to build a triangulation from a set of points. This triangulation is a Delaunay mesh of the convex hull of the set of points. It can be useful to build a mesh form a table function. The coordinates of the points and the value of the table function are defined separately with rows of the form: x y f(x,y) in a file such as: 0.51387 0.175741 0.636237 0.308652 0.534534 0.746765 0.947628 0.171736 0.899823 0.702231 0.226431 0.800819 0.494773 0.12472 0.580623 0.0838988 0.389647 0.456045 ............... Figure 5.8: Delaunay mesh of the convex hull of point set in file xyf Figure 5.9: Isovalue of table function The third column of each line is left untouched by the triangulate command. But you can use this third value to define a table function with rows of the form: x y f(x,y). The following example shows how to make a mesh from the file “xyf” with the format stated just above. The command triangulate command use only use 1st and 2nd rows. mesh Thxy=triangulate("xyf"); // build the Delaunay mesh of the convex hull // points are defined by the first 2 columns of file xyf plot(Thxy,ps="Thxyf.ps"); // (see figure 5.8) fespace Vhxy(Thxy,P1); // create a P1 interpolation Vhxy fxy; // the function // reading the 3rd row to define the function { ifstream file("xyf"); real xx,yy; 5.2. BOUNDARY FEM SPACES BUILT AS EMPTY MESHES 95 for(int i=0;i<fxy.n;i++) file >> xx >>yy >> fxy[][i]; // to read third row only. // xx and yy are just skipped } plot(fxu,ps="xyf.eps"); // plot the function (see figure 5.9) One new way to build a mesh is to have two arrays one the x values and the other for the y values (version 2.23-2): Vhxy xx=x,yy=y; // to set two arrays for the x’s and y’s mesh Th=triangulate(xx[],yy[]); 5.2 Boundary FEM Spaces Built as Empty Meshes To define a Finite Element space on a boundary, we came up with the idea of a mesh with no internal points (call empty mesh). It can be useful to handle Lagrange multipliers in mixed and mortar methods. So the function emptymesh remove all the internal points of a mesh except points on internal boundaries. { // new stuff 2004 emptymesh (version 1.40) // -- useful to build Multiplicator space // build a mesh without internal point // with the same boundary // ----- assert(version>=1.40); border a(t=0,2 * pi){ x=cos(t); y=sin(t);label=1;} mesh Th=buildmesh(a(20)); Th=emptymesh(Th); plot(Th,wait=1,ps="emptymesh-1.eps"); // see figure 5.10 } It is also possible to build an empty mesh of a pseudo subregion with emptymesh(Th,ssd) using the set of edges of the mesh Th; a edge e is in this set if with the two adjacent triangles e = t1 ∩ t2 and ssd[T1] = ssd[T2] where ssd refers to the pseudo region numbering of triangles, when they are stored in an int[int] array of size the number of triangles. { // new stuff 2004 emptymesh (version 1.40) // -- useful to build Multiplicator space // build a mesh without internal point // of peusdo sub domain // ----- assert(version>=1.40); mesh Th=square(10,10); int[int] ssd(Th.nt); for(int i=0;i<ssd.n;i++) // build the pseudo region numbering { int iq=i/2; // because 2 triangle per quad int ix=iq%10; // int iy=iq/10; // ssd[i]= 1 + (ix>=5) + (iy>=5) * 2; } Th=emptymesh(Th,ssd); // build emtpy with 96 CHAPTER 5. MESH GENERATION // all edge e = T1 ∩ T2 and ssd[T1] = ssd[T2] plot(Th,wait=1,ps="emptymesh-2.eps"); // see figure 5.11 savemesh(Th,"emptymesh-2.msh"); } Figure 5.10: The empty mesh with bound- ary Figure 5.11: An empty mesh defined from a pseudo region numbering of triangle 5.3 Remeshing 5.3.1 Movemesh Meshes can be translated, rotated and deformed by movemesh; this is useful for elasticity to watch the deformation due to the displacement Φ(x, y) = (Φ 1 (x, y), Φ 2 (x, y)) of shape. It is also useful to handle free boundary problems or optimal shape problems. If Ω is triangulated as T h (Ω), and Φ is a displacement vector then Φ(T h ) is obtained by mesh Th=movemesh(Th,[Φ1,Φ2]); Sometimes the transformed mesh is invalid because some triangle have flip over (now has negative area).To spot such problems one may check the minimum triangle area in the transformed mesh with checkmovemesh before any real transformation. Example 5.2 Φ 1 (x, y) = x+k∗sin(y∗π)/10), Φ 2 (x, y) = y+k∗cos(yπ)/10) for a big number k > 1. verbosity=4; border a(t=0,1){x=t;y=0;label=1;}; border b(t=0,0.5){x=1;y=t;label=1;}; border c(t=0,0.5){x=1-t;y=0.5;label=1;}; border d(t=0.5,1){x=0.5;y=t;label=1;}; border e(t=0.5,1){x=1-t;y=1;label=1;}; 5.3. REMESHING 97 border f(t=0,1){x=0;y=1-t;label=1;}; func uu= sin(y * pi)/10; func vv= cos(x * pi)/10; mesh Th = buildmesh ( a(6) + b(4) + c(4) +d(4) + e(4) + f(6)); plot(Th,wait=1,fill=1,ps="Lshape.eps"); // see figure 5.12 real coef=1; real minT0= checkmovemesh(Th,[x,y]); // the min triangle area while(1) // find a correct move mesh { real minT=checkmovemesh(Th,[x+coef * uu,y+coef * vv]);// the min triangle area if (minT > minT0/5) break ; // if big enough coef/=1.5; } Th=movemesh(Th,[x+coef * uu,y+coef * vv]); plot(Th,wait=1,fill=1,ps="movemesh.eps"); // see figure 5.13 Figure 5.12: L-shape Figure 5.13: moved L-shape Note 5.4 Consider a function u defined on a mesh Th. A statement like Th=movemesh(Th...) does not change u and so the old mesh still exists. It will be destroyed when no function use it. A statement like u = u redefines u on the new mesh Th with interpolation and therefore destroys the old Th if u was the only function using it. Example 5.3 (movemesh.edp) Now, we given an example of moving mesh with a lagrangian function u defined on the moving mesh. // simple movemesh example mesh Th=square(10,10); fespace Vh(Th,P1); real t=0; // --- // the problem is how to build data without interpolation // so the data u is moving with the mesh as you can see in the plot 98 CHAPTER 5. MESH GENERATION // --- Vh u=y; for (int i=0;i<4;i++) { t=i * 0.1; Vh f= x * t; real minarea=checkmovemesh(Th,[x,y+f]); if (minarea >0 ) // movemesh will be ok Th=movemesh(Th,[x,y+f]); cout << " Min area " << minarea << endl; real[int] tmp(u[].n); tmp=u[]; // save the value u=0; // to change the FEspace and mesh associated with u u[]=tmp; // set the value of u without any mesh update plot(Th,u,wait=1); }; // In this program, since u is only defined on the last mesh, all the // previous meshes are deleted from memory. // -------- 5.4 Regular Triangulation: hTriangle For a set S, we define the diameter of S by diam(S) = sup¦[x −y[; x, y ∈ S¦ The sequence ¦T h ¦ h↓0 of Ω is called regular if they satisfy the following: 1. lim h↓0 max¦diam(T k )[ T k ∈ T h ¦ = 0 2. There is a number σ > 0 independent of h such that ρ(T k ) diam(T k ) ≥ σ for all T k ∈ T h where ρ(T k ) are the diameter of the inscribed circle of T k . We put h(T h ) = max¦diam(T k )[ T k ∈ T h ¦, which is obtained by mesh Th = ......; fespace Ph(Th,P0); Ph h = hTriangle; cout << "size of mesh = " << h[].max << endl; 5.5. ADAPTMESH 99 5.5 Adaptmesh The function f(x, y) = 10.0x 3 + y 3 + tan −1 [ε/(sin(5.0y) −2.0x)] ε = 0.0001 sharply varies in value and the initial mesh given by one of the commands of Section 5.1 cannot reflect its sharp variations. Example 5.4 real eps = 0.0001; real h=1; real hmin=0.05; func f = 10.0 * xˆ3+yˆ3+h * atan2(eps,sin(5.0 * y)-2.0 * x); mesh Th=square(5,5,[-1+2 * x,-1+2 * y]); fespace Vh(Th,P1); Vh fh=f; plot(fh); for (int i=0;i<2;i++) { Th=adaptmesh(Th,fh); fh=f; // old mesh is deleted plot(Th,fh,wait=1); } FreeFem++ uses a variable metric/Delaunay automatic meshing algorithm. The command mesh ATh = adaptmesh(Th, f); create the new mesh ATh adapted to the Hessian D 2 f = (∂ 2 f/∂x 2 , ∂ 2 f/∂x∂y, ∂ 2 f/∂y 2 ) of a function (formula or FE-function). Mesh adaptation is a very powerful tool when the solution of a problem varies locally and sharply. Here we solve the problem (2.1)-(2.2), when f = 1 and Ω is a L-shape domain. Example 5.5 (Adapt.edp) The solution has the singularity r 3/2 , r = [x − γ[ at the point γ of the intersection of two lines bc and bd (see Fig. 5.15). border ba(t=0,1.0){x=t; y=0; label=1;}; border bb(t=0,0.5){x=1; y=t; label=1;}; border bc(t=0,0.5){x=1-t; y=0.5;label=1;}; border bd(t=0.5,1){x=0.5; y=t; label=1;}; border be(t=0.5,1){x=1-t; y=1; label=1;}; border bf(t=0.0,1){x=0; y=1-t;label=1;}; mesh Th = buildmesh ( ba(6)+bb(4)+bc(4)+bd(4)+be(4)+bf(6) ); fespace Vh(Th,P1); // set FE space Vh u,v; // set unknown and test function func f = 1; real error=0.1; // level of error 100 CHAPTER 5. MESH GENERATION Initial mesh First adaptation Second adaptation Figure 5.14: 3D graphs for the initial mesh and 1st and 2nd mesh adaptation problem Poisson(u,v,solver=CG,eps=1.0e-6) = int2d(Th)( dx(u) * dx(v) + dy(u) * dy(v)) - int2d(Th) ( f * v ) + on(1,u=0) ; for (int i=0;i< 4;i++) { Poisson; Th=adaptmesh(Th,u,err=error); error = error/2; } ; plot(u); To speed up the adaptation the default parameter err of adaptmesh is changed by hand; it specifies the required precision, so as to make the new mesh finer or coarser. The problem is coercive and symmetric, so the linear system can be solved with the conjugate gradient method (parameter solver=CG with the stopping criteria on the residual, here eps=1.0e-6). By adaptmesh, the slope of the final solution is correctly computed near the point of intersection of bc and bd as in Fig. 5.16. This method is described in detail in [9]. It has a number of default parameters which can be modified : Si f1,f2 sont des functions et thold, Thnew des maillages. Thnew = adaptmesh(Thold, f1 ... ); Thnew = adaptmesh(Thold, f1,f2 ... ]); Thnew = adaptmesh(Thold, [f1,f2] ... ); 5.5. ADAPTMESH 101 >= >> >? >@ >A >B Figure 5.15: L-shape domain and its boundary name Figure 5.16: Final solution after 4-times adaptation The additional paramters of adaptmesh not written here, hence the ”...” hmin= Minimum edge size. (val is a real. Its default is related to the size of the domain to be meshed and the precision of the mesh generator). hmax= Maximum edge size. (val is a real. It defaults to the diameter of the domain to be meshed) err= P 1 interpolation error level (0.01 is the default). errg= Relative geometrical error. By default this error is 0.01, and in any case it must be lower than 1/ √ 2. Meshes created with this option may have some edges smaller than the -hmin due to geometrical constraints. nbvx= Maximum number of vertices generated by the mesh generator (9000 is the default). nbsmooth= number of iterations of the smoothing procedure (5 is the default). nbjacoby= number of iterations in a smoothing procedure during the metric construction, 0 means no smoothing (6 is the default). ratio= ratio for a prescribed smoothing on the metric. If the value is 0 or less than 1.1 no smoothing is done on the metric (1.8 is the default). If ratio > 1.1, the speed of mesh size variations is bounded by log(ratio). Note: As ratio gets closer to 1, the number of generated vertices increases. This may be useful to control the thickness of refined regions near shocks or boundary layers . omega= relaxation parameter for the smoothing procedure (1.0 is the default). iso= If true, forces the metric to be isotropic (false is the default). 102 CHAPTER 5. MESH GENERATION abserror= If false, the metric is evaluated using the criterium of equi-repartion of relative error (false is the default). In this case the metric is defined by ´ = 1 err coef 2 [1[ max(CutOff, [η[) p (5.1) otherwise, the metric is evaluated using the criterium of equi-distribution of errors. In this case the metric is defined by ´ = 1 err coef 2 [1[ sup(η) −inf(η) p . (5.2) cutoff= lower limit for the relative error evaluation (1.0e-6 is the default). verbosity= informational messages level (can be chosen between 0 and ∞). Also changes the value of the global variable verbosity (obsolete). inquire= To inquire graphically about the mesh (false is the default). splitpbedge= If true, splits all internal edges in half with two boundary vertices (true is the default). maxsubdiv= Changes the metric such that the maximum subdivision of a background edge is bound by val (always limited by 10, and 10 is also the default). rescaling= if true, the function with respect to which the mesh is adapted is rescaled to be between 0 and 1 (true is the default). keepbackvertices= if true, tries to keep as many vertices from the original mesh as possible (true is the default). isMetric= if true, the metric is defined explicitly (false is the default). If the 3 functions m 11 , m 12 , m 22 are given, they directly define a symmetric matrix field whose Hessian is computed to define a metric. If only one function is given, then it represents the isotropic mesh size at every point. For example, if the partial derivatives fxx (= ∂ 2 f/∂x 2 ), fxy (= ∂ 2 f/∂x∂y), fyy (= ∂ 2 f/∂y 2 ) are given, we can set Th=adaptmesh(Th,fxx,fxy,fyy,IsMetric=1,nbvx=10000,hmin=hmin); power= exponent power of the Hessian used to compute the metric (1 is the default). thetamax= minimum corner angle of in degrees (default is 10 ◦ ) where the corner is ABC and the angle is the angle of the two vectors AB, BC, (0 imply no corner, 90 imply perp. corner , ...). splitin2= boolean value. If true, splits all triangles of the final mesh into 4 sub-triangles. 5.6. TRUNC 103 metric= an array of 3 real arrays to set or get metric data information. The size of these three arrays must be the number of vertices. So if m11,m12,m22 are three P1 finite el- ements related to the mesh to adapt, you can write: metric=[m11[],m12[],m22[]] (see file convect-apt.edp for a full example) nomeshgeneration= If true, no adapted mesh is generated (useful to compute only a metric). periodic= Writing periodic=[[4,y],[2,y],[1,x],[3,x]]; builds an adapted periodic mesh. The sample build a biperiodic mesh of a square. (see periodic finite element spaces 6, and see sphere.edp for a full example) We can use the command adaptmesh to build uniform mesh with a contant mesh size. So to build a mesh with a constant mesh size equal to 1 30 try: Example 5.6 uniformmesh.edp mesh Th=square(2,2); // to have initial mesh plot(Th,wait=1,ps="square-0.eps"); Th= adaptmesh(Th,1./3As writing 0.,IsMetric=1,nbvx=10000); // plot(Th,wait=1,ps="square-1.eps"); Th= adaptmesh(Th,1./30.,IsMetric=1,nbvx=10000); // more the one time du to Th= adaptmesh(Th,1./30.,IsMetric=1,nbvx=10000); // adaptation bound maxsubdiv= plot(Th,wait=1,ps="square-2.eps"); Figure 5.17: Initial mesh Figure 5.18: first iteration Figure 5.19: last iteration 5.6 Trunc Two operators have been introduce to remove triangles from a mesh or to divide them. Operator trunc has two parameters label= sets the label number of new boundary item (one by default) 104 CHAPTER 5. MESH GENERATION split= sets the level n of triangle splitting. each triangle is splitted in n n ( one by default). To create the mesh Th3 where alls triangles of a mesh Th are splitted in 33 , just write: mesh Th3 = trunc(Th,1,split=3); The truncmesh.edp example construct all ”trunc” mesh to the support of the basic function of the space Vh (cf. abs(u)>0), split all the triangles in 55, and put a label number to 2 on new boundary. mesh Th=square(3,3); fespace Vh(Th,P1); Vh u; int i,n=u.n; u=0; for (i=0;i<n;i++) // all degree of freedom { u[][i]=1; // the basic function i plot(u,wait=1); mesh Sh1=trunc(Th,abs(u)>1.e-10,split=5,label=2); plot(Th,Sh1,wait=1,ps="trunc"+i+".eps"); // plot the mesh of // the function’s support u[][i]=0; // reset } Figure 5.20: mesh of support the function P1 number 0, splitted in 55 Figure 5.21: mesh of support the function P1 number 6, splitted in 55 5.7 Splitmesh Another way to split mesh triangles is to use splitmesh, for example: { // new stuff 2004 splitmesh (version 1.37) 5.8. MESHING EXAMPLES 105 assert(version>=1.37); border a(t=0,2 * pi){ x=cos(t); y=sin(t);label=1;} mesh Th=buildmesh(a(20)); plot(Th,wait=1,ps="nosplitmesh.eps"); // see figure 5.22 Th=splitmesh(Th,1+5 * (square(x-0.5)+y * y)); plot(Th,wait=1,ps="splitmesh.eps"); // see figure 5.23 } Figure 5.22: initial mesh Figure 5.23: all left mesh triangle is split conformaly in int(1+5 * (square(x-0.5)+y * y) ˆ 2 triangles. 5.8 Meshing Examples Example 5.7 (Two rectangles touching by a side) border a(t=0,1){x=t;y=0;}; border b(t=0,1){x=1;y=t;}; border c(t=1,0){x=t ;y=1;}; border d(t=1,0){x = 0; y=t;}; border c1(t=0,1){x=t ;y=1;}; border e(t=0,0.2){x=1;y=1+t;}; border f(t=1,0){x=t ;y=1.2;}; border g(t=0.2,0){x=0;y=1+t;}; int n=1; mesh th = buildmesh(a(10 * n)+b(10 * n)+c(10 * n)+d(10 * n)); mesh TH = buildmesh ( c1(10 * n) + e(5 * n) + f(10 * n) + g(5 * n) ); plot(th,TH,ps="TouchSide.esp"); // Fig. 5.24 Example 5.8 (NACA0012 Airfoil) border upper(t=0,1) { x = t; 106 CHAPTER 5. MESH GENERATION y = 0.17735 * sqrt(t)-0.075597 * t - 0.212836 * (tˆ2)+0.17363 * (tˆ3)-0.06254 * (tˆ4); } border lower(t=1,0) { x = t; y= -(0.17735 * sqrt(t)-0.075597 * t -0.212836 * (tˆ2)+0.17363 * (tˆ3)-0.06254 * (tˆ4)); } border c(t=0,2 * pi) { x=0.8 * cos(t)+0.5; y=0.8 * sin(t); } mesh Th = buildmesh(c(30)+upper(35)+lower(35)); plot(Th,ps="NACA0012.eps",bw=1); // Fig. 5.25 a b c d h e f g (0, -1 0) (0, 0) (0, 2) (1 0, -1 0) TH th Figure 5.24: Two rectangles touching by a side Figure 5.25: NACA0012 Airfoil Example 5.9 (Cardioid) real b = 1, a = b; border C(t=0,2 * pi) { x=(a+b) * cos(t)-b * cos((a+b) * t/b); y=(a+b) * sin(t)-b * sin((a+b) * t/b); } mesh Th = buildmesh(C(50)); plot(Th,ps="Cardioid.eps",bw=1); // Fig. 5.26 Example 5.10 (Cassini Egg) border C(t=0,2 * pi) { x=(2 * cos(2 * t)+3) * cos(t); y=(2 * cos(2 * t)+3) * sin(t); } mesh Th = buildmesh(C(50)); plot(Th,ps="Cassini.eps",bw=1); // Fig. 5.27 Example 5.11 (By cubic Bezier curve) // A cubic Bezier curve connecting two points with two control points func real bzi(real p0,real p1,real q1,real q2,real t) { return p0 * (1-t)ˆ3+q1 * 3 * (1-t)ˆ2 * t+q2 * 3 * (1-t) * tˆ2+p1 * tˆ3; } real[int] p00=[0,1], p01=[0,-1], q00=[-2,0.1], q01=[-2,-0.5]; 5.8. MESHING EXAMPLES 107 Figure 5.26: Domain with Cardioid curve boundary Figure 5.27: Domain with Cassini Egg curve boundary real[int] p11=[1,-0.9], q10=[0.1,-0.95], q11=[0.5,-1]; real[int] p21=[2,0.7], q20=[3,-0.4], q21=[4,0.5]; real[int] q30=[0.5,1.1], q31=[1.5,1.2]; border G1(t=0,1) { x=bzi(p00[0],p01[0],q00[0],q01[0],t); y=bzi(p00[1],p01[1],q00[1],q01[1],t); } border G2(t=0,1) { x=bzi(p01[0],p11[0],q10[0],q11[0],t); y=bzi(p01[1],p11[1],q10[1],q11[1],t); } border G3(t=0,1) { x=bzi(p11[0],p21[0],q20[0],q21[0],t); y=bzi(p11[1],p21[1],q20[1],q21[1],t); } border G4(t=0,1) { x=bzi(p21[0],p00[0],q30[0],q31[0],t); y=bzi(p21[1],p00[1],q30[1],q31[1],t); } int m=5; mesh Th = buildmesh(G1(2 * m)+G2(m)+G3(3 * m)+G4(m)); plot(Th,ps="Bezier.eps",bw=1); // Fig 5.28 Example 5.12 (Section of Engine) real a= 6., b= 1., c=0.5; border L1(t=0,1) { x= -a; y= 1+b - 2 * (1+b) * t; } border L2(t=0,1) { x= -a+2 * a * t; y= -1-b * (x/a) * (x/a) * (3-2 * abs(x)/a );} border L3(t=0,1) { x= a; y=-1-b + (1+ b ) * t; } border L4(t=0,1) { x= a - a * t; y=0; } border L5(t=0,pi) { x= -c * sin(t)/2; y=c/2-c * cos(t)/2; } border L6(t=0,1) { x= a * t; y=c; } border L7(t=0,1) { x= a; y=c + (1+ b-c ) * t; } border L8(t=0,1) { x= a-2 * a * t; y= 1+b * (x/a) * (x/a) * (3-2 * abs(x)/a); } mesh Th = buildmesh(L1(8)+L2(26)+L3(8)+L4(20)+L5(8)+L6(30)+L7(8)+L8(30)); plot(Th,ps="Engine.eps",bw=1); // Fig. 5.29 Example 5.13 (Domain with U-shape channel) real d = 0.1; // width of U-shape border L1(t=0,1-d) { x=-1; y=-d-t; } 108 CHAPTER 5. MESH GENERATION / / /! /" Figure 5.28: Boundary drawed by Bezier curves L1 L1 L2 L3 L6 L7 L4 L5 Figure 5.29: Section of Engine border L2(t=0,1-d) { x=-1; y=1-t; } border B(t=0,2) { x=-1+t; y=-1; } border C1(t=0,1) { x=t-1; y=d; } border C2(t=0,2 * d) { x=0; y=d-t; } border C3(t=0,1) { x=-t; y=-d; } border R(t=0,2) { x=1; y=-1+t; } border T(t=0,2) { x=1-t; y=1; } int n = 5; mesh Th = buildmesh (L1(n/2)+L2(n/2)+B(n)+C1(n)+C2(3)+C3(n)+R(n)+T(n)); plot(Th,ps="U-shape.eps",bw=1); // Fig 5.30 Example 5.14 (Domain with V-shape cut) real dAg = 0.01; // angle of V-shape border C(t=dAg,2 * pi-dAg) { x=cos(t); y=sin(t); }; real[int] pa(2), pb(2), pc(2); pa[0] = cos(dAg); pa[1] = sin(dAg); pb[0] = cos(2 * pi-dAg); pb[1] = sin(2 * pi-dAg); pc[0] = 0; pc[1] = 0; border seg1(t=0,1) { x=(1-t) * pb[0]+t * pc[0]; y=(1-t) * pb[1]+t * pc[1]; }; border seg2(t=0,1) { x=(1-t) * pc[0]+t * pa[0]; y=(1-t) * pc[1]+t * pa[1]; }; mesh Th = buildmesh(seg1(20)+C(40)+seg2(20)); plot(Th,ps="V-shape.eps",bw=1); // Fig. 5.31 Example 5.15 (Smiling face) real d=0.1; int m=5; real a=1.5, b=2, c=0.7, e=0.01; border F(t=0,2 * pi) { x=a * cos(t); y=b * sin(t); } border E1(t=0,2 * pi) { x=0.2 * cos(t)-0.5; y=0.2 * sin(t)+0.5; } border E2(t=0,2 * pi) { x=0.2 * cos(t)+0.5; y=0.2 * sin(t)+0.5; } func real st(real t) { return sin(pi * t)-pi/2; 5.8. MESHING EXAMPLES 109 L1 C1 L2 C2 C3 B R T (-ca, cb) (ca, cb) (ti p, d) (ti p, -d) Figure 5.30: Domain with U-shape channel changed by d + IAC IAC Figure 5.31: Domain with V-shape cut changed by dAg } border C1(t=-0.5,0.5) { x=(1-d) * c * cos(st(t)); y=(1-d) * c * sin(st(t)); } border C2(t=0,1){x=((1-d)+d * t) * c * cos(st(0.5));y=((1-d)+d * t) * c * sin(st(0.5));} border C3(t=0.5,-0.5) { x=c * cos(st(t)); y=c * sin(st(t)); } border C4(t=0,1) { x=(1-d * t) * c * cos(st(-0.5)); y=(1-d * t) * c * sin(st(-0.5));} border C0(t=0,2 * pi) { x=0.1 * cos(t); y=0.1 * sin(t); } mesh Th=buildmesh(F(10 * m)+C1(2 * m)+C2(3)+C3(2 * m)+C4(3) +C0(m)+E1(-2 * m)+E2(-2 * m)); plot(Th,ps="SmileFace.eps",bw=1); // see Fig. 5.32 } Example 5.16 (3point bending) // Square for Three-Point Bend Specimens fixed on Fix1, Fix2 // It will be loaded on Load. real a=1, b=5, c=0.1; int n=5, m=b * n; border Left(t=0,2 * a) { x=-b; y=a-t; } border Bot1(t=0,b/2-c) { x=-b+t; y=-a; } border Fix1(t=0,2 * c) { x=-b/2-c+t; y=-a; } border Bot2(t=0,b-2 * c) { x=-b/2+c+t; y=-a; } border Fix2(t=0,2 * c) { x=b/2-c+t; y=-a; } border Bot3(t=0,b/2-c) { x=b/2+c+t; y=-a; } border Right(t=0,2 * a) { x=b; y=-a+t; } border Top1(t=0,b-c) { x=b-t; y=a; } border Load(t=0,2 * c) { x=c-t; y=a; } border Top2(t=0,b-c) { x=-c-t; y=a; } mesh Th = buildmesh(Left(n)+Bot1(m/4)+Fix1(5)+Bot2(m/2)+Fix2(5)+Bot3(m/4) +Right(n)+Top1(m/2)+Load(10)+Top2(m/2)); plot(Th,ps="ThreePoint.eps",bw=1); // Fig. 5.33 110 CHAPTER 5. MESH GENERATION . - - + - + +" Figure 5.32: Smiling face (Mouth is change- able) Left Ri ght Bot1 Bot2 Bot3 Top1 Top2 Load Fi x1 Fi x2 (-b, a) (b, -a) Figure 5.33: Domain for three-point bending test 5.9 How to change the label of elements and border elements of a mesh Changing the label of elements and border elements will be done using the keyword change. The parameters for this command line are for a two dimensional and dimensional case: label = is a vector of integer that contains successive pair of the old label number to the new label number . region = is a vector of integer that contains successive pair of the old region number to new region number. These vectors are composed of n l successive pair of number O, N where n l is the number (label or region) that we want to change. For example, we have label = [O 1 , N 1 , ..., O n l , N n l ] (5.3) region = [O 1 , N 1 , ..., O n l , N n l ] (5.4) An example of using this function is given in ”glumesh2D.edp”: Example 5.17 (glumesh2D.edp) 1: 2: mesh Th1=square(10,10); 3: mesh Th2=square(20,10,[x+1,y]); 4: verbosity=3; 5: int[int] r1=[2,0], r2=[4,0]; 6: plot(Th1,wait=1); 7: Th1=change(Th1,label=r1); // Change the label of Edges of Th1 with label 2 in 0. 8: plot(Th1,wait=1); 9: Th2=change(Th2,label=r2); // Change the label of Edges of Th2 with label 4 in 0. 10: mesh Th=Th1+Th2; // ‘‘gluing together’’ of meshes Th1 and Th2 11: cout << " nb lab = " << int1d(Th1,1,3,4)(1./lenEdge)+int1d(Th2,1,2,3)(1./lenEdge) 5.10. MESH IN THREE DIMENSIONS 111 12: << " == " << int1d(Th,1,2,3,4)(1./lenEdge) <<" == " << ((10+20)+10) * 2 << endl; 13: plot(Th,wait=1); 14: fespace Vh(Th,P1); 15: macro Grad(u) [dx(u),dy(u)]; // definition of a macro 16: Vh u,v; 17: solve P(u,v)=int2d(Th)(Grad(u)’ * Grad(v))-int2d(Th)(v)+on(1,3,u=0); 18: plot(u,wait=1); “gluing” different mesh In line 10 of previous file, the method to “gluing” different mesh of the same dimension in FreeFem++ is using. This function is just called using the symbol addition ”+” between meshes. The method implemented need that the point in adjacent mesh are the same. 5.10 Mesh in three dimensions 5.10.1 Read/Write Statements for a Mesh in 3D In three dimensions, the file mesh format supported for input and output files by FreeFem++ are the extension .msh and .mesh. These formats are described in the chapter on Mesh Files in two dimensions. extension file .msh The structure of the files with extension .msh in 3D is given in Table 5.2. In this structure, n v denotes the number of vertices, n tet the number of tetrahedra and n tri the number of triangles For each vertex q i , i = 1, , n v , we denote by (q i x , q i y , q i z ) the x-coordinate, the y-coordinate and the z-coordinate. Each tetrahedra T k , k = 1, , n tet has four vertices q k 1 , q k 2 , q k 3 , q k 4 . The boundary consists of an union of triangles. Each triangle be j , j = 1, , n tri has three vertices q j 1 , q j 2 , q j 3 . n v n tet n tri q 1 x q 1 y q 1 z Vertex label q 2 x q 2 y q 2 z Vertex label . . . . . . . . . . . . q n v x q n v y q n v z Vertex label 1 1 1 2 1 3 1 4 region label 2 1 2 2 2 3 2 4 region label . . . . . . . . . . . . . . . (n tet ) 1 (n tet ) 2 (n tet ) 3 (n tet ) 4 region label 1 1 1 2 1 3 boundary label 2 1 2 2 2 3 boundary label . . . . . . . . . . . . (n t ri) 1 (n tri ) 2 (n tri ) 3 boundary label Table 5.2: The structure of mesh file format “.msh” in three dimensions. 112 CHAPTER 5. MESH GENERATION extension file .mesh The data structure for a three dimensional mesh is composed of the data structure presented in Section 12.1 and a data structure for tetrahedra. The tetrahedra of a three dimensional mesh are refereed using the following field: • Tetrahedra (I) NbOfTetrahedrons ((@@Vertex j i , j=1,4 ), (I) Refφ tet i , i=1 , NbOfTetrahedrons ) This field is express with the notation of Section 12.1. 5.10.2 TeGen: A tetrahedral mesh generator TetGen TetGen is a software developed by Dr. Hang Si of Weierstrass Institute for Applied Anal- ysis and Stochastics of Berlin in Germany [36]. TetGen is a free for research and non-commercial uses. For any commercial licence utilization, a commercial licence is available upon request to Hang Si. This software is a tetrahedral mesh generator of a three dimensional domain defined by its boundary. The input domain take into account a polyhedral or a piecewise linear complex. This tetrahedral- ization is a constrained Delaunay tetrahedralization. The method used in TetGen to control the quality of the mesh is a Delaunay refinement due to Shewchuk [37]. The quality measure of this algorithm is the Radius-Edge Ratio (see Section 1.3.1 [36] for more details). A theoretical bounds of this ratio of the algorithm of Shewchuk is obtained for a given complex of vertices, constrained segments and facets of surface mesh, with no input angle less than 90 degree. This theoretical bounds is 2.0. The launch of Tetgen is done with the keyword tetg. The parameters of this command line is: label = is a vector of integer that contains the old labels number at index 2i and the new labels number at index 2i + 1 of Triangles. This parameters is initialized as label for the keyword change (5.3). switch = A string expression. This string corresponds to the command line switch of Tetgen see Section 3.2 of [36]. nbofholes= Number of holes (default value size of holelist/3 (version 3.11) ). holelist = This array correspond to holelist of tetgenio data structure [36]. A real vector of size 3 nbofholes. In TetGen, each hole is associated with a point inside this domain. This vector is x h 1 , y h 1 , z h 1 , x h 2 , y h 2 , z h 2 , , where x h i , y h i , z h i is the associated point with the i th hole. nbofregions = Number of regions (size of regionlist/5 (version 3.11) ). regionlist = This array corresponds to regionlist of tetgenio data structure [36]. The attribute and the volume constraint of region are given in this real vector of size 5 nbofregions. The i th region is described by five elements: x−coordinate, y−coordinate and z−coordinate of a point inside this domain (x i , y i , z i ); the attribute (at i ) and the maximum volume for tetrahe- dra (mvol i ) for this region. The regionlist vector is: x 1 , y 1 , z 1 , at 1 , mvol 1 , x 2 , y 2 , z 2 , at 2 , mvol 2 , . nboffacetcl= Number of facets constraints size of facetcl/2 (version 3.11) ). 5.10. MESH IN THREE DIMENSIONS 113 facetcl= This array corresponds to facetconstraintlist of tetgenio data structure [36]. The i th facet constraint is defined by the facet marker Ref fc i and the maximum area for faces marea fc i . The facetcl array is: Ref fc 1 , marea fc 1 , Ref fc 2 , marea fc 2 , . This parameters has no effect if switch q is not selected. Principal switch parameters in TetGen: p Tetrahedralization of boundary. q Quality mesh generation. The bound of Radius-Edge Ratio will be given after the option q. By default, this value is 2.0. a Construct with the volumes constraints on tetrahedra. These volumes constraints are defined with the bound of the previous switch q or in the parameter regionlist. A Attributes reference to region given in the regionlist. The other regions have label 0. The option AA gives a different label at each region. This switch work with the option ’p’. If option ’r’ is used, this switch has no effect. r Reconstructs and Refines a previously generated mesh. This character is only used with the command line tetgreconstruction. Y This switch allow to preserve the mesh on the exterior boundary. This switch must be used to ensure conformal mesh between two adjacents mesh. YY This switch allow to preserve the mesh on the exterior and interior boundary. C The consistency of the result’s mesh is testing by TetGen. CC The consistency of the result’s mesh is testing by TetGen and also checks constrained delaunay mesh (if ’p’ switch is selected) or the consistency of Conformal Delaunay (if ’q’ switch is selected). V Give information of the work of TetGen. More information can be obtained in specified ’VV’ or ’VVV’. Q Quiet: No terminal output except errors M The coplanar facets are not merging. T Set a tolerance for coplanar test. The default value is 1e −8. d Itersections of facets are detected. To obtain a tetrahedral mesh generator with tetgen, we need the surface mesh of three dimensional domain. We give now the command line in FreeFem++ to construct these meshes. keyword: “movemesh23” A simple method to construct a surface is to place a two dimensional domain in a three dimensional space. This corresponding to move the domain by a displacement vector of this form Φ(x, y) = (Φ1(x, y), Φ2(x, y), Φ3(x, y)). The result of moving a two dimensional mesh Th2 by this three dimensional displacement is obtained using: mesh3 Th3 = movemesh23(Th2,transfo=[Φ1,Φ2,Φ3]); The parameters of this command line are: 114 CHAPTER 5. MESH GENERATION transfo = [Φ1, Φ2, Φ3] set the displacement vector of transformation Φ(x, y) = [Φ1(x, y), Φ2(x, y), Φ3(x, y)]. label = set integer label of triangles orientation= set integer orientation of mesh. ptmerge = A real expression. When you transform a mesh, some points can be merged. This parameters is the criteria to define two merging points. By default, we use ptmerge = 1e −7 V ol(B), where B is the smallest axis parallel boxes containing the discretized domain of Ω and V ol(B) is the volume of this box. We can ‘do a ‘gluing” of surface meshes using the process given in Section 5.9. An example to obtain a three dimensional mesh using the command line tetg and movemesh23 is given in the file tetgencube.edp. Example 5.18 (tetgencube.edp) // file tetgencube.edp load "msh3" load "tetgen" real x0,x1,y0,y1; x0=1.; x1=2.; y0=0.; y1=2 * pi; mesh Thsq1 = square(5,35,[x0+(x1-x0) * x,y0+(y1-y0) * y]); func ZZ1min = 0; func ZZ1max = 1.5; func XX1 = x; func YY1 = y; mesh3 Th31h = movemesh23(Thsq1,transfo=[XX1,YY1,ZZ1max]); mesh3 Th31b = movemesh23(Thsq1,transfo=[XX1,YY1,ZZ1min]); // /////////////////////////////// x0=1.; x1=2.; y0=0.; y1=1.5; mesh Thsq2 = square(5,8,[x0+(x1-x0) * x,y0+(y1-y0) * y]); func ZZ2 = y; func XX2 = x; func YY2min = 0.; func YY2max = 2 * pi; mesh3 Th32h = movemesh23(Thsq2,transfo=[XX2,YY2max,ZZ2]); mesh3 Th32b = movemesh23(Thsq2,transfo=[XX2,YY2min,ZZ2]); // /////////////////////////////// x0=0.; x1=2 * pi; y0=0.; y1=1.5; mesh Thsq3 = square(35,8,[x0+(x1-x0) * x,y0+(y1-y0) * y]); func XX3min = 1.; func XX3max = 2.; func YY3 = x; func ZZ3 = y; 5.10. MESH IN THREE DIMENSIONS 115 mesh3 Th33h = movemesh23(Thsq3,transfo=[XX3max,YY3,ZZ3]); mesh3 Th33b = movemesh23(Thsq3,transfo=[XX3min,YY3,ZZ3]); // ////////////////////////////// mesh3 Th33 = Th31h+Th31b+Th32h+Th32b+Th33h+Th33b; // "gluing" surface meshs to obtain the surface of cube savemesh(Th33,"Th33.mesh"); // build a mesh of a axis parallel box with TetGen real[int] domain =[1.5,pi,0.75,145,0.0025]; mesh3 Thfinal = tetg(Th33,switch="paAAQY",regionlist=domain); // Tetrahelize the interior of the cube with tetgen savemesh(Thfinal,"Thfinal.mesh"); // build a mesh of a half cylindrical shell of interior radius 1. and exterior radius 2 and heigh 1.5 func mv2x = x * cos(y); func mv2y = x * sin(y); func mv2z = z; mesh3 Thmv2 = movemesh3(Thfinal, transfo=[mv2x,mv2y,mv2z]); savemesh(Thmv2,"halfcylindricalshell.mesh") The command movemesh is describe in the following section. The keyword “tetgtransfo” This keyword correspond to a composition of command line tetg and movemesh23: tetgtransfo( Th2, transfo= [Φ1, Φ2, Φ3] ), ) = tetg( Th3surf, ), where Th3surf = movemesh23( Th2,tranfo=[Φ1, Φ2, Φ3] ) and Th2 is the input two dimensional mesh of tetgtransfo. The parameters of this command line are on the one hand the parameters: label, switch, regionlist nboffacetcl facetcl of keyword tetg and on the other hand the parameter ptmerge of keyword movemesh23. Remark: To use tetgtransfo, the result’s mesh of movemesh23 must be an closed surface and define one region only. Therefore, the parameter regionlist is defined for one region. An example of this keyword can be found in line of file “buildlayers.edp” The keyword ”tetgconvexhull” FreeFem++ , using tetgen, is able to build a tetrahedralization from a set of points. This tetrahedralization is a Delaunay mesh of the convex hull of the set of points. The coordinates of the points can be initialized in two ways. The first is a file that contains the coordinate of points X i = (x i , y i , z i ). This files is organized as follows: n v x 1 y 1 z 1 x 2 y 2 z 2 . . . . . . . . . x n v y n v z n v 116 CHAPTER 5. MESH GENERATION The second way is to give three arrays that correspond respectively to the x−coordinates, y−coordinates and z−coordinates. The parameters of this command line are switch = A string expression. This string corresponds to the command line switch of TetGen see Section 3.2 of [36]. reftet = An integer expression. set the label of tetrahedra. label = An integer expression. set the label of triangles. In the string switch, we can’t used the option ’p’ and ’q’ of tetgen. 5.10.3 Reconstruct/Refine a three dimensional mesh with TetGen Meshes in three dimension can be refined using TetGen with the command line tetgreconstruction. The parameter of this keyword are region= an integer array that allow to change the region number of tetrahedra. This array is defined as the parameter reftet in the keyword change. label= an integer array that allow to change the label of boundary triangles. This array is defined as the parameter label in the keyword change. sizevolume= a reel function. This function allows to constraint volume size of tetrahedra in the domain. (see example 5.31 to build 3d adapt mesh ) The parameter switch nbofregions, regionlist, nboffacetcl and facetcl of the com- mand line which call TetGen (tetg) is used for tetgrefine. In the parameter switch=, the character ’r’ should be used without the character ’p’. For instance, see the manual of TetGen [36] for effect of ’r’ to other character. The parameter regionlist allows to define a new volume constraint in the region. The label in the regionlist will be the previous label of region. This parameter and nbofregions can’t be used with parameter sizevolume. Example: Example 5.19 (refinesphere.edp) // file refinesphere.edp load "msh3" load "tetgen" load "medit" mesh Th=square(10,20,[x * pi-pi/2,2 * y * pi]); // ] −pi 2 , frac−pi2[]0, 2π[ // a parametrization of a sphere func f1 =cos(x) * cos(y); func f2 =cos(x) * sin(y); func f3 = sin(x); // partiel derivative of the parametrization DF func f1x=sin(x) * cos(y); func f1y=-cos(x) * sin(y); func f2x=-sin(x) * sin(y); func f2y=cos(x) * cos(y); func f3x=cos(x); 5.10. MESH IN THREE DIMENSIONS 117 func f3y=0; // M = DF t DF func m11=f1xˆ2+f2xˆ2+f3xˆ2; func m21=f1x * f1y+f2x * f2y+f3x * f3y; func m22=f1yˆ2+f2yˆ2+f3yˆ2; func perio=[[4,y],[2,y],[1,x],[3,x]]; real hh=0.1; real vv= 1/square(hh); verbosity=2; Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); plot(Th,wait=1); verbosity=2; // construction of the surface of spheres real Rmin = 1.; func f1min = Rmin * f1; func f2min = Rmin * f2; func f3min = Rmin * f3; mesh3 Th3=movemesh23(Th,transfo=[f1min,f2min,f3min]); real[int] domain = [0.,0.,0.,145,0.01]; mesh3 Th3sph=tetg(Th3,switch="paAAQYY",nbofregions=1,regionlist=domain); int[int] newlabel = [145,18]; real[int] domainrefine = [0.,0.,0.,145,0.0001]; mesh3 Th3sphrefine=tetgreconstruction(Th3sph,switch="raAQ",reftet=newlabel, nbofregions=1,regionlist=domain,refinesizeofvolume=0.0001); int[int] newlabel2 = [145,53]; func fsize = 0.01/(( 1 + 5 * sqrt( (x-0.5)ˆ2+(y-0.5)ˆ2+(z-0.5)ˆ2) )ˆ3); mesh3 Th3sphrefine2=tetgreconstruction(Th3sph,switch="raAQ",reftet=newlabel2, sizeofvolume=fsize); medit(‘‘sphere’’,Th3sph); medit(‘‘isotroperefine’’ ,Th3sphrefine); medit(‘‘anisotroperefine’’,Th3sphrefine2); 5.10.4 Moving mesh in three dimensions Meshes in three dimensions can be translated rotated and deformed using the command line movemesh as in the 2D case (see section movemesh in chapiter 5). If Ω is tetrahedrized as T h (Ω), and Φ(x, y) = (Φ1(x, y, z), Φ1(x, y, z), Φ3(x, y, z)) is a displacement vector then Φ(T h ) is obtained by mesh3 Th = movemesh( Th, transfo=[Φ1, Φ2, Φ3], ... ); The parameters of movemesh in three dimensions are transfo = [Φ1,Φ2, Φ3] set the displacement vector of 3D transformation [Φ1(x, y, z), Φ2(x, y, z), Φ3(x, y, z)]. 118 CHAPTER 5. MESH GENERATION Middle surface Lower surface upper surface Figure 5.34: Example of Layer mesh in three dimension. region = set integer label of tetrahedra. 0 by default. label = set the label of faces of border. This parameters is initialized as label for the keyword change (5.3). facemerge = An integer expression. When you transform a mesh, some faces can be merged. This parameters equals to one if merge’s faces is considered. Otherwise equals to zero. By default, this parameter is equals to 1. ptmerge = A real expression. When you transform a mesh, some points can be merged. This parameters is the criteria to define two merging points. By default, we use ptmerge = 1e −7 V ol(B), where B is the smallest axis parallel boxes containing the discretion domain of Ω and V ol(B) is the volume of this box. An example of this command can be found in the file ”Poisson3d.edp” located in the directory examples++-3d. 5.10.5 Layer mesh In this section, we present the command line to obtain a Layer mesh: buildlayermesh. This mesh is obtained by extending a two dimensional mesh in the z-axis. The domain Ω 3d defined by the layer mesh is equal to Ω 3d = Ω 2d [zmin, zmax] where Ω 2d is the domain define by the two dimensional mesh, zmin and zmax are function of Ω 2d in R that defines respectively the lower surface and upper surface of Ω 3d . For a vertex of a two dimensional mesh V 2d i = (x i , y i ), we introduce the number of associated vertices in the z−axis M i + 1. We denote by M the maximum of M i over the vertices of the two dimensional mesh. This value are called the number of layers (if ∀i, M i = M then there are M layers in the mesh of Ω 3d ). V 2d i generated M + 1 vertices which are defined by ∀j = 0, . . . , M, V 3d i,j = (x i , y i , θ i (z i,j )), where (z i,j ) j=0,...,M are the M + 1 equidistant points on the interval [zmin(V 2d i ), zmax(V 2d i )]: z i,j = j δα +zmin(V 2d i ), δα = zmax(V 2d i ) −zmin(V 2d i ) M . 5.10. MESH IN THREE DIMENSIONS 119 The function θ i , defined on [zmin(V 2d i ), zmax(V 2d i )], is given by θ i (z) = θ i,0 if z = zmin(V 2d i ), θ i,j if z ∈]θ i,j−1 , θ i,j ], with (θ i,j ) j=0,...,M i are the M i + 1 equidistant points on the interval [zmin(V 2d i ), zmax(V 2d i )]. Set a triangle K = (V 2d i1 , V 2d i2 , V 2d i3 ) of the two dimensional mesh. K is associated with a trian- gle on the upper surface (resp. on the lower surface) of layer mesh: (V 3d i1,M , V 3d i2,M , V 3d i3,M ) (resp. (V 3d i1,0 , V 3d i2,0 , V 3d i3,0 )). Also K is associated with M volume prismatic elements which are defined by ∀j = 0, . . . , M, H j = (V 3d i1,j , V 3d i2,j , V 3d i3,j , V 3d i1,j+1 , V 3d i2,j+1 , V 3d i3,j+1 ). Theses volume elements can have some merged point: • 0 merged point : prism • 1 merged points : pyramid • 2 merged points : tetrahedra • 3 merged points : no elements The elements with merged points are called degenerate elements. To obtain a mesh with tetrahe- dra, we decompose the pyramid into two tetrahedra and the prism into three tetrahedra. These tetrahedra are obtained by cutting the quadrilateral face of pyramid and prism with the diagonal which have the vertex with the maximum index (see [8] for the reaspn of this choice). The triangles on the middle surface obtained with the decomposition of the volume prismatic el- ements are the triangles generated by the edges on the border of the two dimensional mesh. The label of triangles on the border elements and tetrahedra are defined with the label of these associ- ated elements. The arguments of buildlayermesh is a two dimensional mesh and the number of layers M. The parameters of this command are: zbound = [zmin,zmax] where zmin and zmax are functions expression. Theses functions define the lower surface mesh and upper mesh of surface mesh. coef = A function expression between [0,1]. This parameter is used to introduce degenerate element in mesh. The number of associated points or vertex V 2d i is the integer part of coef(V 2d i )M. region = This vector is used to initialized the region of tetrahedra. This vector contain successive pair of the 2d region number at index 2i and the corresponding 3d region number at index 2i + 1, like (5.3). become the labelmid = This vector is used to initialized the 3d labels number of the vertical face or mid face form the 2d label number. This vector contains successive pair of the 2d label number at index 2i and the corresponding 3d label number at index 2i + 1, like (5.3). labelup = This vector is used to initialized the 3d label numbers of the upper/top face form the 2d region number. This vector contains successive pair of the 2d region number at index 2i and the corresponding 3d label number at index 2i + 1, like (5.3). 120 CHAPTER 5. MESH GENERATION labeldown = Same as the previous case but for the lower/down face label . Moreover, we also add post processing parameters that allow to moving the mesh. These parameters correspond to parameters transfo, facemerge and ptmerge of the command line movemesh. The vector region, labelmid, labelup and labeldown These vectors are composed of n l successive pairs of number O i , N l where n l is the number (label or region) that we want to get. An example of this command line is given in buildlayermesh.edp. Example 5.20 (cube.idp) load "medit" load "msh3" func mesh3 Cube(int[int] & NN,real[int,int] &BB ,int[int,int] & L) { // first build the 6 faces of the hex. real x0=BB(0,0),x1=BB(0,1); real y0=BB(1,0),y1=BB(1,1); real z0=BB(2,0),z1=BB(2,1); int nx=NN[0],ny=NN[1],nz=NN[2]; mesh Thx = square(nx,ny,[x0+(x1-x0) * x,y0+(y1-y0) * y]); int[int] rup=[0,L(2,1)], rdown=[0,L(2,0)], rmid=[1,L(1,0), 2,L(0,1), 3, L(1,1), 4, L(0,0) ]; mesh3 Th=buildlayers(Thx,nz, zbound=[z0,z1], labelmid=rmid, labelup = rup, labeldown = rdown); return Th; } The unit cube example: include "Cube.idp" int[int] NN=[10,10,10]; // the number of step in each direction real [int,int] BB=[[0,1],[0,1],[0,1]]; // bounding box int [int,int] L=[[1,2],[3,4],[5,6]]; // the label of the 6 face left,right, // front, back, down, right mesh3 Th=Cube(NN,BB,L); medit("Th",Th); // see figure 5.35 The cone example (an axisymtric mesh on a triangle with degenerateness). Example 5.21 (cone.edp) load "msh3" load "medit" // cone using buildlayers with a triangle real RR=1,HH=1; border Taxe(t=0,HH){x=t;y=0;label=0;}; border Hypo(t=1,0){x=HH * t;y=RR * t;label=1;}; border Vert(t=0,RR){x=HH;y=t;label=2;}; int nn=10; real h= 1./nn; mesh Th2=buildmesh( Taxe(HH * nn)+ Hypo(sqrt(HH * HH+RR * RR) * nn) + Vert(RR * nn) ) ; 5.10. MESH IN THREE DIMENSIONS 121 plot(Th2,wait=1); // the 2d mesh int MaxLayersT=(int(2 * pi * RR/h)/4) * 4; // number of layers real zminT = 0, zmaxT = 2 * pi; // height 2 ∗ pi func fx= y * cos(z); func fy= y * sin(z); func fz= x; int[int] r1T=[0,0], r2T=[0,0,2,2], r4T=[0,2]; // trick function: func deg= max(.01,y/max(x/HH,0.4) /RR); // the function defined the proportion // of number layer close to axis with reference MaxLayersT mesh3 Th3T=buildlayers(Th2,coef= deg, MaxLayersT, zbound=[zminT,zmaxT],transfo=[fx,fy,fz], facemerge=0, region=r1T, labelmid=r2T); medit("cone",Th3T); // see figure 5.36 Figure 5.35: the mesh of a cube made with cube.edp Figure 5.36: the mesh of a cone made with cone.edp Example 5.22 (buildlayermesh.edp) // file buildlayermesh.edp load "msh3" load "tetgen" // Test 1 int C1=99, C2=98; // could be anything 122 CHAPTER 5. MESH GENERATION border C01(t=0,pi){ x=t; y=0; label=1;} border C02(t=0,2 * pi){ x=pi; y=t; label=1;} border C03(t=0,pi){ x=pi-t; y=2 * pi; label=1;} border C04(t=0,2 * pi){ x=0; y=2 * pi-t; label=1;} border C11(t=0,0.7){ x=0.5+t; y=2.5; label=C1;} border C12(t=0,2){ x=1.2; y=2.5+t; label=C1;} border C13(t=0,0.7){ x=1.2-t; y=4.5; label=C1;} border C14(t=0,2){ x=0.5; y=4.5-t; label=C1;} border C21(t=0,0.7){ x= 2.3+t; y=2.5; label=C2;} border C22(t=0,2){ x=3; y=2.5+t; label=C2;} border C23(t=0,0.7){ x=3-t; y=4.5; label=C2;} border C24(t=0,2){ x=2.3; y=4.5-t; label=C2;} mesh Th=buildmesh( C01(10)+C02(10)+ C03(10)+C04(10) + C11(5)+C12(5)+C13(5)+C14(5) + C21(-5)+C22(-5)+C23(-5)+C24(-5)); mesh Ths=buildmesh( C01(10)+C02(10)+ C03(10)+C04(10) + C11(5)+C12(5)+C13(5)+C14(5) ); // construction of a box with one hole and two regions func zmin=0.; func zmax=1.; int MaxLayer=10; func XX = x * cos(y); func YY = x * sin(y); func ZZ = z; int[int] r1=[0,41], r2=[98,98, 99,99, 1,56]; int[int] r3=[4,12]; // The triangles of uppper surface mesh // generated by the triangle in the 2D region of mesh Th of label 4 as label 12. int[int] r4=[4,45]; // The triangles of lower surface mesh // generated by the triangle in the 2D region of mesh Th of label 4 as label 45. mesh3 Th3=buildlayers( Th, MaxLayer, zbound=[zmin,zmax], region=r1, labelmid=r2, labelup = r3, labeldown = r4 ); savemesh(Th3,"box2region1hole.mesh"); // construction of a sphere with TetGen func XX1 = cos(y) * sin(x); func YY1 = sin(y) * sin(x); func ZZ1 = cos(x); string test="paACQ"; cout << "test=" << test << endl; mesh3 Th3sph=tetgtransfo(Ths,transfo=[XX1,YY1,ZZ1],switch=test,nbofregions=1, regionlist=domain); savemesh(Th3sph,"sphere2region.mesh"); 5.11. MESHING EXAMPLES 123 5.11 Meshing examples Example 5.23 (lac.edp) // file ”lac.edp” load ‘‘msh3’’ int nn=5; border cc(t=0,2 * pi){x=cos(t);y=sin(t);label=1;} mesh Th2 = buildmesh(cc(100)); fespace Vh2(Th2,P2); Vh2 ux,uy,p2; int[int] rup=[0,2], rdlow=[0,1], rmid=[1,1,2,1,3,1,4,1]; func zmin = 2-sqrt(4-(x * x+y * y)); func zmax = 2-sqrt(3.); mesh3 Th = buildlayers(Th2,nn, coeff = max((zmax-zmin)/zmax, 1./nn), zbound=[zmin,zmax], labelmid=rmid; labelup=rup; labeldown=rlow); savemesh(Th,’’Th.meshb’’); exec(‘‘medit Th; Th.meshb’’); Example 5.24 (tetgenholeregion.edp) // file ‘‘tetgenholeregion.edp’’ load "msh3’’ load "tetgen" mesh Th=square(10,20,[x * pi-pi/2,2 * y * pi]); // ] −pi 2 , −pi 2 []0, 2π[ // a parametrization of a sphere func f1 =cos(x) * cos(y); func f2 =cos(x) * sin(y); func f3 = sin(x); // partiel derivative of the parametrization DF func f1x=sin(x) * cos(y); func f1y=-cos(x) * sin(y); func f2x=-sin(x) * sin(y); func f2y=cos(x) * cos(y); func f3x=cos(x); func f3y=0; // M = DF t DF func m11=f1xˆ2+f2xˆ2+f3xˆ2; func m21=f1x * f1y+f2x * f2y+f3x * f3y; func m22=f1yˆ2+f2yˆ2+f3yˆ2; func perio=[[4,y],[2,y],[1,x],[3,x]]; real hh=0.1; real vv= 1/square(hh); verbosity=2; Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); plot(Th,wait=1); verbosity=2; 124 CHAPTER 5. MESH GENERATION // construction of the surface of spheres real Rmin = 1.; func f1min = Rmin * f1; func f2min = Rmin * f2; func f3min = Rmin * f3; mesh3 Th3sph = movemesh23(Th,transfo=[f1min,f2min,f3min]); real Rmax = 2.; func f1max = Rmax * f1; func f2max = Rmax * f2; func f3max = Rmax * f3; mesh3 Th3sph2 = movemesh23(Th,transfo=[f1max,f2max,f3max]); cout << "addition" << endl; mesh3 Th3 = Th3sph+Th3sph2; real[int] domain2 = [1.5,0.,0.,145,0.001,0.5,0.,0.,18,0.001]; cout << "==============================" << endl; cout << " tetgen call without hole " << endl; cout << "==============================" << endl; mesh3 Th3fin = tetg(Th3,switch="paAAQYY",nbofregions=2,regionlist=domain2); cout << "=============================" << endl; cout << "finish tetgen call without hole" << endl; cout << "=============================" << endl; savemesh(Th3fin,"spherewithtworegion.mesh"); real[int] hole = [0.,0.,0.]; real[int] domain = [1.5,0.,0.,53,0.001]; cout << "=============================" << endl; cout << " tetgen call with hole " << endl; cout << "=============================" << endl; mesh3 Th3finhole=tetg(Th3,switch="paAAQYY",nbofholes=1,holelist=hole, nbofregions=1,regionlist=domain); cout << "=============================" << endl; cout << "finish tetgen call with hole " << endl; cout << "=============================" << endl; savemesh(Th3finhole,"spherewithahole.mesh"); 5.11.1 Build a 3d mesh of a cube with a balloon First the MeshSurface.idp file to build boundary mesh of a Hexaedra and of a Sphere. func mesh3 SurfaceHex(int[int] & N,real[int,int] &B ,int[int,int] & L,int orientation) { real x0=B(0,0),x1=B(0,1); real y0=B(1,0),y1=B(1,1); real z0=B(2,0),z1=B(2,1); int nx=N[0],ny=N[1],nz=N[2]; mesh Thx = square(ny,nz,[y0+(y1-y0) * x,z0+(z1-z0) * y]); 5.11. MESHING EXAMPLES 125 mesh Thy = square(nx,nz,[x0+(x1-x0) * x,z0+(z1-z0) * y]); mesh Thz = square(nx,ny,[x0+(x1-x0) * x,y0+(y1-y0) * y]); int[int] refx=[0,L(0,0)],refX=[0,L(0,1)]; // Xmin, Ymax faces labels renumbering int[int] refy=[0,L(1,0)],refY=[0,L(1,1)]; // Ymin, Ymax faces labesl renumbering int[int] refz=[0,L(2,0)],refZ=[0,L(2,1)]; // Zmin, Zmax faces labels renumbering mesh3 Thx0 = movemesh23(Thx,transfo=[x0,x,y],orientation=-orientation,label=refx); mesh3 Thx1 = movemesh23(Thx,transfo=[x1,x,y],orientation=+orientation,label=refX); mesh3 Thy0 = movemesh23(Thy,transfo=[x,y0,y],orientation=+orientation,label=refy); mesh3 Thy1 = movemesh23(Thy,transfo=[x,y1,y],orientation=-orientation,label=refY); mesh3 Thz0 = movemesh23(Thz,transfo=[x,y,z0],orientation=-orientation,label=refz); mesh3 Thz1 = movemesh23(Thz,transfo=[x,y,z1],orientation=+orientation,label=refZ); mesh3 Th= Thx0+Thx1+Thy0+Thy1+Thz0+Thz1; return Th; } func mesh3 Sphere(real R,real h,int L,int orientation) { mesh Th=square(10,20,[x * pi-pi/2,2 * y * pi]); // ] −pi 2 , frac−pi2[]0, 2π[ // a parametrization of a sphere func f1 =cos(x) * cos(y); func f2 =cos(x) * sin(y); func f3 = sin(x); // partiel derivative func f1x=sin(x) * cos(y); func f1y=-cos(x) * sin(y); func f2x=-sin(x) * sin(y); func f2y=cos(x) * cos(y); func f3x=cos(x); func f3y=0; // the metric on the sphere M = DF t DF func m11=f1xˆ2+f2xˆ2+f3xˆ2; func m21=f1x * f1y+f2x * f2y+f3x * f3y; func m22=f1yˆ2+f2yˆ2+f3yˆ2; func perio=[[4,y],[2,y],[1,x],[3,x]]; // to store the periodic condition real hh=h/R; // hh mesh size on unite sphere real vv= 1/square(hh); Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); Th=adaptmesh(Th,m11 * vv,m21 * vv,m22 * vv,IsMetric=1,periodic=perio); int[int] ref=[0,L]; mesh3 ThS= movemesh23(Th,transfo=[f1 * R,f2 * R,f3 * R],orientation=orientation,refface=ref); return ThS; } The test of the two functions and the call to tetgen mesh generator 126 CHAPTER 5. MESH GENERATION load "tetgen" include "MeshSurface.idp" real hs = 0.1; // mesh size on sphere int[int] N=[20,20,20]; real [int,int] B=[[-1,1],[-1,1],[-1,1]]; int [int,int] L=[[1,2],[3,4],[5,6]]; mesh3 ThH = SurfaceHex(N,B,L,1); mesh3 ThS =Sphere(0.5,hs,7,1); // "gluing" surface meshs to tolat boundary meshes mesh3 ThHS=ThH+ThS; savemesh(ThHS,"Hex-Sphere.mesh"); exec("ffmedit Hex-Sphere.mesh;rm Hex-Sphere.mesh"); // see 5.37 real voltet=(hsˆ3)/6.; cout << " voltet = " << voltet << endl; real[int] domaine = [0,0,0,1,voltet,0,0,0.7,2,voltet]; mesh3 Th = tetg(ThHS,switch="pqaAAYYQ",nbofregions=2,regionlist=domaine); medit("Cube-With-Ball",Th); // see 5.38 Figure 5.37: The surface mesh of the Hex with internal Sphere Figure 5.38: The tet mesh of the cube with internal ball 5.12 The output solution formats .sol and .solb With the keyword savesol, we can store a scalar functions, a scalar FE functions, a vector fields, a vector FE fields, a symmetric tensor and a symmetric FE tensor.. Such format is used in medit. 5.12. THE OUTPUT SOLUTION FORMATS .SOL AND .SOLB 127 extension file .sol The first two lines of the file are • MeshVersionFormatted 0 • Dimension (I) dim The following fields begin with one of the following keyword: SolAtVertices, SolAtEdges, SolAtTri- angles, SolAtQuadrilaterals, SolAtTetrahedra, SolAtPentahedra, SolAtHexahedra. In each field, we give then in the next line the number of elements in the solutions (SolAtVertices: number of vertices, SolAtTriangles: number of triangles, ...). In other lines, we give the number of solutions , the type of solution (1: scalar, 2: vector, 3: symmetric tensor). And finally, we give the values of the solutions on the elements. The file must be ended with the keyword End. The real element of symmetric tensor ST 3d = ¸ ST 3d xx ST 3d xy ST 3d xz ST 3d yx ST 3d yy ST 3d yz ST 3d zx ST 3d zy ST 3d zz ST 2d = ST 2d xx ST 2d xy ST 2d yx ST 2d yy (5.5) stored in the extension .sol are respectively ST 3d xx , ST 3d yx , ST 3d yy , ST 3d zx , ST 3d zy , ST 3d zz and ST 2d xx , ST 2d yx , ST 2d yy An example of field with the keyword SolAtTetrahedra: • SolAtTetrahedra (I) NbOfTetrahedrons nbsol typesol 1 ... typesol n U k ij , ∀i ∈ ¦1, ..., nbrealsol k ¦ , ∀k ∈ ¦1, ...nbsol¦ ∀j ∈ ¦1, ..., NbOfTetrahedrons¦ where • nbsol is an integer equal to the number of solutions • typesol k , type of the solution number k, is – typesol k = 1 the solution k is scalar. – typesol k = 2 the solution k is vectorial. – typesol k = 3 the solution k is a symmetric tensor or symmetric matrix. • nbrealsol k number of real to discribe solution number k is – nbrealsol k = 1 the solution k is scalar. – nbrealsol k = dim the solution k is vectorial (dim is the dimension of the solution). – nbrealsol k = dim ∗ (dim + 1)/2 the solution k is a symmetric tensor or symmetric matrix. • U k ij is a real equal to the value of the component i of the solution k at tetrahedra j on the associated mesh. This field is written with the notation of Section 12.1. The format .solb is the same as format .sol but in binary (read/write is faster, storage is less). A real scalar functions f1, a vector fields Φ = [Φ1, Φ2, Φ3] and a symmetric tensor ST 3d (5.5) at the vertices of the three dimensional mesh Th3 is stored in the file ”f1PhiTh3.sol” using 128 CHAPTER 5. MESH GENERATION savesol("f1PhiST3dTh3.sol",Th3, f1, [Φ1, Φ2, Φ3], VV3, order=1); where V V 3 = [ST 3d xx , ST 3d yx , ST 3d yy , ST 3d zx , ST 3d zy , ST 3d zz ]. For a two dimensional mesh Th, A real scalar functions f2, a vector fields Ψ = [Ψ1, Ψ2] and a symmetric tensor ST 2d (5.5) at triangles is stored in the file ”f2PsiST2dTh3.solb” using savesol("f2PsiST2dTh3.solb",Th, f2, [Ψ1, Ψ2], VV2, order=0); where V V 2 = [ST 2d xx , ST 2d yx , ST 2d yy ] The arguments of savesol functions are the name of a file, a mesh and solutions. These arguments must be given in this order. The parmameters of this keyword are order = 0 is the solution is given at the center of gravity of elements. 1 is the solution is given at the vertices of elements. In the file, solutions are stored in this order : scalar solutions, vector solutions and finally symmetric tensor solutions. 5.13 medit The keyword medit allows to dipslay a mesh alone or a mesh and one or several functions defined on the mesh using the Pascal Frey’s freeware medit. Medit opens its own window and uses OpenGL extensively. Naturally to use this command medit must be installed. A vizualisation with medit of scalar solutions f1 and f2 continuous, piecewise linear and known at the vertices of the mesh Th is obtained using medit("sol1 sol2",Th, f1, f2, order=1); The first plot named “sol1” display f1. The second plot names “sol2” display f2. The arguments of function medit are the name of the differents scenes (separated by a space) of medit, a mesh and solutions. Each solution is associated with one scene. The scalar, vector and symmetric tensor solutions are specified in the format described in the section dealing with the keyword savesol. The parameters of this command line are order = 0 is the solution is given at the center of gravity of elements. 1 is the solution is given at the vertices of elements. meditff = set the name of execute command of medit. By default, this string is medit. save = set the name of a file .sol or .solb to save solutions. This command line allows also to represent two differents meshes and solutions on them in the same windows. The nature of solutions must be the same. Hence, we can vizualize in the same window the different domains in a domain decomposition method for instance. A vizualisation with medit of scalar solutions h1 and h2 at vertices of the mesh Th1 and Th2 respectively are obtained using medit("sol2domain",Th1, h1, Th2, h2, order=1); Example 5.25 (meditddm.edp) // meditddm.edp load "medit" 5.13. MEDIT 129 // Initial Problem: // Resolution of the following EDP: // −∆u s = f on Ω = ¦(x, y)[1 ≤ sqrt(x 2 +y 2 ) ≥ 2¦ // −∆u 1 = f1 on Ω 1 = ¦(x, y)[0.5 ≤ sqrt(x 2 +y 2 ) ≥ 1.¦ // u = 1 on Γ + Null Neumman condition on Γ 1 and on Γ 2 // We find the solution u in solving two EDP defined on domain Ω and Ω 1 // This solution is visualize with medit verbosity=3; border Gamma(t=0,2 * pi){x=cos(t); y=sin(t); label=1;}; border Gamma1(t=0,2 * pi){x=2 * cos(t); y=2 * sin(t); label=2;}; border Gamma2(t=0,2 * pi){x=0.5 * cos(t); y=0.5 * sin(t); label=3;}; // construction of mesh of domain Ω mesh Th=buildmesh(Gamma1(40)+Gamma(-40)); fespace Vh(Th,P2); func f=sqrt(x * x+y * y); Vh us,v; macro Grad2(us) [dx(us),dy(us)] // EOM problem Lap2dOmega(us,v,init=false)=int2d(Th)(Grad2(v)’ * Grad2(us)) - int2d(Th)(f * v)+on(1,us=1) ; // Definition of EDP defined on the domain Ω // −∆u s = f 1 on Ω 1 , u s = 1 on Γ 1 , ∂u s ∂n = 0 on Γ 2 Lap2dOmega; // construction of mesh of domain Ω 1 mesh Th1=buildmesh(Gamma(40)+Gamma2(-40)); fespace Vh1(Th1,P2); func f1=10 * sqrt(x * x+y * y); Vh1 u1,v1; macro Grad21(u1) [dx(u1),dy(u1)] // EOM problem Lap2dOmega1(u1,v1,init=false)=int2d(Th1)(Grad21(v1)’ * Grad21(u1)) - int2d(Th1)(f1 * v1)+on(1,u1=1) ; // Resolution of EDP defined on the domain Ω 1 // −∆u 1 = f 1 on Ω 1 , u −1 = 1 on Γ 1 , ∂u 1 ∂n = 0 on Γ 2 Lap2dOmega1; // vizualisation of solution of the initial problem medit("solution",Th,us,Th1,u1,order=1,save="testsavemedit.solb"); Example 5.26 (StockesUzawa.edp) // signe of pressure is correct assert(version>1.18); real s0=clock(); mesh Th=square(10,10); fespace Xh(Th,P2),Mh(Th,P1); Xh u1,u2,v1,v2; 130 CHAPTER 5. MESH GENERATION Mh p,q,ppp; varf bx(u1,q) = int2d(Th)( (dx(u1) * q)); varf by(u1,q) = int2d(Th)( (dy(u1) * q)); varf a(u1,u2)= int2d(Th)( dx(u1) * dx(u2) + dy(u1) * dy(u2) ) + on(1,2,4,u1=0) + on(3,u1=1) ; Xh bc1; bc1[] = a(0,Xh); Xh b; matrix A= a(Xh,Xh,solver=CG); matrix Bx= bx(Xh,Mh); matrix By= by(Xh,Mh); Xh bcx=1,bcy=0; func real[int] divup(real[int] & pp) { int verb=verbosity; verbosity=0; b[] = Bx’ * pp; b[] += bc1[] . * bcx[]; u1[] = Aˆ-1 * b[]; b[] = By’ * pp; b[] += bc1[] . * bcy[]; u2[] = Aˆ-1 * b[]; ppp[] = Bx * u1[]; ppp[] += By * u2[]; verbosity=verb; return ppp[] ; }; p=0;q=0;u1=0;v1=0; LinearCG(divup,p[],q[],eps=1.e-6,nbiter=50); divup(p[]); plot([u1,u2],p,wait=1,value=true,coef=0.1); medit("velocity pressure",Th,[u1,u2],p,order=1); 5.14 Mshmet Mshmet is a software developped by P. Frey that allows to compute an anisotropic metric based on solutions (i.e. Hessian-based). This sofware can return also an isotropic metric. Moreover, mshmet can construct also a metric suitable for level sets interface capturing. The solution can be defined on 2D or 3D structured/unstructured meshes. For example, the solution can be an error estimate of a FE solutions. Solutions for mshmet are given as an argument. The solution can be a func, a vector func, a symmetric tensor, a FE func, a FE vector func and a FE symmetric tensor. The symmetric tensor argument is defined as this type of data for datasol argument. This software accepts more than one solution. For example, the metric M computed with mshmet for the solution u defined on the mesh Th is obtained by writing. 5.14. MSHMET 131 fespace Vh(Th,P1); Vh u; // a scalar FE func real[int] M = mshmet(Th,u); The parameters of the keyword mshmet are : • normalization = <b> do a normalisation of all solution in [0, 1]. • aniso = <b> build aniso metric if 1 ( delault 0: iso) • levelset = <b> build metric for level set method (default: false) • verbosity = <l> • nbregul = <l> number of regularization’s iteration of solutions given (default 0). • hmin = <d> • hmax = <d> • err = <d> level of error. • width = <d> the width • metric= a vector of double. This vector contains an initial metric given to mshmet. The structure of the metric vector is described in the next paragraph. • loptions=]a vector of integer of size 7. This vector contains the integer parameters of mshmet(for expert only). – loptions(0): normalization (default 1). – loptions(1): isotropic parameters (default 0). 1 for isotropic metric results otherwise 0. – loptions(2): level set parameters (default 0). 1 for building level set metric otherwise 0. – loptions(3): debug parameters (default 0). 1 for turning on debug mode otherwise 0. – loptions(4): level of verbosity (default 10). – loptions(5): number of regularization’s iteration of solutions given (default 0). – loptions(6): previously metric parameter (default 0). 1 for using previous metric oth- erwise 0. • doptions= a vector of double of size 4. This vector contains the real parameters of mshmet (for expert only). – doptions(0): hmin : min size parameters (default 0.01). – doptions(1): hmax : max size parameters (default 1.0). – doptions(2): eps : tolerance parameters ( default 0.01). – doptions(2): width : relative width for Level Set (0 < w < 1) ( default 0.05). The result of the keyword mshmet is a real[int] which contains the metric computed by mshmet at the different vertices V i of the mesh. With nv is the number of vertices, the structure of this vector is M iso = (m(V 0 ), m(V 1 ), . . . , m(V nv )) t for a isotropic metric m. For a symmetric tensor metric h = ¸ m 11 m 12 m 13 m 21 m 22 m 23 m 31 m 32 m 33 , the parameters metric is M aniso = (H(V 0 ), . . . , H(V nv )) t where H(V i ) is the vector of size 6 defined by [m11,m21,m22,m31,m32,m33] 132 CHAPTER 5. MESH GENERATION Example 5.27 (mshmet.edp) load "mshmet" load "medit" load "msh3" border a(t=0,1.0){x=t; y=0; label=1;}; border b(t=0,0.5){x=1; y=t; label=2;}; border c(t=0,0.5){x=1-t; y=0.5;label=3;}; border d(t=0.5,1){x=0.5; y=t; label=4;}; border e(t=0.5,1){x=1-t; y=1; label=5;}; border f(t=0.0,1){x=0; y=1-t;label=6;}; mesh Th = buildmesh (a(6) + b(4) + c(4) +d(4) + e(4) + f(6)); savemesh(Th,"th.msh"); fespace Vh(Th,P1); Vh u,v; real error=0.01; problem Problem1(u,v,solver=CG,eps=1.0e-6) = int2d(Th,qforder=2)( u * v * 1.0e-10+ dx(u) * dx(v) + dy(u) * dy(v)) +int2d(Th,qforder=2)( (x-y) * v); func zmin=0; func zmax=1; int MaxLayer=10; mesh3 Th3 = buildlayers(Th,MaxLayer,zbound=[zmin,zmax]); fespace Vh3(Th3,P2); fespace Vh3P1(Th3,P1); Vh3 u3,v3; Vh3P1 usol; problem Problem2(u3,v3,solver=sparsesolver) = int3d(Th3)( u3 * v3 * 1.0e-10+ dx(u3) * dx(v3) + dy(u3) * dy(v3) + dz(u3) * dz(v3)) - int3d(Th3)( v3) +on(0,1,2,3,4,5,6,u3=0); Problem2; cout << u3[].min << " " << u3[].max << endl; savemesh(Th3,"metrictest.bis.mesh"); savesol("metrictest.sol",Th3,u3); real[int] bb=mshmet(Th3,u3); cout << bb << endl; for(int ii=0; ii<Th3.nv; ii++) usol[][ii]=bb[ii]; savesol("metrictest.bis.sol",Th3,usol); 5.15 FreeYams FreeYams is a surface mesh adaptation software which is developed by P. Frey. This software is a new version of yams. The adapted surface mesh is constructed with a geometric metric tensor field. This field is based on the intrinsic properties of the discrete surface. Also this software allows to construct a simplification of a mesh. This decimation is based on the Haus- dorff distance between the initial and the current triangulation. Compared to the software yams, FreeYams can be used also to produce anisotropic triangulations adapted to level set simula- tions. A technical report on FreeYams is not available yet but a documentation on yams exists at http://www.ann.jussieu.fr/∼frey/software.html [40]. 5.15. FREEYAMS 133 To call FreeYams in Freefem++, we used the keyword freeyams. The arguments of this function are the initial mesh and/or metric. The metric with freeyams are a function, a FE function, a symmetric tensor function, a symmetric tensor FE function or a vector of double. If the metric is vector of double, this data must be given in metric parameter. Otherwise, the metric is given in the argument. For example, the adapted mesh of Thinit defined by the metric u defined as FE function is obtained in writing. fespace Vh(Thinit,P1); Vh u; mesh3 Th=freeyams(Thinit,u); The symmetric tensor argument for freeyams keyword is defined as this type of data for datasol argument. • aniso = <b> aniso or iso metric (default 0, iso) • mem = <l> memory of for freeyams in Mb (delaulf -1, freeyams choose) • hmin = <d> • hmax = <d> • gradation = <d> • option = <l> 0 : mesh optimization (smoothing+swapping) 1 : decimation+enrichment adaptated to a metric map. (default) -1 : decimation adaptated to a metric map. 2 : decimation+enrichment with a Hausdorff-like method -2 : decimation with a Hausdorff-like method 4 : split triangles recursively. 9 : No-Shrinkage Vertex Smoothing • ridgeangle = <d> • absolute = <b> • verbosity = <i> • metric= vector expression. This parameters contains the metric at the different vertices on the initial mesh. With nv is the number of vertices, this vector is M iso = (m(V 0 ), m(V 1 ), . . . , m(V nv )) t for a scalar metric m. For a symmetric tensor metric h = ¸ m 11 m 12 m 13 m 21 m 22 m 23 m 31 m 32 m 33 , the param- eters metric is M aniso = (H(V 0 ), . . . , H(V nv )) t where H(V i ) is the vector of size 6 defined by [m11,m21,m22,m31,m32,m33] • loptions= a vector of integer of size 13. This vectors contains the integer options of FreeYams. (just for the expert ) 134 CHAPTER 5. MESH GENERATION – loptions(0): anisotropic parameter (default 0). If you give an anisotropic metric 1 otherwise 0. – loptions(1): Finite Element correction parameter (default 0). 1 for no Finite Element correction otherwise 0. – loptions(2): Split multiple connected points parameter (default 1). 1 for splitting mul- tiple connected points otherwise 0. – loptions(3): maximum value of memory size in Mbytes (default -1: the size is given by freeyams). – loptions(4): set the value of the connected component which we want to obtain. (Re- mark: freeyams give an automatic value at each connected component). – loptions(5): level of verbosity – loptions(6): Create point on straight edge (no mapping) parameter (default 0). 1 for creating point on straight edge otherwise 0. – loptions(7): validity check during smoothing parameter. This parameter is only used with No-Shrinkage Vertex Smoothing optimization (optimization option parameter 9). 1 for No validity checking during smoothing otherwise 0. – loptions(8): number of desired’s vertices (default -1). – loptions(9): number of iteration of optimizations (default 30). – loptions(10): no detection parameter (default 0) . 1 for detecting the ridge on the mesh otherwise 0. The ridge definition is given in the parameter doptions(12). – loptions(11): no vertex smoothing parameter (default 0). 1 for smoothing the vertices otherwise 0. – loptions(12): Optimization level parameter (default 0). ∗ 0 : mesh optimization (smoothing+swapping) ∗ 1 : decimation+enrichment adaptated to a metric map. ∗ -1: decimation adaptated to a metric map. ∗ 2 : decimation+enrichment with a Hausdorff-like method ∗ -2: decimation with a Hausdorff-like method ∗ 4 : split triangles recursively. ∗ 9 : No-Shrinkage Vertex Smoothing doptions= a vector of double of size 11. This vectors contains the real options of freeyams. – doptions(0): Set the geometric approximation (Tangent plane deviation) (default 0.01). – doptions(1): Set the lamda parameter (default -1. ). – doptions(2): Set the mu parmeter (default -1. ). – doptions(3): Set the gradation value (Mesh density control) (default 1.3). – doptions(4): Set the minimal size(hmin) (default -2.0: the size is automatically com- puted). – doptions(5): Set the maximal size(hmax) (default -2.0: the size is automatically com- puted). – doptions(6): Set the tolerance of the control of Chordal deviation (default -2.0). – doptions(7): Set the quality of degradation (default 0.599). 5.16. MMG3D 135 – doptions(8): Set the declic parameter (default 2.0). – doptions(9): Set the angular walton limitation parameter (default 45 degree). – doptions(10): Set the angular ridge detection (default 45 degree). Example 5.28 (freeyams.edp) load "msh3" load "medit" load "freeyams" int nn=20; mesh Th2=square(nn,nn); fespace Vh2(Th2,P2); Vh2 ux,uz,p2; int[int] rup=[0,2], rdown=[0,1], rmid=[1,1,2,1,3,1,4,1]; real zmin=0,zmax=1; mesh3 Th=buildlayers(Th2,nn, zbound=[zmin,zmax], reffacemid=rmid, reffaceup = rup, reffacelow = rdown); mesh3 Th3 = freeyams(Th); medit("maillagesurfacique",Th3,wait=1); 5.16 mmg3d Mmg3d is a 3D remeshing software developed by C. Dobrzynski and P. Frey (http://www.math.u-bordeaux1.fr/∼dobj/logiciels/mmg3d.php). To obtain a version of this li- brary send an e-mail at : [email protected] or [email protected]. This software allows to remesh an initial mesh made of tetrahedra. This initial mesh is adapted to a geometric metric tensor field or to a displacement vector (moving rigid body). The metric can be obtained with mshmet (see section 5.14). Remark 5 : (a) If no metric is given, an isotropic metric is computed by analyzing the size of the edges in the initial mesh. (b) if a displacement is given, the vertices of the surface triangles are moved without verifying the geometrical structure of the new surface mesh. The parameters of mmg3d are : • options= vector expression. This vector contains the option parameters of mmg3d. It is a vector of 6 values, with the following meaning: 136 CHAPTER 5. MESH GENERATION (0) optimization parameters : (default 1) 0 : mesh optimization. 1 : adaptation with metric (deletion and insertion vertices) and optimization. -1: adaptation with metric (deletion and insertion vertices) without optimization. 4 : split tetrahedra (be careful modify the surface). 9 : moving mesh with optimization. -9: moving mesh without optimization. (1) debug mode : (default 0) 1 : turn on debug mode. 0 : otherwise. (2) Specify the size of bucket per dimension ( default 64) (3) swapping mode : (default 0) 1 : no edge or face flipping. 0 : otherwise. (4) insert points mode : (default 0) 1 : no edge splitting or collapsing and no insert points. 0 : otherwise. (5) verbosity level (default 3) • memory= integer expression. Set the maximum memory size of new mesh in Mbytes. By default the number of maximum vertices, tetrahedra and triangles are respectively 500 000, 3000 000, 100000 which represent approximately a memory of 100 Mo. • metric= vector expression. This vector contains the metric given at mmg3d. It is a vector of size nv or 6 nv respectively for an istropic and anisotropic metric where nv is the number of vertices in the initial mesh. The structure of metric vector is described in the mshmet’s section(section 5.14). • displacement= [Φ1, Φ2, Φ3] set the displacement vector of the initial mesh Φ(x, y) = [Φ1(x, y), Φ2(x, y), Φ3(x, y)]. • displVect= sets the vector displacement in a vector expression. This vector contains the displacement at each point of the initial mesh. It is a vector of size 3 nv. An example using this function is given in ”mmg3d.edp”: Example 5.29 (mmg3d.edp) // test mmg3d load "msh3" load "medit" load "mmg3d" include "../examples++-3d/cube.idp" int n=6; int[int] Nxyz=[12,12,12]; real [int,int] Bxyz=[[0.,1.],[0.,1.],[0.,1.]]; int [int,int] Lxyz=[[1,1],[2,2],[2,2]]; mesh3 Th=Cube(Nxyz,Bxyz,Lxyz); real[int] isometric(Th.nv);{ for( int ii=0; ii<Th.nv; ii++) isometric[ii]=0.17; 5.16. MMG3D 137 } mesh3 Th3=mmg3d( Th, memory=100, metric=isometric); medit("init",Th); medit("isometric",Th3); An example of a moving mesh is given in fallingspheres.edp”: Example 5.30 (fallingspheres.edp) load "msh3" load "tetgen" load "medit" load "mmg3d" include "MeshSurface.idp" // build mesh of a box (311) wit 2 holes (300,310) real hs = 0.8; int[int] N=[4/hs,8/hs,11.5/hs]; real [int,int] B=[[-2,2],[-2,6],[-10,1.5]]; int [int,int] L=[[311,311],[311,311],[311,311]]; mesh3 ThH = SurfaceHex(N,B,L,1); mesh3 ThSg =Sphere(1,hs,300,-1); mesh3 ThSd =Sphere(1,hs,310,-1); ThSd=movemesh3(ThSd,transfo=[x,4+y,z]); mesh3 ThHS=ThH+ThSg+ThSd; // gluing surface meshes medit("ThHS", ThHS); // see surface mesh real voltet=(hsˆ3)/6.; real[int] domaine = [0,0,-4,1,voltet]; real [int] holes=[0,0,0,0,4,0]; mesh3 Th = tetg(ThHS,switch="pqaAAYYQ",nbofregions=1,regionlist=domaine, nbofholes=2,holelist=holes); medit("Box-With-two-Ball",Th); // End build mesh int[int] opt=[9,0,64,0,0,3]; // options of mmg3d see freeem++ doc real[int] vit=[0,0,-0.3]; func zero = 0.; func dep = vit[2]; fespace Vh(Th,P1); macro Grad(u) [dx(u),dy(u),dz(u)] // Vh uh,vh; // to compute the displacemnt field problem Lap(uh,vh,solver=CG) = int3d(Th)(Grad(uh)’ * Grad(vh)) // ’) for emacs + on(310,300,uh=dep) +on(311,uh=0.); for(int it=0; it<29; it++){ cout<<" ITERATION "<<it<<endl; Lap; plot(Th,uh); Th=mmg3d(Th,options=opt,displacement=[zero,zero,uh],memory=1000); } 138 CHAPTER 5. MESH GENERATION 5.17 A first 3d isotope mesh adaptation process Example 5.31 (Laplace-Adapt-3d.edp) load "msh3" load "tetgen" load "mshmet" load "medit" // build initial mesh int nn = 6; int[int] l1111=[1,1,1,1],l01=[0,1],l11=[1,1]; // label numbering to have all label to 1 mesh3 Th3=buildlayers(square(nn,nn,region=0,label=l1111), nn, zbound=[0,1], labelmid=l11, labelup = l01, labeldown = l01); Th3 = trunc(Th3,(x<0.5) | (y < 0.5) | (z < 0.5) ,label=1); // remove the ]0.5, 1[ 3 cube // end of build initial mesh fespace Vh(Th3,P1); Vh u,v,usol,h; macro Grad(u) [dx(u),dy(u),dz(u)] // EOM problem Poisson(u,v,solver=CG) = int3d(Th3)( Grad(u)’ * Grad(v) ) -int3d(Th3)( 1 * v ) + on(1,u=0); real errm=1e-2; // level of error for(int ii=0; ii<5; ii++) { Poisson; // solve Poisson equation. cout <<" u min, max = " << u[].min << " "<< u[].max << endl; h=0. ; // for resizing h[] because the mesh change h[]=mshmet(Th3,u,normalization=1,aniso=0,nbregul=1,hmin=1e-3,hmax=0.3,err=errm); cout <<" h min, max = " << h[].min << " "<< h[].max << " " << h[].n << " " << Th3.nv << endl; plot(u,wait=1); errm * = 0.8; // change the level of error cout << " Th3" << Th3.nv < " " << Th3.nt << endl; Th3=tetgreconstruction(Th3,switch="raAQ",sizeofvolume=h * h * h/6.); // rebuidl mesh medit("U-adap-iso-"+ii,Th3,u,wait=1);} Chapter 6 Finite Elements As stated in Section 2. FEM approximates all functions w as w(x, y) · w 0 φ 0 (x, y) +w 1 φ 1 (x, y) + +w M−1 φ M−1 (x, y) with finite element basis functions φ k (x, y) and numbers w k (k = 0, , M − 1). The functions φ k (x, y) are constructed from the triangle T i k , and called shape functions. In FreeFem++ the finite element space V h = ¦w[ w 0 φ 0 +w 1 φ 1 + +w M−1 φ M−1 , w i ∈ R¦ is easily created by fespace IDspace(IDmesh,<IDFE>) ; or with pairs of periodic boundary condition in 2d fespace IDspace(IDmesh,<IDFE>, periodic=[[la 1,sa 1],[lb 1,sb 1], ... [la k,sa k],[lb k,sb ]]); and in 3d fespace IDspace(IDmesh,<IDFE>, periodic=[[la 1,sa 1,ta 1],[lb 1,sb 1,tb 1], ... [la k,sa k,ta k],[lb k,sb ,tb ]]); where IDspace is the name of the space (e.g. Vh), IDmesh is the name of the associated mesh and <IDFE> is a identifier of finite element type. In 2D we have a pair of periodic boundary condition, if [la i,sa i],[lb i,sb i] is a pair of int, and the 2 labels la i and lb i refer to 2 pieces of boundary to be in equivalence. If [la i,sa i],[lb i,sb i] is a pair of real, then sa i and sb i give two common abscissa on the two boundary curve, and two points are identified as one if the two abscissa are equal. In 2D, we have a pair of periodic boundary condition,if [la i,sa i,ta i],[lb i,sb i,tb i] is a pair of int, the 2 labels la i and lb i define the 2 piece of boundary to be in equivalence. 139 140 CHAPTER 6. FINITE ELEMENTS If [la i,sa i,ta i],[lb i,sb i,tb i] is a pair of real, then sa i,ta i and sb i,tb i give two common parameters on the two boundary surface, and two points are identified as one if the two parameters are equal. Remark 6 The 2D mesh of the two identified borders must be the same, so to be sure, use the param- eter fixeborder=true in buildmesh command (see 5.1.2) like in example periodic2bis.edp (see 9.7). As of today, the known types of finite element are: P0,P03d piecewise constant discontinuous finite element (2d, 3d), the degrees of freedom are the barycenter element value. P0 h = ¸ v ∈ L 2 (Ω) for all K ∈ T h there is α K ∈ R : v |K = α K ¸ (6.1) P1,P13d piecewise linear continuous finite element (2d, 3d), the degrees of freedom are the vertices values. P1 h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 1 ¸ (6.2) P1dc piecewise linear discontinuous finite element P1dc h = ¸ v ∈ L 2 (Ω) ∀K ∈ T h v |K ∈ P 1 ¸ (6.3) Warning, due to interpolation problem, the degree of freedom is not the vertices but three vectices move inside with T(X) = G+.99(X−G) where G is the barycenter, (version 2.24-4). P1b,P1b3d piecewise linear continuous finite element plus bubble (2d, 3d) The 2d case: P1b h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 1 ⊕Span¦λ K 0 λ K 1 λ K 2 ¦ ¸ (6.4) The 3d case: P1b h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 1 ⊕Span¦λ K 0 λ K 1 λ K 2 λ K 3 ¦ ¸ (6.5) where λ K i , i = 0, .., d are the d+1 barycentric coordinate functions of the element K (triangle or tetrahedron). P2,P23d piecewise P 2 continuous finite element (2d, 3d), P2 h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 2 ¸ (6.6) where P 2 is the set of polynomials of R 2 of degrees ≤ 2. P2b piecewise P 2 continuous finite element plus bubble, P2 h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 2 ⊕Span¦λ K 0 λ K 1 λ K 2 ¦ ¸ (6.7) 141 P2dc piecewise P 2 discontinuous finite element, P2dc h = ¸ v ∈ L 2 (Ω) ∀K ∈ T h v |K ∈ P 2 ¸ (6.8) Warning, due to interpolation problem, the degree of freedom is not the six P2 nodes but six nodes move inside with T(X) = G+.99(X −G) where G is the barycenter, (version 2.24-4). P3 piecewise P 3 continuous finite element (2d) (need load "Element_P3", P2 h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 3 ¸ (6.9) where P 3 is the set of polynomials of R 2 of degrees ≤ 3. P3dc piecewise P 3 discontinuous finite element (2d) (need load "Element_P3dc", P2 h = ¸ v ∈ L 2 (Ω) ∀K ∈ T h v |K ∈ P 3 ¸ (6.10) where P 3 is the set of polynomials of R 2 of degrees ≤ 3. P4 piecewise P 4 continuous finite element (2d) (need load "Element_P4", P2 h = ¸ v ∈ H 1 (Ω) ∀K ∈ T h v |K ∈ P 4 ¸ (6.11) where P 4 is the set of polynomials of R 2 of degrees ≤ 4. P4dc piecewise P 4 discontinuous finite element (2d) (need load "Element_P4dc", P2 h = ¸ v ∈ L 2 (Ω) ∀K ∈ T h v |K ∈ P 3 ¸ (6.12) where P 4 is the set of polynomials of R 2 of degrees ≤ 3. Morley piecewise P 2 non conform finite element (2d) (need load "Morley") P2 h = v ∈ L 2 (Ω) ∀K ∈ T h v |K ∈ P 3 , v continuous at vertices, ∂ n v continuous at middle of edge, (6.13) where P 2 is the set of polynomials of R 2 of degrees ≤ 3. Warning to build the interplant of a function u (scalar) for this finite element, we need the function and 2 partial derivatives (u, u x , u y ), so this vectorial finite element with 3 components (u, u x , u y ). See example bilapMorley.edp of examples++-load for solving BiLaplacien problem : load "Morley" fespace Vh(Th,P2Morley); // the Morley finite element space macro bilaplacien(u,v) ( dxx(u) * dxx(v)+dyy(u) * dyy(v)+2. * dxy(u) * dxy(v)) // fin macro real f=1; Vh [u,ux,uy],[v,vx,vy]; solve bilap([u,ux,uy],[v,vx,vy]) = int2d(Th)( bilaplacien(u,v) ) - int2d(Th)(f * v) + on(1,2,3,4,u=0,ux=0,uy=0) 142 CHAPTER 6. FINITE ELEMENTS P2BR (need load "BernadiRaugel") the Bernadi Raugel Finite Elemen is a Vectorial element (2d) with 2 components, See Bernardi, C., Raugel, G.: Analysis of some finite elements for the Stokes problem. Math. Comp. 44, 71-79 (1985). It is a 2d coupled FE, with the Polynomial space is P1 2 + 3 normals bubbles edges function (P 2 ) and the degre of freedom is 6 values at of the 2 components at the 3 vertices and the 3 flux on the 3 edges So the number degrees of freedom is 9. RT0,RT03d Raviart-Thomas finite element of degree 0. The 2d case: RT0 h = v ∈ H(div) ∀K ∈ T h v |K (x, y) = α 1 K α 2 K +β K [ x y ¸ (6.14) The 3d case: RT0 h = v ∈ H(div) ∀K ∈ T h v |K (x, y, z) = α 1 K α 2 K α 3 K +β K x y z ¸ (6.15) where by writing div w = ¸ d i=1 ∂w i /∂x i with w = (w i ) d i=1 , H(div) = w ∈ L 2 (Ω) d div w ∈ L 2 (Ω) ¸ and where α 1 K , α 2 K , α 3 K , β K are real numbers. RT0Ortho Raviart-Thomas Orthogonal, or Nedelec finite element type I of degree 0 in dimension 2 RT0Orthoh = v ∈ H(curl) ∀K ∈ T h v |K (x, y) = α 1 K α 2 K +β K [ −y x ¸ (6.16) Edge03d Nedelec finite element or Edge Element of degree 0. The 3d case: Edge0 h = v ∈ H(Curl) ∀K ∈ T h v |K (x, y, z) = α 1 K α 2 K α 3 K + β 1 K β 2 K β 3 K x y z ¸ (6.17) where by writing curlw = ∂w 2 /∂x 3 −∂w 3 /∂x 2 ∂w 3 /∂x 1 −∂w 1 /∂x 3 ∂w 1 /∂x 2 −∂w 2 /∂x 1 with w = (w i ) d i=1 , H(curl) = w ∈ L 2 (Ω) d curl w ∈ L 2 (Ω) d ¸ and α 1 K , α 2 K , α 3 K , β 1 K , β 2 K , β 3 K are real numbers. P1nc piecewise linear element continuous at the middle of edge only in 2D ?????. RT1 (need load "Element_Mixte", version 3.13) RT1 h = v ∈ H(div) ∀K ∈ T h (α 2 K , α 2 K , β K ) ∈ P 3 1 , v |K (x, y) = α 1 K α 2 K +β K [ x y ¸ (6.18) RT1Ortho (need load "Element_Mixte", version 3.13, dimension 2) RT1 h = v ∈ H(curl) ∀K ∈ T h (α 2 K , α 2 K , β K ) ∈ P 3 1 , v |K (x, y) = α 1 K α 2 K +β K [ −y x ¸ (6.19) 6.1. USE OF “FESPACE” IN 2D 143 BDM1 (need load "Element_Mixte", version 3.13, dimension 2) the Brezzi-Douglas-Marini finite element BDM1 h = ¸ v ∈ H(div) ∀K ∈ T h v |K ∈ P 2 1 ¸ (6.20) BDM1Ortho (need load "Element_Mixte", version 3.13, dimension 2) the Brezzi-Douglas- Marini Orthogonal also call Nedelec of type II , finite element BDM1Ortho h = ¸ v ∈ H(curl) ∀K ∈ T h v |K ∈ P 2 1 ¸ (6.21) TDNNS1 (need load "Element_Mixte", version 3.13, dimension 2) A new element finite el- ement to approximation symetrique 2x2 matrix in H(divdiv) (i.e σ nn is continuous accross edge). TDNNS1h = ¸ σ ∈ (L 2 ) 2,2 ∀K ∈ T h σ |K ∈ P 2 1 , σ 12 = σ 21 , σ nn is continuous ¸ (6.22) where σ nn = n t σn, and n is a normal to the edge (see [41, section 4.2.2.3] for full detail) 6.1 Use of “fespace” in 2d With the 2d finite element spaces X h = ¦v ∈ H 1 (]0, 1[ 2 )[ ∀K ∈ T h v |K ∈ P 1 ¦ X ph = ¦v ∈ X h [ v([ 0 . ) = v([ 1 . ), v([ . 0 ) = v([ . 1 )¦ M h = ¦v ∈ H 1 (]0, 1[ 2 )[ ∀K ∈ T h v |K ∈ P 2 ¦ R h = ¦v ∈ H 1 (]0, 1[ 2 ) 2 [ ∀K ∈ T h v |K (x, y) = α K β K +γ K [ x y ¦ when T h is a mesh 10 10 of the unit square ]0, 1[ 2 , we only write in FreeFem++ : mesh Th=square(10,10); fespace Xh(Th,P1); // scalar FE fespace Xph(Th,P1, periodic=[[2,y],[4,y],[1,x],[3,x]]); // bi-periodic FE fespace Mh(Th,P2); // scalar FE fespace Rh(Th,RT0); // vectorial FE where Xh,Mh,Rh expresses finite element spaces (called FE spaces ) X h , M h , R h , respectively. To use FE-functions u h , v h ∈ X h , p h , q h ∈ M h and U h , V h ∈ R h , we write : Xh uh,vh; Xph uph,vph; Mh ph,qh; Rh [Uxh,Uyh],[Vxh,Vyh]; Xh[int] Uh(10); // array of 10 function in Xh Rh[int] [Wxh,Wyh](10); // array of 10 functions in Rh. Wxh[5](0.5,0.5) // the 6th function at point (0.5, 0.5) Wxh[5][] // the array of the degre of freedom of the 6 function. The functions U h , V h have two components so we have U h = Uxh Uyh and V h = V xh V yh 144 CHAPTER 6. FINITE ELEMENTS 6.2 Use of fespace in 3d With the 3d finite element spaces X h = ¦v ∈ H 1 (]0, 1[ 3 )[ ∀K ∈ T h v |K ∈ P 1 ¦ X ph = ¦v ∈ X h [ v([ 0 . ) = v([ 1 . ), v([ . 0 ) = v([ . 1 )¦ M h = ¦v ∈ H 1 (]0, 1[ 2 )[ ∀K ∈ T h v |K ∈ P 2 ¦ R h = ¦v ∈ H 1 (]0, 1[ 2 ) 2 [ ∀K ∈ T h v |K (x, y) = α K β K +γ K [ x y ¦ when T h is a mesh 10 10 10 of the unit cubic ]0, 1[ 2 , we write in FreeFem++ : mesh3 Th=buildlayers(square(10,10),10, zbound=[0,1]); // label: 0 up, 1 down; 2 front, 3 left, 4 back, 5: right fespace Xh(Th,P1); // scalar FE fespace Xph(Th,P1, periodic=[[0,x,y],[1,x,y], [2,x,z],[4,x,z], [3,y,z],[5,y,z]]); // three-periodic FE (see Note 6.1) fespace Mh(Th,P2); // scalar FE fespace Rh(Th,RT03d); // vectorial FE where Xh,Mh,Rh expresses finite element spaces (called FE spaces ) X h , M h , R h , respectively. To define and use FE-functions u h , v h ∈ X h and p h , q h ∈ M h and U h , V h ∈ R h , we write: Xh uh,vh; Xph uph,vph; Mh ph,qh; Rh [Uxh,Uyh,Uyzh],[Vxh,Vyh, Vyzh]; Xh[int] Uh(10); // array of 10 function in Xh Rh[int] [Wxh,Wyh,Wzh](10); // array of 10 functions in Rh. Wxh[5](0.5,0.5,0.5) // the 6th function at point (0.5, 0.5, 0.5) Wxh[5][] // the array of the degre of freedom of the 6 function. The functions U h , V h have three components so we have U h = Uxh Uyh Uzh and V h = V xh V yh V zh Note 6.1 ONe problem of the periodic boundary condition is the mesh mus be the same au equiva- lence face, the BuildLayer mesh generatio split quadralateral faces with the diagonal passing through vertex with maximal number, so to be sure to have the same mesh one both face periodic the 2d numbering in corresponding edges must be compatible (for example the same variation). By Default, the numbering of square vertex are correct. To change the mesh numbering you can used the change function like: { // for cleanning memory.. int[int] old2new(0:Th.nv-1); // array set on 0, 1, .., nv-1 fespace Vh2(Th,P1); Vh2 sorder=x+y; // choose ordering increasing on 4 square borders with x or y sort(sorder[],old2new); // build the inverse permutation int[int] new2old=old2newˆ-1; // inverse the permutation 6.3. LAGRANGIAN FINITE ELEMENTS 145 Th= change(Th,renumv=new2old);change} } the full example is in examples++-3d/periodic-3d.edp 6.3 Lagrangian Finite Elements 6.3.1 P0-element For each triangle (d=2) or tetrahedron (d=3) T k , the basis function φ k in Vh(Th,P0) is given by φ k (x) = 1 if (x) ∈ T k , φ k (x) = 0 if (x) ∈ T k If we write Vh(Th,P0); Vh fh=f(x, y); then for vertices q k i , i = 1, 2, ..d + 1 in Fig. 6.1(a), f h is built as fh = f h (x, y) = ¸ k f( ¸ i q k i d + 1 )φ k See Fig. 6.3 for the projection of f(x, y) = sin(πx) cos(πy) on Vh(Th,P0) when the mesh Th is a 4 4-grid of [−1, 1] 2 as in Fig. 6.2. 6.3.2 P1-element k q k q ! k q k T p k q k q ! k q " k q # k q $ k q k T = > Figure 6.1: P 1 and P 2 degrees of freedom on triangle T k For each vertex q i , the basis function φ i in Vh(Th,P1) is given by φ i (x, y) = a k i +b k i x +c k i y for (x, y) ∈ T k , φ i (q i ) = 1, φ i (q j ) = 0 if i = j The basis function φ k 1 (x, y) with the vertex q k 1 in Fig. 6.1(a) at point p = (x, y) in triangle T k simply coincide with the barycentric coordinates λ k 1 (area coordinates) : φ k 1 (x, y) = λ k 1 (x, y) = area of triangle(p, q k 2 , q k 3 ) area of triangle(q k 1 , q k 2 , q k 3 ) 146 CHAPTER 6. FINITE ELEMENTS If we write Vh(Th,P1); Vh fh=g(x.y); then fh = f h (x, y) = n v ¸ i=1 f(q i )φ i (x, y) See Fig. 6.4 for the projection of f(x, y) = sin(πx) cos(πy) into Vh(Th,P1). Figure 6.2: Test mesh Th for projection Figure 6.3: projection to Vh(Th,P0) 6.3.3 P2-element For each vertex or midpoint q i . the basis function φ i in Vh(Th,P2) is given by φ i (x, y) = a k i +b k i x +c k i y +d k i x 2 +e k i xy +f f j y 2 for (x, y) ∈ T k , φ i (q i ) = 1, φ i (q j ) = 0 if i = j The basis function φ k 1 (x, y) with the vertex q k 1 in Fig. 6.1(b) is defined by the barycentric coordi- nates: φ k 1 (x, y) = λ k 1 (x, y)(2λ k 1 (x, y) −1) and for the midpoint q k 2 φ k 2 (x, y) = 4λ k 1 (x, y)λ k 4 (x, y) If we write Vh(Th,P2); Vh fh=f(x.y); then fh = f h (x, y) = M ¸ i=1 f(q i )φ i (x, y) (summation over all vetex or midpoint) See Fig. 6.5 for the projection of f(x, y) = sin(πx) cos(πy) into Vh(Th,P2). 6.4. P1 NONCONFORMING ELEMENT 147 Figure 6.4: projection to Vh(Th,P1) Figure 6.5: projection to Vh(Th,P2) 6.4 P1 Nonconforming Element Refer to [23] for details; briefly, we now consider non-continuous approximations so we shall lose the property w h ∈ V h ⊂ H 1 (Ω) If we write Vh(Th,P1nc); Vh fh=f(x.y); then fh = f h (x, y) = n v ¸ i=1 f(m i )φ i (x, y) (summation over all midpoint) Here the basis function φ i associated with the midpoint m i = (q k i + q k i+1 )/2 where q k i is the i-th point in T k , and we assume that j + 1 = 0 if j = 3: φ i (x, y) = a k i +b k i x +c k i y for (x, y) ∈ T k , φ i (m i ) = 1, φ i (m j ) = 0 if i = j Strictly speaking ∂φ i /∂x, ∂φ i /∂y contain Dirac distribution ρδ ∂T k . The numerical calculations will automatically ignore them. In [23], there is a proof of the estimation n v ¸ k=1 T k [∇w −∇w h [ 2 dxdy 1/2 = O(h) The basis functions φ k have the following properties. 1. For the bilinear form a defined in (2.6) satisfy a(φ i , φ i ) > 0, a(φ i , φ j ) ≤ 0 if i = j n v ¸ k=1 a(φ i , φ k ) ≥ 0 2. f ≥ 0 ⇒u h ≥ 0 148 CHAPTER 6. FINITE ELEMENTS 3. If i = j, the basis function φ i and φ j are L 2 -orthogonal: Ω φ i φ j dxdy = 0 if i = j which is false for P 1 -element. See Fig. 6.6 for the projection of f(x, y) = sin(πx) cos(πy) into Vh(Th,P1nc). See Fig. 6.6 for the projection of f(x, y) = sin(πx) cos(πy) into Vh(Th,P1nc). Figure 6.6: projection to Vh(Th,P1nc) Figure 6.7: projection to Vh(Th,P1b) 6.5 Other FE-space For each triangle T k ∈ T h , let λ k 1 (x, y), λ k 2 (x, y), λ k 3 (x, y) be the area cordinate of the triangle (see Fig. 6.1), and put β k (x, y) = 27λ k 1 (x, y)λ k 2 (x, y)λ k 3 (x, y) (6.23) called bubble function on T k . The bubble function has the feature: 1. β k (x, y) = 0 if (x, y) ∈ ∂T k . 2. β k (q k b ) = 1 where q k b is the barycenter q k 1 +q k 2 +q k 3 3 . If we write Vh(Th,P1b); Vh fh=f(x.y); then fh = f h (x, y) = n v ¸ i=1 f(q i )φ i (x, y) + n t ¸ k=1 f(q k b )β k (x, y) See Fig. 6.7 for the projection of f(x, y) = sin(πx) cos(πy) into Vh(Th,P1b). 6.6. VECTOR VALUED FE-FUNCTION 149 6.6 Vector valued FE-function Functions from R 2 to R N with N = 1 is called scalar function and called vector valued when N > 1. When N = 2 fespace Vh(Th,[P0,P1]) ; make the space V h = ¦w = (w 1 , w 2 )[ w 1 ∈ V h (T h , P 0 ), w 2 ∈ V h (T h , P 1 )¦ 6.6.1 Raviart-Thomas element In the Raviart-Thomas finite element RT0 h , the degree of freedom are the fluxes across edges e of the mesh, where the flux of the function f : R 2 −→R 2 is e f .n e , n e is the unit normal of edge e. This implies a orientation of all the edges of the mesh, for example we can use the global numbering of the edge vertices and we just go from small to large numbers. To compute the flux, we use a quadrature with one Gauss point, the middle point of the edge. Consider a triangle T k with three vertices (a, b, c). Let denote the vertices numbers by i a , i b , i c , and define the three edge vectors e 1 , e 2 , e 3 by sgn(i b −i c )(b−c), sgn(i c −i a )(c−a), sgn(i a −i b )(a−b), We get three basis functions, φ k 1 = sgn(i b −i c ) 2[T k [ (x −a), φ k 2 = sgn(i c −i a ) 2[T k [ (x −b), φ k 3 = sgn(i a −i b ) 2[T k [ (x −c), (6.24) where [T k [ is the area of the triangle T k . If we write Vh(Th,RT0); Vh [f1h,f2h]=[f1(x.y), f2(x, y)]; then fh = f h (x, y) = n t ¸ k=1 6 ¸ l=1 n i l j l [e i l [f j l (m i l )φ i l j l where n i l j l is the j l -th component of the normal vector n i l , ¦m 1 , m 2 , m 3 ¦ = b +c 2 , a +c 2 , b +a 2 and i l = ¦1, 1, 2, 2, 3, 3¦, j l = ¦1, 2, 1, 2, 1, 2¦ with the order of l. a b c 6 n ! n n Figure 6.8: normal vectors of each edge 150 CHAPTER 6. FINITE ELEMENTS Example 6.1 mesh Th=square(2,2); fespace Xh(Th,P1); fespace Vh(Th,RT0); Xh uh,vh; Vh [Uxh,Uyh]; [Uxh,Uyh] = [sin(x),cos(y)]; // ok vectorial FE function vh= xˆ2+yˆ2; // vh Th = square(5,5); // change the mesh // Xh is unchange uh = xˆ2+yˆ2; // compute on the new Xh Uxh = x; // error: impossible to set only 1 component // of a vector FE function. vh = Uxh; // ok // and now uh use the 5x5 mesh // but the fespace of vh is alway the 2x2 mesh plot(uh,ps="onoldmesh.eps"); // figure 6.9 uh = uh; // do a interpolation of vh (old) of 5x5 mesh // to get the new vh on 10x10 mesh. plot(uh,ps="onnewmesh.eps"); // figure 6.10 vh([x-1/2,y])= xˆ2 + yˆ2; // interpolate vh = ((x −1/2) 2 +y 2 ) Figure 6.9: vh Iso on mesh 2 2 Figure 6.10: vh Iso on mesh 5 5 To get the value at a point x = 1, y = 2 of the FE function uh, or [Uxh,Uyh],one writes real value; value = uh(2,4); // get value= uh(2,4) value = Uxh(2,4); // get value= Uxh(2,4) // ------ or ------ x=1;y=2; value = uh; // get value= uh(1,2) value = Uxh; // get value= Uxh(1,2) value = Uyh; // get value= Uyh(1,2). To get the value of the array associated to the FE function uh, one writes 6.7. A FAST FINITE ELEMENT INTERPOLATOR 151 real value = uh[][0] ; // get the value of degree of freedom 0 real maxdf = uh[].max; // maximum value of degree of freedom int size = uh.n; // the number of degree of freedom real[int] array(uh.n)= uh[]; // copy the array of the function uh Note 6.2 For a none scalar finite element function [Uxh,Uyh] the two array Uxh[] and Uyh[] are the same array, because the degree of freedom can touch more than one component. 6.7 A Fast Finite Element Interpolator In practice one may discretize the variational equations by the Finite Element method. Then there will be one mesh for Ω 1 and another one for Ω 2 . The computation of integrals of products of functions defined on different meshes is difficult. Quadrature formulae and interpolations from one mesh to another at quadrature points are needed. We present below the interpolation operator which we have used and which is new, to the best of our knowledge. Let T 0 h = ∪ k T 0 k , T 1 h = ∪ k T 1 k be two triangulations of a domain Ω. Let V (T i h ) = ¦C 0 (Ω i h ) : f[ T i k ∈ P 0 ¦, i = 0, 1 be the spaces of continuous piecewise affine functions on each triangulation. Let f ∈ V (T 0 h ). The problem is to find g ∈ V (T 1 h ) such that g(q) = f(q) ∀q vertex of T 1 h Although this is a seemingly simple problem, it is difficult to find an efficient algorithm in practice. We propose an algorithm which is of complexity N 1 log N 0 , where N i is the number of vertices of T i h , and which is very fast for most practical 2D applications. Algorithm The method has 5 steps. First a quadtree is built containing all the vertices of mesh T 0 h such that in each terminal cell there are at least one, and at most 4, vertices of T 0 h . For each q 1 , vertex of T 1 h do: Step 1 Find the terminal cell of the quadtree containing q 1 . Step 2 Find the the nearest vertex q 0 j to q 1 in that cell. Step 3 Choose one triangle T 0 k ∈ T 0 h which has q 0 j for vertex. Step 4 Compute the barycentric coordinates ¦λ j ¦ j=1,2,3 of q 1 in T 0 k . • − if all barycentric coordinates are positive, go to Step 5 • − else if one barycentric coordinate λ i is negative replace T 0 k by the adjacent triangle opposite q 0 i and go to Step 4. • − else two barycentric coordinates are negative so take one of the two randomly and replace T 0 k by the adjacent triangle as above. 152 CHAPTER 6. FINITE ELEMENTS Step 5 Calculate g(q 1 ) on T 0 k by linear interpolation of f: g(q 1 ) = ¸ j=1,2,3 λ j f(q 0 j ) End Figure 6.11: To interpolate a function at q 0 the knowledge of the triangle which contains q 0 is needed. The algorithm may start at q 1 ∈ T 0 k and stall on the boundary (thick line) because the line q 0 q 1 is not inside Ω. But if the holes are triangulated too (doted line) then the problem does not arise. Two problems need to be solved: • What if q 1 is not in Ω 0 h ? Then Step 5 will stop with a boundary triangle. So we add a step which test the distance of q 1 with the two adjacent boundary edges and select the nearest, and so on till the distance grows. • What if Ω 0 h is not convex and the marching process of Step 4 locks on a boundary? By construction Delaunay-Vorono¨ı mesh generators always triangulate the convex hull of the vertices of the domain. So we make sure that this information is not lost when T 0 h , T 1 h are constructed and we keep the triangles which are outside the domain in a special list. Hence in step 5 we can use that list to step over holes if needed. Note 6.3 Some time in rare case the interpolation process miss some point, we cane change the seach algorithm through global variable searchMethod searchMethod=0; // default value for fast search algorithm searchMethod=1; // safe seach algo, use brute force in case of missing point // (warning can be very expensive in case of lot point of ouside domain) searchMethod=2; // use alway the brute force very very expensive Note 6.4 Step 3 requires an array of pointers such that each vertex points to one triangle of the triangulation. 6.8. KEYWORDS: PROBLEM AND SOLVE 153 Note 6.5 The operator = is the interpolation operator of FreeFem++ , The continuous finite func- tions are extended by continuity to the outside of the domain. Try the following example mesh Ths= square(10,10); mesh Thg= square(30,30,[x * 3-1,y * 3-1]); plot(Ths,Thg,ps="overlapTh.eps",wait=1); fespace Ch(Ths,P2); fespace Dh(Ths,P2dc); fespace Fh(Thg,P2dc); Ch us= (x-0.5) * (y-0.5); Dh vs= (x-0.5) * (y-0.5); Fh ug=us,vg=vs; plot(us,ug,wait=1,ps="us-ug.eps"); // see figure 6.12 plot(vs,vg,wait=1,ps="vs-vg.eps"); // see figure 6.13 Figure 6.12: Extension of a continuous FE- function Figure 6.13: Extention of discontinuous FE- function, see warning 6 6.8 Keywords: Problem and Solve For FreeFem++ a problem must be given in variational form, so we need a bilinear form a(u, v) , a linear form (f, v), and possibly a boundary condition form must be added. problem P(u,v) = a(u,v) - (f,v) + (boundary condition); Note 6.6 When you want to formulate the problem and to solve it in the same time, you can use the keywork solve. 154 CHAPTER 6. FINITE ELEMENTS 6.8.1 Weak form and Boundary Condition To present the principles of Variational Formulations or also called weak forms fr the PDEs, let us take a model problem : a Poisson equation with Dirichlet and Robin Boundary condition . The problem is: Find u a real function defined on domain Ω of R d (d = 2, 3) such that −∇.(κ∇u) = f, in Ω, au +κ ∂u ∂n = b on Γ r , u = g on Γ d (6.25) where • if d = 2 then ∇.(κ∇u) = ∂ x (κ∂ x u) +∂ y (κ∂ y u) with ∂ x u = ∂u ∂x and ∂ y u = ∂u ∂y • if d = 3 then ∇.(κ∇u) = ∂ x (κ∂ x u) + ∂ y (κ∂ y u) + ∂ z (κ∂ z u) with ∂ x u = ∂u ∂x , ∂ y u = ∂u ∂y and , ∂ z u = ∂u ∂z • the border Γ = ∂Ω is split in Γ d and Γ n such that Γ d ∩ Γ n = ∅ and Γ d ∪ Γ n = ∂Ω, • κ is a given positive function, such that ∃κ 0 ∈ R, 0 < κ 0 ≤ κ. • a a given non negative function, • b a given function. Note 6.7 This is the well known Neumann boundary condition if a = 0, and if Γ d is empty. In this case the function appears in the problem just by its derivatives, so it is defined only up to a constant (if u is a solution then u +c is also a solution). Let v a regular test function null on Γ d , by integration by parts we get − Ω ∇.(κ∇u) v dω = Ω κ∇v.∇udω − Γ vκ ∂u ∂n dγ, = Ω fv dω (6.26) where if d = 2 the ∇v.∇u = ( ∂u ∂x ∂v ∂x + ∂u ∂y ∂v ∂y ) , where if d = 3 the ∇v.∇u = ( ∂u ∂x ∂v ∂x + ∂u ∂y ∂v ∂y + ∂u ∂z ∂v ∂z ) , and where n is the unitary outside normal of ∂Ω. Now we note that κ ∂u ∂n = −au +g on Γ r and v = 0 on Γ d and ∂Ω = Γ d ∪ Γ n thus − ∂Ω vκ ∂u ∂n = Γ r auv − Γ r bv The problem becomes: Find u ∈ V g = ¦v ∈ H 1 (Ω)/v = g on Γ d ¦ such that Ω κ∇v.∇udω + Γ r auv dγ = Ω fv dω + Γ r bv dγ, ∀v ∈ V 0 (6.27) where V 0 = ¦v ∈ H 1 (Ω)/v = 0 on Γ d ¦ Except in the case of Neumann conditions everywhere, the problem (6.27) is well posed when κ ≥ κ 0 > 0. Note 6.8 If we have only Neumann boundary condition, linear algebra tells us that the right hand side must be orthogonal to the kernel of the operator for the solution to exist. One way of writing the compatibility condition is: Ω f dω + Γ b dγ = 0 6.9. PARAMETERS AFFECTING SOLVE AND PROBLEM 155 and a way to fix the constant is to solve for u ∈ H 1 (Ω) such that: Ω εuv dω + κ∇v.∇udω = Ω fv dω + Γ r bv dγ, ∀v ∈ H 1 (Ω) (6.28) where ε is a small parameter ( ∼ 10 −10 ). Remark that if the solution is of order 1 ε then the compatibility condition is unsatisfied, otherwise we get the solution such that Ω u = 0, you can also add a Lagrange multiplier to solver the real mathe- maical probleme like in the examples++-tutorial/Laplace-lagrange-mult.edp example. In FreeFem++, the bidimensional problem (6.27) becomes problem Pw(u,v) = int2d(Th)( kappa * ( dx(u) * dx(u) + dy(u) * dy(u)) ) // Ω κ∇v.∇udω + int1d(Th,gn)( a * u * v ) // Γ r auv dγ - int2d(Th)(f * v) // Ω fv dω - int1d(Th,gn)( b * v ) // Γ r bv dγ + on(gd)(u= g) ; // u = g on Γ d where Th is a mesh of the the bidimensional domain Ω, and gd and gn are respectively the boundary label of boundary Γ d and Γ n . And the the three dimensional problem (6.27) becomes macro Grad(u) [dx(u),dy(u),dz(u) ]// EOM : definition of the 3d Grad macro problem Pw(u,v) = int3d(Th)( kappa * ( Grad(u)’ * Grad(v) ) ) // Ω κ∇v.∇udω + int2d(Th,gn)( a * u * v ) // Γ r auv dγ - int3d(Th)(f * v) // Ω fv dω - int2d(Th,gn)( b * v ) // Γ r bv dγ + on(gd)(u= g) ; // u = g on Γ d where Th is a mesh of the three dimensional domain Ω, and gd and gn are respectively the boundary label of boundary Γ d and Γ n . 6.9 Parameters affecting solve and problem The parameters are FE functions real or complex, the number n of parameters is even (n = 2 ∗ k), the k first function parameters are unknown, and the k last are test functions. Note 6.9 If the functions are a part of vectoriel FE then you must give all the functions of the vectorial FE in the same order (see laplaceMixte problem for example). Note 6.10 Don’t mix complex and real parameters FE function. Bug: 1 The mixing of fespace with different periodic boundary condition is not implemented. So all the finite element spaces used for test or unknown functions in a problem, must have the same type of periodic boundary condition or no periodic boundary condition. No clean message is given and the result is impredictible, Sorry. The parameters are: 156 CHAPTER 6. FINITE ELEMENTS solver= LU, CG, Crout,Cholesky,GMRES,sparsesolver, UMFPACK ... The default solver is sparsesolver ( it is equal to UMFPACK if not other sparce solver is defined) or is set to LU if no direct sparse solver is available. The storage mode of the matrix of the underlying linear system depends on the type of solver chosen; for LU the matrix is sky-line non symmetric, for Crout the matrix is sky-line symmetric, for Cholesky the matrix is sky-line symmetric positive definite, for CG the matrix is sparse symmetric positive, and for GMRES, sparsesolver or UMFPACK the matrix is just sparse. eps= a real expression. ε sets the stopping test for the iterative methods like CG. Note that if ε is negative then the stopping test is: [[Ax −b[[ < [ε[ if it is positive then the stopping test is [[Ax −b[[ < [ε[ [[Ax 0 −b[[ init= boolean expression, if it is false or 0 the matrix is reconstructed. Note that if the mesh changes the matrix is reconstructed too. precon= name of a function (for example P) to set the preconditioner. The prototype for the function P must be func real[int] P(real[int] & xx) ; tgv= Huge value (10 30 ) used to implement Dirichlet boundary conditions, see page 157 for descrip- tion. tolpivot= set the tolerence of the pivot in UMFPACK (10 −1 ) and, LU, Crout, Cholesky factorisa- tion (10 −20 ). tolpivotsym= set the tolerence of the pivot sym in UMFPACK strategy= set the integer UMFPACK strategy (0 by default). 6.10 Problem definition Below v is the unknown function and w is the test function. After the ”=” sign, one may find sums of: • identifier(s); this is the name given earlier to the variational form(s) (type varf ) for possible reuse. Remark, that the name in the ”varf” of the unknow of test function is forgotten, we just used the order in argument list to recall name as in a C++ function, see note 6.15, • the terms of the bilinear form itself: if K is a given function, - int3d(Th)( K * v * w) = ¸ T∈Th T K v w 6.10. PROBLEM DEFINITION 157 - int3d(Th,1)( K * v * w) = ¸ T∈Th,T⊂Ω 1 T K v w - int2d(Th)( K * v * w) = ¸ T∈Th T K v w - int2d(Th,1)( K * v * w) = ¸ T∈Th,T⊂Ω 1 T K v w - int1d(Th,2,5)( K * v * w) = ¸ T∈Th (∂T∪Γ)∩(Γ 2 ∪Γ 5 ) K v w - intalledges(Th)( K * v * w) = ¸ T∈Th ∂T K v w - intalledges(Th,1)( K * v * w) = ¸ T∈Th,T⊂Ω 1 ∂T K v w - they contribute to the sparse matrix of type matrix which, whether declared explicitly or not is contructed by FreeFem++ . • the right handside of the PDE, volumic terms of the linear form: for given functions K, f: - int3d(Th)( K * w) = ¸ T∈Th T K w - int2d(Th)( K * w) = ¸ T∈Th T K w - int1d(Th,2,5)( K * w) = ¸ T∈Th (∂T∪Γ)∩(Γ 2 ∪Γ 5 ) K w - intalledges(Th)( f * w) = ¸ T∈Th ∂T f w - a vector of type real[int] • The boundary condition terms : – An ”on” scalar form (for Dirichlet ) : on(1, u = g ) The meaning is for all degree of freedom i of the boundary refered by ”1”, the diagonal term of the matrix a ii = tgv with the terrible geant value tgv (=10 30 by default) and the right hand side b[i] = ”(Π h g)[i]” tgv, where the ”(Π h g)g[i]” is the boundary node value given by the interpolation of g. remark, if tgv < 0 then we put to 0 all term of the line i in the matrix, except diagonal term a ii = 1, and b[i] = ”(Π h g)[i]”. (version ¿ 3.10) . – An ”on” vectorial form (for Dirichlet ) : on(1,u1=g1,u2=g2) If you have vec- torial finite element like RT0, the 2 components are coupled, and so you have : b[i] = ”(Π h (g1, g2))[i]” tgv, where Π h is the vectorial finite element interpolant. – a linear form on Γ (for Neumann in 2d ) -int1d(Th))( f * w) or -int1d(Th,3))( f * w) – a bilinear form on Γ or Γ 2 (for Robin in 2d) int1d(Th))( K * v * w) or int1d(Th,2))( K * v * w). 158 CHAPTER 6. FINITE ELEMENTS – a linear form on Γ (for Neumann in 3d ) -int2d(Th))( f * w) or -int2d(Th,3))( f * w) – a bilinear form on Γ or Γ 2 (for Robin in 3d) int2d(Th))( K * v * w) or int2d(Th,2))( K * v * w). Note 6.11 • If needed, the different kind of terms in the sum can appear more than once. • the integral mesh and the mesh associated to test function or unknown function can be dif- ferent in the case of linear form. • N.x, N.y and N.z are the normal’s components. Important: it is not possible to write in the same integral the linear part and the bilinear part such as in int1d(Th)( K * v * w - f * w) . 6.11 Numerical Integration Let D be a N-dimensional bounded domain. For an arbitrary polynomial f of degree r, if we can find particular (quadrature) points ξ j , j = 1, , J in D and (quadrature) constants ω j such that D f(x) = L ¸ =1 c f(ξ ) (6.29) then we have an error estimate (see Crouzeix-Mignot (1984)), and then there exists a constant C > 0 such that, D f(x) − L ¸ =1 ω f(ξ ) ≤ C[D[h r+1 (6.30) for any function r + 1 times continuously differentiable f in D, where h is the diameter of D and [D[ its measure (a point in the segment [q i q j ] is given as ¦(x, y)[ x = (1 −t)q i x +tq j x , y = (1 −t)q i y +tq j y , 0 ≤ t ≤ 1¦). For a domain Ω h = ¸ n t k=1 T k , T h = ¦T k ¦, we can calculate the integral over Γ h = ∂Ω h by Γ h f(x)ds = int1d(Th)(f) = int1d(Th,qfe= * )(f) = int1d(Th,qforder= * )(f) where * stands for the name of the quadrature formula or the precision (order) of the Gauss formula. 6.11. NUMERICAL INTEGRATION 159 Quadature formula on an edge L (qfe=) qforder= point in [q i q j ](= t) ω exact on P k , k = 1 qf1pE 2 1/2 [q i q j [ 1 2 qf2pE 3 (1 ± 1/3)/2 [q i q j [/2 3 3 qf3pE 6 (1 ± 3/5)/2 (5/18)[q i q j [ 5 1/2 (8/18)[q i q j [ 4 qf4pE 8 (1 ± √ 525+70 √ 30 35 )/2. 18− √ 30 72 [q i q j [ 7 (1 ± √ 525−70 √ 30 35 )/2. 18+ √ 30 72 [q i q j [ 5 qf5pE 10 (1 ± √ 245+14 √ 70 21 )/2 322−13 √ 70 1800 [q i q j [ 9 1/2 64 225 [q i q j [ (1 ± √ 245−14 √ 70 21 )/2 322+13 √ 70 1800 [q i q j [ 2 qf1pElump 2 0 [q i q j [/2 1 +1 [q i q j [/2 where [q i q j [ is the length of segment q i q j . For a part Γ 1 of Γ h with the label “1”, we can calculate the integral over Γ 1 by Γ 1 f(x, y)ds = int1d(Th,1)(f) = int1d(Th,1,qfe=qf2pE)(f) The integrals over Γ 1 , Γ 3 are given by Γ 1 ∪Γ 3 f(x, y)ds = int1d(Th,1,3)(f) For each triangle T k = [q k 1 q k 2 q k 3 ] , the point P(x, y) in T k is expressed by the area coordinate as P(ξ, η): [T k [ = 1 2 1 q k 1 x q k 1 y 1 q k 2 x q k 2 y 1 q k 3 x q k 3 y D 1 = 1 x y 1 q k 2 x q k 2 y 1 q k 3 x q k 3 y D 2 = 1 q k 1 x q k 1 y 1 x y 1 q k 3 x q k 3 y D 3 = 1 q k 1 x q k 1 y 1 q k 2 x q k 2 y 1 x y ξ = 1 2 D 1 /[T k [ η = 1 2 D 2 /[T k [ then 1 −ξ −η = 1 2 D 3 /[T k [ For a two dimensional domain or a border of three dimensional domain Ω h = ¸ n t k=1 T k , T h = ¦T k ¦, we can calculate the integral over Ω h by Ω h f(x, y) = int2d(Th)(f) = int2d(Th,qft= * )(f) = int2d(Th,qforder= * )(f) where * stands for the name of quadrature formula or the order of the Gauss formula. 160 CHAPTER 6. FINITE ELEMENTS Quadature formula on a triangle L qft= qforder= point in T k ω exact on P k , k = 1 qf1pT 2 1 3 , 1 3 [T k [ 1 3 qf2pT 3 1 2 , 1 2 [T k [/3 2 1 2 , 0 [T k [/3 0, 1 2 [T k [/3 7 qf5pT 6 1 3 , 1 3 0.225[T k [ 5 6− √ 15 21 , 6− √ 15 21 (155− √ 15)|T k | 1200 6− √ 15 21 , 9+2 √ 15 21 (155− √ 15)|T k | 1200 9+2 √ 15 21 , 6− √ 15 21 (155− √ 15)|T k | 1200 6+ √ 15 21 , 6+ √ 15 21 (155+ √ 15)|T k | 1200 6+ √ 15 21 , 9−2 √ 15 21 (155+ √ 15)|T k | 1200 9−2 √ 15 21 , 6+ √ 15 21 (155+ √ 15)|T k | 1200 3 qf1pTlump (0, 0) [T k [/3 1 (1, 0) [T k [/3 (0, 1) [T k [/3 9 qf2pT4P1 1 4 , 3 4 [T k [/12 1 3 4 , 1 4 [T k [/12 0, 1 4 [T k [/12 0, 3 4 [T k [/12 1 4 , 0 [T k [/12 3 4 , 0 [T k [/12 1 4 , 1 4 [T k [/6 1 4 , 1 2 [T k [/6 1 2 , 1 4 [T k [/6 15 qf7pT 8 see [38] for detail 7 21 qf9pT 10 see [38] for detail 9 For a three dimensional domain Ω h = ¸ n t k=1 T k , T h = ¦T k ¦, we can calculate the integral over Ω h by Ω h f(x, y) = int3d(Th)(f) = int3d(Th,qfV= * )(f) = int3d(Th,qforder= * )(f) where * stands for the name of quadrature formula or the order of the Gauss formula. Quadature formula on a tetrahedron L qfV= qforder= point in T k ∈ R 3 ω exact on P k , k = 1 qfV1 2 1 4 , 1 4 , 1 4 [T k [ 1 4 qfV2 3 G4(0.58 . . . , 0.13 . . . , 0.13 . . .) [T k [/4 2 14 qfV5 6 G4(0.72 . . . , 0.092 . . . , 0.092 . . .) 0.073 . . . [T k [ 5 G4(0.067 . . . , 0.31 . . . , 0.31 . . .) 0.11 . . . [T k [ G6(0.45 . . . , 0.045 . . . , 0.45 . . .) 0.042 . . . [T k [ 4 qfV1lump G4(1, 0, 0) [T k [/4 1 6.12. VARIATIONAL FORM, SPARSE MATRIX, PDE DATA VECTOR 161 Where G4(a, b, b) such that a + 3b = 1 is the set of the four point in barycentric coordinate ¦(a, b, b, b), (b, a, b, b), (b, b, a, b), (b, b, b, a)¦ and where G6(a, b, b) such that 2a + 2b = 1 is the set of the six points in barycentric coordinate ¦(a, a, b, b), (a, b, a, b), (a, b, b, a), (b, b, a, a), (b, a, b, a), (b, a, a, b)¦. Note 6.12 These tetrahedral quadrature formulae come from http://www.cs.kuleuven.be/ ˜ nines/research/ecf/mtables.html Note 6.13 By default, we use the formula which is exact for polynomials of degree 5 on triangles or edges (in bold in three tables). 6.12 Variational Form, Sparse Matrix, PDE Data Vector In FreeFem++ it is possible to define variational forms, and use them to build matrices and vectors and store them to speed-up the script (4 times faster here). For example let us solve the Thermal Conduction problem of section 3.4. The variational formulation is in L 2 (0, T; H 1 (Ω)); we shall seek u n satisfying ∀w ∈ V 0 ; Ω u n −u n−1 δt w +κ∇u n ∇w) + Γ α(u n −u ue )w = 0 where V 0 = ¦w ∈ H 1 (Ω)/w |Γ 24 = 0¦. So the to code the method with the matrices A = (A ij ), M = (M ij ), and the vectors u n , b n , b , b”, b cl ( notation if w is a vector then w i is a component of the vector). u n = A −1 b n , b = b 0 +Mu n−1 , b” = 1 ε b cl , b n i = b” i if i ∈ Γ 24 b i else if ∈ Γ 24 (6.31) Where with 1 ε = tgv = 10 30 : A ij = 1 ε if i ∈ Γ 24 , andj = i Ω w j w i /dt +k(∇w j .∇w i ) + Γ 13 αw j w i else if i ∈ Γ 24 , orj = i (6.32) M ij = 1 ε if i ∈ Γ 24 , andj = i Ω w j w i /dt else if i ∈ Γ 24 , orj = i (6.33) b 0,i = Γ 13 αu ue w i (6.34) b cl = u 0 the initial data (6.35) // file thermal-fast.edp in examples++-tutorial func fu0 =10+90 * x/6; func k = 1.8 * (y<0.5)+0.2; real ue = 25. , alpha=0.25, T=5, dt=0.1 ; 162 CHAPTER 6. FINITE ELEMENTS mesh Th=square(30,5,[6 * x,y]); fespace Vh(Th,P1); Vh u0=fu0,u=u0; Create three variational formulation, and build the matrices A,M. varf vthermic (u,v)= int2d(Th)(u * v/dt + k * (dx(u) * dx(v) + dy(u) * dy(v))) + int1d(Th,1,3)(alpha * u * v) + on(2,4,u=1); varf vthermic0(u,v) = int1d(Th,1,3)(alpha * ue * v); varf vMass (u,v)= int2d(Th)( u * v/dt) + on(2,4,u=1); real tgv = 1e30; matrix A= vthermic(Vh,Vh,tgv=tgv,solver=CG); matrix M= vMass(Vh,Vh); Now, to build the right hand size we need 4 vectors. real[int] b0 = vthermic0(0,Vh); // constant part of the RHS real[int] bcn = vthermic(0,Vh); // tgv on Dirichlet boundary node ( !=0 ) // we have for the node i : i ∈ Γ 24 ⇔ bcn[i] = 0 real[int] bcl=tgv * u0[]; // the Dirichlet boundary condition part Note 6.14 The boundary condition is implemented by penalization and vector bcn contains the contribution of the boundary condition u = 1 , so to change the boundary condition, we have just to multiply the vector bc[] by the current value f of the new boundary condition term by term with the operator . * . Section 9.6.2 Examples++-tutorial/StokesUzawa.edp gives a real example of using all this features. And the new version of the algorithm is now: ofstream ff("thermic.dat"); for(real t=0;t<T;t+=dt){ real[int] b = b0 ; // for the RHS b += M * u[]; // add the the time dependent part // lock boundary part: b = bcn ? bcl : b ; // do ∀i: b[i] = bcn[i] ? bcl[i] : b[i] ; u[] = Aˆ-1 * b; ff << t <<" "<<u(3,0.5)<<endl; plot(u); } for(int i=0;i<20;i++) cout<<dy(u)(6.0 * i/20.0,0.9)<<endl; plot(u,fill=true,wait=1,ps="thermic.eps"); 6.12. VARIATIONAL FORM, SPARSE MATRIX, PDE DATA VECTOR 163 Note 6.15 The functions appearing in the variational form are formal and local to the varf defi- nition, the only important thing is the order in the parameter list, like in varf vb1([u1,u2],q) = int2d(Th)( (dy(u1)+dy(u2)) * q) + int2d(Th)(1 * q); varf vb2([v1,v2],p) = int2d(Th)( (dy(v1)+dy(v2)) * p) + int2d(Th)(1 * p); To build matrix A from the bilinear part the variational form a of type varf simply write: A = a(Vh,Wh [, ...] ); // where // Vh is "fespace" for the unknow fields with a correct number of component // Wh is "fespace" for the test fields with a correct number of component Possible named parameters in " [, ... ] " are solver= LU, CG, Crout, Cholesky, GMRES, sparsesolver, UMFPACK ... The default solver is GMRES. The storage mode of the matrix of the underlying linear system depends on the type of solver chosen; for LU the matrix is sky-line non symmetric, for Crout the matrix is sky- line symmetric, for Cholesky the matrix is sky-line symmetric positive definite, for CG the matrix is sparse symmetric positive, and for GMRES, sparsesolver or UMFPACK the matrix is just sparse. factorize = if true then do the matrix factorization for LU, Cholesky or Crout, the default value is false. eps= a real expression. ε sets the stopping test for the iterative methods like CG. Note that if ε is negative then the stopping test is: [[Ax −b[[ < [ε[ if it is positive then the stopping test is [[Ax −b[[ < [ε[ [[Ax 0 −b[[ precon= name of a function (for example P) to set the preconditioner. The prototype for the function P must be func real[int] P(real[int] & xx) ; tgv= Huge value (10 30 ) used to implement Dirichlet boundary conditions. tolpivot= set the tolerance of the pivot in UMFPACK (10 − 1) and, LU, Crout, Cholesky factori- sation (10 −20 ). tolpivotsym= set the tolerance of the pivot sym in UMFPACK strategy= set the integer UMFPACK strategy (0 by default). Note 6.16 The line of the matrix corresponding to the space Wh and the column of the matrix corresponding to the space Vh. 164 CHAPTER 6. FINITE ELEMENTS To build the dual vector b (of type real[int]) from the linear part of the variational form a do simply real b(Vh.ndof); b = a(0,Vh); A first example to compute the area of each triangle K of mesh Th, just do: fespace Nh(Th,P0); // the space function constant / triangle Nh areaK; varf varea(unused,chiK) = int2d(Th)(chiK); etaK[]= varea(0,Ph); Effectively, the basic functions of space Nh, are the characteristic function of the element of Th, and the numbering is the numeration of the element, so by construction: etaK[i] = 1 |K i = K i 1; Now, we can use this to compute error indicators like in examples AdaptResidualErrorIndi- cator.edp in directory examples++-tutorial. First to compute a continuous approximation to the function h ”density mesh size” of the mesh Th. fespace Vh(Th,P1); Vh h ; real[int] count(Th.nv); varf vmeshsizen(u,v)=intalledges(Th,qfnbpE=1)(v); varf vedgecount(u,v)=intalledges(Th,qfnbpE=1)(v/lenEdge); // computation of the mesh size // ----------------------------- count=vedgecount(0,Vh); // number of edge / vertex h[]=vmeshsizen(0,Vh); // sum length edge / vertex h[]=h[]./count; // mean lenght edge / vertex To compute error indicator for Poisson equation : η K = K h 2 K [(f + ∆u h )[ 2 + ∂K h e [[ ∂u h ∂n ][ 2 where h K is size of the longest edge ( hTriangle), h e is the size of the current edge ( lenEdge), n the normal. fespace Nh(Th,P0); // the space function contant / triangle Nh etak; varf vetaK(unused,chiK) = intalledges(Th)(chiK * lenEdge * square(jump(N.x * dx(u)+N.y * dy(u)))) +int2d(Th)(chiK * square(hTriangle * (f+dxx(u)+dyy(u))) ); etak[]= vetaK(0,Ph); We add automatic expression optimization by default, if this optimization creates problems, it can be removed with the keyword optimize as in the following example : varf a(u1,u2)= int2d(Th,optimize=false)( dx(u1) * dx(u2) + dy(u1) * dy(u2) ) + on(1,2,4,u1=0) + on(3,u1=1) ; 6.13. INTERPOLATION MATRIX 165 Remark, it is all possible to build interpolation matrix, like in the following example: mesh TH = square(3,4); mesh th = square(2,3); mesh Th = square(4,4); fespace VH(TH,P1); fespace Vh(th,P1); fespace Wh(Th,P1); matrix B= interpolate(VH,Vh); // build interpolation matrix Vh->VH matrix BB= interpolate(Wh,Vh); // build interpolation matrix Vh->Wh and after some operations on sparse matrices are available for example int N=10; real [int,int] A(N,N); // a full matrix real [int] a(N),b(N); A =0; for (int i=0;i<N;i++) { A(i,i)=1+i; if(i+1 < N) A(i,i+1)=-i; a[i]=i; } b=A * b; cout << "xxxx\n"; matrix sparseA=A; cout << sparseA << endl; sparseA = 2 * sparseA+sparseA’; sparseA = 4 * sparseA+sparseA * 5; matrix sparseB=sparseA+sparseA+sparseA; ; cout << "sparseB = " << sparseB(0,0) << endl; 6.13 Interpolation matrix It is also possible to store the matrix of a linear interpolation operator from a finite element space V h to another W h to interpolate(W h ,V h ,...) a function. Note that the continuous finite functions are extended by continuity outside of the domain. The named parameters of function interpolate are: inside= set true to create zero-extension. t= set true to get the transposed matrix op= set an integer written below 0 the default value and interpolate of the function 1 interpolate the ∂ x 2 interpolate the ∂ y 3 interpolate the ∂ z 166 CHAPTER 6. FINITE ELEMENTS U2Vc= set the which is the component of W h come in V h in interpolate process in a int array so the size of the array is number of component of W h , if the put −1 then component is set to 0, like in the following example: (by default the component number is unchanged). fespace V4h(Th4,[P1,P1,P1,P1]); fespace V3h(Th,[P1,P1,P1]); int[int] u2vc=[1,3,-1]; // -1 => put zero on the component matrix IV34= interpolate(V3h,V4h,inside=0,U2Vc=u2vc); // V3h <- V4h V4h [a1,a2,a3,a4]=[1,2,3,4]; V3h [b1,b2,b3]=[10,20,30]; b1[]=IV34 * a1[]; So here we have: b1 == 2, b2 == 4, b3 == 0 . . Example 6.2 (mat interpol.edp) mesh Th=square(4,4); mesh Th4=square(2,2,[x * 0.5,y * 0.5]); plot(Th,Th4,ps="ThTh4.eps",wait=1); fespace Vh(Th,P1); fespace Vh4(Th4,P1); fespace Wh(Th,P0); fespace Wh4(Th4,P0); matrix IV= interpolate(Vh,Vh4); // here the function is // exended by continuity cout << " IV Vh<-Vh4 " << IV << endl; Vh v, vv; Vh4 v4=x * y; v=v4; vv[]= IV * v4[]; // here v == vv => real[int] diff= vv[] - v[]; cout << " || v - vv || = " << diff.linfty << endl; assert( diff.linfty<= 1e-6); matrix IV0= interpolate(Vh,Vh4,inside=1); // here the function is // exended by zero cout << " IV Vh<-Vh4 (inside=1) " << IV0 << endl; matrix IVt0= interpolate(Vh,Vh4,inside=1,t=1); cout << " IV Vh<-Vh4ˆt (inside=1) " << IVt0 << endl; matrix IV4t0= interpolate(Vh4,Vh); cout << " IV Vh4<-Vhˆt " << IV4t0 << endl; matrix IW4= interpolate(Wh4,Wh); cout << " IV Wh4<-Wh " << IW4 << endl; matrix IW4V= interpolate(Wh4,Vh); cout << " IV Wh4<-Vh " << IW4 << endl; Build interpolation matrix A at a array of points (xx[j], yy[j]), i = 0, 2 here a i j = dop(w i c (xx[j], yy[j])) where w i is the basic finite element function, c the component number, dop the type of diff operator like in op def. real[int] xx=[.3,.4],yy=[.1,.4]; int c=0,dop=0; matrix Ixx= interpolate(Vh,xx,yy,op=dop,composante=c); cout << Ixx << endl; Vh ww; real[int] dd=[1,2]; ww[]= Ixx * dd; 6.14. FINITE ELEMENTS CONNECTIVITY 167 6.14 Finite elements connectivity Here, we show how to get informations on a finite element space W h (T n , ∗), where “*” may be P1, P2, P1nc, etc. • Wh.nt gives the number of element of W h • Wh.ndof gives the number of degrees of freedom or unknown • Wh.ndofK gives the number of degrees of freedom on one element • Wh(k,i) gives the number of ith degrees of freedom of element k. See the following example: Example 6.3 (FE.edp) mesh Th=square(5,5); fespace Wh(Th,P2); cout << " nb of degree of freedom : " << Wh.ndof << endl; cout << " nb of degree of freedom / ELEMENT : " << Wh.ndofK << endl; int k= 2, kdf= Wh.ndofK ;; // element 2 cout << " df of element " << k << ":" ; for (int i=0;i<kdf;i++) cout << Wh(k,i) << " "; cout << endl; The output is: Nb Of Nodes = 121 Nb of DF = 121 FESpace:Gibbs: old skyline = 5841 new skyline = 1377 nb of degree of freedom : 121 nb of degree of freedom / ELEMENT : 6 df of element 2:78 95 83 87 79 92 168 CHAPTER 6. FINITE ELEMENTS Chapter 7 Visualization Results created by the finite element method can be a huge set of data, so it is very important to render them easy to grasp. There are two ways of visualization in FreeFem++ : One, the default view, supports the drawing of meshes, isovalues of real FE-functions and of vector fields, all by the command plot (see Section 7.1 below). For publishing purpose, FreeFem++ can store these plots as postscript files. Another method is to use external tools, for example, gnuplot (see Section 7.2), medit (see Section 7.3) using the command system to launch them and/or to save the data in text files. 7.1 Plot With the command plot, meshes, isovalues of scalar functions and vector fields can be displayed. The parameters of the plot command can be , meshes, real FE functions , arrays of 2 real FE functions, arrays of two arrays of double, to plot respectively a mesh, a function, a vector field, or a curve defined by the two arrays of double. Note 7.1 The length of an arrow is always bound to be in [5‰, 5%] of the screen size, to see something (else it will only look like porcupine). The parameters are wait= boolean expression to wait or not (by default no wait). If true we wait for a keyboard event or mouse event, they respond to an event by the following characters + to zoom in around the mouse cursor, - to zoom out around the mouse cursor, = to restore de initial graphics state, c to decrease the vector arrows size, C to increase the vector arrows size, r to refresh the graphic window, f to toggle between color fills and isovalues, b to toggle into black and white, g to toggle to grey or color , v to toggle the display of isovalue scale, ? to show all active keyboard char, 169 170 CHAPTER 7. VISUALIZATION enter go to the next plot, ESC close the graphics process. otherwise do nothing. ps= string expression for the name of the file to save the plot in postscript coef= the vector arrow size between arrow unit and domain unit. fill= do a color fill between isovalues. cmm= string expression to write the graphic window into value= to plot the value of isolines and the value of vector arrows. aspectratio= boolean to be sure that the aspect ratio of plot is preserved or not. bb= array of 2 array ( like [[0.1,0.2],[0.5,0.6]]), to set the bounding box and specify a partial view where the box defined by the two corner points [0.1,0.2] and [0.5,0.6]. nbiso= (int) sets the number of isovalues (20 by default) nbarrow= (int) sets the number of colors of arrow values (20 by default) viso= sets the array of isovalues (an array real[int] of increasing values) varrow= sets the array of color arrows values (an array real[int]) bw= (bool) sets or not the plot in black and white color. grey= (bool) sets or not the plot in grey color. hsv= (array of float) to defined color of 3*n value in HSV color model declared for example by real[int] colors = [h1,s1,v1,... , hn,vn,vn]; where hi,si,vi is the ith color to defined the color table. boundary= (bool) to plot or not the boundary of the domain (true by default). dim= (int) sets dim of the plot 2d or 3d (2 by default) For example: real[int] xx(10),yy(10); mesh Th=square(5,5); fespace Vh(Th,P1); Vh uh=x * x+y * y,vh=-yˆ2+xˆ2; int i; // compute a cut for (i=0;i<10;i++) { x=i/10.; y=i/10.; xx[i]=i; yy[i]=uh; // value of uh at point (i/10. , i/10.) } plot(Th,uh,[uh,vh],value=true,ps="three.eps",wait=true); // figure 7.1 7.1. PLOT 171 // zoom on box defined by the two corner points [0.1,0.2] and [0.5,0.6] plot(uh,[uh,vh],bb=[[0.1,0.2],[0.5,0.6]], wait=true,grey=1,fill=1,value=1,ps="threeg.eps"); // figure 7.2 plot([xx,yy],ps="likegnu.eps",wait=true); // figure 7.3 IsoValue 0.05 0.15 0.25 0.35 0.45 0.55 0.65 0.75 0.85 0.95 1.05 1.15 1.25 1.35 1.45 1.55 1.65 1.75 1.85 1.95 Vec Value 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 Figure 7.1: mesh, isovalue, and vector IsoValue -0.105263 0.0526316 0.157895 0.263158 0.368421 0.473684 0.578947 0.684211 0.789474 0.894737 1 1.10526 1.21053 1.31579 1.42105 1.52632 1.63158 1.73684 1.84211 2.10526 Vec Value 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 Figure 7.2: enlargement in grey of isovalue, and vector Figure 7.3: Plots a cut of uh. Note that a refinement of the same can be obtained in combination with gnuplot To change the color table and to choose the value of iso line you can do : // from: http://en.wikipedia.org/wiki/HSV_color_space // The HSV (Hue, Saturation, Value) model, // defines a color space in terms of three constituent components: // // HSV color space as a color wheel 7.4 // Hue, the color type (such as red, blue, or yellow): // Ranges from 0-360 (but normalized to 0-100% in some applications Here) 172 CHAPTER 7. VISUALIZATION // Saturation, the "vibrancy" of the color: Ranges from 0-100% // The lower the saturation of a color, the more "grayness" is present // and the more faded the color will appear. // Value, the brightness of the color: // Ranges from 0-100% // real[int] colorhsv=[ // color hsv model 4./6., 1 , 0.5, // dark blue 4./6., 1 , 1, // blue 5./6., 1 , 1, // magenta 1, 1. , 1, // red 1, 0.5 , 1 // light red ]; real[int] viso(31); for (int i=0;i<viso.n;i++) viso[i]=i * 0.1; plot(uh,viso=viso(0:viso.n-1),value=1,fill=1,wait=1,hsv=colorhsv); Figure 7.4: hsv color cylinder IsoValue -0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3 Figure 7.5: isovalue with an other color table 7.2. LINK WITH GNUPLOT 173 7.2 link with gnuplot Example 3.2 shows how to generate a gnu-plot from a FreeFem++ file. Let us present here another technique which has the advantage of being online, i.e. one doesn’t need to quit FreeFem++ to generate a gnu-plot. But this work only if gnuplot 1 is installed , and only on unix computer. Add to the previous example: { // file for gnuplot ofstream gnu("plot.gp"); for (int i=0;i<=n;i++) { gnu << xx[i] << " " << yy[i] << endl; } } // the file plot.gp is close because the variable gnu is delete // to call gnuplot command and wait 5 second (thanks to unix command) // and make postscript plot exec("echo ’plot `"plot.gp`" w l ` pause 5 ` set term postscript ` set output `"gnuplot.eps`" ` replot ` quit’ | gnuplot"); 0 0 .5 1 1 .5 2 0 5 1 0 1 5 2 0 " p lo t.g p " Figure 7.6: Plots a cut of uh with gnuplot 7.3 link with medit As said above, medit 2 is a freeware display package by Pascal Frey using OpenGL. Then you may run the following example. Remark: Now medit software is include in FreeFem++ under ffmedit name. 1 http://www.gnuplot.info/ 2 http://www-rocq.inria.fr/gamma/medit/medit.html 174 CHAPTER 7. VISUALIZATION Figure 7.7: medit plot Now with version 3.2 or better load "medit" mesh Th=square(10,10,[2 * x-1,2 * y-1]); fespace Vh(Th,P1); Vh u=2-x * x-y * y; medit("mm",u); Before: mesh Th=square(10,10,[2 * x-1,2 * y-1]); fespace Vh(Th,P1); Vh u=2-x * x-y * y; savemesh(Th,"mm",[x,y,u * .5]); // save mm.points and mm.faces file // for medit // build a mm.bb file { ofstream file("mm.bb"); file << "2 1 1 "<< u[].n << " 2 \n"; for (int j=0;j<u[].n ; j++) file << u[][j] << endl; } // call medit command exec("ffmedit mm"); // clean files on unix OS exec("rm mm.bb mm.faces mm.points"); Chapter 8 Algorithms The complete example is in algo.edp file. 8.1 conjugate Gradient/GMRES Suppose we want to solve the Euler problem (here x has nothing to do with the reserved variable for the first coordinate in FreeFem++ ): find x ∈ R n such that ∇J(x) = ∂J ∂x i (x) = 0 (8.1) where J is a functional (to minimize for example) from R n to R. If the function is convex we can use the conjugate gradient to solve the problem, and we just need the function (named dJ for example) which compute ∇J, so the parameters are the name of that function with prototype func real[int] dJ(real[int] & xx); which compute ∇J, and a vector x of type ( of course the number 20 can be changed) real[int] x(20); to initialize the process and get the result. Given an initial value x (0) , a maximum number i max of iterations, and an error tolerance 0 < < 1: Put x = x (0) and write NLCG(∇J, x, precon= M, nbiter= i max , eps= ); will give the solution of x of ∇J(x) = 0. We can omit parameters precon, nbiter, eps. Here M is the preconditioner whose default is the identity matrix. The stopping test is |∇J(x)| P ≤ |∇J(x (0) )| P Writing the minus value in eps=, i.e., NLCG(∇J, x, precon= M, nbiter= i max , eps= −); we can use the stopping test |∇J(x)| 2 P ≤ The parameters of these three functions are: nbiter= set the number of iteration (by default 100) 175 176 CHAPTER 8. ALGORITHMS precon= set the preconditioner function (P for example) by default it is the identity, remark the prototype is func real[int] P(real[int] &x). eps= set the value of the stop test ε (= 10 −6 by default) if positive then relative test [[∇J(x)[[ P ≤ ε[[∇J(x 0 )[[ P , otherwise the absolute test is [[∇J(x)[[ 2 P ≤ [ε[. veps= set and return the value of the stop test, if positive then relative test [[∇J(x)[[ P ≤ ε[[∇J(x 0 )[[ P , otherwise the absolute test is [[∇J(x)[[ 2 P ≤ [ε[. The return value is minus the real stop test (remark: it is useful in loop). Example 8.1 (algo.edp) For a given function b, let us find the minimizer u of the functional J(u) = 1 2 Ω f([∇u[ 2 ) − Ω ub f(x) = ax +x −ln(1 +x), f (x) = a + x 1 +x , f (x) = 1 (1 +x) 2 under the boundary condition u = 0 on ∂Ω. func real J(real[int] & u) { Vh w;w[]=u; // copy array u in the finite element function w real r=int2d(Th)(0.5 * f( dx(w) * dx(w) + dy(w) * dy(w) ) - b * w) ; cout << "J(u) =" << r << " " << u.min << " " << u.max << endl; return r; } // ----------------------- Vh u=0; // the current value of the solution Ph alpha; // of store df([∇u[ 2 ) int iter=0; alpha=df( dx(u) * dx(u) + dy(u) * dy(u) ); // optimization func real[int] dJ(real[int] & u) { int verb=verbosity; verbosity=0; Vh w;w[]=u; // copy array u in the finite element function w alpha=df( dx(w) * dx(w) + dy(w) * dy(w) ); // optimization varf au(uh,vh) = int2d(Th)( alpha * ( dx(w) * dx(vh) + dy(w) * dy(vh) ) - b * vh) + on(1,2,3,4,uh=0); u= au(0,Vh); verbosity=verb; return u; // warning no return of local array } We want to construct also a preconditioner C with solving the problem: find u h ∈ V 0h such that ∀v h ∈ V 0h , Ω α∇u h .∇v h = Ω bv h where α = f ([∇u[ 2 ). */ varf alap(uh,vh)= int2d(Th)( alpha * ( dx(uh) * dx(vh) + dy(uh) * dy(vh) )) + on(1,2,3,4,uh=0); 8.1. CONJUGATE GRADIENT/GMRES 177 varf amass(uh)= int2d(Th)( uh * vh) + on(1,2,3,4,uh=0); matrix Amass = alap(Vh,Vh,solver=CG); // matrix Alap= alap(Vh,Vh,solver=Cholesky,factorize=1); // // the preconditionner function func real[int] C(real[int] & u) { real[int] w = Amass * u; u = Alapˆ-1 * w; return u; // no return of local array variable } /* To solve the problem, we make 10 iteration of the conjugate gradient, recompute the precondi- tioner and restart the conjugate gradient: */ verbosity=5; int conv=0; real eps=1e-6; for(int i=0;i<20;i++) { conv=NLCG(dJ,u[],nbiter=10,precon=C,veps=eps); // if (conv) break; // if converge break loop alpha=df( dx(u) * dx(u) + dy(u) * dy(u) ); // recompute alpha optimization Alap = alap(Vh,Vh,solver=Cholesky,factorize=1); cout << " restart with new preconditionner " << conv << " eps =" << eps << endl; } plot (u,wait=1,cmm="solution with NLCG"); For a given symmetric positive matrix A, consider the quadratic form J(x) = 1 2 x T Ax −b T x then J(x) is minimized by the solution x of Ax = b. In this case, we can use the function LinearCG LinearCG(A, x, precon= M, nbiter= i max , eps= ±); If A is not symmetric, we can use GMRES(Generalized Minimum Residual) algorithm by LinearGMRES(A, x, precon= M, nbiter= i max , eps= ±); Also, we can use the non-linear version of GMRES algorithm (the functional J is just convex) LinearGMRES(∇J, x, precon= M, nbiter= i max , eps= ±); For detail of these algorithms, refer to [14][Chapter IV, 1.3]. 178 CHAPTER 8. ALGORITHMS 8.2 Optimization Two algorithms of COOOL a package [27] are interfaced with the Newton Raphson method (call Newton) and the BFGS method. These two ones are directly available in FreeFem (no dynamical link to load). Be careful with these algorithms, because their implementation uses full matrices. We also provide several optimization algorithms from the NLopt library [42] as well as an interface for Hansen’s implementation of CMAES (a MPI version of this one is also available). These last algorithms can be found as dynamical links in the example++-load folder as the ff-NLopt and CMA ES files (CMA ES MPI from the example++-mpi folder for the mpi version). 8.2.1 Example of utilization for BFGS or CMAES real[int] b(10),u(10); func real J(real[int] & u) { real s=0; for (int i=0;i<u.n;i++) s +=(i+1) * u[i] * u[i] * 0.5 - b[i] * u[i]; cout << "J ="<< s << " u =" << u[0] << " " << u[1] << "...\n" ; return s; } // the grad of J (this is a affine version (the RHS is in ) func real[int] DJ(real[int] &u) { for (int i=0;i<u.n;i++) u[i]=(i+1) * u[i]-b[i]; return u; // return of global variable ok }; b=1; u=2; // set right hand side and initial gest BFGS(J,dJ,u,eps=1.e-6,nbiter=20,nbiterline=20); cout << "BFGS: J(u) = " << J(u) << endl; Using the CMA evolution strategy is almost the same, except that, as it is a derivative free op- timizer, the dJ argument is omitted and there are some other named parameters to control the behaviour of the algorithm. With the same objective function as above, an example of utilization would be (see cmaes-VarIneq.edp for a complete example): load "ff-cmaes" ... // define J, u and all here real min = cmaes(J,u,stopTolFun=1e-6,stopMaxIter=3000); cout << "minimal value is " << min << " for u = " << u << endl; This algorithm works with a normal multivariate distribution in the parameters space and try to adapt its covariance matrix using the information provides by the successive function evaluations (see [43] for more details). Thus, some specific parameters can be passed to control the starting distribution, size of the sample generations etc... Named parameters for this are the following : seed= Seed for random number generator (val is an integer). No specified value will lead to a clock based seed initialization. 8.2. OPTIMIZATION 179 initialStdDev= Value for the standard deviations of the initial covariance matrix (val is a real). If the value σ is passed, the initial covariance matrix will be set to σI. The expected initial distance between initial X and the argmin should be roughly initialStdDev. Default is 0.3. initialStdDevs= Same as above except that the argument is an array allowing to set a value of the initial standard deviation for each parameter. Entries differing by several orders of magnitude should be avoided (if it can’t be, try rescaling the problem). stopTolFun= Stops the algorithm if function values differences are smaller than the passed one, default is 10 −12 . stopTolFunHist= Stops the algorithm if function value differences of the best values are smaller than the passed one, default is 0 (unused). stopTolX= Stopping criteria triggered if step sizes in the parameters space are smaller than this real value, default is 0. stopTolXFactor= Stopping criteria triggered when the standard deviation increases more than this value. The default value is 10 3 . stopMaxFunEval= Stops the algorithm when stopMaxFunEval function evaluations have been done. Set to 900(n + 3) 2 by default, where n is the parameters space dimension . stopMaxIter= Integer stopping the search when stopMaxIter generations has been sampled. Unused by default. popsize= Integer value used to change the sample size. The default value is 4+3 ln(n)|, see [43] for more details. Increasing the population size usually improves the global search capabilities at the cost of an at most linear reduction of the convergence speed with respect to popsize. paramFile= This string type parameter allows the user to pass all the parameters using an ex- tern file as in Hansen’s original code. More parameters related to the CMA-ES algorithm can be changed with this file. A sample of it can be found in the examples++-load/ffCMAES/ folder under the name initials.par. Note that the parameters passed to the CMAES function in the FreeFem script will be ignored if an input parameters file is given. 8.2.2 The nlOpt optimizers The ff-NLopt package provides a FreeFem interface to the free/open-source library for nonlinear optimization, thus easing the use of several different free optimization (constrained or not) routines available online along with the PDE solver. All the algorithms are well documented in [42], thus no exhaustive informations concerning their mathematical specificities will be found here and we will focus on the way they are called in a FreeFem script. One needing detailed informations about these algorithms should visit the said cite where a description of each of them is given, as well as many bibliographical links. All the nlOpt features are called that way : load "ff-NLopt" ... // define J, u, and maybe grad(J), some constraints etc... real min = nloptXXXXXX(J,u, // unavoidable part grad = <name of grad(J)> , // if needed lb = // lower bounds array 180 CHAPTER 8. ALGORITHMS ub= // upper bounds array ... // some optional arguments : // constraints functions names, // stopping criterions, // algo. specific parameters, // etc... ); XXXXXX refers to the algorithm tag (not necessarily 6 characters long). u is the starting position (a real[int] type array) which will be overwritten by the algorithm, the value at the end being the found argmin. And as usual, J is a function taking a real[int] type array as argument and returning a real. grad, lb and ub are ”half-optionnal” arguments, in the sense that they are obligatory for some routines but not all. The possible optional named parameters are the following, note that they are not used by all al- gorithm s (some does not supports constraints, or a type of constraints, some are gradient-based and other are derivative free, etc...). One can refer to the table after the parameters description to check which are the named parameters supported by a specific algorithm. Using an unsupported parameter will not stop the compiler work and seldom breaks runtime, it will just be ignored. That said, when it is obvious you are missusing a routine, you will get a warning message at runtime (for exemple if you pass a gradient to a derivative free algorithm, or set the population of a non-genetic one, etc...). In the following description, n stands for the dimension of the search space. Half-optional parameters : grad= The name of the function which computes the gradient of the cost function (prototype should be real[int] → real[int], both argument and result should have the size n). This is needed as soon s a gradient-based method is involved, ignored if defined in a derivative free context. lb/ub = Lower and upper bounds arrays (real[int] type) of size n. Used to define the bounds within which the search variable is allowed to move. Needed for some algorithms, optional or unsupported for others. subOpt : Only enabled for the Augmented Lagrangian and MLSL method who need a sub- optimizer in order to work. Just pass the tag of the desired local algorithm with a string. Constraints related parameters (optional - unused if not specified): IConst/EConst : Allows to pass the name of a function implementing some inequality (resp. equality) constraints on the search space. The function type must be real[int] →real[int] where the size of the returned array is equal to the number of constraints (of the same type - it means that all the constraints are computed in one vectorial function). In order to mix inequality and equality constraints in a same minimization attempt, two vectorial functions have to be defined and passed. See example 8.2 for more details about how these constraints have to be implemented. gradIConst/gradEConst : Use to provide the inequality (resp. equality) constraints gra- dient. These are real[int] → real[int,int] type functions. Assuming we have defined a constraint function (either inequality or equality) with p constraints, the size of the matrix returned by its associated gradient must be p n (the i-th line of the matrix is the gradient of the i-th constraint). It is needed in a gradient-based context as soon as an inequality or equality constraint function is passed to the optimizer and ignored in all other cases. 8.2. OPTIMIZATION 181 tolIConst/tolEConst : Tolerance values for each constraint. This is an array of size equal to the number of inequality (resp. equality) constraints. Default value os set to 10 −12 for each constraint of any type. Stopping criteria : stopFuncValue : Makes the algorithm end when the objective function reaches this real value. stopRelXTol : Stops the algorithm when the relative moves in each direction of the search space is smaller than this real value. stopAbsXTol : Stops the algorithm when the moves in each direction of the search space is smaller than the corresponding value in this real[int] array. stopRelFTol : Stops the algorithm when the relative variation of the objective function is smaller than this real value. stopAbsFTol : Stops the algorithm when the variation of the objective function is smaller than this real value. stopMaxFEval : Stops the algorithm when the number of fitness evaluations reaches this integer value. stopTime : Stops the algorithm when the otpimization time in second exceeds this real value. This is not a strict maximum: the time may exceed it slightly, depending upon the algorithm and on how slow your function evaluation is. Note that when an AUGLAG or MLSL method is used, the meta-algorithm and the sub- algorithm may have different termination criteria. Thus, for algorithms of this kind, the following named parameters has been defined (just adding the SO prefix - for Sub-Optimizer) to set the ending condition of the sub-algorithm (the meta one uses the ones above) : SOStopFuncValue, SOStopRelXTol, and so on... If these ones are not used, the sub- optimizer will use those of the master routine. Other named parameters : popSize : integer used to change the size of the sample for stochastic search methods. Default value is a peculiar heuristic to the chosen algorithm. SOPopSize : Same as above, but when the stochastic search is passed to a meta-algorithm. nGradStored : The number (interger type) of gradients to ”remember” from previous optimization steps: increasing this increases the memory requirements but may speed convergence. It is set to a heuristic value by default. If used with AUGLAG or MLSL, it will only affect the given subsidiary algorithm. The following table resume the main characteristics of each algorithm, providing the more important information about which features are supported by which algorithm and what are the unavoidable arguments they need. More details can be found in [42]. 182 CHAPTER 8. ALGORITHMS Id Tag Id Tag Full Name Bounds Gradient -Based Stochastic Constraints Constraints Sub- Opt Full Name Bounds Gradient -Based Stochastic Equality Inequality Sub- Opt DIRECT DIRECTL DIRECTLRand DIRECTNoScal DIRECTLNoScal DIRECTLRandNoScal OrigDIRECT OrigDIRECTL StoGO StoGORand LBFGS PRAXIS Var1 Var2 TNewton TNewtonRestart TNewtonPrecond TNewtonRestartPrecond CRS2 MMA COBYLA NEWUOA NEWUOABound NelderMead Sbplx BOBYQA ISRES SLSQP MLSL MLSLLDS AUGLAG AUGLAGEQ Dividing rectangles ● Locally biased dividing rectangles ● Randomized locally biased dividing rectangles ● Dividing rectangles - no scaling ● Locally biased dividing rectangles - no scaling ● Randomized locally biased dividing rectangles - no scaling ● Original Glabonsky’s dividing rectangles ● ✔ Original Glabonsky’s locally biased dividing rectangles ● ✔ Stochastic(?) Global Optimization ● ● Randomized Stochastic(?) Global Optimization ● ● Low-storage BFGS ● Principal AXIS ✔ Rank-1 shifted limited-memory variable-metric ● Rank-2 shifted limited-memory variable-metric ● Truncated Newton ● Steepest descent restarting truncated Newton ● BFGS preconditionned truncated Newton ● BFGS preconditionned truncated Newton with steepest descent restarting ● Controled random search with local mutation ✔ ● Method of moving asymptots ✔ ● ✔ Constrained optimization by linear approximations ✔ ✔ ✔ NEWUOA NEWUOA for bounded optimization ✔ Nelder-Mead simplex ✔ Subplex ✔ BOBYQA ✔ Improved stochastic ranking evolution strategy ✔ ● ✔ ✔ Sequential least-square quadratic programming ✔ ● ✔ ✔ Multi-level single-linkage ✔ ● ● ● Low discrepancy multi-level single-linkage ✔ ● ● ● Constraints augmented lagrangian ✔ ● ✔ ✔ ● Equality constraints augmented lagrangian ✔ ● ✔ ✔ ● Legend : ✔ Supported and optional Supported and optional Supported and optional Supported and optional Supported and optional ✔ Should be supported and optional, may lead to weird behaviour though. Should be supported and optional, may lead to weird behaviour though. Should be supported and optional, may lead to weird behaviour though. Should be supported and optional, may lead to weird behaviour though. Should be supported and optional, may lead to weird behaviour though. ● Intrinsic characteristic of the algorithm which then need one or more unavoidable parameter to work (for stochastic algorithm, the population size always have a default value, they will then work if it is ommited) Intrinsic characteristic of the algorithm which then need one or more unavoidable parameter to work (for stochastic algorithm, the population size always have a default value, they will then work if it is ommited) Intrinsic characteristic of the algorithm which then need one or more unavoidable parameter to work (for stochastic algorithm, the population size always have a default value, they will then work if it is ommited) Intrinsic characteristic of the algorithm which then need one or more unavoidable parameter to work (for stochastic algorithm, the population size always have a default value, they will then work if it is ommited) Intrinsic characteristic of the algorithm which then need one or more unavoidable parameter to work (for stochastic algorithm, the population size always have a default value, they will then work if it is ommited) ●/✔ ●/✔ For routines with subsidiary algorithms only, indicates that the corresponding feature will depend on the chosen sub- optimizer. For routines with subsidiary algorithms only, indicates that the corresponding feature will depend on the chosen sub- optimizer. For routines with subsidiary algorithms only, indicates that the corresponding feature will depend on the chosen sub- optimizer. For routines with subsidiary algorithms only, indicates that the corresponding feature will depend on the chosen sub- optimizer. For routines with subsidiary algorithms only, indicates that the corresponding feature will depend on the chosen sub- optimizer. 8.2. OPTIMIZATION 183 Example 8.2 (VarIneq.edp) Let Ω be a domain of R 2 , f 1 , f 2 ∈ L 2 (Ω) and g 1 , g 2 ∈ L 2 (∂Ω) four given functions with g 1 ≤ g 2 almost everywhere. We define the space : V = ¸ (v 1 , v 2 ) ∈ H 1 (Ω) 2 ; v 1 [ ∂Ω = g 1 , v 2 [ ∂Ω = g 2 , v 1 ≤ v 2 a.e. ¸ as well as the functional J : H 1 (Ω) 2 −→R: J(v 1 , v 2 ) = 1 2 Ω [∇v 1 [ 2 − Ω f 1 v 1 + 1 2 Ω [∇v 2 [ 2 − Ω f 1 v 2 The problem consists in finding (numerically) two functions (u 1 , u 2 ) = argmin (v 1 ,v 2 )∈V J(v 1 , v 2 ). This can be interpreted as finding u 1 , u 2 as close as possible (in a certain sense) to the solutions of Laplace equation with respectively f 1 , f 2 second members and g 1 , g 2 Dirichlet boundary conditions with the u 1 ≤ u 2 almost everywhere constraint. Here is the corresponding script to treat this variational inequality problem with one of the NLOpt algorithms. The whole script is in the VarIneq2.edp. load "ff-NLopt" // Loading nlopt int NN = 10; mesh Th = square(NN,NN); func f1=1.; // Datas func f2=-1.; func g1=0.; func g2=0.1; int nadapt=3,iter=0; real starttol=1e-12,bctol=6.e-12; fespace Vh(Th,P1); Instead of defining the J functional with explicit integral on the domain, we will write it in quadratic/linear form, since the corresponding matrix and vector will not change along with the iterations and the FreeFem matrix-vector product is optimized, this method will significantly speed up the approximation of the solution. varf BVF(v,w) = int2d(Th)(0.5 * dx(v) * dx(w) + 0.5 * dy(v) * dy(w)); // bilinear varf LVF1(v,w) = int2d(Th)(f1 * w); // and linear parts varf LVF2(v,w) = int2d(Th)(f2 * w); matrix A = BVF(Vh,Vh); // corresponding matrix real[int] b1 = LVF1(0,Vh) , b2 = LVF2(0,Vh); // and vectors Then follows a trick that we will use later to pass the boundary conditions as non-linear equality constraints (although these are of course linear ones, but this approach demonstrate how to use all the features of NLOpt in one shot). varf Vbord(v,w) = on(1,2,3,4,v=1); Vh In,Bord; Bord[] = Vbord(0,Vh,tgv=1); // Bord=1 on the border In[] = Bord[] ? 0:1; // and 0 inside Vh gh1=Bord * g1,gh2=Bord * g2; // gh1=g1 on the border and 0 inside // The functional : func real J(real[int] &X) { Vh u1,u2; 184 CHAPTER 8. ALGORITHMS u1[] = X(0:Vh.ndof-1); // splitting the vector u2[] = X(Vh.ndof:2 * Vh.ndof-1); iter++; real[int] Au1 = A * u1[], Au2 = A * u2[]; Au1 -= b1; Au2 -= b2; real val = u1[]’ * Au1 + u2[]’ * Au2; plot(u1,u2,...); // parameters omitted return val; } To be able to play with gradient-based algorithm, we must have a gradient ready : varf dBFV(v,w) = int2d(Th)(dx(v) * dx(w)+dy(v) * dy(w)); matrix dA = dBFV(Vh,Vh); func real[int] dJ(real[int] &X) { Vh u1,u2; u1[] = X(0:Vh.ndof-1); u2[] = X(Vh.ndof:2 * Vh.ndof-1); real[int] grad1 = dA * u1[], grad2 = dA * u2[]; grad1 -= b1; grad2 -= b2; real[int] Grad(X.n); Grad(0:Vh.ndof-1) = grad1; Grad(Vh.ndof:2 * Vh.ndof-1) = grad2; return Grad; } As we use P1 Lagrange finite elements, the u 1 ≤ u 2 constraint can be expressed directly upon the degree of freedom. In NLOpt, one constraint must have the form f(X) ≤ 0. The function is vectorial in order to handle multiple constraints : func real[int] IneqC(real[int] &X) { real[int] constraints(Vh.ndof); for(int i=0;i<Vh.ndof;++i) constraints[i] = X[i] - X[i+Vh.ndof]; return constraints; // u1i - u2i <= 0 } One also has to define a gradient for each constraint if a gradient search is to be used. Constraint gradient must be a function which returns a matrix. The i-th line of this matrix is the gradient of the i-th constraint with respect to the variables of the search space. func real[int,int] dIneqC(real[int] &X) { real[int,int] dconst(Vh.ndof,2 * Vh.ndof); // so sparse... shame! dconst=0; for(int i=0;i<Vh.ndof;++i) { dconst(i,i) = 1.; dconst(i,i+Vh.ndof) = -1.; } return dconst; } 8.2. OPTIMIZATION 185 As mentioned earlier, we also define a set of equality constraints and their derivatives in order to handle the boundary conditions. One could also use the lb and ub parameters to impose them, this also would avoid the use of large sparse matrix returned by the gradient function (it can be found in the script file, where we set lb to g − and ub to g +). Here again, we can work directly on the degree of freedom because of the P1 finite element. The script could not work with other finite elements without modifications. real[int] BordIndex(Th.nbe); // Indexes of border d.f. { int k=0; // filling the index array for(int i=0;i<Bord.n;++i) if(Bord[][i]) {BordIndex[k]=i; ++k;} } func real[int] BC(real[int] &X) { real[int] bc(2 * Th.nbe); for(int i=0;i<Th.nbe;++i) { int I = BordIndex[i]; bc[i] = X[I] - gh1[][I]; bc[i+Th.nbe] = X[I+Th.nv] - gh2[][I]; } return bc; } func real[int,int] dBC(real[int] &X) // Gradient of boundary conditions { real[int,int] dbc(2 * Th.nbe,2 * Th.nv); // even sparser...:( dbc=0.; for(int i=0;i<Th.nbe;++i) { int I=BordIndex[i]; dbc(i,I) = 1.; dbc(i+Th.nbe,I+Th.nv) = 1.; } return dbc; } Now we fill an initial vector and start the algorithm : real[int] start(2 * Vh.ndof); start(0:Vh.ndof-1) = 0.; // starting with u1=u2=0 is bad start(Vh.ndof:2 * Vh.ndof-1) = 0.01; // a small difference is needed real mini = nloptAUGLAG(J, start, grad=dJ, IConst=IneqC, gradIConst=dIneqC, EConst=BC, gradEConst=dBC, subOpt="LBFGS", stopMaxFEval=10000, stopAbsFTol=starttol ); Here we wrap a BFGS algorithm (which only works with unconstraint problems) in the augmented lagrangian method for both equality and inequality constraints. Another legit choice would be to use SLSQP, the only gradient-based search of the package supporting these two kinds of constraints (note that the subOpt parameter is gone ) : 186 CHAPTER 8. ALGORITHMS Figure 8.1: Numerical Approximation of the Variational Inequality real mini = nloptSLSQP(J, start, grad=dJ, IConst=IneqC, gradIConst=dIneqC, EConst=BC, gradEConst=dBC, stopMaxFEval=10000, stopAbsFTol=starttol ); One can also try to pass derivative free algorithms to AUGLAG and discard the gradients to see what happens, or directly one which handles the two kinds of constraints. Just check the tag in the table. The true script also has a loop in which the algorithm is restarted after mesh adaptation, nothing was said about that to avoid complicating an already relatively long script comment. 8.2.3 Optimization with MPI The only quick way to use the previously presented algorithms on a parallel architecture lies in parallelizing the used cost function (which is in most real life case, the expensive part of the algorithm). Somehow, we provide a parallel version of the CMA-ES algorithm. The parallelization principle is the trivial one of evolving/genetic algorithms : at each iteration the cost function has to be evaluated N times without any dependence at all, these N calculus are then equally distributed to each processes. Calling the MPI version of CMA-ES is nearly the same as calling its sequential version (a complete example of use can be found in the cmaes-mpi-VarIneq.edp file).: load "mpi-cmaes" ... // define J, u and all here real min = cmaesMPI(J,u,stopTolFun=1e-6,stopMaxIter=3000); cout << "minimal value is " << min << " for u = " << u << endl; If the population size is not changed using the popsize parameter, it will use the heuristic value slightly changed to be equal to the closest greater multiple of the size of the communicator used by the optimizer. The FreeFem mpicommworld is used by default. The user can specify his own MPI communicator with the named parameter ” comm=”, see the MPI section of this manual for more informations about communicators in FreeFem++. Chapter 9 Mathematical Models Summary This chapter goes deeper into a number of problems that FreeFem++ can solve. It is a complement to chapter 3 which was only an introduction. Users are invited to contribute to make this data base of problems grow. 9.1 Static Problems 9.1.1 Soap Film Our starting point here will be the mathematical model to find the shape of soap film which is glued to the ring on the xy−plane C = ¦(x, y); x = cos t, y = sin t, 0 ≤ t ≤ 2π¦. We assume the shape of the film is described by the graph (x, y, u(x, y)) of the vertical displacement u(x, y) (x 2 +y 2 < 1) under a vertical pressure p in terms of force per unit area and an initial tension µ in terms of force per unit length. Consider the “small plane” ABCD, A:(x, y, u(x, y)), B:(x, y, u(x+δx, y)), C:(x, y, u(x+δx, y +δy)) and D:(x, y, u(x, y + δy)). Denote by n(x, y) = (n x (x, y), n y (x, y), n z (x, y)) the normal vector of the surface z = u(x, y). We see that the vertical force due to the tension µ acting along the edge AD is −µn x (x, y)δy and the the vertical force acting along the edge AD is µn x (x +δx, y)δy · µ n x (x, y) + ∂n x ∂x δx (x, y)δy. Similarly, for the edges AB and DC we have u(x,y) u(x,y+d y) u(x+d x,y) u(x+d x,y+d y) (¶ u/¶ x) d x T T T T −µn y (x, y)δx, µ(n y (x, y) +∂n y /∂y) (x, y)δx. 187 188 CHAPTER 9. MATHEMATICAL MODELS The force in the vertical direction on the surface ABCD due to the tension µ is given by µ(∂n x /∂x) δxδy +T (∂n y /∂y) δyδx. Assuming small displacements, we have ν x = (∂u/∂x)/ 1 + (∂u/∂x) 2 + (∂u/∂y) 2 · ∂u/∂x, ν y = (∂u/∂y)/ 1 + (∂u/∂x) 2 + (∂u/∂y) 2 · ∂u/∂y. Letting δx → dx, δy → dy, we have the equilibrium of the vertical displacement of soap film on ABCD by p µdxdy∂ 2 u/∂x 2 +µdxdy∂ 2 u/∂y 2 +pdxdy = 0. Using the Laplace operator ∆ = ∂ 2 /∂x 2 + ∂ 2 /∂y 2 , we can find the virtual displacement write the following −∆u = f in Ω (9.1) where f = p/µ, Ω = ¦(x, y); x 2 + y 2 < 1¦. Poisson’s equation (2.1) appears also in electrostatics taking the form of f = ρ/ where ρ is the charge density, the dielectric constant and u is named as electrostatic potential. The soap film is glued to the ring ∂Ω = C, then we have the boundary condition u = 0 on ∂Ω (9.2) If the force is gravity, for simplify, we assume that f = −1. Example 9.1 (a tutorial.edp) 1 : border a(t=0,2 * pi){ x = cos(t); y = sin(t);label=1;}; 2 : 3 : mesh disk = buildmesh(a(50)); 4 : plot(disk); 5 : fespace femp1(disk,P1); 6 : femp1 u,v; 7 : func f = -1; 8 : problem laplace(u,v) = 9 : int2d(disk)( dx(u) * dx(v) + dy(u) * dy(v) ) // bilinear form 10 : - int2d(disk)( f * v ) // linear form 11 : + on(1,u=0) ; // boundary condition 12 : func ue = (xˆ2+yˆ2-1)/4; // ue: exact solution 13 : laplace; 14 : femp1 err = u - ue; 15 : 16 : plot (u,ps="aTutorial.eps",value=true,wait=true); 17 : plot(err,value=true,wait=true); 18 : 19 : cout << "error L2=" << sqrt(int2d(disk)( errˆ2) )<< endl; 20 : cout << "error H10=" << sqrt( int2d(disk)((dx(u)-x/2)ˆ2) 21 : + int2d(disk)((dy(u)-y/2)ˆ2))<< endl; 22 : 23 : disk = adaptmesh(disk,u,err=0.01); 24 : plot(disk,wait=1); 25 : 26 : laplace; 27 : 28 : plot (u,value=true,wait=true); 29 : err = u - ue; // become FE-function on adapted mesh 9.1. STATIC PROBLEMS 189 30 : plot(err,value=true,wait=true); 31 : cout << "error L2=" << sqrt(int2d(disk)( errˆ2) )<< endl; 32 : cout << "error H10=" << sqrt(int2d(disk)((dx(u)-x/2)ˆ2) 33 : + int2d(disk)((dy(u)-y/2)ˆ2))<< endl; IsoValue -0.243997 -0.231485 -0.218972 -0.206459 -0.193947 -0.181434 -0.168921 -0.156409 -0.143896 -0.131383 -0.11887 -0.106358 -0.0938451 -0.0813324 -0.0688198 -0.0563071 -0.0437944 -0.0312817 -0.018769 -0.00625634 Figure 9.1: isovalue of u Figure 9.2: a side view of u In 19th line, the L 2 -error estimation between the exact solution u e , |u h −u e | 0,Ω = Ω [u h −u e [ 2 dxdy 1/2 and from 20th line to 21th line, the H 1 -error seminorm estimation [u h −u e [ 1,Ω = Ω [∇u h −∇u e [ 2 dxdy 1/2 are done on the initial mesh. The results are |u h −u e | 0,Ω = 0.000384045, [u h −u e [ 1,Ω = 0.0375506. After the adaptation, we hava |u h − u e | 0,Ω = 0.000109043, [u h − u e [ 1,Ω = 0.0188411. So the numerical solution is improved by adaptation of mesh. 9.1.2 Electrostatics We assume that there is no current and a time independent charge distribution. Then the electric field E satisfies divE = ρ/, curlE = 0 (9.3) where ρ is the charge density and is called the permittivity of free space. From the second equation in (9.3), we can introduce the electrostatic potential such that E = −∇φ. Then we have Poisson’s equation −∆φ = f, f = −ρ/. We now obtain the equipotential line which is the level curve of φ, when there are no charges except conductors ¦C i ¦ 1,··· ,K . Let us assume K conductors C 1 , , C K within an enclosure C 0 . Each one is held at an electrostatic potential ϕ i . We assume that the enclosure C0 is held at potential 0. In order to know ϕ(x) at any point x of the domain Ω, we must solve −∆ϕ = 0 in Ω, (9.4) 190 CHAPTER 9. MATHEMATICAL MODELS where Ω is the interior of C 0 minus the conductors C i , and Γ is the boundary of Ω, that is ¸ N i=0 C i . Here g is any function of x equal to ϕ i on C i and to 0 on C 0 . The boundary equation is a reduced form for: ϕ = ϕ i on C i , i = 1...N, ϕ = 0 on C 0 . (9.5) Example 9.2 First we give the geometrical informations; C 0 = ¦(x, y); x 2 + y 2 = 5 2 ¦, C 1 = ¦(x, y) : 1 0.3 2 (x − 2) 2 + 1 3 2 y 2 = 1¦, C 2 = ¦(x, y) : 1 0.3 2 (x + 2) 2 + 1 3 2 y 2 = 1¦. Let Ω be the disk enclosed by C 0 with the elliptical holes enclosed by C 1 and C 2 . Note that C 0 is described counterclockwise, whereas the elliptical holes are described clockwise, because the boundary must be oriented so that the computational domain is to its left. // a circle with center at (0 ,0) and radius 5 border C0(t=0,2 * pi) { x = 5 * cos(t); y = 5 * sin(t); } border C1(t=0,2 * pi) { x = 2+0.3 * cos(t); y = 3 * sin(t); } border C2(t=0,2 * pi) { x = -2+0.3 * cos(t); y = 3 * sin(t); } mesh Th = buildmesh(C0(60)+C1(-50)+C2(-50)); plot(Th,ps="electroMesh"); // figure 9.3 fespace Vh(Th,P1); // P1 FE-space Vh uh,vh; // unknown and test function. problem Electro(uh,vh) = // definition of the problem int2d(Th)( dx(uh) * dx(vh) + dy(uh) * dy(vh) ) // bilinear + on(C0,uh=0) // boundary condition on C 0 + on(C1,uh=1) // +1 volt on C 1 + on(C2,uh=-1) ; // -1 volt on C 2 Electro; // solve the problem, see figure 9.4 for the solution plot(uh,ps="electro.eps",wait=true); // figure 9.4 Figure 9.3: Disk with two elliptical holes Figure 9.4: Equipotential lines, where C 1 is located in right hand side 9.1. STATIC PROBLEMS 191 9.1.3 Aerodynamics Let us consider a wing profile S in a uniform flow. Infinity will be represented by a large circle Γ ∞ . As previously, we must solve ∆ϕ = 0 in Ω, ϕ[ S = c, ϕ[ Γ ∞ = u ∞1x −u ∞2x (9.6) where Ω is the area occupied by the fluid, u ∞ is the air speed at infinity, c is a constant to be determined so that ∂ n ϕ is continuous at the trailing edge P of S (so-called Kutta-Joukowski condition). Lift is proportional to c. To find c we use a superposition method. As all equations in (9.6) are linear, the solution ϕ c is a linear function of c ϕ c = ϕ 0 +cϕ 1 , (9.7) where ϕ 0 is a solution of (9.6) with c = 0 and ϕ 1 is a solution with c = 1 and zero speed at infinity. With these two fields computed, we shall determine c by requiring the continuity of ∂ϕ/∂n at the trailing edge. An equation for the upper surface of a NACA0012 (this is a classical wing profile in aerodynamics; the rear of the wing is called the trailing edge) is: y = 0.17735 √ x −0.075597x −0.212836x 2 + 0.17363x 3 −0.06254x 4 . (9.8) Taking an incidence angle α such that tan α = 0.1, we must solve −∆ϕ = 0 in Ω, ϕ[ Γ 1 = y −0.1x, ϕ[ Γ 2 = c, (9.9) where Γ 2 is the wing profile and Γ 1 is an approximation of infinity. One finds c by solving: −∆ϕ 0 = 0 in Ω, ϕ 0 [ Γ 1 = y −0.1x, ϕ 0 [ Γ 2 = 0, (9.10) −∆ϕ 1 = 0 in Ω, ϕ 1 [ Γ 1 = 0, ϕ 1 [ Γ 2 = 1. (9.11) The solution ϕ = ϕ 0 +cϕ 1 allows us to find c by writing that ∂ n ϕ has no jump at the trailing edge P = (1, 0). We have ∂nϕ−(ϕ(P + ) −ϕ(P))/δ where P + is the point just above P in the direction normal to the profile at a distance δ. Thus the jump of ∂ n ϕ is (ϕ 0 [ P + +c(ϕ 1 [ P + −1)) + (ϕ 0 [ P − + c(ϕ 1 [ P − −1)) divided by δ because the normal changes sign between the lower and upper surfaces. Thus c = − ϕ 0 [ P + +ϕ 0 [ P − (ϕ 1 [ P + +ϕ 1 [ P − −2) , (9.12) which can be programmed as: c = − ϕ 0 (0.99, 0.01) +ϕ 0 (0.99, −0.01) (ϕ 1 (0.99, 0.01) +ϕ 1 (0.99, −0.01) −2) . (9.13) Example 9.3 // Computation of the potential flow around a NACA0012 airfoil. // The method of decomposition is used to apply the Joukowski condition // The solution is seeked in the form psi0 + beta psi1 and beta is // adjusted so that the pressure is continuous at the trailing edge border a(t=0,2 * pi) { x=5 * cos(t); y=5 * sin(t); }; // approximates infinity border upper(t=0,1) { x = t; y = 0.17735 * sqrt(t)-0.075597 * t - 0.212836 * (tˆ2)+0.17363 * (tˆ3)-0.06254 * (tˆ4); } border lower(t=1,0) { x = t; 192 CHAPTER 9. MATHEMATICAL MODELS y= -(0.17735 * sqrt(t)-0.075597 * t -0.212836 * (tˆ2)+0.17363 * (tˆ3)-0.06254 * (tˆ4)); } border c(t=0,2 * pi) { x=0.8 * cos(t)+0.5; y=0.8 * sin(t); } wait = true; mesh Zoom = buildmesh(c(30)+upper(35)+lower(35)); mesh Th = buildmesh(a(30)+upper(35)+lower(35)); fespace Vh(Th,P2); // P1 FE space Vh psi0,psi1,vh; // unknown and test function. fespace ZVh(Zoom,P2); solve Joukowski0(psi0,vh) = // definition of the problem int2d(Th)( dx(psi0) * dx(vh) + dy(psi0) * dy(vh) ) // bilinear form + on(a,psi0=y-0.1 * x) // boundary condition form + on(upper,lower,psi0=0); plot(psi0); solve Joukowski1(psi1,vh) = // definition of the problem int2d(Th)( dx(psi1) * dx(vh) + dy(psi1) * dy(vh) ) // bilinear form + on(a,psi1=0) // boundary condition form + on(upper,lower,psi1=1); plot(psi1); // continuity of pressure at trailing edge real beta = psi0(0.99,0.01)+psi0(0.99,-0.01); beta = -beta / (psi1(0.99,0.01)+ psi1(0.99,-0.01)-2); Vh psi = beta * psi1+psi0; plot(psi); ZVh Zpsi=psi; plot(Zpsi,bw=true); ZVh cp = -dx(psi)ˆ2 - dy(psi)ˆ2; plot(cp); ZVh Zcp=cp; plot(Zcp,nbiso=40); Figure 9.5: isovalue of cp = −(∂ x ψ) 2 − (∂ y ψ) 2 Figure 9.6: Zooming of cp 9.1. STATIC PROBLEMS 193 9.1.4 Error estimation There are famous estimation between the numerical result u h and the exact solution u of the problem 2.1 and 2.2: If triangulations ¦T h ¦ h↓0 is regular (see Section 5.4), then we have the estimates [∇u −∇u h [ 0,Ω ≤ C 1 h (9.14) |u −u h | 0,Ω ≤ C 2 h 2 (9.15) with constants C 1 , C 2 independent of h, if u is in H 2 (Ω). It is known that u ∈ H 2 (Ω) if Ω is convex. In this section we check (9.14) and (9.15). We will pick up numericall error if we use the numerical derivative, so we will use the following for (9.14). Ω [∇u −∇u h [ 2 dxdy = Ω ∇u ∇(u −2u h ) dxdy + Ω ∇u h ∇u h dxdy = Ω f(u −2u h ) dxdy + Ω fu h dxdy The constants C 1 , C 2 are depend on T h and f, so we will find them by FreeFem++ . In general, we cannot get the solution u as a elementary functions (see Section 4.8) even if spetical functions are added. Instead of the exact solution, here we use the approximate solution u 0 in V h (T h , P 2 ), h ∼ 0. Example 9.4 1 : mesh Th0 = square(100,100); 2 : fespace V0h(Th0,P2); 3 : V0h u0,v0; 4 : func f = x * y; // sin(pi * x) * cos(pi * y); 5 : 6 : solve Poisson0(u0,v0) = 7 : int2d(Th0)( dx(u0) * dx(v0) + dy(u0) * dy(v0) ) // bilinear form 8 : - int2d(Th0)( f * v0 ) // linear form 9 : + on(1,2,3,4,u0=0) ; // boundary condition 10 : 11 : plot(u0); 12 : 13 : real[int] errL2(10), errH1(10); 14 : 15 : for (int i=1; i<=10; i++) { 16 : mesh Th = square(5+i * 3,5+i * 3); 17 : fespace Vh(Th,P1); 18 : fespace Ph(Th,P0); 19 : Ph h = hTriangle; // get the size of all triangles 20 : Vh u,v; 21 : solve Poisson(u,v) = 22 : int2d(Th)( dx(u) * dx(v) + dy(u) * dy(v) ) // bilinear form 23 : - int2d(Th)( f * v ) // linear form 24 : + on(1,2,3,4,u=0) ; // boundary condition 25 : V0h uu = u; 26 : errL2[i-1] = sqrt( int2d(Th0)((uu - u0)ˆ2) )/h[].maxˆ2; 27 : errH1[i-1] = sqrt( int2d(Th0)( f * (u0-2 * uu+uu) ) )/h[].max; 28 : } 29 : cout << "C1 = " << errL2.max <<"("<<errL2.min<<")"<< endl; 30 : cout << "C2 = " << errH1.max <<"("<<errH1.min<<")"<< endl; We can guess that C 1 = 0.0179253(0.0173266) and C 2 = 0.0729566(0.0707543), where the numbers inside the parentheses are minimum in calculation. 194 CHAPTER 9. MATHEMATICAL MODELS 9.1.5 Periodic Boundary Conditions We now solve the Poisson equation −∆u = sin(x +π/4.) ∗ cos(y +π/4.) on the square ]0, 2π[ 2 under bi-periodic boundary condition u(0, y) = u(2π, y) for all y and u(x, 0) = u(x, 2π) for all x. These boundary conditions are achieved from the definition of the periodic finite element space. Example 9.5 (periodic.edp) mesh Th=square(10,10,[2 * x * pi,2 * y * pi]); // defined the fespacewith periodic condition // label : 2 and 4 are left and right side with y the curve abscissa // 1 and 2 are bottom and upper side with x the curve abscissa fespace Vh(Th,P2,periodic=[[2,y],[4,y],[1,x],[3,x]]); Vh uh,vh; // unknown and test function. func f=sin(x+pi/4.) * cos(y+pi/4.); // right hand side function problem laplace(uh,vh) = // definion of the problem int2d(Th)( dx(uh) * dx(vh) + dy(uh) * dy(vh) ) // bilinear form + int2d(Th)( -f * vh ) // linear form ; laplace; // solve the problem plot(uh); // to see the result plot(uh,ps="period.eps",value=true); IsoValue -0.441699 -0.391928 -0.342157 -0.292387 -0.242616 -0.192845 -0.143075 -0.0933038 -0.0435331 0.00623761 0.0560083 0.105779 0.15555 0.20532 0.255091 0.304862 0.354633 0.404403 0.454174 0.503945 Figure 9.7: The isovalue of solution u with periodic boundary condition The periodic condition does not necessarily require parallel boundaries. Example 9.6 give such example. Example 9.6 (periodic4.edp) real r=0.25; // a diamond with a hole 9.1. STATIC PROBLEMS 195 border a(t=0,1){x=-t+1; y=t;label=1;}; border b(t=0,1){ x=-t; y=1-t;label=2;}; border c(t=0,1){ x=t-1; y=-t;label=3;}; border d(t=0,1){ x=t; y=-1+t;label=4;}; border e(t=0,2 * pi){ x=r * cos(t); y=-r * sin(t);label=0;}; int n = 10; mesh Th= buildmesh(a(n)+b(n)+c(n)+d(n)+e(n)); plot(Th,wait=1); real r2=1.732; func abs=sqrt(xˆ2+yˆ2); // warning for periodic condition: // side a and c // on side a (label 1) x ∈ [0, 1] or x −y ∈ [−1, 1] // on side c (label 3) x ∈ [−1, 0] or x −y ∈ [−1, 1] // so the common abscissa can be respectively x and x + 1 // or you can can try curviline abscissa x −y and x −y // 1 first way // fespace Vh(Th,P2,periodic=[[2,1+x],[4,x],[1,x],[3,1+x]]); // 2 second way fespace Vh(Th,P2,periodic=[[2,x+y],[4,x+y],[1,x-y],[3,x-y]]); Vh uh,vh; func f=(y+x+1) * (y+x-1) * (y-x+1) * (y-x-1); real intf = int2d(Th)(f); real mTh = int2d(Th)(1); real k = intf/mTh; problem laplace(uh,vh) = int2d(Th)( dx(uh) * dx(vh) + dy(uh) * dy(vh) ) + int2d(Th)( (k-f) * vh ) ; laplace; plot(uh,wait=1,ps="perio4.eps"); Figure 9.8: The isovalue of solution u for ∆u = ((y + x) 2 + 1)((y −x) 2 + 1) −k, in Ω and ∂ n u = 0 on hole,and with two periodic boundary condition on external border An other example with no equal border, just to see if the code works. 196 CHAPTER 9. MATHEMATICAL MODELS Example 9.7 (periodic4bis.edp) // irregular boundary condition. // to build border AB macro LINEBORDER(A,B,lab) border A#B(t=0,1){real t1=1.-t; x=A#x * t1+B#x * t;y=A#y * t1+B#y * t;label=lab;} // EOM // compute ||AB|| a=(ax,ay) et B =(bx,by) macro dist(ax,ay,bx,by) sqrt(square((ax)-(bx))+ square((ay)-(by))) // EOM macro Grad(u) [dx(u),dy(u)] // EOM real Ax=0.9,Ay=1; real Bx=2,By=1; real Cx=2.5,Cy=2.5; real Dx=1,Dy=2; real gx = (Ax+Bx+Cx+Dx)/4.; real gy = (Ay+By+Cy+Dy)/4.; LINEBORDER(A,B,1) LINEBORDER(B,C,2) LINEBORDER(C,D,3) LINEBORDER(D,A,4) int n=10; real l1=dist(Ax,Ay,Bx,By); real l2=dist(Bx,By,Cx,Cy); real l3=dist(Cx,Cy,Dx,Dy); real l4=dist(Dx,Dy,Ax,Ay); func s1=dist(Ax,Ay,x,y)/l1; // absisse on AB = ||AX||/||AB|| func s2=dist(Bx,By,x,y)/l2; // absisse on BC = ||BX||/||BC|| func s3=dist(Cx,Cy,x,y)/l3; // absisse on CD = ||CX||/||CD|| func s4=dist(Dx,Dy,x,y)/l4; // absisse on DA = ||DX||/||DA|| mesh Th=buildmesh(AB(n)+BC(n)+CD(n)+DA(n),fixeborder=1); // verbosity=6; // to see the abscisse value pour the periodic condition. fespace Vh(Th,P1,periodic=[[1,s1],[3,s3],[2,s2],[4,s4]]); verbosity=1; Vh u,v; real cc=0; cc= int2d(Th)((x-gx) * (y-gy)-cc)/Th.area; cout << " compatibility =" << int2d(Th)((x-gx) * (y-gy)-cc) <<endl; solve Poission(u,v)=int2d(Th)(Grad(u)’ * Grad(v)+ 1e-10 * u * v) -int2d(Th)(10 * v * ((x-gx) * (y-gy)-cc)); plot(u,wait=1,value=1); Example 9.8 (Period-Poisson-cube-ballon.edp) verbosity=1; load "msh3" load "tetgen" load "medit" bool buildTh=0; 9.1. STATIC PROBLEMS 197 mesh3 Th; try { // a way to build one time the mesh an read if the file exist. Th=readmesh3("Th-hex-sph.mesh"); } catch(...) { buildTh=1;} if( buildTh ){ ... put the code example page // 5.11.1124 without the first line } fespace Ph(Th,P0); verbosity=50; fespace Vh(Th,P1,periodic=[[3,x,z],[4,x,z],[1,y,z],[2,y,z],[5,x,y],[6,x,y]]);// back and front verbosity=1; Ph reg=region; cout << " centre = " << reg(0,0,0) << endl; cout << " exterieur = " << reg(0,0,0.7) << endl; macro Grad(u) [dx(u),dy(u),dz(u)] // EOM Vh uh,vh; real x0=0.3,y0=0.4,z0=06; func f= sin(x * 2 * pi+x0) * sin(y * 2 * pi+y0) * sin(z * 2 * pi+z0); real gn = 1.; real cf= 1; problem P(uh,vh)= int3d(Th,1)( Grad(uh)’ * Grad(vh) * 100) + int3d(Th,2)( Grad(uh)’ * Grad(vh) * 2) + int3d(Th) (vh * f) ; P; plot(uh,wait=1, nbiso=6); medit(" uh ",Th, uh); 9.1.6 Poisson Problems with mixed boundary condition Here we consider the Poisson equation with mixed boundary conditons: For given functions f and g, find u such that −∆u = f in Ω u = g on Γ D , ∂u/∂n = 0 on Γ N (9.16) where Γ D is a part of the boundary Γ and Γ N = Γ ` Γ D . The solution u has the singularity at the points ¦γ 1 , γ 2 ¦ = Γ D ∩ Γ N . When Ω = ¦(x, y); −1 < x < 1, 0 < y < 1¦, Γ N = ¦(x, y); −1 ≤ x < 0, y = 0¦, Γ D = ∂Ω ` Γ N , the singularity will appear at γ 1 = (0, 0), γ 2 (−1, 0), and u has the expression u = K i u S +u R , u R ∈ H 2 (near γ i ), i = 1, 2 with a constants K i . Here u S = r 1/2 j sin(θ j /2) by the local polar coordinate (r j , θ j at γ j such that (r 1 , θ 1 ) = (r, θ). Instead of poler coordinate system (r, θ), we use that r = sqrt( x ˆ 2+y ˆ 2 ) and θ = atan2(y,x) in FreeFem++ . 198 CHAPTER 9. MATHEMATICAL MODELS Figure 9.9: view of the surface isovalue of periodic solution uh Figure 9.10: view a the cut of the solution uh with ffmedit Example 9.9 Assume that f = −230(x 2 +y 2 ) and g = u e = 10(x 2 +y 2 ) 1/4 sin [tan −1 (y/x)]/2 + 30(x 2 y 2 ), where u e S is the exact solution. 1 : border N(t=0,1) { x=-1+t; y=0; label=1; }; 2 : border D1(t=0,1){ x=t; y=0; label=2;}; 3 : border D2(t=0,1){ x=1; y=t; label=2; }; 4 : border D3(t=0,2){ x=1-t; y=1; label=2;}; 5 : border D4(t=0,1) { x=-1; y=1-t; label=2; }; 6 : 7 : mesh T0h = buildmesh(N(10)+D1(10)+D2(10)+D3(20)+D4(10)); 8 : plot(T0h,wait=true); 9 : fespace V0h(T0h,P1); 10 : V0h u0, v0; 11 : 12 : func f=-2 * 30 * (xˆ2+yˆ2); // given function 13 : // the singular term of the solution is K * us (K: constant) 14 : func us = sin(atan2(y,x)/2) * sqrt( sqrt(xˆ2+yˆ2) ); 15 : real K=10.; 16 : func ue = K * us + 30 * (xˆ2 * yˆ2); 17 : 18 : solve Poisson0(u0,v0) = 19 : int2d(T0h)( dx(u0) * dx(v0) + dy(u0) * dy(v0) ) // bilinear form 20 : - int2d(T0h)( f * v0 ) // linear form 21 : + on(2,u0=ue) ; // boundary condition 22 : 23 : // adaptation by the singular term 24 : mesh Th = adaptmesh(T0h,us); 25 : for (int i=0;i< 5;i++) 26 : { 27 : mesh Th=adaptmesh(Th,us); 28 : } ; 29 : 9.1. STATIC PROBLEMS 199 30 : fespace Vh(Th, P1); 31 : Vh u, v; 32 : solve Poisson(u,v) = 33 : int2d(Th)( dx(u) * dx(v) + dy(u) * dy(v) ) // bilinear form 34 : - int2d(Th)( f * v ) // linear form 35 : + on(2,u=ue) ; // boundary condition 36 : 37 : / * plot the solution * / 38 : plot(Th,ps="adaptDNmix.ps"); 39 : plot(u,wait=true); 40 : 41 : Vh uue = ue; 42 : real H1e = sqrt( int2d(Th)( dx(uue)ˆ2 + dy(uue)ˆ2 + uueˆ2 ) ); 43 : 44 : / * calculate the H1 Sobolev norm * / 45 : Vh err0 = u0 - ue; 46 : Vh err = u - ue; 47 : Vh H1err0 = int2d(Th)( dx(err0)ˆ2+dy(err0)ˆ2+err0ˆ2 ); 48 : Vh H1err = int2d(Th)( dx(err)ˆ2+dy(err)ˆ2+errˆ2 ); 49 : cout <<"Relative error in first mesh "<< int2d(Th)(H1err0)/H1e<<endl; 50 : cout <<"Relative error in adaptive mesh "<< int2d(Th)(H1err)/H1e<<endl; From 24th line to 28th, adaptation of meshes are done using the base of singular term. In 42th line, H1e=|u e | 1,Ω is calculated. In last 2 lines, the relative errors are calculated, that is, |u 0 h −u e | 1,Ω /H1e = 0.120421 |u a h −u e | 1,Ω /H1e = 0.0150581 where u 0 h is the numerical solution in T0h and u a h is u in this program. 9.1.7 Poisson with mixte finite element Here we consider the Poisson equation with mixed boundary value problems: For given functions f , g d , g n , find p such that −∆p = 1 in Ω p = g d on Γ D , ∂p/∂n = g n on Γ N (9.17) where Γ D is a part of the boundary Γ and Γ N = Γ ` Γ D . The mixte formulation is: find p and u such that ∇p +u = 0 in Ω ∇.u = f in Ω p = g d on Γ D , ∂u.n = g n .n on Γ N (9.18) where g n is a vector such that g n .n = g n . The variationnal formulation is, ∀v ∈ V 0 , Ω p∇.v +vv = Γ d g d v.n ∀q ∈ P Ω q∇.u = Ω qf ∂u.n = g n .n on Γ N (9.19) 200 CHAPTER 9. MATHEMATICAL MODELS where the functionnal space are: P = L 2 (Ω), V = H(div) = ¦v ∈ L 2 (Ω) 2 , ∇.v ∈ L 2 (Ω)¦ and V 0 = ¦v ∈ V; v.n = 0 on Γ N ¦. To write, the FreeFem++ example, we have just to choose the finites elements spaces. here V space is discretize with Raviart-Thomas finite element RT0 and P is discretize by constant finite element P0. Example 9.10 (LaplaceRT.edp) mesh Th=square(10,10); fespace Vh(Th,RT0); fespace Ph(Th,P0); func gd = 1.; func g1n = 1.; func g2n = 1.; Vh [u1,u2],[v1,v2]; Ph p,q; problem laplaceMixte([u1,u2,p],[v1,v2,q], solver=GMRES,eps=1.0e-10, tgv=1e30,dimKrylov=150) = int2d(Th)( p * q * 1e-15 // this term is here to be sur // that all sub matrix are inversible (LU requirement) + u1 * v1 + u2 * v2 + p * (dx(v1)+dy(v2)) + (dx(u1)+dy(u2)) * q ) + int2d(Th) ( q) - int1d(Th,1,2,3)( gd * (v1 * N.x +v2 * N.y)) // on Γ D + on(4,u1=g1n,u2=g2n); // on Γ N laplaceMixte; plot([u1,u2],coef=0.1,wait=1,ps="lapRTuv.eps",value=true); plot(p,fill=1,wait=1,ps="laRTp.eps",value=true); 9.1.8 Metric Adaptation and residual error indicator We do metric mesh adaption and compute the classical residual error indicator η T on the element T for the Poisson problem. Example 9.11 (adaptindicatorP2.edp) First, we solve the same problem as in a previous example. 1 : border ba(t=0,1.0){x=t; y=0; label=1;}; // see Fig,5.15 2 : border bb(t=0,0.5){x=1; y=t; label=2;}; 3 : border bc(t=0,0.5){x=1-t; y=0.5;label=3;}; 4 : border bd(t=0.5,1){x=0.5; y=t; label=4;}; 5 : border be(t=0.5,1){x=1-t; y=1; label=5;}; 6 : border bf(t=0.0,1){x=0; y=1-t;label=6;}; 9.1. STATIC PROBLEMS 201 7 : mesh Th = buildmesh (ba(6) + bb(4) + bc(4) +bd(4) + be(4) + bf(6)); 8 : savemesh(Th,"th.msh"); 9 : fespace Vh(Th,P2); 10 : fespace Nh(Th,P0); 11 : Vh u,v; 12 : Nh rho; 13 : real[int] viso(21); 14 : for (int i=0;i<viso.n;i++) 15 : viso[i]=10.ˆ(+(i-16.)/2.); 16 : real error=0.01; 17 : func f=(x-y); 18 : problem Probem1(u,v,solver=CG,eps=1.0e-6) = 19 : int2d(Th,qforder=5)( u * v * 1.0e-10+ dx(u) * dx(v) + dy(u) * dy(v)) 20 : + int2d(Th,qforder=5)( -f * v); 21 : / ************* Now, the local error indicator η T is: η T = ¸ h 2 T [[f + ∆u h [[ 2 L 2 (T) + ¸ e∈E K h e [[ [ ∂u h ∂n k ] [[ 2 L 2 (e) 1 2 where h T is the longest’s edge of T, c T is the set of T edge not on Γ = ∂Ω, n T is the outside unit normal to K, h e is the length of edge e, [g] is the jump of the function g across edge (left value minus right value). Of course, we can use a variational form to compute η 2 T , with test function constant function in each triangle. 29 : ************* / 30 : 31 : varf indicator2(uu,chiK) = 32 : intalledges(Th)(chiK * lenEdge * square(jump(N.x * dx(u)+N.y * dy(u)))) 33 : +int2d(Th)(chiK * square(hTriangle * (f+dxx(u)+dyy(u))) ); 34 : for (int i=0;i< 4;i++) 35 : { 36 : Probem1; 37 : cout << u[].min << " " << u[].max << endl; 38 : plot(u,wait=1); 39 : cout << " indicator2 " << endl; 40 : 41 : rho[] = indicator2(0,Nh); 42 : rho=sqrt(rho); 43 : cout << "rho = min " << rho[].min << " max=" << rho[].max << endl; 44 : plot(rho,fill=1,wait=1,cmm="indicator density ",ps="rhoP2.eps", value=1,viso=viso,nbiso=viso.n); 45 : plot(Th,wait=1,cmm="Mesh ",ps="ThrhoP2.eps"); 46 : Th=adaptmesh(Th,[dx(u),dy(u)],err=error,anisomax=1); 47 : plot(Th,wait=1); 48 : u=u; 49 : rho=rho; 50 : error = error/2; 51 : } ; If the method is correct, we expect to look the graphics by an almost constant function η on your computer as in Fig. 9.11. 202 CHAPTER 9. MATHEMATICAL MODELS IsoValue 1e-08 3.16228e-08 1e-07 3.16228e-07 1e-06 3.16228e-06 1e-05 3.16228e-05 0.0001 0.000316228 0.001 0.00316228 0.01 0.0316228 0.1 0.316228 1 3.16228 10 31.6228 100 indicator density Mesh Figure 9.11: Density of the error indicator with isotropic P 2 metric 9.1.9 Adaptation using residual error indicator In the previous example we compute the error indicator, now we use it, to adapt the mesh. The new mesh size is given by the following formulae: h n+1 (x) = h n (x) f n (η K (x)) where η n (x) is the level of error at point x given by the local error indicator, h n is the previous “mesh size” field, and f n is a user function define by f n = min(3, max(1/3, η n /η ∗ n )) where η ∗ n = mean(η n )c, and c is an user coefficient generally close to one. Example 9.12 (AdaptResidualErrorIndicator.edp) First a macro MeshSizecomputation to get a P 1 mesh size as the average of edge length. // macro the get the current mesh size // parameter // in: Th the mesh // Vh P1 fespace on Th // out : // h: the Vh finite element finite set to the current mesh size macro MeshSizecomputation(Th,Vh,h) { / * Th mesh Vh P1 finite element space h the P1 mesh size value * / real[int] count(Th.nv); / * mesh size (lenEdge = integral(e) 1 ds) * / varf vmeshsizen(u,v)=intalledges(Th,qfnbpE=1)(v); / * number of edge / par vertex * / varf vedgecount(u,v)=intalledges(Th,qfnbpE=1)(v/lenEdge); / * computation of the mesh size ----------------------------- * / 9.1. STATIC PROBLEMS 203 count=vedgecount(0,Vh); h[]=0.; h[]=vmeshsizen(0,Vh); cout << " count min = "<< count.min << " " << count.max << endl; h[]=h[]./count; cout << " -- bound meshsize = " <<h[].min << " " << h[].max << endl; } // end of macro MeshSizecomputation A second macro to remesh according to the new mesh size. // macro to remesh according the de residual indicator // in: // Th the mesh // Ph P0 fespace on Th // Vh P1 fespace on Th // vindicator the varf of to evaluate the indicator to 2 // coef on etameam .. // ------ macro ReMeshIndicator(Th,Ph,Vh,vindicator,coef) { Vh h=0; / * evalutate the mesh size * / MeshSizecomputation(Th,Vh,h); Ph etak; etak[]=vindicator(0,Ph); etak[]=sqrt(etak[]); real etastar= coef * (etak[].sum/etak[].n); cout << " etastar = " << etastar << " sum=" << etak[].sum << " " << endl; / * here etaK is discontinous we use the P1 L2 projection with mass lumping . * / Vh fn,sigma; varf veta(unused,v)=int2d(Th)(etak * v); varf vun(unused,v)=int2d(Th)(1 * v); fn[] = veta(0,Vh); sigma[]= vun(0,Vh); fn[]= fn[]./ sigma[]; fn = max(min(fn/etastar,3.),0.3333) ; / * new mesh size * / h = h / fn ; / * plot(h,wait=1); * / / * build the new mesh * / Th=adaptmesh(Th,IsMetric=1,h,splitpbedge=1,nbvx=10000); } We skip the mesh construction, see the previous example, // FE space definition --- fespace Vh(Th,P1); // for the mesh size and solution fespace Ph(Th,P0); // for the error indicator real hinit=0.2; // initial mesh size Vh h=hinit; // the FE function for the mesh size // to build a mesh with a given mesh size : meshsize 204 CHAPTER 9. MATHEMATICAL MODELS Th=adaptmesh(Th,h,IsMetric=1,splitpbedge=1,nbvx=10000); plot(Th,wait=1,ps="RRI-Th-init.eps"); Vh u,v; func f=(x-y); problem Poisson(u,v) = int2d(Th,qforder=5)( u * v * 1.0e-10+ dx(u) * dx(v) + dy(u) * dy(v)) - int2d(Th,qforder=5)( f * v); varf indicator2(unused,chiK) = intalledges(Th)(chiK * lenEdge * square(jump(N.x * dx(u)+N.y * dy(u)))) +int2d(Th)(chiK * square(hTriangle * (f+dxx(u)+dyy(u))) ); for (int i=0;i< 10;i++) { u=u; Poisson; plot(Th,u,wait=1); real cc=0.8; if(i>5) cc=1; ReMeshIndicator(Th,Ph,Vh,indicator2,cc); plot(Th,wait=1); } IsoValue 5.89664e-05 0.000111887 0.000147167 0.000182447 0.000217727 0.000253008 0.000288288 0.000323568 0.000358848 0.000394129 0.000429409 0.000464689 0.000499969 0.000535249 0.00057053 0.00060581 0.00064109 0.00067637 0.000711651 0.000799851 IsoValue -123.488 -123.476 -123.464 -123.452 -123.44 -123.428 -123.416 -123.404 -123.392 -123.38 -123.368 -123.356 -123.344 -123.332 -123.32 -123.308 -123.296 -123.284 -123.272 -123.26 Figure 9.12: the error indicator with isotropic P 1 , the mesh and isovalue of the solution 9.2 Elasticity Consider an elastic plate with undeformed shape Ω] − h, h[ in R 3 , Ω ⊂ R 2 . By the defor- mation of the plate, we assume that a point P(x 1 , x 2 , x 3 ) moves to {(ξ 1 , ξ 2 , ξ 3 ). The vector 9.2. ELASTICITY 205 u = (u 1 , u 2 , u 3 ) = (ξ 1 − x 1 , ξ 2 − x 2 , ξ 3 − x 3 ) is called the displacement vector. By the defor- mation, the line segment x, x +τ∆x moves approximately to x +u(x), x +τ∆x +u(x +τ∆x) for small τ, where x = (x 1 , x 2 , x 3 ), ∆x = (∆x 1 , ∆x 2 , ∆x 3 ). We now calculate the ratio between two segments η(τ) = τ −1 [∆x[ −1 ([u(x +τ∆x) −u(x) +τ∆x[ −τ[∆x[) then we have (see e.g. [16, p.32]) lim τ→0 η(τ) = (1 + 2e ij ν i ν j ) 1/2 −1, 2e ij = ∂u k ∂x i ∂u k ∂x j + ∂u i ∂x j + ∂u j ∂x i where ν i = ∆x i [∆x[ −1 . If the deformation is small, then we may consider that (∂u k /∂x i )(∂u k /∂x i ) ≈ 0 and the following is called small strain tensor ε ij (u) = 1 2 ∂u i ∂x j + ∂u j ∂x i The tensor e ij is called finite strain tensor. Consider the small plane ∆Π(x) centered at x with the unit normal direction n = (n 1 , n 2 , n 3 ), then the surface on ∆Π(x) at x is (σ 1j (x)n j , σ 2j (x)n j , σ 3j (x)n j ) where σ ij (x) is called stress tensor at x. Hooke’s law is the assumption of a linear relation between σ ij and ε ij such as σ ij (x) = c ijkl (x)ε ij (x) with the symmetry c ijkl = c jikl , c ijkl = c ijlk , c ijkl = c klij . If Hooke’s tensor c ijkl (x) do not depend on the choice of coordinate system, the material is called isotropic at x. If c ijkl is constant, the material is called homogeneous. In homogeneous isotropic case, there is Lam´e constants λ, µ (see e.g. [16, p.43]) satisfying σ ij = λδ ij divu + 2µε ij (9.20) where δ ij is Kronecker’s delta. We assume that the elastic plate is fixed on Γ D ] − h, h[, Γ D ⊂ ∂Ω. If the body force f = (f 1 , f 2 , f 3 ) is given in Ω] − h, h[ and surface force g is given in Γ N ] −h, h[, Γ N = ∂Ω ` Γ D , then the equation of equilibrium is given as follows: −∂ j σ ij = f i in Ω] −h, h[, i = 1, 2, 3 (9.21) σ ij n j = g i on Γ N ] −h, h[, u i = 0 on Γ D ] −h, h[, i = 1, 2, 3 (9.22) We now explain the plain elasticity. Plain strain: On the end of plate, the contact condition u 3 = 0, g 3 = is satisfied. In this case, we can suppose that f 3 = g 3 = u 3 = 0 and u(x 1 , x 2 , x 3 ) = u(x 1 , x 2 ) for all −h < x 3 < h. Plain stress: The cylinder is assumed to be very thin and subjected to no load on the ends x 3 = ±h, that is, σ 3i = 0, x 3 = ±h, i 1, 2, 3 The assumption leads that σ 3i = 0 in Ω] − h, h[ and u(x 1 , x 2 , x 3 ) = u(x 1 , x 2 ) for all −h < x 3 < h. 206 CHAPTER 9. MATHEMATICAL MODELS Generalized plain stress: The cylinder is subjected to no load at x 3 = ±h. Introducing the mean values with respect to thickness, u i (x 1 , x 2 ) = 1 2h h −h u(x 1 , x 2 , x 3 )dx 3 and we derive u 3 ≡ 0. Similarly we define the mean values f, g of the body force and surface force as well as the mean values ε ij and σ ij of the components of stress and strain, respectively. In what follows we omit the overlines of u, f, g, ε ij and ε ij . Then we obtain similar equation of equilibrium given in (9.21) replacing Ω] −h, h[ with Ω and changing i = 1, 2. In the case of plane stress, σ ij = λ ∗ δ ij divu + 2µε ij , λ ∗ = (2λµ)/(λ +µ). The equations of elasticity are naturally written in variational form for the displacement vector u(x) ∈ V as Ω [2µ ij (u) ij (v) +λ ii (u) jj (v)] = Ω f v + Γ g v, ∀v ∈ V where V is the linear closed subspace of H 1 (Ω) 2 . Example 9.13 (Beam.edp) Consider elastic plate with the undeformed rectangle shape ]0, 10[]0, 2[. The body force is the gravity force f and the boundary force g is zero on lower and upper side. On the two vertical sides of the beam are fixed. // a weighting beam sitting on a int bottombeam = 2; border a(t=2,0) { x=0; y=t ;label=1;}; // left beam border b(t=0,10) { x=t; y=0 ;label=bottombeam;}; // bottom of beam border c(t=0,2) { x=10; y=t ;label=1;}; // rigth beam border d(t=0,10) { x=10-t; y=2; label=3;}; // top beam real E = 21.5; real sigma = 0.29; real mu = E/(2 * (1+sigma)); real lambda = E * sigma/((1+sigma) * (1-2 * sigma)); real gravity = -0.05; mesh th = buildmesh( b(20)+c(5)+d(20)+a(5)); fespace Vh(th,[P1,P1]); Vh [uu,vv], [w,s]; cout << "lambda,mu,gravity ="<<lambda<< " " << mu << " " << gravity << endl; // deformation of a beam under its own weight real sqrt2=sqrt(2.); // see lame.edp example 3.9 macro epsilon(u1,u2) [dx(u1),dy(u2),(dy(u1)+dx(u2))/sqrt2] // EOM macro div(u,v) ( dx(u)+dy(v) ) // EOM solve bb([uu,vv],[w,s])= int2d(th)( lambda * div(w,s) * div(uu,vv) +2. * mu * ( epsilon(w,s)’ * epsilon(uu,vv) ) ) + int2d(th) (-gravity * s) + on(1,uu=0,vv=0) ; plot([uu,vv],wait=1); 9.2. ELASTICITY 207 plot([uu,vv],wait=1,bb=[[-0.5,2.5],[2.5,-0.5]]); mesh th1 = movemesh(th, [x+uu, y+vv]); plot(th1,wait=1); Example 9.14 (beam-3d.edp) Consider elastic box with the undeformed parallelepiped shape ]0, 5[]0, 1[]0, 1[. The body force is the gravity force f and the boundary force g is zero on all face except one the one vertical left face where the beam is fixed. include "cube.idp" int[int] Nxyz=[20,5,5]; real [int,int] Bxyz=[[0.,5.],[0.,1.],[0.,1.]]; int [int,int] Lxyz=[[1,2],[2,2],[2,2]]; mesh3 Th=Cube(Nxyz,Bxyz,Lxyz); real E = 21.5e4, sigma = 0.29; real mu = E/(2 * (1+sigma)); real lambda = E * sigma/((1+sigma) * (1-2 * sigma)); real gravity = -0.05; fespace Vh(Th,[P1,P1,P1]); Vh [u1,u2,u3], [v1,v2,v3]; cout << "lambda,mu,gravity ="<<lambda<< " " << mu << " " << gravity << endl; real sqrt2=sqrt(2.); macro epsilon(u1,u2,u3) [dx(u1),dy(u2),dz(u3),(dz(u2)+dy(u3))/sqrt2, (dz(u1)+dx(u3))/sqrt2,(dy(u1)+dx(u2))/sqrt2] // EOM macro div(u1,u2,u3) ( dx(u1)+dy(u2)+dz(u3) ) // EOM solve Lame([u1,u2,u3],[v1,v2,v3])= int3d(Th)( lambda * div(u1,u2,u3) * div(v1,v2,v3) +2. * mu * ( epsilon(u1,u2,u3)’ * epsilon(v1,v2,v3) ) // ’) ) - int3d(Th) (gravity * v3) + on(1,u1=0,u2=0,u3=0) ; real dmax= u1[].max; cout << " max displacement = " << dmax << endl; real coef= 0.1/dmax; int[int] ref2=[1,0,2,0]; mesh3 Thm=movemesh3(Th,transfo=[x+u1 * coef,y+u2 * coef,z+u3 * coef],label=ref2); Thm=change(Thm,label=ref2); plot(Th,Thm, wait=1,cmm="coef amplification = "+coef ); // see fig ?? 208 CHAPTER 9. MATHEMATICAL MODELS 9.2.1 Fracture Mechanics Consider the plate with the crack whose undeformed shape is a curve Σ with the two edges γ 1 , γ 2 . We assume the stress tensor σ ij is the state of plate stress regarding (x, y) ∈ Ω Σ = Ω ` Σ. Here Ω stands for the undeformed shape of elastic plate without crack. If the part Γ N of the boundary ∂Ω is fixed and a load / = (f, g) ∈ L 2 (Ω) 2 L 2 (Γ N ) 2 is given, then the displacement u is the minimizer of the potential energy functional c(v; /, Ω Σ ) = Ω Σ ¦w(x, v) −f v¦ − Γ N g v over the functional space V (Ω Σ ), V (Ω Σ ) = ¸ v ∈ H 1 (Ω Σ ) 2 ; v = 0 on Γ D = ∂Ω ` Γ N ¸ , where w(x, v) = σ ij (v)ε ij (v)/2, σ ij (v) = C ijkl (x)ε kl (v), ε ij (v) = (∂v i /∂x j +∂v j /∂x i )/2, (C ijkl : Hooke’s tensor). If the elasticity is homogeneous isotropic, then the displacement u(x) is decomposed in an open neighborhood U k of γ k as in (see e.g. [17]) u(x) = 2 ¸ l=1 K l (γ k )r 1/2 k S C kl (θ k ) +u k,R (x) for x ∈ Ω Σ ∩ U k , k = 1, 2 (9.23) with u k,R ∈ H 2 (Ω Σ ∩U k ) 2 , where U k , k = 1, 2 are open neighborhoods of γ k such that ∂L 1 ∩U 1 = γ 1 , ∂L m ∩ U 2 = γ 2 , and S C k1 (θ k ) = 1 4µ 1 (2π) 1/2 ¸ [2κ −1] cos(θ k /2) −cos(3θ k /2) −[2κ + 1] sin(θ k /2) + sin(3θ k /2) , (9.24) S C k2 (θ k ) = 1 4µ 1 (2π) 1/2 ¸ −[2κ −1] sin(θ k /2) + 3 sin(3θ k /2) −[2κ + 1] cos(θ k /2) + cos(3θ k /2) . where µ is the shear modulus of elasticity, κ = 3 −4ν (ν is the Poisson’s ratio) for plane strain and κ = 3−ν 1+ν for plane stress. The coefficients K 1 (γ i ) and K 2 (γ i ), which are important parameters in fracture mechanics, are called stress intensity factors of the opening mode (mode I) and the sliding mode (mode II), respectively. For simplicity, we consider the following simple crack Ω = ¦(x, y) : −1 < x < 1, −1 < y < 1¦, Σ = ¦(x, y) : −1 ≤ x ≤ 0, y = 0¦ with only one crack tip γ = (0, 0). Unfortunately, FreeFem++ cannot treat crack, so we use the modification of the domain with U-shape channel (see Fig. 5.30) with d = 0.0001. The undeformed crack Σ is approximated by Σ d = ¦(x, y) : −1 ≤ x ≤ −10 ∗ d, −d ≤ y ≤ d¦ ∪¦(x, y) : −10 ∗ d ≤ x ≤ 0, −d + 0.1 ∗ x ≤ y ≤ d −0.1 ∗ x¦ and Γ D = R in Fig. 5.30. In this example, we use three technique: • Fast Finite Element Interpolator from the mesh Th to Zoom for the scale-up of near γ. 9.2. ELASTICITY 209 • After obtaining the displacement vector u = (u, v), we shall watch the deformation of the crack near γ as follows, mesh Plate = movemesh(Zoom,[x+u,y+v]); plot(Plate); • Adaptivity is an important technique here, because a large singularity occurs at γ as shown in (9.23). The first example creates mode I deformation by the opposed surface force on B and T in the vertical direction of Σ, and the displacement is fixed on R. In a laboratory, fracture engineers use photoelasticity to make stress field visible, which shows the principal stress difference σ 1 −σ 2 = (σ 11 −σ 22 ) 2 + 4σ 2 12 (9.25) where σ 1 and σ 2 are the principal stresses. In opening mode, the photoelasticity make symmetric pattern concentrated at γ. Example 9.15 (Crack Opening, K 2 (γ) = 0) {CrackOpen.edp} real d = 0.0001; int n = 5; real cb=1, ca=1, tip=0.0; border L1(t=0,ca-d) { x=-cb; y=-d-t; } border L2(t=0,ca-d) { x=-cb; y=ca-t; } border B(t=0,2) { x=cb * (t-1); y=-ca; } border C1(t=0,1) { x=-ca * (1-t)+(tip-10 * d) * t; y=d; } border C21(t=0,1) { x=(tip-10 * d) * (1-t)+tip * t; y=d * (1-t); } border C22(t=0,1) { x=(tip-10 * d) * t+tip * (1-t); y=-d * t; } border C3(t=0,1) { x=(tip-10 * d) * (1-t)-ca * t; y=-d; } border C4(t=0,2 * d) { x=-ca; y=-d+t; } border R(t=0,2) { x=cb; y=cb * (t-1); } border T(t=0,2) { x=cb * (1-t); y=ca; } mesh Th = buildmesh (L1(n/2)+L2(n/2)+B(n) +C1(n)+C21(3)+C22(3)+C3(n)+R(n)+T(n)); cb=0.1; ca=0.1; plot(Th,wait=1); mesh Zoom = buildmesh (L1(n/2)+L2(n/2)+B(n)+C1(n) +C21(3)+C22(3)+C3(n)+R(n)+T(n)); plot(Zoom,wait=1); real E = 21.5; real sigma = 0.29; real mu = E/(2 * (1+sigma)); real lambda = E * sigma/((1+sigma) * (1-2 * sigma)); fespace Vh(Th,[P2,P2]); fespace zVh(Zoom,P2); Vh [u,v], [w,s]; solve Problem([u,v],[w,s]) = int2d(Th)( 2 * mu * (dx(u) * dx(w)+ ((dx(v)+dy(u)) * (dx(s)+dy(w)))/4 ) + lambda * (dx(u)+dy(v)) * (dx(w)+dy(s))/2 ) -int1d(Th,T)(0.1 * (4-x) * s)+int1d(Th,B)(0.1 * (4-x) * s) +on(R,u=0)+on(R,v=0); // fixed ; 210 CHAPTER 9. MATHEMATICAL MODELS zVh Sx, Sy, Sxy, N; for (int i=1; i<=5; i++) { mesh Plate = movemesh(Zoom,[x+u,y+v]); // deformation near γ Sx = lambda * (dx(u)+dy(v)) + 2 * mu * dx(u); Sy = lambda * (dx(u)+dy(v)) + 2 * mu * dy(v); Sxy = mu * (dy(u) + dx(v)); N = 0.1 * 1 * sqrt((Sx-Sy)ˆ2+4 * Sxyˆ2); // principal stress difference if (i==1) { plot(Plate,ps="1stCOD.eps",bw=1); // Fig. 9.13 plot(N,ps="1stPhoto.eps",bw=1); // Fig. 9.13 } else if (i==5) { plot(Plate,ps="LastCOD.eps",bw=1); // Fig. 9.14 plot(N,ps="LastPhoto.eps",bw=1); // Fig. 9.14 break; } Th=adaptmesh(Th,[u,v]); Problem; } Figure 9.13: Crack open displacement (COD) and Principal stress difference in the first mesh Figure 9.14: COD and Principal stress dif- ference in the last adaptive mesh It is difficult to create mode II deformation by the opposed shear force on B and T that is observed in a laboratory. So we use the body shear force along Σ, that is, the x-component f 1 of the body force f is given by f 1 (x, y) = H(y −0.001) ∗ H(0.1 −y) −H(−y −0.001) ∗ H(y + 0.1) where H(t) = 1 if t > 0; = 0 if t < 0. Example 9.16 (Crack Sliding, K 2 (γ) = 0) (use the same mesh Th) cb=0.01; ca=0.01; mesh Zoom = buildmesh (L1(n/2)+L2(n/2)+B(n)+C1(n) +C21(3)+C22(3)+C3(n)+R(n)+T(n)); (use same FE-space Vh and elastic modulus) fespace Vh1(Th,P1); Vh1 fx = ((y>0.001) * (y<0.1))-((y<-0.001) * (y>-0.1)) ; solve Problem([u,v],[w,s]) = 9.3. NONLINEAR STATIC PROBLEMS 211 int2d(Th)( 2 * mu * (dx(u) * dx(w)+ ((dx(v)+dy(u)) * (dx(s)+dy(w)))/4 ) + lambda * (dx(u)+dy(v)) * (dx(w)+dy(s))/2 ) -int2d(Th)(fx * w) +on(R,u=0)+on(R,v=0); // fixed ; for (int i=1; i<=3; i++) { mesh Plate = movemesh(Zoom,[x+u,y+v]); // deformation near γ Sx = lambda * (dx(u)+dy(v)) + 2 * mu * dx(u); Sy = lambda * (dx(u)+dy(v)) + 2 * mu * dy(v); Sxy = mu * (dy(u) + dx(v)); N = 0.1 * 1 * sqrt((Sx-Sy)ˆ2+4 * Sxyˆ2); // principal stress difference if (i==1) { plot(Plate,ps="1stCOD2.eps",bw=1); // Fig. 9.16 plot(N,ps="1stPhoto2.eps",bw=1); // Fig. 9.15 } else if (i==3) { plot(Plate,ps="LastCOD2.eps",bw=1); // Fig. 9.16 plot(N,ps="LastPhoto2.eps",bw=1); // Fig. 9.16 break; } Th=adaptmesh(Th,[u,v]); Problem; } Figure 9.15: (COD) and Principal stress dif- ference in the first mesh Figure 9.16: COD and Principal stress dif- ference in the last adaptive mesh 9.3 Nonlinear Static Problems Here we propose to solve the following non-linear academic problem of minimization of a functional J(u) = Ω 1 2 f([∇u[ 2 ) −u ∗ b where u is function of H 1 0 (Ω) and f defined by f(x) = a ∗ x +x −ln(1 +x), f (x) = a + x 1 +x , f (x) = 1 (1 +x) 2 212 CHAPTER 9. MATHEMATICAL MODELS 9.3.1 Newton-Raphson algorithm Now, we solve the Euler problem ∇J(u) = 0 with Newton-Raphson algorithm, that is, u n+1 = u n −(∇ 2 J(u n )) −1 ∗ ∇J(u n ) First we introduce the two variational form vdJ and vhJ to compute respectively ∇J and ∇ 2 J // method of Newton-Raphson to solve dJ(u)=0; // u n+1 = u n −( ∂dJ ∂u i ) −1 ∗ dJ(u n ) // --------------------------------------------- Ph dalpha ; // to store 2f ([∇u[ 2 ) optimisation // the variational form of evaluate dJ = ∇J // -------------------------------------- // dJ = f’() * ( dx(u) * dx(vh) + dy(u) * dy(vh) varf vdJ(uh,vh) = int2d(Th)( alpha * ( dx(u) * dx(vh) + dy(u) * dy(vh) ) - b * vh) + on(1,2,3,4, uh=0); // the variational form of evaluate ddJ = ∇ 2 J // hJ(uh,vh) = f’() * ( dx(uh) * dx(vh) + dy(uh) * dy(vh) // + 2 * f’’()( dx(u) * dx(uh) + dy(u) * dy(uh) ) * (dx(u) * dx(vh) + dy(u) * dy(vh)) varf vhJ(uh,vh) = int2d(Th)( alpha * ( dx(uh) * dx(vh) + dy(uh) * dy(vh) ) + dalpha * ( dx(u) * dx(vh) + dy(u) * dy(vh) ) * ( dx(u) * dx(uh) + dy(u) * dy(uh) ) ) + on(1,2,3,4, uh=0); // the Newton algorithm Vh v,w; u=0; for (int i=0;i<100;i++) { alpha = df( dx(u) * dx(u) + dy(u) * dy(u) ) ; // optimization dalpha = 2 * ddf( dx(u) * dx(u) + dy(u) * dy(u) ) ; // optimization v[]= vdJ(0,Vh); // v = ∇J(u) real res= v[]’ * v[]; // the dot product cout << i << " residuˆ2 = " << res << endl; if( res< 1e-12) break; matrix H= vhJ(Vh,Vh,factorize=1,solver=LU); // w[]=Hˆ-1 * v[]; u[] -= w[]; } plot (u,wait=1,cmm="solution with Newton-Raphson"); Remark: This example is in Newton.edp file of examples++-tutorial directory. 9.4. EIGENVALUE PROBLEMS 213 9.4 Eigenvalue Problems This section depends on your installation of FreeFem++; you need to have compiled (see README arpack), ARPACK. This tools is available in FreeFem++ if the word “eigenvalue” appear in line “Load:”, like: -- FreeFem++ v1.28 (date Thu Dec 26 10:56:34 CET 2002) file : LapEigenValue.edp Load: lg_fem lg_mesh eigenvalue This tools is based on the arpack++ 1 the object-oriented version of ARPACK eigenvalue package [1]. The function EigenValue computes the generalized eigenvalue of Au = λBu where sigma =σ is the shift of the method. The matrix OP is defined with A − σB. The return value is the number of converged eigenvalue (can be greater than the number of eigen value nev=) int k=EigenValue(OP,B,nev= , sigma= ); where the matrix OP = A−σB with a solver and boundary condition, and the matrix B. Note 9.1 Boundary condition and Eigenvalue Problems The locking (Dirichlet ) boundary condition is make with exact penalization so we put 1e30=tgv on the diagonal term of the locked degree of freedom (see equation (6.31)). So take Dirichlet boundary condition just on A and not on B. because we solve w = OP − 1 ∗ B ∗ v. If you put locking (Dirichlet ) boundary condition on B matrix (with key work on) you get small spurious modes (10 −30 ), due to boundary condition, but if you forget the locking boundary condition on B matrix (no key work ”on”) you get huge spurious (10 30 ) modes associated to these boundary conditons. We compute only small mode, so we get the good one in this case. sym= the problem is symmetric (all the eigen value are real) nev= the number desired eigenvalues (nev) close to the shift. value= the array to store the real part of the eigenvalues ivalue= the array to store the imag. part of the eigenvalues vector= the FE function array to store the eigenvectors rawvector= an array of type real[int,int] to store eigenvectors by column. (up to version 2-17). For real non symmetric problems, complex eigenvectors are given as two consecutive vectors, so if eigenvalue k and k+1 are complex conjugate eigenvalues, the kth vector will contain the real part and the k +1th vector the imaginary part of the corresponding complex conjugate eigenvectors. tol= the relative accuracy to which eigenvalues are to be determined; sigma= the shift value; maxit= the maximum number of iterations allowed; 1 http://www.caam.rice.edu/software/ARPACK/ 214 CHAPTER 9. MATHEMATICAL MODELS ncv= the number of Arnoldi vectors generated at each iteration of ARPACK. Example 9.17 (lapEignenValue.edp) In the first example, we compute the eigenvalues and the eigen- vectors of the Dirichlet problem on square Ω =]0, π[ 2 . The problem is to find: λ, and ∇u λ in RH 1 0 (Ω) Ω ∇u λ ∇v = λ Ω uv ∀v ∈ H 1 0 (Ω) The exact eigenvalues are λ n,m = (n 2 + m 2 ), (n, m) ∈ N ∗ 2 with the associated eigenvectors are u m,n = sin(nx) ∗ sin(my). We use the generalized inverse shift mode of the arpack++ library, to find 20 eigenvalues and eigenvectors close to the shift value σ = 20. // Computation of the eigen value and eigen vector of the // Dirichlet problem on square ]0, π[ 2 // ---------------------------------------- // we use the inverse shift mode // the shift is given with the real sigma // ------------------------------------- // find λ and u λ ∈ H 1 0 (Ω) such that: // Ω ∇u λ ∇v = λ Ω u λ v, ∀v ∈ H 1 0 (Ω) verbosity=10; mesh Th=square(20,20,[pi * x,pi * y]); fespace Vh(Th,P2); Vh u1,u2; real sigma = 20; // value of the shift // OP = A - sigma B ; // the shifted matrix varf op(u1,u2)= int2d(Th)( dx(u1) * dx(u2) + dy(u1) * dy(u2) - sigma * u1 * u2 ) + on(1,2,3,4,u1=0) ; // Boundary condition varf b([u1],[u2]) = int2d(Th)( u1 * u2 ); // no Boundary condition see note 9.1 matrix OP= op(Vh,Vh,solver=Crout,factorize=1); // crout solver because the matrix in not positive matrix B= b(Vh,Vh,solver=CG,eps=1e-20); // important remark: // the boundary condition is make with exact penalization: // we put 1e30=tgv on the diagonal term of the lock degree of freedom. // So take Dirichlet boundary condition just on a variational form // and not on b variational form. // because we solve w = OP − 1 ∗ B ∗ v int nev=20; // number of computed eigen value close to sigma real[int] ev(nev); // to store the nev eigenvalue Vh[int] eV(nev); // to store the nev eigenvector int k=EigenValue(OP,B,sym=true,sigma=sigma,value=ev,vector=eV, tol=1e-10,maxit=0,ncv=0); 9.4. EIGENVALUE PROBLEMS 215 // tol= the tolerance // maxit= the maximum iteration see arpack doc. // ncv see arpack doc. http://www.caam.rice.edu/software/ARPACK/ // the return value is number of converged eigen value. for (int i=0;i<k;i++) { u1=eV[i]; real gg = int2d(Th)(dx(u1) * dx(u1) + dy(u1) * dy(u1)); real mm= int2d(Th)(u1 * u1) ; cout << " ---- " << i<< " " << ev[i]<< " err= " <<int2d(Th)(dx(u1) * dx(u1) + dy(u1) * dy(u1) - (ev[i]) * u1 * u1) << " --- "<<endl; plot(eV[i],cmm="Eigen Vector "+i+" valeur =" + ev[i] ,wait=1,value=1); } The output of this example is: Nb of edges on Mortars = 0 Nb of edges on Boundary = 80, neb = 80 Nb Of Nodes = 1681 Nb of DF = 1681 Real symmetric eigenvalue problem: A * x - B * x * lambda Thanks to ARPACK++ class ARrcSymGenEig Real symmetric eigenvalue problem: A * x - B * x * lambda Shift and invert mode sigma=20 Dimension of the system : 1681 Number of ’requested’ eigenvalues : 20 Number of ’converged’ eigenvalues : 20 Number of Arnoldi vectors generated: 41 Number of iterations taken : 2 Eigenvalues: lambda[1]: 5.0002 lambda[2]: 8.00074 lambda[3]: 10.0011 lambda[4]: 10.0011 lambda[5]: 13.002 lambda[6]: 13.0039 lambda[7]: 17.0046 lambda[8]: 17.0048 lambda[9]: 18.0083 lambda[10]: 20.0096 lambda[11]: 20.0096 lambda[12]: 25.014 lambda[13]: 25.0283 lambda[14]: 26.0159 lambda[15]: 26.0159 lambda[16]: 29.0258 lambda[17]: 29.0273 lambda[18]: 32.0449 lambda[19]: 34.049 216 CHAPTER 9. MATHEMATICAL MODELS lambda[20]: 34.0492 ---- 0 5.0002 err= -0.000225891 --- ---- 1 8.00074 err= -0.000787446 --- ---- 2 10.0011 err= -0.00134596 --- ---- 3 10.0011 err= -0.00134619 --- ---- 4 13.002 err= -0.00227747 --- ---- 5 13.0039 err= -0.004179 --- ---- 6 17.0046 err= -0.00623649 --- ---- 7 17.0048 err= -0.00639952 --- ---- 8 18.0083 err= -0.00862954 --- ---- 9 20.0096 err= -0.0110483 --- ---- 10 20.0096 err= -0.0110696 --- ---- 11 25.014 err= -0.0154412 --- ---- 12 25.0283 err= -0.0291014 --- ---- 13 26.0159 err= -0.0218532 --- ---- 14 26.0159 err= -0.0218544 --- ---- 15 29.0258 err= -0.0311961 --- ---- 16 29.0273 err= -0.0326472 --- ---- 17 32.0449 err= -0.0457328 --- ---- 18 34.049 err= -0.0530978 --- ---- 19 34.0492 err= -0.0536275 --- IsoValue -0.809569 -0.724351 -0.639134 -0.553916 -0.468698 -0.38348 -0.298262 -0.213045 -0.127827 -0.0426089 0.0426089 0.127827 0.213045 0.298262 0.38348 0.468698 0.553916 0.639134 0.724351 0.809569 Eigen Vector 11 valeur =25.014 Figure 9.17: Isovalue of 11th eigenvector u 4,3 −u 3,4 IsoValue -0.807681 -0.722662 -0.637643 -0.552624 -0.467605 -0.382586 -0.297567 -0.212548 -0.127529 -0.0425095 0.0425095 0.127529 0.212548 0.297567 0.382586 0.467605 0.552624 0.637643 0.722662 0.807681 Eigen Vector 12 valeur =25.0283 Figure 9.18: Isovalue of 12th eigenvector u 4,3 + u 3,4 9.5. EVOLUTION PROBLEMS 217 9.5 Evolution Problems FreeFem++ also solves evolution problems such as the heat equation: ∂u ∂t −µ∆u = f in Ω]0, T[, (9.26) u(x, 0) = u 0 (x) in Ω; (∂u/∂n) (x, t) = 0 on ∂Ω]0, T[. with a positive viscosity coefficient µ and homogeneous Neumann boundary conditions. We solve (9.26) by FEM in space and finite differences in time. We use the definition of the partial derivative of the solution in the time derivative, ∂u ∂t (x, y, t) = lim τ→0 u(x, y, t) −u(x, y, t −τ) τ which indicates that u m (x, y) = u(x, y, mτ) will satisfy approximatively ∂u ∂t (x, y, mτ) · u m (x, y) −u m−1 (x, y) τ The time discretization of heat equation (9.27) is as follows: u m+1 −u m τ −µ∆u m+1 = f m+1 in Ω (9.27) u 0 (x) = u 0 (x) in Ω; ∂u m+1 /∂n(x) = 0 on ∂Ω, for all m = 0, , [T/τ], which is so-called backward Euler method for (9.27). To obtain the variational formulation, multiply with the test function v both sides of the equation: Ω ¦u m+1 v −τ∆u m+1 v¦ = Ω ¦u m +τf m+1 ¦v . By the divergence theorem, we have Ω ¦u m+1 v +τ∇u m+1 ∇v¦ − ∂Ω τ ∂u m+1 /∂n v = Ω ¦u m v +τf m+1 v¦. By the boundary condition ∂u m+1 /∂n = 0, it follows that Ω ¦u m+1 v +τ∇u m+1 ∇v¦ − Ω ¦u m v +τf m+1 v¦ = 0. (9.28) Using the identity just above, we can calculate the finite element approximation u m h of u m in a step-by-step manner with respect to t. Example 9.18 We now solve the following example with the exact solution u(x, y, t) = tx 4 . ∂u ∂t −µ∆u = x 4 −µ12tx 2 in Ω]0, 3[, Ω =]0, 1[ 2 u(x, y, 0) = 0 on Ω, u[ ∂Ω = t ∗ x 4 // heat equation ∂ t u = −µ∆u = x 4 −µ12tx 2 mesh Th=square(16,16); fespace Vh(Th,P1); 218 CHAPTER 9. MATHEMATICAL MODELS Vh u,v,uu,f,g; real dt = 0.1, mu = 0.01; problem dHeat(u,v) = int2d(Th)( u * v + dt * mu * (dx(u) * dx(v) + dy(u) * dy(v))) + int2d(Th) (- uu * v - dt * f * v ) + on(1,2,3,4,u=g); real t = 0; // start from t=0 uu = 0; // u(x,y,0)=0 for (int m=0;m<=3/dt;m++) { t=t+dt; f = xˆ4-mu * t * 12 * xˆ2; g = t * xˆ4; dHeat; plot(u,wait=true); uu = u; cout <<"t="<<t<<"Lˆ2-Error="<<sqrt( int2d(Th)((u-t * xˆ4)ˆ2) ) << endl; } In the last statement, the L 2 -error Ω u −tx 4 2 1/2 is calculated at t = mτ, τ = 0.1. At t = 0.1, the error is 0.000213269. The errors increase with m and 0.00628589 at t = 3. The iteration of the backward Euler (9.28) is made by for loop (see Section 4.10). Note 9.2 The stiffness matrix in the loop is used over and over again. FreeFem++ support reuses of stiffness matrix. 9.5.1 Mathematical Theory on Time Difference Approximations. In this section, we show the advantage of implicit schemes. Let V, H be separable Hilbert space and V is dense in H. Let a be a continuous bilinear form over V V with coercivity and symmetry. Then a(v, v) become equivalent to the norm |v| of V . Problem Ev(f, Ω): For a given f ∈ L 2 (0, T; V ), u 0 ∈ H d dt (u(t), v) +a(u(t), v) = (f(t), v) ∀v ∈ V, , a.e. t ∈ [0, T] (9.29) u(0) = u 0 where V is the dual space of V . Then, there is an unique solution u ∈ L ∞ (0, T; H) ∩ L 2 (0, T; V ). Let us denote the time step by τ > 0, N T = [T/τ]. For the discretization, we put u n = u(nτ) and consider the time difference for each θ ∈ [0, 1] 1 τ u n+1 h −u n h , φ i +a u n+θ h , φ i = 'f n+θ , φ i ` (9.30) i = 1, , m, n = 0, , N T u n+θ h = θu n+1 h + (1 −θ)u n h , f n+θ = θf n+1 + (1 −θ)f n Formula (9.30) is the forward Euler scheme if θ = 0, Crank-Nicolson scheme if θ = 1/2, the backward Euler scheme if θ = 1. 9.5. EVOLUTION PROBLEMS 219 Unknown vectors u n = (u 1 h , , u M h ) T in u n h (x) = u n 1 φ 1 (x) + +u n m φ m (x), u n 1 , , u n m ∈ R are obtained from solving the matrix (M +θτA)u n+1 = ¦M −(1 −θ)τA¦u n +τ ¸ θf n+1 + (1 −θ)f n ¸ (9.31) M = (m ij ), m ij = (φ j , φ i ), A = (a ij ), a ij = a(φ j , φ i ) Refer [22, pp.70–75] for solvability of (9.31). The stability of (9.31) is in [22, Theorem 2.13]: Let ¦T h ¦ h↓0 be regular triangulations (see Section 5.4). Then there is a number c 0 > 0 independent of h such that, [u n h [ 2 ≤ 1 δ [u 0 h [ 2 +τ ¸ n−1 k=0 |f k+θ | 2 V h ¸ θ ∈ [0, 1/2) [u 0 h [ 2 +τ ¸ n−1 k=0 |f k+θ | 2 V h θ ∈ [1/2, 1] (9.32) if the following are satisfied: 1. When θ ∈ [0, 1/2), then we can take a time step τ in such a way that τ < 2(1 −δ) (1 −2θ)c 2 0 h 2 (9.33) for arbitrary δ ∈ (0, 1). 2. When 1/2 ≤ θ ≤ 1, we can take τ arbitrary. Example 9.19 mesh Th=square(12,12); fespace Vh(Th,P1); fespace Ph(Th,P0); Ph h = hTriangle; // mesh sizes for each triangle real tau = 0.1, theta=0.; func real f(real t) { return xˆ2 * (x-1)ˆ2 + t * (-2 + 12 * x - 11 * xˆ2 - 2 * xˆ3 + xˆ4); } ofstream out("err02.csv"); // file to store calculations out << "mesh size = "<<h[].max<<", time step = "<<tau<<endl; for (int n=0;n<5/tau;n++) \\ out<<n * tau<<","; out << endl; Vh u,v,oldU; Vh f1, f0; problem aTau(u,v) = int2d(Th)( u * v + theta * tau * (dx(u) * dx(v) + dy(u) * dy(v) + u * v)) - int2d(Th)(oldU * v - (1-theta) * tau * (dx(oldU) * dx(v)+dy(oldU) * dy(v)+oldU * v)) - int2d(Th)(tau * ( theta * f1+(1-theta) * f0 ) * v ); while (theta <= 1.0) { real t = 0, T=3; // from t=0 to T oldU = 0; // u(x,y,0)=0 out <<theta<<","; 220 CHAPTER 9. MATHEMATICAL MODELS for (int n=0;n<T/tau;n++) { t = t+tau; f0 = f(n * tau); f1 = f((n+1) * tau); aTau; oldU = u; plot(u); Vh uex = t * xˆ2 * (1-x)ˆ2; // exact sol.= tx 2 (1 −x) 2 Vh err = u - uex; // err =FE-sol - exact out<< abs(err[].max)/abs(uex[].max) <<","; // |err| L ∞ (Ω) /|u ex | L ∞ (Ω) } out << endl; theta = theta + 0.1; } G Figure 9.19: max x∈Ω [u n h (θ) −u ex (nτ)[/ max x∈Ω [u ex (nτ)[ at n = 0, 1, , 29 We can see in Fig. 9.19 that u n h (θ) become unstable at θ = 0.4, and figures are omitted in the case θ < 0.4. 9.5.2 Convection The hyperbolic equation ∂ t u +α ∇u = f; for a vector-valued function α, (9.34) appears frequently in scientific problems, for example in the Navier-Stokes equations, in the Convection- Diffusion equation, etc. In the case of 1-dimensional space, we can easily find the general solution (x, t) → u(x, t) = u 0 (x −αt) of the following equation, if α is constant, ∂ t u +α∂ x u = 0, u(x, 0) = u 0 (x), (9.35) because ∂ t u + α∂ x u = −α˙ u 0 + a ˙ u 0 = 0, where ˙ u 0 = du 0 (x)/dx. Even if α is not constant, the construction worsk on similar principles. One begins with the ordinary differential equation (with the convention that α is prolonged by zero apart from (0, L) (0, T)): ˙ X(τ) = +α(X(τ), τ), τ ∈ (0, t) X(t) = x 9.5. EVOLUTION PROBLEMS 221 In this equation τ is the variable and x, t are parameters, and we denote the solution by X x,t (τ). Then it is noticed that (x, t) →v(X(τ), τ) in τ = t satisfies the equation ∂ t v +α∂ x v = ∂ t X˙ v +a∂ x X˙ v = 0 and by the definition ∂ t X = ˙ X = +α and ∂ x X = ∂ x x in τ = t, because if τ = t we have X(τ) = x. The general solution of (9.35) is thus the value of the boundary condition in X x,t (0), that is to say u(x, t) = u 0 (X x,t (0)) where X x,t (0) is on the x axis, u(x, t) = u 0 (X x,t (0)) if X x,t (0) is on the axis of t. In higher dimension Ω ⊂ R d , d = 2, 3, the equation for the convection is written ∂ t u +α ∇u = 0 in Ω (0, T) where a(x, t) ∈ R d . FreeFem++ implements the Characteristic-Galerkin method for convection operators. Recall that the equation (9.34) can be discretized as Du Dt = f i.e. du dt (X(t), t) = f (X(t), t) where dX dt (t) = α(X(t), t) where D is the total derivative operator. So a good scheme is one step of backward convection by the method of Characteristics-Galerkin 1 τ u m+1 (x) −u m (X m (x)) = f m (x) (9.36) where X m (x) is an approximation of the solution at t = mτ of the ordinary differential equation dX dt (t) = α m (X(t)), X((m+ 1)τ) = x. where α m (x) = (α 1 (x, mτ), α 2 (x, mτ)). Because, by Taylor’s expansion, we have u m (X(mτ)) = u m (X((m+ 1)τ)) −τ d ¸ i=1 ∂u m ∂x i (X((m+ 1)τ)) ∂X i ∂t ((m+ 1)τ) +o(τ) = u m (x) −τα m (x) ∇u m (x) +o(τ) (9.37) where X i (t) are the i-th component of X(t), u m (x) = u(x, mτ) and we used the chain rule and x = X((m+ 1)τ). From (9.37), it follows that u m (X m (x)) = u m (x) −τα m (x) ∇u m (x) +o(τ). (9.38) Also we apply Taylor’s expansion for t →u m (x −α m (x)t), 0 ≤ t ≤ τ, then u m (x −ατ) = u m (x) −τα m (x) ∇u m (x) +o(τ). Putting convect (α, −τ, u m ) ≈ u m (x −α m τ) , we can get the approximation u m (X m (x)) ≈ convect ([a m 1 , a m 2 ], −τ, u m ) by X m ≈ x →x −τ[a m 1 (x), a m 2 (x)]). A classical convection problem is that of the “rotating bell” (quoted from [14][p.16]). Let Ω be the unit disk centered at 0, with its center rotating with speed α 1 = y, α 2 = −x We consider the problem (9.34) with f = 0 and the initial condition u(x, 0) = u 0 (x), that is, from (9.36) u m+1 (x) = u m (X m (x)) ≈ convect(α, −τ, u m ). 222 CHAPTER 9. MATHEMATICAL MODELS The exact solution is u(x, t) = u(X(t)) where X equals x rotated around the origin by an angle θ = −t (rotate in clockwise). So, if u 0 in a 3D perspective looks like a bell, then u will have exactly the same shape, but rotated by the same amount. The program consists in solving the equation until T = 2π, that is for a full revolution and to compare the final solution with the initial one; they should be equal. Example 9.20 (convect.edp) border C(t=0, 2 * pi) { x=cos(t); y=sin(t); }; // the unit circle mesh Th = buildmesh(C(70)); // triangulates the disk fespace Vh(Th,P1); Vh u0 = exp(-10 * ((x-0.3)ˆ2 +(y-0.3)ˆ2)); // give u 0 real dt = 0.17,t=0; // time step Vh a1 = -y, a2 = x; // rotation velocity Vh u; // u m+1 for (int m=0; m<2 * pi/dt ; m++) { t += dt; u=convect([a1,a2],-dt,u0); // u m+1 = u m (X m (x)) u0=u; // m++ plot(u,cmm=" t="+t + ", min=" + u[].min + ", max=" + u[].max,wait=0); }; Note 9.3 The scheme convect is unconditionally stable, then the bell become lower and lower (the maximum of u 37 is 0.406 as shown in Fig. 9.21). convection: t=0, min=1.55289e-09, max=0.983612 Figure 9.20: u 0 = e −10((x−0.3) 2 +(y−0.3) 2 ) convection: t=6.29, min=1.55289e-09, max=0.40659m=37 Figure 9.21: The bell at t = 6.29 9.5.3 2D Black-Scholes equation for an European Put option In mathematical finance, an option on two assets is modeled by a Black-Scholes equations in two space variables, (see for example Wilmott et al[39] or Achdou et al [3]). ∂ t u + (σ 1 x) 2 2 ∂ 2 u ∂x 2 + (σ 2 y) 2 2 ∂ 2 u ∂y 2 (9.39) +ρxy ∂ 2 u ∂x∂y +rS 1 ∂u ∂x +rS 2 ∂u ∂y −rP = 0 9.5. EVOLUTION PROBLEMS 223 which is to be integrated in (0, T) R + R + subject to, in the case of a put u(x, y, T) = (K −max (x, y)) + . (9.40) Boundary conditions for this problem may not be so easy to device. As in the one dimensional case the PDE contains boundary conditions on the axis x 1 = 0 and on the axis x 2 = 0, namely two one dimensional Black-Scholes equations driven respectively by the data u(0, +∞, T) and u(+∞, 0, T). These will be automatically accounted for because they are embedded in the PDE. So if we do nothing in the variational form (i.e. if we take a Neumann boundary condition at these two axis in the strong form) there will be no disturbance to these. At infinity in one of the variable, as in 1D, it makes sense to impose u = 0. We take σ 1 = 0.3, σ 2 = 0.3, ρ = 0.3, r = 0.05, K = 40, T = 0.5 (9.41) An implicit Euler scheme is used and a mesh adaptation is done every 10 time steps. To have an unconditionally stable scheme, the first order terms are treated by the Characteristic Galerkin method, which, roughly, approximates ∂u ∂t +a 1 ∂u ∂x +a 2 ∂u ∂y ≈ 1 τ u n+1 (x) −u n (x −ατ) (9.42) Example 9.21 [BlackSchol.edp] // file BlackScholes2D.edp int m=30,L=80,LL=80, j=100; real sigx=0.3, sigy=0.3, rho=0.3, r=0.05, K=40, dt=0.01; mesh th=square(m,m,[L * x,LL * y]); fespace Vh(th,P1); Vh u=max(K-max(x,y),0.); Vh xveloc, yveloc, v,uold; for (int n=0; n * dt <= 1.0; n++) { if(j>20) { th = adaptmesh(th,u,verbosity=1,abserror=1,nbjacoby=2, err=0.001, nbvx=5000, omega=1.8, ratio=1.8, nbsmooth=3, splitpbedge=1, maxsubdiv=5,rescaling=1) ; j=0; xveloc = -x * r+x * sigxˆ2+x * rho * sigx * sigy/2; yveloc = -y * r+y * sigyˆ2+y * rho * sigx * sigy/2; u=u; }; uold=u; solve eq1(u,v,init=j,solver=LU) = int2d(th)( u * v * (r+1/dt) + dx(u) * dx(v) * (x * sigx)ˆ2/2 + dy(u) * dy(v) * (y * sigy)ˆ2/2 + (dy(u) * dx(v) + dx(u) * dy(v)) * rho * sigx * sigy * x * y/2) - int2d(th)( v * convect([xveloc,yveloc],dt,w)/dt) + on(2,3,u=0); j=j+1; }; plot(u,wait=1,value=1); Results are shown on Fig. 9.21). 224 CHAPTER 9. MATHEMATICAL MODELS Figure 9.22: The adapted triangulation IsoValue -1.99835 0.999173 2.99752 4.99587 6.99421 8.99256 10.9909 12.9893 14.9876 16.9859 18.9843 20.9826 22.981 24.9793 26.9777 28.976 30.9744 32.9727 34.9711 39.9669 Figure 9.23: The level line of the European basquet put option 9.6 Navier-Stokes Equation 9.6.1 Stokes and Navier-Stokes The Stokes equations are: for a given f ∈ L 2 (Ω) 2 , −∆u +∇p = f ∇ u = 0 in Ω (9.43) where u = (u 1 , u 2 ) is the velocity vector and p the pressure. For simplicity, let us choose Dirichlet boundary conditions on the velocity, u = u Γ on Γ. In Temam [Theorem 2.2], there ia a weak form of (9.43): Find v = (v 1 , v 2 ) ∈ V (Ω) V (Ω) = ¦w ∈ H 1 0 (Ω) 2 [ divw = 0¦ which satisfy 2 ¸ i=1 Ω ∇u i ∇v i = Ω f w for all v ∈ V Here it is used the existence p ∈ H 1 (Ω) such that u = ∇p, if Ω u v = 0 for all v ∈ V Another weak form is derived as follows: We put V = H 1 0 (Ω) 2 ; W = q ∈ L 2 (Ω) Ω q = 0 9.6. NAVIER-STOKES EQUATION 225 By multiplying the first equation in (9.43) with v ∈ V and the second with q ∈ W, subsequent integration over Ω, and an application of Green’s formula, we have Ω ∇u ∇v − Ω divv p = Ω f v Ω divuq = 0 This yields the weak form of (9.43): Find (u, p) ∈ V W such that a(u, v) +b(v, p) = (f, v) (9.44) b(u, q) = 0 (9.45) for all (v, q) ∈ V W, where a(u, v) = Ω ∇u ∇v = 2 ¸ i=1 Ω ∇u i ∇v i (9.46) b(u, q) = − Ω divuq (9.47) Now, we consider finite element spaces V h ⊂ V and W h ⊂ W, and we assume the following basis functions V h = V h V h , V h = ¦v h [ v h = v 1 φ 1 + +v M V φ M V ¦, W h = ¦q h [ q h = q 1 ϕ 1 + +q M W ϕ M W ¦ The discrete weak form is: Find (u h , p h ) ∈ V h W h such that a(u h , v h ) +b(v h , p) = (f, v h ), ∀v h ∈ V h b(u h , q h ) = 0, ∀q h ∈ W h (9.48) Note 9.4 Assume that: 1. There is a constant α h > 0 such that a(v h , v h ) ≥ α|v h | 2 1,Ω for all v h ∈ Z h where Z h = ¦v h ∈ V h [ b(w h , q h ) = 0 for all q h ∈ W h ¦ 2. There is a constant β h > 0 such that sup v h ∈V h b(v h , q h ) |v h | 1,Ω ≥ β h |q h | 0,Ω for all q h ∈ W h Then we have an unique solution (u h , p h ) of (9.48) satisfying |u −u h | 1,Ω +|p −p h | 0,Ω ≤ C inf v h ∈V h |u −v h | 1,Ω + inf q h ∈W h |p −q h | 0,Ω with a constant C > 0 (see e.g. [20, Theorem 10.4]). 226 CHAPTER 9. MATHEMATICAL MODELS Let us denote that A = (A ij ), A ij = Ω ∇φ j ∇φ i i, j = 1, , M V (9.49) B = (Bx ij , By ij ), Bx ij = − Ω ∂φ j /∂xϕ i By ij = − Ω ∂φ j /∂y ϕ i i = 1, , M W ; j = 1, , M V then (9.48) is written by A B ∗ B 0 U h ¦p h ¦ = F h 0 (9.50) where A = A 0 0 A B ∗ = Bx T By T U h = ¦u 1,h ¦ ¦u 2,h ¦ F h = ¦ Ω f 1 φ i ¦ ¦ Ω f 2 φ i ¦ Penalty method: This method consists of replacing (9.48) by a more regular problem: Find (v h , p h ) ∈ V h ˜ W h satisfying a(u h , v h ) +b(v h , p h ) = (f, v h ), ∀v h ∈ V h b(u h , q h ) −(p h , q h ) = 0, ∀q h ∈ ˜ W h (9.51) where ˜ W h ⊂ L 2 (Ω). Formally, we have divu h = p h and the corresponding algebraic problem A B ∗ B −I U h ¦p h ¦ = F h 0 Note 9.5 We can eliminate p h = (1/)BU h to obtain (A+ (1/)B ∗ B)U h = F h (9.52) Since the matrix A+(1/)B ∗ B is symmetric, positive-definite, and sparse, (9.52) can be solved by known technique. There is a constant C > 0 independent of such that |u h −u h | 1,Ω +|p h −p h | 0,Ω ≤ C (see e.g. [20, 17.2]) Example 9.22 (Cavity.edp) The driven cavity flow problem is solved first at zero Reynolds number (Stokes flow) and then at Reynolds 100. The velocity pressure formulation is used first and then the calculation is repeated with the stream function vorticity formulation. We solve the driven cavity problem by the penalty method (9.51) where u Γ n = 0 and u Γ s = 1 on the top boundary and zero elsewhere ( n is the unit normal to Γ, and s the unit tangent to Γ). The mesh is constructed by mesh Th=square(8,8); 9.6. NAVIER-STOKES EQUATION 227 We use a classical Taylor-Hood element technic to solve the problem: The velocity is approximated with the P 2 FE ( X h space), and the the pressure is approximated with the P 1 FE ( M h space), where X h = ¸ v ∈ H 1 (]0, 1[ 2 ) ∀K ∈ T h v |K ∈ P 2 ¸ and M h = ¸ v ∈ H 1 (]0, 1[ 2 ) ∀K ∈ T h v |K ∈ P 1 ¸ The FE spaces and functions are constructed by fespace Xh(Th,P2); // definition of the velocity component space fespace Mh(Th,P1); // definition of the pressure space Xh u2,v2; Xh u1,v1; Mh p,q; The Stokes operator is implemented as a system-solve for the velocity (u1, u2) and the pressure p. The test function for the velocity is (v1, v2) and q for the pressure, so the variational form (9.48) in freefem language is: solve Stokes (u1,u2,p,v1,v2,q,solver=Crout) = int2d(Th)( ( dx(u1) * dx(v1) + dy(u1) * dy(v1) + dx(u2) * dx(v2) + dy(u2) * dy(v2) ) - p * q * (0.000001) - p * dx(v1) - p * dy(v2) - dx(u1) * q - dy(u2) * q ) + on(3,u1=1,u2=0) + on(1,2,4,u1=0,u2=0); // see Section 5.1.1 for labels 1,2,3,4 Each unknown has its own boundary conditions. If the streamlines are required, they can be computed by finding ψ such that rotψ = u or better, −∆ψ = ∇u Xh psi,phi; solve streamlines(psi,phi) = int2d(Th)( dx(psi) * dx(phi) + dy(psi) * dy(phi)) + int2d(Th)( -phi * (dy(u1)-dx(u2))) + on(1,2,3,4,psi=0); Now the Navier-Stokes equations are solved ∂u ∂t +u ∇u −ν∆u +∇p = 0, ∇ u = 0 with the same boundary conditions and with initial conditions u = 0. 228 CHAPTER 9. MATHEMATICAL MODELS This is implemented by using the convection operator convect for the term ∂u ∂t +u ∇u, giving a discretization in time 1 τ (u n+1 −u n ◦ X n ) −ν∆u n+1 +∇p n+1 = 0, ∇ u n+1 = 0 (9.53) The term u n ◦X n (x) ≈ u n (x−u n (x)τ) will be computed by the operator “convect” , so we obtain int i=0; real nu=1./100.; real dt=0.1; real alpha=1/dt; Xh up1,up2; problem NS (u1,u2,p,v1,v2,q,solver=Crout,init=i) = int2d(Th)( alpha * ( u1 * v1 + u2 * v2) + nu * ( dx(u1) * dx(v1) + dy(u1) * dy(v1) + dx(u2) * dx(v2) + dy(u2) * dy(v2) ) - p * q * (0.000001) - p * dx(v1) - p * dy(v2) - dx(u1) * q - dy(u2) * q ) + int2d(Th) ( -alpha * convect([up1,up2],-dt,up1) * v1 -alpha * convect([up1,up2],-dt,up2) * v2 ) + on(3,u1=1,u2=0) + on(1,2,4,u1=0,u2=0) ; for (i=0;i<=10;i++) { up1=u1; up2=u2; NS; if ( !(i % 10)) // plot every 10 iteration plot(coef=0.2,cmm=" [u1,u2] and p ",p,[u1,u2]); } ; Notice that the stiffness matrices are reused (keyword init=i) 9.6.2 Uzawa Algorithm and Conjugate Gradients We solve Stokes problem without penalty. The classical iterative method of Uzawa is described by the algorithm (see e.g.[20, 17.3], [29, 13] or [30, 13] ): Initialize: Let p 0 h be an arbitrary chosen element of L 2 (Ω). Calculate u h : Once p n h is known, v n h is the solution of u n h = A −1 (f h −B ∗ p n h ) Advance p h : Let p n+1 h be defined by p n+1 h = p n h +ρ n Bu n h 9.6. NAVIER-STOKES EQUATION 229 There is a constant α > 0 such that α ≤ ρ n ≤ 2 for each n, then u n h converges to the solution u h , and then Bv n h →0 as n →∞ from the Advance p h . This method in general converges quite slowly. First we define mesh, and the Taylor-Hood approximation. So X h is the velocity space, and M h is the pressure space. Example 9.23 (StokesUzawa.edp) mesh Th=square(10,10); fespace Xh(Th,P2),Mh(Th,P1); Xh u1,u2,v1,v2; Mh p,q,ppp; // ppp is a working pressure varf bx(u1,q) = int2d(Th)( -(dx(u1) * q)); varf by(u1,q) = int2d(Th)( -(dy(u1) * q)); varf a(u1,u2)= int2d(Th)( dx(u1) * dx(u2) + dy(u1) * dy(u2) ) + on(3,u1=1) + on(1,2,4,u1=0) ; // remark: put the on(3,u1=1) before on(1,2,4,u1=0) // because we want zero on intersection % matrix A= a(Xh,Xh,solver=CG); matrix Bx= bx(Xh,Mh); // B = (Bx By) matrix By= by(Xh,Mh); Xh bc1; bc1[] = a(0,Xh); // boundary condition contribution on u1 Xh bc2; bc2 = O ; // no boundary condition contribution on u2 Xh b; p n h →BA −1 (−B ∗ p n h ) = −divu h is realized as the function divup. func real[int] divup(real[int] & pp) { // compute u1(pp) b[] = Bx’ * pp; b[] * =-1; b[] += bc1[] ; u1[] = Aˆ-1 * b[]; // compute u2(pp) b[] = By’ * pp; b[] * =-1; b[] += bc2[] ; u2[] = Aˆ-1 * b[]; // u n = A −1 (Bx T p n By T p n ) T ppp[] = Bx * u1[]; // ppp = Bxu 1 ppp[] += By * u2[]; // +Byu 2 return ppp[] ; }; Call now the conjugate gradient algorithm: p=0;q=0; // p 0 h = 0 LinearCG(divup,p[],eps=1.e-6,nbiter=50); // p n+1 h = p n h +Bu n h // if n > 50 or [p n+1 h −p n h [ ≤ 10 −6 , then the loop end. divup(p[]); // compute the final solution plot([u1,u2],p,wait=1,value=true,coef=0.1); 230 CHAPTER 9. MATHEMATICAL MODELS 9.6.3 NSUzawaCahouetChabart.edp In this example we solve the Navier-Stokes equation, in the driven-cavity, with the Uzawa algorithm preconditioned by the Cahouet-Chabart method (see [31] for all the details). The idea of the preconditioner is that in a periodic domain, all differential operators commute and the Uzawa algorithm comes to solving the linear operator ∇.((αId + ν∆) −1 ∇, where Id is the identity operator. So the preconditioer suggested is α∆ −1 +νId. To implement this, we reuse the previous example, by including a file. Then we define the time step ∆t, viscosity, and new variational form and matrix. Example 9.24 (NSUzawaCahouetChabart.edp) include "StokesUzawa.edp" // include the Stokes part real dt=0.05, alpha=1/dt; // ∆t cout << " alpha = " << alpha; real xnu=1./400; // viscosity ν = Reynolds number −1 // the new variational form with mass term varf at(u1,u2)= int2d(Th)( xnu * dx(u1) * dx(u2) + xnu * dy(u1) * dy(u2) + u1 * u2 * alpha ) + on(1,2,4,u1=0) + on(3,u1=1) ; A = at(Xh,Xh,solver=CG); // change the matrix // set the 2 convect variational form varf vfconv1(uu,vv) = int2d(Th,qforder=5) (convect([u1,u2],-dt,u1) * vv * alpha); varf vfconv2(v2,v1) = int2d(Th,qforder=5) (convect([u1,u2],-dt,u2) * v1 * alpha); int idt; // index of time set real temps=0; // current time Mh pprec,prhs; varf vfMass(p,q) = int2d(Th)(p * q); matrix MassMh=vfMass(Mh,Mh,solver=CG); varf vfLap(p,q) = int2d(Th)(dx(pprec) * dx(q)+dy(pprec) * dy(q) + pprec * q * 1e-10); matrix LapMh= vfLap(Mh,Mh,solver=Cholesky); The function to define the preconditioner func real[int] CahouetChabart(real[int] & xx) { // xx = (divu)w i // αLapMh −1 +νMassMh −1 pprec[]= LapMhˆ-1 * xx; prhs[] = MassMhˆ-1 * xx; pprec[] = alpha * pprec[]+xnu * prhs[]; return pprec[]; }; The loop in time. Warning with the stop test of the conjugate gradient, because we start from the previous solution and the end the previous solution is close to the final solution, don’t take a relative stop test to the first residual, take an absolute stop test ( negative here) 9.7. VARIATIONAL INEQUALITY 231 for (idt = 1; idt < 50; idt++) { temps += dt; cout << " --------- temps " << temps << " \n "; b1[] = vfconv1(0,Xh); b2[] = vfconv2(0,Xh); cout << " min b1 b2 " << b1[].min << " " << b2[].min << endl; cout << " max b1 b2 " << b1[].max << " " << b2[].max << endl; // call Conjugate Gradient with preconditioner ’ // warning eps < 0 => absolue stop test LinearCG(divup,p[],eps=-1.e-6,nbiter=50,precon=CahouetChabart); divup(p[]); // computed the velocity plot([u1,u2],p,wait=!(idt%10),value= 1,coef=0.1); } IsoValue -0.0791073 -0.0611287 -0.0431501 -0.0251715 -0.00719285 0.0107858 0.0287644 0.046743 0.0647217 0.0827003 0.100679 0.118658 0.136636 0.154615 0.172593 0.190572 0.208551 0.226529 0.244508 0.262487 Vec Value 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 [u1,u2],p || u^n+1 - u^n ]]_L2 =0.00149613 Figure 9.24: Solution of the cavity driven problem at Reynolds number 400 with the Cahouet- Chabart algorithm. 9.7 Variational inequality We present, a classical example of variational inequality. Let us denote ( = ¦u ∈ H 1 0 (Ω), u ≤ g¦ The problem is : u = arg min u∈C J(u) = 1 2 Ω ∇u.∇u − Ω fu where f and g are given function. 232 CHAPTER 9. MATHEMATICAL MODELS The solution is a projection on the convex ( of f for the scalar product ((v, w)) = Ω ∇v.∇w of H 1 0 (Ω) where f is solution of ((f , v)) = Ω fv, ∀v ∈ H 1 0 (Ω). The projection on a convex satisfy clearly ∀v ∈ (, ((u −v, u − ˜ f)) ≤ 0, and after expanding, we get the classical inequality ∀v ∈ (, Ω ∇(u −v)∇u ≤ Ω (u −v)f. We can also rewrite the problem as a saddle point problem Find λ, u such that: max λ∈L 2 (Ω),λ≥0 min u∈H 1 0 (Ω) /(u, λ) = 1 2 Ω ∇u.∇u − Ω fu + Ω λ(u −g) + where ((u −g) + = max(0, u −g) This saddle point problem is equivalent to find u, λ such that: Ω ∇u.∇v +λv + dω = Ω fu, ∀v ∈ H 1 0 (Ω) Ω µ(u −g) + = 0, ∀µ ∈ L 2 (Ω), µ ≥ 0, λ ≥ 0, (9.54) A algorithm to solve the previous problem is: 1. k=0, and choose, λ 0 belong H −1 (Ω) 2. loop on k = 0, ..... (a) set J k = ¦x ∈ Ω/λ k +c ∗ (u k+1 −g) ≤ 0¦ (b) V g,k+1 = ¦v ∈ H 1 0 (Ω)/v = g on I k ¦, (c) V 0,k+1 = ¦v ∈ H 1 0 (Ω)/v = 0 on I k ¦, (d) Find u k+1 ∈ V g,k+1 and λ k+1 ∈ H −1 (Ω) such that Ω ∇u k+1 .∇v k+1 dω = Ω fv k+1 , ∀v k+1 ∈ V 0,k+1 < λ k+1 , v >= Ω ∇u k+1 .∇v −fv dω where <, > is the duality bracket between H 1 0 (Ω) and H −1 (Ω), and c is a penalty constant (large enough). You can find all the mathematic about this algorithm in [33]. Now how to do that in FreeFem++ The full example is: Example 9.25 (VI.edp) mesh Th=square(20,20); real eps=1e-5; fespace Vh(Th,P1); // P1 FE space int n = Vh.ndof; // number of Degree of freedom Vh uh,uhp; // solution and previous one Vh Ik; // to def the set where the containt is reached. real[int] rhs(n); // to store the right and side of the equation real c=1000; // the penalty parameter of the algoritm 9.7. VARIATIONAL INEQUALITY 233 func f=1; // right hand side function func fd=0; // Dirichlet boundary condition function Vh g=0.05; // the discret function g real[int] Aii(n),Aiin(n); // to store the diagonal of the matrix 2 version real tgv = 1e30; // a huge value for exact penalization // of boundary condition // the variatonal form of the problem: varf a(uh,vh) = // definition of the problem int2d(Th)( dx(uh) * dx(vh) + dy(uh) * dy(vh) ) // bilinear form - int2d(Th)( f * vh ) // linear form + on(1,2,3,4,uh=fd) ; // boundary condition form // two version of the matrix of the problem matrix A=a(Vh,Vh,tgv=tgv,solver=CG); // one changing matrix AA=a(Vh,Vh,solver:GC); // one for computing residual // the mass Matrix construction: varf vM(uh,vh) = int2d(Th)(uh * vh); matrix M=vM(Vh,Vh); // to do a fast computing of L 2 norm : sqrt( u’ * (w=M * u)) Aii=A.diag; // get the diagonal of the matrix (appear in version 1.46-1) rhs = a(0,Vh,tgv=tgv); Ik =0; uhp=-tgv; // previous value is Vh lambda=0; for(int iter=0;iter<100;++iter) { real[int] b(n) ; b=rhs; // get a copy of the Right hand side real[int] Ak(n); // the complementary of Ik ( !Ik = (Ik-1)) // Today the operator Ik- 1. is not implement so we do: Ak= 1.; Ak -= Ik[]; // build Ak = ! Ik // adding new locking condition on b and on the diagonal if (Ik ==1 ) b = Ik[] . * g[]; b * = tgv; b -= Ak . * rhs; Aiin = Ik[] * tgv; Aiin += Ak . * Aii; // set Aii= tgv i ∈ Ik A.diag = Aiin; // set the matrix diagonal (appear in version 1.46-1) set(A,solver=CG); // important to change preconditioning for solving uh[] = Aˆ-1 * b; // solve the problem with more locking condition lambda[] = AA * uh[]; // compute the residual ( fast with matrix) lambda[] += rhs; // remark rhs = − fv Ik = ( lambda + c * ( g- uh)) < 0.; // the new of locking value plot(Ik, wait=1,cmm=" lock set ",value=1,ps="VI-lock.eps",fill=1 ); plot(uh,wait=1,cmm="uh",ps="VI-uh.eps"); // trick to compute L 2 norm of the variation (fast method) real[int] diff(n),Mdiff(n); diff= uh[]-uhp[]; Mdiff = M * diff; real err = sqrt(Mdiff’ * diff); cout << " || u_{k=1} - u_{k} ||_2 " << err << endl; if(err< eps) break; // stop test 234 CHAPTER 9. MATHEMATICAL MODELS uhp[]=uh[] ; // set the previous solution } savemesh(Th,"mm",[x,y,uh * 10]); // for medit plotting Remark, as you can see on this example, some vector , or matrix operator are not implemented so a way is to skip the expression and we use operator +=, -= to merge the result. 9.8 Domain decomposition We present, three classic examples, of domain decomposition technique: first, Schwarz algorithm with overlapping, second Schwarz algorithm without overlapping (also call Shur complement), and last we show to use the conjugate gradient to solve the boundary problem of the Shur complement. 9.8.1 Schwarz Overlap Scheme To solve −∆u = f, in Ω = Ω 1 ∪ Ω 2 u[ Γ = 0 the Schwarz algorithm runs like this −∆u n+1 1 = f in Ω 1 u n+1 1 [ Γ 1 = u n 2 −∆u n+1 2 = f in Ω 2 u n+1 2 [ Γ 2 = u n 1 where Γ i is the boundary of Ω i and on the condition that Ω 1 ∩ Ω 2 = ∅ and that u i are zero at iteration 1. Here we take Ω 1 to be a quadrangle, Ω 2 a disk and we apply the algorithm starting from zero. Figure 9.25: The 2 overlapping mesh TH and th Example 9.26 (Schwarz-overlap.edp) int inside = 2; // inside boundary int outside = 1; // outside boundary border a(t=1,2){x=t;y=0;label=outside;}; border b(t=0,1){x=2;y=t;label=outside;}; 9.8. DOMAIN DECOMPOSITION 235 border c(t=2,0){x=t ;y=1;label=outside;}; border d(t=1,0){x = 1-t; y = t;label=inside;}; border e(t=0, pi/2){ x= cos(t); y = sin(t);label=inside;}; border e1(t=pi/2, 2 * pi){ x= cos(t); y = sin(t);label=outside;}; int n=4; mesh th = buildmesh( a(5 * n) + b(5 * n) + c(10 * n) + d(5 * n)); mesh TH = buildmesh( e(5 * n) + e1(25 * n) ); plot(th,TH,wait=1); // to see the 2 meshes The space and problem definition is : fespace vh(th,P1); fespace VH(TH,P1); vh u=0,v; VH U,V; int i=0; problem PB(U,V,init=i,solver=Cholesky) = int2d(TH)( dx(U) * dx(V)+dy(U) * dy(V) ) + int2d(TH)( -V) + on(inside,U = u) + on(outside,U= 0 ) ; problem pb(u,v,init=i,solver=Cholesky) = int2d(th)( dx(u) * dx(v)+dy(u) * dy(v) ) + int2d(th)( -v) + on(inside ,u = U) + on(outside,u = 0 ) ; The calculation loop: for ( i=0 ;i< 10; i++) { PB; pb; plot(U,u,wait=true); }; Figure 9.26: Isovalues of the solution at iteration 0 and iteration 9 236 CHAPTER 9. MATHEMATICAL MODELS Figure 9.27: The two none overlapping mesh TH and th 9.8.2 Schwarz non Overlap Scheme To solve −∆u = f in Ω = Ω 1 ∪ Ω 2 u[ Γ = 0, the Schwarz algorithm for domain decomposition without overlapping runs like this Let introduce Γ i is common the boundary of Ω 1 and Ω 2 and Γ i e = ∂Ω i ` Γ i . The problem find λ such that (u 1 [ Γ i = u 2 [ Γ i ) where u i is solution of the following Laplace problem: −∆u i = f in Ω i u i [ Γ i = λ u i [ Γ i e = 0 To solve this problem we just make a loop with upgradingλ with λ = λ± (u 1 −u 2 ) 2 where the sign + or − of ± is choose to have convergence. Example 9.27 (Schwarz-no-overlap.edp) // schwarz1 without overlapping int inside = 2; int outside = 1; border a(t=1,2){x=t;y=0;label=outside;}; border b(t=0,1){x=2;y=t;label=outside;}; border c(t=2,0){x=t ;y=1;label=outside;}; border d(t=1,0){x = 1-t; y = t;label=inside;}; border e(t=0, 1){ x= 1-t; y = t;label=inside;}; border e1(t=pi/2, 2 * pi){ x= cos(t); y = sin(t);label=outside;}; int n=4; mesh th = buildmesh( a(5 * n) + b(5 * n) + c(10 * n) + d(5 * n)); mesh TH = buildmesh ( e(5 * n) + e1(25 * n) ); plot(th,TH,wait=1,ps="schwarz-no-u.eps"); fespace vh(th,P1); fespace VH(TH,P1); vh u=0,v; VH U,V; vh lambda=0; 9.8. DOMAIN DECOMPOSITION 237 int i=0; problem PB(U,V,init=i,solver=Cholesky) = int2d(TH)( dx(U) * dx(V)+dy(U) * dy(V) ) + int2d(TH)( -V) + int1d(TH,inside)(lambda * V) + on(outside,U= 0 ) ; problem pb(u,v,init=i,solver=Cholesky) = int2d(th)( dx(u) * dx(v)+dy(u) * dy(v) ) + int2d(th)( -v) + int1d(th,inside)(-lambda * v) + on(outside,u = 0 ) ; for ( i=0 ;i< 10; i++) { PB; pb; lambda = lambda - (u-U)/2; plot(U,u,wait=true); }; plot(U,u,ps="schwarz-no-u.eps"); Figure 9.28: Isovalues of the solution at iteration 0 and iteration 9 without overlapping 9.8.3 Schwarz-gc.edp To solve −∆u = f in Ω = Ω 1 ∪ Ω 2 u[ Γ = 0, the Schwarz algorithm for domain decomposition without overlapping runs like this Let introduce Γ i is common the boundary of Ω 1 and Ω 2 and Γ i e = ∂Ω i ` Γ i . The problem find λ such that (u 1 [ Γ i = u 2 [ Γ i ) where u i is solution of the following Laplace problem: −∆u i = f in Ω i u i [ Γ i = λ u i [ Γ i e = 0 238 CHAPTER 9. MATHEMATICAL MODELS The version of this example for Shur componant. The border problem is solve with conjugate gradient. First, we construct the two domain Example 9.28 (Schwarz-gc.edp) // Schwarz without overlapping (Shur complenement Neumann -> Dirichet) real cpu=clock(); int inside = 2; int outside = 1; border Gamma1(t=1,2){x=t;y=0;label=outside;}; border Gamma2(t=0,1){x=2;y=t;label=outside;}; border Gamma3(t=2,0){x=t ;y=1;label=outside;}; border GammaInside(t=1,0){x = 1-t; y = t;label=inside;}; border GammaArc(t=pi/2, 2 * pi){ x= cos(t); y = sin(t);label=outside;}; int n=4; // build the mesh of Ω 1 and Ω 2 mesh Th1 = buildmesh( Gamma1(5 * n) + Gamma2(5 * n) + GammaInside(5 * n) + Gamma3(5 * n)); mesh Th2 = buildmesh ( GammaInside(-5 * n) + GammaArc(25 * n) ); plot(Th1,Th2); // defined the 2 FE space fespace Vh1(Th1,P1), Vh2(Th2,P1); Note 9.6 It is impossible to define a function just on a part of boundary, so the lambda function must be defined on the all domain Ω 1 such as Vh1 lambda=0; // take λ ∈ V h1 The two Poisson problem: Vh1 u1,v1; Vh2 u2,v2; int i=0; // for factorization optimization problem Pb2(u2,v2,init=i,solver=Cholesky) = int2d(Th2)( dx(u2) * dx(v2)+dy(u2) * dy(v2) ) + int2d(Th2)( -v2) + int1d(Th2,inside)(-lambda * v2) + on(outside,u2= 0 ) ; problem Pb1(u1,v1,init=i,solver=Cholesky) = int2d(Th1)( dx(u1) * dx(v1)+dy(u1) * dy(v1) ) + int2d(Th1)( -v1) + int1d(Th1,inside)(+lambda * v1) + on(outside,u1 = 0 ) ; or, we define a border matrix , because the lambda function is none zero inside the domain Ω 1 : varf b(u2,v2,solver=CG) =int1d(Th1,inside)(u2 * v2); matrix B= b(Vh1,Vh1,solver=CG); The boundary problem function, λ −→ Γ i (u 1 −u 2 )v 1 9.9. FLUID/STRUCTURES COUPLED PROBLEM 239 func real[int] BoundaryProblem(real[int] &l) { lambda[]=l; // make FE function form l Pb1; Pb2; i++; // no refactorization i !=0 v1=-(u1-u2); lambda[]=B * v1[]; return lambda[] ; }; Note 9.7 The difference between the two notations v1 and v1[] is: v1 is the finite element function and v1[] is the vector in the canonical basis of the finite element function v1 . Vh1 p=0,q=0; // solve the problem with Conjugate Gradient LinearCG(BoundaryProblem,p[],eps=1.e-6,nbiter=100); // compute the final solution, because CG works with increment BoundaryProblem(p[]); // solve again to have right u1,u2 cout << " -- CPU time schwarz-gc:" << clock()-cpu << endl; plot(u1,u2); // plot 9.9 Fluid/Structures Coupled Problem This problem involves the Lam´e system of elasticity and the Stokes system for viscous fluids with velocity u and pressure p: −∆u +∇p = 0, ∇ u = 0, in Ω, u = u Γ on Γ = ∂Ω where u Γ is the velocity of the boundaries. The force that the fluid applies to the boundaries is the normal stress h = (∇u +∇u T )n −pn Elastic solids subject to forces deform: a point in the solid, at (x,y) goes to (X,Y) after. When the displacement vector v = (v 1 , v 2 ) = (X −x, Y −y) is small, Hooke’s law relates the stress tensor σ inside the solid to the deformation tensor : σ ij = λδ ij ∇.v + 2µ ij , ij = 1 2 ( ∂v i ∂x j + ∂v j ∂x i ) where δ is the Kronecker symbol and where λ, µ are two constants describing the material me- chanical properties in terms of the modulus of elasticity, and Young’s modulus. The equations of elasticity are naturally written in variational form for the displacement vector v(x) ∈ V as Ω [2µ ij (v) ij (w) +λ ii (v) jj (w)] = Ω g w + Γ h w, ∀w ∈ V The data are the gravity force g and the boundary stress h. 240 CHAPTER 9. MATHEMATICAL MODELS Example 9.29 (fluidStruct.edp) In our example the Lam´e system and the Stokes system are coupled by a common boundary on which the fluid stress creates a displacement of the boundary and hence changes the shape of the domain where the Stokes problem is integrated. The geometry is that of a vertical driven cavity with an elastic lid. The lid is a beam with weight so it will be deformed by its own weight and by the normal stress due to the fluid reaction. The cavity is the 10 10 square and the lid is a rectangle of height l = 2. A beam sits on a box full of fluid rotating because the left vertical side has velocity one. The beam is bent by its own weight, but the pressure of the fluid modifies the bending. The bending displacement of the beam is given by (uu,vv) whose solution is given as follows. // Fluid-structure interaction for a weighting beam sitting on a // square cavity filled with a fluid. int bottombeam = 2; // label of bottombeam border a(t=2,0) { x=0; y=t ;label=1;}; // left beam border b(t=0,10) { x=t; y=0 ;label=bottombeam;}; // bottom of beam border c(t=0,2) { x=10; y=t ;label=1;}; // rigth beam border d(t=0,10) { x=10-t; y=2; label=3;}; // top beam real E = 21.5; real sigma = 0.29; real mu = E/(2 * (1+sigma)); real lambda = E * sigma/((1+sigma) * (1-2 * sigma)); real gravity = -0.05; mesh th = buildmesh( b(20)+c(5)+d(20)+a(5)); fespace Vh(th,P1); Vh uu,w,vv,s,fluidforce=0; cout << "lambda,mu,gravity ="<<lambda<< " " << mu << " " << gravity << endl; // deformation of a beam under its own weight solve bb([uu,vv],[w,s]) = int2d(th)( lambda * div(w,s) * div(uu,vv) +2. * mu * ( epsilon(w,s)’ * epsilon(uu,vv) ) ) + int2d(th) (-gravity * s) + on(1,uu=0,vv=0) + fluidforce[]; ; plot([uu,vv],wait=1); mesh th1 = movemesh(th, [x+uu, y+vv]); plot(th1,wait=1); Then Stokes equation for fluids ast low speed are solved in the box below the beam, but the beam has deformed the box (see border h): // Stokes on square b,e,f,g driven cavite on left side g border e(t=0,10) { x=t; y=-10; label= 1; }; // bottom border f(t=0,10) { x=10; y=-10+t ; label= 1; }; // right border g(t=0,10) { x=0; y=-t ;label= 2;}; // left border h(t=0,10) { x=t; y=vv(t,0) * ( t>=0.001 ) * (t <= 9.999); label=3;}; // top of cavity deformed mesh sh = buildmesh(h(-20)+f(10)+e(10)+g(10)); plot(sh,wait=1); 9.9. FLUID/STRUCTURES COUPLED PROBLEM 241 We use the Uzawa conjugate gradient to solve the Stokes problem like in example Section 9.6.2 fespace Xh(sh,P2),Mh(sh,P1); Xh u1,u2,v1,v2; Mh p,q,ppp; varf bx(u1,q) = int2d(sh)( -(dx(u1) * q)); varf by(u1,q) = int2d(sh)( -(dy(u1) * q)); varf Lap(u1,u2)= int2d(sh)( dx(u1) * dx(u2) + dy(u1) * dy(u2) ) + on(2,u1=1) + on(1,3,u1=0) ; Xh bc1; bc1[] = Lap(0,Xh); Xh brhs; matrix A= Lap(Xh,Xh,solver=CG); matrix Bx= bx(Xh,Mh); matrix By= by(Xh,Mh); Xh bcx=0,bcy=1; func real[int] divup(real[int] & pp) { int verb=verbosity; verbosity=0; brhs[] = Bx’ * pp; brhs[] += bc1[] . * bcx[]; u1[] = Aˆ-1 * brhs[]; brhs[] = By’ * pp; brhs[] += bc1[] . * bcy[]; u2[] = Aˆ-1 * brhs[]; ppp[] = Bx * u1[]; ppp[] += By * u2[]; verbosity=verb; return ppp[] ; }; do a loop on the two problem for(step=0;step<2;++step) { p=0;q=0;u1=0;v1=0; LinearCG(divup,p[],eps=1.e-3,nbiter=50); divup(p[]); Now the beam will feel the stress constraint from the fluid: Vh sigma11,sigma22,sigma12; Vh uu1=uu,vv1=vv; sigma11([x+uu,y+vv]) = (2 * dx(u1)-p); sigma22([x+uu,y+vv]) = (2 * dy(u2)-p); sigma12([x+uu,y+vv]) = (dx(u1)+dy(u2)); which comes as a boundary condition to the PDE of the beam: 242 CHAPTER 9. MATHEMATICAL MODELS IsoValue -2.62541 -2.26528 -1.90515 -1.54503 -1.1849 -0.824776 -0.46465 -0.104524 0.255603 0.615729 0.975855 1.33598 1.69611 2.05623 2.41636 2.77649 3.13661 3.49674 3.85686 4.21699 Vec Value 0 0.0499861 0.0999722 0.149958 0.199944 0.249931 0.299917 0.349903 0.399889 0.449875 0.499861 0.549847 0.599833 0.649819 0.699806 0.749792 0.799778 0.849764 0.89975 0.949736 [u1,u2],p Figure 9.29: Fluid velocity and pressure (left) and displacement vector (center) of the structure and displaced geometry (right) in the fluid-structure interaction of a soft side and a driven cavity solve bbst([uu,vv],[w,s],init=i) = int2d(th)( lambda * div(w,s) * div(uu,vv) +2. * mu * ( epsilon(w,s)’ * epsilon(uu,vv) ) ) + int2d(th) (-gravity * s) + int1d(th,bottombeam)( -coef * ( sigma11 * N.x * w + sigma22 * N.y * s + sigma12 * (N.y * w+N.x * s) ) ) + on(1,uu=0,vv=0); plot([uu,vv],wait=1); real err = sqrt(int2d(th)( (uu-uu1)ˆ2 + (vv-vv1)ˆ2 )); cout << " Erreur L2 = " << err << "----------\n"; Notice that the matrix generated by bbst is reused (see init=i). Finally we deform the beam th1 = movemesh(th, [x+0.2 * uu, y+0.2 * vv]); plot(th1,wait=1); } // end of loop 9.10 Transmission Problem Consider an elastic plate whose displacement change vertically, which is made up of three plates of different materials, welded on each other. Let Ω i , i = 1, 2, 3 be the domain occupied by i-th material with tension µ i (see Section 9.1.1). The computational domain Ω is the interior of Ω 1 ∪ Ω 2 ∪ Ω 3 . The vertical displacement u(x, y) is obtained from −µ i ∆u = f in Ω i (9.55) µ i ∂ n u[ Γ i = −µ j ∂ n u[ Γ j on Ω i ∩ Ω j if 1 ≤ i < j ≤ 3 (9.56) 9.10. TRANSMISSION PROBLEM 243 where ∂ n u[ Γ i denotes the value of the normal derivative ∂ n u on the boundary Γ i of the domain Ω i . By introducing the characteristic function χ i of Ω i , that is, χ i (x) = 1 if x ∈ Ω i ; χ i (x) = 0 if x ∈ Ω i (9.57) we can easily rewrite (9.55) and (9.56) to the weak form. Here we assume that u = 0 on Γ = ∂Ω. problem Transmission: For a given function f, find u such that a(u, v) = (f, v) for all v ∈ H 1 0 (Ω) (9.58) a(u, v) = Ω µ∇u ∇v, (f, v) = Ω fv where µ = µ 1 χ 1 +µ 2 χ 2 +µ 3 χ 3 . Here we notice that µ become the discontinuous function. With dissipation, and at the thermal equilibrium, the temperature equation is: This example explains the definition and manipulation of region, i.e. subdomains of the whole domain. Consider this L-shaped domain with 3 diagonals as internal boundaries, defining 4 subdomains: // example using region keyword // construct a mesh with 4 regions (sub-domains) border a(t=0,1){x=t;y=0;}; border b(t=0,0.5){x=1;y=t;}; border c(t=0,0.5){x=1-t;y=0.5;}; border d(t=0.5,1){x=0.5;y=t;}; border e(t=0.5,1){x=1-t;y=1;}; border f(t=0,1){x=0;y=1-t;}; // internal boundary border i1(t=0,0.5){x=t;y=1-t;}; border i2(t=0,0.5){x=t;y=t;}; border i3(t=0,0.5){x=1-t;y=t;}; mesh th = buildmesh (a(6) + b(4) + c(4) +d(4) + e(4) + f(6)+i1(6)+i2(6)+i3(6)); fespace Ph(th,P0); // constant discontinuous functions / element fespace Vh(th,P1); // P 1 continuous functions / element Ph reg=region; // defined the P 0 function associated to region number plot(reg,fill=1,wait=1,value=1); region is a keyword of FreeFem++ which is in fact a variable depending of the current position (is not a function today, use Ph reg=region; to set a function). This variable value returned is the number of the subdomain of the current position. This number is defined by ”buildmesh” which scans while building the mesh all its connected component. So to get the number of a region containing a particular point one does: int nupper=reg(0.4,0.9); // get the region number of point (0.4,0.9) int nlower=reg(0.9,0.1); // get the region number of point (0.4,0.1) cout << " nlower " << nlower << ", nupper = " << nupper<< endl; // defined the characteristics functions of upper and lower region Ph nu=1+5 * (region==nlower) + 10 * (region==nupper); plot(nu,fill=1,wait=1); This is particularly useful to define discontinuous functions such as might occur when one part of the domain is copper and the other one is iron, for example. 244 CHAPTER 9. MATHEMATICAL MODELS IsoValue -0.315789 0.157895 0.473684 0.789474 1.10526 1.42105 1.73684 2.05263 2.36842 2.68421 3 3.31579 3.63158 3.94737 4.26316 4.57895 4.89474 5.21053 5.52632 6.31579 Figure 9.30: the function reg IsoValue 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Figure 9.31: the function nu We this in mind we proceed to solve a Laplace equation with discontinuous coefficients (ν is 1, 6 and 11 below). Ph nu=1+5 * (region==nlower) + 10 * (region==nupper); plot(nu,fill=1,wait=1); problem lap(u,v) = int2d(th)( nu * ( dx(u) * dx(v) * dy(u) * dy(v) )) + int2d(-1 * v) + on(a,b,c,d,e,f,u=0); plot(u); 9.11. FREE BOUNDARY PROBLEM 245 IsoValue 0.000900259 0.00270078 0.0045013 0.00630181 0.00810233 0.00990285 0.0117034 0.0135039 0.0153044 0.0171049 0.0189054 0.020706 0.0225065 0.024307 0.0261075 0.027908 0.0297086 0.0315091 0.0333096 0.0351101 Figure 9.32: the isovalue of the solution u 9.11 Free Boundary Problem The domain Ω is defined with: real L=10; // longueur du domaine real h=2.1; // hauteur du bord gauche real h1=0.35; // hauteur du bord droite // maillage d’un tapeze border a(t=0,L){x=t;y=0;}; // bottom: Γ a border b(t=0,h1){x=L;y=t;}; // right: Γ b border f(t=L,0){x=t;y=t * (h1-h)/L+h;}; // free surface: Γ f border d(t=h,0){x=0;y=t;}; // left: Γ d int n=4; mesh Th=buildmesh (a(10 * n)+b(6 * n)+f(8 * n)+d(3 * n)); plot(Th,ps="dTh.eps"); Figure 9.33: The mesh of the domain Ω The free boundary problem is: Find u and Ω such that: 246 CHAPTER 9. MATHEMATICAL MODELS −∆u = 0 in Ω u = y on Γ b ∂u ∂n = 0 on Γ d ∪ Γ a ∂u ∂n = q K n x and u = y on Γ f We use a fixed point method; Ω 0 = Ω in two step, fist we solve the classical following problem: −∆u = 0 in Ω n u = y on Γ n b ∂u ∂n = 0 on Γ n d ∪ Γ n a u = y on Γ n f The variational formulation is: find u on V = H 1 (Ω n ), such than u = y on Γ n b and Γ n f Ω n ∇u∇u = 0, ∀u ∈ V with u = 0 on Γ n b ∪ Γ n f and secondly to construct a domain deformation T(x, y) = [x, y −v(x, y)] where v is solution of the following problem: −∆v = 0 in Ω n v = 0 on Γ n a ∂v ∂n = 0 on Γ n b ∪ Γ n d ∂v ∂n = ∂u ∂n − q K n x on Γ n f The variational formulation is: find v on V , such than v = 0 on Γ n a Ω n ∇v∇v = Γ n f ( ∂u ∂n − q K n x )v , ∀v ∈ V with v = 0 on Γ n a Finally the new domain Ω n+1 = T(Ω n ) Example 9.30 (freeboundary.edp) The FreeFem++ :implementation is: real q=0.02; // flux entrant real K=0.5; // permeabilit´ e fespace Vh(Th,P1); int j=0; Vh u,v,uu,vv; problem Pu(u,uu,solver=CG) = int2d(Th)( dx(u) * dx(uu)+dy(u) * dy(uu)) + on(b,f,u=y) ; problem Pv(v,vv,solver=CG) = int2d(Th)( dx(v) * dx(vv)+dy(v) * dy(vv)) + on (a, v=0) + int1d(Th,f)(vv * ((q/K) * N.y- (dx(u) * N.x+dy(u) * N.y))); 9.11. FREE BOUNDARY PROBLEM 247 real errv=1; real erradap=0.001; verbosity=1; while(errv>1e-6) { j++; Pu; Pv; plot(Th,u,v ,wait=0); errv=int1d(Th,f)(v * v); real coef=1; // real mintcc = checkmovemesh(Th,[x,y])/5.; real mint = checkmovemesh(Th,[x,y-v * coef]); if (mint<mintcc || j%10==0) { // mesh to bad => remeshing Th=adaptmesh(Th,u,err=erradap ) ; mintcc = checkmovemesh(Th,[x,y])/5.; } while (1) { real mint = checkmovemesh(Th,[x,y-v * coef]); if (mint>mintcc) break; cout << " min |T] " << mint << endl; coef /= 1.5; } Th=movemesh(Th,[x,y-coef * v]); // calcul de la deformation cout << "\n\n"<<j <<"------------ errv = " << errv << "\n\n"; } plot(Th,ps="d_Thf.eps"); plot(u,wait=1,ps="d_u.eps"); Figure 9.34: The final solution on the new domain Ω 72 248 CHAPTER 9. MATHEMATICAL MODELS Figure 9.35: The adapted mesh of the domain Ω 72 9.12 Non linear Elasticity (nolinear-elas.edp) The nonlinear elasticity problem is: find the displacement (u 1 , u 2 ) minimizing J min J(u 1 , u 2 ) = Ω f(F2) − Γ p P a u 2 where F2(u 1 , u 2 ) = A(E[u 1 , u 2 ], E[u 1 , u 2 ]) and A(X, Y ) is bilinear sym. positive form with respect two matrix X, Y . where f is a given ( 2 function, and E[u 1 , u 2 ] = (E ij ) i=1,2, j=1,2 is the Green-Saint Venant deformation tensor defined with: E ij = 0.5(∂ i u j +∂ j u i ) + ¸ k ∂ i u k ∂ j u k Denote u = (u 1 , u 2 ), v = (v 1 , v 2 ), w = (w 1 , w 2 ). So, the differential of J is DJ(u)(v) = DF2(u)(v) f (F2(u))) − Γ p P a v 2 where DF2(u)(v) = 2 A( DE[u](v) , E[u] ) and DE is the first differential of E. The second order differential is D 2 J(u)((v), (w)) = DF2(u)(v) DF2(u)(w) f (F2(u))) + D 2 F2(u)(v, w) f (F2(u))) where D 2 F2(u)(v, w) = 2 A( D 2 E[u](v, w) , E[u] ) + 2 A( DE[u](v) , DE[u](w) ). and D 2 E is the second differential of E. So all notations can be define with macros: macro EL(u,v) [dx(u),(dx(v)+dy(u)),dy(v)] // is [ 11 , 2 12 , 22 ] macro ENL(u,v) [ (dx(u) * dx(u)+dx(v) * dx(v)) * 0.5, (dx(u) * dy(u)+dx(v) * dy(v)) , (dy(u) * dy(u)+dy(v) * dy(v)) * 0.5 ] // EOM ENL macro dENL(u,v,uu,vv) [(dx(u) * dx(uu)+dx(v) * dx(vv)), (dx(u) * dy(uu)+dx(v) * dy(vv)+dx(uu) * dy(u)+dx(vv) * dy(v)), 9.12. NON LINEAR ELASTICITY (NOLINEAR-ELAS.EDP) 249 (dy(u) * dy(uu)+dy(v) * dy(vv)) ] // macro E(u,v) (EL(u,v)+ENL(u,v)) // is [E 11 , 2E 12 , E 22 ] macro dE(u,v,uu,vv) (EL(uu,vv)+dENL(u,v,uu,vv)) // macro ddE(u,v,uu,vv,uuu,vvv) dENL(uuu,vvv,uu,vv) // macro F2(u,v) (E(u,v)’ * A * E(u,v)) // macro dF2(u,v,uu,vv) (E(u,v)’ * A * dE(u,v,uu,vv) * 2. ) // macro ddF2(u,v,uu,vv,uuu,vvv) ( (dE(u,v,uu,vv)’ * A * dE(u,v,uuu,vvv)) * 2. + (E(u,v)’ * A * ddE(u,v,uu,vv,uuu,vvv)) * 2. ) // EOM The Newton Method is choose n = 0,and u O , v O the initial displacement • loop: • find (du, dv) : solution of D 2 J(u n , v n )((w, s), (du, dv)) = DJ(u n , v n )(w, s), ∀w, s • un = un −du, vn = vn −dv • until (du, dv) small is enough The way to implement this algorithm in FreeFem++ is use a macro tool to implement A and F2, f, f ,f . A macro is like in ccp preprocessor of C++ , but this begin by macro and the end of the macro definition is before the comment //. In this case the macro is very useful because the type of parameter can be change. And it is easy to make automatic differentiation. Figure 9.36: The deformed domain // non linear elasticity model // for hyper elasticity problem // ----------------------------- macro f(u) (u) // end of macro macro df(u) (1) // end of macro macro ddf(u) (0) // end of macro // -- du caouchouc --- (see the notes of Herve Le Dret.) // ------------------------------- 250 CHAPTER 9. MATHEMATICAL MODELS real mu = 0.012e5; // kg/cm 2 real lambda = 0.4e5; // kg/cm 2 // // σ = 2µE +λtr(E)Id // A(u, v) = σ(u) : E(v) // // ( a b ) // ( b c ) // // tr * Id : (a,b,c) -> (a+c,0,a+c) // so the associed matrix is: // ( 1 0 1 ) // ( 0 0 0 ) // ( 1 0 1 ) // ------------------v real a11= 2 * mu + lambda ; real a22= mu ; // because [0, 2 ∗ t12, 0] A[0, 2 ∗ s12, 0] = // = 2 ∗ mu ∗ (t12 ∗ s12 +t21 ∗ s21) = 4 ∗ mu ∗ t12 ∗ s12 real a33= 2 * mu + lambda ; real a12= 0 ; real a13= lambda ; real a23= 0 ; // symetric part real a21= a12 ; real a31= a13 ; real a32= a23 ; // the matrix A. func A = [ [ a11,a12,a13],[ a21,a22,a23],[ a31,a32,a33] ]; real Pa=1e2; // a pressure of 100 Pa // ---------------- int n=30,m=10; mesh Th= square(n,m,[x,.3 * y]); // label: 1 bottom, 2 right, 3 up, 4 left; int bottom=1, right=2,upper=3,left=4; plot(Th); fespace Wh(Th,P1dc); fespace Vh(Th,[P1,P1]); fespace Sh(Th,P1); Wh e2,fe2,dfe2,ddfe2; // optimisation Wh ett,ezz,err,erz; // optimisation Vh [uu,vv], [w,s],[un,vn]; [un,vn]=[0,0]; // intialisation [uu,vv]=[0,0]; 9.13. COMPRESSIBLE NEO-HOOKEAN MATERIALS: COMPUTATIONAL SOLUTIONS251 varf vmass([uu,vv],[w,s],solver=CG) = int2d(Th)( uu * w + vv * s ); matrix M=vmass(Vh,Vh); problem NonLin([uu,vv],[w,s],solver=LU)= int2d(Th,qforder=1)( // (D 2 J(un)) part dF2(un,vn,uu,vv) * dF2(un,vn,w,s) * ddfe2 + ddF2(un,vn,w,s,uu,vv) * dfe2 ) - int1d(Th,3)(Pa * s) - int2d(Th,qforder=1)( // (DJ(un)) part dF2(un,vn,w,s) * dfe2 ) + on(right,left,uu=0,vv=0); ; // Newton’s method // --------------- Sh u1,v1; for (int i=0;i<10;i++) { cout << "Loop " << i << endl; e2 = F2(un,vn); dfe2 = df(e2) ; ddfe2 = ddf(e2); cout << " e2 max " <<e2[].max << " , min" << e2[].min << endl; cout << " de2 max "<< dfe2[].max << " , min" << dfe2[].min << endl; cout << "dde2 max "<< ddfe2[].max << " , min" << ddfe2[].min << endl; NonLin; // compute [uu, vv] = (D 2 J(un)) −1 (DJ(un)) w[] = M * uu[]; real res = sqrt(w[]’ * uu[]); // norme L 2 of[uu, vv] u1 = uu; v1 = vv; cout << " Lˆ2 residual = " << res << endl; cout << " u1 min =" <<u1[].min << ", u1 max= " << u1[].max << endl; cout << " v1 min =" <<v1[].min << ", v2 max= " << v1[].max << endl; plot([uu,vv],wait=1,cmm=" uu, vv " ); un[] -= uu[]; plot([un,vn],wait=1,cmm=" displacement " ); if (res<1e-5) break; } plot([un,vn],wait=1); mesh th1 = movemesh(Th, [x+un, y+vn]); plot(th1,wait=1); // see figure 9.36 9.13 Compressible Neo-Hookean Materials: Computational Solutions Author : Alex Sadovsky [email protected] 252 CHAPTER 9. MATHEMATICAL MODELS 9.13.1 Notation In what follows, the symbols u, F, B, C, σ denote, respectively, the displacement field, the deforma- tion gradient, the left Cauchy-Green strain tensor B = FF T , the right Cauchy-Green strain tensor C = F T F, and the Cauchy stress tensor. We also introduce the symbols I 1 := tr C and J := det F. Use will be made of the identity ∂J ∂C = JC −1 (9.59) The symbol I denotes the identity tensor. The symbol Ω 0 denotes the reference configuration of the body to be deformed. The unit volume in the reference (resp., deformed) configuration is denoted dV (resp., dV 0 ); these two are related by dV = JdV 0 , which allows an integral over Ω involving the Cauchy stress T to be rewritten as an integral of the Kirchhoff stress κ = JT over Ω 0 . Recommended References For an exposition of nonlinear elasticity and of the underlying linear- and tensor algebra, see [34]. For an advanced mathematical analysis of the Finite Element Method, see [35]. An explanation of the Finite Element formulation of a nonlinear elastostatic boundary value problem, see http:// www.engin.brown.edu/courses/en222/Notes/FEMfinitestrain/FEMfinitestrain. htm. 9.13.2 A Neo-Hookean Compressible Material Constitutive Theory and Tangent Stress Measures The strain energy density function is given by W = µ 2 (I 1 −tr I −2 ln J) (9.60) (see [32], formula (12)). The corresponding 2nd Piola-Kirchoff stress tensor is given by S n := ∂W ∂E (F n ) = µ(I −C −1 ) (9.61) The Kirchhoff stress, then, is κ = FSF T = µ(B−I) (9.62) The tangent Kirchhoff stress tensor at F n acting on δF n+1 is, consequently, ∂κ ∂F (F n )δF n+1 = µ F n (δF n+1 ) T +δF n+1 (F n ) T (9.63) The Weak Form of the BVP in the Absence of Body (External) Forces The Ω 0 we are considering is an elliptical annulus, whose boundary consists of two concentric ellipses (each allowed to be a circle as a special case), with the major axes parallel. Let P denote the dead stress load (traction) on a portion ∂Ω t 0 (= the inner ellipse) of the boundary ∂Ω 0 . On the rest of the boundary, we prescribe zero displacement. 9.13. COMPRESSIBLE NEO-HOOKEAN MATERIALS: COMPUTATIONAL SOLUTIONS253 The weak formulation of the boundary value problem is 0 = Ω 0 κ[F] : ¸ (∇⊗w)(F) −1 ¸ − ∂Ω t 0 P ˆ N 0 ¸ For brevity, in the rest of this section we assume P = 0. The provided FreeFem++ code, however, does not rely on this assumption and allows for a general value and direction of P. Given a Newton approximation u n of the displacement field u satisfying the BVP, we seek the correction δu n+1 to obtain a better approximation u n+1 = u n +δu n+1 by solving the weak formulation 0 = Ω 0 κ[F n +δF n+1 ] : ¸ (∇⊗w)(F n +δF n+1 ) −1 ¸ − ∂Ω 0 P ˆ N 0 = Ω 0 κ[F n ] + ∂κ ∂F [F n ]δF n+1 ¸ : ¸ (∇⊗w)(F n +δF n+1 ) −1 ¸ = Ω 0 κ[F n ] + ∂κ ∂F [F n ]δF n+1 ¸ : ¸ (∇⊗w)(F −1 n +F −2 n δF n+1 ) ¸ = Ω 0 κ[F n ] : ¸ (∇⊗w)F −1 n ¸ − Ω 0 κ[F n ] : ¸ (∇⊗w)(F −2 n δF n+1 ) ¸ + Ω 0 ∂κ ∂F [F n ]δF n+1 ¸ : ¸ (∇⊗w)F −1 n ¸ for all test functions w, (9.64) where we have taken δF n+1 = ∇⊗δu n+1 Note: Contrary to standard notational use, the symbol δ here bears no variational context. By δ we mean simply an increment in the sense of Newton’s Method. The role of a variational virtual displacement here is played by w. 9.13.3 An Approach to Implementation in FreeFem++ The associated file is examples++-tutorial/nl-elast-neo-Hookean.edp. Introducing the code-like notation, where a string in <>’s is to be read as one symbol, the individual components of the tensor < TanK >:= ∂κ ∂F [F n ]δF n+1 (9.65) will be implemented as the macros < TanK11 >, < TanK12 >, . . .. The individual components of the tensor quantities D 1 := F n (δF n+1 ) T +δF n+1 (F n ) T , D 2 := F −T n δF n+1 , D 3 := (∇⊗w)F −2 n δF n+1 , and D 4 := (∇⊗w)F −1 n , will be implemented as the macros < d1Aux11 >, < d1Aux12 >, . . . , < d1Aux22 >, < d2Aux11 >, < d2Aux12 >, . . . , < d2Aux22 > < d3Aux11 >, < d3Aux12 >, . . . , < d3Aux22 > < d4Aux11 >, < d4Aux12 >, . . . , < d4Aux22 > , (9.66) 254 CHAPTER 9. MATHEMATICAL MODELS respectively. In the above notation, the tangent Kirchhoff stress term becomes ∂κ ∂F (F n ) δF n+1 = µ D 1 (9.67) while the weak BVP formulation acquires the form 0 = Ω 0 κ[F n ] : D 4 − Ω 0 κ[F n ] : D 3 + Ω 0 ∂κ ∂F [F n ]δF n+1 ¸ : D 4 for all test functions w (9.68) Chapter 10 MPI Parallel version A first attempt of parallelization of FreeFem++ is made here with mpi. An extended interface with MPI has been added to FreeFem++ version 3.5, (see the MPI documentation for the functionality of the language at http://www.mpi-forum.org/docs/mpi21-report.pdf). 10.1 MPI keywords The following keywords and concepts are used: mpiComm to defined a communication world mpiGroup to defined a group of processors in the communication world mpiRequest to defined a equest to wait for the end of the communication 10.2 MPI constants mpisize The total number of processes, mpirank the id-number of my current process in ¦0, ..., mpisize −1¦, mpiUndefined The MPI_Undefined constant, mpiAnySource The MPI_ANY_SOURCE constant, mpiCommWorld The MPI_COMM_WORLD constant , ... and all the keywords of MPI Op for the reduce operator: mpiMAX, mpiMIN, mpiSUM, mpiPROD, mpiLAND, mpiLOR, mpiLXOR, mpiBAND, mpiBXOR. 10.3 MPI Constructor int[int] proc1=[1,2,3],proc2=[0,4]; mpiGroup grp(procs); // set MPI Group to proc 1,2,3 in MPI COMM WORLD 255 256 CHAPTER 10. MPI PARALLEL VERSION mpiGroup grp1(comm,proc1); // set MPI Group to proc 1,2,3 in comm mpiGroup grp2(grp,proc2); // set MPI Group to grp union proc1 mpiComm comm=mpiCommWorld; // set a MPI Comm to MPI COMM WORLD mpiComm ncomm(mpiCommWorld,grp); // set the MPI Comm form grp // MPI COMM WORLD mpiComm ncomm(comm,color,key); // MPI_Comm_split(MPI_Comm comm, // int color, int key, MPI_Comm * ncomm) mpiComm nicomm(processor(local_comm,local_leader), processor(peer_comm,peer_leader),tag); // build MPI_INTERCOMM_CREATE(local_comm, local_leader, peer_comm, // remote_leader, tag, &nicomm) mpiComm ncomm(intercomm,hight) ; // build using // MPI_Intercomm_merge( intercomm, high, &ncomm) mpiRequest rq; // defined an MPI_Request mpiRequest[int] arq(10); // defined an array of 10 MPI_Request 10.4 MPI functions mpiSize(comm) ; // return the size of comm (int) mpiRank(comm) ; // return the rank in comm (int) processor(i) // return processor i with no Resquest in MPI_COMM_WORLD processor(mpiAnySource) // return processor any source // with no Resquest in MPI_COMM_WORLD processor(i,comm) // return processor i with no Resquest in comm processor(comm,i) // return processor i with no Resquest in comm processor(i,rq,comm) // return processor i with Resquest rq in comm processor(i,rq) // return processor i with Resquest rq in // MPI_COMM_WORLD processorblock(i) // return processor i in MPI_COMM_WORLD // in block mode for synchronously communication processorblock(mpiAnySource) // return processor any source // in MPI_COMM_WORLD in block mode for synchronously communication processorblock(i,comm) // return processor i in in comm in block mode mpiBarrier(comm) ; // do a MPI Barrier on communicator comm, mpiWait(rq); // wait on of Request, mpiWaitAll(arq); // wait add of Request array, mpiWtime() ; // return MPIWtime in second (real), mpiWtick() ; // return MPIWTick in second (real), where a processor is just a integer rank, pointer to a MPI_comm and pointer to a MPI_Request, and processorblock with a special MPI_Request. 10.5 MPI communicator operator int status; // to get the MPI status of send / recv processor(10) << a << b; // send a,b asynchronously to the process 1, processor(10) >> a >> b;// receive a,b synchronously from the process 10, broadcast(processor(10,comm),a); // broadcast from processor 10.6. SCHWARZ EXAMPLE IN PARALLEL 257 // of com to other comm processor status=Send( processor(10,comm) , a); // send synchronously Recv} // to the process 10 the data a status=Recv( processor(10,comm) , a); // receive synchronously // from the process 10 the data a; status=Isend( processor(10,comm) , a); // send asynchronously to // the process 10 , the data a without request status=Isend( processor(10,rq,comm) , a) ; // send asynchronously to to // the process 10, the data a with request status=Irecv( processor(10,rq) , a) ; // receive synchronously from // the process 10, the data a; status=Irecv( processor(10) , a) ; // Error // Error asynchronously without request . broadcast(processor(comm,a)); // Broadcast to all process of comm where the data type of a can be of type of int,real, complex, int[int], double[int], complex[int], int[int,int], double[int,int], complex[int,int], mesh, mesh3, mesh[int], mesh3[int], matrix, matrix<complex> processor(10,rq) << a ; // send asynchronously to the process 10 // the data a with request processor(10,rq) >> a ; // receive asynchronously from the process 10 // the data a with request If a,b are arrays or full matrices of int, real, or complex, we can use the following MPI functions: mpiAlltoall(a,b[,comm]) ; mpiAllgather(a,b[,comm]) ; mpiGather(a,b,processor(..) ) ; mpiScatter(a,b,processor(..)) ; mpiReduce(a,b,processor(..),mpiMAX) ; mpiAllReduce(a,b,comm, mpiMAX) ; mpiReduceScatter(a,b,comm, mpiMAX) ; See the examples++-mpi/essai.edp to test of all this functionality and Thank, to Guy-Antoine Atenekeng Kahou, for his help to code this interface. 10.6 Schwarz example in parallel This example is a rewritting of example schwarz-overlap in section 9.8.1. [examples++-mpi] Hecht%lamboot LAM 6.5.9/MPI 2 C++/ROMIO - Indiana University [examples++-mpi] hecht% mpirun -np 2 FreeFem++-mpi schwarz-c.edp // a new coding version c, methode de schwarz in parallele // with 2 proc. // ------------------------------- // F.Hecht december 2003 // ---------------------------------- // to test the broadcast instruction // and array of mesh 258 CHAPTER 10. MPI PARALLEL VERSION // add add the stop test // --------------------------------- if ( mpisize != 2 ) { cout << " sorry, number of processors !=2 " << endl; exit(1);} verbosity=3; int interior = 2; int exterior = 1; border a(t=1,2){x=t;y=0;label=exterior;}; border b(t=0,1){x=2;y=t;label=exterior;}; border c(t=2,0){x=t ;y=1;label=exterior;}; border d(t=1,0){x = 1-t; y = t;label=interior;}; border e(t=0, pi/2){ x= cos(t); y = sin(t);label=interior;}; border e1(t=pi/2, 2 * pi){ x= cos(t); y = sin(t);label=exterior;}; int n=4; mesh[int] Th(mpisize); if (mpirank == 0) Th[0] = buildmesh( a(5 * n) + b(5 * n) + c(10 * n) + d(5 * n)); else Th[1] = buildmesh ( e(5 * n) + e1(25 * n) ); broadcast(processor(0),Th[0]); broadcast(processor(1),Th[1]); fespace Vh(Th[mpirank],P1); fespace Vhother(Th[1-mpirank],P1); Vh u=0,v; Vhother U=0; int i=0; problem pb(u,v,init=i,solver=Cholesky) = int2d(Th[mpirank])( dx(u) * dx(v)+dy(u) * dy(v) ) - int2d(Th[mpirank])( v) + on(interior,u = U) + on(exterior,u= 0 ) ; for ( i=0 ;i< 20; i++) { cout << mpirank << " looP " << i << endl; pb; // send u to the other proc, receive in U processor(1-mpirank) << u[]; processor(1-mpirank) >> U[]; real err0,err1; err0 = int1d(Th[mpirank],interior)(square(U-u)) ; // send err0 to the other proc, receive in err1 processor(1-mpirank)<<err0; processor(1-mpirank)>>err1; real err= sqrt(err0+err1); cout <<" err = " << err << " err0 = " << err0 << ", err1 = " << err1 << endl; if(err<1e-3) break; }; if (mpirank==0) plot(u,U,ps="uU.eps"); 10.6. SCHWARZ EXAMPLE IN PARALLEL 259 10.6.1 True parallel Schwarz example This is a explanation of the two script examples++-mpi/MPIGMRES[2]D.edp, a Schwarz par- allel with a complexity almost independent of the number of process (with a coarse grid precondi- tioner). Thank to F. Nataf. To solve the following Poisson problem on domain Ω with boundary Γ in L 2 (Ω) : −∆u = f, in Ω, and u = g on Γ, where f and g are two given functions of L 2 (Ω) and of H 1 2 (Γ), Let introduce (π i ) i=1,..,N p a regular partition of the unity of Ω, q-e-d: π i ∈ ( 0 (Ω) : π i ≥ 0 and N p ¸ i=1 π i = 1. Denote Ω i the sub domain which is the support of π i function and also denote Γ i the boundary of Ω i . The parallel Schwarz method is Let = 0 the iterator and a initial guest u 0 respecting the boundary condition (i.e. u 0 |Γ = g). ∀i = 1.., N p : −∆u i = f, in Ω i , and u i = u on Γ i ` Γ, u i = g on Γ i ∩ Γ (10.1) u +1 = ¸ N p i=1 π i u i (10.2) After discretization with the Lagrange finite element method, with a compatible mesh T hi of Ω i , i. e., the exist a global mesh T h such that T hi is include in T h . Let us denote: • V hi the finite element space corresponding to domain Ω i , • A hi is the set of the degree of freedom σ k i , • A Γ i hi is the set of the degree of freedom of V hi on the boundary Γ i of Ω i , • σ k i (v h ) is the value the degree of freedom k, • V 0hi = ¦v h ∈ V hi : ∀k ∈ A Γ i hi , σ k i (v h ) = 0¦, • the conditional expression a ? b : c is defined like in C of C++ language by a?b : c ≡ if a is true then return b else return c . Remark we never use finite element space associated to the full domain Ω because it to expensive. We have to defined to operator to build the previous algorithm: We denote u h|i the restriction of u h on V hi , so the discrete problem on Ω i of problem (10.1) is find u hi ∈ V hi such that: where g k i is the value of g associated to the degree of freedom k ∈ A Γ i hi . In FreeFem++, it can be written has with U is the vector corresponding to u h|i and the vector U1 is the vector corresponding to u hi is the solution of: real[int] U1(Ui.n); 260 CHAPTER 10. MPI PARALLEL VERSION real[int] b= onG . * U; b = onG ? b : Bi ; U1 = Aiˆ-1 * b; where onG[i] = (i ∈ Γ i ` Γ)?1 : 0, and Bi the right of side of the problem, are defined by fespace Whi(Thi,P2); // def of the Finite element space. varf vPb(U,V)= int3d(Thi)(grad(U)’ * grad(V)) + int3d(Thi)(F * V) +on(1,U=g) + on(10,U=G); varf vPbon(U,V)=on(10,U=1)+on(1,U=0); matrix Ai = vPb(Whi,Whi,solver=sparsesolver); real[int] onG = vPbon(0,Whi); real[int] Bi=vPb(0,Whi); where the freefem++ label of Γ is 1 and the label of Γ i ` Γ is 10. To build the transfer/update part corresponding to (10.2) equation on process i, let us call njpart the number the neighborhood of domain of Ω i (i.e: π j is none 0 of Ω i ), we store in an array jpart of size njpart all this neighborhood. Let us introduce two array of matrix, Smj[j] to defined the vector to send from i to j a neighborhood process, and the matrix rMj[j] to after to reduce owith neighborhood j domain. So the tranfert and update part compute v i = π i u i + ¸ j∈J i π j u j and can be write the freefem++ function Update: func bool Update(real[int] &ui, real[int] &vi) { int n= jpart.n; for(int j=0;j<njpart;++j) Usend[j][]=sMj[j] * ui; mpiRequest[int] rq(n * 2); for (int j=0;j<n;++j) Irecv(processor(jpart[j],comm,rq[j ]), Ri[j][]); for (int j=0;j<n;++j) Isend(processor(jpart[j],comm,rq[j+n]), Si[j][]); for (int j=0;j<n * 2;++j) int k= mpiWaitAny(rq); // apply the unity local partition . vi = Pii * ui; // set to π i u i for(int j=0;j<njpart;++j) vi += rMj[j] * Vrecv[j][]; // add π j u j return true; } where the buffer are defined by: InitU(njpart,Whij,Thij,aThij,Usend) // defined the send buffer InitU(njpart,Whij,Thij,aThij,Vrecv) // defined the revc buffer with the following macro definition: macro InitU(n,Vh,Th,aTh,U) Vh[int] U(n); for(int j=0;j<n;++j) {Th=aTh[j]; U[j]=0;} // First gmres algorithm: you can easily accelerate the fixe point algorithm by using a parallel GMRES algorithm after the introduction the following affine / i operator sub domain Ω i . func real[int] DJ0(real[int]& U) { real[int] V(U.n) , b= onG . * U; b = onG ? b : Bi ; V = Aiˆ-1 * b; Update(V,U); 10.6. SCHWARZ EXAMPLE IN PARALLEL 261 V -= U; return V; } Where the parallel MPIGMRES or MPICG algorithm is just a simple way to solve in parallel the following A i x i = b i , i = 1, .., N p by just changing the dot product by reduce the local dot product of all process with the following MPI code: template<class R> R ReduceSum1(R s,MPI_Comm * comm) { R r=0; MPI_Allreduce( &s, &r, 1 ,MPI_TYPE<R>::TYPE(), MPI_SUM, * comm ); return r; } This is done in MPIGC dynamics library tool. Second gmres algorithm: Use scharwz algorithm as a preconditioner of basic GMRES method to solving the parallel problem. func real[int] DJ(real[int]& U) // the original problem { ++kiter; real[int] V(U.n); V = Ai * U; V = onGi ? 0.: V; // remove boundary term ... return V; } func real[int] PDJ(real[int]& U) // the preconditioner { real[int] V(U.n); real[int] b= onG ? 0. : U; V = Aiˆ-1 * b; Update(V,U); return U; } Third gmres algorithm: Add a coarse solver to the previous algorithm First build a coarse grid on processor 0, and the matrix AC,Rci,Pci; // if(mpiRank(comm)==0) AC = vPbC(VhC,VhC,solver=sparsesolver); // the corase problem Pci= interpolate(Whi,VhC); // the projection on coarse grid. Rci = Pci’ * Pii; // the Restiction on Process i grid with the partition π i func bool CoarseSolve(real[int]& V,real[int]& U,mpiComm& comm) { // solvibg the coarse probleme real[int] Uc(Rci.n),Bc(Uc.n); Uc= Rci * U; mpiReduce(Uc,Bc,processor(0,comm),mpiSUM); if(mpiRank(comm)==0) Uc = ACˆ-1 * Bc; broadcast(processor(0,comm),Uc); V = Pci * Uc; } 262 CHAPTER 10. MPI PARALLEL VERSION The New precondtionner func real[int] PDJC(real[int]& U) // { // Precon C1= Precon //, C2 precon Coarse // Idea : F. Nataf. // 0 ˜ (I C1A)(I-C2A) => I ˜ - C1AC2A +C1A +C2A // New Prec P= C1+C2 - C1AC2 = C1(I- A C2) +C2 // ( C1(I- A C2) +C2 ) Uo // V = - C2 * Uo // .... real[int] V(U.n); CoarseSolve(V,U,comm); V = -V; // -C2 * Uo U += Ai * V; // U = (I-A C2) Uo real[int] b= onG ? 0. : U; U = Aiˆ-1 * b; // ( C1( I -A C2) Uo V = U -V; // Update(V,U); return U; } The code to the 4 algorithms: real epss=1e-6; int rgmres=0; if(gmres==1) { rgmres=MPIAffineGMRES(DJ0,u[],veps=epss,nbiter=300,comm=comm, dimKrylov=100,verbosity=ipart ? 0: 50); real[int] b= onG . * u[]; b = onG ? b : Bi ; v[] = Aiˆ-1 * b; Update(v[],u[]); } else if(gmres==2) rgmres= MPILinearGMRES(DJ,precon=PDJ,u[],Bi,veps=epss,nbiter=300,comm=comm ,dimKrylov=100,verbosity=ipart ? 0: 50); else if(gmres==3) rgmres= MPILinearGMRES(DJ,precon=PDJC,u[],Bi,veps=epss,nbiter=300,comm=comm, dimKrylov=100,verbosity=ipart ? 0: 50); else // algo Shwarz for demo ... for(int iter=0;iter <10; ++iter) .... We have all ingredient to solve in parallel if we have et the partitions of the unity. To build this partition we do: the initial step on process 1 tp build a coarse mesh, T h ∗ of the full domain, and build the partition π function constant equal to i on each sub domain O i , i = 1, .., N p , of the grid with the Metis graph partitioner [?] and on each process i in 1.., N p do 1. Broadcast from process 1, the mesh T h ∗ (call Thii in freefem++ script), and π function, 2. remark that the characteristic function 1I O i of domain O i , is defined by (π = i)?1 : 0, 10.6. SCHWARZ EXAMPLE IN PARALLEL 263 3. let us call Π 2 P (resp. Π 2 V ) the L 2 on P ∗ h the space of the constant finite element function per element on T h ∗ (resp. V ∗ h the space of the affine continuous finite element per element on T h ∗ ). and build in parallel the π i and Ω i , such that O i ⊂ Ω i where O i = supp((Π 2 V Π 2 C ) m 1I O i ), and m is a the overlaps size on the coarse mesh (generally one), (this is done in function AddLayers(Thii,suppii[],nlayer,phii[]); We choose a function π ∗ i = (Π 2 1 Π 2 0 ) m 1I O i so the partition of the unity is simply defined by π i = π ∗ i ¸ N p j=1 π ∗ j (10.3) The set J i of neighborhood of the domain Ω i , and the local version on V hi can be defined the array jpart and njpart with: Vhi pii=π ∗ i ; Vhi[int] pij(npij); // local partition of 1 = pii + ¸ j pij[j] int[int] jpart(npart); int njpart=0; Vhi sumphi = π ∗ i ; for (int i=0;i<npart;++i) if(i != ipart ) { if(int3d(Thi)( π ∗ j )>0) { pij[njpart]=π ∗ j ; sumphi[] += pij[njpart][]; jpart[njpart++]=i;}}} pii[]=pii[] ./ sumphi[]; for (int j=0;j<njpart;++j) pij[j][] = pij[j][] ./ sumphi[]; jpart.resize(njpart); 4. We call T h ∗ ij the sub mesh part of T hi where π j are none zero. and tank to the function trunc to build this array, for(int jp=0;jp<njpart;++jp) aThij[jp] = trunc(Thi,pij[jp]>1e-10,label=10); 5. At this step we have all on the coarse mesh , so we can build the fine final mesh by splitting all meshes : Thi, Thij[j],Thij[j] with freefem++ trunc mesh function which do restriction and slipping. 6. The construction of the send/recv matrices sMj and rMj : can done with this code: mesh3 Thij=Thi; // variable meshes fespace Whij(Thij,Pk); // variable fespace .. matrix Pii; Whi wpii=pii; Pii = wpii[]; // Diagonal matrix corresponding π i matrix[int] sMj(njpart), rMj(njpart); // M send/rend case.. for(int jp=0;jp<njpart;++jp) { int j=jpart[jp]; Thij = aThij[jp]; // change mesh to change Whij,Whij matrix I = interpolate(Whij,Whi); // Whij <- Whi sMj[jp] = I * Pii; // Whi -> s Whij rMj[jp] = interpolate(Whij,Whi,t=1); }} // Whij -> Whi 264 CHAPTER 10. MPI PARALLEL VERSION To buil a not to bad application, I have add code tout change variable from parametre value with the following code include "getARGV.idp" verbosity=getARGV("-vv",0); int vdebug=getARGV("-d",1); int ksplit=getARGV("-k",10); int nloc = getARGV("-n",25); string sff=getARGV("-p,",""); int gmres=getARGV("-gmres",3); bool dplot=getARGV("-dp",0); int nC = getARGV("-N" ,max(nloc/10,4)); And small include to make graphic in parallel of distribute solution of vector u on mesh T h with the following interface: include "MPIplot.idp" func bool plotMPIall(mesh &Th,real[int] & u,string cm) { PLOTMPIALL(mesh,Pk, Th, u,{ cmm=cm,nbiso=20,fill=1,dim=3,value=1}); return 1;} remark the {cmm=cm, ... =1} in the macro argument is a way to quote macro argument so the argument is cmm=cm, ... =1. Chapter 11 Parallel sparse solvers Parallel sparse solvers use several processors to solve linear systems of equation. Like sequential, parallel linear solvers can be direct or iterative. In FreeFem++ both are available. 11.1 Using parallel sparse solvers in FreeFem++ We recall that the solver parameters are defined in the following commands: solve, problem, set (setting parameter of a matrix) and in the construction of the matrix corresponding to a bilinear form. In these commands, the parameter solver must be set to sparsesolver for parallel sparse solver. We have added specify parameters to these command lines for parallel sparse solvers. These are • lparams: vector of integer parameters (l is for the c++ type long) • dparams: vector of real parameters • sparams: string parameters • datafilename: name of the file which contains solver parameters The following four parameters are only for direct solvers and are vectors. These parameters allow the user to preprocess the matrix (see the section on sparse direct solver above for more information). • permr: row permutation (integer vector) • permc: column permutation or inverse row permutation (integer vector) • scaler: row scaling (real vector) • scalec: column scaling (real vector) There are two possibilities to control solver parameters. The first method defines parameters with lparams, dparams and sparams in .edp file. The second one reads the solver parameters from a data file. The name of this file is specified by datafilename. If lparams, dparams, sparams or datafilename is not provided by the user, the solver’s default value is used. To use parallel solver in FreeFem++ , we need to load the dynamic library corresponding to this solver. For example to use MUMPS solver as parallel solver in FreeFem, write in the .edp file load ”MUMPS FreeFem”. If the libraries are not loaded, the default sparse solver will be loaded (default sparse solver is UMFPACK). The table 11.1 gives this new value for the different libraries. 265 266 CHAPTER 11. PARALLEL SPARSE SOLVERS default sparse solver Libraries real complex MUMPS FreeFem mumps mumps real SuperLU DIST FreeFem SuperLU DIST previous solver complex SuperLU DIST FreeFem previous solver SuperLU DIST real pastix FreeFem pastix previous solver complex pastix FreeFem previous solver pastix hips FreeFem hips previous solver hypre FreeFem hypre previous solver parms FreeFem parms previous solver Table 11.1: Default sparse solver for real and complex arithmetics when we load a parallel sparse solver library We also add functions (see Table 11.2) with no parameter to change the default sparse solver in the .edp file. To use these functions, we need to load the library corresponding to the solver. An example of using different parallel sparse solvers for the same problem is given in testdirectsolvers.edp (directory example+ +−mpi). default sparse solver function real complex defaulttoMUMPS() mumps mumps realdefaulttoSuperLUdist() SuperLU DIST previous solver complexdefaulttoSuperLUdist() previous solver SuperLU DIST realdefaultopastix() pastix previous solver complexdefaulttopastix() previous solver pastix defaulttohips() hips previous solver defaulttohypre() hypre previous solver defaulttoparms() parms previous solver Table 11.2: Functions that allow to change the default sparse solver for real and complex arithmetics and the result of these functions Example 11.1 (testdirectsolvers.edp) load "../src/solver/MUMPS_FreeFem" // default solver : real-> MUMPS, complex -> MUMPS load "../src/solver/real_SuperLU_DIST_FreeFem" // default solver : real-> SuperLU DIST, complex -> MUMPS load "../src/solver/real_pastix_FreeFem" // default solver : real-> pastix, complex -> MUMPS // solving with pastix { matrix A = [[ 1, 2, 2, 1, 1], [ 2, 12, 0, 10 , 10], [ 2, 0, 1, 0, 2], [ 1, 10, 0, 22, 0.], [ 1, 10, 2, 0., 22]]; 11.1. USING PARALLEL SPARSE SOLVERS IN FREEFEM++ 267 real[int] xx = [ 1,32,45,7,2], x(5), b(5), di(5); b=A * xx; cout << "b=" << b << endl; cout << "xx=" << xx << endl; set(A,solver=sparsesolver,datafilename="ffpastix_iparm_dparm.txt"); cout << "solving solution" << endl; x = Aˆ-1 * b; cout << "b=" << b << endl; cout << "x=" << endl; cout << x << endl; di = xx-x; if(mpirank==0){ cout << "x-xx="<< endl; cout << "Linf "<< di.linfty << " L2 " << di.l2 << endl; } } // solving with SuperLU DIST realdefaulttoSuperLUdist(); // default solver : real-> SuperLU DIST, complex -> MUMPS { matrix A = [[ 1, 2, 2, 1, 1], [ 2, 12, 0, 10 , 10], [ 2, 0, 1, 0, 2], [ 1, 10, 0, 22, 0.], [ 1, 10, 2, 0., 22]]; real[int] xx = [ 1,32,45,7,2], x(5), b(5), di(5); b=A * xx; cout << "b=" << b << endl; cout << "xx=" << xx << endl; set(A,solver=sparsesolver,datafilename="ffsuperlu_dist_fileparam.txt"); cout << "solving solution" << endl; x = Aˆ-1 * b; cout << "b=" << b << endl; cout << "x=" << endl; cout << x << endl; di = xx-x; if(mpirank==0){ cout << "x-xx="<< endl; cout << "Linf "<< di.linfty << " L2 " << di.l2 << endl; } } // solving with MUMPS defaulttoMUMPS(); // default solver : real-> MUMPS, complex -> MUMPS { matrix A = [[ 1, 2, 2, 1, 1], [ 2, 12, 0, 10 , 10], [ 2, 0, 1, 0, 2], [ 1, 10, 0, 22, 0.], [ 1, 10, 2, 0., 22]]; real[int] xx = [ 1,32,45,7,2], x(5), b(5), di(5); 268 CHAPTER 11. PARALLEL SPARSE SOLVERS b=A * xx; cout << "b=" << b << endl; cout << "xx=" << xx << endl; set(A,solver=sparsesolver,datafilename="ffmumps_fileparam.txt"); cout << "solving solution" << endl; x = Aˆ-1 * b; cout << "b=" << b << endl; cout << "x=" << endl; cout << x << endl; di = xx-x; if(mpirank==0){ cout << "x-xx="<< endl; cout << "Linf "<< di.linfty << " L2 " << di.l2 << endl; } } 11.2 Sparse direct solver In this section, we present the sparse direct solvers interfaced with FreeFem++ . 11.2.1 MUMPS solver MUltifrontal Massively Parallel Solver (MUMPS) is a free library [?, ?, ?]. This package solves linear system of the form A x = b where A is a square sparse matrix with a direct method. The square matrix considered in MUMPS can be either unsymmetric, symmetric positive definite or general symmetric. The method implemented in MUMPS is a direct method based on a multifrontal approach [?]. It constructs a direct factorization A = LU, A = L t DL depending of the symmetry of the matrix A. MUMPS uses the following libraries : BLAS[?, ?], BLACS and ScaLAPACK[?]. Remark 7 MUMPS does not solve linear system with a rectangular matrix. Installation of MUMPS To used MUMPS in FreeFem++ , you have to install the MUMPS package into your computer. MUMPS is written in Fortran 90. The parallel version is constructed using MPI [?] for message passing and BLAS [?, ?], BLACS and ScaLAPACK[?]. Therefore, a fortran compiler is needed, and MPI, BLAS, BLACS and ScaLAPACK . An installation procedure to obtain this package is given in the file README COMPILE in the directory src/solver of FreeFem++ . Creating Library of MUMPS interface for FreeFem++ : The MUMPS interface for FreeFem++ is given in file MUMPS freefem.cpp (directory src/solver/ ). This interface works with the release 3.8.3 and 3.8.4 of MUMPS. To used MUMPS in FreeFem++ , we need the library corresponding to this interface. A description to obtain this library is given in the file README COMPILE in the directory src/solver of FreeFem++ . We recall here the procedure. Go to the directory src/solver in FreeFem++ package. Edit the file makefile-sparsesolver.inc to yours system: comment Section 1, comment line corresponding to libraries BLAS, BLACS, ScaLAPACK, Metis, scotch in Section 2 and comment in Section 3 the paragraph corresponding to MUMPS solver. And then type make mumps in a terminal window. Now we give a short description of MUMPS parameters before describing the method to call MUMPS in FreeFem++ . 11.2. SPARSE DIRECT SOLVER 269 MUMPS parameters: There are four input parameters in MUMPS (see [?]). Two integers SYM and PAR, a vector of integer of size 40 INCTL and a vector of real of size 15 CNTL. The first parameter gives the type of the matrix: 0 for unsymmetric matrix, 1 for symmetric positive matrix and 2 for general symmetric. The second parameter defined if the host processor work during the factorization and solves steps : PAR=1 host processor working and PAR=0 host processor not working. The parameter INCTL and CNTL is the control parameter of MUMPS. The vectors ICNTL and CNTL in MUMPS becomes with index 1 like vector in fortran. A short description of all parameters of ICNTL and CNTL is given in ffmumps fileparam.txt. For more details see the users’ guide [?]. We describe now some elements of the main parameters of ICNTL for MUMPS. Input matrix parameter The input matrix is controlled by parameters ICNTL(5) and IC- NTL(18). The matrix format (resp. matrix pattern and matrix entries) are controlled by INCTL(5) (resp. INCTL(18)). The different values of ICNTL(5) are 0 for assembled format and 1 for element format. In the current release of Freefem++, we consider that FE matrix or matrix is storage in assembled format. Therefore, INCTL(5) is treated as 0 value. The main option for ICNTL(18): INCLTL(18)=0 centrally on the host processor, ICNTL(18)=3 distributed the input matrix pattern and the entries (recommended option for distributed matrix by developer of MUMPS). For other values of ICNTL(18) see the user’s guide of MUMPS. These values can be used also in Freefem++. The default option implemented in FreeFem++ are ICNTL(5)=0 and ICNTL(18)=0. Preprocessing parameter The preprocessed matrix A p that will be effectively factored is defined by A p = P D r AQ c D c P t where P is the permutation matrix, Q c is the column permutation, D r and D c are diagonal matrix for respectively row and column scaling. The ordering strategy to obtain P is controlled by param- eter ICNTL(7). The permutation of zero free diagonal Q c is controlled by parameter ICNTL(6). The row and column scaling is controlled by parameter ICNTL(18). These option are connected and also strongly related with ICNTL(12) (see documentation of mumps for more details [?]). The parameters permr, scaler, and scalec in FreeFem++ allow to give permutation matrix(P), row scaling (D r ) and column scaling (D c ) of the user respectively. Calling MUMPS in FreeFem++ To call MUMPS in FreeFem++ , we need to load the dy- namic library MUMPS freefem.dylib (MacOSX), MUMPS freefem.so (Unix) or MUMPS freefem.dll (Windows). This is done in typing load ”MUMPS freefem” in the .edp file. We give now the two methods to give the option of MUMPS solver in FreeFem++ . Solver parameters is defined in .edp file: In this method, we need to give the parameters lparams and dparams. These parameters are defined for MUMPS by lparams[0] = SYM, lparams[1] = PAR, ∀i = 1, . . . , 40, lparams[i+1] = ICNTL(i). ∀i = 1, . . . , 15, dparams[i −1] = CNTL(i). Reading solver parameters on a file: The structure of data file for MUMPS in FreeFem++ is : first line parameter SYM and second line parameter PAR and in the following line the different value 270 CHAPTER 11. PARALLEL SPARSE SOLVERS of vectors ICNTL and CNTL. An example of this parameter file is given in ffmumpsfileparam.txt. 0 / * SYM :: 0 for non symmetric matrix, 1 for symmetric definite positive matrix and 2 general symmetric matrix * / 1 / * PAR :: 0 host not working during factorization and solves steps, 1 host working during factorization and solves steps * / -1 / * ICNTL(1) :: output stream for error message * / -1 / * ICNTL(2) :: output for diagnostic printing, statics and warning message * / -1 / * ICNTL(3) :: for global information * / 0 / * ICNTL(4) :: Level of printing for error, warning and diagnostic message * / 0 / * ICNTL(5) :: matrix format : 0 assembled format, 1 elemental format. * / 7 / * ICNTL(6) :: control option for permuting and/or scaling the matrix in analysis phase * / 3 / * ICNTL(7) :: pivot order strategy : AMD, AMF, metis, pord scotch * / 77 / * ICNTL(8) :: Row and Column scaling strategy * / 1 / * ICNTL(9) :: 0 solve Ax = b, 1 solve the transposed system Aˆt x = b : parameter is not considered in the current release of freefem++ * / 0 / * ICNTL(10) :: number of steps of iterative refinement * / 0 / * ICNTL(11) :: statics related to linear system depending on ICNTL(9) * / 1 / * ICNTL(12) :: constrained ordering strategy for general symmetric matrix * / 0 / * ICNTL(13) :: method to control splitting of the root frontal matrix * / 20 / * ICNTL(14) :: percentage increase in the estimated working space (default 20%) * / 0 / * ICNTL(15) :: not used in this release of MUMPS * / 0 / * ICNTL(16) :: not used in this release of MUMPS * / 0 / * ICNTL(17) :: not used in this release of MUMPS * / 3 / * ICNTL(18) :: method for given : matrix pattern and matrix entries : * / 0 / * ICNTL(19) :: method to return the Schur complement matrix * / 0 / * ICNTL(20) :: right hand side form ( 0 dense form, 1 sparse form) : parameter will be set to 0 for freefem++ * / 0 / * ICNTL(21) :: 0, 1 kept distributed solution : parameter is not considered in the current release of freefem++ * / 0 / * ICNTL(22) :: controls the in-core/out-of-core (OOC) facility * / 0 / * ICNTL(23) :: maximum size of the working memory in Megabyte than MUMPS can allocate per working processor * / 0 / * ICNTL(24) :: control the detection of null pivot * / 0 / * ICNTL(25) :: control the computation of a null space basis * / 0 / * ICNTL(26) :: This parameter is only significant with Schur option (ICNTL(19) not zero). : parameter is not considered in the current release of freefem++ * / -8 / * ICNTL(27) (Experimental parameter subject to change in next release of MUMPS) :: control the blocking factor for multiple righthand side during the solution phase : parameter is not considered in the current release of freefem++ * / 0 / * ICNTL(28) :: not used in this release of MUMPS * / 0 / * ICNTL(29) :: not used in this release of MUMPS * / 0 / * ICNTL(30) :: not used in this release of MUMPS * / 11.2. SPARSE DIRECT SOLVER 271 0 / * ICNTL(31) :: not used in this release of MUMPS * / 0 / * ICNTL(32) :: not used in this release of MUMPS * / 0 / * ICNTL(33) :: not used in this release of MUMPS * / 0 / * ICNTL(34) :: not used in this release of MUMPS * / 0 / * ICNTL(35) :: not used in this release of MUMPS * / 0 / * ICNTL(36) :: not used in this release of MUMPS * / 0 / * ICNTL(37) :: not used in this release of MUMPS * / 0 / * ICNTL(38) :: not used in this release of MUMPS * / 1 / * ICNTL(39) :: not used in this release of MUMPS * / 0 / * ICNTL(40) :: not used in this release of MUMPS * / 0.01 / * CNTL(1) :: relative threshold for numerical pivoting * / 1e-8 / * CNTL(2) :: stopping criteria for iterative refinement * / -1 / * CNTL(3) :: threshold for null pivot detection * / -1 / * CNTL(4) :: determine the threshold for partial pivoting * / 0.0 / * CNTL(5) :: fixation for null pivots * / 0 / * CNTL(6) :: not used in this release of MUMPS * / 0 / * CNTL(7) :: not used in this release of MUMPS * / 0 / * CNTL(8) :: not used in this release of MUMPS * / 0 / * CNTL(9) :: not used in this release of MUMPS * / 0 / * CNTL(10) :: not used in this release of MUMPS * / 0 / * CNTL(11) :: not used in this release of MUMPS * / 0 / * CNTL(12) :: not used in this release of MUMPS * / 0 / * CNTL(13) :: not used in this release of MUMPS * / 0 / * CNTL(14) :: not used in this release of MUMPS * / 0 / * CNTL(15) :: not used in this release of MUMPS * / If no solver parameter is given, we used default option of MUMPS solver. example A simple example of calling MUMPS in FreeFem++ with this two methods is given in the file testsolver MUMPS.edp in the directory examples++-mpi. 11.2.2 SuperLU distributed solver The package SuperLU DIST [?, ?] solves linear systems using LU factorization. It is a free scientific library under BSD license. The web site of this project is http://crd.lbl.gov/∼xiaoye/SuperLU. This library provides functions to handle square or rectangular matrix in real and complex arithmetics. The method implemented in SuperLU DIST is a supernodal method [?]. New release of this package includes a parallel symbolic factorization [?]. This scientific library is written in C and MPI for communications. Installation of SuperLU DIST: To use SuperLU DIST in FreeFem++ , you have to install SuperLU DIST package. We need MPI and ParMetis library to do this compilation. An instal- lation procedure to obtain this package is given in the file README COMPILE in the directory src/solver/ of the freefem++ package. Creating Library of SuperLU DIST interface for FreeFem++ : The FreeFem++ interface to SuperLU DIST for real (resp. complex) arithmetics is given in file real SuperLU DIST FreeFem.cpp (resp. complex SuperLU DIST FreeFem.cpp). These files are in the directory src/solver/. These interfaces are compatible with the release 3.2.1 of SuperLU DIST. To use SuperLU DIST in FreeFem++ , we need libraries corresponding to these interfaces. A description to obtain these libraries is given in the file README COMPILE in the directory src/solver of FreeFem++ . We recall here the procedure. Go to the directory src/solver in FreeFem++ package. Edit the file makefile-sparsesolver.inc in your system : comment Section 272 CHAPTER 11. PARALLEL SPARSE SOLVERS 1, comment line corresponding to libraries BLAS, Metis, ParMetis in Section 2 and comment in Section 3 the paragraph corresponding to SuperLU DIST solver. And just type make rsludist (resp. make csludist) in the terminal to obtain the dynamic library of interface for real (resp. complex) arithmetics. Now we give a short description of SuperLU DIST parameters before describing the method to call SuperLU DIST in FreeFem++ . SuperLU DIST parameters: We describe now some parameters of SuperLU DIST. The Su- perLU DIST library use a 2D-logical process group. This process grid is specifies by nprow (process row) and npcol (process column) such that N p = nprownpcol where N p is the number of all process allocated for SuperLU DIST. The input matrix parameters is controlled by ”matrix= ” in sparams for internal parameter or in the third line of parameters file. The different value are matrix = assembled global matrix are available on all process matrix = distributedglobal the global matrix is distributed among all the process matrix = distributed the input matrix is distributed (not yet implemented) The option arguments of SuperLU DIST are described in the section Users-callable routine of [?]. The parameter Fact and TRANS are specified in FreeFem++ interfaces to SuperLU DIST during the different steps. For this reason, the value given by the user for this option is not considered. The factorization LU is calculated in SuperLU DIST on the matrix A p . A p = P c P r D r AD c P t c where P c and P r is the row and column permutation matrix respectively, D r and D c are diagonal matrix for respectively row and column scaling. The option argument RowPerm (resp. ColPerm) control the row (resp. column) permutation matrix. D r and D c is controlled by the parameter DiagScale. The parameter permr, permc, scaler, and scalec in FreeFem++ is provided to give row permutation, column permutation, row scaling and column scaling of the user respectively. The other parameters for LU factorization are ParSymFact and ReplaceTinyPivot. The parallel symbolic factorization works only on a power of two processes and need the ParMetis ordering [?]. The default option argument of SuperLU DIST are given in the file ffsuperlu dist fileparam.txt. Calling SuperLU DIST in FreeFem++ To call SuperLU DIST in FreeFem++ , we need to load the library dynamic correspond to interface. This done by the following line load ”real superlu DIST FreeFem” (resp. load ”complex superlu DIST FreeFem”) for real (resp. complex) arith- metics in the file .edp. Solver parameters is defined in .edp file: To call SuperLU DIST with internal parameter, we used the parameters sparams. The value of parameters of SuperLU DIST in sparams is defined by sparams =”nprow=1, npcol=1, matrix= distributedgloba, Fact= DOFACT, Equil=NO, ParSymbFact=NO, ColPerm= MMD AT PLUS A, RowPerm= LargeDiag, DiagPivotThresh=1.0, IterRefine=DOUBLE, Trans=NOTRANS, ReplaceTinyPivot=NO, SolveInitialized=NO, PrintStat=NO, DiagScale=NOEQUIL ” This value correspond to the parameter in the file ffsuperlu dist fileparam.txt. If one parameter is not specify by the user, we take the default value of SuperLU DIST. Reading solver parameters on a file: The structure of data file for SuperLU DIST in FreeFem++ is given in the file ffsuperlu dist fileparam.txt (default value of the FreeFem++ interface). 11.2. SPARSE DIRECT SOLVER 273 1 / * nprow : integer value * / 1 / * npcol : integer value * / distributedglobal / * matrix input : assembled, distributedglobal, distributed * / DOFACT / * Fact : DOFACT, SamePattern, SamePattern_SameRowPerm, FACTORED * / NO / * Equil : NO, YES * / NO / * ParSymbFact : NO, YES * / MMD_AT_PLUS_A / * ColPerm : NATURAL, MMD_AT_PLUS_A, MMD_ATA, METIS_AT_PLUS_A, PARMETIS, MY_PERMC * / LargeDiag / * RowPerm : NOROWPERM, LargeDiag, MY_PERMR * / 1.0 / * DiagPivotThresh : real value * / DOUBLE / * IterRefine : NOREFINE, SINGLE, DOUBLE, EXTRA * / NOTRANS / * Trans : NOTRANS, TRANS, CONJ * / NO / * ReplaceTinyPivot : NO, YES * / NO / * SolveInitialized : NO, YES * / NO / * RefineInitialized : NO, YES * / NO / * PrintStat : NO, YES * / NOEQUIL / * DiagScale : NOEQUIL, ROW, COL, BOTH * / If no solver parameter is given, we used default option of SuperLU DIST solver. Example 11.2 A simple example of calling SuperLU DIST in FreeFem++ with this two methods is given in the file testsolver superLU DIST.edp in the directory examples++-mpi. 11.2.3 Pastix solver Pastix (Parallel Sparse matrix package) is a free scientific library under CECILL-C license. This package solves sparse linear system with a direct and block ILU(k) iterative methods. This solver can be applied to a real or complex matrix with a symmetric pattern [?]. Installation of Pastix: To used Pastix in FreeFem++ , you have to install pastix package in first. To compile this package, we need a fortran 90 compiler, scotch [?] or Metis [?] ordering library and MPI. An installation procedure to obtain this package is given in the file .src/solver/ README COMPILE in the section pastix of the FreeFem++ package. Creating Library of pastix interface for FreeFem++ : The FreeFem++ interface to pastix is given in file real pastix FreeFem.cpp (resp. complex pastix FreeFem.cpp) for real (resp.complex) arithmetics. This interface is compatible with the release 2200 of pastix and is designed for a global matrix. We have also implemented interface for distributed matrices. To use pastix in FreeFem++ , we need the library corresponding to this interface. A description to obtain this library is given in the file README COMPILE in the directory src/solver of FreeFem++ . We recall here the procedure. Go to the directory src/solver in FreeFem++ package. Edit the file makefile-sparsesolver.inc to yours system : comment Section 1, comment line corresponding to libraries BLAS, METIS and SCOTCH in Section 2 and comment in Section 3 the paragraph corresponding to pastix solver. And just type make rpastix (resp. make cpastix) in the terminal to obtain the dynamic library of interface for real (resp. complex) arithmetics. Now we give a short description of pastix parameters before describing the method to call pastix in FreeFem++ . 274 CHAPTER 11. PARALLEL SPARSE SOLVERS Pastix parameters: The input matrix parameter of FreeFem++ depend on pastix interface. matrix=assembled for non distributed matrix. It is the same parameter for SuperLU DIST. There are four parameters in Pastix : iparm, dparm, perm and invp. These parameters are respectively the integer parameters (vector of size 64), real parameters (vector of size 64), permutation matrix and inverse permutation matrix respectively. iparm and dparm vectors are described in [?]. The parameters permr and permc in FreeFem++ are provided to give permutation matrix and inverse permutation matrix of the user respectively. Solver parameters defined in .edp file: To call Pastix in FreeFem++ in this case, we need to specify the parameters lparams and dparams. These parameters are defined by ∀i = 0, . . . , 63, lparams[i] = iparm[i]. ∀i = 0, . . . , 63, dparams[i] = dparm[i]. Reading solver parameters on a file: The structure of data file for pastix parameters in FreeFem++ is : first line structure parameters of the matrix and in the following line the value of vectors iparm and dparm in this order. assembled / * matrix input :: assembled, distributed global and distributed * / iparm[0] iparm[1] ... ... iparm[63] dparm[0] dparm[1] ... ... dparm[63] An example of this file parameter is given in ffpastix iparm dparm.txt with a description of these parameters. This file is obtained with the example file iparm.txt and dparm.txt including in the pastix package. If no solver parameter is given, we use the default option of pastix solver. Example: A simple example of calling pastix in FreeFem++ with this two methods is given in the file testsolver pastix.edp in the directory examples++-mpi. In Table 11.3, we recall the different matrix considering in the different direct solvers. 11.3 Parallel sparse iterative solver Concerning iterative solvers, we have chosen pARMS [?] , HIPS [?] and Hypre [?]. Each software implements a different type of parallel preconditioner. So, pARMS implements algebraic domain decomposition preconditioner type such as additive Schwartz [?] and interface method [?]; while 11.3. PARALLEL SPARSE ITERATIVE SOLVER 275 square matrix rectangular matrix direct solver sym sym pattern unsym sym sym pattern unsym SuperLU DIST yes yes yes yes yes yes MUMPS yes yes yes no no no pastix yes yes no no no no Table 11.3: Type of matrix used by the different direct sparse solver HIPS implement hierarchical incomplete factorization [?] and finally HYPRE implements multilevel preconditioner are AMG(Algebraic MultiGrid) [?] and parallel approximated inverse [?]. To use one of these programs in FreeFem++, you have to install it independently of FreeFem++. It is also necessary to install the MPI communication library which is essential for communication between the processors and, in some cases, software partitioning graphs like METIS [?] or Scotch [?]. All this preconditioners are used with Krylov subspace methods accelerators. Krylov subspace methods are iterative methods which consist in finding a solution x of linear system Ax = b inside the affine space x 0 +K m by imposing that b −Ax⊥/ m , where K m is Krylov subspace of dimension m defined by K m = ¦r 0 , Ar 0 , A 2 r 0 , ..., A m−1 r 0 ¦ and / m is another subspace of dimension m which depends on type of Krylov subspace. For example in GMRES, / m = AK m . We realized an interface which is easy to use, so that the call of these different softwares in FreeFem++ is done in the same way. You just have to load the solver and then specify the parameters to apply to the specific solvers. In the rest of this chapter, when we talk about Krylov subspace methods we mean one among GMRES, CG and BICGSTAB. 11.3.1 pARMS solver pARMS ( parallel Algebraic Multilevel Solver) is a software developed by Youssef Saad and al at University of Minnesota [?]. This software is specialized in the resolution of large sparse non symmetric linear systems of equation. Solvers developed in pARMS is the Krylov subspace type. It consists of variants of GMRES like FGMRES(Flexible GMRES) , DGMRES(Deflated GMRES) [?] and BICGSTAB. pARMS also implements parallel preconditioner like RAS (Restricted Additive Schwarz)[?] and Schur Complement type preconditioner [?]. All these parallel preconditioners are based on the principle of domain decomposition. Thus, the matrix A is partitioned into sub matrices A i (i = 1, ..., p) where p represents the number of partitions one needs. The union of A i forms the original matrix. The solution of the overall system is obtained by solving the local systems on A i (see [?]). Therefore, a distinction is made between iterations on A and the local iterations on A i . To solve the local problem on A i there are several preconditioners as ilut (Incomplete LU with threshold), iluk(Incomplete LU with level of fill in) and ARMS( Algebraic Recursive Multilevel Solver). But to use pAMRS in FreeFem++ you have first to install pAMRS. Installation of pARMS To install pARMS, you must first download the pARMS package at [?]. Once the download is complete, you must unpack package pARMS and follow the installation procedure described in file README to create the library libparms.a. Using pARMS as interface to FreeFem++ Before calling pARMS solver inside FreeFem++, you must compile file parms FreeFem.cpp to create a dynamic library parms FreeFem.so. To do this, move to the directory src/solver of FreeFem++, edit the file makefileparms.inc to specify 276 CHAPTER 11. PARALLEL SPARSE SOLVERS the following variables: PARMS DIR : Directory of pARMS PARMS INCLUDE : Directory for header of pARMS METIS : METIS directory METIS LIB : METIS librairy MPI : MPI directory MPI INCLUDE : MPI headers FREEFEM : FreeFem++ directory FREEFEM INCLUDE : FreeFem++ header for sparse linear solver LIBBLAS : Blas library After that, in the command line type make parms to create parms FreeFem.so. As usual in FreeFem++, we will show by examples how to call pARMS in FreeFem++. There are three ways of doing this: Example 1: Default parameters This example comes from user guide of FreeFem++ [?] at page 12. Example 11.3 1: load parms_freefem // Tell FreeFem that you will use pARMS 2: border C(t=0,2 * pi){x=cos(t); y=sin(t);label=1;} 3: mesh Th = buildmesh (C(50)); 4: fespace Vh(Th,P2); 5: Vh u,v; 6: func f= x * y; 7: problem Poisson(u,v,solver=sparsesolver) = // bilinear part will use 8: int2d(Th)(dx(u) * dx(v) + dy(u) * dy(v)) // a sparse solver, in this case pARMS 9: - int2d(Th)( f * v) // right hand side 10: + on(1,u=0) ; // Dirichlet boundary condition 11: 12: real cpu=clock(); 13: Poisson; // SOLVE THE PDE 14: plot(u); 15: cout << " CPU time = " << clock()-cpu << endl; In line 1 of example 11.3 we load in memory the pARMS dynamic library with interface FreeFem++. After this, in line 7 we specify that the bilinear form will be solved by the last sparse linear solver load in memory which, in this case, is pARMS. The parameter used in pARMS in this case is the default one since the user does not have to provide any parameter. Here are some default parameters: solver=FGMRES, Krylov dimension=30, Maximum of Krylov=1000, Tolerance for convergence=1e− 08.(see book of Saad [?] to understand all this parameters.) preconditionner=Restricted Additif Schwarz [?], Inner Krylov dimension=5, Maximum of inner Krylov dimension=5, Inner preconditionner=ILUK. To specify the parameters to apply to the solver, the user can either give an integer vector for integer parameters and real vectors for real parameters or provide a file which contains those parameters. 11.3. PARALLEL SPARSE ITERATIVE SOLVER 277 Example 2: User specifies parameters inside two vectors Lets us consider Navier Stokes example 11.4 . In this example we solve linear systems coming from discretization of Navier Stokes equation with pARMS. Parameters of solver is specified by user. Example 11.4 (Stokes.edp) include "manual.edp" include "includes.edp"; include "mesh_with_cylinder.edp"; include "bc_poiseuille_in_square.edp"; include "fe_functions.edp"; 0: load parms_FreeFem 1: int[int] iparm(16); real[int] dparm(6); 2: int ,ii; 3: for(ii=0;ii<16;ii++){iparm[ii]=-1;} for(ii=0;ii<6;ii++) dparm[ii]=-1.0; 4: fespace Vh(Th,[P2,P2,P1]); 5: iparm[0]=0; 6: varf Stokes ([u,v,p],[ush,vsh,psh],{solver=sparsesolver}) = int2d(Th)( nu * ( dx(u) * dx(ush) + dy(u) * dy(ush) + dx(v) * dx(vsh) + dy(v) * dy(vsh) ) - p * psh * (1.e-6) // p epsilon - p * (dx(ush)+dy(vsh)) // + dx(p) * ush + dy(p) * vsh - (dx(u)+dy(v)) * psh // psh div(u) ) + on(cylinder,infwall,supwall,u=0.,v=0.)+on(inlet,u=uc,v=0); // Bdy conditions 7: matrix AA=Stokes(VVh,VVh); 8: set(AA,solver=sparsesolver,lparams=iparm,dparams=dparm); // Set pARMS as linear solver 9: real[int] bb= Stokes(0,VVh); real[int] sol(AA.n); 10: sol= AAˆ-1 * bb; We need two vectors to specify the parameters of the linear solver. In line 1 of example 11.4 we have declared these vectors(int[int] iparm(16); real[int] dparm(6);) . In line 3 we have initialized these vectors by negative values. We do this because all parameters values in pARMS are positive and if you do not change the negative values of one entry of this vector, the default value will be set. In tables (table 11.4 and 11.5) , we have the meaning of differents entries of these vectors. We run example 11.4 on cluster paradent of Grid5000 and report results in table 11.8. In this example, we fix the matrix size (in term of finite element, we fix the mesh) and increase the number of processors used to solve the linear system. We saw that, when the number of processors increases, the time for solving the linear equation decreases, even if the number of iteration increases. This proves that, using pARMS as solver of linear systems coming from discretization of partial differential equation in FreeFem++ can decrease drastically the total time of simulation. 11.3.2 Interfacing with HIPS HIPS ( Hierarchical Iterative Parallel Solver) is a scientific library that provides an efficient parallel iterative solver for very large sparse linear systems. HIPS is available as free software under the CeCILL-C licence. The interface that we realized is compatible with release 1.2 beta.rc4 of HIPS. HIPS implements two solver classes which are the iteratives class ( GMRES, PCG) and the Di- rect class. Concerning preconditionners, HIPS implements a type of multilevel ILU. For further informations on those preconditionners see [?, ?]. 278 CHAPTER 11. PARALLEL SPARSE SOLVERS Entries of iparm Significations of each entries iparm[0] Krylov subspace methods. Differents values for this parameters are specify on table 11.6 iparm[1] Preconditionner. Differents preconditionners for this parameters are specify on table 11.7 iparm[2] Krylov subspace dimension in outer iteration: default value 30 iparm[3] Maximum of iterations in outer iteration: default value 1000 iparm[4] Number of level in arms when used. iparm[5] Krylov subspace dimension in inner iteration: default value 3 iparm[6] Maximum of iterations in inner iteration: default value 3 iparm[7] Symmetric(=1 for symmetric) or unsymmetric matrix: default value 0(unsymmetric matrix) iparm[8] Overlap size between different subdomain: default value 0(no overlap) iparm[9] Scale the input matrix or not: Default value 1 (Matrix should be scale) iparm[10] Block size in arms when used: default value 20 iparm[11] lfil0 (ilut, iluk, and arms) : default value 20 iparm[12] lfil for Schur complement const : default value 20 iparm[13] lfil for Schur complement const : default value 20 iparm[14] Multicoloring or not in ILU when used : default value 1 iparm[15] Inner iteration : default value 0 iparm[16] Print message when solving:default 0(no message print). 0: no message is print, 1: Convergence informations like number of iteration and residual , 2: Timing for a different step like preconditioner 3 : Print all informations. Table 11.4: Meaning of lparams corresponding variables for example 11.4 Entries of dparm Significations of each entries dparm[0] precision for outer iteration : default value 1e-08 dparm[1] precision for inner iteration: default value 1e-2 dparm[2] tolerance used for diagonal domain: : default value 0.1 dparm[3] drop tolerance droptol0 (ilut, iluk, and arms) : default value 1e-2 dparm[4] droptol for Schur complement const: default value 1e-2 dparm[5] droptol for Schur complement const: default value 1e-2 Table 11.5: Significations of dparams corresponding variables for example 11.4 Values of iparm[0] Krylov subspace methods 0 FGMRES (Flexible GMRES) 1 DGMRES (Deflated GMRES) 2 BICGSTAB Table 11.6: Krylov Solvers in pARMS 11.3. PARALLEL SPARSE ITERATIVE SOLVER 279 Values of iparm[1] Preconditionners 0 Preconditioners type is additive Schwartz preconditioner with ilu0 as local preconditioner, 1 preconditioner type is additive Schwartz preconditioner with iluk as local preconditioner, 2 preconditioner type is additive Schwartz preconditioner with ilut as local preconditioner, 3 preconditioner type is additive Schwartz preconditioner with arms as local preconditioner, 4 preconditioner type is Left Schur complement preconditioner with ilu0 as local preconditioner, 5 preconditioner type is Left Schur complement preconditioner with ilut as local preconditioner, 6 preconditioner type is Left Schur complement preconditioner with iluk as local preconditioner, 7 preconditioner type is Left Schur complement preconditioner with arms as local preconditioner, 8 preconditioner type is Right Schur complement preconditioner with ilu0 as local preconditioner, 9 preconditioner type is Right Schur complement preconditioner with ilut as local preconditioner, 10 preconditioner type is Right Schur complement preconditioner with iluk as local preconditioner, 11 preconditioner type is Right Schur complement preconditioner with arms as local preconditioner, 12 preconditioner type is sch gilu0 , Schur complement preconditioner with global ilu0 13 preconditioner type is SchurSymmetric GS preconditioner Table 11.7: Preconditionners in pARMS n= 471281 nnz=13 10 6 Te=571,29 np add(iluk) schur(iluk) nit time nit time 4 230 637.57 21 557.8 8 240 364.12 22 302.25 16 247 212.07 24 167.5 32 261 111.16 25 81.5 Table 11.8: Convergence and time for solving linear system from example 11.4 280 CHAPTER 11. PARALLEL SPARSE SOLVERS n matrix size nnz number of non null entries inside matrix nit number of iteration for convergence time Time for convergence Te Time for constructing finite element matrix np number of processor Table 11.9: Legend of table 11.8 Installation of HIPS To install HIPS, first download the HIPS package at [?], unpack it and go to the HIPS source directory. The installation of HIPS is machine dependence. For example, to install HIPS on a linux cluster copy the file Makefile Inc Examples/makefile.inc.gnu on the root directory of HIPS with the name makefile.inc. After this, edit makefile.inc to set values of different variables and type make all. Using HIPS as the interface to FreeFem++ Before calling the HIPS solver inside FreeFem++, you must compile file hips FreeFem.cpp to create dynamic library hips FreeFem.so. To do this, move to the directory src/solver of FreeFem++ and edit the file makefile.inc to specify the fol- lowing variables: HIPS DIR : Directory of HIPS HIPS INCLUDE: -I$(HIPS DIR)/SRC/INCLUDE : Directory for HIPS headers LIB DIR : -L$(HIPS DIR)/LIB : Librairies directory LIBHIPSSEQUENTIAL : $(HIPS DIR)/LIB/libhipssequential.a: HIPS utilities library LIBHIPS : $(HIPS DIR)/LIB/libhips.a: HIPS library FREEFEM : FreeFem++ directory FREEFEM INCLUDE : FreeFem headers for sparse linear solver METIS : METIS directory METIS LIB : METIS library MPI : MPI directory MPI INCLUDE : MPI headers After specifies all the variables, in the command line in the directory src/solver type make hips to create hips FreeFem.so. Like with pARMS, the calling of HIPS in FreeFem++ can be done in three different manners. We will present only one example where the user specifies the parameters through keywords lparams and dparams. Laplacian 3D solve with HIPS Let us consider the 3D Laplacian example inside FreeFem++ package where after discretization we want to solve the linear equation with Hips. Example 11.5 is Laplacian3D using Hips as linear solver. We first load Hips solver at line 2. From line 4 to 15 we specify the parameters for the Hips solver and in line 46 of example 11.5 we set these parameters in the linear solver. In Table 11.10 results of running example 11.5 on Cluster Paradent of Grid5000 are reported. We can see in this running example the efficiency of parallelism. Example 11.5 (Laplacian3D.edp) 1: load "msh3" 2: load "hips_FreeFem" // load library 3: int nn=10,iii; 11.3. PARALLEL SPARSE ITERATIVE SOLVER 281 4: int[int] iparm(14); 5: real[int] dparm(6); 6: for(iii=0;iii<14;iii++)iparm[iii]=-1; 7: for(iii=0;iii<6;iii++) dparm[iii]=-1; 8: iparm[0]=0; // use iterative solver 9: iparm[1]=1; // PCG as Krylov method 10:iparm[4]=0; // Matrix are symmetric 11:iparm[5]=1; // Pattern are also symmetric 12: iparm[9]=1; // Scale matrix 13:dparm[0]=1e-13; // Tolerance to convergence 14: dparm[1]=5e-4; // Threshold in ILUT 15: dparm[2]=5e-4; // Threshold for Schur preconditionner 16: mesh Th2=square(nn,nn); 17: fespace Vh2(Th2,P2); 18: Vh2 ux,uz,p2; 19: int[int] rup=[0,2], rdown=[0,1], rmid=[1,1,2,1,3,1,4,1]; 20:real zmin=0,zmax=1; 21: mesh3 Th=buildlayers(Th2,nn, zbound=[zmin,zmax], reffacemid=rmid, reffaceup = rup, reffacelow = rdown); 22: savemesh(Th,"copie.mesh"); 23: mesh3 Th3("copie.mesh"); 24: fespace Vh(Th,P2); 25: func ue = 2 * x * x + 3 * y * y + 4 * z * z + 5 * x * y+6 * x * z+1; 26: func uex= 4 * x+ 5 * y+6 * z; 27: func uey= 6 * y + 5 * x; 28: func uez= 8 * z +6 * x; 29: func f= -18. ; 30: Vh uhe = ue; // 31: cout << " uhe min: " << uhe[].min << " max:" << uhe[].max << endl; 32: Vh u,v; 33: macro Grad3(u) [dx(u),dy(u),dz(u)] // EOM 34: varf va(u,v)= int3d(Th)(Grad3(v)’ * Grad3(u)) // ’) for emacs + int2d(Th,2)(u * v) - int3d(Th)(f * v) - int2d(Th,2) ( ue * v + (uex * N.x +uey * N.y +uez * N.z) * v ) + on(1,u=ue); 35: real cpu=clock(); 36: matrix Aa; 37: Aa=va(Vh,Vh); 38: varf l(unused,v)=int3d(Th)(f * v); 39: Vh F; F[]=va(0,Vh); 40: if(mpirank==0){ cout << "Taille " << Aa.n << endl; cout << "Non zeros " << Aa.nbcoef << endl; } 41: if(mpirank==0) 42: cout << "CPU TIME FOR FORMING MATRIX = " << clock()-cpu << endl; 43: set(Aa,solver=sparsesolver,dparams=dparm, lparams=iparm); // Set hips as linear solver 44: u[]=Aaˆ-1 * F[]; Legend of table 11.10 are give in table 11.9. 282 CHAPTER 11. PARALLEL SPARSE SOLVERS n = 4 10 6 nnz = 118 10 6 Te=221.34 np nit time 8 190 120.34 16 189 61.08 32 186 31.70 64 183 23.44 Table 11.10: Iterations and Timing of solving linear system from example 11.5 Entries of iparm Significations of each entries iparm[0] Strategy use for solving ( Iterative=0 or Hybrid=1 or Direct=2 ). Defaults values are : Iterative iparm[1] Krylov methods. If iparm[0]=0, give type of Krylov methods: 0 for GMRES, 1 for PCG iparm[2] Maximum of iterations in outer iteration: default value 1000 iparm[3] Krylov subspace dimension in outer iteration: default value 40 iparm[4] Symmetric(=0 for symmetric) and 1 for unsymmetric matrix: default value 1(unsymmetric matrix) iparm[5] Pattern of matrix are symmetric or not: default value 0 iparm[6] Partition type of input matrix: dafault value 0 iparm[7] Number of level that use the HIPS locally consistent fill-in: Default value 2 iparm[8] Numbering in indices array will start at 0 or 1: Default value 0 iparm[9] Scale matrix. Default value 1 iparm[10] Reordering use inside subdomains for reducing fill-in: Only use for iterative. Default value 1 iparm[11] Number of unknowns per node in the matrix non-zero pattern graph: Default value 1 iparm[12] This value is used to set the number of time the normalization is applied to the matrix: Default 2. iparm[13] Level of informations printed during solving: Default 5. iparm[14] HIPS DOMSIZE Subdomain size Table 11.11: Significations of lparams corresponding to HIPS interface 11.3. PARALLEL SPARSE ITERATIVE SOLVER 283 dparm[0] HIPS PREC: Relative residual norm: Default=1e-9 dparm[1] HIPS DROPTOL0: Numerical threshold in ILUT for interior domain (important : set 0.0 in HYBRID: Default=0.005) dparm[2] HIPS DROPTOL1 : Numerical threshold in ILUT for Schur preconditioner: Default=0.005 dparm[3] HIPS DROPTOLE : Numerical threshold for coupling between the interior level and Schur: Default 0.005 dparm[4] HIPS AMALG : Numerical threshold for coupling between the interior level and Schur: Default=0.005 dparm[5] HIPS DROPSCHUR : Numerical threshold for coupling between the interior level and Schur: Default=0.005 Table 11.12: Significations of dparams corresponding to HIPS interface 11.3.3 Interfacing with HYPRE HYPRE ( High Level Preconditioner) is a suite of parallel preconditioner developed at Lawrence Livermore National Lab [?] . There are two main classes of preconditioners developed in HYPRE: AMG (Algebraic MultiGrid) and Parasails (Parallel Sparse Approximate Inverse). Now, suppose we want to solve Ax = b. At the heart of AMG there is a series of progressively coarser(smaller) representations of the matrix A. Given an approximation ˆ x to the solution x, consider solving the residual equation Ae = r to find the error e, where r = b −Aˆ x. A fundamental principle of AMG is that it is an algebraically smooth error. To reduce the algebraically smooth errors further, they need to be represented by a smaller defect equation (coarse grid residual equation) A c e c = r c , which is cheaper to solve. After solving this coarse equation, the solution is then interpolated in fine grid represented here by matrix A. The quality of AMG depends on the choice of coarsening and interpolating operators. The sparse approximate inverse approximates the inverse of a matrix A by a sparse matrix M. A technical idea to construct matrix M is to minimize the Frobenuis norm of the residual matrix I −MA. For more details on this preconditioner technics see [?]. HYPRE implement three Krylov subspace solvers: GMRES, PCG and BiCGStab. Installation of HYPRE To install HYPRE, first download the HYPRE package at [?], unpack it and go to the HYPRE/src source directory and do ./configure to configure Hypre. After this just type make all to create libHYPRE.a. Using HYPRE as interface to FreeFem++ Before calling HYPRE solver inside FreeFem++ , you must compile the file hypre FreeFem.cpp to create dynamic library hypre FreeFem.so. To do this, move to the directory src/solver of FreeFem++ , edit the file makefile.inc to specify the following variables: 284 CHAPTER 11. PARALLEL SPARSE SOLVERS HY PRE DIR : Directory of HYPRE HY PRE INCLUDE = -I$(HY PRE DIR)src/hypre/include/ : Directory for header of HYPRE HY PRE LIB = -L$(HIPS DIR)/src/lib/ -lHYPRE : Hypre Library FREEFEM : FreeFem++ directory FREEFEM INCLUDE : FreeFem header for sparse linear solver METIS : METIS directory METIS LIB : METIS library MPI : MPI directory MPI INCLUDE : MPI headers Like with pARMS, the calling of HIPS in FreeFem++ can be done in three manners. We will present only one example where the user specifies its parameters through keywords lparams and dparams. Laplacian 3D solve with HYPRE Let us consider again the 3D Laplacian example inside FreeFem++ package where after discretization we want to solve the linear equation with Hypre. Example 11.6 is the Laplacian3D using Hypre as linear solver. Example 11.6 is the same as 11.5, so we just show here the lines where we set some Hypre parameters. We first load the Hypre solver at line 2. From line 4 to 15 we specifies the parameters to set to Hypre solver and in line 43 we set parameters to Hypre solver. It should be noted that the meaning of the entries of these vectors is different from those of Hips . In the case of HYPRE, the meaning of differents entries of vectors iparm and dparm are given in tables 11.13 to 11.17. In Table ?? the results of running example 11.6 on Cluster Paradent of Grid5000 are reported. We can see in this running example the efficiency of parallelism, in particular when AMG are use as preconditioner. Example 11.6 (Laplacian3D.edp) 1: load "msh3" 2: load "hipre_FreeFem" // load librairie 3: int nn=10,iii; 4: int[int] iparm(20); 5: real[int] dparm(6); 6: for(iii=0;iii<20;iii++)iparm[iii]=-1; 7: for(iii=0;iii<6;iii++) dparm[iii]=-1; 8: iparm[0]=2; // PCG as krylov method 9: iparm[1]=0; // AMG as preconditionner 2: if ParaSails 10:iparm[7]=7; // Interpolation 11:iparm[9]=6; // AMG Coarsen type 12: iparm[10]=1; // Measure type 13: iparm[16]=2; // Additive schwarz as smoother 13:dparm[0]=1e-13; // Tolerance to convergence 14: dparm[1]=5e-4; // Threshold 15: dparm[2]=5e-4; // truncation factor . . . 43: set(Aa,solver=sparsesolver,dparams=dparm, lparams=iparm); 11.3. PARALLEL SPARSE ITERATIVE SOLVER 285 iparms[0] Solver identification: 0: BiCGStab, 1: GMRES, 2: PCG. By default=1 iparms[1] Preconditioner identification: 0: BOOMER AMG, 1: PILUT, 2: Parasails, 3: Schwartz Default=0 iparms[2] Maximum of iteration: Default=1000 iparms[3] Krylov subspace dim: Default= 40 iparms[4] Solver print info level: Default=2 iparms[5] Solver log : Default=1 iparms[6] Solver stopping criteria only for BiCGStab : Default=1 dparms[0] Tolerance for convergence : Default = 1.0e −11 Table 11.13: Definitions of common entries of iparms and dparms vectors for every precon- ditioner in HYPRE iparms[7] AMG interpolation type: Default=6 iparms[8] Specifies the use of GSMG - geometrically smooth coarsening and interpolation: Default=1 iparms[9] AMG coarsen type: Default=6 iparms[10] Defines whether local or global measures are used: Default=1 iparms[11] AMG cycle type: Default=1 iparms[12] AMG Smoother type: Default=1 iparms[13] AMG number of levels for smoothers: Default=3 iparms[14] AMG number of sweeps for smoothers: Default=2 iparms[15] Maximum number of multigrid levels: Default=25 iparms[16] Defines which variant of the Schwartz method is used: 0: hybrid multiplicative Schwartz method (no overlap across processor boundaries) 1: hybrid additive Schwartz method (no overlap across processor boundaries) 2: additive Schwartz method 3: hybrid multiplicative Schwartz method (with overlap across processor boundaries) Default=1 iparms[17] Size of the system of PDEs: Default=1 iparms[18] Overlap for the Schwarz method: Default=1 iparms[19] Type of domain used for the Schwarz method 0: each point is a domain 1: each node is a domain (only of interest in “systems” AMG) 2: each domain is generated by agglomeration (default) dparms[1] AMG strength threshold: Default=0.25 dparms[2] Truncation factor for the interpolation: Default=1e-2 dparms[3] Sets a parameter to modify the definition of strength for diagonal dominant portions of the matrix: Default=0.9 dparms[3] Defines a smoothing parameter for the additive Schwartz method Default=1. Table 11.14: Definitions of other entries of iparms and dparms if preconditioner is BOOMER AMG 286 CHAPTER 11. PARALLEL SPARSE SOLVERS iparms[7] Row size in Parallel ILUT: Default=1000 iparms[8] Set maximum number of iterations: Default=30 dparms[1] Drop tolerance in Parallel ILUT: Default=1e-5 Table 11.15: Definitions of other entries of iparms and dparms if preconditioner is PILUT iparms[7] Number of levels in Parallel Sparse Approximate inverse: Default=1 iparms[8] Symmetric parameter for the ParaSails preconditioner: 0: nonsymmetric and/or indefinite problem, and nonsymmetric preconditioner 1: SPD problem, and SPD (factored) preconditioner 2: nonsymmetric, definite problem, and SPD (factored) preconditioner Default=0 dparms[1] Filters parameters:The filter parameter is used to drop small nonzeros in the preconditioner, to reduce the cost of applying the preconditioner: Default=0.1 dparms[2] Threshold parameter: Default=0.1 Table 11.16: Definitions of other entries of iparms and dparms if preconditioner is ParaSails iparms[7] Defines which variant of the Schwartz method is used: 0: hybrid multiplicative Schwartz method (no overlap across processor boundaries) 1: hybrid additive Schwartz method (no overlap across processor boundaries) 2: additive Schwartz method 3: hybrid multiplicative Schwartz method (with overlap across processor boundaries) Default=1 iparms[8] Overlap for the Schwartz method: Default=1 iparms[9] Type of domain used for the Schwartz method 0: each point is a domain 1: each node is a domain (only of interest in “systems” AMG) 2: each domain is generated by agglomeration (default) Table 11.17: Definitions of other entries of iparms and dparms if preconditionner is Schwartz n=4 10 6 nnz=13 10 6 Te=571,29 np AMG nit time 8 6 1491.83 16 5 708.49 32 4 296.22 64 4 145.64 Table 11.18: Convergence and time for solving linear system from example 11.4 11.4. DOMAIN DECOMPOSITION 287 11.3.4 Conclusion With the different runs presented here, we wanted to illustrate the gain in time when we increase the number of processors used for the simulations. We saw that in every case the time for the construction of the finite element matrix is constant. This is normal because until now this phase is sequential in FreeFem++ . In contrast, phases for solving the linear system are parallel. We saw on several examples presented here that when we increase the number of processors, in general we decrease the time used for solving the linear systems. But this not true in every case. In several case, when we increase the number of processors the time to convergence also increases. There are two main reasons for this. First, the increase of processors can lead to the increase of volume of exchanged data across processors consequently increasing the time for solving the linear systems. Furthermore, in decomposition domain type preconditioners, the number of processors generally corresponds to the number of sub domains. In subdomain methods, generally when we increase the number of subdomains we decrease convergence quality of the preconditioner. This can increase the time used for solving linear equations. To end this, we should note that good use of the preconditioners interfaced in FreeFem++ is empiric, because it is difficult to know what is a good preconditioner for some type of problems. Although, the efficiency of preconditioners sometimes depends on how its parameters are set. For this reason we advise the user to pay attention to the meaning of the parameters in the user guide of the iterative solvers interfaced in FreeFem++ . 11.4 Domain decomposition In the previous section, we saw that the phases to construct a matrix are sequential. One strategy to construct the matrix in parallel is to divide geometrically the domain into subdomains. In every subdomain we construct a local submatrix and after that we assemble every submatrix to form the global matrix. We can use this technique to solve pde directly in domain Ω. In this case, in every subdomains you have to define artificial boundary conditions to form consistent equations in every subdomains. After this, you solve equation in every subdomains and define a strategy to obtain the global solution. In terms of parallel programming for FreeFem++ , with MPI, this means that the user must be able to divide processors avaible for computation into subgroups of processors and also must be able to realize different type of communications in FreeFem++ script. Here is a wrapper of some MPI functions. 11.4.1 Communicators and groups Groups mpiGroup grpe(mpiGroup gp,KN < long >): Create MPI Group from existing group gp by given vector Communicators Communicators is an abstract MPI object which allows MPI user to communicate across group of processors. Communicators can be Intracommunicators(involves a single group) or Intercommunicators (involves two groups). When we not specify type of communicator it will be Intracommunicators mpiComm cc(mpiComm comm, mpiGroup gp): Creates a new communicator. comm communica- tor(handle), gp group which is a subset of the group of comm (handle). Return new communicator 288 CHAPTER 11. PARALLEL SPARSE SOLVERS mpiComm cc(mpiGroup gp): Same as previous constructor but default comm here is MPI COMM WORLD. mpiComm cc(mpiComm comm, int color, int key): Creates new communicators based on colors and key. This constructor is based on MPI Comm split routine of MPI. mpiComm cc(MPIrank p,int key): Same constructor than the last one. Here colors and comm is defined in MPIrank. This constructor is based on MPI Comm split routine of MPI. Example 11.7 (commsplit.edp) 1: int color=mpiRank(comm)%2; 2: mpiComm ccc(processor(color,comm),0); 3: mpiComm qpp(comm,); 4: mpiComm cp(cc,color,0); mpiComm cc(mpiComm comm, int high): Creates an intracommunicator from an intercommunica- tor. comm intercommunicator, high Used to order the groups within comm (logical) when creating the new communicator. This constructor is based on MPI Intercomm merge routine of MPI. mpiComm cc(MPIrank p1, MPIrank p2, int tag): This constructor creates an intercommuncator from two intracommunicators. p1 defined local (intra)communicator and rank in local comm of leader (often 0) while p2 defined remote communicator and rank in peer comm of remote leader (often 0). tag Message tag to use in constructing intercommunicator. This constructor is based on MPI Intercomm create. Example 11.8 (merge.edp) 1: mpiComm comm,cc; 2: int color=mpiRank(comm)%2; 3: int rk=mpiRank(comm); 4: int size=mpiSize(comm); 4: cout << "Color values " << color << endl; 5: mpiComm ccc(processor((rk<size/2),comm),rk); 6: mpiComm cp(cc,color,0); 7: int rleader; 8: if (rk == 0) { rleader = size/2; } 9: else if (rk == size/2) { rleader = 0;} 10: else { rleader = 3; } 11: mpiComm qqp(processor(0,ccc),processor(rleader,comm),12345); 12:int aaa=mpiSize(ccc); 13:cout << "number of processor" << aaa << endl; 11.4.2 Process In FreeFem++ we wrap MPI process by function call processor which create internal FreeFem++ object call MPIrank. This mean that do not use MPIrank in FreeFem++ script. processor(int rk): Keep process rank inside object MPIrank. Rank is inside MPI COMM WORLD. processor(int rk, mpiComm cc) and processor(mpiComm cc,int rk) process rank inside communi- cator cc. processor(int rk, mpiComm cc) and processor(mpiComm cc,int rk) process rank inside communi- cator cc. processorblock(int rk) : This function is exactlly the same than processor(int rk) but is use in case of blocking communication. processorblock(int rk, mpiComm cc) : This function is exactlly the same than processor(int rk,mpiComm cc) but use a synchronization point. 11.4. DOMAIN DECOMPOSITION 289 11.4.3 Points to Points communicators In FreeFem++ you can call MPI points to points communications functions. Send(processor(int rk,mpiComm cc),Data D) : Blocking send of Data D to processor of rank rk inside communicator cc. Note that Data D can be: int, real,complex , int[int], real[int],complex[int], Mesh, Mesh3, Matrix. Recv(processor(int rk,mpiComm cc),Data D): Receive Data D from process of rank rk in com- municator cc. Note that Data D can be: int, real,complex , int[int], real[int],complex[int], Mesh, Mesh3, Matrix and should be the same type than corresponding send. Isend(processor(int rk,mpiComm cc),Data D) : Non blocking send of Data D to processor of rank rk inside communicator cc. Note that Data D can be: int, real,complex , int[int], real[int],complex[int], Mesh, Mesh3, Matrix. Recv(processor(int rk,mpiComm cc),Data D): Receive corresponding to send. 11.4.4 Global operations In FreeFem++ you can call MPI global communication functions. broadcast(processor(int rk,mpiComm cc),Data D): Process rk Broadcast Data D to all process in- side communicator cc. Note that Data D can be: int, real,complex , int[int], real[int],complex[int], Mesh, Mesh3, Matrix. broadcast(processor(int rk),Data D): Process rk Broadcast Data D to all process inside MPI COMM WORLD. Note that Data D can be: int, real,complex , int[int], real[int],complex[int], Mesh, Mesh3, Matrix. mpiAlltoall(Data a,Data b): Sends data a from all to all processes. Receive buffer is Data b. This is done inside communicator MPI COMM WORLD. mpiAlltoall(Data a,Data b, mpiComm cc): Sends data a from all to all processes. Receive buffer is Data b. This is done inside communicator cc. mpiGather(Data a,Data b,processor(mpiComm,int rk) : Gathers together values Data a from a group of processes. Process of rank rk get data on communicator rk. This function is like MPI Gather mpiAllgather(Data a,Data b) : Gathers Data a from all processes and distribute it to all in Data b. This is done inside communicator MPI COMM WORLD. This function is like MPI Allgather mpiAllgather(Data a,Data b, mpiComm cc) : Gathers Data a from all processes and distribute it to all in Data b. This is done inside communicator cc. This function is like MPI Allgather mpiScatter(Data a,Data b,processor(int rk, mpiComm cc)) : Sends Data a from one process whith rank rk to all other processes in group represented by communicator mpiComm cc. mpiReduce(Data a,Data b,processor(int rk, mpiComm cc),MPI Op op), Reduces values Data a on all processes to a single value Data b on process of rank rk and communicator cc. Operation use in reduce is: MPI Op op which can be: mpiMAX, mpiMIN, mpiSUM, mpiPROD, mpiLAND, mpiLOR, mpiLXOR, mpiBAND, mpiBXOR, mpiMAXLOC, mpiMINLOC. Note that, for all global operations, only int[int] and real[int] are data type take in account in FreeFem++ . 290 CHAPTER 11. PARALLEL SPARSE SOLVERS The following example present in details of Schwartz domain decomposition algorithm for solving Laplacian2d problem. In this example we use two level of parallelism to solve simple Laplacian2d in square domain. We have few number of subdomain and in every subdomain we use parallel sparse solver to solve local problem. Example 11.9 (schwarz.edp) 1:load "hypre_FreeFem"; // Load Hypre solver 2:func bool AddLayers(mesh & Th,real[int] &ssd,int n,real[int] &unssd) { // build a continuous function uussd (P1) : // ssd in the caracteristics function on the input sub domain. // such that : // unssd = 1 when ssd =1; // add n layer of element (size of the overlap) // and unssd = 0 ouside of this layer ... // --------------------------------- fespace Vh(Th,P1); fespace Ph(Th,P0); Ph s; assert(ssd.n==Ph.ndof); assert(unssd.n==Vh.ndof); unssd=0; s[]= ssd; // plot(s,wait=1,fill=1); Vh u; varf vM(u,v)=int2d(Th,qforder=1)(u * v/area); matrix M=vM(Ph,Vh); for(int i=0;i<n;++i) { u[]= M * s[]; // plot(u,wait=1); u = u>.1; // plot(u,wait=1); unssd+= u[]; s[]= M’ * u[]; // ’; s = s >0.1; } unssd /= (n); u[]=unssd; ssd=s[]; return true; } 3: mpiComm myComm; // Create communicator with value MPI COMM WORLD 4: int membershipKey,rank,size; // Variables for manage communicators 5: rank=mpiRank(myComm); size=mpiSize(myComm); // Rank of process and size of communicator 6: bool withmetis=1, RAS=0; // Use or not metis for partitioning Mesh 7: int sizeoverlaps=5; // size off overlap 8: int withplot=1; 9: mesh Th=square(100,100); 10: int[int] chlab=[1,1 ,2,1 ,3,1 ,4,1 ]; 11: Th=change(Th,refe=chlab); 12: int nn=2,mm=2, npart= nn * mm; 11.4. DOMAIN DECOMPOSITION 291 13: membershipKey = mpiRank(myComm)%npart; // Coloring for partitioning process group 14: mpiComm cc(processor(membershipKey,myComm),rank); // Create MPI communicator according previous coloring 15: fespace Ph(Th,P0),fespace Vh(Th,P1); 16: Ph part; 17: Vh sun=0,unssd=0; 18: real[int] vsum=sun[],reducesum=sun[]; // Data use for control partitioning. 19: Ph xx=x,yy=y,nupp; 20: part = int(xx * nn) * mm + int(yy * mm); 21: if(withmetis) { load "metis"; int[int] nupart(Th.nt); metisdual(nupart,Th,npart); for(int i=0;i<nupart.n;++i) part[][i]=nupart[i]; } 22: if(withplot>1) 21: plot(part,fill=1,cmm="dual",wait=1); 22: mesh[int] aTh(npart); 23: mesh Thi=Th; 24: fespace Vhi(Thi,P1); 25: Vhi[int] au(npart),pun(npart); 26: matrix[int] Rih(npart), Dih(npart), aA(npart); 27: Vhi[int] auntgv(npart), rhsi(npart); 28: i=membershipKey; Ph suppi= abs(part-i)<0.1; AddLayers(Th,suppi[],sizeoverlaps,unssd[]); Thi=aTh[i]=trunc(Th,suppi>0,label=10,split=1); Rih[i]=interpolate(Vhi,Vh,inside=1); // Vh -> Vhi if(RAS) { suppi= abs(part-i)<0.1; varf vSuppi(u,v)=int2d(Th,qforder=1)(suppi * v/area); unssd[]= vSuppi(0,Vh); unssd = unssd>0.; if(withplot>19) plot(unssd,wait=1); } pun[i][]=Rih[i] * unssd[]; // this is global operation sun[] += Rih[i]’ * pun[i][]; // also global operation like broadcast’; vsum=sun[]; if(withplot>9) plot(part,aTh[i],fill=1,wait=1); // Add mpireduce for sum all sun and pun local contribution. 29: mpiReduce(vsum, reducesum,processor(0,myComm),mpiSUM); // MPI global operation MPi Reduce on global communicator 30: broadcast(processor(0,myComm),reducesum); // Broadcast sum on process 0 to all process 31: sun[]=reducesum; 32: plot(sun,wait=1); 33: i=membershipKey 34: Thi=aTh[i]; 35: pun[i]= pun[i]/sun; 292 CHAPTER 11. PARALLEL SPARSE SOLVERS 36: if(withplot>8) plot(pun[i],wait=1); 37: macro Grad(u) [dx(u),dy(u)] // EOM 38: sun=0; 39: i=membershipKey Thi=aTh[i]; varf va(u,v) = int2d(Thi)(Grad(u)’ * Grad(v)) // ’) +on(1,u=1) + int2d(Th)(v) +on(10,u=0) ; 40: aA[i]=va(Vhi,Vhi); 41: set(aA[i],solver=sparsesolver,mpicomm=cc); // Set parameters for Solver Hypre. mpicomm=cc means you not solve on global process but in group on of process define by cc 42: rhsi[i][]= va(0,Vhi); 43: Dih[i]=pun[i][]; 44: real[int] un(Vhi.ndof); 45: un=1.; 46: real[int] ui=Dih[i] * un; 47: sun[] += Rih[i]’ * ui; // ’; 48: varf vaun(u,v) = on(10,u=1); 49: auntgv[i][]=vaun(0,Vhi); // store arry of tgv on Gamma intern. 56: reducesum=0; vsum=sun; 57: mpiReduce(vsum, reducesum,processor(0,myComm),mpiSUM); // MPI global operation MPi Reduce on global communicator 58: broadcast(processor(0,myComm),reducesum); // Broadcast sum on process 0 to all other process 59: sun[]=reducesum; 60: if(withplot>5) 61: plot(sun,fill=1,wait=1); 62: cout << sun[].max << " " << sun[].min<< endl; 63: assert( 1.-1e-9 <= sun[].min && 1.+1e-9 >= sun[].max); 64: int nitermax=1000; { Vh un=0; for(int iter=0;iter<nitermax;++iter) { real err=0,rerr=0; Vh un1=0; i=membershipKey; Thi=aTh[i]; real[int] ui=Rih[i] * un[]; // ’; real[int] bi = ui . * auntgv[i][]; bi = auntgv[i][] ? bi : rhsi[i][]; ui=au[i][]; ui= aA[i] ˆ-1 * bi; // Solve local linear system on group of process represented by color membershipKey bi = ui-au[i][]; err += bi’ * bi; // ’; au[i][]= ui; bi = Dih[i] * ui; // Prolongation of current solution to obtain right hand un1[] += Rih[i]’ * bi; // ’; } 65: reducesum=0; vsum=un1[]; 66: mpiReduce(vsum, reducesum,processor(0,myComm),mpiSUM); // MPI global operation MPi Reduce on global communicator 11.4. DOMAIN DECOMPOSITION 293 67: broadcast(processor(0,myComm),reducesum); // Broadcast sum on process 0 to all other process 68: un1[]=reducesum; 69: real residrela=0; 70: mpiReduce(err,residrela ,processor(0,myComm),mpiSUM); 71: broadcast(processor(0,myComm),residrela); 72: err=residrela; err= sqrt(err); 73: if(rank==0) cout << iter << " Err = " << err << endl; 74: if(err<1e-5) break; 75: un[]=un1[]; 76: if(withplot>2) 77: plot(au,dim=3,wait=0,cmm=" iter "+iter,fill=1 ); 78: } 79: plot(un,wait=1,dim=3); 80: } 294 CHAPTER 11. PARALLEL SPARSE SOLVERS Chapter 12 Mesh Files 12.1 File mesh data structure The mesh data structure, output of a mesh generation algorithm, refers to the geometric data structure and in some case to another mesh data structure. In this case, the fields are • MeshVersionFormatted 0 • Dimension (I) dim • Vertices (I) NbOfVertices ( ((R) x j i , j=1,dim) , (I) Refφ v i , i=1 , NbOfVertices ) • Edges (I) NbOfEdges (@@Vertex 1 i , @@Vertex 2 i , (I) Refφ e i , i=1 , NbOfEdges ) • Triangles (I) NbOfTriangles ((@@Vertex j i , j=1,3 ), (I) Refφ t i , i=1 , NbOfTriangles ) • Quadrilaterals (I) NbOfQuadrilaterals ((@@Vertex j i , j=1,4 ), (I) Refφ t i , i=1 , NbOfQuadrilaterals ) • Geometry (C * ) FileNameOfGeometricSupport – VertexOnGeometricVertex (I) NbOfVertexOnGeometricVertex (@@Vertex i , @@Vertex geo i , i=1,NbOfVertexOnGeometricVertex ) – EdgeOnGeometricEdge (I) NbOfEdgeOnGeometricEdge (@@Edge i , @@Edge geo i , i=1,NbOfEdgeOnGeometricEdge ) • CrackedEdges (I) NbOfCrackedEdges (@@Edge 1 i , @@Edge 2 i , i=1 , NbOfCrackedEdges ) 295 296 CHAPTER 12. MESH FILES When the current mesh refers to a previous mesh, we have in addition • MeshSupportOfVertices (C * ) FileNameOfMeshSupport – VertexOnSupportVertex (I) NbOfVertexOnSupportVertex (@@Vertex i , @@Vertex supp i , i=1,NbOfVertexOnSupportVertex ) – VertexOnSupportEdge (I) NbOfVertexOnSupportEdge (@@Vertex i , @@Edge supp i , (R) u supp i , i=1,NbOfVertexOnSupportEdge ) – VertexOnSupportTriangle (I) NbOfVertexOnSupportTriangle (@@Vertex i , @@Tria supp i , (R) u supp i , (R) v supp i , i=1 , NbOfVertexOnSupportTriangle ) – VertexOnSupportQuadrilaterals (I) NbOfVertexOnSupportQuadrilaterals (@@Vertex i , @@Quad supp i , (R) u supp i , (R) v supp i , i=1 , NbOfVertexOnSupportQuadrilaterals ) 12.2 bb File type for Store Solutions The file is formatted such that: 2 nbsol nbv 2 ((U ij , ∀i ∈ ¦1, ..., nbsol¦) , ∀j ∈ ¦1, ..., nbv¦) where • nbsol is a integer equal to the number of solutions. • nbv is a integer equal to the number of vertex . • U ij is a real equal the value of the i solution at vertex j on the associated mesh background if read file, generated if write file. 12.3 BB File Type for Store Solutions The file is formatted such that: 2 n typesol 1 ... typesol n nbv 2 U k ij , ∀i ∈ ¦1, ..., typesol k ¦ , ∀k ∈ ¦1, ...n¦ ∀j ∈ ¦1, ..., nbv¦ where • n is a integer equal to the number of solutions • typesol k , type of the solution number k, is 12.4. METRIC FILE 297 – typesol k = 1 the solution k is scalar (1 value per vertex) – typesol k = 2 the solution k is vectorial (2 values per unknown) – typesol k = 3 the solution k is a 22 symmetric matrix (3 values per vertex) – typesol k = 4 the solution k is a 22 matrix (4 values per vertex) • nbv is a integer equal to the number of vertices • U k ij is a real equal to the value of the component i of the solution k at vertex j on the associated mesh background if read file, generated if write file. 12.4 Metric File A metric file can be of two types, isotropic or anisotropic. the isotropic file is such that nbv 1 h i ∀i ∈ ¦1, ..., nbv¦ where • nbv is a integer equal to the number of vertices. • h i is the wanted mesh size near the vertex i on background mesh, the metric is ´ i = h −2 i Id, where Id is the identity matrix. The metric anisotrope nbv 3 a11 i ,a21 i ,a22 i ∀i ∈ ¦1, ..., nbv¦ where • nbv is a integer equal to the number of vertices, • a11 i , a12 i , a22 i is metric ´ i = a11 i a12 i a12 i a22 i which define the wanted mesh size in a vicinity of the vertex i such that h in direction u ∈ R 2 is equal to [u[/ √ u ´ i u , where is the dot product in R 2 , and [ [ is the classical norm. 12.5 List of AM FMT, AMDBA Meshes The mesh is only composed of triangles and can be defined with the help of the following two integers and four arrays: nbt is the number of triangles. nbv is the number of vertices. nu(1:3,1:nbt) is an integer array giving the three vertex numbers counterclockwise for each triangle. 298 CHAPTER 12. MESH FILES c(1:2,nbv) is a real array giving the two coordinates of each vertex. refs(nbv) is an integer array giving the reference numbers of the vertices. reft(nbv) is an integer array giving the reference numbers of the triangles. AM FMT Files In fortran the am fmt files are read as follows: open(1,file=’xxx.am_fmt’,form=’formatted’,status=’old’) read (1, * ) nbv,nbt read (1, * ) ((nu(i,j),i=1,3),j=1,nbt) read (1, * ) ((c(i,j),i=1,2),j=1,nbv) read (1, * ) ( reft(i),i=1,nbt) read (1, * ) ( refs(i),i=1,nbv) close(1) AM Files In fortran the am files are read as follows: open(1,file=’xxx.am’,form=’unformatted’,status=’old’) read (1, * ) nbv,nbt read (1) ((nu(i,j),i=1,3),j=1,nbt), & ((c(i,j),i=1,2),j=1,nbv), & ( reft(i),i=1,nbt), & ( refs(i),i=1,nbv) close(1) AMDBA Files In fortran the amdba files are read as follows: open(1,file=’xxx.amdba’,form=’formatted’,status=’old’) read (1, * ) nbv,nbt read (1, * ) (k,(c(i,k),i=1,2),refs(k),j=1,nbv) read (1, * ) (k,(nu(i,k),i=1,3),reft(k),j=1,nbt) close(1) msh Files First, we add the notions of boundary edges nbbe is the number of boundary edge. nube(1:2,1:nbbe) is an integer array giving the two vertex numbers refbe(1:nbbe) is an integer array giving the two vertex numbers In fortran the msh files are read as follows: open(1,file=’xxx.msh’,form=’formatted’,status=’old’) read (1, * ) nbv,nbt,nbbe read (1, * ) ((c(i,k),i=1,2),refs(k),j=1,nbv) read (1, * ) ((nu(i,k),i=1,3),reft(k),j=1,nbt) read (1, * ) ((ne(i,k),i=1,2), refbe(k),j=1,nbbe) close(1) 12.5. LIST OF AM FMT, AMDBA MESHES 299 ftq Files In fortran the ftq files are read as follows: open(1,file=’xxx.ftq’,form=’formatted’,status=’old’) read (1, * ) nbv,nbe,nbt,nbq read (1, * ) (k(j),(nu(i,j),i=1,k(j)),reft(j),j=1,nbe) read (1, * ) ((c(i,k),i=1,2),refs(k),j=1,nbv) close(1) where if k(j) = 3 then the element j is a triangle and if k = 4 the the element j is a quadrilateral. 300 CHAPTER 12. MESH FILES Chapter 13 Addition of a new finite element 13.1 Some notations For a function f taking value in R N , N = 1, 2, , we define the finite element approximation Π h f of f. Let us denote the number of the degrees of freedom of the finite element by NbDoF. Then the i-th base ω K i (i = 0, , NbDoF − 1) of the finite element space has the j-th component ω K ij for j = 0, , N −1. The operator Π h is called the interpolator of the finite element. We have the identity ω K i = Π h ω K i . Formally, the interpolator Π h is constructed by the following formula: Π h f = kPi−1 ¸ k=0 α k f j k (P p k )ω K i k (13.1) where P p is a set of npPi points, In the formula (13.1), the list p k , j k , i k depend just on the type of finite element (not on the element), but the coefficient α k can be depending on the element. Example 1: with the classical scalar Lagrange finite element, we have kPi = npPi = NbOfNode and • P p is the point of the nodal points • the α k = 1, because we take the value of the function at the point P k • p k = k , j k = k because we have one node per function. • j k = 0 because N = 1 Example 2: The Raviart-Thomas finite element: RT0 h = ¦v ∈ H(div)/∀K ∈ T h v |K (x, y) = α K β K +γ K [ x y ¦ (13.2) The degrees of freedom are the flux through an edge e of the mesh, where the flux of the function f : R 2 −→ R 2 is e f .n e , n e is the unit normal of edge e (this implies a orientation of all the edges of the mesh, for example we can use the global numbering of the edge vertices and we just go to small to large number). To compute this flux, we use a quadrature formula with one point, the middle point of the edge. Consider a triangle T with three vertices (a, b, c). Let denote the vertices numbers by i a , i b , i c , and define the three edge vectors e 0 , e 1 , e 2 by sgn(i b −i c )(b−c), sgn(i c −i a )(c−a), sgn(i a −i b )(a−b), The three basis functions are: ω K 0 = sgn(i b −i c ) 2[T[ (x −a), ω K 1 = sgn(i c −i a ) 2[T[ (x −b), ω K 2 = sgn(i a −i b ) 2[T[ (x −c), (13.3) 301 302 CHAPTER 13. ADDITION OF A NEW FINITE ELEMENT where [T[ is the area of the triangle T. So we have N = 2, kPi = 6; npPi = 3; and: • P p = ¸ b+c 2 , a+c 2 , b+a 2 ¸ • α 0 = −e 0 2 , α 1 = e 0 1 , α 2 = −e 1 2 , α 3 = e 1 1 , α 4 = −e 2 2 , α 5 = e 2 1 (effectively, the vector (−e m 2 , e m 1 ) is orthogonal to the edge e m = (e m 1 , e m 2 ) with a length equal to the side of the edge or equal to e m 1). • i k = ¦0, 0, 1, 1, 2, 2¦, • p k = ¦0, 0, 1, 1, 2, 2¦ , j k = ¦0, 1, 0, 1, 0, 1, 0, 1¦. 13.2 Which class to add? Add file FE ADD.cpp in directory src/femlib for example first to initialize : #include "error.hpp" #include "rgraph.hpp" using namespace std; #include "RNM.hpp" #include "fem.hpp" #include "FESpace.hpp" #include "AddNewFE.h" namespace Fem2D { Then add a class which derive for public TypeOfFE like: class TypeOfFE_RTortho : public TypeOfFE { public: static int Data[]; // some numbers TypeOfFE_RTortho(): TypeOfFE( 0+3+0, // nb degree of freedom on element 2, // dimension N of vectorial FE (1 if scalar FE) Data, // the array data 1, // nb of subdivision for plotting 1, // nb of sub finite element (generaly 1) 6, // number kPi of coef to build the interpolator (13.1) 3, // number npPi of integration point to build interpolator 0 // an array to store the coef α k to build interpolator // here this array is no constant so we have // to rebuilt for each element. ) { const R2 Pt[] = { R2(0.5,0.5), R2(0.0,0.5), R2(0.5,0.0) }; // the set of Point in ˆ K for (int p=0,kk=0;p<3;p++) { P_Pi_h[p]=Pt[p]; for (int j=0;j<2;j++) pij_alpha[kk++]= IPJ(p,p,j); }} // definition of i k , p k , j k in (13.1) void FB(const bool * watdd, const Mesh & Th,const Triangle & K, const R2 &PHat, RNMK_ & val) const; 13.2. WHICH CLASS TO ADD? 303 void Pi_h_alpha(const baseFElement & K,KN_<double> & v) const ; } ; where the array data is form with the concatenation of five array of size NbDoF and one array of size N. This array is: int TypeOfFE_RTortho::Data[]={ // for each df 0,1,3 : 3,4,5,// the support of the node of the df 0,0,0,// the number of the df on the node 0,1,2,// the node of the df 0,0,0,// the df come from which FE (generally 0) 0,1,2,// which are de df on sub FE 0,0 };// for each component j = 0, N −1 it give the sub FE associated where the support is a number 0, 1, 2 for vertex support, 3, 4, 5 for edge support, and finaly 6 for element support. The function to defined the function ω K i , this function return the value of all the basics function or this derivatives in array val, computed at point PHat on the reference triangle corresponding to point R2 P=K(Phat); on the current triangle K. The index i, j, k of the array val(i, j, k) corresponding to: i is basic function number on finite element i ∈ [0, NoF[ j is the value of component j ∈ [0, N[ k is the type of computed value f(P), dx(f)(P), dy(f)(P), ... i ∈ [0, last operatortype[. Remark for optimization, this value is computed only if whatd[k] is true, and the numbering is defined with enum operatortype { op_id=0, op_dx=1,op_dy=2, op_dxx=3,op_dyy=4, op_dyx=5,op_dxy=5, op_dz=6, op_dzz=7, op_dzx=8,op_dxz=8, op_dzy=9,op_dyz=9 }; const int last_operatortype=10; The shape function : void TypeOfFE_RTortho::FB(const bool * whatd,const Mesh & Th,const Triangle & K, const R2 & PHat,RNMK_ & val) const { // R2 P(K(PHat)); R2 A(K[0]), B(K[1]),C(K[2]); R l0=1-P.x-P.y,l1=P.x,l2=P.y; assert(val.N() >=3); assert(val.M()==2 ); val=0; 304 CHAPTER 13. ADDITION OF A NEW FINITE ELEMENT R a=1./(2 * K.area); R a0= K.EdgeOrientation(0) * a ; R a1= K.EdgeOrientation(1) * a ; R a2= K.EdgeOrientation(2) * a ; // ------------ if (whatd[op_id]) // value of the function { assert(val.K()>op_id); RN_ f0(val(’.’,0,0)); // value first component RN_ f1(val(’.’,1,0)); // value second component f1[0] = (P.x-A.x) * a0; f0[0] = -(P.y-A.y) * a0; f1[1] = (P.x-B.x) * a1; f0[1] = -(P.y-B.y) * a1; f1[2] = (P.x-C.x) * a2; f0[2] = -(P.y-C.y) * a2; } // ---------------- if (whatd[op_dx]) // value of the dx of function { assert(val.K()>op_dx); val(0,1,op_dx) = a0; val(1,1,op_dx) = a1; val(2,1,op_dx) = a2; } if (whatd[op_dy]) { assert(val.K()>op_dy); val(0,0,op_dy) = -a0; val(1,0,op_dy) = -a1; val(2,0,op_dy) = -a2; } for (int i= op_dy; i< last_operatortype ; i++) if (whatd[op_dx]) assert(op_dy); } The function to defined the coefficient α k : void TypeOfFE_RT::Pi_h_alpha(const baseFElement & K,KN_<double> & v) const { const Triangle & T(K.T); for (int i=0,k=0;i<3;i++) { R2 E(T.Edge(i)); R signe = T.EdgeOrientation(i) ; v[k++]= signe * E.y; v[k++]=-signe * E.x; } } 13.2. WHICH CLASS TO ADD? 305 Now , we just need to add a new key work in FreeFem++, Two way, with static or dynamic link so at the end of the file, we add : With dynamic link is very simple (see section C of appendix), just add before the end of FEM2d namespace add: static TypeOfFE_RTortho The_TypeOfFE_RTortho; // static AddNewFE("RT0Ortho", The_TypeOfFE_RTortho); } // FEM2d namespace Try with ”./load.link” command in examples++-load/ and see BernardiRaugel.cpp or Morley.cpp new finite element examples. Otherwise with static link (for expert only), add // let the 2 globals variables static TypeOfFE_RTortho The_TypeOfFE_RTortho; // // ----- the name in freefem ---- static ListOfTFE typefemRTOrtho("RT0Ortho", & The_TypeOfFE_RTortho); // // link with FreeFem++ do not work with static library .a // FH so add a extern name to call in init static FE // (see end of FESpace.cpp) void init_FE_ADD() { }; // --- end -- } // FEM2d namespace To inforce in loading of this new finite element, we have to add the two new lines close to the end of files src/femlib/FESpace.cpp like: // correct Problem of static library link with new make file void init_static_FE() { // list of other FE file.o extern void init_FE_P2h() ; init_FE_P2h() ; extern void init_FE_ADD() ; // new line 1 init_FE_ADD(); // new line 2 } and now you have to change the makefile. First, create a file FE ADD.cpp contening all this code, like in file src/femlib/Element P2h.cpp, after modifier the Makefile.am by adding the name of your file to the variable EXTRA DIST like: # Makefile using Automake + Autoconf # ---------------------------------- # $Id$ # This is not compiled as a separate library because its # interconnections with other libraries have not been solved. EXTRA_DIST=BamgFreeFem.cpp BamgFreeFem.hpp CGNL.hpp CheckPtr.cpp \ ConjuguedGradrientNL.cpp DOperator.hpp Drawing.cpp Element_P2h.cpp \ 306 CHAPTER 13. ADDITION OF A NEW FINITE ELEMENT Element_P3.cpp Element_RT.cpp fem3.hpp fem.cpp fem.hpp FESpace.cpp \ FESpace.hpp FESpace-v0.cpp FQuadTree.cpp FQuadTree.hpp gibbs.cpp \ glutdraw.cpp gmres.hpp MatriceCreuse.hpp MatriceCreuse_tpl.hpp \ MeshPoint.hpp mortar.cpp mshptg.cpp QuadratureFormular.cpp \ QuadratureFormular.hpp RefCounter.hpp RNM.hpp RNM_opc.hpp RNM_op.hpp \ RNM_tpl.hpp FE_ADD.cpp and do in the freefem++ root directory autoreconf ./reconfigure make For codewarrior compilation add the file in the project an remove the flag in panal PPC linker FreeFEm++ Setting Dead-strip Static Initializition Code Flag. Appendix A Table of Notations Here mathematical expressions and corresponding FreeFem++ commands are explained. A.1 Generalities δ ij Kronecker delta (0 if i = j, 1 if i = j for integers i, j) ∀ for all ∃ there exist i.e. that is PDE partial differential equation (with boundary conditions) ∅ the empty set N the set of integers (a ∈ N ⇔int a); “int” means long integer inside FreeFem++ R the set of real numbers (a ∈ R ⇔real a) ;double inside FreeFem++ C the set of complex numbers (a ∈ C ⇔complex a); complex¡double¿ R d d-dimensional Euclidean space A.2 Sets, Mappings, Matrices, Vectors Let E, F, G be three sets and A subset of E. ¦x ∈ E[ P¦ the subset of E consisting of the elements possessing the property P E ∪ F the set of elements belonging to E or F E ∩ F the set of elements belonging to E and F E ` A the set ¦x ∈ E[ x ∈ A¦ E + F E ∪ F with E ∩ F = ∅ 307 308 APPENDIX A. TABLE OF NOTATIONS E F the cartesian product of E and F E n the n-th power of E (E 2 = E E, E n = E E n−1 ) f : E →F the mapping form E into F, i.e., E ÷ x →f(x) ∈ F I E or I the identity mapping in E,i.e., I(x) = x ∀x ∈ E f ◦ g for f : F →G and g : E →F, E ÷ x →(f ◦ g)(x) = f(g(x)) ∈ G (see Section ??) f[ A the restriction of f : E →F to the subset A of E ¦a k ¦ column vector with components a k (a k ) row vector with components a k (a k ) T denotes the transpose of a matrix (a k ), and is ¦a k ¦ ¦a ij ¦ matrix with components a ij , and (a ij ) T = (a ji ) A.3 Numbers For two real numbers a, b [a, b] is the interval ¦x ∈ R[ a ≤ x ≤ b¦ ]a, b] is the interval ¦x ∈ R[ a < x ≤ b¦ [a, b[ is the interval ¦x ∈ R[ a ≤ x < b¦ ]a, b[ is the interval ¦x ∈ R[ a < x < b¦ A.4 Differential Calculus ∂f/∂x the partial derivative of f : R d →R with respect to x ( dx(f)) ∇f the gradient of f : Ω →R,i.e., ∇f = (∂f/∂x, ∂f/∂y) divf or ∇.f the divergence of f : Ω →R d , i.e., divf = ∂f 1 /∂x + ∂f 2 /∂y ∆f the Laplacian of f : Ω →R, i.e., ∆f = ∂ 2 f/∂x 2 + ∂ 2 f/∂y 2 A.5. MESHES 309 A.5 Meshes Ω usually denotes a domain on which PDE is defined Γ denotes the boundary of Ω,i.e., Γ = ∂Ω (keyword border, see Section 5.1.2) T h the triangulation of Ω, i.e., the set of triangles T k , where h stands for mesh size (keyword mesh, buildmesh, see Section 5) n t the number of triangles in T h (get by Th.nt, see “mesh.edp”) Ω h denotes the approximated domain Ω h = ∪ n t k=1 T k of Ω. If Ω is polygonal domain, then it will be Ω = Ω h Γ h the boundary of Ω h n v the number of vertices in T h (get by Th.nv) [q i q j ] the segment connecting q i and q j q k 1 , q k 2 , q k 3 the vertices of a triangle T k with anti-clock direction (get the coordinate of q k j by (Th[k-1][j-1].x, Th[k-1][j-1].y)) I Ω the set ¦i ∈ N[ q i ∈ Γ h ¦ A.6 Finite Element Spaces L 2 (Ω) the set w(x, y) Ω [w(x, y)[ 2 dxdy < ∞ norm: |w| 0,Ω = Ω [w(x, y)[ 2 dxdy 1/2 scalar product: (v, w) = Ω vw H 1 (Ω) the set w ∈ L 2 (Ω) Ω [∂w/∂x[ 2 +[∂w/∂y[ 2 dxdy < ∞ norm: |w| 1,Ω = |w| 2 0,Ω +|∇u| 2 0.Ω 1/2 H m (Ω) the set w ∈ L 2 (Ω) Ω ∂ |α| w ∂x α 1 ∂y α 2 ∈ L 2 (Ω) ∀α = (α 1 , α 2 ) ∈ N 2 , [α[ = α 1 + α 2 scalar product: (v, w) 1,Ω = ¸ |α|≤m Ω D α vD α w H 1 0 (Ω) the set ¦w ∈ H 1 (Ω) [ u = 0 on Γ¦ 310 APPENDIX A. TABLE OF NOTATIONS L 2 (Ω) 2 denotes L 2 (Ω) L 2 (Ω), and also H 1 (Ω) 2 = H 1 (Ω) H 1 (Ω) V h denotes the finite element space created by “ fespace Vh(Th,*)” in FreeFem++ (see Section 6 for “*”) Π h f the projection of the function f into V h (“ func f=xˆ2 * yˆ3; Vh v = f;” means v = Π h f) ¦v¦ for FE-function v in V h means the column vector (v 1 , , v M ) T if v = v 1 φ 1 + +v M φ M , which is shown by “ fespace Vh(Th,P2); Vh v; cout << v[] << endl;” Appendix B Grammar B.1 The bison grammar start: input ENDOFFILE; input: instructions ; instructions: instruction | instructions instruction ; list_of_id_args: | id | id ’=’ no_comma_expr | FESPACE id | type_of_dcl id | type_of_dcl ’&’ id | ’[’ list_of_id_args ’]’ | list_of_id_args ’,’ id | list_of_id_args ’,’ ’[’ list_of_id_args ’]’ | list_of_id_args ’,’ id ’=’ no_comma_expr | list_of_id_args ’,’ FESPACE id | list_of_id_args ’,’ type_of_dcl id | list_of_id_args ’,’ type_of_dcl ’&’ id ; list_of_id1: id | list_of_id1 ’,’ id ; id: ID | FESPACE ; list_of_dcls: ID | ID ’=’ no_comma_expr | ID ’(’ parameters_list ’)’ | list_of_dcls ’,’ list_of_dcls ; parameters_list: no_set_expr | FESPACE ID | ID ’=’ no_set_expr 311 312 APPENDIX B. GRAMMAR | parameters_list ’,’ no_set_expr | parameters_list ’,’ id ’=’ no_set_expr ; type_of_dcl: TYPE | TYPE ’[’ TYPE ’]’ ; ID_space: ID | ID ’[’ no_set_expr ’]’ | ID ’=’ no_set_expr | ’[’ list_of_id1 ’]’ | ’[’ list_of_id1 ’]’ ’[’ no_set_expr ’]’ | ’[’ list_of_id1 ’]’ ’=’ no_set_expr ; ID_array_space: ID ’(’ no_set_expr ’)’ | ’[’ list_of_id1 ’]’ ’(’ no_set_expr ’)’ ; fespace: FESPACE ; spaceIDa : ID_array_space | spaceIDa ’,’ ID_array_space ; spaceIDb : ID_space | spaceIDb ’,’ ID_space ; spaceIDs : fespace spaceIDb | fespace ’[’ TYPE ’]’ spaceIDa ; fespace_def: ID ’(’ parameters_list ’)’ ; fespace_def_list: fespace_def | fespace_def_list ’,’ fespace_def ; declaration: type_of_dcl list_of_dcls ’;’ | ’fespace’ fespace_def_list ’;’ | spaceIDs ’;’ | FUNCTION ID ’=’ Expr ’;’ | FUNCTION type_of_dcl ID ’(’ list_of_id_args ’)’ ’{’ instructions’}’ | FUNCTION ID ’(’ list_of_id_args ’)’ ’=’ no_comma_expr ’;’ ; begin: ’{’ ; end: ’}’ ; for_loop: ’for’ ; while_loop: ’while’ ; instruction: ’;’ | ’include’ STRING | ’load’ STRING | Expr ’;’ | declaration | for_loop ’(’ Expr ’;’ Expr ’;’ Expr ’)’ instruction | while_loop ’(’ Expr ’)’ instruction | ’if’ ’(’ Expr ’)’ instruction B.1. THE BISON GRAMMAR 313 | ’if’ ’(’ Expr ’)’ instruction ELSE instruction | begin instructions end | ’border’ ID border_expr | ’border’ ID ’[’ array ’]’ ’;’ | ’break’ ’;’ | ’continue’ ’;’ | ’return’ Expr ’;’ ; bornes: ’(’ ID ’=’ Expr ’,’ Expr ’)’ ; border_expr: bornes instruction ; Expr: no_comma_expr | Expr ’,’ Expr ; unop: ’-’ | ’+’ | ’!’ | ’++’ | ’--’ ; no_comma_expr: no_set_expr | no_set_expr ’=’ no_comma_expr | no_set_expr ’+=’ no_comma_expr | no_set_expr ’-=’ no_comma_expr | no_set_expr ’ * =’ no_comma_expr | no_set_expr ’/=’ no_comma_expr ; no_set_expr: no_ternary_expr | no_ternary_expr ’?’ no_set_expr ’:’ no_set_expr ; no_ternary_expr: unary_expr | no_ternary_expr ’ * ’ no_ternary_expr | no_ternary_expr ’. * ’ no_ternary_expr | no_ternary_expr ’./’ no_ternary_expr | no_ternary_expr ’/’ no_ternary_expr | no_ternary_expr ’%’ no_ternary_expr | no_ternary_expr ’+’ no_ternary_expr | no_ternary_expr ’-’ no_ternary_expr | no_ternary_expr ’<<’ no_ternary_expr | no_ternary_expr ’>>’ no_ternary_expr | no_ternary_expr ’&’ no_ternary_expr | no_ternary_expr ’&&’ no_ternary_expr | no_ternary_expr ’|’ no_ternary_expr | no_ternary_expr ’||’ no_ternary_expr | no_ternary_expr ’<’ no_ternary_expr | no_ternary_expr ’<=’ no_ternary_expr | no_ternary_expr ’>’ no_ternary_expr | no_ternary_expr ’>=’ no_ternary_expr 314 APPENDIX B. GRAMMAR | no_ternary_expr ’==’ no_ternary_expr | no_ternary_expr ’!=’ no_ternary_expr ; sub_script_expr: no_set_expr | ’:’ | no_set_expr ’:’ no_set_expr | no_set_expr ’:’ no_set_expr ’:’ no_set_expr ; parameters: | no_set_expr | FESPACE | id ’=’ no_set_expr | sub_script_expr | parameters ’,’ FESPACE | parameters ’,’ no_set_expr | parameters ’,’ id ’=’ no_set_expr ; array: no_comma_expr | array ’,’ no_comma_expr ; unary_expr: pow_expr | unop pow_expr %prec UNARY ; pow_expr: primary | primary ’ˆ’ unary_expr | primary ’_’ unary_expr | primary ’ ´ ’ ; // transpose primary: ID | LNUM | DNUM | CNUM | STRING | primary ’(’ parameters ’)’ | primary ’[’ Expr ’]’ | primary ’[’ ’]’ | primary ’.’ ID | primary ’++’ | primary ’--’ | TYPE ’(’ Expr ’)’ ; | ’(’ Expr ’)’ | ’[’ array ’]’ ; B.2. THE TYPES OF THE LANGUAGES, AND CAST 315 B.2 The Types of the languages, and cast B.3 All the operators - CG, type :<TypeSolveMat> - Cholesky, type :<TypeSolveMat> - Crout, type :<TypeSolveMat> - GMRES, type :<TypeSolveMat> - LU, type :<TypeSolveMat> - LinearCG, type :<Polymorphic> operator() : ( <long> : <Polymorphic>, <KN<double> * >, <KN<double> * > ) - N, type :<Fem2D::R3> - NoUseOfWait, type :<bool * > - P, type :<Fem2D::R3> - P0, type :<Fem2D::TypeOfFE> - P1, type :<Fem2D::TypeOfFE> - P1nc, type :<Fem2D::TypeOfFE> - P2, type :<Fem2D::TypeOfFE> - RT0, type :<Fem2D::TypeOfFE> - RTmodif, type :<Fem2D::TypeOfFE> - abs, type :<Polymorphic> operator() : ( <double> : <double> ) - acos, type :<Polymorphic> operator() : ( <double> : <double> ) - acosh, type :<Polymorphic> operator() : ( <double> : <double> ) - adaptmesh, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>... ) - append, type :<std::ios_base::openmode> - asin, type :<Polymorphic> operator() : ( <double> : <double> ) - asinh, type :<Polymorphic> operator() : ( <double> : <double> ) - atan, type :<Polymorphic> operator() : ( <double> : <double> ) ( <double> : <double>, <double> ) - atan2, type :<Polymorphic> operator() : ( <double> : <double>, <double> ) - atanh, type :<Polymorphic> operator() : ( <double> : <double> ) 316 APPENDIX B. GRAMMAR - buildmesh, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <E_BorderN> ) - buildmeshborder, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <E_BorderN> ) - cin, type :<istream> - clock, type :<Polymorphic> ( <double> : ) - conj, type :<Polymorphic> operator() : ( <complex> : <complex> ) - convect, type :<Polymorphic> operator() : ( <double> : <E_Array>, <double>, <double> ) - cos, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) - cosh, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) - cout, type :<ostream> - dumptable, type :<Polymorphic> operator() : ( <ostream> : <ostream> ) - dx, type :<Polymorphic> operator() : ( <LinearComb<MDroit, C_F0>> : <LinearComb<MDroit, C_F0>> ) ( <double> : <std::pair<FEbase<double> * , int>> ) ( <LinearComb<MGauche, C_F0>> : <LinearComb<MGauche, C_F0>> ) - dy, type :<Polymorphic> operator() : ( <LinearComb<MDroit, C_F0>> : <LinearComb<MDroit, C_F0>> ) ( <double> : <std::pair<FEbase<double> * , int>> ) ( <LinearComb<MGauche, C_F0>> : <LinearComb<MGauche, C_F0>> ) - endl, type :<char> - exec, type :<Polymorphic> operator() : ( <long> : <string> ) - exit, type :<Polymorphic> operator() : ( <long> : <long> ) - exp, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) B.3. ALL THE OPERATORS 317 - false, type :<bool> - imag, type :<Polymorphic> operator() : ( <double> : <complex> ) - int1d, type :<Polymorphic> operator() : ( <CDomainOfIntegration> : <Fem2D::Mesh>... ) - int2d, type :<Polymorphic> operator() : ( <CDomainOfIntegration> : <Fem2D::Mesh>... ) - intalledges, type :<Polymorphic> operator( : ( <CDomainOfIntegration> : <Fem2D::Mesh>... ) - jump, type :<Polymorphic> operator( : ( <LinearComb<MDroit, C_F0>> : <LinearComb<MDroit, C_F0>> ) ( <double> : <double> ) ( <complex > : <complex > ) ( <LinearComb<MGauche, C_F0>> : <LinearComb<MGauche, C_F0>> ) - label, type :<long * > - log, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) - log10, type :<Polymorphic> operator() : ( <double> : <double> ) - max, type :<Polymorphic> operator() : ( <double> : <double>, <double> ) ( <long> : <long>, <long> ) - mean, type :<Polymorphic> operator( : ( <double> : <double> ) ( <complex> : <complex> ) - min, type :<Polymorphic> operator() : ( <double> : <double>, <double> ) ( <long> : <long>, <long> ) - movemesh, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>, <E_Array>... ) - norm, type :<Polymorphic> operator( : ( <double> : <std::complex<double>> ) - nuTriangle, type :<long> 318 APPENDIX B. GRAMMAR - nuEdge, type :<long> - on, type :<Polymorphic> operator() : ( <BC_set<double>> : <long>... ) - otherside, type :<Polymorphic> operator( : ( <LinearComb<MDroit, C_F0>> : <LinearComb<MDroit, C_F0>> ) ( <LinearComb<MGauche, C_F0>> : <LinearComb<MGauche, C_F0>> ) - pi, type :<double> - plot, type :<Polymorphic> operator() : ( <long> : ... ) - pow, type :<Polymorphic> operator() : ( <double> : <double>, <double> ) ( <complex> : <complex>, <complex> ) - qf1pE, type :<Fem2D::QuadratureFormular1d> - qf1pT, type :<Fem2D::QuadratureFormular> - qf1pTlump, type :<Fem2D::QuadratureFormular> - qf2pE, type :<Fem2D::QuadratureFormular1d> - qf2pT, type :<Fem2D::QuadratureFormular> - qf2pT4P1, type :<Fem2D::QuadratureFormular> - qf3pE, type :<Fem2D::QuadratureFormular1d> - qf5pT, type :<Fem2D::QuadratureFormular> - readmesh, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <string> ) - real, type :<Polymorphic> operator() : ( <double> : <complex> ) - region, type :<long * > - savemesh, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>, <string>... ) - sin, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) - sinh, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) - sqrt, type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) - square, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <long>, <long> ) B.3. ALL THE OPERATORS 319 ( <Fem2D::Mesh> : <long>, <long>, <E_Array> ) - tan, type :<Polymorphic> operator() : ( <double> : <double> ) - true, type :<bool> - trunc, type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>, <bool> ) - verbosity, type :<long * > - wait, type :<bool * > - x, type :<double * > - y, type :<double * > - z, type :<double * > 320 APPENDIX B. GRAMMAR Appendix C Dynamical link Now, it’s possible to add built-in functionnalites in FreeFem++ under the three environnents Linux, Windows and MacOS X 10.3 or newer. It is agood idea to, first try the example load.edp in directory example++-load. You will need to install a c++ compiler (generally g++/gcc compiler) to compile your function. Windows Install the cygwin environnent or the mingw MacOs Install the developer tools xcode on the apple DVD Linux/Unix Install the correct compiler (gcc for instance) Now, assume that you are in a shell window (a cygwin window under Windows) in the directory example++-load. Remark that in the sub directory include they are all the FreeFem++ include file to make the link with FreeFem++. Note C.1 If you try to load dynamically a file with command load "xxx" • Under unix (Linux or MacOs), the file xxx.so twill be loaded so it must be either in the search directory of routine dlopen (see the environment variable $LD_LIBRARY_PATH or in the current directory, and the suffix ".so" or the prefix "./" is automatically added. • Under Windows, The file xxx.dll will be loaded so it must be in the loadLibary search directory which includes the directory of the application, The compilation of your module: the script ff-c++ compiles and makes the link with FreeFem++, but be careful, the script has no way to known if you try to compile for a pure Windows environment or for a cygwin environment so to build the load module under cygwin you must add the -cygwin parameter. C.1 A first example myfunction.cpp The following defines a new function call myfunction with no parameter, but using the x, y current value. 321 322 APPENDIX C. DYNAMICAL LINK #include <iostream> #include <cfloat> using namespace std; #include "error.hpp" #include "AFunction.hpp" #include "rgraph.hpp" #include "RNM.hpp" #include "fem.hpp" #include "FESpace.hpp" #include "MeshPoint.hpp" using namespace Fem2D; double myfunction(Stack stack) { // to get FreeFem++ data MeshPoint &mp= * MeshPointStack(stack); // the struct to get x,y, normal , value double x= mp.P.x; // get the current x value double y= mp.P.y; // get the current y value // cout << "x = " << x << " y=" << y << endl; return sin(x) * cos(y); } Now the Problem is to build the link with FreeFem++, to do that we need two classes, one to call the function myfunction All FreeFem++ evaluable expression must be a struct/class C++ which derive from E F0. By default this expression does not depend of the mesh position, but if they derive from E F0mps the expression depends of the mesh position, and for more details see [12]. // A class build the link with FreeFem++ // generaly this class are already in AFunction.hpp // but unfortunatly, I have no simple function with no parameter // in FreeFem++ depending of the mesh, template<class R> class OneOperator0s : public OneOperator { // the class to defined a evaluated a new function // It must devive from E F0 if it is mesh independent // or from E F0mps if it is mesh dependent class E_F0_F :public E_F0mps { public: typedef R ( * func)(Stack stack) ; func f; // the pointeur to the fnction myfunction E_F0_F(func ff) : f(ff) {} // the operator evaluation in FreeFem++ AnyType operator()(Stack stack) const {return SetAny<R>( f(stack)) ;} }; typedef R ( * func)(Stack ) ; func f; public: // the function which build the FreeFem++ byte code E_F0 * code(const basicAC_F0 & ) const { return new E_F0_F(f);} // the constructor to say ff is a function without parameter C.1. A FIRST EXAMPLE MYFUNCTION.CPP 323 // and returning a R OneOperator0s(func ff): OneOperator(map_type[typeid(R).name()]),f(ff){} }; To finish we must add this new function in FreeFem++ table , to do that include : void init(){ Global.Add("myfunction","(",new OneOperator0s<double>(myfunction)); } LOADFUNC(init); It will be called automatically at load module time. To compile and link, use the ff-c++ script : % ff-c++ myfunction.cpp g++ -c -g -Iinclude myfunction.cpp g++ -bundle -undefined dynamic_lookup -g myfunction.o -o ./myfunction.dylib To, try the simple example under Linux or MacOS, do % FreeFem++-nw load.edp -- FreeFem++ v 1.4800028 (date Tue Oct 4 11:56:46 CEST 2005) file : load.edp Load: lg_fem lg_mesh eigenvalue UMFPACK 1 : // Example of dynamic function load 2 : // -------------------------------- 3 : // Id : freefem+ +doc.tex, v1.1102010/06/0411 : 27 : 24hechtExp 4 : 5 : load "myfunction" load: myfunction load: dlopen(./myfunction) = 0xb01cc0 6 : mesh Th=square(5,5); 7 : fespace Vh(Th,P1); 8 : Vh uh=myfunction(); // warning do not forget () 9 : cout << uh[].min << " " << uh[].max << endl; 10 : sizestack + 1024 =1240 ( 216 ) -- square mesh : nb vertices =36 , nb triangles = 50 , nb boundary edges 20 Nb of edges on Mortars = 0 Nb of edges on Boundary = 20, neb = 20 Nb Of Nodes = 36 Nb of DF = 36 0 0.841471 times: compile 0.05s, execution -3.46945e-18s CodeAlloc : nb ptr 1394, size :71524 Bien: On a fini Normalement Under Windows, launch FreeFem++ with the mouse (or ctrl O) on the example. 324 APPENDIX C. DYNAMICAL LINK C.2 Example: Discrete Fast Fourier Transform This will add FFT to FreeFem++, taken from http://www.fftw.org/. To download and install under download/include just go in download/fftw and trymake. The 1D dfft (fast discret fourier transform) for a simple array f of size n is defined by the following formula dfft(f, ε) k = n−1 ¸ j=0 f i e ε2πikj/n The 2D DFFT for an array of size N = n m is dfft(f, m, ε) k+nl = m−1 ¸ j =0 n−1 ¸ j=0 f i+nj e ε2πi(kj/n+lj /m) Remark: the value n is given by size(f)/m, and the numbering is row-major order. So the classical discrete DFFT is ˆ f = dfft(f, −1)/ √ n and the reverse dFFT f = dfft( ˆ f, 1)/ √ n Remark: the 2D Laplace operator is f(x, y) = 1/ √ N m−1 ¸ j =0 n−1 ¸ j=0 ˆ f i+nj e ε2πi(xj+yj ) and we have f k+nl = f(k/n, l/m) So ¯ ∆f kl = −((2π) 2 (( ˜ k) 2 + ( ˜ l) 2 )) ´ f kl where ˜ k = k if k ≤ n/2 else ˜ k = k −n and ˜ l = l if l ≤ m/2 else ˜ l = l −m. And to have a real function we need all modes to be symmetric around zero, so n and m must be odd. Compile to build a new library % ff-c++ dfft.cpp ../download/install/lib/libfftw3.a -I../download/install/include export MACOSX_DEPLOYMENT_TARGET=10.3 g++ -c -Iinclude -I../download/install/include dfft.cpp g++ -bundle -undefined dynamic_lookup dfft.o -o ./dfft.dylib ../download/install/lib/libfftw3.a To test , -- FreeFem++ v 1.4800028 (date Mon Oct 10 16:53:28 EEST 2005) file : dfft.edp Load: lg_fem cadna lg_mesh eigenvalue UMFPACK 1 : // Example of dynamic function load 2 : // -------------------------------- 3 : // Id : freefem+ +doc.tex, v1.1102010/06/0411 : 27 : 24hechtExp 4 : // Discret Fast Fourier Transform 5 : // ------------------------------- 6 : load "dfft" lood: init dfft load: dlopen(dfft.dylib) = 0x2b0c700 C.2. EXAMPLE: DISCRETE FAST FOURIER TRANSFORM 325 7 : 8 : int nx=32,ny=16,N=nx * ny; 9 : // warning the Fourier space is not exactly the unite square due to periodic conditions 10 : mesh Th=square(nx-1,ny-1,[(nx-1) * x/nx,(ny-1) * y/ny]); 11 : // warring the numbering is of the vertices (x,y) is 12 : // given by i = x/nx +nx ∗ y/ny 13 : 14 : fespace Vh(Th,P1); 15 : 16 : func f1 = cos(2 * x * 2 * pi) * cos(3 * y * 2 * pi); 17 : Vh<complex> u=f1,v; 18 : Vh w=f1; 19 : 20 : 21 : Vh ur,ui; 22 : // in dfft the matrix n,m is in row-major order ann array n,m is 23 : // store j + m * i ( the transpose of the square numbering ) 24 : v[]=dfft(u[],ny,-1); 25 : u[]=dfft(v[],ny,+1); 26 : u[] /= complex(N); 27 : v = f1-u; 28 : cout << " diff = "<< v[].max << " " << v[].min << endl; 29 : assert( norm(v[].max) < 1e-10 && norm(v[].min) < 1e-10) ; 30 : // ------- a more hard example ---- 31 : // Lapacien en FFT 32 : // −∆u = f with biperiodic condition 33 : func f = cos(3 * 2 * pi * x) * cos(2 * 2 * pi * y); // 34 : func ue = +(1./(square(2 * pi) * 13.)) * cos(3 * 2 * pi * x) * cos(2 * 2 * pi * y); // 35 : Vh<complex> ff = f; 36 : Vh<complex> fhat; 37 : fhat[] = dfft(ff[],ny,-1); 38 : 39 : Vh<complex> wij; 40 : // warning in fact we take mode between -nx/2, nx/2 and -ny/2,ny/2 41 : // thank to the operator ?: 42 : wij = square(2. * pi) * (square(( x<0.5?x * nx:(x-1) * nx)) + square((y<0.5?y * ny:(y-1) * ny))); 43 : wij[][0] = 1e-5; // to remove div / 0 44 : fhat[] = fhat[]./ wij[]; // 45 : u[]=dfft(fhat[],ny,1); 46 : u[] /= complex(N); 47 : ur = real(u); // the solution 48 : w = real(ue); // the exact solution 49 : plot(w,ur,value=1 ,cmm=" ue ", wait=1); 50 : w[] -= ur[]; // array sub 51 : real err= abs(w[].max)+abs(w[].min) ; 52 : cout << " err = " << err << endl; 53 : assert( err < 1e-6); 54 : sizestack + 1024 =3544 ( 2520 ) ----------CheckPtr:-----init execution ------ NbUndelPtr 2815 Alloc: 111320 NbPtr 6368 -- square mesh : nb vertices =512 , nb triangles = 930 , nb boundary edges 92 326 APPENDIX C. DYNAMICAL LINK Nb of edges on Mortars = 0 Nb of edges on Boundary = 92, neb = 92 Nb Of Nodes = 512 Nb of DF = 512 0x2d383d8 -1 16 512 n: 16 m:32 dfft 0x402bc08 = 0x4028208 n = 16 32 sign = -1 --- --- ---0x2d3ae08 1 16 512 n: 16 m:32 dfft 0x4028208 = 0x402bc08 n = 16 32 sign = 1 --- --- --- diff = (8.88178e-16,3.5651e-16) (-6.66134e-16,-3.38216e-16) 0x2d3cfb8 -1 16 512 n: 16 m:32 dfft 0x402de08 = 0x402bc08 n = 16 32 sign = -1 --- --- ---0x2d37ff8 1 16 512 n: 16 m:32 dfft 0x4028208 = 0x402de08 n = 16 32 sign = 1 --- --- --- err = 3.6104e-12 times: compile 0.13s, execution 2.05s ----------CheckPtr:-----end execution -- ------ NbUndelPtr 2815 Alloc: 111320 NbPtr 26950 CodeAlloc : nb ptr 1693, size :76084 Bien: On a fini Normalement CheckPtr:Nb of undelete pointer is 2748 last 114 CheckPtr:Max Memory used 228.531 kbytes Memory undelete 105020 C.3 Load Module for Dervieux’ P0-P1 Finite Volume Method the associed edp file is examples++-load/convect dervieux.edp // Implementation of P1-P0 FVM-FEM // --------------------------------------------------------------------- // Id : freefem+ +doc.tex, v1.1102010/06/0411 : 27 : 24hechtExp // compile and link with ff-c++ mat dervieux.cpp (i.e. the file name without .cpp) #include <iostream> #include <cfloat> #include <cmath> using namespace std; #include "error.hpp" #include "AFunction.hpp" #include "rgraph.hpp" #include "RNM.hpp" // remove problem of include #undef HAVE_LIBUMFPACK #undef HAVE_CADNA #include "MatriceCreuse_tpl.hpp" #include "MeshPoint.hpp" #include "lgfem.hpp" #include "lgsolver.hpp" #include "problem.hpp" class MatrixUpWind0 : public E_F0mps { public: typedef Matrice_Creuse<R> * Result; Expression emat,expTh,expc,expu1,expu2; MatrixUpWind0(const basicAC_F0 & args) { C.3. LOAD MODULE FOR DERVIEUX’ P0-P1 FINITE VOLUME METHOD 327 args.SetNameParam(); emat =args[0]; // the matrix expression expTh= to<pmesh>(args[1]); // a the expression to get the mesh expc = CastTo<double>(args[2]); // the expression to get c (must be a double) // a array expression [ a, b] const E_Array * a= dynamic_cast<const E_Array * >((Expression) args[3]); if (a->size() != 2) CompileError("syntax: MatrixUpWind0(Th,rhi,[u1,u2])"); int err =0; expu1= CastTo<double>(( * a)[0]); // fist exp of the array (must be a double) expu2= CastTo<double>(( * a)[1]); // second exp of the array (must be a double) } ˜MatrixUpWind0(){ } static ArrayOfaType typeargs() { return ArrayOfaType(atype<Matrice_Creuse<R> * >(), atype<pmesh>(),atype<double>(),atype<E_Array>());} static E_F0 * f(const basicAC_F0 & args){ return new MatrixUpWind0(args);} AnyType operator()(Stack s) const ; }; int fvmP1P0(double q[3][2], double u[2],double c[3], double a[3][3], double where[3] ) { // computes matrix a on a triangle for the Dervieux FVM for(int i=0;i<3;i++) for(int j=0;j<3;j++) a[i][j]=0; for(int i=0;i<3;i++){ int ip = (i+1)%3, ipp =(ip+1)%3; double unL =-((q[ip][1]+q[i][1]-2 * q[ipp][1]) * u[0] -(q[ip][0]+q[i][0]-2 * q[ipp][0]) * u[1])/6; if(unL>0) { a[i][i] += unL; a[ip][i]-=unL;} else{ a[i][ip] += unL; a[ip][ip]-=unL;} if(where[i]&&where[ip]){ // this is a boundary edge unL=((q[ip][1]-q[i][1]) * u[0] -(q[ip][0]-q[i][0]) * u[1])/2; if(unL>0) { a[i][i]+=unL; a[ip][ip]+=unL;} } } return 1; } // the evaluation routine AnyType MatrixUpWind0::operator()(Stack stack) const { Matrice_Creuse<R> * sparse_mat =GetAny<Matrice_Creuse<R> * >(( * emat)(stack)); MatriceMorse<R> * amorse =0; MeshPoint * mp(MeshPointStack(stack)) , mps= * mp; Mesh * pTh = GetAny<pmesh>(( * expTh)(stack)); ffassert(pTh); Mesh & Th ( * pTh); 328 APPENDIX C. DYNAMICAL LINK { map< pair<int,int>, R> Aij; KN<double> cc(Th.nv); double infini=DBL_MAX; cc=infini; for (int it=0;it<Th.nt;it++) for (int iv=0;iv<3;iv++) { int i=Th(it,iv); if ( cc[i]==infini) { // if nuset the set mp->setP(&Th,it,iv); cc[i]=GetAny<double>(( * expc)(stack)); } } for (int k=0;k<Th.nt;k++) { const Triangle & K(Th[k]); const Vertex & A(K[0]), &B(K[1]),&C(K[2]); R2 Pt(1./3.,1./3.); R u[2]; MeshPointStack(stack)->set(Th,K(Pt),Pt,K,K.lab); u[0] = GetAny< R>( ( * expu1)(stack) ) ; u[1] = GetAny< R>( ( * expu2)(stack) ) ; int ii[3] ={ Th(A), Th(B),Th(C)}; double q[3][2]= { { A.x,A.y} ,{B.x,B.y},{C.x,C.y} } ; // coordinates of 3 vertices (input) double c[3]={cc[ii[0]],cc[ii[1]],cc[ii[2]]}; double a[3][3], where[3]={A.lab,B.lab,C.lab}; if (fvmP1P0(q,u,c,a,where) ) { for (int i=0;i<3;i++) for (int j=0;j<3;j++) if (fabs(a[i][j]) >= 1e-30) { Aij[make_pair(ii[i],ii[j])]+=a[i][j]; } } } amorse= new MatriceMorse<R>(Th.nv,Th.nv,Aij,false); } sparse_mat->pUh=0; sparse_mat->pVh=0; sparse_mat->A.master(amorse); sparse_mat->typemat=(amorse->n == amorse->m) ? TypeSolveMat(TypeSolveMat::GMRES) : TypeSolveMat(TypeSolveMat::NONESQUARE); // none square matrice (morse) * mp=mps; if(verbosity>3) { cout << " End Build MatrixUpWind : " << endl;} return sparse_mat; } void init() { cout << " lood: init Mat Chacon " << endl; C.4. MORE ON ADDING A NEW FINITE ELEMENT 329 Global.Add("MatUpWind0","(", new OneOperatorCode<MatrixUpWind0 >( )); } LOADFUNC(init); C.4 More on Adding a new finite element First read the section 13 of the appendix, we add two new finite elements examples in the directory examples++-load. The Bernardi-Raugel Element The Bernardi-Raugel finite element is meant to solve the Navier Stokes equations in u, p formulation; the velocity space P br K is minimal to prove the inf-sup condition with piecewise constant pressure by triangle. The finite element space V h is V h = ¦u ∈ H 1 (Ω) 2 ; ∀K ∈ T h , u |K ∈ P br K ¦ where P br K = span¦λ K i e k ¦ i=1,2,3,k=1,2 ∪ ¦λ K i λ K i+1 n K i+2 ¦ i=1,2,3 with notation 4 = 1, 5 = 2 and where λ K i are the barycentric coordinates of the triangle K, (e k ) k=1,2 the canonical basis of R 2 and n K k the outer normal of triangle K opposite to vertex k. // The P2BR finite element : the Bernadi Raugel Finite Element // F. Hecht, decembre 2005 // ------------- // See Bernardi, C., Raugel, G.: Analysis of some finite elements for the Stokes problem. Math. Comp. 44, 71-79 (1985). // It is a 2d coupled FE // the Polynomial space is P1 2 + 3 normals bubbles edges function (P 2 ) // the degree of freedom is 6 values at of the 2 componants at the 3 vertices // and the 3 flux on the 3 edges // So 9 degrees of freedom and N= 2. // ----------------------- related files: // to check and validate : testFE.edp // to get a real example : NSP2BRP0.edp // ------------------------------------------------------------ // ----------------------- #include "error.hpp" #include "AFunction.hpp" #include "rgraph.hpp" using namespace std; #include "RNM.hpp" #include "fem.hpp" #include "FESpace.hpp" #include "AddNewFE.h" 330 APPENDIX C. DYNAMICAL LINK namespace Fem2D { class TypeOfFE_P2BRLagrange : public TypeOfFE { public: static int Data[]; TypeOfFE_P2BRLagrange(): TypeOfFE(6+3+0, 2, Data, 4, 1, 6+3 * (2+2), // nb coef to build interpolation 9, // np point to build interpolation 0) { .... // to long see the source } void FB(const bool * whatd, const Mesh & Th,const Triangle & K,const R2 &P, RNMK_ & val) const; void TypeOfFE_P2BRLagrange::Pi_h_alpha(const baseFElement & K,KN_<double> & v) const; } ; // on what nu df on node node of df int TypeOfFE_P2BRLagrange::Data[]={ 0,0, 1,1, 2,2, 3,4,5, 0,1, 0,1, 0,1, 0,0,0, 0,0, 1,1, 2,2, 3,4,5, 0,0, 0,0, 0,0, 0,0,0, 0,1, 2,3, 4,5, 6,7,8, 0,0 }; void TypeOfFE_P2BRLagrange::Pi_h_alpha(const baseFElement & K,KN_<double> & v) const { const Triangle & T(K.T); int k=0; // coef pour les 3 sommets fois le 2 composantes for (int i=0;i<6;i++) v[k++]=1; // integration sur les aretes for (int i=0;i<3;i++) { R2 N(T.Edge(i).perp()); N * = T.EdgeOrientation(i) * 0.5 ; v[k++]= N.x; v[k++]= N.y; v[k++]= N.x; v[k++]= N.y; } } void TypeOfFE_P2BRLagrange::FB(const bool * whatd,const Mesh & ,const Triangle & K,const R2 & P,RNMK_ & val) const { .... // to long see the source } C.4. MORE ON ADDING A NEW FINITE ELEMENT 331 // ---- cooking to add the finite elemet to freefem table -------- // a static variable to def the finite element static TypeOfFE_P2BRLagrange P2LagrangeP2BR; // now adding FE in FreeFEm++ table static AddNewFE P2BR("P2BR",&P2LagrangeP2BR); // --- end cooking } // end FEM2d namespace A way to check the finite element load "BernadiRaugel" // a macro the compute numerical derivative macro DD(f,hx,hy) ( (f(x1+hx,y1+hy)-f(x1-hx,y1-hy))/(2 * (hx+hy))) // mesh Th=square(1,1,[10 * (x+y/3),10 * (y-x/3)]); real x1=0.7,y1=0.9, h=1e-7; int it1=Th(x1,y1).nuTriangle; fespace Vh(Th,P2BR); Vh [a1,a2],[b1,b2],[c1,c2]; for (int i=0;i<Vh.ndofK;++i) cout << i << " " << Vh(0,i) << endl; for (int i=0;i<Vh.ndofK;++i) { a1[]=0; int j=Vh(it1,i); a1[][j]=1; // a bascis functions plot([a1,a2], wait=1); [b1,b2]=[a1,a2]; // do the interpolation c1[] = a1[] - b1[]; cout << " ---------" << i << " " << c1[].max << " " << c1[].min << endl; cout << " a = " << a1[] <<endl; cout << " b = " << b1[] <<endl; assert(c1[].max < 1e-9 && c1[].min > -1e-9); // check if the interpolation is correct // check the derivative and numerical derivative cout << " dx(a1)(x1,y1) = " << dx(a1)(x1,y1) << " == " << DD(a1,h,0) << endl; assert( abs(dx(a1)(x1,y1)-DD(a1,h,0) ) < 1e-5); assert( abs(dx(a2)(x1,y1)-DD(a2,h,0) ) < 1e-5); assert( abs(dy(a1)(x1,y1)-DD(a1,0,h) ) < 1e-5); assert( abs(dy(a2)(x1,y1)-DD(a2,0,h) ) < 1e-5); } 332 APPENDIX C. DYNAMICAL LINK A real example using this finite element, just a small modification of the NSP2P1.edp examples, just the begenning is change to load "BernadiRaugel" real s0=clock(); mesh Th=square(10,10); fespace Vh2(Th,P2BR); fespace Vh(Th,P0); Vh2 [u1,u2],[up1,up2]; Vh2 [v1,v2]; And the plot instruction is also changed because the pressure is constant, and we cannot plot isovalues of peacewise constant functions. The Morley Element See the example bilapMorley.edp. C.5 Add a new sparse solver Warning the sparse solver interface as been completely rewritten in version 3.2 , so the section is obsolete, the example in are correct/ Only a fast sketch of the code is given here; for details see the .cpp code from SuperLU.cpp or NewSolve.cpp. First the include files: #include <iostream> using namespace std; #include "rgraph.hpp" #include "error.hpp" #include "AFunction.hpp" // #include "lex.hpp" #include "MatriceCreuse_tpl.hpp" #include "slu_ddefs.h" #include "slu_zdefs.h" A small template driver to unified the double and Complex version. template <class R> struct SuperLUDriver { }; template <> struct SuperLUDriver<double> { .... double version }; template <> struct SuperLUDriver<Complex> { .... Complex version C.5. ADD A NEW SPARSE SOLVER 333 }; To get Matrix value, we have just to remark that the Morse Matrice the storage, is the SLU NR format is the compressed row storage, this is the transpose of the compressed column storage. So if AA is a MatriceMorse you have with SuperLU notation. n=AA.n; m=AA.m; nnz=AA.nbcoef; a=AA.a; asub=AA.cl; xa=AA.lg; options.Trans = TRANS; Dtype_t R_SLU = SuperLUDriver<R>::R_SLU_T(); Create_CompCol_Matrix(&A, m, n, nnz, a, asub, xa, SLU_NC, R_SLU, SLU_GE); To get vector infomation, to solver the linear solver x = A −1 b void Solver(const MatriceMorse<R> &AA,KN_<R> &x,const KN_<R> &b) const { .... Create_Dense_Matrix(&B, m, 1, b, m, SLU_DN, R_SLU, SLU_GE); Create_Dense_Matrix(&X, m, 1, x, m, SLU_DN, R_SLU, SLU_GE); .... } The two BuildSolverSuperLU function, to change the default sparse solver variable DefSparseSolver<double>::solver MatriceMorse<double>::VirtualSolver * BuildSolverSuperLU(DCL_ARG_SPARSE_SOLVER(double,A)) { if(verbosity>9) cout << " BuildSolverSuperLU<double>" << endl; return new SolveSuperLU<double>( * A,ds.strategy,ds.tgv,ds.epsilon,ds.tol_pivot,ds.tol_pivot_sym,ds.sparams,ds.perm_r,ds.perm_c); } MatriceMorse<Complex>::VirtualSolver * BuildSolverSuperLU(DCL_ARG_SPARSE_SOLVER(Complex,A)) { if(verbosity>9) cout << " BuildSolverSuperLU<Complex>" << endl; return new SolveSuperLU<Complex>( * A,ds.strategy,ds.tgv,ds.epsilon,ds.tol_pivot,ds.tol_pivot_sym,ds.sparams,ds.perm_r,ds.perm_c); } The link to FreeFem++ class Init { public: Init(); }; 334 APPENDIX C. DYNAMICAL LINK To set the 2 default sparse solver double and complex: DefSparseSolver<double>::SparseMatSolver SparseMatSolver_R ; ; DefSparseSolver<Complex>::SparseMatSolver SparseMatSolver_C; To save the default solver type TypeSolveMat::TSolveMat TypeSolveMatdefaultvalue=TypeSolveMat::defaultvalue; To reset to the default solver, call this function: bool SetDefault() { if(verbosity>1) cout << " SetDefault sparse to default" << endl; DefSparseSolver<double>::solver =SparseMatSolver_R; DefSparseSolver<Complex>::solver =SparseMatSolver_C; TypeSolveMat::defaultvalue =TypeSolveMat::SparseSolver; } To set the default solver to superLU, call this function: bool SetSuperLU() { if(verbosity>1) cout << " SetDefault sparse solver to SuperLU" << endl; DefSparseSolver<double>::solver =BuildSolverSuperLU; DefSparseSolver<Complex>::solver =BuildSolverSuperLU; TypeSolveMat::defaultvalue =TypeSolveMatdefaultvalue; } To add new function/name defaultsolver,defaulttoSuperLUin freefem++, and set the default solver to the new solver., just do: void init() { SparseMatSolver_R= DefSparseSolver<double>::solver; SparseMatSolver_C= DefSparseSolver<Complex>::solver; if(verbosity>1) cout << "\n Add: SuperLU, defaultsolver defaultsolverSuperLU" << endl; TypeSolveMat::defaultvalue=TypeSolveMat::SparseSolver; DefSparseSolver<double>::solver =BuildSolverSuperLU; DefSparseSolver<Complex>::solver =BuildSolverSuperLU; // test if the name "defaultsolver" exist in freefem++ if(! Global.Find("defaultsolver").NotNull() ) Global.Add("defaultsolver","(",new OneOperator0<bool>(SetDefault)); Global.Add("defaulttoSuperLU","(",new OneOperator0<bool>(SetSuperLU)); } LOADFUNC(init); C.5. ADD A NEW SPARSE SOLVER 335 To compile superlu.cpp, just do: 1. download the SuperLu 3.0 package and do curl http://crd.lbl.gov/˜xiaoye/SuperLU/superlu_3.0.tar.gz -o superlu_3.0.tar.gz tar xvfz superlu_3.0.tar.gz go SuperLU_3.0 directory $EDITOR make.inc make 2. In directoy include do to have a correct version of SuperLu header due to mistake in case of inclusion of double and Complex version in the same file. tar xvfz ../SuperLU_3.0-include-ff.tar.gz I will give a correct one to compile with freefm++. To compile the freefem++ load file of SuperLu with freefem do: some find like : ff-c++ SuperLU.cpp -L$HOME/work/LinearSolver/SuperLU_3.0/ -lsuperlu_3.0 And to test the simple example: A example: load "SuperLU" verbosity=2; for(int i=0;i<3;++i) { // if i == 0 then SuperLu solver // i == 1 then GMRES solver // i == 2 then Default solver { matrix A = [[ 0, 1, 0, 10], [ 0, 0, 2, 0], [ 0, 0, 0, 3], [ 4,0 , 0, 0]]; real[int] xx = [ 4,1,2,3], x(4), b(4); b = A * xx; cout << b << " " << xx << endl; set(A,solver=sparsesolver); x = Aˆ-1 * b; cout << x << endl; } { matrix<complex> A = [[ 0, 1i, 0, 10], [ 0 , 0, 2i, 0], [ 0, 0, 0, 3i], [ 4i,0 , 0, 0]]; complex[int] xx = [ 4i,1i,2i,3i], x(4), b(4); 336 APPENDIX C. DYNAMICAL LINK b = A * xx; cout << b << " " << xx << endl; set(A,solver=sparsesolver); x = Aˆ-1 * b; cout << x << endl; } if(i==0)defaulttoGMRES(); if(i==1)defaultsolver(); } To Test do for exemple: FreeFem++ SuperLu.edp FreeFem++ LGPL License This is The FreeFem++ software. Programs in it were maintained by • Fr´ed´eric hecht <[email protected]> • Jacques Morice <[email protected]> All its programs except files the comming from COOOL sofware (files in directory src/Algo) and the file mt19937ar.cpp which may be redistributed under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPY- ING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called ”this License”). Each licensee is addressed as ”you”. A ”library” means a collection of software functions and/or data prepared so as to be con- veniently linked with application programs (which use some of those functions and data) to form executables. The ”Library”, below, refers to any such software library or work which has been distributed under these terms. A ”work based on the Library” means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another lan- guage. (Hereinafter, translation is included without limitation in the term ”modification”.) ”Source code” for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library’s complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 337 338 APPENDIX C. DYNAMICAL LINK 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is en- tirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. C.5. ADD A NEW SPARSE SOLVER 339 If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a ”work that uses the Library”. Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a ”work that uses the Library” with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a ”work that uses the library”. The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a ”work that uses the Library” uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a ”work that uses the Library” with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modifi- cation of the work for the customer’s own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable ”work that uses the Library”, as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mech- anism is one that (1) uses at run time a copy of the library already present on the user’s computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. 340 APPENDIX C. DYNAMICAL LINK c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the ”work that uses the Library” must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients’ exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do C.5. ADD A NEW SPARSE SOLVER 341 not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circum- stance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and ”any later version”, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICA- BLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY ”AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- NESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 342 APPENDIX C. DYNAMICAL LINK REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, IN- CIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR IN- ABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix D Keywords Main Keywords adaptmesh Cmatrix R3 bool border break buildmesh catch cin complex continue cout element else end fespace for func if ifstream include int intalledge load macro matrix mesh movemesh ofstream plot problem real return savemesh solve string try throw vertex varf while Second category of Keywords int1d int2d on square Third category of Keywords dx dy convect jump mean Fourth category of Keywords wait ps solver CG LU UMFPACK factorize init endl Other Reserved Words x, y, z, pi, i, sin, cos, tan, atan, asin, acos, cotan,sinh,cosh,tanh,cotanh, exp, log, log10, sqrt abs, max, min, 343 344 APPENDIX D. KEYWORDS Bibliography [1] R. B. Lehoucq, D. C. Sorensen, and C. Yang ARPACK Users’ Guide: Solution of Large-Scale Eigenvalue Problems with Implicitly Restarted Arnoldi Methods SIAM, ISBN 0-89871-407-9 // http://www.caam.rice.edu/software/ARPACK/ [2] I. Babbu ˇ ska, Error bounds for finite element method, Numer. Math. 16, 322-333. [3] Y. Achdou and O. Pironneau, Computational Methods for Option Pricing. SIAM monograph (2005). [4] D. Bernardi, F.Hecht, K. Ohtsuka, O. Pironneau, freefem+ documentation, on the web at ftp://www.freefem.org/freefemplus. [5] D. Bernardi, F.Hecht, O. Pironneau, C. Prud’homme, freefem documentation, on the web at http://www. freefem.fr/freefem [6] T.A. Davis: Algorithm 8xx: UMFPACK V4.1, an unsymmetric-pattern multifrontal method TOMS, 2003 (submitted for publication) http://www.cise.ufl.edu/ research/sparse/umfpack [7] P.L. George, Automatic triangulation, Wiley 1996. [8] F. Hecht, Outils et algorithmes pour la m´ethode des ´el´ements finis, HdR, Universit´e Pierre et Marie Curie, France, 1992 [9] F. Hecht, The mesh adapting software: bamg. INRIA report 1998. [10] A. Perronnet et. al. Library Modulef , INRIA, http://www.inria-rocq/ modulef [11] A. Ern and J.-L. Guermond, Discontinuous Galerkin methods for Friedrichs’ sym- metric systems and Second-order PDEs, SIAM J. Numer. Anal., (2005). See also: Theory and Practice of Finite Elements, vol. 159 of Applied Mathematical Sciences, Springer-Verlag, New York, NY, 2004. [12] F. Hecht. C++ Tools to construct our user-level language. Vol 36, N°, 2002 pp 809-836, Mod´el. math et Anal Num´er. [13] J.L. Lions, O. Pironneau: Parallel Algorithms for boundary value problems, Note CRAS. Dec 1998. Also : Superpositions for composite domains (to appear) [14] B. Lucquin, O. Pironneau: Introduction to Scientific Computing Wiley 1998. 345 346 BIBLIOGRAPHY [15] I. Danaila, F. Hecht, and O. Pironneau. Simulation num´erique en C++. Dunod, Paris, 2003. [16] J. Ne ˇ cas, L. Hlav ´ a ˇ cek, Mathematical theory of elastic and elasto-plastic bodies: An introduction, Elsevier, 1981. [17] K. Ohtsuka, O. Pironneau and F. Hecht: Theoretical and Numerical analysis of energy release rate in 2D fracture, INFORMATION 3 (2000), 303–315. [18] F. Preparata, M. Shamos Computational Geometry Springer series in Computer sciences, 1984. [19] R. Rannacher: On Chorin’s projection method for the incompressible Navier-Stokes equations, in ”Navier-Stokes Equations: Theory and Numerical Methods” (R. Raut- mann, et al., eds.), Proc. Oberwolfach Conf., August 19-23, 1991, Springer, 1992 [20] J.E. Roberts and Thomas J.-M: Mixed and Hybrid Methods, Handbook of Nu- merical Anaysis, Vol.II, North-Holland, 1993 [21] J.L. Steger: The Chimera method of flow simulation, Workshop on applied CFD, Univ of Tennessee Space Institute, August 1991. [22] M. Tabata: Numerical solutions of partial differential equations II (in Japanese), Iwanami Applied Math., 1994 [23] F. Thomasset: Implementation of finite element methods of Navier-Stokes Equations, Springer-Verlag, 1981 [24] N. Wirth: Algorithms + Data Structures = Programs, Prentice Hall, 1976 [25] Bison The GNU compiler-compiler documentation (on the web). [26] B. Stroustrup, The C++ , programming language, Third edition, Addison-Wesley 1997. [27] L. Deng, Wences Gouveia, COOOL: a package of tools for writing optimization code and solving optimization problems, http://coool.mines.edu [28] B. Riviere, M. Wheeler, V. Girault, A priori error estimates for finite element methods based on discontinuous approximation spaces for elliptic problems. SIAM J. Numer. Anal. 39 (2001), no. 3, 902–931 (electronic). [29] R. Glowinski and O. Pironneau, Numerical methods for the Stokes problem, Chap- ter 13 of Energy Methods in Finite Element Analysis, R.Glowinski, E.Y. Rodin, O.C. Zienkiewicz eds., J.Wiley & Sons, Chichester, UK, 1979, pp. 243-264. [30] R. Glowinski, Numerical Methods for Nonlinear Variational Problems, Springer- Verlag, New York, NY, 1984. [31] R. Glowinski, Finite Element Methods for Incompressible Viscous Flow. In Hand- book of Numerical Analysis, Vol. IX, P.G. Ciarlet and J.L. Lions, eds., North-Holland, Amsterdam, 2003, pp.3-1176. BIBLIOGRAPHY 347 [32] C. Horgan, G. Saccomandi, Constitutive Models for Compressible Nonlinearly Elastic Materials with Limiting Chain Extensibility, Journal of Elasticity, Volume 77, Number 2, November 2004, pp. 123-138(16). [33] Kazufumi Ito, and Karl Kunisch, Semi smooth newton methods for variational inequalities of the first kind , M2AN, vol 37, N ◦ , 2003, pp 41-62. [34] R.W. Ogden, Non-Linear Elastic Deformations, Dover, 1984. [35] P.A. Raviart, J.M. Thomas, Introduction ` a l’analyse num´erique des ´equations aux d´eriv´ees partielles, Masson, 1983. [36] Hang Si, TetGen Users’ Guide: A quality Tetrahedral Mesh Generator and Three- Dimensional Delaunay Triangulator // http://tetgen.berlios.de [37] J.R. Shewchuk, Tetrahedral Mesh Generation by Delaunay Refinement Proceeding of the Fourteenth Anual Symposium on Computational Geometry (Minneapolis, Min- nesota), pp 86–95, 1998. [38] M. A. Taylor, B. A. Wingate , L. P. Bos, Several new quadrature formulas for polynomial integration in the triangle , Report-no: SAND2005-0034J, http://xyz. lanl.gov/format/math.NA/0501496 [39] P. Willmott, S. Howison, J. Dewynne : A student introduction to mathematical finance, Cambridge University Press (1995). [40] P. Frey, A fully automatic adaptive isotropic surface remeshing procedure. INRIA RT–0252, 2001. [41] Astrid Sabine Sinwel, A New Family of Mixed Finite Elements for Elas- ticity http://www.numa.uni-linz.ac.at/Teaching/PhD/Finished/ sinwel-diss.pdf, Thesis, 2009, Johannes Kepler Universit¨at, Austria [42] Steven G. Johnson, The NLopt nonlinear-optimization package, http:// ab-initio.mit.edu/nlopt [43] N. Hansen, The CMA Evolution Strategy, http://www.lri.fr/ ˜ hansen/ cmaesintro.html Index <<, 79 matrix, 75 >>, 79 .*, 73 . * , 162 ./, 73 =, 153 ?:, 59 [], 16, 150, 239 , 55 ’, 73 3d beam-3d.edp, 207 periodic, 196 time dependent, 27 accuracy, 19 acos, 62 acosh, 62 adaptation, 99, 116, 138 adaptmesh, 38, 50, 99, 100 abserror=, 102 anisomax=, 201 cutoff=, 102 err=, 101 errg=, 101 hmax=, 101 hmin=, 101 inquire=, 102 IsMetric=, 102 iso=, 101 keepbackvertices=, 102 maxsubdiv=, 102 metric=, 103 nbjacoby=, 101 nbsmooth=, 101 nbvx=, 101 nomeshgeneration=, 103 omega=, 101 periodic=, 103 powerin=, 102 ratio=, 101 rescaling=, 102 splitin2=, 102 splitpbedge=, 102 thetamax=, 102 uniform, 103 verbosity=, 102 adj, 91 alphanumeric, 55 append, 79 area, 58 area coordinate, 159 argument, 60 ARGV, 80 array, 56, 65, 77, 161 .l1, 68 .l2, 68 .linfty, 68 .max, 68 .min, 68 .sum, 68 ::, 66 ?:, 66 = + - * / . * ./ += -= /= * = , 67 column, 70 dot product, 68 FE function, 77 fespace, 143, 144 im, 66, 67 line, 70 max, 66 mesh, 257 min, 66, 77 quantile, 68 re, 66, 67 renumbering, 70 resize, 66 348 INDEX 349 sort, 66 sum, 66 varf, 164 asin, 62 asinh, 62 assert(), 58 atan, 62 atan2, 62 atanh, 62 axisymmetric, 27 backward Euler method, 217 barycentric coordinates, 13 BDM1, 143 BDM1Ortho, 143 be, 91 bessel, 63 BFGS, 178 BiLaplacien, 141 block matrix, 72 bool, 56 border, 86, 88 boundary condition, 162 break, 78 broadcast, 257 bubble, 148 buildlayers, 121 buildmesh, 22 fixeborder, 87 fixeborder=, 87 fixeborder=1, 196 nbvx=, 87 catch, 82 Cauchy, 54 ceil, 62 CG, 155 change, 110 Characteristics-Galerkin, 33 checkmovemesh, 96 Cholesky, 155, 177 cin, 58, 79 clock, 11 CMAES, 178 initialStdDev=, 179 seed=, 178 column, 70 compatibility condition, 154 compiler, 55 Complex, 56 complex, 46, 60, 73 Complex geometry,, 30 concatenation, 100 cone, 120 conj, 60 connectivity, 167 continue, 78 convect, 34, 228, 230 cos, 62 cosh, 62 cout, 58, 79 Crout, 155 cube, 120 de Moivre’s formula, 60 default, 79 defaultsolver, 334 defaulttoGMRES, 335 defaulttoSuperLU, 334 degree of freedom, 13 DFFT, 324 diag, 74, 233 diagonal matrix, 74 dimKrylov=, 200 Dirichlet, 19, 25, 54, 154 discontinuous functions, 243 Discontinuous-Galerkin, 33 displacement vector, 205 divide term to term, 73 domain decomposition, 236, 237 dot product, 73, 77 dumptable, 58 Edge03d, 142 EigenValue, 214 ivalue=, 213 maxit=, 213 ncv=, 214 nev=, 213 rawvector=, 213 sigma=, 213 sym=, 213 tol=, 213 350 INDEX value=, 213 vector=, 213 eigenvalue problems, 26 Element, 91 elements, 13, 14 emptymesh, 95 endl, 79 erf, 63 erfc, 63 exception, 82 exec, 58, 173, 174 exit, 257 exp, 62 expression optimization, 164 external C++ function, 37 factorize=, 177 false, 56, 58 FE function [], 150 complex, 46, 64, 73 n, 150 value, 150 FE space, 143, 144 FE-function, 64, 143, 144 FEspace (int ,int ), 167 ndof, 167 nt, 167 fespace, 139 BDM1, 13, 143 BDM1Ortho, 13, 143 Edge03d, 14, 142 Morley, 13, 141 P0, 13, 140 P03d, 14 P1, 13, 140 P13d, 14, 140 P1b, 13, 140 P1b3d, 14, 140 P1dc, 13, 140 P1nc, 13, 142 P2, 13, 140 P23d, 14 P2b, 13 P2BR, 13, 142, 329 P2dc, 13, 141 P2h, 13 P3, 13, 141 P3dc, 13, 141 P4, 13, 141 P4dc, 13, 141 periodic=, 155, 194 RT0, 13, 142 RT03d, 14 RT0Ortho, 13, 142 RT1, 13, 142 RT1Ortho, 13, 142 TDNNS1, 143 ffmedit, 173 ffNLOpt, 180 FFT, 324 file am, 297, 298 am fmt, 90, 297, 298 amdba, 297, 298 bamg, 90, 295 data base, 295 ftq, 299 mesh, 90 msh, 298 nopo, 90 finite element space, 139 Finite Volume Methods, 36 fixed, 79 floor, 62 fluid, 226 for, 78 Fourier, 28 func, 57 function tables, 94 functions, 62 gamma, 63 geometry input , 24 getline, 61 global area, 58 cin, 58 endl, 58 false, 58 hTriangle, 57 label, 57 INDEX 351 lenEdge, 57 N, 57 nTonEgde, 58 nuEdge, 58 nuTriangle, 57 pi, 58 region, 57 searchMethod, 152 true, 58 volume, 58 x, 57 y, 57 z, 57 GMRES, 155 gnuplot, 173 graphics packages, 19 hat function, 13 Helmholtz, 46 hTriangle, 57, 201 ifstream, 79 ill posed problems, 26 im, 66, 67 imag, 60 include, 8, 80, 230 includepath, 8 init, 36 init=, 156 initial condition, 54 inside=, 166 int, 56 int1d, 156 int2d, 156 int3d, 155, 156 intalledges, 156, 201 interpolate, 165 inside=, 166 op=, 166 t=, 166 interpolation, 153 Irecv, 257 Isend, 257 isotropic, 205 j0, 63 j1, 63 jn, 63 jump, 201 l1, 67 l2, 67 label, 57, 85, 86 label on the boundaries, 25 label=, 103 lagrangian, 97 Laplace operator, 19 lenEdge, 57, 201 level line, 35 lgamma, 63 line, 70 LinearCG, 175 eps=, 175 nbiter=, 175 precon=, 175 veps=, 175 LinearGMRES, 175 eps=, 175 nbiter=, 175 precon=, 175 veps=, 175 linfty, 67 load, 8 loadpath, 8 log, 62 log10, 62 LU, 155 m, 333 macro, 35, 81, 249 parameter, 81 quote, 264 quoting, 81, 82 with parameter, 41 without parameter, 35 mass lumping, 37 matrix, 16, 57, 177 =, 230 array, 71 block, 72 complex, 74 constant, 72 diag, 74, 233 factorize=, 212 interpolate, 165 352 INDEX renumbering, 71, 73 resize, 73, 74 set, 72 solver=, 230 stiffness matrix, 16 varf, 72, 163 eps=, 163 precon=, 163 solver=, 163 solver=factorize, 163 tgv=, 163 tolpivot =, 163 MatUpWind0, 37 max, 66 maximum, 59 mean, 2 medit, 173, 174 meditff=, 128 order=, 128 save=, 128 membrane, 19 mesh, 57 (), 91 +, 111 [], 91 3point bending, 109 adaptation, 38, 50, 99 beam, 105 Bezier curve, 106 Cardioid, 106 Cassini Egg, 106 change, 110 connectivity, 91 NACA0012, 105 regular, 98 Section of Engine, 107 Smiling face, 108 U-shape channel, 107 uniform, 103 V-shape cut, 108 mesh adaptation, 37 mesh3, 113 min, 66, 77 minimum, 59 mixed, 28 mixed Dirichlet Neumann, 19 modulus, 60 Morley, 141 movemesh, 96, 114 movemesh23, 113 orientation=, 114 ptmerge=, 114 transfo=, 114 mpiAllgather, 257 mpiAllReduce, 257 mpiAlltoall, 257 mpiAnySource, 255 mpiBAND, 255 mpiBarrier, 256 mpiBXOR, 255 mpiComm, 255 mpiCommWorld, 255 mpiGather, 257 mpiGroup, 255 mpiLAND, 255 mpiLOR, 255 mpiLXOR, 255 mpiMAX, 255 mpiMIN, 255 mpiPROD, 255 mpiRank, 256 mpirank, 255 mpiReduce, 257 mpiReduceScatter, 257 mpiRequest, 255 mpiScatter, 257 mpiSize, 256 mpisize, 255 mpiSUM, 255 mpiUndefined, 255 mpiWait, 256 mpiWtick, 256 mpiWtime, 256 multi-physics system, 30 multiple meshes, 30 N, 57, 158 n, 150, 333 Navier-Stokes, 228, 230 nbcoef, 333 nbe, 91 ndof, 167 ndofK, 167 Neumann, 54, 157, 158 INDEX 353 Newton, 178, 212 NLCG, 177 eps=, 175 nbiter=, 175 veps=, 175 nodes, 13 non-homogeneous Dirichlet, 19 nonlinear, 30 nonlinear problem, 27 norm, 324 normal, 35, 158 noshowbase, 79 noshowpos, 79 nt, 167, 309 nTonEdge, 35, 58 nuEdge, 58 number of degrees of freedom, 167 number of element, 167 nuTriangle, 57 nv, 309 ofstream, 79 append, 79 on, 157 intersection, 229 scalar, 157 optimize=, 164 outer product, 70, 73 P, 57 P0, 140 P1, 140 P1b, 140 P1dc, 140 P1nc, 142 P2, 140 P2BR, 142 P2dc, 141 P3, 141 P3dc, 141 P4, 141 P4dc, 141 parabolic, 27 periodic, 139, 155, 194 3d, 196 pi, 58 plot, 169 aspectratio=, 170 bb=, 170 border, 88 boundary=, 170 bw=, 170 cmm=, 170 coef=, 170 cut, 170 dim=, 170 grey=, 170 hsv=, 170 mesh, 88 nbarrow=, 170 nbiso=, 170 ps=, 170 value=, 170 varrow=, 170 viso=, 35, 170 point region, 91 triange, 91 polar, 60 pow, 62 precision, 79 precon=, 156, 163, 231 problem, 36, 57, 153 eps=, 156 init=, 156 precon=, 156 solver=, 156 strategy =, 156, 163 tgv=, 156 tolpivot =, 156 tolpivotsym =, 156, 163 processor, 256, 257 processorblock, 256 product Hermitian dot, 73 dot, 73, 77 outer, 73 term to term, 73 qfnbpE=, 164, 202 qforder=, 230 qft=, 159 qfV=, 160 quadrature: qf5pT, 160 354 INDEX quadrature: qfV5, 161 quadrature:default, 161 quadrature:qf1pE, 159 quadrature:qf1pElump, 159 quadrature:qf1pT, 160 quadrature:qf1pTlump, 160 quadrature:qf2pE, 159 quadrature:qf2pT, 160 quadrature:qf2pT4P1, 160 quadrature:qf3pE, 159 quadrature:qf4pE, 158 quadrature:qf5pE, 158 quadrature:qf5pT, 159 quadrature:qf7pT, 160 quadrature:qf9pT, 159 quadrature:qfe=, 160, 161 quadrature:qforder=, 160, 161 quadrature:qft=, 160, 161 quadrature:qfV, 160 quadrature:qfV1, 161 quadrature:qfV1lump, 161 quadrature:qfV2, 161 quadrature:qfV5, 160 quantile, 70 radiation, 30 rand, 63 randinit, 63 randint31, 63 randint32, 63 random, 63 randreal1, 63 randreal2, 63 randreal3, 63 randreal53, 63 re, 66, 67 read files, 90 readmesh, 89, 111 readmesh3, 196 real, 56, 60 rectangle, 85 region, 57, 91, 243 region indicator, 30 renumbering, 70 resize, 66, 74 Reusable matrices, 228 rint, 62 Robin, 28, 154, 157, 158 RT0, 142 RT0Ortho, 142 RT1, 142 RT1Ortho, 142 savemesh, 89, 111 savesol order=, 127 schwarz, 257 scientific, 79 searchMethod, 152 sec:Plot, 169 Secv, 257 Send, 257 set, 36 matrix, 72 showbase, 79 showpos, 79 shurr, 236, 237 sin, 62 singularity, 99 sinh, 62 solve, 57, 153 eps=, 156 init=, 156 linear system, 73 precon=, 156 solver=, 156 strategy=, 156, 163 tgv=, 16, 156 tolpivot=, 156 tolpivotsym=, 156, 163 solver=, 177 CG, 100, 155 Cholesky, 155 Crout, 155 GMRES, 155 LU, 155 sparsesolver, 155 UMFPACK, 155 sort, 66, 144 sparsesolver, 155 split=, 103 splitmesh, 104 square, 85, 201 flags=, 86 INDEX 355 label=, 86 region=, 86 Stokes, 226 stokes, 224 stop test, 156 absolue, 230 strain tensor, 205 strategy=, 156 streamlines, 227 stress tensor, 205 string, 56 concatenation, 61 find, 61 subdomains, 243 sum, 66 tan, 62 tanh, 62 Taylor-Hood, 229 TDNNS1, 143 tetg, 112 facetcl=, 112 holelist=, 112 nboffacetcl=, 112 nbofholes=, 112 nbofregions=, 112 regionlist=, 112 switch=, 112 tetgconvexhull, 115 tetgreconstruction, 113 tetgtransfo, 115 facetcl=, 115 nboffacetcl=, 115 ptmerge=, 115 refface=, 115 regionlist=, 115 switch=, 115 tgamma, 63 tgv= < 0, 157 tolpivot=, 156 tolpivotsym=, 156 transpose, 73, 77, 314 triangle [], 91 area, 92 label, 91, 92 region, 92 triangulate, 94 triangulation files, as well as read and write, 24 true, 56, 58 trunc, 103 label=, 103 split=, 103 try, 82 tutorial LaplaceRT.edp, 200 adapt.edp, 99 adaptindicatorP2.edp, 200 AdaptResidualErrorIndicator.edp, 202 aTutorial.edp, 188 beam.edp, 206 BlackSchol.edp, 223 convect.edp, 222 fluidStruct.edp, 240 freeboundary.edp, 246 movemesh.edp, 97 NSUzawaCahouetChabart.edp, 230 periodic.edp, 194 periodic4.edp, 194 periodic4bis.edp, 196 readmesh.edp, 90 Schwarz-gc.edp, 238 Schwarz-no-overlap.edp, 236 Schwarz-overlap.edp, 234 StokesUzawa.edp, 229 tutotial VI.edp, 232 type of finite element, 140 UMFPACK, 155 upwinding, 33 varf, 16, 57, 156, 161, 230 array, 163 matrix, 163 optimize=, 164 variable, 55 variational formulation, 20 veps=, 177 verbosity, 5, 8 version, 58 vertex 356 INDEX label, 91 x, 91 y, 91 viso, 35 volume, 58 weak form, 20 while, 78 whoinElement, 91 write files, 90 x, 57 y, 57 y0, 63 y1, 63 yn, 63 z, 57 Book Description Fruit of a long maturing process freefem, in its last avatar, FreeFem++, is a high level integrated development environment (IDE) for partial differential equations (PDE). It is the ideal tool for teaching the finite element method but it is also perfect for research to quickly test new ideas or multi-physics and complex applications. FreeFem++ has an advanced automatic mesh generator, capable of a posteri- ori mesh adaptation; it has a general purpose elliptic solver interfaced with fast algorithms such as the multi-frontal method UMFPACK. Hyperbolic and parabolic problems are solved by iterative algorithms prescribed by the user with the high level language of FreeFem++. It has several triangular finite elements, including discontinuous elements. Finally everything is there in FreeFem++ to prepare re- search quality reports: color display online with zooming and other features and postscript printouts. This book is ideal for students at Master level, for researchers at any level and for engineers also in financial mathematics. Editorial Reviews ”. . . Impossible to put the book down, suspense right up to the last page. . . ” A. Tanh, Siam Chronicle. ”. . . The chapter on discontinuous fems is so hilarious . . . .” B. Galerkine, . FreeFem++ Third Edition, Version 3.18 http://www.freefem.org/ff++ Fr´d´ric Hecht1,4 e e mailto:[email protected] http://www.ann.jussieu.fr/˜hecht In collaboration with: • Olivier Pironneau, mailto:[email protected], http://www. ann.jussieu.fr/pironneau Olivier Pironneau is a professor of numerical analysis at the university of Paris VI and at LJLL. His scientific contributions are in numerical methods for fluids. He is a member of the Institut Universitaire de France and of the French Academy of Sciences • Jacques Morice, mailto:[email protected]. Jacaues Morice is a Post-Doct at LJLL. His doing is Thesis in University of Bordeaux I on fast multipole method (FMM). In this version, he do all three dimensions mesh generation and coupling with medit software. Antoine Le Hyaric, mailto:[email protected], http://www. ann.jussieu.fr/˜lehyaric/ Antoine Le Hyaric is a research engineer from the ”Centre National de la Recherche Scientifique” (CNRS) at LJLL . He is an expert in software engineering for scientific applications. He has applied his skills mainly to electromagnetics simulation, parallel computing and three-dimensional visualization. • • Kohji Ohtsuka,mailto:[email protected], http://www.comfos.org/ Kohji Ohtsuka is a professor at the Hiroshima Kokusai Gakuin University, Japan and chairman of the World Scientific and Engineering academy and Society, Japan chapter. His research is in fracture dynamics, modeling and computing. ´ Acknowledgments We are very grateful to l’Ecole Polytechnique (Palaiseau, France) for printing the second edition of this manual (http://www.polytechnique.fr ), and to l’Agence Nationale de la Recherche (Paris, France) for funding of the extension of FreeFem++ to a parallel tridimensional version (http://www.agence-nationale-recherche.fr) R´f´rence : ANR-07-CIS7-002ee 01. iv Contents 1 Introduction 1.1 Installation . . . . . . . . . . . . . . . . . . . 1.1.1 For everyone: . . . . . . . . . . . . . . 1.1.2 For the pros: Installation from sources 1.2 How to use FreeFem++ . . . . . . . . . . . 1.3 Environment variables, and the init file . . . . 1.4 History . . . . . . . . . . . . . . . . . . . . . . 1 2 2 3 7 8 9 11 12 17 17 19 19 24 26 27 29 30 30 32 33 37 40 42 43 46 48 50 52 55 55 56 57 58 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Getting Started 2.0.1 FEM by FreeFem++ : how does it work? . . . . . . . . . . . . . . . 2.0.2 Some Features of FreeFem++ . . . . . . . . . . . . . . . . . . . . . 2.1 The Development Cycle: Edit–Run/Visualize–Revise . . . . . . . . . . . . . 3 Learning by Examples 3.1 Membranes . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Heat Exchanger . . . . . . . . . . . . . . . . . . . . . . 3.3 Acoustics . . . . . . . . . . . . . . . . . . . . . . . . . 3.4 Thermal Conduction . . . . . . . . . . . . . . . . . . . 3.4.1 Axisymmetry: 3D Rod with circular section . . 3.4.2 A Nonlinear Problem : Radiation . . . . . . . . 3.5 Irrotational Fan Blade Flow and Thermal effects . . . . 3.5.1 Heat Convection around the airfoil . . . . . . . 3.6 Pure Convection : The Rotating Hill . . . . . . . . . . 3.7 A Projection Algorithm for the Navier-Stokes equations 3.8 The System of elasticity . . . . . . . . . . . . . . . . . 3.9 The System of Stokes for Fluids . . . . . . . . . . . . . 3.10 A Large Fluid Problem . . . . . . . . . . . . . . . . . . 3.11 An Example with Complex Numbers . . . . . . . . . . 3.12 Optimal Control . . . . . . . . . . . . . . . . . . . . . 3.13 A Flow with Shocks . . . . . . . . . . . . . . . . . . . . 3.14 Classification of the equations . . . . . . . . . . . . . . 4 Syntax 4.1 Data Types . . . . 4.2 List of major types 4.3 Global Variables . . 4.4 System Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii 4.5 4.6 4.7 4.8 Arithmetics . . . . . . . . . . . . . . . . . . . . . . . . string expression . . . . . . . . . . . . . . . . . . . . . Functions of one Variable . . . . . . . . . . . . . . . . . Functions of two Variables . . . . . . . . . . . . . . . . 4.8.1 Formula . . . . . . . . . . . . . . . . . . . . . . 4.8.2 FE-functions . . . . . . . . . . . . . . . . . . . Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.9.1 Arrays with two integer indices versus matrices 4.9.2 Matrix construction and setting . . . . . . . . . 4.9.3 Matrix Operations . . . . . . . . . . . . . . . . 4.9.4 Other arrays . . . . . . . . . . . . . . . . . . . . Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . Input/Output . . . . . . . . . . . . . . . . . . . . . . . 4.11.1 Script arguments . . . . . . . . . . . . . . . . . preprocessor . . . . . . . . . . . . . . . . . . . . . . . . Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CONTENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 61 62 64 64 64 65 70 72 73 77 78 79 80 80 82 85 85 85 86 89 91 94 95 96 96 98 99 103 104 105 110 111 111 112 116 117 118 123 124 126 128 130 132 135 138 4.9 4.10 4.11 4.12 4.13 5 Mesh Generation 5.1 Commands for Mesh Generation . . . . . . . . . . . . . . . . . . . . 5.1.1 Square . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.2 Border . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.3 Data Structures and Read/Write Statements for a Mesh . . 5.1.4 Mesh Connectivity . . . . . . . . . . . . . . . . . . . . . . . 5.1.5 The keyword ”triangulate” . . . . . . . . . . . . . . . . . . . 5.2 Boundary FEM Spaces Built as Empty Meshes . . . . . . . . . . . 5.3 Remeshing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Movemesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 Regular Triangulation: hTriangle . . . . . . . . . . . . . . . . . . 5.5 Adaptmesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.6 Trunc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7 Splitmesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.8 Meshing Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.9 How to change the label of elements and border elements of a mesh 5.10 Mesh in three dimensions . . . . . . . . . . . . . . . . . . . . . . . . 5.10.1 Read/Write Statements for a Mesh in 3D . . . . . . . . . . . 5.10.2 TeGen: A tetrahedral mesh generator . . . . . . . . . . . . 5.10.3 Reconstruct/Refine a three dimensional mesh with TetGen . 5.10.4 Moving mesh in three dimensions . . . . . . . . . . . . . . . 5.10.5 Layer mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.11 Meshing examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.11.1 Build a 3d mesh of a cube with a balloon . . . . . . . . . . . 5.12 The output solution formats .sol and .solb . . . . . . . . . . . . . . 5.13 medit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.14 Mshmet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.15 FreeYams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.16 mmg3d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.17 A first 3d isotope mesh adaptation process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CONTENTS 6 Finite Elements 6.1 Use of “fespace” in 2d . . . . . . . . . . . . . . . . 6.2 Use of fespace in 3d . . . . . . . . . . . . . . . . . . 6.3 Lagrangian Finite Elements . . . . . . . . . . . . . 6.3.1 P0-element . . . . . . . . . . . . . . . . . . 6.3.2 P1-element . . . . . . . . . . . . . . . . . . 6.3.3 P2-element . . . . . . . . . . . . . . . . . . 6.4 P1 Nonconforming Element . . . . . . . . . . . . . 6.5 Other FE-space . . . . . . . . . . . . . . . . . . . . 6.6 Vector valued FE-function . . . . . . . . . . . . . . 6.6.1 Raviart-Thomas element . . . . . . . . . . . 6.7 A Fast Finite Element Interpolator . . . . . . . . . 6.8 Keywords: Problem and Solve . . . . . . . . . . . . 6.8.1 Weak form and Boundary Condition . . . . 6.9 Parameters affecting solve and problem . . . . . 6.10 Problem definition . . . . . . . . . . . . . . . . . . 6.11 Numerical Integration . . . . . . . . . . . . . . . . 6.12 Variational Form, Sparse Matrix, PDE Data Vector 6.13 Interpolation matrix . . . . . . . . . . . . . . . . . 6.14 Finite elements connectivity . . . . . . . . . . . . . iii 139 143 144 145 145 145 146 147 148 149 149 151 153 154 155 156 158 161 165 167 169 169 173 173 175 175 178 178 179 186 187 187 187 189 191 193 194 197 199 200 202 204 208 211 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Visualization 7.1 Plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 link with gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3 link with medit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Algorithms 8.1 conjugate Gradient/GMRES . . . . . . . . . . . . . 8.2 Optimization . . . . . . . . . . . . . . . . . . . . . 8.2.1 Example of utilization for BFGS or CMAES 8.2.2 The nlOpt optimizers . . . . . . . . . . . . . 8.2.3 Optimization with MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Mathematical Models 9.1 Static Problems . . . . . . . . . . . . . . . . . . . . . . . 9.1.1 Soap Film . . . . . . . . . . . . . . . . . . . . . . 9.1.2 Electrostatics . . . . . . . . . . . . . . . . . . . . 9.1.3 Aerodynamics . . . . . . . . . . . . . . . . . . . . 9.1.4 Error estimation . . . . . . . . . . . . . . . . . . 9.1.5 Periodic Boundary Conditions . . . . . . . . . . 9.1.6 Poisson Problems with mixed boundary condition 9.1.7 Poisson with mixte finite element . . . . . . . . . 9.1.8 Metric Adaptation and residual error indicator . . 9.1.9 Adaptation using residual error indicator . . . . . 9.2 Elasticity . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2.1 Fracture Mechanics . . . . . . . . . . . . . . . . . 9.3 Nonlinear Static Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Parallel sparse solvers 11. . . . . .3 Pastix solver . . . . . . . . . . . . . . . 9. . . .3 An Approach to Implementation in FreeFem++ . . . . . . . . . . . . . . Parallel version MPI keywords . 11. . Navier-Stokes Equation . . . . . . . . . . . . . . . . .3. . . Variational inequality . . 9. . . . . . . . . . . . . . . . . . . . . . . . . .2 10. . . . . . . . . . . . . . . . . . . . . . .2 A Neo-Hookean Compressible Material .10 9.1 pARMS solver . . . . . . .2. MPI functions . . 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8. . . .5 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11. . . . .5. . . . . . . . . . . . 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Domain decomposition . . . . . . Free Boundary Problem .4 Domain decomposition . . . . . . . . . . . . . . . . . . . . . . . 11. . . . . . . 11. . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Parallel sparse iterative solver .6. . 11. . . . . . 9. . . . . . . . .8. . .13. . . . . . . . . . . . . . . . . . . . . .1 MUMPS solver .6 . . . . . .1 Stokes and Navier-Stokes . . . . . . . .3 10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4.3 Schwarz-gc. . . . . Transmission Problem . . .1 10. . . .2 Uzawa Algorithm and Conjugate Gradients . . . . . 9. . . . .12 9. . . .6. .3 Interfacing with HYPRE . . . . . . 212 213 217 218 220 222 224 224 228 230 231 234 234 236 237 239 242 245 248 251 252 252 253 255 255 255 255 256 256 257 259 265 265 268 268 271 273 274 275 277 283 287 287 287 288 9.edp) . . . . . . . . . . . . . . . . . . . . . Eigenvalue Problems . . . . . . . . . . . . . . . . . .6. . . . . . . . . . 11. . .edp .2 Process . . . . . . . . . . . . . . . .13. . . . . . .5. . . . . . . .iv 9. . . 11. . . . . . . . . . . . . . . . . . . . .9 9. . .5. . 11. . . . . . . . . . . . . . . .2 Interfacing with HIPS .7 9. . . 9. . . . . . . . . . .edp . . . . . . .5 10. . . . . . .1 True parallel Schwarz . . . . . . MPI constants . . . . . .4 Conclusion . . . . . . . . . . . . . . . . . . . . .8. . . . 9. .2 Convection . . . . . . .4 10. . . . . . . . . . . . .11 9. . . . . . example . . . . . . . .2 Schwarz non Overlap Scheme . . . .3 NSUzawaCahouetChabart. . . . . . . . . . . . . . . . . . .2 Sparse direct solver . . . . . .1 Newton-Raphson algorithm .1 Communicators and groups . . .13 10 MPI 10. . . . . . . . . . . Compressible Neo-Hookean Materials: Computational Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3. . . .1 Mathematical Theory on Time Difference Approximations. . . . .1 Schwarz Overlap Scheme . . . . . . . . .3.1 Notation . . . . . .2. . 9.3. . .4 9. . . . . .2 SuperLU distributed solver . . . . .1 Using parallel sparse solvers in FreeFem++ 11. . . . . . . . . . . . . . . . Non linear Elasticity (nolinear-elas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fluid/Structures Coupled Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11. . . . . . . . . . . . . MPI communicator operator Schwarz example in parallel 10.4. 9. . . . . . . . . . . . . . . . . . . . . . 9. . . . . . . . . . . . . . . . . . .3. . . . . . . . . . . 11. . . . . . . . . . . . . . . . . .6 9. . . . . . . . . . . . . Evolution Problems . . . . 11. . . . . . . . . . . . . . . . . . . . . . . .8 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6. . . . . . . MPI Constructor . . . . . . . .2. . . . . CONTENTS . . 9. .13. . . . . . . . . . . . . . . . . . . . . . . . . .3 2D Black-Scholes equation for an European Put option . . . . . . . . . . . . . . . . .2 Which class to add? . . . . . . . . . . . . . . . . . . . . . . . .3 BB File Type for Store Solutions . . Mappings. . . . . . . . . . . . 315 B. . . . . . . . . . . . . . . . . 12. . . . . 301 13. . . . . . .3 All the operators . . . . . . .2 Example: Discrete Fast Fourier Transform .cpp . . . . . . . . . . . 289 11. . . . . . . .CONTENTS v 11. . . . . . . . 12. . AMDBA Meshes 295 295 296 296 297 297 .3 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. .4 Global operations . . . 307 307 307 308 308 309 309 . . . . . 311 B. . . . . and cast . . . . . . . . . . . . . . . . . . 315 C Dynamical link C. . . . . . . . . . . . . . . . . . . . 12. . . . . . . . . . . . . . . . . . . .6 Finite Element Spaces . . . .3 Load Module for Dervieux’ P0-P1 Finite Volume Method C. . . . . . . . . D Keywords 321 321 324 326 329 332 343 . . . . . . . . . . . . . . . . . . . . . . . 289 12 Mesh Files 12. . . . A. . . . . . . . . . . 302 A Table of Notations A. . . .4 Metric File . . . . . . . . A. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5 Add a new sparse solver . . . . . . . . . . . . . . . . . .1 Some notations . . . . . . . . . . . . . . . . . . . . C. . . . . . . . . .5 Meshes . . . . . . . . . . . . . . . . . . . . .1 File mesh data structure . . . . . . . 12. . . . . . . . . . . C. . . . . . . . . . . . Vectors A. A. . .3 Points to Points communicators . . . . . . . . . .4 More on Adding a new finite element . . . . . . . . . . . . . . . . . C. . . . .5 List of AM FMT. . . . . . . . . . . . . . . . . . . . . . . . .2 The Types of the languages. . . . . . . . . . . . . . . . . . . . . . . . . . . .2 bb File type for Store Solutions . . . . Matrices. . . . . . . . . . . . . . . . . . . . . . 13 Addition of a new finite element 301 13. . . . . . . . . . . . . . .1 Generalities . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . .2 Sets. . . . . . . . . . . . . .4 Differential Calculus . . . . . . . . . . . . A. . . . . . .1 The bison grammar . . . . . . . . . . . . .1 A first example myfunction. . . . . . . . . . . . . . . . . . . . . . B Grammar 311 B. . . . . . . . . . . . . . . . . . . . . vi CONTENTS . FreeFem++.Preface Fruit of a long maturing process. freefem. It is the ideal tool for teaching the finite element method but it is also perfect for research to quickly test new ideas or multi-physics and complex applications. FreeFem++ has an advanced automatic mesh generator. vii . capable of a posteriori mesh adaptation. for researchers at any level. including discontinuous elements. is a high level integrated development environment (IDE) for numerically solving partial differential equations (PDE). Hyperbolic and parabolic problems are solved by iterative algorithms prescribed by the user with the high level language of FreeFem++. Finally everything is there in FreeFem++ to prepare research quality reports: color display online with zooming and other features and postscript printouts. it has a general purpose elliptic solver interfaced with fast algorithms such as the multi-frontal method UMFPACK. SuperLU . This manual is meant for students at Master level. and for engineers (including financial engineering) with some understanding of variational methods for partial differential equations. in its last avatar. It has several triangular finite elements. viii CONTENTS . linear or nonlinear coupled systems. and X11R6) .e. The characteristics of FreeFem++ are: • Problem description (real or complex valued) by their variational formulations. however this part is not a CAD system. however the user is required to describe the iterative procedures which reduce the problem to a set of linear problems. mathematics and even banking are modeled by one or several partial differential equations. it is not a package. Vista and 7 and on MacOS 10 (powerpc. multi-equations. • Easy geometric input by analytic description of boundaries by pieces. • Automatic mesh generator. • Multi-variables. bi-dimensional and three-dimensional static or time dependent. intel) Moreover FreeFem++ is highly adaptive. it is an integrated product with its own high level programming language. the user must specify the intersection points. Some algorithms like Schwarz’ domain decomposition method also require data interpolation on multiple meshes within one program. FreeFem++ is a software to solve these equations numerically. This software runs on all UNIX OS (with g++ 3. arbitrary finite element spaces on arbitrary unstructured and adapted bi-dimensional meshes. possibly on different meshes. i. Many phenomena involve several coupled systems. on Window 2000. with access to the internal vectors and matrices if needed. FreeFem++ can handle these difficulties. for instance when two boundaries intersect. for example: fluid-structure interactions.3 or later. As its name implies. NT. engineering. it is a free software (see the copyrights for full detail) based on the Finite Element Method.Chapter 1 Introduction A partial differential equation is a relation between a function of several variables and its (partial) derivatives. the inner point density is proportional to the density of points on the boundaries [7]. These require different finite element approximations and polynomial degrees. based on the Delaunay-Voronoi algorithm. Lorentz forces for aluminium casting and ocean-atmosphere problems are three such systems. 1 . Many problems in physics. XP. mesh files for further manipulations of input and output data. discontinuous P1 and Raviart-Thomas elements.freefem. GMRES.1 1. parabolic and hyperbolic problems.. UMFPACK) and eigenvalue and eigenvector solvers.. mean.org/ff++/ And choose your platform: Linux. generation of .txt. • A parallel version using mpi 1. or go to the end of the page to get the full list of downloads. • Many examples and tutorials: elliptic.2 CHAPTER 1. • Online graphics. Windows. CG. intalledges. Apple Mac OS X and some Linux systems. Install by double click on the appropriate file. residual error indicator. • A large variety of triangular finite elements : linear. • High level user friendly typed input language with an algebra of analytic and finite element functions.eps.. Fluid structure interactions.1 Installation For everyone: First open the following web page http://www. Crout. • Multiple finite element meshes within one application with automatic interpolation of data on different meshes and possible storage of the interpolation matrices. elasticity.1. eigenvalue problem. INTRODUCTION • Metric-based anisotropic mesh adaptation. .. . P2dc and keywords: jump. (but no quadrangles).. The metric can be computed automatically from the Hessian of any FreeFem++ function [9]. the mini-element. . • Near optimal execution speed (compared with compiled C++ implementations programmed directly). • Tools to define discontinuous Galerkin finite element formulations P0. Cholesky. NavierStokes flows. Schwarz’s domain decomposition method. quadratic Lagrangian elements and more. P1dc.. elements of a non-scalar type. • A large variety of linear direct and iterative solvers (LU. . Remark 1 : Binaries are available for Microsoft Windows.gnu. MacOS X. 2 For the pros: Installation from sources This section is for those who for some reason do not wish to use the binaries and hence need to recompile FreeFem++ or install it from the source code: The documentation archive : The documentation is also open source. go the the directory and put the FreeFem+. written by Antoine Le Hyaric.org/system/mac/texmac. the installed files are in C:\Programs Files\FreeFem++ In this directory. Where to go from here An integrated environment called FreeFem++-cs. By now you should have two new icons on your desktop: • FreeFem++ (VERSION). where (VERSION) is the version of the files (for example 3.exe will not be found.app application in the /Applications directory.ctan.edp in directory examples++-tutorial for example..1.exe. you may proceed to the next paragraph ”How to use FreeFem++”.app) and click on button change All.. INSTALLATION 3 Windows binaries install First download the windows installation executable.com A and under MacOS X we have used Apple’s Developer Tools ”Xcode” and L TEX from http: //www. If you want a terminal access to FreeFem++ just copy the file FreeFem++ in a directory of your $PATH shell environment variable.1. under MS-Windows you will have to use cygwin http://www.” This is required otherwise the program ffglut. you have all the .. check the box ”Add application directory to your system path your system path . the FreeFem++ application without graphic windows.3-0-P4). Under the finder pick a .. By default.exe. to regenerate it you A need a L TEX environment capable of compiling a CVS archive. double click on a . then double click it. 1.cygwin. Unless you wish to profile now your own development environment. • FreeFem++ (VERSION) Examples a link to the FreeFem++ folder of examples.edp file icon.dll files and other applications: FreeFem++-nw.app.ffglut.1. If you want to automatically launch the FreeFem++. In most cases just answer yes (or typr return) to all questions. .. is provided with FreeFem++ . to install FreeFem++.exe the FreeFem++ application. Otherwise in the Additional Task windows. MacOS X binaries install Download the MacOS X binary version file. extract all the files with a double click on the icon of the file.exe . select menu File -> Get Info an change Open with: (choose FreeFem++. The syntax for the command-line tools are the same as those of FreeFem. drawbdmesh .gz to a directory called freefem++-(VERSION) enter the following commands in a shell window : tar zxvf freefem++-(VERSION). a mesh file viewer 9. the Drag and Drop CoCoa MacOSX Application 6. ffglut the visualization tools through a pipe of freefem++ (remark: if ffglut is not in the system path.org/ff++/index. a mesh file convertor 8.4 CHAPTER 1. standard version. postscript plot output only (batch version. The following programs are produced.app. /Applications/FreeFem++. cvmsh2 . 2.freefem. ffmedit the freefem++ version of medit software (thanks to P. just follow the INSTALL and README files.gz cd freefem++-(VERSION) To compile and install FreeFem++ .1000000 level of freefem output -fglut filepath : the file name of save all plots (replot with ffglut -glut command : change the command ffglut -gff command : change the command ffglut with space quotting -nowait : nowait at the end on window -wait : wait at the end on window -nw : no ffglut (=> no graphics windows) -ne : no edp script output -cd : Change directory to script dir with default ffglut : ffglut .tar. FreeFem++-mpi. with a graphical interface based on GLUT/OpenGL (use ffglut visualization tool) or not just add -nw parameter.htm To extract files from the compressed archive freefem++-(VERSION). FreeFem++. you will have no plot) 3. depending on the system you are running : 1. the bamg mesh generator 7. FreeFem++-nw. parallel version. no graphics windows via ffglut ) 4. INTRODUCTION The C++ archive : FreeFem++ must be compiled from the source archive. Frey) The FreeFem++ parameter command: Brochet-2:˜ hecht$ FreeFem++ Syntaxe: FreeFem++ [ -v verbosity ] [ -fglut filepath ] [ -glut command ] [ -nw] [ -f] -v verbosity : 0 -. bamg . postscript output only 5. as indicated in http://www.tar. cut and past the following list: P0 P1 P2 P3 P4 P5 P1dc P2dc P3dc P4dc P5dc RT0 RT1 RT2 RT3 RT4 RT5 macro plot int1d int2d solve movemesh adaptmesh trunc checkmovemesh on func buildmesh square Eigenvalue min max imag exec LinearCG NLCG Newton BFGS LinearGMRES catch try intalledges jump average mean load savemesh convect abs sin cos tan atan asin acos cotan sinh cosh tanh cotanh atanh asinh acosh pow exp log log10 sqrt dx dy endl cout . under unix: go into the directory examples++-tutorial and run FreeFem++ on the example script LaplaceP1.htm • Open Notepad++ and Enter F5 • In the new window enter the command FreeFem++ "$(FULL_CURRENT_PATH)" • Click on Save. Link with other text editors notepad++ at http://notepad-plus. and to replay do ffglut filename. do one time nedit -import edp.1.FreeFem++-nw on the command-line are • FreeFem++ [-?] [-vnn] [-fglut file1] [-glut file2] [-f] the edpfilepath where • or FreeFem++-nw -? [-vnn] [-fglut file1] [-glut file2] [-f] the -? show the usage. INSTALLATION 5 Remark 2 In most cases you can set the level of output (verbosity) to value nn by adding the parameters -v nn on the command line. now choose the short cut key to launch directly FreeFem++ (for example alt+shift+R) • To add Color Syntax Compatible with FreeFem++ In Notepad++. – In Menu "Parameters"->"Configuration of the Color Syntax" proceed as follows: – In the list "Language" select C++ – Add ”edp” in the field "add ext" – Select "INSTRUCTION WORD" in the list "Description" and in the field "supple mentary key word". The notation [] means ”optional”.edp If you are using nedit as your text editor.1. edpfilepath wher -fglut filename to store all the data for graphic in file filename. The syntax of tools FreeFem++.edp files. and enter FreeFem++ in the box ”Name”. -nw no call to ffglut -v nn set the level of verbosity to nn before execution of the script.sourceforge. -glut ffglutprogam to change the visualisator program’s. As an installation test.net/uk/site.nedit to have coloring syntax for your . if no file path then you get a dialog box to choose the edp file on windows systeme.edp with the command : FreeFem++ LaplaceP1. nedit . select main file full directory path with 8. Crimson Editor availble at http://www. Tick the 8.crimsoneditor. TeX. cut and past the following list mesh real fespace varf matrix problem string border complex ifstream ofstream – Click on Save & Close.exe on the second line and $(FilePath) and $(FileDir) on third and fourth lines. • in the 3 lines below.com this is a multipurpose text editor with advanced features such as syntax coloring. Download it from http://www. • for color syntax. etc..com/ and adapted as follows: • Go to the Tools/Preferences/File association menu and add the . ” ”supplementary key word”.freefem. add a FreeFem++ item (1st line) with the path to freefem++.3 nedit on the Mac OS. However winedt is not free after the trial period. TeXnicCenter for Windows: this is the easiest and will be the best once we find a volunteer to program the color syntax.exe 2.edp extension set • In the same panel in Tools/User Tools.winedt. Now nodepad++ is configured. search for FreeFem++. • Select the Tools tab and create a new item: call it freefem. 1. It has a ”‘tool”’ menu which can be configured to launch FreeFem++ programs as in: • Select the Tools/Customize item which will bring up a dialog box. C. select Main file with further option then Full path and click also on the 8.org to localize winedt to FreeFem++ without disturbing the winedt functional mode for LateX. INTRODUCTION – Select ”TYPE WORD” in the list ”Description” and ..3 box 3.texniccenter.6 CHAPTER 1.zip and put files in the corresponding sub-folder of Crimson folder (C:\Program Files\Crimson Editor ). Cygwin/Xfree and linux.3 box. winedt for Windows : this is the best but it could be tricky to set up. Download it from http://www.org/ It is also an editor for TeX/LaTeX. extract file from crimson-freefem. to import the color syntax do nedit -import edp. a macro is available on www. It comes ready with color syntax for .1: Integrated environment for FreeFem++ development with Windows 1.e.sourceforge.net. To teach it to launch FreeFem++ files.edp file. the menu Tools/Handle Command/new command) and create a command which does /usr/local/bin/FreeFem++-CoCoa %%p Figure 1. available at http://smultron. do a ”command B” (i. HOW TO USE FREEFEM++ 7 Smultron on the Mac.2.1.2 How to use FreeFem++ . for example FreeFem++ your-edp-file-path 1. FreeFem++-nw. loadpath. includepath.. 10 lots. Remark 3 The variable verbosity changes the level of internal printing (0.app (see above).edp file. .app.. . You can also launch this application and use the menu: File → Open. INTRODUCTION Under MacOS X with Graphic Interfaces To test an . just drag and drop the file icon on the MacOS application icon FreeFem++. FreeFem++-mpi. Figure 1. The Tools menu has an item to launch FreeFem++ by a Ctrl+1 command. . Add at least the path name.).pref to initialize global variables: verbosity.2: The 3 panels of the integrated environment built with the Smultron Editor with FreeFem++ in action. etc. One of the best ways however on the Mac is to use a text editor like Smultron.8 CHAPTER 1. . . The include files are searched from the includepath list and the load files are searched from loadpath list. 1 few. nothing (unless there are syntax errors). according to your needs. In Terminal mode Choose the type of application from FreeFem++. the default value is 2. and the init file FreeFem++ reads a user’s init file named freefem++.3 Environment variables. .10 was its last release).pref • under windows freefem++. Remark.” and not ”:” because ”:” is used under Windows. this software is no longer maintained but still in use because it .1.pref freefem++.. which included interpolation over multiple meshes (functions defined on one mesh can be used on any other mesh). written in Pascal. HISTORY The syntax of the file is: verbosity= 5 loadpath += "/Library/FreeFem++/lib" loadpath += "/Users/hecht/Library/FreeFem++/lib" includepath += "/Library/FreeFem++/edp" includepath += "/Users/hecht/Library/FreeFem++/edp" # comment load += "funcTemplate" load += "myfunction" The possible paths for this file are • under unix and MacOs /etc/freefem++. The first C version lead to freefem 3.4.pref $ ..4.dir2" export FF_LOADPATH="dir. .freefem++. export FF_VERBOSITY=50 export FF_INCLUDEPATH="dir. A thorough rewriting in C++ led to freefem+ (freefem+ 1.pref $(HOME)/.pref 9 We can also use shell environment variable to change verbosity and the search rule before the init files.dir3"" Remark: the separator between directories must be ”. 1. it offered mesh adaptativity on a single mesh only./FreeFem++-nw -. do export FF_VERBOSITY=100. to show the list of init of freefem++. PCfem.4 History The project has evolved from MacFem..verbosity is set to 100 insert init-files /etc/freefem++.2. entirely re-written again in C++ with a thorough usage of template and generic programming for coupled systems of unknown size at compile time. The language syntax of FreeFem++ is the result of a new design which makes use of the STL [26]. for each point. one had to find the containing triangle. The freefem language allows for a quick specification of any partial differential system of equations.10 CHAPTER 1. templates and bison for its implementation. INTRODUCTION handles a problem description using the strong form of the PDEs. but a recompilation is then necessary. . more detail can be found in [12]. This version also grew out of hand because of the evolution of the template syntax in C++.linear P1 and quadratic P2 Lagrangian elements. Like all versions of freefem it has a high level user friendly input language which is not too far from the mathematical writing of the problems. Therefore the library of finite elements available in FreeFem++ will grow with the version number and with the number of users who program more new elements. discontinuous P1 and Raviart-Thomas elements and a few others like bubble elements. We have been working for a few years now on FreeFem++ . Doing it in a minimum number of operations was the challenge. So far we have discontinuous P0 elements. Implementing the interpolation from one unstructured mesh to another was not easy because it had to be fast and non-diffusive. This is one of the basic problems of computational geometry (see Preparata & Shamos[18] for example). The outcome is a versatile software in which any new finite element can be included in a few hours. Our implementation is O(n log n) and based on a quadtree. As illustrated in Fig.1 // defining the boundary 1: border C(t=0. y)| x = cos(t). y) on ∂Ω. Figure 2. y) satisfying − ∆u(x. let us explain how FreeFem++ solves Poisson’s equation: for a given function f (x. y) ∈ Ω. y) = f (x. The boundary C = ∂Ω is C = {(x. y) for all (x. we can see the isovalue of u by using plot (see line 13 below). y) = 0 for all (x.2*pi){x=cos(t). y) = xy and Ω is the unit disk.1) (2. 0 ≤ t ≤ 2π} Note that in FreeFem++ the domain Ω is assumed to described by its boundary that is on the left side of its boundary oriented by the parameter. find a function u(x.2.2) Here ∂Ω is the boundary of the bounded open set Ω ⊂ R2 and ∆u = ∂ u + ∂ u .1: mesh Th by build(C(50)) Figure 2. 2. . 2 2 (2.2: isovalue by plot(u) Example 2. u(x. y = sin(t).Chapter 2 Getting Started To illustrate with an example. y).} 11 . ∂x2 ∂y 2 The following is a FreeFem++ program which computes u when f (x. y=sin(t). y=sin(t). // definition of a called f function 6: real cpu=clock().v.solver=LU) = // defines the PDE 8: int2d(Th)(dx(u)*dx(v) + dy(u)*dy(v)) // bilinear part 9: . The keyword “label” can be added to define a group of boundaries for later use (boundary conditions for instance). 2nd line: the triangulation Th of Ω is automatically generated by buildmesh(C(50)) using 50 points on C as in Fig. Note that the qualifier solver=LU is not required and by default a multi-frontal LU would have been used. Note also that the lines containing clock are equally not required.v.pi) {x=cos(t). Finally note how close to the mathematics FreeFem++ input language is. // defines u and v as piecewise-P1 continuous functions 5: func f= x*y.8). // get the clock in second 7: solve Poisson(u.1. So an elliptic hole can be added by . 1st line: the boundary Γ is described analytically by a parametric equation for x and for y. label=C} Boundaries can be referred to either by name ( Gamma1 for example) or by label ( C here) or even by its internal number here 1 for the first half circle and 2 for the second (more examples are in Section 5. Hence the circle could also have been described as two half circle with the same label: border Gamma1(t=0. 12: cout << " CPU time = " << clock()-cpu << endl. label=C} border Gamma2(t=pi.12 CHAPTER 2.P1). GETTING STARTED // the triangulated domain Th is on the left side of its boundary 2: mesh Th = buildmesh (C(50)). 2. y=sin(t).2*pi){x=cos(t).0. 4: Vh u. The domain is assumed to be on the left side of the boundary which is implicitly oriented by the parametrization. Exercise : Change P1 into P2 and run the program.u=0) . 2. must be specified and crossings of Γj are not allowed j=0 except at end points . When Γ = J Γj then each curve Γj . fespace Vh(Th. Line 8 and 9 correspond to the mathematical variational equation ( Th ∂u ∂v ∂u ∂v + )dxdy = ∂x ∂x ∂y ∂y f vdxdy Th for all v which are in the finite element space Vh and zero on the boundary C.int2d(Th)( f*v) // right hand side 10: + on(C. // Dirichlet boundary condition 11: plot(u). // the finite element space defined over Th is called here Vh 3.1 FEM by FreeFem++ : how does it work? This first example shows how FreeFem++ executes with no effort all the usual steps required by the finite element method (FEM). Let us go through them one by one. y) ∈ T .} then the inside of the ellipse would be triangulated as well as the outside. P3 continuous piecewise cubic.f). we notice that all corners of Γh = ∂Ωh are on Γ. P2 continuous piecewise quadratic. wk are real numbers (2. Mesh adaptation can be performed also against a given function f by calling adaptmesh(Th.5*sin(t). The wk are called the degree of freedom of w and M the number of the degree of freedom. y on each triangle of Th . . The easiest way to define φk is by making use of the barycentric coordinates λi (x. a space of polynomial functions on elements. Refinement of the mesh are done by increasing the number of points on Γ. 3 of a point q = (x.P1) defines Vh to be the space of continuous functions which are affine in x.1. Now the name Th (Th in FreeFem++ ) refers to the family {Tk }k=1. basis can be found.4 1 . Traditionally h refers to the mesh size.} If by mistake one had written border C(t=0. but it is seldom that we will have to use them explicitly. 2. the number of vertices. usually.2*pi){x=0. y=0. λi q i = q i i i 1 where q . Here fespace Vh(Th. (need load "Element_P3") P4 continuous piecewise quartic. P1 ) = w(x. As it is a linear vector space of finite dimension. k=1 3rd line: A finite element space is. for example. A typical hat function is shown on figure 2.(need load "Element_P4") RT0 Raviart-Thomas piecewise constant. The canonical basis is made of functions.3) where M is the dimension of Vh . y).3*cos(t). (see section 6 for the full description) P0 piecewise constant. i.1+0. with certain matching properties at edges. buildmesh(C(100)). Automatic mesh generation is based on the Delaunay-Voronoi algorithm. Then it is easy to see that the restriction of φk on T is precisely λk . nt to the number of triangles in Th and nv to the number of vertices. It is said also that the nodes of this finite element method are the vertices. However.3*cos(t). Currently FreeFem++ implements the following elements in 2d.1+0.nt of triangles shown in figure 2. a “skin” remains between the exact domain Ω and its approximation Ωh = ∪nt Tk .··· . i = 1. vertices etc. 2. If Ω is not a polygonal domain. y) = k=1 wk φk (x.5*sin(t). triangles here only. i = 1. 3 are the 3 vertices of T . because inner vertices are determined by the density of points on the boundary. Then M Vh (Th . P1 continuous piecewise linear. y). called the hat functions φk which are continuous piecewise affine and are equal to 1 on one vertex and 0 on all others.13 border C(t=2*pi. y=0. y) w(x. defined by λi = 1.0){x=0.e. .4: Graph of φ1 (left) and φ6 RT1 Raviart-Thomas degree 1 piecewise constant (need load "Element_Mixte") BDM1 Brezzi-Douglas-Marini degree 1 piecewise constant (need load "Element_Mixte") RT0Ortho Nedelec type 1 degree 0 piecewise constant RT1Ortho Nedelec type 1 degree 1 piecewise constant (need load "Element_Mixte") BDM1Ortho Brezzi-Douglas-Marini degree 1 piecewise constant (need load "Element_Mixte") P1nc piecewise linear non-conforming.. Currently FreeFem++ implements the following elements in 3d. Morley Morley finite element (need load "Morley") P2BR P2 Bernardi-Raugel finite element (need load "BernadiRaugel. P2dc piecewise quadratic discontinuous.cpp") P0edge a finite element constant per edge P1edge to P5edge a finite element polynomial on edge (need load "Element_PkEdge") . .(need load "Element_P4dc") P1b piecewise linear continuous plus bubble. To get the full list. P13d continuous piecewise linear.. (see section 6 for the full description) P03d piecewise constant.(need load "Element_P3dc") P4dc piecewise quartic discontinuous. P2b piecewise quadratic continuous plus bubble. P23d continuous piecewise quadratic. P1dc piecewise linear discontinuous. . Edge03d The Nedelec Edge element P1b3d piecewise linear continuous plus bubble. in a unix terminal.3: mesh Th Figure 2..14  # CHAPTER 2. GETTING STARTED $  " $ ! ! # & % # & " % ! & " % ! % " Figure 2. RT03d Raviart-Thomas piecewise constant. in directory examples++-tutorial do FreeFem++ dumptable. P2h quadratic homogene continuous (without P1) P3dc piecewise cubic discontinuous.edp grep TypeOfFE lestables Note that other elements can be added fairly easily. y) (2.. the unknown (here u) and test functions (here v) are present.. indeed to construct the linear systems FreeFem++ finds out which integral contributes to the bilinear form by checking if both terms . Step4: Solution and visualization 6th line: The current time in seconds is stored into the real-valued variable cpu. y) = k=0 uk φk (x. v) − (f. // the problem is solved here or declared and solved at the same time as in Vh u. v) = Ω ∀v satisfying v = 0 on ∂Ω.6) u· f v dxdy In FreeFem++ the Poisson problem can be declared only as in Vh u. y) and integrating the result over Ω: − v∆u dxdy = vf dxdy Ω Ω Then.1) by v(x. solve Poisson(u. 7th line The problem is solved.4) 5th line: the right hand side f is defined analytically using the keyword func.2).v) = and solved later as in . u is unused) f v dxdy −→ int2d(Th)( f*v ) Ω In FreeFem++ bilinear terms and linear terms should not be under the same integral.v declares that u and v are approximated as above. and (2. v dxdy.5) is written with dx(u) = ∂u/∂x.v.1) and its Dirichlet boundary conditions (2.v) =int(. . dy(u) = ∂u/∂y and u· Ω v dxdy −→ int2d(Th)( dx(u)*dx(v) + dy(u)*dy(v) ) (Notice here... Poisson. This variational formulation is derived by multiplying (2. namely M −1 u(x. by Green’s formula.15 Step3: Setting the problem 4th line: Vh u.5) (2.. y) uh (x. 7th–9th lines: defines the bilinear form of equation (2. . v) = Ω (2.v. (f.. problem Poisson(u. v) = 0 with a(u. the problem is converted into finding u such that a(u. // stiffness matrix. y) = i=0 u[][i]φi (x. · · · . Vh F. the user needs not study C++ for using FreeFem++ .e.. M − 1 are the basis functions of Vh like in equation (2. M − 1.. Access to matrices and vectors Internally FreeFem++ will solve a linear system of the type M −1 Aij uj − Fi = 0. i = 0.2 (see Section 7.M −1 ).v. the dimension of the space Vh).3).ndof is the number of degree of freedom (i.. . meaning that Poisson is declared only here and when it is called (by simply writing Poisson. and M = Vh.v. The vector F in (2.1 Here u and F are finite element function. postscript and other commands).. The linear system (2.. Note. The matrix A = (Aij ) is called stiffness matrix .4) and replacing v by φi in (2.12 page 162 for details) varf a(u.16 CHAPTER 2. 2. // u[] is the vector associated to the function u Note 2.. And the Dirichlet conditions are implemented by penalty. see the index item solve!tgv=. y) = i=0 F[][i]φi (x. but it helps to guess what is allowed in the language. 12th line: The computing time (not counting graphics) is written on the console Notice the C++-like syntax. y).7) will be solved by the Conjugate Gradient method..7) is solved by UMFPACK unless another option is mentioned specifically as in Vh u.unused=0). problem Poisson(u. If the user wants to access A directly he can do so by using (see section 6..v) = int2d(Th)( dx(u)*dx(v) + dy(u)*dy(v)) + on(C.7) which is found by using (2. .u=0) . Fi = Ω f φi dxdy (2. ) then (2. y) where φi . GETTING STARTED 11th line: The visualization is done as illustrated in Fig.. matrix A=a(Vh.1 for zoom..Vh). j=0 i = 0. namely by setting Aii = 1030 and Fi = 1030 ∗ 0 if i is a boundary degree of freedom. So we have M −1 M −1 u(x. F[] = l(0. F(x.. // F[] is the vector associated to the function F The problem can then be solved by u[]=Aˆ-1*F[].Vh).. that the number 1030 is called tgv (tr`s grande valeur ) and it is e generally possible to change this value .5).7) can also be constructed manually varf l(unused.v) = int2d(Th)(f*v)+on(C. and u[] and F[] give the array of value associated ( u[]≡ (ui )i=0.solver=CG) = int2d(..M −1 and F[]≡ (Fi )i=0. P2).8+0.} plot(a(50)+b(-30). THE DEVELOPMENT CYCLE: EDIT–RUN/VISUALIZE–REVISE 17 2. 2.} border b(t=0. polymorphic and reentrant with macro generation (see 9. If you are a FEM beginner. y=0. plot(Th.12). one key guideline is that FreeFem++ rarely generates an internal finite element array. The development cycle will have the following steps: Modeling: From strong forms of PDE to weak forms. one must know the variational formulation to use FreeFem++ . a typical example is the time dependent heat equation with an implicit time scheme: the internal matrix can be factorized only once and FreeFem++ can be taught to do so. Use the plotparameter ps="toto. note that this can also be done in terminal mode by : % FreeFem++ mycode.edp Visualization: Use the keyword plot to display functions while FreeFem++ is running. plot(f.label=2. you may also have to read a book on variational formulations.2 Some Features of FreeFem++ The language of FreeFem++ is typed.edp). Le Hyaric.1 The Development Cycle: Edit–Run/Visualize–Revise An integrated environment is provided with FreeFem++ by A. // plot Th then needs a mouse click fespace Vh(Th.label=1.wait=debug). // plot the borders to see the intersection // (so change (0. except for the time lost in the interpretation of the language (which can be reduced by a systematic usage of varf and matrices instead of problem. this was adopted for speed and consequently FreeFem++ could be hard to beat in terms of execution speed.eps" to generate a postscript file to archive the results.”.0. // plot the function f .3*sin(t).3 in b) then needs a mouse click mesh Th = buildmesh(a(50)+b(-30)).2. Debugging: A global variable ”debug” (for example) can help as in wait=true to wait=false.1. Programming: Write the code in FreeFem++ language using a text editor such as the one provided in the integrated environment.2*pi){ x=0. one should also have an eye on the reusability of the variational formulation so as to keep the same internal matrices.3*cos(t).2*pi){ x=cos(t). Every variable must be typed and declared in a statement each statement separated from the next by a semicolon ”. Many examples and tutorials are also given along with this documentation and it is best to study them and learn by example. Run: Run the code (here written in file mycode. y=sin(t). bool debug = true. The syntax is that of C++ by default augmented with something that is more akin to TEX.8 in 0.wait=debug). Explanations for some of these examples are given in this documentation in the next chapter. border a(t=0. Use the plot-parameter wait=1 to stop the program at each plot.wait=debug). For the specialist. Vh f = sin(pi*x)*cos(pi*y). If you use the same symbol twice as in real aaa =1.wait=debug). The following example works: . then you will get the message 2 : real aaa.. error Compile error : parse error line number :2. plot(g. .. .... Error line number 2.. mesh Th = square(10. Vh u.Vh). 2 : mesh Th = square(10.. plot(Th). GETTING STARTED // plot the function g Changing debug to false will make the plots flow continuously.. matrix A=a(Vh..18 Vh g = sin(pi*x + cos(pi*y)).. code = 1 token . .10. For example... just as you would do in C++. The identifier aaa exists the existing type is <Pd> the new type is <Pd> If you find that the program isn’t doing what you want you may also use cout to display in text format on the console window the value of variables.. (we did our best)! Nevertheless they are displayed at the right place.10. watching the flow of graphs on the screen (while drinking coffee) can then become a pleasant experience. Another trick is to comment in and out by using the“ //” as in C++. They are not always very explicit because of the template structure of the C++ code.. before parse error current line = 2 Compile error : parse error line number :2. For example real aaa =1. cout<<u.. fespace Vh. if you forget parenthesis as in bool debug = true.edp. Error messages are displayed in the console window. in file bb. cout<<A. // real aaa. then you will get the following message from FreeFem++. real aaa. CHAPTER 2. recall that ∂ϕ = ϕ · n. is obtained by solving Laplace’s equation: −∆ϕ = f in Ω. A number of simple examples cover a good deal of the capacity of FreeFem++ and are self-explanatory. then due to the membrane’s rigidity the angle with the normal vector n is zero. one has: ϕ|Γ = 0. For the modeling part this chapter continues at Chapter 9 where some PDEes of physics. like us. and a force f (x)dx is exerted on each surface element dx = dx1 dx2 . ϕ(x). 3. who don’t like to read manuals. If a part Γ2 of the membrane border Γ is not fixed to the support but is left hanging.1 Membranes Summary Here we shall learn how to solve a Dirichlet and/or mixed Dirichlet Neumann problem for the Laplace operator with application to the equilibrium of a membrane under load. ϕ|Γ = z. x2 ) then the boundary conditions would be of non-homogeneous Dirichlet type. thus the boundary conditions are ∂ϕ |Γ = 0 ϕ|Γ1 = z.Chapter 3 Learning by Examples This chapter is for those. The vertical membrane displacement. ∆ϕ = ∂x2 ∂x2 1 19 . We shall also check the accuracy of the method and interface with other graphics packages. As the membrane is fixed to its planar support. If the support wasn’t planar but at an elevation z(x1 . Let us recall also that the Laplace operator ∆ ∂n is defined by: ∂ 2ϕ ∂ 2ϕ + 2. An elastic membrane Ω is attached to a planar rigid support Γ. engineering and finance are studied in greater depth. ∂n 2 where Γ1 = Γ − Γ2 . the easiest proof is to notice that ϕ is the state of least energy. v)w1 + B(u. Dautray-Lions (1988). plot(Th..e.edp the length of the semimajor axis and semiminor axis border Gamma1(t=0.w. real a=2... // file membrane. savemesh(Th. f=1.theta) { x = a * cos(t). Recall that (x ∈ Rd . or ask help form a colleague or drop the matter.eps"). w2 . Now if you want to solve a system of PDE like A(u. Ω Example Let an ellipse have the length of the semimajor axis a = 2. WARNING Unlike freefem+ which had both weak and strong forms. plot(phi. Strang (1986) and Raviart-Thomas (1983)). E(φ) = min E(v). v) = 0 don’t close this manual. // func z=x. i..w)=int2d(Th)(dx(phi)*dx(w) + dy(phi)*dy(w)) . ps="membraneTh. Vh phi. v)w2 ) = 0 ∀w1 .wait=true.eps").msh"). ps="membrane. } border Gamma2(t=theta.b=1.20 CHAPTER 3.int2d(Th)(f*w) + on(Gamma1. It is not possible to go further in using this software if you don’t know the weak form (i. // // Plot phi Plot Th .. B(u. variational formulation) of your problem: either you read a book. v) = 0. Programming this case with FreeFem++ gives: Example 3.e. } mesh Th=buildmesh(Gamma1(100)+Gamma2(50)). LEARNING BY EXAMPLES With such ”mixed boundary conditions” the problem has a unique solution (see (1987). FreeFem++ implements only weak formulations.wait=true.1 (membrane. // P2 conforming triangular FEM solve Laplace(phi.phi=z). y = b*sin(t). what is known as the weak form of the PDE or its variational formulation (also known here as the theorem of virtual work) ϕ· Ω w= Ω fw ∀w ∈ V Next an integration by parts (Green’s formula) will show that this is equivalent to the PDE when second derivatives exist.2*pi) { x = a * cos(t).edp) real theta=4. y = b*sin(t). ϕ−z∈V with E(v) = 1 ( | v|2 − f v) Ω 2 and where V is the subspace of the Sobolev space H 1 (Ω) of functions which have zero trace on Γ1 .*pi/3. fespace Vh(Th.P2)."Th. d = 2 here) H 1 (Ω) = {u ∈ L2 (Ω) : u ∈ (L2 (Ω))d } Calculus of variation shows that the minimum must satisfy. and unitary the semiminor axis Let the surface force be f = 1. because in weak form it is (A(u. 5 -1 -1.txt" 2 1.2 0 -0.5 2 Figure 3.5 -1 -1. MEMBRANES 21 "phi.5 1 0.1: Mesh and level lines of the membrane deformation. .1.5 -1 -0.5 -2 1 0.3.6 0.5 0 0.5 -2 2 1.8 0.8 -1 -2 -1.5 0 -0.5 1 0.6 -0.4 0.5 0 -0. Below: the same in 3D drawn by gnuplot from a file generated by FreeFem++ .4 -0.5 1 1.2 -0. The system is solved by a multi-frontal Gauss LU factorization implemented in the package UMFPACK.2 (membranerror.edp) solve laplace(phi.22 CHAPTER 3.. func phiexact=sin(xˆ2+yˆ2-1).P2).n++) { mesh Th=buildmesh(Gamma1(20*(n+1))+Gamma2(10*(n+1))).*pi/3. plot(phi. // Plot phi with full color display Next we would like to check the results! One simple way is to adjust the parameters so as to know the solutions. This keyword calls a triangulation subroutine based on the Delaunay test.phi=0). // the length of the semimajor axis and semiminor axis border Gamma1(t=0.w. f = −4(cos(x2 + y 2 − 1) − (x2 + y 2 ) sin(x2 + y 2 − 1)) except that on Γ2 ∂n ϕ = 2 instead of zero. a linear system is derived from the discrete formulation whose size is the number of vertices plus the number of midedges in the triangulation.Gamma2)(2*w)+ on(Gamma1. } border Gamma2(t=theta. as was briefly indicated in the previous chapter.2*pi) { x = a * cos(t). an array two values Example 3. The keyword plot will display both Th and ϕ (remove Th if ϕ only is desired) and the qualifier fill=true replaces the default option (colored level lines) by a full color display. How fine the triangulation becomes is controlled by the size of the closest boundary edges. Results are on figure 3. real[int] L2error(2). y = b*sin(t). For instance on the unit circle a=1 .w)=int2d(Th)(dx(phi)*dx(w) + dy(phi)*dy(w)) . // for(int n=0.n<2. . So we will consider a non-homogeneous Neumann condition and solve fw + 2w ∀w ∈ V ( ϕ· w = Ω Ω Γ2 We will do that with two triangulations. compute the L2 error: = Ω |ϕ − ϕe |2 and print the error in both cases as well as the log of their ratio an indication of the rate of convergence. } func f=-4*(cos(xˆ2+yˆ2-1) -(xˆ2+yˆ2)*sin(xˆ2+yˆ2-1)).theta) { x = a * cos(t). real a=1. // file membranerror. which first triangulates with only the boundary points.. Vh phi.1. LEARNING BY EXAMPLES A triangulation is built by the keyword buildmesh. fespace Vh(Th.int1d(Th.b=1. // to remove all default output real theta=4. y = b*sin(t).edp verbosity =0.fill=true).wait=true. then adds internal points by subdividing the edges.int2d(Th)(f*w) . ϕe = sin(x2 + y 2 − 1) solves the problem when z = 0. The PDE is then discretized using the triangular second order finite element method on the triangulation.. msh").0)]<<"\n\n\n" } } We use the finite element numbering.i++) { for (int j=0.x << " "<< Th[i][0].00117128 convergence rate = 1. Then open gnuplot and do set palette rgbformulae 30. MEMBRANES plot(Th.94s We find a rate of 1.32 splot "graph. It will be useless if you don’t save the triangulation as well. which is not close enough to the 3 predicted by the theory. cout <<" convergence rate = "<< log(L2error[0]/L2error[1])/log(2.) the output is L2error 0 = 0.02s.2.eps plot generated by FreeFem++ and you want to use other graphic facilities. then you must store the solution in a file very much like in C++. j++) ff<<Th[i][j].n++) cout << " L2error " << n << " = "<< // 23 Plot Th and phi L2error[n] <<endl. The Geometry is always a polygon so we lose one order due to the geometry approximation in O(h2 ) Now if you are not satisfied with the . but not with P1nc because the 3 first degrees of freedom of P2 or P2 are on vertices and not with P1nc.wait=true.phi. For the triangulation the name is important: it is the extension that determines the format.x << " "<< Th[i][j]. j <3.txt" w l pal This works with P2 and P1.3. Here is an interface with gnuplot to produce the right part of figure 3.ps="membrane. ff<<Th[i][0]. // to build a gnuplot data file { ofstream ff("graph.j) is the global index of j T h degrees of freedom of triangle number i. consequently you must do { ofstream ff("phi.n<2.y<< " "<<phi[][Vh(i. Still that may not take you where you want. } for(int n=0.txt").y<< " "<<phi[][Vh(i. L2error[n]= sqrt(int2d(Th)((phi-phiexact)ˆ2)). for (int i=0.txt"). where Wh(i.31. } savemesh(Th. execution 6.9829 times: compile 0. ff << phi[]. .j)]<<endl.eps").1."Th.nt.93591.00462991 L2error 1 = 0.i<Th. <<endl. be 2 thermal conductors within an enclosure C0 . y=-3. The problem Let {Ci }1.1){ C24(t=0.} label=C2. x=-1-t. label=C1. The first one is held at a constant temperature u1 the other one has a given thermal conductivity κ2 5 times larger than the one of C0 . mesh Th=buildmesh( C0(50) + C11(5)+C12(20)+C13(5)+C14(20) + C21(-5)+C22(-20)+C23(-5)+C24(-20)).1){ C13(t=0.} label=C2. Example 3.} label=C1. 1 u − g ∈ H0 (Ω) : Ω 1 u v = 0 ∀v ∈ H0 (Ω) Let us assume that C0 is a circle of radius 5 centered at the origin. y=-3+6*t. as well as read and write operations.eps").2*pi){x=5*cos(t). y=5*sin(t).1){ C21(t=0. y=3-6*t. Ci are rectangles.} to see the border of the domain C0(50) // + C11(5)+C12(20)+C13(5)+C14(20) + C21(-5)+C22(-20)+C23(-5)+C24(-20).2 Heat Exchanger Summary Here we shall learn more about geometry input and triangulation files.3 (heatex.2 . x=-1. . x=2. 1. The second equation is a reduced form for: u = ui on Ci .1){ C23(t=0. y=3.wait=1).} label=C2.1){ C22(t=0. C2=98. that is C0 ∪ C1 Here g is any function of x equal to ui on Ci .1){ x=1+t. ps="heatexb. x=-2+t. In order to know u(x) at any point x of the domain Ω.edp int C1=99.1){ C12(t=0. C1 being at the constant temperature u1 = 60◦ C. x=-2.} border border border border border border border border plot( C11(t=0.24 CHAPTER 3.edp) // file heatex. u|Γ = g where Ω is the interior of C0 minus the conductors C1 and Γ is the boundary of Ω.} label=C1. y=-3+6*t. y=3. x=1. x=2-t. We assume that the border of enclosure C0 is held at temperature 20◦ C and that we have waited long enough for thermal equilibrium. LEARNING BY EXAMPLES 3. wait=true. // could be anything such that = 0 and C1 = C2 border C0(t=0.} label=C2.1){ C14(t=0.} label=C1. 1 The variational formulation for this problem is in the subspace H0 (Ω) ⊂ H 1 (Ω) of functions which have zero traces on Γ. we must solve · (κ u) = 0 in Ω. y=-3. plot(Th. i = 0. y=3-6*t. and set Dirichlet conditions on the vertical axis. IsoValue 15.3158 30. Vh kappa=1+2*(x<-1)*(x>-2)*(y<3)*(y>-3).2632 89. border C121(t=0.2105 68.2: The heat exchanger Exercise Use the symmetry of the problem with respect to the axes.7. solve a(u. HEAT EXCHANGER fespace Vh(Th.8421 81.4211 72.0526 85.} border C122(t=0. 25 Note the following: • C0 is oriented counterclockwise by t. while C1 is oriented clockwise and C2 is oriented counterclockwise.5789 55. ps="heatex. It is not possible to change the (uniform) distribution of vertices but a piece of boundary can always be cut in two or more parts.4737 93.wait=true.. above).v)= int2d(Th)(kappa*(dx(u)*dx(v)+dy(u)*dy(v))) +on(C0.7368 38. label=C1. • C1 and C2 are built by joining pieces of straight lines. borders have an internal number corresponding to their order in the program (check it by adding a cout<<C22./* C12(20) */ + C121(12)+C122(8)+. label=C1. value=true. To group them in the same logical unit to input the boundary conditions in a readable way we assigned a label on the boundaries..1053 26. ..1579 47.3684 51.7895 22. label=C1. • As usual the mesh density is controlled by the number of vertices assigned to each boundary.. y=3-6*t.9474 43.1) x=2. This is essential to understand how a mesh can be output to a file and re-read (see below).2.6316 76.5263 34.3.u=20)+on(C1... fill=true.7){ x=2. plot(u. for instance C12 could be replaced by C121+C122: // border C12(t=0.).6842 104.0. and Neumann conditions on the horizontal axis.u=60). buildmesh(. As said earlier. y=3-6*t.7895 60 64.eps"). triangulate only one half of the domain.v. y=3-6*t.P1).1){ x=2.211 Figure 3.} . This is why C1 is viewed as a hole by buildmesh. Vh u. plot(us). Wh us. a phenomenon called “resonance”. y= 1+2*t .} x= 0.1) a1(t=0. y= t .1) { { { { { { { x= 5. 2 ∂t When the solution wave is monochromatic (and that depend on the boundary and initial conditions).4 (sound.} x=5-2*t. u is of the form u(x.edp) real kc2=1. 3. y= 1-t . This sign may make the problem ill posed for some values of k .} x= 1-t. and then later on we write a similar program but we wish to read the mesh from that file. ∂n (3. At resonance there are non-zero solutions even when g = 0.1) a4(t=0.1) a2(t=0. fespace Wh(Sh. Note that the names of the boundaries are lost but either their internal number (in the case of C0) or their label number (for C1 and C2) are kept. So the following program may or may not work: Example 3.msh"). Then this is how the condenser should be computed: mesh Sh=readmesh("condensor.vs.P1). solve b(us.edp . Note the “+” sign in front of the Laplace operator and that k > 0 is c real.3 Acoustics Summary Here we go to grip with ill posed problems and eigenvalue problems Pressure variations in air at rest are governed by the wave equation: ∂ 2u − c2 ∆u = 0. t) = Re(v(x)eikt ) where v is a solution of Helmholtz’s equation: k 2 v + c2 ∆v = 0 in Ω. border border border border border border border a0(t=0.1) where g is the source. LEARNING BY EXAMPLES Writing and reading triangulation files Suppose that at the end of the previous program we added the line savemesh(Th. y= 1 .} x= 3-2*t. ∂v |Γ = g.} // file sound.1) a6(t=0. y=3-2*t .vs)= int2d(Sh)(dx(us)*dx(vs)+dy(us)*dy(vs)) +on(1.} x= 1+4*t.1) a5(t=0. y= 0 .us=0)+on(99.us=-1).msh")."condensor.} x= t. func g=y*(1-y). y= 3 .1) a3(t=0.26 CHAPTER 3.us=1)+on(98. eps"). We must solve the temperature equation in Ω in a time interval (0. the plate is surrounded by air at x temperature ue and initially at temperature u = u0 + L u1 . We shall also show how to treat an axisymmetric problem and show also how to deal with a nonlinear problem. y. u(x. To find all the ue one can do the following real sigma = 20. matrix B= b(Vh.value=ev.4.2) .solver=CG. Lz) of rectangular cross section Ω = (0. 6) × (0.a4)(g*v). as a first approximation the problem is 2D.vector=eV.sigma* u1*u2 ). THERMAL CONDUCTION mesh Th=buildmesh( a0(20) + a1(20) + a2(20) + a3(20) + a4(20) + a5(20) + a6(20)). plot(v.eps"). ∂n (3.v)=int2d(Th)(u*v * kc2 .solver=Crout.v.Vh. T ). T ). ps="sound.B. then for any given solution u + ue is another a solution. wait=1.P1).u2)= int2d(Th)( dx(u1)*dx(u2) + dy(u1)*dy(u2) .1 matrix OP= op(Vh.ps="eigen.3. 27 Results are on Figure 3.3.sigma=sigma. Vh u.wait=1. // the shifted matrix varf op(u1. 1). Vh[int] eV(nev). In the plane perpendicular to the plate at z = Lz/2. v=eV[0].sym=true. Lx) × (0.int1d(Th.T). How air cools a plate We seek the temperature distribution in a plate (0. then the solution is not unique: if ue = 0 is an eigen state. 0) = u0 + xu1 ∂u κ + α(u − ue ) = 0 on Γ × (0. cout<<ev(0)<<" 2 eigen values "<<ev(1)<<endl.[u2]) = int2d(Th)( u1*u2 ) . tol=1e-10.4 Thermal Conduction Summary Here we shall learn how to deal with a time dependent parabolic problem.factorize=1). the temperature varies little with the coordinate z.dy(u)*dy(v)) . Ly) × (0. But when kc2 is an eigenvalue of the problem.sigma B . solve sound(u. ∂t u − · (κ u) = 0 in Ω × (0.dx(u)*dx(v) . // number of requested eigenvalues near sigma // // to store the nev eigenvalue to store the nev eigenvector int k=EigenValue(OP.ncv=0). // value of the shift // OP = A . fespace Vh(Th.Vh. real[int] ev(nev). varf b([u1].maxit=0. 3. plot(u. int nev=2. // no Boundary condition see note 9.eps=1e-20). // uold ≡ un−1 = un ≡u thermic. y) satisfying for all w ∈ H 1 (Ω): un − un−1 ( w + κ un w) + α(un − uu e)w = 0 δt Γ Ω func u0 =10+90*x/6. or mixed) type.28 CHAPTER 3. real ue = 25. for(real t=0.3)(alpha*ue*v) .5)<<endl. mesh Th=square(30. Right: first eigen state (λ = (k/c)2 = 19.5)+0.uold. one below the middle horizontal line and ten times less above. alpha=0.3: Left:Amplitude of an acoustic signal coming from the left vertical wall. Vh u=u0.int1d(Th.2.5. The term α(u − ue ) accounts for the loss of temperature by convection in air. . we shall seek un (x.u=u0).[6*x.v)= int2d(Th)(u*v/dt + k*(dx(u) * dx(v) + dy(u) * dy(v))) + int1d(Th. Mathematically this boundary condition is of Fourier (or Robin. fespace Vh(Th.t<T. // here solve the thermic problem ff<<u(3. ofstream ff("thermic. dt=0. LEARNING BY EXAMPLES Figure 3.1 . so as to simulate a thermostat. The variational formulation is in L2 (0.8*(y<0.v.dat").y]).1.P1). in loose terms and after applying an implicit Euler finite difference approximation in time.int2d(Th)(uold*v/dt) + on(2.1. problem thermic(u.3)(alpha*u*v) . T . T=5. func k = 1. H 1 (Ω)).4256) close to 20 of eigenvalue problem :−∆ϕ = λϕ and ∂ϕ = 0 on Γ ∂n Here the diffusion κ will take two values.0.t+=dt){ uold=u.4.25. 9. θ polar angle in a fixed plane perpendicular to the axis): 1 1 2 2 ∆u = ∂r (r∂r u) + 2 ∂θθ u + ∂zz . R[×]0. the same procedure can be used..5 2 2. Results are shown on Figure 3. |[ .0. We take the convention of numbering of the edges as in square() (1 for the bottom horizontal .0. For instance to print x → ∂u (x.5) for all times in file thermic. 0.4. z u(t = 0) = u0 + (u1 − u) Lz u|Γ4 = u0 .5 Figure 3. α(u − ue ) + ∂u |Γ ∪Γ = 0.4: Temperature at T=4.9)<<endl.0. Right: decay of temperature versus time at x=3. In cylindrical coordinates. so the domain Ω is again a rectangle ]0.9) one would do ∂y for(int i=0. 56 "thermic. THERMAL CONDUCTION plot(u). z is the distance along the axis.5 4 4. Notice also that the way we store the temperature at point (3.3. r r Symmetry implies that we loose the dependence with respect to θ.4..5 3. Should a one dimensional plot be required.1 Axisymmetry: 3D Rod with circular section Let us now deal with a cylindrical rod instead of a flat plate. the problem is now: r∂t u − ∂r (r∂r u) − ∂z (r∂z u) = 0 in Ω.3) . } 29 Notice that we must separate by hand the bilinear part from the linear one. y=0.5 3 3. For simplicity we take κ = 1.dat" 54 52 50 48 46 44 42 40 38 36 34 0 0. ∂n 1 3 (3. the Laplace operator becomes (r is the distance to the axis.5 1 1.0*i/20.4.i++) cout<<dy(u)(6.dat.). u|Γ2 = u1 .i<20. 30 CHAPTER 3. fespace Vh(Th..int2d(Th)(uold*v*x/dt) + on(2. in the FreeFem++ syntax r becomes x and z becomes y and the problem is: problem thermaxi(u.t+=dt){ vold=v.4.v=u0-ue).b. for(real t=0.w. Still one can prove existence and uniqueness for u and because of this degeneracy no boundary conditions need to be imposed on Γ1 . problem thermradia(v. thermradia. This adds to the loss by convection and gives the following boundary condition: ∂u + α(u − ue ) + c[(u + 273)4 − (ue + 273)4 ] = 0 κ ∂n The problem is nonlinear. 3. If m denotes the iteration index. 3. with multiple meshes within one problem.v)=int2d(Th)((u*v/dt + dx(u)*dx(v) + dy(u)*dy(v))*x) + int1d(Th.int2d(Th)(vold*w/dt) + on(2. .3)(b*v*w) .w) = int2d(Th)(v*w/dt + k*(dx(v) * dx(w) + dy(v) * dy(w))) + int1d(Th.3)(alpha*x*u*v) .m++){ b= alpha + rad * (v + 2*uek) * ((v+uek)ˆ2 + uekˆ2). // finite element space real rad=1e-8. plot(vold). LEARNING BY EXAMPLES Note that the PDE has been multiplied by r. with time steps dt. and must be solved iteratively.3)(alpha*x*ue*v) . We also learn how to manipulate the region indicator and see how smooth is the projection operator from one mesh to another. uek=ue+273. } } vold=v+ue. After discretization in time with an implicit scheme.5 Irrotational Fan Blade Flow and Thermal effects Summary Here we will learn how to deal with a multi-physics system of PDEs on a Complex geometry.. a semi-linearization of the radiation condition gives ∂um+1 + α(um+1 − ue ) + c(um+1 − ue )(um + ue + 546)((um + 273)2 + (ue + 273)2 ) = 0.4.m<5. ∂n because we have the identity a4 − b4 = (a − b)(a + b)(a2 + b2 ).t<T. for(int m=0. .P1). Notice that the bilinear form degenerates at x = 0.int1d(Th.2 A Nonlinear Problem : Radiation Heat loss through radiation is a loss proportional to the absolute temperature to the fourth power (Stefan’s Law).1.u=u0).4.v=u0-ue. // def of the physical constants Vh vold. The iterative process will work with v = u − ue . solve potential(psi.5 (potential. (3. IRROTATIONAL FAN BLADE FLOW AND THERMAL EFFECTS 31 Incompressible flow Without viscosity and vorticity incompressible flows have a velocity given by: u= ∂ψ ∂x2 ∂ψ − ∂x1 .075597*t .17363x3 − 0.} mesh Th= buildmesh(C(50)+Splus(70)+Sminus(70)). label=S. A zoom of the streamlines are shown on Figure 3.w. Vh psi.17363*(tˆ3)-0. ψ|S = 0. which means that ψ satisfies: ψ constant on the walls.w)=int2d(Th)(dx(psi)*dx(w)+dy(psi)*dy(w))+ on(C.06254*(tˆ4). As the fluid slips along the walls.06254*(tˆ4)).2*pi) { x=5*cos(t).17735*sqrt(t)-0.5. one way to model this problem is to write ∆ψ = 0 in Ω. Airfoil Let us consider a wing profile S in a uniform flow. where ψ is solution of ∆ψ = 0 This equation expresses both incompressibility ( ·u = 0) and absence of vortex ( ×u = 0).3. . y= -(0. Infinity will be represented by a large circle C where the flow is assumed to be of uniform velocity.212836x2 + 0.} border Splus(t=0.17735*sqrt(t)-0. ψ|C = u∞ y. plot(psi.075597*t -0.212836*(tˆ2)+0. border C(t=0.0){ x =t. y = 0. y=5*sin(t).212836*(tˆ2)+0.075597x − 0.0.psi = y) + on(S.5.psi=0). where ∂Ω = C ∪ S The NACA0012 Airfoil An equation for the upper surface of a NACA0012 (this is a classical wing profile in aerodynamics) is: √ y = 0. normal velocity is zero. fespace Vh(Th.edp) // file potential. and this translates into non constant Dirichlet data for ψ.edp real S=99. label=S.wait=1).} border Sminus(t=1. One can also prescribe the normal velocity at an artificial boundary.17363*(tˆ3)-0.06254x4 .4) Example 3.1){ x = t.P2).17735 x − 0. Note that an incidence angle has been added here (see Chapter 9).y=0. .2){x=1+t. thermic. int i.init=i.} // added to have a fine mesh at trail mesh Sh = buildmesh(C(25)+Splus(-90)+Sminus(-90)+D(200)). Wh v. Furthermore there is convection of heat by the flow.4817 98. u2=-dx(psi)*(region==air).7262 22.vv..5143 17. ∂v |C = 0 ∂n But now the domain is outside AND inside S and κ takes a different value in air and in steel.01*(region==air)+0. problem thermic(v.5.region.30233 12. to be plugged at the end of the previous program: . fespace W0(Sh. real dt=0.6339 69.2698 85.int2d(Sh)(vold*vv/dt). air=Sh(-1. Much like in the previous section the heat equation for the temperature v is ∂t v − · (κ v) + u · v = 0. W0 k=0.i++){ v=vold.9395 -3.32 CHAPTER 3.P1).vv.0). for(i=0. fespace Wh(Sh. v(t = 0) = v0 .8459 75. nbT=50.7861 48.5116 Figure 3.09037 7. 3.5741 43..i<nbT. hence the term u · v above.1*(region==steel). W0 u1=dy(psi)*(region==air).3621 38. Wh vold = 120*(region==steel).05.21 59. border D(t=0.solver=LU)= int2d(Sh)(v*vv/dt + k*(dx(v) * dx(vv) + dy(v) * dy(vv)) + 10*(u1*dx(v)+u2*dy(v))*vv).0).0578 80. Consider the following.1 Heat Convection around the airfoil Now let us assume that the airfoil is hot and that air is there to cool it.5. Right: temperature distribution at time T=25 (now the maximum is at 90 instead of 120).998 54.5: Zoom around the NACA0012 airfoil showing the streamlines (curve ψ = constant). int steel=Sh(0. LEARNING BY EXAMPLES IsoValue -10.P0).4219 64.9382 28.region.1502 33.12159 2. To obtain such a plot use the interactive graphic command: “+” and p. t) = c0 (x. consider the rotation vector field u = [u1. where xt = ˙ d(t → xt ) dt u1 = y. that is for a full revolution and to compare the final solution with the initial one. 3. 0) where xt is the particle path in the flow starting at point x at time 0. ˙ . The exact solution c(xt . u2 = −x. } 33 Notice here • how steel and air are identified by the mesh parameter region which is defined when buildmesh is called and takes an integer value corresponding to each connected component of Ω. Pure convection by u is ∂t c + u. u2]. they should be equal. • how the convection terms are added without upwinding. 0) The game consists in solving the equation until T = 2π. t) at time t en point xt is given by c(xt . We will learn about Characteristics-Galerkin and Discontinuous-Galerkin Finite Element Methods. c = 0 in Ω × (0. xt=0 = x.6 Pure Convection : The Rotating Hill Summary Here we will present two methods for upwinding for the simplest convection problem. T ) c(t = 0) = c0 in Ω. The ODE are reversible and we want the solution at point x at time t ( not at point xt ) the initial point is x−t . . So xt are solutions of xt = u(xt ). PURE CONVECTION : THE ROTATING HILL plot(v). The factor 10 in front of the convection terms is a quick way of multiplying the velocity by 10 (else it is too slow to see something). and we have c(x.3. Upwinding is necessary when the Pecley number |u|L/κ is large (here is a typical length scale). t) = c0 (x−t . • The solver is Gauss’ LU factorization and when init= 0 the LU decomposition is reused so it is much faster after the first iteration.6. Let Ω be the unit disk centered at 0. edp Vh w.3)ˆ2 +(y-0. v1 = y. Uh cold.edp) border C(t=0. real dt = 0. }. c=convect([u1.u2]. this is possible because xτ is then a polygonal curve which can be computed exactly and the solution exists always when u is divergence free.P1dc).min + ". b/ it may diverge in rare cases when |u| is too small due to quadrature error. LEARNING BY EXAMPLES Solution by a Characteristics-Galerkin Method In FreeFem++ there is an operator called convect([u1. m<2*pi/dt .5. Solution by Discontinuous-Galerkin FEM Discontinuous Galerkin methods take advantage of the discontinuities of c at the edges to build upwinding.-dt. plot(c.P1).cmm=" t="+t + ". mesh Th = buildmesh(C(100)). Example 3. min=" + c[]. // file convects.05. Uh u1 = y. max=" + } // file convects. When u is piecewise constant. al=0. Remark 4 3D plots can be done by adding the qualifyer ”dim=3” to the plot instruction.3)ˆ2)).7 (convects end..3)ˆ2)).6 (convects. There are may formulations DC possible. fespace Vh(Th.3)ˆ2 +(y-0.edp) .t=0. m++) { t += dt.17. ˙ xτ =0 = x. Example 3. cold=c. 2*pi) { x=cos(t). ccold. u2 = -x.34 CHAPTER 3. c = exp(-10*((x-0.cold). cc = exp(-10*((x-0. dt = 0.edp c[]. convect returns c(xdf ) = C ◦ X.u2]. . y=sin(t). real u. u2] starting at point x at time τ = 0. Finally [c] is the jump of c across an edge with the convention that c+ refers to the value on the right of the oriented edge. We shall implement here the so-called dual-P1 formulation (see Ern[11]): ( Ω cn+1 − cn +u· δt c)w + 1 (α|n · u| − n · u)[c]w = 2 E |n · u|cw − EΓ ∀w − where E is the set of inner edges and EΓ is the set of boundary edges where u · n < 0 (in our case there is no such edges)..dt.max). The method is very powerful but has two limitations: a/ it is not conservative. so xτ is solution of the following ODE: xτ = u(xτ ). fespace Uh(Th.c) which compute c ◦ X with X is the convect field defined by X(x) = xdt and where xτ is particule path in the steady state velocity field u = [u1. v2 = -x. for (int m=0. 0. IsoValue -0.C)((n<0)*abs(n)*cc*w) // unused because cc=0 on ∂Ω− .int1d(Th.65 0.min + ".75 0.ps="convectCG.2 0.7 0.eps".3.1].0.fill=1.2. t+=dt) { ccold=cc. Notice also the macro where the parameter u is not used (but the syntax needs one) and which ends with a //. }. real [int] viso=[-0.6.x.2 0.1 0.max).wait=1.fill=1.fill=1.cmm="t="+t + ".viso=viso).6.1 0. nTonEdge which is one if the triangle has a boundary edge and zero otherwise.65 0.w) = int2d(Th)((cc/dt+(v1*dx(cc)+v2*dy(cc)))*w) + intalledges(Th)((1-nTonEdge)*w*(al*abs(n)-n/2)*jump(cc)) // .4 0.int2d(Th)(ccold*w/dt).0. plot(c.45 0.0.N.55 0. As easily guessed N.1.35 0.0.5.0.8 0.0.5 0. max=" + cc[]. Results of both methods are shown on Figure 3.5) (so all internal edges are see two times ).5 0. intalledges to integrate on all edges of all triangles intalledges(Th) ≡ T ∈Th ∂T (3. Notice the new keywords.3 0.9 1 IsoValue -0.x*v1+N.0.7.5 0.wait=1.y*v2).1.0.y*v2) // Macro without parameter problem Adual(cc.8. it simply replaces the name n by (N.4 0.6 0.5 0.9 1 Figure 3.55 0.45 0. on the right with Discontinuous P1 Galerkin FEM.1.6 0.25 0.3.eps". plot(c.25 0.75 0. Adual. left with Characteristics-Galerkin.-0. for ( t=0.x*v1+N.viso=viso).3 0.0.1 0 0. plot(cc.6: The rotated hill after one revolution.8 0.1 0 0.5 0. this is done with the plot-modifier viso.9.7 0. Now if you think that DG is too slow try this . min=" + cc[].y is the normal to the edge.4.6 with identical levels for the level line.35 0.5 0. jump to implement [c].1. t< 2*pi . PURE CONVECTION : THE ROTATING HILL 35 macro n() (N.2.ps="convectDG. 36 CHAPTER 3. LEARNING BY EXAMPLES // the same DG very much faster varf aadual(cc,w) = int2d(Th)((cc/dt+(v1*dx(cc)+v2*dy(cc)))*w) + intalledges(Th)((1-nTonEdge)*w*(al*abs(n)-n/2)*jump(cc)); varf bbdual(ccold,w) = - int2d(Th)(ccold*w/dt); matrix AA= aadual(Vh,Vh); matrix BB = bbdual(Vh,Vh); set (AA,init=t,solver=sparsesolver); Vh rhs=0; for ( t=0; t< 2*pi ; t+=dt) { ccold=cc; rhs[] = BB* ccold[]; cc[] = AAˆ-1*rhs[]; plot(cc,fill=0,cmm="t="+t + ", min=" + cc[].min + ", max=" + cc[].max); }; Notice the new keyword set to specify a solver in this framework; the modifier init is used to tel the solver that the matrix has not changed (init=true), and the name parameter are the same that in problem definition (see. 6.9) . Finite Volume Methods can also be handled with FreeFem++ but it requires programming. For instance the P0 − P1 Finite Volume Method of Dervieux et al associates to each P0 function c1 a P0 function c0 with constant value around each vertex q i equal to c1 (q i ) on the cell σi made by all the medians of all triangles having q i as vertex. Then upwinding is done by taking left or right values at the median: 1 1 n+1 n (c − c1 ) + δt u · nc− = 0 ∀i ∂σi σi It can be programmed as load "mat_dervieux"; // external module in C++ must be loaded border a(t=0, 2*pi){ x = cos(t); y = sin(t); } mesh th = buildmesh(a(100)); fespace Vh(th,P1); Vh vh,vold,u1 = y, u2 = -x; Vh v = exp(-10*((x-0.3)ˆ2 +(y-0.3)ˆ2)), vWall=0, rhs =0; real dt = 0.025; // qf1pTlump means mass lumping is used FVM(v,vh) = int2d(th,qft=qf1pTlump)(v*vh/dt) - int2d(th,qft=qf1pTlump)(vold*vh/dt) + int1d(th,a)(((u1*N.x+u2*N.y)<0)*(u1*N.x+u2*N.y)*vWall*vh) + rhs[] ; problem matrix A; MatUpWind0(A,th,vold,[u1,u2]); for ( int t=0; t< 2*pi ; t+=dt){ vold=v; rhs[] = A * vold[] ; FVM; 3.7. A PROJECTION ALGORITHM FOR THE NAVIER-STOKES EQUATIONS plot(v,wait=0); }; 37 the mass lumping parameter forces a quadrature formula with Gauss points at the vertices so as to make the mass matrix diagonal; the linear system solved by a conjugate gradient method for instance will then converge in one or two iterations. The right hand side rhs is computed by an external C++ function MatUpWind0(...) which is programmed as // computes matrix a on a triangle for the Dervieux FVM q[3][2], // the 3 vertices of a triangle T u[2], // convection velocity on T c[3], // the P1 function on T a[3][3], // output matrix where[3] ) // where>0 means we’re on the boundary int fvmP1P0(double double double double double { for(int i=0;i<3;i++) for(int j=0;j<3;j++) a[i][j]=0; for(int i=0;i<3;i++){ int ip = (i+1)%3, ipp =(ip+1)%3; double unL =-((q[ip][1]+q[i][1]-2*q[ipp][1])*u[0] -(q[ip][0]+q[i][0]-2*q[ipp][0])*u[1])/6; if(unL>0) { a[i][i] += unL; a[ip][i]-=unL;} else{ a[i][ip] += unL; a[ip][ip]-=unL;} if(where[i]&&where[ip]){ // this is a boundary edge unL=((q[ip][1]-q[i][1])*u[0] -(q[ip][0]-q[i][0])*u[1])/2; if(unL>0) { a[i][i]+=unL; a[ip][ip]+=unL;} } } return 1; } It must be inserted into a larger .cpp file, shown in Appendix A, which is the load module linked to FreeFem++ . 3.7 A Projection Algorithm for the Navier-Stokes equations Summary Fluid flows require good algorithms and good triangultions. We show here an example of a complex algorithm and or first example of mesh adaptation. An incompressible viscous fluid satisfies: ∂t u + u · u+ p − ν∆u = 0, u|t=0 = u0 , A possible algorithm, proposed by Chorin, is 1 m+1 [u − um oX m ] + δt −∆pm+1 = − pm − ν∆um = 0, · um oX m , u|Γ = uΓ , ·u=0 u|Γ = uΓ . in Ω×]0, T [, ∂n pm+1 = 0, 38 where uoX(x) = u(x − u(x)δt) since ∂t u + u · teristics, as in the previous section. CHAPTER 3. LEARNING BY EXAMPLES u is approximated by the method of charac- An improvement over Chorin’s algorithm, given by Rannacher, is to compute a correction, q, to the pressure (the overline denotes the mean over Ω) −∆q = and define um+1 = u + ˜ qδt, pm+1 = pm − q − pm − q where u is the (um+1 , v m+1 ) of Chorin’s algorithm. ˜ The backward facing step The geometry is that of a channel with a backward facing step so that the inflow section is smaller than the outflow section. This geometry produces a fluid recirculation zone that must be captured correctly. This can only be done if the triangulation is sufficiently fine, or well adapted to the flow. Remark (FH), The are a technical difficulty is the example, the discret flow flux must be 0 and in the previous version this is not the case, the correction is not so simple. ·u− ·u Example 3.8 (NSprojection.edp) // file NSprojection.edp border a0(t=1,0){ x=0; y=t; label=1;} border a1(t=0,1){ x=2*t; y=0; label=2;} border a2(t=0,1){ x=2; y=-t/2; label=2;} border a3(t=0,1){ x=2+18*tˆ1.2; y=-0.5; label=2;} border a4(t=0,1){ x=20; y=-0.5+1.5*t; label=3;} border a5(t=1,0){ x=20*t; y=1; label=4;} int n=1; mesh Th= buildmesh(a0(3*n)+a1(20*n)+a2(10*n)+a3(150*n)+a4(5*n)+a5(100*n)); plot(Th); fespace Vh(Th,P1); real nu = 0.0025, dt = 0.2; // Reynolds=200 func uBCin = 4*y*(1-y)*(y>0)*(x<2) ; func uBCout = 4./1.5*(y+0.5)*(1-y) *(x>19); Vh w,u = uBCin, v =0, p = 0, q=0; real area= int2d(Th)(1.); Vh ubc = uBCin + uBCout; real influx0 = int1d(Th,1) (ubc*N.x), // FH add outflux0 = int1d(Th,3) (ubc*N.x); // FH add verbosity=1; for(int n=0;n<300;n++){ Vh uold = u, vold = v, pold=p; Vh f=convect([uold,vold],-dt,uold); real outflux = int1d(Th,3) (f*N.x); f = f - (influx0+outflux)/outflux0 * uBCout; outflux = int1d(Th,3) (f*N.x); assert( abs(influx0+outflux) < 1e-10); // // FH add // FH add // FH add WARNING the flux must be 0 .. solve pb4u(u,w,init=n,solver=LU) =int2d(Th)(u*w/dt +nu*(dx(u)*dx(w)+dy(u)*dy(w))) 3.7. A PROJECTION ALGORITHM FOR THE NAVIER-STOKES EQUATIONS -int2d(Th)((convect([uold,vold],-dt,uold)/dt-dx(p))*w) + on(1,u = 4*y*(1-y)) + on(2,4,u = 0) + on(3,u=f); plot(u); solve pb4v(v,w,init=n,solver=LU) = int2d(Th)(v*w/dt +nu*(dx(v)*dx(w)+dy(v)*dy(w))) -int2d(Th)((convect([uold,vold],-dt,vold)/dt-dy(p))*w) +on(1,2,3,4,v = 0); real meandiv = int2d(Th)(dx(u)+dy(v))/area; solve pb4p(q,w,init=n,solver=LU)= int2d(Th)(dx(q)*dx(w)+dy(q)*dy(w)) - int2d(Th)((dx(u)+ dy(v)-meandiv)*w/dt)+ on(3,q=0); 39 real meanpq = int2d(Th)(pold - q)/area; if(n%50==49){ Th = adaptmesh(Th,[u,v],q,err=0.04,nbvx=100000); plot(Th, wait=true); ubc = uBCin + uBCout; // reinterpolate B.C. influx0 = int1d(Th,1) (ubc*N.x); // FH add outflux0 = int1d(Th,3) (ubc*N.x); // FH add } p = pold-q-meanpq; u = u + dx(q)*dt; v = v + dy(q)*dt; real err = sqrt(int2d(Th)(square(u-uold)+square(v-vold))/Th.area) ; cout << " iter " << n << " Err L2 = " << err << endl; if(err < 1e-3) break; } plot(p,wait=1,ps="NSprojP.eps"); plot(u,wait=1,ps="NSprojU.eps"); Figure 3.7: Rannacher’s projection algorithm: result on an adapted mesh (top) showing the pressure (middle) and the horizontal velocity u at Reynolds 400. We show in figure 3.7 the numerical results obtained for a Reynolds number of 400 where mesh adaptation is done after 50 iterations on the first mesh. 40 CHAPTER 3. LEARNING BY EXAMPLES 3.8 The System of elasticity Elasticity Solid objects deform under the action of applied forces: a point in the solid, originally at (x, y, z) will come to (X, Y, Z) after some time; the vector u = (u1 , u2 , u3 ) = (X − x, Y − y, Z − z) is called the displacement. When the displacement is small and the solid is elastic, Hooke’s law gives a relationship between the stress tensor σ(u) = (σij (u)) and the strain tensor (u) = ij (u) σij (u) = λδij .u + 2µ ij (u), where the Kronecker symbol δij = 1 if i = j, 0 otherwise, with ij (u) 1 ∂ui ∂uj + ), = ( 2 ∂xj ∂xi and where λ, µ are two constants that describe the mechanical properties of the solid, and are themselves related to the better known constants E, Young’s modulus, and ν, Poisson’s ratio: E Eν µ= , λ= . 2(1 + ν) (1 + ν)(1 − 2ν) Lam´’s system Let us consider a beam with axis Oz and with perpendicular section Ω. The e components along x and y of the strain u(x) in a section Ω subject to forces f perpendicular to the axis are governed by −µ∆u − (µ + λ) ( .u) = f in Ω, where λ, µ are the Lam´ coefficients introduced above. e Remark, we do not used this equation because the associated variationnal form does not give the right boundary condition, we simply use −div(σ) = f where the corresponding variationnal form is: σ(u) : (v) dx − Ω Ω i,j inΩ vf dx = 0; aij bij . where : denote the tensor scalar product, i.e. a : b = So the variationnal form can be written as : λ .u .v + 2µ (u) : (v) dx − Ω vf dx = 0; Ω Example Consider elastic plate with the undeformed rectangle shape [0, 20] × [−1, 1]. The body force is the gravity force f and the boundary force g is zero on lower, upper and right sides. The left vertical sides of the beam is fixed. The boundary conditions are σ.n = g = 0 on Γ1 , Γ4 , Γ3 , u = 0 on Γ2 3.8. THE SYSTEM OF ELASTICITY Here u = (u, v) has two components. 41 The above two equations are strongly coupled by their mixed derivatives, and thus any iterative solution on each of the components is risky. One should rather use FreeFem++ ’s system approach and write: Example 3.9 (lame.edp) // file lame.edp mesh Th=square(10,10,[20*x,2*y-1]); fespace Vh(Th,P2); Vh u,v,uu,vv; real sqrt2=sqrt(2.); macro epsilon(u1,u2) [dx(u1),dy(u2),(dy(u1)+dx(u2))/sqrt2] // EOM // the sqrt2 is because we want: epsilon(u1,u2)’* epsilon(v1,v2) == (u) : (v) macro div(u,v) ( dx(u)+dy(v) ) // EOM real E = 21e5, nu = 0.28, mu= E/(2*(1+nu)); real lambda = E*nu/((1+nu)*(1-2*nu)), f = -1; solve lame([u,v],[uu,vv])= int2d(Th)( lambda*div(u,v)*div(uu,vv) +2.*mu*( epsilon(u,v)’*epsilon(uu,vv) ) ) - int2d(Th)(f*vv) + on(4,u=0,v=0); real coef=100; plot([u,v],wait=1,ps="lamevect.eps",coef=coef); mesh th1 = movemesh(Th, [x+u*coef, y+v*coef]); plot(th1,wait=1,ps="lamedeform.eps"); real dxmin = u[].min; real dymin = v[].min; cout << " - dep. cout << " dep. max x = "<< dxmin<< " y=" << dymin << endl; (20,0) = " << u(20,0) << " " << v(20,0) << endl; // The numerical results are shown on figure 3.8 and the output is: -- square mesh : nb vertices =121 , nb triangles = 200 , -- Solve : min -0.00174137 max 0.00174105 min -0.0263154 max 1.47016e-29 - dep. max x = -0.00174137 y=-0.0263154 dep. (20,0) = -1.8096e-07 -0.0263154 times: compile 0.010219s, execution 1.5827s nb boundary edges 40 42 CHAPTER 3. LEARNING BY EXAMPLES Figure 3.8: Solution of Lam´’s equations for elasticity for a 2D beam deflected by its own e weight and clamped by its left vertical side; result are shown with a amplification factor equal to 100. Remark: the size of the arrow is automatically bound, but the color gives the real length 3.9 The System of Stokes for Fluids In the case of a flow invariant with respect to the third coordinate (two-dimensional flow), flows at low Reynolds number (for instance micro-organisms) satisfy, −∆u + p = 0 ·u=0 where u = (u1 , u2 ) is the fluid velocity and p its pressure. The driven cavity is a standard test. It is a box full of liquid with its lid moving horizontally at speed one. The pressure and the velocity must be discretized in compatible fintie element spaces for the LBB conditions to be satisfied: sup p∈Ph (u, p) ≥ β|u| ∀u ∈ Uh |p| // int n=3; mesh Th=square(10*n,10*n); fespace Uh(Th,P1b); Uh u,v,uu,vv; fespace Ph(Th,P1); Ph p,pp; file stokes.edp solve stokes([u,v,p],[uu,vv,pp]) = int2d(Th)(dx(u)*dx(uu)+dy(u)*dy(uu) + dx(v)*dx(vv)+ dy(v)*dy(vv) + dx(p)*uu + dy(p)*vv + pp*(dx(u)+dy(v)) - 1e-10*p*pp) The fluid velocity and pressure are solution of the Navier-Stokes equations with varying density function of the temperature.9: Solution of Stokes’ equations for the driven cavity problem. ·u=0 2 k µT = cµ .v=0) + on(3. The results are on the front page of this book.u=0. 43 Remark. Results are shown on figure 3.v=0).9 3. plot([u. This comes to ∂t θ + u θ − · (κm θ) = 0 T ∂t u + u u − · (µT u) + p + e(θ − θ0 )e2 . The geometry is trapezoidal with prescribed inflow made of cool air at the bottom and warm air above and so are the initial conditions. Figure 3.2.p.10. A LARGE FLUID PROBLEM + on(1.10 A Large Fluid Problem A friend of one of us in Auroville-India was building a ramp to access an air conditioned room.wait=1).u=1.3. showing the velocity field and the pressure level lines.v]. I told him ”no way” and decided to check numerically. However the Navier-Stokes cum temperature equations have a RANS k − model and a Boussinesq approximation for the buoyancy.4. we add a stabilization term -10e-10*p*pp to fixe the constant part of the pressure. As I was visiting the construction site he told me that he expected to cool air escaping by the door to the room to slide down the ramp and refrigerate the feet of the coming visitors. slip velocity at the top (artificial) boundary and no-slip at the bottom. κT = κµT µT ∂t k + u k + − · (µT k) = | u + uT |2 2 . there is free outflow. stress. cin >> reylnods.u2x.-dt.1.0001.iter=0. border aa(t=0.09 . temp1.P0).up2=0.44 2 CHAPTER 3.temp=25) .temp1)*q ) + on(ff.1.5)/4. numu=nu/sqrt( 0.5){ x=0. vv. fespace Vh(Th. y = L. kappa=0.} border ee(t=L. // // // velocity space pressure space for gradients real reylnods=500. func g=(x)*(1-x)*4.P1b). problem TEMPER(temp.0){x= t .09). assert(reylnods>1 && reylnods < 100000).u1y.ep1.6) We use a time discretization which preserves positivity and uses the method of characteristics (X m (x) ≈ x − um (x)δt) 1 m+1 (θ − θm ◦ X m ) − · (κm θm+1 ) = 0 T δt 1 m+1 (u − um ◦ X m ) − · (µm um+1 ) + pm+1 + e(θm+1 − θ0 )e2 .001. eee=9. up1=0.q.L){x=15.5.P1). real s0=clock().bb)(temp*q* 0.} border cc(t=-1.u2y. · um+1 = 0 T δt m 1 m+1 µm (k − k m ◦ X m ) + k m+1 m − · (µm k m+1 ) = T | um + umT |2 T δt km 2 1 m+1 c1 c ˙ m m+1 m m m+1 ) = k m | um + umT |2 ( − ◦ X ) + c2 (µT − m δt k cµ 2 m+1 2 k µm+1 = cµ m+1 . y=t . fespace V0h(Th.0.3/0.} int n=8. int i=0.q) = // temperature equation int2d(Th)( alpha*temp*q + kappa * ( dx(temp)*dx(q) + dy(temp)*dy(q) )) // + int1d(Th. // cout << " Enter the reynolds number :".up1=0. fespace Vh2(Th.0){ x=0. y= . y=t .ep=0.v2.prode.prodk. real dt=0. nuep=pow(nu.} border ff(t=0. y=0 . k=0. c1m = 1.v1.4. y=t .} border dd(t=15. Vh u1x=0. V0h muT=1. κm+1 = κµm+1 (3.25e-4.14){x=1+t. // inflow Vh p=0.7) T T T In variational form and with appropriated boundary conditions the problem is: real L=6.k1. Vh2 u1.} border bb(t=0.1) + int2d(Th) ( -alpha*convect([up1. LEARNING BY EXAMPLES ∂t + u + c2 k − c cµ · (µT )= c1 k| u + 2 uT |2 = 0 (3.1){x=t.1*t . Vh2 u2. real alpha=0.81/303. real nu=1.0. mesh Th=buildmesh(aa(n)+bb(9*n) + cc(4*n) + dd(10*n)+ee(6*n) + ff(n)).aa. up2=0.up2].temp=35. 2.1) + int2d(Th) ( prodk*q-alpha*convect([up1.p.5. { real[int] xx(21).k=0.5..u2=0) + on(aa.q)= // get the rate of turbulent viscous energy int2d(Th)( (1.i<21.cmm="u1 x=0.y) + on(cc.25ˆ(1. } cout << " " << yy << endl.aa.ps="StokesP2P1.ep= 0.u2= -up1*N.yy].cmm="pressure y=0.q)= // get the kinetic turbulent energy int2d(Th)( (ep1/k1+alpha)*k*q + muT * ( dx(k)*dx(q) + dy(k)*dy(q) )) // + int1d(Th.i/20.bb.dx(u1)*q . nu=1.p*dx(v1) . } dt = 0. plot(coef=0.wait=1.aa. // plot([yy.up2]. xx[i]=u1(0./reylnods./nbiter) .ep=nuep*pow(stress.bb.up2].000001) .u2] et p ".aa.-dt.0001) + on(aa.5)) . real coefdt = 0.u2]./nbiter).q]) = // Navier-Stokes k-epsilon and Boussinesq int2d(Th)( alpha*( u1*v1 + u2*v2) + muT * (dx(u1)*dx(v1)+dy(u1)*dy(v1)+dx(u2)*dx(v2)+dy(u2)*dy(v2)) // ( 2*dx(u1)*dx(v1) + 2*dy(u2)*dy(v2)+(dy(u1)+dx(u2))*(dy(v1)+dx(v2))) + p*q*(0.pp].yy(21).-dt.bb. int nbiter = 3./nbiter).i++) { yy[i]=i/20.-dt. cut=0. A LARGE FLUID PROBLEM + on(aa. .bb)(temp*q*0.).u2=0) + on(ee.u1=3.5 cup"). 45 problem kine(k.0. // plot([xx.p].value=1.3.temp=35) .ep1)*q ) + on(ff. solve NS ([u1.u2=0) + on(bb.up2].u2=0) .999). real tol=0. for (int i=0.5ˆ(1.999 cup").wait=1).u1=0.05.-dt.k1)*q ) + on(ff. real coefcut = 0.25ˆ(1.coeftol = 0.92*ep1/k1+alpha)*ep*q + c1m*muT * ( dx(ep)*dx(q) + dy(ep)*dy(q) )) // + int1d(Th.10.1.up2)*v2 ) + on(ff.x/N. problem viscturb(ep.1) + int2d(Th) ( prode*q-alpha*convect([up1.[u1.v2.u2.eps".wait=1.1) + int2d(Th) (eee*(temp-35)*v1 -alpha*convect([up1.dy(u2)*q ) + int1d(Th.up1)*v1 -alpha*convect([up1.k=numu*stress) .up2].cmm=" [u1.pp(21).dd.0001) + on(aa..[v1.01.bb.dd)(u1*v1* 0.bb)(temp*q*0. pp[i]=p(i/20.p*dy(v2) . plot([u1. cut = cut *coefcut. d] where for instance v = sin(π y−c ). one has −∆θ = v 2 IB . LEARNING BY EXAMPLES for (iter=1.ps").hmin=1. where IB is 1 in the object and 0 elsewhere.5.126.09*k*k/ep. } cout << "CPU " <<clock()-s0 << "s " << endl.value=1.iter++) { cout << " dt = " << dt << " -----------------------.err=tol.i<=500.splitpbedge=1. k1=k.fill=true. dt = dt*coefdt.u2]. // solves temperature equation if ( !(i % 5)){ plot(temp.cmm=" [u1.i++) { up1=u1. plot(k.ps="ThNS.dy(u2)]. viscturb. denoted by B.u2]. So the boundary of the domain is made up of a part Γ1 where v = 0 and of another part Γ2 = [c. } cout << "CPU " << clock()-s0 << "s " << endl. temp1=min(temp1.[dx(u1). abserror=0. ep1=ep./1000). We consider a rectangular oven where the wave is emitted by part of the upper wall.35). NS. // Solves Navier-Stokes prode =0. kappa=muT/0.dx(u1).u2] et p ". Th=adaptmesh(Th.ps"). plot(coef=0.dy(u1).126*k*(pow(2*dx(u1). plot(ep.[u1. 3. inquire=0. θΓ = 0 .p.25). c−d Within an object to be cooked.2. plot(Th. stress=abs(dy(u1)). kine. muT=0." << endl. the heat source is proportional to v 2 . for (i=0. amplitude is given by Helmholtz’s equation: βv + ∆v = 0.ratio=1. For a plane monochromatic wave. } if (iter>= nbiter) break.46 CHAPTER 3.eps").09/0.ps="plotNS_"+iter+"_"+i+". alpha=1/dt. temp1=max(temp.wait=1). At equilibrium. TEMPER. prodk= prode*k/ep*0. tol = tol *coeftol.41.wait=1).cutoff=cut.2)+pow(2*dy(u2).iter<=nbiter.2))/2.wait=1).2)+2*pow(dx(u2)+dy(u1).ps="temp_"+iter+"_"+i+". up2=u2.11 An Example with Complex Numbers In a microwave oven heat comes from molecular excitation by an electromagnetic field. wait=1).ps". y= l+g-l*(t-5)/3. . plot(Th.y=g. mesh Th = buildmesh(a0(10*n)+a1(10*n)+a2(10*n)+a3(10*n) +a4(10*n)+a5(10*n)+b0(5*n)+b1(10*n)+b2(5*n)+b3(10*n)).label=1. real meat = Th(a-f-e/2. Results are shown on figure 3.4){x=0.8) {x=a-e-f.01).y=b.P1).} border a4(t=4.label=1.} border a3(t=3. b=20. Vh vr=real(v).10 (muwave.y=b-(b-c)*(t-3). vi=imag(v).uu)= int2d(Th)(dx(u)* dx(uu)+ dy(u)* dy(uu)) . c=15. label=3. fill=true).u=0). fespace Uh(Th.} border a2(t=2.w.edp border b0(t=0.y=c-(c-d)*(t-4). y= d*(6-t). label=3.v=0) + on(2. solve temperature(u.P1).} border b3(t=5.1) {x=a*t. y=g+l*(t-1)/3.} border b1(t=1. Vh R=(region-air)/(meat-air).} border a1(t=1.11.2. fill=true).wait=1.ps="imuonde.int2d(Th)(ff*uu) + on(1.0.w) = int2d(Th)(v*w*(1+R) -(dx(v)*dx(w)+dy(v)*dy(w))*(1-0.label=2. label=3.region. Uh u.g+l/2).10: A microwave oven: real (left) and imaginary (middle) parts of wave and temperature (right). label=3.label=1.2) {x=a. y= b*(t-1).5i)) + on(1. f=2.edp) real a=20. v=sin(pi*(y-c)/(c-d))). l=12. border a0(t=0. air= Th(0.wait=1. y=0. fespace Vh(Th.uu.} int n=2. d=8.5){x=0. y=l+g.10 √ In the program below β = 1/(1 − I/2) in the air and 2/(1 − I/2) in the object (i = −1): Example 3.3. e=2.01. ff=1e5*(vrˆ2 + viˆ2)*R.label=1. g=2.ps". plot(vr. AN EXAMPLE WITH COMPLEX NUMBERS 47 Figure 3.6){ x=0. solve muwave(v.3) { x=a*(3-t).label=1. plot(vi.5) {x=a-f-e*(t-4).region.} border a5(t=5.} // file muwave. Vh<complex> v.4) {x=a-f.1) {x=a-f+e*(t-1).} border b2(t=4.ps="rmuonde. Ie=(((x-1)ˆ2+ yˆ2)<=4). }. mesh th = buildmesh(aa(70)+bb(35)+cc(35)+dd(35)). d) · u) = 0.ps". y = 5*sin(t). z[0]=2. border dd(t=0.u. and so on for Jc and Jd .uh.du. δc = 0. c. u|Γ = uΓ where the desired state ud . }. − (κ · δu) ≈ (δκ · u) δu|Γ = 0 Obviously Jb is equal to δJ when δb = 1. 3.0001). 2*pi) { x = 5*cos(t). δd are variations of b. ud=u. δc. problem A(u. func real J(real[int] & Z) { for (int i=0. 2*pi) { x = -3+cos(t). A.ps="tempmuonde. 2*pi) { x = cos(t).edp border aa(t=0. δd = 0.P1). y = -3+sin(t). To solve this problem by the quasi-Newton BFGS method we need the derivatives of J with respect to b.n. z[1]=3. c.48 CHAPTER 3. } . fespace Vh(th.i++)z[i]=Z[i]. }. 2*pi) { x = cos(t). For example consider the following inverse problem min J = E b.u=xˆ3-yˆ3). border cc(t=0. D are separated subsets of Ω. }. f<<s<<" ". Id=((xˆ2+(y+3)ˆ2)<1. We self explanatory notations. real s= int2d(th)(Ie*(u-ud)ˆ2). ofstream f("J. return s.txt"). Vh Ib=((xˆ2+yˆ2)<1. d we have δJ ≈ 2 E (u − ud )δu. fill=true).i<z.0001).uh) =int2d(th)((1+z[0]*Ib+z[1]*Ic+z[2]*Id)*(dx(u)*dx(uh) +dy(u)*dy(uh))) + on(aa. y = sin(t).wait=1. the boundary data uΓ and the observation set E ⊂ Ω are all given. ud. All this is implemented in the following program // file optimcontrol. z[2]=4. C. Furthermore let us assume that κ(x) = 1 + bIB (x) + cIC (x) + dID (x) ∀x ∈ Ω where B.0001). y = sin(t).c. real[int] z(3).d∈R (u − ud )2 : − (κ(b. if δb. c. Ic=(((x+3)ˆ2+ yˆ2)<1. border bb(t=0. A.12 Optimal Control Thanks to the function BFGS it is possible to solve complex nonlinear optimization problem within FreeFem++. d. LEARNING BY EXAMPLES plot(u. 25 118.i++) { for(int j=0. C.Z. E are circles of boundaries bb.75 81. for(int j=0.j++) Z[j]=1. } real[int] Z(3). plot(ud. dz[i]=1.12.ps="u.eps"). d = 4.n.j<z.j++) cout<<z[j]<<endl.11 shows u at convergence and the successive function evaluations of J.75 -31. func real[int] DJ(real[int] &Z) { for(int i=0.txt" 40 35 30 25 20 15 10 5 0 0 5 10 15 20 25 30 35 Figure 3.25 -93.75 -106. The unknowns are packed into array z. cout << "BFGS: J(z) = " << J(Z) << endl. } return dJdz.nbiter=15.j<z. d = 4. The desired state ud is the solution of the PDE for b = 2. D.value=1.i<z.n.du=0).25 93.00125.j<dz.e-6.uh) =int2d(th)((1+z[0]*Ib+z[1]*Ic+z[2]*Id)*(dx(du)*dx(uh)+dy(du)*dy(uh))) +int2d(th)((dz[0]*Ib+dz[1]*Ic+dz[2]*Id)*(dx(u)*dx(uh)+dy(u)*dy(uh))) +on(aa.25 -18.75 106.75 56. dJdz(3). for(int j=0. p|Γ = 0 δJ = − Ω ( · (κ p))δu . In this example the sets B.75 31. Define p by IsoValue -118. The program found b = 2.00551.j++) dz[j]=0.25 43.nbiterline=20).25 6. dd. BFGS(J. On the right the successive evaluations of J by BFGS (5 values above 500 have been removed for readability) − Consequently · (κ p) = 2IE (u − ud ).3.DJ. Notice that it is necessary to recopy Z into z because one is a local variable while the other one is global.75 -56. c = 3.25 -43. Note that an adjoint state could have been used. B. problem B(du. c = 3. dJdz[i]= 2*int2d(th)(Ie*(u-ud)*du).n.75 -81. Figure 3.25 68.00109.11: On the left the level lines of u.75 -6. cc.n.25 -68. OPTIMAL CONTROL 49 real[int] dz(3).25 18. ee are the domain Ω is the circle of boundary aa.75 45 "J.eps=1. 10) .e. border bbb(t=0.y=1-t.x0-rr){x=t.}.y=t. (3. δc = δd = 0 and so on: Jb = − B p· u.} border aaa2(t=x0+rr.}. int anew=1. border ccc(t=0. 1 (pm+1 − pm ◦ X m ) + · um+1 = 0 (γ − 1)δt¯m p ρm m+1 ¯ ˜ (u − um ◦ X m ) + pm+1 = 0 δt ρm ¯ m+1 m m ρ =ρ ◦X + (pm+1 − pm ◦ X m ) m (γ − 1)¯ p A numerical result is given on Figure 3. Jd = − D p· u Remark As BFGS stores an M × M matrix where M is the number of unknowns.2){x=t.1){x=0. plot(Th. int m=5.}.y=0.12 and the FreeFem++ script is verbosity=1.}.0){ x=x0+rr*cos(t). it is dangerously expensive to use this method when the unknown x is a Finite Element Function.50 = Ω CHAPTER 3.8) Then the derivatives are found by setting δb = 1. else Th = readmesh("Th_circle.5. real x0=0. and finally mesh adaptation . 3. i.y0=0.13 A Flow with Shocks Compressible Euler equations should be discretized with Finite Volumes or FEM with flux up-winding scheme but these are not implemented in FreeFem++ .}. border cercle(t=pi.mesh"). One should use another optimizer such as the NonLinear Conjugate Gradient NLCG (also a key word of FreeFem++). border aaa1(t=0. Nevertheless acceptable results can be obtained with the method of characteristics provided that the mean values ¯ f = 1 (f + + f − ) are used at shocks in the scheme.9) (3. See the file algo. border ddd(t=0. p and then update ρ. LEARNING BY EXAMPLES (κ p · δu) = − Ω (δκ p · u) (3. Jc = − C p· u. rr=0. if(anew) Th = buildmesh (ccc(5*m) +ddd(3*m) + aaa1(2*m) + cercle(5*m) + aaa2(5*m) + bbb(2*m) ).y=0.y=y0+rr*sin(t).edp in the examples folder.1){x=2.2. mesh Th.wait=0). 2 ∂t ρ + u ρ + ρ · u = 0 ¯ ¯ ρu ρ(∂t u + ¯ u+ p=0 ρ ¯ ∂t p + u p + (γ − 1)¯ · u = 0 ¯ p One possibility is to couple u.y=1.2){x=2-t. dt = dt/10. u0=2. Wh u.u1) + vh*convect([u1. r1 = 1.6)(rh*u) // +int1d(Th. fespace Wh(Th. value=1.r1) + uh*convect([u1.u=u0) + on(2.eps". pena=2.-dt.04844 2.vh.k++) { .-dt.gg>>v1[].18966 2.uh. v1= 0.v1].P1). err0=err0/10.75452 51 Figure 3.v1].0714186 0.35385 0.r.r=0) + on(2.v1.(dx(rh)*u + dy(rh)*v)) ) + int2d(Th)(-(rh*convect([u1.x*dx(u)+N.y*dy(u) ) if(anew){ u1= u0.05993 1.90722 2.P1).txt"). fespace Vh(Th. Vh r.10) real dt=0.3. ifstream gg("v.495066 0.vh. ifstream ggg("r.v.777498 0.12: Pressure for a Euler flow around a disk at Mach 2 computed by (3. macro dn(u) (N. A FLOW WITH SHOCKS IsoValue 0.62479 1.txt"). int j=80.v1].rh. } // def the normal derivative problem eul(u.} else { ifstream g("u.v1))/dt) +int1d(Th.wait=1).212634 0.u1. plot(u1.636282 0.v=0).1)(rh*v) + on(2.k<3.20115 1.13.rh) = int2d(Th)( (u*uh+v*vh+r*rh)/dt + ((dx(r)*uh+ dy(r)*vh) . err0=0.g>>u1[].6133 2.v.48358 1.01.-dt.ps="eta.918714 1.33087 2. for(int k=0.00625.34236 1.r1.47209 2.uh.ggg>>r1[].txt").76601 1. ratio=1.mesh"). possibly. nbvx=40000.i++){ eul. splitpbedge=1. here by convention one PDE corresponds to one scalar valued F and ϕ. m (x)) = 0 ∀x ∈ Ω ⊂ Rd . (x). u1=u.rescaling=1) . a time loop. abserror=1. nbsmooth=3.52 CHAPTER 3. ∂x1 ∂xd ∂x1 ∂xd The range of x over which the equation is taken. Yet the approximations and algorithms suited to the problem depend on its type: • Finite Elements compatible (LBB conditions) for elliptic systems • Finite difference on the parabolic variable and a time loop on each elliptic subsystem of parabolic systems. ∂2ϕ The general form of a second order. Characteristics-Galerkin.nbjacoby=2. j=5. then expect difficulties (like shock discontinuities)! Elliptic.ff<<v[].ps="mach.txt"). value=1). plot(r1. savemesh(Th. ofstream fff("r. Unless indicated otherwise. dt = dt/10. } 3.r=r. maxsubdiv=5. here m. ∂ϕ ∂ϕ ∂ 2ϕ ∂ mϕ (x).8. ofstream ff("v. then the PDE is actually a system of PDEs. Finite Volumes for hyperbolic systems plus. · · · ."Th_circle. αϕ + a · ϕ+B : ( ϕ) = f in Ω ⊂ Rd . r1=abs(r). If F is linear with respect to its arguments. omega=1.f<<u[]. When the system changes type.wait=0). If F and ϕ are vector valued functions. ofstream f("u. F (ϕ(x). cout<<"k="<<k<<" E="<<int2d(Th)(uˆ2+vˆ2+r)<<endl. linear scalar PDE is ∂xi ∂xj and A : B means d i. The highest derivation index. LEARNING BY EXAMPLES if(k==20){ err0=err0/10. . is called the order.j=1 aij bij .txt").err=err0. Petrov-Galerkin.eps".} for(int i=0. r1 = sqrt(u*u+v*v). then the PDE is said to be linear. better stability diagrams when the schemes are implicit in time. here Ω. is called the domain of the PDE.fff<<r[]. · · · .14 Classification of the equations Summary It is usually not easy to determine the type of a system. 2 (x). parabolic and hyperbolic equations A partial differential equation (PDE) is a relation between a function of several variables and its derivatives.v=v. plot(Th.r. v1=v. Discontinuous-Galerkin.i<j.wait=0. • Upwinding. } Th = adaptmesh (Th.txt").8. r1=r.value=1). plot(r. u=u. x2 = x and its linearized form is: ∂ 2 u ∂u ∂ 2 ϕ ∂ϕ ∂ 2 u − − = 0. or hyperbolic according to the type of the linearized equation. B(x) ∈ Rd×d are the PDE coefficients. If the coefficients are independent of x. If it is the equation of an ellipse (ellipsoid if d ≥ 2). it is said to be non linear. If µ > 0. ∂t The biharmonic equation is elliptic: ∆(∆ϕ) = f in Ω. ∂t2 ∂x ∂x2 we have d = 2. and hyperboloids have several). ∂ϕ/∂xi by zi and ∂ 2 ϕ/∂xi ∂xj by zi zj . T [⊂ Rd+1 : ∂ϕ − µ∆ϕ = f ∂t ∀x ∈ Ω ⊂ Rd . the PDE is still said to be hyperbolic. T [. the wave equation is hyperbolic: ∂ 2ϕ − µ∆ϕ = f ∂t2 in Q. parabolic. Those are said to be locally elliptic. ∂t2 ∂x ∂x2 ∂x ∂x2 which for the unknown u is locally elliptic if Examples Laplace’s equation is elliptic: ∆ϕ ≡ ∂ 2ϕ ∂ 2ϕ ∂ 2ϕ + 2 + · · · + 2 = f. The convection diffusion equation is parabolic if µ = 0 and hyperbolic otherwise: ∂ϕ + a ϕ − µ∆ϕ = f. and for reasons that will appear more clearly later. the PDE is said to be parabolic or hyperbolic. ∀t ∈]0. α(x) ∈ R. ∂ϕ ∂x < 0 and locally hyperbolic if ∂ϕ ∂x > 0. the PDE is said to have constant coefficients. If the PDE is not linear. the degree is no longer 2 but 1. by replacing ϕ by 1. x1 = t.14. paraboloids have one. . The heat equation is parabolic in Q = Ω×]0. CLASSIFICATION OF THE EQUATIONS 53 where f (x). For example. by studying whether or not the polynomial system P (z) associated with the PDE system has branches at infinity (ellipsoids have no branches at infinity.3. a(x) ∈ Rd . for the non linear equation ∂ 2 ϕ ∂ϕ ∂ 2 ϕ − = 1. the PDE is said to be elliptic. if it is the equation of a parabola or a hyperbola. ∂x2 ∂x2 ∂xd 1 ∀x ∈ Ω ⊂ Rd . To a PDE we associate a quadratic form. These concepts can be generalized to systems. where z is a vector in Rd : α + a · z + z T Bz = f. If A ≡ 0. The whole set of conditions are also called Cauchy conditions. ∀x ∈ Γ. ∂n ϕ·n). The wave equation is well posed with ϕ and ∂ϕ given at t = 0 and Dirichlet or Neumann or mixed conditions on ∂Ω. Finding a set of boundary conditions that defines a unique ϕ is a difficult art. an elliptic equation is well posed (i. In general. For example. called a Robin (or Fourier ) condition is written as: ϕ(x) + β(x) ∂ϕ (x) given on Γ. ∂ϕ given on Γ2 . T [. the heat equation is well posed with ϕ given at t = 0 and Dirichlet or Neumann or mixed conditions on ∂Ω. ∂t . Laplace’s equations is well posed with a Dirichlet or Neumann condition but also with ϕ given on Γ1 . ∂n Γ1 ∪ Γ2 = Γ. ˙ ˙ Γ1 ∩ Γ2 = ∅. For instance. LEARNING BY EXAMPLES Boundary conditions A relation between a function and its derivatives is not sufficient to define the function. Thus. given on Γ for a general second order PDE) ∂n where n is the normal at x ∈ Γ directed towards the exterior of Ω (by definition ∂ϕ = ∂n Another classical condition. ϕ(x) given. Neumann or Robin conditions on the whole boundary. is called a Dirichlet boundary condition. or on part of Γ is necessary. The Neumann condition is ∂ϕ (x) given on Γ (or n · B ϕ. Parabolic and hyperbolic equations rarely require boundary conditions on all of Γ×]0.54 CHAPTER 3. Here t is time so the first condition is called an initial condition. Additional information on the boundary Γ = ∂Ω of Ω. ϕ is unique) with one Dirichlet.e. Such information is called a boundary condition. mesh Th=square(10.i<=20. each statement are separated from the next by a semicolon ‘.’.Chapter 4 Syntax 4. arrays of finite element functions (func[basic type]). Vh u = x+ exp(y). fespace Vh(Th. 55 . vectors . arrays (example: real[int]). } // // unit square mesh P1 lagrange finite element space // // new block // not the same r error because Vh is a global name // end of block // here r back to 0.01 The type declarations are compulsory in FreeFem++ .1 Data Types In essence FreeFem++ is a compiler: its language is typed. except the fespace variable. sparse matrices. in a declarative statement.}.wait=true). because it will be used as an operator in the future.P1). Every variable must be declared of a certain type. // two array of size n for (i=0. strings (string).P1). polymorphic.10). yy[i]= sin(i*pi/10). The variable name is just an alphanumeric string.01. plot(u. with exception and reentrant. analytical functions (func). . 2D finite element spaces (fespace) . etc. } The life of a variable is the current block {.1 real r= 0. linear and bilinear operators. Example 4. { real r = 2.i++) // which can be used in statements such as { xx[i]= cos(i*pi/10). fespace Vh(Th. reals (real). bidimensional (2D) finite element meshes (mesh).yy(n). in the end this feature is an asset because it is easy to make bugs in a language with many implicit types. For instance int i. The language allows the manipulation of basic types integers (int). .n=20. n are integer. and the variables local to a block are destroyed at the end of the block as follows. // i. real[int] xx(n). the underscore character “ ” is not allowed. func f = z * x + r * log(y). such as: "This is a string in double quotes. The result of a comparison is a boolean type as in bool fool=(1<2).-2) (-3.230769. Similar examples can be built with ==. >. complex Complex numbers. endl. a[1] = 2.153846) ofstream to declare an output file . . string declare the variable to store a text enclosed within double quotes. a[3] = 4. endl. a[0] = 1. cout << "a = " << a << endl. int declares an integer. <=. string[string ] declares a variable that store multiple strings with string index. This produces the output. b = b = b = b = b " " " " = 2 + 3i. ifstream to declare an input file . << a + b << << a + b << << a * b << << a / b << √ −1. endl. Here’s the output. which makes fool to be true.33333 4 5 real[string ] declares a variable that store multiple real numbers with string index.0. a[4] = 5. a a a a + * / b b b b = = = = (2. real[int] a(5). such as 1 + 2i.2) (0. a = 5 1 : 2 3.56 CHAPTER 4.3333333. SYNTAX 4.2 List of major types bool is used for logical expression and flow-control. endl. ! =. FreeFem++ understand that i = complex cout << cout << cout << cout << a = "a + "a "a * "a / 1i. real[int ] declares a variable that stores multiple real numbers with integer index. >=.4) (-2." real declares the variable to store a number such as “12. <. a[2] = 3.345”. y components of P . mesh creates the triangulation. Raising functions to a numerical power is done.P.region. solve declares a problem and solves it. see Section 5. 0 otherwise (int value).y) (int value).23. By P.x and N. GLOBAL VARIABLES 57 func defines a function without argument..N. N. are reserved words used to link the language to the finite element tools: x is the x coordinate of the current point (real value) y is the y coordinate of the current point (real value) z is the z coordinate of the current point (real value) label contains the label number of a boundary if the current point is on a boundary.z is reserved and can be used in 3D. N. For example func f=cos(x)+sin(y) .y. Also P. ).y. we can get the x. y. yˆ0. for instance.z is reserved.. matrix defines a sparse matrix.nu_triangle. Remark that the function’s type is given by the expression’s type. region returns the region number of the current point (x. 4. varf defines a full variational form. N gives the outward unit normal vector at the current point if it is on a curve defined by border (R3 value).4. by xˆ1. see Section Section 6. . lenEdge gives the length of the current edge lenEdge = |q i − q j | if the current edge is [q i . fespace defines a new type of finite element space.label. P gives the current point (R2 value. . problem declares the weak form of a partial differential problem without solving it.x.z. if independent variables are x.3. q j ] hTriangle gives the size of the current triangle nuTriangle gives the index of the current triangle (int value).3 Global Variables The names x.y are x and y components of the normal vector. P. volume give the volume of the current tetrahedra (real value). To execute a system command in the string (not implemented on Carbon MacOS). // after version 3.12-1 This is useful to launch another executable from within FreeFem++ . ostream cin is the standard input device (default is keyboard). true means “true” in bool value. exec("shell command"). nTonEdge gives the number of adjacent triangle of the current edge (integer ).exe").40). . and all the operator and functions of a FreeFem++ program: dumptable(cout). the standard output is only the console. pi is the realvalue approximation value of π. endl adds an ”end of line” to the input/output flow. On MS-Windows. system("shell command"). area give the area of the current triangle (real value). SYNTAX nuEdge gives the index of the current edge in the triangle (int value). the full path of the executable. then we must write exec("c:\\cygwin\\bin\\ls. at this time. assert(version>=1. On MS-Windows. (istreamvalue).58 CHAPTER 4. false means “false” in bool value. if there is the command “ls. Another useful system command is assert() to make sure something is true. cout is the standard output device (default is console).exe” in the subdirectory “c:\cygwin\bin\”. 4. For example. which return the value of the system call.4 System Commands Here is how to show all the types. cout <<"max and min of "<<a<<" and "<<b<<" is "<<max(a. cout << " min == (a < b ? a : b ) is " << (a < b ? a : b) << endl. The power ab of two integers a. cout <<"the minus of "<<a<<" is "<< -a << endl.5 Arithmetics On integers . minus of "<<a<<" and "<<pi<<" are "<< a+b <<". minus of "<<a<<" and "<<b<<" are "<<a+b<<". cout <<a<<"%0"<<" is "<< a%b << endl. quotient of them are 60. quotient of them are "<<a*b<<". b=0. <<"plus. cout <<"multiplication. ∗ are the usual arithmetic summation (plus). cout <<a<<" plus -"<<b<<" need bracket:"<<a<<"+(-"<<b<<")="<<a+(-b)<<endl.The operators / and % yield the quotient and the remainder from the division of the first expression by the second. <<"the minus of "<<a<<" is "<< -a << endl. However. b is calculated by writing aˆb. "<<a/b<< endl. ARITHMETICS 59 4. cout <<a<<"/0"<<" is "<< a/b << endl. The following are examples similar to Example 4. b are obtained by max(a. /. +. cout <<"plus. ˆ” are extended to real numbers or variables. −."<<min(a. 2 remainder from division of 12 by 5 is 2 the minus of 12 is -12 12 plus -5 need bracket :12+(-5)=7 max and min of 12 and 5 is 12. −. <<"remainder from division of "<<a<<" by "<<b<<" is "<< a%b << endl. 7 multiplication. Example 4. subtraction (minus) and multiplication (times).b)<<". ∗. % calculates the remainder of the integer parts of two real numbers.2 Computations with the integers int a = 12. The maximum or minimum of two integers a. "<<a-b<<endl.5. . "<< a-b << endl. <<"multiplication. "<<a/b<<endl. %” and “ max. <<a<<" plus -"<<b<<" need bracket :"<<a<<"+(-"<<b<<")="<<a + (-b) << endl.).b)<< endl. The classical C++ ”arithmetical if” expression a ? b : c is equal to the value of expression b if the value of expression a is true otherwise is equal to value of expression c. quotient of them are "<<a*b<<". min. the operators “+. If the second number of / or % is zero the behavior is undefined.b).5 5th power of 12 is 248832 min == (a < b ? a : b) is 5 12/0 : long long long Fatal error : ExecError Div by 0 at exec line Exec error : exit 9 By the relation integer ⊂ real.4. b = 5. respectively. cout <<b<<"th power of "<<a<<" is "<<aˆb<< endl.2 real cout cout cout cout cout a=sqrt(2.b) or min(a. produce the following result: plus. cout <<"remainder from division of "<<a<<" by "<<b<<" is "<<a%b<<endl. b = pi. minus of 12 and 5 are 17. 41421 plus -3. b) has a representation with √ polar coordinate (r. ∗. 0. i= −1. /” and “ ˆ” are also applicable on complex-typed variables. SYNTAX plus.72738 By the relation bool ⊂ int ⊂ real ⊂ complex.41421 is -1. The imaginary and real parts of a complex number z can be obtained with imag and real. φ). " <<imag(z1)<<endl. cout <<"Plus. z2 = a+sqrt(2.14159)=-1. and de Moivre’s formula z n = rn (cos nφ + i sin nφ).72738 multiplication. z2=a+sqrt(2. "<< pc(z1-z2) << endl. Complex numbers such as 5+9i.3 real a=2.)*1i.60 It gives the following output: CHAPTER 4. So z his also z = r(cos φ + i sin φ). " <<pc(z1/z2)<< endl. cout <<pc(z2)<<" = "<<toPolar(z2)<<endl.44288. b=5. cout <<"Absolute of "<<pc(z1)<<" is "<<abs(z1)<<endl.41421 and 3. r is called the modulus and φ the argument of z. In the following example. cout <<"Multiplication. -1.41421 1. Example 4. The conjugate of a + bi (a. We can attach to it the point (a. The same point (a. which can also be computed with the operator ”conj”.14159 are 4. complex z1=a+b*1i. b) in the Cartesian plane where the x-axis is for the real part and the y-axis for the imaginary part.complex numbers like a + i b and a + i 2.450158 remainder from division of 1.0)*1i.14159 is 1 the minus of 1. } cout <<"Standard output of the complex "<<pc(z1)<<" is the pair " <<z1<<endl. but “%. b=5. b. √ With real variables a=2.14159 need bracket :1. by conj(a+b*1i) in FreeFem++ . return r+imag(z)+"i)". quotient of them are "<<pc(z1*z2)<<". we shall show them using FreeFem++ programming. Internally the complex number z = a + ib is considered as the pair (a. func string pc(complex z) // printout complex to (real)+i(imaginary) { string r = "("+real(z). √ max. are valid expressions.45. min” cannot be used.33. quotient of them are 4. minus of "<<pc(z1)<<" and "<<pc(z2)<<" are "<< pc(z1+z2) <<".0 must be declared by complex z1 = a+b*1i.41421 by 3.33.41421+(-3. minus of 1. b are reals) is defined by a − bi. if (imag(z)>=0) r = r+"+". −. the operators “+. cout <<"Real/imaginary part of "<<pc(z1)<<" is "<<real(z1)<<". b) of real numbers a. } // printout complex to |z|*(cos(arg(z))+i*sin(arg(z))) func string toPolar(complex z) { return abs(z)+"*(cos("+arg(z)+")+i*sin("+arg(z)+"))".55581.45."<<arg(z2)<<") = " . cout <<" and polar("<<abs(z2)<<". r = a2 + b2 and φ = tan−1 (b/a). rfind("abc") << endl. STRING EXPRESSION << pc(polar(abs(z2). ifstream toto("xyf").5233i). cout << " t55 " << t55 << endl. cout <<"de Moivre’s formula: "<<pc(z2)<<"ˆ3 = "<<toPolar(z2ˆ3)<<endl.45+5.41421i)ˆ3 = 22. } } // string concatenation // new operator . cout << i << " : " << s << endl.37072-12.41421i) are (4.find("abc".45+1.33 Absolute of (2.41421i) is (2.33) Plus. (0+3.33i)ˆ(2. (1. cout << " find abc from 10 " << t2.77".33i) is 5.45+1.638*(cos(1.523509)) and polar(2.45+1.find("abc") << endl.45+5.53526+16. quotient of them are (-1.523509)+i*sin(0.5.45+1. cout << " " << string("abcc").10) << endl. for (int i=0. cout <<"conjugate of "<<pc(z2)<<" is "<<pc(conj(z2))<<endl.0-6 jan 2009 FH string s.length << endl.41421i) (2.82887*(cos(0. cout << "r find abc " << t2.41421i) = 2.41421i) de Moivre’s formula: (2.45-1. cout << " ffind abc from 10 " <<t2.86612 (2.523509) = (2.33i) is 2. cout << " find abc " << t2.33i) and (2.57053)) conjugate of (2.692+1. minus of (2.33i) is the pair (2.45+5.0.++i) { getline(toto.45. 61 Here’s the output from Example 4.45+5.45+1. cout <<pc(z1)<<"ˆ"<<pc(z2)<<" is "<< pc(z1ˆz2) << endl.45. 5.10) << endl. string t2. // t2 = "12340abcdefghijk-005678".57053)+i*sin(1. { // add getline version 3.3 Standard output of the complex (2.74421i).s). string t1="0123456789".41421i) is (8.45+5.i<10. cout << t2 << endl. t2 ="12340005678".9+6. t2(4:3) = "abcdefghijk-".45+1.6.82887.4. string t55=t2(4:3).91579i) Multiplication.rfind("abc".arg(z2)))<<endl.7078i) 4.19883i) Real/imaginary part of (2.6 string expression In the following example you some example string expression string tt="toto1"+1+" -. Cardioid real b = 1. } mesh Th = buildmesh(C(50)).. the hyperbolic functions. asinh(x). Example 4. The real function which rounds a real to an integer floor(x) rounds to largest integral value not greater than x. the indefinite integral of an elementary function cannot always be expressed in terms of elementary functions. and tanh x = sinh x/ cosh x called by sinh(x). acos(x)(=arccos x). logarithmic. exponential.y)= xy . the exponent function exp(x) (= ex ). In FreeFem++ . tan(x) assume angles measured in radians. however. The derivative of an elementary function is also an elementary function. SYNTAX 4. cosh(x). cosh−1 x = ln x + x2 − 1 . } func real phiy(real t) { return (a+b)*sin(t)-b*sin(t*(a+b)/b)... the trigonometric functions sin(x). tan x (called circular function or inverse trigonometric function ) asin(x)(=arcsin x). f (x)g(x). each applied a finite number of times.62 CHAPTER 4. the logarithmic function log(x)(= ln x) or log10(x) (= log10 x).4 The following is an example where an elementary function is used to build the border of a domain. cos(x). sinh x = ex − e−x /2. real a = b. all elementary functions can thus be created. . the atan2(x. } border C(t=0.y) function computes the principal value of the arc tangent of y/x. y=phiy(t). func real phix(real t) { return (a+b)*cos(t)-b*cos(t*(a+b)/b). trigonometric. √ √ sinh−1 x = ln x + x2 + 1 . acosh(x) and atanh(x). circular) and the functions obtained from those by the four arithmetic operations f (x) + g(x). the inverse of sin x. Elementary Functions denotes for us the class of functions presented above (polynomials.2*pi) { x=phix(t). cosh x = ex + e−x /2. cos x. f (x) − g(x). ceil(x) round to smallest integral value not less than x. tanh(x). using the signs of both arguments to determine the quadrant of the return value. similarly rint(x) returns the integral value nearest to x (according to the prevailing rounding mode) in floating-point format).7 Functions of one Variable Fundamental functions are built into FreeFem++ as well as The power function xˆ y = pow(x. f (x)/g(x) and by composition f (g(x)). atan(x)(=arctan x) are also implemented. y1(x). • randreal1() generates uniform real in [0.e.x) are the Bessel functions of first and second kind. • randreal2() generates uniform real in [0. 0.1752i.4483310−17 + 1. • randreal3() generates uniform real in (0.77679 − 2. erfc(x) = 1 − erf(x). j1(x). The erfc(x) = function calculates the complementary error function of x. • the function tgamma(x) calculates the Γ function of x. 1] (32-bit resolution). .0572i.html for full detail). • The erf(x) function calculates the error function. 1) (32-bit resolution). 63 Using FreeFem++ . we can define log z for z = 0 by ln z = ln |z| + i arg z. respectively.10715i. Random Functions can be define as FreeFem++ has a Mersenne Twister function (see page http://www.7.4. cos(pi/2-1i) and log(1+2i). the function jn(n.math.17). and the functions which calls it are: • randint32() generates unsigned 32-bit integers. x) computes the Bessel function of the second kind for the integer order n for the positive integer value x (expressed as a real).jp/˜m-mat/MT/emt. • randinit(seed ) initializes the state vector by using one 32-bit integer ”seed”. 1) (32-bit resolution). i.1752i. 9. sin(pi+1i). x) computes the Bessel function of the first kind of the integer order n. for the positive integer value x (expressed as a real). • randint31() generates unsigned 31-bit integers. FUNCTIONS OF ONE VARIABLE Taking the principal value. where erf(x) = √2 (pi) x 0 exp(−t2 )dt.x). jn(n. y0(x). • randres53() generates uniform real in [0.hiroshima-u. The functions y0(x) and y1(x) compute the linearly independent Bessel function of the second kind of the order 0 and the order 1. It is a very fast and accurate random number generator Of period 2219937 −1. respectively. Library Functions form the mathematical library (version 2. we calculated exp(1+4i).8896710−16 − 1. which may be zero.804719 + 1. the function yn(n. we then have −1.ac. The functions j0(x) and j1(x) compute the Bessel function of the first kind of the order 0 and the order 1.sci. 1) with 53-bit resolution. yn(n. lgamma(x) calculates the natural logorithm of the absolute value of the Γ function of x. 1. • the functions j0(x). -pi+2*pi*y]).5.0. Vh fh = f. 2[2 fespace Vh(Th. func g=abs( sin(z/10)*exp(zˆ2/10) ). we can write an elementary function as follows func f = sin(x)*cos(y).23. for example func f=cos(x)+sin(y) . leading to an interpolation error. func g = (xˆ2+3*yˆ2)*exp(1-xˆ2-yˆ2). y and z are reserved word as explained in in Section 4. Vh<complex> zh = zf. // zh is the projection of zf // to complex value Vh space The construction of fh (=fh ) is explained in Section 6. mesh Th = square(20. plot(fh). // ] − π. fespace Vh(Th.[-2+2*x. π[2 // // // // z = x + iy √ z // f= g = | sin z/10 exp z 2 /10| contour lines of f contour lines of g We call also construct elementary functions of two variables from elementary functions f (x) or g(y) by the four arithmetic operations plus composition applied a finite number of times.[-pi+2*pi*x.20. func h = max(-0.P1). So when the two variables of the function are x and y. x. an interpolation is used. 4. In func. Complex valued function create functions with 2 variables x. Vh gh = g. y as follows.1*log(fˆ2+gˆ2)). mesh Th=square(20. func f=imag(sqrt(z)).P2). If the value of a FE-function is requested at a point which is not a degree of freedom. The power operator can be used in functions such as xˆ1. By opposition elementary functions are evaluated only when needed. SYNTAX 4. we may define the function without its argument. .8 4. // fh is the projection of f to Vh (real value) func zf=(xˆ2*(1+y)ˆ3+yˆ2)*exp(x+1i*y). an elementary function can be evaluated at any point exactly. plot(gh). func f=xˆ2*(1+y)ˆ3+yˆ2. while by contrast.1 Functions of two Variables Formula The general form of real functions of two independent variables a. Remark that the function type is given by the expression type. b).64 CHAPTER 4. // square ] − 2. Hence FE-functions are not defined only by their formula but also by the mesh and the finite element which enter in their definitions.2 FE-functions Finite element functions are also constructed like elementary functions by an arithmetic formula involving elementary functions. Vh fh=f. b is usually written as c = f (a. In FreeFem++ . yˆ0.3.8. func z=x+y*1i. The difference is that they are evaluated at declaration time and FreeFem++ stores the array of its values at the places associated with he degree of freedom of the finite element type.20.-2+2*y]).8. sum << endl. For instance real [int] tab(10). mesh Th=square(20. // set all the array to 1.9.1 The command plot applies only for real or complex FE-functions (2d or 3d) and not to elementary functions. func g=abs( sin(z/10)*exp(zˆ2/10) ). y as follows.14.min << " max:" << tab. // set unset value cout <<" resize tab: " << tab << endl. . π[2 // // // Fig. cout << tab[1] << " " << tab[9] << " size of tab = " << tab. the size of the array must be known at execution time. // z = x + iy √ // f= z g = | sin z/10 exp z 2 /10| 4.-pi+2*pi*y]). func z=x+y*1i.1: √ z has branch Figure 4. arrays with with integer indices and the second type is arrays with string indices. Vh gh = g.20.[-pi+2*pi*x.15.2 isovalue of g Figure 4. func f=imag(sqrt(z)).n << " min: " << tab. plot(gh). and there are 2 kinds of arrays: The first is similar to vector. tt["+"]=1.1 isovalue of f 4.2: | sin(z/10) exp(z 2 /10)| 4. In the first case.e. i. // 2 array of 10 real real [int] tab2. tab1(10). // bug array with no size tab = 1. Complex valued functions create functions with 2 variables x. // ] − π. real [string] tt. plot(fh).P2). ARRAYS 65 Note 4.9 Arrays An array stores multiple objects. fespace Vh(Th.03. // tab.resize(12).max << " sum : " << tab. Fig.03 tab[1]=2. Vh fh = f.4.5. and implementation is done with the KN<> class and all the vector operator of KN<> are implemented. // change the size of array tab // to 12 with preserving first value tab(10:11)=3. 6.b(5).8.14 d 5 -5 -4 -3 -2 -1 ii = 5 4 3 max:2. and scilab // 2.03 1. cout << " t1(2:3:10)= " << t1 << endl.23-1) tab. d.03 1.03 1. complex arrays with.03 size of tab = 10 min: 1. a[2]=0.re) to generate the real and imaginary real array from the complex array (without copy) : // // { int[int] tt(2:10).23-1) d = ( a ? b : 0 ). . n-1 : d[i] = a[i] ? b[i] : c[i] .14 3. // for i = 0.15 sum : 11.03 1. in the third case.. (v2. // sort array d and ii in parallel cout << " d " << d << "\n ii = " << ii << endl.03 1. cout << " tt(2:10)= " << tt << endl.03 1..5. tt=1:2:5. cout << " d = ( a ? b : c ) is " << d << endl. (v2. d = ( a ? 1 : c ). // sort the array tab (version 2.03 3. n-1: d[i] = a[i] ? b[i] : 0 .03 3 2 1 0 Arrays can be set like in matlab or scilab with the operator ::.2) d=-1:-5. int[int] t1(2:3:10).in. -5 (v3.03 1. // for i = 0.42 1.66 CHAPTER 4. int[int] ii(0:d. // for i = 0. a = 1.2) sort(d. n-1: d[i] = a[i] ? 1 : c[i] . .03 resize tab: 12 1. real[int] a(5).14 3.:2:5 => " << tt << endl. (v2.03 1.9.3.. // for i = 0. two operators (.15 3.15 1. cout << " 1. . . // set array ii to 0. c = 3.4.8.03 2.10 // 2. the array generator of a:c is equivalent to a:1:c.03 1. and the array set by a:b:c is set to size |(b − a)/c| + 1 and the value i is set by a + i(b − a)/c.03 2.7.n-1).14 0 1.23-1) d = ( a ? 1 : 0 ).ii).1.. SYNTAX cout<<tt["a"]<<" "<<tt["+"]<<endl.2 mai 2009 like matlab.03 1. b = 2.5.real. // set d to -1. } version 3.n-1 (v3.sort .03 1.-2.d(5). There are int.03 1. d = ( a ? b : c ). n-1: d[i] = a[i] ? 0 : 1 .18) cout << " tab (after sort) " << tab << endl.c(5).15 1.5 d = ( a ? b : c ) is 5 3 3 2 3 tab (after sort) 12 1.03 1. produces the output 2.03 1. +0i:10.= 3 (2.re real part array " << tt.3.6.+0i:10.9.5.4.). // 2.10 complex[int] t1(2.5:3.0) (9.5:3.999 => 6 1 1. cout << " tt.:10.:10.0) (3.:3:10.0) (8.9.4. cout << " t1(2.)= " << t1 << endl.0) (4.0) (5. cout << " tt(2.:3.:3:10. cout << " 1.999.999 => " << tt << endl.re real part array 2 3 4 5 6 7 8 9 10 tt.:3.5 3 3.9.+0i)= " << tt << endl.im imag part array " << tt.8.:3.5.:10.re << endl .3.im imag part array 0 0 0 0 0 0 0 0 0 2 9 9 the all integer array operators are : { . } { complex[int] tt(2.+0i). ARRAYS 67 { real[int] tt(2:10). // the real part array of the complex array cout << " tt.+0i)= 9 (2.+0i:10.0) (6.5 2 2.0) tt.)= 3 2 5 8 1. // the imag part array of the complex array } The output is : tt(2:10)= 9 2 3 4 5 6 7 8 9 10 t1(2:3:10)= 3 2 5 8 1.5:3. // 2.10 real[int] t1(2.5.8.5.7.4.6.8.:0. tt=1.).7.:0.8. // 2.:0.0) (8. cout << " t1(2:3:10)= " << t1 << endl.im << endl .0) (5.0) t1(2. cout << " tt(2:10)= " << tt << endl. // 2.5 tt(2.).0) (7.0) (10.:2:5 => 3 1 3 5 tt(2:10) = = 9 2 3 4 5 6 7 8 9 10 t1(2. c = a+4*b.min << endl. b *= a. */ // ||a||_1 = " << a. a =1. cout << " c =a+4b : c= " << c << endl. c = -a+4*b. cout <<" b /= 2 : " << b << endl. ||a||_2 = " << a. cout << " c =2*a+4b : c= " << c << endl.*b =a.* a same b = b .* b. b =" << b << endl.the methods -// // // // // // // // cout cout cout cout cout cout cout cout } << << << << << << << << " " " " " " " " produce the output . : c= " << c << endl. ||a||_infty = " << a. /* this operator do not exist c = b/2 . a quantile 0. cout << " c c = b*2 .linfty << endl.quantile(0. cout <<" b += a : " << b << endl. : c= " << c << endl./ b. ---. cout << " c =-a+4b : c= " << c << endl. a(0:4:2) = 2.l2 << endl./ a =a. b /= a. cout << " c =-a-b : c= " << c << endl. b += 2*a. cout << " c CHAPTER 4.max << endl. c = 2*a+4*b. a’*a = " << (a’*a) << endl. c = a+b.2 = " << a. b /= 2. : c= " << c << endl. cout << " c c = 2 * b. b += a. cout << " c c = a .l1 << endl. real[int] a(N). cout << " c =b/2 : c= " << c << endl./b =2*b =b*2 : c= " << c << endl. b =" << b << endl. b = a+ a. max a_i = " << a. cout << "b/=a. sum a_i = " << a. cout <<" a = " << a << endl. SYNTAX // // same b = b . cout << " c =-a-4b : c= " << c << endl. min a_i = " << a. cout <<" b += 2*a : " << b << endl.68 int N=5. a(3:4) = 4. c = -a-b. c = -a-4*b. cout << " c =a+b : c=" << c << endl.sum << endl.c(N).b(N). cout <<" b = a+a : " << b << endl.2) << endl. c = a . cout << "b*=a. 4 0. b =5 10 b/=a.4 0.4 c =2*b 5 10 20 20 c =b*2 5 10 20 20 . b =5 5 c =a+b : c=5 7 2.5 c =a.5 10 40 40 3.5 5 10 10 2.4.5 7 14 14 c =2*a+4b : c= 5 24 12 c =a+4b : c= 5 22 c =-a+4b : c= 5 18 24 48 48 11 22 44 44 9 18 36 36 c =-a-4b : c= 5 -22 -11 c =-a-b : c= 5 -7 -3.5 : c= 5 0.4 0./b 0.*b : c= 5 10 2.9.5 5 10 10 3 1 3 2 2 2 3 4 3 3 4 3 2 4 8 8 3 6 12 12 5 10 20 20 2.4 : c= 5 10 : c= 5 10 -22 -44 -44 -7 -14 -14 10 40 40 c =a. ARRAYS 69 5 3 == 3 a = 5 2 b = a+a : 5 4 b += a : 5 6 b += 2*a : 5 10 b /= 2 : 5 5 b*=a. 30i.6.M). Example of array with renumbering (version 2.403124237 ||a||_infty = 4 sum a_i = 13 max a_i = 4 min a_i = 1 a’*a = 41 a quantile 0. c=[4. real[int] b(N). complex[int. c(I)= a.quantile(q) computes v from an array a of size n for a given number q ∈]0.1 Arrays with two integer indices versus matrices Some example are given below to transform full matrices into sparse matrices. real[int.3].i<I. The renumbering is always given by an integer array. This statisticial function a.40i].cc=[10i. .4.int] C(N.2.-1. and if a value in the array is negative. 1[ such that #{i/a[i] < v} ∼ q ∗ n .3 or better) . the mapping is not imaged. The output is b = a(I) : 5 2 c(I) = a 5 4 4 4 -3 2 -3 2 1 2 4. b= a(I).2 = 2 CHAPTER 4.n.9.2 Quantiles are points taken at regular intervals from the cumulative distribution function of a random variable. b=[1.n.20i.M=4. // for( i=0. int[int] I=[2.i++) if(I[i] >=0) b[i]=a[I[i]]. int N=3. it is equivalent to v = a[q ∗ n] when the array a is sorted.3.int] A(N.M). Here the array values are random. SYNTAX Note 4.c(M).i<b.5.3]. // the integer mapping to set the renumbering b=c=-3. so the value is not set.7]. // for( i=0.0].70 ||a||_1 = 13 ||a||_2 = 6. cout << " b = a(I) : " << b << "\n c(I) = a " << c << endl.2. complex[int] cb=[1.i++) if(I[i] >=0) C(I[i])=a[i]. J).j) = b(i)*c(j) product B(i. int [int] I=[2. C -= 5i*cb*cc’. C += 3*cb*cc’.J(j)) B(I(i).0.9.-160) (-300. // matrix B.j) // outer product A = 2. B=A(Iˆ-1.1].2. ARRAYS 71 b=[1. A=1.3].J). int [int] J=[2.Jˆ-1). B = b*c’.-480) A = 3 4 8 16 24 10 20 30 12 24 36 14 28 42 5 3 5 2 3 2 1 1 4 4 4 -3 2 -3 2 1 2 . the output is b = a(I) : 5 2 c(I) = a 5 4 A = 3 4 1 3 4 C = 3 4 (-50.*b*c’)(Iˆ-1. cout << " A = " << A << endl.2) = 2.-120) (-200.-360) (-600.-40) (-100.-240) (-400.0:2) = 3.-120) (-300. // C = cb*cc’.3]. B = A.Jˆ-1). outer product set the all matrix // the full line 2 // the full column 1 // set the column 2 set the line 1 from 0 to 2 // // this transforms an array into a sparse matrix // // B(i. B = b*c’.j)= A(I(i). A(2.1. // B = (3.*b*c’.4. A(1.-240) (-450.0.j) = b(i)*c(j) outer product B(i.-160) (-100. A(:. B = (2*b*c’)(I.J(j))= A(i.1) = 5. A(0:N-1. B=A(I.-80) (-150.-320) (-150. cout << " C = " << C << endl.Jˆ-1) = // // outer outer " << B outer product B(i.*b*c’)(Iˆ-1. cout << " A = " << A << endl. // cout << "B = (3.-80) (-200.:) = 4.J(j)) = b(i)*c(j) << endl.j) = b(I(i))*c(J(j)) product B(I(i). C be respectively two int[int] arrays and a real[int] array.usd[1][]. // to dispatch // the solution on each part.2 Matrix construction and setting • To change the linear system solver associated to a matrix do set(M. ]. [usd[0][]. let I.0 . 0. // to now to pack the right hand side real[int] bb =[rhssd[0][]. set(M.Csd[2] 0 .Csd[1]’. 0. 0. rhssd[1][]. The three arrays define the matrix as follows A= k C[k]MI[k]. ] where Asd and Csd are arrays of matrices (from example mortar-DN-4.72 CHAPTER 4. • To set from a block matrix matrix M=[ [ [ [ [ [ ].0 .Asd[1] . SYNTAX 4.solver=sparsesolver).0 . 0.0 . • To set or get all the indices and coefficients of the sparse matrix A.0 . ]. and A=[I.Csd[0] 0 . 4.Csd[2]’.0 . matrix DD=vDD(Lh. Asd[0] . xx = Mˆ-1 * bb.rhssd[3][].Asd[2] . 3].usd[3][].lh[]] = xx. One can write [I. • To set from a constant matrix matrix A = [[ [ [ [ 0.12 page 162 for details) varf vDD(u.Csd[3] Csd[0]’.J[k] where Mab = (δia δjb )ij one has: Mab a basic matrix with the only non zero term mab = 1.v) = int2d(Thm)(u*v*1e-10).C]=A . The default solver is GMRES.Csd[1] 0 . 0. 2.rhsl[] ].rhssd[2][]. Note .DD ]. to get all the term of the matrix A (the arrays are automatically resized). to change all the term matrices. 0]]. 0.9.C] .usd[2][].0 .0 .solver=sparsesolver). 0].0 . 0.J.Csd[3]’. • from a variational form: (see section 6.Asd[3] .J.0 .Lh). 1.edp of examples++-tuturial).J. ]. 10]. 1).J(15). ARRAYS 73 that the size of the matrix is with n= I. • matrix renumbering int[int] I(15). B=A(Iˆ-1. fespace Vh(Th.J is forgotten to build a diagonal matrix.v) = .resize(10.gg. m of the matrix. in complex case you get the Hermitian product.u=1). so mathematically we have a’*b= aT b .Jˆ-1). f = x*y.v) = int2d(Th)(1*dx(u)*dx(v)+2*dx(u)*dy(v)+3*dy(u)*dx(v)+4*dy(u)*dy(v)) + on(1. terms two array for renumbering // the aim is to transform a matrix into a sparse matrix // copie matrix A // B(i. the matrix in real cases and Hermitian transpose in complex cases. so it is the dot product (example real DotProduct=a’*b) .max.9. Remark that I. g = sin(pi*x). varf mati(u.* is the term to term multiply operator.5 mesh Th = square(2.2.P1). B=A(I.J).9. 4.g.3. and similarly for the n. // a complex valued finite element function ff= x*(y+1i).j) = A(I(i).J(j))= A(i.3 Matrix Operations The multiplicative operators *. Vh f./ is the term to term divide operator. and % group left to right. B. varf mat(u. there are some compound operators also: • ˆ-1 is for solving the linear system (example: b = Aˆ-1 x) • ’ * is the compound of transposition and matrix product.max and m=J. // matrix B. • . B = A.J(j)) // B(I(i). • . gg = exp(pi*x*1i). Vh<complex> ff. /.4.4.j) resize the sparse matrix and remove out of bound // // where A is a given matrix.20). • ’ is the (unary) right transposition for arrays. • a*b’ is the outer product (example matrix B=a’*b ) Example 4. m0[] = A*f[]. cout << "m1 = "<< m1[] << endl. cout << " J= " << J << endl.74 CHAPTER 4.3.4. The resizing of a sparse matrix A is also allowed: A. cout << "f = " << f[] << endl. cout << "hermitien outer Product = "<< (AA=ff[]*gg[]’) << endl. cout << "hermitien Product = "<< ff[]’*gg[] << endl.u=1). diagofA = A.diag = diagofA . m1[] = f[].*g[]. m2[] = f[]. sparse matrix Vh m0.n).100). cout << "outer Product = "<< (A=ff[]*gg[]’) << endl. // // set a new matrix set a diagonal matrix D from the array diagofA.diag. A=[I.C]=A.J(1). cout << "dot Product = "<< f[]’*g[] << endl. SYNTAX int2d(Th)(1*dx(u)*dx(v)+2i*dx(u)*dy(v)+3*dy(u)*dx(v)+4*dy(u)*dy(v)) + on(1.2. Note that the new size can be greater or smaller than the previous size.C]. all new term are set to zero. real[int] C(1). // // // a complex get the diagonal of the matrix set the diagonal of the matrix // version 2. m01[] = A’*f[]. cout << "g = " << g[] << endl.resize(10. Vh m1. cout << "m01 = " << m01[] << endl. resized) // get of the sparse term of the matrix A (the array are cout << " I= " << I << endl. Vh m2. matrix<complex> AA = mati(Vh.Vh). cout << "m0 = " << m0[] << endl. . [I. A. cout << "A = " << A << endl. cout << "m2 = "<< m2[] << endl.J. Vh m01./g[]. matrix D=[diagofA] . real[int] diagofA(A.Vh). cout << " D = " << D << endl. matrix A = mat(Vh. cout << " C= " << C << endl.17 or better --- int[int] I(1).J. 5 0.5 1e+30 1e+30 0. 0.5 0. A =   0.5   0. but in FreeFem++ in index as in C begin at zero).4.5   0.0000000000000000199e+30 5 5 1.2 × 10−16 (= {v}T {w} = {v} · {w}) T T T (= A{v}) (= AT {v}) ··· vM wM )T = (v1 /w1 · · · vM /wM )T = (v1 w1 T −NaN 0 0 −NaN 0. 0.5 0.5 1e+30 0.  0.5 8.5 0. 0..25 −2.5 -2. C array: I= 18 0 1 3 5 J= 18 0 4 3 1 C= 18 1e+30 0. −2. .5 0. D = # Sparce Matrix (Morse) # first line: n m (is symmetic) nbcoef # after for each nonzero coefficient: i j a_ij where (i. ARRAYS On the triangulation of Figure 2..25 0.25 −2.9.5 1030 0 0 0 0 0.   1030 0.5 0.5 1e+30 -2. {v} = f[] = {w} = g[] = A*f[] = A’*f[] = f[]. 30..5 −2...5 -2.5 0.  0.m} Note 4.*g[] = f[].2 × 10−16 −1.5 0.25 0 0.5 0. the following gives an error matrix AAA = Aˆ-1.1 × 1015 f[]’*g[] = 0. 10 0.0000000000000000199e+30 6 6 1. J.0000000000000000199e+30 3 3 1.0000000000000000199e+30 2 2 1.5 1. 1030   −2. 0. 0.25 5 × 1029 1030 0 0 0 0 0. 1030 0.4 this produces  1030 0..5 1e+30 1 5 0 4 4 2 1 5 1 5 3 2 0 4 0 1 4 5 0 2 4 5 1 2 4 1 3 4 The output of a diagonal sparse matrix D (Warning du to fortran interface the indices start on the output at one. 0.5 1 0 1 1.0000000000000000199e+30 {1. 0.n}x{1.5 0.0000000000000000199e+30 4 4 1.5 -2.5 0.5 The output of the I.5 0..2 × 10−16 0 1 1.3 The operators ˆ-1 cannot be used to create a matrix./g[] = T 75 the following:  −2..5 0 5 × 1029 1030 −1.j) \in 6 6 1 6 1 1 1.  30  0.5 0. 02 -0.775557562e-17 -1.469446952e-18 -5. load "lapack" load "fflapack" int n=5.++i) for(int j=0.081668171e-17 -2.02 -0.j<n.k<n.02 -0. cout << B << endl.02 -0.B(n. cout << A1 << endl.i<n.02 0.18 -0.02 -0.02 -0.j<n.02 -0.02 -0. // inv(A1).n).++j) for(int k=0.02 -0.02 0.i<n.j)= (i==j) ? n+1 : 1. for(int i=0.510281038e-17 -4.int] A(n.18 -0. B=0.387778781e-17 -1.edp a full matrix is inverted using the lapack library and this small dynamic link interface (see for more detail section C page 321).387778781e-17 -4. for(int i=0.++k) B(i.551115123e-17 1 -2.775557562e-17 1. cout << A1 << endl.A1(n.02 -0.02 -0.k)*A1(k.714451465e-17 -5. SYNTAX In examples++-load/lapack.76 CHAPTER 4.02 -0.02 -0.551115123e-17 -4. A1=Aˆ-1.j) +=A(i.18 -0.040834086e-17 3.02 -0.n).040834086e-17 -2.j). real[int.++j) A(i.469446952e-17 0 -1.02 0. A1+Aˆ-1.857225733e-17 1 -2.++i) for(int j=0.387778781e-17 -9.081668171e-17 0 3.040834086e-17 1 -1.163336342e-17 1 5 5 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 .02 -0.18 5 5 1 -1.02 -0.18 -0.02 0. attention ne marche pas // def in load "fflapack" // def in load "lapack" and the output is: 5 5 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 1 1 1 1 1 6 error: dgesv_ 0 5 5 0. cout << A << endl.n). 4.9. ARRAYS 77 to compile lapack.cpp or fflapack.cpp you must have the library lapack on you system and try in directory examples++-load ff-c++ lapack.cpp -llapack ff-c++ fflapack.cpp -llapack 4.9.4 Other arrays It is also possible to make an array of FE functions, with the same syntax, and we can treat them as vector valued function if we need them. Example 4.6 In the following example, Poisson’s equation is solved for 3 different given functions f = 1, sin(πx) cos(πy), |x − 1||y − 1|, whose solutions are stored in an array of FE function. mesh Th=square(20,20,[2*x,2*y]); fespace Vh(Th,P1); Vh u, v, f; problem Poisson(u,v) = int2d(Th)( dx(u)*dx(v) + dy(u)*dy(v)) + int2d(Th)( -f*v ) + on(1,2,3,4,u=0) ; Vh[int] uu(3); f=1; Poisson; uu[0] = u; f=sin(pi*x)*cos(pi*y); Poisson; uu[1] = u; f=abs(x-1)*abs(y-1); Poisson; uu[2] = u; for (int i=0; i<3; i++) plot(uu[i], wait=true); // an array of FE function // problem1 // // // problem2 problem3 plots all solutions For the second case, it is just a map of the STL1 [26] so no operations on vector are allowed, except the selection of an item . The transpose or Hermitian conjugation operator is ’ as in Matlab or Scilab, so the way to compute the dot product of two array a,b is real ab= a’*b. int i; real [int] tab(10), tab1(10); // 2 array of 10 real real [int] tab2; // Error: array with no size tab = 1; // set all the array to 1 tab[1]=2; cout << tab[1] << " " << tab[9] << " size of tab = " << tab.n << " " << tab.min << " " << tab.max << " " << endl; tab1=tab; tab=tab+tab1; tab=2*tab+tab1*5; tab1=2*tab-tab1*5; t tab+=tab; cout << " dot product " << tab’*tab << endl; // tab tab cout << tab << endl; cout << tab[1] << " " << tab[9] << endl; real[string] map; // a dynamic array for (i=0;i<10;i=i+1) { tab[i] = i*i; 1 Standard template Library, now part of standard C++ 78 cout << i << " " << tab[i] << "\n"; }; map["1"]=2.0; map[2]=3.0; CHAPTER 4. SYNTAX // 2 is automatically cast to the string "2" cout << " map[\"1\"] = " << map["1"] << "; "<< endl; cout << " map[2] = " << map[2] << "; "<< endl; 4.10 Loops The for and while loops are implemented in FreeFem++ together with break and continue keywords. In for-loop, there are three parameters; the INITIALIZATION of a control variable, the CONDITION to continue, the CHANGE of the control variable. While CONDITION is true, for-loop continue. for (INITIALIZATION; CONDITION; CHANGE) { BLOCK of calculations } An example below shows a sum from 1 to 10 with result is in sum, int sum=0; for (int i=1; i<=10; i++) sum += i; The while-loop while (CONDITION) { BLOCK of calculations or change of control variables } is executed repeatedly until CONDITION become false. The sum from 1 to 10 can also be computed by while as follows, int i=1, sum=0; while (i<=10) { sum += i; i++; } We can exit from a loop in midstream by break. The continue statement will pass the part from continue to the end of the loop. Example 4.7 for (int i=0;i<10;i=i+1) cout << i << "\n"; real eps=1; while (eps>1e-5) { eps = eps/2; if( i++ <100) break; cout << eps << endl;} 4.11. INPUT/OUTPUT for (int j=0; j<20; j++) { if (j<10) continue; cout << "j = " << j << endl; } 79 4.11 Input/Output The syntax of input/output statements is similar to C++ syntax. It uses cout, cin, endl, <<,>>. To write to (resp. read from) a file, declare a new variable ofstream ofile("filename"); or ofstream ofile("filename",append); (resp. ifstream ifile("filename"); ) and use ofile (resp. ifile) as cout (resp. cin). The word append in ofstream ofile("filename",append); means openning a file in append mode. Note 4.4 The file is closed at the exit of the enclosing block, Example 4.8 int i; cout << " std-out" << endl; cout << " enter i= ? "; cin >> i ; { ofstream f("toto.txt"); f << i << "coucou’\n"; }; // { ifstream f("toto.txt"); f >> i; } { ofstream f("toto.txt",append); // to append to the existing file "toto.txt" f << i << "coucou’\n"; }; // close the file f because the variable f is delete cout << i << endl; close the file f because the variable f is delete Some functions are available to format the output. • int nold=f.precision(n) Sets the number of digits printed to the right of the decimal point. This applies to all subsequent floating point numbers written to that output stream. However, this won’t make floating-point ”integers” print with a decimal point. It’s necessary to use fixed for that effect. • f.scientific Formats floating-point numbers in scientific notation ( d.dddEdd ) • f.fixed Used fixed point notation ( d.ddd ) for floating-point numbers. Opposite of scientific. 80 CHAPTER 4. SYNTAX • f.showbase Converts insertions to an external form that can be read according to the C++ lexical conventions for integral constants. By default, showbase is not set. • f.noshowbase unset showbase flags • f.showpos inserts a plus sign (+) into a decimal conversion of a positive integral value. • f.noshowpos unset showpos flags • f.default reset all the previous flags (fmtflags) to the default expect precision. Where f is output stream descriptor, for example cout. Remark, all these methods except the first return the stream f, so they can be chained as in cout.scientific.showpos << 3 << endl; 4.11.1 Script arguments There is a very useful predefined array in Freefem++ ARGV that contains all the arguments of the script used in the command line. The following code prints out the first three of these arguments: // for(int i=0;i<ARGV.n;++i) { cout << ARGV[i] << endl; } version 3.8-1 And to get argument unused in getARGV.idp include script file, getARGV(n,defaultvalue) // ...) getARGV(after,defaultvalue) // get the nth parameter unused if exist (n = 1, get the arg after the string after if exist The type of default value can be int, real, string, 4.12 preprocessor The preprocessor handles directives for source file inclusion (include ”script-name.idp”), macro definitions. There are two types of macros, object-like and function-like. Object-like macros do not take parameters; function-like macros do. The generic syntax for declaring an identifier as a macro of each type is, respectively, macro <identifier>() <replacement token list> // EOM a // comment to end the macro macro <identifier>(<parameter list>) <replacement token list> // EOM An example of macro without parameter macro xxx() {real i=0;int j=0;cout << i << " " << j << endl;} // 4.12. PREPROCESSOR xxx /* replace xxx by the <replacement token list> */ 81 The freefem++ code associated: 1 2 3 4 : // macro without parameter : macro xxx {real i=0;int j=0;cout << i << " " << j << endl;}// : : {real i=0;int j=0;cout << i << " " << j << endl;} An example of macro parameter macro toto(i) i // // quoting parameter the {} are remove toto({real i=0;int j=0;cout << i << " " << j << endl;}) // and only one level of {} are remove toto({{real i=0;int j=0;cout << i << " " << j << endl;}}) The freefem++ code created : 6 8 9 10 11 : macro toto(i ) i // : // quoting parameter the \{\} are remove : real i=0;int j=0;cout << i << " " << j << endl; : // and only one level of \{\} are remove : {real i=0;int j=0;cout << i << " " << j << endl;} Use a macro as parameter of macro to transforme full matrix in formal array like in : real[int,int] CC(7,7),EE(6,3),EEps(4,4); macro VIL6(v,i) [ v(1,i), v(2,i),v(4,i), v(5,i),v(6,i) ] macro VIL3(v,i) [ v(1,i), v(2,i) ] // apply v on array macro VV6(v,vv) [ v(vv,1), v(vv,2), v(vv,4), v(vv,5), v(vv,6) ] macro VV3(v,vv) [ v(vv,1), v(vv,2) ] // so formal matrix to build func C5x5 = VV6(VIL6,CC); func E5x2 = VV6(VIL3,EE); func Eps = VV3(VIL3,EEps); // EOM // EOM element : // EOM // EOM problem.. The freefem++ code created : 16 17 18 19 20 21 22 23 24 25 1 : real[int,int] CC(7,7),EE(6,3),EEps(4,4); : : macro VIL6(v,i ) [ v(1,i), v(2,i),v(4,i), v(5,i),v(6,i) ] // : macro VIL3(v,i ) [ v(1,i), v(2,i) ] // EOM : // apply v on array element : : macro VV6(v,vv ) [ v(vv,1), v(vv,2), : v(vv,4), v(vv,5), v(vv,6) ] // EOM : macro VV3(v,vv ) [ v(vv,1), v(vv,2) ] // EOM : // so formal matrix to build problem.. : func C5x5 = : [ [ CC(1,1), CC(2,1),CC(4,1), CC(5,1),CC(6,1) ] 82 CHAPTER 4. SYNTAX 1 : 26 : 1 : 1 : 27 : 28 : [ CC(1,2), CC(2,2),CC(4,2), CC(5,2),CC(6,2) ] , [ CC(1,4), CC(2,4),CC(4,4), CC(5,4),CC(6,4) ] , [ CC(1,5), CC(2,5),CC(4,5), CC(5,5),CC(6,5) ] , [ CC(1,6), CC(2,6),CC(4,6), CC(5,6),CC(6,6) ] func E5x2 = [ [ EE(1,1), EE(2,1) ] , [ EE(1,2), EE(2,2 [ EE(1,4), EE(2,4) ] , [ EE(1,5), EE(2,5) ] , [ EE(1,6), EE(2,6) ] ] ; func Eps = [ [ EEps(1,1), EEps(2,1) ] , [ EEps(1,2), EEps(2,2) ] ] ; finally the operator # to do concatenation of parameter: to build vectorial operation, like in macro div(u) (dx(u#1)+ dy(u#2)) mesh Th=square(2,2); fespace Vh(Th,P1); Vh v1=x,v2=y; cout << int2d(Th)(div(v)) << endl; // EOM The freefem++ code created : 31 32 33 34 : macro div(u ) (dx(u#1)+ dy(u#2)) //EOM : mesh Th=square(2,2); fespace Vh(Th,P1); : Vh v1=x,v2=y; : cout << int2d(Th)( (dx(v1)+ dy(v2)) ) << endl; And to finish a amazing test to verified the quoting : macro foo(i,j,k) i j k foo(,,) foo( {int [}, {int] a(10},{);}) // EOM empty line // the result: 36 : 37 : 38 : macro foo(i,j,k ) i j k//EOM // empty line int [ int] a(10 ); To defined macro in a macro you can use the two new word NewMacro , EndMacro key word to set and and claose de macro definition (version 3.11, and not well tested). 4.13 Exception handling In the version 2.3 of FreeFem++, exception handing was added as in C++. But today only the C++ exceptions are caught. Note that in C++ all the errors attached to ExecError, assert, exit, ... call exceptions too so it may be hard to find the cause of the error. The exceptions handle all ExecError: 4.13. EXCEPTION HANDLING Example 4.9 A simple example: catch a division by zero: 83 real a; try { a=1./0.; } catch (...) // in versions > 2.3 all exceptions can be caught { cout << " Catch an ExecError " << endl; a =0; } The output is 1/0 : d d d current line = 3 Exec error : Div by 0 -- number :1 Try:: catch (...) exception Catch an ExecError Example 4.10 : a more realistic example with a none invertible matrix: int nn=5 ; mesh Th=square(nn,nn); verbosity=5; fespace Vh(Th,P1); // P1 FE space Vh uh,vh; // unkown and test function. func f=1; // right hand side function func g=0; // boundary condition function real cpu=clock(); problem laplace(uh,vh,solver=Cholesky,tolpivot=1e-6) = // definion of the problem int2d(Th)( dx(uh)*dx(vh) + dy(uh)*dy(vh) ) // bilinear form + int2d(Th)( -f*vh ) // linear form ; try { cout << " Try Cholesky \n"; laplace; plot(uh); cout << "-- lap Cholesky " << nn << "x" << nn << " << " s, max =" << uh[].max << endl; } catch(...) { cout << " Catch cholesky PB " << endl; } // solve the problem // to see the result : " << -cpu+clock() // catch all The output is Nb of edges on Mortars = 0 Nb of edges on Boundary = 20. nb triangles = 50 . ...23124e-13 < 1e-06 current line = 28 Exec error : FATAL ERREUR dans .SizeOfSkyline =210 -.discontinous Galerkin =0 size of Mat =196 Bytes -.) exception Catch cholesky PB ..../femlib/MatriceCreuse_tpl. all -...size of Matrix 196 Bytes skyline =1 -.. all ERREUR choleskypivot (35)= -1. Nb Of Nodes = 36 Nb of DF = 36 Try Cholesky -.boundary int Optimized = 1.square mesh : nb vertices =36 .84 CHAPTER 4.hpp cholesky line: -.int in Optimized = 1.. neb = 20 Nb Mortars 0 number of real boundary edges 20 Number of Edges = 85 Number of Boundary Edges = 20 neb = 20 Number of Mortars Edges = 0 Nb Of Mortars with Paper Def = 0 Nb Of Mortars = 0 .Change of Mesh 0 0x312e9e8 Problem(): initmat 1 VF (discontinuous Galerkin) = 0 -.number :545 catch an erreur in solve => set sol = 0 !!!!!!! Try:: catch (. SYNTAX -. proceeds as follows: la b e l= 3 la b e l = 4 la b e l = 2 la b e l= 1 Figure 5. 1]2 .edp. real y0=0.1.1 Commands for Mesh Generation Let us begin with the two important keywords border and buildmesh All examples in this section come from the files mesh.y1=1.10) write real x0=1.Chapter 5 Mesh Generation 5. 5. 5. generates a 4 × 5 grid in the unit square [0.1: Boundary labels of the mesh by square(10.m=20.8.1.edp and tablefunction. 85 . mesh Th=square(n. x1 ] × [y0 .1 Square The command“square” triangulates the unit square. The labels of the boundaries are shown in Fig.5).2. int n=5.m.y0+(y1-y0)*y]).[x0+(x1-x0)*x. y1 ].x1=1. To construct a n × m grid in the rectangle [x0 . The following mesh Th = square(4. 8).5.} inner. plot(Th.m.5.14].} upper.1){x C05(t=0.1){x C12(t=0.edp : for (int i=0. int others = 2.} others.5*t.8) 3 same as case 0 except in two corners such that no triangle with 3 vertices on boundary (v 3.flags=i.3.1){x = = = = = = = = 0. Adding the named parameter label=labs will change the 4 default label numbers to labs[i-1]. } 5. int inner = 3.1){x C04(t=0. This can be used to structure the mesh if an area thouches a border and create new regions by dividing larger ones: int upper = 1. 1. 1+0.wait=1. -0. -1.} upper.13. border border border border border border border border C01(t=0.5-1. 0.12.1){x C03(t=0. 0.14].} inner.i<5. 1. 0.5*t. y y y y y y y y = = = = = = = = -1+t.region=10). To see all these fags at work.} others.++i) { int[int] labs=[11. label label label label label label label label = = = = = = = = upper. The pieces can only intersect at their endpoints.} others.1. for example int[int] labs=[11. 2 will produce a mesh where all quads are split with diagonal x + y = cte (v 3. -t.86 CHAPTER 5.[x0+(x1-x0)*x.} .cmm=" square flags = "+i ).1 Adding the named parameter flags=icase with icase: 0 will produce a mesh where all quads are split with diagonal x − y = cte 1 will produce Union Jack flag type of mesh. 0.2 Border Boundaries are defined piecewise by parametrized curves.5*t. try the file examples++/square-mesh. mesh Th=square(3.12.5*t.label=labs.5*t. 0.5+0. MESH GENERATION Note 5. -0.5. 0.8) mesh Th=square(n. but it is possible to join more than two endpoints.1){x C06(t=0.y0+(y1-y0)*y].5+0. 0. for instance (v 3.8) 4 same as case 2 except in two corners such that no triangle with 3 vertices on boundary (v 3.1){x C11(t=0.1){x C02(t=0. and adding the named parameter region=10 will change the region number to 10.13.5*t.flags=icase). plot(Th.5*t.25. plot(C01(-n)+C02(-n)+C03(-n)+C04(-n)+C05(-n)+C06(-n)+ C11(n)+C12(n)+C13(n).75. 6). mesh Th = buildmesh(C01(-n)+C02(-n)+C03(-n)+C04(-n)+C05(-n)+C06(-n)+ C11(n)+C12(n)+C13(n)). y = -0.} 87 int n = 10. wait=true). // figure 5. label = inner.5+0.3 cout << "Part 1 has region number " << Th(0. y) | x = ϕx (t). COMMANDS FOR MESH GENERATION border C13(t=0. wait=true). where mj are positive or negative numbers to indicate how many vertices should be on Γj .4.5. to set the maximal number of vertices in the mesh.region << endl. ϕy (t)). cout << "Part 2 has redion number " << Th(0. -0.25).3: Generated mesh Triangulation keywords assume that the domain is defined as being on the left (resp right) of its oriented parameterized boundary Γj = {(x. -0. Figure 5. to say if the mesh generator can change the boundary mesh or not (by default the boundary mesh can change.1){x = 1.25). beware that with periodic boundary conditions (see.region << endl. fixeborder=<bool value> . t0 ≤ t ≤ t1 . then the domain lies on the shaded area. If it is as in Fig. aj ≤ t ≤ bj } To check the orientation plot t → (ϕx (t). . y = ϕy (t).1. otherwise it lies on the opposite side The general expression to define a triangulation with buildmesh is mesh Mesh_Name = buildmesh(Γ1 (m1 ) + · · · + ΓJ (mj ) OptionalParameter). 5. it can be dangerous . Γ = ∪J ΓJ . and the optional parameter (separed with comma) can be j=1 nbvx=<int value> .2: Multiple border ends intersect Figure 5. 1: 2: 3: 4: 5: 6: 7: border a(t=0. y=sin(t).label=1.eps").2*pi){ x=cos(t). // figure 5. y = j y(t)) (d j x(t)/d t. d j y(t)/d t) t = t1 t = t0 t = t0 t = t1 t = t0 (x = t.88 CHAPTER 5.2*pi){ x=0.2 Notice that the orientation is changed by “b(-30)” in 5th line.} plot(a(50)+b(+30)) . // figure 5. and assign “1” to the unit disk (“2” to the circle inside). The following example shows how to change the orientation.wait=1.3*sin(t).wait=1.3: . y=0.eps"). φy (t)) The orientation of boundaries can be changed by changing the sign of mj . The example generates the unit disk with a small circular hole.4: Orientation of the boundary defined by (φx (t). but it can also be omitted. mesh Thwithhole = buildmesh(a(50)+b(-30)). ps="fileName" is used to generate a postscript file with identification shown on the figure. // to see a plot of the border mesh mesh Thwithouthole= buildmesh(a(50)+b(+30)).5: mesh without hole Figure 5.3 Borders are evaluated only at the time plot or buildmesh is called so the global variable are defined at this time andhere since r is changed between the two border calls the following code will not work because the first border will be computed with r=0.label=2.3*cos(t).6: mesh with hole Note 5.} border b(t=0.3+0. In 7th line. y = -t) (x = t.ps="Thwithouthole.ps="Thwithhole. Figure 5. plot(Thwithouthole. y = t) Figure 5. The boundary label must be non-zero. MESH GENERATION  G j t = t1 (x = j x(t).5 plot(Thwithhole.6 Note 5. i = 1.309016994375. i i For each vertex q i .  #   ! In the left figure. ) . ns = 10 q 1 = (−0. COMMANDS FOR MESH GENERATION 89 real r=1. . the mesh is shown on Fig. nv . modulef. q k2 . // bug (a trap) because // the two circle have the same radius = 0.msh"). Hecht ”bamg : a bidimentional anisotropic mesh generator” (downloadable from the FreeFem web site. whose structure is shown on Table 5.1. of 1st side L1 are q 6 . nt number of triangles and ns the number of edges on boundary. (see Section 12).1. 14 q = (−0. q 6 . y=r*sin(t).2*pi){ x=r*cos(t). The edge of 10th side L10 are q 10 . #  ! ! & ' nv = 14. k = 1. q k3 that are oriented counterclockwise. . . There nv denotes the number of vertices. · · · . . 0. .   vertices of T1 are q 9 . . .7.3 Data Structures and Read/Write Statements for a Mesh Users who want to read a triangulation made elsewhere should see the structure of the file generated below: border C(t=0.label=1. . The vertices of T16 are q 9 . nt = 16. . . The boundary consists of 10 lines Li .2*pi) { x=cos(t). y=sin(t). } mesh Th = buildmesh(C(10)). 10 has three vertices q k1 . .2*pi){ x=r*cos(t).} r=0. q 10 . More details can be found on the file format . qy ) the x-coordinate and y-coordinate.msh in the article by F. .. y=r*sin(t). "    " $  "  ! The . Each triangle Tk .7: mesh by buildmesh(C(10)) In FreeFem++ there are many mesh file formats available for communication with other tools such as emc2. . . i = 1.1. we have the following. 5. edge . · · · .951056516295) "  ' % % & $  !    #   The .309016994375. savemesh("mesh_sample.951056516295) . 10 whose end points are q i1 . The informations about Th are saved in the file “mesh sample. . The extension of a file implies its format. Figure 5.msh”. . q 5 . .3 . −0. . border a(t=0.label=1. · · · . q 10 . . . border b(t=0. .} mesh Thwithhole = buildmesh(a(50)+b(-30)). denote by (qx . q 6 .3 5.5. . . q 12 . q i2 . 0){ x=t.P1). y=t.nopo").1 (Readmesh.msh"). y=t.90 Content of the file 14 16 10 -0.g. label=5. y=0. // format database db mesh "bamg" savemesh(th. // "bamg"-type mesh savemesh(th. y=1. label=5.1){ x=1. // read the mesh Example 5. int n=10.}.}. border left(t=1.am_fmt").0){ x=t.951056516295 1 . mesh th= buildmesh(floor(n)+right(n)+ceiling(n)+left(n)). -0.am_fmt"). label=5. .msh"). border left(t=1.309016994375 0.}. .Th"). int n=10.1){ x=t. label=5. y=1. savemesh(th.nopo")."toto.0){ x=0.}. unless this number is overwritten by the keyword ”label”."toto. femp1 f = sin(x)*cos(y).Th"). label=1. // the unit square border right(t=0. // "formatted Marrocco" format savemesh(th. y=t.}. // modulef format see [10] mesh th2 = readmesh("toto.309016994375 -0.edp) border floor(t=0. // freefem format savemesh(th. label=5. y=0.951056516295 1 9 12 10 0 5960 ··· 9 10 6 0 651 521 ··· 10 6 1 CHAPTER 5.msh” A mesh file can be read into FreeFem++ except that the names of the borders are lost and only their reference numbers are kept.309016994375 0."toto.}."toto."toto.1){ x=1.msh")."toto. border ceiling(t=1. label=5.}. MESH GENERATION Explanation nv nt ne 1 1 boundary label=1 qy qx 2 2 qx qy boundary label=1 14 14 qx qy 11 12 13 21 22 23 boundary label=1 region label=0 region label=0 161 162 163 region label=0 11 12 boundary label=1 21 22 boundary label=1 101 102 boundary label=1 Table 5.951056516295 1 0. label=1. // format freefem savemesh(th. y=t.0){ x=0. ··· ··· .1: The structure of “mesh sample. border ceiling(t=1.msh"). mesh th= buildmesh(floor(n)+right(n)+ceiling(n)+left(n))."toto. // modulef format see [10] mesh th2 = readmesh("toto. Here are some examples: border floor(t=0. // format "formated Marrocco" savemesh(th."toto. savemesh(th.}. // the unit square border right(t=0. fespace femp1(th.1){ x=t. So these borders have to be referenced by the number which corresponds to their order of appearance in the program. int nr00 = Th(0.u). // hack of get vertex coordinates // get vertices information : int nbvertices=Th. { mesh Th=square(2.6).19 << " old method: " << Thx[][i] << " " << Thy[][i] << endl. cout << " nb of Triangles = " << nbtriangles << endl.P1).label // v 2. // get data of the mesh int nbtriangles=Th.1. COMMANDS FOR MESH GENERATION 91 { // save solution ofstream file("f.label << endl. cout << " nb of vertices = " << nbvertices << endl.6). << Th(i). plot(g). femp1 Thx=x.37) fespace femp1(Th. } // close reading file (end block) fespace Vh2(th2.2).y << ". ∂u // u = 0 on Γ1 and ∂n = g on Γ2 solve pb(u. file << f[] << endl.nuTriangle.x << " " << Th(i).5)( g*v) // ∂n = g on Γ2 + on(1. j++) cout << i << " " << j << " Th[i][j] = " << Th[i][j] << " x = "<< Th[i][j].region.dx(u)*dx(v)-dy(u)*dy(v) ) + int2d(th)(-g*v) ∂u + int1d(th.55.nt. j <3.i<nbvertices.0.Thy=y.u=0) .i++) for (int j=0. .i++) cout << "Th(" <<i << ") : " // << endl.nv.v) = int2d(th)( u*v .P1).6) // then triangle number // int it00 = Th(0.0.txt"). label=" << Th[i][j].55. // // Th(i) return the vextex i of Th Th[k] return the triangle k of Th // get mesh information (version 1.x << " . 5. y= "<< Th[i][j]. plot (th2. Vh2 u.txt").i<nbtriangles. for (int i=0. file >> g[] .v. // find u such that // u + ∆u = g in Ω .55. for (int i=0.1. // method to find information of point (0. } // close the file (end block) { // read ifstream file("f.y << " " << Th(i).5.4 Mesh Connectivity The following example explains methods to obtain mesh information.0. be(k).6). // return the boundary element k ∈ {0.Element .P0). area K " << area00 << endl.e=1. femp0 nuT.ee. // // dump ------------------------------------------------------- cout << " point (0.adj(ee=e)) not adjacent element .nbe − 1} Th. real nll00 = Th[it00].adj(e) .k<nbelement.y // or region number (old method) // ------------------------------------------------------fespace femp0(Th. T h.label.be(k)[l].adj((ee=e)) != Th[k]) << endl.i<Th.6).6).0..be(k). // return the triangle containing the boundary elmt k Th. // a P0 function to get the region number // inquire int it0=nuT(0.adj((ee=e))) << " " << ee << " adj: " << ( Th[k].k<nbelement.55.area. // return the number of boundary element Th. // return the edge number of triangle containing // the boundary elmt k Th[k]. // note : if k == int(Th[k].. .i++) nuT[][i]=i. // a P0 function to get triangle numbering for (int i=0.55. // return the vertices l ∈ {0. // new method to get boundary information and mesh adjacent int k=0. region = " << nr0 << " == " << nr00 << "..be(k).nt.label << endl. int nbelement = Th.l=1.6) :triangle number " << it00 << " " << it00 << ". and change // the value of e to the corresponding edge in the adjacent triangle Th[k] == Th[k].55. // in () to make difference with named parameters. MESH GENERATION // info of a triangle // new in version 2. for (int k=0. Th.adj(e) // true adjacent triangle cout << " print mesh connectivity " << endl.55. 1} of boundary elmt k Th.55. label " << Th[k]. int nr0=nuReg(0.adj(e) // non adjacent triangle return the same Th[k] != Th[k].whoinElement . cout << k << " " << e << " <=> " << int(Th[k].0.0.0. // // Hack to get a triangle containing point x. // for (int k=0.19 // new in version 2.e<3.++k) for (int e=0.6).region. // number of region of Th’s containing (0. real area00 = Th[it00].19 same as region in this case. // return adjacent triangle to k by edge e. real nrr00 = Th[it00]. and ee is change by method adj.92 CHAPTER 5. // number of triangle Th’s containing (0.nbe . femp0 nuReg=region.++e) // remark FH hack: set ee to e.++k) cout << k << " : " << int(Th[k][0]) << " " << int(Th[k][1]) << " " << int(Th[k][2]) << " .0.nt. 5 .label << " tria " << int(Th.5.. 6 2 <=> 3 0 adj: 1 7 0 <=> 7 0 adj: 0 7 1 <=> 4 0 adj: 1 7 2 <=> 6 1 adj: 1 0 : 0 1 .k<nbboundaryelement. y= 0.5. label=3 7 0 Th[i][j] = 4 x = 0. label=0 7 1 Th[i][j] = 8 x = 1 . label=3 7 2 Th[i][j] = 7 x = 0. label 0 .5 1 3 old method: 0.5 1 Th(8) : 1 1 3 old method: 1 1 Nb Of Nodes = 8 Nb of DF = 8 print mesh connectivity 0 : 0 1 4 . COMMANDS FOR MESH GENERATION 93 int nbboundaryelement = Th.. label=2 6 2 Th[i][j] = 8 x = 1 .5 .5.whoinElement << endl.be(k).++k) cout << k << " : " << Th..be(k)[1] << " . y= 0. label 1 tria 0 2 .. 6 0 Th[i][j] = 4 x = 0. label 0 1 : 0 4 3 . label " << Th.. y= 0.5. y= 1.1. Nb of Triangles 8 Nb of edge on user boundary 8 . label=3 Nb Of Nodes = 9 Nb of DF = 9 -. label 0 0 0 <=> 3 1 adj: 1 0 1 <=> 1 2 adj: 1 0 2 <=> 0 2 adj: 0 .5 0 . for (int k=0. y= 1. label=4 0 1 Th[i][j] = 1 x = 0. 6 : 4 5 8 . label=0 6 1 Th[i][j] = 5 x = 1 .be(k)[0] << " " << Th. nb boundary edges 8 Nb of Vertices 9 . y= 0. } the output is: -. y= 0.5 . label=0 . Th(7) : 0.5 .5. y= 1.. Nb of edges on true boundary 8 number of real boundary edges 8 nb of Triangles = 8 0 0 Th[i][j] = 0 x = 0 .5 . nb triangles = 8 ..nbe.Element) << " " << Th.be(k). y= 0..5 0 1 old method: 0. label=1 0 2 Th[i][j] = 4 x = 0.be(k).vector function’s bound 0 1 nb of vertices = 9 Th(0) : 0 0 4 old method: 0 0 Th(1) : 0.square mesh : nb vertices =9 . label 0 7 : 4 8 7 .vector function’s bound 0 1 -. y) in a file such as: 0.yy.P1).580623 0. The following example shows how to make a mesh from the file “xyf” with the format stated just above.800819 0.456045 .746765 0.. label 4 tria 2 2 1 1 5 1 CHAPTER 5.ps")... // (see figure 5..534534 0.636237 0..899823 0.947628 0.. This triangulation is a Delaunay mesh of the convex hull of the set of points.94 1 : 1 2 ..8) fespace Vhxy(Thxy.389647 0...12472 0.171736 0. label 1 tria . label 4 tria 7 : 3 6 .702231 0..ps="Thxyf.0838988 0..51387 0..494773 0.308652 0. But you can use this third value to define a table function with rows of the form: x y f(x. MESH GENERATION 5. 6 : 0 3 . // create a P1 interpolation // the function reading the 3rd row to define the function . real xx. The command triangulate command use only use 1st and 2nd rows.226431 0.175741 0. The coordinates of the points and the value of the table function are defined separately with rows of the form: x y f(x. It can be useful to build a mesh form a table function..8: Delaunay mesh of the convex hull of point set in file xyf Figure 5.5 The keyword ”triangulate” FreeFem++ is able to build a triangulation from a set of points.9: Isovalue of table function The third column of each line is left untouched by the triangulate command. // { ifstream file("xyf").. Figure 5.y). Vhxy fxy.1. // build the Delaunay mesh of the convex hull // points are defined by the first 2 columns of file xyf plot(Thxy.. mesh Thxy=triangulate("xyf").. i++) // build the pseudo region numbering { int iq=i/2. plot(Th. { // // new stuff 2004 emptymesh (version 1. mesh Th=triangulate(xx[].2 Boundary FEM Spaces Built as Empty Meshes To define a Finite Element space on a boundary.40) // -.i<fxy.useful to build Multiplicator space // build a mesh without internal point // of peusdo sub domain // ----assert(version>=1. Th=emptymesh(Th).eps").40).label=1. xx and yy are just skipped plot the function (see figure 5.ps="xyf.10). mesh Th=square(10.23-2): Vhxy xx=x. } Th=emptymesh(Th.ssd) using the set of edges of the mesh Th. border a(t=0.eps"). It can be useful to handle Lagrange multipliers in mixed and mortar methods.i++) file >> xx >>yy >> fxy[][i]. y=sin(t). So the function emptymesh remove all the internal points of a mesh except points on internal boundaries.2.} mesh Th=buildmesh(a(20)).yy=y. // int iy=iq/10. { // new stuff 2004 emptymesh (version 1.2*pi){ x=cos(t).nt).9) One new way to build a mesh is to have two arrays one the x values and the other for the y values (version 2. // ssd[i]= 1 + (ix>=5) + (iy>=5)*2.40). BOUNDARY FEM SPACES BUILT AS EMPTY MESHES for(int i=0.n. we came up with the idea of a mesh with no internal points (call empty mesh).5. int[int] ssd(Th. // to set two arrays for the x’s and y’s 5.ps="emptymesh-1. // } plot(fxu. a edge e is in this set if with the two adjacent triangles e = t1 ∩ t2 and ssd[T 1] = ssd[T 2] where ssd refers to the pseudo region numbering of triangles.ssd). } // see figure 5.yy[]). // because 2 triangle per quad int ix=iq%10.n. for(int i=0.40) -. // 95 // to read third row only.i<ssd. when they are stored in an int[int] array of size the number of triangles.useful to build Multiplicator space // build a mesh without internal point // with the same boundary // ----- assert(version>=1.10 It is also possible to build an empty mesh of a pseudo subregion with emptymesh(Th. // build emtpy with .wait=1. y=0.3 5. y) = y +k ∗cos(yπ)/10) for a big number k > 1.11 Figure 5."emptymesh-2.label=1.To spot such problems one may check the minimum triangle area in the transformed mesh with checkmovemesh before any real transformation.y=t.10: ary The empty mesh with bound. rotated and deformed by movemesh. Sometimes the transformed mesh is invalid because some triangle have flip over (now has negative area).}.5){x=1.y=0. border d(t=0.}.Φ2]).}. y).[Φ1.y=t. savemesh(Th.1){x=1-t. this is useful for elasticity to watch the deformation due to the displacement Φ(x. y) = x+k ∗sin(y ∗π)/10).y=1. border c(t=0.label=1. Φ2 (x.5. . border b(t=0.0.msh").5){x=1-t.1 Remeshing Movemesh Meshes can be translated.label=1. Φ2 (x.ps="emptymesh-2. verbosity=4. and Φ is a displacement vector then Φ(Th ) is obtained by mesh Th=movemesh(Th.11: An empty mesh defined from a pseudo region numbering of triangle 5. y) = (Φ1 (x.}.label=1.96 // plot(Th. It is also useful to handle free boundary problems or optimal shape problems. } CHAPTER 5.5.5.2 Φ1 (x.1){x=0.0. MESH GENERATION all edge e = T 1 ∩ T 2 and ssd[T 1] = ssd[T 2] // see figure 5. border a(t=0. y)) of shape.}.eps").label=1.1){x=t.3. Example 5. If Ω is triangulated as Th (Ω).5.wait=1.Figure 5. border e(t=0. 1){x=0.) does not change u and so the old mesh still exists.eps"). REMESHING border f(t=0.3 (movemesh. real t=0.4 Consider a function u defined on a mesh Th.. A statement like Th=movemesh(Th. plot(Th.10).y=1-t. func vv= cos(x*pi)/10. // --// the problem is how to build data without interpolation so the data u is moving with the mesh as you can see in the plot simple movemesh example // . // see figure 5.3.5. // the min triangle area if (minT > minT0/5) break .wait=1.}.y+coef*vv]).eps").[x+coef*uu.wait=1. fespace Vh(Th. real minT0= checkmovemesh(Th.12: L-shape Figure 5.P1).5.edp) Now. // mesh Th=square(10. plot(Th.[x+coef*uu.label=1.y]). A statement like u = u redefines u on the new mesh Th with interpolation and therefore destroys the old Th if u was the only function using it. // if big enough coef/=1. // see figure 5. It will be destroyed when no function use it.13: moved L-shape Note 5.13 Figure 5. // the min triangle area while(1) // find a correct move mesh { real minT=checkmovemesh(Th. } Th=movemesh(Th.fill=1. we given an example of moving mesh with a lagrangian function u defined on the moving mesh.12 real coef=1. Example 5.ps="Lshape.[x..ps="movemesh.fill=1. 97 mesh Th = buildmesh ( a(6) + b(4) + c(4) +d(4) + e(4) + f(6)).y+coef*vv]). func uu= sin(y*pi)/10. .4 Regular Triangulation: hTriangle For a set S. fespace Ph(Th. // set the value of u without any mesh update plot(Th. Vh f= x*t.98 CHAPTER 5.[x.i++) { t=i*0.wait=1). x.n). cout << " Min area " << minarea << endl. We put h(Th ) = max{diam(Tk )| Tk ∈ Th }. }. // save the value u=0. which is obtained by mesh Th = . for (int i=0. // to change the FEspace and mesh associated with u u[]=tmp. all the // previous meshes are deleted from memory. // -------- 5..P0). Ph h = hTriangle.y+f]). cout << "size of mesh = " << h[].. // In this program. since u is only defined on the last mesh. There is a number σ > 0 independent of h such that ρ(Tk ) ≥σ diam(Tk ) for all Tk ∈ Th where ρ(Tk ) are the diameter of the inscribed circle of Tk .i<4.u. lim max{diam(Tk )| Tk ∈ Th } = 0 h↓0 2. // movemesh will be ok real[int] tmp(u[].max << endl. tmp=u[].y+f]). . y ∈ S} The sequence {Th }h↓0 of Ω is called regular if they satisfy the following: 1.1. MESH GENERATION // --- Vh u=y.. real minarea=checkmovemesh(Th.. if (minarea >0 ) Th=movemesh(Th. we define the diameter of S by diam(S) = sup{|x − y|.[x.. // level of error . y=t. fespace Vh(Th. border ba(t=0.0001 The function sharply varies in value and the initial mesh given by one of the commands of Section 5. y) = 10. hmin=0.5){x=1-t.5. create the new mesh ATh adapted to the Hessian D2 f = (∂ 2 f /∂x2 .5. // set FE space Vh u.label=1.}. } // old mesh is deleted FreeFem++ uses a variable metric/Delaunay automatic meshing algorithm.}. label=1.1 cannot reflect its sharp variations.fh. f).edp) The solution has the singularity r3/2 .05.0*xˆ3+yˆ3+h*atan2(eps.}.5.0x3 + y 3 + tan−1 [ε/(sin(5. y=1. plot(Th.[-1+2*x. Vh fh=f. fespace Vh(Th. Example 5. y=1-t. border bc(t=0.}.}. y=0.fh).1)-(2. r = |x − γ| at the point γ of the intersection of two lines bc and bd (see Fig.P1).5 Adaptmesh f (x.}. real error=0. // set unknown and test function func f = 1.P1). 5.wait=1).0y) − 2. ∂ 2 f /∂x∂y. for (int i=0.5. mesh Th=square(5. plot(fh).5.0){x=t. border be(t=0.0.1){x=1-t. ∂ 2 f /∂y 2 ) of a function (formula or FE-function).0001.1){x=0.1){x=0. fh=f.0*x). border bd(t=0.0.15). when f = 1 and Ω is a L-shape domain.2). label=1.0x)] ε = 0.5 (Adapt. Mesh adaptation is a very powerful tool when the solution of a problem varies locally and sharply.1.label=1. label=1. mesh Th = buildmesh ( ba(6)+bb(4)+bc(4)+bd(4)+be(4)+bf(6) ). ADAPTMESH 99 5.0*y)-2. h=1.v. y=0.sin(5. border bb(t=0.i++) { Th=adaptmesh(Th. The command mesh ATh = adaptmesh(Th.i<2.4 real real real func eps = 0.1. f = 10.5. Here we solve the problem (2. y=t. border bf(t=0. Example 5.0.5.5){x=1. label=1.-1+2*y]). Thnew = adaptmesh(Thold. for (int i=0.v.. here eps=1.f2] . Thnew des maillages.. Th=adaptmesh(Th.. so the linear system can be solved with the conjugate gradient method (parameter solver=CG with the stopping criteria on the residual. f1. so as to make the new mesh finer or coarser. MESH GENERATION In it ia l m e s h F ir s t a d a p t a t io n S e c o n d a d a p t a t io n Figure 5.f2 . f1 .16.i< 4.. it specifies the required precision. plot(u).. Thnew = adaptmesh(Thold. . ). ).0e-6).0e-6) = int2d(Th)( dx(u)*dx(v) + dy(u)*dy(v)) .u=0) . By adaptmesh.. The problem is coercive and symmetric. To speed up the adaptation the default parameter err of adaptmesh is changed by hand. Thnew = adaptmesh(Thold.int2d(Th) ( f*v ) + on(1.eps=1. This method is described in detail in [9].14: 3D graphs for the initial mesh and 1st and 2nd mesh adaptation problem Poisson(u. ]). error = error/2. 5.100 CHAPTER 5. It has a number of default parameters which can be modified : Si f1.err=error). [f1. the slope of the final solution is correctly computed near the point of intersection of bc and bd as in Fig.solver=CG.u.i++) { Poisson. } .f2 sont des functions et thold. (val is a real. the speed of mesh size variations is bounded by log(ratio).01.8 is the default). omega= relaxation parameter for the smoothing procedure (1. the number of generated vertices increases.1. If the value is 0 or less than 1.15: boundary name L-shape domain and its Figure 5. nbvx= Maximum number of vertices generated by the mesh generator (9000 is the default).16: adaptation Final solution after 4-times The additional paramters of adaptmesh not written here. iso= If true. By default this error is 0. This may be useful to control the thickness of refined regions near shocks or boundary layers . It defaults to the diameter of the domain to be meshed) err= P1 interpolation error level (0. nbsmooth= number of iterations of the smoothing procedure (5 is the default).1 no smoothing is done on the metric (1.5..” hmin= Minimum edge size. (val is a real. Its default is related to the size of the domain to be meshed and the precision of the mesh generator).0 is the default). forces the metric to be isotropic (false is the default).5. If ratio > 1. errg= Relative geometrical error. and in any case it must be √ lower than 1/ 2. 0 means no smoothing (6 is the default). ADAPTMESH 101 > A > @ > B > ? > > > = Figure 5. Meshes created with this option may have some edges smaller than the -hmin due to geometrical constraints. ratio= ratio for a prescribed smoothing on the metric. hmax= Maximum edge size. hence the ”. . Note: As ratio gets closer to 1. nbjacoby= number of iterations in a smoothing procedure during the metric construction.01 is the default).. (5.2) cutoff= lower limit for the relative error evaluation (1.fxx. maxsubdiv= Changes the metric such that the maximum subdivision of a background edge is bound by val (always limited by 10. and 10 is also the default).hmin=hmin).. m22 are given. 90 imply perp. thetamax= minimum corner angle of in degrees (default is 10◦ ) where the corner is ABC and the angle is the angle of the two vectors AB. If only one function is given. |η|) p (5. (0 imply no corner. rescaling= if true. If the 3 functions m11 . tries to keep as many vertices from the original mesh as possible (true is the default). isMetric= if true. if the partial derivatives fxx (= ∂ 2 f /∂x2 ). the function with respect to which the mesh is adapted is rescaled to be between 0 and 1 (true is the default).102 CHAPTER 5. keepbackvertices= if true. corner . inquire= To inquire graphically about the mesh (false is the default). splitpbedge= If true. they directly define a symmetric matrix field whose Hessian is computed to define a metric.1) otherwise. BC. the metric is evaluated using the criterium of equi-distribution of errors. MESH GENERATION abserror= If false. splitin2= boolean value. the metric is evaluated using the criterium of equi-repartion of relative error (false is the default).0e-6 is the default). fyy (= ∂ 2 f /∂y 2 ) are given. In this case the metric is defined by M= 1 err coef2 |H| max(CutOff.fxy. fxy (= ∂ 2 f /∂x∂y).fyy. we can set Th=adaptmesh(Th. splits all internal edges in half with two boundary vertices (true is the default). power= exponent power of the Hessian used to compute the metric (1 is the default). m12 . If true..nbvx=10000. Also changes the value of the global variable verbosity (obsolete). splits all triangles of the final mesh into 4 sub-triangles.IsMetric=1. In this case the metric is defined by M= 1 err coef2 |H| sup(η) − inf(η) p . For example.). . verbosity= informational messages level (can be chosen between 0 and ∞). . the metric is defined explicitly (false is the default). then it represents the isotropic mesh size at every point. 6 Trunc Two operators have been introduce to remove triangles from a mesh or to divide them.1. plot(Th.eps")./30. Th= adaptmesh(Th.IsMetric=1.wait=1. 1 So to build a mesh with a constant mesh size equal to 30 try: Example 5.IsMetric=1.eps"). So if m11.m12. plot(Th. builds an adapted periodic mesh.x]].edp for a full example) We can use the command adaptmesh to build uniform mesh with a contant mesh size..m22[]] (see file convect-apt. Operator trunc has two parameters label= sets the label number of new boundary item (one by default) .nbvx=10000). no adapted mesh is generated (useful to compute only a metric).y].y].nbvx=10000).1. Th= adaptmesh(Th.ps="square-0./30. periodic= Writing periodic=[[4.1.wait=1.6 uniformmesh. you can write: metric=[m11[].nbvx=10000). and see sphere.18: first iteration Figure 5.[1. The size of these three arrays must be the number of vertices. (see periodic finite element spaces 6.m12[].wait=1..eps")..m22 are three P1 finite elements related to the mesh to adapt.x]. // to have initial mesh // // more the one time du to // adaptation bound Figure 5.5.19: last iteration 5. TRUNC 103 metric= an array of 3 real arrays to set or get metric data information.2).IsMetric=1. Th= adaptmesh(Th.[3.ps="square-2. The sample build a biperiodic mesh of a square.6.[2.17: Initial mesh Figure 5.edp mesh Th=square(2. maxsubdiv= plot(Th./3As writing 0.edp for a full example) nomeshgeneration= If true.ps="square-1. } all degree of freedom the basic function i // plot the mesh of the function’s support // reset Figure 5. The truncmesh. Vh u. // u[][i]=0.104 CHAPTER 5.Sh1. just write: mesh Th3 = trunc(Th.e-10.eps"). To create the mesh Th3 where alls triangles of a mesh Th are splitted in 3×3 .ps="trunc"+i+". splitted in 5×5 5. for example: { // new stuff 2004 splitmesh (version 1. u=0.split=3).split=5.1.wait=1. fespace Vh(Th.label=2). each triangle is splitted in n × n ( one by default). // plot(u.n=u.3).abs(u)>1.20: mesh of support the function Figure 5. splitted in 5×5 P1 number 6. for (i=0.edp example construct all ”trunc” mesh to the support of the basic function of the space Vh (cf. MESH GENERATION split= sets the level n of triangle splitting. split all the triangles in 5×5. mesh Sh1=trunc(Th. abs(u)>0). int i.i<n.37) .P1).n.i++) // { u[][i]=1.7 Splitmesh Another way to split mesh triangles is to use splitmesh.21: mesh of support the function P1 number 0. mesh Th=square(3. and put a label number to 2 on new boundary. plot(Th.wait=1). }.label=1.y=1+t.y=1.8 Meshing Examples Example 5. 5.0){x = 0. 5.0){x=t .1+5*(square(x-0.0){x=t .2){x=1.eps").2.2. // Fig.8 (NACA0012 Airfoil) border upper(t=0. MESHING EXAMPLES assert(version>=1.y=1.}.ps="TouchSide. y=sin(t).1){x=1. Th=splitmesh(Th.ps="splitmesh.y=0.1){x=t .22 see figure 5.ps="nosplitmesh. int n=1.wait=1.eps").1) { x = t.}. mesh TH = buildmesh ( c1(10*n) + e(5*n) + f(10*n) + g(5*n) ).y=1+t.}.y=1. plot(Th.0){x=0.y=t.23: all left mesh triangle is split conformaly in int(1+5*(square(x-0.TH.8.}.} mesh Th=buildmesh(a(20)).7 (Two rectangles touching by a side) border a(t=0. border d(t=1. plot(th.24 Example 5. border e(t=0. border f(t=1.}.5.0. border a(t=0.1){x=t.2*pi){ x=cos(t).}.wait=1.5)+y*y)ˆ 2 triangles. plot(Th. border g(t=0.23 Figure 5. border b(t=0.5)+y*y)).37). . border c(t=1. mesh th = buildmesh(a(10*n)+b(10*n)+c(10*n)+d(10*n)). border c1(t=0.esp").22: initial mesh Figure 5. y=t.}. } 105 // // see figure 5. plot(Th.real q1.real p1. } mesh Th = buildmesh(C(50)).25: NACA0012 Airfoil Example 5.-1 0 ) e (1 0 .2*pi) { x=(2*cos(2*t)+3)*cos(t). q00=[-2.bw=1). p01=[0.17735*sqrt(t)-0. MESH GENERATION y = 0.26 Example 5. } real[int] p00=[0.bw=1).075597*t . // Fig.2*pi) { x=0. } mesh Th = buildmesh(C(50)).8*sin(t).06254*(tˆ4)). y=(2*cos(2*t)+3)*sin(t). 5. a = b.-1 0 ) Figure 5. q01=[-2. 5.bw=1). } mesh Th = buildmesh(c(30)+upper(35)+lower(35)).ps="Cardioid.real t) { return p0*(1-t)ˆ3+q1*3*(1-t)ˆ2*t+q2*3*(1-t)*tˆ2+p1*tˆ3. y= -(0.17363*(tˆ3)-0. } border lower(t=1.06254*(tˆ4).real q2.9 (Cardioid) real b = 1. // Fig.1]. } border c(t=0.075597*t -0.11 (By cubic Bezier curve) // A cubic Bezier curve connecting two points with two control points func real bzi(real p0.0 ) d th b h c g T H f (0 . 5.212836*(tˆ2)+0. plot(Th.0) { x = t.27 Example 5. // Fig.24: side Two rectangles touching by a Figure 5.25 (0 .17363*(tˆ3)-0.-0.212836*(tˆ2)+0. y=(a+b)*sin(t)-b*sin((a+b)*t/b).17735*sqrt(t)-0.-1].5.ps="NACA0012.5].8*cos(t)+0.0.eps".0.eps".106 CHAPTER 5.2*pi) { x=(a+b)*cos(t)-b*cos((a+b)*t/b).eps". border C(t=0.1]. plot(Th. y=0.ps="Cassini.2 ) a (0 . .10 (Cassini Egg) border C(t=0. MESHING EXAMPLES 107 Figure 5.. y=bzi(p01[1].bw=1).-0.7].26: boundary Domain with Cardioid curve Figure 5.eps". q10=[0.p00[1].bw=1).1.1) { x=bzi(p00[0].p01[1].t).t).q31[0].q21[1].4].-1].t).q20[1].5.q10[1]. y= 1+b*(x/a)*(x/a)*(3-2*abs(x)/a).1) { x= -a. plot(Th.p21[0].p01[0]. y=c.q01[0]. border G1(t=0. } border L2(t=0.1) { x=bzi(p21[0].p21[1]. q20=[3.ps="Engine. border G4(t=0.1) { x= a-2*a*t. y=c + (1+ b-c )*t.1) { x= -a+2*a*t. int m=5.t). b= 1.a*t. y= -1-b*(x/a)*(x/a)*(3-2*abs(x)/a ).1. border G2(t=0. // Fig.5.1]. } border L6(t=0. q21=[4.t).29 Example 5. y=-1-b + (1+ b )*t. border G3(t=0.-0. } border L8(t=0.p00[0]. y= 1+b .q10[0].5]. real[int] p21=[2.9].1) { x= a*t.5. } } } } // Fig 5. q11=[0. y=bzi(p21[1]. } border L5(t=0.1) { x= a.t).8.1) { x= a.q00[0].0.-0.1) { x= a .q30[0].p11[0].q21[0].q30[1].95]. y=bzi(p11[1].eps". border L1(t=0. q31=[1. y=c/2-c*cos(t)/2.t).0.1-d) { x=-1. } mesh Th = buildmesh(L1(8)+L2(26)+L3(8)+L4(20)+L5(8)+L6(30)+L7(8)+L8(30)). } border L4(t=0.12 (Section of Engine) real a= 6. y=bzi(p00[1]. mesh Th = buildmesh(G1(2*m)+G2(m)+G3(3*m)+G4(m)).27: Domain with Cassini Egg curve boundary real[int] p11=[1.5.2*(1+b)*t. plot(Th. y=0.1.13 (Domain with U-shape channel) real d = 0.q11[1].p11[1].q31[1].q20[0].1.ps="Bezier..} border L3(t=0. border L1(t=0.q01[1].28 Example 5. 5. real[int] q30=[0.pi) { x= -c*sin(t)/2. } border L7(t=0.q00[1].t).1) { x=bzi(p11[0].1) { x=bzi(p01[0].2]. } // width of U-shape .q11[0]. y=-d-t. c=0.5. border seg2(t=0. real a=1. pc(2).30 Example 5. y=-d.2) { x=-1+t.2*cos(t)-0. y=0.eps". pa[0] = cos(dAg).1-d) { x=-1.01.29: Section of Engine border L2(t=0.2*pi-dAg) { x=cos(t). // Fig. // Fig 5.5.2*d) { x=0.01. y=sin(t).ps="V-shape. c=0. } int n = 5.1) { x=(1-t)*pb[0]+t*pc[0].ps="U-shape.bw=1).15 (Smiling face) real d=0. } border B(t=0.2*sin(t)+0. y=b*sin(t). } border E1(t=0.2*pi) { x=0. y=1. }. } border R(t=0.5. } border C1(t=0. border seg1(t=0. y=-1+t. } border T(t=0.14 (Domain with V-shape cut) real dAg = 0.2*pi) { x=a*cos(t). pb[0] = cos(2*pi-dAg). mesh Th = buildmesh (L1(n/2)+L2(n/2)+B(n)+C1(n)+C2(3)+C3(n)+R(n)+T(n)). y=d-t.28: curves Boundary drawed by Bezier L 7 L 1 L 4 L 1 L 3 L 5 L 6 L 2 Figure 5.bw=1). y=1-t.1) { x=t-1. } func real st(real t) { return sin(pi*t)-pi/2. y=(1-t)*pb[1]+t*pc[1].eps".2) { x=1. 5. }. e=0. MESH GENERATION / " / ! /  / Figure 5.31 Example 5.2*cos(t)+0.1. b=2. y=0.7. pb[1] = sin(2*pi-dAg).5. y=(1-t)*pc[1]+t*pa[1].108 CHAPTER 5. int m=5. plot(Th.5.2) { x=1-t.2*sin(t)+0. // angle of V-shape border C(t=dAg. } border C2(t=0. pb(2). plot(Th. }.1) { x=-t. pa[1] = sin(dAg). pc[1] = 0. real[int] pa(2). y=-1. pc[0] = 0.5.2*pi) { x=0.1) { x=(1-t)*pc[0]+t*pa[0]. mesh Th = buildmesh(seg1(20)+C(40)+seg2(20)). y=d. . border F(t=0. } border C3(t=0. } border E2(t=0. 30: Domain with U-shape channel Figure 5. y=a. } border Bot3(t=0.5)). y=0.5) { x=(1-d)*c*cos(st(t)). } border Bot2(t=0. c=0. y=-a.2*c) { x=-b/2-c+t.31: Domain with V-shape cut changed by d changed by dAg } border border border border C1(t=-0.2*a) { x=b. y=-a. } border Top2(t=0. // Fig. } border Load(t=0.c b ) ( tip .eps".-0. y=-a. } border Bot1(t=0. y=a-t.2*pi) { x=0.b/2-c) { x=b/2+c+t.ps="SmileFace. y=-a.1) { x=(1-d*t)*c*cos(st(-0. y=(1-d*t)*c*sin(st(-0. } mesh Th=buildmesh(F(10*m)+C1(2*m)+C2(3)+C3(2*m)+C4(3) +C0(m)+E1(-2*m)+E2(-2*m)). } border Top1(t=0.5.8.b-c) { x=-c-t.} C3(t=0.16 (3point bending) Square for Three-Point Bend Specimens fixed on Fix1. real a=1.d ) R T 109 I A C  + I A C Figure 5.d ) C 2 ( tip .5. y=-a.b-2*c) { x=-b/2+c+t.1){x=((1-d)+d*t)*c*cos(st(0.1*cos(t). } border Right(t=0. MESHING EXAMPLES (-c a . Fix2 // It will be loaded on Load.1*sin(t).5. plot(Th. m=b*n. y=a.5) { x=c*cos(st(t)). y=(1-d)*c*sin(st(t)).c b ) L 1 C 1 C 3 L 2 B (c a . } border Fix1(t=0.bw=1).1. b=5.32 Example 5.0.eps". } C4(t=0. } // see Fig..5)). plot(Th. } C2(t=0.5)). } border Fix2(t=0.y=((1-d)+d*t)*c*sin(st(0. y=a. int n=5.2*c) { x=c-t.} border C0(t=0. y=c*sin(st(t)).2*c) { x=b/2-c+t. y=-a+t.33 // .2*a) { x=-b.ps="ThreePoint. } mesh Th = buildmesh(Left(n)+Bot1(m/4)+Fix1(5)+Bot2(m/2)+Fix2(5)+Bot3(m/4) +Right(n)+Top1(m/2)+Load(10)+Top2(m/2)).b-c) { x=b-t.b/2-c) { x=-b+t.5)). border Left(t=0. 5.bw=1). 5. 33: Domain for three-point bending test Figure 5.edp) (5. .0]. Onl . N where nl is the number (label or region) that we want to change.label=r1). These vectors are composed of nl successive pair of number O.1. 6: plot(Th1.1.32: Smiling face (Mouth is changeable) 5.label=r2).-a ) B o t2 F ix 1 F ix 2 Figure 5. // ‘‘gluing together’’ of meshes Th1 and Th2 11: cout << " nb lab = " << int1d(Th1..10).4) 1: 2: mesh Th1=square(10. 10: mesh Th=Th1+Th2.3)(1. Nnl ] An example of using this function is given in ”glumesh2D. 9: Th2=change(Th2.17 (glumesh2D. 7: Th1=change(Th1. ....y]). region = is a vector of integer that contains successive pair of the old region number to new region number.wait=1). // Change the label of Edges of Th2 with label 4 in 0. +  + (-b .10. Nnl ] region = [O1 .110 CHAPTER 5.3) (5. 4: verbosity=3.. . N1 . MESH GENERATION .edp”: Example 5.4)(1./lenEdge) .. + " . Onl . 5: int[int] r1=[2. 8: plot(Th1.9 How to change the label of elements and border elements of a mesh Changing the label of elements and border elements will be done using the keyword change.wait=1).3. N1 . The parameters for this command line are for a two dimensional and dimensional case: label = is a vector of integer that contains successive pair of the old label number to the new label number .[x+1. // Change the label of Edges of Th1 with label 2 in 0.a ) L e ft T o p 2 B o t1 L o a d T o p 1 R ig h t B o t3 (b .0]. r2=[4.2. 3: mesh Th2=square(20. we have label = [O1 . For example./lenEdge)+int1d(Th2. .mesh. j = 1.wait=1). (nt ri)1 (ntet )2 12 22 .msh The structure of the files with extension . region label region label . ./lenEdge) <<" == " << ((10+20)+10)*2 << endl. n qx v 11 21 . n qz v 13 23 . .msh and . q k2 . MESH IN THREE DIMENSIONS 111 12: << " == " << int1d(Th.2: The structure of mesh file format “. q k4 . (ntet )1 11 21 . 14: fespace Vh(Th. ntet the number of tetrahedra and i i i ntri the number of triangles For each vertex q i . q j3 .2. ntet 1 qy 2 qy . 13: plot(Th. . // definition of a macro 16: Vh u. The method implemented need that the point in adjacent mesh are the same. boundary label Table 5. ntri 1 qz 2 qz . . the method to “gluing” different mesh of the same dimension in FreeFem++ is using.1. the file mesh format supported for input and output files by FreeFem++ are the extension . .wait=1). qz ) the x-coordinate. . k = 1.v)=int2d(Th)(Grad(u)’*Grad(v))-int2d(Th)(v)+on(1.5. i = 1. .P1). . nv 1 qx 2 qx . The boundary consists of an union of triangles. extension file . . Each tetrahedra Tk . Vertex label Vertex label . · · · . · · · .4)(1. These formats are described in the chapter on Mesh Files in two dimensions. In this structure. . Each triangle bej . nv .10.2. . q k3 . ntet has four vertices q k1 . . .3.dy(u)]. . . · · · .u=0).10.10 5. .msh in 3D is given in Table 5. 15: macro Grad(u) [dx(u). “gluing” different mesh In line 10 of previous file.1 Mesh in three dimensions Read/Write Statements for a Mesh in 3D In three dimensions. . .msh” in three dimensions. . . we denote by (qx . . (ntri )3 (ntet )4 region label boundary label boundary label . . 17: solve P(u. .v. qy . 18: plot(u. n qy v 12 22 . the y-coordinate and the z-coordinate.3. . . q j2 . Vertex label 14 24 . nv denotes the number of vertices. This function is just called using the symbol addition ”+” between meshes. . ntri has three vertices q j1 . (ntri )2 (ntet )3 13 23 . 5. The launch of Tetgen is done with the keyword tetg. A theoretical bounds of this ratio of the algorithm of Shewchuk is obtained for a given complex of vertices. In TetGen. This tetrahedralization is a constrained Delaunay tetrahedralization.4 ) .11) ).3). xh . · · · . .1 [36] for more details). constrained segments and facets of surface mesh. zi is the associated point with the ith 1 2 i hole. y1 . This string corresponds to the command line switch of Tetgen see Section 3.112 CHAPTER 5. · · · . y−coordinate and z−coordinate of a point inside this domain (xi . The quality measure of this algorithm is the Radius-Edge Ratio (see Section 1. mvol1 . The parameters of this command line is: label = is a vector of integer that contains the old labels number at index 2i and the new labels number at index 2i + 1 of Triangles.mesh The data structure for a three dimensional mesh is composed of the data structure presented in Section 12. where xh . j=1. z2 . z1 . The input domain take into account a polyhedral or a piecewise linear complex. h h h h h h This vector is xh . each hole is associated with a point inside this domain.1.0. nboffacetcl= Number of facets constraints size of facetcl/2 (version 3. (I) Ref φtet i . TetGen is a free for research and non-commercial uses.3. This theoretical bounds is 2.11) ).10. at2 . with no input angle less than 90 degree. nbofregions = Number of regions (size of regionlist/5 (version 3. MESH GENERATION extension file .1 and a data structure for tetrahedra. The regionlist vector is: x1 . i=1 . A real vector of size 3 × nbofholes. nbofholes= Number of holes (default value size of holelist/3 (version 3. The tetrahedra of a three dimensional mesh are refereed using the following field: • Tetrahedra (I) NbOfTetrahedrons ( ( @@Vertexji . y1 . Hang Si of Weierstrass Institute for Applied Analysis and Stochastics of Berlin in Germany [36]. switch = A string expression. This software is a tetrahedral mesh generator of a three dimensional domain defined by its boundary. The attribute and the volume constraint of region are given in this real vector of size 5 × nbofregions. zi ). The ith region is described by five elements: x−coordinate. regionlist = This array corresponds to regionlist of tetgenio data structure [36]. yi . a commercial licence is available upon request to Hang Si. z2 .2 TeGen: A tetrahedral mesh generator TetGen TetGen is a software developed by Dr.11) ). yi . The method used in TetGen to control the quality of the mesh is a Delaunay refinement due to Shewchuk [37]. This parameters is initialized as label for the keyword change (5. holelist = This array correspond to holelist of tetgenio data structure [36]. y2 . z1 .2 of [36]. For any commercial licence utilization. mvol2 . at1 . the attribute (ati ) and the maximum volume for tetrahedra (mvoli ) for this region. y2 . x2 . 5. NbOfTetrahedrons ) This field is express with the notation of Section 12. y). V Give information of the work of TetGen. CC The consistency of the result’s mesh is testing by TetGen and also checks constrained delaunay mesh (if ’p’ switch is selected) or the consistency of Conformal Delaunay (if ’q’ switch is selected). Φ3(x. YY This switch allow to preserve the mesh on the exterior and interior boundary.10. The default value is 1e − 8. a Construct with the volumes constraints on tetrahedra.5. d Itersections of facets are detected. This switch work with the option ’p’. This switch must be used to ensure conformal mesh between two adjacents mesh. These volumes constraints are defined with the bound of the previous switch q or in the parameter regionlist. This corresponding to move the domain by a displacement vector of this form Φ(x. This parameters 1 2 i has no effect if switch q is not selected. Φ2(x.Φ3]). A Attributes reference to region given in the regionlist. We give now the command line in FreeFem++ to construct these meshes. The facetcl array is: Ref1 c . C The consistency of the result’s mesh is testing by TetGen. By default.transfo=[Φ1. this value is 2. The ith facet constraint is defined by the facet marker Refif c and the maximum area for faces f f mareaf c . The option AA gives a different label at each region. The parameters of this command line are: . mareaf c . Principal switch parameters in TetGen: p Tetrahedralization of boundary. MESH IN THREE DIMENSIONS 113 facetcl= This array corresponds to facetconstraintlist of tetgenio data structure [36]. we need the surface mesh of three dimensional domain. r Reconstructs and Refines a previously generated mesh. · · · . y)). More information can be obtained in specified ’VV’ or ’VVV’. Ref2 c . If option ’r’ is used. Q Quiet: No terminal output except errors M The coplanar facets are not merging. q Quality mesh generation. The other regions have label 0. this switch has no effect. The result of moving a two dimensional mesh Th2 by this three dimensional displacement is obtained using: mesh3 Th3 = movemesh23(Th2. T Set a tolerance for coplanar test. To obtain a tetrahedral mesh generator with tetgen. keyword: “movemesh23” A simple method to construct a surface is to place a two dimensional domain in a three dimensional space. mareaf c . The bound of Radius-Edge Ratio will be given after the option q. y). y) = (Φ1(x.0. Y This switch allow to preserve the mesh on the exterior boundary.Φ2. This character is only used with the command line tetgreconstruction. .transfo=[XX2.y0+(y1-y0)*y]). Φ3(x label = set integer label of triangles orientation= set integer orientation of mesh. x1=2. x0=1. // /////////////////////////////// x0=0.edp. func XX3max = 2. some points can be merged. y).. YY1 = y.5.YY1.[x0+(x1-x0)*x. mesh3 Th32h = movemesh23(Thsq2..YY2min. func ZZ3 = y.8. y0=0. When you transform a mesh.. mesh3 Th31b = movemesh23(Thsq1.18 (tetgencube. Example 5.5. YY2max = 2*pi. ZZ1max = 1.ZZ1min]).YY1. where B is the smallest axis parallel boxes containing the discretized domain of Ω and V ol(B) is the volume of this box. y1=2*pi.9. MESH GENERATION transfo = [Φ1. func func func func ZZ2 = y. x1=2. mesh Thsq3 = square(35. y). mesh Thsq1 = square(5..x1.[x0+(x1-x0)*x.5.. func YY3 = x. ptmerge = A real expression.transfo=[XX1. Φ2(x. y) = [Φ1(x. This parameters is the criteria to define two merging points.edp mesh3 Th31h = movemesh23(Thsq1. By default.. XX1 = x.ZZ1max]).transfo=[XX1.ZZ2]). We can ‘do a ‘gluing” of surface meshes using the process given in Section 5. Φ2..y1. An example to obtain a three dimensional mesh using the command line tetg and movemesh23 is given in the file tetgencube..YY2max. // /////////////////////////////// x0=1.8. x1=2*pi. . func XX3min = 1. func func func func ZZ1min = 0.y0.y0+(y1-y0)*y]).y0+(y1-y0)*y]).transfo=[XX2. y0=0. XX2 = x.ZZ2]). file tetgencube. y0=0. mesh Thsq2 = square(5. Φ3] set the displacement vector of transformation Φ(x.35.[x0+(x1-x0)*x.114 CHAPTER 5. y1=1. mesh3 Th32b = movemesh23(Thsq2..edp) // load "msh3" load "tetgen" real x0. YY2min = 0. y1=1. we use ptmerge = 1e − 7 V ol(B).. . Φ3] ). . MESH IN THREE DIMENSIONS 115 mesh3 Th33h = movemesh23(Thsq3.mv2y.regionlist=domain). znv .mesh"). // build a mesh of a half cylindrical shell of interior radius 1. func mv2y = x*sin(y). Remark: To use tetgtransfo. the parameter regionlist is defined for one region. zi ). The keyword “tetgtransfo” This keyword correspond to a composition of command line tetg and movemesh23: tetgtransfo( Th2. // Tetrahelize the interior of the cube with tetgen savemesh(Thfinal. . This tetrahedralization is a Delaunay mesh of the convex hull of the set of points.75.transfo=[XX3min.ZZ3]). · · · ). Therefore. The parameters of this command line are on the one hand the parameters: label. ynv z1 z2 ."halfcylindricalshell. // "gluing" surface meshs to obtain the surface of cube savemesh(Th33.edp” The keyword ”tetgconvexhull” FreeFem++ .mesh").switch="paAAQY". // build a mesh of a axis parallel box with TetGen real[int] domain =[1. where Th3surf = movemesh23( Th2. .YY3.0. is able to build a tetrahedralization from a set of points. transfo=[mv2x. Φ3] ) and Th2 is the input two dimensional mesh of tetgtransfo. mesh3 Thfinal = tetg(Th33. The coordinates of the points can be initialized in two ways. switch. yi . Φ2. transfo= [Φ1.pi."Th33.5 func mv2x = x*cos(y).YY3. mesh3 Thmv2 = movemesh3(Thfinal. regionlist nboffacetcl facetcl of keyword tetg and on the other hand the parameter ptmerge of keyword movemesh23. exterior radius 2 and heigh 1. func mv2z = z. xnv y1 y2 .tranfo=[Φ1. // ////////////////////////////// mesh3 Th33 = Th31h+Th31b+Th32h+Th32b+Th33h+Th33b.0. Φ2.145. the result’s mesh of movemesh23 must be an closed surface and define one region only. This files is organized as follows: nv x1 x2 . An example of this keyword can be found in line of file “buildlayers.transfo=[XX3max. .mv2z]).10. . mesh3 Th33b = movemesh23(Thsq3. using tetgen.0025].5. The first is a file that contains the coordinate of points Xi = (xi . · · · ) = tetg( Th3surf. savemesh(Thmv2.ZZ3]).mesh") and The command movemesh is describe in the following section."Thfinal.5. Example: Example 5. we can’t used the option ’p’ and ’q’ of tetgen. func f3 = sin(x). f rac−pi2[×]0.3 Reconstruct/Refine a three dimensional mesh with TetGen Meshes in three dimension can be refined using TetGen with the command line tetgreconstruction. In the string switch. y−coordinates and z−coordinates. f1y=-cos(x)*sin(y).10. This parameter and nbofregions can’t be used with parameter sizevolume. regionlist. nboffacetcl and facetcl of the command line which call TetGen (tetg) is used for tetgrefine.116 CHAPTER 5. func f2 =cos(x)*sin(y). 5.2 of [36]. partiel derivative of the parametrization DF // ] −pi . This string corresponds to the command line switch of TetGen see Section 3. This function allows to constraint volume size of tetrahedra in the domain.edp . MESH GENERATION The second way is to give three arrays that correspond respectively to the x−coordinates. label= an integer array that allow to change the label of boundary triangles. f3x=cos(x). In the parameter switch=.edp) load "msh3" load "tetgen" load "medit" mesh Th=square(10. The parameters of this command line are switch = A string expression. sizevolume= a reel function.20. f2x=-sin(x)*sin(y). The label in the regionlist will be the previous label of region. the character ’r’ should be used without the character ’p’. f2y=cos(x)*cos(y). The parameter regionlist allows to define a new volume constraint in the region. 2π[ 2 a parametrization of a sphere // file refinesphere.[x*pi-pi/2.2*y*pi]).31 to build 3d adapt mesh ) The parameter switch nbofregions. The parameter of this keyword are region= an integer array that allow to change the region number of tetrahedra. reftet = An integer expression. label = An integer expression.19 (refinesphere. // func f1 =cos(x)*cos(y). (see example 5. // func func func func func f1x=sin(x)*cos(y). set the label of tetrahedra. This array is defined as the parameter reftet in the keyword change. set the label of triangles. For instance. see the manual of TetGen [36] for effect of ’r’ to other character. This array is defined as the parameter label in the keyword change. y.18]. medit(‘‘isotroperefine’’ . // func m11=f1xˆ2+f2xˆ2+f3xˆ2.5)ˆ2+(y-0.IsMetric=1. Th=adaptmesh(Th.. transfo=[Φ1.periodic=perio).switch="paAAQYY".0. . medit(‘‘sphere’’. y.0.[2. Φ3(x.regionlist=domain.. int[int] newlabel2 = [145. 117 M = DF t DF construction of the surface of spheres mesh3 Th3=movemesh23(Th..5.Th3sphrefine).x]. y) = (Φ1(x.10. z).[1.53].. y.01].y].transfo=[f1min.wait=1). Φ2. ).0.Th3sph). Φ3].y]. verbosity=2. nbofregions=1.. real hh=0.m21*vv.periodic=perio).m22*vv. y. The parameters of movemesh in three dimensions are transfo = [Φ1.IsMetric=1.[3. plot(Th. medit(‘‘anisotroperefine’’.switch="raAQ".5)ˆ2) )ˆ3).switch="raAQ". func fsize = 0. Th=adaptmesh(Th. If Ω is tetrahedrized as Th (Ω).m11*vv. real[int] domain = [0. mesh3 Th3sph=tetg(Th3. verbosity=2. func m22=f1yˆ2+f2yˆ2+f3yˆ2. sizeofvolume=fsize). MESH IN THREE DIMENSIONS func f3y=0.m21*vv.nbofregions=1. int[int] newlabel = [145. Rmin*f2. z). z).0.m22*vv.1.reftet=newlabel2. z). Φ3] set the displacement vector of 3D transformation [Φ1(x.f2min.5)ˆ2+(z-0.10.4 Moving mesh in three dimensions Meshes in three dimensions can be translated rotated and deformed using the command line movemesh as in the 2D case (see section movemesh in chapiter 5). Rmin*f1. z)) is a displacement vector then Φ(Th ) is obtained by mesh3 Th = movemesh( Th. real[int] domainrefine = [0.. // real func func func Rmin f1min f2min f3min = = = = 1. Φ1(x.reftet=newlabel. Rmin*f3.0. real vv= 1/square(hh).Th3sphrefine2).145. y.. mesh3 Th3sphrefine2=tetgreconstruction(Th3sph.0.f3min]).Φ2.m11*vv. func m21=f1x*f1y+f2x*f2y+f3x*f3y. Φ3(x.x]].145.. func perio=[[4.0001].0001).regionlist=domain). 5. y.. mesh3 Th3sphrefine=tetgreconstruction(Th3sph. z .refinesizeofvolume=0. Φ2(x. and Φ(x.01/(( 1 + 5*sqrt( (x-0. By default. we introduce the number of associated vertices in the z−axis Mi + 1. Mi = M then there are M layers in the mesh of Ω3d ). . Otherwise equals to zero. 3d Vi. 0 by default.10. This mesh is obtained by extending a two dimensional mesh in the z-axis. We denote by M the maximum of Mi over the vertices of the two dimensional mesh. we use ptmerge = 1e − 7 V ol(B). For a vertex of a two dimensional mesh Vi2d = (xi . ptmerge = A real expression. By default. This parameters is initialized as label for the keyword change (5. . label = set the label of faces of border. M. zmax(Vi2d )]: zi.3). zmin and zmax are function of Ω2d in R that defines respectively the lower surface and upper surface of Ω3d .34: Example of Layer mesh in three dimension.M are the M + 1 equidistant points on the interval [zmin(Vi2d ). region = set integer label of tetrahedra.edp” located in the directory examples++-3d. . When you transform a mesh. MESH GENERATION Middle surface Lower surface Figure 5. yi . where (zi. An example of this command can be found in the file ”Poisson3d. Vi2d generated M + 1 vertices which are defined by ∀j = 0. zmax] where Ω2d is the domain define by the two dimensional mesh.5 Layer mesh In this section..j = j δα + zmin(Vi2d ). δα = zmax(Vi2d ) − zmin(Vi2d ) . .. some faces can be merged. The domain Ω3d defined by the layer mesh is equal to Ω3d = Ω2d × [zmin. this parameter is equals to 1. M .118 upper surface CHAPTER 5. This parameters equals to one if merge’s faces is considered. This parameters is the criteria to define two merging points.j = (xi . where B is the smallest axis parallel boxes containing the discretion domain of Ω and V ol(B) is the volume of this box. When you transform a mesh.. 5.j )j=0. θi (zi..j )). some points can be merged. yi ). This value are called the number of layers (if ∀i. facemerge = An integer expression. we present the command line to obtain a Layer mesh: buildlayermesh. Vi2. M.0 )). The arguments of buildlayermesh is a two dimensional mesh and the number of layers M . Vi2.. These tetrahedra are obtained by cutting the quadrilateral face of pyramid and prism with the diagonal which have the vertex with the maximum index (see [8] for the reaspn of this choice).3). 119 with (θi. .M . θi. coef = A function expression between [0. Vi3. like (5. Vi3. The parameters of this command are: zbound = [zmin. Theses volume elements can have some merged point: • 0 merged point : prism • 1 merged points : pyramid • 2 merged points : tetrahedra • 3 merged points : no elements The elements with merged points are called degenerate elements.0 .10. The triangles on the middle surface obtained with the decomposition of the volume prismatic elements are the triangles generated by the edges on the border of the two dimensional mesh. .j .j . become the labelmid = This vector is used to initialized the 3d labels number of the vertical face or mid face form the 2d label number. is given by θi (z) = θi.M ) (resp.j+1 . Vi3. . Vi2 . region = This vector is used to initialized the region of tetrahedra. 3d 3d 3d (Vi1.0 if z = zmin(Vi2d ). This vector contains successive pair of the 2d label number at index 2i and the corresponding 3d label number at index 2i + 1.j ]. like (5. 2d 2d 2d Set a triangle K = (Vi1 . zmax(Vi2d )].j .3).j−1 . This vector contain successive pair of the 2d region number at index 2i and the corresponding 3d region number at index 2i + 1. Also K is associated with M volume prismatic elements which are defined by ∀j = 0. 3d 3d 3d 3d 3d 3d Hj = (Vi1. Vi2. Vi3.3).j+1 ). zmax(Vi2d )].Mi are the Mi + 1 equidistant points on the interval [zmin(Vi2d ).. defined on [zmin(Vi2d ).j if z ∈]θi.M . θi. like (5. This parameter is used to introduce degenerate element in mesh. This vector contains successive pair of the 2d region number at index 2i and the corresponding 3d label number at index 2i + 1. MESH IN THREE DIMENSIONS The function θi . The label of triangles on the border elements and tetrahedra are defined with the label of these associated elements. .5.j )j=0. Vi1. Vi2. labelup = This vector is used to initialized the 3d label numbers of the upper/top face form the 2d region number.j+1 .0 . on the lower surface) of layer mesh: (Vi1. K is associated with a trian3d 3d 3d gle on the upper surface (resp.zmax] where zmin and zmax are functions expression.. Theses functions define the lower surface mesh and upper mesh of surface mesh. Vi3 ) of the two dimensional mesh.. .1]. The number of associated points or vertex Vi2d is the integer part of coef (Vi2d )M . we decompose the pyramid into two tetrahedra and the prism into three tetrahedra. To obtain a mesh with tetrahedra. MESH GENERATION labeldown = Same as the previous case but for the lower/down face label . border Taxe(t=0. .real[int.[5. the number of step in each direction // bounding box // the label of the 6 face // front.1). // real [int. real x0=BB(0.ny.1). Moreover. mesh3 Th=buildlayers(Thx.6]].[x0+(x1-x0)*x.1).10]. right // see figure 5.[0.y=t.ny=NN[1]. we also add post processing parameters that allow to moving the mesh.int] &BB .0){x=HH*t. back.4].label=0. mesh Thx = square(nx. real z0=BB(2.L(2.z1=BB(2. rdown=[0.1). labelmid. medit("Th".1]].y0+(y1-y0)*y]).0)].1].1].[3.y1=BB(1. left. The vector region.int[int.y=0.edp) load "msh3" load "medit" // cone using buildlayers with a triangle real RR=1.nz.idp) load "medit" load "msh3" func mesh3 Cube(int[int] & NN. facemerge and ptmerge of the command line movemesh. labelup = rup. mesh Th2=buildmesh( Taxe(HH*nn)+ Hypo(sqrt(HH*HH+RR*RR)*nn) + Vert(RR*nn) ) .HH=1. rmid=[1.z1]. 4.20 (cube.}.120 CHAPTER 5. border Hypo(t=1. int nn=10.2].35 The cone example (an axisymtric mesh on a triangle with degenerateness)./nn.}. Nl where nl is the number (label or region) that we want to get.1). 3.nz=NN[2].L(0.edp.L(2.1)].21 (cone. real h= 1.Th).0).10.idp" int[int] NN=[10. zbound=[z0.BB. These parameters correspond to parameters transfo. return Th. int nx=NN[0].label=2.int] & L) { // first build the 6 faces of the hex. labelmid=rmid. int [int. int[int] rup=[0.HH){x=t. 2. } The unit cube example: include "Cube.RR){x=HH.int] BB=[[0. L(1. An example of this command line is given in buildlayermesh.0) ].int] L=[[1.0). Example 5. real y0=BB(1.y=RR*t.0).label=1.}.[0. labeldown = rdown). Example 5.right. mesh3 Th=Cube(NN.0). border Vert(t=0.L).x1=BB(0.L(1. L(0. down. labelup and labeldown These vectors are composed of nl successive pairs of number Oi . 2. // see figure 5.transfo=[fx.01. C2=98.0. func fz= x. MESH IN THREE DIMENSIONS plot(Th2. int MaxLayersT=(int(2*pi*RR/h)/4)*4. func fy= y*sin(z).22 (buildlayermesh. r4T=[0.edp Example 5. real zminT = 0.2].y/max(x/HH.0.10.5. facemerge=0. r2T=[0.edp) // load "msh3" load "tetgen" file buildlayermesh. // the function defined the proportion // of number layer close to axis with reference MaxLayersT mesh3 Th3T=buildlayers(Th2.Th3T). MaxLayersT.36 Figure 5. // // 121 the 2d mesh number of layers // height 2 ∗ pi // trick function: func deg= max(. zmaxT = 2*pi. medit("cone".zmaxT].fy.2]. labelmid=r2T).36: the mesh of a cone made with cube.0].edp // int C1=99. func fx= y*cos(z). int[int] r1T=[0. // Test 1 could be anything .4) /RR).edp cone.wait=1).35: the mesh of a cube made with Figure 5.fz]. region=r1T. zbound=[zminT.coef= deg. label=1. MaxLayer. func XX = x*cos(y).transfo=[XX1.nbofregions=1. func YY1 = sin(y)*sin(x).2){ x=2.7){ x=0.} C11(t=0. label=C2.2*pi){ x=pi.zmax].2-t. C23(t=0. int[int] r3=[4.41].3. // The triangles of uppper surface // generated by the triangle in the 2D region of mesh Th of label label 12.pi){ x=t. y=2."sphere2region. labelmid=r2. regionlist=domain).98.7){ x=3-t. y=2.45].3+t.99. savemesh(Th3.ZZ1].2. label=1. int MaxLayer=10. label=C1.2){ x=0. 99. 1. y=2*pi-t. mesh 4 as mesh 4 as mesh3 Th3=buildlayers( Th.2){ x=3.} C02(t=0. func ZZ = z. label=C1.} C04(t=0. label=C2.} y=4. r2=[98. . labeldown = r4 ).} C13(t=0. label=C1. y=2*pi. y=t.0.} C14(t=0.5.12]. cout << "test=" << test << endl. region=r1.122 border border border border border border border border border border border border CHAPTER 5. C22(t=0. label=C1. y=2. label=C2.} C12(t=0. label=1.} mesh Th=buildmesh( C01(10)+C02(10)+ C03(10)+C04(10) + C11(5)+C12(5)+C13(5)+C14(5) + C21(-5)+C22(-5)+C23(-5)+C24(-5)).mesh").5+t.YY1. zbound=[zmin.7){ x= 2.56]. func zmax=1. // construction of a sphere with TetGen func XX1 = cos(y)*sin(x). labelup = r3. func ZZ1 = cos(x).5-t.2*pi){ x=0. savemesh(Th3sph.switch=test.pi){ x=pi-t. C01(10)+C02(10)+ C03(10)+C04(10) + C11(5)+C12(5)+C13(5)+C14(5) ).5.5.5+t. y=0.5+t."box2region1hole.} y=2.} C03(t=0.. y=4.5.. mesh3 Th3sph=tetgtransfo(Ths.5. // construction of a box with one hole and two regions mesh Ths=buildmesh( func zmin=0. MESH GENERATION C01(t=0.} y=4. int[int] r4=[4. func YY = x*sin(y). y=4.2){ x=1. label=1.mesh").0.0. C24(t=0. int[int] r1=[0. // The triangles of lower surface // generated by the triangle in the 2D region of mesh Th of label label 45. label=C2.0. string test="paACQ".5-t.7){ x=1.} C21(t=0. label=1.p2. mesh3 Th = buildlayers(Th2.uy.m11*vv.[3. f3y=0.periodic=perio).1. func m22=f1yˆ2+f2yˆ2+f3yˆ2.m11*vv. func zmin = 2-sqrt(4-(x*x+y*y)).nn.edp) // file ”lac.x].meshb’’).3.m22*vv. border cc(t=0. f2x=-sin(x)*sin(y).IsMetric=1.2*y*pi]). f2y=cos(x)*cos(y).edp” load ‘‘msh3’’ int nn=5. func f3 = sin(x).y]. MESHING EXAMPLES 123 5.P2). // file ‘‘tetgenholeregion. verbosity=2. Th=adaptmesh(Th.periodic=perio).} mesh Th2 = buildmesh(cc(100)). int[int] rup=[0. Vh2 ux.24 (tetgenholeregion.4. rdlow=[0.[x*pi-pi/2.edp’’ // func f1 =cos(x)*cos(y).1]. labelmid=rmid.meshb’’). M = DF t DF . Example 5.1. f3x=cos(x). Th=adaptmesh(Th. func f2 =cos(x)*sin(y).11 Meshing examples Example 5. plot(Th. rmid=[1.1.11.m21*vv.2. exec(‘‘medit Th. 1. real hh=0.2].1].5. func perio=[[4.23 (lac. coeff = max((zmax-zmin)/zmax.20. func m21=f1x*f1y+f2x*f2y+f3x*f3y. Th. savemesh(Th.y=sin(t).m21*vv.[1. −pi [×]0. labeldown=rlow).’’Th. 2π[ 2 2 a parametrization of a sphere partiel derivative of the parametrization DF // func m11=f1xˆ2+f2xˆ2+f3xˆ2.[2. // func func func func func func f1x=sin(x)*cos(y).IsMetric=1.2*pi){x=cos(t). zbound=[zmin. // ] −pi . verbosity=2.edp) load "msh3’’ load "tetgen" mesh Th=square(10. f1y=-cos(x)*sin(y). fespace Vh2(Th2.x]]. func zmax = 2-sqrt(3.1. labelup=rup.y].m22*vv./nn).wait=1).). real vv= 1/square(hh).zmax]. f3min]).001].124 CHAPTER 5.transfo=[f1max. mesh3 Th3finhole=tetg(Th3.0. mesh3 Th3 = Th3sph+Th3sph2.0.. Rmin*f3. func mesh3 SurfaceHex(int[int] & N. cout << "=============================" << endl. cout << " tetgen call with hole " << endl.nbofregions=2.z0+(z1-z0)*y]).0.transfo=[f1min..f3max]). Rmax*f2.1).mesh"). cout << "addition" << endl.53. cout << "=============================" << endl.1). cout << "=============================" << endl. real[int] domain2 = [1. cout << "finish tetgen call with hole " << endl.0). construction of the surface of spheres mesh3 Th3sph = movemesh23(Th. mesh3 Th3fin = tetg(Th3.]..ny=N[1].1 Build a 3d mesh of a cube with a balloon First the MeshSurface.x1=B(0. cout << " tetgen call without hole " << endl..idp file to build boundary mesh of a Hexaedra and of a Sphere.switch="paAAQYY".nbofholes=1."spherewithtworegion.0.int orientation) { real x0=B(0.001.regionlist=domain).0.5. cout << "finish tetgen call without hole" << endl.mesh")."spherewithahole.. real[int] hole = [0.0.regionlist=domain2). MESH GENERATION // real func func func Rmin f1min f2min f3min = = = = 1.[y0+(y1-y0)*x.5.0.0). cout << "==============================" << endl..nz.f2min.0.switch="paAAQYY".18.145. . savemesh(Th3finhole.holelist=hole. real z0=B(2. real y0=B(1.0. mesh Thx = square(ny. cout << "=============================" << endl. nbofregions=1..real[int.0.0. mesh3 Th3sph2 = movemesh23(Th. real[int] domain = [1.y1=B(1. Rmin*f1. cout << "=============================" << endl.11. 5.0).z1=B(2. Rmax*f3.. Rmax*f1.int[int.0.int] &B . real func func func Rmax f1max f2max f3max = = = = 2. int nx=N[0].001]. savemesh(Th3fin.int] & L.. cout << "==============================" << endl.f2max.. Rmin*f2.5. cout << "=============================" << endl.nz=N[2].1). m21*vv.y.1)].z1].L(0.periodic=perio).refZ=[0.y]. renumbering // // // 125 Xmin.IsMetric=1.z0].m22*vv. func f2x=-sin(x)*sin(y). func m22=f1yˆ2+f2yˆ2+f3yˆ2.11.IsMetric=1.transfo=[x.5. int[int] ref=[0. MESHING EXAMPLES mesh Thy = square(nx.m11*vv.1)].y1. // partiel derivative func f1x=sin(x)*cos(y). 2π[ 2 // a parametrization of a sphere func f1 =cos(x)*cos(y). // ] −pi .y].[x0+(x1-x0)*x.label=refX).orientation=+orientation.y. Zmax faces labels mesh3 Thx0 = movemesh23(Thx.x.y].[2.orientation=+orientation.y0+(y1-y0)*y]).orientation=-orientation. mesh3 Thy1 = movemesh23(Thy.m21*vv. func f3 = sin(x).0)].m11*vv.y].transfo=[x0.nz. Th=adaptmesh(Th. mesh3 Thx1 = movemesh23(Thx. Th=adaptmesh(Th.ny. f rac−pi2[×]0. renumbering int[int] refy=[0.refface=ref return ThS.orientation=-orientation.label=refY). func perio=[[4.int orientation) { mesh Th=square(10. func f2 =cos(x)*sin(y).label=refy).y0.[1. Ymax faces labesl Zmin.transfo=[x.transfo=[x.m11*vv.L(0. func m21=f1x*f1y+f2x*f2y+f3x*f3y.[x0+(x1-x0)*x. mesh3 Th= Thx0+Thx1+Thy0+Thy1+Thz0+Thz1.refX=[0. } func mesh3 Sphere(real R.m11*vv.L(2. func f3x=cos(x).IsMetric=1.1)].periodic=perio).y].label=refx). Th=adaptmesh(Th.L(2. func f3y=0.transfo=[x.[3. // the metric on the sphere M = DF t DF func m11=f1xˆ2+f2xˆ2+f3xˆ2. mesh3 Thy0 = movemesh23(Thy. Ymax faces labels Ymin.f3*R].L(1.periodic=perio).transfo=[x1.0)].real h.2*y*pi]). return Th.periodic=perio).orientation=+orientation.orientation=orientation.m21*vv. mesh3 Thz0 = movemesh23(Thz.x]].m21*vv.x.m22*vv.20. int[int] refx=[0.IsMetric=1.int L.orientation=-orientation.m22*vv. Th=adaptmesh(Th. renumbering int[int] refz=[0. } The test of the two functions and the call to tetgen mesh generator .y].L(1. func f1y=-cos(x)*sin(y).[x*pi-pi/2.m22*vv. mesh3 Thz1 = movemesh23(Thz.label=refz). func f2y=cos(x)*cos(y).0)].f2*R. mesh Thz = square(nx.x].label=refZ). // hh mesh size on unite sphere real vv= 1/square(hh). mesh3 ThS= movemesh23(Th.L].z0+(z1-z0)*y]).transfo=[f1*R.refY=[0. // to store the periodic condition real hh=h/R. 7.rm Hex-Sphere.7.20].2].38 Figure 5.1]. a vector fields.[3.0. savemesh(ThHS.hs. a symmetric tensor and a symmetric FE tensor. // see 5.37: The surface mesh of the Hex Figure 5.nbofregions=2. real voltet=(hsˆ3)/6.Th).switch="pqaAAYYQ".1]].1).38: The tet mesh of the cube with with internal Sphere internal ball 5.0.0.int] L=[[1. // see 5. real[int] domaine = [0. mesh3 ThH = SurfaceHex(N. int[int] N=[20.L.solb With the keyword savesol.126 CHAPTER 5.voltet.B.[-1.4].idp" real hs = 0.2. cout << " voltet = " << voltet << endl.20.[5..0. we can store a scalar functions. exec("ffmedit Hex-Sphere.mesh.mesh").sol and . // boundary meshes // mesh size on sphere "gluing" surface meshs to tolat mesh3 ThHS=ThH+ThS. mesh3 ThS =Sphere(0.1. real [int. medit("Cube-With-Ball".regionlist=domaine).mesh")..1). int [int."Hex-Sphere. Such format is used in medit. MESH GENERATION load "tetgen" include "MeshSurface.1. .0.37 mesh3 Th = tetg(ThHS.1].[-1.voltet].12 The output solution formats .6]]. a vector FE fields.int] B=[[-1.5. a scalar FE functions. SolAtTriangles: number of triangles. The format . And finally. we give then in the next line the number of elements in the solutions (SolAtVertices: number of vertices. typesoln ∀k ∈ {1. – nbrealsolk = dim the solution k is vectorial (dim is the dimension of the solution).sol but in binary (read/write is faster. A real scalar functions f 1.12. SolAtQuadrilaterals. .. STyy An example of field with the keyword SolAtTetrahedra: • SolAtTetrahedra (I) NbOfTetrahedrons nbsol Uk . STzy . SolAtTetrahedra.SOLB extension file . STzx . THE OUTPUT SOLUTION FORMATS . This field is written with the notation of Section 12. the type of solution (1: scalar..5) at the vertices of the three dimensional mesh Th3 is stored in the file ”f1PhiTh3. – typesolk = 3 the solution k is a symmetric tensor or symmetric matrix.sol are respectively STxx . The real element of symmetric tensor   3d 3d 3d STxx STxy STxz 2d 2d STxx STxy 3d 3d 3d ST 3d =  STyx STyy STyz  ST 2d = (5. . is – typesolk = 1 the solution k is scalar. – nbrealsolk = dim ∗ (dim + 1)/2 the solution k is a symmetric tensor or symmetric matrix. we give the values of the solutions on the elements. SolAtTriangles. STyy .. we give the number of solutions . Φ2. STyx . .. – typesolk = 2 the solution k is vectorial.. ij where • nbsol is an integer equal to the number of solutions • typesolk . In other lines. STyx . 3: symmetric tensor)..solb is the same as format . In each field.. NbOfTetrahedrons} ∀i ∈ {1.SOL AND .). 2: vector.sol” using typesol1 .5.1. . STzz and STxx . • nbrealsolk number of real to discribe solution number k is – nbrealsolk = 1 the solution k is scalar... a vector fields Φ = [Φ1.5) 2d ST 2d STyx yy 3d ST 3d ST 3d STzx zy zz 3d 3d 3d 3d 3d 3d 2d 2d 2d stored in the extension .sol The first two lines of the file are • MeshVersionFormatted 0 • Dimension (I) dim 127 The following fields begin with one of the following keyword: SolAtVertices. type of the solution number k.. storage is less). SolAtEdges. SolAtHexahedra.. The file must be ended with the keyword End. nbrealsolk } . SolAtPentahedra.nbsol} ∀j ∈ {1. • Uk is a real equal to the value of the component i of the solution k at tetrahedra j on the ij associated mesh.. . Φ3] and a symmetric tensor ST 3d (5. we can vizualize in the same window the different domains in a domain decomposition method for instance. In the file. For a two dimensional mesh Th. Each solution is associated with one scene. Medit opens its own window and uses OpenGL extensively. MESH GENERATION savesol("f1PhiST3dTh3.Th. STzy . STyx . order=0). 2d 2d 2d where V V 2 = [STxx . solutions are stored in this order : scalar solutions. h1. 5. These arguments must be given in this order.sol". a mesh and solutions. vector solutions and finally symmetric tensor solutions. STyy ] The arguments of savesol functions are the name of a file. 1 is the solution is given at the vertices of elements. STzz ]. The parameters of this command line are order = 0 is the solution is given at the center of gravity of elements. By default. A vizualisation with medit of scalar solutions f 1 and f 2 continuous. [Ψ1. The nature of solutions must be the same. VV3.13 medit The keyword medit allows to dipslay a mesh alone or a mesh and one or several functions defined on the mesh using the Pascal Frey’s freeware medit. Hence. STyy .25 (meditddm. A real scalar functions f 2. Ψ2]. The parmameters of this keyword are order = 0 is the solution is given at the center of gravity of elements. a vector fields Ψ = [Ψ1.Th3. 1 is the solution is given at the vertices of elements.128 CHAPTER 5. piecewise linear and known at the vertices of the mesh Th is obtained using medit("sol1 sol2". f 1.solb” using savesol("f2PsiST2dTh3. This command line allows also to represent two differents meshes and solutions on them in the same windows.solb". h2. f 2. Ψ2] and a symmetric tensor ST 2d (5. order=1). save = set the name of a file . Naturally to use this command medit must be installed. STyx . Φ3]. f 1. VV2.edp .Th1.sol or . 3d 3d 3d 3d 3d 3d where V V 3 = [STxx . Φ2. A vizualisation with medit of scalar solutions h1 and h2 at vertices of the mesh Th1 and Th2 respectively are obtained using medit("sol2domain". order=1).solb to save solutions. this string is medit. The second plot names “sol2” display f2.5) at triangles is stored in the file ”f2PsiST2dTh3.edp) load "medit" // meditddm. STzx . [Φ1. The scalar. The first plot named “sol1” display f1. meditff = set the name of execute command of medit. a mesh and solutions.Th. Example 5. Th2. The arguments of function medit are the name of the differents scenes (separated by a space) of medit. vector and symmetric tensor solutions are specified in the format described in the section dealing with the keyword savesol. f 2. order=1). 5. // signe of pressure is correct .u1=1) .u1. func f1=10*sqrt(x*x+y*y).P2).int2d(Th)(f*v)+on(1.v1. y)|0.v2. y)|1 ≤ sqrt(x2 + y 2 ) ≥ 2} −∆u1 = f 1 on Ω1 = {(x.18).dy(u1)] construction of mesh of domain Ω1 construction of mesh of domain Ω // EOM // EOM problem Lap2dOmega1(u1.} u = 1 on Γ + Null Neumman condition on Γ1 and on Γ2 We find the solution u in solving two EDP defined on domain Ω and Ω1 // This solution is visualize with medit verbosity=3. func f=sqrt(x*x+y*y). // Resolution of EDP defined on the domain Ω1 // −∆u1 = f1 on Ω1 .Mh(Th.2*pi){x=cos(t). label=3. Example 5.Th1. border Gamma(t=0.P1). us = 1 on Γ1 .solb").int2d(Th1)(f1*v1)+on(1.init=false)=int2d(Th)(Grad2(v)’ *Grad2(us)) . macro Grad2(us) [dx(us). y=0. fespace Vh(Th.2*pi){x=2*cos(t). border Gamma1(t=0. ∂us = 0 on Γ2 ∂n Lap2dOmega.save="testsavemedit.v1. MEDIT 129 // // // // // Initial Problem: // Resolution of the following EDP: −∆us = f on Ω = {(x.}.}.us. real s0=clock().init=false)=int2d(Th1)(Grad21(v1)’ *Grad21(u1)) .5*cos(t). Vh1 u1. y=sin(t).dy(us)] problem Lap2dOmega(us.P2). // mesh Th=buildmesh(Gamma1(40)+Gamma(-40)).5 ≤ sqrt(x2 + y 2 ) ≥ 1.order=1. // vizualisation of solution of the initial problem medit("solution". macro Grad21(u1) [dx(u1). // Definition of EDP defined on the domain Ω // −∆us = f1 on Ω1 . label=1. // mesh Th1=buildmesh(Gamma(40)+Gamma2(-40)). mesh Th=square(10.edp) assert(version>1.}. fespace Vh1(Th1. border Gamma2(t=0.10). y=2*sin(t).u2.us=1) .2*pi){x=0.Th.13. fespace Xh(Th.P2). Vh us.v1.26 (StockesUzawa. label=2.v.5*sin(t). Xh u1. ∂u1 = 0 on Γ2 ∂n Lap2dOmega1.v. u − 1 = 1 on Γ1 . v1=0.q=0. p=0.Th.130 Mh p.p. matrix By= by(Xh. u2[] = Aˆ-1*b[].p. u1[] = Aˆ-1*b[].wait=1. b[] = Bx’*pp.1). the metric M computed with mshmet for the solution u defined on the mesh T h is obtained by writing.Xh). varf a(u1. verbosity=verb.coef=0.order=1). ppp[] = Bx*u1[].4. Xh bcx=1.*bcy[]. func real[int] divup(real[int] & pp) { int verb=verbosity. a FE vector func and a FE symmetric tensor. varf by(u1.*bcx[]. MESH GENERATION varf bx(u1.p[]. divup(p[]). bc1[] = a(0. the solution can be an error estimate of a FE solutions. Frey that allows to compute an anisotropic metric based on solutions (i.Mh).eps=1.2. b[] = By’*pp. CHAPTER 5. }.ppp. mshmet can construct also a metric suitable for level sets interface capturing.bcy=0. b[] += bc1[] .q) = int2d(Th)( (dy(u1)*q)). a symmetric tensor.q) = int2d(Th)( (dx(u1)*q)).e-6.solver=CG). Hessian-based). ppp[] += By*u2[]. The solution can be a func. This software accepts more than one solution.u1=1) .nbiter=50). Xh b. Xh bc1.q. LinearCG(divup.Xh. This sofware can return also an isotropic metric. Moreover.[u1. .e. Solutions for mshmet are given as an argument. a FE func. The symmetric tensor argument is defined as this type of data for datasol argument.q[]. For example. return ppp[] . verbosity=0. matrix Bx= bx(Xh. 5. The solution can be defined on 2D or 3D structured/unstructured meshes. a vector func.u1=0) + on(3. plot([u1.u1=0. For example.u2].u2].u2)= int2d(Th)( dx(u1)*dx(u2) + dy(u1)*dy(u2) ) + on(1. b[] += bc1[] . matrix A= a(Xh.value=true.14 Mshmet Mshmet is a software developped by P. medit("velocity pressure".Mh). real[int] M = mshmet(Th. Vh u. 1 for using previous metric otherwise 0. This vector contains the real parameters of mshmet (for expert only). . • hmin = <d> • hmax = <d> • err = <d> level of error. // a scalar FE func The parameters of the keyword mshmet are : • normalization = <b> do a normalisation of all solution in [0. 1 for building level set metric otherwise 0.5. . – doptions(1): hmax : max size parameters (default 1. .14.05). 1 for isotropic metric results otherwise 0.u). – doptions(0): hmin : min size parameters (default 0.01). 1 for turning on debug mode otherwise 0. • loptions=]a vector of integer of size 7. With nv is the number of vertices. – loptions(1): isotropic parameters (default 0).01). – loptions(0): normalization (default 1). 1]. – loptions(5): number of regularization’s iteration of solutions given (default 0). . This vector contains the integer parameters of mshmet(for expert only). the structure of this vector is Miso = (m(V0 ). . MSHMET 131 fespace Vh(Th. – doptions(2): width : relative width for Level Set (0 < w < 1) ( default 0.m22. . H(Vnv ))t where H(Vi ) is the vector of size 6 defined by [m11. For a symmetric tensor metric h =  m21 m22 m23 . • aniso = <b> build aniso metric if 1 ( delault 0: iso) • levelset = <b> build metric for level set method (default: false) • verbosity = <l> • nbregul = <l> number of regularization’s iteration of solutions given (default 0).m32.0). • width = <d> the width • metric= a vector of double. – loptions(4): level of verbosity (default 10). The result of the keyword mshmet is a real[int] which contains the metric computed by mshmet at the different vertices Vi of the mesh.m21. the parameters m31 m32 m33 metric is Maniso = (H(V0 ). m(Vnv ))t   m11 m12 m13 for a isotropic metric m. . – doptions(2): eps : tolerance parameters ( default 0.P1). This vector contains an initial metric given to mshmet. The structure of the metric vector is described in the next paragraph. • doptions= a vector of double of size 4. – loptions(2): level set parameters (default 0).m31. – loptions(6): previously metric parameter (default 0).m33] . m(V1 ). – loptions(3): debug parameters (default 0). . 27 (mshmet."th.1){x=1-t. border c(t=0. Vh u.01.edp) load "mshmet" load "medit" load "msh3" CHAPTER 5.v3.}.Th3. MESH GENERATION border a(t=0.1){x=0. cout << u3[].0){x=t.5){x=1.0e-10+ dx(u3)*dx(v3) + dy(u3)*dy(v3) + dz(u3)*dz(v3)) . border f(t=0.1){x=0. y=t.msh"). border e(t=0. y=0.label=6. This field is based on the intrinsic properties of the discrete surface.MaxLayer. border d(t=0. for(int ii=0. The adapted surface mesh is constructed with a geometric metric tensor field.u3).0e-10+ dx(u)*dx(v) + dy(u)*dy(v)) +int2d(Th.sol".0.ann.usol).bis.label=3. Vh3 u3.}.P1).min << " " << u3[]. Vh3P1 usol. fespace Vh3(Th3.Th3. int MaxLayer=10. y=1-t.}. ii++) usol[][ii]=bb[ii]. ii<Th3. y=1. Also this software allows to construct a simplification of a mesh.solver=CG.5.5. cout << bb << endl. mesh Th = buildmesh (a(6) + b(4) + c(4) +d(4) + e(4) + f(6)). A technical report on FreeYams is not available yet but a documentation on yams exists at http://www.eps=1. label=4.P2).5.solver=sparsesolver) = int3d(Th3)( u3*v3*1.15 FreeYams FreeYams is a surface mesh adaptation software which is developed by P. FreeYams can be used also to produce anisotropic triangulations adapted to level set simulations.v.qforder=2)( (x-y)*v).P1).6. real[int] bb=mshmet(Th3.int3d(Th3)( v3) +on(0.4.1. 5.v3.max << endl.sol".u3=0). savemesh(Th.0.3.html [40]. savemesh(Th3.zbound=[zmin.zmax]). fespace Vh3P1(Th3. savesol("metrictest. Compared to the software yams.0e-6) = int2d(Th.jussieu.}.v. problem Problem2(u3. border b(t=0. label=2.5. problem Problem1(u.u3). This decimation is based on the Hausdorff distance between the initial and the current triangulation. y=t. label=1. label=5. Frey. func zmax=1.mesh"). func zmin=0.0.5){x=1-t. . mesh3 Th3 = buildlayers(Th.fr/∼frey/software.nv.}. y=0. real error=0.qforder=2)( u*v*1. Problem2.2.1.5. fespace Vh(Th. savesol("metrictest.132 Example 5.bis."metrictest. This software is a new version of yams.}. . This parameters contains the metric at the different vertices on the initial mesh. a FE function. the adapted mesh of T hinit defined by the metric u defined as FE function is obtained in writing. If the metric is vector of double. . (default) -1 : decimation adaptated to a metric map. we used the keyword freeyams. For a symmetric tensor metric h =  m21 m22 m23 . The arguments of this function are the initial mesh and/or metric. this vector is Miso = (m(V0 ). FREEYAMS 133 To call FreeYams in Freefem++.15.m32. mesh3 Th=freeyams(Thinit. . . the paramm31 m32 m33 eters metric is Maniso = (H(V0 ).m33] • loptions= a vector of integer of size 13. 9 : No-Shrinkage Vertex Smoothing • ridgeangle = <d> • absolute = <b> • verbosity = <i> • metric= vector expression. For example. This vectors contains the integer options of FreeYams. iso) • mem = <l> memory of for freeyams in Mb (delaulf -1. Vh u. With nv is the number of vertices. a symmetric tensor function.u). this data must be given in metric parameter. a symmetric tensor FE function or a vector of double. freeyams choose) • hmin = <d> • hmax = <d> • gradation = <d> • option = <l> 0 : mesh optimization (smoothing+swapping) 1 : decimation+enrichment adaptated to a metric map. . .m21. • aniso = <b> aniso or iso metric (default 0. . Otherwise. m(Vnv ))t  m11 m12 m13 for a scalar metric m. H(Vnv ))t where H(Vi ) is the vector of size 6 defined by [m11. (just for the expert )  . The symmetric tensor argument for freeyams keyword is defined as this type of data for datasol argument. fespace Vh(Thinit. the metric is given in the argument. 2 : decimation+enrichment with a Hausdorff-like method -2 : decimation with a Hausdorff-like method 4 : split triangles recursively.m22. .P1).5. The metric with freeyams are a function. m(V1 ).m31. – doptions(5): Set the maximal size(hmax) (default -2. – doptions(3): Set the gradation value (Mesh density control) (default 1. . MESH GENERATION – loptions(0): anisotropic parameter (default 0).0). – loptions(8): number of desired’s vertices (default -1). – loptions(1): Finite Element correction parameter (default 0). – loptions(10): no detection parameter (default 0) . 1 for no Finite Element correction otherwise 0. decimation+enrichment with a Hausdorff-like method decimation with a Hausdorff-like method split triangles recursively. ). ∗ ∗ ∗ ∗ ∗ ∗ ∗ 0: 1: -1: 2: -2: 4: 9: mesh optimization (smoothing+swapping) decimation+enrichment adaptated to a metric map. – loptions(7): validity check during smoothing parameter.0: the size is automatically computed). If you give an anisotropic metric 1 otherwise 0.599). No-Shrinkage Vertex Smoothing doptions= a vector of double of size 11. – doptions(7): Set the quality of degradation (default 0. – doptions(1): Set the lamda parameter (default -1. 1 for splitting multiple connected points otherwise 0. – doptions(2): Set the mu parmeter (default -1. – loptions(3): maximum value of memory size in Mbytes (default -1: the size is given by freeyams). – loptions(11): no vertex smoothing parameter (default 0). This parameter is only used with No-Shrinkage Vertex Smoothing optimization (optimization option parameter 9). 1 for No validity checking during smoothing otherwise 0.134 CHAPTER 5.3).01). 1 for creating point on straight edge otherwise 0. – loptions(12): Optimization level parameter (default 0). 1 for detecting the ridge on the mesh otherwise 0. This vectors contains the real options of freeyams. – doptions(4): Set the minimal size(hmin) (default -2.0: the size is automatically computed). – loptions(9): number of iteration of optimizations (default 30). The ridge definition is given in the parameter doptions(12). 1 for smoothing the vertices otherwise 0. – loptions(4): set the value of the connected component which we want to obtain. (Remark: freeyams give an automatic value at each connected component). ). – loptions(5): level of verbosity – loptions(6): Create point on straight edge (no mapping) parameter (default 0). – doptions(0): Set the geometric approximation (Tangent plane deviation) (default 0. – loptions(2): Split multiple connected points parameter (default 1). decimation adaptated to a metric map. – doptions(6): Set the tolerance of the control of Chordal deviation (default -2. 4. with the following meaning: . mesh3 Th3 = freeyams(Th). The parameters of mmg3d are : • options= vector expression.nn.ubordeaux1. an isotropic metric is computed by analyzing the size of the edges in the initial mesh. To obtain a version of this library send an e-mail at : cecile.u-bordeaux1.1.1].14). It is a vector of 6 values. Frey (http://www. the vertices of the surface triangles are moved without verifying the geometrical structure of the new surface mesh.fr or pascal.fr. rmid=[1.1.php).nn).1].2]. This vector contains the option parameters of mmg3d.wait=1). fespace Vh2(Th2. (b) if a displacement is given.3. – doptions(9): Set the angular walton limitation parameter (default 45 degree).16 mmg3d Mmg3d is a 3D remeshing software developed by C. Remark 5 : (a) If no metric is given.p2.28 (freeyams.zmax=1.uz. int[int] rup=[0. reffacelow = rdown). zbound=[zmin.Th3.zmax]. reffacemid=rmid.math.1.5. This initial mesh is adapted to a geometric metric tensor field or to a displacement vector (moving rigid body). – doptions(10): Set the angular ridge detection (default 45 degree). 135 Example 5.dobrzynski@math. Dobrzynski and P. MMG3D – doptions(8): Set the declic parameter (default 2. The metric can be obtained with mshmet (see section 5. This software allows to remesh an initial mesh made of tetrahedra. rdown=[0. real zmin=0. reffaceup = rup. mesh Th2=square(nn.16. mesh3 Th=buildlayers(Th2.P2)[email protected]) load "msh3" load "medit" load "freeyams" int nn=20. 5. medit("maillagesurfacique".0). Vh2 ux.fr/∼dobj/logiciels/mmg3d. { for( int ii=0. 0 : otherwise.17.].[2. Set the maximum memory size of new mesh in Mbytes. y).idp" int n=6.nv. 0 : otherwise. • metric= vector expression. It is a vector of size 3 nv. 3000 000.]]. (4) insert points mode : (default 0) 1 : no edge splitting or collapsing and no insert points. MESH GENERATION (0) optimization parameters : (default 1) 0 : mesh optimization.2]]. Φ2.1. tetrahedra and triangles are respectively 500 000. ii<Th.edp”: Example 5. -9: moving mesh without optimization. This vector contains the metric given at mmg3d. It is a vector of size nv or 6 nv respectively for an istropic and anisotropic metric where nv is the number of vertices in the initial mesh. int[int] Nxyz=[12. 4 : split tetrahedra (be careful modify the surface). This vector contains the displacement at each point of the initial mesh. mesh3 Th=Cube(Nxyz.1. y)].. 100000 which represent approximately a memory of 100 Mo. (2) Specify the size of bucket per dimension ( default 64) (3) swapping mode : (default 0) 1 : no edge or face flipping.]. • displacement= [Φ1. (5) verbosity level (default 3) • memory= integer expression..[0. The structure of metric vector is described in the mshmet’s section(section 5..int] Bxyz=[[0.136 CHAPTER 5. real[int] isometric(Th.12]. Φ2(x.Bxyz.Lxyz). y) = [Φ1(x.12. 0 : otherwise. y). An example using this function is given in ”mmg3d.int] Lxyz=[[1. -1: adaptation with metric (deletion and insertion vertices) without optimization.nv)./examples++-3d/cube.edp) // load "msh3" load "medit" load "mmg3d" include ".29 (mmg3d. test mmg3d .. 1 : adaptation with metric (deletion and insertion vertices) and optimization.[0. By default the number of maximum vertices. (1) debug mode : (default 0) 1 : turn on debug mode. int [int. ii++) isometric[ii]=0.[2. real [int. Φ3(x. • displVect= sets the vector displacement in a vector expression.1]. Φ3] set the displacement vector of the initial mesh Φ(x. 9 : moving mesh with optimization.14).1.2]. real[int] domaine = [0. Th=mmg3d(Th. Lap.solver=CG) = int3d(Th)(Grad(uh)’*Grad(vh)) // ’) for emacs + on(310.[311.1. MMG3D } mesh3 Th3=mmg3d( Th. it++){ cout<<" ITERATION "<<it<<endl.16..4.. nbofholes=2.dz(u)] // options of mmg3d see freeem++ doc // Vh uh.int] B=[[-2.voltet].B.memory=1000).0.[-10.-0.[-2. fespace Vh(Th. func dep = vit[2].Th).0.hs.P1).nbofregions=1.311]].idp" // load "tetgen" load "medit" load "mmg3d" build mesh of a box (311) wit 2 holes (300. macro Grad(u) [dx(u).5.options=opt.z]).-4.). real [int. An example of a moving mesh is given in fallingspheres.0]. int[int] N=[4/hs.0. real [int] holes=[0.[311.uh=dep) +on(311.64. memory=100.dy(u).0. // see surface mesh real voltet=(hsˆ3)/6. } .311].5/hs]. for(int it=0.311]. real[int] vit=[0. medit("isometric".310.1).2].edp”: Example 5.displacement=[zero. func zero = 0. ThSd=movemesh3(ThSd.310) real hs = 0. ThHS).regionlist=domaine. // End build mesh int[int] opt=[9. mesh3 ThHS=ThH+ThSg+ThSd.vh. int [int.uh=0.uh). mesh3 ThH = SurfaceHex(N.5]].switch="pqaAAYYQ".Th3).int] L=[[311.8.300.zero.3].6].0.-1). mesh3 ThSg =Sphere(1.0.vh.4+y.300.transfo=[x. plot(Th.30 (fallingspheres.hol medit("Box-With-two-Ball".uh].L. 137 medit("init".hs. metric=isometric).8/hs.1.11. // to compute the displacemnt field problem Lap(uh.3]. // gluing surface meshes medit("ThHS".-1). mesh3 Th = tetg(ThHS.0.edp) load "msh3" include "MeshSurface. it<29.Th). mesh3 ThSd =Sphere(1.0. min << " "<< u[].1.err=errm). MESH GENERATION 5.solver=CG) = int3d(Th3)( Grad(u)’*Grad(v) ) -int3d(Th3)( 1*v ) + on(1. // level of error for(int ii=0.n << " " << Th3. Vh u.l01=[0.17 A first 3d isotope mesh adaptation process Example 5.nbregul=1. Th3=tetgreconstruction(Th3.wait=1).u. labeldown = l01).u=0). ii++) { Poisson. labelmid=l11.8. cout <<" u min.switch="raAQ". // rebuidl mesh medit("U-adap-iso-"+ii. macro Grad(u) [dx(u). nn.l11=[1. // for resizing h[] because the mesh change h[]=mshmet(Th3.31 (Laplace-Adapt-3d.1.hmin=1e-3.5) | (y < 0. cout <<" h min.nn.} // EOM . .(x<0.min << " "<< h[].1].label=l1111). Th3 = trunc(Th3.3.region=0. // solve Poisson equation.label=1).1].max << endl.nv << endl. errm*= 0.wait=1).v. zbound=[0. // label numbering to have all label to 1 mesh3 Th3=buildlayers(square(nn.nt << endl.normalization=1.dz(u)] problem Poisson(u.v.5) | (z < 0. plot(u.5) .Th3.dy(u).P1).aniso=0.138 CHAPTER 5. h=0.max << " " << h[]. labelup = l01. max = " << u[].5. int[int] l1111=[1.u. ii<5. // change the level of error cout << " Th3" << Th3.nv < " " << Th3. real errm=1e-2.1].usol.h. 1[3 cube // end of build initial mesh fespace Vh(Th3.1]. // remove the ]0.).sizeofvolume=h*h*h/6. max = " << h[].hmax=0.edp) load "msh3" load "tetgen" load "mshmet" load "medit" // build initial mesh int nn = 6. wi ∈ R } is easily created by fespace IDspace(IDmesh.sa i..[lb 1.ta 1].sa 1. 139 .<IDFE>) .if [la i.sa 1]. or with pairs of periodic boundary condition in 2d fespace IDspace(IDmesh. the 2 labels la i and lb i define the 2 piece of boundary to be in equivalence.tb ]]). periodic=[[la 1.[lb k. · · · . If [la i.sa k. y) + w1 φ1 (x. Vh).[lb i.sa k].<IDFE>. [la k. FEM approximates all functions w as w(x. y) + · · · + wM −1 φM −1 (x.. In FreeFem++ the finite element space Vh = {w | w0 φ0 + w1 φ1 + · · · + wM −1 φM −1 . y) and numbers wk (k = 0.[lb i.sb 1. and in 3d fespace IDspace(IDmesh. y) with finite element basis functions φk (x.sb . [la k.[lb 1. if [la i.. and called shape functions.sa i].sb 1]. where IDspace is the name of the space (e.ta k]. The functions φk (x.tb 1].g. y) w0 φ0 (x.tb i] is a pair of int. M − 1).Chapter 6 Finite Elements As stated in Section 2. and the 2 labels la i and lb i refer to 2 pieces of boundary to be in equivalence.sb i. . In 2D.[lb k. y) are constructed from the triangle Tik .sa i].. .ta i]. In 2D we have a pair of periodic boundary condition. IDmesh is the name of the associated mesh and <IDFE> is a identifier of finite element type. and two points are identified as one if the two abscissa are equal. periodic=[[la 1. we have a pair of periodic boundary condition. then sa i and sb i give two common abscissa on the two boundary curve.[lb i.<IDFE>.sb i] is a pair of real.sb ]]).sb i] is a pair of int. [lb i. 3d) The 2d case: P 1bh = v ∈ H 1 (Ω) ∀K ∈ Th v|K ∈ P1 ⊕ Span{λK λK λK } 0 1 2 (6.2) Warning. FINITE ELEMENTS If [la i.1) P1.. P 2h = v ∈ H 1 (Ω) ∀K ∈ Th v|K ∈ P2 ⊕ Span{λK λK λK } 0 1 2 (6. the degrees of freedom are the vertices values.P03d piecewise constant discontinuous finite element (2d. the degree of freedom is not the vertices but three vectices move inside with T (X) = G+.tb i give two common parameters on the two boundary surface. 3d).ta i and sb i.P23d piecewise P2 continuous finite element (2d.24-4). d are the d + 1 barycentric coordinate functions of the element K (triangle i or tetrahedron).P13d piecewise linear continuous finite element (2d.. 3d).3) v|K ∈ P1 (6. P 2h = v ∈ H 1 (Ω) ∀K ∈ Th where P2 is the set of polynomials of R2 of degrees ≤ 2. use the parameter fixeborder=true in buildmesh command (see 5.ta i].sb i. 3d). (version 2. P 0h = v ∈ L2 (Ω) for all K ∈ Th there is αK ∈ R : v|K = αK (6. due to interpolation problem. so to be sure. P 1h = v ∈ H 1 (Ω) ∀K ∈ Th P1dc piecewise linear discontinuous finite element P 1dch = v ∈ L2 (Ω) ∀K ∈ Th v|K ∈ P1 (6. the degrees of freedom are the barycenter element value.P1b3d piecewise linear continuous finite element plus bubble (2d.sa i. Remark 6 The 2D mesh of the two identified borders must be the same. .99(X −G) where G is the barycenter. P2.tb i] is a pair of real.2) like in example periodic2bis. P1b. P2b piecewise P2 continuous finite element plus bubble. the known types of finite element are: P0. then sa i. As of today. and two points are identified as one if the two parameters are equal.5) where λK .7) v|K ∈ P2 (6.4) The 3d case: P 1bh = v ∈ H 1 (Ω) ∀K ∈ Th v|K ∈ P1 ⊕ Span{λK λK λK λK } 0 1 2 3 (6.6) .7).140 CHAPTER 6.edp (see 9. i = 0.1. 13) v|K ∈ P3 (6. ux .3. due to interpolation problem.vx.9) where P2 is the set of polynomials of R2 of degrees ≤ 3. P3dc piecewise P3 discontinuous finite element (2d) (need load "Element_P3dc".v) ( dxx(u)*dxx(v)+dyy(u)*dyy(v)+2.edp of examples++-load for solving BiLaplacien problem : load "Morley" fespace Vh(Th.2.u=0. so this vectorial finite element with 3 components (u.[v. we need the function and 2 partial derivatives (u.ux.vx.4.99(X − G) where G is the barycenter.12) v|K ∈ P4 (6.ux. uy ).[v. (6.8) Warning. the degree of freedom is not the six P2 nodes but six nodes move inside with T (X) = G + . solve bilap([u. P 2dch = v ∈ L2 (Ω) ∀K ∈ Th v|K ∈ P2 (6. Warning to build the interplant of a function u (scalar) for this finite element. P 2h = v ∈ L2 (Ω) ∀K ∈ Th where P4 is the set of polynomials of R2 of degrees ≤ 3. // the Morley finite element space macro bilaplacien(u. uy ).ux=0.v) ) . See example bilapMorley. (version 2. P 2h = v ∈ L2 (Ω) ∀K ∈ Th where P3 is the set of polynomials of R2 of degrees ≤ 3.24-4). v continuous at vertices. ∂n v continuous at middle of edge. P4dc piecewise P4 discontinuous finite element (2d) (need load "Element_P4dc". P4 piecewise P4 continuous finite element (2d) (need load "Element_P4".P2Morley).vy]. Morley piecewise P2 non conform finite element (2d) (need load "Morley") P 2h = v ∈ L2 (Ω) ∀K ∈ Th v|K ∈ P3 .141 P2dc piecewise P2 discontinuous finite element.*dxy(u)*dxy(v)) // fin macro real f=1.11) v|K ∈ P3 (6.uy=0) . P 2h = v ∈ H 1 (Ω) ∀K ∈ Th where P4 is the set of polynomials of R2 of degrees ≤ 4.uy]. Vh [u. P 2h = v ∈ H 1 (Ω) ∀K ∈ Th where P3 is the set of polynomials of R2 of degrees ≤ 3.10) v|K ∈ P3 (6.uy].vy]) = int2d(Th)( bilaplacien(u.int2d(Th)(f*v) + on(1. ux . P3 piecewise P3 continuous finite element (2d) (need load "Element_P3". RT03d Raviart-Thomas finite element of degree 0. y) = α1 K α2 K + βK | −y x (6.13) RT 1h = v ∈ H(div) ∀K ∈ Th 2 2 3 (αK .17) where by writing curlw = with w = (wi )d . αK . βK are real numbers. y) = + βK | x y (6. βK ) ∈ P1 . It is a 2d coupled FE. βK . Math. y. αK . or Nedelec finite element type I of degree 0 in dimension 2 α1 RT 0Orthoh = v ∈ H(curl) ∀K ∈ Th v|K (x. αK ..142 CHAPTER 6. αK .13.14) v|K (x.: Analysis of some finite elements for the Stokes problem. C. βK . v|K (x. The 2d case: RT 0h = v ∈ H(div) ∀K ∈ Th The 3d case: RT 0h = v ∈ H(div) ∀K ∈ Th d i=1 ∂wi /∂xi α1 K α2 K v|K (x. P1nc piecewise linear element continuous at the middle of edge only in 2D ?????. z) = α1 K α2 K α3 K + βK x y z (6.15) where by writing div w = with w = (wi )d . i=1 H(div) = w ∈ L2 (Ω)d div w ∈ L2 (Ω) 3 2 1 and where αK . dimension 2) RT 1h = v ∈ H(curl) ∀K ∈ Th 2 2 3 (αK . RT0Ortho Raviart-Thomas Orthogonal. αK . y) = α1 K α2 K + βK | x y (6. i=1 H(curl) = w ∈ L2 (Ω)d curl w ∈ L2 (Ω)d 1 2 3 1 2 3 and αK . RT0. 44. with the Polynomial space is P 12 + 3 normals bubbles edges function (P2 ) and the degre of freedom is 6 values at of the 2 components at the 3 vertices and the 3 flux on the 3 edges So the number degrees of freedom is 9. βK ) ∈ P1 . y) = αK + βK | −y (6. Comp. See Bernardi. FINITE ELEMENTS P2BR (need load "BernadiRaugel") the Bernadi Raugel Finite Elemen is a Vectorial element (2d) with 2 components. 71-79 (1985). version 3. The 3d case: Edge0h = v ∈ H(Curl) ∀K ∈ Th ∂w2 /∂x3 −∂w3 /∂x2 ∂w3 /∂x1 −∂w1 /∂x3 ∂w1 /∂x2 −∂w2 /∂x1 v|K (x.18) RT1Ortho (need load "Element_Mixte". y. βK are real numbers. RT1 (need load "Element_Mixte". z) = α1 K α2 K α3 K + 1 βK 2 βK 3 βK × x y z (6. Raugel. version 3. v|K (x.19) . G.16) 2 x K Edge03d Nedelec finite element or Edge Element of degree 0. αK . 10).20) BDM 1h = v ∈ H(div) ∀K ∈ Th v|K ∈ P1 BDM1Ortho (need load "Element_Mixte".[1. finite element BDM 1Orthoh = v ∈ H(curl) ∀K ∈ Th 2 v|K ∈ P1 (6.vh. and n is a normal to the edge (see [41. fespace Xh(Th.5.Mh. With the 2d finite element spaces v|K ∈ P1 } . y) = + γK | x } y when Th is a mesh 10 × 10 of the unit square ]0.2.13. qh ∈ Mh and Uh .y]. 1[2 )| ∀K ∈ Th Rh = {v ∈ H 1 (]0.Wyh](10). Rh .1 Use of “fespace” in 2d Xh = {v ∈ H 1 (]0. we write : Xh uh.[4. . ph .x]]). 1[2 )2 | ∀K ∈ Th v|K ∈ P2 } αK βK v|K (x.2 ∀K ∈ Th 2 σ|K ∈ P1 . 1[2 .5) // the 6th function at point (0. USE OF “FESPACE” IN 2D 143 BDM1 (need load "Element_Mixte".0. The functions Uh .2. Vh have two components so we have Uh = U xh U yh and Vh = V xh V yh . periodic=[[2.Uyh]. v(| 0 ) = v(| 1 )} .P1). σ12 = σ21 . Mh . section 4. vh ∈ Xh .21) TDNNS1 (need load "Element_Mixte".RT0). fespace Xph(Th. 0. T DN N S1h = σ ∈ (L2 )2. To use FE-functions uh .13.22) where σnn = nt σn.P2).qh. Vh ∈ Rh . 1[2 )| ∀K ∈ Th . Mh = {v ∈ H 1 (]0. // // scalar FE bi-periodic FE // scalar FE // vectorial FE where Xh. respectively.5) Wxh[5][] // the array of the degre of freedom of the 6 function. Xh[int] Uh(10). dimension 2) the Brezzi-Douglas-Marini finite element 2 (6.6. version 3.3] for full detail) 6. dimension 2) A new element finite element to approximation symetrique 2x2 matrix in H(divdiv) (i. Mh ph. version 3.13.P1. version 3.5.y].vph. fespace Mh(Th. // array of 10 functions in Rh. fespace Rh(Th.[3. we only write in FreeFem++ : mesh Th=square(10.1.e σnn is continuous accross edge). // array of 10 function in Xh Rh[int] [Wxh.Vyh]. dimension 2) the Brezzi-DouglasMarini Orthogonal also call Nedelec of type II .x]. Wxh[5](0.Rh expresses finite element spaces (called FE spaces ) Xh . Xph uph. Rh [Uxh.[Vxh. σnn is continuous (6. Xph = {v ∈ Xh | v(| 0 ) = v(| 1 ). zbound=[0.0. vh ∈ Xh and ph . To define and use FE-functions uh . periodic=[[0.[1.P1). // array set on 0. Mh = {v ∈ H 1 (]0. 0. we write in FreeFem++ : mesh3 Th=buildlayers(square(10.5) // the array of the degre of The functions Uh .5.z].[4. . the BuildLayer mesh generatio split quadralateral faces with the diagonal passing through vertex with maximal number. Xph uph.5) // Wxh[5][] freedom of the 6 function.y. 4 back.z]. 1.x. .144 CHAPTER 6.RT03d).old2new).qh. Vh2 sorder=x+y. Vh ∈ Rh . // array of 10 function in Xh // array of 10 functions in Rh.vh.nv-1).Uyzh]. 5: right fespace Xh(Th. By Default.y].Uyh. // inverse the permutation . 1[2 )2 | ∀K ∈ Th v|K ∈ P2 } αK βK v|K (x. 1[3 )| ∀K ∈ Th . 1[2 )| ∀K ∈ Th Rh = {v ∈ H 1 (]0. Xph = {v ∈ Xh | v(| 0 ) = v(| 1 ).5. qh ∈ Mh and Uh . 1 down. FINITE ELEMENTS 6.Wzh](10). // scalar FE fespace Rh(Th.x..10). To change the mesh numbering you can used the change function like: { // for cleanning memory. [3.z]. // choose ordering increasing on 4 square borders with x or y sort(sorder[].0. Mh ph.x.P1). 2 front.vph.. we write: Xh uh. // label: 0 up. the 6th function at point (0. // build the inverse permutation int[int] new2old=old2newˆ-1.Rh expresses finite element spaces (called FE spaces ) Xh .Vyh. the numbering of square vertex are correct. 3 left.2 Use of fespace in 3d Xh = {v ∈ H 1 (]0. nv-1 fespace Vh2(Th. int[int] old2new(0:Th. 1[2 .1) fespace Mh(Th. Wxh[5](0. 0. With the 3d finite element spaces v|K ∈ P1 } . // vectorial FE where Xh. Vyzh]. y) = + γK | x } y when Th is a mesh 10 × 10 × 10 of the unit cubic ]0. // three-periodic FE (see Note 6. Rh[int] [Wxh.1 ONe problem of the periodic boundary condition is the mesh mus be the same au equivalence face. [2.[5.5.1]). v(| 0 ) = v(| 1 )} . Xh[int] Uh(10).[Vxh.5. // scalar FE fespace Xph(Th.10.z]]).Mh.Wyh.P2). Vh have three components so we have Uh = U xh U yh U zh and Vh = V xh V yh V zh Note 6. Mh .P1.. Rh . respectively.x.y. Rh [Uxh.y]. so to be sure to have the same mesh one both face periodic the 2d numbering in corresponding edges must be compatible (for example the same variation). 1]2 as in Fig.P0) when the mesh Th is a 4 × 4-grid of [−1.1 Lagrangian Finite Elements P0-element φk (x) = 1 if (x) ∈ Tk . y) = λk (x. Vh fh=f (x. 6.3.. y). y) with the vertex q k1 in Fig. y) = ak + bk x + ck y for (x. 6.3 6.edp 6. φk (x) = 0 if (x) ∈ Tk For each triangle (d=2) or tetrahedron (d=3) Tk .6.2.3. 6.P0) is given by If we write Vh(Th. . y) = k f( iq ki d+1 )φk See Fig.d + 1 in Fig.1(a) at point p = (x. the basis function φi in Vh(Th. 6. then for vertices q ki . y) = sin(πx) cos(πy) on Vh(Th. q k2 . y) ∈ Tk . φi (q j ) = 0 if i = j The basis function φk1 (x. q k3 ) area of triangle(q k1 . 6. i i i φi (q i ) = 1.3 for the projection of f (x. q k2 . the basis function φk in Vh(Th. y) = 1 area of triangle(p.change} } 145 the full example is in examples++-3d/periodic-3d.renumv=new2old).3.2 P1-element q T p k k  q =  k  >  q q k ! k T k q k ! q k q k " q k # q k $ Figure 6.P1) is given by φi (x. LAGRANGIAN FINITE ELEMENTS Th= change(Th. 2.1(a). y) in triangle Tk simply coincide with the barycentric coordinates λk (area coordinates) : 1 φk1 (x.P0). i = 1.1: P1 and P2 degrees of freedom on triangle Tk For each vertex q i . fh is built as fh = fh (x. q k3 ) . y) = ak + bk x + ck y + dk x2 + ek xy + fj y 2 for (x.P0) 6. the basis function φi in Vh(Th. y) = sin(πx) cos(πy) into Vh(Th. Figure 6. y)(2λk (x. Vh fh=f (x.P1). CHAPTER 6.3: projection to Vh(Th. y) = i=1 f (q i )φi (x. 6.P2) is given by φi (q i ) = 1. Vh fh=g(x. y) 1 4 If we write Vh(Th.P2). then M fh = fh (x.2: Test mesh Th for projection Figure 6.y). .3. y) = 4λk (x.5 for the projection of f (x. FINITE ELEMENTS then nv fh = fh (x. 6. y) ∈ Tk . 6. i i i i i For each vertex or midpoint q i . y) = λk (x.1(b) is defined by the barycentric coordinates: φk1 (x.3 P2-element f φi (x. y)λk (x.4 for the projection of f (x. y) = sin(πx) cos(πy) into Vh(Th. y) with the vertex q k1 in Fig. φi (q j ) = 0 if i = j The basis function φk1 (x. y) = i=1 f (q i )φi (x.P2).146 If we write Vh(Th. y) (summation over all vetex or midpoint) See Fig. y) See Fig.y).P1). y) − 1) 1 1 and for the midpoint q k2 φk2 (x. In [23].P1nc). For the bilinear form a defined in (2. i i i φi (mi ) = 1. nv a(φi .6.4: projection to Vh(Th. φj ) ≤ 0 if i = j a(φi .4 P1 Nonconforming Element Refer to [23] for details. Vh fh=f (x.P1) Figure 6. and we assume that j + 1 = 0 if j = 3: φi (x. then fh = fh (x. The numerical calculations will automatically ignore them. y) = ak + bk x + ck y for (x.6) satisfy a(φi . φk ) ≥ 0 k=1 2. y) i=1 (summation over all midpoint) Here the basis function φi associated with the midpoint mi = (q ki + q ki+1 )/2 where q ki is the i-th point in Tk . ∂φi /∂y contain Dirac distribution ρδ∂Tk .P2) 6. we now consider non-continuous approximations so we shall lose the property wh ∈ Vh ⊂ H 1 (Ω) If we write Vh(Th. there is a proof of the estimation nv 1/2 | w− k=1 Tk wh | dxdy 2 = O(h) The basis functions φk have the following properties. briefly. y) = nv f (mi )φi (x. 1.4. P1 NONCONFORMING ELEMENT 147 Figure 6. y) ∈ Tk . φi (mj ) = 0 if i = j Strictly speaking ∂φi /∂x. f ≥ 0 ⇒ uh ≥ 0 .5: projection to Vh(Th. φi ) > 0.y). Figure 6. y)λk2 (x. 6. βk (x. let λk1 (x. the basis function φi and φj are L2 -orthogonal: φi φj dxdy = 0 Ω if i = j which is false for P1 -element. See Fig. λk2 (x. . y) + k=1 f (q kb )βk (x. y) = i=1 f (q i )φi (x. 6. y) = 0 if (x.P1b). y) = 27λk1 (x. q k1 +q k2 +q k3 .148 CHAPTER 6.6 for the projection of f (x. y) ∈ ∂Tk . then nv nt fh = fh (x.5 Other FE-space For each triangle Tk ∈ Th . y). y).6: projection to Vh(Th.P1b) 6.P1nc) Figure 6. 6. βk (q kb ) = 1 where q kb is the barycenter If we write Vh(Th. Vh fh=f (x.P1nc). The bubble function has the feature: 1.23) 2.P1nc). y) = sin(πx) cos(πy) into Vh(Th. λk3 (x. 6. 3 (6. y) See Fig. y) = sin(πx) cos(πy) into Vh(Th.7: projection to Vh(Th. y) be the area cordinate of the triangle (see Fig.1).7 for the projection of f (x.P1b). If i = j.y). FINITE ELEMENTS 3. See Fig. y) called bubble function on Tk .6 for the projection of f (x. y)λk3 (x. y) = sin(πx) cos(πy) into Vh(Th. and put βk (x. 2|Tk | (6. sgn(ia −ib )(a−b). the degree of freedom are the fluxes across edges e of the mesh. ic . This implies a orientation of all the edges of the mesh. P0 ).8: normal vectors of each edge . Vh [f1h. y) = k=1 l=1 nil jl |eil |fjl (mil )φil jl where nil jl is the jl -th component of the normal vector nil . P1 )} 6. 2|Tk | φk = 2 sgn(ic − ia ) (x − b).ne . sgn(ic −ia )(c−a). . w2 ∈ Vh (Th . and define the three edge vectors e1 .P1]) . ib .6 Vector valued FE-function Functions from R2 to RN with N = 1 is called scalar function and called vector valued when N > 1. e2 .24) where |Tk | is the area of the triangle Tk . m2 . {m1 . 3}. 1.RT0).6. 2 2 2 and il = {1. we use a quadrature with one Gauss point.[P0.6. c).f2h]=[f 1(x. y)]. f 2(x. make the space Vh = {w = (w1 . the middle point of the edge. VECTOR VALUED FE-FUNCTION 149 6. b. We get three basis functions. 1. φk = 1 sgn(ib − ic ) (x − a). ne is the unit normal of edge e. e3 by sgn(ib −ic )(b−c). c n ! 6 n a n  b Figure 6. where the flux of the function f : R2 −→ R2 is e f . 2} with the order of l. When N = 2 fespace Vh(Th. 3. 2|Tk | φk = 3 sgn(ia − ib ) (x − c). then nt 6 fh = f h (x. w2 )| w1 ∈ Vh (Th . m3 } = b+c a+c b+a . 2. Consider a triangle Tk with three vertices (a. 1. 2.6.y). If we write Vh(Th. To compute the flux. jl = {1.1 Raviart-Thomas element In the Raviart-Thomas finite element RT 0h . Let denote the vertices numbers by ia . 2. for example we can use the global numbering of the edge vertices and we just go from small to large numbers. 2. fespace Vh(Th. // ok // and now uh use the 5x5 mesh but the fespace of vh is alway the 2x2 mesh // figure 6.2) get value= Uxh(1.Uyh].ps="onnewmesh. Xh uh. uh = xˆ2+yˆ2. // // // To get the value of the array associated to the FE function uh. Vh [Uxh.4) get value= Uxh(2. [Uxh.10: vh Iso on mesh 5 × 5 To get the value at a point x = 1. value = uh(2. x=1. Uxh = x. FINITE ELEMENTS Example 6. // // ok vectorial FE function // vh // change the mesh // Xh is unchange // compute on the new Xh error: impossible to set only 1 component // of a vector FE function.Uyh].5).2) get value= Uyh(1.eps"). vh= xˆ2+yˆ2. vh([x-1/2.9: vh Iso on mesh 2 × 2 Figure 6. // plot(uh. // // get value= uh(2.4) // -----.ps="onoldmesh. value = Uxh. vh = Uxh. value = uh.4).or -----get value= uh(1.P1).eps").y=2.2).4). one writes . value = Uxh(2.y])= xˆ2 + yˆ2.RT0).10 // interpolate vh = ((x − 1/2)2 + y 2 ) // Figure 6.Uyh] = [sin(x). plot(uh.2).one writes real value. value = Uyh. // figure 6. uh = uh. y = 2 of the FE function uh.1 mesh Th=square(2. or [Uxh.vh.cos(y)]. fespace Xh(Th.150 CHAPTER 6. Th = square(5.9 do a interpolation of vh (old) of 5x5 mesh // to get the new vh on 10x10 mesh. h Algorithm The method has 5 steps.n)= uh[]. 0 0 Step 3 Choose one triangle Tk ∈ Th0 which has qj for vertex.2 For a none scalar finite element function [Uxh. We propose an algorithm which is of complexity N 1 log N 0 . // // 151 get the value of degree of freedom 0 maximum value of degree of freedom // the number of degree of freedom // copy the array of the function uh Note 6. opposite qi • − else two barycentric coordinates are negative so take one of the two randomly and 0 replace Tk by the adjacent triangle as above.3 of q 1 in Tk . We present below the interpolation operator 0 1 which we have used and which is new.7 A Fast Finite Element Interpolator In practice one may discretize the variational equations by the Finite Element method. int size = uh.n. and which is very fast for most practical 2D applications. . and at most 4.7. real maxdf = uh[]. Let V (T i ) = {C 0 (Ωi ) : f |T i ∈ P0 }. • − if all barycentric coordinates are positive.max. vertices of Th0 . go to Step 5 0 • − else if one barycentric coordinate λi is negative replace Tk by the adjacent triangle 0 and go to Step 4. The problem is to find g ∈ V (Th1 ) such that g(q) = f (q) ∀q vertex of Th1 Although this is a seemingly simple problem. Let Th0 = ∪k Tk . Quadrature formulae and interpolations from one mesh to another at quadrature points are needed. 6. For each q 1 . Then there will be one mesh for Ω1 and another one for Ω2 . to the best of our knowledge. vertex of Th1 do: Step 1 Find the terminal cell of the quadtree containing q 1 . where N i is the number of vertices of T i . 0 Step 4 Compute the barycentric coordinates {λj }j=1.2. h h k i = 0. A FAST FINITE ELEMENT INTERPOLATOR real value = uh[][0] . Let f ∈ V (Th0 ). it is difficult to find an efficient algorithm in practice. First a quadtree is built containing all the vertices of mesh Th0 such that in each terminal cell there are at least one.Uyh] the two array Uxh[] and Uyh[] are the same array. 1 be the spaces of continuous piecewise affine functions on each triangulation. because the degree of freedom can touch more than one component. real[int] array(uh.6. The computation of integrals of products of functions defined on different meshes is difficult. Th1 = ∪k Tk be two triangulations of a domain Ω. 0 Step 2 Find the the nearest vertex qj to q 1 in that cell. . So we make sure that this information is not lost when Th0 . • What if Ω0 is not convex and the marching process of Step 4 locks on a boundary? By h construction Delaunay-Vorono¨ mesh generators always triangulate the convex hull of the ı vertices of the domain.152 CHAPTER 6. Note 6. So we add a step h which test the distance of q 1 with the two adjacent boundary edges and select the nearest. Hence in step 5 we can use that list to step over holes if needed.3 Some time in rare case the interpolation process miss some point.4 Step 3 requires an array of pointers such that each vertex points to one triangle of the triangulation. // safe seach algo. // default value for fast search algorithm searchMethod=1. But if the holes are triangulated too (doted line) then the problem does not arise.3 0 λj f (qj ) End Figure 6.2. and so on till the distance grows. FINITE ELEMENTS 0 Step 5 Calculate g(q 1 ) on Tk by linear interpolation of f : g(q 1 ) = j=1. The algorithm may start at q 1 ∈ Tk and stall on the boundary (thick line) because the line q 0 q 1 is not inside Ω. we cane change the seach algorithm through global variable searchMethod searchMethod=0. use brute force in case of missing point // (warning can be very expensive in case of lot point of ouside domain) searchMethod=2. Th1 are constructed and we keep the triangles which are outside the domain in a special list. // use alway the brute force very very expensive Note 6.11: To interpolate a function at q 0 the knowledge of the triangle which contains 0 q 0 is needed. Two problems need to be solved: • What if q 1 is not in Ω0 ? Then Step 5 will stop with a boundary triangle. ps="overlapTh. v).8 Keywords: Problem and Solve For FreeFem++ a problem must be given in variational form.(f. fespace Fh(Thg. Dh vs= (x-0.Figure 6.wait=1. and possibly a boundary condition form must be added. plot(Ths.ug. fespace Dh(Ths. problem P(u. you can use the keywork solve. The continuous finite functions are extended by continuity to the outside of the domain. Try the following example mesh Ths= square(10.wait=1). KEYWORDS: PROBLEM AND SOLVE 153 Note 6. Ch us= (x-0.y*3-1]). v) .ps="us-ug.5)*(y-0. a linear form (f.vg=vs.vg.Thg.6.P2dc).wait=1. mesh Thg= square(30. // // see figure 6.5)*(y-0.10).P2dc). Fh ug=us. .5).eps").13 Figure 6.P2).v) + (boundary condition).v) = a(u. so we need a bilinear form a(u.eps").5 The operator = is the interpolation operator of FreeFem++ .12: Extension of a continuous FE.8.[x*3-1.eps".12 see figure 6.ps="vs-vg.30. fespace Ch(Ths. plot(vs.5). plot(us. Note 6. see warning 6 6.6 When you want to formulate the problem and to solve it in the same time.13: Extention of discontinuous FEfunction function.v) . (κ u) = f.(κ u) v dω = Ω κ v. • the border Γ = ∂Ω is split in Γd and Γn such that Γd ∩ Γn = ∅ and Γd ∪ Γn = ∂Ω. u dω − Γ vκ ∂u dγ.154 CHAPTER 6.(κ u) = ∂x (κ∂x u) + ∂y (κ∂y u) with ∂x u = ∂u ∂x in Ω.7 This is the well known Neumann boundary condition if a = 0. linear algebra tells us that the right hand side must be orthogonal to the kernel of the operator for the solution to exist. • a a given non negative function. such that ∃κ0 ∈ R. the problem (6. ∂u Now we note that κ ∂n = −au + g on Γr and v = 0 on Γd and ∂Ω = Γd ∪ Γn thus . au + κ ∂u = b on ∂n Γr . u dω + Ω Γr auv dγ = Ω f v dω + Γr bv dγ. and if Γd is empty. Note 6.26) + ∂u ∂v ∂z ∂z ) ∂v ∂v ∂v where if d = 2 the v. • b a given function. u=g on Γd (6.8. − ∂Ω vκ ∂u = ∂n auv − Γr Γr bv The problem becomes: Find u ∈ Vg = {v ∈ H 1 (Ω)/v = g on Γd } such that κ v. ∂y u = ∂u ∂y and . • κ is a given positive function. so it is defined only up to a constant (if u is a solution then u + c is also a solution). One way of writing the compatibility condition is: f dω + Ω Γ b dγ = 0 .27) where V0 = {v ∈ H 1 (Ω)/v = 0 on Γd } Except in the case of Neumann conditions everywhere.25) and ∂y u = ∂u ∂y . u = ( ∂u ∂x + ∂u ∂y ) . The problem is: Find u a real function defined on domain Ω of Rd (d = 2. FINITE ELEMENTS 6. ∀v ∈ V0 (6.1 Weak form and Boundary Condition To present the principles of Variational Formulations or also called weak forms fr the PDEs. where • if d = 2 then • if d = 3 then ∂z u = ∂u ∂z . u = ( ∂u ∂x + ∂x ∂y ∂x and where n is the unitary outside normal of ∂Ω. In this case the function appears in the problem just by its derivatives. where if d = 3 the v.8 If we have only Neumann boundary condition. 3) such that − . . by integration by parts we get − Ω 0 < κ0 ≤ κ.27) is well posed when κ ≥ κ0 > 0. Let v a regular test function null on Γd . Note 6.(κ u) = ∂x (κ∂x u) + ∂y (κ∂y u) + ∂z (κ∂z u) with ∂x u = ∂u ∂x . let us take a model problem : a Poisson equation with Dirichlet and Robin Boundary condition . = ∂n f v dω Ω ∂u ∂v ∂y ∂y (6. 9 If the functions are a part of vectoriel FE then you must give all the functions of the vectorial FE in the same order (see laplaceMixte problem for example).9 Parameters affecting solve and problem The parameters are FE functions real or complex.int2d(Th. Remark that if the solution is of order 1 then the compatibility condition is unsatisfied. the number n of parameters is even (n = 2 ∗ k). In FreeFem++. No clean message is given and the result is impredictible. u dω Ω + int2d(Th.v) = int2d(Th)( kappa*( dx(u)*dx(u) + + int1d(Th.int3d(Th)(f*v) // f v dω Ω .gn)( a * u*v ) .gn)( a * u*v ) // auv dγ Γr .gn)( b * v ) + on(gd)(u= g) . PARAMETERS AFFECTING SOLVE AND PROBLEM and a way to fix the constant is to solve for u ∈ H 1 (Ω) such that: εuv dω + κ v.int2d(Th)(f*v) . the k first function parameters are unknown. must have the same type of periodic boundary condition or no periodic boundary condition. Bug: 1 The mixing of fespace with different periodic boundary condition is not implemented.int1d(Th.dz(u) ] // EOM : definition of the 3d Grad macro problem Pw(u. the bidimensional problem (6. And the the three dimensional problem (6. dy(u)*dy(u)) ) // κ v. 6. and gd and gn are respectively the boundary label of boundary Γd and Γn . Note 6. and gd and gn are respectively the boundary label of boundary Γd and Γn .27) becomes problem Pw(u.9.28) where ε is a small parameter ( ∼ 10−10 ). Note 6. The parameters are: . and the k last are test functions.6.10 Don’t mix complex and real parameters FE function.v) = int3d(Th)( kappa*( Grad(u)’*Grad(v) ) ) // κ v.27) becomes macro Grad(u) [dx(u). you can also add a Lagrange multiplier to solver the real mathemaical probleme like in the examples++-tutorial/Laplace-lagrange-mult.gn)( b * v ) // bv dγ Γr + on(gd)(u= g) . ∀v ∈ H 1 (Ω) (6.edp example. u dω = Ω Ω 155 f v dω + Γr bv dγ. otherwise we ε get the solution such that Ω u = 0. u dω Ω // auv dγ Γr // f v dω Ω // bv dγ Γr // u = g on Γd where Th is a mesh of the the bidimensional domain Ω.dy(u). Sorry. // u = g on Γd where Th is a mesh of the three dimensional domain Ω. So all the finite element spaces used for test or unknown functions in a problem. Crout. for Crout the matrix is sky-line symmetric. FINITE ELEMENTS solver= LU. ε sets the stopping test for the iterative methods like CG. tolpivot= set the tolerence of the pivot in UMFPACK (10−1 ) and. and for GMRES. for LU the matrix is sky-line non symmetric. see note 6.15. if it is false or 0 the matrix is reconstructed. tolpivotsym= set the tolerence of the pivot sym in UMFPACK strategy= set the integer UMFPACK strategy (0 by default). LU.. Cholesky factorisation (10−20 ). After the ”=” sign. CG.Cholesky. Note that if the mesh changes the matrix is reconstructed too. int3d(Th)( K*v*w) = T ∈Th T Kvw .. we just used the order in argument list to recall name as in a C++ function. The prototype for the tgv= Huge value (1030 ) used to implement Dirichlet boundary conditions. this is the name given earlier to the variational form(s) (type varf ) for possible reuse. Note that if ε is negative then the stopping test is: ||Ax − b|| < |ε| if it is positive then the stopping test is ||Ax − b|| < |ε| ||Ax0 − b|| init= boolean expression. Crout. eps= a real expression. UMFPACK . precon= name of a function (for example P) to set the preconditioner. see page 157 for description. The default solver is sparsesolver ( it is equal to UMFPACK if not other sparce solver is defined) or is set to LU if no direct sparse solver is available. function P must be func real[int] P(real[int] & xx) . for Cholesky the matrix is sky-line symmetric positive definite.10 Problem definition Below v is the unknown function and w is the test function. one may find sums of: • identifier(s).sparsesolver. The storage mode of the matrix of the underlying linear system depends on the type of solver chosen.156 CHAPTER 6. sparsesolver or UMFPACK the matrix is just sparse. for CG the matrix is sparse symmetric positive. • the terms of the bilinear form itself: if K is a given function. 6.GMRES. Remark. that the name in the ”varf” of the unknow of test function is forgotten. 5)( K*v*w) = - Kvw T ∈Th (∂T ∪Γ)∩(Γ2 ∪Γ5 ) intalledges(Th)( K*v*w) = T ∈Th ∂T Kvw Kvw T ∈Th. g2))[i]” × tgv.1)( K*v*w) = . • the right handside of the PDE.2))( K*v*w). PROBLEM DEFINITION int3d(Th.T ⊂Ω1 T 157 Kvw - int2d(Th)( K*v*w) = T ∈Th T Kvw Kvw T ∈Th. remark. volumic terms of the linear form: for given functions K.2. except diagonal term aii = 1.u1=g1. if tgv < 0 then we put to 0 all term of the line i in the matrix. – a linear form on Γ (for Neumann in 2d ) f*w) -int1d(Th))( f*w) or -int1d(Th.1)( K*v*w) = T ∈Th.T ⊂Ω1 T int2d(Th. – An ”on” vectorial form (for Dirichlet ) : on(1.10) . u = g ) The meaning is for all degree of freedom i of the boundary refered by ”1”.1)( K*v*w) = int1d(Th. where the ”(Πh g)g[i]” is the boundary node value given by the interpolation of g.they contribute to the sparse matrix of type matrix which. and so you have : b[i] = ”(Πh (g1.10. . the 2 components are coupled. f : int3d(Th)( K*w) = T ∈Th T Kw Kw T ∈Th T int2d(Th)( K*w) = int1d(Th. (version ¿ 3. the diagonal term of the matrix aii = tgv with the terrible geant value tgv (=1030 by default) and the right hand side b[i] = ”(Πh g)[i]” × tgv.T ⊂Ω1 ∂T intalledges(Th.a vector of type real[int] • The boundary condition terms : – An ”on” scalar form (for Dirichlet ) : on(1. and b[i] = ”(Πh g)[i]”.u2=g2) If you have vectorial finite element like RT0. whether declared explicitly or not is contructed by FreeFem++ .5)( K*w) = Kw T ∈Th (∂T ∪Γ)∩(Γ2 ∪Γ5 ) intalledges(Th)( f*w) = T ∈Th ∂T fw .3))( – a bilinear form on Γ or Γ2 (for Robin in 2d) int1d(Th))( K*v*w) or int1d(Th.6. where Πh is the vectorial finite element interpolant.2. FINITE ELEMENTS -int2d(Th))( f*w) or -int2d(Th.3))( – a bilinear form on Γ or Γ2 (for Robin in 3d) int2d(Th))( K*v*w) or int2d(Th. • N. .y and N. y)| x = (1 − t)qx + tqx .158 – a linear form on Γ (for Neumann in 3d ) f*w) CHAPTER 6. • the integral mesh and the mesh associated to test function or unknown function can be different in the case of linear form.2))( K*v*w).11 Numerical Integration Let D be a N -dimensional bounded domain. J in D and (quadrature) constants ωj such that L f (x) = D =1 c f (ξ ) (6.qforder=*)(f) where * stands for the name of the quadrature formula or the precision (order) of the Gauss formula. 0 ≤ t ≤ 1}). and then there exists a constant C > 0 such that. Note 6.11 • If needed. j = 1. the different kind of terms in the sum can appear more than once. For a domain Ωh = nt k=1 Tk .30) for any function r + 1 times continuously differentiable f in D. N. y = (1 − t)qy + tqy . L f (x) − D =1 ω f (ξ ) ≤ C|D|hr+1 (6. · · · . if we can find particular (quadrature) points ξ j .qfe=*)(f) = int1d(Th.f*w) . Th = {Tk }.x. 6. For an arbitrary polynomial f of degree r. where h is the diameter of D and |D| its measure (a point in the segment [q i q j ] is given as i j i j {(x.z are the normal’s components.29) then we have an error estimate (see Crouzeix-Mignot (1984)). Important: it is not possible to write in the same integral the linear part and the bilinear part such as in int1d(Th)( K*v*w . we can calculate the integral over Γh = ∂Ωh by f (x)ds = int1d(Th)(f) Γh = int1d(Th. For a part Γ1 of Γh with the label “1”. NUMERICAL INTEGRATION L 1 2 3 4 (qfe=) qf1pE qf2pE qf3pE qf4pE Quadature formula on an edge qforder= point in [q i q j ](= t) ω 2 1/2 |q i q j | 3 (1 ± 1/3)/2 |q i q j |/2 6 (1 ± 3/5)/2 (5/18)|q i q j | (8/18)|q i q j | √ 1/2 8 (1 ± √525+70 30 )/2. the point P (x.3)(f) Γ1 ∪Γ3 For each triangle Tk = [q k1 q k2 q k3 ] .6. we can calculate the integral over Γ1 by f (x.1.11.qft=*)(f) = int2d(Th. y) in Tk is expressed by the area coordinate as P (ξ.qforder=*)(f) where * stands for the name of quadrature formula or the order of the Gauss formula. (1 ± (1 ± 2 qf1pElump 2 √ 245+14 70 )/2 21 √ 245−14 70 )/2 21 √ 159 exact on Pk .qfe=qf2pE)(f) The integrals over Γ1 . For a two dimensional domain or a border of three dimensional domain Ωh = we can calculate the integral over Ωh by f (x. y) = int2d(Th)(f) Ωh Th = {Tk }.1)(f) Γ1 = int1d(Th. Γ3 are given by f (x. = int2d(Th. y)ds = int1d(Th. k = 1 3 5 7 5 qf5pE 10 √ 1/2 0 +1 √ 18− 30 i j |q q | 72 √ 18+ 30 i j |q q | 72 √ 322−13 70 i j |q q | 1800 64 i j |q q | 225 √ 322+13 70 i j |q q | 1800 |q i q j |/2 9 1 |q i q j |/2 where |q i q j | is the length of segment q i q j . 35 √ 525−70 30 (1 ± √ 35 )/2. . η): k 1 qx 1 k 1 qx 2 k 1 qx 3 k qy 1 k qy 2 k qy 3 1 |Tk | = 2 D1 = 1 x k 1 qx 2 k 1 qx 3 y k qy 2 k qy 3 D2 = k 1 qx 1 1 x k 1 qx 3 k qy 1 y k qy 3 D3 = k 1 qx 1 k2 1 qx 1 x k qy 1 k2 qy y 1 ξ = D1 /|Tk | 2 1 η = D2 /|Tk | 2 1 then 1 − ξ − η = D3 /|Tk | 2 nt k=1 Tk .1. y)ds = int1d(Th. .) 0.45 .042 . 4 see [38] for detail see [38] for detail nt k=1 Tk . |Tk | G4(0.2 3 |Tk |/3 2 1 |Tk |/3 2. y) = int3d(Th)(f) Ωh = int3d(Th. . . 21 21 √ √ 6+ 15 6+ 15 . . .092 . 0. |Tk | G4(1.72 . . 2 1 1 2. 21 21 exact on Pk .073 . |Tk |/3 |Tk |/3 |Tk |/3 |Tk |/12 |Tk |/12 |Tk |/12 |Tk |/12 |Tk |/12 |Tk |/12 |Tk |/6 |Tk |/6 |Tk |/6 1 1 7 9 For a three dimensional domain Ωh = by Th = {Tk }. 0. 0) (0.31 .) 0. .) 0. .225|Tk | 3. . 0. . 4 0.045 . k = 1 2 7 qf5pT 5 (155− 15)|Tk | 1200 √ (155− 15)|Tk | 1200 √ (155− 15)|Tk | 1200 √ (155+ 15)|Tk | 1200 √ (155+ 15)|Tk | 1200 √ (155+ 15)|Tk | 1200 3 qf1pTlump 9 qf2pT4P1 15 21 qf7pT qf9pT 8 10 (0. . 0.qfV=*)(f) = int3d(Th.160 L 1 3 qft= qf1pT qf2pT CHAPTER 6. 0) |Tk |/4 L 1 4 14 qfV= qfV1 qfV2 qfV5 qforder= 2 3 6 exact on Pk . 0. . 21 21 √ √ 6+ 15 9−2 15 . . . 0) (1. 3 1 1 .31 .0 4 3 4. . . |Tk | G6(0. we can calculate the integral over Ωh f (x.58 . . 4 3 1 4. . . . . 21 21 √ √ 9+2 15 6− 15 . . . . 21 21 √ √ 6− 15 9+2 15 . 3 √ √ √ 6− 15 6− 15 . 4 G4(0. . . 0 0.11 . 0. . Quadature formula on a tetrahedron point in Tk ∈ R3 ω 1 1 1 |Tk | 4. 4.45 . 3 4 1 . .092 . .qforder=*)(f) where * stands for the name of quadrature formula or the order of the Gauss formula. 4 1 1 4. 1 4 0. . 1 |Tk |/3 2 1 1 6 0. 0. . 21 21 √ √ 9−2 15 6+ 15 . .067 . . 0. FINITE ELEMENTS Quadature formula on a triangle qforder= point in Tk ω 1 1 2 |Tk | 3. .13 . k = 1 2 5 4 qfV1lump 1 .13 . . . . 0. 1) 1 3 4. .) |Tk |/4 G4(0. 0 1 1 4. ε bn = i b”i if i ∈ Γ24 bi else if ∈ Γ24 (6. b.32) (6. b) such that a + 3b = 1 is the set of the four point in barycentric coordinate {(a. orj = i  Ω (6.34) (6.6. b.35) b0. The variational formulation is in L2 (0. SPARSE MATRIX.be/ ˜nines/research/ecf/mtables.12 Variational Form. a). we shall seek un satisfying ∀w ∈ V0 . b). a. H 1 (Ω)).8*(y<0. (b.i = bcl = u Γ13 0 αuue wi the initial data // file thermal-fast.2.1 . b. Sparse Matrix.12. PDE DATA VECTOR Where G4(a.edp in examples++-tutorial func fu0 =10+90*x/6. bcl ( notation if w is a vector then wi is a component of the vector). PDE Data Vector In FreeFem++ it is possible to define variational forms.31) = tgv = 1030 :  1 if i ∈ Γ24 . un = A−1 bn . and the vectors un . b. andj = i  ε Aij = wj wi /dt + k( wj . .4. (b.5)+0. (a. b. (b. b). b. (b. b). b. Note 6. b. 6. wi ) + αwj wi else if i ∈ Γ24 . b) such that 2a + 2b = 1 is the set of the six points in barycentric coordinate {(a. orj = i  Ω Γ13  1  if i ∈ Γ24 . (b. (a. T=5. b. b. a. b. andj = i ε Mij = wj wi /dt else if i ∈ Γ24 . b)}.33) (6.13 By default. b” = 1 bcl . a. a. Ω un − un−1 w + κ un w) + δt α(un − uue )w = 0 Γ where V0 = {w ∈ H 1 (Ω)/w|Γ24 = 0}.cs. Where with 1 ε b = b0 + M un−1 . b.25.12 These tetrahedral quadrature formulae come from http://www. func k = 1.kuleuven. . a). a)} 161 and where G6(a. a. a. b). VARIATIONAL FORM. dt=0.html Note 6. a). b . (b. alpha=0. b”. we use the formula which is exact for polynomials of degree 5 on triangles or edges (in bold in three tables). a. T . So the to code the method with the matrices A = (Aij ). M = (Mij ). b). b. real ue = 25. and use them to build matrices and vectors and store them to speed-up the script (4 times faster here). a. bn . b. For example let us solve the Thermal Conduction problem of section 3. wait=1. plot(u). to build the right hand size we need 4 vectors. varf vthermic0(u. varf vthermic (u.i++) cout<<dy(u)(6.edp gives a real example of using all this features.i<20. matrix A= vthermic(Vh. // the Dirichlet boundary condition part Note 6.P1).0.0.5.fill=true.dat").v)= int2d(Th)(u*v/dt + k*(dx(u) * dx(v) + dy(u) * dy(v))) + int1d(Th. // constant part of the RHS bcn = vthermic(0. And the new version of the algorithm is now: ofstream ff("thermic.u=1).2 Examples++-tutorial/StokesUzawa. and build the matrices A.v)= int2d(Th)( u*v/dt) real tgv = 1e30. plot(u. fespace Vh(Th.tgv=tgv.0*i/20.t+=dt){ real[int] b = b0 . ff << t <<" "<<u(3. + on(2. Now.ps="thermic. varf vMass (u. // tgv on Dirichlet boundary node ( !=0 ) // we have for the node i : i ∈ Γ24 ⇔ bcn[i] = 0 bcl=tgv*u0[].6.v) = int1d(Th. . // u[] = Aˆ-1*b.4.u=u0.Vh). } for(int i=0. Create three variational formulation.Vh).3)(alpha*u*v) + on(2.u=1). Section 9.t<T.14 The boundary condition is implemented by penalization and vector bcn contains the contribution of the boundary condition u= 1 . FINITE ELEMENTS mesh Th=square(30.[6*x. b += M*u[].3)(alpha*ue*v).0.Vh.5)<<endl. matrix M= vMass(Vh. real[int] real[int] real[int] b0 = vthermic0(0. so to change the boundary condition.162 CHAPTER 6.Vh).eps"). we have just to multiply the vector bc[] by the current value f of the new boundary condition term by term with the operator .1. Vh u0=fu0. // do ∀i: // for the RHS add the the time dependent part // lock boundary part: b[i] = bcn[i] ? bcl[i] : b[i] . b = bcn ? bcl : b . for(real t=0.solver=CG).4.y]).M .9)<<endl.1.*. the default value is f alse. Cholesky or Crout.15 The functions appearing in the variational form are formal and local to the varf definition.u2]. Cholesky. ] " are solver= LU.. function P must be func real[int] P(real[int] & xx) . tolpivotsym= set the tolerance of the pivot sym in UMFPACK strategy= set the integer UMFPACK strategy (0 by default).p) = int2d(Th)( (dy(v1)+dy(v2)) *p) + int2d(Th)(1*p). varf vb2([v1. factorize = if true then do the matrix factorization for LU. tolpivot= set the tolerance of the pivot in UMFPACK (10− 1) and.. The storage mode of the matrix of the underlying linear system depends on the type of solver chosen. for CG the matrix is sparse symmetric positive.. eps= a real expression. Cholesky factorisation (10−20 ). CG. for Crout the matrix is skyline symmetric. Crout. To build matrix A from the bilinear part the variational form a of type varf simply write: A = a(Vh.Wh [. Note that if ε is negative then the stopping test is: ||Ax − b|| < |ε| if it is positive then the stopping test is ||Ax − b|| < |ε| ||Ax0 − b|| The prototype for the precon= name of a function (for example P) to set the preconditioner. . PDE DATA VECTOR 163 Note 6. Crout. The default solver is GMRES. the only important thing is the order in the parameter list.. sparsesolver. UMFPACK . for LU the matrix is sky-line non symmetric. sparsesolver or UMFPACK the matrix is just sparse. LU. GMRES. tgv= Huge value (1030 ) used to implement Dirichlet boundary conditions.v2]. VARIATIONAL FORM..12. for Cholesky the matrix is sky-line symmetric positive definite. . Note 6. like in varf vb1([u1. ε sets the stopping test for the iterative methods like CG..q) = int2d(Th)( (dy(u1)+dy(u2)) *q) + int2d(Th)(1*q). SPARSE MATRIX.16 The line of the matrix corresponding to the space Wh and the column of the matrix corresponding to the space Vh.] ). and for GMRES.6. . // where // Vh is "fespace" for the unknow fields with a correct number of component // Wh is "fespace" for the test fields with a correct number of component Possible named parameters in " [. u2)= int2d(Th.Vh).optimize=false)( + on(1. b = a(0. Vh h .u1=0) + dx(u1)*dx(u2) + dy(u1)*dy(u2) ) on(3.qfnbpE=1)(v).P1).P0). fespace Nh(Th.v)=intalledges(Th. // the space function contant / triangle Nh etak. etak[]= vetaK(0. First to compute a continuous approximation to the function h ”density mesh size” of the mesh T h./count. it can be removed with the keyword optimize as in the following example : varf a(u1. he is the size of the current edge ( lenEdge).y*dy(u)))) +int2d(Th)(chiK*square(hTriangle*(f+dxx(u)+dyy(u))) ).nv). varf vedgecount(u. if this optimization creates problems. .Vh).v)=intalledges(Th.Ph). varf vmeshsizen(u. We add automatic expression optimization by default. Nh areaK.Vh). FINITE ELEMENTS To build the dual vector b (of type real[int]) from the linear part of the variational form a do simply real b(Vh. are the characteristic function of the element of Th. // computation of the mesh size // ----------------------------count=vedgecount(0. real[int] count(Th. // the space function constant / triangle int2d(Th)(chiK).ndof). Effectively. the basic functions of space N h. // mean lenght edge / vertex To compute error indicator for Poisson equation : ηK = K h2 |(f + ∆uh )|2 + K ∂K he |[ ∂uh 2 ]| ∂n where hK is size of the longest edge ( hTriangle). n the normal. Ki Now. // sum length edge / vertex h[]=h[]. A first example to compute the area of each triangle K of mesh T h. // number of edge / vertex h[]=vmeshsizen(0.chiK) = intalledges(Th)(chiK*lenEdge*square(jump(N.u1=1) .chiK) = etaK[]= varea(0. so by construction: etaK[i] = 1|Ki = 1.Ph).4.164 CHAPTER 6. and the numbering is the numeration of the element. just do: fespace Nh(Th. varf varea(unused. we can use this to compute error indicators like in examples AdaptResidualErrorIndicator. fespace Vh(Th.qfnbpE=1)(v/lenEdge).2.P0). varf vetaK(unused.edp in directory examples++-tutorial.x*dx(u)+N. 4).Vh). The named parameters of function interpolate are: inside= set true to create zero-extension. // a full matrix 6. INTERPOLATION MATRIX Remark. Th = square(4.i<N.4).i++) { A(i.3). real [int.int] A(N. if(i+1 < N) A(i.P1)...0) << endl. fespace Wh(Th.13 Interpolation matrix It is also possible to store the matrix of a linear interpolation operator from a finite element space Vh to another Wh to interpolate(Wh . matrix B= interpolate(VH. like in the following example: mesh mesh mesh TH = square(3. cout << sparseA << endl.6. a[i]=i. matrix sparseA=A.i+1)=-i.. 165 fespace VH(TH.Vh). fespace Vh(th.P1). for (int i=0. it is all possible to build interpolation matrix. . matrix BB= interpolate(Wh. Note that the continuous finite functions are extended by continuity outside of the domain.b(N).N). sparseA = 4*sparseA+sparseA*5.) a function. // // build interpolation matrix Vh->VH build interpolation matrix Vh->Wh and after some operations on sparse matrices are available for example int N=10. } b=A*b. cout << "sparseB = " << sparseB(0. real [int] a(N).13. cout << "xxxx\n". A =0.Vh . matrix sparseB=sparseA+sparseA+sparseA.P1). t= set true to get the transposed matrix op= set an integer written below 0 the default value and interpolate of the function 1 interpolate the ∂x 2 interpolate the ∂y 3 interpolate the ∂z .i)=1+i. sparseA = 2*sparseA+sparseA’. th = square(2. 2].30].yy=[. fespace Vh4(Th4.a2. fespace Vh(Th. . assert( diff.wait=1).P0).4). cout << " IV Wh4<-Vh " << IW4 << endl.eps". // here v == vv => here the function is // exended by zero Build interpolation matrix A at a array of points (xx[j]. dop the type of diff operator like in op def. v=v4.4]. matrix IVt0= interpolate(Vh.166 CHAPTER 6. real[int] xx=[. FINITE ELEMENTS U2Vc= set the which is the component of Wh come in Vh in interpolate process in a int array so the size of the array is number of component of Wh . vv[]= IV*v4[]. // cout << " IV Vh<-Vh4 (inside=1) " << IV0 << endl.v[].4].a3.Vh).2.dop=0. Vh4 v4=x*y. // V3h <.V4h.3.Vh4.ps="ThTh4.P1]). c the component number. matrix IW4= interpolate(Wh4.P1]). matrix IW4V= interpolate(Wh4.4].2 (mat interpol. cout << " IV Vh4<-Vhˆt " << IV4t0 << endl..5. matrix IV4t0= interpolate(Vh4.inside=0.P1). int c=0.P1.Vh4). yy[j])) where wi is the basic finite element function.edp) mesh Th=square(4. i = 0..[x*0. So here we have: b1 == 2.P1. vv.linfty<= 1e-6). // // here the function is exended by continuity cout << " IV Vh<-Vh4 " << IV << endl. fespace Wh4(Th4.op=dop. matrix Ixx= interpolate(Vh. int[int] u2vc=[1. b3 == 0 .P1). matrix IV0= interpolate(Vh.5]).inside=1).a4]=[1.V4h V4h [a1. fespace Wh(Th. plot(Th. cout << Ixx << endl.1. like in the following example: (by default the component number is unchanged).3. Vh v. if the put −1 then component is set to 0.b3]=[10.xx. cout << " IV Wh4<-Wh " << IW4 << endl. mesh Th4=square(2.3.[P1. cout << " IV Vh<-Vh4ˆt (inside=1) " << IVt0 << endl.y*0. real[int] diff= vv[] .Vh4. fespace V3h(Th. matrix IV= interpolate(Vh.[P1.Vh).vv || = " << diff. ww[]= Ixx*dd. 2 here i ai j = dop(wc (xx[j].P0). b2 == 4. b1[]=IV34*a1[].composante=c). .inside=1. V3h [b1.2. cout << " || v .b2. // -1 => put zero on the component matrix IV34= interpolate(V3h.-1].U2Vc=u2vc).linfty << endl. real[int] dd=[1.yy. Vh ww.P1.Th4. yy[j]).t=1). fespace V4h(Th4. Example 6.Wh).20. P2.i++) cout << Wh(k.P2).i<kdf. The output is: Nb Of Nodes = 121 Nb of DF = 121 FESpace:Gibbs: old skyline = 5841 new skyline = 1377 nb of degree of freedom : 121 nb of degree of freedom / ELEMENT : 6 df of element 2:78 95 83 87 79 92 . etc.i) gives the number of ith degrees of freedom of element k.ndofK << endl.3 (FE. P1nc.edp) mesh Th=square(5.5). kdf= Wh. fespace Wh(Th. See the following example: Example 6. ∗).i) << " ".. // element 2 cout << " df of element " << k << ":" . cout << " nb of degree of freedom : " << Wh. cout << endl.6. • Wh.ndof gives the number of degrees of freedom or unknown Wh. int k= 2. for (int i=0. where “*” may be P1.ndofK gives the number of degrees of freedom on one element Wh(k.ndof << endl. FINITE ELEMENTS CONNECTIVITY 167 6.nt gives the number of element of Wh • • • Wh.ndofK . cout << " nb of degree of freedom / ELEMENT : " << Wh.14. we show how to get informations on a finite element space Wh (Tn .14 Finite elements connectivity Here. FINITE ELEMENTS .168 CHAPTER 6. 5%] of the screen size. real FE functions .1 Plot With the command plot. so it is very important to render them easy to grasp. meshes. meshes. If true we wait for a keyboard event or mouse event. arrays of two arrays of double. The parameters are wait= boolean expression to wait or not (by default no wait). v to toggle the display of isovalue scale. Another method is to use external tools. isovalues of scalar functions and vector fields can be displayed. . the default view. to see something (else it will only look like porcupine).1 The length of an arrow is always bound to be in [5‰. For publishing purpose. 7. = to restore de initial graphics state.to zoom out around the mouse cursor. to plot respectively a mesh.1 below). FreeFem++ can store these plots as postscript files. f to toggle between color fills and isovalues.2). The parameters of the plot command can be .Chapter 7 Visualization Results created by the finite element method can be a huge set of data. a function. b to toggle into black and white. g to toggle to grey or color . 169 . gnuplot (see Section 7. for example.3) using the command system to launch them and/or to save the data in text files. or a curve defined by the two arrays of double. isovalues of real FE-functions and of vector fields. medit (see Section 7. Note 7. r to refresh the graphic window. There are two ways of visualization in FreeFem++ : One. arrays of 2 real FE functions. supports the drawing of meshes. all by the command plot (see Section 7. c to decrease the vector arrows size. a vector field. ? to show all active keyboard char. they respond to an event by the following characters + to zoom in around the mouse cursor. C to increase the vector arrows size. fill= do a color fill between isovalues.1.vh=-yˆ2+xˆ2.v1.0. aspectratio= boolean to be sure that the aspect ratio of plot is preserved or not. // figure 7. xx[i]=i.si.value=true..5. where hi.i<10.) } plot(Th.vh].uh.0..[0.5). y=i/10.i++) { x=i/10.6]. CHAPTER 7.ps="three. boundary= (bool) to plot or not the boundary of the domain (true by default).5. to set the bounding box and specify a partial view where the box defined by the two corner points [0.170 enter go to the next plot. dim= (int) sets dim of the plot 2d or 3d (2 by default) For example: real[int] xx(10). ESC close the graphics process. . VISUALIZATION ps= string expression for the name of the file to save the plot in postscript coef= the vector arrow size between arrow unit and domain unit.vn]. // compute a cut for (i=0.0. cmm= string expression to write the graphic window into value= to plot the value of isolines and the value of vector arrows.yy(10).[uh.2] and [0. mesh Th=square(5. i/10. Vh uh=x*x+y*y.eps". bb= array of 2 array ( like [[0.wait=true).6]]). int i..1.vi is the ith color to defined the color table. grey= (bool) sets or not the plot in grey color. yy[i]=uh. fespace Vh(Th. hn. otherwise do nothing. .2]. nbiso= (int) sets the number of isovalues (20 by default) nbarrow= (int) sets the number of colors of arrow values (20 by default) viso= sets the array of isovalues (an array real[int] of increasing values) varrow= sets the array of color arrows values (an array real[int]) bw= (bool) sets or not the plot in black and white color.0...1 .vn. // value of uh at point (i/10. hsv= (array of float) to defined color of 3*n value in HSV color model declared for example by real[int] colors = [h1.P1).s1. 10526 1.5 0.85 0. and vector Figure 7.684211 0.05 0.4 0.[uh.vh].15 0.2 plot([xx. the color type (such as red.5. Value) model.4 1.1 1.yy].63158 1.8 0.45 1.9 1 1.52632 1. PLOT 171 // zoom on box defined by the two corner points [0.5.2: enlargement in grey of isovalue.95 1. Saturation.6]].1.0.3 0.73684 1.473684 0. Note that a refinement of the same can be obtained in combination with gnuplot To change the color table and to choose the value of iso line you can do : // // // // // // // from: http://en.[0.0.2 0.9 1 1.7 1.3 1.eps").4 1.wait=true).65 1.1 0.wikipedia.3 0.0. or yellow): Ranges from 0-360 (but normalized to 0-100% in some applications Here) .85 1.2 0. defines a color space in terms of three constituent components: HSV color space as a color wheel 7. // figure 7.55 1.7.org/wiki/HSV_color_space The HSV (Hue.7 0.75 1.789474 0.578947 0. // figure 7.55 0.263158 0.7 0.ps="threeg.0.1: mesh.3: Plots a cut of uh.10526 Vec Value 0 0. wait=true.9 IsoValue -0.5 1. and vector Figure 7.6 0. isovalue.1 0.2].21053 1.42105 1.6 1.75 0.65 0.value=1.8 1.25 0.6 0.7 1.31579 1.6 1.4 Hue.1.894737 1 1.8 0.95 Vec Value 0 0.fill=1. blue.1 1.05 1.eps".1.3 IsoValue 0.6] plot(uh.grey=1.2 1.84211 2.105263 0.3 1.8 1.35 1.2] and [0.5 1.0526316 0.157895 0.9 Figure 7.368421 0.35 0.25 1.45 0.15 1.bb=[[0.2 1.5 0.4 0.ps="likegnu. 1 1.5 0. 1 .4 2. // Value.1 2.5: isovalue with an other color table .8 2.3 2.n.5.8 0.9 1 1. VISUALIZATION // Saturation.1./6..5 . 1. 1. 1 // light red ].7 1.viso=viso(0:viso.i++) viso[i]=i*0.9 3 Figure 7.. plot(uh.6 0.7 0. 1 . for (int i=0.n-1).8 1.5 2..3 0. 1.172 CHAPTER 7. the "vibrancy" of the color: Ranges from 0-100% // The lower the saturation of a color. the more "grayness" is present // and the more faded the color will appear. real[int] viso(31).2 0. 1.fill=1. // dark blue 4. 1 .7 2.6 1.1 0.wait=1.3 1.5 1. // blue 5. // red 1.value=1.4 1.2 1.9 2 2.4 0. // magenta 1./6. 0.2 2./6.4: hsv color cylinder Figure 7.6 2. .hsv=colorhsv). IsoValue -0 0.i<viso. the brightness of the color: // Ranges from 0-100% // real[int] colorhsv=[ // color hsv model 4. 0. 2 shows how to generate a gnu-plot from a FreeFem++ file.5 1. } } // the file plot.3 link with medit As said above.gnuplot. for (int i=0.gp").7. and only on unix computer.gp" 7.i<=n.fr/gamma/medit/medit. // 0. Add to the previous example: { // file for gnuplot ofstream gnu("plot.e.eps\" \ replot \ quit’ | gnuplot"). 1 2 http://www. Remark: Now medit software is include in FreeFem++ under ffmedit name.gp\" w l \ pause 5 \ set term postscript \ set output \"gnuplot.inria.info/ http://www-rocq.html . But this work only if gnuplot1 is installed . one doesn’t need to quit FreeFem++ to generate a gnu-plot. Then you may run the following example. LINK WITH GNUPLOT 173 7.5 0 0 5 10 15 20 Figure 7.i++) { gnu << xx[i] << " " << yy[i] << endl. Let us present here another technique which has the advantage of being online.6: Plots a cut of uh with gnuplot 1 2 "plot. medit 2 is a freeware display package by Pascal Frey using OpenGL.gp is close because the variable gnu is delete to call gnuplot command and wait 5 second (thanks to unix command) // and make postscript plot exec("echo ’plot \"plot.2 link with gnuplot Example 3. i.2. bb").points and mm.P1). fespace Vh(Th.10.n . Vh u=2-x*x-y*y. Vh u=2-x*x-y*y.[x.174 CHAPTER 7.P1). // save mm."mm".y. clean files on unix OS call medit command .2*y-1]).[2*x-1. } // exec("ffmedit mm").faces file // for medit // build a mm.bb mm.2 or better load "medit" mesh Th=square(10. medit("mm".2*y-1]).bb file { ofstream file("mm. for (int j=0.points"). // exec("rm mm.u).n << " 2 \n".u*.10.7: medit plot Now with version 3. savemesh(Th.j<u[]. j++) file << u[][j] << endl. fespace Vh(Th. VISUALIZATION Figure 7. Before: mesh Th=square(10. file << "2 1 1 "<< u[].[2*x-1.faces mm.5]). will give the solution of x of J(x) = 0. 8. The stopping test is J(x) Writing the minus value in eps=.. NLCG( J. and a vector x of type ( of course the number 20 can be changed) real[int] x(20). eps= − ). nbiter. we can use the stopping test J(x) The parameters of these three functions are: nbiter= set the number of iteration (by default 100) 2 P P ≤ J(x(0) ) P ≤ 175 .edp file. and we just need the function (named dJ for example) which compute J. We can omit parameters precon. and an error tolerance 0 < < 1: Put x = x(0) and write NLCG( J. precon= M . a maximum number imax of iterations. Here M is the preconditioner whose default is the identity matrix. nbiter= imax . x.1 conjugate Gradient/GMRES Suppose we want to solve the Euler problem (here x has nothing to do with the reserved variable for the first coordinate in FreeFem++ ): find x ∈ Rn such that J(x) = ∂J (x) ∂xi =0 (8. If the function is convex we can use the conjugate gradient to solve the problem. Given an initial value x(0) .e. nbiter= imax . so the parameters are the name of that function with prototype func real[int] dJ(real[int] & xx). i. which compute J. x. eps.1) where J is a functional (to minimize for example) from Rn to R. precon= M .Chapter 8 Algorithms The complete example is in algo. to initialize the process and get the result. eps= ). // Ph alpha.1 (algo.Vh).4.uh=0). cout << "J(u) =" << r << " " << u.176 CHAPTER 8.uh=0). under the boundary condition u = 0 on ∂Ω. return r.4. eps= set the value of the stop test ε (= 10−6 by default) if positive then relative test || J(x)||P ≤ ε|| J(x0 )||P . if positive then relative test || J(x)||P ≤ ε|| J(x0 )||P . func real J(real[int] & u) { Vh w. // copy array u in the finite element function w alpha=df( dx(w)*dx(w) + dy(w)*dy(w) ).w[]=u.max << endl. // optimization varf au(uh. */ varf alap(uh. verbosity=0. P veps= set and return the value of the stop test. ALGORITHMS precon= set the preconditioner function (P for example) by default it is the identity. Vh w. Example 8.vh) = int2d(Th)( alpha*( dx(w)*dx(vh) + dy(w)*dy(vh) ) .edp) For a given function b.min << " " << u.w[]=u. // warning no return of local array } We want to construct also a preconditioner C with solving the problem: find uh ∈ V0h such that ∀vh ∈ V0h .2. // copy array u in the finite element function w real r=int2d(Th)(0. verbosity=verb. the current value of the solution // of store df (| u|2 ) // optimization func real[int] dJ(real[int] & u) { int verb=verbosity. } // ----------------------Vh u=0. 1+x f (x) = 1 (1 + x)2 f (x) = ax + x − ln(1 + x). return u. otherwise the absolute test is || J(x)||2 ≤ |ε|. . int iter=0.3. remark the prototype is func real[int] P(real[int] &x).vh)= int2d(Th)( alpha *( dx(uh)*dx(vh) + dy(uh)*dy(vh) )) + on(1.b*vh) + on(1.2. alpha=df( dx(u)*dx(u) + dy(u)*dy(u) ).3.5*f( dx(w)*dx(w) + dy(w)*dy(w) ) . otherwise the absolute test is || J(x)||2 ≤ |ε|. u= au(0. let us find the minimizer u of the functional J(u) = 1 2 f (| u|2 ) − Ω Ω ub f (x) = a + x . Ω α uh .b*w) . vh = Ω bvh where α = f (| u|2 ). The return value is minus P the real stop test (remark: it is useful in loop). we can use the non-linear version of GMRES algorithm (the functional J is just convex) LinearGMRES( J. CONJUGATE GRADIENT/GMRES 177 varf amass(uh)= int2d(Th)( uh*vh) + on(1. return u. 1.i++) { conv=NLCG(dJ. eps= ± ). // // matrix Amass = alap(Vh.solver=Cholesky.veps=eps).Vh. x. consider the quadratic form 1 J(x) = xT Ax − bT x 2 then J(x) is minimized by the solution x of Ax = b. x.wait=1.1.Vh. } plot (u. // if (conv) break. int conv=0. If A is not symmetric. eps= ± ). nbiter= imax . // recompute alpha optimization Alap = alap(Vh.nbiter=10. precon= M .i<20.4.factorize=1).solver=CG). cout << " restart with new preconditionner " << conv << " eps =" << eps << endl.cmm="solution with NLCG").Vh. For a given symmetric positive matrix A.3].uh=0). In this case. recompute the preconditioner and restart the conjugate gradient: */ verbosity=5.3.8. precon= M . // if converge break loop alpha=df( dx(u)*dx(u) + dy(u)*dy(u) ).precon=C. For detail of these algorithms.factorize=1). we can use GMRES(Generalized Minimum Residual) algorithm by LinearGMRES(A. precon= M . we can use the function LinearCG LinearCG(A.solver=Cholesky. we make 10 iteration of the conjugate gradient. nbiter= imax . // func real[int] C(real[int] & u) { real[int] w = Amass*u. . refer to [14][Chapter IV. Also. nbiter= imax .2. } the preconditionner function // no return of local array variable /* To solve the problem.u[]. x. u = Alapˆ-1*w. eps= ± ). real eps=1e-6. for(int i=0. matrix Alap= alap(Vh. These two ones are directly available in FreeFem (no dynamical link to load).eps=1. the dJ argument is omitted and there are some other named parameters to control the behaviour of the algorithm. except that.. 8.178 CHAPTER 8. b=1.i<u..u.stopTolFun=1e-6. for (int i=0. ALGORITHMS 8.b[i]*u[i]. This algorithm works with a normal multivariate distribution in the parameters space and try to adapt its covariance matrix using the information provides by the successive function evaluations (see [43] for more details). return u.nbiter=20. because their implementation uses full matrices. as it is a derivative free optimizer. cout << "minimal value is " << min << " for u = " << u << endl. We also provide several optimization algorithms from the NLopt library [42] as well as an interface for Hansen’s implementation of CMAES (a MPI version of this one is also available).\n" .stopMaxIter=3000). } // the grad of J (this is a affine version (the RHS is in ) func real[int] DJ(real[int] &u) { for (int i=0.n.i++) s +=(i+1)*u[i]*u[i]*0.. No specified value will lead to a clock based seed initialization. // set right hand side and initial gest BFGS(J.2. cout << "J ="<< s << " u =" << u[0] << " " << u[1] << ". Named parameters for this are the following : seed= Seed for random number generator (val is an integer). cout << "BFGS: J(u) = " << J(u) << endl.n. func real J(real[int] & u) { real s=0. Thus. size of the sample generations etc. .u(10). Using the CMA evolution strategy is almost the same.2 Optimization Two algorithms of COOOL a package [27] are interfaced with the Newton Raphson method (call Newton) and the BFGS method. an example of utilization would be (see cmaes-VarIneq.. return s.i++) u[i]=(i+1)*u[i]-b[i].edp for a complete example): load "ff-cmaes" .. // return of global variable ok }.5 . // define J. Be careful with these algorithms. some specific parameters can be passed to control the starting distribution.1 Example of utilization for BFGS or CMAES real[int] b(10).e-6. With the same objective function as above.dJ. u=2.nbiterline=20). These last algorithms can be found as dynamical links in the example++-load folder as the ff-NLopt and CMA ES files (CMA ES MPI from the example++-mpi folder for the mpi version).u..i<u. u and all here real min = cmaes(J. initialStdDevs= Same as above except that the argument is an array allowing to set a value of the initial standard deviation for each parameter. The default value is 103 . More parameters related to the CMA-ES algorithm can be changed with this file. All the nlOpt features are called that way : load "ff-NLopt" .par. // unavoidable part grad = <name of grad(J)> .2 The nlOpt optimizers The ff-NLopt package provides a FreeFem interface to the free/open-source library for nonlinear optimization. as well as many bibliographical links. see [43] for more details. // if needed lb = // lower bounds array . some constraints etc. u. default is 10−12 . Increasing the population size usually improves the global search capabilities at the cost of an at most linear reduction of the convergence speed with respect to popsize. try rescaling the problem). Set to 900(n + 3)2 by default. stopTolXFactor= Stopping criteria triggered when the standard deviation increases more than this value. the initial covariance matrix will be set to σI. 8. stopMaxIter= Integer stopping the search when stopMaxIter generations has been sampled. If the value σ is passed. One needing detailed informations about these algorithms should visit the said cite where a description of each of them is given. stopTolFunHist= Stops the algorithm if function value differences of the best values are smaller than the passed one. stopTolX= Stopping criteria triggered if step sizes in the parameters space are smaller than this real value. All the algorithms are well documented in [42]. stopTolFun= Stops the algorithm if function values differences are smaller than the passed one.2. thus easing the use of several different free optimization (constrained or not) routines available online along with the PDE solver. default is 0 (unused).. default is 0.. Default is 0. A sample of it can be found in the examples++-load/ffCMAES/ folder under the name initials. Entries differing by several orders of magnitude should be avoided (if it can’t be. paramFile= This string type parameter allows the user to pass all the parameters using an extern file as in Hansen’s original code. OPTIMIZATION 179 initialStdDev= Value for the standard deviations of the initial covariance matrix (val is a real).3.. The expected initial distance between initial X and the argmin should be roughly initialStdDev.. Note that the parameters passed to the CMAES function in the FreeFem script will be ignored if an input parameters file is given.8. stopMaxFunEval= Stops the algorithm when stopMaxFunEval function evaluations have been done. thus no exhaustive informations concerning their mathematical specificities will be found here and we will focus on the way they are called in a FreeFem script.u.2. popsize= Integer value used to change the sample size. real min = nloptXXXXXX(J. where n is the parameters space dimension . Unused by default. The default value is 4 + 3 ln(n) . // define J. and maybe grad(J). etc. One can refer to the table after the parameters description to check which are the named parameters supported by a specific algorithm. And as usual. optional or unsupported for others.2 for more details about how these constraints have to be implemented.). both argument and result should have the size n). etc. you will get a warning message at runtime (for exemple if you pass a gradient to a derivative free algorithm. J is a function taking a real[int] type array as argument and returning a real. CHAPTER 8. grad. gradIConst/gradEConst : Use to provide the inequality (resp. specific parameters. Just pass the tag of the desired local algorithm with a string.unused if not specified): IConst/EConst : Allows to pass the name of a function implementing some inequality (resp. the value at the end being the found argmin. This is needed as soon s a gradient-based method is involved.. it will just be ignored. lb/ub = Lower and upper bounds arrays (real[int] type) of size n. // etc. when it is obvious you are missusing a routine. or a type of constraints. XXXXXX refers to the algorithm tag (not necessarily 6 characters long). ALGORITHMS // upper bounds array // some optional arguments : // constraints functions names. lb and ub are ”half-optionnal” arguments. equality) constraints on the search space. equality) constraints gradient. // stopping criterions. n stands for the dimension of the search space. Using an unsupported parameter will not stop the compiler work and seldom breaks runtime. The function type must be real[int] → real[int] where the size of the returned array is equal to the number of constraints (of the same type .).. In the following description. . or set the population of a non-genetic one. some are gradient-based and other are derivative free. Half-optional parameters : grad= The name of the function which computes the gradient of the cost function (prototype should be real[int] → real[int].. Constraints related parameters (optional . two vectorial functions have to be defined and passed. the size of the matrix returned by its associated gradient must be p × n (the i-th line of the matrix is the gradient of the i-th constraint).180 ub= . These are real[int] → real[int. // algo. subOpt : Only enabled for the Augmented Lagrangian and MLSL method who need a suboptimizer in order to work... in the sense that they are obligatory for some routines but not all..it means that all the constraints are computed in one vectorial function). It is needed in a gradient-based context as soon as an inequality or equality constraint function is passed to the optimizer and ignored in all other cases. Needed for some algorithms. The possible optional named parameters are the following. ignored if defined in a derivative free context. u is the starting position (a real[int] type array) which will be overwritten by the algorithm. note that they are not used by all algorithm s (some does not supports constraints. That said.int] type functions.. In order to mix inequality and equality constraints in a same minimization attempt. Used to define the bounds within which the search variable is allowed to move. See example 8. ). Assuming we have defined a constraint function (either inequality or equality) with p constraints.. . stopTime : Stops the algorithm when the otpimization time in second exceeds this real value. stopMaxFEval : Stops the algorithm when the number of fitness evaluations reaches this integer value. Note that when an AUGLAG or MLSL method is used. stopRelFTol : Stops the algorithm when the relative variation of the objective function is smaller than this real value. equality) constraints. . It is set to a heuristic value by default. OPTIMIZATION 181 tolIConst/tolEConst : Tolerance values for each constraint. the meta-algorithm and the subalgorithm may have different termination criteria..for Sub-Optimizer) to set the ending condition of the sub-algorithm (the meta one uses the ones above) : SOStopFuncValue. If used with AUGLAG or MLSL. depending upon the algorithm and on how slow your function evaluation is. Other named parameters : popSize : integer used to change the size of the sample for stochastic search methods. providing the more important information about which features are supported by which algorithm and what are the unavoidable arguments they need. The following table resume the main characteristics of each algorithm.8. but when the stochastic search is passed to a meta-algorithm. stopRelXTol : Stops the algorithm when the relative moves in each direction of the search space is smaller than this real value. If these ones are not used. Default value is a peculiar heuristic to the chosen algorithm. SOPopSize : Same as above. This is not a strict maximum: the time may exceed it slightly. the following named parameters has been defined (just adding the SO prefix . SOStopRelXTol. for algorithms of this kind. Default value os set to 10−12 for each constraint of any type. nGradStored : The number (interger type) of gradients to ”remember” from previous optimization steps: increasing this increases the memory requirements but may speed convergence. Thus. Stopping criteria : stopFuncValue : Makes the algorithm end when the objective function reaches this real value. This is an array of size equal to the number of inequality (resp. it will only affect the given subsidiary algorithm. the suboptimizer will use those of the master routine. stopAbsXTol : Stops the algorithm when the moves in each direction of the search space is smaller than the corresponding value in this real[int] array. and so on. More details can be found in [42]. stopAbsFTol : Stops the algorithm when the variation of the objective function is smaller than this real value.2. they will then work if it is ommited) For routines with subsidiary algorithms only. indicates that the corresponding feature will depend on the chosen suboptimizer. ● ●/✔ .no scaling Bounds Gradient Constraints SubStochastic -Based Equality Inequality Opt Original Glabonsky’s dividing rectangles Original Glabonsky’s locally biased dividing rectangles Stochastic(?) Global Optimization Randomized Stochastic(?) Global Optimization Low-storage BFGS Principal AXIS Rank-1 shifted limited-memory variable-metric Rank-2 shifted limited-memory variable-metric Truncated Newton Steepest descent restarting truncated Newton BFGS preconditionned truncated Newton BFGS preconditionned truncated Newton with steepest descent restarting ● ● ● ● ● ● ● ● ● ● ✔ ✔ ✔ ● ● ● ● ● ● ● ● ● Controled random search with local mutation Method of moving asymptots Constrained optimization by linear approximations NEWUOA NEWUOA for bounded optimization Nelder-Mead simplex Subplex BOBYQA Improved stochastic ranking evolution strategy Sequential least-square quadratic programming Multi-level single-linkage Low discrepancy multi-level single-linkage Constraints augmented lagrangian Equality constraints augmented lagrangian ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ● ● ✔ ✔ ✔ ● ● ● ● ● ● ● ● ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ● ● ● ● Legend : Supported and optional Should be supported and optional.no scaling Locally biased dividing rectangles . may lead to weird behaviour though. ALGORITHMS Id Tag DIRECT DIRECTL DIRECTLRand DIRECTNoScal DIRECTLNoScal DIRECTLRandNoScal OrigDIRECT OrigDIRECTL StoGO StoGORand LBFGS PRAXIS Var1 Var2 TNewton TNewtonRestart TNewtonPrecond TNewtonRestartPrecond CRS2 MMA COBYLA NEWUOA NEWUOABound NelderMead Sbplx BOBYQA ISRES SLSQP MLSL MLSLLDS AUGLAG AUGLAGEQ Full Name Dividing rectangles Locally biased dividing rectangles Randomized locally biased dividing rectangles Dividing rectangles . Intrinsic characteristic of the algorithm which then need one or more unavoidable parameter to work (for stochastic algorithm.182 CHAPTER 8. the population size always have a default value.no scaling Randomized locally biased dividing rectangles . mesh Th = square(NN.bctol=6. The whole script is in the VarIneq2. Vh gh1=Bord*g1. u2 ) = argmin J(v1 .Vh). Bord[] = Vbord(0.5*dy(v)*dy(w)). real starttol=1e-12.1.tgv=1).2 (VarIneq. Here is the corresponding script to treat this variational inequality problem with one of the NLOpt algorithms. v2 ) ∈ H 1 (Ω)2 . varf BVF(v. as well as the functional J : H 1 (Ω)2 −→ R: J(v1 .gh2=Bord*g2.. func f2=-1.2.5*dx(v)*dx(w) + 0. v1 ≤ v2 a. // and linear parts varf LVF2(v. f2 second members and g1 .P1). OPTIMIZATION 183 Example 8. f2 ∈ L2 (Ω) and g1 .e.4. f1 . // corresponding matrix real[int] b1 = LVF1(0. varf Vbord(v.NN). // Loading nlopt // Datas Instead of defining the J functional with explicit integral on the domain.Vh). // Bord=1 on the border // and 0 inside gh1=g1 on the border and 0 inside // The functional : // func real J(real[int] &X) { Vh u1. func g1=0. Vh In.iter=0. load "ff-NLopt" int NN = 10. u2 as close as possible (in a certain sense) to the solutions of Laplace equation with respectively f1 .w) = on(1.edp.v=1).Vh) . (v1 . g2 Dirichlet boundary conditions with the u1 ≤ u2 almost everywhere constraint. g2 ∈ L2 (∂Ω) four given functions with g1 ≤ g2 almost everywhere.. b2 = LVF2(0.edp) Let Ω be a domain of R2 .Vh.2. // bilinear varf LVF1(v. fespace Vh(Th.u2.w) = int2d(Th)(f2*w). In[] = Bord[] ? 0:1. this method will significantly speed up the approximation of the solution.v2 )∈V This can be interpreted as finding u1 . . but this approach demonstrate how to use all the features of NLOpt in one shot). v2 |∂Ω = g2 . v1 |∂Ω = g1 .. we will write it in quadratic/linear form.e-12. We define the space : V = (v1 . since the corresponding matrix and vector will not change along with the iterations and the FreeFem matrix-vector product is optimized. func f1=1.w) = int2d(Th)(0. v2 ) = 1 2 | v1 |2 − Ω Ω f1 v1 + 1 2 | v2 |2 − Ω Ω f1 v2 The problem consists in finding (numerically) two functions (u1 . v2 ).w) = int2d(Th)(f1*w). int nadapt=3. func g2=0. matrix A = BVF(Vh. // and vectors Then follows a trick that we will use later to pass the boundary conditions as non-linear equality constraints (although these are of course linear ones.3.Bord.8. grad2 = dA*u2[]. for(int i=0.ndof-1) = grad2. } CHAPTER 8.ndof-1). return val. real[int] grad1 = dA*u1[].n). In NLOpt. u1[] = X(0:Vh.ndof). real val = u1[]’*Au1 + u2[]’*Au2.ndof-1)..i+Vh.ndof:2*Vh. return Grad.i<Vh.i) = 1. } return dconst. shame! . for(int i=0. Au2 = A*u2[]. dconst=0.ndof-1). } // so sparse.ndof]. u2[] = X(Vh. Au2 -= b2.i<Vh... Au1 -= b1.184 u1[] = X(0:Vh.ndof. Grad(Vh.u2.ndof:2*Vh.Vh). real[int] Grad(X.w) = int2d(Th)(dx(v)*dx(w)+dy(v)*dy(w)). plot(u1. dconst(i.ndof). return constraints. we must have a gradient ready : varf dBFV(v. ALGORITHMS // splitting the vector // parameters omitted To be able to play with gradient-based algorithm.++i) constraints[i] = X[i] .). The i-th line of this matrix is the gradient of the i-th constraint with respect to the variables of the search space. one constraint must have the form f (X) ≤ 0..u2i <= 0 } One also has to define a gradient for each constraint if a gradient search is to be used.int] dconst(Vh. Constraint gradient must be a function which returns a matrix. iter++. Grad(0:Vh. grad1 -= b1. matrix dA = dBFV(Vh. u2[] = X(Vh. The function is vectorial in order to handle multiple constraints : func real[int] IneqC(real[int] &X) { real[int] constraints(Vh. // u1i ..ndof-1). the u1 ≤ u2 constraint can be expressed directly upon the degree of freedom.ndof) = -1.. } As we use P1 Lagrange finite elements.ndof-1) = grad1.u2. func real[int] dJ(real[int] &X) { Vh u1. real[int] Au1 = A*u1[]. grad2 -= b2.ndof:2*Vh.2*Vh..ndof.int] dIneqC(real[int] &X) { real[int.++i) { dconst(i.X[i+Vh. func real[int.ndof. ++i) if(Bord[][i]) {BordIndex[k]=i.nbe. } return dbc. stopMaxFEval=10000. { int k=0.. this also would avoid the use of large sparse matrix returned by the gradient function (it can be found in the script file.gh2[][I]. One could also use the lb and ub parameters to impose them.. IConst=IneqC.:( Now we fill an initial vector and start the algorithm : real[int] start(2*Vh.nv) = 1.i<Th. start.nv). start(Vh. Gradient of boundary conditions // even sparser. grad=dJ.++i) { int I = BordIndex[i].8. real[int] BordIndex(Th.int] dBC(real[int] &X) // { real[int.f. OPTIMIZATION 185 As mentioned earlier. for(int i=0. dbc(i+Th.. dbc(i. where we set lb to g − and ub to g + ). bc[i] = X[I] . } // Indexes of border d. stopAbsFTol=starttol ). Here we wrap a BFGS algorithm (which only works with unconstraint problems) in the augmented lagrangian method for both equality and inequality constraints. gradEConst=dBC. The script could not work with other finite elements without modifications.ndof).int] dbc(2*Th. // filling the index array for(int i=0.I) = 1. gradIConst=dIneqC.n.2*Th. subOpt="LBFGS".nbe).gh1[][I]. } func real[int. } return bc. for(int i=0. EConst=BC.nbe] = X[I+Th.nv] . // // starting with u1=u2=0 is bad a small difference is needed real mini = nloptAUGLAG(J.nbe). Another legit choice would be to use SLSQP.2.i<Th.01.} } func real[int] BC(real[int] &X) { real[int] bc(2*Th.ndof-1) = 0.nbe..nbe. start(0:Vh.ndof:2*Vh. bc[i+Th. we can work directly on the degree of freedom because of the P1 finite element.i<Bord.nbe. dbc=0. ++k.I+Th.ndof-1) = 0..++i) { int I=BordIndex[i]. Here again. the only gradient-based search of the package supporting these two kinds of constraints (note that the subOpt parameter is gone ) : . we also define a set of equality constraints and their derivatives in order to handle the boundary conditions.. start.edp file). 8. gradIConst=dIneqC. stopMaxFEval=10000. // define J. gradEConst=dBC.2. nothing was said about that to avoid complicating an already relatively long script comment.. If the population size is not changed using the popsize parameter. . IConst=IneqC. or directly one which handles the two kinds of constraints.3 Optimization with MPI The only quick way to use the previously presented algorithms on a parallel architecture lies in parallelizing the used cost function (which is in most real life case.stopTolFun=1e-6. Somehow. One can also try to pass derivative free algorithms to AUGLAG and discard the gradients to see what happens. we provide a parallel version of the CMA-ES algorithm. The true script also has a loop in which the algorithm is restarted after mesh adaptation. ALGORITHMS Figure 8. grad=dJ.u. Just check the tag in the table. EConst=BC. Calling the MPI version of CMA-ES is nearly the same as calling its sequential version (a complete example of use can be found in the cmaes-mpi-VarIneq. see the MPI section of this manual for more informations about communicators in FreeFem++. stopAbsFTol=starttol ). these N calculus are then equally distributed to each processes. The user can specify his own MPI communicator with the named parameter ” comm=”. The FreeFem mpicommworld is used by default. u and all here real min = cmaesMPI(J. The parallelization principle is the trivial one of evolving/genetic algorithms : at each iteration the cost function has to be evaluated N times without any dependence at all. it will use the heuristic value slightly changed to be equal to the closest greater multiple of the size of the communicator used by the optimizer.1: Numerical Approximation of the Variational Inequality real mini = nloptSLSQP(J.186 CHAPTER 8..: load "mpi-cmaes" .stopMaxIter=3000). cout << "minimal value is " << min << " for u = " << u << endl. the expensive part of the algorithm). y) + ∂nx δx (x. We see that the vertical force due to the tension µ acting along the edge AD is −µnx (x. y + δy)). Users are invited to contribute to make this data base of problems grow. u(x. y. y. It is a complement to chapter 3 which was only an introduction. ny (x. y. y)δy µ nx (x. y)) the normal vector of the surface z = u(x. B:(x. for the edges AB and DC we have u ( x . y)δy and the the vertical force acting along the edge AD is µnx (x + δx. 9.y ) T T T u ( x + d x . C:(x. y) (x2 + y 2 < 1) under a vertical pressure p in terms of force per unit area and an initial tension µ in terms of force per unit length. µ (ny (x. nz (x. y)) of the vertical displacement u(x. y) = (nx (x. x = cos t. y). 0 ≤ t ≤ 2π}. y = sin t.y + d y ) u ( x + d x . ∂x Similarly. Consider the “small plane” ABCD. y)). u(x + δx.y + d y ) T u ( x . u(x.1 9. y). y). y)δx. y)δx.1. y) + ∂ny /∂y) (x. 187 . u(x + δx.Chapter 9 Mathematical Models Summary This chapter goes deeper into a number of problems that FreeFem++ can solve. y + δy)) and D:(x.y ) (¶ u /¶ x )d x −µny (x.1 Static Problems Soap Film Our starting point here will be the mathematical model to find the shape of soap film which is glued to the ring on the xy−plane C = {(x. y. y)). Denote by n(x. A:(x. y. u(x. y). y)δy. We assume the shape of the film is described by the graph (x. // // // bilinear form // linear form boundary condition ue: exact solution plot (u.v.1) where f = p/µ.v) = int2d(disk)( dx(u)*dx(v) + dy(u)*dy(v) ) .value=true. ∂u/∂y. x2 + y 2 < 1}.ue. δy → dy. for simplify.ps="aTutorial.188 CHAPTER 9. Example 9. Letting δx → dx. disk = adaptmesh(disk. The soap film is glued to the ring ∂Ω = C. problem laplace(u. plot(err.1 (a tutorial.value=true. we can find the virtual displacement write the following −∆u = f in Ω (9. mesh disk = buildmesh(a(50)). femp1 err = u . we have νx = (∂u/∂x)/ νy = (∂u/∂y)/ 1 + (∂u/∂x)2 + (∂u/∂y)2 1 + (∂u/∂x)2 + (∂u/∂y)2 ∂u/∂x.label=1. func ue = (xˆ2+yˆ2-1)/4. laplace. y = sin(t). y). func f = -1.P1). cout << "error H10=" << sqrt( int2d(disk)((dx(u)-x/2)ˆ2) + int2d(disk)((dy(u)-y/2)ˆ2))<< endl.01). fespace femp1(disk.err=0. // become FE-function on adapted mesh .edp) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : border a(t=0. Assuming small displacements. MATHEMATICAL MODELS The force in the vertical direction on the surface ABCD due to the tension µ is given by µ (∂nx /∂x) δxδy + T (∂ny /∂y) δyδx.wait=true). Ω = {(x. plot(disk). Using the Laplace operator ∆ = ∂ 2 /∂x2 + ∂ 2 /∂y 2 .value=true. Poisson’s equation (2.u. plot (u.wait=1).1) appears also in electrostatics taking the form of f = ρ/ where ρ is the charge density.2*pi){ x = cos(t). err = u . then we have the boundary condition u = 0 on ∂Ω (9. we assume that f = −1. femp1 u.ue.wait=true).2) If the force is gravity.wait=true). we have the equilibrium of the vertical displacement of soap film on ABCD by p µdxdy∂ 2 u/∂x2 + µdxdy∂ 2 u/∂y 2 + pdxdy = 0. plot(disk. cout << "error L2=" << sqrt(int2d(disk)( errˆ2) )<< endl. the dielectric constant and u is named as electrostatic potential. laplace.eps".u=0) .}.int2d(disk)( f*v ) + on(1. wait=true).4) .9.181434 -0.3) where ρ is the charge density and is called the permittivity of free space.206459 -0. The results are uh − ue 0.··· .0375506.156409 -0. CK within an enclosure C0 . After the adaptation.Ω = 0. we hava uh − ue 0. From the second equation in (9. : cout << "error H10=" << sqrt(int2d(disk)((dx(u)-x/2)ˆ2) : + int2d(disk)((dy(u)-y/2)ˆ2))<< endl.Ω = 0. STATIC PROBLEMS 30 31 32 33 : plot(err.0312817 -0.K .0188411.243997 -0.0563071 -0.Ω = 0.1.000109043. the H 1 -error seminorm estimation 1/2 |uh − ue |1.0813324 -0. curlE = 0 (9. We now obtain the equipotential line which is the level curve of φ.2 Electrostatics We assume that there is no current and a time independent charge distribution. f = −ρ/ .168921 -0. Then we have Poisson’s equation −∆φ = f .143896 -0. So the numerical solution is improved by adaptation of mesh. |uh − ue |1.Ω = Ω |uh − ue |2 dxdy and from 20th line to 21th line.000384045. · · · . Then the electric field E satisfies divE = ρ/ .Ω = Ω | uh − ue |2 dxdy are done on the initial mesh. 1/2 uh − ue 0.193947 -0.1: isovalue of u In 19th line.2: a side view of u Figure 9.3). Let us assume K conductors C1 . |uh − ue |1.0938451 -0.0437944 -0.0688198 -0.218972 -0. we must solve −∆ϕ = 0 in Ω. 9.1.value=true.00625634 Figure 9.Ω = 0. when there are no charges except conductors {Ci }1. : cout << "error L2=" << sqrt(int2d(disk)( errˆ2) )<< endl.231485 -0. the L2 -error estimation between the exact solution ue . (9. In order to know ϕ(x) at any point x of the domain Ω. Each one is held at an electrostatic potential ϕi .11887 -0.106358 -0. We assume that the enclosure C0 is held at potential 0.018769 -0. 189 IsoValue -0.131383 -0. we can introduce the electrostatic potential such that E = − φ. uh=1) + on(C2.. Vh uh.N. whereas the elliptical holes are described clockwise. C2 = {(x.wait=true).190 CHAPTER 9. C1 = 1 1 {(x. that is N Ci . } border C2(t=0..5) Example 9.3 * cos(t). where C1 is located in right hand side .2*pi) { x = -2+0. y = 5 * sin(t). // a circle with center at (0 . y = 3*sin(t). } border C1(t=0.2 First we give the geometrical informations. ϕ = 0 on C0 . MATHEMATICAL MODELS where Ω is the interior of C0 minus the conductors Ci .4 Figure 9.0) and radius 5 border C0(t=0. Let Ω be the disk enclosed by C0 with the elliptical holes enclosed by C1 and C2 .uh=-1) . i=0 Here g is any function of x equal to ϕi on Ci and to 0 on C0 . y) : 0. because the boundary must be oriented so that the computational domain is to its left. fespace Vh(Th. C0 = {(x. i = 1.32 (x − 2)2 + 312 y 2 = 1}.2*pi) { x = 2+0.uh=0) // + on(C1. and Γ is the boundary of Ω.vh) = // int2d(Th)( dx(uh)*dx(vh) + dy(uh)*dy(vh) ) + on(C0.ps="electroMesh").4: Equipotential lines. (9.eps". plot(Th.3: Disk with two elliptical holes Figure 9. Note that C0 is described counterclockwise.2*pi) { x = 5 * cos(t). // problem Electro(uh.3 * cos(t).P1).ps="electro. } mesh Th = buildmesh(C0(60)+C1(-50)+C2(-50)).32 (x + 2)2 + 312 y 2 = 1}. // figure 9. The boundary equation is a reduced form for: ϕ = ϕi on Ci . see figure 9. // figure 9. x2 + y 2 = 52 }. // solve the problem.3 // P1 FE-space unknown and test function. y) : 0. y = 3*sin(t).4 for the solution plot(uh. definition of the problem // bilinear boundary condition on C0 // +1 volt on C1 // -1 volt on C2 Electro.vh. y). 212836x2 + 0. ϕ|Γ1 = y − 0. ϕ|Γ2 = c. An equation for the upper surface of a NACA0012 (this is a classical wing profile in aerodynamics. .11) −∆ϕ1 = 0 in Ω. 0). One finds c by solving: − ∆ϕ0 = 0 in Ω. −0. }.13) Example 9.1.2*pi) { x=5*cos(t).06254x4 . ϕ1 |Γ1 = 0.12) (ϕ1 |P + + ϕ1 |P − − 2) which can be programmed as: c=− ϕ0 (0. We have ∂nϕ − (ϕ(P + ) − ϕ(P ))/δ where P + is the point just above P in the direction normal to the profile at a distance δ. Thus ϕ0 |P + + ϕ0 |P − c=− . } border lower(t=1.17735 x − 0. (ϕ1 (0.01) + ϕ0 (0. (9. ϕ|Γ∞ = u∞1x − u∞2x (9. we shall determine c by requiring the continuity of ∂ϕ/∂n at the trailing edge.06254*(tˆ4).99.8) Taking an incidence angle α such that tan α = 0. As previously. y = 0. the solution ϕc is a linear function of c ϕc = ϕ0 + cϕ1 . ϕ|S = c.7) where ϕ0 is a solution of (9.17363*(tˆ3)-0. ϕ0 |Γ1 = y − 0. (9.1) { x = t.01) − 2) (9.9.99.99. // approximates infinity border a(t=0. border upper(t=0. The solution ϕ = ϕ0 + cϕ1 allows us to find c by writing that ∂n ϕ has no jump at the trailing edge P = (1.17735*sqrt(t)-0. Lift is proportional to c.1x. −0. The method of decomposition is used to apply the Joukowski condition // The solution is seeked in the form psi0 + beta psi1 and beta is // adjusted so that the pressure is continuous at the trailing edge y=5*sin(t). As all equations in (9. With these two fields computed.075597*t .9) where Γ2 is the wing profile and Γ1 is an approximation of infinity. (9. ϕ1 |Γ2 = 1.1. Infinity will be represented by a large circle Γ∞ . c is a constant to be determined so that ∂n ϕ is continuous at the trailing edge P of S (so-called Kutta-Joukowski condition).1x. STATIC PROBLEMS 191 9.01) + ϕ1 (0. (9. (9.01) . the rear of the wing is called the trailing edge) is: √ y = 0.10) (9.075597x − 0.6) are linear.17363x3 − 0.3 // // Computation of the potential flow around a NACA0012 airfoil.6) where Ω is the area occupied by the fluid. ϕ0 |Γ2 = 0. 0. we must solve ∆ϕ = 0 in Ω.0. 0. we must solve −∆ϕ = 0 in Ω.1. u∞ is the air speed at infinity.0) { x = t.212836*(tˆ2)+0. To find c we use a superposition method.3 Aerodynamics Let us consider a wing profile S in a uniform flow.99. Thus the jump of ∂n ϕ is (ϕ0 |P + + c(ϕ1 |P + − 1)) + (ϕ0 |P − + c(ϕ1 |P − − 1)) divided by δ because the normal changes sign between the lower and upper surfaces.6) with c = 0 and ϕ1 is a solution with c = 1 and zero speed at infinity. 075597*t -0.bw=true).-0. MATHEMATICAL MODELS y= -(0.99.1*x) // + on(upper.dy(psi)ˆ2.psi0=y-0.5: (∂y ψ)2 isovalue of cp = −(∂x ψ)2 − Figure 9.192 CHAPTER 9.6: Zooming of cp .vh) = // int2d(Th)( dx(psi1)*dx(vh) + dy(psi1)*dy(vh) ) + on(a. ZVh Zpsi=psi.vh. plot(Zpsi. y=0. plot(psi0).5.lower.lower.psi1=1).06254*(tˆ4)).01).17735*sqrt(t)-0.99.99.99. Vh psi0.8*sin(t). fespace Vh(Th.01)-2). // continuity of pressure at trailing edge real beta = psi0(0. plot(psi1).212836*(tˆ2)+0.-0. Figure 9. // P1 FE space unknown and test function.nbiso=40). beta = -beta / (psi1(0.8*cos(t)+0. ZVh Zcp=cp.psi1=0) // + on(upper. plot(Zcp. plot(psi). definition of the problem // bilinear form boundary condition form definition of the problem // bilinear form boundary condition form Vh psi = beta*psi1+psi0.P2).P2).01)+ psi1(0. solve Joukowski1(psi1. plot(cp). } border c(t=0.0. solve Joukowski0(psi0. mesh Zoom = buildmesh(c(30)+upper(35)+lower(35)).2*pi) { x=0. } wait = true.vh) = // int2d(Th)( dx(psi0)*dx(vh) + dy(psi0)*dy(vh) ) + on(a.01)+psi0(0.0.17363*(tˆ3)-0.psi0=0). ZVh cp = -dx(psi)ˆ2 . // fespace ZVh(Zoom. mesh Th = buildmesh(a(30)+upper(35)+lower(35)).psi1. 0729566(0. It is known that u ∈ H 2 (Ω) if Ω is convex.P1). then we have the estimates | u− uh |0. // sin(pi*x)*cos(pi*y).14). | u− Ω uh |2 dxdy = Ω u· (u − 2uh ) dxdy + Ω uh · uh dxdy = Ω f (u − 2uh ) dxdy + Ω f uh dxdy The constants C1 . if u is in H 2 (Ω).v.4. func f = x*y.min<<")"<< endl.v) = int2d(Th)( dx(u)*dx(v) + dy(u)*dy(v) ) // bilinear form .int2d(Th)( f*v ) // linear form + on(1. // // bilinear form // linear form boundary condition We can guess that C1 = 0.4 Error estimation There are famous estimation between the numerical result uh and the exact solution u of the problem 2. In this section we check (9. i<=10.4).2. real[int] errL2(10). Instead of the exact solution.0173266) and C2 = 0. so we will use the following for (9.14) and (9. C2 independent of h. } cout << "C1 = " << errL2. We will pick up numericall error if we use the numerical derivative. Ph h = hTriangle.u=0) .1. // boundary condition V0h uu = u. . V0h u0.max <<"("<<errL2.14) 2 u − uh ≤ C2 h (9.max <<"("<<errH1.3.4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : mesh Th0 = square(100.15) with constants C1 . so we will find them by FreeFem++ . fespace Ph(Th. fespace V0h(Th0. here we use the approximate solution u0 in Vh (Th .2: If triangulations {Th }h↓0 is regular (see Section 5. i++) { mesh Th = square(5+i*3. errH1(10).u0)ˆ2) )/h[]. h ∼ 0.0707543).maxˆ2. // get the size of all triangles Vh u. we cannot get the solution u as a elementary functions (see Section 4. fespace Vh(Th. solve Poisson(u.int2d(Th0)( f*v0 ) + on(1.v0. cout << "C2 = " << errH1.P2). C2 are depend on Th and f .5+i*3).1 and 2.Ω (9.max.Ω ≤ C1 h 0.8) even if spetical functions are added. where the numbers inside the parentheses are minimum in calculation.100).4. Example 9.15).2.v0) = int2d(Th0)( dx(u0)*dx(v0) + dy(u0)*dy(v0) ) . solve Poisson0(u0. STATIC PROBLEMS 193 9. for (int i=1.0179253(0.min<<")"<< endl. P2 ).P0). plot(u0). errH1[i-1] = sqrt( int2d(Th0)( f*(u0-2*uu+uu) ) )/h[].u0=0) .3.9.1. errL2[i-1] = sqrt( int2d(Th0)((uu . In general. edp) mesh Th=square(10.25. MATHEMATICAL MODELS 9.255091 0. 0) = u(x.[3.105779 0.edp) real r=0.eps".vh.periodic=[[2. // right problem laplace(uh.391928 -0. Example 9.x]]). // defined the fespacewith // label : 2 and 4 are left and right side with y // 1 and 2 are bottom and upper side with x fespace Vh(Th.0435331 0.x].404403 0. // solve the problem plot(uh). Example 9.)*cos(y+pi/4.). y) = u(2π.143075 -0.0933038 -0. // unknown func f=sin(x+pi/4. // to see the result plot(uh. These boundary conditions are achieved from the definition of the periodic finite element space.7: The isovalue of solution u with periodic boundary condition The periodic condition does not necessarily require parallel boundaries. y) for all y and u(x.292387 -0. laplace.P2. // periodic condition the curve abscissa the curve abscissa and test function. // a diamond with a hole .242616 -0.vh) = int2d(Th)( dx(uh)*dx(vh) + dy(uh)*dy(vh) ) + int2d(Th)( -f*vh ) .) ∗ cos(y + π/4. Example 9.1.ps="period. 2π[2 under bi-periodic boundary condition u(0.10. Vh uh.454174 0. hand side function definion of the problem // bilinear form // linear form IsoValue -0.354633 0.6 give such example.194 CHAPTER 9.[1.342157 -0.503945 Figure 9.5 Periodic Boundary Conditions −∆u = sin(x + π/4.y].20532 0.y].5 (periodic.15555 0.6 (periodic4.[2*x*pi.[4.441699 -0.2*y*pi]).304862 0. 2π) for all x.value=true).) We now solve the Poisson equation on the square ]0.192845 -0.0560083 0.00623761 0. [4. 1] or x − y ∈ [−1.1){ x=t. // 2 second way fespace Vh(Th.[3.x-y]]). 1] // on side c (label 3) x ∈ [−1.label=4.x+y]. laplace. in Ω and ∂n u = 0 on hole.periodic=[[2.}. Vh uh. plot(uh. problem laplace(uh.vh. func f=(y+x+1)*(y+x-1)*(y-x+1)*(y-x-1). y=-t. real k = intf/mTh.}. 0] or x − y ∈ [−1.and with two periodic boundary condition on external border An other example with no equal border.x+y].1){ x=t-1.P2.x-y].[3.1){x=-t+1. y=-r*sin(t). plot(Th.8: The isovalue of solution u for ∆u = ((y + x)2 + 1)((y − x)2 + 1) − k. 1] // so the common abscissa can be respectively x and x + 1 // or you can can try curviline abscissa x − y and x − y // 1 first way // fespace Vh(Th. border e(t=0. func abs=sqrt(xˆ2+yˆ2). int n = 10.}.eps"). just to see if the code works.[4.label=1. border d(t=0.1){ x=-t.label=0.9.vh) = int2d(Th)( dx(uh)*dx(vh) + dy(uh)*dy(vh) ) + int2d(Th)( (k-f)*vh ) .wait=1.wait=1). y=t.[1.}.1.1+x].periodic=[[2. y=1-t.label=2. Figure 9. y=-1+t.732.ps="perio4. real mTh = int2d(Th)(1).label=3. mesh Th= buildmesh(a(n)+b(n)+c(n)+d(n)+e(n)). // warning for periodic condition: // side a and c // on side a (label 1) x ∈ [0.2*pi){ x=r*cos(t). border b(t=0. . real r2=1.1+x]]). border c(t=0.x].P2.x]. STATIC PROBLEMS 195 border a(t=0.}.[1. real intf = int2d(Th)(f). Dx.[4.x. plot(u.edp) verbosity=1.s3]. real Dx=1.8 (Period-Poisson-cube-ballon.Dy.Ay.} // EOM // compute ||AB|| a=(ax.C. fespace Vh(Th.v)=int2d(Th)(Grad(u)’*Grad(v)+ 1e-10*u*v) -int2d(Th)(10*v*((x-gx)*(y-gy)-cc)). s3=dist(Cx.Cy=2. // to see the abscisse value pour the periodic condition.7 (periodic4bis.[2.y)/l4.Ax.s2].value=1).196 Example 9.Cx. l4=dist(Dx.edp) CHAPTER 9.Dy=2. real real real real func func func func l1=dist(Ax. l3=dist(Cx.y)/l1.-t. // to build border AB macro LINEBORDER(A. s4=dist(Dx. // // // // absisse absisse absisse absisse on on on on AB BC CD DA = = = = ||AX||/||AB|| ||BX||/||BC|| ||CX||/||CD|| ||DX||/||DA|| // mesh Th=buildmesh(AB(n)+BC(n)+CD(n)+DA(n). l2=dist(Bx. real gy = (Ay+By+Cy+Dy)/4.Cy). verbosity=6.s1]. Vh u. LINEBORDER(A. cc= int2d(Th)((x-gx)*(y-gy)-cc)/Th. real cc=0.y=A#y*t1+B#y*t. x=A#x*t1+B#x*t. s1=dist(Ax.fixeborder=1).Bx. real Cx=2.2) LINEBORDER(C.5. real Bx=2.Cy.x.By=1.By.1){real t1=1.[3.ay.Ay).x.Cy.bx.lab) border A#B(t=0.5.y)/l2. .By.Dy).A.P1. Example 9.B.By).v.dy(u)] // EOM // real Ax=0.9.Dy. load "msh3" load "tetgen" load "medit" bool buildTh=0..wait=1.. verbosity=1. real gx = (Ax+Bx+Cx+Dx)/4.B.area.Ay=1.y)/l3. cout << " compatibility =" << int2d(Th)((x-gx)*(y-gy)-cc) <<endl.3) LINEBORDER(D. s2=dist(Bx.periodic=[[1.Ay.ay) et B =(bx.1) LINEBORDER(B.4) int n=10.D.by) macro dist(ax.x. solve Poission(u.s4]]).label=lab.by) sqrt(square((ax)-(bx))+ square((ay)-(by))) // EOM macro Grad(u) [dx(u). MATHEMATICAL MODELS irregular boundary condition. When Ω = {(x.y0=0.mesh"). 0 < y < 1}. and u has the expression u = Ki uS + uR .z]. ΓN = {(x. γ2 } = ΓD ∩ ΓN . θ).dy(u). macro Grad(u) [dx(u).7) << endl.vh. 0). y). 1/2 . the singularity will appear at γ1 = (0.4. put the code example page // 5.z]. plot(uh. STATIC PROBLEMS 197 mesh3 Th.0.1)( Grad(uh)’*Grad(vh)*100) + int3d(Th.... −1 ≤ x < 0.1. γ2 (−1. ΓD = ∂Ω \ ΓN . uR ∈ H 2 (near γi ).z0=06. find u such that − ∆u = f u = g in Ω on ΓD . cout << " centre = " << reg(0.. medit(" uh ".y]]).wait=1.x.. Th=readmesh3("Th-hex-sph.z]. θ1 ) = (r.Th.// back and front verbosity=1. problem P(uh. try { // a way to build one time the mesh an read if the file exist.1124 without the first line } fespace Ph(Th.[1.x.periodic=[[3.[5.y].[4.) { buildTh=1.1. verbosity=50. func f= sin(x*2*pi+x0)*sin(y*2*pi+y0)*sin(z*2*pi+z0).x.x.y. real cf= 1. real x0=0. Ph reg=region. fespace Vh(Th.[2. y = 0}.9. Instead of poler coordinate system (r.16) where ΓD is a part of the boundary Γ and ΓN = Γ \ ΓD . 2 with a constants Ki . we use that r = sqrt( xˆ+yˆ ) and 2 2 θ = atan2(y. θj at γj such that (r1 . The solution u has the singularity at the points {γ1 .11. θ).} if( buildTh ){ . y). i = 1.2)( Grad(uh)’*Grad(vh)*2) + int3d(Th) (vh*f) .x) in FreeFem++ .P0). P.dz(u)] Vh uh. −1 < x < 1.P1. 0).z].y.vh)= int3d(Th.3.[6.0) << endl. real gn = 1.0. Here uS = rj sin(θj /2) by the local polar coordinate (rj .0. cout << " exterieur = " << reg(0. ∂u/∂n = 0 on ΓN (9. // EOM 9. } catch(. nbiso=6). uh).6 Poisson Problems with mixed boundary condition Here we consider the Poisson equation with mixed boundary conditons: For given functions f and g. y=0. func ue = K*us + 30*(xˆ2*yˆ2). V0h u0.wait=true). y=1-t. y=t.9: view of the surface isovalue of view a the cut of the solution uh with ffmedit periodic solution uh Example 9. label=2. }. v0. }. } .}.v0) = int2d(T0h)( dx(u0)*dx(v0) + dy(u0)*dy(v0) ) . // given function // the singular term of the solution is K*us (K: constant) func us = sin(atan2(y.1) { x=-1. func f=-2*30*(xˆ2+yˆ2).us).P1). label=2. solve Poisson0(u0.i< 5. }.i++) { mesh Th=adaptmesh(Th. y=0. D1(t=0.int2d(T0h)( f*v0 ) + on(2. D2(t=0.1){ x=t.1){ x=1.us). // // bilinear form // linear form boundary condition adaptation by the singular term .}. y=1.9 Assume that f = −2 × 30(x2 + y 2 ) and g = ue = 10(x2 + y 2 )1/4 sin [tan−1 (y/x)]/2 + 30(x2 y 2 ).10: Figure 9.x)/2)*sqrt( sqrt(xˆ2+yˆ2) ).198 CHAPTER 9. label=2.1) { x=-1+t. where ue S is the exact solution. for (int i=0. plot(T0h. D4(t=0. real K=10. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : border border border border border N(t=0. label=1. fespace V0h(T0h.u0=ue) .2){ x=1-t. mesh T0h = buildmesh(N(10)+D1(10)+D2(10)+D3(20)+D4(10)). MATHEMATICAL MODELS Figure 9. D3(t=0. // mesh Th = adaptmesh(T0h. label=2.. adaptation of meshes are done using the base of singular term. find p such that − ∆p = 1 p = gd in Ω on ΓD . ∀q ∈ P Ωp in Ω in Ω on ΓD . ∂p/∂n = gn on ΓN (9.0150581 where u0 is the numerical solution in T0h and ua is u in this program.Ω is calculated.n qf Ω Ωq . Vh H1err0 = int2d(Th)( dx(err0)ˆ2+dy(err0)ˆ2+err0ˆ2 ).v) = int2d(Th)( dx(u)*dx(v) + dy(u)*dy(v) ) .int2d(Th)( f*v ) + on(2.u = f p = gd where gn is a vector such that gn .18) .Ω /H1e 1.ue.n = gn . plot(u. Vh H1err = int2d(Th)( dx(err)ˆ2+dy(err)ˆ2+errˆ2 ). u0 − ue h ua h − ue 1. gn . 199 // // bilinear form // linear form boundary condition /* calculate the H1 Sobolev norm */ Vh err0 = u0 .n = gn . the relative errors are calculated. P1). Vh err = u .120421 = 0. Vh uue = ue. In 42th line.u = ∂u. Vh u. real H1e = sqrt( int2d(Th)( dx(uue)ˆ2 + dy(uue)ˆ2 + uueˆ2 ) ).v + vv = Γd gd v. The mixte formulation is: find p and u such that p+u = 0 . cout <<"Relative error in adaptive mesh "<< int2d(Th)(H1err)/H1e<<endl. STATIC PROBLEMS 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 : : : : : : : : : : : : : : : : : : : : : fespace Vh(Th. From 24th line to 28th.n on ΓN (9.n on ΓN (9. gd .u=ue) .ps="adaptDNmix. v. that is.Ω /H1e = 0.1. cout <<"Relative error in first mesh "<< int2d(Th)(H1err0)/H1e<<endl.wait=true). H1e= ue 1. solve Poisson(u.n = gn .ps"). /* plot the solution */ plot(Th.7 Poisson with mixte finite element Here we consider the Poisson equation with mixed boundary value problems: For given functions f . ∂u.17) where ΓD is a part of the boundary Γ and ΓN = Γ \ ΓD .9.19) . The variationnal formulation is. ∀v ∈ V0 . h h 9. In last 2 lines.ue.1. func g2n = 1. bc(t=0.3)( gd*(v1*N.y)) // on ΓD + on(4. y=0. the FreeFem++ example.5){x=1-t.200 where the functionnal space are: P = L2 (Ω).1. 9.5){x=1.0.ps="laRTp.P0). 1 2 3 4 5 6 : : : : : : border border border border border border ba(t=0.label=6.u2=g2n).}.edp) First.wait=1.11 (adaptindicatorP2.value=true).15 . label=5.10). label=2.int1d(Th.0e-10.fill=1. be(t=0.q. solver=GMRES. To write.label=3.}.value=true).0.2.eps". y=t. // see Fig. we solve the same problem as in a previous example.5.1. bb(t=0.}.eps=1. MATHEMATICAL MODELS V = H(div) = {v ∈ L2 (Ω)2 . fespace Vh(Th.RT0). here V space is discretize with Raviart-Thomas finite element RT0 and P is discretize by constant finite element P0.}.[v1.eps". we have just to choose the finites elements spaces.1.u1=g1n.ps="lapRTuv. y=1-t.0. func gd = 1.q].5. y=0. bf(t=0.edp) mesh Th=square(10.wait=1. Vh [u1.x +v2*N. label=4.u2].v2].8 Metric Adaptation and residual error indicator We do metric mesh adaption and compute the classical residual error indicator ηT on the element T for the Poisson problem. Ph p. plot([u1.1){x=1-t.1){x=0. fespace Ph(Th.}. CHAPTER 9. func g1n = 1.1){x=0.u2]..v ∈ L2 (Ω)} on ΓN }. y=t. label=1. and V0 = {v ∈ V.p].u2.5. bd(t=0. Example 9.0){x=t. y=1.5. problem laplaceMixte([u1.v2.}. tgv=1e30.dimKrylov=150) = int2d(Th)( p*q*1e-15 // this term is here to be sur // that all sub matrix are inversible (LU requirement) + u1*v1 + u2*v2 + p*(dx(v1)+dy(v2)) + (dx(u1)+dy(u2))*q ) + int2d(Th) ( q) ..n = 0 .5. // on ΓN laplaceMixte.10 (LaplaceRT.. v.coef=0.[v1. plot(p.1. Example 9. max << endl. Nh rho.1.eps=1. fespace Vh(Th.viso=viso.[dx(u). real error=0. u=u. func f=(x-y). plot(Th.ps="ThrhoP2.n). fespace Nh(Th.v. ET is the set of T edge not on Γ = ∂Ω. plot(Th. Th=adaptmesh(Th. nT is the outside unit normal to K.P2).i< 4.i++) viso[i]=10.err=error.wait=1). we can use a variational form to compute ηT .0e-10+ dx(u)*dx(v) + dy(u)*dy(v)) + int2d(Th.i<viso.msh").01.eps"). cout << " indicator2 " << endl.min << " max=" << rho[]. for (int i=0. 2 Of course.P0).nbiso=viso.anisomax=1).chiK) = intalledges(Th)(chiK*lenEdge*square(jump(N.x*dx(u)+N. plot(rho.cmm="Mesh ".0e-6) = int2d(Th.wait=1.y*dy(u)))) +int2d(Th)(chiK*square(hTriangle*(f+dxx(u)+dyy(u))) ).v.Nh).dy(u)]. rho[] = indicator2(0.wait=1).). error = error/2. value=1. rho=rho. Vh u. problem Probem1(u. the local error indicator ηT is:  ηT = h2 ||f + ∆uh ||2 2 (T ) + T L e∈EK 1 ∂uh 2 he || [ ] || 2  ∂nk L (e) 2 where hT is the longest’s edge of T .)/2. we expect to look the graphics by an almost constant function η on your computer as in Fig.min << " " << u[]. plot(u.eps". with test function constant function in each triangle. savemesh(Th.solver=CG.max << endl.wait=1. . cout << u[].qforder=5)( u*v*1. 9.ˆ(+(i-16. cout << "rho = min " << rho[].n. } . for (int i=0. he is the length of edge e."th.11. [g] is the jump of the function g across edge (left value minus right value). /************* 201 Now. 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 : : : : : : : : : : : : : : : : : : : : : : : *************/ varf indicator2(uu.cmm="indicator density ".9. If the method is correct.fill=1.ps="rhoP2. real[int] viso(21).qforder=5)( -f*v). STATIC PROBLEMS 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 : : : : : : : : : : : : : : : mesh Th = buildmesh (ba(6) + bb(4) + bc(4) +bd(4) + be(4) + bf(6)). rho=sqrt(rho).i++) { Probem1. v)=intalledges(Th.00316228 0.qfnbpE=1)(v/lenEdge).qfnbpE=1)(v).6228 100 CHAPTER 9.nv). Example 9.1. to adapt the mesh. max(1/3.9 Adaptation using residual error indicator In the previous example we compute the error indicator.316228 1 3.16228e-07 1e-06 3.h) { /* Th mesh Vh P1 finite element space h the P1 mesh size value */ real[int] count(Th.0316228 0.001 0. and c is an user coefficient generally close to one.*/ . /* mesh size (lenEdge = integral(e) 1 ds) */ varf vmeshsizen(u. /* number of edge / par vertex */ varf vedgecount(u. MATHEMATICAL MODELS Mesh Figure 9.12 (AdaptResidualErrorIndicator. The new mesh size is given by the following formulae: hn+1 (x) = hn (x) fn (ηK (x)) where ηn (x) is the level of error at point x given by the local error indicator.edp) First a macro MeshSizecomputation to get a P1 mesh size as the average of edge length.1 0.202 indicator density IsoValue 1e-08 3.0001 0. now we use it.Vh. ηn /ηn )) where ηn = mean(ηn )c.16228e-05 0.16228 10 31.11: Density of the error indicator with isotropic P2 metric 9. hn is the previous “mesh ∗ ∗ size” field. // macro the get the current mesh size // parameter // in: Th the mesh // Vh P1 fespace on Th // out : // h: the Vh finite element finite set to the current mesh size macro MeshSizecomputation(Th.16228e-06 1e-05 3. /* computation of the mesh size ----------------------------.01 0.16228e-08 1e-07 3.000316228 0.v)=intalledges(Th. and fn is a user function define by fn = min(3. Vh. // // // initial mesh size // the FE function for the mesh size to build a mesh with a given mesh size : meshsize . /* here etaK is discontinous we use the P1 L2 projection with mass lumping ..Vh).sigma. h[]=0.coef) { Vh h=0. cout << " -.h). /*evalutate the mesh size */ MeshSizecomputation(Th. fn = max(min(fn/etastar. fespace Ph(Th.Vh.Vh). etak[]=sqrt(etak[]).Ph. see the previous example. Vh h=hinit. // FE space definition --for the mesh size and solution // for the error indicator fespace Vh(Th.wait=1). varf vun(unused. real etastar= coef*(etak[].min << " " << count.v)=int2d(Th)(etak*v). ------ 2 macro ReMeshIndicator(Th. STATIC PROBLEMS count=vedgecount(0.vindicator. sigma[]= vun(0.max << endl.1.max << endl./ sigma[]. real hinit=0. fn[]= fn[].3.IsMetric=1. h[]=h[].9.sum << " " << endl.nbvx=10000).. varf veta(unused./count.0.bound meshsize = " <<h[].P0). */ /* build the new mesh */ Th=adaptmesh(Th. fn[] = veta(0. /* plot(h. */ Vh fn. cout << " count min = "<< count.3333) .splitpbedge=1. etak[]=vindicator(0.sum/etak[]. cout << " etastar = " << etastar << " sum=" << etak[].P1). // // // // // // // // macro to remesh according the de residual indicator in: Th the mesh Ph P0 fespace on Th Vh P1 fespace on Th vindicator the varf of to evaluate the indicator to coef on etameam .min << " " << h[].h. Ph etak. /* new mesh size */ h = h / fn .2.).v)=int2d(Th)(1*v). } We skip the mesh construction. } // end of macro MeshSizecomputation 203 A second macro to remesh according to the new mesh size.Vh).Ph).Vh).n). h[]=vmeshsizen(0. Ph.y*dy(u)))) +int2d(Th)(chiK*square(hTriangle*(f+dxx(u)+dyy(u))) ).344 -123.0e-10+ .00060581 0.000288288 0.89664e-05 0.26 Figure 9.eps").000253008 0.IsMetric=1. h[ in R3 . for (int i=0. ξ3 ).296 -123.qforder=5)( f*v).392 -123.00057053 0.000464689 0. if(i>5) cc=1.qforder=5)( u*v*1. x2 .000358848 0.44 -123. func f=(x-y).368 -123. ReMeshIndicator(Th.h.000111887 0.chiK) = intalledges(Th)(chiK*lenEdge*square(jump(N.000394129 0.000323568 0.416 -123.452 -123. x3 ) moves to P(ξ1 . Ω ⊂ R2 .308 -123.38 -123. The vector .indicator2. MATHEMATICAL MODELS Th=adaptmesh(Th.000535249 0. ξ2 .wait=1).2 Elasticity Consider an elastic plate with undeformed shape Ω×] − h.x*dx(u)+N.00067637 0.wait=1). Vh u.000182447 0.332 -123.ps="RRI-Th-init.404 -123.284 -123.12: the error indicator with isotropic P1 .i++) { u=u.000711651 0.nbvx=10000).cc). } IsoValue 5.8. we assume that a point P (x1 .Vh.00064109 0.464 -123.000499969 0.32 -123. plot(Th.476 -123.428 -123.356 -123. Poisson.wait=1.v. dx(u)*dx(v) + dy(u)*dy(v)) varf indicator2(unused. real cc=0.488 -123.204 CHAPTER 9. By the deformation of the plate.splitpbedge=1.000147167 0. the mesh and isovalue of the solution 9. problem Poisson(u. plot(Th.v) = int2d(Th.000429409 0.000799851 IsoValue -123.int2d(Th.u. plot(Th.272 -123.i< 10.000217727 0. 2. h[. h[ and u(x1 . cijkl = cijlk . h[. 2eij = ∂uk ∂uk + ∂xi ∂xj ∂uj ∂ui + ∂xj ∂xi τ →0 where νi = ∆xi |∆x|−1 . g3 = is satisfied. we can suppose that f3 = g3 = u3 = 0 and u(x1 . then we may consider that (∂uk /∂xi )(∂uk /∂xi ) ≈ 0 and the following is called small strain tensor εij (u) = 1 2 ∂uj ∂ui + ∂xj ∂xi The tensor eij is called finite strain tensor. If cijkl is constant. Plain stress: The cylinder is assumed to be very thin and subjected to no load on the ends x3 = ±h. [16. where x = (x1 . p. If Hooke’s tensor cijkl (x) do not depend on the choice of coordinate system. ∆x = (∆x1 .22) We now explain the plain elasticity. x + τ ∆x moves approximately to x + u(x). x3 ) = u(x1 . h[. x2 . = gi on ΓN ×] − h. By the deformation. In homogeneous isotropic case. Hooke’s law is the assumption of a linear relation between σij and εij such as σij (x) = cijkl (x)εij (x) with the symmetry cijkl = cjikl . i = 1.g. there is Lam´ constants λ. h[. If the body force f = (f1 . f3 ) is given in Ω×] − h.9. σ3j (x)nj ) where σij (x) is called stress tensor at x. We now calculate the ratio between two segments η(τ ) = τ −1 |∆x|−1 (|u(x + τ ∆x) − u(x) + τ ∆x| − τ |∆x|) then we have (see e. In this case. u3 ) = (ξ1 − x1 . the material is called isotropic at x. then the surface on ∆Π(x) at x is (σ1j (x)nj .32]) lim η(τ ) = (1 + 2eij νi νj )1/2 − 1. . σ2j (x)nj . x2 . ∆x2 . ∆x3 ).43]) satisfying e σij = λδij divu + 2µεij (9.g. x2 ) for all −h < x3 < h. 3 The assumption leads that σ3i = 0 in Ω×] − h. 2. h[ and surface force g is given in ΓN ×] − h. p.20) where δij is Kronecker’s delta. x3 ). ξ3 − x3 ) is called the displacement vector . the contact condition u3 = 0. Consider the small plane ∆Π(x) centered at x with the unit normal direction n = (n1 . the line segment x. x2 . We assume that the elastic plate is fixed on ΓD ×] − h. the material is called homogeneous. h[.2. ELASTICITY 205 u = (u1 . n3 ). f2 . 3 (9. 3 ui = 0 on ΓD ×] − h. Plain strain: On the end of plate. [16. i 1. that is. x + τ ∆x + u(x + τ ∆x) for small τ . ΓN = ∂Ω \ ΓD . µ (see e. x2 ) for all −h < x3 < h. n2 . ΓD ⊂ ∂Ω. u2 . x3 ) = u(x1 . ξ2 − x2 . 2. cijkl = cklij . i = 1.21) (9. If the deformation is small. then the equation of equilibrium is given as follows: − ∂j σij σij nj = fi in Ω×] − h. σ3i = 0. x3 = ±h. ). mesh th = buildmesh( b(20)+c(5)+d(20)+a(5)). ui (x1 . f . εij and εij .*mu*( epsilon(w.P1]).[w.vv].13 (Beam. Similarly we define the mean values f . Introducing the mean values with respect to thickness. MATHEMATICAL MODELS Generalized plain stress: The cylinder is subjected to no load at x3 = ±h. 10[×]0.vv=0) . cout << "lambda. plot([uu.dy(u2).9 macro epsilon(u1.}. g of the body force and surface force as well as the mean values εij and σ ij of the components of stress and strain.206 CHAPTER 9. x2 . x2 ) = 1 2h h u(x1 .gravity ="<<lambda<< " " << mu << " " << gravity << endl.vv) ) ) + int2d(th) (-gravity*s) + on(1. Vh [uu.uu=0.v) ( dx(u)+dy(v) ) // EOM solve bb([uu.(dy(u1)+dx(u2))/sqrt2] // EOM macro div(u. // deformation of a beam under its own weight real sqrt2=sqrt(2.05.mu. Then we obtain similar equation of equilibrium given in (9.edp) Consider elastic plate with the undeformed rectangle shape ]0. 2.10) { x=10-t.label=bottombeam. y=2. In the case of plane stress.wait=1). fespace Vh(th. λ∗ = (2λµ)/(λ + µ). // see lame. y=0 . 2[. real sigma = 0. Example 9.edp example 3. ∀v ∈ V where V is the linear closed subspace of H 1 (Ω)2 . border a(t=2. real mu = E/(2*(1+sigma)).21) replacing Ω×] − h. σij = λ∗ δij divu + 2µεij . // top beam real E = 21.}.s].0) { x=0.vv].2) { x=10. x3 )dx3 −h and we derive u3 ≡ 0.s)*div(uu. respectively.vv) +2.u2) [dx(u1). [w. g.}. The equations of elasticity are naturally written in variational form for the displacement vector u(x) ∈ V as [2µ Ω ij (u) ij (v) + λ ii (u) jj (v)] = Ω f ·v+ Γ g · v. The body force is the gravity force f and the boundary force g is zero on lower and upper side. // left beam border b(t=0.s])= int2d(th)( lambda*div(w.label=1. // rigth beam border d(t=0. h[ with Ω and changing i = 1. label=3. y=t . // a weighting beam sitting on a int bottombeam = 2. real gravity = -0.5. real lambda = E*sigma/((1+sigma)*(1-2*sigma)). y=t .vv]. // bottom of beam border c(t=0.10) { x=t.[P1. . On the two vertical sides of the beam are fixed. In what follows we omit the overlines of u.label=1.s)’*epsilon(uu.29.}. Lxyz).int] Lxyz=[[1. 1[.u3].z+u3*coef].u2=0. gravity = -0.wait=1.2.label=ref2). 5[×]0.mu.-0.2].(dy(u1)+dx(u2))/sqrt2] // macro div(u1.u3)*div(v1.1.5].5]]).u2. 207 Example 9.dy(u2). mesh th1 = movemesh(th.dz(u3).29. mesh3 Thm=movemesh3(Th.5. real real real real E = 21.int] Bxyz=[[0.Bxyz. Vh [u1.v3].u1=0. plot(Th.u2. int [int.5].u3) [dx(u1). real coef= 0.0.v3) +2.0].idp" int[int] Nxyz=[20. wait=1.5.u3) ( dx(u1)+dy(u2)+dz(u3) ) // EOM EOM solve Lame([u1.v2.Thm.]].9. 1[×]0. macro epsilon(u1.max.u3)’*epsilon(v1.v3) ) // ’) ) . mu = E/(2*(1+sigma)).wait=1).u2.v2. int[int] ref2=[1.. lambda = E*sigma/((1+sigma)*(1-2*sigma)).2.vv].P1]).u2. The body force is the gravity force f and the boundary force g is zero on all face except one the one vertical left face where the beam is fixed.14 (beam-3d.int3d(Th) (gravity*v3) + on(1.2]..bb=[[-0.u3=0) .label=ref2). include "cube.5.v2.gravity ="<<lambda<< " " << mu << " " << gravity << endl.[P1.v2.1.y+u2*coef.[2. cout << "lambda.cmm="coef amplification = "+coef ).5e4. (dz(u1)+dx(u3))/sqrt2. [x+uu.transfo=[x+u1*coef.1/dmax.[v1.5. cout << " max displacement = " << dmax << endl. y+vv]). fespace Vh(Th. // see fig ?? .*mu*( epsilon(u1. mesh3 Th=Cube(Nxyz. plot(th1. real dmax= u1[]. [v1.05. real [int.(dz(u2)+dy(u3))/sqrt2.2. real sqrt2=sqrt(2.u3].[0.2]].).]. Thm=change(Thm.u2.[2. sigma = 0.].P1.u2.[0.v3])= int3d(Th)( lambda*div(u1.[2.. ELASTICITY plot([uu.edp) Consider elastic box with the undeformed parallelepiped shape ]0. then the displacement u(x) is decomposed in an open neighborhood Uk of γk as in (see e. we consider the following simple crack Ω = {(x. The undeformed crack Σ is approximated by Σd = {(x. . γ2 . y) : −1 ≤ x ≤ −10 ∗ d. . −1 < y < 1}. If the part ΓN of the boundary ∂Ω is fixed and a load L = (f .30) with d = 0. v = 0 where w(x. MATHEMATICAL MODELS 9. (Cijkl : Hooke’s tensor). so we use the modification of the domain with U-shape channel (see Fig. 5. v) = σij (v)εij (v)/2. σij (v) = Cijkl (x)εkl (v). where Uk . k = 1. −d ≤ y ≤ d} ∪{(x. then the displacement u is the minimizer of the potential energy functional E(v.30.24) where µ is the shear modulus of elasticity. 5. y) : −1 < x < 1. κ = 3 − 4ν (ν is the Poisson’s ratio) for plane strain and 3−ν κ = 1+ν for plane stress. V (ΩΣ ) = v ∈ H 1 (ΩΣ )2 . Unfortunately. k = 1. which are important parameters in fracture mechanics. FreeFem++ cannot treat crack.0001. −d + 0. ∂Lm ∩ U2 = γ2 .g.R (x) 1/2 for x ∈ ΩΣ ∩ Uk . For simplicity. ΩΣ ) = ΩΣ {w(x.1 ∗ x ≤ y ≤ d − 0. εij (v) = (∂vi /∂xj + ∂vj /∂xi )/2. Here Ω stands for the undeformed shape of elastic plate without crack. respectively. (9. v) − f · v} − ΓN g·v over the functional space V (ΩΣ ). 2 are open neighborhoods of γk such that ∂L1 ∩ U1 = γ1 . and C Sk1 (θk ) = C Sk2 (θk ) = 1 1 4µ (2π)1/2 1 1 4µ (2π)1/2 [2κ − 1] cos(θk /2) − cos(3θk /2) −[2κ + 1] sin(θk /2) + sin(3θk /2) −[2κ − 1] sin(θk /2) + 3 sin(3θk /2) −[2κ + 1] cos(θk /2) + cos(3θk /2) . y) : −10 ∗ d ≤ x ≤ 0. on ΓD = ∂Ω \ ΓN . y) ∈ ΩΣ = Ω \ Σ.2. y = 0} with only one crack tip γ = (0. In this example. If the elasticity is homogeneous isotropic. 0).1 ∗ x} and ΓD = R in Fig.23) with uk.R ∈ H 2 (ΩΣ ∩ Uk )2 .1 Fracture Mechanics Consider the plate with the crack whose undeformed shape is a curve Σ with the two edges γ1 . The coefficients K1 (γi ) and K2 (γi ). Σ = {(x. L.208 CHAPTER 9. We assume the stress tensor σij is the state of plate stress regarding (x. y) : −1 ≤ x ≤ 0. 2 (9. g) ∈ L2 (Ω)2 × L2 (ΓN )2 is given. we use three technique: • Fast Finite Element Interpolator from the mesh Th to Zoom for the scale-up of near γ. are called stress intensity factors of the opening mode (mode I) and the sliding mode (mode II). [17]) 2 u(x) = l=1 C Kl (γk )rk Skl (θk ) + uk. Vh [u.1. because a large singularity occurs at γ as shown in (9.P2). which shows the principal stress difference σ1 − σ2 = 2 (σ11 − σ22 )2 + 4σ12 (9.0001. y=cb*(t-1).5. } border C3(t=0.2.[w.v]. } mesh Th = buildmesh (L1(n/2)+L2(n/2)+B(n) +C1(n)+C21(3)+C22(3)+C3(n)+R(n)+T(n)).ca-d) { x=-cb. and the displacement is fixed on R.25) where σ1 and σ2 are the principal stresses. plot(Plate). In opening mode. y=-ca. the photoelasticity make symmetric pattern concentrated at γ.[x+u.wait=1). plot(Th. real mu = E/(2*(1+sigma)).1) { x=(tip-10*d)*t+tip*(1-t). } border T(t=0.[P2. .15 (Crack Opening. fracture engineers use photoelasticity to make stress field visible. real cb=1. } border R(t=0. v). Example 9. real E = 21. int n = 5.2) { x=cb. ca=0.9. y=-d*t.ca-d) { x=-cb.u=0)+on(R.v=0). The first example creates mode I deformation by the opposed surface force on B and T in the vertical direction of Σ. } border C21(t=0. y=-d+t. real sigma = 0.1*(4-x)*s)+int1d(Th. [w.2) { x=cb*(t-1).23).0.1) { x=-ca*(1-t)+(tip-10*d)*t. fespace Vh(Th. y=ca. plot(Zoom. mesh Zoom = buildmesh (L1(n/2)+L2(n/2)+B(n)+C1(n) +C21(3)+C22(3)+C3(n)+R(n)+T(n)). • Adaptivity is an important technique here. } border C22(t=0. tip=0. } border B(t=0.y+v]). cb=0.1) { x=(tip-10*d)*(1-t)+tip*t. mesh Plate = movemesh(Zoom. border L1(t=0. y=d. fespace zVh(Zoom.T)(0. real lambda = E*sigma/((1+sigma)*(1-2*sigma)).1*(4-x)*s) +on(R. we shall watch the deformation of the crack near γ as follows. ca=1.1) { x=(tip-10*d)*(1-t)-ca*t. // fixed . } border C4(t=0. y=ca-t. ELASTICITY 209 • After obtaining the displacement vector u = (u.B)(0.s].2) { x=cb*(1-t).2*d) { x=-ca. solve Problem([u.1.edp} real d = 0. K2 (γ) = 0) {CrackOpen.29. } border C1(t=0.v].s]) = int2d(Th)( 2*mu*(dx(u)*dx(w)+ ((dx(v)+dy(u))*(dx(s)+dy(w)))/4 ) + lambda*(dx(u)+dy(v))*(dx(w)+dy(s))/2 ) -int1d(Th.wait=1). } border L2(t=0. y=-d-t. y=-d.P2]). In a laboratory. y=d*(1-t). bw=1).001) ∗ H(0.01. ca=0.[w. Fig.001) ∗ H(y + 0.y+v]). Sy = lambda*(dx(u)+dy(v)) + 2*mu*dy(v). plot(N. mesh Zoom = buildmesh (L1(n/2)+L2(n/2)+B(n)+C1(n) +C21(3)+C22(3)+C3(n)+R(n)+T(n)).14: COD and Principal stress dif(COD) and Principal stress difference in the ference in the last adaptive mesh first mesh It is difficult to create mode II deformation by the opposed shear force on B and T that is observed in a laboratory. Fig.bw=1).bw=1). Fig.01.v]).[x+u. Vh1 fx = ((y>0.001)*(y<0.eps". 9.14 9.001)*(y>-0. MATHEMATICAL MODELS zVh Sx. = 0 if t < 0. y) = H(y − 0. for (int i=1. that is. i++) { mesh Plate = movemesh(Zoom.P1). the x-component f1 of the body force f is given by f1 (x. Problem. solve Problem([u.1)) . N = 0.13: Crack open displacement Figure 9.13 9.1*1*sqrt((Sx-Sy)ˆ2+4*Sxyˆ2). N.ps="LastCOD.eps". } Th=adaptmesh(Th.eps".1))-((y<-0.16 (Crack Sliding.1) where H(t) = 1 if t > 0. } // deformation near γ // principal stress difference // // // // Fig.ps="1stCOD. Sxy.210 CHAPTER 9. Sx = lambda*(dx(u)+dy(v)) + 2*mu*dx(u). break. i<=5.s]) = .bw=1).1 − y) − H(−y − 0. } else if (i==5) { plot(Plate. Sy.ps="LastPhoto. if (i==1) { plot(Plate. Sxy = mu*(dy(u) + dx(v)). (use same FE-space Vh and elastic modulus) fespace Vh1(Th. plot(N.13 9. K2 (γ) = 0) (use the same mesh Th) cb=0.v]. So we use the body shear force along Σ.ps="1stPhoto. Example 9.eps".14 Figure 9.[u. u=0)+on(R. if (i==1) { plot(Plate. i<=3. break.bw=1). Fig.3. plot(N.v]). N = 0. Problem. 9.[x+u.bw=1).3 Nonlinear Static Problems J(u) = Ω Here we propose to solve the following non-linear academic problem of minimization of a functional 1 f (| u|2 ) − u ∗ b 2 1 where u is function of H0 (Ω) and f defined by f (x) = a ∗ x + x − ln(1 + x). Sy = lambda*(dx(u)+dy(v)) + 2*mu*dy(v). } 211 // fixed // deformation near γ // principal stress difference // // // // Fig. .eps". Sxy = mu*(dy(u) + dx(v)). Sx = lambda*(dx(u)+dy(v)) + 2*mu*dx(u).v=0). NONLINEAR STATIC PROBLEMS int2d(Th)( 2*mu*(dx(u)*dx(w)+ ((dx(v)+dy(u))*(dx(s)+dy(w)))/4 ) + lambda*(dx(u)+dy(v))*(dx(w)+dy(s))/2 ) -int2d(Th)(fx*w) +on(R.16 9.15 9.eps".ps="LastCOD2. } Th=adaptmesh(Th.ps="LastPhoto2.16 Figure 9.ps="1stPhoto2.9. i++) { mesh Plate = movemesh(Zoom.15: (COD) and Principal stress dif. Fig.Figure 9.bw=1). } else if (i==3) { plot(Plate. for (int i=1.eps". f (x) = a + x .[u.16 9. 1+x f (x) = 1 (1 + x)2 .eps".16: COD and Principal stress difference in the first mesh ference in the last adaptive mesh 9. plot(N.y+v]). Fig.1*1*sqrt((Sx-Sy)ˆ2+4*Sxyˆ2).bw=1).ps="1stCOD2. 212 CHAPTER 9. .3.cmm="solution with Newton-Raphson").4. // // // optimization optimization // v = J(u) the dot product // Remark: This example is in Newton. v[]= vdJ(0.4.w.b*vh) + on(1. u[] -= w[]. matrix H= vhJ(Vh.vh) = int2d(Th)( alpha*( dx(u)*dx(vh) + dy(u)*dy(vh) ) . dalpha = 2*ddf( dx(u)*dx(u) + dy(u)*dy(u) ) . 2 Now.2. // // // the Newton algorithm Vh v. MATHEMATICAL MODELS 9.2.3. w[]=Hˆ-1*v[].solver=LU).3.Vh).wait=1.vh) = f’()*( dx(uh)*dx(vh) + dy(uh)*dy(vh) // + 2*f’’()( dx(u)*dx(uh) + dy(u)*dy(uh) ) * (dx(u)*dx(vh) + dy(u)*dy(vh)) varf vhJ(uh. // un+1 = un − ( ∂dJ −1 ) ∗ dJ(un ) ∂ui // --------------------------------------------Ph dalpha . the variational form of evaluate ddJ = 2 J hJ(uh.factorize=1.1 Newton-Raphson algorithm J(u) = 0 with Newton-Raphson algorithm. uh=0). real res= v[]’*v[]. we solve the Euler problem un+1 = un − ( J(un ))−1 ∗ J(un ) J and 2J First we introduce the two variational form vdJ and vhJ to compute respectively // method of Newton-Raphson to solve dJ(u)=0.i++) { alpha = df( dx(u)*dx(u) + dy(u)*dy(u) ) . cout << i << " residuˆ2 = " << res << endl. uh=0). u=0. that is.vh) = int2d(Th)( alpha*( dx(uh)*dx(vh) + dy(uh)*dy(vh) ) + dalpha*( dx(u)*dx(vh) + dy(u)*dy(vh) )*( dx(u)*dx(uh) + dy(u)*dy(uh) ) ) + on(1.edp file of examples++-tutorial directory. // to store 2f (| u|2 ) optimisation // the variational form of evaluate dJ = J // -------------------------------------// dJ = f’()*( dx(u)*dx(vh) + dy(u)*dy(vh) varf vdJ(uh. if( res< 1e-12) break. for (int i=0. } plot (u.i<100.Vh. sigma= ). part of the eigenvalues vector= the FE function array to store the eigenvectors rawvector= an array of type real[int. the kth vector will contain the real part and the k + 1th vector the imaginary part of the corresponding complex conjugate eigenvectors. sigma= the shift value. where the matrix OP = A − σB with a solver and boundary condition.nev= . sym= the problem is symmetric (all the eigen value are real) nev= the number desired eigenvalues (nev) close to the shift.4 Eigenvalue Problems This section depends on your installation of FreeFem++. but if you forget the locking boundary condition on B matrix (no key work ”on”) you get huge spurious (1030 ) modes associated to these boundary conditons. value= the array to store the real part of the eigenvalues ivalue= the array to store the imag.B. For real non symmetric problems. and the matrix B. EIGENVALUE PROBLEMS 213 9. So take Dirichlet boundary condition just on A and not on B.edp Load: lg_fem lg_mesh eigenvalue This tools is based on the arpack++ 1 the object-oriented version of ARPACK eigenvalue package [1]. (up to version 2-17). maxit= the maximum number of iterations allowed. The matrix OP is defined with A − σB.4.int] to store eigenvectors by column.caam.28 (date Thu Dec 26 10:56:34 CET 2002) file : LapEigenValue. so if eigenvalue k and k + 1 are complex conjugate eigenvalues.edu/software/ARPACK/ . because we solve w = OP − 1 ∗ B ∗ v. This tools is available in FreeFem++ if the word “eigenvalue” appear in line “Load:”. tol= the relative accuracy to which eigenvalues are to be determined. Note 9. so we get the good one in this case.9. you need to have compiled (see README arpack). We compute only small mode. 1 http://www.FreeFem++ v1. due to boundary condition.31)).rice. ARPACK. complex eigenvectors are given as two consecutive vectors. The return value is the number of converged eigenvalue (can be greater than the number of eigen value nev=) int k=EigenValue(OP. If you put locking (Dirichlet ) boundary condition on B matrix (with key work on) you get small spurious modes (10−30 ). The function EigenValue computes the generalized eigenvalue of Au = λBu where sigma =σ is the shift of the method. like: -.1 Boundary condition and Eigenvalue Problems The locking (Dirichlet ) boundary condition is make with exact penalization so we put 1e30=tgv on the diagonal term of the locked degree of freedom (see equation (6. and uλ in R×H0 (Ω) uλ v = λ Ω Ω uv 1 ∀v ∈ H0 (Ω) The exact eigenvalues are λn.17 (lapEignenValue.P2). .solver=CG. // So take Dirichlet boundary condition just on a variational form // and not on b variational form.214 CHAPTER 9.m = (n2 + m2 ). // // important remark: // the boundary condition is make with exact penalization: we put 1e30=tgv on the diagonal term of the lock degree of freedom. mesh Th=square(20. // Boundary condition no Boundary condition see note // crout solver because the varf b([u1]. π[2 ---------------------------------------we use the inverse shift mode the shift is given with the real sigma ------------------------------------1 find λ and uλ ∈ H0 (Ω) such that: uλ v = λ Ω 1 uλ v. π[2 . // value of the shift varf // OP = A . // because we solve w = OP − 1 ∗ B ∗ v // number of computed eigen value close to sigma // // to store the nev eigenvalue to store the nev eigenvector int nev=20. We use the generalized inverse shift mode of the arpack++ library.B.[pi*x. fespace Vh(Th. Vh u1.n = sin(nx) ∗ sin(my).solver=Crout. int k=EigenValue(OP. MATHEMATICAL MODELS ncv= the number of Arnoldi vectors generated at each iteration of ARPACK.sym=true.sigma* u1*u2 ) + on(1.sigma=sigma. real sigma = 20. 1 The problem is to find: λ.u2. Example 9.sigma B .20. // // // // // // // // Ω Computation of the eigen value and eigen vector of the Dirichlet problem on square ]0.value=ev.pi*y]). Vh[int] eV(nev).u1=0) .ncv=0).Vh.edp) In the first example. tol=1e-10.eps=1e-20). matrix in not positive matrix B= b(Vh.maxit=0. // the shifted matrix op(u1. m) ∈ N∗ 2 with the associated eigenvectors are um. (n.vector=eV.u2)= int2d(Th)( dx(u1)*dx(u2) + dy(u1)*dy(u2) .1 matrix OP= op(Vh. we compute the eigenvalues and the eigenvectors of the Dirichlet problem on square Ω =]0.3. to find 20 eigenvalues and eigenvectors close to the shift value σ = 20.factorize=1). ∀v ∈ H0 (Ω) verbosity=10.Vh.4. // 9.[u2]) = int2d(Th)( u1*u2 ). real[int] ev(nev).2. 0039 lambda[7]: 17. 215 for (int i=0.value=1).00074 lambda[3]: 10."<<endl.i++) { u1=eV[i]." << i<< " " << ev[i]<< " err= " <<int2d(Th)(dx(u1)*dx(u1) + dy(u1)*dy(u1) . plot(eV[i].0159 lambda[16]: 29.i<k.0096 lambda[11]: 20.014 lambda[13]: 25.0283 lambda[14]: 26.rice. cout << " ---.9.0083 lambda[10]: 20. real gg = int2d(Th)(dx(u1)*dx(u1) + dy(u1)*dy(u1)). neb = 80 Nb Of Nodes = 1681 Nb of DF = 1681 Real symmetric eigenvalue problem: A*x . } The output of this example is: Nb of edges on Mortars = 0 Nb of edges on Boundary = 80.0273 lambda[18]: 32. ncv see arpack doc.0048 lambda[9]: 18.B*x*lambda Shift and invert mode sigma=20 Dimension Number of Number of Number of Number of of the system : ’requested’ eigenvalues : ’converged’ eigenvalues : Arnoldi vectors generated: iterations taken : 1681 20 20 41 2 Eigenvalues: lambda[1]: 5. real mm= int2d(Th)(u1*u1) .wait=1.0002 lambda[2]: 8.edu/software/ARPACK/ the return value is number of converged eigen value.cmm="Eigen Vector "+i+" valeur =" + ev[i] .4.0011 lambda[5]: 13.0096 lambda[12]: 25.(ev[i])*u1*u1) << " --.0159 lambda[15]: 26.0046 lambda[8]: 17.0449 lambda[19]: 34.0011 lambda[4]: 10.caam.002 lambda[6]: 13.0258 lambda[17]: 29. EIGENVALUE PROBLEMS // // // // tol= the tolerance maxit= the maximum iteration see arpack doc.049 .B*x*lambda Thanks to ARPACK++ class ARrcSymGenEig Real symmetric eigenvalue problem: A*x . http://www. 00227747 --5 13.552624 -0.0046 err= -0.004179 --6 17.002 err= -0.297567 -0.382586 0.0258 err= -0.0457328 --18 34.637643 0.0291014 --13 26.00639952 --8 18.127529 -0.0039 err= -0.0096 err= -0.807681 -0.0536275 --- CHAPTER 9.639134 0.0283 err= -0.0530978 --19 34.809569 Eigen Vector 12 valeur =25.0326472 --17 32.00074 err= -0.213045 -0.722662 0.809569 -0.553916 0.467605 -0.014 IsoValue -0.0154412 --12 25.0218544 --15 29.0159 err= -0.212548 0.552624 0.0011 err= -0.0311961 --16 29.0048 err= -0.3 − u3.0425095 0.0426089 0.0002 err= -0.0011 err= -0.38348 0.297567 0.298262 -0.216 lambda[20]: 34.0110483 --10 20.212548 -0.38348 -0.0159 err= -0.0273 err= -0.127827 -0.000225891 --1 8.014 err= -0.0425095 0.639134 -0.467605 0.00134596 --3 10.0096 err= -0.18: u4.0110696 --11 25.4 Isovalue of 12th eigenvector .298262 0.722662 -0.000787446 --2 10.724351 -0.0218532 --14 26.0283 IsoValue -0.0426089 0. MATHEMATICAL MODELS Eigen Vector 11 valeur =25.0492 ------------------------------------------------------------0 5.807681 Figure 9.0449 err= -0.127529 0.213045 0.00862954 --9 20.468698 0.0492 err= -0.468698 -0.0083 err= -0.00134619 --4 13.637643 -0.3 + u3.17: u4.553916 -0.4 Isovalue of 11th eigenvector Figure 9.049 err= -0.724351 0.382586 -0.00623649 --7 17.127827 0. 26) on ∂Ω×]0. Ω =]0.P1). (∂u/∂n) (x. y. [T /τ ]. To obtain the variational formulation. y. y. multiply with the test function v both sides of the equation: {um+1 v − τ ∆um+1 v} = Ω Ω {um + τ f m+1 }v . ∂u − µ∆u = x4 − µ12tx2 in Ω×]0.28) Using the identity just above.5 Evolution Problems ∂u − µ∆u = f in Ω×]0. (9. 0) = 0 on Ω. y. T [. y. T [. ∂u u(x. t) = lim τ →0 ∂t τ which indicates that um (x. we can calculate the finite element approximation um of um in a h step-by-step manner with respect to t. We use the definition of the partial derivative of the solution in the time derivative. Example 9. By the boundary condition ∂um+1 /∂n = 0. ∂t u(x. y. We solve (9.9. y) τ The time discretization of heat equation (9.27) is as follows: um+1 − um − µ∆um+1 = f m+1 in Ω τ u0 (x) = u0 (x) in Ω.27). 3[. y) = u(x. 1[2 ∂t u(x. t) = tx4 . · · · . FreeFem++ also solves evolution problems such as the heat equation: with a positive viscosity coefficient µ and homogeneous Neumann boundary conditions. y) − um−1 (x. mτ ) will satisfy approximatively ∂u (x.16). t) = 0 (9.27) on ∂Ω.5. t − τ ) (x.26) by FEM in space and finite differences in time. EVOLUTION PROBLEMS 217 9. for all m = 0. u|∂Ω = t ∗ x4 // mesh Th=square(16. ∂um+1 /∂n(x) = 0 (9. mτ ) ∂t um (x. 0) = u0 (x) in Ω. heat equation ∂t u = −µ∆u = x4 − µ12tx2 . By the divergence theorem. fespace Vh(Th. it follows that {um+1 v + τ um+1 · Ω v} − Ω {um v + τ f m+1 v} = 0.18 We now solve the following example with the exact solution u(x. y. which is so-called backward Euler method for (9. t) − u(x. we have {um+1 v + τ um+1 · Ω v} − ∂Ω τ ∂um+1 /∂n v = Ω {um v + τ f m+1 v}. φi + a uh . real dt = 0.5. V ). plot(u. } In the last statement. NT = [T /τ ]. T ] (9. t ∈ [0. T . V ). H) ∩ L2 (0. φi h τ h i = 1.1. a. . · · · .v) = int2d(Th)( u*v + dt*mu*(dx(u)*dx(v) + dy(u)*dy(v))) + int2d(Th) (.y. the error is 0. mu = 0.uu*v . the L2 -error Ω u − tx4 is calculated at t = mτ. T . n = 0.1. v) + a(u(t).uu. Let us denote the time step by τ > 0. // start from t=0 uu = 0. v) dt u(0) = u0 ∀v ∈ V. In this section.3. the backward Euler scheme if θ = 1.u=g). cout <<"t="<<t<<"Lˆ2-Error="<<sqrt( int2d(Th)((u-t*xˆ4)ˆ2) ) << endl.2.30) Formula (9.000213269. real t = 0.wait=true).28) is made by for loop (see Section 4. h h h f n+θ = θf n+1 + (1 − θ)f n (9. problem dHeat(u. MATHEMATICAL MODELS Vh u.29) where V is the dual space of V .e.f.30) is the forward Euler scheme if θ = 0. // u(x.00628589 at t = 3.dt*f*v ) + on(1. Problem Ev(f. Ω): For a given f ∈ L2 (0. Then. At t = 0.v.1 Mathematical Theory on Time Difference Approximations.1.10).g. uu = u. FreeFem++ support reuses of stiffness matrix. Let a be a continuous bilinear form over V × V with coercivity and symmetry. v) = (f (t).01.2 The stiffness matrix in the loop is used over and over again. m. τ = 0. Let V. φi = f n+θ . T . . The errors increase with m and 0. we show the advantage of implicit schemes. NT un+θ = θun+1 + (1 − θ)un . v) become equivalent to the norm v of V . · · · . dHeat.4.0)=0 for (int m=0. 9. 1] 1 n+1 n+θ u − un . Then a(v. g = t*xˆ4. u0 ∈ H d (u(t). Crank-Nicolson scheme if θ = 1/2. 2 1/2 Note 9. H be separable Hilbert space and V is dense in H.m++) { t=t+dt. f = xˆ4-mu*t*12*xˆ2. The iteration of the backward Euler (9. For the discretization.218 CHAPTER 9.m<=3/dt. there is an unique solution u ∈ L∞ (0. we put un = u(nτ ) and consider the time difference for each θ ∈ [0. (1-theta)*tau*(dx(oldU)*dx(v)+dy(oldU)*dy(v)+oldU*v)) . pp. When 1/2 ≤ θ ≤ 1. A = (aij ).0) { real t = 0. φi ).". for (int n=0.32)  |u0 |2 + τ n−1 f k+θ 2 θ ∈ [1/2. Vh f1. Example 9. φi ) un .19 mesh Th=square(12. · · · .2*xˆ3 + xˆ4). we can take τ arbitrary.. then we can take a time step τ in such a way that τ< for arbitrary δ ∈ (0.P1).y.max<<". // file to store calculations out << "mesh size = "<<h[]. 1/2) k=0 h δ Vh n 2 |uh | ≤ (9.v) = int2d(Th)( u*v + theta*tau*(dx(u)*dx(v) + dy(u)*dy(v) + u*v)) .11*xˆ2 .n<5/tau. 2. problem aTau(u. Theorem 2.9. mij = (φj . Vh u. // mesh sizes for each triangle real tau = 0.   1 |u0 |2 + τ n−1 f k+θ 2 θ ∈ [0.".csv"). 1/2).33) // // from t=0 to T u(x. aij = a(φj . EVOLUTION PROBLEMS Unknown vectors un = (u1 .13]: Let {Th }h↓0 be regular triangulations (see Section 5.int2d(Th)(oldU*v .v.5. while (theta <= 1. 1).n++) \\ out<<n*tau<<".int2d(Th)(tau*( theta*f1+(1-theta)*f0 )*v ). out <<theta<<". uM )T in h h un (x) = un φ1 (x) + · · · + un φm (x).12). fespace Vh(Th.0)=0 .4). 1] k=0 h V h if the following are satisfied: 1. 1 m h are obtained from solving the matrix (M + θτ A)un+1 = {M − (1 − θ)τ A}un + τ θf n+1 + (1 − θ)f n M = (mij ). 2(1 − δ) 2 h (1 − 2θ)c2 0 (9. When θ ∈ [0. Then there is a number c0 > 0 independent of h such that.31). oldU = 0. time step = "<<tau<<endl.70–75] for solvability of (9. theta=0. fespace Ph(Th. The stability of (9. un ∈ R 1 m 219 (9.31) is in [22. · · · . out << endl. f0. Ph h = hTriangle. T=3. } ofstream out("err02.P0).1.oldU. func real f(real t) { return xˆ2*(x-1)ˆ2 + t*(-2 + 12*x .31) Refer [22. 1. t) X(t) = x .n<T/tau. (9. } out << endl.220 CHAPTER 9.5. f0 = f(n*tau). 1.4. Vh uex = t*xˆ2*(1-x)ˆ2. the ˙ ˙ ˙ construction worsk on similar principles. 29 h We can see in Fig.19: maxx∈Ω |un (θ) − uex (nτ )|/ maxx∈Ω |uex (nτ )| at n = 0. u(x.exact // err L∞ (Ω) / uex L∞ (Ω) G Figure 9. in the ConvectionDiffusion equation. Vh err = u .= tx2 (1 − x)2 // err =FE-sol . for example in the Navier-Stokes equations. L) × (0. } // exact sol.19 that un (θ) become unstable at θ = 0. 0) = u0 (x). oldU = u. Even if α is not constant. aTau. t) = u0 (x − αt) of the following equation. f1 = f((n+1)*tau). 9. 9. ∂t u + α∂x u = 0. τ ∈ (0. In the case of 1-dimensional space.uex. T )): ˙ X(τ ) = +α(X(τ ). · · · .4. theta = theta + 0. and figures are omitted in the case h θ < 0. out<< abs(err[].".max) <<". etc. One begins with the ordinary differential equation (with the convention that α is prolonged by zero apart from (0. τ ). if α is constant. we can easily find the general solution (x.n++) { t = t+tau. t) → u(x. MATHEMATICAL MODELS for (int n=0. where u0 = du0 (x)/dx.35) because ∂t u + α∂x u = −αu0 + au0 = 0.2 Convection ∂t u + α · u = f . plot(u).max)/abs(uex[].34) The hyperbolic equation appears frequently in scientific problems. (9. for a vector-valued function α. In higher dimension Ω ⊂ Rd . um ) by X m ≈ x → x − τ [am (x). t) ∈ Rd . t are parameters. we can get the approximation um (X m (x)) ≈ convect ([am . mτ )).t (0) is on the axis of t. dt where αm (x) = (α1 (x. d = 2. t) = f (X(t). X((m + 1)τ ) = x. .t (τ ). by Taylor’s expansion. −τ. we have d u (X(mτ )) = u (X((m + 1)τ )) − τ i=1 m m ∂um ∂Xi (X((m + 1)τ )) ((m + 1)τ ) + o(τ ) ∂xi ∂t (9. it follows that um (X m (x)) = um (x) − τ αm (x) · um (x) + o(τ ). −τ. am ]. Then it is noticed that (x. t) = u0 (Xx. The general solution of (9. (9.34) with f = 0 and the initial condition u(x. um ) ≈ um (x − αm τ ) . t) = u0 (Xx.16]). mτ ) and we used the chain rule and x = X((m + 1)τ ). mτ ). t) where (t) = α(X(t).t (0). t) → v(X(τ ). −τ. From (9. α2 = −x We consider the problem (9.37).t (0)) if Xx. that is.37) = um (x) − τ αm (x) · um (x) + o(τ ) where Xi (t) are the i-th component of X(t).9.38) Also we apply Taylor’s expansion for t → um (x − αm (x)t). because if τ = t we have X(τ ) = x. then um (x − ατ ) = um (x) − τ αm (x) · Putting convect (α. So a good scheme is one step of backward convection by the method of Characteristics-Galerkin 1 m+1 u (x) − um (X m (x)) = f m (x) τ (9. um ). t) Dt dt dt where D is the total derivative operator. 0) = u0 (x). Because.35) is thus the value of the boundary condition in Xx. that is to say u(x. Let Ω be the unit disk centered at 0. T ) where a(x. u(x. 0 ≤ t ≤ τ . (X(t). um (x) + o(τ ). FreeFem++ implements the Characteristic-Galerkin method for convection operators. from (9.t (0)) where Xx. 3. 1 2 1 2 A classical convection problem is that of the “rotating bell” (quoted from [14][p. the equation for the convection is written ∂t u + α · u = 0 in Ω × (0. and we denote the solution by Xx.5. Recall that the equation (9.e. am (x)]).36) where X m (x) is an approximation of the solution at t = mτ of the ordinary differential equation dX (t) = αm (X(t)). um (x) = u(x. EVOLUTION PROBLEMS 221 In this equation τ is the variable and x. with its center rotating with speed α1 = y.36) um+1 (x) = um (X m (x)) ≈ convect(α. α2 (x.t (0) is on the x axis. τ ) in τ = t satisfies the equation ∂t v + α∂x v = ∂t X v + a∂x X v = 0 ˙ ˙ ˙ and by the definition ∂t X = X = +α and ∂x X = ∂x x in τ = t.34) can be discretized as Du du dX = f i. max. u=convect([a1.3)2 ) Figure 9. but rotated by the same amount.3) 2 +(y−0.21). // time step Vh a1 = -y.29 9.u0).P1).55289e-09.39) .29. if u0 in a 3D perspective looks like a bell. they should be equal. // um+1 for (int m=0. unit circle mesh Th = buildmesh(C(70)).5.min + ". Example 9. (see for example Wilmott et al[39] or Achdou et al [3]). So.222 CHAPTER 9. t) = u(X(t)) where X equals x rotated around the origin by an angle θ = −t (rotate in clockwise). min=1. }. }.17. The program consists in solving the equation until T = 2π. // rotation velocity Vh u. // um+1 = um (X m (x)) u0=u.3)ˆ2 +(y-0. 2*pi) { x=cos(t).20 (convect. a2 = x. max=0. that is for a full revolution and to compare the final solution with the initial one.3)ˆ2)).3 2D Black-Scholes equation for an European Put option In mathematical finance. max=0. then the bell become lower and lower (the maximum of u37 is 0. min=" + u[]. ∂t u + (σ1 x)2 ∂ 2 u (σ2 y)2 ∂ 2 u + 2 ∂x2 2 ∂y 2 2u ∂ ∂u ∂u + ρxy + rS1 + rS2 − rP = 0 ∂x∂y ∂x ∂y (9.20: u0 = e−10((x−0. MATHEMATICAL MODELS The exact solution is u(x. an option on two assets is modeled by a Black-Scholes equations in two space variables.wait=0). m++) { t += dt.406 as shown in Fig.3 The scheme convect is unconditionally stable. convection: t=0.983612 convection: t=6.21: The bell at t = 6. 9.40659m=37 Figure 9. // m++ plot(u. max=" + u[]. then u will have exactly the same shape.edp) border C(t=0. Vh u0 = exp(-10*((x-0.-dt.55289e-09. m<2*pi/dt . min=1. y=sin(t). // the triangulates the disk // give u0 real dt = 0.a2]. // fespace Vh(Th.cmm=" t="+t + ". Note 9.t=0. +∞.nbjacoby=2. }. T ) = (K − max (x.8. σ2 = 0.value=1). Vh u=max(K-max(x. Vh xveloc.). yveloc = -y*r+y*sigyˆ2+y*rho*sigx*sigy/2. in the case of a put u (x. it makes sense to impose u = 0. We take σ1 = 0. fespace Vh(th. T ). v. y.3. To have an unconditionally stable scheme.abserror=1.3. approximates ∂u ∂u ∂u 1 n+1 + a1 + a2 ≈ u (x) − un (x − ατ ) ∂t ∂x ∂y τ (9. j=j+1. So if we do nothing in the variational form (i.edp int m=30. K = 40. j=0.u. r = 0.int2d(th)( v*convect([xveloc.0.L=80. maxsubdiv=5.3. yveloc.v.8. These will be automatically accounted for because they are embedded in the PDE. T = 0. 223 (9.wait=1.01. nbsmooth=3. rho=0. T ) × R+ × R+ subject to. roughly.rescaling=1) . r=0. as in 1D.u=0). As in the one dimensional case the PDE contains boundary conditions on the axis x1 = 0 and on the axis x2 = 0. omega=1.3. Results are shown on Fig. EVOLUTION PROBLEMS which is to be integrated in (0.9.001. n++) { if(j>20) { th = adaptmesh(th. which. solve eq1(u. y))+ .dt.40) Boundary conditions for this problem may not be so easy to device.verbosity=1. plot(u. ρ = 0. 9. err=0.05. the first order terms are treated by the Characteristic Galerkin method. dt=0. mesh th=square(m.m.LL=80.P1).LL*y]). 0. At infinity in one of the variable. real sigx=0.3.edp] // file BlackScholes2D.w)/dt) + on(2.21). if we take a Neumann boundary condition at these two axis in the strong form) there will be no disturbance to these. xveloc = -x*r+x*sigxˆ2+x*rho*sigx*sigy/2. j=100.21 [BlackSchol. for (int n=0.0.yveloc]. K=40.41) An implicit Euler scheme is used and a mesh adaptation is done every 10 time steps.solver=LU) = int2d(th)( u*v*(r+1/dt) + dx(u)*dx(v)*(x*sigx)ˆ2/2 + dy(u)*dy(v)*(y*sigy)ˆ2/2 + (dy(u)*dx(v) + dx(u)*dy(v))*rho*sigx*sigy*x*y/2) .e. splitpbedge=1. uold=u. }.init=j.5 (9. nbvx=5000.3.05.[L*x. ratio=1. namely two one dimensional Black-Scholes equations driven respectively by the data u (0.42) Example 9.uold. sigy=0. . u=u. n*dt <= 1.3.y).5. T ) and u (+∞. 2].9859 18.43) where u = (u1 .981 24.6 9.9876 16.9793 26. MATHEMATICAL MODELS IsoValue -1.999173 2. For simplicity. u2 ) is the velocity vector and p the pressure.9669 Figure 9.99835 0.99256 10.99752 4.9909 12. W = q ∈ L2 (Ω) Ω q=0 .224 CHAPTER 9. u = uΓ on Γ. there ia a weak form of (9.976 30.22: The adapted triangulation Figure 9.9893 14.23: The level line of the European basquet put option 9. v2 ) ∈ V (Ω) 1 V (Ω) = {w ∈ H0 (Ω)2 | divw = 0} which satisfy 2 ui · i=1 Ω vi = Ω f ·w for all v ∈ V p.99421 8.9777 28.1 Navier-Stokes Equation Stokes and Navier-Stokes −∆u + p = f ·u =0 The Stokes equations are: for a given f ∈ L2 (Ω)2 . in Ω (9.9711 39. if Here it is used the existence p ∈ H 1 (Ω) such that u = u·v =0 Ω for all v ∈ V Another weak form is derived as follows: We put 1 V = H0 (Ω)2 .43): Find v = (v1 .9826 22.6.9843 20.9744 32. let us choose Dirichlet boundary conditions on the velocity.99587 6. In Temam [Theorem 2.9727 34. Ω + p − ph 0.44) (9.48) Note 9. and an application of Green’s formula.4 Assume that: 1. qh ) = 0.6. we consider finite element spaces V h ⊂ V and Wh ⊂ W . p) = (f .48) satisfying u − uh 1. subsequent integration over Ω.9.46) (9.43) with v ∈ V and the second with q ∈ W . v h ). p) ∈ V × W such that a(u.47) b(u. and we assume the following basis functions V h = Vh × Vh . Vh = {vh | vh = v1 φ1 + · · · + vMV φMV }.Ω + inf qh ∈Wh p − qh 0. q) = − Ω divu q Now. .45) a(u. v) b(u. v) + b(v.g. Wh = {qh | qh = q1 ϕ1 + · · · + qMW ϕMW } The discrete weak form is: Find (uh . q) ∈ V × W . qh ) ≥ βh qh v h 1. where 2 (9. Theorem 10.Ω for all v h ∈ Zh for all qh ∈ Wh } for all qh ∈ Wh Then we have an unique solution (uh . v h ) ≥ α v h where Zh = {v h ∈ V h | b(wh . [20. There is a constant αh > 0 such that a(v h . ∀v h ∈ V h b(uh . ph ) of (9.Ω with a constant C > 0 (see e. NAVIER-STOKES EQUATION 225 By multiplying the first equation in (9. qh ) = 0 2. q) = 0 for all (v. p) = (f . v h ) + b(v h . ph ) ∈ V h × Wh such that a(uh .43): Find (u.4]).Ω 0. v) = Ω u· v= i=1 Ω ui · vi (9. ∀qh ∈ Wh (9.Ω ≤C inf u − vh v h ∈V h 1. There is a constant βh > 0 such that sup v h ∈V h b(v h . we have u· Ω v− Ω divv p = Ω f ·v divu q = 0 Ω This yields the weak form of (9.Ω 2 1. (9.226 Let us denote that A = (Aij ). MW . Aij = Ω CHAPTER 9.h } {u2.h } Fh = { { Ω f1 φi } Ω f2 φi } Uh {ph } = Fh 0 (9. [20. · · · .52) can be solved by known technique. j = 1. ph ) ∈ V h × Wh satisfying a(uh .2]) Example 9.48) is written by A B∗ B 0 where A= A 0 0 A B∗ = BxT By T Uh = {u1.5 We can eliminate ph = (1/ )BUh to obtain (A + (1/ )B ∗ B)U h = F h (9.48) by a more regular problem: Find ˜ (v h . j = 1.49) ∂φj /∂y ϕi B = (Bxij . · · · . MATHEMATICAL MODELS φj · φi i. ˜ where Wh ⊂ L2 (Ω).Ω ≤C . 1.22 (Cavity. and s the unit tangent to Γ).Ω + ph − ph 0. We solve the driven cavity problem by the penalty method (9.g. v h ) + b(v h . MV ∂φj /∂x ϕi Byij = − Ω (9. 17. The velocity pressure formulation is used first and then the calculation is repeated with the stream function vorticity formulation.52) Since the matrix A + (1/ )B ∗ B is symmetric. · · · .51) Note 9. we have divuh = ph and the corresponding algebraic problem A B∗ B − I Uh {ph } = Fh 0 (9. qh ) − (ph . positive-definite.51) where uΓ · n = 0 and uΓ · s = 1 on the top boundary and zero elsewhere ( n is the unit normal to Γ. ∀v h ∈ V h ˜ ∀qh ∈ Wh b(uh . Formally.edp) The driven cavity flow problem is solved first at zero Reynolds number (Stokes flow) and then at Reynolds 100. v h ). Bxij = − Ω i = 1.8). The mesh is constructed by mesh Th=square(8. qh ) = 0. ph ) = (f .50) Penalty method: This method consists of replacing (9. and sparse. Byij ). MV then (9. There is a constant C > 0 independent of such that uh − uh (see e. −∆ψ = ×u Xh psi.3.4 Each unknown has its own boundary conditions.q.6.p*q*(0.v1.p.u1=0. Mh p.9. u2) and the pressure p. NAVIER-STOKES EQUATION We use a classical Taylor-Hood element technic to solve the problem: 227 The velocity is approximated with the P2 FE ( Xh space). so the variational form (9.4.dy(u2)*q ) + on(3.p*dx(v1) . If the streamlines are required. 1[2 ) ∀K ∈ Th The FE spaces and functions are constructed by fespace Xh(Th. 1[2 ) ∀K ∈ Th and Mh = v ∈ H 1 (]0.v2.p*dy(v2) .P2). Now the Navier-Stokes equations are solved ∂u +u· ∂t u − ν∆u + p = 0.dx(u1)*q .48) in freefem language is: solve Stokes (u1. solve streamlines(psi.q. Xh u1.P1). v2) and q for the pressure. The test function for the velocity is (v1.phi) = int2d(Th)( dx(psi)*dx(phi) + dy(psi)*dy(phi)) + int2d(Th)( -phi*(dy(u1)-dx(u2))) + on(1.phi.2. ·u=0 with the same boundary conditions and with initial conditions u = 0.u2=0) + on(1. // definition of the velocity component space // definition of the pressure space v|K ∈ P2 v|K ∈ P1 The Stokes operator is implemented as a system-solve for the velocity (u1. fespace Mh(Th.4.solver=Crout) = int2d(Th)( ( dx(u1)*dx(v1) + dy(u1)*dy(v1) + dx(u2)*dx(v2) + dy(u2)*dy(v2) ) . where Xh = v ∈ H 1 (]0.1 for labels 1.2.psi=0). they can be computed by finding ψ such that rotψ = u or better.v2. and the the pressure is approximated with the P1 FE ( Mh space).3.u2=0).u1=1. Xh u2.2. // see Section 5.000001) .1. .v1.u2. 228 CHAPTER 9. MATHEMATICAL MODELS ∂u ∂t This is implemented by using the convection operator convect for the term discretization in time 1 n+1 τ (u +u· u, giving a − un ◦ X n ) − ν∆un+1 + · un+1 pn+1 = 0, =0 (9.53) The term un ◦ X n (x) ≈ un (x − un (x)τ ) will be computed by the operator “convect” , so we obtain int i=0; real nu=1./100.; real dt=0.1; real alpha=1/dt; Xh up1,up2; problem NS (u1,u2,p,v1,v2,q,solver=Crout,init=i) = int2d(Th)( alpha*( u1*v1 + u2*v2) + nu * ( dx(u1)*dx(v1) + dy(u1)*dy(v1) + dx(u2)*dx(v2) + dy(u2)*dy(v2) ) - p*q*(0.000001) - p*dx(v1) - p*dy(v2) - dx(u1)*q - dy(u2)*q ) + int2d(Th) ( -alpha* convect([up1,up2],-dt,up1)*v1 -alpha*convect([up1,up2],-dt,up2)*v2 ) + on(3,u1=1,u2=0) + on(1,2,4,u1=0,u2=0) ; for (i=0;i<=10;i++) { up1=u1; up2=u2; NS; if ( !(i % 10)) plot(coef=0.2,cmm=" [u1,u2] and p } ; // ",p,[u1,u2]); plot every 10 iteration Notice that the stiffness matrices are reused (keyword init=i) 9.6.2 Uzawa Algorithm and Conjugate Gradients We solve Stokes problem without penalty. The classical iterative method of Uzawa is described by the algorithm (see e.g.[20, 17.3], [29, 13] or [30, 13] ): Initialize: Let p0 be an arbitrary chosen element of L2 (Ω). h Calculate uh : Once pn is known, v n is the solution of h h un = A−1 (f h − B ∗ pn ) h h Advance ph : Let pn+1 be defined by h pn+1 = pn + ρn Bun h h h 9.6. NAVIER-STOKES EQUATION 229 There is a constant α > 0 such that α ≤ ρn ≤ 2 for each n, then un converges to the solution uh , h and then Bv n → 0 as n → ∞ from the Advance ph . This method in general converges quite slowly. h First we define mesh, and the Taylor-Hood approximation. So Xh is the velocity space, and Mh is the pressure space. Example 9.23 (StokesUzawa.edp) mesh Th=square(10,10); fespace Xh(Th,P2),Mh(Th,P1); Xh u1,u2,v1,v2; Mh p,q,ppp; // ppp is a working pressure varf bx(u1,q) = int2d(Th)( -(dx(u1)*q)); varf by(u1,q) = int2d(Th)( -(dy(u1)*q)); varf a(u1,u2)= int2d(Th)( dx(u1)*dx(u2) + dy(u1)*dy(u2) ) + on(3,u1=1) + on(1,2,4,u1=0) ; // remark: put the on(3,u1=1) before on(1,2,4,u1=0) // because we want zero on intersection % matrix A= a(Xh,Xh,solver=CG); matrix Bx= bx(Xh,Mh); matrix By= by(Xh,Mh); Xh bc1; bc1[] = a(0,Xh); Xh bc2; bc2 = O ; Xh b; // // // B = (Bx By) boundary condition contribution on u1 no boundary condition contribution on u2 pn → BA−1 (−B ∗ pn ) = −divuh is realized as the function divup. h h func real[int] divup(real[int] & pp) { b[] = Bx’*pp; b[] *=-1; b[] += bc1[] ; // u1[] = Aˆ-1*b[]; // u2[] = Aˆ-1*b[]; compute u1(pp) compute u2(pp) b[] = By’*pp; b[] *=-1; b[] += bc2[] ; // un = A−1 (BxT pn By T pn )T ppp[] = Bx*u1[]; ppp[] += By*u2[]; return ppp[] ; }; // // ppp = Bxu1 +Byu2 Call now the conjugate gradient algorithm: p=0;q=0; // p0 = 0 h LinearCG(divup,p[],eps=1.e-6,nbiter=50); // pn+1 = pn + Bun h h h // if n > 50 or |pn+1 − pn | ≤ 10−6 , then the loop end. h h divup(p[]); // compute the final solution plot([u1,u2],p,wait=1,value=true,coef=0.1); 230 CHAPTER 9. MATHEMATICAL MODELS 9.6.3 NSUzawaCahouetChabart.edp In this example we solve the Navier-Stokes equation, in the driven-cavity, with the Uzawa algorithm preconditioned by the Cahouet-Chabart method (see [31] for all the details). The idea of the preconditioner is that in a periodic domain, all differential operators commute and the Uzawa algorithm comes to solving the linear operator .((αId + ν∆)−1 , where Id is the identity operator. So the preconditioer suggested is α∆−1 + νId. To implement this, we reuse the previous example, by including a file. Then we define the time step ∆t, viscosity, and new variational form and matrix. Example 9.24 (NSUzawaCahouetChabart.edp) include "StokesUzawa.edp" real dt=0.05, alpha=1/dt; cout << " alpha = " << alpha; real xnu=1./400; // include the Stokes part // ∆t // viscosity ν = Reynolds number−1 // the new variational form with mass term varf at(u1,u2)= int2d(Th)( xnu*dx(u1)*dx(u2) + xnu*dy(u1)*dy(u2) + u1*u2*alpha ) + on(1,2,4,u1=0) + on(3,u1=1) ; A = at(Xh,Xh,solver=CG); // change the matrix varf varf vfconv1(uu,vv) vfconv2(v2,v1) // set the 2 convect variational form = int2d(Th,qforder=5) (convect([u1,u2],-dt,u1)*vv*alpha); = int2d(Th,qforder=5) (convect([u1,u2],-dt,u2)*v1*alpha); // index of time set // current time int idt; real temps=0; Mh pprec,prhs; varf vfMass(p,q) = int2d(Th)(p*q); matrix MassMh=vfMass(Mh,Mh,solver=CG); varf vfLap(p,q) = int2d(Th)(dx(pprec)*dx(q)+dy(pprec)*dy(q) + pprec*q*1e-10); matrix LapMh= vfLap(Mh,Mh,solver=Cholesky); The function to define the preconditioner func real[int] { CahouetChabart(real[int] & xx) // pprec[]= LapMhˆ-1* xx; prhs[] = MassMhˆ-1*xx; pprec[] = alpha*pprec[]+xnu* prhs[]; return pprec[]; }; // xx = (divu)wi αLapM h−1 + νM assM h−1 The loop in time. Warning with the stop test of the conjugate gradient, because we start from the previous solution and the end the previous solution is close to the final solution, don’t take a relative stop test to the first residual, take an absolute stop test ( negative here) 9.7. VARIATIONAL INEQUALITY 231 for (idt = 1; idt < 50; idt++) { temps += dt; cout << " --------- temps " << temps << " \n "; b1[] = vfconv1(0,Xh); b2[] = vfconv2(0,Xh); cout << " min b1 b2 " << b1[].min << " " << b2[].min << endl; cout << " max b1 b2 " << b1[].max << " " << b2[].max << endl; // call Conjugate Gradient with preconditioner ’ // warning eps < 0 => absolue stop test LinearCG(divup,p[],eps=-1.e-6,nbiter=50,precon=CahouetChabart); divup(p[]); // computed the velocity plot([u1,u2],p,wait=!(idt%10),value= 1,coef=0.1); } [u1,u2],p || u^n+1 - u^n ]]_L2 =0.00149613 IsoValue -0.0791073 -0.0611287 -0.0431501 -0.0251715 -0.00719285 0.0107858 0.0287644 0.046743 0.0647217 0.0827003 0.100679 0.118658 0.136636 0.154615 0.172593 0.190572 0.208551 0.226529 0.244508 0.262487 Vec Value 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 Figure 9.24: Solution of the cavity driven problem at Reynolds number 400 with the CahouetChabart algorithm. 9.7 Variational inequality We present, a classical example of variational inequality. 1 Let us denote C = {u ∈ H0 (Ω), u ≤ g} The problem is : u = arg min J(u) = u∈C 1 2 u. u − Ω Ω fu where f and g are given function. 232 CHAPTER 9. MATHEMATICAL MODELS The solution is a projection on the convex C of f for the scalar product ((v, w)) = Ω v. w of 1 1 H0 (Ω) where f is solution of ((f , v)) = Ω f v, ∀v ∈ H0 (Ω). The projection on a convex satisfy ˜ clearly ∀v ∈ C, ((u − v, u − f )) ≤ 0, and after expanding, we get the classical inequality ∀v ∈ C, Ω (u − v) u ≤ Ω (u − v)f. We can also rewrite the problem as a saddle point problem Find λ, u such that: max min L(u, λ) = 1 2 u. u − Ω Ω 1 λ∈L2 (Ω),λ≥0 u∈H0 (Ω) fu + Ω λ(u − g)+ where ((u − g)+ = max(0, u − g) This saddle point problem is equivalent to find u, λ such that:  1  u. v + λv + dω = f u, ∀v ∈ H0 (Ω)  Ω Ω   µ(u − g) = 0, Ω + (9.54) ∀µ ∈ L2 (Ω), µ ≥ 0, λ ≥ 0, A algorithm to solve the previous problem is: 1. k=0, and choose, λ0 belong H −1 (Ω) 2. loop on k = 0, ..... (a) set Ik = {x ∈ Ω/λk + c ∗ (uk+1 − g) ≤ 0} 1 (b) Vg,k+1 = {v ∈ H0 (Ω)/v = g on Ik }, 1 (c) V0,k+1 = {v ∈ H0 (Ω)/v = 0 on Ik }, (d) Find uk+1 ∈ Vg,k+1 and λk+1 ∈ H −1 (Ω) such that   uk+1 . vk+1 dω = f vk+1 ,  Ω Ω ∀vk+1 ∈ V0,k+1  < λ , v >=  k+1 uk+1 . v − f v dω Ω 1 where <, > is the duality bracket between H0 (Ω) and H −1 (Ω), and c is a penalty constant (large enough). You can find all the mathematic about this algorithm in [33]. Now how to do that in FreeFem++ The full example is: Example 9.25 (VI.edp) mesh Th=square(20,20); real eps=1e-5; fespace Vh(Th,P1); int n = Vh.ndof; Vh uh,uhp; Vh Ik; real[int] rhs(n); real c=1000; // // // P1 FE space // number of Degree of freedom // solution and previous one to def the set where the containt is reached. to store the right and side of the equation // the penalty parameter of the algoritm 9.7. VARIATIONAL INEQUALITY func f=1; func fd=0; Vh g=0.05; real[int] Aii(n),Aiin(n); real tgv = 1e30; // 233 // right hand side function Dirichlet boundary condition function // the discret function g // to store the diagonal of the matrix 2 version // a huge value for exact penalization // of boundary condition definition of the problem // bilinear form // linear form boundary condition form // the variatonal form of the problem: varf a(uh,vh) = // int2d(Th)( dx(uh)*dx(vh) + dy(uh)*dy(vh) ) - int2d(Th)( f*vh ) + on(1,2,3,4,uh=fd) ; // // two version of the matrix of the problem matrix A=a(Vh,Vh,tgv=tgv,solver=CG); matrix AA=a(Vh,Vh,solver:GC); // // one changing one for computing residual // the mass Matrix construction: varf vM(uh,vh) = int2d(Th)(uh*vh); matrix M=vM(Vh,Vh); // to do a fast computing of L2 norm : u’*(w=M*u)) Aii=A.diag; // sqrt( get the diagonal of the matrix (appear in version 1.46-1) rhs = a(0,Vh,tgv=tgv); Ik =0; uhp=-tgv; // previous value is Vh lambda=0; for(int iter=0;iter<100;++iter) { real[int] b(n) ; b=rhs; // get a copy of the Right hand side real[int] Ak(n); // the complementary of Ik ( !Ik = (Ik-1)) // Today the operator Ik- 1. is not implement so we do: Ak= 1.; Ak -= Ik[]; // build Ak = ! Ik // adding new locking condition on b and on the diagonal if (Ik ==1 ) b = Ik[] .* g[]; b *= tgv; b -= Ak .* rhs; Aiin = Ik[] * tgv; Aiin += Ak .* Aii; // set Aii= tgv i ∈ Ik A.diag = Aiin; // set the matrix diagonal (appear in version 1.46-1) set(A,solver=CG); // important to change preconditioning for solving uh[] = Aˆ-1* b; // solve the problem with more locking condition lambda[] = AA * uh[]; // compute the residual ( fast with matrix) lambda[] += rhs; // remark rhs = − f v Ik = ( lambda + c*( g- uh)) < 0.; // the new of locking value plot(Ik, wait=1,cmm=" lock set ",value=1,ps="VI-lock.eps",fill=1 ); plot(uh,wait=1,cmm="uh",ps="VI-uh.eps"); // trick to compute L2 norm of the variation (fast method) real[int] diff(n),Mdiff(n); diff= uh[]-uhp[]; Mdiff = M*diff; real err = sqrt(Mdiff’*diff); cout << " || u_{k=1} - u_{k} ||_2 " << err << endl; if(err< eps) break; // stop test 234 uhp[]=uh[] ; } savemesh(Th,"mm",[x,y,uh*10]); CHAPTER 9. MATHEMATICAL MODELS // set the previous solution // for medit plotting Remark, as you can see on this example, some vector , or matrix operator are not implemented so a way is to skip the expression and we use operator +=, -= to merge the result. 9.8 Domain decomposition We present, three classic examples, of domain decomposition technique: first, Schwarz algorithm with overlapping, second Schwarz algorithm without overlapping (also call Shur complement), and last we show to use the conjugate gradient to solve the boundary problem of the Shur complement. 9.8.1 To solve Schwarz Overlap Scheme −∆u = f, in Ω = Ω1 ∪ Ω2 u|Γ = 0 the Schwarz algorithm runs like this −∆un+1 = f in Ω1 1 −∆un+1 = f in Ω2 2 un+1 |Γ1 = un 2 1 un+1 |Γ2 = un 1 2 where Γi is the boundary of Ωi and on the condition that Ω1 ∩ Ω2 = ∅ and that ui are zero at iteration 1. Here we take Ω1 to be a quadrangle, Ω2 a disk and we apply the algorithm starting from zero. Figure 9.25: The 2 overlapping mesh TH and th Example 9.26 (Schwarz-overlap.edp) int inside = 2; int outside = 1; border a(t=1,2){x=t;y=0;label=outside;}; border b(t=0,1){x=2;y=t;label=outside;}; // // inside boundary outside boundary plot(U.label=inside.wait=1).i< 10.v.u = 0 ) .0){x=t . = ) + on(outside. border d(t=1.}. Figure 9.}.label=outside. mesh th = buildmesh( a(5*n) + b(5*n) + c(10*n) + d(5*n)). vh u=0. }. DOMAIN DECOMPOSITION 235 border c(t=2.label=inside. problem PB(U.wait=true).U= 0 ) .init=i.init=i.solver=Cholesky) int2d(th)( dx(u)*dx(v)+dy(u)*dy(v) + int2d(th)( -v) + on(inside . y = sin(t). y = t.u. mesh TH = buildmesh( e(5*n) + e1(25*n) ).V.8. 2*pi){ x= cos(t). pi/2){ x= cos(t).y=1. // to see the 2 meshes The space and problem definition is : fespace vh(th. border e1(t=pi/2.solver=Cholesky) int2d(TH)( dx(U)*dx(V)+dy(U)*dy(V) + int2d(TH)( -V) + on(inside. i++) { PB. y = sin(t).P1). int i=0.v.9.TH.u = U) = ) + on(outside. pb.U = u) problem pb(u. fespace VH(TH. The calculation loop: for ( i=0 .}. plot(th. int n=4.V.}. VH U. border e(t=0.26: Isovalues of the solution at iteration 0 and iteration 9 .0){x = 1-t.P1).label=outside. P1).label=inside. fespace vh(th. border d(t=1. fespace VH(TH. y = sin(t). border b(t=0. y = t.label=inside. VH U.0){x=t .2 To solve Schwarz non Overlap Scheme −∆u = f in Ω = Ω1 ∪ Ω2 u|Γ = 0. MATHEMATICAL MODELS Figure 9.}. border e1(t=pi/2. mesh th = buildmesh( a(5*n) + b(5*n) + c(10*n) + d(5*n)).TH.}. int outside = 1. int n=4.8. y = t.wait=1. the Schwarz algorithm for domain decomposition without overlapping runs like this Let introduce Γi is common the boundary of Ω1 and Ω2 and Γi = ∂Ωi \ Γi . plot(th. border e(t=0.P1). vh lambda=0. 1){ x= 1-t.V.}. 2*pi){ x= cos(t).ps="schwarz-no-u. border a(t=1.label=outside.236 CHAPTER 9.y=1. vh u=0.label=outside.2){x=t. mesh TH = buildmesh ( e(5*n) + e1(25*n) ).y=t.eps").}.0){x = 1-t.label=outside. .edp) // schwarz1 without overlapping int inside = 2.1){x=2.}.27: The two none overlapping mesh TH and th 9.27 (Schwarz-no-overlap.}.v. e The problem find λ such that (u1 |Γi = u2 |Γi ) where ui is solution of the following Laplace problem: −∆ui = f in Ωi ui |Γi = λ ui |Γi = 0 e To solve this problem we just make a loop with upgradingλ with λ = λ± (u1 − u2 ) 2 where the sign + or − of ± is choose to have convergence.label=outside. Example 9.y=0. border c(t=2. Figure 9. plot(U.solver=Cholesky) = int2d(TH)( dx(U)*dx(V)+dy(U)*dy(V) ) + int2d(TH)( -V) + int1d(TH. problem pb(u.wait=true). plot(U.28: Isovalues of the solution at iteration 0 and iteration 9 without overlapping 9. 237 for ( i=0 .solver=Cholesky) = int2d(th)( dx(u)*dx(v)+dy(u)*dy(v) ) + int2d(th)( -v) + int1d(th.u. i++) { PB.u = 0 ) .8.v. }. DOMAIN DECOMPOSITION int i=0.inside)(lambda*V) + on(outside.9. problem PB(U. pb.u.ps="schwarz-no-u. lambda = lambda .i< 10.edp −∆u = f in Ω = Ω1 ∪ Ω2 u|Γ = 0.U= 0 ) .init=i. the Schwarz algorithm for domain decomposition without overlapping runs like this Let introduce Γi is common the boundary of Ω1 and Ω2 and Γi = ∂Ωi \ Γi .8.(u-U)/2.inside)(-lambda*v) + on(outside.init=i.eps").V.3 To solve Schwarz-gc. e The problem find λ such that (u1 |Γi = u2 |Γi ) where ui is solution of the following Laplace problem: −∆ui = f in Ωi ui |Γi = λ ui |Γi = 0 e . y=0. 2*pi){ x= cos(t). The boundary problem function.solver=CG) =int1d(Th1.P1). // fespace Vh1(Th1.init=i. problem Pb1(u1.u1 = 0 ) . int i=0. border Gamma1(t=1. because the lambda function is none zero inside the domain Ω1 : varf b(u2. // take λ ∈ Vh1 The two Poisson problem: Vh1 u1. λ −→ Γi (u1 − u2 )v1 .}. border GammaInside(t=1.label=outside. border Gamma2(t=0.}. int n=4. y = sin(t).v1. MATHEMATICAL MODELS The version of this example for Shur componant. border GammaArc(t=pi/2.238 CHAPTER 9. Vh2 u2.solver=Cholesky) = int2d(Th1)( dx(u1)*dx(v1)+dy(u1)*dy(v1) ) + int2d(Th1)( -v1) + int1d(Th1. defined the 2 FE space Note 9.6 It is impossible to define a function just on a part of boundary. border Gamma3(t=2.0){x=t .1){x=2. y = t.init=i.inside)(u2*v2).inside)(+lambda*v1) + on(outside. so the lambda function must be defined on the all domain Ω1 such as Vh1 lambda=0.y=t.Vh1. // for factorization optimization problem Pb2(u2.label=outside.edp) // Schwarz without overlapping (Shur complenement Neumann -> Dirichet) real cpu=clock(). int outside = 1.label=inside.u2= 0 ) .2){x=t.solver=Cholesky) = int2d(Th2)( dx(u2)*dx(v2)+dy(u2)*dy(v2) ) + int2d(Th2)( -v2) + int1d(Th2.label=outside. int inside = 2. First. // build the mesh of Ω1 and Ω2 mesh Th1 = buildmesh( Gamma1(5*n) + Gamma2(5*n) + GammaInside(5*n) + Gamma3(5*n)). The border problem is solve with conjugate gradient. mesh Th2 = buildmesh ( GammaInside(-5*n) + GammaArc(25*n) ). plot(Th1. matrix B= b(Vh1. we define a border matrix . we construct the two domain Example 9.v2. or.Th2).inside)(-lambda*v2) + on(outside.v1.label=outside.}.P1). Vh2(Th2.0){x = 1-t.solver=CG).y=1.v2.28 (Schwarz-gc.v2.}.}. Pb1. . ij ∂vj 1 ∂vi = ( + ) 2 ∂xj ∂xi where δ is the Kronecker symbol and where λ. and Young’s modulus. When the displacement vector v = (v1 .eps=1.u2 cout << " -. v1=-(u1-u2). // solve again to have right u1. schwarz-gc:" << clock()-cpu << endl.9. at (x.u2). v2 ) = (X − x. // plot 9.nbiter=100).7 The difference between the two notations v1 and v1[] is: v1 is the finite element function and v1[] is the vector in the canonical basis of the finite element function v1 . FLUID/STRUCTURES COUPLED PROBLEM 239 func real[int] BoundaryProblem(real[int] &l) { lambda[]=l. in Ω. // compute the final solution. lambda[]=B*v1[]. return lambda[] .9 Fluid/Structures Coupled Problem This problem involves the Lam´ system of elasticity and the Stokes system for viscous fluids with e velocity u and pressure p: −∆u + p = 0. Pb2. The force that the fluid applies to the boundaries is the normal stress h = ( u + uT )n − pn Elastic solids subject to forces deform: a point in the solid. Y − y) is small.q=0.e-6. // // make FE function form l no refactorization i !=0 Note 9.p[]. i++. Vh1 p=0.Y) after. }. ∀w ∈ V The data are the gravity force g and the boundary stress h. µ are two constants describing the material mechanical properties in terms of the modulus of elasticity.CPU time plot(u1.y) goes to (X. Hooke’s law relates the stress tensor σ inside the solid to the deformation tensor : σij = λδij . The equations of elasticity are naturally written in variational form for the displacement vector v(x) ∈ V as [2µ Ω ij (v) ij (w) + λ ii (v) jj (w)] = Ω g·w+ Γ h · w. because CG works with increment BoundaryProblem(p[]).9.v + 2µ ij . // solve the problem with Conjugate Gradient LinearCG(BoundaryProblem. · u = 0. u = uΓ on Γ = ∂Ω where uΓ is the velocity of the boundaries. 0)*( t>=0.5.}.label=bottombeam. // left beam border b(t=0. label= 1. The bending displacement of the beam is given by (uu.vv) ) ) + int2d(th) (-gravity*s) + on(1.}. plot(th1. y=-10.}. .999).wait=1).0) { x=0. plot([uu.vv. label=3. [x+uu. int bottombeam = 2. real lambda = E*sigma/((1+sigma)*(1-2*sigma)). y=t . .29 (fluidStruct. mesh th = buildmesh( b(20)+c(5)+d(20)+a(5)).vv]. y=-10+t . The cavity is the 10 × 10 square and the lid is a rectangle of height l = 2. MATHEMATICAL MODELS Example 9.e. y=-t .g driven cavite on left side g x=t. // left x=t. // top beam real E = 21.}. // right x=0.10) { x=t.s]) = int2d(th)( lambda*div(w. y=2.fluidforce=0.}. }. // bottom of beam border c(t=0. label= 1. // Fluid-structure interaction for a weighting beam sitting on a // square cavity filled with a fluid. The geometry is that of a vertical driven cavity with an elastic lid. y+vv]). fespace Vh(th.uu=0.w.label=1.label= 2.edp) In our example the Lam´ system and the Stokes system are coupled e by a common boundary on which the fluid stress creates a displacement of the boundary and hence changes the shape of the domain where the Stokes problem is integrated.s. A beam sits on a box full of fluid rotating because the left vertical side has velocity one.vv].label=1.wait=1).[w. The beam is bent by its own weight.2) { x=10.s)’*epsilon(uu.29. // label of bottombeam border a(t=2.f. real mu = E/(2*(1+sigma)). // bottom x=10. plot(sh.vv) whose solution is given as follows.*mu*( epsilon(w.vv=0) + fluidforce[].P1). cout << "lambda.gravity ="<<lambda<< " " << mu << " " << gravity << endl.10) { x=10-t. The lid is a beam with weight so it will be deformed by its own weight and by the normal stress due to the fluid reaction. Vh uu. Then Stokes equation for fluids ast low speed are solved in the box below the beam.10) h(t=0.wait=1). // deformation of a beam under its own weight solve bb([uu. mesh th1 = movemesh(th. y=t . // top of cavity deformed border border border border e(t=0. but the beam has deformed the box (see border h): // Stokes on square b.001 )*(t <= 9. }.10) { { { { mesh sh = buildmesh(h(-20)+f(10)+e(10)+g(10)). real gravity = -0. y=vv(t.mu. // rigth beam border d(t=0.vv) +2.05. y=0 .10) g(t=0. but the pressure of the fluid modifies the bending. real sigma = 0.10) f(t=0. label=3.240 CHAPTER 9.}.s)*div(uu. Mh).q=0.q) = int2d(sh)( -(dx(u1)*q)). verbosity=verb.v1=0.P1). do a loop on the two problem for(step=0.vv1=vv.y+vv]) = (dx(u1)+dy(u2)). brhs[] = By’*pp. func real[int] divup(real[int] & pp) { int verb=verbosity.step<2.q. matrix By= by(Xh.eps=1.*bcx[]. Xh brhs. u1[] = Aˆ-1*brhs[].ppp. ppp[] += By*u2[]. Now the beam will feel the stress constraint from the fluid: Vh sigma11.u2.u1=0) . divup(p[]). brhs[] += bc1[] .sigma22.9. sigma12([x+uu. Xh u1. matrix A= Lap(Xh. matrix Bx= bx(Xh.u1=0. which comes as a boundary condition to the PDE of the beam: . ppp[] = Bx*u1[].y+vv]) = (2*dy(u2)-p).6. bc1[] = Lap(0. brhs[] = Bx’*pp. Xh bcx=0.e-3. varf bx(u1. Vh uu1=uu. }. varf by(u1.p[]. FLUID/STRUCTURES COUPLED PROBLEM 241 We use the Uzawa conjugate gradient to solve the Stokes problem like in example Section 9.*bcy[].v2.q) = int2d(sh)( -(dy(u1)*q)).2 fespace Xh(sh. LinearCG(divup.Mh).solver=CG). Xh bc1.sigma12. sigma22([x+uu.Xh).Mh(sh. varf Lap(u1. sigma11([x+uu.Xh. brhs[] += bc1[] . return ppp[] . u2[] = Aˆ-1*brhs[].u2)= int2d(sh)( dx(u1)*dx(u2) + dy(u1)*dy(u2) ) + on(2.v1.bcy=1.nbiter=50).++step) { p=0. verbosity=0.P2).y+vv]) = (2*dx(u1)-p).9.3.u1=1) + on(1. Mh p. 26528 -1.wait=1). cout << " Erreur L2 = " << err << "----------\n".0499861 0.599833 0.vv=0).p IsoValue -2.2*vv]).199944 0.1). 3 be the domain occupied by i-th material with tension µi (see Section 9.89975 0.649819 0.54503 -1. welded on each other.vv) +2. plot([uu. i = 1. y) is obtained from − µi ∆u = f in Ωi µi ∂n u|Γi = −µj ∂n u|Γj on Ωi ∩ Ωj if 1 ≤ i < j ≤ 3 (9.vv) ) ) + int2d(th) (-gravity*s) + int1d(th.[w. Notice that the matrix generated by bbst is reused (see init=i).104524 0.1849 -0. The computational domain Ω is the interior of Ω1 ∪ Ω2 ∪ Ω3 .1. The vertical displacement u(x.85686 4.849764 0.77649 3.21699 Vec Value 0 0.x*s) ) ) + on(1.90515 -1.x*w + sigma22*N.29: Fluid velocity and pressure (left) and displacement vector (center) of the structure and displaced geometry (right) in the fluid-structure interaction of a soft side and a driven cavity solve bbst([uu.49674 3.uu=0.46465 -0.13661 3.s)*div(uu.549847 0.bottombeam)( -coef*( sigma11*N.33598 1.56) . } // end of loop 9.y*s + sigma12*(N.s)’*epsilon(uu.55) (9.242 [u1.249931 0.62541 -2.05623 2.u2]. real err = sqrt(int2d(th)( (uu-uu1)ˆ2 + (vv-vv1)ˆ2 )). Finally we deform the beam th1 = movemesh(th.41636 2.824776 -0.749792 0. plot(th1.y*w+N. [x+0.299917 0.975855 1.s]. 2.949736 CHAPTER 9.799778 0.349903 0.*mu*( epsilon(w.vv].0999722 0.init=i) = int2d(th)( lambda*div(w. MATHEMATICAL MODELS Figure 9.vv].255603 0. which is made up of three plates of different materials. Let Ωi .wait=1).699806 0.615729 0.399889 0.149958 0. y+0.2*uu.69611 2.499861 0.449875 0.10 Transmission Problem Consider an elastic plate whose displacement change vertically. }.0. i. v) = a(u.0.58) µ u· v. So to get the number of a region containing a particular point one does: int nupper=reg(0. plot(nu.}. Consider this L-shaped domain with 3 diagonals as internal boundaries.5. // defined the characteristics functions of upper and lower region Ph nu=1+5*(region==nlower) + 10*(region==nupper). // P1 continuous functions / element Ph reg=region.9.57) we can easily rewrite (9.}.e. This number is defined by ”buildmesh” which scans while building the mesh all its connected component.y=0. Here we notice that µ become the discontinuous function.9) int nlower=reg(0. find u such that a(u.0. // get the region number of point (0.5){x=t.4. v) 1 for all v ∈ H0 (Ω) (9. defining 4 subdomains: // example using region keyword construct a mesh with 4 regions (sub-domains) // border border border border border border a(t=0. d(t=0.y=1.}.wait=1).fill=1. problem Transmission: For a given function f .P1). . This is particularly useful to define discontinuous functions such as might occur when one part of the domain is copper and the other one is iron.y=1-t. border i3(t=0. // constant discontinuous functions / element fespace Vh(th.}. f(t=0.y=t. subdomains of the whole domain.10.5.5){x=t.}. // get the region number of point (0. use Ph reg=region.y=1-t. // defined the P0 function associated to region number plot(reg.y=t. TRANSMISSION PROBLEM 243 where ∂n u|Γi denotes the value of the normal derivative ∂n u on the boundary Γi of the domain Ωi .4.fill=1.1){x=0.0.5){x=1-t.1).5){x=1-t. χi (x) = 0 if x ∈ Ωi (9. Here we assume that u = 0 on Γ = ∂Ω.5. χi (x) = 1 if x ∈ Ωi . region is a keyword of FreeFem++ which is in fact a variable depending of the current position (is not a function today.9). By introducing the characteristic function χi of Ωi .0. This variable value returned is the number of the subdomain of the current position.1){x=t.P0).value=1). and at the thermal equilibrium.y=0. // border i1(t=0. b(t=0.1) cout << " nlower " << nlower << ". internal boundary mesh th = buildmesh (a(6) + b(4) + c(4) +d(4) + e(4) + f(6)+i1(6)+i2(6)+i3(6)).5.wait=1.4. nupper = " << nupper<< endl. c(t=0.0.y=t.1){x=0.}. fespace Ph(th. that is.9.0.}. v) = Ω (f.5){x=1.}. With dissipation. e(t=0. the temperature equation is: This example explains the definition and manipulation of region. for example. border i2(t=0. (f.1){x=1-t.55) and (9.56) to the weak form. to set a function). v) = Ω fv where µ = µ1 χ1 + µ2 χ2 + µ3 χ3 .0.0.y=t. plot(u).789474 1.52632 6.36842 2.63158 3.u=0). 6 and 11 below).68421 3 3. Ph nu=1+5*(region==nlower) + 10*(region==nupper).315789 0.89474 5.157895 0.e.b.f.30: the function reg Figure 9.26316 4.21053 5.10526 1. problem lap(u.73684 2.31: the function nu We this in mind we proceed to solve a Laplace equation with discontinuous coefficients (ν is 1.fill=1.244 IsoValue -0.31579 3.d. MATHEMATICAL MODELS IsoValue 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Figure 9.05263 2.31579 CHAPTER 9.c. .wait=1). plot(nu.473684 0.v) = int2d(th)( nu*( dx(u)*dx(v)*dy(u)*dy(v) )) + int2d(-1*v) + on(a.94737 4.42105 1.57895 4. 00990285 0.00630181 0.0135039 0.020706 0. real h=2. d(t=h.00810233 0.0){x=t.0117034 0. // // // // // maillage d’un tapeze bottom: Γa right: Γb free surface: Γf left: Γd int n=4. f(t=L.9.}.027908 0. Figure 9.0225065 0.1.0189054 0.0171049 0.y=t.35.y=t*(h1-h)/L+h. real h1=0.024307 0.y=0. // // border border border border a(t=0.}.y=t.11 Free Boundary Problem // longueur du domaine hauteur du bord gauche hauteur du bord droite The domain Ω is defined with: real L=10.11.32: the isovalue of the solution u 9.}.0045013 0.00270078 0.ps="dTh.0315091 0.}.0153044 0.0){x=0. mesh Th=buildmesh (a(10*n)+b(6*n)+f(8*n)+d(3*n)).L){x=t.33: The mesh of the domain Ω The free boundary problem is: Find u and Ω such that: . plot(Th. FREE BOUNDARY PROBLEM IsoValue 0.0297086 0.eps"). b(t=0.h1){x=L.0333096 0.0351101 245 Figure 9.0261075 0.000900259 0. y.x+dy(u)*N.5.246              CHAPTER 9.P1).f)(vv*((q/K)*N. fist we solve the classical following problem:   −∆u = 0 in Ωn     u = y on Γn b ∂u  = 0 on Γn ∪ Γn a  ∂n d    n u = y on Γf The variational formulation is: find u on V = H 1 (Ωn ).y))). y) = [x.u=y) . v=0) + int1d(Th.(dx(u)*N. // // flux entrant permeabilit´ e . int j=0.uu. MATHEMATICAL MODELS −∆u = 0 u=y ∂u =0 ∂n ∂u q = nx and u = y ∂n K in Ω on Γb on Γd ∪ Γa on Γf We use a fixed point method. y)] where v is solution of the following problem:  in Ωn  −∆v = 0     v =0 on Γn a  ∂v on Γn ∪ Γn d b  ∂n = 0   ∂v  ∂u q   = − nx on Γn f ∂n ∂n K The variational formulation is: find v on V .f. such than v = 0 on Γn a v v = Ωn Γn f ( ∂u q − nx )v . Vh u.edp) The FreeFem++ :implementation is: real q=0.02. y − v(x. Ω0 = Ω in two step.uu.solver=CG) = int2d(Th)( dx(v)*dx(vv)+dy(v)*dy(vv)) + on (a.vv.solver=CG) = int2d(Th)( dx(u)*dx(uu)+dy(u)*dy(uu)) + on(b. ∂n K ∀v ∈ V with v = 0 on Γn a Finally the new domain Ωn+1 = F(Ωn ) Example 9. fespace Vh(Th.30 (freeboundary.v. problem Pv(v. Ωn ∀u ∈ V with u = 0 on Γn ∪ Γn b f and secondly to construct a domain deformation F(x. real K=0.vv. such than u = y on Γn and Γn b f u u = 0. problem Pu(u. f)(v*v). Pv. Pu.34: The final solution on the new domain Ω72 . if (mint>mintcc) break.wait=0). verbosity=1.[x.[x.[x. real erradap=0.[x.y-coef*v]).eps"). // calcul de la deformation cout << "\n\n"<<j <<"-----------. } plot(Th..v . while(errv>1e-6) { j++.eps"). // mesh to bad => remeshing Figure 9.11. cout << " min |T] coef /= 1. plot(u.001.err=erradap ) . } Th=movemesh(Th.. plot(Th. errv=int1d(Th.y])/5. " << mint << endl. mintcc = checkmovemesh(Th. real coef=1. FREE BOUNDARY PROBLEM 247 real errv=1.ps="d_u.y-v*coef]). // real mintcc = checkmovemesh(Th.errv = " << errv << "\n\n".ps="d_Thf. real mint = checkmovemesh(Th.wait=1.9.y])/5.u.5.[x. if (mint<mintcc || j%10==0) { Th=adaptmesh(Th. } while (1) { real mint = checkmovemesh(Th.y-v*coef]).u. DE[u](w) ).(dx(v)+dy(u)).uu. w) f (F 2(u))) // EOM ENL .5(∂i uj + ∂j ui ) + k ∂i uk ×∂j uk Denote u = (u1 . So.35: The adapted mesh of the domain Ω72 9. and D2 E is the second differential of E.12 Non linear Elasticity (nolinear-elas. // is [ 11 . u2 ) = Ω The nonlinear elasticity problem is: find the displacement (u1 .edp) min J(u1 . and E[u1 . u2 ] = (Eij )i=1.v. 22 ] DF 2(u)(v) DF 2(u)(w) f (F 2(u))) D2 F 2(u)(v.dy(v)] macro ENL(u. v = (v1 . The second order differential is D2 J(u)((v). v2 ). u2 ) = A(E[u1 . (w)) = + where D2 F 2(u)(v. where f is a given C 2 function. Y ) is bilinear sym. w) . (dy(u)*dy(u)+dy(v)*dy(v))*0. w) = 2 A( D2 E[u](v.2 is the Green-Saint Venant deformation tensor defined with: Eij = 0.v) [ (dx(u)*dx(u)+dx(v)*dx(v))*0. (dx(u)*dy(u)+dx(v)*dy(v)) .vv) [(dx(u)*dx(uu)+dx(v)*dx(vv)). j=1. MATHEMATICAL MODELS Figure 9.2. w = (w1 . Y .248 CHAPTER 9. (dx(u)*dy(uu)+dx(v)*dy(vv)+dx(uu)*dy(u)+dx(vv)*dy(v)). positive form with respect two matrix X.v) [dx(u).5.5 ] macro dENL(u. 2 12 . E[u1 . So all notations can be define with macros: macro EL(u. u2 ]. u2 ) minimizing J f (F 2) − Γp Pa u2 where F 2(u1 . u2 ]) and A(X. w2 ). the differential of J is DJ(u)(v) = DF 2(u)(v) f (F 2(u))) − Γp Pa v2 where DF 2(u)(v) = 2 A( DE[u](v) . E[u] ) and DE is the first differential of E. u2 ). E[u] ) + 2 A( DE[u](v) . uuu. s until (du.v)’*A*dE(u. (du.EDP) (dy(u)*dy(uu)+dy(v)*dy(vv)) ] // 249 macro macro macro macro macro macro E(u.vv.vv) (EL(uu. 2E12 .v.v)’*A*E(u.uuu. dv)) = DJ(un . vn )((w.uu.v.9. And it is easy to make automatic differentiation.uuu. vn = vn − dv ∀w. NON LINEAR ELASTICITY (NOLINEAR-ELAS.uu.v. f .) // ------------------------------- .vvv))*2.uu.v. s).v) (E(u. vO the initial displacement • loop: • find (du.and uO .36: The deformed domain // // // macro f(u) (u) macro df(u) (1) macro ddf(u) (0) // non linear elasticity model for hyper elasticity problem ----------------------------// end of macro // end of macro // end of macro -.vv)’*A*dE(u. s).v.uu.v.vv. E22 ] // // // // // EOM The Newton Method is choose n = 0.v.f .v)) dF2(u.du caouchouc --. Figure 9.v)) dE(u.vv.uu.vv) (E(u. f .vvv))*2.vv)+dENL(u. A macro is like in ccp preprocessor of C++ .v.v)’*A*ddE(u.12.uu.v)+ENL(u. dv) : solution of D2 J(un . ) // is [E11 .vv)) ddE(u.uuu. ) ddF2(u. • • un = un − du.vvv) ( (dE(u. dv) small is enough The way to implement this algorithm in FreeFem++ is use a macro tool to implement A and F 2.v.uu.uu.v) (EL(u.vv)*2.vv) F2(u. + (E(u.vvv.uu.(see the notes of Herve Le Dret. but this begin by macro and the end of the macro definition is before the comment //. vn )(w.vvv) dENL(uuu. In this case the macro is very useful because the type of parameter can be change. [uu.c) -> (a+c. right=2. ------------------v // because [0. 0] = = 2 ∗ mu ∗ (t12 ∗ s12 + t21 ∗ s21) = 4 ∗ mu ∗ t12 ∗ s12 // real a21= a12 .0]. plot(Th).vn]. v) = σ(u) : E(v) // // ( a b ) // ( b c ) // // tr*Id : (a. [w.a22. real real real real a33= a12= a13= a23= lambda .0].vv]=[0.m.m=10. // symetric part the matrix A. 0 . a pressure of 100 Pa 1 bottom.012e5.s].vv].fe2.dfe2.erz.250 real mu = 0. real a31= a13 . // 2*mu + lambda . mesh Th= square(n.P1).3*y]). real a32= a23 .err.[P1. // // optimisation optimisation // intialisation . [un. 0] A[0.upper=3.b.ddfe2.4e5.0.a13]. // label: int bottom=1.P1]). 3 up. // ---------------int n=30.left=4.a33] ]. fespace Sh(Th. 2 right. real Pa=1e2. Wh e2. real lambda = 0. 4 left.[ a31. lambda .a23].vn]=[0. fespace Vh(Th. // // σ = 2µE + λtr(E)Id // A(u.[un. fespace Wh(Th.[x. 0 . MATHEMATICAL MODELS // // kg/cm2 kg/cm2 // real a11= 2*mu + real a22= mu ..a+c) // so the associed matrix is: // ( 1 0 1 ) // ( 0 0 0 ) // ( 1 0 1 ) CHAPTER 9. // func A = [ [ a11. Vh [uu. 2 ∗ s12.ezz.P1dc).a12.a32. Wh ett. 2 ∗ t12.[ a21. cmm=" displacement " ). vv " ).max << endl.36 9. [x+un. plot(th1.13.solver=CG) = int2d(Th)( uu*w + vv*s ).w.max << " .vn.cmm=" uu.s)*dfe2 ) + on(right. dfe2 = df(e2) .s]. vv] = (D2 J(un))−1 (DJ(un)) w[] = M*uu[].s]. mesh th1 = movemesh(Th. cout << " Lˆ2 residual = " << res << endl.v1.int2d(Th. for (int i=0. e2 = F2(un. cout << " u1 min =" <<u1[].vv)*dF2(un.max << " .max << " .min << ". . un[] -= uu[]. plot([uu.wait=1).qforder=1)( // (D2 J(un)) part dF2(un. // norme L2 of [uu.wait=1).solver=LU)= int2d(Th. min" << e2[].vn].int1d(Th. } plot([un. // Newton’s method // --------------Sh u1. y+vn]).uu. v2 max= " << v1[]. // see figure 9. problem NonLin([uu.[w.vv].min << endl. cout << " de2 max "<< dfe2[].vn].s.w.i++) { cout << "Loop " << i << endl. plot([un.vn.max << endl.min << endl.vv]. COMPRESSIBLE NEO-HOOKEAN MATERIALS: COMPUTATIONAL SOLUTIONS251 varf vmass([uu.w. cout << " v1 min =" <<v1[].13 Compressible Neo-Hookean Materials: Computational Solutions Author : Alex Sadovsky mailsashas@gmail.[w.vn. matrix M=vmass(Vh. cout << "dde2 max "<< ddfe2[].left.qforder=1)( // (DJ(un)) part dF2(un. real res = sqrt(w[]’ * uu[]).Vh).min << ".min << endl.vv=0).9.s)*ddfe2 + ddF2(un.wait=1.vv]. v1 = vv. vv] u1 = uu. min" << ddfe2[]. min" << dfe2[]. ddfe2 = ddf(e2).3)(Pa*s) .vn. if (res<1e-5) break.uu.wait=1. u1 max= " << u1[]. // compute [uu. cout << " e2 max " <<e2[].vn).vv)*dfe2 ) .com .uu=0.i<10. NonLin. The corresponding 2nd Piola-Kirchoff stress tensor is given by Sn := The Kirchhoff stress. C. On the rest of the boundary.63) (9. the symbols u.13. with the major axes parallel. . consequently.59) ∂C The symbol I denotes the identity tensor.62) ∂W (Fn ) = µ(I − C−1 ) ∂E (9. respectively. F. is κ = FSFT = µ(B − I) The tangent Kirchhoff stress tensor at Fn acting on δFn+1 is.edu/courses/en222/Notes/FEMfinitestrain/FEMfinitestrain. htm. deformed) configuration is denoted dV (resp. these two are related by dV = JdV0 .engin. Let P denote the dead stress load (traction) on a portion ∂Ωt (= the inner ellipse) of the boundary ∂Ω0 . which allows an integral over Ω involving the Cauchy stress T to be rewritten as an integral of the Kirchhoff stress κ = JT over Ω0 . 9. MATHEMATICAL MODELS 9. The unit volume in the reference (resp. see http:// www.60) (see [32]. formula (12)). Recommended References For an exposition of nonlinear elasticity and of the underlying linear. An explanation of the Finite Element formulation of a nonlinear elastostatic boundary value problem. Use will be made of the identity ∂J = JC−1 (9. see [35]. the right Cauchy-Green strain tensor C = FT F.and tensor algebra. ∂κ (Fn )δFn+1 = µ Fn (δFn+1 )T + δFn+1 (Fn )T ∂F (9. and the Cauchy stress tensor. the displacement field.. then.252 CHAPTER 9. σ denote. B.2 given by A Neo-Hookean Compressible Material µ (I1 − tr I − 2 ln J) 2 Constitutive Theory and Tangent Stress Measures The strain energy density function is W = (9. whose boundary consists of two concentric ellipses (each allowed to be a circle as a special case). dV0 ).13. For an advanced mathematical analysis of the Finite Element Method. the left Cauchy-Green strain tensor B = FFT .1 Notation In what follows. see [34].brown. We also introduce the symbols I1 := tr C and J := det F..61) The Weak Form of the BVP in the Absence of Body (External) Forces The Ω0 we are considering is an elliptical annulus. The symbol Ω0 denotes the reference configuration of the body to be deformed. 0 we prescribe zero displacement. the deformation gradient. < d1Aux12 >...3 An Approach to Implementation in FreeFem++ The associated file is examples++-tutorial/nl-elast-neo-Hookean. < d4Aux11 >.13. . < d3Aux12 >. < d3Aux22 > .. The individual components of the tensor quantities D1 := Fn (δFn+1 )T + δFn+1 (Fn )T .. < d2Aux11 >. does not rely on this assumption and allows for a general value and direction of P .65) < T anK >:= ∂F will be implemented as the macros < T anK11 >. . < d3Aux11 >. < d4Aux12 >. Introducing the code-like notation. where a string in <>’s is to be read as one symbol. .. . D2 := F−T δFn+1 . however. < d2Aux12 >. < d4Aux22 >        ⊗ w)F−1 . the symbol δ here bears no variational context. < T anK12 >. 9. Ω0 κ[Fn ] : Ω0 κ[Fn ] : Ω0 ( ( ⊗ ⊗ w)F−1 n w)(F−2 δFn+1 ) n : ( ⊗ w)F−1 n ∂κ ∂F [Fn ]δFn+1 (9. < d1Aux22 >. n ⊗ w)F−2 δFn+1 . COMPRESSIBLE NEO-HOOKEAN MATERIALS: COMPUTATIONAL SOLUTIONS253 The weak formulation of the boundary value problem is 0 = − Ω0 κ[F] : ( ˆ ∂Ωt P · N0 0 ⊗ w)(F)−1 For brevity. (9. .edp. . The provided FreeFem++ code.13. . . the individual components of the tensor ∂κ [Fn ]δFn+1 (9.66) . we seek the correction δun+1 to obtain a better approximation un+1 = un + δun+1 by solving the weak formulation 0 = = = = − + Ω0 κ[Fn + δFn+1 ] : Ω0 Ω0 ( ⊗ w)(Fn + δFn+1 )−1 − : : ( ( κ[Fn ] + κ[Fn ] + ∂κ ∂F [Fn ]δFn+1 ∂κ ∂F [Fn ]δFn+1  ˆ  P · N0  ∂Ω0     ⊗ w)(Fn + δFn+1 )−1      −1 + F−2 δF  ⊗ w)(Fn  n+1 ) n              for all test functions w. ... < d2Aux22 > .64) where we have taken δFn+1 = ⊗ δun+1 Note: Contrary to standard notational use. The role of a variational virtual displacement here is played by w. in the rest of this section we assume P = 0. n D3 := ( and D4 := ( will be implemented as the macros < d1Aux11 >. Given a Newton approximation un of the displacement field u satisfying the BVP.. n . By δ we mean simply an increment in the sense of Newton’s Method..9. the tangent Kirchhoff stress term becomes ∂κ (Fn ) δFn+1 = µ D1 ∂F while the weak BVP formulation acquires the form 0 = − + Ω0 (9. MATHEMATICAL MODELS respectively.254 CHAPTER 9.68) . In the above notation.67) κ[Fn ] : D4 Ω0 κ[Fn ] : D3 Ω0 ∂κ ∂F [Fn ]δFn+1     : D4  for all test functions w (9. 2. // set MPI Group to proc 1.2 MPI constants mpisize The total number of processes. mpiBXOR.org/docs/mpi21-report. mpiLAND. mpiCommWorld The MPI_COMM_WORLD constant .. mpiPROD. mpiUndefined The MPI_Undefined constant.1 MPI keywords The following keywords and concepts are used: mpiComm to defined a communication world mpiGroup to defined a group of processors in the communication world mpiRequest to defined a equest to wait for the end of the communication 10.2.5. mpiLOR.pdf).. . . mpiGroup grp(procs). mpirank the id-number of my current process in {0. An extended interface with MPI has been added to FreeFem++ version 3.3]. mpiAnySource The MPI_ANY_SOURCE constant. 10.proc2=[0.Chapter 10 MPI Parallel version A first attempt of parallelization of FreeFem++ is made here with mpi. and all the keywords of MPI Op for the reduce operator: mpiMAX.. 10.3 in MPI COMM WORLD 255 ..mpi-forum.3 MPI Constructor int[int] proc1=[1.4]. mpisize − 1}. mpiLXOR. (see the MPI documentation for the functionality of the language at http://www. mpiSUM.. mpiBAND. mpiMIN. // receive a. // defined an MPI_Request mpiRequest[int] arq(10). mpiComm mpiComm comm=mpiCommWorld. high.local_leader). // wait add of Request array.rq. where a processor is just a integer rank.hight) . // to get the MPI status of send / recv processor(10) << a << b.rq) // return processor i with Resquest rq in // MPI_COMM_WORLD processorblock(i) // return processor i in MPI_COMM_WORLD // in block mode for synchronously communication processorblock(mpiAnySource) // return processor any source // in MPI_COMM_WORLD in block mode for synchronously communication processorblock(i. // build using // MPI_Intercomm_merge( intercomm. CHAPTER 10. ncomm(mpiCommWorld. pointer to a MPI_comm and pointer to a MPI_Request.grp). // send a.i) // return processor i with no Resquest in comm processor(i. int key.comm) // return processor i in in comm in block mode mpiBarrier(comm) . and processorblock with a special MPI_Request.comm) // return processor i with Resquest rq in comm processor(i. // remote_leader.b synchronously from the process 10. tag. mpiWaitAll(arq). processor(peer_comm.3 in comm set MPI Group to grp union proc1 set a MPI Comm to MPI COMM WORLD // set the MPI Comm form grp // MPI COMM WORLD mpiComm ncomm(comm. // MPI_Comm_split(MPI_Comm comm. mpiWtick() . // int color.proc2). mpiWtime() . &nicomm) mpiComm ncomm(intercomm.5 MPI communicator operator int status. &ncomm) mpiRequest rq. // wait on of Request. // return MPIWtime in second (real). 10.256 mpiGroup grp1(comm.peer_leader).comm) // return processor i with no Resquest in comm processor(comm.b asynchronously to the process 1.proc1). mpiRank(comm) .a).color. processor(10) >> a >> b. // build MPI_INTERCOMM_CREATE(local_comm. // do a MPI Barrier on communicator comm.key). // return MPIWTick in second (real).4 MPI functions // // return the size of comm (int) return the rank in comm (int) mpiSize(comm) . // broadcast from processor .2. processor(i) // return processor i with no Resquest in MPI_COMM_WORLD processor(mpiAnySource) // return processor any source // with no Resquest in MPI_COMM_WORLD processor(i. MPI_Comm *ncomm) mpiComm nicomm(processor(local_comm. // defined an array of 10 MPI_Request 10. broadcast(processor(10.tag). mpiWait(rq).comm). peer_comm. mpiGroup grp2(grp. local_leader. MPI PARALLEL VERSION // // // set MPI Group to proc 1. b. [examples++-mpi] Hecht%lamboot LAM 6. mesh. // receive synchronously from // the process 10. // Broadcast to all process of comm where the data type of a can be of type of int. matrix<complex> processor(10.comm.b. mpiReduceScatter(a.rq) << a . int[int]. mesh3.processor(. // Error // Error asynchronously without request . to Guy-Antoine Atenekeng Kahou. complex. complex[int.edp to test of all this functionality and Thank. the data a with request status=Irecv( processor(10. a).rq) .int]. SCHWARZ EXAMPLE IN PARALLEL // status=Send( processor(10.rq. // // send asynchronously to // the data receive asynchronously from // the data the process 10 a with request the process 10 a with request If a. mesh3[int]. // send asynchronously to to // the process 10.int]. matrix. complex[int]. double[int].5. status=Isend( processor(10. a) . mpiReduce(a. double[int.1. the data a without request status=Isend( processor(10.9/MPI 2 C++/ROMIO . processor(10.). methode de schwarz in parallele with 2 proc. 257 of com to other comm processor // send synchronously to the process 10 the data a // receive synchronously // from the process 10 the data a. we can use the following MPI functions: mpiAlltoall(a.comm.comm) .rq) >> a .b.processor(. a) . a). broadcast(processor(comm.b.int].processor(.comm]) .6 Schwarz example in parallel This example is a rewritting of example schwarz-overlap in section 9.b[. a). mpiAllReduce(a. a) . mpiGather(a. the data a...Hecht december 2003 ---------------------------------to test the broadcast instruction and array of mesh . mpiScatter(a. 10. // send asynchronously to // the process 10 .) ) .10. mpiMAX) .b[.b are arrays or full matrices of int. for his help to code this interface. mpiMAX) .comm) .8.edp // // // // // // // a new coding version c.mpiMAX) ..)) . ------------------------------F.b. See the examples++-mpi/essai.real.Indiana University [examples++-mpi] hecht% mpirun -np 2 FreeFem++-mpi schwarz-c. real.comm) . mesh[int].comm]) . or complex. int[int.a)).comm) . status=Irecv( processor(10) . mpiAllgather(a.6. Recv} // status=Recv( processor(10. label=exterior. receive in err1 processor(1-mpirank)<<err0. MPI PARALLEL VERSION add add the stop test --------------------------------- if ( mpisize != 2 ) { cout << " sorry.solver=Cholesky) = int2d(Th[mpirank])( dx(u)*dx(v)+dy(u)*dy(v) ) . if (mpirank == 0) Th[0] = buildmesh( a(5*n) + b(5*n) + c(10*n) + d(5*n)).u = U) + on(exterior. // send u to the other proc. Vhother U=0.u= 0 ) .258 // // CHAPTER 10.int2d(Th[mpirank])( v) + on(interior. border e1(t=pi/2.i< 20.P1). border d(t=1.2){x=t. i++) { cout << mpirank << " looP " << i << endl. fespace Vh(Th[mpirank]. for ( i=0 . border a(t=1. real err= sqrt(err0+err1).err1.}.1){x=2.label=exterior. real err0. number of processors !=2 " << endl.label=interior. exit(1). if (mpirank==0) plot(u.y=1.}. int exterior = 1. else Th[1] = buildmesh ( e(5*n) + e1(25*n) ).eps").ps="uU. y = t. // send err0 to the other proc. int i=0. problem pb(u. int interior = 2. mesh[int] Th(mpisize).} verbosity=3.label=exterior. if(err<1e-3) break. err0 = int1d(Th[mpirank]. broadcast(processor(0). 2*pi){ x= cos(t). err1 = " << err1 << endl. pi/2){ x= cos(t).Th[1]).}. Vh u=0. pb. border c(t=2.y=0. fespace Vhother(Th[1-mpirank].0){x = 1-t. cout <<" err = " << err << " err0 = " << err0 << ".U. border e(t=0. receive in U processor(1-mpirank) << u[].P1). y = sin(t).v. y = sin(t).}.v.interior)(square(U-u)) . processor(1-mpirank) >> U[].label=interior.y=t.0){x=t .}. . border b(t=0. int n=4. processor(1-mpirank)>>err1.label=exterior.}. broadcast(processor(1).init=i. }.Th[0]). 2) = Np i=1 πi ui After discretization with the Lagrange finite element method. so the discrete problem on Ωi of problem (10.e. ui = g on Γi ∩ Γ (10... SCHWARZ EXAMPLE IN PARALLEL 259 10. Let introduce (πi )i=1. |Γ ∀i = 1. the exist a global mesh Th such that Thi is include in Th . k • Nhi is the set of the degree of freedom σi . i. The parallel Schwarz method is Let = 0 the iterator and a initial guest u0 respecting the boundary condition (i. u +1 and ui = u on Γi \ Γ. In FreeFem++. Nataf...1) (10. q-e-d: Np 1 πi ∈ C 0 (Ω) : πi ≥ 0 and i=1 πi = 1. with a compatible mesh Thi of Ωi .. Thank to F.Np a regular partition of the unity of Ω. Γ • V0hi = {vh ∈ Vhi : ∀k ∈ Nhii . in Ω.1) is find Γ k uhi ∈ Vhi such that: where gi is the value of g associated to the degree of freedom k ∈ Nhii . We have to defined to operator to build the previous algorithm: We denote uh|i the restriction of uh on Vhi . Let us denote: • Vhi the finite element space corresponding to domain Ωi . . in Ωi .n). Denote Ωi the sub domain which is the support of πi function and also denote Γi the boundary of Ωi . • the conditional expression a ? b : c is defined like in C of C++ language by a?b : c ≡ if a is true then return b . e.10.6. a Schwarz parallel with a complexity almost independent of the number of process (with a coarse grid preconditioner). k • σi (vh ) is the value the degree of freedom k.1 True parallel Schwarz example This is a explanation of the two script examples++-mpi/MPIGMRES[2]D.6. Np : −∆ui = f. where f and g are two given functions of L2 (Ω) and of H 2 (Γ).. u0 = g). To solve the following Poisson problem on domain Ω with boundary Γ in L2 (Ω) : −∆u = f. Γ • Nhii is the set of the degree of freedom of Vhi on the boundary Γi of Ωi . k σi (vh ) = 0}. and u = g on Γ.edp. it can be written has with U is the vector corresponding to uh|i and the vector U1 is the vector corresponding to uhi is the solution of: real[int] U1(Ui. else return c Remark we never use finite element space associated to the full domain Ω because it to expensive. varf vPb(U.2) equation on process i.Whi). b = onG ? b : Bi .comm. where the freefem++ label of Γ is 1 and the label of Γi \ Γ is 10. and Bi the right of side of the problem.Whi).++j) Isend(processor(jpart[j]. mpiRequest[int] rq(n*2).Vh.Vrecv) // // defined the send buffer defined the revc buffer with the following macro definition: macro InitU(n. // set to πi ui for(int j=0. varf vPbon(U.260 real[int] b= onG .U=0). // def of the Finite element space.j<n. real[int] &vi) { int n= jpart. Let us introduce two array of matrix.Usend) InitU(njpart. } where the buffer are defined by: InitU(njpart.V)=on(10.++j) int k= mpiWaitAny(rq). let us call njpart the number the neighborhood of domain of Ωi (i. // apply the unity local partition .comm. for(int j=0.j<n.rq[j+n]). real[int] onG = vPbon(0. Update(V.U=G).aThij. MPI PARALLEL VERSION where onG[i] = (i ∈ Γi \ Γ)?1 : 0.Whij.* U.Th.U=g) + on(10. Ri[j][]).rq[j ]). So the tranfert and update part compute vi = πi ui + j∈Ji πj uj and can be write the freefem++ function Update: func bool Update(real[int] &ui. for (int j=0.U=1)+on(1. .Whij. U1 = Aiˆ-1*b. // add πj uj return true. matrix Ai = vPb(Whi. func real[int] DJ0(real[int]& U) { real[int] V(U.n) . are defined by fespace Whi(Thi.V)= int3d(Thi)(grad(U)’*grad(V)) + int3d(Thi)(F*V) +on(1. real[int] Bi=vPb(0. Smj[j] to defined the vector to send from i to j a neighborhood process.P2).Whi.j<n. // U[j]=0.++j) {Th=aTh[j].U) Vh[int] U(n). V = Aiˆ-1*b. vi = Pii*ui. we store in an array jpart of size njpart all this neighborhood.U).j<njpart.} First gmres algorithm: you can easily accelerate the fixe point algorithm by using a parallel GMRES algorithm after the introduction the following affine Ai operator sub domain Ωi . CHAPTER 10.j<njpart.aThij.aTh.j<n*2.n.++j) Irecv(processor(jpart[j].++j) vi += rMj[j]*Vrecv[j][]. To build the transfer/update part corresponding to (10.* U.Thij. b= onG .solver=sparsesolver).++j) Usend[j][]=sMj[j]*ui. for (int j=0.e: πj is none 0 of Ωi ).Thij. for(int j=0. b = onG ? b : Bi . Si[j][]). and the matrix rM j[j] to after to reduce owith neighborhood j domain. for (int j=0. V = Aiˆ-1*b. } 261 Where the parallel MPIGMRES or MPICG algorithm is just a simple way to solve in parallel the following Ai xi = bi . // the preconditioner Third gmres algorithm: Add a coarse solver to the previous algorithm First build a coarse grid on processor 0.Bc(Uc. // the Restiction on Process i grid with the partition πi CoarseSolve(real[int]& V. V = Ai*U. 1 .Uc).VhC. Pci’*Pii. } func real[int] PDJ(real[int]& U) { real[int] V(U. return V. Update(V.Pci. Uc= Rci*U. return r.processor(0. Second gmres algorithm: Use scharwz algorithm as a preconditioner of basic GMRES method to solving the parallel problem.mpiComm& comm) // solvibg the coarse probleme func bool { real[int] Uc(Rci. SCHWARZ EXAMPLE IN PARALLEL V -= U. func real[int] DJ(real[int]& U) { ++kiter. This is done in MPIGC dynamics library tool..comm).n).n).mpiSUM).. mpiReduce(Uc. real[int] b= onG ? 0.n).MPI_TYPE<R>::TYPE(). &r.U).MPI_Comm * comm) { R r=0.. } . and the matrix AC.real[int]& U. V = Pci*Uc. : U. if(mpiRank(comm)==0) Uc = ACˆ-1*Bc.Rci. Np by just changing the dot product by reduce the local dot product of all process with the following MPI code: template<class R> R ReduceSum1(R s. i = 1.solver=sparsesolver). // the projection on coarse grid. } // the original problem // remove boundary term .10. broadcast(processor(0.comm).VhC). . if(mpiRank(comm)==0) AC = vPbC(VhC. MPI_Allreduce( &s. } MPI_SUM.Bc. real[int] V(U. return U. return V. Pci= Rci = // // the corase problem interpolate(Whi.. *comm ).n).6. V = onGi ? 0.: V. precon=PDJC.veps=epss. ++iter) . dimKrylov=100. Np do 1.. V = U -V. real[int] b= onG . Broadcast from process 1. V = -V..u[]. Np . and π function..comm=comm . real[int] V(U. 2.comm=comm. dimKrylov=100.. return U. I . real[int] b= onG ? 0. Nataf.nbiter=300. Update(V. and build the partition π function constant equal to i on each sub domain Oi .comm).Bi..u[]). else if(gmres==3) rgmres= MPILinearGMRES(DJ.U.262 The New precondtionner CHAPTER 10.... the mesh Th ∗ (call Thii in freefem++ script).. i = 1.verbosity=ipart ? 0: 50). else // algo Shwarz for demo .nbiter=300. C2 precon Coarse // Idea : F. remark that the characteristic function 1Oi of domain Oi . ..C2*Uo // . is defined by (π = i)?1 : 0. Update(v[]. U = Aiˆ-1*b. if(gmres==1) { rgmres=MPIAffineGMRES(DJ0.C1AC2A +C1A +C2A // New Prec P= C1+C2 .veps=epss. U += Ai*V.precon=PDJ.nbiter=300. v[] = Aiˆ-1*b.C1AC2 = C1(I. MPI PARALLEL VERSION func real[int] PDJC(real[int]& U) { // Precon C1= Precon //..iter <10.u[]. Th ∗ of the full domain. : U.verbosity=ipart ? 0: 50). // 0 ˜ (I C1A)(I-C2A) => I ˜ .A C2) +C2 ) Uo // V = . To build this partition we do: the initial step on process 1 tp build a coarse mesh.. for(int iter=0. CoarseSolve(V.A C2) +C2 // ( C1(I. } else if(gmres==2) rgmres= MPILinearGMRES(DJ. of the grid with the Metis graph partitioner [?] and on each process i in 1.u[]. We have all ingredient to solve in parallel if we have et the partitions of the unity. int rgmres=0.comm=comm. b = onG ? b : Bi .dimKrylov=100.veps=epss.* u[]. } // // // // -C2*Uo U = (I-A C2) Uo ( C1( I -A C2) Uo // The code to the 4 algorithms: real epss=1e-6.verbosity=ipart ? 0: 50).n).U).Bi. 10.6. SCHWARZ EXAMPLE IN PARALLEL 263 ∗ 3. let us call Π2 (resp. Π2 ) the L2 on Ph the space of the constant finite element function per P V ∗ ∗ the space of the affine continuous finite element per element on element on Th (resp. Vh Th ∗ ). and build in parallel the πi and Ωi , such that Oi ⊂ Ωi where Oi = supp((Π2 Π2 )m 1Oi ), I V C and m is a the overlaps size on the coarse mesh (generally one), (this is done in function AddLayers(Thii,suppii[],nlayer,phii[]); We choose a ∗ function πi = (Π2 Π2 )m 1Oi so the partition of the unity is simply defined by I 1 0 πi = ∗ πi Np ∗ j=1 πj (10.3) The set Ji of neighborhood of the domain Ωi , and the local version on Vhi can be defined the array jpart and njpart with: ∗ Vhi pii=πi ; pij[j] Vhi[int] pij(npij); // local partition of 1 = pii + j int[int] jpart(npart); int njpart=0; ∗ Vhi sumphi = πi ; for (int i=0;i<npart;++i) if(i != ipart ) { ∗ if(int3d(Thi)( πj )>0) { ∗ pij[njpart]=πj ; sumphi[] += pij[njpart][]; jpart[njpart++]=i;}}} pii[]=pii[] ./ sumphi[]; for (int j=0;j<njpart;++j) pij[j][] = pij[j][] ./ sumphi[]; jpart.resize(njpart); 4. We call Th ∗ the sub mesh part of Thi where πj are none zero. and tank to the function ij trunc to build this array, for(int jp=0;jp<njpart;++jp) aThij[jp] = trunc(Thi,pij[jp]>1e-10,label=10); 5. At this step we have all on the coarse mesh , so we can build the fine final mesh by splitting all meshes : Thi, Thij[j],Thij[j] with freefem++ trunc mesh function which do restriction and slipping. 6. The construction of the send/recv matrices sMj and rMj : can done with this code: mesh3 Thij=Thi; // variable meshes fespace Whij(Thij,Pk); // variable fespace .. matrix Pii; Whi wpii=pii; Pii = wpii[]; // Diagonal matrix corresponding ×πi matrix[int] sMj(njpart), rMj(njpart); // M send/rend case.. for(int jp=0;jp<njpart;++jp) { int j=jpart[jp]; Thij = aThij[jp]; // change mesh to change Whij,Whij matrix I = interpolate(Whij,Whi); // Whij <- Whi sMj[jp] = I*Pii; // Whi -> s Whij rMj[jp] = interpolate(Whij,Whi,t=1); }} // Whij -> Whi 264 CHAPTER 10. MPI PARALLEL VERSION To buil a not to bad application, I have add code tout change variable from parametre value with the following code include "getARGV.idp" verbosity=getARGV("-vv",0); int vdebug=getARGV("-d",1); int ksplit=getARGV("-k",10); int nloc = getARGV("-n",25); string sff=getARGV("-p,",""); int gmres=getARGV("-gmres",3); bool dplot=getARGV("-dp",0); int nC = getARGV("-N" ,max(nloc/10,4)); And small include to make graphic in parallel of distribute solution of vector u on mesh Th with the following interface: include "MPIplot.idp" func bool plotMPIall(mesh &Th,real[int] & u,string cm) { PLOTMPIALL(mesh,Pk, Th, u,{ cmm=cm,nbiso=20,fill=1,dim=3,value=1}); return 1;} remark the {cmm=cm, ... =1} in the macro argument is a way to quote macro argument so the argument is cmm=cm, ... =1. Chapter 11 Parallel sparse solvers Parallel sparse solvers use several processors to solve linear systems of equation. Like sequential, parallel linear solvers can be direct or iterative. In FreeFem++ both are available. 11.1 Using parallel sparse solvers in FreeFem++ We recall that the solver parameters are defined in the following commands: solve, problem, set (setting parameter of a matrix) and in the construction of the matrix corresponding to a bilinear form. In these commands, the parameter solver must be set to sparsesolver for parallel sparse solver. We have added specify parameters to these command lines for parallel sparse solvers. These are • lparams: vector of integer parameters (l is for the c++ type long) • dparams: vector of real parameters • sparams: string parameters • datafilename: name of the file which contains solver parameters The following four parameters are only for direct solvers and are vectors. These parameters allow the user to preprocess the matrix (see the section on sparse direct solver above for more information). • permr: row permutation (integer vector) • permc: column permutation or inverse row permutation (integer vector) • scaler: row scaling (real vector) • scalec: column scaling (real vector) There are two possibilities to control solver parameters. The first method defines parameters with lparams, dparams and sparams in .edp file. The second one reads the solver parameters from a data file. The name of this file is specified by datafilename. If lparams, dparams, sparams or datafilename is not provided by the user, the solver’s default value is used. To use parallel solver in FreeFem++ , we need to load the dynamic library corresponding to this solver. For example to use MUMPS solver as parallel solver in FreeFem, write in the .edp file load ”MUMPS FreeFem”. If the libraries are not loaded, the default sparse solver will be loaded (default sparse solver is UMFPACK). The table 11.1 gives this new value for the different libraries. 265 266 CHAPTER 11. PARALLEL SPARSE SOLVERS default sparse solver Libraries real complex MUMPS FreeFem mumps mumps real SuperLU DIST FreeFem SuperLU DIST previous solver complex SuperLU DIST FreeFem previous solver SuperLU DIST real pastix FreeFem pastix previous solver complex pastix FreeFem previous solver pastix hips FreeFem hips previous solver hypre FreeFem hypre previous solver parms FreeFem parms previous solver Table 11.1: Default sparse solver for real and complex arithmetics when we load a parallel sparse solver library We also add functions (see Table 11.2) with no parameter to change the default sparse solver in the .edp file. To use these functions, we need to load the library corresponding to the solver. An example of using different parallel sparse solvers for the same problem is given in testdirectsolvers.edp (directory example+ + −mpi). default sparse solver function real complex defaulttoMUMPS() mumps mumps realdefaulttoSuperLUdist() SuperLU DIST previous solver complexdefaulttoSuperLUdist() previous solver SuperLU DIST realdefaultopastix() pastix previous solver complexdefaulttopastix() previous solver pastix defaulttohips() hips previous solver defaulttohypre() hypre previous solver defaulttoparms() parms previous solver Table 11.2: Functions that allow to change the default sparse solver for real and complex arithmetics and the result of these functions Example 11.1 (testdirectsolvers.edp) load "../src/solver/MUMPS_FreeFem" // default solver : real-> MUMPS, complex -> MUMPS load "../src/solver/real_SuperLU_DIST_FreeFem" // default solver : real-> SuperLU DIST, complex -> MUMPS load "../src/solver/real_pastix_FreeFem" // default solver : real-> pastix, complex -> MUMPS // { matrix A = [[ 1, 2, 2, 1, [ 2, 12, 0, [ 2, 0, 1, [ 1, 10, 0, [ 1, 10, 2, 1], 10 , 10], 0, 2], 22, 0.], 0., 22]]; solving with pastix 11.1. USING PARALLEL SPARSE SOLVERS IN FREEFEM++ 267 real[int] xx = [ 1,32,45,7,2], x(5), b(5), di(5); b=A*xx; cout << "b=" << b << endl; cout << "xx=" << xx << endl; set(A,solver=sparsesolver,datafilename="ffpastix_iparm_dparm.txt"); cout << "solving solution" << endl; x = Aˆ-1*b; cout << "b=" << b << endl; cout << "x=" << endl; cout << x << endl; di = xx-x; if(mpirank==0){ cout << "x-xx="<< endl; cout << "Linf "<< di.linfty << " L2 " << di.l2 << endl; } } // realdefaulttoSuperLUdist(); // default solver : { matrix A = [[ 1, 2, 2, 1, 1], [ 2, 12, 0, 10 , 10], [ 2, 0, 1, 0, 2], [ 1, 10, 0, 22, 0.], [ 1, 10, 2, 0., 22]]; solving with SuperLU DIST real-> SuperLU DIST, complex -> MUMPS real[int] xx = [ 1,32,45,7,2], x(5), b(5), di(5); b=A*xx; cout << "b=" << b << endl; cout << "xx=" << xx << endl; set(A,solver=sparsesolver,datafilename="ffsuperlu_dist_fileparam.txt"); cout << "solving solution" << endl; x = Aˆ-1*b; cout << "b=" << b << endl; cout << "x=" << endl; cout << x << endl; di = xx-x; if(mpirank==0){ cout << "x-xx="<< endl; cout << "Linf "<< di.linfty << " L2 " << di.l2 << endl; } } // defaulttoMUMPS(); // { matrix A = [[ 1, 2, 2, 1, [ 2, 12, 0, [ 2, 0, 1, [ 1, 10, 0, [ 1, 10, 2, 1], 10 , 10], 0, 2], 22, 0.], 0., 22]]; default solver : real-> MUMPS, complex -> MUMPS solving with MUMPS real[int] xx = [ 1,32,45,7,2], x(5), b(5), di(5); 268 b=A*xx; cout << "b=" << b << endl; cout << "xx=" << xx << endl; CHAPTER 11. PARALLEL SPARSE SOLVERS set(A,solver=sparsesolver,datafilename="ffmumps_fileparam.txt"); cout << "solving solution" << endl; x = Aˆ-1*b; cout << "b=" << b << endl; cout << "x=" << endl; cout << x << endl; di = xx-x; if(mpirank==0){ cout << "x-xx="<< endl; cout << "Linf "<< di.linfty << " L2 " << di.l2 << endl; } } 11.2 Sparse direct solver In this section, we present the sparse direct solvers interfaced with FreeFem++ . 11.2.1 MUMPS solver MUltifrontal Massively Parallel Solver (MUMPS) is a free library [?, ?, ?]. This package solves linear system of the form A x = b where A is a square sparse matrix with a direct method. The square matrix considered in MUMPS can be either unsymmetric, symmetric positive definite or general symmetric. The method implemented in MUMPS is a direct method based on a multifrontal approach [?]. It constructs a direct factorization A = L U , A = Lt D L depending of the symmetry of the matrix A. MUMPS uses the following libraries : BLAS[?, ?], BLACS and ScaLAPACK[?]. Remark 7 MUMPS does not solve linear system with a rectangular matrix. Installation of MUMPS To used MUMPS in FreeFem++ , you have to install the MUMPS package into your computer. MUMPS is written in Fortran 90. The parallel version is constructed using MPI [?] for message passing and BLAS [?, ?], BLACS and ScaLAPACK[?]. Therefore, a fortran compiler is needed, and MPI, BLAS, BLACS and ScaLAPACK . An installation procedure to obtain this package is given in the file README COMPILE in the directory src/solver of FreeFem++ . Creating Library of MUMPS interface for FreeFem++ : The MUMPS interface for FreeFem++ is given in file MUMPS freefem.cpp (directory src/solver/ ). This interface works with the release 3.8.3 and 3.8.4 of MUMPS. To used MUMPS in FreeFem++ , we need the library corresponding to this interface. A description to obtain this library is given in the file README COMPILE in the directory src/solver of FreeFem++ . We recall here the procedure. Go to the directory src/solver in FreeFem++ package. Edit the file makefile-sparsesolver.inc to yours system: comment Section 1, comment line corresponding to libraries BLAS, BLACS, ScaLAPACK, Metis, scotch in Section 2 and comment in Section 3 the paragraph corresponding to MUMPS solver. And then type make mumps in a terminal window. Now we give a short description of MUMPS parameters before describing the method to call MUMPS in FreeFem++ . 11.2. SPARSE DIRECT SOLVER 269 MUMPS parameters: There are four input parameters in MUMPS (see [?]). Two integers SYM and PAR, a vector of integer of size 40 INCTL and a vector of real of size 15 CNTL. The first parameter gives the type of the matrix: 0 for unsymmetric matrix, 1 for symmetric positive matrix and 2 for general symmetric. The second parameter defined if the host processor work during the factorization and solves steps : PAR=1 host processor working and PAR=0 host processor not working. The parameter INCTL and CNTL is the control parameter of MUMPS. The vectors ICNTL and CNTL in MUMPS becomes with index 1 like vector in fortran. A short description of all parameters of ICNTL and CNTL is given in ffmumps fileparam.txt. For more details see the users’ guide [?]. We describe now some elements of the main parameters of ICNTL for MUMPS. Input matrix parameter The input matrix is controlled by parameters ICNTL(5) and ICNTL(18). The matrix format (resp. matrix pattern and matrix entries) are controlled by INCTL(5) (resp. INCTL(18)). The different values of ICNTL(5) are 0 for assembled format and 1 for element format. In the current release of Freefem++, we consider that FE matrix or matrix is storage in assembled format. Therefore, INCTL(5) is treated as 0 value. The main option for ICNTL(18): INCLTL(18)=0 centrally on the host processor, ICNTL(18)=3 distributed the input matrix pattern and the entries (recommended option for distributed matrix by developer of MUMPS). For other values of ICNTL(18) see the user’s guide of MUMPS. These values can be used also in Freefem++. The default option implemented in FreeFem++ are ICNTL(5)=0 and ICNTL(18)=0. Preprocessing parameter The preprocessed matrix Ap that will be effectively factored is defined by Ap = P Dr A Qc Dc P t where P is the permutation matrix, Qc is the column permutation, Dr and Dc are diagonal matrix for respectively row and column scaling. The ordering strategy to obtain P is controlled by parameter ICNTL(7). The permutation of zero free diagonal Qc is controlled by parameter ICNTL(6). The row and column scaling is controlled by parameter ICNTL(18). These option are connected and also strongly related with ICNTL(12) (see documentation of mumps for more details [?]). The parameters permr, scaler, and scalec in FreeFem++ allow to give permutation matrix(P ), row scaling (Dr ) and column scaling (Dc ) of the user respectively. Calling MUMPS in FreeFem++ To call MUMPS in FreeFem++ , we need to load the dynamic library MUMPS freefem.dylib (MacOSX), MUMPS freefem.so (Unix) or MUMPS freefem.dll (Windows). This is done in typing load ”MUMPS freefem” in the .edp file. We give now the two methods to give the option of MUMPS solver in FreeFem++ . Solver parameters is defined in .edp file: In this method, we need to give the parameters lparams and dparams. These parameters are defined for MUMPS by lparams[0] = SYM, lparams[1] = PAR, lparams[i+1] = ICNTL(i). dparams[i − 1] = CNTL(i). ∀i = 1, . . . , 40, ∀i = 1, . . . , 15, Reading solver parameters on a file: The structure of data file for MUMPS in FreeFem++ is : first line parameter SYM and second line parameter PAR and in the following line the different value metis. pord scotch*/ 77 /* ICNTL(8) :: Row and Column scaling strategy */ 1 /* ICNTL(9) :: 0 solve Ax = b. PARALLEL SPARSE SOLVERS of vectors ICNTL and CNTL. AMF. 0 /* SYM :: 0 for non symmetric matrix. statics and warning message */ -1 /* ICNTL(3) :: for global information */ 0 /* ICNTL(4) :: Level of printing for error. 1 host working during factorization and solves steps*/ -1 /* ICNTL(1) :: output stream for error message */ -1 /* ICNTL(2) :: output for diagnostic printing. 1 elemental format. 1 kept distributed solution : parameter is not considered in the current release of freefem++ */ 0 /* ICNTL(22) :: controls the in-core/out-of-core (OOC) facility */ 0 /* ICNTL(23) :: maximum size of the working memory in Megabyte than MUMPS can allocate per working processor */ 0 /* ICNTL(24) :: control the detection of null pivot */ 0 /* ICNTL(25) :: control the computation of a null space basis */ 0 /* ICNTL(26) :: This parameter is only significant with Schur option (ICNTL(19) not zero). warning and diagnostic message */ 0 /* ICNTL(5) :: matrix format : 0 assembled format. 1 sparse form) : parameter will be set to 0 for freefem++ */ 0 /* ICNTL(21) :: 0. 1 for symmetric definite positive matrix and 2 general symmetric matrix*/ 1 /* PAR :: 0 host not working during factorization and solves steps.txt.270 CHAPTER 11. 1 solve the transposed system Aˆt x = b : parameter is not considered in the current release of freefem++*/ 0 /* ICNTL(10) :: number of steps of iterative refinement */ 0 /* ICNTL(11) :: statics related to linear system depending on ICNTL(9) */ 1 /* ICNTL(12) :: constrained ordering strategy for general symmetric matrix */ 0 /* ICNTL(13) :: method to control splitting of the root frontal matrix */ 20 /* ICNTL(14) :: percentage increase in the estimated working space (default 20%)*/ 0 /* ICNTL(15) :: not used in this release of MUMPS */ 0 /* ICNTL(16) :: not used in this release of MUMPS */ 0 /* ICNTL(17) :: not used in this release of MUMPS */ 3 /* ICNTL(18) :: method for given : matrix pattern and matrix entries : */ 0 /* ICNTL(19) :: method to return the Schur complement matrix */ 0 /* ICNTL(20) :: right hand side form ( 0 dense form. An example of this parameter file is given in ffmumpsfileparam. */ 7 /* ICNTL(6) :: control option for permuting and/or scaling the matrix in analysis phase */ 3 /* ICNTL(7) :: pivot order strategy : AMD. : parameter is not considered in the current release of freefem++ */ -8 /* ICNTL(27) (Experimental parameter subject to change in next release of MUMPS) :: control the blocking factor for multiple righthand side during the solution phase : parameter is not considered in the current release of freefem++ */ 0 /* ICNTL(28) :: not used in this release of MUMPS*/ 0 /* ICNTL(29) :: not used in this release of MUMPS*/ 0 /* ICNTL(30) :: not used in this release of MUMPS*/ . you have to install SuperLU DIST package. These interfaces are compatible with the release 3. To use SuperLU DIST in FreeFem++ .2 SuperLU distributed solver The package SuperLU DIST [?.edp in the directory examples++-mpi.11. we need libraries corresponding to these interfaces.lbl. SPARSE DIRECT SOLVER 0 0 0 0 0 0 0 0 1 0 0. The web site of this project is http://crd. It is a free scientific library under BSD license. This scientific library is written in C and MPI for communications. Creating Library of SuperLU DIST interface for FreeFem++ : The FreeFem++ interface to SuperLU DIST for real (resp.0 0 0 0 0 0 0 0 0 0 0 /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* ICNTL(31) :: not used in this release of MUMPS*/ ICNTL(32) :: not used in this release of MUMPS*/ ICNTL(33) :: not used in this release of MUMPS*/ ICNTL(34) :: not used in this release of MUMPS*/ ICNTL(35) :: not used in this release of MUMPS*/ ICNTL(36) :: not used in this release of MUMPS*/ ICNTL(37) :: not used in this release of MUMPS*/ ICNTL(38) :: not used in this release of MUMPS*/ ICNTL(39) :: not used in this release of MUMPS*/ ICNTL(40) :: not used in this release of MUMPS*/ CNTL(1) :: relative threshold for numerical pivoting */ CNTL(2) :: stopping criteria for iterative refinement */ CNTL(3) :: threshold for null pivot detection */ CNTL(4) :: determine the threshold for partial pivoting */ CNTL(5) :: fixation for null pivots */ CNTL(6) :: not used in this release of MUMPS */ CNTL(7) :: not used in this release of MUMPS */ CNTL(8) :: not used in this release of MUMPS */ CNTL(9) :: not used in this release of MUMPS */ CNTL(10) :: not used in this release of MUMPS */ CNTL(11) :: not used in this release of MUMPS */ CNTL(12) :: not used in this release of MUMPS */ CNTL(13) :: not used in this release of MUMPS */ CNTL(14) :: not used in this release of MUMPS */ CNTL(15) :: not used in this release of MUMPS */ 271 If no solver parameter is given. we used default option of MUMPS solver. New release of this package includes a parallel symbolic factorization [?].cpp).inc in your system : comment Section . An installation procedure to obtain this package is given in the file README COMPILE in the directory src/solver/ of the freefem++ package. complex SuperLU DIST FreeFem.1 of SuperLU DIST. Installation of SuperLU DIST: To use SuperLU DIST in FreeFem++ . We need MPI and ParMetis library to do this compilation.2. ?] solves linear systems using LU factorization. The method implemented in SuperLU DIST is a supernodal method [?]. Go to the directory src/solver in FreeFem++ package. A description to obtain these libraries is given in the file README COMPILE in the directory src/solver of FreeFem++ .2.gov/∼xiaoye/SuperLU. This library provides functions to handle square or rectangular matrix in real and complex arithmetics. complex) arithmetics is given in file real SuperLU DIST FreeFem.cpp (resp. 11.2. We recall here the procedure. Edit the file makefile-sparsesolver. example A simple example of calling MUMPS in FreeFem++ with this two methods is given in the file testsolver MUMPS. These files are in the directory src/solver/.01 1e-8 -1 -1 0. And just type make rsludist (resp. Fact= DOFACT. This done by the following line load ”real superlu DIST FreeFem” (resp. RowPerm= LargeDiag. The parallel symbolic factorization works only on a power of two processes and need the ParMetis ordering [?]. ParSymbFact=NO. The parameter permr. For this reason. ReplaceTinyPivot=NO. ParMetis in Section 2 and comment in Section 3 the paragraph corresponding to SuperLU DIST solver. Metis. This process grid is specifies by nprow (process row) and npcol (process column) such that Np = nprow npcol where Np is the number of all process allocated for SuperLU DIST. PrintStat=NO. DiagPivotThresh=1. The other parameters for LU factorization are ParSymFact and ReplaceTinyPivot. SolveInitialized=NO. load ”complex superlu DIST FreeFem”) for real (resp.0. and scalec in FreeFem++ is provided to give row permutation. complex) arithmetics. Now we give a short description of SuperLU DIST parameters before describing the method to call SuperLU DIST in FreeFem++ . DiagScale=NOEQUIL ” This value correspond to the parameter in the file ffsuperlu dist fileparam. column) permutation matrix. The factorization LU is calculated in SuperLU DIST on the matrix Ap . complex) arithmetics in the file . we take the default value of SuperLU DIST. ColPerm= MMD AT PLUS A. The parameter Fact and TRANS are specified in FreeFem++ interfaces to SuperLU DIST during the different steps. column permutation.txt. Dr and Dc are diagonal matrix for respectively row and column scaling. matrix= distributedgloba. Ap = Pc Pr Dr A Dc Pct where Pc and Pr is the row and column permutation matrix respectively. PARALLEL SPARSE SOLVERS 1. Calling SuperLU DIST in FreeFem++ To call SuperLU DIST in FreeFem++ . Trans=NOTRANS. Solver parameters is defined in . The option argument RowPerm (resp. The input matrix parameters is controlled by ”matrix= ” in sparams for internal parameter or in the third line of parameters file.edp file: To call SuperLU DIST with internal parameter. we need to load the library dynamic correspond to interface. row scaling and column scaling of the user respectively. The default option argument of SuperLU DIST are given in the file ffsuperlu dist fileparam. SuperLU DIST parameters: We describe now some parameters of SuperLU DIST.272 CHAPTER 11. The SuperLU DIST library use a 2D-logical process group.txt (default value of the FreeFem++ interface).edp. If one parameter is not specify by the user. . The value of parameters of SuperLU DIST in sparams is defined by sparams =”nprow=1. Reading solver parameters on a file: The structure of data file for SuperLU DIST in FreeFem++ is given in the file ffsuperlu dist fileparam. make csludist) in the terminal to obtain the dynamic library of interface for real (resp. npcol=1. scaler. Equil=NO. ColPerm) control the row (resp. comment line corresponding to libraries BLAS. we used the parameters sparams. Dr and Dc is controlled by the parameter DiagScale. IterRefine=DOUBLE. the value given by the user for this option is not considered.txt. The different value are matrix = assembled global matrix are available on all process matrix = distributedglobal the global matrix is distributed among all the process matrix = distributed the input matrix is distributed (not yet implemented) The option arguments of SuperLU DIST are described in the section Users-callable routine of [?]. permc. make cpastix) in the terminal to obtain the dynamic library of interface for real (resp. LargeDiag. And just type make rpastix (resp. Installation of Pastix: To used Pastix in FreeFem++ . YES */ NO /* ParSymbFact : NO. An installation procedure to obtain this package is given in the file . SamePattern. . MY_PERMC */ LargeDiag /* RowPerm : NOROWPERM. COL. you have to install pastix package in first. CONJ*/ NO /* ReplaceTinyPivot : NO. complex) arithmetics. comment line corresponding to libraries BLAS. scotch [?] or Metis [?] ordering library and MPI. YES*/ NO /* SolveInitialized : NO. Example 11. To use pastix in FreeFem++ . This interface is compatible with the release 2200 of pastix and is designed for a global matrix. distributed */ DOFACT /* Fact : DOFACT. YES*/ NO /* RefineInitialized : NO. distributedglobal. 11. METIS_AT_PLUS_A. PARMETIS. MMD_AT_PLUS_A.edp in the directory examples++-mpi. Creating Library of pastix interface for FreeFem++ : The FreeFem++ interface to pastix is given in file real pastix FreeFem. ROW.2 A simple example of calling SuperLU DIST in FreeFem++ with this two methods is given in the file testsolver superLU DIST. SINGLE. FACTORED */ NO /* Equil : NO. To compile this package. Now we give a short description of pastix parameters before describing the method to call pastix in FreeFem++ . YES*/ NO /* PrintStat : NO. A description to obtain this library is given in the file README COMPILE in the directory src/solver of FreeFem++ . We have also implemented interface for distributed matrices.inc to yours system : comment Section 1. we need the library corresponding to this interface.3 Pastix solver Pastix (Parallel Sparse matrix package) is a free scientific library under CECILL-C license. This solver can be applied to a real or complex matrix with a symmetric pattern [?]. MY_PERMR */ 1. we used default option of SuperLU DIST solver. BOTH*/ If no solver parameter is given.0 /* DiagPivotThresh : real value */ DOUBLE /* IterRefine : NOREFINE. We recall here the procedure.cpp (resp.11. YES*/ NOEQUIL /* DiagScale : NOEQUIL. SPARSE DIRECT SOLVER 273 1 /* nprow : integer value */ 1 /* npcol : integer value */ distributedglobal /* matrix input : assembled. we need a fortran 90 compiler. TRANS. Edit the file makefile-sparsesolver. EXTRA */ NOTRANS /* Trans : NOTRANS. This package solves sparse linear system with a direct and block ILU(k) iterative methods. complex pastix FreeFem.complex) arithmetics. MMD_ATA.cpp) for real (resp. SamePattern_SameRowPerm.src/solver/ README COMPILE in the section pastix of the FreeFem++ package. METIS and SCOTCH in Section 2 and comment in Section 3 the paragraph corresponding to pastix solver. Go to the directory src/solver in FreeFem++ package. DOUBLE.2.2. YES */ MMD_AT_PLUS_A /* ColPerm : NATURAL. edp in the directory examples++-mpi. . This file is obtained with the example file iparm. pARMS implements algebraic domain decomposition preconditioner type such as additive Schwartz [?] and interface method [?]. .3. assembled iparm[0] iparm[1] . If no solver parameter is given. .. Solver parameters defined in . These parameters are respectively the integer parameters (vector of size 64). . perm and invp.txt and dparm.. dparm. we use the default option of pastix solver. iparm and dparm vectors are described in [?].txt with a description of these parameters.3 Parallel sparse iterative solver Concerning iterative solvers. PARALLEL SPARSE SOLVERS Pastix parameters: The input matrix parameter of FreeFem++ depend on pastix interface. There are four parameters in Pastix : iparm..274 CHAPTER 11. The parameters permr and permc in FreeFem++ are provided to give permutation matrix and inverse permutation matrix of the user respectively. 63.txt including in the pastix package.. Example: A simple example of calling pastix in FreeFem++ with this two methods is given in the file testsolver pastix. . .. ∀i = 0. dparm[63] /* matrix input :: assembled. HIPS [?] and Hypre [?]. we recall the different matrix considering in the different direct solvers. we need to specify the parameters lparams and dparams. . 63. .. distributed global and distributed */ An example of this file parameter is given in ffpastix iparm dparm. It is the same parameter for SuperLU DIST. we have chosen pARMS [?] . . Each software implements a different type of parallel preconditioner. So.. while . In Table 11.. These parameters are defined by ∀i = 0. matrix=assembled for non distributed matrix. permutation matrix and inverse permutation matrix respectively. real parameters (vector of size 64). dparams[i] = dparm[i]. iparm[63] dparm[0] dparm[1] . Reading solver parameters on a file: The structure of data file for pastix parameters in FreeFem++ is : first line structure parameters of the matrix and in the following line the value of vectors iparm and dparm in this order. 11. . lparams[i] = iparm[i].edp file: To call Pastix in FreeFem++ in this case. Therefore. Thus. move to the directory src/solver of FreeFem++. Once the download is complete.a. To do this. edit the file makef ileparms.so.1 pARMS solver pARMS ( parallel Algebraic Multilevel Solver ) is a software developed by Youssef Saad and al at University of Minnesota [?]. . You just have to load the solver and then specify the parameters to apply to the specific solvers. We realized an interface which is easy to use. software partitioning graphs like METIS [?] or Scotch [?]. To use one of these programs in FreeFem++. Ar0 . All this preconditioners are used with Krylov subspace methods accelerators. The union of Ai forms the original matrix. Using pARMS as interface to FreeFem++ Before calling pARMS solver inside FreeFem++. CG and BICGSTAB. 11.3: Type of matrix used by the different direct sparse solver HIPS implement hierarchical incomplete factorization [?] and finally HYPRE implements multilevel preconditioner are AMG(Algebraic MultiGrid) [?] and parallel approximated inverse [?].. p) where p represents the number of partitions one needs. the matrix A is partitioned into sub matrices Ai (i = 1. Am−1 r0 } and Lm is another subspace of dimension m which depends on type of Krylov subspace. you have to install it independently of FreeFem++. But to use pAMRS in FreeFem++ you have first to install pAMRS. pARMS also implements parallel preconditioner like RAS (Restricted Additive Schwarz)[?] and Schur Complement type preconditioner [?].. . For example in GMRES. in some cases.inc to specify . In the rest of this chapter. All these parallel preconditioners are based on the principle of domain decomposition. when we talk about Krylov subspace methods we mean one among GMRES.11. Krylov subspace methods are iterative methods which consist in finding a solution x of linear system Ax = b inside the affine space x0 + Km by imposing that b − Ax⊥Lm . It consists of variants of GMRES like FGMRES(Flexible GMRES) . It is also necessary to install the MPI communication library which is essential for communication between the processors and.3. This software is specialized in the resolution of large sparse non symmetric linear systems of equation. iluk(Incomplete LU with level of fill in) and ARMS( Algebraic Recursive Multilevel Solver). so that the call of these different softwares in FreeFem++ is done in the same way.. The solution of the overall system is obtained by solving the local systems on Ai (see [?]).3.. To solve the local problem on Ai there are several preconditioners as ilut (Incomplete LU with threshold).cpp to create a dynamic library parms F reeF em. DGMRES(Deflated GMRES) [?] and BICGSTAB. Lm = AKm . PARALLEL SPARSE ITERATIVE SOLVER direct solver sym SuperLU DIST yes MUMPS yes pastix yes square matrix sym pattern unsym yes yes yes yes yes no sym yes no no rectangular matrix sym pattern unsym yes yes no no no no 275 Table 11. you must compile file parms F reeF em. Solvers developed in pARMS is the Krylov subspace type. where Km is Krylov subspace of dimension m defined by Km = {r0 . Installation of pARMS To install pARMS. you must unpack package pARMS and follow the installation procedure described in file README to create the library libparms. A2 r0 . you must first download the pARMS package at [?]. a distinction is made between iterations on A and the local iterations on Ai ... To specify the parameters to apply to the solver. in line 7 we specify that the bilinear form will be solved by the last sparse linear solver load in memory which.so.) preconditionner=Restricted Additif Schwarz [?].} 3: mesh Th = buildmesh (C(50)). is pARMS. // SOLVE THE PDE 14: plot(u).u=0) . Maximum of inner Krylov dimension=5.int2d(Th)( f*v) // right hand side 10: + on(1. Here are some default parameters: solver=FGMRES.v.P2). 4: fespace Vh(Th. 5: Vh u. we will show by examples how to call pARMS in FreeFem++. 15: cout << " CPU time = " << clock()-cpu << endl. Tolerance for convergence=1e− 08. There are three ways of doing this: Example 1: Default parameters This example comes from user guide of FreeFem++ [?] at page 12. Maximum of Krylov=1000. After this.3 1: load parms_freefem // Tell FreeFem that you will use pARMS 2: border C(t=0. Example 11. the user can either give an integer vector for integer parameters and real vectors for real parameters or provide a file which contains those parameters. Krylov dimension=30. As usual in FreeFem++.3 we load in memory the pARMS dynamic library with interface FreeFem++. Inner preconditionner=ILUK. 13: Poisson. 6: func f= x*y. 7: problem Poisson(u.276 the following variables: CHAPTER 11. in the command line type make parms to create parms F reeF em. The parameter used in pARMS in this case is the default one since the user does not have to provide any parameter. in this case. // Dirichlet boundary condition 11: 12: real cpu=clock().label=1. . PARALLEL SPARSE SOLVERS P ARM S DIR : Directory of pARMS Directory for header of pARMS P ARM S IN CLU DE : M ET IS : METIS directory M ET IS LIB : METIS librairy MPI : MPI directory M P I IN CLU DE : MPI headers F REEF EM : FreeFem++ directory F REEF EM IN CLU DE : FreeFem++ header for sparse linear solver LIBBLAS : Blas library After that. Inner Krylov dimension=5. In line 1 of example 11. y=sin(t).(see book of Saad [?] to understand all this parameters.2*pi){x=cos(t).v.solver=sparsesolver) = // bilinear part will use 8: int2d(Th)(dx(u)*dx(v) + dy(u)*dy(v)) // a sparse solver. in this case pARMS 9: . e-6) // p epsilon .5) . real[int] dparm(6). the time for solving the linear equation decreases. real[int] sol(AA. ?]. In line 3 we have initialized these vectors by negative values.n).(dx(u)+dy(v))*psh // psh div(u) ) + on(cylinder. For further informations on those preconditionners see [?.p*(dx(ush)+dy(vsh)) // + dx(p)*ush + dy(p)*vsh .edp".. 10: sol= AAˆ-1 * bb.v. In this example. we fix the mesh) and increase the number of processors used to solve the linear system.8.4 on cluster paradent of Grid5000 and report results in table 11. We need two vectors to specify the parameters of the linear solver. real[int] dparm(6). This proves that.edp" include "includes.infwall.VVh).2 Interfacing with HIPS HIPS ( Hierarchical Iterative Parallel Solver ) is a scientific library that provides an efficient parallel iterative solver for very large sparse linear systems. include "fe_functions.rc4 of HIPS. we have the meaning of differents entries of these vectors.11. . 5: iparm[0]=0.dparams=dparm).2 beta. We saw that. HIPS is available as free software under the CeCILL-C licence.4 we have declared these vectors(int[int] iparm(16). In line 1 of example 11.p]. The interface that we realized is compatible with release 1.lparams=iparm. using pARMS as solver of linear systems coming from discretization of partial differential equation in FreeFem++ can decrease drastically the total time of simulation.u=uc. In this example we solve linear systems coming from discretization of Navier Stokes equation with pARMS. 2: int . Parameters of solver is specified by user.ii<16.) .{solver=sparsesolver}) = int2d(Th)( nu*( dx(u)*dx(ush) + dy(u)*dy(ush) + dx(v)*dx(vsh) + dy(v)*dy(vsh) ) . include "bc_poiseuille_in_square.edp".v=0). 4: fespace Vh(Th. include "mesh_with_cylinder.edp". even if the number of iteration increases. 0: load parms_FreeFem 1: int[int] iparm(16). HIPS implements a type of multilevel ILU.3.edp) include "manual. 8: set(AA. Example 11. 6: varf Stokes ([u. we fix the matrix size (in term of finite element.} for(ii=0.)+on(inlet. We run example 11.vsh.v=0. // Bdy conditions 7: matrix AA=Stokes(VVh.P2.p*psh*(1. We do this because all parameters values in pARMS are positive and if you do not change the negative values of one entry of this vector.u=0.ii++) dparm[ii]=-1. PARALLEL SPARSE ITERATIVE SOLVER 277 Example 2: User specifies parameters inside two vectors Lets us consider Navier Stokes example 11. the default value will be set.psh].supwall.4 . 3: for(ii=0.4 and 11. when the number of processors increases.ii++){iparm[ii]=-1.4 (Stokes.ii.[ush. // Set pARMS as linear solver 9: real[int] bb= Stokes(0.ii<6. PCG) and the Direct class.edp". HIPS implements two solver classes which are the iteratives class ( GMRES. 11.0.P1]).[P2.3. Concerning preconditionners.VVh).solver=sparsesolver. In tables (table 11. 4 Entries of dparm Significations of each entries dparm[0] precision for outer iteration : default value 1e-08 dparm[1] precision for inner iteration: default value 1e-2 dparm[2] tolerance used for diagonal domain: : default value 0.6: Krylov Solvers in pARMS . 2: Timing for a different step like preconditioner 3 : Print all informations. Table 11.1 dparm[3] drop tolerance droptol0 (ilut. 0: no message is print. 1: Convergence informations like number of iteration and residual .4 Values of iparm[0] Krylov subspace methods 0 FGMRES (Flexible GMRES) 1 DGMRES (Deflated GMRES) 2 BICGSTAB Table 11. Differents values for this parameters are specify on table 11. iluk. iluk.4: Meaning of lparams corresponding variables for example 11.278 Entries of iparm iparm[0] iparm[1] iparm[2] iparm[3] iparm[4] iparm[5] iparm[6] iparm[7] iparm[8] iparm[9] iparm[10] iparm[11] iparm[12] iparm[13] iparm[14] iparm[15] iparm[16] CHAPTER 11. Differents preconditionners for this parameters are specify on table 11.7 Krylov subspace dimension in outer iteration: default value 30 Maximum of iterations in outer iteration: default value 1000 Number of level in arms when used. Krylov subspace dimension in inner iteration: default value 3 Maximum of iterations in inner iteration: default value 3 Symmetric(=1 for symmetric) or unsymmetric matrix: default value 0(unsymmetric matrix) Overlap size between different subdomain: default value 0(no overlap) Scale the input matrix or not: Default value 1 (Matrix should be scale) Block size in arms when used: default value 20 lfil0 (ilut.5: Significations of dparams corresponding variables for example 11. and arms) : default value 1e-2 dparm[4] droptol for Schur complement const: default value 1e-2 dparm[5] droptol for Schur complement const: default value 1e-2 Table 11. and arms) : default value 20 lfil for Schur complement const : default value 20 lfil for Schur complement const : default value 20 Multicoloring or not in ILU when used : default value 1 Inner iteration : default value 0 Print message when solving:default 0(no message print). PARALLEL SPARSE SOLVERS Significations of each entries Krylov subspace methods.6 Preconditionner. preconditioner type is 7 Left Schur complement preconditioner with arms as local preconditioner. preconditioner type is 5 Left Schur complement preconditioner with ilut as local preconditioner.11. preconditioner type is 2 additive Schwartz preconditioner with ilut as local preconditioner. preconditioner type is 1 additive Schwartz preconditioner with iluk as local preconditioner.07 24 167.57 21 557.29 np add(iluk) schur(iluk) nit time nit time 4 230 637.8 8 240 364.8: Convergence and time for solving linear system from example 11.5 32 261 111. preconditioner type is 8 Right Schur complement preconditioner with ilu0 as local preconditioner.3. preconditioner type is 12 sch gilu0 . preconditioner type is 11 Right Schur complement preconditioner with arms as local preconditioner. PARALLEL SPARSE ITERATIVE SOLVER 279 Values of iparm[1] Preconditionners Preconditioners type is 0 additive Schwartz preconditioner with ilu0 as local preconditioner.12 22 302. preconditioner type is 9 Right Schur complement preconditioner with ilut as local preconditioner. Schur complement preconditioner with global ilu0 preconditioner type is 13 SchurSymmetric GS preconditioner Table 11.5 Table 11.4 .16 25 81.25 16 247 212. preconditioner type is 6 Left Schur complement preconditioner with iluk as local preconditioner. preconditioner type is 4 Left Schur complement preconditioner with ilu0 as local preconditioner. preconditioner type is 3 additive Schwartz preconditioner with arms as local preconditioner.7: Preconditionners in pARMS n= 471281 nnz=13 × 106 Te=571. preconditioner type is 10 Right Schur complement preconditioner with iluk as local preconditioner. so. We will present only one example where the user specifies the parameters through keywords lparams and dparams.so. PARALLEL SPARSE SOLVERS matrix size number of non null entries inside matrix number of iteration for convergence Time for convergence Time for constructing finite element matrix number of processor Table 11. After this.10 results of running example 11. Using HIPS as the interface to FreeFem++ Before calling the HIPS solver inside FreeFem++. // load library . first download the HIPS package at [?]. in the command line in the directory src/solver type make hips to create hips F reeF em.5 is Laplacian3D using Hips as linear solver. edit makefile.8 Installation of HIPS To install HIPS.gnu on the root directory of HIPS with the name makefile. unpack it and go to the HIPS source directory. The installation of HIPS is machine dependence. Laplacian 3D solve with HIPS Let us consider the 3D Laplacian example inside FreeFem++ package where after discretization we want to solve the linear equation with Hips.cpp to create dynamic library hips F reeF em. For example. to install HIPS on a linux cluster copy the file M akef ile Inc Examples/makef ile.5 we set these parameters in the linear solver.inc to specify the following variables: HIP S DIR : Directory of HIPS HIP S IN CLU DE: -I$(HIP S DIR)/SRC/INCLUDE : Directory for HIPS headers LIB DIR : -L$(HIP S DIR)/LIB : Librairies directory LIBHIP SSEQU EN T IAL : $(HIP S DIR)/LIB/libhipssequential.a: HIPS library F REEF EM : FreeFem++ directory F REEF EM IN CLU DE : FreeFem headers for sparse linear solver M ET IS : METIS directory METIS library M ET IS LIB : MPI : MPI directory M P I IN CLU DE : MPI headers After specifies all the variables. move to the directory src/solver of FreeFem++ and edit the file makef ile.a: HIPS utilities library LIBHIP S : $(HIP S DIR)/LIB/libhips.280 n nnz nit time Te np CHAPTER 11.5 on Cluster Paradent of Grid5000 are reported.5 (Laplacian3D. you must compile file hips F reeF em. We first load Hips solver at line 2. the calling of HIPS in FreeFem++ can be done in three different manners. Example 11.iii. We can see in this running example the efficiency of parallelism. To do this. In Table 11. From line 4 to 15 we specify the parameters for the Hips solver and in line 46 of example 11.inc.9: Legend of table 11. Example 11. Like with pARMS.inc.edp) 1: load "msh3" 2: load "hips_FreeFem" 3: int nn=10.inc to set values of different variables and type make all. 37: Aa=va(Vh. F[]=va(0.2]. reffacelow = rdown).P2). 35: real cpu=clock().3.n << endl. 27: func uey= 6*y + 5*x. 28: func uez= 8*z +6*x.min << " max:" << uhe[]. 40: if(mpirank==0){ cout << "Taille " << Aa.11.max << endl.nn. 7: for(iii=0.iii++)iparm[iii]=-1.nn). // Threshold for Schur preconditionner 16: mesh Th2=square(nn. 18: Vh2 ux. // Tolerance to convergence 14: dparm[1]=5e-4. 29: func f= -18. 24: fespace Vh(Th. 23: mesh3 Th3("copie.v.v)=int3d(Th)(f*v). lparams=iparm).nbcoef << endl.mesh").u=ue).mesh").1.p2.solver=sparsesolver.iii<14.1. PARALLEL SPARSE ITERATIVE SOLVER 281 4: int[int] iparm(14). 25: func ue = 2*x*x + 3*y*y + 4*z*z + 5*x*y+6*x*z+1. // Scale matrix 13:dparm[0]=1e-13.int3d(Th)(f*v) .iii<6.y +uez*N.dy(u). // PCG as Krylov method 10:iparm[4]=0.Vh).1]. // Pattern are also symmetric 12: iparm[9]=1. 20:real zmin=0. // Set hips as linear solver 44: u[]=Aaˆ-1*F[]. 36: matrix Aa. 39: Vh F.v)= int3d(Th)(Grad3(v)’ *Grad3(u)) // ’) for emacs + int2d(Th.2) ( ue*v + (uex*N.3.1]. zbound=[zmin. reffaceup = rup. . // 31: cout << " uhe min: " << uhe[]. 30: Vh uhe = ue.zmax=1.Vh). 17: fespace Vh2(Th2. reffacemid=rmid.x +uey*N. 32: Vh u. // use iterative solver 9: iparm[1]=1.P2).dz(u)] // EOM 34: varf va(u. 19: int[int] rup=[0. cout << "Non zeros " << Aa."copie.9.zmax].2.iii++) dparm[iii]=-1. rdown=[0. } 41: if(mpirank==0) 42: cout << "CPU TIME FOR FORMING MATRIX = " << clock()-cpu << endl.1.uz. 33: macro Grad3(u) [dx(u). // Threshold in ILUT 15: dparm[2]=5e-4.int2d(Th.4. 43: set(Aa. // Matrix are symmetric 11:iparm[5]=1. Legend of table 11. 22: savemesh(Th. 21: mesh3 Th=buildlayers(Th2. 8: iparm[0]=0. .10 are give in table 11. 5: real[int] dparm(6).dparams=dparm.2)(u*v) . rmid=[1. 6: for(iii=0. 38: varf l(unused.z)*v ) + on(1. 26: func uex= 4*x+ 5*y+6*z. HIPS DOMSIZE Subdomain size Table 11.34 61. Default value 1 Reordering use inside subdomains for reducing fill-in: Only use for iterative.34 time 120.44 Table 11. 1 for PCG Maximum of iterations in outer iteration: default value 1000 Krylov subspace dimension in outer iteration: default value 40 Symmetric(=0 for symmetric) and 1 for unsymmetric matrix: default value 1(unsymmetric matrix) Pattern of matrix are symmetric or not: default value 0 Partition type of input matrix: dafault value 0 Number of level that use the HIPS locally consistent fill-in: Default value 2 Numbering in indices array will start at 0 or 1: Default value 0 Scale matrix. PARALLEL SPARSE SOLVERS n = 4 × 106 np 8 16 32 64 nnz = 118 × 106 nit 190 189 186 183 Te=221.08 31. Defaults values are : Iterative Krylov methods. give type of Krylov methods: 0 for GMRES.282 CHAPTER 11.11: Significations of lparams corresponding to HIPS interface . Level of informations printed during solving: Default 5. Default value 1 Number of unknowns per node in the matrix non-zero pattern graph: Default value 1 This value is used to set the number of time the normalization is applied to the matrix: Default 2.5 Entries of iparm iparm[0] iparm[1] iparm[2] iparm[3] iparm[4] iparm[5] iparm[6] iparm[7] iparm[8] iparm[9] iparm[10] iparm[11] iparm[12] iparm[13] iparm[14] Significations of each entries Strategy use for solving ( Iterative=0 or Hybrid=1 or Direct=2 ).70 23.10: Iterations and Timing of solving linear system from example 11. If iparm[0]=0. edit the file makef ile.005 dparm[5] HIP S DROP SCHU R : Numerical threshold for coupling between the interior level and Schur: Default=0. ˆ consider solving the residual equation Ae = r to find the error e. Given an approximation x to the solution x.cpp to create dynamic library hypre F reeF em.inc to specify the following variables: . After solving this coarse equation. Using HYPRE as interface to FreeFem++ Before calling HYPRE solver inside FreeFem++ . the solution is then interpolated in fine grid represented here by matrix A. For more details on this preconditioner technics see [?]. HYPRE implement three Krylov subspace solvers: GMRES. A technical idea to construct matrix M is to minimize the Frobenuis norm of the residual matrix I − M A.0 in HYBRID: Default=0.so. where r = b − Aˆ. There are two main classes of preconditioners developed in HYPRE: AMG (Algebraic MultiGrid) and Parasails (Parallel Sparse Approximate Inverse).12: Significations of dparams corresponding to HIPS interface 283 11. unpack it and go to the HYPRE/src source directory and do .005 Table 11. which is cheaper to solve.3. PCG and BiCGStab. At the heart of AMG there is a series of progressively coarser(smaller) representations of the matrix A. To do this. suppose we want to solve Ax = b. PARALLEL SPARSE ITERATIVE SOLVER dparm[0] HIP S P REC: Relative residual norm: Default=1e-9 dparm[1] HIP S DROP T OL0: Numerical threshold in ILUT for interior domain (important : set 0.3 Interfacing with HYPRE HYPRE ( High Level Preconditioner ) is a suite of parallel preconditioner developed at Lawrence Livermore National Lab [?] ./configure to configure Hypre. The quality of AMG depends on the choice of coarsening and interpolating operators. they need to be represented by a smaller defect equation (coarse grid residual equation) Ac ec = rc . Installation of HYPRE To install HYPRE.005 dparm[4] HIP S AM ALG : Numerical threshold for coupling between the interior level and Schur: Default=0. Now. The sparse approximate inverse approximates the inverse of a matrix A by a sparse matrix M . A fundamental x principle of AMG is that it is an algebraically smooth error. To reduce the algebraically smooth errors further. first download the HYPRE package at [?]. After this just type make all to create libHYPRE.005 dparm[3] HIP S DROP T OLE : Numerical threshold for coupling between the interior level and Schur: Default 0.a.005) HIP S DROP T OL1 : Numerical threshold in ILUT for dparm[2] Schur preconditioner: Default=0.3. move to the directory src/solver of FreeFem++ . you must compile the file hypre F reeF em.11. 6 on Cluster Paradent of Grid5000 are reported.6 is the same as 11. 7: for(iii=0.17. Example 11. We first load the Hypre solver at line 2.5. In Table ?? the results of running example 11. lparams=iparm).6 is the Laplacian3D using Hypre as linear solver. 5: real[int] dparm(6).edp) 1: load "msh3" 2: load "hipre_FreeFem" // load librairie 3: int nn=10. the calling of HIPS in FreeFem++ can be done in three manners. 8: iparm[0]=2.solver=sparsesolver. // PCG as krylov method 9: iparm[1]=0.iii++) dparm[iii]=-1. // Interpolation 11:iparm[9]=6. so we just show here the lines where we set some Hypre parameters. Laplacian 3D solve with HYPRE Let us consider again the 3D Laplacian example inside FreeFem++ package where after discretization we want to solve the linear equation with Hypre.iii++)iparm[iii]=-1. 6: for(iii=0. It should be noted that the meaning of the entries of these vectors is different from those of Hips . We can see in this running example the efficiency of parallelism. // AMG as preconditionner 2: if ParaSails 10:iparm[7]=7. // Tolerance to convergence 14: dparm[1]=5e-4.iii<20.dparams=dparm.6 (Laplacian3D.13 to 11.284 HY P RE DIR : HY P RE IN CLU DE = CHAPTER 11. 4: int[int] iparm(20). PARALLEL SPARSE SOLVERS Directory of HYPRE -I$(HY P RE DIR)src/hypre/include/ : Directory for header of HYPRE HY P RE LIB = -L$(HIP S DIR)/src/lib/ -lHYPRE : Hypre Library F REEF EM : FreeFem++ directory F REEF EM IN CLU DE : FreeFem header for sparse linear solver M ET IS : METIS directory M ET IS LIB : METIS library MPI : MPI directory M P I IN CLU DE : MPI headers Like with pARMS. From line 4 to 15 we specifies the parameters to set to Hypre solver and in line 43 we set parameters to Hypre solver. in particular when AMG are use as preconditioner.iii<6. // AMG Coarsen type 12: iparm[10]=1. // Measure type 13: iparm[16]=2. // truncation factor . . . Example 11. . the meaning of differents entries of vectors iparm and dparm are given in tables 11. 43: set(Aa. Example 11. In the case of HYPRE. // Additive schwarz as smoother 13:dparm[0]=1e-13.iii. // Threshold 15: dparm[2]=5e-4. We will present only one example where the user specifies its parameters through keywords lparams and dparams. iparms[16] iparms[17] iparms[18] iparms[19] dparms[1] dparms[2] dparms[3] dparms[3] Table 11.25 Truncation factor for the interpolation: Default=1e-2 Sets a parameter to modify the definition of strength for diagonal dominant portions of the matrix: Default=0. 1: PILUT. By default=1 Preconditioner identification: iparms[1] 0: BOOMER AMG.3.0e − 11 iparms[0] 285 Table 11. 1: GMRES.14: Definitions of other entries of iparms and dparms if preconditioner is BOOMER AMG . 3: Schwartz Default=0 iparms[2] Maximum of iteration: Default=1000 iparms[3] Krylov subspace dim: Default= 40 iparms[4] Solver print info level: Default=2 iparms[5] Solver log : Default=1 iparms[6] Solver stopping criteria only for BiCGStab : Default=1 dparms[0] Tolerance for convergence : Def ault = 1.9 Defines a smoothing parameter for the additive Schwartz method Default=1.geometrically smooth coarsening and interpolation: Default=1 AMG coarsen type: Default=6 Defines whether local or global measures are used: Default=1 AMG cycle type: Default=1 AMG Smoother type: Default=1 AMG number of levels for smoothers: Default=3 AMG number of sweeps for smoothers: Default=2 Maximum number of multigrid levels: Default=25 Defines which variant of the Schwartz method is used: 0: hybrid multiplicative Schwartz method (no overlap across processor boundaries) 1: hybrid additive Schwartz method (no overlap across processor boundaries) 2: additive Schwartz method 3: hybrid multiplicative Schwartz method (with overlap across processor boundaries) Default=1 Size of the system of PDEs: Default=1 Overlap for the Schwarz method: Default=1 Type of domain used for the Schwarz method 0: each point is a domain 1: each node is a domain (only of interest in “systems” AMG) 2: each domain is generated by agglomeration (default) AMG strength threshold: Default=0. PARALLEL SPARSE ITERATIVE SOLVER Solver identification: 0: BiCGStab. 2: PCG. 2: Parasails.11.13: Definitions of common entries of iparms and dparms vectors for every preconditioner in HYPRE iparms[7] iparms[8] iparms[9] iparms[10] iparms[11] iparms[12] iparms[13] iparms[14] iparms[15] AMG interpolation type: Default=6 Specifies the use of GSMG . 286 CHAPTER 11.83 5 708.64 Table 11.17: Definitions of other entries of iparms and dparms if preconditionner is Schwartz n=4 × 106 np 8 16 32 64 nnz=13 × 106 Te=571.4 . and nonsymmetric preconditioner iparms[8] 1: SPD problem. and SPD (factored) preconditioner 2: nonsymmetric.16: Definitions of other entries of iparms and dparms if preconditioner is ParaSails Defines which variant of the Schwartz method is used: 0: hybrid multiplicative Schwartz method (no overlap across processor boundaries) 1: hybrid additive Schwartz method (no overlap across processor boundaries) iparms[7] 2: additive Schwartz method 3: hybrid multiplicative Schwartz method (with overlap across processor boundaries) Default=1 iparms[8] Overlap for the Schwartz method: Default=1 Type of domain used for the Schwartz method 0: each point is a domain iparms[9] 1: each node is a domain (only of interest in “systems” AMG) 2: each domain is generated by agglomeration (default) Table 11.18: Convergence and time for solving linear system from example 11. to reduce the cost of applying the preconditioner: Default=0.1 Table 11.29 AMG nit time 6 1491.49 4 296.15: Definitions of other entries of iparms and dparms if preconditioner is PILUT iparms[7] Number of levels in Parallel Sparse Approximate inverse: Default=1 Symmetric parameter for the ParaSails preconditioner: 0: nonsymmetric and/or indefinite problem. definite problem. PARALLEL SPARSE SOLVERS iparms[7] Row size in Parallel ILUT: Default=1000 iparms[8] Set maximum number of iterations: Default=30 dparms[1] Drop tolerance in Parallel ILUT: Default=1e-5 Table 11. and SPD (factored) preconditioner Default=0 Filters parameters:The filter parameter is used to dparms[1] drop small nonzeros in the preconditioner.1 dparms[2] Threshold parameter: Default=0.22 4 145. For this reason we advise the user to pay attention to the meaning of the parameters in the user guide of the iterative solvers interfaced in FreeFem++ . In this case. generally when we increase the number of subdomains we decrease convergence quality of the preconditioner. 11. In several case. comm communicator(handle). we wanted to illustrate the gain in time when we increase the number of processors used for the simulations. Furthermore.3. phases for solving the linear system are parallel. This is normal because until now this phase is sequential in FreeFem++ . the increase of processors can lead to the increase of volume of exchanged data across processors consequently increasing the time for solving the linear systems. Although. you solve equation in every subdomains and define a strategy to obtain the global solution. mpiGroup gp): Creates a new communicator. gp group which is a subset of the group of comm (handle). the number of processors generally corresponds to the number of sub domains. To end this. the efficiency of preconditioners sometimes depends on how its parameters are set. in decomposition domain type preconditioners. we saw that the phases to construct a matrix are sequential. when we increase the number of processors the time to convergence also increases. DOMAIN DECOMPOSITION 287 11. But this not true in every case. One strategy to construct the matrix in parallel is to divide geometrically the domain into subdomains. we should note that good use of the preconditioners interfaced in FreeFem++ is empiric. Return new communicator . In every subdomain we construct a local submatrix and after that we assemble every submatrix to form the global matrix. There are two main reasons for this. We saw that in every case the time for the construction of the finite element matrix is constant. This can increase the time used for solving linear equations. We saw on several examples presented here that when we increase the number of processors. We can use this technique to solve pde directly in domain Ω.4 Conclusion With the different runs presented here. In subdomain methods. this means that the user must be able to divide processors avaible for computation into subgroups of processors and also must be able to realize different type of communications in FreeFem++ script. Communicators can be Intracommunicators(involves a single group) or Intercommunicators (involves two groups). because it is difficult to know what is a good preconditioner for some type of problems. First. In contrast.KN < long >): Create M P I Group from existing group gp by given vector Communicators Communicators is an abstract MPI object which allows MPI user to communicate across group of processors.4 Domain decomposition In the previous section. Here is a wrapper of some MPI functions. in every subdomains you have to define artificial boundary conditions to form consistent equations in every subdomains. After this. with MPI. In terms of parallel programming for FreeFem++ . in general we decrease the time used for solving the linear systems.4.11. When we not specify type of communicator it will be Intracommunicators mpiComm cc(mpiComm comm.1 Communicators and groups Groups mpiGroup grpe(mpiGroup gp. 11.4. edp) 1: int color=mpiRank(comm)%2.mpiComm cc) but use a synchronization point. 4: cout << "Color values " << color << endl.4. Here colors and comm is defined in MPIrank.color. processor(int rk.} 10: else { rleader = 3. processorblock(int rk. mpiComm cc) : This function is exactlly the same than processor(int rk.). mpiComm cc) and processor(mpiComm cc. int high): Creates an intracommunicator from an intercommunicator. 5: mpiComm ccc(processor((rk<size/2). int color. 4: mpiComm cp(cc. 12:int aaa=mpiSize(ccc). 13:cout << "number of processor" << aaa << endl.color. } 11: mpiComm qqp(processor(0. 6: mpiComm cp(cc. int key): Creates new communicators based on colors and key. Rank is inside MPI COMM WORLD. 7: int rleader. } 9: else if (rk == size/2) { rleader = 0. processor(int rk): Keep process rank inside object MPIrank. comm intercommunicator.processor(rleader. mpiComm cc) and processor(mpiComm cc. . 4: int size=mpiSize(comm). Example 11. int tag): This constructor creates an intercommuncator from two intracommunicators. This constructor is based on MPI Comm split routine of MPI.comm).comm). MPIrank p2.ccc).int rk) process rank inside communicator cc. 2: int color=mpiRank(comm)%2.0). processorblock(int rk) : This function is exactlly the same than processor(int rk) but is use in case of blocking communication. tag Message tag to use in constructing intercommunicator.rk). PARALLEL SPARSE SOLVERS mpiComm cc(mpiGroup gp): Same as previous constructor but default comm here is MPI COMM WORLD.8 (merge. mpiComm cc(mpiComm comm.0). 2: mpiComm ccc(processor(color. mpiComm cc(mpiComm comm. mpiComm cc(MPIrank p.int rk) process rank inside communicator cc.0).7 (commsplit.2 Process In FreeFem++ we wrap MPI process by function call processor which create internal FreeFem++ object call MPIrank.int key): Same constructor than the last one. This constructor is based on MPI Comm split routine of MPI.cc. 11.edp) 1: mpiComm comm. p1 defined local (intra)communicator and rank in local comm of leader (often 0) while p2 defined remote communicator and rank in peer comm of remote leader (often 0). This constructor is based on MPI Intercomm create.12345). mpiComm cc(MPIrank p1. 3: int rk=mpiRank(comm). processor(int rk.288 CHAPTER 11.comm). This constructor is based on MPI Intercomm merge routine of MPI. 8: if (rk == 0) { rleader = size/2. 3: mpiComm qpp(comm. Example 11. This mean that do not use MPIrank in FreeFem++ script. high Used to order the groups within comm (logical) when creating the new communicator. int[int].Data b. real.4.mpiComm cc). Isend(processor(int rk.Data b) : Gathers Data a from all processes and distribute it to all in Data b. real. for all global operations.complex[int]. Note that Data D can be: int. broadcast(processor(int rk). This function is like MPI Gather mpiAllgather(Data a.complex[int]. This is done inside communicator cc. mpiAlltoall(Data a.Data b.complex . mpiReduce(Data a. mpiComm cc). real[int]. int[int].complex . Note that. only int[int] and real[int] are data type take in account in FreeFem++ . Recv(processor(int rk. Mesh. mpiBAND. Receive buffer is Data b. broadcast(processor(int rk. Note that Data D can be: int. int[int]. This is done inside communicator MPI COMM WORLD. Mesh3. Matrix. Mesh3. mpiBXOR. real[int]. int[int]. mpiSUM. mpiComm cc)) : Sends Data a from one process whith rank rk to all other processes in group represented by communicator mpiComm cc.processor(mpiComm. Matrix. mpiMINLOC.3 Points to Points communicators In FreeFem++ you can call MPI points to points communications functions. Mesh3.int rk) : Gathers together values Data a from a group of processes.complex[int]. real[int]. This function is like MPI Allgather mpiAllgather(Data a. mpiLOR. Mesh. This is done inside communicator MPI COMM WORLD. Mesh. real.processor(int rk.MPI Op op). int[int].11. mpiComm cc): Sends data a from all to all processes. mpiMIN. Matrix. mpiComm cc) : Gathers Data a from all processes and distribute it to all in Data b. This is done inside communicator cc.4.mpiComm cc).processor(int rk. Mesh3.mpiComm cc). Matrix. mpiGather(Data a.Data D): Process rk Broadcast Data D to all process inside MPI COMM WORLD. mpiLAND.Data D) : Blocking send of Data D to processor of rank rk inside communicator cc. Operation use in reduce is: MPI Op op which can be: mpiMAX. Reduces values Data a on all processes to a single value Data b on process of rank rk and communicator cc. Mesh.complex .Data D): Receive Data D from process of rank rk in communicator cc.Data D): Process rk Broadcast Data D to all process inside communicator cc. Mesh.complex[int]. This function is like MPI Allgather mpiScatter(Data a. DOMAIN DECOMPOSITION 289 11. Note that Data D can be: int.Data b.Data b.Data b.complex .mpiComm cc).Data D): Receive corresponding to send. Note that Data D can be: int.complex[int]. real[int]. real. mpiPROD. . mpiLXOR. real.4. Send(processor(int rk. mpiAlltoall(Data a. mpiMAXLOC. Recv(processor(int rk. 11.4 Global operations In FreeFem++ you can call MPI global communication functions. Mesh3.Data b): Sends data a from all to all processes.mpiComm cc).complex . Process of rank rk get data on communicator rk. Matrix and should be the same type than corresponding send.Data D) : Non blocking send of Data D to processor of rank rk inside communicator cc. Receive buffer is Data b. Note that Data D can be: int. real[int]. assert(unssd.refe=chlab). // Variables for manage communicators 5: rank=mpiRank(myComm). // plot(s.1 .1 .Vh). // Use or not metis for partitioning Mesh 7: int sizeoverlaps=5.1 . varf vM(u.fill=1). 12: int nn=2. // add n layer of element (size of the overlap) // and unssd = 0 ouside of this layer .ndof). // ’. // Rank of process and size of communicator 6: bool withmetis=1.edp) 1:load "hypre_FreeFem". assert(ssd.qforder=1)(u*v/area). for(int i=0. unssd=0. // Load Hypre solver 2:func bool AddLayers(mesh & Th. npart= nn*mm.i<n.1.wait=1. // such that : // unssd = 1 when ssd =1. 9: mesh Th=square(100. // unssd+= u[]. return true.n==Ph. s = s >0..P0). plot(u. In this example we use two level of parallelism to solve simple Laplacian2d in square domain.1 ].P1). Example 11.int n. // size off overlap 8: int withplot=1.rank. PARALLEL SPARSE SOLVERS The following example present in details of Schwartz domain decomposition algorithm for solving Laplacian2d problem.real[int] &unssd) { // build a continuous function uussd (P1) : // ssd in the caracteristics function on the input sub domain.size. u[]=unssd. fespace Ph(Th. // u = u>. We have few number of subdomain and in every subdomain we use parallel sparse solver to solve local problem. 10: int[int] chlab=[1.. Ph s.1. Vh u. // --------------------------------fespace Vh(Th. 11: Th=change(Th.3.real[int] &ssd. plot(u. s[]= ssd.wait=1). ssd=s[]. } unssd /= (n). RAS=0.9 (schwarz.290 CHAPTER 11. . } 3: mpiComm myComm.n==Vh.++i) { u[]= M*s[].ndof).wait=1).4.v)=int2d(Th. matrix M=vM(Ph.2.100). size=mpiSize(myComm). // Create communicator with value MPI COMM WORLD 4: int membershipKey.mm=2. s[]= M’*u[]. mpiSUM). // Coloring for partitioning process group 14: mpiComm cc(processor(membershipKey.unssd=0. 16: Ph part.4.P1). DOMAIN DECOMPOSITION 291 13: membershipKey = mpiRank(myComm)%npart.suppi[].fill=1.fill=1. // also global operation like broadcast’.n.11. Thi=aTh[i]=trunc(Th.myComm). 32: plot(sun. // Create MPI communicator according previous coloring 15: fespace Ph(Th.Vh).pun(npart). 23: mesh Thi=Th.wait=1). for(int i=0.inside=1). // Add mpireduce for sum all sun and pun local contribution.qforder=1)(suppi*v/area).reducesum). 17: Vh sun=0.P0). int[int] nupart(Th.wait=1).nt).++i) part[][i]=nupart[i].myComm). rhsi(npart). Dih(npart).i<nupart. // Data use for control partitioning.unssd[]).myComm).Th. varf vSuppi(u. 18: real[int] vsum=sun[]. 19: Ph xx=x.1. // Vh -> Vhi if(RAS) { suppi= abs(part-i)<0.fespace Vh(Th.1. Rih[i]=interpolate(Vhi. 21: if(withmetis) { load "metis".wait=1).reducesum=sun[].cmm="dual". 29: mpiReduce(vsum. 33: i=membershipKey 34: Thi=aTh[i].v)=int2d(Th.split=1).Vh. .rank). 27: Vhi[int] auntgv(npart). 20: part = int(xx*nn)*mm + int(yy*mm). if(withplot>19) plot(unssd.P1). reducesum. 25: Vhi[int] au(npart). 24: fespace Vhi(Thi. 35: pun[i]= pun[i]/sun. // MPI global operation MPi Reduce on global communicator 30: broadcast(processor(0.suppi>0. unssd[]= vSuppi(0. 28: i=membershipKey. AddLayers(Th. vsum=sun[]. // this is global operation sun[] += Rih[i]’*pun[i][]. 22: mesh[int] aTh(npart). unssd = unssd>0. if(withplot>9) plot(part. // Broadcast sum on process 0 to all process 31: sun[]=reducesum.aTh[i]. metisdual(nupart.npart).yy=y. 26: matrix[int] Rih(npart).wait=1)..sizeoverlaps. } pun[i][]=Rih[i]*unssd[].nupp.label=10. } 22: if(withplot>1) 21: plot(part.processor(0. Ph suppi= abs(part-i)<0. aA(npart). } 65: reducesum=0. for(int iter=0. // MPI global operation MPi Reduce on global communicator . real[int] bi = ui .mpiSUM). bi = auntgv[i][] ? bi : rhsi[i][].max).. // ’. 45: un=1.292 36: 37: 38: 39: CHAPTER 11.min<< endl. 56: reducesum=0. i=membershipKey.* auntgv[i][].u=1) + int2d(Th)(v) +on(10. reducesum.wait=1). 57: mpiReduce(vsum.max << " " << sun[].++iter) { real err=0. { Vh un=0. // ’. // MPI global operation MPi Reduce on global communicator 58: broadcast(processor(0. 66: mpiReduce(vsum.v) = int2d(Thi)(Grad(u)’*Grad(v)) // ’) +on(1. // Prolongation of current solution to obtain right hand un1[] += Rih[i]’*bi.u=0) .rerr=0. au[i][]= ui. macro Grad(u) [dx(u). 41: set(aA[i]. // store arry of tgv on Gamma intern.processor(0. err += bi’*bi. // Broadcast sum on process 0 to all other process 59: sun[]=reducesum.mpiSUM). i=membershipKey Thi=aTh[i]. vsum=un1[]. // Solve local linear system on group of process represented by color membershipKey bi = ui-au[i][]. 64: int nitermax=1000.iter<nitermax. 48: varf vaun(u.solver=sparsesolver. 47: sun[] += Rih[i]’*ui.ndof). 44: real[int] un(Vhi.-1e-9 <= sun[]. bi = Dih[i]*ui. // ’. 49: auntgv[i][]=vaun(0.u=1).Vhi).myComm). 43: Dih[i]=pun[i][]. Thi=aTh[i]. 62: cout << sun[].fill=1. 63: assert( 1.dy(u)] // EOM sun=0. // ’.myComm). vsum=sun. real[int] ui=Rih[i]*un[]. reducesum. mpicomm=cc means you not solve on global process but in group on of process define by cc 42: rhsi[i][]= va(0.Vhi). 46: real[int] ui=Dih[i]*un.processor(0. PARALLEL SPARSE SOLVERS if(withplot>8) plot(pun[i]. ui= aA[i] ˆ-1 * bi. 40: aA[i]=va(Vhi.mpicomm=cc).+1e-9 >= sun[].reducesum). ui=au[i][].myComm).Vhi). // Set parameters for Solver Hypre. varf va(u.min && 1.v) = on(10. Vh un1=0.wait=1). 60: if(withplot>5) 61: plot(sun. myComm). 78: } 79: plot(un. err= sqrt(err). 80: } . 73: if(rank==0) cout << iter << " Err = " << err << endl. // Broadcast sum on process 0 to all other process 68: un1[]=reducesum. 75: un[]=un1[].11.mpiSUM).residrela).myComm).fill=1 ).wait=1.processor(0. DOMAIN DECOMPOSITION 293 67: broadcast(processor(0.reducesum). 74: if(err<1e-5) break.cmm=" iter "+iter. 69: real residrela=0.wait=0. 70: mpiReduce(err. 76: if(withplot>2) 77: plot(au.dim=3.residrela .myComm).4. 72: err=residrela. 71: broadcast(processor(0.dim=3). PARALLEL SPARSE SOLVERS .294 CHAPTER 11. dim ) . i=1 . @@Edge2 . i=1. (I) Ref φti . NbOfQuadrilaterals ) • Geometry (C*) FileNameOfGeometricSupport – VertexOnGeometricVertex (I) NbOfVertexOnGeometricVertex ( @@Vertexi . j=1. @@Edgegeo . @@Vertexgeo . @@Vertex2 .1 File mesh data structure The mesh data structure. j=1.NbOfEdgeOnGeometricEdge ) i • CrackedEdges (I) NbOfCrackedEdges ( @@Edge1 . output of a mesh generation algorithm. i=1 . refers to the geometric data structure and in some case to another mesh data structure.3 ) . j=1. (I) Ref φv . NbOfEdges ) i i i • Triangles (I) NbOfTriangles ( ( @@Vertexji . In this case. (I) Ref φti . (I) Ref φe . NbOfVertices ) i • Edges (I) NbOfEdges ( @@Vertex1 . i=1 . i=1.Chapter 12 Mesh Files 12.4 ) . NbOfTriangles ) • Quadrilaterals (I) NbOfQuadrilaterals ( ( @@Vertexji . i=1 .NbOfVertexOnGeometricVertex ) i – EdgeOnGeometricEdge (I) NbOfEdgeOnGeometricEdge ( @@Edgei . i=1 . the fields are • MeshVersionFormatted 0 • Dimension (I) dim • Vertices (I) NbOfVertices ( ( (R) xji . NbOfCrackedEdges ) i i 295 . i=1 . typesoln nbv 2 Uk . nbv}) where • nbsol is a integer equal to the number of solutions.3 BB File Type for Store Solutions ∀j ∈ {1.. @@Edgesupp . i=1 .NbOfVertexOnSupportEdge ) – VertexOnSupportTriangle (I) NbOfVertexOnSupportTriangle ( @@Vertexi . 12. nbsol}) .296 CHAPTER 12. .... is . ∀i ∈ {1. • Uij is a real equal the value of the i solution at vertex j on the associated mesh background if read file. (R) usupp . we have in addition • MeshSupportOfVertices (C*) FileNameOfMeshSupport – VertexOnSupportVertex (I) NbOfVertexOnSupportVertex ( @@Vertexi . i=1. generated if write file. • nbv is a integer equal to the number of vertex .2 bb File type for Store Solutions The file is formatted such that: 2 nbsol nbv 2 ((Uij . NbOfVertexOnSupportTriangle ) . ∀i ∈ {1. type of the solution number k..... (R) usupp . ∀k ∈ {1.NbOfVertexOnSupportVertex ) i – VertexOnSupportEdge (I) NbOfVertexOnSupportEdge ( @@Vertexi .. @@Triasupp . i=1.. typesolk } . nbv} The file is formatted such that: 2 n typesol1 . (R) visupp i i – VertexOnSupportQuadrilaterals (I) NbOfVertexOnSupportQuadrilaterals ( @@Vertexi . . MESH FILES When the current mesh refers to a previous mesh.. @@Quadsupp . ∀j ∈ {1.. NbOfVertexOnSupportQuadrilaterals ) 12. (R) usupp i i .n} ij where • n is a integer equal to the number of solutions • typesolk . .. .. .. @@Vertexsupp .. (R) visupp i i . isotropic or anisotropic.... AMDBA Meshes The mesh is only composed of triangles and can be defined with the help of the following two integers and four arrays: nbt nbv is the number of triangles. METRIC FILE – typesolk = 1 the solution k is scalar (1 value per vertex) – typesolk = 2 the solution k is vectorial (2 values per unknown) 297 – typesolk = 3 the solution k is a 2×2 symmetric matrix (3 values per vertex) – typesolk = 4 the solution k is a 2×2 matrix (4 values per vertex) • nbv is a integer equal to the number of vertices • Uk is a real equal to the value of the component i of the solution k at vertex j on the ij associated mesh background if read file. • hi is the wanted mesh size near the vertex i on background mesh. is the number of vertices..a22i ∀i ∈ {1.12.4 Metric File A metric file can be of two types. generated if write file. nbv} where • nbv is a integer equal to the number of vertices. 12. a22i is metric Mi = a11i a12i which define the wanted mesh size in a a12i a22i √ vicinity of the vertex i such that h in direction u ∈ R2 is equal to |u|/ u · Mi u . where · is the dot product in R2 . 12. nu(1:3. .a21i . and | · | is the classical norm.5 List of AM FMT. where Id is the identity matrix. . a12i . the isotropic file is such that nbv 1 hi ∀i ∈ {1. • a11i . . i The metric anisotrope nbv 3 a11i . nbv} where • nbv is a integer equal to the number of vertices..1:nbt) is an integer array giving the three vertex numbers counterclockwise for each triangle.. the metric is Mi = h−2 Id.4. j).i=1.j=1.nbt.*) ( reft(i).j=1.j=1.i=1.nbt) read (1.*) ((c(i.nbv) close(1) AM Files In fortran the am files are read as follows: open(1.msh’. & ((c(i.am’.file=’xxx.status=’old’) read (1.nbv) read (1.nbbe read (1. MESH FILES is a real array giving the two coordinates of each vertex.i=1.j).*) ((c(i.2).file=’xxx.nbt) read (1.2).nbt).i=1.k).form=’formatted’.2).i=1.(nu(i.3). & ( reft(i).reft(k).form=’unformatted’.*) nbv.*) nbv.nbv) read (1.*) ( refs(i).j).nbt).3).*) (k.nbt) read (1.j=1.2). refbe(k).status=’old’) read (1. & ( refs(i).nbt read (1.reft(k).j=1.(c(i.*) (k.i=1.j=1.nbt read (1.*) ((ne(i. we add the notions of boundary edges nbbe is the number of boundary edge. nube(1:2.i=1. is an integer array giving the reference numbers of the vertices.status=’old’) read (1.1:nbbe) is an integer array giving the two vertex numbers refbe(1:nbbe) is an integer array giving the two vertex numbers In fortran the msh files are read as follows: open(1.i=1.amdba’.form=’formatted’.nbbe) close(1) .nbv) refs(nbv) reft(nbv) CHAPTER 12. AM FMT Files In fortran the am fmt files are read as follows: open(1.nbt read (1) ((nu(i.nbv).i=1.*) ((nu(i.k). is an integer array giving the reference numbers of the triangles.refs(k).i=1.nbt) close(1) msh Files First.j).*) ((nu(i.i=1.status=’old’) read (1.k).j=1.am_fmt’.3).i=1.k).file=’xxx.k).form=’formatted’.*) nbv.3).*) nbv.nbv) close(1) AMDBA Files In fortran the amdba files are read as follows: open(1.j=1.file=’xxx.i=1.nbv) read (1.2).refs(k).j=1.298 c(1:2. k).j=1. . LIST OF AM FMT.*) (k(j).nbe) read (1.j=1.file=’xxx.(nu(i.12.nbq read (1.nbt.refs(k).i=1.j).reft(j).form=’formatted’.ftq’.2). AMDBA MESHES ftq Files In fortran the ftq files are read as follows: open(1.k(j)).*) ((c(i.nbe.*) nbv.status=’old’) read (1.5.nbv) close(1) 299 where if k(j) = 3 then the element j is a triangle and if k = 4 the the element j is a quadrilateral.i=1. 300 CHAPTER 12. MESH FILES . e1 . and define the three edge vectors e0 . We have the identity ωi = Πh ωi . In the formula (13. e2 by sgn(ib − ic )(b − c). ik depend just on the type of finite element (not on the element).ne . · · · . sgn(ia − ib )(a − b). jk = k because we have one node per function. where the flux of the function f : R2 −→ R2 is e f . 2|T | (13. sgn(ic − ia )(c − a). N bDoF − 1) of the finite element space has the j-th component ωij for j = 0. 2|T | K ω1 = sgn(ic − ia ) (x − b). Formally. b.1) where Pp is a set of npP i points. we use a quadrature formula with one point. but the coefficient αk can be depending on the element. · · · . 2. we have kPi = npPi = NbOfNode and • Pp is the point of the nodal points • the αk = 1. ne is the unit normal of edge e (this implies a orientation of all the edges of the mesh. we define the finite element approximation Πh f of f . Then K K the i-th base ωi (i = 0. • jk = 0 because N = 1 Example 2: The Raviart-Thomas finite element: RT 0h = {v ∈ H(div)/∀K ∈ Th v|K (x. Example 1: with the classical scalar Lagrange finite element. Let denote the vertices numbers by ia . N = 1. the list pk . the middle point of the edge. 2|T | K ω2 = sgn(ia − ib ) (x − c). for example we can use the global numbering of the edge vertices and we just go to small to large number). · · · .3) 301 . ib . N − 1. because we take the value of the function at the point Pk • pk = k .1). To compute this flux. ic . y) = αK βK + γK | x } y (13. K K The operator Πh is called the interpolator of the finite element. the interpolator Πh is constructed by the following formula: kPi−1 Πh f = k=0 K αk fjk (Ppk )ωik (13. c).1 Some notations For a function f taking value in RN . jk .Chapter 13 Addition of a new finite element 13. Consider a triangle T with three vertices (a.2) The degrees of freedom are the flux through an edge e of the mesh. The three basis functions are: K ω0 = sgn(ib − ic ) (x − a). Let us denote the number of the degrees of freedom of the finite element by N bDoF . 2. ADDITION OF A NEW FINITE ELEMENT where |T | is the area of the triangle T . RNMK_ & val) const. So we have N = 2. ) { const R2 Pt[] = { R2(0. em ) 2 1 2 1 2 1 2 1 is orthogonal to the edge em = (em . 0. 1. const Mesh & Th.p++) { P_Pi_h[p]=Pt[p]. kPi = 6. and: • Pp = b+c a+c b+a 2 .5).0) }. 2}.0.j++) pij_alpha[kk++]= IPJ(p. em ) with a length equal to the side of the edge or equal 1 2 to em 1). for (int j=0. 2. α2 = −e1 .hpp" #include "FESpace. jk in (13.5). }} // definition of ik . // nb degree of freedom on element 2. // nb of sub finite element (generaly 1) 6. #include "RNM. 1. ˆ // the set of Point in K for (int p=0. α1 = e0 .2 Which class to add? Add file FE ADD. // nb of subdivision for plotting 1. // number npP i of integration point to build interpolator 0 // an array to store the coef αk to build interpolator // here this array is no constant so we have // to rebuilt for each element. • pk = {0. // dimension N of vectorial FE (1 if scalar FE) Data.h" namespace Fem2D { Then add a class which derive for public TypeOfFE like: class TypeOfFE_RTortho : public TypeOfFE { public: static int Data[].1) 3. 1. α3 = e1 .const Triangle & K.p<3. 2} .j). . α4 = −e2 . // the array data 1. 1}. 1.hpp" #include "AddNewFE. 2 • α0 = −e0 . pk .hpp" #include "fem.p. 1. R2(0. jk = {0. 0.5.0. 1. 13.hpp" #include "rgraph. R2(0. npPi = 3. const R2 &PHat. 0. • ik = {0.j<2. α5 = e2 (effectively.kk=0. the vector (−em .0. // number kP i of coef to build the interpolator (13. 0. 1. 2 . 0.hpp" using namespace std.0. // some numbers TypeOfFE_RTortho(): TypeOfFE( 0+3+0.5.302 CHAPTER 13.cpp in directory src/femlib for example first to initialize : #include "error.1) void FB(const bool * watdd. B(K[1]). 303 where the array data is form with the concatenation of five array of size NbDoF and one array of size N. 4. dx(f )(P ).op_dyz=9 }.1. op_dyx=5.0 }.0. last operatortype[. k) corresponding to: i is basic function number on finite element i ∈ [0.// 0. .2.1. 2 for vertex support.1.KN_<double> & v) const . this value is computed only if whatd[k] is true. computed at point PHat on the reference triangle corresponding to point R2 P=K(Phat).l1=P.2. N [ k is the type of computed value f (P ).l2=P.y. . N oF [ j is the value of component j ∈ [0. // for each df 0.y. val=0. j. K The function to defined the function ωi . const R2 & PHat.3 : the support of the node of the df the number of the df on the node the node of the df the df come from which FE (generally 0) which are de df on sub FE for each component j = 0. assert(val. 5 for edge support. R l0=1-P.N() >=3).C(K[2]). 3. dy(f )(P ). and the numbering is defined with enum operatortype { op_id=0.// 0. op_dx=1. WHICH CLASS TO ADD? void Pi_h_alpha(const baseFElement & K.op_dy=2. N − 1 it give the sub FE associated where the support is a number 0. this function return the value of all the basics function or this derivatives in array val.2.op_dxy=5. i ∈ [0. op_dzz=7. } .4.op_dxz=8.M()==2 ). op_dxx=3. k of the array val(i.x. op_dzx=8.// 0.0.const Mesh & Th. Remark for optimization.. This array is: int TypeOfFE_RTortho::Data[]={ // 3.// 0.x-P.5. const int last_operatortype=10. assert(val. op_dzy=9.13.0. The index i.op_dyy=4.. op_dz=6. j.// 0. on the current triangle K. The shape function : void TypeOfFE_RTortho::FB(const bool *whatd. R2 A(K[0]).RNMK_ & val) const { // R2 P(K(PHat)). and finaly 6 for element support.const Triangle & K.0. 1. x-C. f0[2] = -(P.op_dx) = a2. val(0.y-C. } The function to defined the coefficient αk : void TypeOfFE_RT::Pi_h_alpha(const baseFElement & K. i< last_operatortype . v[k++]= signe*E.op_dx) = a1.1.y)*a0.K()>op_id).0.x)*a0. ADDITION OF A NEW FINITE ELEMENT a=1. f0[1] = -(P.’. } } . a0= K.KN_<double> & v) const { const Triangle & T(K.x-A.Edge(i)). f1[0] = (P.area).1. i++) if (whatd[op_dx]) assert(op_dy).op_dy) = -a2.y)*a1.EdgeOrientation(1) * a .0. a2= K. val(0. f0[0] = -(P.K()>op_dx).0)). val(1. } if (whatd[op_dy]) { assert(val./(2*K.EdgeOrientation(i) .y)*a2. // -----------value of the function if (whatd[op_id]) { assert(val.op_dx) = a0. val(2.’.304 R R R R CHAPTER 13.y-A. } if (whatd[op_dx]) { assert(val. for (int i=0.0. RN_ f0(val(’.x-B. f1[1] = (P.1. v[k++]=-signe*E. f1[2] = (P. R signe = T. val(1.0.EdgeOrientation(0) * a .K()>op_dy). } // // // // value first component value second component // ---------------value of the dx of function for (int i= op_dy.x)*a2. RN_ f1(val(’.y-B.EdgeOrientation(2) * a .T).y.op_dy) = -a0.1.i<3.op_dy) = -a1. val(2.x. a1= K.k=0.i++) { R2 E(T.x)*a1.0)). link” command in examples++-load/ and see BernardiRaugel.13.cpp new finite element examples.cpp like: // correct Problem of static library link with new make file void init_static_FE() { // list of other FE file. EXTRA_DIST=BamgFreeFem. we add : With dynamic link is very simple (see section C of appendix). with static or dynamic link so at the end of the file.cpp ConjuguedGradrientNL. First. like in file src/femlib/Element P2h. Otherwise with static link (for expert only). // // ----. init_FE_P2h() . Two way. The_TypeOfFE_RTortho). after modifier the Makefile.hpp Drawing./load. just add before the end of FEM2d namespace add: static TypeOfFE_RTortho The_TypeOfFE_RTortho.a // FH so add a extern name to call in init static FE // (see end of FESpace.end -} // FEM2d namespace To inforce in loading of this new finite element. } // // FEM2d namespace Try with ”.hpp CGNL. // --.cpp or Morley.cpp DOperator.cpp) void init_FE_ADD() { }. extern void init_FE_ADD() . // new line 2 } and now you have to change the makefile.cpp contening all this code.am by adding the name of your file to the variable EXTRA DIST like: # Makefile using Automake + Autoconf # ---------------------------------# $Id$ # This is not compiled as a separate library because its # interconnections with other libraries have not been solved. we just need to add a new key work in FreeFem++.cpp.o extern void init_FE_P2h() .cpp \ \ . & The_TypeOfFE_RTortho). static AddNewFE("RT0Ortho". WHICH CLASS TO ADD? 305 Now .2. we have to add the two new lines close to the end of files src/femlib/FESpace.cpp BamgFreeFem. // // link with FreeFem++ do not work with static library . create a file FE ADD. add // let the 2 globals variables static TypeOfFE_RTortho The_TypeOfFE_RTortho.cpp Element_P2h.the name in freefem ---static ListOfTFE typefemRTOrtho("RT0Ortho".hpp CheckPtr. // new line 1 init_FE_ADD(). .cpp fem.cpp mshptg.hpp fem.cpp Element_RT.hpp RNM.cpp FESpace. ADDITION OF A NEW FINITE ELEMENT \ \ \ \ \ Element_P3.hpp RNM_opc.cpp glutdraw.hpp RNM_tpl.hpp RNM_op.hpp FE_ADD.hpp MatriceCreuse./reconfigure make For codewarrior compilation add the file in the project an remove the flag in panal PPC linker FreeFEm++ Setting Dead-strip Static Initializition Code Flag.cpp and do in the freefem++ root directory autoreconf .cpp fem3.hpp MatriceCreuse_tpl.cpp FQuadTree.cpp FQuadTree.cpp QuadratureFormular.cpp QuadratureFormular.hpp mortar.hpp gibbs.hpp FESpace-v0.hpp RefCounter.cpp gmres.hpp FESpace.306 CHAPTER 13.hpp MeshPoint. that is PDE partial differential equation (with boundary conditions) ∅ the empty set N the set of integers (a ∈ N ⇔ int a). complex¡double¿ Rd d-dimensional Euclidean space A.double inside FreeFem++ C the set of complex numbers (a ∈ C ⇔ complex a). A. “int” means long integer inside FreeFem++ R the set of real numbers (a ∈ R ⇔ real a) . G be three sets and A subset of E. Matrices. F.1 ∀ for all Generalities δij Kronecker delta (0 if i = j.2 Sets. j) ∃ there exist i.e. {x ∈ E| P } the subset of E consisting of the elements possessing the property P E ∪ F the set of elements belonging to E or F E ∩ F the set of elements belonging to E and F E \ A the set {x ∈ E| x ∈ A} E + F E ∪ F with E ∩ F = ∅ 307 .Appendix A Table of Notations Here mathematical expressions and corresponding FreeFem++ commands are explained. Mappings. 1 if i = j for integers i. Vectors Let E. and (aij )T = (aji ) A.e.i. divf = ∂f1 /∂x + ∂f2 /∂y ∆f the Laplacian of f : Ω → R.e.i..e. i. i.. b [a. b] is the interval {x ∈ R| a < x ≤ b} [a. ∂f /∂y) . divf or f = (∂f /∂x.e. ∆f = ∂ 2 f /∂x2 + ∂ 2 f /∂y 2 .4 Differential Calculus ∂f /∂x the partial derivative of f : Rd → R with respect to x ( dx(f)) f the gradient of f : Ω → R. TABLE OF NOTATIONS E n the n-th power of E (E 2 = E × E. b] is the interval {x ∈ R| a ≤ x ≤ b} ]a... E x → (f ◦ g)(x) = f (g(x)) ∈ G (see Section ??) f |A the restriction of f : E → F to the subset A of E {ak } column vector with components ak (ak ) row vector with components ak (ak )T denotes the transpose of a matrix (ak ). E n = E × E n−1 ) f : E → F the mapping form E into F . and is {ak } {aij } matrix with components aij . E x → f (x) ∈ F IE or I the identity mapping in E. b[ is the interval {x ∈ R| a < x < b} A.. i.e. I(x) = x ∀x ∈ E f ◦ g for f : F → G and g : E → F . b[ is the interval {x ∈ R| a ≤ x < b} ]a.308 E × F the cartesian product of E and F APPENDIX A.f the divergence of f : Ω → Rd .3 Numbers For two real numbers a. e.x. Γ = ∂Ω (keyword border. Th[k-1][j-1].nv) [q i q j ] the segment connecting q i and q j q k1 . i. see “mesh.5. α2 ) ∈ N2 ..A.Ω = 1 H0 (Ω) the set {w ∈ H 1 (Ω) | u = 0 on Γ } . y)|2 dxdy vw Ω scalar product: (v.5 Meshes Ω usually denotes a domain on which PDE is defined Γ denotes the boundary of Ω. If Ω is polygonal domain.e. w)1.edp”) Ωh denotes the approximated domain Ωh = ∪nt Tk of Ω. q k3 the vertices of a triangle Tk with anti-clock direction (get the coordinate of q kj by (Th[k-1][j-1]. then it k=1 will be Ω = Ωh Γh the boundary of Ωh nv the number of vertices in Th (get by Th. buildmesh. |α| = α1 + α2 ∂xα1 ∂y α2 Dα vDα w |α|≤m Ω scalar product: (v. w) = H 1 (Ω) the set w ∈ L2 (Ω) Ω |∂w/∂x|2 + |∂w/∂y|2 dxdy < ∞ norm: w = w 2 0. where h stands for mesh size (keyword mesh.. q k2 .Ω 1.i.Ω + u 1/2 2 0. see Section 5. y)|2 dxdy < ∞ norm: w 0.nt. see Section 5) nt the number of triangles in Th (get by Th.1.y)) IΩ the set {i ∈ N| q i ∈ Γh } A. the set of triangles Tk .6 Finite Element Spaces w(x. MESHES 309 A.Ω H m (Ω) the set w ∈ L2 (Ω) Ω ∂ |α| w ∈ L2 (Ω) ∀α = (α1 .Ω = Ω |w(x.2) Th the triangulation of Ω. y) Ω 1/2 L2 (Ω) the set |w(x. cout << v[] << endl.” means v = Πh f) {v} for FE-function v in Vh means the column vector (v1 .” . Vh v = f. TABLE OF NOTATIONS L2 (Ω)2 denotes L2 (Ω) × L2 (Ω).310 APPENDIX A. and also H 1 (Ω)2 = H 1 (Ω) × H 1 (Ω) Vh denotes the finite element space created by “ fespace Vh(Th.*)” in FreeFem++ (see Section 6 for “*”) Πh f the projection of the function f into Vh (“ func f=xˆ2*yˆ3. vM )T if v = v1 φ1 +· · ·+vM φM . which is shown by “ fespace Vh(Th. Vh v. · · · .P2). instructions .’ ’[’ list_of_id_args ’]’ | list_of_id_args ’. list_of_dcls: | | | ID ID ’=’ no_comma_expr ID ’(’ parameters_list ’)’ list_of_dcls ’.’ id . list_of_id_args: | id | id ’=’ no_comma_expr | FESPACE id | type_of_dcl id | type_of_dcl ’&’ id | ’[’ list_of_id_args ’]’ | list_of_id_args ’.’ type_of_dcl ’&’ id .’ type_of_dcl id | list_of_id_args ’.1 start: input: The bison grammar input ENDOFFILE. id: ID | FESPACE . instructions: instruction | instructions instruction .’ id ’=’ no_comma_expr | list_of_id_args ’. list_of_id1: id | list_of_id1 ’. parameters_list: no_set_expr | FESPACE ID | ID ’=’ no_set_expr 311 .Appendix B Grammar B.’ FESPACE id | list_of_id_args ’.’ list_of_dcls .’ id | list_of_id_args ’. ’ .’ spaceIDs ’.312 | parameters_list ’.’ no_set_expr | parameters_list ’. fespace_def_list: fespace_def | fespace_def_list ’. type_of_dcl list_of_dcls ’.’ ’fespace’ fespace_def_list ’.’ id ’=’ no_set_expr . GRAMMAR ID_space: ID | ID ’[’ no_set_expr ’]’ | ID ’=’ no_set_expr | ’[’ list_of_id1 ’]’ | ’[’ list_of_id1 ’]’ ’[’ no_set_expr ’]’ | ’[’ list_of_id1 ’]’ ’=’ no_set_expr . ’while’ .’ FUNCTION type_of_dcl ID ’(’ list_of_id_args ’)’ ’{’ instructions’}’ FUNCTION ID ’(’ list_of_id_args ’)’ ’=’ no_comma_expr ’.’ Expr ’.’ fespace_def . declaration: | | | | | begin: ’{’ end: ’}’ for_loop: while_loop: . . .’ | declaration | for_loop ’(’ Expr ’.’ FUNCTION ID ’=’ Expr ’. APPENDIX B. instruction: ’. spaceIDa : | spaceIDb : | spaceIDs : | ID_array_space spaceIDa ’. type_of_dcl: TYPE | TYPE ’[’ TYPE ’]’ . fespace_def: ID ’(’ parameters_list ’)’ .’ Expr ’)’ instruction | while_loop ’(’ Expr ’)’ instruction | ’if’ ’(’ Expr ’)’ instruction . ’for’ . fespace fespace ’[’ TYPE ’]’ spaceIDb spaceIDa .’ ID_array_space ID_space spaceIDb ’. ID_array_space: ID ’(’ no_set_expr ’)’ | ’[’ list_of_id1 ’]’ ’(’ no_set_expr ’)’ .’ | ’include’ STRING | ’load’ STRING | Expr ’.’ ID_space . fespace: FESPACE . ’ ’continue’ ’.’ . no_ternary_expr: unary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr | no_ternary_expr ’*’ no_ternary_expr ’.’ Expr ’)’ .’ Expr .B. no_comma_expr | Expr ’. no_set_expr: no_ternary_expr | no_ternary_expr ’?’ no_set_expr ’:’ no_set_expr . 313 bornes: ’(’ ID ’=’ Expr ’. no_comma_expr: no_set_expr | no_set_expr ’=’ no_comma_expr | no_set_expr ’+=’ no_comma_expr | no_set_expr ’-=’ no_comma_expr | no_set_expr ’*=’ no_comma_expr | no_set_expr ’/=’ no_comma_expr .’ ’break’ ’. THE BISON GRAMMAR | | | | | | | ’if’ ’(’ Expr ’)’ instruction ELSE instruction begin instructions end ’border’ ID border_expr ’border’ ID ’[’ array ’]’ ’. border_expr: Expr: bornes instruction . unop: | | | | ’-’ ’+’ ’!’ ’++’ ’--’ .*’ no_ternary_expr ’./’ no_ternary_expr ’/’ no_ternary_expr ’%’ no_ternary_expr ’+’ no_ternary_expr ’-’ no_ternary_expr ’<<’ no_ternary_expr ’>>’ no_ternary_expr ’&’ no_ternary_expr ’&&’ no_ternary_expr ’|’ no_ternary_expr ’||’ no_ternary_expr ’<’ no_ternary_expr ’<=’ no_ternary_expr ’>’ no_ternary_expr ’>=’ no_ternary_expr .’ ’return’ Expr ’.1. ’ FESPACE parameters ’. GRAMMAR parameters: | | | | | | | array: no_set_expr FESPACE id ’=’ no_set_expr sub_script_expr parameters ’.’ id ’=’ no_set_expr . // transpose . ’(’ Expr ’)’ ’[’ array ’]’ . unary_expr: pow_expr | unop pow_expr %prec UNARY .’ no_comma_expr .’ ID primary ’++’ primary ’--’ TYPE ’(’ Expr ’)’ . no_comma_expr | array ’. APPENDIX B. pow_expr: primary | primary ’ˆ’ unary_expr | primary ’_’ unary_expr | primary ’´ . ’ primary: | | | | | | | | | | | | | ID LNUM DNUM CNUM STRING primary ’(’ parameters ’)’ primary ’[’ Expr ’]’ primary ’[’ ’]’ primary ’.314 | no_ternary_expr ’==’ no_ternary_expr | no_ternary_expr ’!=’ no_ternary_expr . sub_script_expr: no_set_expr | ’:’ | no_set_expr ’:’ no_set_expr | no_set_expr ’:’ no_set_expr ’:’ no_set_expr .’ no_set_expr parameters ’. <KN<double> *>. type :<TypeSolveMat> . THE TYPES OF THE LANGUAGES. type :<Polymorphic> ( <double> : <double> ) operator() : .append. type :<Polymorphic> operator() : ( <double> : <double> ) .adaptmesh. type :<std::ios_base::openmode> . type :<Fem2D::TypeOfFE> . type :<Polymorphic> ( <double> : <double> ) .GMRES.NoUseOfWait.B.asinh.CG. type :<bool *> . type :<Fem2D::R3> .abs. type :<Polymorphic> operator() : ( <long> : <Polymorphic>. type :<Fem2D::R3> .N. type :<TypeSolveMat> . ) .. <KN<double> *> ) . type :<Polymorphic> operator() : ( <double> : <double> ) ( <double> : <double>. type :<TypeSolveMat> .P1. type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>. type :<Fem2D::TypeOfFE> .Cholesky. type :<Fem2D::TypeOfFE> . type :<Polymorphic> ( <double> : <double> ) operator() : . and cast All the operators .RTmodif. type :<Fem2D::TypeOfFE> .atanh.2 B.P0.Crout.atan. AND CAST 315 B.P2. <double> ) . type :<Polymorphic> operator() : ( <double> : <double> ) ..RT0.LinearCG. type :<Polymorphic> operator() : ( <double> : <double>.acos.atan2.asin. type :<Polymorphic> ( <double> : <double> ) operator() : operator() : .P.3 The Types of the languages. type :<Fem2D::TypeOfFE> . type :<TypeSolveMat> . type :<Fem2D::TypeOfFE> .acosh.LU. type :<TypeSolveMat> .2.P1nc. <double> ) . type :<Polymorphic> ( <long> : <long> ) operator() : operator() : . type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <E_BorderN> ) . <double> ) . C_F0>> : <LinearComb<MGauche. int>> ) ( <LinearComb<MGauche.cin.exp. type :<Polymorphic> ( <double> : ) . type :<ostream> .endl. type :<Polymorphic> ( <Fem2D::Mesh> : <E_BorderN> ) . type :<Polymorphic> operator() : ( <complex> : <complex> ) . type :<Polymorphic> ( <ostream> : <ostream> ) operator() : operator() : . C_F0>> ) .exit.buildmesh.clock.convect. C_F0>> : <LinearComb<MDroit.dumptable. type :<Polymorphic> operator() : ( <LinearComb<MDroit.buildmeshborder. type :<Polymorphic> ( <long> : <string> ) . type :<Polymorphic> operator() : ( <LinearComb<MDroit.dy. type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) . int>> ) ( <LinearComb<MGauche.conj. type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) . type :<Polymorphic> operator() : ( <double> : <E_Array>.exec. C_F0>> : <LinearComb<MDroit. GRAMMAR .dx. C_F0>> ) . C_F0>> ) ( <double> : <std::pair<FEbase<double> *. <double>. type :<char> . type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) .316 APPENDIX B.cout. C_F0>> : <LinearComb<MGauche. C_F0>> ) ( <double> : <std::pair<FEbase<double> *.cosh. type :<istream> .cos. . <long> ) .norm.nuTriangle. type :<Polymorphic> ( <CDomainOfIntegration> : operator() : <Fem2D::Mesh>.log.log10.min. type :<Polymorphic> operator( : ( <double> : <std::complex<double>> ) .. C_F0>> ) <LinearComb<MGauche. ) .int1d. ) 317 .false.jump. type :<bool> .3. <double> ) ( <long> : <long>. type :<Polymorphic> operator() : ( <double> : <double>.mean. C_F0>> ) .. type :<Polymorphic> ( <double> : <double> ) operator() : .. C_F0>> : ( <double> : <double> ) ( <complex > : <complex > ) ( <LinearComb<MGauche. type :<Polymorphic> operator( : ( <LinearComb<MDroit. ) . ALL THE OPERATORS . type :<Polymorphic> operator( : ( <CDomainOfIntegration> : <Fem2D::Mesh>.. type :<Polymorphic> operator( : ( <double> : <double> ) ( <complex> : <complex> ) . type :<long> . type :<long *> .movemesh..imag. C_F0>> : <LinearComb<MDroit.max. <E_Array>. type :<Polymorphic> operator() : ( <double> : <complex> ) . ) operator() : <Fem2D::Mesh>. type :<Polymorphic> ( <CDomainOfIntegration> : . type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) ..int2d. type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>.. <double> ) ( <long> : <long>.label.B.intalledges. type :<Polymorphic> operator() : ( <double> : <double>. <long> ) . sinh. C_F0>> : . type :<long> .. type :<long *> . type :<Polymorphic> operator() : ( <double> : <complex> ) .pow. type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) .readmesh. type :<Fem2D::QuadratureFormular> .nuEdge. type :<double> .318 .savemesh. type :<Fem2D::QuadratureFormular> qf1pTlump.plot.sqrt. <double> ) ( <complex> : <complex>. type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) . type :<Fem2D::QuadratureFormular> qf3pE. C_F0>> ) operator() : .pi. type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>. type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <string> ) . type :<Fem2D::QuadratureFormular> qf2pE. type :<Fem2D::QuadratureFormular> qf2pT4P1. type :<Polymorphic> operator( : ( <LinearComb<MDroit.sin.otherside. ) .. <long> ) ..on. type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <long>.. type :<Polymorphic> ( <long> : .square. ) . C_F0>> ) <LinearComb<MGauche. type :<Polymorphic> operator() : ( <double> : <double> ) ( <complex> : <complex> ) . GRAMMAR <LinearComb<MDroit. type :<Polymorphic> operator() : ( <double> : <double>.region. type :<Fem2D::QuadratureFormular1d> qf1pT. type :<Polymorphic> operator() : ( <BC_set<double>> : <long>. <complex> ) qf1pE.. type :<Fem2D::QuadratureFormular1d> qf2pT. C_F0>> : ( <LinearComb<MGauche.real. ) APPENDIX B. <string>.. type :<Fem2D::QuadratureFormular1d> qf5pT. type :<double *> . type :<long *> wait. <bool> ) verbosity. <long>. type :<bool> . type :<Polymorphic> operator() : ( <double> : <double> ) .trunc. type :<bool *> x.3. type :<Polymorphic> operator() : ( <Fem2D::Mesh> : <Fem2D::Mesh>.tan.B. <E_Array> ) 319 . ALL THE OPERATORS ( <Fem2D::Mesh> : <long>.true. type :<double *> y. type :<double *> z. 320 APPENDIX B. GRAMMAR . 1 A first example myfunction. assume that you are in a shell window (a cygwin window under Windows) in the directory example++-load. C. Note C. It is agood idea to. Remark that in the sub directory include they are all the FreeFem++ include file to make the link with FreeFem++.so" or the prefix ". Windows Install the cygwin environnent or the mingw MacOs Install the developer tools xcode on the apple DVD Linux/Unix Install the correct compiler (gcc for instance) Now. Windows and MacOS X 10. The compilation of your module: the script ff-c++ compiles and makes the link with FreeFem++. and the suffix ". • Under Windows.so twill be loaded so it must be either in the search directory of routine dlopen (see the environment variable $LD_LIBRARY_PATH or in the current directory. The file xxx. but be careful.Appendix C Dynamical link Now. first try the example load. y current value. 321 .dll will be loaded so it must be in the loadLibary search directory which includes the directory of the application. the file xxx./" is automatically added. but using the x.edp in directory example++-load. it’s possible to add built-in functionnalites in FreeFem++ under the three environnents Linux. You will need to install a c++ compiler (generally g++/gcc compiler) to compile your function.3 or newer.1 If you try to load dynamically a file with command load "xxx" • Under unix (Linux or MacOs). the script has no way to known if you try to compile for a pure Windows environment or for a cygwin environment so to build the load module under cygwin you must add the -cygwin parameter.cpp The following defines a new function call myfunction with no parameter. y. func f.} // }. } Now the Problem is to build the link with FreeFem++. // A class build the link with FreeFem++ // generaly this class are already in AFunction. to do that we need two classes.P. one to call the function myfunction All FreeFem++ evaluable expression must be a struct/class C++ which derive from E F0. public: // the function which build the FreeFem++ byte code E_F0 * code(const basicAC_F0 & ) const { return new E_F0_F(f). normal .y. I have no simple function with no parameter // in FreeFem++ depending of the mesh.hpp" #include "MeshPoint.322 APPENDIX C.hpp" #include "rgraph. double myfunction(Stack stack) { // to get FreeFem++ data MeshPoint &mp= *MeshPointStack(stack).hpp" #include "FESpace. value double x= mp.P. func f. but if they derive from E F0mps the expression depends of the mesh position. DYNAMICAL LINK #include <iostream> #include <cfloat> using namespace std.} // the constructor to say ff is a function without parameter // . // the pointeur to the fnction myfunction E_F0_F(func ff) : f(ff) {} // the operator evaluation in FreeFem++ AnyType operator()(Stack stack) const {return SetAny<R>( f(stack)) .hpp but unfortunatly. typedef R (*func)(Stack ) . // the struct to get x. #include "error. return sin(x)*cos(y).hpp" #include "AFunction. // get the current x value double y= mp. // get the current y value // cout << "x = " << x << " y=" << y << endl.x.hpp" #include "RNM.hpp" using namespace Fem2D.hpp" #include "fem. and for more details see [12]. By default this expression does not depend of the mesh position. // template<class R> class OneOperator0s : public OneOperator { the class to defined a evaluated a new function It must devive from E F0 if it is mesh independent // or from E F0mps if it is mesh dependent class E_F0_F :public E_F0mps { public: typedef R (*func)(Stack stack) . Nb of edges on Mortars = 0 Nb of edges on Boundary = 20. .05s. } LOADFUNC(init). to do that include : void init(){ Global.4800028 (date Tue Oct 4 11:56:46 CEST 2005) file : load.o -o . size :71524 Bien: On a fini Normalement Under Windows.46945e-18s CodeAlloc : nb ptr 1394.edp -.tex. use the ff-c++ script : % ff-c++ myfunction.1102010/06/0411 : 27 : 24hechtExp 4 : 5 : load "myfunction" load: myfunction load: dlopen(. A FIRST EXAMPLE MYFUNCTION. v1.FreeFem++ v 1.max << endl.min << " " << uh[]. try the simple example under Linux or MacOS.5). launch FreeFem++ with the mouse (or ctrl O) on the example."(".P1).CPP 323 OneOperator0s(func }. neb = 20 Nb Of Nodes = 36 Nb of DF = 36 0 0.edp Load: lg_fem lg_mesh eigenvalue UMFPACK 1 : // Example of dynamic function load 2 : // -------------------------------3 : // Id : f reef em + +doc. It will be called automatically at load module time.dylib To. // warning do not forget () cout << uh[].1.new OneOperator0s<double>(myfunction)). execution -3./myfunction) = 0xb01cc0 6 7 8 9 10 : : : : : mesh Th=square(5.f(ff){} To finish we must add this new function in FreeFem++ table . To compile and link.cpp g++ -bundle -undefined dynamic_lookup -g myfunction. sizestack + 1024 =1240 ( 216 ) nb boundary edges 20 -. do % FreeFem++-nw load.name()]).Add("myfunction"./myfunction.C. // and returning a R ff): OneOperator(map_type[typeid(R). Vh uh=myfunction(). fespace Vh(Th.cpp g++ -c -g -Iinclude myfunction. nb triangles = 50 .841471 times: compile 0.square mesh : nb vertices =36 . √ √ ˆ ˆ So the classical discrete DFFT is f = dfft(f.tex. -.o -o .FreeFem++ v 1. m.. so n and m must be odd.a -I. ε)k+nl = j =0 j=0 fi+nj eε2πi(kj/n+lj /m) Remark: the value n is given by size(f )/m.org/../download/install/include export MACOSX_DEPLOYMENT_TARGET=10. DYNAMICAL LINK C./download/install/include dfft.fftw.3 g++ -c -Iinclude -I.2 Example: Discrete Fast Fourier Transform This will add FFT to FreeFem++.dylib) = 0x2b0c700 . To download and install under download/include just go in download/fftw and trymake. taken from http://www.. 1)/ n Remark: the 2D Laplace operator is √ m−1 n−1 ˆ f (x.1102010/06/0411 : 27 : 24hechtExp 4 : // Discret Fast Fourier Transform 5 : // ------------------------------6 : load "dfft" lood: init dfft load: dlopen(dfft.edp Load: lg_fem cadna lg_mesh eigenvalue UMFPACK 1 : // Example of dynamic function load 2 : // -------------------------------3 : // Id : f reef em + +doc.4800028 (date Mon Oct 10 16:53:28 EEST 2005) file : dfft.cpp . The 1D dfft (fast discret fourier transform) for a simple array f of size n is defined by the following formula n−1 dfft(f.cpp g++ -bundle -undefined dynamic_lookup dfft./download/install/lib/libfftw3. Compile to build a new library % ff-c++ dfft. ε)k = j=0 fi eε2πikj/n The 2D DFFT for an array of size N = n × m is m−1 n−1 dfft(f./download/install/lib/libfftw3. l l And to have a real function we need all modes to be symmetric around zero.324 APPENDIX C. v1.dylib . and the numbering is row-major order.a To test . y) = 1/ N fi+nj eε2πi(xj+yj ) j =0 j=0 and we have fk+nl = f (k/n./dfft. l/m) So ˜ ∆fkl = −((2π)2 ((k)2 + (˜ 2 ))fkl l) ˜ ˜ where k = k if k ≤ n/2 else k = k − n and ˜ = l if l ≤ m/2 else ˜ = l − m. −1)/ n and the reverse dFFT f = dfft(f .. ny=16.2.v.y) is 12 : // given by i = x/nx + nx ∗ y/ny 13 : 14 : fespace Vh(Th. 17 : Vh<complex> u=f1.m is in row-major order ann array n. cout << " err = " << err << endl. 27 : v = f1-u.P1).NbUndelPtr 2815 Alloc: 111320 NbPtr 6368 -. Vh<complex> fhat.(ny-1)*y/ny]).5?x*nx:(x-1)*nx)) + square((y<0. // the solution w = real(ue)./ wij[].C. 19 : 20 : 21 : Vh ur.ny/2 // thank to the operator ?: wij = square(2.ny.ny-1. // the exact solution plot(w. wait=1).min) .ny.-1).cmm=" ue ". // 34 : func ue = +(1.-1). assert( err < 1e-6). 25 : u[]=dfft(v[].ur. 9 : // warning the Fourier space is not exactly the unite square due to periodic conditions 10 : mesh Th=square(nx-1.ny. 26 : u[] /= complex(N).ui. sizestack + 1024 =3544 ( 2520 ) ----------CheckPtr:-----init execution -----. // 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 : : : : : : : : : : : : : : : : : : : : Vh<complex> ff = f.))*cos(3*2*pi*x)*cos(2*2*pi*y).+1). 11 : // warring the numbering is of the vertices (x.max << " " << v[].m is 23 : // store j + m* i ( the transpose of the square numbering ) 24 : v[]=dfft(u[].square mesh : nb vertices =512 . // u[]=dfft(fhat[]. 18 : Vh w=f1. u[] /= complex(N). 15 : 16 : func f1 = cos(2*x*2*pi)*cos(3*y*2*pi). w[] -= ur[]. nx/2 and -ny/2.min << endl. 30 : // ------. EXAMPLE: DISCRETE FAST FOURIER TRANSFORM 325 7 : 8 : int nx=32. wij[][0] = 1e-5. 28 : cout << " diff = "<< v[].max) < 1e-10 && norm(v[].min) < 1e-10) . 22 : // in dfft the matrix n. fhat[] = dfft(ff[].5?y*ny:(y-1)*ny))). Vh<complex> wij.*pi)*(square(( x<0.N=nx*ny. nb boundary edges 92 .ny. ur = real(u).1).a more hard example ---31 : // Lapacien en FFT 32 : // −∆u = f with biperiodic condition 33 : func f = cos(3*2*pi*x)*cos(2*2*pi*y).max)+abs(w[]. // warning in fact we take mode between -nx/2.value=1 ./(square(2*pi)*13. // array sub real err= abs(w[]. // to remove div / 0 fhat[] = fhat[].[(nx-1)*x/nx. 29 : assert( norm(v[]. nb triangles = 930 . hpp" #include "AFunction.--.hpp" // remove problem of include #undef HAVE_LIBUMFPACK #undef HAVE_CADNA #include "MatriceCreuse_tpl.hpp" #include "lgsolver.--.hpp" #include "MeshPoint.88178e-16. Expression emat. size :76084 Bien: On a fini Normalement CheckPtr:Nb of undelete pointer is 2748 last 114 CheckPtr:Max Memory used 228.--.1102010/06/0411 : 27 : 24hechtExp // compile and link with ff-c++ mat dervieux.err = 3.expu1.531 kbytes Memory undelete 105020 C.--.hpp" #include "RNM.expu2. MatrixUpWind0(const basicAC_F0 & args) { .tex. #include "error.6104e-12 times: compile 0.-3.edp // Implementation of P1-P0 FVM-FEM --------------------------------------------------------------------// Id : f reef em + +doc.hpp" #include "problem. DYNAMICAL LINK Nb of edges on Mortars = 0 Nb of edges on Boundary = 92.e.diff = (8.cpp (i.expTh. v1. execution 2. neb = 92 Nb Of Nodes = 512 Nb of DF = 512 0x2d383d8 -1 16 512 n: 16 m:32 dfft 0x402bc08 = 0x4028208 n = 16 32 sign = -1 --.3 Load Module for Dervieux’ P0-P1 Finite Volume Method the associed edp file is examples++-load/convect dervieux.---0x2d37ff8 1 16 512 n: 16 m:32 dfft 0x4028208 = 0x402de08 n = 16 32 sign = 1 --.-----.--.326 APPENDIX C.05s ----------CheckPtr:-----end execution -.hpp" // class MatrixUpWind0 : public E_F0mps { public: typedef Matrice_Creuse<R> * Result.---0x2d3ae08 1 16 512 n: 16 m:32 dfft 0x4028208 = 0x402bc08 n = 16 32 sign = 1 --.expc.3.66134e-16.13s.--.5651e-16) (-6.38216e-16) 0x2d3cfb8 -1 16 512 n: 16 m:32 dfft 0x402de08 = 0x402bc08 n = 16 32 sign = -1 --.NbUndelPtr 2815 Alloc: 111320 NbPtr 26950 CodeAlloc : nb ptr 1693.hpp" #include "rgraph.hpp" #include "lgfem. the file name without .cpp) #include <iostream> #include <cfloat> #include <cmath> using namespace std. [u1. double u[2]. a[ip][i]-=unL.i++) for(int j=0. . ffassert(pTh). Mesh * pTh = GetAny<pmesh>((*expTh)(stack)).} else{ a[i][ip] += unL. if(unL>0) { a[i][i] += unL. atype<pmesh>(). ipp =(ip+1)%3.} } } return 1. // second exp of the array (must be a double) } ˜MatrixUpWind0(){ } static ArrayOfaType typeargs() { return ArrayOfaType(atype<Matrice_Creuse<R>*>(). MeshPoint *mp(MeshPointStack(stack)) . b] const E_Array * a= dynamic_cast<const E_Array*>((Expression) args[3]).atype<E_Array>()). double where[3] ) { // computes matrix a on a triangle for the Dervieux FVM for(int i=0.i<3.j<3. emat =args[0]. a[ip][ip]+=unL.C.u2])"). for(int i=0. double unL =-((q[ip][1]+q[i][1]-2*q[ipp][1])*u[0] -(q[ip][0]+q[i][0]-2*q[ipp][0])*u[1])/6.SetNameParam(). // fist exp of the array (must be a double) expu2= CastTo<double>((*a)[1]). double) 327 // // // the matrix expression a the expression to get the mesh the expression to get c (must be a // a array expression [ a. int fvmP1P0(double q[3][2]. int err =0. if (a->size() != 2) CompileError("syntax: MatrixUpWind0(Th.} if(where[i]&&where[ip]){ // this is a boundary edge unL=((q[ip][1]-q[i][1])*u[0] -(q[ip][0]-q[i][0])*u[1])/2. LOAD MODULE FOR DERVIEUX’ P0-P1 FINITE VOLUME METHOD args.i++){ int ip = (i+1)%3.3. expc = CastTo<double>(args[2]). } // the evaluation routine AnyType MatrixUpWind0::operator()(Stack stack) const { Matrice_Creuse<R> * sparse_mat =GetAny<Matrice_Creuse<R>* >((*emat)(stack)).double c[3]. if(unL>0) { a[i][i]+=unL. expTh= to<pmesh>(args[1]).atype<double>().rhi.} AnyType operator()(Stack s) const .} static E_F0 * f(const basicAC_F0 & args){ return new MatrixUpWind0(args). MatriceMorse<R> * amorse =0. }. mps=*mp. Mesh & Th (*pTh). double a[3][3].i<3. a[ip][ip]-=unL. expu1= CastTo<double>((*a)[0]).j++) a[i][j]=0. double q[3][2]= { { A.iv++) { int i=Th(it.&C(K[2]).K.K(Pt).K. u[0] = GetAny< R>( (*expu1)(stack) ) .lab). const Vertex & A(K[0]).ii[j])]+=a[i][j].nv.x.y}. sparse_mat->A.where) ) { for (int i=0.x. sparse_mat->typemat=(amorse->n == amorse->m) ? TypeSolveMat(TypeSolveMat::GMRES) : TypeSolveMat(TypeSolveMat::NONESQUARE).nv. if(verbosity>3) { cout << " return sparse_mat. where[3]={A.k++) { const Triangle & K(Th[k]).Pt.c.{B. if ( cc[i]==infini) { mp->setP(&Th. DYNAMICAL LINK // if nuset the set for (int k=0.A.iv<3.a. R2 Pt(1.i++) for (int j=0.Th.328 { map< pair<int.B. u[1] = GetAny< R>( (*expu2)(stack) ) .cc[ii[1]].x. double a[3][3]. } } APPENDIX C. if (fvmP1P0(q.lab}. sparse_mat->pVh=0.j++) if (fabs(a[i][j]) >= 1e-30) { Aij[make_pair(ii[i]. cc=infini./3.nt.u.).false).{C.C. } void init() { cout << " lood: init Mat Chacon " << endl..master(amorse)./3.Aij.lab.k<Th. // coordinates of 3 vertices (input) double c[3]={cc[ii[0]]. R> Aij.iv).Th(C)}.it<Th.int>.it.it++) for (int iv=0. double infini=DBL_MAX.cc[ii[2]]}.nt.y} } .y} .B.1. // none square matrice (morse) *mp=mps. &B(K[1]). KN<double> cc(Th. cc[i]=GetAny<double>((*expc)(stack)). Th(B).lab.nv). R u[2].i<3. int ii[3] ={ Th(A).} . } sparse_mat->pUh=0.iv). for (int it=0. End Build MatrixUpWind : " << endl. MeshPointStack(stack)->set(Th. } } } amorse= new MatriceMorse<R>(Th.j<3.C. 3 i i i+1 i+2 br ∀K ∈ Th . u|K ∈ PK } with notation 4 = 1."(". Math.hpp" #include "rgraph. // // // // ----------------------. new OneOperatorCode<MatrixUpWind0 >( )). Comp.C.Add("MatUpWind0".2 the canonical basis of R2 and nK the outer normal of triangle K opposite to vertex k k. we add two new finite elements examples in the directory examples++-load. MORE ON ADDING A NEW FINITE ELEMENT Global.2. decembre 2005 // ------------// See Bernardi. } LOADFUNC(init).h" ----------------------- .hpp" #include "AddNewFE. 5 = 2 and where λK are the barycentric coordinates of the triangle K.hpp" #include "FESpace. The finite element space Vh is Vh = {u ∈ H 1 (Ω)2 .hpp" using namespace std.hpp" #include "fem. 329 C.related files: to check and validate : testFE. i (ek )k=1. The Bernardi-Raugel Element The Bernardi-Raugel finite element is meant to solve the br Navier Stokes equations in u. #include "RNM. // The P2BR finite element : the Bernadi Raugel Finite Element // F. 44.4. the velocity space PK is minimal to prove the inf-sup condition with piecewise constant pressure by triangle. Hecht.hpp" #include "AFunction. G. p formulation.4 More on Adding a new finite element First read the section 13 of the appendix. C.edp to get a real example : NSP2BRP0.2 ∪ {λK λK nK }i=1..k=1. // It is a 2d coupled FE // the Polynomial space is P 12 + 3 normals bubbles edges function (P2 ) // the degree of freedom is 6 values at of the 2 componants at the 3 vertices // and the 3 flux on the 3 edges // So 9 degrees of freedom and N= 2. 71-79 (1985).2.edp -----------------------------------------------------------// #include "error.3. where br PK = span{λK ek }i=1. Raugel.: Analysis of some finite elements for the Stokes problem. 0.. 0. 3. v[k++]= N.i<3. v[k++]= N.const R2 &P. TypeOfFE { public: TypeOfFE_P2BRLagrange(): TypeOfFE(6+3+0.x. 6+3*(2+2). 0.0.0 }.7.0. 0.4.5.EdgeOrientation(i)*0. DYNAMICAL LINK class TypeOfFE_P2BRLagrange : public static int Data[].5.const Triangle & K. 2. 0.T).KN_<double> & v) const { const Triangle & T(K. 0. // on what nu df on node node of df int TypeOfFE_P2BRLagrange::Data[]={ 0..2. 6.x.1.0. // coef pour les 3 sommets fois le 2 composantes for (int i=0.2. v[k++]= N. 4.5. 2. } .const Mesh & . 0..0.. 0.8. 0.5 . 1. // np point to build interpolation 0) { . 2.330 namespace Fem2D { APPENDIX C. 4.1.0. void TypeOfFE_P2BRLagrange::Pi_h_alpha(const baseFElement & K. // nb coef to build interpolation 9. // integration sur les aretes for (int i=0.1.perp()).const R2 & P.4.const Triangle & K. 1. void TypeOfFE_P2BRLagrange::Pi_h_alpha(const baseFElement & K.y.RNMK_ & val) const { . 1.i++) v[k++]=1. } } void TypeOfFE_P2BRLagrange::FB(const bool * whatd. *= T. RNMK_ & val) const.0.3.0.1.y. // to long see the source } void FB(const bool * whatd.0. 3.1. 2. v[k++]= N. 0. Data.1.0. // to long see the source } N ..i++) { R2 N(T.KN_<double> & v) const..Edge(i).i<6. 0. const Mesh & Th. int k=0. y1) = " << dx(a1)(x1. // --.0) ) < 1e-5).max < 1e-9 && c1[].h) ) < 1e-5).i) << endl.y1+hy)-f(x1-hx. plot([a1. abs(dy(a1)(x1. fespace Vh(Th.b1[]. abs(dy(a2)(x1.1. abs(dx(a2)(x1.0) ) < 1e-5). h=1e-7.i<Vh. for (int i=0.++i) cout << i << " " << Vh(0. real x1=0. // now adding FE in FreeFEm++ table static AddNewFE P2BR("P2BR".ndofK.y1) << " == " << DD(a1.C. c1[] = a1[] .max << " " << c1[].hy) ( (f(x1+hx.0.a2]. a1[][j]=1.&P2LagrangeP2BR). int it1=Th(x1.a2]. .h.i<Vh. abs(dx(a1)(x1.b2]. [b1.h) ) < 1e-5).y1). cout << " b = " << b1[] <<endl.y1)-DD(a2.P2BR). wait=1).end cooking } // end FEM2d namespace A way to check the finite element load "BernadiRaugel" // a macro the compute numerical derivative macro DD(f.0. Vh [a1.4.a2].++i) { a1[]=0. // check if the interpolation is correct // cout << assert( assert( assert( assert( } check the derivative and numerical derivative " dx(a1)(x1.min << endl. for (int i=0.nuTriangle.b2]=[a1. MORE ON ADDING A NEW FINITE ELEMENT // 331 ---.0) << endl.min > -1e-9).h.y1-hy))/(2*(hx+hy))) // mesh Th=square(1.9.[c1.c2]. cout << " a = " << a1[] <<endl. assert(c1[]. int j=Vh(it1.y1)-DD(a1.i).[b1. // // a bascis functions do the interpolation cout << " ---------" << i << " " << c1[].cooking to add the finite elemet to freefem table -------// a static variable to def the finite element static TypeOfFE_P2BRLagrange P2LagrangeP2BR.ndofK.y1=0.[10*(x+y/3).h.7.hx.10*(y-x/3)]).y1)-DD(a1.y1)-DD(a2. double version }.h" #include "slu_zdefs. the example in are correct/ Only a fast sketch of the code is given here. DYNAMICAL LINK A real example using this finite element. First the include files: #include <iostream> using namespace std. fespace Vh2(Th.P2BR).P0).. so the section is obsolete. Vh2 [v1.2 .h" #include "lex.332 APPENDIX C. template <> struct SuperLUDriver<double> { .cpp code from SuperLU.v2].hpp" #include "slu_ddefs.5 Add a new sparse solver Warning the sparse solver interface as been completely rewritten in version 3. The Morley Element See the example bilapMorley.cpp or NewSolve. Vh2 [u1. and we cannot plot isovalues of peacewise constant functions..hpp" #include "error. fespace Vh(Th. template <> struct SuperLUDriver<Complex> { . template <class R> struct SuperLUDriver { }. #include "rgraph.edp examples.up2]. just the begenning is change to load "BernadiRaugel" real s0=clock(). And the plot instruction is also changed because the pressure is constant..hpp" #include "AFunction.cpp.hpp" A small template driver to unified the double and Complex version..[up1.10). just a small modification of the NSP2P1. for details see the . Complex version ..hpp" // #include "MatriceCreuse_tpl.. C.u2]. mesh Th=square(10.edp. this is the transpose of the compressed column storage.epsilon.A)) { if(verbosity>9) cout << " BuildSolverSuperLU<Complex>" << endl. is the SLU NR format is the compressed row storage. So if AA is a MatriceMorse you have with SuperLU notation. 1. asub. return new SolveSuperLU<double>(*A. SLU_GE).const KN_<R> &b) const { .m.KN_<R> &x. SLU_GE).epsilon. m. a.5. } The two BuildSolverSuperLU function. m. n=AA. xa=AA.a. nnz.ds.Trans = TRANS. SLU_DN.ds. Create_Dense_Matrix(&B.strategy.tol_pivot.ds. .ds..ds.lg. ADD A NEW SPARSE SOLVER }. m. SLU_NC. Dtype_t R_SLU = SuperLUDriver<R>::R_SLU_T(). SLU_GE).tol_pivot.. R_SLU..C. asub=AA. To get vector infomation. .tgv. m=AA.ds..ds.n. to change the default sparse solver variable DefSparseSolver<double>::solver MatriceMorse<double>::VirtualSolver * BuildSolverSuperLU(DCL_ARG_SPARSE_SOLVER(double. SLU_DN. we have just to remark that the Morse Matrice the storage. n. m. return new SolveSuperLU<Complex>(*A.tol_ } The link to FreeFem++ class Init { public: Init().ds.. x. 333 To get Matrix value. options. Create_Dense_Matrix(&X.strategy. Create_CompCol_Matrix(&A. b. xa. R_SLU.tol } MatriceMorse<Complex>::VirtualSolver * BuildSolverSuperLU(DCL_ARG_SPARSE_SOLVER(Complex..A)) { if(verbosity>9) cout << " BuildSolverSuperLU<double>" << endl. a=AA. R_SLU. }.ds. to solver the linear solver x = A−1 b void Solver(const MatriceMorse<R> &AA. 1.tgv.cl. m.nbcoef. nnz=AA.ds. new OneOperator0<bool>(SetDefault)). and set the default solver to the new solver. DefSparseSolver<double>::solver =SparseMatSolver_R. TypeSolveMat::defaultvalue =TypeSolveMatdefaultvalue. } To add new function/name defaultsolver.defaulttoSuperLUin freefem++. DefSparseSolver<Complex>::SparseMatSolver SparseMatSolver_C. DefSparseSolver<double>::solver =BuildSolverSuperLU.Find("defaultsolver"). call this function: bool SetSuperLU() { if(verbosity>1) cout << " SetDefault sparse solver to SuperLU" << endl. Global.new OneOperator0<bool>(SetSuperLU)). just do: void init() { SparseMatSolver_R= DefSparseSolver<double>::solver. } To set the default solver to superLU.Add("defaultsolver". . To save the default solver type TypeSolveMat::TSolveMat TypeSolveMatdefaultvalue=TypeSolveMat::defaultvalue. if(verbosity>1) cout << "\n Add: SuperLU. . To reset to the default solver. TypeSolveMat::defaultvalue =TypeSolveMat::SparseSolver. DefSparseSolver<Complex>::solver =SparseMatSolver_C..Add("defaulttoSuperLU".NotNull() ) Global. DefSparseSolver<Complex>::solver =BuildSolverSuperLU. DefSparseSolver<double>::solver =BuildSolverSuperLU. // test if the name "defaultsolver" exist in freefem++ if(! Global. call this function: bool SetDefault() { if(verbosity>1) cout << " SetDefault sparse to default" << endl."(". DefSparseSolver<Complex>::solver =BuildSolverSuperLU. DYNAMICAL LINK To set the 2 default sparse solver double and complex: DefSparseSolver<double>::SparseMatSolver SparseMatSolver_R . TypeSolveMat::defaultvalue=TypeSolveMat::SparseSolver. defaultsolver defaultsolverSuperLU" << endl. } LOADFUNC(init)."(". SparseMatSolver_C= DefSparseSolver<Complex>::solver.334 APPENDIX C. [ 0. 0. real[int] xx = [ 4. [ 0. In directoy include do to have a correct version of SuperLu header due to mistake in case of inclusion of double and Complex version in the same file. x = Aˆ-1*b. 10].. cout << b << " " << xx << endl. b(4). b(4). 0. [ 0 .1. To compile the freefem++ load file of SuperLu with freefem do: some find like : ff-c++ SuperLU. . tar xvfz . ADD A NEW SPARSE SOLVER To compile superlu. 2.i<3. just do: 1.++i) { // if i == 0 then SuperLu solver // i == 1 then GMRES solver // i == 2 then Default solver { matrix A = [[ 0.0 .tar. 0. [ 4i.inc make 2.gz I will give a correct one to compile with freefm++. [ 0.0 directory $EDITOR make. set(A.gov/˜xiaoye/SuperLU/superlu_3. 2i.C. 0]]. complex[int] xx = [ 4i. for(int i=0.0/ -lsuperlu_ And to test the simple example: A example: load "SuperLU" verbosity=2. 0.0 package and do 335 curl http://crd. 3].gz go SuperLU_3. 0.0-include-ff. 0]].3i]. 1i. cout << x << endl.cpp -o supe -L$HOME/work/LinearSolver/SuperLU_3.tar. 0.solver=sparsesolver).3]. x(4). 0. 10].1i. 0]. 0.0.cpp. 3i]. [ 4.2i. b = A*xx.gz tar xvfz superlu_3.tar. 0]. 0.lbl.2./SuperLU_3. } { matrix<complex> A = [[ 0. 1. 0.0 . x(4).0.5. download the SuperLu 3. cout << b << " " << xx << endl.edp .336 b = A*xx.solver=sparsesolver). } if(i==0)defaulttoGMRES(). if(i==1)defaultsolver(). set(A. cout << x << endl. } APPENDIX C. x = Aˆ-1*b. DYNAMICAL LINK To Test do for exemple: FreeFem++ SuperLu. in any medium. You may copy and distribute verbatim copies of the Library’s complete source code as you receive it. 1. A ”library” means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.jussieu. You may charge a fee for the physical act of transferring a copy. Activities other than copying. Each licensee is addressed as ”you”. (Hereinafter. A ”work based on the Library” means either the Library or any derivative work under copyright law: that is to say. refers to any such software library or work which has been distributed under these terms. Programs in it were maintained by • Fr´d´ric hecht <Frederic. For a library. The ”Library”. 337 .fr> e e • Jacques Morice <[email protected]@upmc. and you may at your option offer warranty protection in exchange for a fee.fr> All its programs except files the comming from COOOL sofware (files in directory src/Algo) and the file mt19937ar. complete source code means all the source code for all modules it contains. a work containing the Library or a portion of it.cpp which may be redistributed under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2. plus any associated interface definition files. below. plus the scripts used to control compilation and installation of the library. either verbatim or with modifications and/or translated straightforwardly into another language. Whether that is true depends on what the Library does and what the program that uses the Library does. and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). they are outside its scope. translation is included without limitation in the term ”modification”. and distribute a copy of this License along with the Library. distribution and modification are not covered by this License. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called ”this License”). keep intact all the notices that refer to this License and to the absence of any warranty.) ”Source code” for a work means the preferred form of the work for making modifications to it. The act of running a program using the Library is not restricted.FreeFem++ LGPL License This is The FreeFem++ software. February 1999 GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING. DISTRIBUTION AND MODIFICATION 0. provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty. which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. (For example. But when you distribute the same sections as part of a whole which is a work based on the Library. You may copy and distribute the Library (or a portion or derivative of it. Therefore. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. . Once this change is made in a given copy. the square root function must still compute square roots. You may modify your copy or copies of the Library or any portion of it. DYNAMICAL LINK 2. then you must make a good faith effort to ensure that. then this License. so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. then you can specify that version instead if you wish. and its terms. it is irreversible for that copy. To do this. provided that you also meet all of these conditions: a) The modified work must itself be a software library. a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. the distribution of the whole must be on the terms of this License. in the event an application does not supply such function or table. rather. it is not the intent of this section to claim rights or contest your rights to work written entirely by you. In addition. Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it. Thus.) These requirements apply to the modified work as a whole. do not apply to those sections when you distribute them as separate works. instead of to this License. and performs whatever part of its purpose remains meaningful. version 2. and can be reasonably considered independent and separate works in themselves. 3. under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code. thus forming a work based on the Library. and thus to each and every part regardless of who wrote it. 4. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. you must alter all the notices that refer to this License. so that they refer to the ordinary GNU General Public License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared. other than as an argument passed when the facility is invoked. whose permissions for other licensees extend to the entire whole.338 APPENDIX C. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.) Do not make any other change in these notices. If identifiable sections of that work are not derived from the Library. the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. and copy and distribute such modifications or work under the terms of Section 1 above. the facility still operates. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. in isolation. The executable is therefore covered by this License. as well as a reference directing the user to the copy of this License. you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above). as long as the modified version is interface-compatible with the version that the work was made with. The threshold for this to be true is not precisely defined by law. and. As an exception to the Sections above. provided that the terms permit modification of the work for the customer’s own use and reverse engineering for debugging such modifications. if the user installs one. then the use of the object file is unrestricted.) b) Use a suitable shared library mechanism for linking with the Library. However. is called a ”work that uses the Library”. When a ”work that uses the Library” uses material from a header file that is part of the Library. If such an object file uses only numerical parameters. and therefore falls outside the scope of this License. rather than a ”work that uses the library”. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions. 6. then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code. if the work is a derivative of the Library. the object code for the work may be a derivative work of the Library even though the source code is not. Section 6 states terms for distribution of such executables. regardless of whether it is legally a derivative work. you must include the copyright notice for the Library among them. You must supply a copy of this License. is not a derivative work of the Library. Such a work. Any executables containing that work also fall under Section 6. 5. (Executables containing this object code plus portions of the Library will still fall under Section 6. you may also combine or link a ”work that uses the Library” with the Library to produce a work containing portions of the Library. A program that contains no derivative of any portion of the Library. and small macros and small inline functions (ten lines or less in length). Also. linking a ”work that uses the Library” with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library). but is designed to work with the Library by being compiled or linked with it.C. as object code and/or source code. rather than copying library functions into the executable. data structure layouts and accessors. and distribute that work under terms of your choice. and (2) will operate properly with a modified version of the library. you may distribute the object code for the work under the terms of Section 6. Whether this is true is especially significant if the work can be linked without the Library. or if the work is itself a library. even though third parties are not compelled to copy the source along with the object code. if the work is an executable linked with the Library. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License.5. with the complete machine-readable ”work that uses the Library”. whether or not they are linked directly with the Library itself.) Otherwise. so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. ADD A NEW SPARSE SOLVER 339 If distribution of object code is made by offering access to copy from a designated place. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user’s computer system. If the work during execution displays copyright notices. . the required form of the ”work that uses the Library” must include any data and utility programs needed for reproducing the executable from it. since you have not signed it. as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues). You are not responsible for enforcing compliance by third parties with this License. agreement or otherwise) that contradict the conditions of this License. and so on) of the operating system on which the executable runs. DYNAMICAL LINK c) Accompany the work with a written offer. Therefore. link with. by modifying or distributing the Library (or any work based on the Library). 7. For an executable. 8. You are not required to accept this License. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. they do . d) If distribution of the work is made by offering access to copy from a designated place. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. modify. as a special exception. provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted. These actions are prohibited by law if you do not accept this License. to give the same user the materials specified in Subsection 6a. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 11. kernel. You may not copy. uncombined with any other library facilities. and distribute such a combined library. the recipient automatically receives a license from the original licensor to copy. valid for at least three years. sublicense. distribute.340 APPENDIX C. offer equivalent access to copy the above specified materials from the same place. parties who have received copies. and explaining where to find the accompanying uncombined form of the same work. and all its terms and conditions for copying. conditions are imposed on you (whether by court order. unless that component itself accompanies the executable. the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler. However. modify. This must be distributed under the terms of the Sections above. or distribute the Library is void. sublicense. for a charge no more than the cost of performing this distribution. link with or modify the Library subject to these terms and conditions. Each time you redistribute the Library (or any work based on the Library). and will automatically terminate your rights under this License. However. Any attempt otherwise to copy. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License. However. or rights. link with. from you under this License will not have their licenses terminated so long as such parties remain in full compliance. or distribute the Library except as expressly provided under this License. nothing else grants you permission to modify or distribute the Library or its derivative works. you indicate your acceptance of this License to do so. If. You may not impose any further restrictions on the recipients’ exercise of the rights granted herein. 10. distributing or modifying the Library or works based on it. above. and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library. 9. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system. then as a consequence you may not distribute the Library at all. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. Each version is given a distinguishing version number. If any portion of this section is held invalid or unenforceable under any particular circumstance. If the Library does not specify a license version number. write to the author to ask for permission. this License incorporates the limitation as if written in the body of this License. the balance of the section is intended to apply. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations.C. NO WARRANTY 15. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY ”AS IS” WITHOUT WARRANTY OF ANY KIND. if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you. you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. but may differ in detail to address new problems or concerns. write to the Free Software Foundation. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. and the section as a whole is intended to apply in other circumstances. SHOULD THE LIBRARY PROVE DEFECTIVE. TO THE EXTENT PERMITTED BY APPLICABLE LAW. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these. the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. EITHER EXPRESSED OR IMPLIED. so that distribution is permitted only in or among countries not thus excluded. THERE IS NO WARRANTY FOR THE LIBRARY. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims. 14. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE. In such case. For software which is copyrighted by the Free Software Foundation. Such new versions will be similar in spirit to the present version. INCLUDING. this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. ADD A NEW SPARSE SOLVER 341 not excuse you from the conditions of this License. then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. For example. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces. BUT NOT LIMITED TO. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. we sometimes make exceptions for this. it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. . YOU ASSUME THE COST OF ALL NECESSARY SERVICING. If the Library specifies a version number of this License which applies to it and ”any later version”.5. 13. you may choose any version ever published by the Free Software Foundation. 12. INCLUDING ANY GENERAL. DYNAMICAL LINK REPAIR OR CORRECTION. EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER. OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE. SPECIAL. END OF TERMS AND CONDITIONS .342 APPENDIX C. BE LIABLE TO YOU FOR DAMAGES. INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE). pi.tanh. y. acos. log10. sin.sinh.cotanh. atan. asin. max. cotan. i. min. z. log.cosh. cos. tan. exp.Appendix D Keywords Main Keywords adaptmesh Cmatrix R3 bool border break buildmesh catch cin complex continue cout element else end fespace for func if ifstream include int intalledge load macro matrix mesh movemesh ofstream plot problem real return savemesh solve string try throw vertex varf while Second category of Keywords int1d int2d on square Third category of Keywords dx dy convect jump mean Fourth category of Keywords wait ps solver CG LU UMFPACK factorize init endl Other Reserved Words x. sqrt abs. 343 . 344 APPENDIX D. KEYWORDS . D. New York. e e [13] J. Computational Methods for Option Pricing.Hecht. Vol 36.caam. Note CRAS. Pironneau. Pironneau. Achdou and O.1. Hecht. K. Hecht.ufl. Springer-Verlag. Sorensen. Lehoucq. N°. Library Modulef . The mesh adapting software: bamg. Error bounds for finite element method.L. O.. George. Yang ARPACK Users’ Guide: Solution of Large-Scale Eigenvalue Problems with Implicitly Restarted Arnoldi Methods SIAM. [5] D. and C. NY. Prud’homme. 159 of Applied Mathematical Sciences. [8] F. Ern and J. Anal.Bibliography [1] R. freefem+ documentation. Discontinuous Galerkin methods for Friedrichs’ symmetric systems and Second-order PDEs. C. INRIA report 1998. Outils et algorithmes pour la m´thode des ´l´ments finis.rice. Lucquin. Babbuˇka. 16. ISBN 0-89871-407-9 // http://www. Universit´ e ee e Pierre et Marie Curie.A. (2005). O.fr/freefem [6] T.freefem.Hecht. F. math et Anal Num´r. SIAM monograph (2005). F. al.-L. Bernardi. Wiley 1996. Guermond. 345 . HdR. [10] A. http://www. O.edu/software/ARPACK/ [2] I. Numer. Math. Also : Superpositions for composite domains (to appear) [14] B. 322-333. Numer. on the web at http://www. Hecht.cise. 2004. Pironneau. on the web at ftp://www. vol. Lions. Pironneau: Introduction to Scientific Computing Wiley 1998. C. Ohtsuka. freefem documentation. Davis: Algorithm 8xx: UMFPACK V4. See also: Theory and Practice of Finite Elements. s [3] Y. 2002 pp 809-836. Dec 1998. SIAM J. France.inria-rocq/ modulef [11] A. Automatic triangulation. C++ Tools to construct our user-level language. Perronnet et.L. [4] D. Mod´l. B. freefem.org/freefemplus. INRIA.edu/ research/sparse/umfpack [7] P. 2003 (submitted for publication) http://www. Pironneau: Parallel Algorithms for boundary value problems. an unsymmetric-pattern multifrontal method TOMS. Bernardi. 1992 [9] F. O. [12] F. L. Hlavacek. Rodin. 1979. Glowinski and O. 303–315. Shamos Computational Geometry Springer series in Computer sciences. Wheeler. Preparata. Chichester. North-Holland. Dunod. Elsevier. [29] R. Vol. [27] L. 1993 [21] J. [22] M. pp. North-Holland. Iwanami Applied Math. and O. NY. Riviere. O. Prentice Hall. COOOL: a package of tools for writing optimization code and solving optimization problems. The C++ . Lions. IX..C. Deng. A priori error estimates for finite element methods based on discontinuous approximation spaces for elliptic problems. Wirth: Algorithms + Data Structures = Programs. Steger: The Chimera method of flow simulation. Numerical Methods for Nonlinear Variational Problems.). eds.Y. no. P. Pironneau and F. Springer. Pironneau. http://coool. et al. Numerical methods for the Stokes problem.-M: Mixed and Hybrid Methods. pp. Amsterdam. Oberwolfach Conf.Wiley & Sons. M. O. J. [31] R. L. Hecht: Theoretical and Numerical analysis of energy release rate in 2D fracture. Necas. M. UK. [30] R. Wences Gouveia. Addison-Wesley 1997. in ”Navier-Stokes Equations: Theory and Numerical Methods” (R. Ohtsuka. Numer.L. 1976 [25] Bison The GNU compiler-compiler documentation (on the web). F. Zienkiewicz eds. Workshop on applied CFD. 1991..II. ˇ ´ˇ [16] J. Simulation num´rique en C++. 243-264. SpringerVerlag. 2003.G. [19] R. Pironneau. August 19-23. 1984. V. Chapter 13 of Energy Methods in Finite Element Analysis. R. Tabata: Numerical solutions of partial differential equations II (in Japanese).346 BIBLIOGRAPHY [15] I.mines. Anal. New York. Hecht. Stroustrup. Third edition. 2003. 902–931 (electronic). Glowinski.edu [28] B. Finite Element Methods for Incompressible Viscous Flow. 3.Glowinski. Ciarlet and J. programming language. . August 1991. [26] B. [18] F. Handbook of Numerical Anaysis. eds. Roberts and Thomas J. e Paris. Thomasset: Implementation of finite element methods of Navier-Stokes Equations. E. Univ of Tennessee Space Institute. Mathematical theory of elastic and elasto-plastic bodies: An introduction..E. Rannacher: On Chorin’s projection method for the incompressible Navier-Stokes equations.. Glowinski. 1984. In Handbook of Numerical Analysis. Rautmann. INFORMATION 3 (2000). Vol. [17] K. 1981. 1992 [20] J. 1981 [24] N. Springer-Verlag.3-1176. Danaila. SIAM J. Girault. 39 (2001). Proc.. 1994 [23] F. Johnson.A.W. Wingate . 123-138(16). http:// ab-initio. N◦ . Shewchuk. Constitutive Models for Compressible Nonlinearly Elastic Materials with Limiting Chain Extensibility. Volume 77.BIBLIOGRAPHY 347 [32] C. A. M2AN.html . INRIA RT–0252. Austria a [42] Steven G. Raviart. Tetrahedral Mesh Generation by Delaunay Refinement Proceeding of the Fourteenth Anual Symposium on Computational Geometry (Minneapolis. 2001. Journal of Elasticity.R. A New Family of Mixed Finite Elements for Elasticity http://www. 2003. Thomas. Howison. 1984. 1983. [33] Kazufumi Ito.de [37] J. Dover. e e [36] Hang Si. Report-no: SAND2005-0034J. Thesis. Cambridge University Press (1995). Introduction a l’analyse num´rique des ´quations aux ` e e d´riv´es partielles. pp. [35] P. Hansen. Several new quadrature formulas for polynomial integration in the triangle . Willmott. and Karl Kunisch. The CMA Evolution Strategy. 2009. Number 2.lri.numa. J. The NLopt nonlinear-optimization package. G. pp 86–95.uni-linz. Ogden. http://xyz. [40] P. Taylor. [41] Astrid Sabine Sinwel. November 2004. B. vol 37.berlios. 1998. Bos.edu/nlopt [43] N.pdf. Saccomandi. A. Horgan. http://www. Masson.NA/0501496 [39] P. Dewynne : A student introduction to mathematical finance. L. Semi smooth newton methods for variational inequalities of the first kind . TetGen Users’ Guide: A quality Tetrahedral Mesh Generator and ThreeDimensional Delaunay Triangulator // http://tetgen. [34] R. [38] M. Non-Linear Elastic Deformations. P.at/Teaching/PhD/Finished/ sinwel-diss. J. pp 41-62. A fully automatic adaptive isotropic surface remeshing procedure.ac.mit.gov/format/math.fr/˜hansen/ cmaesintro. S. lanl. Minnesota). Frey.M. Johannes Kepler Universit¨t. 62 acosh. 99. 75 >>. 66 mesh. 55 append.*. 70 max. 161 . 66 ?:.max.l2. 58 area coordinate. 70 dot product. 38. 162 . 68 . 79 matrix. 99.linfty. 68 . 196 time dependent. 102 metric=. 68 ::. 67 column. 207 periodic./ += -= /= *= . 55 ’. 143.Index <<.* . 80 array. 66. 101 nomeshgeneration=. 102 maxsubdiv=. 67 line. 102 splitpbedge=. 66 = + . 19 acos. 102 ratio=. 68 FE function. 68 .* / . 101 periodic=. 79 area.*. 102 adj. 100 abserror=.min. 79 . 56. 77 fespace. 68 . 66 348 . 62 adaptation. 66. 103 powerin=. 201 cutoff=. 102 uniform. 73 =. 59 []. 159 argument. 77 quantile. 102 iso=. 91 alphanumeric. 102 anisomax=. 116.l1. 103 verbosity=. 101 inquire=. 103 nbjacoby=. 27 accuracy. 150. 101 nbvx=.edp. 153 ?:. 68 re. 77. 102 IsMetric=. 257 min. 68 . 101 hmax=. 101 rescaling=. 73 3d beam-3d. 67 renumbering.sum. 101 hmin=. 138 adaptmesh. 103 omega=. 73 . 101 nbsmooth=. 101 errg=. 239 . 66. 60 ARGV. 70 resize. 16. 102 err=. 101 keepbackvertices=. 65. 50. 102 splitin2=. 102 thetamax=./. 144 im. 334 degree of freedom. 91 bessel. 56 border. 177 cin. 121 buildmesh. 22 fixeborder. 78 broadcast. 334 defaulttoGMRES. 200 Dirichlet. 142 EigenValue. 164 asin. 19. 233 diagonal matrix. 34. 214 ivalue=. 74 dimKrylov=. 213 ncv=. 62 atanh. 178 BiLaplacien. 243 Discontinuous-Galerkin. 11 CMAES. 335 defaulttoSuperLU. 62 cout. 155. 62 atan2. 73. 213 maxit=. 148 buildlayers. 87 fixeborder=1. 100 cone. 58. 141 block matrix. 178 column. 82 Cauchy. 73 domain decomposition. 79 clock. 54. 167 continue. 63 BFGS. 205 divide term to term. 66 sum. 228. 324 diag. 154 discontinuous functions. 155 change. 79 defaultsolver. 230 cos. 54 ceil. 86. 236. 143 BDM1Ortho. 162 break. 60 connectivity. 257 bubble. 213 sigma=. 13 DFFT. 96 Cholesky. 58 Edge03d. 74. 70 compatibility condition. 87 catch. 213 349 . 179 seed=. 196 nbvx=. 25. 62 axisymmetric. 155 cube. 143 be. 154 compiler. 30 concatenation. 58 atan. 62 assert(). 46. 66 varf. 120 de Moivre’s formula. 56 complex. 62 cosh. 110 Characteristics-Galerkin. 60. 178 initialStdDev=. 237 dot product. 79 Crout. 13 BDM1. 120 conj. 213 sym=. 62 asinh. 214 nev=.INDEX sort. 78 convect. 33 displacement vector. 55 Complex. 27 backward Euler method. 58. 87 fixeborder=. 62 CG. 88 boundary condition. 73 Complex geometry. 60 default. 217 barycentric coordinates. 213 tol=. 77 dumptable.. 33 checkmovemesh. 213 rawvector=. 72 bool. 324 file am. 140 P1b. 91 elements. 141 P4. 90 finite element space. 79 erf. 90. 194 RT0. 13. 64. 63 erfc. 141 periodic=. 14. 13 P2BR. 58 endl. 13. 297. 94 functions. 46. 79 floor. 90. 173. 144 FEspace (int . 14 emptymesh. 144 FE-function. 13. 13. 143. 57 function tables. 13. 140 P1b3d. 140 P1nc. 142 Morley. 143 Edge03d. 150 complex. 13. 13. 173 ffNLOpt. 14 P1. 298 nopo. 295 ftq. 174 exit. 143 BDM1Ortho. 14 RT0Ortho. 57 label. 150 FE space. 13. 298 bamg. 257 exp. 142 RT1. 143. 58 false. 62 fluid. 13 P3. 95 endl. 143 ffmedit. 141 P4dc. 139 BDM1. 141 P2h. 213 eigenvalue problems.int ). 13. 167 nt. 14 P2b. 37 factorize=. 142 TDNNS1. 14. 299 mesh. 140 P13d. 58.350 value=. 140 P03d. 13. 226 for. 13. 78 Fourier. 63 geometry input . 142 RT03d. 28 func. 62 gamma. 36 fixed. 13. 297. 13. 13. 329 P2dc. 142 RT1Ortho. 26 Element. 213 vector=. 56. 142. 150 value. 141 P0. 63 exception. 62 expression optimization. 139 Finite Volume Methods. 297. 177 false. 58 hTriangle. 142 P2. 167 fespace. 141 P3dc. 13. 180 FFT. 140 P1dc. 73 n. 13. 61 global area. 64. 140 P23d. 58 FE function []. 13. 57 INDEX . 164 external C++ function. 13. 24 getline. 155. 58 cin. 167 ndof. 13. 295 data base. 13. 90 msh. 82 exec. 298 am fmt. 14. 298 amdba. 257 isotropic. 233 factorize=. 13 Helmholtz. 58 nuEdge. 264 quoting. 156 int3d. 67 l2. 175 precon=. 16. 8 init. 165 inside=. 57 searchMethod. 257 Isend. 81 quote. 57. 155 gnuplot. 57 N. 156 int2d. 63 line. 57 y. 70 LinearCG. 175 linfty. 25 label=. 37 matrix. 201 l1. 57. 74 constant. 333 macro. 62 LU. 80. 79 ill posed problems. 175 nbiter=. 97 Laplace operator. 249 parameter. 201 interpolate. 63 jn. 103 lagrangian. 71 block. 60 include. 81. 66. 72 diag. 35. 72 complex. 165 351 .INDEX lenEdge. 230 includepath. 8 loadpath. 85. 175 veps=. 156 intalledges. 36 init=. 166 interpolation. 153 Irecv. 81. 35 mass lumping. 26 im. 156. 58 region. 155 m. 67 imag. 177 =. 57 nTonEgde. 58 x. 212 interpolate. 201 level line. 8. 57 GMRES. 175 eps=. 63 jump. 86 label on the boundaries. 230 array. 152 true. 19 hat function. 173 graphics packages. 58 nuTriangle. 57. 58 volume. 155. 54 inside=. 63 j1. 156 initial condition. 67 load. 57 pi. 82 with parameter. 74. 46 hTriangle. 205 j0. 166 t=. 35 lgamma. 67 label. 175 eps=. 201 ifstream. 175 veps=. 41 without parameter. 166 op=. 166 int. 62 log10. 175 LinearGMRES. 57. 19 lenEdge. 175 precon=. 56 int1d. 8 log. 175 nbiter=. 57 z. 255 mpiLXOR. 255 mpiComm. 255 mpiMIN. 255 mpiReduce. 257 mpiAllReduce. 163 precon=. 256 mpisize. 113 orientation=. 98 Section of Engine. 163 MatUpWind0. 91 ndof. 255 mpiGather. 37 mesh3. 37 max. 255 mpiLAND. 257 mpiGroup. 163 tgv=. 128 order=. 174 meditff=. 91 +. 57 (). 256 mpiWtick. 72. 163 eps=. 255 mpiUndefined. 50. 66. 106 Cardioid. 105 Bezier curve. 256 mpiWtime. 255 mpiMAX. 73 resize. 256 mpirank. 109 adaptation. 157. 108 mesh adaptation. 255 mpiPROD. 19 modulus. 16 varf. 106 change. 163 solver=. 38. 59 mixed. 19 mesh. 91 3point bending. 99 beam. 114 movemesh23.352 renumbering. 255 mpiRank. 163 solver=factorize. 71. 105 regular. 60 Morley. 128 membrane. 114 ptmerge=. 257 mpiReduceScatter. 113 min. 257 mpiRequest. 163 tolpivot =. 111 []. 74 set. 114 transfo=. 255 mpiSUM. 228. 141 movemesh. 150. 255 mpiCommWorld. 77 minimum. 173. 54. 257 mpiAlltoall. 66 maximum. 72 solver=. 107 Smiling face. 158 INDEX . 110 connectivity. 106 Cassini Egg. 57. 230 nbcoef. 230 stiffness matrix. 2 medit. 256 mpiBXOR. 103 V-shape cut. 255 mpiBarrier. 255 mpiWait. 107 uniform. 128 save=. 257 mpiSize. 73. 28 mixed Dirichlet Neumann. 59 mean. 96. 91 NACA0012. 256 multi-physics system. 30 multiple meshes. 167 ndofK. 158 n. 167 Neumann. 255 mpiBAND. 255 mpiScatter. 255 mpiLOR. 114 mpiAllgather. 108 U-shape channel. 30 N. 333 nbe. 333 Navier-Stokes. 257 mpiAnySource. 79 precon=. 257 processorblock. 167 nuTriangle. 163. 58 nuEdge. 141 P4. 170 value=. 156. 58 plot. 256. 140 P1. 230 qft=. 139. 60 pow. 156 init=. 175 nbiter=. 256 product Hermitian dot. 57 P0. 157 intersection. 159 qfV=. 140 P1dc. 169 aspectratio=. 73 P. 164 outer product. 309 nTonEdge. 175 veps=. 156 solver=. 153 eps=. 73. 140 P2BR. 79 on. 160 quadrature: qf5pT. 309 ofstream. 156 precon=. 167. 324 normal. 170 grey=. 156 tolpivotsym =. 141 P3. 70. 156 strategy =.INDEX Newton. 156. 141 P3dc. 196 pi. 194 3d. 170 nbiso=. 27 norm. 57. 156 tolpivot =. 170 dim=. 141 P4dc. 170 mesh. 27 periodic. 91 polar. 79 nt. 170 border. 170 ps=. 212 NLCG. 57 nv. 167 number of element. 73 dot. 170 cut. 170 point region. 140 P1nc. 229 scalar. 170 varrow=. 160 353 . 58 number of degrees of freedom. 79 noshowpos. 231 problem. 177 eps=. 170 hsv=. 142 P2dc. 158 noshowbase. 62 precision. 202 qforder=. 88 boundary=. 77 outer. 170 cmm=. 73 term to term. 141 parabolic. 164. 170 coef=. 163 tgv=. 35. 170 viso=. 73 qfnbpE=. 35. 178. 91 triange. 170 bb=. 170 bw=. 155. 142 P2. 35. 13 non-homogeneous Dirichlet. 19 nonlinear. 30 nonlinear problem. 88 nbarrow=. 79 append. 36. 163 processor. 140 P1b. 175 nodes. 157 optimize=. 156. 62 solve. 79 searchMethod. 257 set. 103 splitmesh. 156. 85 region. 160 quadrature:qf2pE. 156. 156 tolpivot=. 66. 160 quadrature:qf1pTlump. 16. 158 quadrature:qf5pE. 155 Crout. 155 split=. 177 CG. 159 quadrature:qf7pT. 160 quadrature:qfV1. 156 init=. 62 singularity. 63 randreal2. 56. 63 re. 196 real. 163 tgv=. 28. 74 Reusable matrices. 79 showpos. 160.354 quadrature: qfV5. 142 RT1. 66. 158 quadrature:qf5pT. 91. 157. 152 sec:Plot. 257 Send. 57. 63 randreal3. 99 sinh. 63 randint32. 161 quadrature:qfV5. 159 quadrature:qfe=. 57. 161 quadrature:qf1pE. 159 quadrature:qf1pElump. 86 INDEX . 72 showbase. 73 precon=. 161 quadrature:qforder=. 201 flags=. 142 RT0Ortho. 161 quadrature:qfV2. 89. 156 solver=. 70 resize. 60 rectangle. 155 sparsesolver. 158 RT0. 159 quadrature:qf4pE. 63 randreal53. 161 quadrature:qfV. 160 quantile. 155 Cholesky. 155 LU. 156 linear system. 169 Secv. 142 savemesh. 111 readmesh3. 127 schwarz. 236. 161 quadrature:qfV1lump. 155 UMFPACK. 63 randinit. 30 renumbering. 63 random. 66. 257 scientific. 155 GMRES. 144 sparsesolver. 161 quadrature:qft=. 159 quadrature:qf2pT. 30 rand. 228 rint. 62 Robin. 36 matrix. 237 sin. 163 solver=. 161 quadrature:default. 85. 156 tolpivotsym=. 100. 160 quadrature:qf3pE. 243 region indicator. 90 readmesh. 142 RT1Ortho. 160. 104 square. 111 savesol order=. 63 randreal1. 153 eps=. 159 quadrature:qf1pT. 70 radiation. 154. 63 randint31. 156 strategy=. 160. 160 quadrature:qf2pT4P1. 79 shurr. 155 sort. 89. 67 read files. 160 quadrature:qf9pT. 163 optimize=. 206 BlackSchol. 24 true. 20 veps=.edp. 234 StokesUzawa.edp. 112 holelist=. 8 version. 177 verbosity. 86 Stokes. 155 upwinding. 230 strain tensor. 194 periodic4bis. 112 nbofregions=. 230 array. 90 Schwarz-gc. 196 readmesh. 112 tetgconvexhull.edp. 222 fluidStruct. 61 subdomains. 156 absolue.INDEX label=. 230 periodic. 112 switch=. 58 trunc. 61 find.edp. 82 tutorial LaplaceRT. 58 vertex .edp.edp. 103 split=. 156. 112 nboffacetcl=. 115 nboffacetcl=. 92 label.edp. 140 UMFPACK. 314 triangle []. 238 Schwarz-no-overlap. as well as read and write. 92 355 region. 157 tolpivot=. 16. 92 triangulate. 115 facetcl=. 236 Schwarz-overlap. 113 tetgtransfo. 194 periodic4.edp. 226 stokes. 202 aTutorial. 99 adaptindicatorP2. 115 tetgreconstruction. 112 facetcl=. 229 tutotial VI. 143 tetg.edp.edp. 115 regionlist=. 200 adapt. 91. 91 area. 115 refface=.edp. 56.edp. 205 strategy=. 57.edp. 66 tan. 94 triangulation files. 156 tolpivotsym=. 232 type of finite element. 112 regionlist=. 188 beam.edp. 33 varf. 156 transpose. 224 stop test. 62 Taylor-Hood.edp.edp. 55 variational formulation. 227 stress tensor. 115 tgamma. 164 variable.edp. 86 region=. 103 try.edp. 63 tgv= < 0. 73. 156 streamlines. 240 freeboundary. 5. 115 ptmerge=. 200 AdaptResidualErrorIndicator. 161. 163 matrix. 243 sum. 62 tanh.edp. 56 concatenation.edp. 205 string. 103 label=.edp. 223 convect. 229 TDNNS1. 115 switch=. 112 nbofholes=. 77. 97 NSUzawaCahouetChabart. 246 movemesh. 90 x. 58 weak form. 78 whoinElement. 57 INDEX . 63 z. 63 y1. 91 x. 20 while. 57 y. 57 y0. 63 yn. 91 y. 91 viso. 35 volume.356 label. 91 write files. . . It is the ideal tool for teaching the finite element method but it is also perfect for research to quickly test new ideas or multi-physics and complex applications. . Siam Chronicle. FreeFem++. ”. It has several triangular finite elements. . Impossible to put the book down. suspense right up to the last page. including discontinuous elements. for researchers at any level and for engineers also in financial mathematics. Tanh. ” A. . FreeFem++ has an advanced automatic mesh generator. Galerkine. Finally everything is there in FreeFem++ to prepare research quality reports: color display online with zooming and other features and postscript printouts. Editorial Reviews ”. B.” . in its last avatar. This book is ideal for students at Master level. . . . Hyperbolic and parabolic problems are solved by iterative algorithms prescribed by the user with the high level language of FreeFem++. capable of a posteriori mesh adaptation. it has a general purpose elliptic solver interfaced with fast algorithms such as the multi-frontal method UMFPACK. .Book Description Fruit of a long maturing process freefem. The chapter on discontinuous fems is so hilarious . . is a high level integrated development environment (IDE) for partial differential equations (PDE). .
Copyright © 2024 DOKUMEN.SITE Inc.