9.1. Interpolation 1D par élements finis#
cours master M1 mécanique: éléments finis (Marc Buffat , UCB Lyon 1)
%matplotlib inline
import sys,os
import numpy as np
import scipy as sp
import matplotlib
import matplotlib.pyplot as plt
from random import random
from validation.validation import check_function
from IPython.display import display, Markdown, Latex
def printmd(string):
display(Markdown(string))
# test si numero étudiant spécifier
try: NUMERO_ETUDIANT
except NameError: NUMERO_ETUDIANT = None
if type(NUMERO_ETUDIANT) is not int :
NUMERO_ETUDIANT = 12345
NOM = "test"
PRENOM = "test"
#raise AssertionError("NUMERO_ETUDIANT non défini")
# parametres spécifiques
_uid_ = NUMERO_ETUDIANT
np.random.seed(_uid_)
_a_ = 1+np.random.randint(3)
_b_ = 1+np.random.randint(3)
_L_ = 1.+np.random.randint(5)
printmd("## Etudiant {} {} id={}".format(NOM,PRENOM,NUMERO_ETUDIANT))
printmd("### fonction à interpoler f(x) = {} sin({} x) sur l'intervalle [0,L] avec L={}".format(_a_,_b_,_L_))
Etudiant test test id=12345
fonction à interpoler f(x) = 3 sin(2 x) sur l’intervalle [0,L] avec L=2.0
9.1.1. Fonction à interpoler f(x)#
Ecrire la fonction f(x) à interpoler, et définir la longueur de l’intervalle dans la variable L
## BEGIN SOLUTION
L = _L_
def f(x):
return _a_*np.sin(_b_*x)
## END SOLUTION
assert(L == _L_)
assert(np.abs(f(0))<1.0e-5)
assert(np.abs(f(np.pi/(2*_b_))-_a_)<1.0e-5)
printmd("### Validation OK")
Validation OK
9.1.2. Interpolation par élements finis \(P^1\)#
On choisit de faire une interpolation avec des polynômes \(P^1\).
Pour cela on définit les deux fonctions de forme \(N_1(\chi)\) et \(N_2(\chi)\) sur l’intervalle de référence \([0,1]\)
9.1.2.1. fonctions de forme sur [0,1]#
Ecrire les 2 fonctions de forme \(P^1\) sur \([0,1]\): N1(xsi) et N2(xsi)
def N1(xsi):
## BEGIN SOLUTION
return 1-xsi
## END SOLUTION
def N2(xsi):
## BEGIN SOLUTION
return xsi
## END SOLUTION
assert((N1(0.)==1.) and (N1(1.)==0.0))
assert((N2(0.)==0.) and (N2(1.)==1.0))
printmd("## Validation OK")
Validation OK
9.1.2.2. tracer les 2 fonctions de forme sur [0,1]#
avec un titre et des labels
## BEGIN SOLUTION
X=np.linspace(0,1,21)
plt.plot(X,N1(X),label="N1")
plt.plot(X,N2(X),label="N2")
plt.title("Fonction de forme P1")
plt.legend();
## END SOLUTION
9.1.2.3. Fonctions de base P1#
Ecrire une fonction TraceBaseP1(Ne,L) qui, sur sur un maillage de Ne elements de \([0,L]\), trace toutes les fonctions de base.
La fonction devra utiliser les 2 fonctions de forme précédentes (en utilisant un changement de variable)
def TraceBaseP1(Ne,L):
'''trace toutes les fonctions de base P1 sur un maillage [0,L] de Ne elts'''
## BEGIN SOLUTION
h = L/Ne
Xp = np.linspace(0,L,Ne+1)
Xsi = np.linspace(0,1,20)
Phi1 = N1(Xsi)
Phi2 = N2(Xsi)
cols = plt.cm.get_cmap('hsv', Ne+2)
for k in range(Ne):
X = Xp[k] + Xsi*h
plt.plot(X,Phi1,color=cols(k),label="N{}".format(k))
plt.plot(X,Phi2,color=cols(k+1))
plt.legend()
plt.title("Fonctions de base")
return
## END SOLUTION
# verification
TraceBaseP1(4,L)
/tmp/ipykernel_1319102/606310683.py:9: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.
cols = plt.cm.get_cmap('hsv', Ne+2)
'''verification utilisation des fonctions de forme'''
orig_N1 = N1
orig_N2 = N2
del N2,N1
try:
TraceBaseP1(4,L)
except NameError as error:
printmd("### Validation OK")
pass
else:
raise AssertionError("erreur n'utilise pas les fonctions de forme")
finally:
N1 = orig_N1
N2 = orig_N2
Validation OK
9.1.2.4. interpolation P1#
écrire une fonction interpolP1(x,Yp,L) qui calcule l’interpolation en x de la fonction \(f(x)\) donnée par ses valeurs nodales \(Yp\) sur un maillage équiréparti du segment \([0,L]\)
La fonction doit utiliser les fonctions de forme N1,N2
def interpolP1(x,Yp,L):
## BEGIN SOLUTION
n = Yp.size
ne = n-1
Xe = np.linspace(0,L,ne+1)
k = np.searchsorted(Xe,x,side='right')
if k > ne: k=ne
k = k-1
xsi = (x-Xe[k])/(Xe[k+1]-Xe[k])
yi = Yp[k]*N1(xsi)+Yp[k+1]*N2(xsi)
return yi
## END SOLUTION
# verification sur une fonction lineaire! on doit trouver 0.5
Ne = 3
Xp = np.linspace(0,L,2*Ne+1)
Yp = Xp
print(interpolP1(0.5,Yp,L))
0.5
Ne = 4
Xp = np.linspace(0,L,Ne+1)
Yp = f(Xp)
''' verification aux pts d interpolation '''
for i,x in enumerate(Xp):
yi = interpolP1(x,Yp,L)
assert(np.abs(yi-Yp[i])<1.e-10)
'''verification utilisation des fonctions de forme'''
orig_N1 = N1
orig_N2 = N2
del N2,N1
try:
interpolP1(0.5,Yp,L)
except NameError as error:
printmd("## Validation OK")
pass
else:
raise AssertionError("erreur n'utilise pas les fonctions de forme")
finally:
N1 = orig_N1
N2 = orig_N2
Validation OK
9.1.2.5. tracé de l’interpolation P1#
tracer l’interpolation et comparer avec la fonction f(x).
tracer l’erreur (ecart)
## BEGIN SOLUTION
Ne=8
Xp=np.linspace(0,L,Ne+1)
Yp=f(Xp)
X = np.linspace(0,L,100)
Y = [interpolP1(x,Yp,L) for x in X]
Ye = f(X)
# tracer
plt.figure(figsize=(12,6))
plt.subplot(1,2,1)
plt.plot(Xp,Yp,'o')
plt.plot(X,Y)
plt.plot(X,Ye)
plt.subplot(1,2,2)
plt.plot(X,Y-Ye);
## END SOLUTION
9.1.2.6. évolution de l’erreur#
écrire une fonction erreurP1(F,L,ne) qui calcule la norme (norme du max) de l’erreur d’interpolation entre une fonction F(x) et son interpolation sur ne elements P1.
étudier l’évolution de cette erreur d’interpolation en fonction de ne.
en déduire la précision (on pourra utiliser polyfit de numpy)
def erreurP1(F,L,ne):
'''calcul erreur interpolation (norme du max) de la fonction F sur [0,L] avec ne elts'''
## BEGIN SOLUTION
Xp= np.linspace(0,L,ne+1)
Yp= F(Xp)
X = np.linspace(0,L,100)
Y = [interpolP1(x,Yp,L) for x in X]
Ye = F(X)
Err=np.max(np.abs(Y-Ye))
return Err
## END SOLUTION
# vérification que l'erreur décroit en fct de Ne
print("erreur Ne=4,8 ",erreurP1(f,L,4),erreurP1(f,L,8),"Gain:",erreurP1(f,L,4)/erreurP1(f,L,8))
erreur Ne=4,8 0.3662500790238097 0.09160385116255165 Gain: 3.9981952109622165
'''test sur une fonction lineaire'''
Fl = lambda x:2*x+1
assert np.abs(erreurP1(Fl,L,4)) < 1.e-8
assert np.abs(erreurP1(Fl,L,8)) < 1.e-8
printmd("### Validation OK")
Validation OK
9.1.2.7. Erreur d’interpolation#
En utilisant la fonction erreurP1 tracer l’évolution de l’erreur en fonction de Ne et calculer la précision (ordre) de l’interpolation
## BEGIN SOLUTION
NE=[4,8,16,32,64,128]
Err=np.zeros(len(NE))
for i,ne in enumerate(NE):
Err[i]=erreurP1(f,L,ne)
#
plt.loglog(NE,Err,'x-')
pente=np.round(np.polyfit(np.log(NE),np.log(Err),deg=1)[0],2)
print("ordre ",-pente)
## END SOLUTION
ordre 2.0
9.1.2.8. Commentaires#
écrire vos commentaires et faire une analyse (2 pts)
=== BEGIN ANSWER ===
=== END ANSWER ===
9.1.3. Interpolation par élements finis \(P^2\)#
On choisit maintenant de faire une interpolation avec des polynômes \(P^2\).
Pour cela on définit les trois fonctions de forme \(N_1(\chi)\), \(N_2(\chi)\) , \(N_3(\chi)\) sur l’intervalle de référence \([0,1]\) associées aux 3 points d’interpolation \(\chi=0 , \frac{1}{2}, 1\)
9.1.3.1. fonctions de forme sur [0,1]#
Ecrire les 3 fonctions de forme N1(xsi),N2(xsi) et N3(xsi)
def N1(xsi):
## BEGIN SOLUTION
return 2*(1-xsi)*(0.5-xsi)
## END SOLUTION
def N2(xsi):
## BEGIN SOLUTION
return 4*xsi*(1-xsi)
## END SOLUTION
def N3(xsi):
## BEGIN SOLUTION
return 2*xsi*(xsi-0.5)
## END SOLUTION
assert((N1(0.)==1.) and (N1(1.)==0.0) and (N1(0.5)==0.))
assert((N2(0.)==0.) and (N2(1.)==0.0) and (N2(0.5)==1.))
assert((N3(0.)==0.) and (N3(1.)==1.0) and (N3(0.5)==0.))
printmd("## Validation OK")
Validation OK
9.1.3.2. tracer les fonctions de base sur [0,1]#
## BEGIN SOLUTION
X=np.linspace(0,1,21)
plt.plot(X,N1(X),label="N1")
plt.plot(X,N2(X),label="N2")
plt.plot(X,N3(X),label="N3")
plt.title("Fonction de forme P1")
plt.legend();
## END SOLUTION
9.1.3.3. Fonctions de base P2#
Ecrire une fonction TraceBaseP2() qui sur sur un maillage de Ne elements sur [0,L][0,L] trace les fonctions de base. La fonction devra utiliser les fonctions de forme précédentes
def TraceBaseP2(Ne,L):
'''trace les fonctions de base P2 sur un maillage [0,L] de Ne elts'''
## BEGIN SOLUTION
h = L/Ne
Xp = np.linspace(0,L,Ne+1)
Xsi = np.linspace(0,1,20)
Phi1 = N1(Xsi)
Phi2 = N2(Xsi)
Phi3 = N3(Xsi)
cols = plt.cm.get_cmap('hsv', 2*Ne+2)
for k in range(Ne):
X = Xp[k] + Xsi*h
plt.plot(X,Phi1,color=cols(2*k),label="N{}".format(2*k))
plt.plot(X,Phi2,color=cols(2*k+1),label="N{}".format(2*k+1))
plt.plot(X,Phi3,color=cols(2*k+2))
plt.legend()
plt.title("Fonctions de base")
return
## END SOLUTION
# verification
TraceBaseP2(4,L)
/tmp/ipykernel_1319102/1927418173.py:10: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.
cols = plt.cm.get_cmap('hsv', 2*Ne+2)
'''verification utilisation des fonctions de forme'''
orig_N1 = N1
orig_N2 = N2
orig_N3 = N3
del N3,N2,N1
try:
TraceBaseP2(4,L)
except NameError as error:
printmd("### Validation OK")
pass
else:
raise AssertionError("erreur n'utilise pas les fonctions de forme")
finally:
N1 = orig_N1
N2 = orig_N2
N3 = orig_N3
Validation OK
9.1.3.4. interpolation P2#
écrire une fonction interpolP2 qui calcule l’interpolation en x de la fonction \(f(x)\) donnée par ses valeurs nodales \(Yp\) sur un maillage équirépartir du segment \([0,L]\). La fonction doit utiliser les fonctions de forme.
def interpolP2(x,Yp,L):
## BEGIN SOLUTION
n = Yp.size
ne = (n-1)//2
Xe = np.linspace(0,L,ne+1)
k = np.searchsorted(Xe,x,side='right')
if k > ne: k=ne
k = k-1
xsi = (x-Xe[k])/(Xe[k+1]-Xe[k])
yi = Yp[2*k]*N1(xsi)+Yp[2*k+1]*N2(xsi)+Yp[2*k+2]*N3(xsi)
return yi
## END SOLUTION
# verification sur une fonction quadratique on doit trouver 0.25
Ne = 3
Xp = np.linspace(0,L,2*Ne+1)
Yp = Xp*Xp
print(interpolP2(0.5,Yp,L))
0.25
Ne = 4
Xp = np.linspace(0,L,2*Ne+1)
Yp = f(Xp)
''' verification aux pts d interpolation '''
for i,x in enumerate(Xp):
yi = interpolP2(x,Yp,L)
assert(np.abs(yi-Yp[i])<1.e-10)
'''verification utilisation des fonctions de forme'''
orig_N1 = N1
orig_N2 = N2
orig_N3 = N3
del N3,N2,N1
try:
interpolP2(0.5,Yp,L)
except NameError as error:
printmd("## Validation OK")
pass
else:
raise AssertionError("erreur n'utilise pas les fonctions de forme")
finally:
N1 = orig_N1
N2 = orig_N2
N3 = orig_N3
Validation OK
9.1.3.5. tracé interpolation#
tracer la fonction interpolée de f(x) ainsi que l’erreur d’interpolation
## BEGIN SOLUTION
Ne=8
Xp=np.linspace(0,L,2*Ne+1)
Yp=f(Xp)
X = np.linspace(0,L,100)
Y = [ interpolP2(x,Yp,L) for x in X]
Ye = f(X)
# tracer
plt.figure(figsize=(12,6))
plt.subplot(1,2,1)
plt.plot(Xp,Yp,'o')
plt.plot(X,Y)
plt.subplot(1,2,2)
plt.plot(X,Y-Ye);
## END SOLUTION
9.1.3.6. Analyse de l’erreur#
Analyser cette interpolation et son évolution en fonction de Ne.
écrire une fonction erreurP2(F,L,ne) qui calcule la norme (norme du max) de l’erreur d’interpolation entre une fonction F(x) et son interpolation sur ne elements P2.
étudier l’évolution de cette erreur d’interpolation en fonction de Ne.
en déduire la précision (on pourra utiliser polyfit de numpy)
def erreurP2(F,L,ne):
'''calcul erreur interpolation (norme du max) de la fonction F sur [0,L] avec ne elts'''
## BEGIN SOLUTION
Xp= np.linspace(0,L,ne+1)
Yp= F(Xp)
X = np.linspace(0,L,200)
Y = [interpolP2(x,Yp,L) for x in X]
Ye = F(X)
Err=np.max(np.abs(Y-Ye))
return Err
## END SOLUTION
# vérification
print("erreur Ne=4,8 ",erreurP2(f,L,4),erreurP2(f,L,8),"Gain:",erreurP2(f,L,4)/erreurP2(f,L,8))
erreur Ne=4,8 0.18189212393470489 0.022740822509053737 Gain: 7.998484833267957
'''test sur une fonction quadratique'''
Fl = lambda x:3*x*x+2*x+1
assert np.abs(erreurP2(Fl,L,4)) < 1.e-8
assert np.abs(erreurP2(Fl,L,8)) < 1.e-8
printmd("### Validation OK")
Validation OK
## BEGIN SOLUTION
NE=[4,8,16,32,64,128]
Err=np.zeros(len(NE))
for i,ne in enumerate(NE):
Err[i]=erreurP2(f,L,ne)
#
plt.loglog(NE,Err)
pente= np.round(np.polyfit(np.log(NE),np.log(Err),deg=1)[0],2)
print("ordre ",-pente)
## END SOLUTION
ordre 2.98
9.1.3.7. Commentaires#
ecrire vos commentaires et anamyse(2 pts)
=== BEGIN ANSWER ===
=== END ANSWER ===