import numpy
# calculate the number of interior grid points
def calc_matrix_size(nx, ny):
size = 0
for m1 in range(1, nx):
for m2 in range(1, ny):
if inside(m1, m2, nx, ny): size = size + 1
return size
# calculate the index of an interior grid point
# (asserts that the grid point lies inside)
def calc_index(m1_, m2_, nx, ny):
i = 0 # interior grid point number (= equation number)
for m1 in range(1, nx):
for m2 in range(1, ny):
if inside(m1, m2, nx, ny):
if m1 == m1_ and m2 == m2_: return i
i = i + 1
# Solve equation -Laplace u = f with Dirichlet boundary
# conditions in a subdomain of the square (0, a) x (0, b).
def fdm_solve_2d_2(a, b, nx, ny, f, g):
hx = a/float(nx)
hx2 = hx*hx
hy = b/float(ny)
hy2 = hy*hy
size = calc_matrix_size(nx, ny)
print "matrix size =", size
I = []
J = []
V = []
rhs = numpy.zeros(size)
print "Assembling."
i_c = 0 # interior grid point number (= equation number)
for m1 in range(1, nx):
for m2 in range(1, ny):
if inside(m1, m2, nx, ny):
# matrix entry
I.append(i_c)
J.append(i_c)
V.append(2./hx2 + 2./hy2)
x_phys = m1*hx
y_phys = m2*hy
coeff = -1./hx2
if away_from_left_bdy(m1, m2, nx, ny):
i_l = calc_index(m1-1, m2, nx, ny)
I.append(i_c)
J.append(i_l)
V.append(coeff)
else: rhs[i_c] = rhs[i_c] - coeff * g(x_phys-hx, y_phys, a, b)
coeff = -1./hx2
if away_from_right_bdy(m1, m2, nx, ny):
i_r = calc_index(m1+1, m2, nx, ny)
I.append(i_c)
J.append(i_r)
V.append(coeff)
else: rhs[i_c] = rhs[i_c] - coeff * g(x_phys+hx, y_phys, a, b)
coeff = -1./hy2
if away_from_bottom_bdy(m1, m2, nx, ny):
i_b = i_c - 1
I.append(i_c)
J.append(i_b)
V.append(coeff)
else: rhs[i_c] = rhs[i_c] - coeff * g(x_phys, y_phys-hy, a, b)
coeff = -1./hy2
if away_from_top_bdy(m1, m2, nx, ny):
i_t = i_c + 1
I.append(i_c)
J.append(i_t)
V.append(coeff)
else: rhs[i_c] = rhs[i_c] - coeff * g(x_phys, y_phys+hy, a, b)
# rhs entry
rhs[i_c] = rhs[i_c] + f(x_phys, y_phys)
# increasing active grid point number
i_c = i_c + 1
# creating CSR matrix from arrays I, J, V
m = sparse.coo_matrix((V,(I,J)),shape=(size,size))
m = m.tocsr()
rhs = array(rhs)
print "Solving."
t = time()
#sol, res = gmres(m, rhs, tol=1.e-8) # also possible: cg, cgs, qmr, gmres, bicg, bicgstab, ...
sol = spsolve(m, rhs)
print "Matrix solve took", time()-t, "s."
# Plotting
print "Plotting."
from mpl_toolkits.mplot3d import Axes3D
from pylab import figure, savefig
import numpy as np
from numpy import zeros, sin
from matplotlib import cm
fig = figure()
ax = Axes3D(fig)
X, Y = np.mgrid[0:(nx+1)*hx:hx, 0:(ny+1)*hy:hy]
m = zeros((nx+1, ny+1), dtype="float")
# defining values at Cartesian grid points
i_c = 0
for m1 in range(nx+1):
for m2 in range(ny+1):
if inside(m1, m2, nx, ny):
m[m1][m2] = sol[i_c]
i_c = i_c + 1
else:
if on_boundary(m1, m2, nx, ny):
x_phys = m1*hx
y_phys = m2*hy
m[m1][m2] = g(x_phys, y_phys, a, b)
else: m[m1][m2] = 0
# putting them into the array Z for plotting
Z = m
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
savefig("surface1.png")
# Problem parameters
# right-hand side
def f(x,y):
return 1.
# Dirichlet boundary conditions
def g(x,y,a,b):
#return x*y
return 0
# outer rectangle measures
a = 1.
b = 1.
# divisions
nx = 60
ny = 60
# deleted cells in the lower-left corner
dx = 30
dy = 30
# define the domain boundary
def on_boundary(m1, m2, nx, ny):
if m1 == 0: return True
if m1 == nx: return True
if m2 == 0: return True
if m2 == ny: return True
if m1 == dx and m2 <= dy: return True
if m1 <= dx and m2 == dy: return True
return False
def inside(m1, m2, nx, ny):
if m1 < 1 or m1 > nx-1 or m2 < 1 or m2 > ny-1: return False
if m1 <= dx and m2 <= dy: return False
return True
def away_from_left_bdy(m1, m2, nx, ny):
if m1 > dx + 1: return True
if m1 > 1 and m2 > dy: return True
return False
def away_from_right_bdy(m1, m2, nx, ny):
return m1 < nx - 1
def away_from_bottom_bdy(m1, m2, nx, ny):
if m2 > dy + 1: return True
if m1 > dx and m2 > 1: return True
return False
def away_from_top_bdy(m1, m2, nx, ny):
return m2 < ny-1
# Solve by FDM
fdm_solve_2d_2(a, b, nx, ny, f, g)