python et hpc

64
Python et HPC Marc Daumas [email protected]

Upload: others

Post on 10-Feb-2022

19 views

Category:

Documents


0 download

TRANSCRIPT

Python et HPC

Marc Daumas

[email protected]

Première question :Identifier la ressource critique

• Limitation de la loi d’Amdahl

T total = T calculs parallélisés / # opérateurs + T gestion

• Données utilisées plusieurs fois

– Localité spatiale et temporelle

– Ré-utilisation croissante avec la taille du problème

• Passage à l’échelle

Multi-cœur, Multi-CPU, Supercalculateurs, GPU

Programmation efficace en C, C++, CUDA…

Puissance de calcul

• Mémoire principale

• Disque dur / SSD

• Réseau

• Caches (niveaux L1, L2 ou L3)

Utiliser plusieurs cœurs, CPU, machines…

• Problématique indépendante des outils de développement

Taille ouBande passante

• Grande latence (en mois ou en années)– Loi de Moore (puissance doublée tous les 18 mois)

• Onéreux 126 k€/an (Paris) à $160k/an (US)– AWS c3.large ponctuelle $0.0158/heure soit $138/an– Facteurs 913x ou 1159x

• Chasse aux bugs– Typiquement 80% de l’effort

« Ce que l'on conçoit bien s'énonce clairement,Et les mots pour le dire arrivent aisément. » Nicolas Boileau, L’Art Poétique (1674)

Développeur

• Fonctionnement en silos, cycle en V

– Compétence métier (biologie, physique…)

– Modélisation mathématique

– Développement informatique

• Obsolescences entre 2 et 5 ans

– Matériel et logiciel

– Fonctionnement plutôt qu’investissement

Python représente un solution attractive

Autres éléments

• Code responsable de la gestion des objets

– Création / destruction

– Ni ré-entrant ni compatible multi-threads

GIL : Global Interpreter Lock

• Modèles de parallélisme de Python

– Utilisation de bibliothèques

– Threads bloqués sur des entrées/sorties

Limitation de Python

Question 2 :Exemple de développement agile

• Présentation du problème

• Mise sous forme de système d’équations

• Résolution numérique

• Visualisation des résultats intermédiaires

• Intégration numérique

• Résultat de l’étude numérique

Plan

L’inspiration

Problème initial

Résultat intermédiaire

Problème à traiter

Evaluation et analyse de l’entropie générée par un écoulement anisotherme

Jean-Marc AVELLANEDA1*, Quentin NICOLAU1, Marc DAUMAS1, Françoise BATAILLE1

1PROMES CNRS, Rambla de la thermodynamique, Tecnosud, 66100 Perpignan

*(auteur correspondant : [email protected])

Résumé - Afin d’optimiser les récepteurs solaires des centrales thermodynamiques à concentration, il

importe de comprendre les écoulements turbulents convectifs fortement anisothermes. L’analyse de

l’entropie générée est un moyen d’investigation puis d’optimisation de leur performance. La présente

étude envisage cette problématique dans le cadre simplifié de la couche limite laminaire située au-

dessus d’une plaque à température différente de l’écoulement. Le fluide à vitesse et température fixées

dans la zone d’écoulement libre, subit en proche paroi et dans la couche limite les effets thermiques et

visqueux qui sont générateurs d’entropie. Nous étudions l’influence des paramètres thermiques

(température de paroi et écart de température entre la paroi et l’écoulement libre) sur l’importance et la

composition de la génération d’entropie locale et totale dans la couche limite.

Nomenclature

U ¥ Vitesse de l’écoulement libre,

1.m s-

T¥ Température de l’écoulement libre, K

wT Température de paroi, K

q Température adimensionnée (8)

t Paramètre thermique ( ( )w wT T T¥- )

TD Ecart de température wT T¥- , K

Taux d’entropie générée

genS¢¢¢& volumique, 1 3. .W K m- -

genS¢¢& surfacique, 1 2. .W K m- -

genS¢& linéique, 1 1. .W K m- -

3S , 2S , 1S : taux adimensionnés associés

respectivement à chacun des taux ci-dessus

1. Introduction

L’optimisation des récepteurs solaires de centrales solaires thermodynamiques à

concentration suppose de maximiser l’échange de chaleur entre le fluide caloporteur et les

parois exposées au rayonnement solaire concentré, tout en minimisant les pertes d’énergie par

frottement visqueux. Cet optimum peut être recherché en employant les techniques de

minimisation de l’entropie générée durant le processus d’échange [1], la perte de puissance

utile étant directement liée au taux de production d’entropie du fait des irréversibilités. L’optimum entropique peut par exemple être recherché à l’aide d’une méthode variationnelle

[2]. La connaissance du champ d’entropie au sein de l’écoulement permet de connaître les lieux et paramètres à optimiser. Les récepteurs solaires sont le siège d’écoulements turbulents

fortement anisothermes et asymétriques complexes [3][4][5] et il est utile d’effectuer une analyse du champ d’entropie dans une configuration plus abordable en premier lieu. La

théorie de la couche limite [6] offre un cadre idéal pour une première approche et a été

utilisée, par exemple, pour étudier l’influence de la vitesse de déplacement d’une plaque sur

l’entropie produite par l’écoulement externe d’un fluide [7]. Après avoir rappelé les équations

gouvernant la couche limite laminaire, nous dérivons les expressions de la production d’entropie et étudions son importance, sa composition relative entre facteurs thermiques et

visqueux ainsi que sa dépendance par rapport au rapport entre la température de paroi et

l’écart de température entre la paroi et l’écoulement libre.

Expérience considérée

• Un changement de variable

• Deux nouvelles équations différentielles

• Avec leurs conditions aux limites

Modélisation mathématique

h = yU

¥

nx

¢¢¢f +1

2f ¢¢f = 0 ¢¢q +

1

2Pr f ¢q = 0

f (0) = 0, ¢f (0) = 0, q(0) = 0

limh®¥

¢f (h) =1, limh®¥

q (h) =1

• Paramètres adimensionnés

• Création d’entropie pour le phénomène

• Existe-t-il un minimum ?

Création d’entropie élémentaire

q =T

w-T

DTt =

Tw

DTDT =T

w-T

¥

S3dxdydzò =

¢q 2

Rex

t -q( )2

h2

4Rex

+1æ

èçç

ö

ø÷÷+

Pr Ec

Rex

t -q( )¢¢f 2

é

ë

êêê

ù

û

úúú

dxdydzò

• Présentation du problème

• Mise sous forme de système d’équations

• Résolution numérique

• Affichage des résultats intermédiaires

• Intégration numérique

• Présentation des résultats

Plan

• On crée une classe équation différentielle et f

– Paramètre C dans l’équation différentielle de f

– Paramètre λ pour les conditions aux limites

– Un constructeur

class bvp_eq_diff:

class f(bvp_eq_diff):

def __init__ (self, λ = 0., C = 1.):

self.C, self.λ, f.ordre = C, λ, 3

Groupe d’équations similaires

• On se ramène à un système d’équations différentielles du premier ordre

– F vecteur contenant [f, f’, f’’]

– F’ est exprimé comme une fonction f.eq(η, F)

def eq (self, η, F):

"Vector expression of f'''+Cff'' = 0”

# F = [f , f' , f'' ]

# F' = [f' , f'' , -Cff'' ]

return [F[1], F[2], -self.C*F[0]*F[2]]

Réduire l’ordre de l’équation

• Conditions initiales ou IVP

– Initial Value Problem

• Critères

– Réel ou complexe

– Singularité et raideur

– Ordre de la solution, adaptabilité du pas

• Méthodes dans scipy.integrate.ode

vode, zvode, lsoda, dopri5, dop853

Problème de Cauchy

• BVP (Boundary Value Problem)

– Condition exprimée sous forme de résidu

– Basé sur les valeurs de F aux bornes de l’intervalle

– Le résidu tend vers 0

def bc(self, lower, upper):

"""Boundary condition (residual)

f(0) = 0, f'(0) = λ, f'(∞) = 1"""

return [lower[0], lower[1] - self.λ, upper[1]-1]

Conditions aux limites

• Présentation du problème

• Mise sous forme de système d’équations

• Résolution numérique

• Visualisation des résultats intermédiaires

• Intégration numérique

• Résultat de l’étude numérique

Plan

• Méthode avec les paramètres courants

– Vecteur F partout nul comme point de départ

– Tolérance sur la norme du résidu limitée à 10-8

class bvp_eq_diff:

def solve(self, η, guess = None,

tol = 1e-8, verbose = 0):

"""Solve differential equation with

BVP library function of scipy.integrate"""

if guess is None:

guess = self.guess(η)

Calcul de la solution(1/2)

• Calcul de la solution

• Vérification de l’absence d’erreur

res = solve_bvp(

fun = self.eq, bc = self.bc,

x = η, y = guess, tol = tol, verbose = verbose)

if not(res.success):

print ("Problem solving differential equation",

type(self).__name__,

"with C = %g and λ = %g" % (self.C, self.λ))

return res

Calcul de la solution(2/2)

• Calcul de la solution dont on connaît la forme

– L’infini est ramené à 5 ou 10

– 200 intervalles entre 0 et 5

η = np.linspace(0., 5., 201) # ∞ is 5

f_guess = np.zeros((3, η.size))

for λ in [1.5, 1.397, 1.294, 1.1566, 1.0536, 0.985,

0.5386, 0.1953, -0.107, -0.2511, -0.3198]:

f_res = f(λ).solve(η, f_guess)

plt.plot(η, f_res.sol(η)[1],

label=r"$f'(0) = %g$"%λ )

Création des objets et équations

• Présentation du problème

• Mise sous forme de système d’équations

• Résolution numérique

• Visualisation des résultats intermédiaires

• Intégration numérique

• Résultat de l’étude numérique

Plan

Figure initiale

Phénomène monotone !

Iteration Max residual Total nodes Nodes added

1 4.58e-02 201 399

2 2.70e-08 600 2

3 7.82e-09 602 0

Solved in 3 iterations, number of nodes 602, maximum

relative residual 7.82e-09.

Iteration Max residual Total nodes Nodes added

1 4.53e+00 201 400

2 7.04e-01 601 (1198)

Number of nodes is exceeded after iteration 2,

maximum relative residual 7.04e-01.

Messages de l’application

plt.plot(η, f_res.sol(η)[0], label="$f$" )

plt.plot(η, f_res.sol(η)[1], label="$f'$" )

plt.plot(η, f_res.sol(η)[2], label="$f''$" )

plt.legend(loc=1)

plt.show()

On continueavec λ = 0

class θ(bvp_eq_diff):

def __init__ (self, f, Pr = 1.):

self.f, self.Pr, θ.ordre = f, Pr, 2

def eq (self, η, TH):

"Vector expression of θ''+1/2Prfθ'= 0"

# TH = [θ , θ']

# TH' = [θ' ,-1/2Prfθ']

return [TH[1], -0.5*self.Pr*self.f(η)*TH[1]]

def bc(self, lower, upper):

"""Boundary condition (residual)

θ(0) = 1, θ(∞) = 0"""

return [lower[0]-1, upper[0]]

Traitement de la 2ème fonction

On peut maintenanttravailler avec f et θ

Rappel

On introduit trois intégrales paramétrées par

Création d’entropie

W1= w

1dh

0

¥

ò =¢q 2h2

t -q( )2

dh0

¥

ò =t

w¢q h

1-twq

æ

èçç

ö

ø÷÷

2

dh0

¥

ò

W2

= w2dh

0

¥

ò =¢q 2

t -q( )2

dh0

¥

ò =t

w¢q

1-twq

æ

èçç

ö

ø÷÷

2

dh0

¥

ò

W3= w

3dh

0

¥

ò =¢¢f 2

t -qdh

0

¥

ò =t

w¢¢f 2

1-twq

dh0

¥

ò

tw

=DT

Tw

S3=

¢q 2

Rex

t -q( )2

h2

4Rex

+1æ

èçç

ö

ø÷÷+

Pr Ec

Rex

t -q( )¢¢f 2

def ω1_fct (η, θ, τw):

return ((τw*θ[1]*η)/(1 - τw*θ[0]))**2

def ω2_fct (η, θ, τw):

return ( τw*θ[1] /(1 - τw*θ[0]))**2

def ω3_fct (f, θ, τw):

return τw*f[2]**2/(1 - τw*θ[0])

τw_min = 0. # python2 proof

τw_max = 1.

τw_steps = 20

τw_pt = np.linspace(τw_min, τw_max, τw_steps+1)

Expression des radicaux en Python

Forme des radicaux pour τ = 2

Qualité de l’approximation par une gaussienne

Héritée de FuncAnimation dans matplotlib

class MyAnim(FuncAnimation):

def __init__(self, fig, interval = 100):

self.ax, self.lines = fig.add_subplot(1,1,1), {}

FuncAnimation.__init__(

self, fig, self.toutes,

frames=τw_pt[1:], interval = interval)

Une classe pour nos animations

def etape (self, key, x, y, style = "-",

label = None, w = 0):

if w == 0: w = 1/max(y)

y *= w

if key in self.lines:

self.lines[key].set_ydata(y)

else:

self.lines[key], = self.ax.plot(

x, y, style, label = label)

plt.legend(loc=1)

return w

Dictionnaire des courbes

def toutes (self, τw):

self.ω1 (τw)

self.etape("ω2", η, ω2_fct(η , θ_pt, τw),

label = "$ω2/||ω2||_{\infty}}$")

self.etape("ω3", η, ω3_fct(f_pt, θ_pt, τw),

label = "$ω3/||ω3||_{\infty}}$")

self.ax.set_xlabel("$τ=$ {0:6.2f}".format(1/τw))

Les courbes normales

Comparaison avec une distribution normale

– Calcul des paramètres

– Tracé de la fonctiondef ω1 (self, τw):

y = ω1_fct(η, θ_pt, τw)

Ns_ω, Ns_μ, Ns_σ = norm_approx (y, η, dη)

Ns = Ns_ω*st.norm(Ns_μ, Ns_σ).pdf(η)

w = self.etape("ω1", η, y,

label = "$ω1/||ω1||_{\infty}}$")

w = self.etape("N(ω1)", η, Ns, ':', w = w,

label = "$N(ω1)/||ω1||_{\infty}}$”)

Les courbes de ω1

Evolution de la formedes radicaux selon τ

• Présentation du problème

• Mise sous forme de système d’équations

• Résolution numérique

• Visualisation des résultats intermédiaires

• Intégration numérique

• Résultat de l’étude numérique

Plan

Méthodes disponibles à partir des valeurs

• Trapèzestrapz(ω1_fct(η, θ_pt, τw), dx = dη)

• Simpsonsimps(ω1_fct(η, θ_pt, τw), dx = dη)

• Romberg

Le nombre d’intervalles doit être une puissance de 2romb(ω1_fct(η, θ_pt, τw), dx = dη)

Bibliothèque scipy.integrate

τw_steps = 200

τw_pt = np.linspace(τw_min, τw_max, τw_steps+1)

Ω1 = np.array(

[simps (ω1_fct (η , θ_pt, τw), dx = dη)

for τw in τw_pt])

Ω2 = np.array(

[simps (ω2_fct (η , θ_pt, τw), dx = dη)

for τw in τw_pt])

Ω3 = np.array(

[simps (ω3_fct (f_pt, θ_pt, τw), dx = dη)

for τw in τw_pt])

Bibliothèque scipy.integrate

Lecture des courbes log-log

• Présentation du problème

• Mise sous forme de système d’équations

• Résolution numérique

• Visualisation des résultats intermédiaires

• Intégration numérique

• Résultat de l’étude numérique

Plan

def qpoly_approx (x, y, deg = 4, label = None):

approx = st.linregress(log(x), log(y))

poly = cheb2poly(

chebfit(x, y/(x**(approx.slope)), deg))[::-1]

if label is not None :

print (label % approx.slope)

print (poly1d(poly), "\n")

return approx.slope, poly

Ω1_deg, Ω1_pol = qpoly_approx(τw_pt, Ω1,

label = "Ω1(τ) = P1(1/τ)/τ**%g with P1(x) =”)

Regression linéaire

Ω1(τ) = P1(1/τ)/τ**2.09858 with P1(x) =

4 3 2

46.17 x - 54.15 x + 23.08 x - 3.805 x + 1.124

Ω2(τ) = P2(1/τ)/τ**2.2015 with P2(x) =

4 3 2

56.7 x - 65.2 x + 27.33 x - 4.474 x + 0.6957

Ω3(τ) = P3(1/τ)/τ**1.09734 with P3(x) =

4 3 2

17.1 x - 20 x + 8.53 x - 1.412 x + 0.4194

Bibliothèque scipy.integrate

Qualité de l’approximation

• L’intégrale initiale se réecrit avec

• Tous les termes sont des puissances de x ou τ

• L’intégration analytique est possible dès que le lien entre x, z et τ est suffisamment simple

• Le minimum de création d‘entropie du phénomène peut être calculé

Création d’entropie du phénomène

S3dxdyò dz=

1

Rex

W1

4Rex

+W2+ Pr EcW

3

æ

èçç

ö

ø÷÷

nx

dxdzò

Rex

=U

¥x

n

Géométrie de la zone de transfert dans une centrale à tour

Question 3 :Parce que les performances comptent

L’inspiration

• Algorithme k-means pour l’enseignement

– Cours Algorithmes et Programmation Parallèle

– Embarrassingly parallel (@scale)

• Recherche parallèle de la valeur de k (trop facile )

• Distribution des données– Diviser pour régner & Introduction à Hadoop

• Parallélisation multi-thread, multi-proc, cluster…

• Bonne préparation d’un stage– Entreprise, association, collectivité territoriale…

– Carte des clients, adhérents, usagers...

Réécriture des fonctions - Exemple

def reevaluate_centers(mu, G, w):

return

[x/w[i] if w[i] else mu[i]

for i, x in enumerate(G)]

def has_converged(mu1, mu2):

return (

set([tuple(a) for a in mu1])

== set([tuple(a) for a in mu2]))

Améliorations

12912261 function calls (12912246 primitive calls) in 9.996 seconds

ncalls tottime percall cumtime percall filename:lineno(function)

1395856 3.525 0.000 6.971 0.000 linalg.py:2022(norm)

116160 1.804 0.000 8.776 0.000 kmeans.py:17(<listcomp>)

1395856 1.034 0.000 1.034 0.000 numpy.core.multiarray.dot

1395856 0.817 0.000 0.817 0.000 ravel

1395856 0.682 0.000 0.846 0.000 numeric.py:463(asarray)

60 0.642 0.011 9.991 0.167 kmeans.py:8(cluster_points)

1395856 0.397 0.000 0.562 0.000 linalg.py:111(isComplexType)

116160 0.396 0.000 0.553 0.000 builtins.min

2791731 0.353 0.000 0.353 0.000 builtins.issubclass

1395856 0.164 0.000 0.164 0.000 numpy.core.multiarray.array

Profilage (avant)

308 function calls in 0.009 seconds

ncalls tottime percall cumtime percall filename:lineno(function)

5 0.009 0.002 0.009 0.002 cymeans.find_centers

5 0.000 0.000 0.000 0.000 builtins.print

5 0.000 0.000 0.000 0.000 random.py:289(sample)

60 0.000 0.000 0.000 0.000 random.py:229(_randbelow)

10 0.000 0.000 0.000 0.000 abc.py:178(__instancecheck__)

10 0.000 0.000 0.000 0.000 builtins.isinstance

15 0.000 0.000 0.000 0.000 _weakrefset.py:70(__contains__)

5 0.000 0.000 0.000 0.000 math.log

62 0.000 0.000 0.000 0.000 'getrandbits' of '_random.Random‘

60 0.000 0.000 0.000 0.000 'add' of 'set‘

Profilage (après)

• Abandonnée grâce à un décorateur Python

@boundscheck(False)

Vérification des bornes des tableaux

• Remplacé par un typage statique

cdef int reevaluate_centers(

int K,

double[:,:] mu,

double[:,:] G,

double[:] w) nogil:

Typage dynamique des paramètres

• Déclarations explicites et typées

• Sortir toutes les créations et destructions des boucles intérieures

cdef int changed = 0

cdef double temp

Variables

Evolutions d’un code fonctionnel

Non régressionfor i in range(K):

if w[i]:

temp = G[i,0]/w[i]

if (temp != mu[i,0]):

changed = 1; mu[i,0] = temp

temp = G[i,1]/w[i]

if (temp != mu[i,1]):

changed = 1; mu[i,1] = temp

return changed

Algorithme en place

Question 4 :MPI4Py

Marc Daumas

Quatre fonctions à connaître (6 en C)

from mpi4py import MPI

comm = MPI.COMM_WORLD

rank = comm.Get_rank()

size = comm.Get_size()

if rank == 0:

data = {'a': 7, 'b': 3.14}

comm.send(data, dest=1, tag=11)

elif rank == 1:

data = comm.recv(source=0, tag=11)

Modèlemaître/esclace

data = comm.bcast(data, root=0)

data = comm.scatter(data, root=0)

data = comm.gather(data, root=0)

Traitement spécifique pour les tableaux NumPy

comm.Bcast(data, root=0)

comm.Scatter(sendbuf, recvbuf, root=0)

comm.Gather(sendbuf, recvbuf, root=0)

comm.Allgather([x, MPI.DOUBLE], [xg, MPI.DOUBLE])

Communications globales

Conclusion :Faire porter ses efforts

sur la ressource critique

Marc Daumas

[email protected]