Skip to content

Commit fc7b0a2

Browse files
committed
Crank-Nicholson
1 parent cbf366e commit fc7b0a2

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# PythonMisc
22
Some fairly standalone python scripts
33

4+
* crank_nicholson: basic Crank-Nicholson solver for a parabolic PDE on an interval
5+
46
* readSketchnet: tool to read data from the sketch-a-net dataset http://cybertron.cg.tu-berlin.de/eitz/projects/classifysketch/
57

68
* oncampus: Should graphs be sent from a warwick computer to the screen or a file.

crank_nicholson.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from scipy.sparse import diags
2+
import scipy.linalg
3+
import numpy as np, sys
4+
#np.set_printoptions(precision=3)
5+
6+
#solve
7+
#du/dt = D d2u/dx^2 + a du/dx + f(u)
8+
#forward in time for a length of time T e.g. [0,T]
9+
#on an interval of length L e.g. [0,L]
10+
#formulae of http://georg.io/2013/12/Crank_Nicolson_Convection_Diffusion
11+
12+
#Can easily modify the code to make f be a function of x or t too,
13+
#but would then actually care about their values.
14+
15+
#f should be a vectorized function or just return a constant
16+
#u is the initial condition u(0,x)
17+
18+
#BC order is the derivative of u which is assumed 0 at the edge
19+
#0 means Dirichlet (so you just assume there's a fixed 0 beyond
20+
# the edge, so the edge equation is just like the bulk
21+
# -i.e. the diagonals are constant
22+
#1 means Neumann (like georg.io)
23+
#2 means second deriv is 0
24+
# so the imaginary point is like u[-1]-u[0]=u[0]-u[1] or u[-1]=2*u[0]-u[1]
25+
26+
#Or: -1 means Dirichlet where the edges are not fixed at 0 but
27+
#at whatever the corresponding edge value in the IC is.
28+
29+
def crank_nicholson(u, L, T, n_timesteps, D, a = 0,
30+
f = lambda u: 0, leftBCOrder=2, rightBCOrder=2):
31+
nx = np.shape(u)[0]
32+
dx = L/(nx-1.)
33+
dt = T/(n_timesteps+0.0)
34+
sigma = D*dt/(2.*dx*dx)
35+
rho = a*dt/(4.*dx)
36+
37+
A=np.zeros((3,nx))
38+
A[0,:]=-(sigma+rho)
39+
A[2,:]=rho-sigma
40+
A[1,:]=1+2*sigma
41+
A[1,0]=(1,1+2*sigma,1+sigma+rho,1+2*rho)[leftBCOrder+1]
42+
A[1,-1]=(1,1+2*sigma,1+sigma-rho,1-2*rho)[rightBCOrder+1]
43+
A[0,1]=(0,-(sigma+rho),-(sigma+rho),-2*rho)[leftBCOrder+1]
44+
A[2,-2]=(0,rho-sigma,rho-sigma,2*rho)[rightBCOrder+1]
45+
if 0:
46+
dense_A=diags([A[2,:-1],A[1,:],A[0,1:]],[-1,0,1]).toarray()
47+
print (dense_A)
48+
49+
B_dia=(1-2*sigma)*np.ones(nx)
50+
B_top=(sigma+rho)*np.ones(nx-1)
51+
B_bot=(sigma-rho)*np.ones(nx-1)
52+
B_dia[0] =(1,1-2*sigma,1-sigma-rho,1-2*rho)[leftBCOrder+1]
53+
B_dia[-1]=(1,1-2*sigma,1-sigma+rho,1+2*rho)[rightBCOrder+1]
54+
B_top[0]=(0,sigma+rho,sigma+rho,2*rho)[leftBCOrder+1]
55+
B_bot[-1]=(0,sigma-rho,sigma-rho,-2*rho)[rightBCOrder+1]
56+
#B=diags([sigma-rho,B_dia,sigma+rho],[-1,0,1],shape=(nx,nx))
57+
B=diags([B_bot,B_dia,B_top],[-1,0,1],shape=(nx,nx))
58+
#print(B.toarray())
59+
60+
for idx in range(n_timesteps):
61+
rhs=B.dot(u)+dt*f(u)
62+
u = scipy.linalg.solve_banded((1,1),A,rhs)
63+
return u
64+
65+
if __name__=="__main__":
66+
n=100
67+
u=np.concatenate([np.zeros(n//2),np.ones(n//2)])
68+
u=np.arange(n)/10.
69+
u=u[::-1]
70+
#u=np.ones(n)
71+
u_source=(np.arange(n)-n//2)/(n/2.)
72+
u=np.abs(u_source)
73+
#u=[min(i,0.3) for i in u]
74+
D=0.01
75+
nt=100
76+
L=1
77+
T=10
78+
out=crank_nicholson(u,L,T, nt,D,0,lambda u:0)
79+
out2=crank_nicholson(u,L,T, nt,D,-0.003)
80+
#print(out2-out)
81+
from matplotlib import pyplot as plt
82+
x=list(range(n))
83+
plt.plot(x,out,x,out2)
84+
plt.show()

0 commit comments

Comments
 (0)