Ce document traite de la résolution de l'équation de Poisson bidimensionnelle par la méthode des éléments finis. La page Équation de Poisson 1D : méthode des éléments finis développe le cas unidimensionel.
Soit un domaine de de frontière . Soient deux fonctions et . On recherche une fonction deux fois dérivable vérifiant l'équation différentielle
Par exemple dans un problème de diffusion thermique, u désigne la température, a est la conductivité thermique et s est la source thermique. Dans un problème d'électrostatique u est le potentiel, a la permittivité électrique et s la densité volumique de charge. Cette équation aux dérivées partielles est plus générale que l'équation de Poisson mais se ramène à celle-ci dans un milieu homogène, c'est-à-dire lorsque a est uniforme :
On se place dans le cas de coordonnées cartésiennes, qui correspond à un problème invariant par translation dans la direction Z. On a donc :
Pour que l'équation admette une unique solution, il faut définir des conditions limites sur .
Pour une fonction de classe C1, on a :
où désigne le vecteur unitaire orthogonal à et dirigé dans le sens sortant par rapport à . La même égalité est évidemment valable pour la coordonnée y. Appliquons ce théorème à :
On obtient :
et de même :
La somme de ces deux égalités conduit à :
qui devient, en utilisant l'équation :
Cette égalité est écrite dans le cas bidimensionnel, où est une surface plane et le contour de cette surface. est donc l'élément de surface et l'élément du contour. Le même résultat est bien sûr valable en tridimensionnel ( est alors un volume et la surface qui le délimite).
Soit V l'ensemble des fonctions de carré sommable et dont le gradient est aussi de carré sommable sur .
La formulation variationnelle du problème (la recherche de u) s'énonce ainsi [1] : on recherche une fonction telle que pour toute fonction on ait l'égalité . Cet énoncé est souvent appelé forme faible du problème de Poisson car les exigences sur la fonction u sont moindres que pour l'équation (elle n'est plus nécessairement deux fois dérivable).
Séparons la frontière du domaine en deux parties : la partie sur laquelle une condition limite de Dirichlet est imposée, la partie sur laquelle une condition limite de Neumann est imposée. L'égalité s'écrit :
Comme il est montré dans Équation de Poisson 1D : méthode des éléments finis, la formulation variationnelle doit être modifiée en considérant les fonctions de V qui s'annulent sur . Notons V0 l'ensemble de ces fonctions. La formulation variationnelle devient : obtenir une fonction u telle que pour toute fonction :
La condition de Neumann consiste à fixer la valeur de sur . Une variante de la condition de Neumann est la condition de Robin, qui consiste à écrire sur la frontière :
où K0, u0 et g0 sont des constantes. Pour K0=0, on retrouve la condition de Neumann avec g0 la composante normale du gradient sur la frontière. Plus généralement, ces trois constantes peuvent dépendre du point de la frontière (auquel cas il ne s'agit plus de constantes). Dans ce document, on nommera condition de Neumann la condition définie par l'équation .
Finalement, l'égalité de la formulation variationnelle s'écrit :
Le domaine est subdivisé en triangles : chaque maille est un triangle et comporte donc trois nœuds. Une maille partage avec une maille voisine deux nœuds. La figure suivante montre un maillage triangulaire très simple pour un domaine rectangulaire (celui que nous utiliserons pour les tests) :
Figure pleine pageLe maillage comporte P nœuds. Le nœud Ni a pour coordonnées (xi,yi). En général, les nœuds ne sont évidemment pas disposés sur une grille.
Les fonctions u et v du problème variationnel sont considérées dans l'ensemble, noté Vh, des fonctions continues et affines par morceaux sur le maillage (l'indice h désigne le maillage). Pour on a sur chaque maille : . Si les mailles sont assez petites, les valeurs de uh aux nœuds sont censées être de bonnes approximations de u, la solution de l'équation avec les conditions limites. La fonction uh est une solution du problème variationnel mais elle n'est évidemment pas une solution de .
Si l'on note et les coefficients de uh pour deux mailles voisines, on a sur le côté commun à ces deux mailles, par continuité :
ce qui est l'équation de la droite passant par les deux nœuds communs. On a bien évidemment :
où sont les coefficients d'un des trois triangles qui partagent le nœud Ni.
On définit les fonctions affines par morceaux suivantes, pour :
Autrement dit, la fonction vaut 1 sur le nœud Ni et 0 sur tous les autres nœuds. Ces fonctions constituent une base Vh. Pour toute fonction , on a en effet :
Le support de est constitué des triangles qui ont le nœud Ni en commun. La figure suivante montre le support de et de :
Figure pleine pagePour un noeud Ni, la fonction s'annule sur le côté opposé de chaque triangle auxquels ce nœud appartient.
Considérons un nœud Ni et ses nœuds voisins. Le support de est constitué des triangles définis avec le nœud Ni et ces voisins. La figure suivante montre ces triangles :
Figure pleine pageConsidérons un de ces triangles, dont les sommets sont notés 1,2,3, le sommet 1 étant le nœud Ni. Les coefficients de sur ce triangle sont solutions des trois équations suivantes :
Si detT désigne le déterminant de ce système, il est facile de démontrer que, si les sommets N1,N2,N3 sont ordonnés dans le sens direct, l'aire du triangle s'écrit :
Si les trois points ne sont pas alignés, ce système a un déterminant non nul. L'unique solulion peut être obtenue sans difficulté avec les règles de Cramer :
Soit Vh,0 l'ensemble des fonctions affines par morceaux sur le maillage et qui s'annulent sur les nœuds qui appartiennent à la frontière (la partie de la frontière où une condition de Dirichlet est appliquée). Notons les indices de tous les nœuds à l'exception de ces nœuds (indices des nœuds intérieurs). Pour toute fonction on a :
La formulation variationnelle s'énonce comme suit. Trouver une fonction telle que pour toute fonction on ait :
Un énoncé équivalent est : trouver une fonction telle que :
Introduisons les composantes de uh sur la base :
Les sont les valeurs de uh aux nœuds, autrement dit les approximations de la solution u. Le report de cette décomposition dans conduit à un système d'équations linéaires pour les composantes :
Ce système comporte plus d'inconnues que d'équations : le nombre d'équations est égal aux nombres de nœuds à l'exception de ceux de la frontière où une condition de Dirichlet est appliquée alors que le nombre d'inconnues est égal aux nombre total de nœuds. Il faut donc enlever du système les des nœuds qui sont sur . Pour cela, on écrit uh comme la somme d'une fonction de Vh,0 (qui s'annule sur la frontière de Dirichlet) et d'une fonction de Vh,d, l'ensemble des fonctions affines par morceaux qui vérifient précisément la condition de Dirichlet choisie :
Il peut être démontré que uh est indépendant du choix de uh,d [1]. On choisit donc la fonction la plus simple : celle qui s'annule sur tous les nœuds à l'exception de ceux où la condition de Dirichlet est appliquée. Notons Nd les indices des nœuds où une condition de Dirichlet est appliquée. On a :
Les dans la seconde somme sont connues puisqu'il s'agit des valeurs de u sur les nœuds appartenant à la frontière où une condition de Dirichlet est appliquée.
On obtient un système d'équations pour les inconnues :
Réécrivons ces équations en mettant à gauche la combinaison linéaire des inconnues :
Posons :
Le système d'équations linéaires s'écrit :
La matrice du système d'équations est M=A+R. La matrice A est indépendante des conditions limites. La matrice R est non nulle seulement si une condition de Robin () est appliquée sur une partie de la frontière .
Pour , le coefficient Aij est non nul si les nœuds i et j ont une partie de leur support en commun, autrement dit si ce sont deux nœuds voisins (rappelons que les nœuds où une condition de Dirichlet est appliquée sont exclus). Pour évaluer approximativement l'intégrale sur un triangle T dont les sommets sont N1,N2,N3, on utilise la formule de quadrature du barycentre :
où ST est l'aire du triangle. Considérons , l'intégrale sur un des deux triangles dont un côté est constitué des nœuds i et j, le troisième étant noté Nk. Soient les coefficients qui définissent sur ce triangle et les coefficients qui définissent sur le même triangle.
Figure pleine pageOn a :
La formule du barycentre donne :
En pratique, il sera plus simple d'attribuer une valeur de a à chaque nœud et on écrira donc :
Pour chacun des triangles auxquels le nœud Ni appartient, on calcule ATij pour les deux autres nœuds (d'indice ) et on ajoute le résultat au coefficient Aij de la matrice (pour chaque sommet voisin, il y a deux termes).
Il faut aussi déterminer le coefficient sur la diagonale :
Le support de la fonction à intégrer est constitué des triangles auquel le nœud Ni appartient. Pour un de ces triangles, l'intégrale vaut approximativement :
Pour , Rij est non nul si les deux nœuds Ni et Nj sont voisins et s'ils appartiennent à une frontière où une condition de Robin est appliquée.
Figure pleine pageLe produit est non nul sur le triangle constitué de ces deux nœuds et du nœud Nk. Rij est l'intégrale sur le segment NiNj de . Les coefficients a et K0 seront dans la plupart des cas constants sur le segment ou peuvent être considérés comme tel. Si est l'abscisse sur le segment, on a :
où d est la distance entre les deux nœuds. On a donc :
Il faut aussi déterminer le coefficient sur la diagonale :
La fonction à intégrer est non nulle sur les deux segments (notés 1 et 2) de la frontière auquel le nœud Ni appartient :
Figure pleine pageNotons a1,K1 et a2,K2 les valeurs des coefficients aux milieux des segments 1 et 2. On a :
Les matrices A et R sont symétriques. La ligne i de la matrice A comporte un coefficient diagonal et des coefficients non diagonaux correspondant aux nœuds voisins du nœud Ni. La ligne i de la matrice R comporte un coefficients diagonal et des coefficients non diagonaux correspondant aux nœuds voisins de Ni situés sur le bord .
Rappelons que tous les nœuds qui interviennent dans le calcul de ces deux matrices sont des nœuds intérieurs, c'est-à-dire qu'il faut exclure les nœuds où une condition de Dirichlet et appliquée.
Il faut expliciter les coefficients de la matrice colonne B. Le premier terme de Bij est :
Pour (nœud intérieur), il faut considérer les nœuds Nk (de la frontière où une condition de Dirichlet est appliquée) tels que le support de ait une partie commune avec celui de . est non nul si et seulement si Ni est voisin d'un nœud de la frontière de Dirichlet. La figure suivante montre un nœud de ce type et les triangles qui constituent la partie commune des supports.
Figure pleine pageL'intégrale sur un triangle se calcule comme indiqué plus haut au sujet de Aij. Pour le nœud Nk voisin de Ni, dont la valeur est , l'intégrale se fait sur deux triangles, les deux triangles qui partagent le côté NiNk. Pour chacun des triangles auxquels le nœuds Ni appartient, on repère parmi les deux autres nœuds ceux qui sont sur la frontière de Dirichlet puis on ajoute le terme correspondant dans Bi. Pour chaque triangle auquel le nœud Ni appartient, on identifie ceux pour lesquels au moins un des deux autres nœuds est sur un bord de Dirichlet (triangles grisés sur la figure ci-dessus). À chacun de ces triangles correspond un ou deux termes dans .
Le deuxième terme de Bij est :
Il s'agit du terme qui contient la source de l'équation de Poisson. Pour , il faut évaluer l'intégrale sur le support de , qui est constitué des triangles auxquels ce nœud appartient. Pour un de ces triangles, dont les sommets sont N1,N2,N3, la formule de quadrature du barycentre donne :
La fonction vaut 1/3 au barycentre. Pour la source, on considère plutôt la moyenne des valeurs aux sommets du triangle :
Le troisième terme de Bij est :
Ce coefficient peut être non nul s'il existe un nœud Nk de la frontière de Dirichlet tel que soit non nul sur au moins un segment de la frontière de Neumann. Cela ne peut se rencontrer qu'à la jonction entre ces deux frontières, comme le montre la figure suivante :
Figure pleine pageL'intégrale se fait sur le segment NkNi. Le calcul est similaire à celui du coefficient Rij. On obtient :
où d est la distance NkNi.
Le quatrième terme de Bij est :
Ce terme contient la condition de Neumann (gradient g0) et le terme constant de la condition de Robin. Il est non nul si et seulement si le nœud Ni appartient à la frontière . L'intégrale se fait sur le ou les deux segments de la frontière adjacents à ce nœud.
La structure de données qui contient la définition du maillage est une liste de nœuds qui est générée au moment de la création du maillage. Chaque nœud Ni est un objet qui contient les informations suivantes :
import numpy as np
import scipy.sparse as sparse
import scipy.sparse.linalg as linalg
from scipy.linalg import solve
DIR = 1
NEU = 2
class Noeud:
def __init__(self,x,y,a,s,lim=0,ksi=0,K0=0,u0=0,g0=0,bord=False):
self.xy = np.array([x,y])
self.x = x
self.y = y
self.a = a
self.s = s
self.lim = lim
self.ksi = ksi
self.K0 = K0
self.u0 = u0
self.g0 = g0
self.noeuds_voisins = []
self.indice = 0 # indice dans le maillage
self.bord= bord
def ajouterVoisin(self,noeud):
self.noeuds_voisins.append(noeud)
def extraireTriangles(self):
N = len(self.noeuds_voisins)
triangles = []
for i in range(N-1):
n1 = self
n2 = self.noeuds_voisins[i]
n3 = self.noeuds_voisins[i+1]
triangles.append([n1,n2,n3])
if not(self.bord):
n1 = self
n2 = self.noeuds_voisins[N-1]
n3 = self.noeuds_voisins[0]
triangles.append([n1,n2,n3])
return triangles
La fonction extraireTriangles extrait la liste des triangles auxquels le nœud appartient. Chaque triangle est une liste de trois nœuds, le premier étant le nœud central. Dans un triangle, les nœuds sont rangés dans le sens direct, c'est-à-dire que . Lorsqu'un nœud n'est pas sur un bord, le dernier nœud de la liste des voisins forme un triangle avec le premier.
class ElementsFinis2D:
def __init__(self):
self.noeuds_dirichlet = []
self.noeuds = []
self.indice = 0
self.indice_dirichlet = 0
def ajouterNoeud(self,noeud):
if noeud.lim == DIR:
noeud.indice = self.indice_dirichlet
self.noeuds_dirichlet.append(noeud)
self.indice_dirichlet += 1
else:
noeud.indice = self.indice
self.noeuds.append(noeud)
self.indice += 1
def definirMaillage(self,maillage):
self.noeuds_dirichlet = []
self.noeuds = []
self.indice = 0
self.indice_dirichlet = 0
for noeud in maillage:
self.ajouterNoeud(noeud)
def fonctionPhi(self,triangle):
n1 = triangle[0]
n2 = triangle[1]
n3 = triangle[2]
detT = n2.x*n3.y-n2.x*n1.y-n1.x*n3.y-n2.y*n3.x+n2.y*n1.x+n1.y*n3.x
if detT <=0 :
print("Erreur de définition du triangle")
print(n1.xy)
print(n2.xy)
print(n3.xy)
ST = 0.5*detT
c0 = (n2.y-n3.y)/detT
c1 = (n3.x-n2.x)/detT
c2 = (n2.x*n3.y-n3.x*n2.y)/detT
return [ST,c0,c1,c2]
def creerMatrices(self):
self.Nnoeuds = len(self.noeuds)
self.M = np.zeros((self.Nnoeuds,self.Nnoeuds),dtype=np.float64)
self.B = np.zeros(self.Nnoeuds,dtype=np.float64)
def matriceA(self):
for i in range(self.Nnoeuds):
Ni = self.noeuds[i]
triangles = Ni.extraireTriangles()
Aii = 0
for t in range(len(triangles)):
[ST,ci0,ci1,ci2] = self.fonctionPhi(triangles[t])
Aii += (triangles[t][0].a+triangles[t][1].a+triangles[t][2].a)/3*(ci0*ci0+ci1*ci1)*ST
if triangles[t][1].lim != DIR:
j = triangles[t][1].indice
[ST,cj0,cj1,cj2] = self.fonctionPhi([triangles[t][1],triangles[t][2],triangles[t][0]])
self.M[i,j] += (triangles[t][0].a+triangles[t][1].a+triangles[t][2].a)/3*(ci0*cj0+ci1*cj1)*ST
if triangles[t][2].lim != DIR:
j = triangles[t][2].indice
[ST,cj0,cj1,cj2] = self.fonctionPhi([triangles[t][2],triangles[t][0],triangles[t][1]])
self.M[i,j] += (triangles[t][0].a+triangles[t][1].a+triangles[t][2].a)/3*(ci0*cj0+ci1*cj1)*ST
self.M[i,i] += Aii
def matriceR(self):
for i in range(self.Nnoeuds):
Ni = self.noeuds[i]
Rii = 0
if Ni.lim==NEU:
for n in Ni.noeuds_voisins:
if n.lim == NEU:
d = np.sqrt((Ni.x-n.x)**2+(Ni.y-n.y)**2)
Rii += -(Ni.a*Ni.K0+n.a*n.K0)/2*d/3
j = n.indice
self.M[i,j] += -1/6*(Ni.a*Ni.K0+n.a*n.K0)/2*d
self.M[i,i] += Rii
def matriceB1(self):
for i in range(self.Nnoeuds):
B1i = 0
Ni = self.noeuds[i]
triangles = Ni.extraireTriangles()
for t in range(len(triangles)):
[ST,ci0,ci1,ci2] = self.fonctionPhi(triangles[t])
if triangles[t][1].lim == DIR :
[ST,cj0,cj1,cj2] = self.fonctionPhi([triangles[t][1],triangles[t][2],triangles[t][0]])
B1i += -triangles[t][1].ksi*(triangles[t][0].a+triangles[t][1].a+triangles[t][2].a)/3*(ci0*cj0+ci1*cj1)*ST
if triangles[t][2].lim == DIR:
[ST,cj0,cj1,cj2] = self.fonctionPhi([triangles[t][2],triangles[t][0],triangles[t][1]])
B1i += -triangles[t][2].ksi*(triangles[t][0].a+triangles[t][1].a+triangles[t][2].a)/3*(ci0*cj0+ci1*cj1)*ST
self.B[i] += B1i
def matriceB2(self):
for i in range(self.Nnoeuds):
B2i = 0
Ni = self.noeuds[i]
triangles = Ni.extraireTriangles()
for t in range(len(triangles)):
[ST,ci0,ci1,ci2] = self.fonctionPhi(triangles[t])
B2i += (triangles[t][0].s+triangles[t][1].s+triangles[t][2].s)/9*ST
self.B[i] += B2i
def matriceB3(self):
for i in range(self.Nnoeuds):
Ni = self.noeuds[i]
if Ni.lim == NEU:
B3i = 0
for n in Ni.noeuds_voisins:
if n.lim == DIR:
d = np.sqrt((Ni.x-n.x)**2+(Ni.y-n.y)**2)
B3i += n.ksi*(Ni.a*Ni.K0+n.a*n.K0)/2*d/6
self.B[i] += B3i
def matriceB4(self):
for i in range(self.Nnoeuds):
Ni = self.noeuds[i]
if Ni.lim == NEU:
B4i = 0
for n in Ni.noeuds_voisins:
if n.lim == NEU:
d = np.sqrt((Ni.x-n.x)**2+(Ni.y-n.y)**2)
B4i += 0.5*(Ni.a*(Ni.g0-Ni.K0*Ni.u0)+n.a*(n.g0-n.K0*n.u0))*0.5*d
self.B[i] += B4i
def solve(self,solver="iterative"):
self.creerMatrices()
self.matriceA()
self.matriceR()
self.matriceB1()
self.matriceB2()
self.matriceB3()
self.matriceB4()
if solver=="iterative":
M = sparse.bsr_array(self.M)
ksi,exitCode = linalg.cg(M, self.B, atol=1e-5)
print("exitCode : ",exitCode)
else:
ksi = solve(self.M,self.B)
for i in range(self.Nnoeuds):
self.noeuds[i].ksi = ksi[i]
La fonction ajouterNoeud ajoute un nœud, soit dans la liste des nœuds internes, soit dans la liste des nœuds d'une frontière de Dirichlet. L'indice dans la liste est affecté au nœud. La fonction definirMaillage définit le maillage complet donné par une liste de nœuds.
La fonction fonctionPhi calcule, pour un triangle donné (liste de trois nœuds), l'aire ST et les coefficients c0,c1,c2 de la fonction relative au premier nœud du triangle.
La fonction creerMatrices crée les deux matrices qui définissent le système linéaire. Les fonctions matriceX remplissent ces matrices en calculant les différents coefficients Aij,Rij,B1i,B2i,B3i,B4i.
La fonction solve appelle les fonctions de création et de remplissage précédentes et calcule la solution du système, par défaut par la méthode itérative du gradient conjugué. Les valeurs de obtenues sont affectées aux nœuds.
On considère le domaine carré . La source est nulle (s=0) et le coefficient a est uniforme (le même partout). En x=0 et x=1 on applique des conditions limites de Dirichlet, avec respectivement les valeurs 0 et 1. En y=0 et y=1 on applique des conditions de Neumann avec g0=0. La solution est : u(x,y)=x (il s'agit en fait d'un problème unidimensionnel).
La structure du maillage est montré sur la figure suivante :
Figure pleine pageLes 4 nœuds des coins sont affectés de la condition de Dirichlet. Chaque nœud non situé sur un bord a 6 nœuds voisins.
Il s'agit de générer la liste des nœuds puis d'attribuer les voisins de chaque nœud. Soit N le nombre de nœuds sur chaque axe.
N = 50
x = np.linspace(0,1,N)
y = np.linspace(0,1,N)
maillage = []
a = 1
s = 0
for j in range(N):
for i in range(N):
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n = Noeud(x[i],y[j],a,s)
else:
if i==0:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif i==N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=1,bord=True)
if j==0 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,bord=True)
elif j==N-1 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,bord=True)
maillage.append(n)
L'attribution des voisins pour chaque nœud dépend seulement du maillage. On la réalise donc dans une fonction afin de pouvoir la réutiliser pour d'autres exemples :
def attribuerVoisins(N,maillage):
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n.ajouterVoisin(maillage[indice+1])
n.ajouterVoisin(maillage[indice+N+1])
n.ajouterVoisin(maillage[indice+N])
n.ajouterVoisin(maillage[indice-1])
n.ajouterVoisin(maillage[indice-1-N])
n.ajouterVoisin(maillage[indice-N])
else:
if i==0 and j==0:
n.ajouterVoisin(maillage[indice+1])
n.ajouterVoisin(maillage[indice+N+1])
n.ajouterVoisin(maillage[indice+N])
elif i==0 and j==N-1:
n.ajouterVoisin(maillage[indice-N])
n.ajouterVoisin(maillage[indice+1])
elif i==0:
n.ajouterVoisin(maillage[indice-N])
n.ajouterVoisin(maillage[indice+1])
n.ajouterVoisin(maillage[indice+N+1])
n.ajouterVoisin(maillage[indice+N])
if i==N-1 and j==0:
n.ajouterVoisin(maillage[indice+N])
n.ajouterVoisin(maillage[indice-1])
elif i==N-1 and j==N-1:
n.ajouterVoisin(maillage[indice-1])
n.ajouterVoisin(maillage[indice-1-N])
n.ajouterVoisin(maillage[indice-N])
elif i==N-1:
n.ajouterVoisin(maillage[indice+N])
n.ajouterVoisin(maillage[indice-1])
n.ajouterVoisin(maillage[indice-1-N])
n.ajouterVoisin(maillage[indice-N])
if j==0 and i!=0 and i!=N-1:
n.ajouterVoisin(maillage[indice+1])
n.ajouterVoisin(maillage[indice+N+1])
n.ajouterVoisin(maillage[indice+N])
n.ajouterVoisin(maillage[indice-1])
if j==N-1 and i!=0 and i!=N-1:
n.ajouterVoisin(maillage[indice-1])
n.ajouterVoisin(maillage[indice-N-1])
n.ajouterVoisin(maillage[indice-N])
n.ajouterVoisin(maillage[indice+1])
indice+= 1
attribuerVoisins(N,maillage)
Pour le maillage considéré, il est aisé de tracer u(x,y) car les nœuds sont disposés sur une grille. Dans le cas général, il faudra procéder à une interpolation dans les triangles (par la fonction affine par morceaux) pour obtenir les valeurs de u sur une grille.
elem = ElementsFinis2D()
elem.definirMaillage(maillage)
elem.solve()
U = np.zeros((N,N),dtype=np.float64)
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
U[j,i] = n.ksi
indice+= 1
from matplotlib.pyplot import *
figure()
contour(U,10,extent=(0,1,0,1))
fig1.pdf
figure()
plot(x,U[N//2,:])
grid()
fig2.pdf
On reprend l'exemple A avec une source uniforme et des conditions de Dirichlet nulle en x=0 et x=1 :
N = 50
x = np.linspace(0,1,N)
y = np.linspace(0,1,N)
maillage = []
a = 1
s = 1
for j in range(N):
for i in range(N):
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n = Noeud(x[i],y[j],a,s)
else:
if i==0:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif i==N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
if j==0 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,bord=True)
elif j==N-1 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,bord=True)
maillage.append(n)
attribuerVoisins(N,maillage)
elem = ElementsFinis2D()
elem.definirMaillage(maillage)
elem.solve()
U = np.zeros((N,N),dtype=np.float64)
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
U[j,i] = n.ksi
indice+= 1
from matplotlib.pyplot import *
figure()
contour(U,10,extent=(0,1,0,1))
fig3.pdf
figure()
plot(x,U[N//2,:])
grid()
fig4.pdf
On reprend l'exemple A avec une source uniforme et des conditions de Dirichlet nulle sur les quatre bords :
N = 50
x = np.linspace(0,1,N)
y = np.linspace(0,1,N)
maillage = []
a = 1
s = 1
for j in range(N):
for i in range(N):
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n = Noeud(x[i],y[j],a,s)
else:
if i==0:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif i==N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
if j==0 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif j==N-1 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
maillage.append(n)
attribuerVoisins(N,maillage)
elem = ElementsFinis2D()
elem.definirMaillage(maillage)
elem.solve()
U = np.zeros((N,N),dtype=np.float64)
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
U[j,i] = n.ksi
indice+= 1
from matplotlib.pyplot import *
figure()
contour(U,10,extent=(0,1,0,1))
fig5.pdf
figure()
plot(x,U[N//2,:])
grid()
fig6.pdf
On reprend l'exemple A avec deux milieux différents : la moitié à droite du domaine a une valeur de a deux fois plus grande.
N = 50
x = np.linspace(0,1,N)
y = np.linspace(0,1,N)
maillage = []
a1 = 1
a2 = 2
s = 0
for j in range(N):
for i in range(N):
if i < N//2 : a=a1
else : a=a2
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n = Noeud(x[i],y[j],a,s)
else:
if i==0:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif i==N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=1,bord=True)
if j==0 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,bord=True)
elif j==N-1 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,bord=True)
maillage.append(n)
attribuerVoisins(N,maillage)
elem = ElementsFinis2D()
elem.definirMaillage(maillage)
elem.solve()
U = np.zeros((N,N),dtype=np.float64)
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
U[j,i] = n.ksi
indice+= 1
from matplotlib.pyplot import *
figure()
contour(U,10,extent=(0,1,0,1))
fig7.pdf
figure()
plot(x,U[N//2,:])
grid()
fig8.pdf
Un objet de forme carrée est introduit dans le domaine, avec une condition de Dirichlet sur ses bords. Les quatres bords du domaine ont une condition de Dirichlet. La figure suivante montre comment l'objet est défini :
Figure pleine page
N = 50
x = np.linspace(0,1,N)
y = np.linspace(0,1,N)
maillage = []
a = 1
s = 0
# bords de l'objet
e = 5
i1 = N//2-e
i2 = N//2+e
j1 = N//2-e
j2 = N//2+e
for j in range(N):
for i in range(N):
if (i==i1 and j1<=j<=j2) or (i==i2 and j1<=j<=j2) or (j==j1 and i1<=i<=i2) or (j==j2 and i1<=i<=i2):
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=1)
else:
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n = Noeud(x[i],y[j],a,s)
else:
if i==0:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif i==N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
if j==0 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif j==N-1 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
maillage.append(n)
attribuerVoisins(N,maillage)
elem = ElementsFinis2D()
elem.definirMaillage(maillage)
elem.solve()
U = np.zeros((N,N),dtype=np.float64)
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
U[j,i] = n.ksi
indice+= 1
from matplotlib.pyplot import *
figure()
contour(U,10,extent=(0,1,0,1))
fig9.pdf
figure()
plot(x,U[N//2,:])
grid()
fig10.pdf
On reprend l'exemple A mais avec une condition de Robin sur les bords en y=0 et y=1 :
N = 50
x = np.linspace(0,1,N)
y = np.linspace(0,1,N)
maillage = []
a = 1
s = 0
for j in range(N):
for i in range(N):
if i!=0 and i!=N-1 and j!=0 and j!=N-1:
n = Noeud(x[i],y[j],a,s)
else:
if i==0:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=0,bord=True)
elif i==N-1:
n = Noeud(x[i],y[j],a,s,lim=DIR,ksi=1,bord=True)
if j==0 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,K0=-1,u0=0,bord=True)
elif j==N-1 and i!=0 and i!=N-1:
n = Noeud(x[i],y[j],a,s,lim=NEU,g0=0,K0=-1,u0=0,bord=True)
maillage.append(n)
attribuerVoisins(N,maillage)
elem = ElementsFinis2D()
elem.definirMaillage(maillage)
elem.solve()
U = np.zeros((N,N),dtype=np.float64)
indice = 0
for j in range(N):
for i in range(N):
n = maillage[indice]
U[j,i] = n.ksi
indice+= 1
from matplotlib.pyplot import *
figure()
contour(U,10,extent=(0,1,0,1))
fig11.pdf
figure()
plot(x,U[N//2,:])
grid()
fig12.pdf