Solution of the 2D Poisson problem using our own FEM codeĀ¶

InĀ [1]:
from import_hack import *
from methodsnm.mesh_2d import *
from methodsnm.visualize import *
mesh = StructuredRectangleMesh(10, 10)
DrawMesh2D(mesh)
source module for methodsNM imported.
No description has been provided for this image

On the mesh, we define a finite element space:

InĀ [2]:
from methodsnm.fes import *
fes = P1_Triangle_Space(mesh)

On the mesh, with the given finite element space, we define the variational formulation: $$ \int_{\Omega} \nabla u \cdot \nabla v dx + \int_{\Omega} u v dx = \int_{\Omega} f v dx $$ Replacing

  • $u \leadsto u_h = \sum_j u_j \phi_j $ and
  • $v \leadsto v_h = \phi_i$ we obtain a linear system:
InĀ [3]:
from methodsnm.forms import *
from methodsnm.formint import *
from numpy import pi, cos

blf = BilinearForm(fes)
c = GlobalFunction(lambda x: 1, mesh = mesh)
blf += LaplaceIntegral(c)
blf += MassIntegral(c)
blf.assemble()

lf = LinearForm(fes)
f = GlobalFunction(lambda x: (1 + pi**2) * cos(pi*x[0]), mesh = mesh)
lf += SourceIntegral(f)
lf.assemble()
Warning: Using numerical differentiation for deriv evaluation in <class 'methodsnm.fe_2d.P1_Triangle_FE'> object.

blf.matrix

InĀ [4]:
print(blf.matrix, "\n", lf.vector)
<Compressed Sparse Row sparse matrix of dtype 'float64'
	with 761 stored elements and shape (121, 121)>
  Coords	Values
  (0, 0)	1.0008333398518834
  (0, 1)	-0.49958333558253515
  (0, 11)	-0.4995833357098663
  (1, 0)	-0.49958333558253515
  (1, 1)	2.002500011016954
  (1, 2)	-0.49958333558253515
  (1, 11)	0.0008333333333333335
  (1, 12)	-0.9991666712924016
  (2, 1)	-0.49958333558253515
  (2, 2)	2.002500011016953
  (2, 3)	-0.49958333558253504
  (2, 12)	0.0008333333333333335
  (2, 13)	-0.9991666712924011
  (3, 2)	-0.49958333558253504
  (3, 3)	2.002500011016953
  (3, 4)	-0.4995833355825348
  (3, 13)	0.0008333333333333328
  (3, 14)	-0.9991666712924011
  (4, 3)	-0.4995833355825348
  (4, 4)	2.002500011016953
  (4, 5)	-0.49958333558253504
  (4, 14)	0.0008333333333333335
  (4, 15)	-0.9991666712924009
  (5, 4)	-0.49958333558253504
  (5, 5)	2.0025000110169526
  :	:
  (115, 115)	2.002500005465838
  (115, 116)	-0.4995833346997928
  (116, 105)	-0.9991666712924011
  (116, 106)	0.0008333333333333328
  (116, 115)	-0.4995833346997928
  (116, 116)	2.002500005465838
  (116, 117)	-0.4995833346997928
  (117, 106)	-0.9991666712924016
  (117, 107)	0.0008333333333333335
  (117, 116)	-0.4995833346997928
  (117, 117)	2.0025000054658375
  (117, 118)	-0.49958333469979216
  (118, 107)	-0.9991666712924014
  (118, 108)	0.0008333333333333328
  (118, 117)	-0.49958333469979216
  (118, 118)	2.0025000054658375
  (118, 119)	-0.4995833346997928
  (119, 108)	-0.9991666712924011
  (119, 109)	0.0008333333333333328
  (119, 118)	-0.4995833346997928
  (119, 119)	2.002500005465838
  (119, 120)	-0.4995833346997928
  (120, 109)	-0.49958333558253504
  (120, 119)	-0.4995833346997928
  (120, 120)	1.00083333581159 
 [ 1.80268617e-02  5.21378644e-02  4.52694327e-02  3.39697135e-02
  1.93448021e-02  2.82628661e-03 -1.39688855e-02 -2.93966857e-02
 -4.19469335e-02 -5.03911232e-02 -3.58758170e-02  5.39027006e-02
  1.02529004e-01  8.72163791e-02  6.33664073e-02  3.33136901e-02
 -3.22332137e-09 -3.33136962e-02 -6.33664125e-02 -8.72163828e-02
 -1.02529006e-01 -5.39026750e-02  5.39027006e-02  1.02529004e-01
  8.72163791e-02  6.33664073e-02  3.33136901e-02 -3.22332137e-09
 -3.33136962e-02 -6.33664125e-02 -8.72163828e-02 -1.02529006e-01
 -5.39026750e-02  5.39027006e-02  1.02529004e-01  8.72163791e-02
  6.33664073e-02  3.33136901e-02 -3.22332137e-09 -3.33136962e-02
 -6.33664125e-02 -8.72163828e-02 -1.02529006e-01 -5.39026750e-02
  5.39027006e-02  1.02529004e-01  8.72163791e-02  6.33664073e-02
  3.33136901e-02 -3.22332137e-09 -3.33136962e-02 -6.33664125e-02
 -8.72163828e-02 -1.02529006e-01 -5.39026750e-02  5.39027006e-02
  1.02529004e-01  8.72163791e-02  6.33664073e-02  3.33136901e-02
 -3.22332137e-09 -3.33136962e-02 -6.33664125e-02 -8.72163828e-02
 -1.02529006e-01 -5.39026750e-02  5.39027006e-02  1.02529004e-01
  8.72163791e-02  6.33664073e-02  3.33136901e-02 -3.22332137e-09
 -3.33136962e-02 -6.33664125e-02 -8.72163828e-02 -1.02529006e-01
 -5.39026750e-02  5.39027006e-02  1.02529004e-01  8.72163791e-02
  6.33664073e-02  3.33136901e-02 -3.22332136e-09 -3.33136962e-02
 -6.33664125e-02 -8.72163828e-02 -1.02529006e-01 -5.39026750e-02
  5.39027006e-02  1.02529004e-01  8.72163791e-02  6.33664073e-02
  3.33136901e-02 -3.22332137e-09 -3.33136962e-02 -6.33664125e-02
 -8.72163828e-02 -1.02529006e-01 -5.39026750e-02  5.39027006e-02
  1.02529004e-01  8.72163791e-02  6.33664073e-02  3.33136901e-02
 -3.22332137e-09 -3.33136962e-02 -6.33664125e-02 -8.72163828e-02
 -1.02529006e-01 -5.39026750e-02  3.58758388e-02  5.03911395e-02
  4.19469464e-02  2.93966938e-02  1.39688880e-02 -2.82628983e-03
 -1.93448107e-02 -3.39697268e-02 -4.52694493e-02 -5.21378827e-02
 -1.80268581e-02]

Next, we solve the linear system. And we use a direct solver from scipy for that (for now):

InĀ [5]:
uh = FEFunction(fes)
from scipy.sparse.linalg import spsolve
uh.vector = spsolve(blf.matrix, lf.vector)

Finally, we can visualize the solution:

InĀ [6]:
DrawFunction2D(uh)
No description has been provided for this image

This problem now contained several simplifications, that can be removed step by step:

  • qualitative evaluation only (no quantitative evaluation, no convergence study)
  • boundary conditions are natural. Different boundary conditions make it more difficult
  • 1D $\leadsto$ 2D
  • P1 (low order) discretization vs. P2 and higher order discretizations
InĀ [7]:
from methodsnm.forms import compute_difference_L2

uex =  GlobalFunction(lambda x: cos(pi*x[0]), mesh = mesh)
l2diff = compute_difference_L2(uh, uex, mesh, intorder = 6)

print("l2diff =", l2diff)
l2diff = 0.006129571367563993