• Aucun résultat trouvé

Adaptation de maillages en parallèle

N/A
N/A
Protected

Academic year: 2021

Partager "Adaptation de maillages en parallèle"

Copied!
92
0
0

Texte intégral

(1)

Adaptation de maillages en parallèle

Mémoire

Christian Tye Gingras

Maîtrise en mathématiques Maître ès sciences (M.Sc.)

Québec, Canada

(2)
(3)

Résumé

L’adaptation de maillages anisotrope permet d’améliorer grandement la précision de méthodes numériques telles que la méthode des éléments finis. L’adaptation peut être très coûteuse en temps de calcul, mais montre un grand potentiel de parallélisation. Ce projet consiste à développer une implémentation parallèle de l’adaptation de maillages anisotrope basée sur des estimateurs métrique et hiérarchique. On introduit les notions de base de l’adaptation et de la programmation parallèle. On développe une stratégie de parallélisation applicable à la fois en deux dimensions et en trois dimensions. Enfin, on applique cette stratégie dans le cadre de la méthode des éléments finis dans le but d’en évaluer l’efficacité et la rapidité.

(4)
(5)

Table des matières

Résumé iii

Table des matières v

Liste des tableaux vii

Liste des figures ix

Remerciements xiii Introduction 1 1 Notions mathématiques 3 1.1 Introduction à la problématique . . . 3 1.2 Maillage . . . 5 1.3 Interpolation . . . 7 1.4 Espaces fonctionnels . . . 9 2 Adaptation de maillage 11 2.1 Estimateurs d’erreur . . . 11

2.2 Opérations d’adaptation sur les maillages . . . 15

3 La programmation parallèle 23 3.1 Motivation . . . 23

3.2 Définitions. . . 24

3.3 Architecture matérielle . . . 26

3.4 Principes de base de la programmation parallèle. . . 27

4 Parallélisation de l’adaptation 35 4.1 Chargement en mémoire de la solution éléments finis et du maillage et partition 35 4.2 Calcul des estimateurs d’erreur . . . 37

4.3 Séquence d’adaptation de maillage . . . 39

5 Résultats numériques 43 5.1 Analyse de l’efficacité de l’adaptation en parallèle . . . 44

Conclusion 71

(6)

A Programmation par passage de messages 77

(7)

Liste des tableaux

5.1 Accélération sur l’atteinte de la valeur de 1.80 × 10−6 en norme L2, adaptation P1

métrique sur la fonction f1, cible de 300 000 sommets . . . 54

5.2 Accélération sur l’atteinte de la valeur de 3 × 10−6 en norme L2, adaptation P1

hiérarchique sur la fonction f1, cible de 300 000 sommets . . . 54

5.3 Accélération sur l’atteinte de la valeur de 4 × 10−9 en norme L2, adaptation P2

métrique sur la fonction f1, cible de 300 000 sommets . . . 55

5.4 Accélération sur l’atteinte de la valeur de 6 × 10−9 en norme L2, adaptation P2

hiérarchique sur la fonction f1, cible de 300 000 sommets . . . 55

5.5 Accélération sur l’atteinte de la valeur de 1.5 × 10−4 en norme L2, adaptation P1

hiérarchique sur la fonction f2, cible de 300 000 sommets . . . 58

5.6 Accélération sur l’atteinte de la valeur de 2 × 10−6 en norme L2, adaptation P2

hiérarchique sur la fonction f2, cible de 300 000 sommets . . . 61

5.7 Accélération sur l’atteinte de la valeur de 5.6 × 10−6 en norme L2, adaptation P1

hiérarchique sur la fonction f3, cible de 300 000 sommets . . . 61

5.8 Accélération sur l’atteinte de la valeur de 6 × 10−9 en norme L2, adaptation P2

hiérarchique sur la fonction f3, cible de 300 000 sommets . . . 66

5.9 Accélération sur l’atteinte de la valeur de 2.5 × 10−5 en norme L2, adaptation P1

(8)
(9)

Liste des figures

1.1 Interpolation linéaire par morceaux . . . 4

1.2 Maillage régulier sur un domaine carré . . . 6

1.3 Maillage adapté pour une fonction gaussienne . . . 7

2.1 Coquilles autour d’un sommet et d’une arête . . . 15

2.2 Raffinement d’arête. . . 16

2.3 Suppression d’un noeud . . . 17

2.4 Retournements d’arête légal et illégal. . . 18

2.5 Déplacement de sommet . . . 19

3.1 Limites de l’accélération selon α . . . 25

3.2 Architecture à mémoire partagée . . . 27

3.3 Architecture à mémoire distribuée . . . 28

3.4 Parallélisation des traitements sur les entrées d’un vecteur . . . 31

3.5 Exemple de graphe des tâches . . . 32

4.1 Partition d’un maillage régulier sur quatre coeurs . . . 36

4.2 Calcul séquentiel des dérivées à l’interface . . . 39

4.3 Calcul des dérivées en parallèle sans communication . . . 39

4.4 Problème de raffinement à l’interface . . . 40

4.5 Maillage raffiné après une séquence d’adaptation à interface fixe, avant repartition-nement . . . 42

5.1 La fonction gaussienne f1 . . . 45

5.2 Accélération de l’adaptation P1 sur la fonction f1, cible de 300 000 sommets, sans pénalisation . . . 46

5.3 Adaptation P1 métrique sur la fonction f1, cible de 300 000 sommets, sans pénali-sation des arêtes d’interface . . . 48

5.4 Adaptation P1 métrique sur la fonction f1, cible de 300 000 sommets, avec pénali-sation des arêtes d’interface par poids de 100 . . . 49

5.5 Adaptation P1 hiérarchique sur la fonction f1, cible de 300 000 sommets, sans pé-nalisation des arêtes d’interface . . . 50

5.6 Adaptation P1 hiérarchique sur la fonction f1, cible de 300 000 sommets, avec pé-nalisation des arêtes d’interface par poids de 100 . . . 51

5.7 Morceau d’interface initial conservé pendant dix adaptations complètes, sans pé-nalisation des arêtes d’interface . . . 52

5.8 Comparaison entre la partition initiale d’un maillage et la deuxième partition suite à une séquence d’adaptation hiérarchique . . . 53

(10)

5.9 Adaptation P2 métrique sur la fonction f1, cible de 300 000 sommets, avec

pénali-sation des arêtes d’interface . . . 56

5.10 Adaptation P2 hiérarchique sur la fonction f1, cible de 300 000 sommets, avec pé-nalisation des arêtes d’interface . . . 57

5.11 La fonction f2 Mountains and valleys . . . 58

5.12 Adaptation P1 hiérarchique sur la fonction f2, cible de 300 000 sommets . . . 59

5.13 Adaptation P2 hiérarchique sur la fonction f2, cible de 300 000 sommets . . . 60

5.14 Évolution d’un maillage adapté en P1par 1 coeur sur la fonction f2, cible de 50 000 sommets . . . 62

5.15 Évolution d’un maillage adapté en P1par 8 coeurs sur la fonction f2, cible de 50 000 sommets . . . 63

5.16 Adaptation P1 hiérarchique sur la fonction f3, cible de 300 000 sommets . . . 64

5.17 Adaptation P2 hiérarchique sur la fonction f3, cible de 300 000 sommets . . . 65

5.18 Adaptation P1 métrique sur la fonction f4, cible de 200 000 sommets . . . 68

(11)
(12)
(13)

Remerciements

J’aimerais d’abord remercier toutes les personnes qui ont contribué de près ou de loin à mon projet de maîtrise. Sans votre aide, ce mémoire n’aurait pu voir le jour.

Mes calculs parallèles n’auraient pu avoir lieu sans l’aide du supercalculateur Colosse de l’Uni-versité Laval et de son équipe technique. Je tiens donc à remercier Calcul Québec et Calcul Canada de m’avoir offert l’accès à cette ressource informatique, ainsi que la Fondation Ca-nadienne pour l’Innovation (FCI), le Conseil de la Recherche en Sciences Naturelles et Génie (CRSNG), NanoQuébec et le Fonds Québécois de Recherche sur la Nature et les Technologies (FQRNT) pour leur financement dans l’exploitation de Colosse.

J’aimerais une fois de plus souligner l’apport financier du CRSNG et du FQRNT, cette fois-ci pour l’aide qui m’a été apportée sous forme de bourses d’études supérieures.

Merci à toute l’équipe du GIREF et en particulier aux professionnels de recherche. L’aide ap-portée par Cristian Tibirna, Jean Deteix et Éric Chamberland est très importante à l’ensemble des étudiants du laboratoire. En particulier, je n’aurais pas pu pousser mon projet si loin sans les conseils d’Éric.

Un grand merci à André Fortin, mon professeur et directeur de recherche, qui m’a donné ma chance et m’a guidé tout au long de mes études. Malgré la multitude de projets et de tâches à sa charge, j’ai toujours eu droit à son écoute attentive et à ses conseils avisés. Merci à tous les professeurs du département et en particulier José Urquiza et Robert Guénette, qui ont pris le temps de m’aider lorsque j’en avais besoin. Merci également aux examinateurs qui ont accepté d’évaluer mon mémoire.

J’aimerais aussi remercier tous mes compatriotes étudiants et mes amis avec qui j’ai eu beau-coup de plaisir pendant toutes ces années. Tous les bons moments passés en votre compagnie ont fait toute la différence pour moi. Je n’aurais pas pu accomplir autant de choses sans les petits bonheurs quotidiens et le soutien que vous m’avez apportés.

Finalement, merci à ma famille et surtout à mes parents. Je souhaite vous dédier ce mémoire, vous qui avez toujours été là pour moi. Votre support et vos encouragements sont à la base de mes accomplissements.

(14)
(15)

Introduction

La méthode des éléments finis est un incontournable dans la résolution numérique des équa-tions aux dérivées partielles. Ces équaéqua-tions possèdent de nombreuses applicaéqua-tions dans la modélisation de phénomènes naturels, notamment en physique, en chimie et en biologie, et nous sommes souvent intéressés à obtenir une approximation numérique précise de leur so-lution. Cependant, l’un des problèmes auxquels nous sommes rapidement confrontés lorsque nous voulons obtenir une bonne précision est la grande taille des systèmes à résoudre lorsqu’on emploie des maillages réguliers. En effet, la précision dépend du maillage utilisé par la mé-thode des éléments finis. Typiquement, plus ce maillage est fin, plus les résultats sont précis, mais plus les calculs sont coûteux. Par exemple, pour certaines équations, notamment celles de Navier-Stokes, un ordinateur standard peut nécessiter plusieurs jours pour compléter les cal-culs avec un niveau d’erreur acceptable. Dans ce genre de situation, l’adaptation de maillage, utilisée en conjonction avec la méthode des éléments finis, permet de contrôler l’erreur sur la solution approchée tout en limitant la taille du problème. Malgré tout, l’adaptation possède elle-même un coût non négligeable en temps de calcul.

Le Groupe Interdisciplinaire de Recherche en Élements Finis (GIREF), basé à l’Université Laval, possède une implémentation de la méthode des éléments finis et de certaines méthodes d’adaptation dans une librairie nommée MEF++. Au cours des dernières années, beaucoup d’efforts ont été déployés pour paralléliser la résolution des systèmes d’équations, étape néces-saire à l’obtention de la solution éléments finis. La parallélisation permet d’utiliser plusieurs unités de calcul simultanément pour résoudre un même problème, améliorant ainsi grande-ment la rapidité de l’exécution et ouvrant la voie à des calculs de grande envergure. Cepen-dant, l’adaptation de maillages n’était pas incluse dans cet effort de parallélisation malgré un besoin bien présent d’en améliorer les performances. Il était donc devenu possible d’utiliser des maillages de très grande taille pour résoudre des équations aux dérivées partielles, mais il était toujours impossible de raffiner ces maillages dans un temps raisonnable.

L’objectif de ce mémoire est de développer et d’étudier une première implémentation paral-lèle des principales méthodes d’adaptation utilisées au GIREF. Si cette implémentation nous permet d’obtenir rapidement des résultats satisfaisants, la porte sera ouverte à l’emploi de l’adaptation de maillage dans des problèmes éléments finis de grande envergure.

(16)

L’idée d’adapter des maillages en parallèle n’est pas nouvelle, puisque plusieurs auteurs se sont déjà penchés sur le problème, dont Mesri et al. [17], De Cougny et Shephard [9] et Alauzet et al. [2]. Ce qui sera nouveau dans notre projet est que nous paralléliserons les méthodes d’adaptation du GIREF, c’est-à-dire l’adaptation métrique développée par Habashi et al. [12] ainsi que l’adaptation hiérarchique développée par Bois et al. [4].

Les deux premiers chapitres concernent les bases théoriques des méthodes d’adaptation cou-ramment utilisées au GIREF. On aborde aussi, au chapitre 2, certains aspects de leur implé-mentation séquentielle, c’est-à-dire non parallèle. Au chapitre 3, le sujet de la programmation parallèle sera présenté. Nous y introduirons les outils qui s’offrent à nous ainsi que quelques techniques de base en programmation parallèle. Au chapitre 4, nous traiterons plus spécifi-quement de la parallélisation de l’algorithme d’adaptation. Au chapitre 5, nous montrerons et analyserons les résultats numériques obtenus par notre implémentation parallèle.

(17)

Chapitre 1

Notions mathématiques

Dans ce chapitre, plusieurs notions mathématiques seront introduites. Celles-ci nous seront utiles tout au long de ce mémoire puisqu’elles constitueront la base des différentes méthodes d’adaptation qui seront parallélisées.

1.1

Introduction à la problématique

Voyons tout d’abord un aperçu de ce qu’est l’adaptation de maillages. Considérons un domaine Ω ⊂ Rn, n = 1, 2, 3 fermé et borné. Soit u : Ω → R une fonction inconnue que l’on veut approximer par une fonction uh continue et polynomiale par morceaux. Pour construire cette

approximation, il nous est possible d’évaluer u en un nombre fini de points de notre choix et d’interpoler ces valeurs par morceaux.

Pour faire une analogie concrète, on peut imaginer que nous avons une barre de métal et que nous voulons estimer la distribution de la chaleur sur toute sa longueur. Le seul instrument dont nous disposons est un thermomètre qui indique la température ponctuellement. Comme il nous est impossible de tester directement la température en tout point de la barre, nous devrons la relever en un nombre limité de points, puis interpoler pour estimer la valeur partout sur la barre.

Bien évidemment, le choix des points d’évaluation possédera une importance capitale dans la qualité de l’approximation. On voudra choisir les points qui feront en sorte que l’erreur, ou la différence entre la fonction exacte et la fonction approximée, sera minimale. Tel qu’illustré à la figure 1.1, on observe que celle-ci dépend à la fois du nombre de points d’évaluation et de leur emplacement par rapport aux zones de fortes variations de la fonction.

Par contre, nous n’avons aucune connaissance à priori de la fonction u. Nous devrons donc utiliser des noeuds d’interpolation arbitraires pour en faire une première approximation. Grâce à ce que nous apprendrons de celle-ci, nous pourrons modifier le nombre et l’emplacement de ces noeuds pour que notre prochaine approximation soit plus précise.

(18)

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 x u(x) fonction analytique approximation

(a) 11 points uniformes

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 x u(x) fonction analytique approximation (b) 41 points uniformes 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 x u(x) fonction analytique approximation

(c) 11 points non uniformes

(19)

La question est maintenant de savoir comment nous y parviendrons. Pour réduire l’erreur à un niveau acceptable, la méthode la plus instinctive et facile à mettre en oeuvre serait d’augmenter le nombre de points d’approximation partout sur le domaine. Le problème avec cette approche est que, dans la plupart des applications, cela se traduit par une augmentation substantielle des temps de calcul. En effet, pour approximer les valeurs de la fonction recherchée, certaines méthodes telles que les volumes finis et les éléments finis nécessitent la résolution de systèmes d’équations dont la taille dépend du nombre de points d’approximation de la fonction. Si nous voulons réduire le temps de calcul tout en gardant un niveau d’erreur acceptable, il faut plutôt augmenter le nombre de sommets du maillage là où l’erreur est forte tout en le réduisant là où l’erreur est faible. C’est l’idée de base de l’adaptation de maillages.

Nous apprendrons au chapitre 2 à estimer l’erreur d’une approximation de fonction sur un maillage, mais nous aurons besoin pour cela d’introduire certaines notions mathématiques.

1.2

Maillage

Dans toute cette section, nous supposerons que nous avons un domaine fermé et borné Ω ⊂ Rn, n = 1, 2, 3 et une fonction u : Ω → R que l’on supposera suffisamment régulière. Nous y verrons des notions empruntées à la méthode des éléments finis et tirées de l’ouvrage de Ciarlet et Lunéville [7]. Celles-ci nous seront utiles tout au long de ce mémoire, puisque c’est aux éléments finis que nous appliquerons l’adaptation de maillages. C’est pourquoi nous supposerons, pour le reste du mémoire, que la fonction u est la solution analytique d’une équation aux dérivées partielles et uh une solution éléments finis qui l’approxime.

Définition 1.2.1. Un élément est un triplet de la forme (K, Σ, P ) où K est un fermé borné, Σ est l’ensemble des degrés de liberté de l’élément et P un espace de fonctions polynômiales.

Un degré de liberté est une inconnue dans un problème éléments finis et peut représenter, entre autres, la valeur de la fonction à approximer en un certain point de l’élément. Ces degrés de liberté sont utilisés dans l’approximation de u par une fonction de l’espace P que nous définirons plus loin. Pour la suite, nous utiliserons surtout le terme élément pour faire référence au sous-domaine qu’il occupe.

Définition 1.2.2. Un maillage est un assemblage d’éléments respectant les propriétés sui-vantes :

– Tout élément K est d’intérieur non vide.

– L’intersection de l’intérieur de deux éléments Ki, Kj, i 6= j est vide, i.e. Ki◦∩ Kj◦ = ∅

– L’intersection de deux éléments différents est soit vide, soit un sommet commun, une arête commune ou une face commune.

(20)

Figure 1.2 – Maillage régulier sur un domaine carré

Dans la méthode des éléments finis, on peut utiliser des éléments de diverses formes tels que, en 2D, des triangles et des quadrangles et, en 3D, des tétraèdres, des prismes et des hexaèdres. Toutefois, dans le cadre de ce travail, nous nous limiterons à l’adaptation de maillages composés de triangles ou de tétraèdres.

On prendra généralement comme point de départ des maillages réguliers, c’est-à-dire dont la disposition et la taille des éléments sont semblables partout sur le domaine. Le maillage final est dit adapté. Des exemples de tels maillages sont illustrés aux figures1.2et1.3.

Définition 1.2.3. Pour évaluer la qualité d’un élément triangulaire, nous utiliserons la formule suivante tirée de [1] :

4√3AK

l21+ l22+ l23 (1.1)

où AK est l’aire de l’élément K et li est la longueur de l’arête i de cet élément.

Cette formule nous permet d’associer une valeur de qualité maximale au triangle équilatéral, une valeur faible aux triangles étirés et une valeur nulle aux triangles dégénérés. Notons qu’il existe d’autres formules possédant les mêmes propriétés, mais nous nous limiterons à celle-ci.

Il est possible d’évaluer la qualité d’un élément non seulement dans la métrique euclidienne standard, mais aussi dans n’importe quelle métrique. Un élément pourrait donc être de piètre qualité dans la métrique euclidienne, mais d’excellente qualité dans une autre. La définition

(21)

Figure 1.3 – Maillage adapté pour une fonction gaussienne

de métrique sera présentée à la section1.4, mais contentons-nous pour l’instant de mentionner qu’il s’agit d’une généralisation de la notion de longueur.

On dira qu’un maillage est isotrope s’il est composé de triangles de qualité près de 1 en mé-trique euclidienne. À l’opposé, un maillage dont les éléments sont étirés est dit anisotrope. Le concept de qualité des éléments en métrique euclidienne était particulièrement important avant l’apparition des méthodes d’adaptation anisotrope ayant pour but de donner des élé-ments étirés. En effet, les éléélé-ments de faible qualité avaient la réputation de donner de mauvais résultats, ce qui est vrai lorsqu’ils sont étirés dans une mauvaise direction, mais l’approxima-tion peut être excellente lorsqu’ils sont correctement orientés. D’ailleurs, les deux méthodes d’adaptation étudiées dans ce mémoire produisent des éléments anisotropes.

On pourrait également définir la qualité pour les éléments tétraédriques, mais cela ne sera pas nécéssaire pour la compréhension du mémoire.

1.3

Interpolation

Rappelons maintenant les bases de l’interpolation de Lagrange, tirées de [11] et de [10]. On note Pkl’espace des polynômes de degré inférieur ou égal à k. L’interpolation consiste à approximer

une fonction connue en un certain nombre de points par l’unique polynôme passant par ces points. Dans notre cas, la fonction u sera approximée par une fonction de Pk sur chaque élément du maillage. Le but recherché est de faire en sorte que notre approximation uh soit une fonction continue et Pk par morceaux.

(22)

Pour des polynômes à n variables, la règle suivante nous permet d’obtenir la dimension d’une base complète de l’espace Pk :

dim(Pk) =

(n + k)! k!n! = N

Cela signifie que nous avons besoin de N noeuds d’interpolation xi sur chaque élément. Ces

noeuds correspondent aux degrés de liberté donnant la valeur de la fonction u en certains points de notre élément. On associe à ces noeuds les fonctions de Lagrange Li(x) :

(

Li(xi) = 1 ∀i

Li(xj) = 0 ∀j 6= i

Si les points d’interpolation xi sont bien choisis, alors les fonctions Li forment une base de Pk et on peut les combiner linéairement pour obtenir l’unique polynôme de degré k passant par les points (xi, uh(xi)). Le choix des points d’interpolation est aussi important lorsque vient le

temps de s’assurer que la fonction uh sera continue aux interfaces entre les éléments.

Par exemple, il est facile de voir que si nous choisissons les sommets des éléments comme points d’interpolation en P1, alors on a bel et bien continuité aux interfaces des éléments.

Démonstration

Paramétrisons l’arête de sommets a et b commune à deux éléments K1 et K2 adjacents :

r(s) = a + s(b − a)

où s ∈ [0, 1]

Soient f1 : K1 → R et f2 : K2 → R les polynômes de degré 1 interpolés grâce aux valeurs

estimées sur les sommets de leur élément respectif. Par hypothèse, on a f1(a) = f2(a) et

f1(b) = f2(b). Ces fonctions peuvent être exprimées le long de l’arête par deux polynômes

p1(s) = f1(r(s)) et p2(s) = f2(r(s)), qui sont de degré 1. Or, ces deux polynômes d’une

va-riable et de degré 1 passent par deux points identiques (0, f1(r(0))) et (1, f1(r(1))), ce qui

implique qu’ils sont identiques pour tout s ∈ [0, 1]. Ainsi, f1 et f2 partagent les mêmes valeurs tout le long de l’arête partagée, ce qui nous permet de conclure sur la continuité de la fonction

uh aux interfaces entre les éléments. 

Il nous reste à déterminer l’erreur commise lors de l’interpolation. Nous nous limiterons à l’erreur en une dimension.

Définition 1.3.1. Soit x0 < x1< x2 < · · · < xn des noeuds d’interpolation. L’erreur

d’inter-polation entre une fonction f : R → R dérivable n + 1 fois et le polynôme d’interd’inter-polation pn

sur un intervalle [x0, xn] est définie par :

(23)

Nous aurons besoin du résultat suivant nous permettant d’associer une expression analytique à l’erreur d’interpolation :

ei(x) =

fn+1(ξ)

(n + 1)!(x − x0)(x − x1) · · · (x − xn) (1.3)

pour un certain ξ ∈ [x0, xn]. La valeur de ce paramètre dépend de x.

1.4

Espaces fonctionnels

Nous allons voir ici les espaces fonctionnels et les normes tels que décrits dans les ouvrages de Fortin et Garon [11] et de Ciarlet et Lunéville [7]. Ces concepts seront particulièrement utiles, car ils nous permettront de comparer les fonctions entre elles, de définir certaines notions d’erreurs et éventuellement de se créer des outils pour évaluer la qualité des approximations.

Tout d’abord, rappelons la définition de métrique tirée de [16].

Définition 1.4.1. Une métrique sur un ensemble X quelconque est une fonction d : X × X → [0, ∞) telle que, pour tout x, y, z dans X,

1) d(x, y) ≥ 0

2) d(x, y) = 0 ⇔ x = y 3) d(x, y) = d(y, x)

4) d(x, z) ≤ d(x, y) + d(y, z)

Plus intuitivement, si nous nous situons dans l’espace Rn, une métrique permet d’associer à toute paire de points une valeur de distance entre ceux-ci.

Définition 1.4.2. Soit Ω ∈ Rn un ouvert borné. On définit l’espace vectoriel normé L2(Ω) par l’ensemble des fonctions de carré sommable sur le domaine Ω :

L2(Ω) =  u : Ω → R Z Ω u2dΩ < ∞ 

accompagné de la norme k.k0,Ω définie par

kuk0,Ω = Z

u2dΩ 1/2

On intègre ici au sens de Lebesgue, ce qui veut dire que les ensembles de mesure nulle n’ont aucun effet sur le résultat de l’intégrale. Les ensembles de mesure nulle comprennent entre autres les ensembles de cardinalité au plus dénombrable. Par exemple, intégrer sur le domaine Ω1 = [0, 1] est équivalent à intégrer sur le domaine Ω2 = [0, 1]\Q.

(24)

Définition 1.4.3. On définit l’espace vectoriel H1(Ω) par l’ensemble des fonctions suivantes : H1(Ω) =  u ∈ L2 ∂u ∂xi ∈ L2(Ω), 1 ≤ i ≤ n 

accompagné de la norme k.k1,Ω définie par

kuk1,Ω= Z Ω u2+ n X i=1  ∂u ∂xi 2! dΩ !1/2

L’espace H1(Ω) appartient à la famille des espaces de Sobolev, qui sont classiques dans l’étude de la méthode des éléments finis. À titre informatif, la dérivée dans la définition est prise au sens des distributions, ce qui permet d’inclure à H1(Ω) des fonctions qui ne sont pas dérivables au sens classique.

On remarque que toute fonction u dans H1(Ω) appartient également à L2(Ω) et que :

kuk21,Ω= kuk20,Ω+ n X i=1 ∂u ∂xi 2 0,Ω

Définition 1.4.4. On définit, sur H1(Ω), la semi-norme |.|1,Ω par l’expression suivante :

|u|1,Ω= n X i=1 Z Ω  ∂u ∂xi 2 dv !1/2 = n X i=1 ∂u ∂xi 2 0,Ω !1/2

La semi-norme ne fait intervenir que les dérivées premières. En pratique, nous nous servirons de la norme L2 et de la semi-norme H1, puisqu’elles nous permettent de mesurer séparément l’erreur sur la fonction elle-même et ses dérivées, contrairement à la norme H1.

(25)

Chapitre 2

Adaptation de maillage

Maintenant que nous possédons les outils essentiels, nous pouvons étudier les deux principales méthodes d’adaptation qui sont implantées au GIREF. Les informations qu’on retrouve ici s’inspirent des travaux de Boiteau [5], de Couët [8], de Bois [3] ainsi que de Habashi et al. [12].

2.1

Estimateurs d’erreur

Le but ultime de l’adaptation est de minimiser l’erreur entre une fonction définie sur un domaine Ω et son approximation Pn par morceaux sur un maillage. Pour y parvenir, nous aurons besoin d’estimateurs d’erreurs. Dans les sections suivantes, nous verrons les estimateurs sur lesquels les méthodes d’adaptation métrique et hiérarchique sont basées.

2.1.1 Estimateur d’erreur métrique

L’idée de l’adaptation par métrique est d’associer aux arêtes du maillage une longueur dif-férente de la métrique euclidienne standard. On veut que cette longueur tienne compte de l’erreur commise sur les arêtes lorsqu’on approxime une fonction f sur un maillage T . L’es-timateur d’erreur utilisé ici sera dérivé de l’erreur d’interpolation. Concentrons-nous pour le moment sur le cas 1D, sachant que nous pourrons généraliser cela en plusieurs dimensions.

Soit fk une approximation P1 par morceaux de la fonction f sur T . Selon l’équation 1.3, l’erreur d’interpolation sur un intervalle [xi, xi+1] est :

ei(x) =

1 2f

00

i)(x − xi)(x − xi+1)

pour un certain ξ ∈ [xi, xi+1]. On pose hi = (xi+1− xi) et s = (x − xi)/hi de sorte que

0 ≤ s ≤ 1. On obtient : ei(x) = h2i 2 f 00 (ξi)s(s − 1)

Puisque |s(s − 1)| ≤ 1/4, on peut simplifier cette expression et obtenir :

|ei(x)| ≤ h2i 8 f00(ξi) (2.1)

(26)

pour un certain ξ ∈ [xi, xi+1] et où hi = (xi+1− xi). Supposons pour l’instant que nous

connaissons la dérivée seconde de f en tout point et qu’elle est positive. Nous voulons créer une longueur d’arête li qui serait liée à l’erreur d’interpolation exprimée par l’équation2.1:

li=

p

hif00(ξi(x))hi (2.2)

En substituant dans (2.1), on obtient :

ei(x) ≤

l2i

8 (2.3)

Il suffirait donc de modifier le maillage de telle sorte que, pour tout i :

li ≤ C

où C est une constante que nous avons choisie comme étant une longueur cible correspondant à la précision voulue. Ainsi, en contrôlant la longueur de chaque arête dans cette métrique, on contrôlerait du même coup l’erreur d’interpolation sur tout le maillage. Nous n’avons cepen-dant utilisé dans notre raisonnement que l’erreur en un point précis de l’arête. Pour associer une longueur à notre arête dans son ensemble, nous calculerons plutôt sur celle-ci une approxi-mation de la valeur moyenne de l’erreur. Ne connaissant la valeur du terme ξi(x) en aucun point de l’arête, nous ne pouvons pas évaluer exactement l’erreur moyenne sur celle-ci. On intègre plutôt sur l’intervalle de valeurs que peut prendre ξi(x) :

l(xi, xi+1) = 1 hi Z xi+1 xi p hif00(x)hi dx

En 2D et 3D, on peut utiliser le même raisonnement. On veut utiliser une métrique semblable pour évaluer l’erreur d’interpolation le long d’une arête i de sommets a et b, que l’on peut paramétriser suivant une variable s ∈ [0, 1] :

r(s) = (x(s), y(s)) = (ax, ay) + s(bx− ax, by− ay)

On pose F (s) = f (r(s)) et on peut à nouveau utiliser l’expression (2.1) :

ei(s) ≤ 1 8 F00(ξi)

pour un certain ξi(s) ∈ [0, 1]. Développons par la règle de dérivation en chaîne :

F0(ξi) = fx(r(ξi))x0(ξi) + fy(r(ξi))y0(ξi)

= fx(r(ξi))(bx− ax) + fy(r(ξi))(by− ay)

On procède de même pour la dérivée seconde :

(27)

Exprimons F00 sous forme matricielle : F00(ξi) = −→ abTH(r(ξi)) −→ ab

où H est la matrice hessienne de f . Supposons pour l’instant qu’elle est définie positive. On obtient donc : ei(s) ≤ 1 8 −→ abTH(r(ξi)) −→ ab

On définit comme suit la longueur d’arête :

li = q abTH(r(ξ i)) −→ ab

et on obtient à nouveau l’expression (2.3). Pour les mêmes raisons que dans le cas unidi-mensionnel, nous devrons approximer l’erreur sur toute l’arête plutôt qu’en un seul point en intégrant sur l’intervalle de valeurs que peut prendre ξi(s) :

l(a, b) = Z 1

0

q

abTH(r(l))ab dl

Il reste quelques précisions à faire :

– On a supposé que nous connaissions les valeurs des dérivées secondes, ce qui n’est pas le cas en pratique. Il faut approximer ces valeurs en n’utilisant que l’approximation linéaire (P1) par morceaux de la fonction à partir de laquelle on veut adapter le maillage. Les

dérivées de fonctions PN par morceaux sont généralement discontinues et peu précises,

d’où le besoin d’utiliser une méthode plus sophistiquée. La méthode utilisée au GIREF et décrite par Zhang et Naga [22] consiste essentiellement à créer, autour de chaque sommet, un polynôme d’ordre plus élevé et à utiliser ses dérivées. On obtient ce polynôme par la méthode des moindres carrés en utilisant les données contenues dans un patch autour du sommet en question. Lors d’une exécution parallèle, les données seront disséminées sur plusieurs unités de mémoire séparées, ce qui causera des problèmes au moment de rassembler les informations nécessaires à la construction du patch. Nous y reviendrons au chapitre 4.

– On a aussi fait l’hypothèse que la dérivée seconde était positive dans le cas unidimen-sionnel et que la matrice hessienne était définie positive dans le cas multidimenunidimen-sionnel. Cela a été fait dans le but d’éviter les problèmes avec la racine carrée et de respecter les propriétés d’une métrique. En pratique, on va transformer quelque peu les données pour s’assurer de respecter nos hypothèses. H étant symétrique, on peut l’exprimer sous la forme PTDP où P est la matrice orthogonale contenant les vecteurs propres de H et où D est la matrice diagonale contenant les valeurs propres associées. Pour transformer H en matrice définie positive, il suffit de prendre la valeur absolue des valeurs propres et de redéfinir la matrice hessienne :

(28)

– On peut étendre ce type d’adaptation à des approximations quadratiques en travaillant sur leur gradient. Il faut alors évaluer les dérivées troisièmes, c’est-à-dire évaluer les hessiens des dérivées premières et intersecter les métriques obtenues. On peut aussi procéder par la méthode de Pagnutti et Ollivier-Gooch pour étendre l’adaptation par métrique aux approximations de degrés plus élevés. Pour de plus amples renseignements sur l’intersection de métrique et l’approche de Pagnutti et Ollivier-Gooch, on réfère le lecteur intéressé à Boiteau ([5]).

2.1.2 Estimateur d’erreur hiérarchique

On pose u la solution inconnue d’une équation aux dérivées partielles sur un domaine Ω et ukh une approximation Pk par morceaux sur un maillage T . L’estimateur d’erreur que nous utiliserons sera lié à l’expression u − ukh. On s’intéressera à la norme L2 et à la semi-norme H1 de celle-ci. Notre but sera de contrôler le niveau d’erreur en norme L2 tout en minimisant la semi-norme. Puisque cette dernière est la norme du gradient de l’erreur, la maintenir près de zéro revient à garder l’erreur constante sur le maillage. C’est ce qu’on appelle le principe d’équirépartition de l’erreur. L’équirépartition est souhaitable, puisqu’une petite valeur de l’erreur en norme L2ne contredit pas l’existence de zones où l’erreur sera localement beaucoup

plus élevée qu’ailleurs.

L’idée principale de l’adaptation hiérarchique est de créer, à partir de ukh, une approximation uk+1h de degré plus élevé et plus précise. On peut alors faire l’estimation suivante :

ku − ukhk = ku − uk+1h + uk+1h − ukhk ≤ ku − uhk+1k + kuk+1h − ukhk ' kuk+1h − ukhk

Plaçons nous sur un élément K. Posons

uk+1h = ukh+ ck+1h

où ck+1h est un polynôme de degré k + 1 dont les coefficients sont à déterminer. Le terme ukh n’étant que de degré k, les dérivées d’ordre k + 1 de uk+1h sont déterminées uniquement par le terme ck+1h . Supposons aussi que nous avons récupéré le gradient gh = ∇ukh par la méthode de Zhang et Naga [22]. Puisque uk+1h est une approximation de u et que ghest une approximation de son gradient, on peut estimer les coefficients de ck+1h en liant ses dérivées d’ordre k + 1 aux dérivées d’ordre k des composantes de gh.

Une fois ck+1h connu, il ne reste qu’à calculer

kuk+1h − ukhk = kck+1h k

et on a approximé l’erreur sur l’élément K.

Nous n’entrerons pas plus en détails dans les fondements de l’adaptation hiérarchique ni dans la construction de uk+1h . On réfère pour cela le lecteur à Bois et al. [3].

(29)

Figure 2.1 – Coquilles autour d’un sommet et d’une arête

2.2

Opérations d’adaptation sur les maillages

Nous introduirons ici les quatre opérations d’adaptation de maillage : le raffinement, le déraf-finement, le retournement d’arête ou de face ainsi que le déplacement de sommet. Toutes ces opérations sont communes aux adaptations métrique et hiérarchique, mais elles ont des objec-tifs légèrement différents. En métrique, elles ont pour but de contrôler la longueur de l’arête dans la métrique définie précédemment, excepté pour le retournement, qui sert à améliorer la qualité des éléments dans cette même métrique. En hiérarchique, on utilise le raffinement et le déraffinement afin de contrôler la norme L2 de l’erreur tandis qu’on utilise le retournement et le déplacement pour minimiser la semi-norme H1.

Avant d’entrer dans le vif du sujet, introduisons le concept de coquille, qui est omniprésent dans le processus d’adaptation. Une coquille est une copie d’une petite partie du maillage centrée autour de la composante qu’on tente de modifier. Avant d’intégrer véritablement les changements dans le maillage initial, on effectue tous les traitements dans la coquille et on vérifie si le résultat satisfait nos exigeances.

Nous adapterons en bouclant plusieurs fois sur les composantes du maillage, et chaque boucle sera réservée à un seul type d’opération. Voyons maintenant la mécanique derrière cela. Dans ce qui suit, chacune des opérations sera présentée de manière sommaire, puis les particularités propres aux méthodes métrique et hiérarchique seront précisées.

(30)

Figure 2.2 – Raffinement d’arête

2.2.1 Raffinement d’arête

Là où notre critère nous indique que l’erreur est trop élevée, on procède au raffinement des arêtes. On crée un sommet sur le point milieu de l’arête, puis on relie ce point aux sommets des éléments adjacents par des arêtes et des faces, selon la dimension. Ainsi, on divise tous ces éléments en deux.

Métrique

Le critère pour le raffinement dans l’adaptation par métrique est fort simple. On itère sur toutes les arêtes du maillage et pour chacune, on calcule la longueur grâce à notre métrique. Puis, on vérifie si cette valeur dépasse la longueur cible multipliée par un certain facteur de tolérance.

Hiérarchique

Pour le raffinement hiérarchique, on itère sur tous les éléments pour comparer l’erreur L2 locale au seuil d’erreur permis. Ce seuil est proportionnel à l’aire occupée par l’élément et dépend de l’erreur désirée par l’utilisateur. Lorsqu’un élément possède une erreur trop élevée, on marque ses arêtes pour le raffinement. Avant le raffinement de chaque arête, on vérifie si la somme des erreurs sur les éléments autour de celle-ci n’est pas devenue trop petite au cours de la boucle d’adaptation, puisque le raffinement des autres arêtes peut réduire la taille des éléments, de sorte que nous n’ayons plus besoin d’adapter. Ainsi, ce ne sont pas toutes les arêtes marquées au préalable qui sont adaptées.

2.2.2 Suppression de noeuds

Pour éviter de se retrouver avec trop de sommets là où notre critère d’erreur est déjà respecté avec une bonne marge de manoeuvre, il faut procéder au déraffinement par suppression de noeuds. Pour y parvenir, on crée une coquille contenant tous les éléments autour du noeud concerné, on retire le sommet ainsi que toutes les arêtes et les faces dont il faisait partie, puis

(31)

Figure 2.3 – Suppression d’un noeud

on remaille la coquille afin de retrouver des éléments utilisables. Nous ne nous attarderons pas à la méthode utilisée pour remailler, puisqu’il s’agit d’une opération complexe qui ne concerne en rien la parallélisation. Également, il faut porter une attention particulière lors de la suppression de sommets au bord de la frontière, puisque cela peut modifier notre domaine.

Métrique

Le critère de déraffinement dans la métrique est semblable à celui du raffinement. On trouve les arêtes dont la longueur dans la métrique est plus petite que la longueur cible divisée par le facteur de tolérance. Un des sommets de chaque arête dépassant le critère est alors choisi de manière arbitraire et est marqué pour le déraffinement. Puisque l’élimination d’un sommet peut affecter les arêtes des autres sommets, il faut revérifier, avant le déraffinement d’un sommet marqué, si le critère est toujours respec´té malgré les changements à proximité.

Hiérarchique

On tente de déraffiner tous les sommets. Les étapes de déraffinement dans le cas hiérarchique sont semblables au cas métrique, mais on ajoute en plus un retournement d’arêtes après le remaillage de la coquille afin d’optimiser leur disposition. On décide ensuite si on conserve ou non les changements effectués en calculant l’erreur L2.

(32)

Figure 2.4 – Retournements d’arête légal et illégal

2.2.3 Retournement

Le retournement consiste à trouver l’orientation optimale d’une arête (ou face) entre deux éléments. La figure2.4 illustre le cas 2D. On teste chacune des configurations possibles, puis on sélectionne celle qui remplit le mieux nos exigences selon la méthode d’adaptation. Il faut faire attention au cas où nous avons une coquille non convexe, puisque le retournement résulterait en un élément dit renversé. Lorsque cela se produit, la coquille finale ne possède plus la même frontière, ce qui rend la réinsertion impossible.

Métrique

On itère sur tous les éléments en marquant les arêtes de ceux dont la qualité n’est pas suffisante dans notre métrique liée à l’erreur. Pour chaque arête marquée, on tente le retournement et on conserve les résultats uniquement si la qualité des éléments autour s’est améliorée.

On rappelle que la qualité d’un triangle, définie par la relation1.1, permet de quantifier son caractère équilatéral. Ce concept est fortement relié à l’adaptation par métrique, qui cherche à rendre toutes les arêtes de même longueur dans la métrique non euclidienne. En améliorant la qualité métrique des éléments, on tend à obtenir des arêtes de longueurs égales.

(33)

Figure 2.5 – Déplacement de sommet

Hiérarchique

On tente de retourner chaque arête en conservant chaque fois la configuration minimisant l’erreur en semi-norme H1. On boucle ainsi sur l’ensemble des arêtes jusqu’à ce que ce processus devienne stable. Le processus convergera bel et bien vers une configuration stable, tel que démontré par Lagüe [15].

2.2.4 Déplacement

Le déplacement d’un noeud est une opération complexe. Pour chaque noeud, on cherche la position qui nous permettrait de minimiser un certain critère dépendant de la méthode d’adap-tation. Il faut tenir compte de la position d’arrivée du noeud et s’assurer qu’elle se trouve bien dans la coquille autour du noeud. Sinon, on peut se retrouver avec un maillage dont les élé-ments se superposent ou encore des éléélé-ments dégénérés d’intérieur vide.

Lors d’une séquence complète d’adaptation, c’est l’opération qui est effectuée le plus grand nombre de fois et elle accapare une importante part des temps de calcul.

Métrique

On voit les arêtes reliées au noeud comme étant des ressorts. Soit xj le noeud central et xi l’autre sommet d’une arête. La constante de Hooke associée est donnée par :

ki(xj) = e(xi− xj)/kxi− xjk

où e(xi− xj) est la longueur euclidienne et kxi − xjk est la longueur dans notre métrique.

On tente alors de minimiser l’énergie du système de ressorts tout en essayant de conserver kxi− xjk = 1.

Trouver le point optimisant ces critères différents ne se fait pas de manière exacte. Il faudra procéder par une heuristique qui nous permettra d’itérer vers un point offrant un juste équilibre entre la minimisation de l’énergie et le contrôle de la longueur des arêtes. Pour plus de détails sur l’heuristique utilisée, on réfère le lecteur à [12]. Cela dit, peu importe la méthode utilisée,

(34)

il est inutile de travailler trop longtemps à bien approximer la valeur optimale xj, puisque celle-ci changera lorsque les autres sommets seront déplacés et manipulés.

Hiérarchique

Le but que nous nous fixons ici est de minimiser la semi-norme de l’erreur sur la coquille :

F (xj) =

Z

K(xj)

|∇u − ∇uh|

où xj est le noeud à déplacer et où K(xj) est la coquille d’éléments entourant xj. Pour ce

faire, nous utilisons la procédure proposée par Bois [3], qui consiste à effectuer une descente du gradient afin de trouver le nouveau point x0j minimisant F . Il faut tout d’abord approximer le gradient de F , ce qui est fait par une méthode de différences finies. Les deux directions choisies sont celles de l’arête la plus longue touchant xj, notée elong et la direction de l’arête

la plus orthogonale à elong, notée eorth. On utilise alors les formules classiques de différences finies pour approximer la dérivée dans chacune de ces directions et en déduire le gradient :

∇F (xj) · eorth= F (xj+ horth∗ eorth) − F (xj) horth ∇F (xj) · elong= F (xj+ hlong∗ elong) − F (xj) hlong

où horth et hlong sont les longueurs de l’arête dans la direction eorth et elong respectivement.

2.2.5 Nombre de sommets désirés et calcul de l’erreur désirée

Nous avons mentionné au tout début de ce mémoire que l’adaptation de maillage avait pour but de minimiser l’erreur commise par une solution éléments finis sur un maillage tout en minimisant le nombre de sommets du maillage. Dans la pratique, on tend plutôt à vouloir obtenir un maillage possédant le nombre de sommets désirés tout en adaptant le maillage à la fonction. On peut ainsi mieux contrôler la durée des calculs.

Pour appliquer cela, nous aurons besoin d’une formule pour transformer le nombre de sommets désirés en critère d’erreur après chaque modification du maillage. Selon un résultat théorique, nous pouvons lier la norme L2 de l’erreur e à la longueur euclidienne des arêtes du maillage h :

e = C1hk+1 (2.4)

où C1 est une constante inconnue et k le degré d’interpolation.

Le nombre d’éléments N , quant à lui, obéit à la relation suivante :

N = C2h−Dim (2.5)

(35)

En combinant ces deux équations, on obtient :

e = CN−Dimk+1 (2.6)

Cette formule s’applique à la fois à l’erreur et au nombre d’éléments désirés et actuels :

eD = CN −(k+1) Dim D (2.7) eA= CN −k+1 Dim A (2.8)

En combinant ces deux formules, on peut éliminer la constante inconnue et obtenir une formule que l’on pourra utiliser pour l’adaptation hiérarchique :

eD eA = ND NA −(k+1)Dim (2.9) eD = eA  NA ND (k+1)Dim (2.10)

En pratique, nous avons utilisé le rapport des nombres de sommets désiré et actuel plutôt que celui du nombre d’éléments :

eD = eA

 sA

sD

(k+1)Dim

(2.11)

Les deux formules sont équivalentes.

En métrique, on utilise plutôt la longueur d’arête liée à l’erreur dans la formule empirique suivante :

l0D = sA sD

1/Dim

∗ lA∗ lD+ lCorrec

où lA est la longueur moyenne d’arête actuelle dans la métrique, lD est la longueur désirée

calculée précédemment, l0D est la nouvelle longueur désirée et lCorrecun facteur de correction. La valeur initiale de lD est fixée initialement par l’utilisateur.

2.2.6 Algorithme complet

Maintenant que nous avons rassemblé tous les morceaux nécessaires à l’adaptation de maillage, voyons maintenant comment se déroule une exécution typique de notre algorithme.

En général, on fait appel à l’adaptation lorsque nous avons déjà calculé une solution sur un maillage et que l’on tente d’améliorer celui-ci. Il faut donc charger en mémoire le maillage et la solution. Avec ces informations, on peut évaluer les dérivées grâce à la méthode par patch de Zhang et Naga [22] et créer nos estimateurs d’erreur. Ceux-ci nous permettront de

(36)

modifier notre maillage en conséquence. On lance ensuite la phase d’adaptation, au cours de laquelle nous appliquerons un certain nombre d’opérations d’adaptation ordonnées et choisies par l’utilisateur, ce que l’on nomme une séquence. Par exemple, voici une séquence simple :

– Raffinement d’arêtes – Déraffinement de sommets – Retournement d’arêtes – Déplacement de sommets

Il est possible de rallonger la séquence en dupliquant les opérations. On peut exécuter des séquences aussi longues qu’on le désire, mais on ne peut pas améliorer indéfiniment la qualité de maillage avec une seule et même solution éléments finis. En effet, bien que notre maillage s’améliore au cours de l’adaptation, nos estimateurs d’erreurs, eux, ne s’améliorent pas. Il est préférable, au bout de quelques opérations d’adaptation, de recalculer une nouvelle solution éléments finis plus précise avec le maillage adapté, puis d’adapter à nouveau au besoin.

En somme, on peut segmenter notre algorithme en quatre étapes :

– Chargement en mémoire de la solution éléments finis et du maillage ; – Calcul des estimateurs d’erreur selon la méthode d’adaptation choisie ; – Séquence d’adaptation de maillage ;

– Écriture des résultats sur disque.

Nous reviendrons sur chacune des étapes importantes lorsque viendra le temps de paralléliser l’algorithme, mais d’abord, nous verrons les rudiments de la programmation parallèle.

(37)

Chapitre 3

La programmation parallèle

3.1

Motivation

La programmation parallèle permet d’exécuter un programme en utilisant plusieurs unités de calcul simultanément. L’idée d’utiliser des ordinateurs parallèles n’est pas nouvelle, mais ces machines sophistiquées deviennent de plus en plus présentes et à notre portée. En particulier, l’Université Laval s’est dotée en 2009 du supercalculateur Colosse, que nous utiliserons pour nos propres calculs d’adaptation de maillages. Avant de l’utiliser, il faudra apprendre à s’en servir convenablement afin de pouvoir profiter au maximum des possibilités qu’il nous offre. En effet, on ne peut pas lancer en parallèle un programme qui a été conçu pour une exécution séquentielle. Il faut paralléliser le code afin qu’il soit non seulement fonctionnel en parallèle, mais aussi efficace, ce qui est loin d’être trivial.

Voyons tout d’abord les raisons qui peuvent justifier l’effort de parallélisation. Le premier bénéfice évident est la réduction des temps de calculs. Comme problème type, on peut imaginer que nous avons besoin de calculer la sommation de 2000 nombres réels que l’on distribue sur deux coeurs. Bien évidemment, on donnera 1000 nombres à chacune des unités, qui effectueront séparément la sommation de leurs éléments respectifs, puis on additionnera leurs résultats. Logiquement, puisque chacun des coeurs n’a que la moitié des opérations à faire, le temps d’exécution de l’algorithme devrait être coupé de moitié. Nous verrons que l’amélioration des performances n’est pas toujours aussi spectaculaire, mais les gains que l’on peut obtenir peuvent tout de même se révéler substanciels. La deuxième raison fondamentale justifiant l’effort de parallélisation est la possibilité d’augmenter la taille des problèmes. Prenons la méthode des éléments finis en exemple. Comme nous le savons, la précision de ses résultats dépend, entre autres, du nombre d’éléments composant le maillage. Or, la taille du système à résoudre pour obtenir notre solution augmente avec le nombre d’éléments du maillage, si bien que la quantité de mémoire vive disponible à la résolution devient un facteur limitant. La parallélisation permet alors de diviser les besoins en mémoire sur plusieurs unités et ainsi de repousser ces limitations.

(38)

En ce qui concerne l’adaptation de maillages, la réduction du temps de calcul est le principal motif de la parallélisation. Comme nous allons le voir au chapitre4, la séquence d’adaptation, qui est l’étape la plus coûteuse en temps de calcul, se révèle être facilement parallélisable.

3.2

Définitions

Commençons par introduire quelques notions essentielles au calcul des performances paral-lèles :

Définition 3.2.1. Notons Tp(n) le temps d’exécution d’un algorithme exécuté avec p coeurs avec une entrée de taille n. L’accélération Sp(n) est donnée par la formule suivante :

Sp(n) =

T1(n)

Tp(n)

Lorsque possible, on utilise pour T1(n) le temps d’exécution de l’algorithme séquentiel le plus

rapide pour la résolution du problème de taille n, qui n’est pas nécessairement l’algorithme parallèle exécuté par un seul coeur. Cela permet d’évaluer les gains réels de la parallélisation.

On dit que l’accélération est linéaire ou idéale pour p coeurs si

Sp(n) ≈ p

Définition 3.2.2. L’efficacité est donnée par

Ep(n) =

Sp(n)

p

Ces définitions permettront d’évaluer de manière assez intuitive la qualité d’une implémen-tation parallèle. En effet, l’accélération permet de savoir par quel coefficient on peut diviser le temps de calcul séquentiel (à un coeur) en exécutant le programme en parallèle avec un certain nombre d’unités de calculs. L’efficacité permet quant à elle de mesurer en moyenne à quelle vitesse travaille un coeur utilisé en parallèle par rapport à un coeur en séquentiel.

L’accélération linéaire est théoriquement la meilleure accélération que l’on puisse obtenir. On voit facilement que, dans ce cas, l’efficacité des coeurs est de 1, c’est-à-dire que les coeurs travaillent aussi bien en parallèle qu’en séquentiel. Il est même possible d’obtenir des per-formances supérieures, dites superlinéaires, pouvant être dues à des effets de cache possibles lorsque plusieurs modules de mémoire cache sont disponibles en parallèle. Il est cependant rare que l’on puisse obtenir des performances linéaires ou superlinéaires dans les applications complexes. En effet, il peut arriver qu’un algorithme soit composé d’un partie parallélisable et d’une partie non-parallélisable, ce qui peut affecter grandement les performances parallèles.

Loi 3.2.1. Notons α la proportion d’un programme pouvant être parallélisée. La loi de Amdahl nous permet de borner l’accélération par l’expression suivante :

Sp(n) ≤

1 1 − α

(39)

1 2 3 4 5 6 7 8 9 10 Nombre de coeurs Acceleration 20 21 22 23 24 25 26 27 28 29 210 alpha=0.6 alpha=0.7 alpha=0.8 alpha=0.9

Figure 3.1 – Limites de l’accélération selon α

ou encore

Tp(n) ≥ (1 − α)T1(n)

La figure 3.1illustre cette borne sur l’accélération.

Ainsi, si nous avons dans un programme une portion non parallélisable d’à peine 5%, nous sommes limités à une accélération de 20, et ce, peu importe le nombre de coeurs utilisés. À première vue, cette loi semble nous décourager de mettre des efforts dans la parallélisation d’un algorithme, puisque nous en atteignons rapidement la limite. Cependant, dans la plupart des applications, on observe que la proportion non parallélisable d’un problème décroît lorsque la taille n du problème augmente. Cela nous permet de supposer que si α tend vers 1 lorsque n tend vers l’infini, alors il est possible d’atteindre une accélération linéaire. Plus concrètement, nous pouvons affirmer que même si le parallélisme ne nous permet pas d’accélérer comme bon nous semble la résolution de n’importe quel problème, celui-ci peut tout de même nous aider à résoudre des problèmes de très grande taille en un temps raisonnable.

(40)

3.3

Architecture matérielle

Dans la présente section, nous verrons quelques concepts d’architecture matérielle portant sur l’organisation et l’utilisation de la mémoire dans certains systèmes parallèles. Bien que nous n’étudierons pas le sujet en détail, ces connaissances nous permettront de mieux comprendre les possibilités et les limitations de la programmation parallèle. Pour plus de détails, le lecteur peut consulter l’ouvrage de Rauber et al.[20].

Classiquement, les architectures parallèles sont classées selon la taxonomie de Flynn, qui inclut quatre classes :

– Single instruction, single data (SISD) – Single instruction, multiple data (SIMD) – Multiple instructions, single data (MISD) – Multiple instructions, multiple data (MIMD)

L’architecture SISD est la plus ancienne et comprend les ordinateurs séquentiels classiques. On ne peut exécuter qu’une seule instruction à la fois et sur une seule donnée à la fois. La classe SIMD inclut les ordinateurs capables d’exécuter une seule instruction à la fois, mais sur plusieurs données simultanément. Bien que cette contrainte puisse sembler restrictive pour une machine parallèle, une panoplie de problèmes consistent à traiter une grande quantité de données par les mêmes instructions. On peut aussi qualifier certains programmes parallèles comme étant de type SIMD. La classe MISD est une classe peu utilisée en pratique, englobant les machines capables d’exécuter plusieurs traitements simultanés, mais sur une seule donnée. Finalement, la classe MIMD est la plus puissante et comprend la plupart des ordinateurs parallèles tels que nous les connaissons. Ces machines permettent l’exécution simultanée de différentes instructions, chacune pouvant manipuler des données différentes. Leurs unités de calculs peuvent fonctionner de manière complètement asynchrone et indépendante des autres. Cette classe d’architecture peut elle-même être divisée en deux sous-classes dépendant de l’organisation de la mémoire : Les ordinateurs à mémoire partagée et à mémoire distribuée.

Dans les ordinateurs à mémoire partagée, tous les coeurs peuvent accéder aux mêmes espaces en mémoire et ce, sans délai de latence. Cela peut constituer un avantage, mais le partage de la mémoire peut entraîner des problèmes de course critique, ou "race condition". Il s’agit de situations issues de l’utilisation simultanée du même espace mémoire par plusieurs processus. Par exemple, un processus peut essayer de lire une donnée en cours d’écriture par un autre processus, de telle sorte que la donnée lue sera incohérente et le programme n’aura plus le comportement souhaité. Pour éviter une telle situation, il faut synchroniser les processus en ordonnant l’accès aux ressources. Les efforts que doivent déployer les programmeurs pour syn-chroniser efficacement les processus peuvent être considérables lorsque les applications sont complexes, car la moindre erreur peut entraîner un mauvais fonctionnement intermittent dé-pendant de l’ordre d’exécution des instructions en parallèle. Malgré tout, il faut noter qu’il est

(41)

Interconnexion

Mémoire partagée

CPU CPU CPU CPU

Figure 3.2 – Architecture à mémoire partagée

possible de programmer les ordinateurs à mémoire partagée comme s’ils avaient une mémoire distribuée, dont nous verrons sous peu le fonctionnement. Ainsi, nous avons le libre choix de l’implémentation parallèle avec la mémoire partagée. Cependant, il y a une limite au nombre de processeurs que l’on peut brancher à une même unité de mémoire. Il est donc impossible de créer un supercalculateur basé uniquement sur ce genre de système. Puisque l’utilisation d’un grand nombre de processeurs est primordiale en calcul de haute performance, ce type d’organisation de mémoire n’est pas approprié à nos besoins.

Les processeurs d’un ordinateur à mémoire distribuée possèdent chacun un espace mémoire dont ils ont l’utilisation exclusive. C’est le système parallèle le plus simple à mettre en oeuvre, puisqu’il ne s’agit conceptuellement que d’un regroupement d’ordinateurs en réseau. Si nous avons à échanger des données entre les processus, nous devrons passer par une librairie de passage de messages, notamment une librairie implémentant le standard MPI [18]. Le passage de données d’une unité de mémoire à l’autre souffre d’un délai de latence qui dépend du réseau les reliant. Cela dit, il n’y a pas de limite au nombre de processeurs que l’on peut relier de cette manière. C’est pourquoi nos efforts seront dirigés vers l’utilisation de ce type de machine parallèle ainsi que de son outil de base, la librairie de passage de messages. Les fonctionnalités offertes par le standard MPI seront décrites dans la section A.

Avant de continuer, mentionnons que rien n’empêche les deux concepts architecturaux d’être intégrés dans un seul et même système. Colosse, le supercalculateur de l’Université Laval, en est un exemple. Il est composé de 960 noeuds possédant chacun 24 gigaoctets de mémoire et chaque noeud possède deux processeurs à quatre coeurs se partageant cette mémoire.

3.4

Principes de base de la programmation parallèle

L’utilisation de plusieurs unités de calculs pour exécuter une série d’instructions ne se fait pas de manière triviale ou automatique. Pour utiliser nos coeurs de manière efficace, il faut que chacun d’eux soit en mesure d’exécuter en parallèle un travail complémentaire à celui des autres. Il faut aussi réduire au minimum la charge de travail induite par le simple fait d’utiliser notre code de manière parallèle. L’application de quelques techniques peut nous aider à guider

(42)

Réseau

CPU CPU CPU CPU

M M M M

Figure 3.3 – Architecture à mémoire distribuée

nos efforts en ce sens.

3.4.1 Décomposition du problème

L’étape la plus importante de l’écriture d’un programme parallèle est de déterminer comment séparer la tâche à effectuer sur plusieurs unités de calculs. Celles-ci doivent pouvoir travailler simultanément et l’on doit éviter autant que possible les temps d’attente. Il faut donc diviser le travail en parts dont le temps d’exécution est à peu près égal.

Cela dit, la répartition du travail peut être relativement complexe. Dans la plupart des cas, il est impossible de séparer sur plusieurs coeurs un bloc d’instructions pour une exécution parallèle, car les données générées par les premières instructions du bloc sont utilisées par les suivantes. Cela nous amène au concept de dépendance entre les tâches.

On dit que deux tâches sont indépendantes l’une de l’autre si leur résultat final ne dépend pas de l’ordre dans lequel elles ont été exécutées, incluant une exécution simultanée. Cela signifie que si nous sommes capables d’extraire, à un certain point de notre algorithme, n tâches indépendantes, alors nous pourrons utiliser n coeurs pour les exécuter et ce, de manière efficace. Au contraire, une tâche peut être dépendante d’une autre. Cela signifie que l’exécution d’une des tâches doit nécessairement être complétée avant que celle qui en dépend puisse être entamée.

L’absence d’indépendance entre les tâches empêche le parallélisme et est donc un obstacle qu’il faut contourner. Ce ne sera pas toujours possible, puisque certains algorithmes contiennent au moins une étape dont dépendent toutes les autres. Dans le meilleur des cas, la tâche prioritaire peut elle-même être divisée en plus petites tâches indépendantes et exécutées en parallèle. Dans le cas contraire, il n’y a rien qu’on puisse faire, excepté exécuter une partie en séquentiel tout en exécutant ce qui suit en parallèle. Il faut éviter autant que possible cette situation, comme la loi de Amdahl (3.2.1) nous l’indique. En ce sens, s’il existe une multitude d’algorithmes pour résoudre le problème, il peut être avantageux d’utiliser un algorithme X moins efficace qu’un algorithme Y si le premier est plus facilement parallélisable. On peut alors espérer que l’exécution parallèle de l’algorithme X sera plus avantageuse que l’exécution séquentielle de

(43)

l’algorithme Y.

Exemple

Pour illustrer le concept de dépendance entre les tâches, considérons la méthode de Gauss pour la résolution de systèmes d’équations linéaires. Soit un système Ax = b de taille n × n :

      a1,1 a1,2 · · · a1,n a2,1 a2,2 · · · a2,n .. . ... . .. ... an,1 an,2 · · · an,n             x1 x2 .. . xn       =       b1 b2 .. . bn      

La méthode de Gauss consiste à effectuer des opérations sur les lignes de la matrices et du terme de droite de manière à obtenir un système triangulaire supérieur. La première étape de l’algorithme est de faire apparaître des zéros sous le terme a1,1 en additionnant, sur chaque

ligne suivante, la première ligne multipliée par la bonne constante :

      a1,1 a1,2 · · · a1,n 0 a∗2,2 · · · a∗2,n .. . ... . .. ... 0 a∗n,2 · · · a∗ n,n             x1 x2 .. . xn       =       b1 b∗2 .. . b∗n      

De cette manière, à toute étape i = 1, 2, ..., n de l’algorithme, on viendra introduire des zéros sous le terme ai,i. Notons que sa valeur n’est pas nécessairement la même qu’au départ dans

la matrice originale. Pour simplifier l’exemple, on suppose que ai,i est non nul à ce moment. Étudions la dépendance entre les tâches, que l’on considérera ici comme les opérations sur les lignes. À l’étape i de l’algorithme, on manipule des lignes de la matrice qui ont toutes été modifiées dans les étapes précédentes de l’algorithme. Ainsi, pour continuer, il faut absolument avoir complété les i − 1 étapes précédentes, puisqu’autrement nous n’aurons pas les données nécessaires. Les tâches de l’étape i sont dépendantes des tâches des i − 1 étapes précédentes. Autrement dit, on ne peut pas exécuter en parallèle deux étapes i et j, où i 6= j. Cela dit, les modifications sur chaque ligne à l’intérieur d’une même étape sont indépendantes entre elles et peuvent être exécutées simultanément. On remarque ici que nous avons un mélange de tâches

dépendantes et indépendantes. 

Voyons maintenant comment, en pratique, on peut découper un algorithme séquentiel en tâches indépendantes en vue de le paralléliser. Il existe de multiples façons d’y arriver, le concept de tâches étant assez large. Nous devrons faire un choix sur le type de tâches que nous tenterons d’extraire de notre algorithme et pour ce faire, introduisons la notion de granularité. On dira d’une tâche simple, c’est-à-dire comportant peu d’instructions machines, qu’elle possède une granularité fine et d’une tâche complexe qu’elle possède une granularité grossière. À partir de cette notion de granularité et de la nature même des tâches, nous allons introduire quatre

(44)

niveaux de parallélismes : Le niveau des instructions, des structures de données, des boucles et le parallélisme fonctionnel. Ces niveaux de parallélisation nous aideront face à diverses situations lorsque viendra le temps de diviser les algorithmes en tâches indépendantes.

Mentionnons avant de commencer qu’il est possible d’appliquer plusieurs niveaux de parallé-lisation dans un même algorithme et même de les imbriquer, chacun d’eux n’entrant pas en contradiction avec les autres.

Niveau des instructions

Le parallélisme au niveau des instructions utilise la granularité la plus fine qui soit, où nos tâches ne représentent qu’une ou quelques instructions de bases. À ce niveau, des instructions simples peuvent s’effectuer en parallèle si elles sont indépendantes.

En général, les programmeurs ne s’occupent pas du parallélisme à un niveau aussi bas et ce sera également notre cas. Sachons toutefois que celui-ci peut être mis en place automatiquement par certaines fonctionnalités spéciales des processeurs et des compilateurs si elles sont disponibles.

Niveaux des structures de données et des boucles

Le parallélisme au niveau des structures de données et celui au niveau des boucles s’appliquent aux segments de code répétitifs s’exécutant de manière indépendante sur un grand nombre de données. Bien que cela puisse sembler plutôt restreint comme classe de problèmes, une grande variété d’applications scientifiques consiste justement à effectuer ce genre de tâches. Dans de telles situations, la parallélisation peut apporter de grands bénéfices, puisqu’il est facile d’écrire un code parallèle générique permettant d’utiliser un nombre variable de coeurs selon nos besoins. C’est pourquoi nous devrions exploiter ces niveaux de parallélisme autant que possible.

On utilise le parallélisme au niveau des structures lorsqu’on doit appliquer un même traite-ment sur chacune des entrées d’un structure de données, comme par exemple un vecteur. Le traitement appliqué sur une donnée individuelle doit être indépendant de celui qui est appli-qué sur les autres données. La stratégie de parallélisation consiste à diviser notre structure en autant de parts que l’on veut, créant ainsi autant de tâches que l’on pourra assigner à nos coeurs. Les librairies MPI et pthread sont bien adaptées à ce niveau de parallélisme grâce aux fonctionnalités qu’elles offrent pour lancer de multiples instances du même programme et distribuer ou partager les données. C’est sur ce niveau de parallélisme que reposera en grande partie notre algorithme parallèle d’adaptation de maillages. Dans notre cas, la structure à di-viser entre les processus sera le maillage et les opérations d’adaptation seront les traitements que l’on appliquera indépendamment sur chaque composante. Nous reviendrons en détail sur l’algorithme parallèle au chapitre4.

Figure

Figure 1.1 – Interpolation linéaire par morceaux
Figure 1.3 – Maillage adapté pour une fonction gaussienne
Figure 2.3 – Suppression d’un noeud
Figure 3.4 – Parallélisation des traitements sur les entrées d’un vecteur
+7

Références

Documents relatifs

L’application de la méthode de 2-raffinement à la carte d’optimalité 6.6 génère le maillage de la figure 6.7 dont l’erreur relative globale estimée par lissage du champ

Les opérateurs d’édi- tion topologique de la TCM couvrent les transformations nécessaires pour adapter la topologie du modèle CAO aux besoins du maillage : suppression

L’exérèse chirurgicale constitue le traitement de choix des adénocarcinomes gastriques résécables. Malgré une chirurgie radicale, une résection curative est

En revanche, les courbes frontières des domaines peuvent avoir une allure en dents de scie comme l’illustrent Figure 10(a) et Figure 10(c) et il convient de les lisser pour éviter

paramètres biologiques ... 80 Tableau VII: prévalence de la carence martiale et de l'anémie gravidique ... 81 Tableau VIII: corrélation entre l’état des réserves en fer

gambiae expérimentalement exposées à des conditions reproduisant la saison des pluies et la saison sèche permettront (1) d’identifier un plus grand nombre de marqueurs

These changes in bonds and angles correspond to the W-O and A(Sr, Ce)–O stretching and twisting motions.. The structure was identified as a tetragonal scheelite and the XRD

101 - 54602 Villers lès Nancy Cedex France Unité de recherche INRIA Rennes : IRISA, Campus universitaire de Beaulieu - 35042 Rennes Cedex France Unité de recherche INRIA Rhône-Alpes