Julia and partial differential equations
Using the example of the most typical physical models, we will consolidate the skills of working with functions and learn about the fast, convenient and beautiful PyPlot visualizer, which provides all the power of the Python Matplotlib. There will be a lot of pictures (hidden under spoilers)
Make sure everything under the hood is clean and fresh:
]status
Status `C:\Users\Игорь\.julia\environments\v1.0\Project.toml`
[537997a7] AbstractPlotting v0.9.0
[ad839575] Blink v0.8.1
[159f3aea] Cairo v0.5.6
[5ae59095] Colors v0.9.5
[8f4d0f93] Conda v1.1.1
[0c46a032] DifferentialEquations v5.3.1
[a1bb12fb] Electron v0.3.0
[5789e2e9] FileIO v1.0.2
[5752ebe1] GMT v0.5.0
[28b8d3ca] GR v0.35.0
[c91e804a] Gadfly v1.0.0+ #master (https://github.com/GiovineItalia/Gadfly.jl.git)
[4c0ca9eb] Gtk v0.16.4
[a1b4810d] Hexagons v0.2.0
[7073ff75] IJulia v1.13.0+ [`C:\Users\Игорь\.julia\dev\IJulia`]
[6218d12a] ImageMagick v0.7.1
[c601a237] Interact v0.9.0
[b964fa9f] LaTeXStrings v1.0.3
[ee78f7c6] Makie v0.9.0+ #master (https://github.com/JuliaPlots/Makie.jl.git)
[7269a6da] MeshIO v0.3.1
[47be7bcc] ORCA v0.2.0
[58dd65bb] Plotly v0.2.0
[f0f68f2c] PlotlyJS v0.12.0+ #master (https://github.com/sglyon/PlotlyJS.jl.git)
[91a5bcdd] Plots v0.21.0
[438e738f] PyCall v1.18.5
[d330b81b] PyPlot v2.6.3
[c4c386cf] Rsvg v0.2.2
[60ddc479] StatPlots v0.8.1
[b8865327] UnicodePlots v0.3.1
[0f1e0344] WebIO v0.4.2
[c2297ded] ZMQ v1.0.0
julia>]
pkg> add PyCall
pkg> add LaTeXStrings
pkg> add PyPlot
pkg> build PyPlot # если не произошел автоматический build# в случае нытья - просто качайте всё что он попросит, питон довольно требовательный
pkg> add Conda # это для использования Jupyter - очень удобная штука
pkg> add IJulia # вызывается как на заглавной картинке
pkg> build IJulia # если не произошел автоматический build
Now to the tasks!
Transport equation
In physics, the term transfer refers to irreversible processes, as a result of which spatial displacement (transfer) of mass, momentum, energy, charge, or some other physical quantity occurs in a physical system.
A linear one-dimensional transport equation (or advection equation) —the simplest partial differential equation — is written as
For the numerical solution of the transport equation, you can use an explicit difference scheme:
Where - the value of the grid function on the upper time layer. This scheme is stable at Courant number
Nonlinear transfer
Line source (absorption transfer): . We use the explicit difference scheme:
using Plots
pyplot()
a = 0.2
b = 0.01
ust = x -> x^2 * exp( -(x-a)^2/b ) # начальное условие
bord = t -> 0. # граничное# можно задавать значения по-умолчаниюfunction transferequi(;C0 = 1., C1 = 0., B = 0., Nx = 50, Nt = 50, tlmt = 0.01)
dx = 1/Nx
dt = tlmt/Nt
b0 = 0.5B*dt
c0 = C0*dt/dx
c1 = C1*dt/dx
print("Kurant: $c0$c1")
x = [i for i in range(0, length = Nx, step = dx)]# один из способов задать массив с помощью цикла
t = [i for i in range(0, length = Nt, step = dt)] # ранжированая переменная - не массив
U = zeros(Nx, Nt)
U[:,1] = ust.(x)
U[1,:] = bord.(t)
for j = 1:Nt-1, i = 2:Nx
U[i, j+1] = ( 1-b0-c0-c1*U[i,j] )*U[i,j] + ( c0-b0+c1*U[i,j] )*U[i-1,j]
end
t, x, U
end
t, X, Ans0 = transferequi( C0 = 4., C1 = 1., B = 1.5, tlmt = 0.2 )
plot(X, Ans0[:,1], lab = "t1")
plot!(X, Ans0[:,10], lab = "t10")
p = plot!(X, Ans0[:,40], lab = "t40")
plot( p, heatmap(t, X, Ans0) ) # объединим одним в одно изображение
Strengthen absorption:
t, X, Ans0 = transferequi( C0 = 2., C1 = 1., B = 3.5, tlmt = 0.2 )
plot(X, Ans0[:,1])
plot!(X, Ans0[:,10])
p = plot!(X, Ans0[:,40])
plot( p, heatmap(t, X, Ans0) )
t, X, Ans0 = transferequi( C0 = 1., C1 = 15., B = 0.1, Nx = 100, Nt = 100, tlmt = 0.4 )
plot(X, Ans0[:,1])
plot!(X, Ans0[:,20])
plot!(X, Ans0[:,90])
heatmap(t, X, Ans0)
Heat equation
The differential heat equation (or heat diffusion equation) is written as follows:
This equation is of parabolic type, containing the first derivative with respect to time t and the second with respect to the spatial coordinate x. It describes the temperature dynamics, for example, of a cooling or heated metal rod (the T function describes the temperature profile along the x-coordinate along the rod). The coefficient D is called the coefficient of thermal conductivity (diffusion). It can be either constant or depend, either explicitly on the coordinates, or on the desired function D (t, x, T) itself.
Consider a linear equation (diffusion coefficient and heat sources do not depend on temperature). Difference approximation of a differential equation using an explicit and implicit Euler scheme, respectively:
δ(x) = x==0 ? 0.5 : x>0 ? 1 : 0 # дельта-функция с использованием тернарного оператора
startcond = x-> δ(x-0.45) - δ(x-0.55) # начальное условие
bordrcond = x-> 0. # условие на границе
D(u) = 1 # коэффициент диффузии
Φ(u) = 0 # функция описывающая источники# чтоб ввести греческую букву вводим LaTex команду и жмем Tab# \delta press Tab -> δfunction linexplicit(Nx = 50, Nt = 40; tlmt = 0.01)
dx = 1/Nx
dt = tlmt/Nt
k = dt/(dx*dx)
print("Kurant: $k dx = $dx dt = $dt k<0.5? $(k<0.5)")
x = [i for i in range(0, length = Nx, step = dx)] # один из способов задать массив с помощью цикла
t = [i for i in range(0, length = Nt, step = dt)] # ранжированая переменная - не массив
U = zeros(Nx, Nt)
U[: ,1] = startcond.(x)
U[1 ,:] = U[Nt,:] = bordrcond.(t)
for j = 1:Nt-1, i = 2:Nx-1
U[i, j+1] = U[i,j]*(1-2k*D( U[i,j] )) + k*U[i-1,j]*D( U[i-1,j] ) + k*U[i+1,j]*D( U[i+1,j] ) + dt*Φ(U[i,j])
end
t, x, U
end
t, X, Ans2 = linexplicit( tlmt = 0.005 )
plot(X, Ans2[:,1], lab = "t1")
plot!(X, Ans2[:,10], lab = "t10")
p = plot!(X, Ans2[:,40], lab = "t40", title = "Explicit scheme")
plot( p, heatmap(t, X, Ans2) )
functionnonexplicit(Nx = 50, Nt = 40; tlmt = 0.01)
dx = 1/Nx
dt = tlmt/Nt
k = dt/(dx*dx)
print("Kurant: $k dx = $dx dt = $dt k<0.5? $(k<0.5)\n")
x = [ifori in range(0, length = Nx, step = dx)]
t = [ifori in range(0, length = Nt, step = dt)]
U = zeros(Nx, Nt)
η = zeros(Nx+1)
ξ = zeros(Nx)
U[: ,1] = startcond.(x)
U[1 ,:] = bordrcond.(t)
U[Nt,:] = bordrcond.(t)
forj = 1:Nt-1
b = -1 - 2k*D( U[1,j] )
c = -k*D( U[2,j] )
d = U[1,j] + dt*Φ(U[1,j])
ξ[2] = c/b
η[2] = -d/b
fori = 2:Nx-1
a = -k*D( U[i-1,j] )
b = -2k*D( U[i,j] ) - 1
c = -k*D( U[i+1,j] )
d = U[i,j] + dt*Φ(U[i,j])
ξ[i+1] = c / (b-a*ξ[i])
η[i+1] = (a*η[i]-d) / (b-a*ξ[i])
end
U[Nx,j+1] = η[Nx]
fori = Nx:-1:2
U[i-1,j+1] = ξ[i]*U[i,j+1] + η[i]
endend
t, x, U
endplot(X, Ans2[:,1], lab = "ex_t1")
plot!(X, Ans2[:,10], lab = "ex_t10")
plot!(X, Ans2[:,40], lab = "ex_t40")
plot!(X, Ans3[:,1], lab = "non_t1")
plot!(X, Ans3[:,10], lab = "non_t10")
plot!(X, Ans3[:,40], lab = "non_t40", title = "Comparison schemes")
Nonlinear heat equation
Much more interesting solutions can be obtained for a nonlinear heat equation, for example, with a nonlinear heat source. . If you set it in this form, then you get a solution in the form of heat fronts that extend in both directions from the primary heating zone
Φ(u) = 1e3*(u-u^3)
t, X, Ans4 = linexplicit( tlmt = 0.005 )
plot(X, Ans4[:,1], lab = "ex_t1")
plot!(X, Ans4[:,10], lab = "ex_t10")
plot!(X, Ans4[:,40], lab = "ex_t40", title = "Thermal front")
Even more unexpected solutions are possible if the diffusion coefficient is also nonlinearity. For example, if you takea , then we can observe the effect of burning environment, localized in the area of its primary heating (S-mode of combustion "with exacerbation").
At the same time, we will check how our implicit scheme works with nonlinearity and sources and diffusion coefficient
D(u) = u*u
Φ(u) = 1e3*abs(u)^(3.5)
t, X, Ans5 = linexplicit( tlmt = 0.0005 )
t, X, Ans6 = nonexplicit( tlmt = 0.0005 )
plot(X, Ans5[:,1], lab = "ex_t1")
plot!(X, Ans5[:,10], lab = "ex_t10")
p1 = plot!(X, Ans5[:,40], lab = "ex_t40", title = "Burning with aggravation")
p2 = heatmap(abs.(Ans6-Ans5), title = "Difference")
# построим разницу между результатами схем
plot(p1, p2)
Wave equation
Wave equation of hyperbolic type
describes one-dimensional linear waves without dispersion. For example, string vibrations, sound in a liquid (gas), or electromagnetic waves in a vacuum (in the latter case, the equation must be written in vector form).
The simplest difference scheme that approximates this equation is the explicit five-point scheme.
This scheme, called the “cross”, has the second order of accuracy in time and spatial coordinate and is three-layer in time.
# функция задающая начальное условие
ψ = x -> x^2 * exp( -(x-0.5)^2/0.01 )
# поведение на границах
ϕ(x) = 0
c = x -> 1# решение одномерного волнового уравнения
function pdesolver(N = 100, K = 100, L = 2pi, T = 10, a = 0.1 )
dx = L/N;
dt = T/K;
gam(x) = c(x)*c(x)*a*a*dt*dt/dx/dx;
print("Kurant-Fridrihs-Levi: $(dt*a/dx) dx = $dx dt = $dt")
u = zeros(N,K);
x = [i for i in range(0, length = N, step = dx)]
# инициализируем первые два временных слоя
u[:,1] = ψ.(x);
u[:,2] = u[:,1] + dt*ψ.(x);
# задаём поведение на границах
fill!( u[1,:], 0);
fill!( u[N,:], ϕ(L) );
for t = 2:K-1, i = 2:N-1
u[i,t+1] = -u[i,t-1] + gam( x[i] )* (u[i-1,t] + u[i+1,t]) + (2-2*gam( x[i] ) )*u[i,t];
end
x, u
end
N = 50; # количество шагов по координате
K = 40; # и по времени
a = 0.1; # скорость распространения волны
L = 1; # длина образца
T = 1; # длительность эксперимента
t = [i for i in range(0, length = K, stop = T)]
X, U = pdesolver(N, K, L, T, a) # вызываем расчетную функцию
plot(X, U[:,1])
plot!(X, U[:,40])
To build a surface, we will use PyPlot not as an environment of Plots, but directly:
using PyPlot
surf(t, X, U)
And for dessert, wave propagation at a speed dependent on the coordinates:
ψ = x -> x>1/3 ? 0 : sin(3pi*x)^2
c = x -> x>0.5 ? 0.5 : 1
X, U = pdesolver(400, 400, 8, 1.5, 1)
plot(X, U[:,1])
plot!(X, U[:,40])
plot!(X, U[:,90])
plot!(X, U[:,200], xaxis=("Распространение волнового фронта", (0, 1.5), 0:0.5:2) )
U2 = [ U[i,j] for i = 1:60, j = 1:size(U,2) ] # срежем пустую область
surf(U2) # такие вещи лучше смотреть с разных ракурсов
heatmap(U, yaxis=("Координаты возмущения", (0, 50), 0:10:50))
It's enough for today. For more detailed information:
link PyPlot to the githabb , more examples of using Plots as an environment, and a good Russian-language Julia memo .