Diffusion Equation
The diffusion equation allows to describe the dynamics of a diffusive system, such as the temperature in a material, the movement of ink in water, and even the propagation of cancer cells in the brain. In the following, we will show some applications of this equation:
EXAMPLES
1D Diffusion Equation |
---|
The simplest problem where the diffusion equation appears is in the hear flux along a one dimensional rod of length , subjected to the boundary conditions y , where is the temperature at a distance from the left edge at a time . If the diffusion coefficient is constant (the bar is homogeneous), then we can write the diffusion equation as
where is the diffusion coefficient that characterizes the material from which the rod is made of. For the particular case in which we keep the edges cold (, ) and an initial profile , the problem can be solved analytically, and the solution is
We can solve the diffusion equation numerically through finite differences, using the FTCS scheme:
that we can write as
,
where is the temperature in the position at the time , and . Here, is the size of the divisions (from to ) of the interval , such that and ; while $\Delta t$ is the time step, which must fulfill the numerical convergence criteria
.
In this way, we can get to the same analytical solution and then solve more complicated problems for this system, which don't have analytical solution. We now show the analytical solution versus the numerical solution:
Código (C++)
#include<fstream>
#include<cmath>
using namespace std;
//const double D=2.2;
const int Ndx=70, tmax=1000; // segundos
const double L=100.0; // metros
const double Tmax=5; // Kelvin
const double dx=L/(Ndx-1), dt=0.9*(dx*dx/(2.0*3.2)), r=dt/(dx*dx);
// Coeficiente de difusion
double D(double x)
{
// double Dx = (x<L/2.0)? 3.2 : 0.2; // metros²/segundo
double Dx = 2.2;
return Dx;
}
// Condicion de Borde 1: T(0,t)=g1(t)
//double g1(double t){ return 1+500*exp(-0.001*(t-100)*(t-100));}
//double g1(double t){ return 1+(Tmax-1)*(2*atan(t/100)/M_PI);}
double g1(double t){ return 0.0;}
// Condicion de Borde 2: T(L,t)=g2(t)
double g2(double t){ return 0.0;}
// Condicion Inicial: T(x,0)=f(x) (Se debe cumplir f(0)=T(0,0)=g1(0) y f(L)=T(L,0)=g2(0))
double f(double x){ return sin(M_PI*x/L);}
int main()
{
double T[Ndx]; // T(x,t)
double Tant[Ndx]; // T(x,t) (copia)
for (int j=0; j<Ndx; j++) T[j]=0;
// Condicion inical
for (int j=0; j<Ndx-1; j++) T[j]=f(j*dx);
ofstream arch("calor.dat");
arch << "#x" << "\t" << "#t" << "\t" << "T(x,t)" << endl;
for (double t=0; t<=tmax; t+=dt)
{
if (int(t/dt)%50==0)
{
/* DIBUJO GNUPLOT */
cout<<"plot [0:"<<L<<"][0:" << Tmax << "]";
cout << " '-' w l ls 3 lw 8 t 'D=3.2',"; // Puntos para la barra
cout << " '-' w l ls 2 lw 8 t 'D=1.2',"; // Puntos para la barra
cout << " '-' ls 2 lc 0 t 'Time: t=" << t << "'" << endl; // Puntos T(x,t)
cout << "0 0" << endl << L/2 << " 0" << endl; // La barra va de (0,0) a (L/2,0)
cout << 'e' << endl; // Terminamos los 2 puntos que definen la barra.
cout << L/2 << " 0" << endl << L << " 0" << endl; // La barra va de (0,0) a (L/2,0)
cout << 'e' << endl; // Terminamos los 2 puntos que definen la barra.
for (int j=0; j<Ndx; j++)
{
arch << j*dx << " " << t << " " << T[j] << endl;
cout << j*dx << " " << T[j] << endl;
}
cout << 'e' << endl << flush;
}
// Aplicando condiciones de Borde
T[0]=g1(t);
T[Ndx-1]=g2(t);
// Haciendo una copia del arreglo
for(int j=0; j<Ndx; j++) Tant[j]=T[j];
// Resolviendo entre medio
for (int j=1; j<Ndx-1; j++)
{
T[j]=Tant[j] + D(j*dx)*r*(Tant[j+1]-2*Tant[j]+Tant[j-1]);
}
}
cout << "pause 2" << endl;
arch.close();
return 0;
}
Compilado el programa, ejecutar con
Código (python)
from numpy import *
Ndx=70; tmax=50; # segundos
L=100.0; # metros
Tmax=5.0; # Kelvin
D=20.0
dx=L/(Ndx-1); dt=0.8*(dx*dx/(2.0*D)); r=dt/(dx*dx)
Temp = []
# Condicion de Borde 1: T(0,t)=g1(t)
def g1(t): return 0.0
# Condicion de Borde 2: T(L,t)=g2(t)
def g2(t): return 0.0
# Condicion Inicial: T(x,0)=f(x) (Se debe cumplir f(0)=T(0,0)=g1(0) y f(L)=T(L,0)=g2(0))
def f(x): return Tmax*sin(pi*x/L);
T = [0.0]*Ndx # T(x,t)
Tant = [0.0]*Ndx # T(x,t) (copia)
# Condicion inical
for j in xrange(Ndx-1): T[j]=f(j*dx)
#print "#x","#t","#T(x,t)"
for n in xrange(int(tmax/dt)):
# Aplicando condiciones de Borde
t=n*dt
T[0]=g1(t)
T[Ndx-1]=g2(t)
# Haciendo una copia del arreglo
Tant=list(T)
# Resolviendo entre medio
for j in xrange(Ndx-1):
T[j]=Tant[j] + D*r*(Tant[j+1]-2*Tant[j]+Tant[j-1])
# Cada 10 pasos...
if (int(t/dt)%10==0):
# Anadimos al arreglo de temperaturas la lista de temperaturas en este paso
Temp += [ list(T) ]
# for j in xrange(Ndx):
# print j*dx, t, T[j]
Temp = array(Temp)
from mpl_toolkits.mplot3d.axes3d import get_test_data
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
X = array([j*dx for j in xrange(Ndx)] )
Y = array([n*dt for n in xrange(len(Temp))] )
X, Y = meshgrid(X, Y)
Z = Temp
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, vmin=0, vmax=Tmax, linewidth=0, antialiased=False)
ax.set_zlim3d(0, Tmax)
show()
Modelo de crecimiento de un tumor |
---|
Existen varios modelos que permiten estudiar el crecimiento de un tumor. Uno de los modelos más simples para modelar la evolución de un glioblastoma en presencia de quimioterapia se puede formular postulando que la tasa de crecimiento de células cancerígenas tiene un término difusivo y uno de crecimiento poblacional, es decir,
donde es la concentración de células tumorales en un sitio en un tiempo , y es una función que describe los efectos de la quimioterapia. El coeficiente de difusión en general depende de la concentración de células cancerígenas , es decir, .
Si suponemos simetría esférica, podemos expresar la ecuación anterior como
Para este caso particular, vamos a elegir
,
de modo que en zonas donde , y vale a lo más cuando la concentración es muy grande. Resolvemos la ecuación usando diferencias finitas, tal como suele resolverse la ecuación de difusión.
Para comenzar, daremos una condición inicial correspondiente a un tumor localizado en el centro del cerebro, como muestran las figuras a continuación.
Usando un tratamiento representado por dos pulsos a los 200 y 500 segundos, dados por
hacemos evolucionar el sistema y lo mostramos a continuación.
En este caso, el tratamiento no es capaz de eliminar el tumor, el cual sigue creciendo sin control.
Código (python)
#* ECUACION DE CRECIMIENTO DE UN TUMOR CEREBRAL *#
#* *#
#* Este programa encuentra la solucion a una de las ecuaciones *#
#* propuestas para la propagacion de un tumor, tomada del *#
#* trabajo de Tiberiu Harko y M. K. Mak: *#
#* TRAVELLING WAVE SOLUTIONS OF THE REACTION-DIFFUSION MATHEMATICAL *#
#* MODEL OF GLIOBLASTOMA GROWTH: AN ABEL EQUATION BASED APPROACH: *#
#* dc/dt = V.(D Vc) + rho*c - G(t)c *#
#* donde c=c(r,t) es la densidad de celulas tumorales en la *#
#* posicion r en tiempo t, rho la tasa neta de proliferacion, *#
#* y D=D(c(r)), el coef. de difusion, que depende de c. *#
#* G(t) es una funcion de influencia externa, que representa el *#
#* efecto de la quimioterapia. *#
#* *#
#* Suponiendo simetria radial, se obtiene *#
#* dc/dt = D'(c(r))*(dc/dr)^2 + D(c(r))*d^2c/dr^2 + rho*c - G(t)c *#
#***********************************************************************#
# AUTOR: FELIPE GONZALEZ CATALDO, Octubre 2015.
from numpy import *
R=9.9 # Radio del cerebro (cm)
N=100 # Divisiones del intervalo [0,R]
Dmax=0.010 # Maximo coeficiente de difusion (ver D abajo), en cm^2/sec
Dmin=0.001 # Minimo coeficiente de difusion (ver D abajo), en cm^2/sec
rho=0.005 # rho= tasa neta de proliferacion, en 1/sec
dr=R/(N-1)
dt=0.8*dr*dr/(2*Dmax) # Mientras mas grande la difusion, mas chico debe ser dt
t=0.0; tmax=2000.0
c = [0.0]*N
c_ant = [0.0]*N
# Coeficiente de difusion:
def D(c,r):
return Dmin+ 0.63661977*(Dmax-Dmin)*arctan(c) # 2/pi=0.6366
# Derivada parcial del coef. de difusion respecto a c (derivar arriba):
def Dc(c,r):
return 0.63661977*(Dmax-Dmin)/(1+c*c)
# Derivada parcial del coef. de difusion respecto a r (derivar arriba):
def Dr(c,r):
return 0.0
# Condicion inicial c(r,0)=f(r)
def f(r):
return exp(-50*(r/R)**2) if r<R/2.0 else 0.0
# When chemotherapy is administered, G(t) is constant, and G(t) = 0 otherwise
def G(t):
return 10*rho*exp(-(t-200)**2/1000)+10*rho*exp(-(t-500)**2/1000) #+100*rho*exp(-(t-2000)**2/1000)
def PrintForGnuplot(u):
# Con esta funcion imprimimos la funcion para gnuplot: r, c(r)
print "plot [0:",R,"][0:5] '-' w l ls 12 lw 3 title 't=", t,"'"
for j in xrange(N):
print j*dr, c[j]
print "end"
print "set grid"
# print "pause",1
def PrintContoursGnuplot(u):
# Con esta funcion imprimimos un mapa de contornos pm3d map de gnuplot
# print "set isosample 10,10"
print "set dgrid3d 31,31,31"
print "set pm3d map"
print "set cbrange [0:1]"
print "set title 't=", t,"'"
print "splot [-"+str(R)+":"+str(R)+"][-"+str(R)+":"+str(R)+"][] '-' title 't=", t,"'"
No = 15
do = 2.0*pi/No
for i in xrange(No):
for j in xrange(N):
x=j*dr*cos(i*do);
y=j*dr*sin(i*do);
print x, y , c[j]
print "e"
# print "set grid"
# Condicion inicial c(r,0)=f(r)
for j in xrange(N):
c[j]=f(j*dr);
c_ant[j]=f(j*dr);
interval = int(tmax/dt/500)
while(t<=tmax):
# if int(t/dt)%interval==0: PrintForGnuplot(c)
if int(t/dt)%(interval*20)==0: PrintContoursGnuplot(c)
#*** METODO PREDICTOR ****#
# Primero los bordes
c[0] = c_ant[0] + dt*( D(c_ant[0],0*dr)*(4.0*(c_ant[1]-c_ant[0])/(dr*dr)) )
c[0] += dt*( rho*c_ant[0] - G(t)*c_ant[0] )
c[N-1]=0.0 # c(R)=0
# Luego entre medio
for j in xrange(1,N-1):
dcdr = (c_ant[j+1]-c_ant[j-1])/(2.0*dr)
c[j] = c_ant[j] + dt*( dcdr*( Dr(c_ant[j],j*dr) + Dc(c_ant[j],j*dr)*dcdr ) )
c[j] += dt*( D(c_ant[j],j*dr)*(c_ant[j+1]-2*c_ant[j]+c_ant[j-1])/(dr*dr) )
c[j] += dt*( D(c_ant[j],j*dr)*dcdr/(j*dr) )
c[j] += dt*( rho*c_ant[j] - G(t)*c_ant[j] )
#************************#
# Guardamos las posiciones nuevas para la vuelta siguiente
c_ant = list(c)
t+=dt
# >>END OF WHILE<<