Avertissement : pour les versions précédentes avant le 23/05/18, bug fixé sur le critère de convergence (le pas d'espace $h$ doit être élevé au carré et non au cube)
Veuillez vous assurer à l'exécution du code parallèle (avec la commande "mpirun") que le nombre de processeurs soit égal au produit du nombre de sous-domaines selon x par le nombre de sous-domaines selon y et le nombre de sous-domaines selon z ( paramètres "x_domains", "y_domains" et "z_domains" situés dans le fichier "param" ) :
Nous allons commencer par discrétiser le membre de droite de l'équation ci-dessus, c'est-à-dire dans le domaine spatial. Pour cela, nous écrivons les développements de Taylor suivants :
On obtient les mêmes relations pour les variable $y$ et $z$. En prenant $h_{x}=size_{x}/N_{x}$, $h_{y}=size_{y}/N_{y}$ et $h_{z}=size_{z}/N_{z}$ avec la convention $\theta(x_{m},y_{m},z_{m})=\theta[i][j][k]$, on obtient :
Cette formule est implémentée de la façon ci-dessous pour la version parallélisée en langage C (fichier explUtilPar.c) ; à noter que les variables xs, xe, ys, ye, zs, ze représentent les coordonnées qui délimitent le sous-domaine correspondant au process de rank "me" :
// Perform an explicit update on the points within the domain
for (i=xs[me];i<=xe[me];i++)
for (j=ys[me];j<=ye[me];j++)
for (k=zs[me];k<=ze[me];k++)
x[i][j][k] = weightx*(x0[i-1][j][k] + x0[i+1][j][k] + x0[i][j][k]*diagx)
+ weighty*(x0[i][j-1][k] + x0[i][j+1][k] + x0[i][j][k]*diagy)
+ weightz*(x0[i][j][k-1] + x0[i][j][k+1] + x0[i][j][k]*diagz);
La convergence relie la solution exacte à la solution calculée numériquement. Si l'on a $h_{x}=h_{y}=h_{z}=h$, le schéma explicite \eqref{eq9} est trouvé stable si :
Cette condition de stabilité nous donne une estimation pour le choix du pas de temps $\Delta t$. Dans l'algorithme, nous choisissons :
\begin{equation}
\Delta t=\dfrac{1}{8\kappa}\,\text{min}(h_{x},h_{y},h_{z})^{2}
\label{11}
\end{equation}
Nous allons décomposer le domaine 3D (appelé aussi "grille") à calculer en différents sous-domaines cubiques en affectant pour chacun d'entre eux un processus. Le gain sur le temps d'exécution est obtenu en opérant parallèlement les calculs sur chaque sous-domaine et en mettant à jour, pour chaque itération, les 6 faces de chaque cube. On qualifie cette décomposition de "Topologie cartésienne de processus" car les sous-domaines sont des cubes ou des parallépipèdes. Nous prenons pour convention, dans la version Fortran90 et C, les indices (i,j) des tableaux utilisés tels que (i,j)=(ligne,colonne). Ci-dessous une figure montrant une décomposition avec 16 processus avec x_domains=2, y_domains=4 et z_domains=2 :
Figure 1 : Rangs des processus avec la convention (ligne,colonne)$\,\equiv\,$(x_domains,y_domains) et la dimension z_domains
En Fortran, les éléments d'un tableau 2D sont contigus en mémoire selon les colonnes : on dit qu'il est "column major". En langage C, c'est le contraire, les éléments sont contigus selon les lignes : il est qualifié de "row major".
La parallélisation implique de faire communiquer entre eux les processus de chaque sous-domaine. En effet, comme nous pouvons le voir dans le bout de code ci-dessous, pour une itération donnée avec un processus de rank "me", nous calculons les prochaines valeurs du sous-domaine correspondant grâce à la fonction "computeNext", puis nous envoyons, avec la fonction "updateBound" les faces de chaque cube (voir figure ci-dessous), c'est-à-dire les matrices, aux processus situés aux faces Nord-Sud, Est-Ouest, Avant-Arrière, du processus courant "me".
// Until convergence
while(!convergence)
{
step = step + 1;
t = t + dt ;
// Perform one step of the explicit scheme
computeNext(x0, x, dt, &resLoc, hx, hy, hz, me, xs, ys, zs, xe, ye, ze, k0);
// Update the partial solution along the interface
updateBound(x0, neighBor, comm3d, column_type, me, xs, ys, zs, xe, ye, ze,
xcell, ycell, zcell);
// Sum reduction to get error
MPI_Allreduce(&resLoc, &result, 1, MPI_DOUBLE, MPI_SUM, comm);
// Current error
result= sqrt(result);
// Break if convergence reached or step greater than maxStep
if ((result<epsilon) || (step>maxStep)) break;
}
La figure suivante est un exemple de communication pour une décomposition 3D du domaine global en 8 sous-domaines, autrement dit avec 8 processus. Un seul plan de 4 processus est affiché, il faut imaginer un second plan parallèle au premier pour représenter l'ensemble des 8 sous-domaines :
Figure 2 : Exemple de communications entre 8 processus
Comme dans le cas 2D, les cellules phantômes (ghost cells) sont initialisées en début de code à la valeur constante du bord de la grille.
Pour obtenir un gif animé représentant l'évolution temporelle de la diffusion, nous avons besoin des fichiers de données correspondant à des intervalles de temps différents. Nous utilisons pour cela le script generate_outputs_heat3d qui va les produire. Nous nous servons ensuite du script Matlab generate_gif_heat3d.m pour générer ce gif.
Voici une animation réalisée avec un maillage 32x64x16 :
Figure 3 : Gif animé montrant l'évolution de la température sur le domaine
Pour évaluer les performances du code, nous accomplissons un benchmark en faisant varier le nombre de processus pour 3 tailles de grilles différentes (64^3, 128^3 et 256^3). Le script run_benchmark_heat3d permet de générer les temps d'exécution pour chacun de ces deux paramètres.
Le graphique suivant, obtenu avec le script Matlab plot_performances_heat3d.m, synthétise ce benchmark :
Figure 4 : SpeedUp en fonction du nombre de processus et de la taille du domaine
Les performances pour 1 seul processus correspondent à l'exécution du code séquentiel. Pour un nombre de processus supérieur à 1 (versions parallélisées), les runtimes sont inférieurs à la version séquentielle. Nous remarquons que les meilleures performances sont obtenues avec 8 processus, indépendamment de la taille du maillage. Ceci peut s'expliquer par le fait que ce benchmark ait été réalisé avec un processeur i7 8 coeurs. En effet, le processeur i7 implémente "l'Hyper-Threading" ; dans notre cas, cette technique multitâche permet d'avoir une optimisation physique pour 8 processus et une optimisation logique pour un nombre plus élevé.
ps : contribuez comme moi au projet Cosmology@Home dont le but est d'affiner le modèle décrivant le mieux notre Univers.