using Plots
Uma equação a derivada parciais é uma equação cuja incógnita (ou variável dependente) depende de mais de uma variável independente e que envolve derivadas parciais da incógnita.
Em vários exemplos, uma das variáveis independentes é uma variável temporal, denotada por $t$.
Outras váriáveis podem indicar coordenadas espaciais, como $x$, $y$, $z$.
Em outros casos, podemos ter variáveis indicando comprimento de arco $s$, distância $r$ até um ponto ou um eixo, ângulo $\theta$, temperatura, umidade, salinidade, concentração de uma substância, etc.
A ordem de uma equação diferencial é dada pela ordem da derivada parcial de maior ordem.
Certas combinações ou vetores de deriadas parciais recebem notações e denominações especiais, como o gradiente $\nabla u$, o divergente $\nabla \cdot u$ e o laplaciano $\Delta u$, como vistos no curso de Cálculo de várias variáveis.
É comum que uma das variáveis seja a variável temporal e que estejamos interessados em descobrir $u(t,x)$ para $t\geq t_0$, a partir do conhecimento do estado inicial $u(t_0,x) = u_0(x)$, em um instante inicial $t_0$.
Nesse caso, temos um problema de valor inicial.
Na maioria dos casos, a região de interesse não é o espaço todo, nem mesmo um semi-espaço $t\geq t_0$.
É comum termos um domínio espacial limitado $\Omega\subset \mathbb{R}^d$, em algum espaço Euclidiano $\mathbb{R}^d$ (ou mesmo em uma variedade).
Nesse caso, esperamos que a equação a derivadas parciais seja satisfeita no domínio $\Omega$, mas sendo necessário determinar o que acontece no bordo $\partial\Omega$ do domínio.
Nesse caso, temos um problema de valores de contorno.
Veremos exemplos de problemas de valores de contorno as aplicações.
Há vários métodos numéricos para a resolução de equações a derivadas parciais, como diferenças finitas, elementos finitos, volumes finitos, etc.
E cada método possui diversas variações.
Aqui, vamos considerar apenas diferenças finitas.
Diferenças finitas podem ser justificadas a partir de expansões de Taylor.
Esta é como um método de Euler para a resolução de EDOs.
Dada uma função diferenciável $u=u(x)$ em um ponto $x\in\mathbb{R}$, temos que
Mas quão boa é essa aproximação?
Isso depende da regularidade de $u$.
Se a função for contínua e diferenciável em todos os pontos mas a sua derivada não for contínua no ponto, então essa aproximação pode nao ser muito boa.
Por exemplo, considere, para $0<\theta<1$, a função
Mas $u(\cdot)$ não é duas vezes diferenciável na origem e $u'(\cdot)$ é apenas Hölder contínua na origem.
A diferença finita de $u$ na origem é
Lembre-se que a parte $\cdots$ contém termos de ordem $h^n$, com $n=3,4, \cdots$.
Assim, podemos escrever
Aproximações para a segunda derivada também podem ser obtida com combinações apropriadas.
Por exemplo, uma aproximação de segunda ordem clássica é
Verifique!
Observe que
No caso de uma dimensão espacial, em um intervalo $I=[0,L]$, podemos considerar uma malha uniforme composta por $N$ pontos $0=x_1<x_2<\ldots<x_N=L$, com um espaçamento igual $x_{i+1}-x_i =h$, $i=1, \ldots, n$, onde $h>0$ é constante.
Nesse caso, temos $N$ pontos e $N-1$ intervalos, com $(N-1)h=L$ e $x_i = (i-1)h$.
N = 20
L = 4
x = range(0.0, L, length=N)
scatter(x, zero(x), markersize=4, legend=false)
plot!(title="Malha uniforme", titlefont=10, size=(600,100), ylims=(-0.1, 0.2))
A discretização não precisa ser uniforme.
Podemos considerar qualquer malha satisfazendo $0=x_1<x_2<\ldots<x_N=L$.
Pode ser útil, por exemplo, ter um espaçamento menor em regiões onde a derivada tem uma variação maior.
Podemos construir malhas não-uniformes com simples transformações.
Por exemplo, considerando $s_i = (i-1)h$, $i=1, \ldots, N$, com $h>0$ constante e $(N-1)h=1$, que é uma malha uniforme no intervalo unitário $[0,1]$, podemos definir
N = 20
L = 4
s = range(0.0, 1.0, length=N)
x = L/2 * (1 .+ cos.(π * s))
#x = L/2 * ( 1 .+ [cos((2i - 1)/(2N) * π) for i in 1:N])
scatter(x, zero(x), markersize=4, legend=false)
scatter!(x,x->√((L/2)^2-(x-L/2)^2), markersize=3, legend=false)
plot!(title="Distribuição dos pontos de Chebyshev", titlefont=10, size=(600,300))
Essa ideia pode ser estendida a dimensões maiores de forma natural.
No caso de um domínio bidimensional retangular $\Omega = (0,L_x) \times (0,L_y)$, considerando espaçamentos uniformes $h_x$ e $h_y$, com $N_x$ pontos no eixo $x$ e $N_y$ pontos no eixo $y$, temos
L_x = 4.0
L_y = 2.0
N_x = 20
N_y = 10
x = range(0.0, L_x, length=N_x)
y = range(0.0, L_y, length=N_y)
scatter(x, repeat(y',length(x)), legend=false, color=1, size=(600,300))
Da mesma forma, podemos considerar malhas não-uniformes
A malha pode ser não-uniforme na direção de ambos os eixos ou em apenas um deles
L_x = 4.0
L_y = 2.0
N_x = 20
N_y = 10
x = range(0.0, L_x, length=N_x)
s = range(0.0, 1.0, length=N_y)
y = L/2 * (1 .+ cos.(π * s))
scatter(x, repeat(y',length(x)), legend=false, color=1, size=(600,300),
xlabel="x", ylabel="y", title="Malha não-uniforme em y", titlefont=10)
L_x = 4.0
L_y = 2.0
N_x = 20
N_y = 10
r = range(0.0, 1.0, length=N_x)
s = range(0.0, 1.0, length=N_y)
x = L/2 * (1 .+ cos.(π * r))
y = L/2 * (1 .+ cos.(π * s))
scatter(x, repeat(y',length(x)), legend=false, color=1, size=(600,300),
xlabel="x", ylabel="y", title="Malha não-uniforme em ambas as direções", titlefont=10)
O artigo Solving PDEs in Julia (JuliaCon 2018 workshop), por Chris Rackauckas dá uma boa ideia de métodos e exemplos de resolução de EDPs em Julia.
O artigo está um pouco desatualizado, pois é de 2018 e a linguagem e, principalmente, os pacotes de resolução de equações diferenciais têm evoluido muito rapidamente.
Mas ainda assim o artigo pode ser útil.
Um novo artigo, com o mesmo espírito desse, está em vias de ser escrito.