Fem Python PDF
Fem Python PDF
Fem Python PDF
M. M. Sussman
[email protected]
Office Hours: 11:10AM-12:10PM, Thack 622
1 / 45
Topics
Introduction
Code
2 / 45
Purpose
3 / 45
Problem description
I ODE u 00 + 2u 0 + u = f = (x + 2)
I Neumann boundary conditions
I Why? Because all 3 terms, real solution with exponentials
I Exact u = (1 + x)e1x + x(1 ex )
I Done when get correct convergence rate to exact solution
I Other b.c., rhs are available
4 / 45
How to debug and test?
5 / 45
Strategy
6 / 45
Class structure
I Mesh
I Shapefns
I FiniteElement
I Including integration over this element
I FunctionSpace
I Including assembly of integrals
7 / 45
Pseudo code
mesh=Mesh( ... )
sfns=Shapefns( ... )
V=FunctionSpace(mesh,sfns)
R
b= f
A= 0i 0j + 2 0i j + i j
R R R
8 / 45
Topics
Introduction
Code
9 / 45
Coding strategy for classes
10 / 45
Details of classes Mesh and Shapefns
I Mesh
I Mesh(N,a,b)
N is number of elements
a is left endpoint
b is right endpoint
I coordinates() or coordinates(n)
returns all coordinates or nth coordinate
I cells() or cells(n)
returns all nodes numbers of nth cell or all node numbers
I size()
returns number of mesh cells
I Shapefns
I Shapefns()
I eval(n,xi) returns n ()
I ddx(n,xi) returns 0n ()
I size() returns the number of required nodes
11 / 45
Shapefns
class Shapefns(object):
"""
Define Quadratic Lagrange shape functions
These will be defined on the (local) interval [0,1], with
mid point 0.5
Shapefns()
eval(n,xi): phi[n](xi)
ddx(n,xi): dphi[n](xi)
size(): number of nodes for these shape functions
"""
12 / 45
Shapefns
class Shapefns(object):
"""
Define Quadratic Lagrange shape functions
These will be defined on the (local) interval [0,1], with
mid point 0.5
Shapefns()
eval(n,xi): phi[n](xi)
ddx(n,xi): dphi[n](xi)
size(): number of nodes for these shape functions
"""
def __init__(self):
12 / 45
Shapefns
class Shapefns(object):
"""
Define Quadratic Lagrange shape functions
These will be defined on the (local) interval [0,1], with
mid point 0.5
Shapefns()
eval(n,xi): phi[n](xi)
ddx(n,xi): dphi[n](xi)
size(): number of nodes for these shape functions
"""
def __init__(self):
"""
an array of functions for phi and deriv phi
"""
self.__phi=[lambda xi: 2.0 * (xi-0.5) * (xi-1.0) ,\
lambda xi: 4.0 * xi * (1.0-xi), \
lambda xi: 2.0 * xi * (xi-0.5)]
12 / 45
Shapefns
class Shapefns(object):
"""
Define Quadratic Lagrange shape functions
These will be defined on the (local) interval [0,1], with
mid point 0.5
Shapefns()
eval(n,xi): phi[n](xi)
ddx(n,xi): dphi[n](xi)
size(): number of nodes for these shape functions
"""
def __init__(self):
"""
an array of functions for phi and deriv phi
"""
self.__phi=[lambda xi: 2.0 * (xi-0.5) * (xi-1.0) ,\
lambda xi: 4.0 * xi * (1.0-xi), \
lambda xi: 2.0 * xi * (xi-0.5)]
# and dphi (derivative of phi w.r.t. xi)
# derivative of second factor * first + derivative of first factor * sec
self.__dphi=[lambda xi: 2.0 * (xi-0.5) + 2.0*(xi - 1.0) ,\
lambda xi: -4.0 * xi + 4.0*(1.0 - xi), \
lambda xi: 2.0 * xi + 2.0*(xi - 0.5)]
12 / 45
Shapefns
class Shapefns(object):
"""
Define Quadratic Lagrange shape functions
These will be defined on the (local) interval [0,1], with
mid point 0.5
Shapefns()
eval(n,xi): phi[n](xi)
ddx(n,xi): dphi[n](xi)
size(): number of nodes for these shape functions
"""
def __init__(self):
"""
an array of functions for phi and deriv phi
"""
self.__phi=[lambda xi: 2.0 * (xi-0.5) * (xi-1.0) ,\
lambda xi: 4.0 * xi * (1.0-xi), \
lambda xi: 2.0 * xi * (xi-0.5)]
# and dphi (derivative of phi w.r.t. xi)
# derivative of second factor * first + derivative of first factor * sec
self.__dphi=[lambda xi: 2.0 * (xi-0.5) + 2.0*(xi - 1.0) ,\
lambda xi: -4.0 * xi + 4.0*(1.0 - xi), \
lambda xi: 2.0 * xi + 2.0*(xi - 0.5)]
self.__N=3 #number of nodes in quadratic Lagrange polynomial
12 / 45
Shapefns, contd
def eval(self,n,xi):
"""
the function phi[n](xi), for any xi
"""
return self.__phi[n](xi)
def ddx(self,n,xi):
"""
the function dphi[n](xi), for any xi
"""
return self.__dphi[n](xi)
def size(self):
"""
the number of points
"""
return self.__N
13 / 45
Shapefns, contd
def eval(self,n,xi):
"""
the function phi[n](xi), for any xi
"""
return self.__phi[n](xi)
def ddx(self,n,xi):
"""
the function dphi[n](xi), for any xi
"""
return self.__dphi[n](xi)
def size(self):
"""
the number of points
"""
return self.__N
13 / 45
What about the Mesh Class?
14 / 45
Test it!
15 / 45
Test code
N=5
rightpt = 5.0
print "\n\nFEM1D.py Test case, dx=",rightpt/N
mesh = Mesh(N,0.0,rightpt)
coords = mesh.coordinates()
print "mesh.coordinates()=",coords
sfns = Shapefns()
print "sfns.size()-3=", sfns.size()-3
xi = np.linspace(0,1,100)
import matplotlib.pyplot as plt
if True:
for n in range(3):
plt.plot(xi,sfns.eval(n,xi))
plt.show()
plt.plot(xi,sfns.ddx(n,xi))
plt.show()
16 / 45
Shape function plots
17 / 45
FiniteElement class
I Describes a single finite element
I A FunctionSpace will contain many of these
I Constructed from
1. Mesh
2. shape functions
3. this elements number (agrees with one of the Mesh intervals
4. 3 numbers to use for DOFs.
I Methods:
endpts(): element end points
dofpts(): array of DOF locations
dofnos(): DOF numbers
numDofs(): length of dofnos()
eval(n,x): evaluate n (x) (not )
ddxl(n,x): evaluate 0n (x) (not ) R
integral(f1,f2,derivative): e f1 (x)f2 (x)n (x) dx
I f1 and f2 are optional
I put 0 in integral if derivative=True
I returns a vector, one value for each n
18 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
self.__numDofs = sfns.size()
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
self.__numDofs = sfns.size()
assert(sfns.size() == len(dofnos))
self.__dofnos=dofnos
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
self.__numDofs = sfns.size()
assert(sfns.size() == len(dofnos))
self.__dofnos=dofnos
self.__dofpts=np.linspace(self.__endpts[0],self.__endpts[1],self.__numDofs)
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
self.__numDofs = sfns.size()
assert(sfns.size() == len(dofnos))
self.__dofnos=dofnos
self.__dofpts=np.linspace(self.__endpts[0],self.__endpts[1],self.__numDofs)
self.__sfns=sfns
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
self.__numDofs = sfns.size()
assert(sfns.size() == len(dofnos))
self.__dofnos=dofnos
self.__dofpts=np.linspace(self.__endpts[0],self.__endpts[1],self.__numDofs)
self.__sfns=sfns
# Gauss points and weights: 3-pts are high enough for this
self.__gausspts = np.array(\
(.112701665379258311482073460022,.5,.887298334620741688517926539978))
self.__gausswts = np.array((5.0/18.0,8.0/18.0,5.0/18.0))
19 / 45
FiniteElement constructor
def __init__(self,mesh,sfns,eltno,dofnos):
"""
mesh is the mesh it is built on
sfns is the Shapefuns member
eltno is this elements number
endnos is a pair of ints giving the numbers of the endpoints
in the mesh
dofnos is an array of ints giving the numbers of the dofs
"""
# this element no. is same as mesh element no.
assert(0 <= eltno < mesh.size())
self.__eltno = eltno
endnos = mesh.cells(eltno)
assert(len(endnos) == 2)
self.__endpts = np.array(mesh.coordinates(endnos))
self.__numDofs = sfns.size()
assert(sfns.size() == len(dofnos))
self.__dofnos=dofnos
self.__dofpts=np.linspace(self.__endpts[0],self.__endpts[1],self.__numDofs)
self.__sfns=sfns
# Gauss points and weights: 3-pts are high enough for this
self.__gausspts = np.array(\
(.112701665379258311482073460022,.5,.887298334620741688517926539978))
self.__gausswts = np.array((5.0/18.0,8.0/18.0,5.0/18.0))
# for efficiency, generate an array of shape functions evaluated
# at the Gauss points
self.__gaussvals = np.empty([self.__numDofs,self.__gausspts.size])
for n in range(self.__numDofs):
self.__gaussvals[n,:]=sfns.eval(n,self.__gausspts[:])
19 / 45
FiniteElement accessor methods
def endpts(self):
""" access endpoints """
return self.__endpts
def dofpts(self):
""" access dofpoints """
return self.__dofpts
def dofnos(self):
""" access dof point numbers """
return self.__dofnos
def numDofs(self):
""" access numDofs """
return self.__numDofs
20 / 45
FiniteElement evaluation methods
def eval(self,n,x):
"""
evaluate the n-th shape function on this element
at the spatial coordinate x
"""
# map x to xi
xx=np.array(x)
xi=(xx-self.__endpts[0])/(self.__endpts[1]-self.__endpts[0])
# evaluate
return self.__sfns.eval(n,xi)*(xi >= 0.)*(xi <= 1.)
def ddx(self,n,x):
"""
evaluate the n-th shape function on this element
at the spatial coordinate x
"""
# map x to xi
xi=(x-self.__endpts[0])/(self.__endpts[1]-self.__endpts[0])
# evaluate
return self.__sfns.ddx(n,xi)*(xi>=0.)*(xi <= 1.0)
21 / 45
Gau integration on the reference element
P
I Q= i f (i )wi
I Integration points (Gau points) tabulated
I Weights wi tabulated
I Integral on the true element requires affine transformation,
x = L + x0
I Assume functions f are given at DOF points.
22 / 45
FiniteElement integration
def integral(self, f1=None, f2=None, derivative=False):
"""
Integrate either phi[i](xi)*f1(xi)*f2(xi) or dphi[i]*f1*f2
over this element, depending on if derivative is False or True
Returns a vector of 3 results, one for
phi[0], one for phi[1], and one for phi[2].
f1 and f2 are assumed to have been mapped to this element
as arrays
if derivative is True, phi is replaced with dphi
"""
L = self.__endpts[1]-self.__endpts[0] # length of element
t = self.__gausswts.copy()
gp = self.__gausspts
23 / 45
FiniteElement integration
def integral(self, f1=None, f2=None, derivative=False):
"""
Integrate either phi[i](xi)*f1(xi)*f2(xi) or dphi[i]*f1*f2
over this element, depending on if derivative is False or True
Returns a vector of 3 results, one for
phi[0], one for phi[1], and one for phi[2].
f1 and f2 are assumed to have been mapped to this element
as arrays
if derivative is True, phi is replaced with dphi
"""
L = self.__endpts[1]-self.__endpts[0] # length of element
t = self.__gausswts.copy()
gp = self.__gausspts
23 / 45
FiniteElement integration
def integral(self, f1=None, f2=None, derivative=False):
"""
Integrate either phi[i](xi)*f1(xi)*f2(xi) or dphi[i]*f1*f2
over this element, depending on if derivative is False or True
Returns a vector of 3 results, one for
phi[0], one for phi[1], and one for phi[2].
f1 and f2 are assumed to have been mapped to this element
as arrays
if derivative is True, phi is replaced with dphi
"""
L = self.__endpts[1]-self.__endpts[0] # length of element
t = self.__gausswts.copy()
gp = self.__gausspts
if f1 != None:
assert(len(f1) == self.__numDofs)
fvals = np.zeros([self.__gausspts.size])
for n in range(self.__numDofs):
fvals += f1[n]*self.__gaussvals[n,:]
t*=fvals
23 / 45
FiniteElement integration
def integral(self, f1=None, f2=None, derivative=False):
"""
Integrate either phi[i](xi)*f1(xi)*f2(xi) or dphi[i]*f1*f2
over this element, depending on if derivative is False or True
Returns a vector of 3 results, one for
phi[0], one for phi[1], and one for phi[2].
f1 and f2 are assumed to have been mapped to this element
as arrays
if derivative is True, phi is replaced with dphi
"""
L = self.__endpts[1]-self.__endpts[0] # length of element
t = self.__gausswts.copy()
gp = self.__gausspts
if f1 != None:
assert(len(f1) == self.__numDofs)
fvals = np.zeros([self.__gausspts.size])
for n in range(self.__numDofs):
fvals += f1[n]*self.__gaussvals[n,:]
t*=fvals
if f2 != None:
assert(len(f2) == self.__numDofs)
fvals = np.zeros([self.__gausspts.size])
for n in range(self.__numDofs):
fvals += f2[n]*self.__gaussvals[n,:]
t *= fvals
23 / 45
FiniteElement integration contd
if derivative:
# really: t *= L*(1/L)
q = np.dot(np.array([self.__sfns.ddx(0,gp), \
self.__sfns.ddx(1,gp), \
self.__sfns.ddx(2,gp)]),t)
else:
t *= L # correct for affine map x->xi
q = np.dot(np.array([self.__sfns.eval(0,gp), \
self.__sfns.eval(1,gp), \
self.__sfns.eval(2,gp)]),t)
return q
24 / 45
Test it!
elt = FiniteElement(mesh,sfns,0,[0,1,2])
25 / 45
Test it!
elt = FiniteElement(mesh,sfns,0,[0,1,2])
25 / 45
Test it!
elt = FiniteElement(mesh,sfns,0,[0,1,2])
25 / 45
Test it!
elt = FiniteElement(mesh,sfns,0,[0,1,2])
25 / 45
Test results
26 / 45
FunctionSpace class
27 / 45
FunctionSpace constructor
def __init__(self,mesh,sfns):
"""
mesh is the mesh
sfns is the Shapefuns
"""
28 / 45
FunctionSpace constructor
def __init__(self,mesh,sfns):
"""
mesh is the mesh
sfns is the Shapefuns
"""
self.__size=mesh.size()
# number the elements in same way as mesh
self.__elts = list([])
self.__dofpts = list([])
self.__nDOFs=0
28 / 45
FunctionSpace constructor
def __init__(self,mesh,sfns):
"""
mesh is the mesh
sfns is the Shapefuns
"""
self.__size=mesh.size()
# number the elements in same way as mesh
self.__elts = list([])
self.__dofpts = list([])
self.__nDOFs=0
for n in range(self.__size):
# ASSUMING only boundary points are number 0 and (self.__size)
if n == 0:
self.__nDOFs += 3
dofs = [2*n, 2*n+1, 2*n+2]
newdofs = range(3)
else:
self.__nDOFs += 2
dofs=[2*n, 2*n+1, 2*n+2]
newdofs = range(1,3)
fe = FiniteElement(mesh,sfns,n,dofs)
self.__elts.append(fe)
for i in newdofs:
self.__dofpts.append(fe.dofpts()[i])
28 / 45
FunctionSpace constructor
def __init__(self,mesh,sfns):
"""
mesh is the mesh
sfns is the Shapefuns
"""
self.__size=mesh.size()
# number the elements in same way as mesh
self.__elts = list([])
self.__dofpts = list([])
self.__nDOFs=0
for n in range(self.__size):
# ASSUMING only boundary points are number 0 and (self.__size)
if n == 0:
self.__nDOFs += 3
dofs = [2*n, 2*n+1, 2*n+2]
newdofs = range(3)
else:
self.__nDOFs += 2
dofs=[2*n, 2*n+1, 2*n+2]
newdofs = range(1,3)
fe = FiniteElement(mesh,sfns,n,dofs)
self.__elts.append(fe)
for i in newdofs:
self.__dofpts.append(fe.dofpts()[i])
28 / 45
FunctionSpace constructor
def __init__(self,mesh,sfns):
"""
mesh is the mesh
sfns is the Shapefuns
"""
self.__size=mesh.size()
# number the elements in same way as mesh
self.__elts = list([])
self.__dofpts = list([])
self.__nDOFs=0
for n in range(self.__size):
# ASSUMING only boundary points are number 0 and (self.__size)
if n == 0:
self.__nDOFs += 3
dofs = [2*n, 2*n+1, 2*n+2]
newdofs = range(3)
else:
self.__nDOFs += 2
dofs=[2*n, 2*n+1, 2*n+2]
newdofs = range(1,3)
fe = FiniteElement(mesh,sfns,n,dofs)
self.__elts.append(fe)
for i in newdofs:
self.__dofpts.append(fe.dofpts()[i])
self.__dofpts = np.array(self.__dofpts)
28 / 45
FunctionSpace int_phi_phi
29 / 45
int_phi_phi code
N = elt.numDofs()
for j in range(N):
phi = elt.eval(j,elt.dofpts())
A[d0,d0[j]] += elt.integral(phi,cc,derivative=derivative[0])
return A
30 / 45
int_phi_phi code
for j in range(N):
phi = elt.eval(j,elt.dofpts())
A[d0,d0[j]] += elt.integral(phi,cc,derivative=derivative[0])
return A
30 / 45
int_phi_phi code
30 / 45
Exercise 12 (5 points)
31 / 45
Test it!
Test early! Test often! Dont discard your test code!
V=FunctionSpace(mesh,sfns)
print "V.Ndofs()-correct=",V.Ndofs()-(2*N+1)
print "V.size()-correct=",V.size()-N
x = V.dofpts()
f = x.copy()
print "error in integral x over [",x[0],",",x[-1],"]=",\
np.sum(V.int_phi(f))-x[-1]**2/2.
f = 0.0*x+1
print "error in integral 1 over [",x[0],",",x[-1],"]=",\
np.sum(V.int_phi(f))-x[-1]
f = x.copy()**2
print "error in integral x**2 over [",x[0],",",x[-1],"]=",\
np.sum(V.int_phi(f))-x[-1]**3/3.
f = x.copy()**3
print "error in integral x**3 over [",x[0],",",x[-1],"]=",\
np.sum(V.int_phi(f))-x[-1]**4/4.
f = x.copy()**4
print "error in integral x**4 over [",x[0],",",x[-1],"]=",\
np.sum(V.int_phi(f))-x[-1]**5/5.," should be nonzero."
print "norm(V.dofpts()-correct)=",\
la.norm(V.dofpts()-np.linspace(0,coords[-1],2*N+1))
P
Note that i i (x) = 1.
32 / 45
Test results
V.Ndofs()-correct= 0
V.size()-correct= 0
error in integral x over [ 0.0 , 5.0 ]= 0.0
error in integral 1 over [ 0.0 , 5.0 ]= 8.881784197e-16
error in integral x**2 over [ 0.0 , 5.0 ]= 0.0
error in integral x**3 over [ 0.0 , 5.0 ]= 2.84217094304e-14
error in integral x**4 over [ 0.0 , 5.0 ]= 0.0416666666667 should be nonzero.
norm(V.dofpts()-correct)= 0.0
33 / 45
Test FunctionSpace matrix integration
Z
Aij = i j
A=V.int_phi_phi()
if N == 5 and np.abs(coords[-1]-5.0) < 1.e-10:
print "error A00=",A[0,0]-2./15.
print "error A01=",A[0,1]-1./15.
print "error A02=",A[0,2]+1./30.
print "error A11=",A[1,1]-8./15.
print "error A12=",A[1,2]-1./15.
print
print "error A22=",A[2,2]-4./15.
print "error A23=",A[2,3]-1./15.
print "error A24=",A[2,4]+1./30.
print "error A33=",A[3,3]-8./15.
print "error A34=",A[3,4]-1./15.
print
34 / 45
More test FunctionSpace matrix integration
Z
Bij = ci j
c = (1.0+x)
B = V.int_phi_phi(c)
if N == 5 and np.abs(coords[-1]-5.0) < 1.e-10:
print "error B00=",B[0,0]-3./20.
print "error B01=",B[0,1]-1./15.
print "error B02=",B[0,2]+1./20.
print "error B11=",B[1,1]-12./15.
print "error B12=",B[1,2]-2./15.
print
print "error B22=",B[2,2]-8./15.
print "error B23=",B[2,3]-2./15.
print "error B24=",B[2,4]+1./12.
print "error B33=",B[3,3]-4./3.
print "error B34=",B[3,4]-3./15.
35 / 45
Test FunctionSpace Laplace matrix integration
Z
Cij = 0i 0j
C = V.int_phi_phi(derivative=[True,True])
if N == 5 and np.abs(coords[-1]-5.0) < 1.e-10:
print "\n Laplace Matrix"
print "error C00*3=",C[0,0]-7./3.
print "error C01*3=",C[0,1]+8./3.
print "error C02*3=",C[0,2]-1./3.
print "error C11*3=",C[1,1]-16./3.
print "error C12*3=",C[1,2]+8./3.
print
print "error C22*3=",C[2,2]-14./3.
print "error C23*3=",C[2,3]+8./3.
print "error C24*3=",C[2,4]-1./3.
print "error C33*3=",C[3,3]-16./3.
print "error C34*3=",C[3,4]+8./3.
print
36 / 45
Test FunctionSpace Laplace matrix multiply
Z
Cij = 0i 0j
soln2 = np.ones([Ndofs])
b2 = np.dot(C,soln2)
print "const soln Laplace, norm check=",la.norm(b2)
soln = x
b0 = np.dot(C,soln)
rhs0 = V.int_phi(np.zeros([Ndofs]))
# natural b.c. not satisfied, dont check them
rhs0[0] = -b0[0]
rhs0[-1] = -b0[-1]
print "soln=x Laplace, norm check=",la.norm(rhs0+b0)
soln = x**2
b1 = np.dot(C,soln)
rhs1 = V.int_phi(2.0*np.ones([Ndofs]))
# natural b.c. not satisfied on right, dont check it
rhs1[-1] = -b1[-1]
print "soln=x**2 Laplace, norm check=",la.norm(rhs1+b1)
37 / 45
Test FunctionSpace derivative matrix multiply
Z
Dij = i 0j
D = V.int_phi_phi(derivative=[False,True])
soln = np.ones([V.Ndofs()])
b2 = np.dot(D,soln)
print "norm check (rhs d/dx+Neumann, const soln)=",la.norm(b2)
D[0,0] = 1.0
D[0,1:] = 0.0
D[-1,-1] = 1.0
D[-1,0:-1] = 0.0
soln = x
b3 = np.dot(D,soln)
rhs3 = V.int_phi(np.ones([Ndofs]))
rhs3[0] = soln[0]
rhs3[-1] = soln[-1]
print "norm check (d/dx+Dirichlet soln=x)=",la.norm(rhs3-b3)
38 / 45
Topics
Introduction
Code
39 / 45
Verification
u 00 + 2u 0 + u = f x [0, 1]
1. u = 1, f = 1, Dirichlet b.c.
2. u = x, f = 1 + x, Dirichlet b.c.
3. u = x 2 , f = 2 + 2x + x 2 , Dirichlet b.c.
40 / 45
Verification function
def verification(title,N,rhsfn,exactfn):
"""
generic verification runs for PDE u+2*u+u=rhs on [0,1]
Dirichlet b.c.
title= descriptive title
N=number of elements
rhsfn=function for rhs as function of x
exactfn=function for exact solution as function of x
MMS 4/16/14
"""
# N elements in [0,1]
mesh = Mesh(N,0.0,1.0)
rhs = rhsfn(x)
b = V.int_phi(rhs)
41 / 45
Verification function contd
# solve
u = la.solve(A,b)
# check
print title," relative error=",la.norm(u-exact)/la.norm(exact)
42 / 45
Run verification
43 / 45
Solve the given problem
44 / 45
Convergence estimate
I Appears to be O(h4 )
I Only expect O(h3 )
I Superconvergent at the nodes because mesh is uniform?
45 / 45