PDE solver in julia 0.6.0 by wanglj
Finite difference of time:
∂ρ∂t(xi,tj)=ρ(xi,tj+Δt)−ρ(xi,tj)Δt+O(Δt)Finite difference of space:
∂2ρ∂x2(xi,tj)=ρ(xi+Δx,tj)−2ρ(xi,tj)+ρ(xi−Δx,tj)dx2+O(Δx2)Apply equation(2) and (3) to equation(1), and let ρi,j=ρ(xi,tj), we get the expression of forward time evolution
ρi,j+1−ρi,jΔt=Dρi+1,j−2ρi,j+ρi−1,jΔx2⇒ρi,j+1=(1−2λ)ρi,j+λ(ρi+1,j+ρi−1,j)where λ=D⋅ΔtΔx2
Supplemented by initial condition: ρi,0=ρ(xi), and Boundary conditions: ρ0,j=ρ0, ρm,j=ρm, we can solve it like this:
[ρ1,j+1ρ2,j+1⋮ρm−1,j+1]=[1−2λλ0λ1−2λλ⋱⋱⋱0λ1−2λ][ρ1,jρ2,j⋮ρm−1,j]+λ[ρ00⋮ρm]Sovling an example system with initial value of ρcenter=1.0 at center and boundary conditions with ρL=ρR=0.
# Define constants and calculate standard dt.
const nx = 100
const dx = 1.e-11
const D = 1.69e-9
const steps = 100
dt = 0.5 * dx^2 /(2 * D)
# Set grid and initial value(including boundary conditions) for dx.
grid = zeros(Float64, nx, steps)
grid[50, 1] = 1.0
Lbound = 0.0
Rbound = 0.0
grid[1, :] = Lbound
grid[nx, :] = Rbound
# Set up tridiagonal and sparse matrix for A and R.
lbd = D * dt / dx^2
matAsp = SymTridiagonal(fill(1 - 2 * lbd, nx - 2), fill(lbd, nx - 3))
matRsp = spzeros(nx - 2)
matRsp[1] = Lbound
matRsp[nx - 2] = Rbound
# Calculate and plot.
for i = 2:steps
grid[2:nx-1, i] = matAsp * grid[2:nx-1, i - 1] + lbd * matRsp
end
using Plots
#plotly(size=(600,400))
#plot(grid[:,1], title="t")
gr()
anim = @animate for i=1:steps
plot(grid[:, i])
plot!(ylims = (0, 1), yticks = 0:0.1:1, title="t = $(round(i * dt * 1.E12, 3)) ps")
end every 10
gif(anim, "pics/forward.gif", fps = 5)
WARNING: using Plots.grid in module Main conflicts with an existing identifier. INFO: Saved animation to /home/wanglj/PDE/pics/forward.gif
In implicit scheme, time evolves backwards.
ρi,j−ρi,j−1Δt=Dρi+1,j−2ρi,j+ρi−1,jΔx2⇒(1+2λ)ρi,j−λ(ρi+1,j+ρi−1,j)=ρi,j−1where λ=D⋅ΔtΔx2
Supplemented by initial condition: ρi,0=ρ(xi), and Boundary conditions: ρ0,j=ρ0, ρm,j=ρm, we can solve it like this:
[1+2λ−λ0−λ1+2λ−λ⋱⋱⋱0−λ1+2λ][ρ1,jρ2,j⋮ρm−1,j]−λ[ρ00⋮ρm]=[ρ1,j−1ρ2,j−1⋮ρm−1,j−1]Sovling an example system with initial value of ρcenter=1.0 at center and boundary conditions with ρL=ρR=0.
const nx = 100
const dx = 1.e-11
const D = 1.69e-9
const steps = 100
dt = 0.5 * dx^2 /(2 * D)
# Set grid and initial value(including boundary conditions) for dx.
grid = zeros(Float64, nx, steps)
grid[50, 1] = 1.0
Lbound = 0.0
Rbound = 0.0
grid[1, :] = Lbound
grid[nx, :] = Rbound
# Set up tridiagonal and sparse matrix for A and R.
lbd = D * dt / dx^2
matRsp = spzeros(nx - 2)
matRsp[1] = Lbound
matRsp[nx - 2] = Rbound
# Calculate and plot.
ds = zeros(nx - 3)
d = zeros(nx - 2)
for i = 2:steps
bmatrix = grid[2:nx-1, i-1] + lbd * matRsp
ds .= -lbd
d .= 1 + 2 * lbd
grid[2:nx-1, i] = LAPACK.ptsv!(d, ds, bmatrix)
end
anim = @animate for i=1:steps
plot(grid[:, i])
plot!(ylims = (0, 1), yticks = 0:0.1:1, title="t = $(round(i * dt * 1.E12, 3)) ps")
end every 10
gif(anim, "pics/backward.gif", fps = 5)
INFO: Saved animation to /home/wanglj/PDE/pics/backward.gif
In Crank-Nicolson scheme, we take the average of explicit scheme and implicit scheme.
ρi,j+1−ρi,jΔt=D2(ρi+1,j−2ρi,j+ρi−1,jΔx2+ρi+1,j+1−2ρi,j+1+ρi−1,j+1Δx2)⇒(2+2λ)ρi,j+1−λ(ρi+1,j+1+ρi−1,j+1)=(2−2λ)ρi,j+λ(ρi+1,j+ρi−1,j)where λ=D⋅ΔtΔx2
Supplemented by initial condition: ρi,0=ρ(xi), and Boundary conditions: ρ0,j=ρ0, ρm,j=ρm, we can solve it like this:
[2+2λ−λ0−λ2+2λ−λ⋱⋱⋱0−λ2+2λ][ρ1,jρ2,j⋮ρm−1,j]−λ[ρ00⋮ρm]=[2−2λλ0λ2−2λλ⋱⋱⋱0λ2−2λ][ρ1,jρ2,j⋮ρm−1,j]+λ[ρ00⋮ρm]Sovling an example system with initial value of ρcenter=1.0 at center and boundary conditions with ρL=ρR=0.
const nx = 100
const dx = 1.e-11
const D = 1.69e-9
const steps = 100
dt = 0.5 * dx^2 /(2 * D)
# Set grid and initial value(including boundary conditions) for dx.
grid = zeros(Float64, nx, steps)
grid[50, 1] = 1.0
Lbound = 0.0
Rbound = 0.0
grid[1, :] = Lbound
grid[nx, :] = Rbound
# Set up tridiagonal and sparse matrix for A and R.
lbd = D * dt / dx^2
matBsp = SymTridiagonal(fill(2 - 2 * lbd, nx - 2), fill(lbd, nx - 3))
matRsp = spzeros(nx - 2)
matRsp[1] = Lbound
matRsp[nx - 2] = Rbound
# Calculate and plot.
ds = zeros(nx - 3)
d = zeros(nx - 2)
for i = 2:steps
bmatrix = matBsp * grid[2:nx-1, i-1] + 2 * lbd * matRsp
ds .= -lbd
d .= 2 + 2 * lbd
grid[2:nx-1, i] = LAPACK.ptsv!(d, ds, bmatrix)
end
anim = @animate for i=1:steps
plot(grid[:, i])
plot!(ylims = (0, 1), yticks = 0:0.1:1, title="t = $(round(i * dt * 1.E12, 3)) ps")
end every 10
gif(anim, "pics/crank-nicolson.gif", fps = 5)
INFO: Saved animation to /home/wanglj/PDE/pics/crank-nicolson.gif
The finite difference in Crank-Nicolson scheme for the above equation is: ρi,j+1−ρi,jΔt=D2(ρi+1,j−2ρi,j+ρi−1,jΔx2+ρi+1,j+1−2ρi,j+1+ρi−1,j+1Δx2)+D⋅U′(xi)2kBT(ρi+1,j+1−ρi−1,j+12Δx+ρi+1,j−ρi−1,j2Δx)+D⋅U′′(xi)2kBT(ρi,j+1+ρi,j)⇒(2+2λ+τi)ρi,j+1+(ηi−λ)ρi+1,j+1−(λ+ηi)ρi−1,j+1=(2−2λ−τi)ρi,j+(λ−ηi)ρi+1,j+(λ+ηi)ρi−1,j
where λ=D⋅ΔtΔx2, ηi=−D⋅Δt2kBTΔx⋅U′(xi), τi=−D⋅ΔtkBT⋅U′′(xi).
Rewrite this in matrix form,
A→ρi,j+1−R=B→ρi,j+RSupplemented by initial condition: ρi,0=ρ(xi), and Boundary conditions: ρ0,j=ρ0, ρm,j=ρm, we can solve it like this:
[2+2λ+τ1η1−λ0−(λ+η2)2+2λ+τ2η2−λ⋱⋱⋱0−(λ+ηm−1)2+2λ+τm−1][ρ1,jρ2,j⋮ρm−1,j]+[−(λ+η1)ρ00⋮(ηm−1−λ)ρm]=[2−2λ−τ1λ−η10λ+η22−2λ−τ2λ−η2⋱⋱⋱0λ+ηm−12−2λ−τm−1][ρ1,jρ2,j⋮ρm−1,j]+[(λ+η1)ρ00⋮(λ−ηm−1)ρm]Sovling an example system with initial value of ρ=1.0 at x=30Å and boundary conditions with ρL=ρR=0 using the potential profile of nw=0.
using DataFrames
df = readtable("csv/new0_1d.csv")
# Fit potential curve and its derivative from csv data file using Scipy.
using PyCall
@pyimport importlib.machinery as machinery
loader = machinery.SourceFileLoader("CsvFit","/home/wanglj/PDE/potential.py")
cf = loader[:load_module]("CsvFit")
fit = cf[:Potential]("csv/new0_1d.csv")
fit2 = cf[:Potential]("csv/new1_extended2nd_1d.csv")
display(plot([df[:z].*1.e9, df[:z].*1.e9], [fit[:f](df[:z]), fit2[:f](df[:z])], title="potential", label=["new 0","new 1"]))
display(plot([df[:z].*1.e9, df[:z].*1.e9], [fit[:grad](df[:z]).*1.e-9, fit2[:grad](df[:z]).*1.e-9], title="first derivative"))
display(plot([df[:z].*1.e9, df[:z].*1.e9], [fit[:grad2](df[:z]).*1.e-18, fit2[:grad2](df[:z]).*1.e-18], title="second derivative"))
WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 in #readtable#84 at /home/wanglj/.julia/v0.6/DataFrames/src/dataframe/io.jl WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 in #readtable#84 at /home/wanglj/.julia/v0.6/DataFrames/src/dataframe/io.jl WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 WARNING: Compat.UTF8String is deprecated, use String instead. likely near In[5]:2 in builddf at /home/wanglj/.julia/v0.6/DataFrames/src/dataframe/io.jl
const nx = 100
const dx = 1.e-10
const D = 1.69e-9
const steps = 100
const kBT = 0.593 # kcal/mol
dt = 0.5 * dx^2 /(2 * D)
# Set grid and initial value(including boundary conditions) for dx.
grid = zeros(Float64, nx, steps)
# Set η and τ array
η = [ - D * dt * fit[:grad](dx * i + 12.5e-10)[1] / (2 * kBT * dx) for i in 1:nx - 2]
τ = [ - D * dt * fit[:grad2](dx * i + 12.5e-10)[1] / kBT for i in 1:nx - 2]
grid[30, 1] = 1.0
Lbound = 0.0
Rbound = 0.0
grid[1, :] = Lbound
grid[nx, :] = Rbound
# Set up tridiagonal and sparse matrix for B and R.
λ = D * dt / dx^2
matBsp = Tridiagonal(fill(λ, nx - 3), fill(2 - 2 * λ, nx - 2), fill(λ, nx - 3))
matBsp[1, 1] -= τ[1]
matBsp[1, 2] -= η[1]
for i = 2:nx - 3
matBsp[i, i] -= τ[i]
matBsp[i, i-1] += η[i]
matBsp[i, i+1] -= η[i]
end
matBsp[nx-2, nx-2] -= τ[end]
matBsp[nx-2, nx-3] += η[end]
matRsp = spzeros(nx - 2)
matRsp[1] = Lbound * 2 * (λ + η[1])
matRsp[nx - 2] = Rbound * 2 * (λ - η[end])
# Calculate and plot.
dg = fill(2 + 2 * λ, nx - 2) # Diagonal elements
doff = fill(- λ, nx - 3) # Offdiagonal elements
dl = doff - η[2:end]
ds = dg + τ
du = doff + η[1:end - 1]
# Solve tridiagonal system.
for i = 2:steps
bmatrix = matBsp * grid[2:nx-1, i-1] + matRsp
# dl = doff - η[2:end]
# ds = dg + τ
# du = doff + η[1:end - 1]
grid[2:nx-1, i] = LAPACK.gtsv!(copy(dl), copy(ds), copy(du), bmatrix)
end
anim = @animate for i=1:steps
plot(grid[:, i])
plot!(ylims = (0, 1), yticks = 0:0.1:1, title="t = $(round(i * dt * 1.E12, 3)) ps")
end every 10
gif(anim, "pics/potential-crank-nicolson.gif", fps = 5)
WARNING: redefining constant dx INFO: Saved animation to /home/wanglj/PDE/pics/potential-crank-nicolson.gif
When reaction terms are added to the equation(16), equations corresponding to different nw become coupled equations:
{∂ρ0(x,t)∂t=D∂∂x[∂ρ0(x,t)∂x+1kBT∂U0(x)∂xρ0(x,t)]−[k0→1+kwf0(x)]ρ0(x,t)+k1→0ρ1(x,t)∂ρ1(x,t)∂t=D∂∂x[∂ρ1(x,t)∂x+1kBT∂U1(x)∂xρ1(x,t)]−[k1→2+k1→0+kwf1(x)]ρ1(x,t)+k2→1ρ2(x,t)+k0→1ρ0(x,t)∂ρ2(x,t)∂t=D∂∂x[∂ρ2(x,t)∂x+1kBT∂U2(x)∂xρ2(x,t)]−[k2→3+k2→1+kwf2(x)]ρ2(x,t)+k3→2ρ3(x,t)+k1→2ρ1(x,t)⋮⋮∂ρn−1(x,t)∂t=D∂∂x[∂ρn−1(x,t)∂x+1kBT∂Un−1(x)∂xρn−1(x,t)]−[kn−1→n+kn−1→n−2+kwfn−1(x)]ρn−1(x,t)+kn→n−1ρn(x,t)+kn−2→n−1ρn−2(x,t)∂ρn(x,t)∂t=D∂∂x[∂ρn(x,t)∂x+1kBT∂Un(x)∂xρn(x,t)]−[kn→n−1+kwfn(x)]ρn(x,t)+kn−1→nρn−1(x,t)Let ρki,j=ρk(xi,tj), the finite difference in Crank-Nicolson scheme for nw=k is: ρki,j+1−ρki,jΔt=D2(ρki+1,j−2ρki,j+ρi−1,jΔx2+ρi+1,j+1−2ρi,j+1+ρi−1,j+1Δx2)+D⋅U′k(xi)2kBT(ρki+1,j+1−ρki−1,j+12Δx+ρki+1,j−ρki−1,j2Δx)+D⋅U′′k(xi)2kBT(ρki,j+1+ρki,j)−kk→k−1+kk→k+1+kwfk(xi)2(ρki,j+1+ρki,j)+kk−1→k2(ρk−1i,j+1+ρk−1i,j)+kk+1→k2(ρk+1i,j+1+ρk+1i,j)⇒(2+2λ+τki)ρki,j+1+(ηi−λ)ρki+1,j+1−(λ+ηki)ρki−1,j+1+ξkiρki,j+1−ζkρk+1i,j+1−κkρk−1i,j+1=(2−2λ−τki)ρki,j+(λ−ηki)ρki+1,j+(λ+ηki)ρki−1,j−ξkiρki,j+1+ζkρk+1i,j+1+κkρk−1i,j+1
where
λ=D⋅ΔtΔx2ηki=−D⋅Δt2kBTΔx⋅U′k(xi)τki=−D⋅ΔtkBT⋅U′′k(xi)ξki=(kk→k+1+kk→k−1+kwfk(xi))Δtζk=kk+1→kΔtκk=kk−1→kΔtWe further define following (m−1)×(m−1) matrices:
Ak=[2+2λ+τk1ηk1−λ0−(λ+ηk2)2+2λ+τk2ηk2−λ⋱⋱⋱0−(λ+ηkm−1)2+2λ+τkm−1]Bk=[2−2λ−τk1λ−ηk10λ+ηk22−2λ−τk2λ−ηk2⋱⋱⋱0λ+ηkm−12−2λ−τkm−1]Ξk=[ξk1ξk2⋱ξkm−1]Zk=[ζkζk⋱ζk]Kk=[κkκk⋱κk]Pk,j=[ρk1,jρk2,j⋮ρkm−1,j]Rk=[(λ+ηk1)ρk00⋮(λ−ηkm−1)ρkm]Rewrite in matrix form,
[A0+Ξ0−Z00−K1A1+Ξ1−Z1⋱⋱⋱0−KnAn+Ξn][P0,jP1,j⋮Pn,j]−[R0R1⋮Rn]=[B0−Ξ0Z00K1B1−Ξ1Z1⋱⋱⋱0KnBn−Ξn][P0,j−1P1,j−1⋮Pn,j−1]+[R0R1⋮Rn]Sovling an example system with initial value of ρ=1.0 at x=40Å for all nw=0:9 and boundary conditions with ρL=ρR=0 using the potential profile of nw=0.
# Non-adjustable constants
const kBT = 0.593 # kcal/mol
const kB = 1.38e-23
const T = 298.15
const r_ion = 1.75e-10
const r_water = 1.40e-10
const m_ion = 35.453
const m_water = 18.015
const NA = 6.02e23
const Λ3 = 4.87e-33
const μ_water = - 2.386 # kcal/mol
# Adjustable constants
const nx = 100
const dx = 1.e-10
const D = 1.69e-9
const steps = 1000
const nw = 10
const ρ_water = 130 # M/m^3
ΔE = [-12.14, -11.86, -11.42, -10.94, -10.47, -10.56, -10.35, -10.41, -10.35, -10.39] # kcal/mol
dt = 0.5 * dx^2 /(2 * D)
# Set grid and initial value(including boundary conditions) for dx.
# init_value = [[30, 1.0], [35, 0.8], [40, 0.6], [45, 0.4], [50, 0.2]]
init_value = []
for i = 1:nw
push!(init_value, [40, 1.0])
end
grids = [] # [nx, steps] * nw
Lbound = 0.0
Rbound = 0.0
# Set potential profile fittings for every nw.
fits = [] # f * nw
for i = 1:nw
push!(grids, zeros(Float64, nx, steps))
grids[i][1, :] = Lbound
grids[i][nx, :] = Rbound
grids[i][Int(init_value[i][1]), 1] = init_value[i][2]
push!(fits, fit)
end
λ = D * dt / dx^2
# Set η and τ array
ηs = [] # [nx - 2] * nw
τs = [] # [nx - 2] * nw
for i = 1:nw
push!(ηs, [ - D * dt * fits[i][:grad](dx * x + 12.5e-10)[1] / (2 * kBT * dx) for x in 1:nx - 2])
push!(τs, [ - D * dt * fits[i][:grad2](dx * x + 12.5e-10)[1] / kBT for x in 1:nx - 2])
end
# Set k_xx
k_evp =zeros(nw)
k_adp = zeros(nw)
k_wf = zeros(nw)
for i = 1:nw
i - 1 < 4 ? ii = 4 : ii = i
r_cluster = 1.2 * (r_ion^3 + r_water^3 * (ii - 1))^(1/3)
μ = (m_ion + m_water * (i - 1)) * m_water / (m_ion + m_water * i) / NA
k_adp_temp = π * (r_cluster + r_water)^2 * sqrt(8 * kB * T / (π * μ))
if i < nw
k_adp[i] = k_adp_temp * ρ_water * NA
k_evp[i + 1] = k_adp_temp * i / Λ3 * exp((ΔE[i] - μ_water) / kBT)
end
end
# Set up matrices A, B, Ξ, Z, K, R
matA = []
matB = []
matΞ = []
matZ = []
matK = []
matR = []
for i = 1:nw
push!(matA, Tridiagonal([ - λ - ηs[i][x] for x in 2:nx - 2],
[2 + 2 * λ + τs[i][x] for x in 1:nx - 2],
[- λ + ηs[i][x] for x in 1:nx - 3]))
push!(matB, Tridiagonal([ λ + ηs[i][x] for x in 2:nx - 2],
[2 - 2 * λ - τs[i][x] for x in 1:nx - 2],
[ λ - ηs[i][x] for x in 1:nx - 3]))
push!(matΞ, Diagonal(fill((k_adp[i] + k_evp[i] + k_wf[i]) * dt, nx - 2)))
push!(matZ, Diagonal(fill(k_evp[i] * dt, nx - 2))) # subdiagonal
push!(matK, Diagonal(fill(k_adp[i] * dt, nx - 2))) # superdiagonal
matRtmp = spzeros(nx - 2)
matRtmp[1] = Lbound * 2 * (λ + ηs[i][1])
matRtmp[nx - 2] = Rbound * 2 * (λ - ηs[i][end])
push!(matR, matRtmp)
end
# Setup full matrices.
amatrix = hcat(matA[1] + matΞ[1], - matZ[2])
bmatrix = hcat(matB[1] - matΞ[1], matZ[2])
for i = 1:nw - 2
amatrix = hcat(amatrix, zeros(nx - 2, nx - 2))
bmatrix = hcat(bmatrix, zeros(nx - 2, nx - 2))
end
rmatrix = matR[1]
prepmatrix = grids[1][2:nx - 1, 1]
for i = 2:nw - 1
rowA = hcat(-matK[i - 1], matA[i] + matΞ[i], - matZ[i + 1])
rowB = hcat(matK[i - 1], matB[i] - matΞ[i], matZ[i + 1])
for j = 1:i - 2
rowA = hcat(zeros(nx - 2, nx - 2), rowA)
rowB = hcat(zeros(nx - 2, nx - 2), rowB)
end
for j = i + 2: nw
rowA = hcat(rowA, zeros(nx - 2, nx - 2))
rowB = hcat(rowB, zeros(nx - 2, nx - 2))
end
amatrix = vcat(amatrix, rowA)
bmatrix = vcat(bmatrix, rowB)
rmatrix = vcat(rmatrix, matR[i])
prepmatrix = vcat(prepmatrix, grids[i][2:nx - 1, 1])
end
rowA = hcat(-matK[nw - 1], matA[nw] + matΞ[nw])
rowB = hcat(matK[nw - 1], matB[nw] - matΞ[nw])
for i = 1:nw - 2
rowA = hcat(zeros(nx - 2, nx - 2), rowA)
rowB = hcat(zeros(nx - 2, nx - 2), rowB)
end
amatrix = vcat(amatrix, rowA)
bmatrix = vcat(bmatrix, rowB)
rmatrix = vcat(rmatrix, matR[nw])
prepmatrix = vcat(prepmatrix, grids[nw][2:nx - 1, 1])
# Solve tridiagonal system.
for i = 2:steps
pmatrix = LAPACK.gesv!(copy(full(amatrix)), bmatrix * prepmatrix + rmatrix)
# pmatrix = inv(full(amatrix)) * (bmatrix * prepmatrix + rmatrix)
prepmatrix = pmatrix[1]
for j = 1:nw
grids[j][2:nx - 1, i] = pmatrix[1][1 + (nx - 2) * (j - 1):nx - 2 + (nx - 2) * (j - 1)]
end
end
WARNING: redefining constant steps
anim = @animate for i=1:steps
plot([grids[x][:, i] for x in 1:nw])
plot!(ylims = (0, 1), yticks = 0:0.1:1, title="t = $(round(i * dt * 1.E12, 3)) ps")
end every 10
gif(anim, "pics/coupled.gif", fps = 5)
INFO: Saved animation to /home/wanglj/PDE/pics/coupled.gif