Considriamo un volume $\Omega\subset \mathbb{R}^N$ e osserviamo che data la densità di particelle in un dato istante temporale che si trovano in un punto dello spazio, i.e $\rho=\rho(t,\vec{x})$, possiamo mettere in relazione la variazione di quest'ultima con il flusso delle particelle $\vec{J}(t,\vec{x})$:
$$ \partial_t \int_\Omega \rho(t,\vec{x}) d\vec{x} = -\int_{\partial\Omega} \vec{J}(t,\vec{x})\cdot \vec{n}$$quest'ultima equazione integrale infatti ci dice che la virazione di massa all'interno del volume $\Omega$ devo corrispondere a un flusso di particelle al di fuori del volume ( all'interno). Supponiamo ora di lavoare con funzioni lisce, allora possiamo manipolare l'equazione precedente per ottenere la seguente formula, utilizzando il teorema di Gauss:
$$\int_\Omega \partial_t \rho(t,x) + \nabla\cdot \vec{J}(t,\vec{x}) d\vec{x}= 0$$siccome le funzioni sono lisce e la precedente equazione vale su ogni dominio $\Omega\subset \mathbb{R}$ abbiamo che l' integranda è nulla, di conseguenza otteniamo l'equazione alle derivate parziali nota con il nome di equzione di continuità :
$$\partial_t \rho + \nabla \cdot \vec{J} = 0$$Studiamo ora dei metodi che ci permettono di risolvere in generale equazioni scritte in questa forma, i metodi ai volumi finiti (FVM) Partiamo dall'equaione di continuità in una dimensione e consideriamo come dominio l'intervallo chiuso $[a,b]$. Allora dividiamo l'intervallo in dei volumi finiti, ovvero dei sotto intervalli $V_i=(x_{i-1},x_i)$ dove:
$$x_0 = a\qquad x_n = b \qquad x_i = i\cdot h_x$$a questo punto siamo pronti a definire la quantità $\overline{\rho}_i(t) = \frac{1}{h_x}\int_{V_i} \rho(t,x) dx$, che prende il nome di densità media di volume sull' i-esimo volume finito. A questo punto integriamo l'equazione di continuità per ottenere la seguente euqazione:
$$\int^{t_{j+1}}_{t_j} \partial_t \rho dt = -\int_{t_j}^{t_j{+1}}\partial_x J dt \Rightarrow \rho(t_{j+1},\vec{x})=\rho(t_j,\vec{x}) - \int_{t_j}^{t_{j+1}} \partial_x J dt$$dove $t_j = j*h_t$. Integriamo ora in spazio l'equazione precedente e dividiamo per $h_x$ in modo tale da ottenere un equazione in termini delle densità medie di volume:
$$\overline{\rho}_i (t_{j+1}) = \overline{\rho}(t_j) - \int_{x_{i-1}}^{x_i} dx\frac{1}{h_x}\int_{t_j}^{t_{j+1}} \partial_x J dt$$Siccome stiamo lavorando con funzioni lisce possiamo invertire l'ordine di integrazione (per il teorema di Fubini-Tonelli):
$$\overline{\rho}_i(t_{j+1}) = \overline{\rho}_i(t_{j}) - \int_{t_j}^{t_{j+1}} dt \frac{J_{i}(t) - J_{i-1}(t)}{h_x}$$$$\overline{\rho}_i(t_{j+1}) = \overline{\rho}_i(t_{j}) - \frac{1}{h_x}\int_{t_j}^{t_{j+1}}J_{i}(t) - J_{i-1}(t)$$portando al limite $h_t\to 0$ (e utilizzando il teorema della media integrale che vedremo a breve) otteniamo la seguente discrettizzazione in spazio dell' equazione di continuità :
$$\partial_t \overline{\rho}_i = \frac{1}{h_x} \Big(J_i(t)-J_{i-1}(t)\Big)$$Questa equazione è uno schema numerico per l'approsimazione di continuità , in una dimensione questa approssimazione corrisponde a un approssimazione del primo ordine utilizzando il metodo delle differenze finite, invece in più dimensioni i due metodi si distinguono. Osserviamo ora che abbiamo trovato uno schema numerico per approssimare la soluzione dell'equazione di continuità , poichè per un $h_x$ sufficentemente piccolo $\overline{\rho}_{i+1}(t)\approx \rho_{i+\frac{1}{2}}(t)$.
Teorema (Media Integrale) Data una funzione $f:[a,b]\to \mathbb{R}$ continua, esiste $c\in (a,b)$ tale che:
$$\frac{1}{b-a}\int_a^bf(x) = f(c)$$Corollario Fissato un punto $x_0\in (a,b)$ abbiamo che:
$$\rho(t,x_0) = \frac{1}{h_x}\int_{x_0-\frac{h_x}{2}}^{x_0 + \frac{h_x}{2}} \rho(t,x) dx = \overline{\rho}(t,x_0)$$
Esempio (Equazione Del Calore) Consideriamo ora come legge fisica la legge di Fourier, che ci dice che le particelle si muvono contro gradiente:
$$ \vec{J}(t,\vec{x}) = -\nabla \rho (t, \vec{x})=-\partial_x \rho(t,x)$$dunque dobbiamo approssimare la quantità , $J_i(t)-J_{i-1}(t)$, per fare questo utilizziamo le differenze finite del primo ordine in avanti e all'indietro:
$$J_i(t) = k\bigg[\frac{\rho_{i+1}-\rho_{i}}{h_x}\bigg] \qquad J_{i-1}(t) = k\bigg[\frac{\rho_{i}-\rho_{i-1}}{h_x}\bigg]$$ $$J_i(t) - J_{i-1}(t) = \frac{k}{h_x}\bigg(\rho_{i+1}-2 \rho_i + \rho_{i-1}\bigg)$$dunque l'equazione che rappresenta il metodo ai volumi finiti diventa:
$$ \partial_t \overline{\rho} = \frac{1}{h_x^2}\bigg(\rho_{i+1}-2\rho_i+\rho_{i-1}\bigg)$$in virtu del precedente corollario possiamo sostuire $\rho_i$ con $\overline{\rho}_{i}$, per ottenere:
$$ \partial_t \overline{\rho} = \frac{1}{h_x^2}\bigg(\overline{\rho}_{i+1}-2\overline{\rho}_i+\overline{\rho}_{i-1}\bigg)$$integrando questa semi-discretizzazione sapaziale con il metodo di Eulero otteniamo il seguente schema numerico:
$$ \overline{\rho}(t_{j+1}) = \overline{\rho}(t_{j})+\frac{h_t}{h_x^2}\bigg(\overline{\rho}_{i+1}(t_j)-2\overline{\rho}_i(t_j)+\overline{\rho}_{i-1}(t_j)\bigg)$$per chi è famigliare con il metodo delle differenze finite ques'ultimo schema numerico corrisponde a un approssimazione alle differenze finite del secondo ordine.
%matplotlib inline
from matplotlib import animation, rc
from IPython.display import HTML
import numpy as np
import matplotlib.pyplot as plt
def g(x):
if 1 <= x <= 2:
return 1
else:
return 0
#Inizializziamo l' asse x
a= 0; b = 4; T=0.3;
hx = 0.02; ht = 0.0001
print("Curant Number: {}".format(ht/hx**2))
N = int((b-a)/hx);
M = int(T/ht);
t = np.zeros(N+1);
Rho = np.zeros(N+1)
for i in range(0,N+1):
t[i] = (i+0.5)*hx
Rho[i] = g((i+.5)*hx)
plt.plot(t,Rho)
Rho[0]=0.0; Rho[-1]=0.0;
for i in range(1,M+1):
RhoN = np.zeros(N+1)
for i in range(1,N+1-1):
RhoN[i] = Rho[i]+(ht/(hx**2))*(Rho[i+1]-2*Rho[i]+Rho[i-1]);
RhoN[0]=0.0; RhoN[-1]=0.0;
Rho = RhoN
plt.plot(t,RhoN)
plt.title("Heat at t:"+str(M*ht))
import numpy as np
import matplotlib.pyplot as plt
def g(x):
if 1 <= x <= 2:
return 1
else:
return 0
#Inizializziamo l' asse x
a= 0; b = 4; T=3;
hx = 0.05; ht = 0.001
print("Curant Number: {}".format(ht/hx**2))
N = int((b-a)/hx);
M = int(T/ht);
t = np.zeros(N+1);
Rho = np.zeros(N+1)
for i in range(0,N+1):
t[i] = (i+0.5)*hx
Rho[i] = g((i+.05)*hx)
Rho[0]=0.0; Rho[-1]=0.0; #Impongo condizioni al bordo
#Costruiamo il plot
fig, ax = plt.subplots()
ax.set_xlim(( 0, 4))
ax.set_ylim((0, 1.1))
line, = ax.plot([], [], lw=2)
plt.title("Heat Equation")
def init():
line.set_data([], [])
return (line,)
def animate(j):
global Rho;
RhoN = np.zeros(N+1)
for i in range(1,N+1-1):
RhoN[i] = Rho[i]+(ht/(hx**2))*(Rho[i+1]-2*Rho[i]+Rho[i-1]);
RhoN[0]=0.0; RhoN[-1]=0.0;
Rho = RhoN
line.set_data(t, Rho)
return (line,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=1000, interval=5, blit=True);
HTML(anim.to_html5_video())
Osservazione (Numero Di Courant)
import numpy as np
import matplotlib.pyplot as plt
def g(x):
if 1 <= x <= 2:
return 1
else:
return 0
#Inizializziamo l' asse x
a= 0; b = 4; T=3;
hx = 0.05; ht = 0.00252
print("Curant Number: {}".format(ht/hx**2))
N = int((b-a)/hx);
M = int(T/ht);
t = np.zeros(N+1);
Rho = np.zeros(N+1)
for i in range(0,N+1):
t[i] = (i+0.5)*hx
Rho[i] = g((i+.05)*hx)
Rho[0]=0.0; Rho[-1]=0.0; #Impongo condizioni al bordo
#Costruiamo il plot
fig, ax = plt.subplots()
ax.set_xlim(( 0, 4))
ax.set_ylim((0, 1.1))
line, = ax.plot([], [], lw=2)
plt.title("Heat Equation")
def init():
line.set_data([], [])
return (line,)
def animate(j):
global Rho;
RhoN = np.zeros(N+1)
for i in range(1,N+1-1):
RhoN[i] = Rho[i]+(ht/(hx**2))*(Rho[i+1]-2*Rho[i]+Rho[i-1]);
RhoN[0]=0.0; RhoN[-1]=0.0;
Rho = RhoN
line.set_data(t, Rho)
return (line,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=1000, interval=5, blit=True);
HTML(anim.to_html5_video())
Osserviamo che perchè il metodo numerico sia stabile dobbiamo richiedere che il numero di Courant rispetti la seguente disuguaglianza:
$$ \frac{1}{k}\frac{h_t}{h_x^2} \leq 1$$Esempio (Equazione Dei Mezzi Porosi) Prendiamo ora come legge fisica la legge di Darcy, che ci dice che la velocità delle particelle nei mezzi porosi è data dal equazione:
$$ \vec{v} = -\frac{k}{\mu} \nabla \rho = -\frac{k}{\mu}\partial_x \rho$$siccome $\vec{J}=\rho \vec{v}$ possiamo scrivere l'equazione:
$$J = \frac{k}{\mu} \rho \partial_x \rho$$sostituendo quest'ultimo risultato all'interno dell' equazione di continuità otteniamo:
$$\partial_t \rho = -\nabla\cdot (\rho v) = - \partial_x \Bigg( \rho \Big( -\frac{k}{\mu} \partial_x \rho \Big) \Bigg)$$Dunque anche in questo caso dobbiamo trovare un modo per approssimare il flusso e faremo queto utilizzando le differenze finite in avanti e all' indietro:
$$J_i(t) = \frac{k}{\mu} \rho_i(t) \bigg( \frac{\rho_{i+1}(t) -\rho_i(t)}{h_t}\bigg)\qquad J_{i-1}(t) = \frac{k}{\mu} \rho_i(t) \bigg( \frac{\rho_{i}(t) -\rho_{i-1}(t)}{h_t}\bigg)$$$$J_i(t)-J_{i-1}(t) = -\frac{k}{\mu}\rho_i(t)\bigg(\frac{\rho_i(t)-\rho_{i-1}(t)}{h_t}\bigg)$$questo mi porta alla seguente semi discretizzazione numerica per il metodo l'equazione dei mezzi porosi:
$$\partial_t \overline{\rho}_i(t) = -\frac{k}{\mu}\overline{\rho}_i(t)\bigg(\frac{\overline{\rho}_i(t)-\overline{\rho}_{i-1}(t)}{h_t}\bigg)$$import numpy as np
import matplotlib.pyplot as plt
def g(x):
if 1 <= x <= 2:
return 1
else:
return 0
#Inizializziamo l' asse x
a= 0; b = 4; T=3;
hx = 0.05; ht = 0.001
print("Curant Number: {}".format(ht/hx**2))
N = int((b-a)/hx);
M = int(T/ht);
t = np.zeros(N+1);
Rho = np.zeros(N+1)
for i in range(0,N+1):
t[i] = (i+0.5)*hx
Rho[i] = g((i+.05)*hx)
Rho[0]=0.0; Rho[-1]=0.0; #Impongo condizioni al bordo
#Costruiamo il plot
fig, ax = plt.subplots()
ax.set_xlim(( 0, 4))
ax.set_ylim((0, 1.1))
line, = ax.plot([], [], lw=2)
plt.title("Porous Media Equation")
def init():
line.set_data([], [])
return (line,)
def animate(j):
global Rho;
RhoN = np.zeros(N+1)
for i in range(1,N+1-1):
RhoN[i] = Rho[i]+(ht/(hx**2))*Rho[i]*(Rho[i+1]-2*Rho[i]+Rho[i-1]);
RhoN[0]=0.0; RhoN[-1]=0.0;
Rho = RhoN
line.set_data(t, Rho)
return (line,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=1000, interval=5, blit=True);
HTML(anim.to_html5_video())
Esercizio (Equazione Del Trasporto e Metodi UpWind) Consideriamo ora come legge fisica per il flusso, la legg del trasporto:
$$\vec{J}(t,\vec{x}) = v\rho(t,x)$$l'equazione che si ottiene dall 'equazione di continuità in questo caso è:
$$\partial_t \rho = v\partial_x \rho$$si osservi cosa succede allo schema numerico quando abbiamo una velocità postiva e una velocità negativa.
import numpy as np
import matplotlib.pyplot as plt
def g(x):
if 1 <= x <= 2:
return 1
else:
return 0
#Inizializziamo l' asse x
a= 0; b = 4; T=3;
hx = 0.05; ht = 0.001
print("Curant Number: {}".format(ht/hx))
N = int((b-a)/hx);
M = int(T/ht);
t = np.zeros(N+1);
Rho = np.zeros(N+1)
for i in range(0,N+1):
t[i] = (i+0.5)*hx
Rho[i] = g((i+.05)*hx)
Rho[0]=0.0; Rho[-1]=0.0; #Impongo condizioni al bordo
#Costruiamo il plot
fig, ax = plt.subplots()
ax.set_xlim(( 0, 4))
ax.set_ylim((0, 1.1))
line, = ax.plot([], [], lw=2)
plt.title("Transport Equation")
def init():
line.set_data([], [])
return (line,)
def animate(j):
global Rho;
RhoN = np.zeros(N+1)
for i in range(1,N+1-1):
RhoN[i] = Rho[i]-(ht/(hx))*(Rho[i+1]-Rho[i]);
RhoN[0]=0.0; RhoN[-1]=0.0;
Rho = RhoN
line.set_data(t, Rho)
return (line,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=1000, interval=5, blit=True);
HTML(anim.to_html5_video())
import numpy as np
import matplotlib.pyplot as plt
def g(x):
if 1 <= x <= 2:
return 1
else:
return 0
#Inizializziamo l' asse x
a= 0; b = 4; T=3;
hx = 0.05; ht = 0.001
print("Curant Number: {}".format(ht/hx))
N = int((b-a)/hx);
M = int(T/ht);
t = np.zeros(N+1);
Rho = np.zeros(N+1)
for i in range(0,N+1):
t[i] = (i+0.5)*hx
Rho[i] = g((i+.05)*hx)
Rho[0]=0.0; Rho[-1]=0.0; #Impongo condizioni al bordo
#Costruiamo il plot
fig, ax = plt.subplots()
ax.set_xlim(( 0, 4))
ax.set_ylim((0, 1.1))
line, = ax.plot([], [], lw=2)
plt.title("Transport Equation")
def init():
line.set_data([], [])
return (line,)
def animate(j):
global Rho;
RhoN = np.zeros(N+1)
for i in range(1,N+1-1):
RhoN[i] = Rho[i]+(ht/(hx))*(Rho[i+1]-Rho[i]);
RhoN[0]=0.0; RhoN[-1]=0.0;
Rho = RhoN
line.set_data(t, Rho)
return (line,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=1000, interval=5, blit=True);
HTML(anim.to_html5_video())