DriftDiffusionPoissonSystems.jl — A 2D Finite Element Method Solver for Drift-Diffusion-Poisson Systems and Semilinear Poisson Equations Written in Julia
This package provides a numerical solution to drift-diffusion poisson equations in Slotboom variables. The system
is solved for (V,u,v) in a domain
It is possible to prescribe
- arbitrary Dirichlet boundary conditions, homogenous Neumann boundary conditions
- arbitrary constants $ \epsilon, U_T, n_i, \tau_p, \tau_n$
- arbitrary functions
$\mu_p, \mu_n, C$
The implemented solution method is fixed-point iteration.
This package includes a function for solving 2D semilinear poisson equations.
where \Omega is an arbitrary domain and \Omega_N denote Dirichlet and
Neumann boundary, respectively.In this case, the right hand side function
It is possible to prescribe
- arbitrary Dirchlet and/or Neumann boundary conditions,
- an arbitrary right-hand side function
f
with partial derivative w.r.t solutiong
, and - a constant coefficient in the elliptic operator.
The user can provide a mesh generated by GMSH (www.gmsh.info) or provide the mesh
information in the composite type mesh
.
- Input: Path to mesh file.
- Output: Composite type
mesh
.
read_mesh
reads the GMSH file and creates a composite type mesh
, which
contains all necessary information about the mesh.
mesh
contains the following fields:
nodes
: 2 × nr_nodes array containing the node coordinatesedges
: 4 × nr_edges array. Lines 1 and 2: nodes forming the edge. Line 3: physical property. Line 4: geometrical property (defining the boundary condition).elements
: 5 × nr_elements array. Lines 1, 2, and 3: node indices forming the triangle. Line 4: physical property. Line 5: geometrical property.
The physical properties are currently not used as well as the geometrical property of the elements. These quantities may be used to define subdomains later.
- Input: Array
Endpoints
, ArrayDirPoints
defining the length/position of the 3- and 7-section in the image below mesh-widthh
, meshnamemeshname
- Output: Rectangular .geo file for form indicated below
meshname.geo
construct_mesh
creates a rectangular mesh with 8 boundary subdivisions of the form
The 4x2-array Endpoints
defines the rectangle endpoints, where the first column defines the x-coordinates,
the second column the y-coordinates. One row defines one endpoint, the rows must be entered
in the sequence indicated in the image.
The 2x2-array DirPoints
defines the boundary sections 3 and 7 in the picture.
The first row defines the y-coordinates of section 7, where Dirpoints[1,1] is the lower (smaller)
y-coordinate, and Dirpoints[1,2] is the upper (greater) y-coordinate, Dirpoints[2,:] should be entered
analogously.
- Input: mesh
mesh
, boundary dataVbddata
, boundary dataubddata
, boundary datavbddata
, constantepsilon
, constantU_T
constantn_i
, constanttau_p
, constanttau_n
, mobility functionmu_p
, mobility functionmu_n
, charge density functionC
, constanttol
- Output: solution arrays
V
,u
,v
solve_ddpe
takes the input from above and provides the solutions as arrays on the supplied mesh.
The Input needs to be as follows:
mesh::mesh
- all input variables marked as constants must be Float64
- all input variables marked as functions must be functions of two arguments, e.g.
(x,y) -> x+y
- the boundary data arrays must be 3 × n Arrays, where n is the number of different
edge physical properties defined in the GMSH file. The first row needs
to contain the geometrical properties defined in the GMSH file, the second row
contains either
'D'
(for a Dirichlet boundary) or'N'
(for a Neumann boundary) at the respective type of edge. The third row contains a function of two coordinates giving the value of the solution on the boundary, e.g.(x,y) ->0
for homogeneous conditions.
- Input: mesh
mesh
, ellipticity constantA
, right-hand side functionf
, partial derivative off
with respect to ug
, boundary databddata
. - Output: solution values
u
on the mesh nodes.
solve_semlin_poisson takes the named input and provides the array of solution values at the nodes of the supplied mesh. The input needs to be as follows:
mesh::mesh
.A::Float64
: only constants are allowed.f::Function
: a function of three arguments, e.g.(x,y,z) -> x+y+z
. The first two arguments are the spatial coordinates, the third argument is the dependence off
onu
.g::Function
: the partial derivative of the right hand side with respect to the solution as a function of three arguments, where the third argument is the solution u. E.g. iff
is of the formf(x,y,u) = 4*x*y*u^2
,g
must be entered as(x,y,u) -> 8*x*y*u
bddata::Array
: 3 × n Array, where n is the number of different edge physical properties defined in the GMSH file. The first row needs to contain the geometrical properties defined in the GMSH file, the second row contains either'D'
(for a Dirichlet boundary) or'N'
(for a Neumann boundary) at the respective type of edge. The third row contains a function of two coordinates giving the value of the solution on the boundary, e.g.(x,y) -> 0
for homogeneous conditions.
The codes and meshes for the following tests are stored in the test folder.
This code creates a rectangular mesh testmesh.msh
with vertices (-1,-1), (1,-1), (1,1), (-1,1).
The 7
-section in this example stretches from (-1, -0.1) to (-1, 0.1), the 3
-section from (1, -0.1) to (1, 0.1).
The mesh-width in this example is 0.05.
function test_meshcreate()
Endpoints = [-1.0 -1.0 ; 1.0 -1.0 ; 1.0 1.0 ; -1.0 1.0]
Dirpoints = [-0.1 0.1 ; -0.1 0.1]
h = 0.05
meshname = "testmesh"
construct_mesh(Endpoints, Dirpoints, h, meshname)
run(`gmsh -2 $meshname.geo`)
end
The last line compiles the .geo file created by construct_mesh(...) using gmsh.
Calculates a solution of the drift diffusion poisson equations on the mesh constructed by test_meshcreate(...) with the following parameters:
U_T = 1.0
tau_p = 1.0
tau_n = 1.0
mu_p = (x,y) -> 1.0
mu_n = (x,y) -> 1.0
n_i = 1.0
epsilon = 1.6021766*10.0^(-19)
C = (x,y) -> 0
The variable epilson
was chosen such that it cancels out with the elementary charge q
in the potential equation.
With these variables, the functions V = c*(x+y), u = exp(-c*(x+y)), v = exp(c*(x+y))
are exact solutions
to the drift diffusion poisson equations for any real constant c
. In this example, the boundary data was chosen to obtain these solutions:
Vbddata = [1 2 3 4 5 6 7 8; 'D' 'D' 'D' 'D' 'D' 'D' 'D' 'D'; (x,y)-> c*(x+y) (x,y)->c*(x+y) (x,y)->c*(x+y) (x,y)->c*(x+y) (x,y)->c*(x+y) (x,y)->c*(x+y) (x,y)->c*(x+y) (x,y)->c*(x+y);]
ubddata = [1 2 3 4 5 6 7 8; 'D' 'D' 'D' 'D' 'D' 'D' 'D' 'D'; (x,y) ->exp(-c*(x+y)) (x,y) -> exp(-c*(x+y)) (x,y) -> exp(-c*(x+y)) (x,y) -> exp(-c*(x+y)) (x,y) -> exp(-c*(x+y)) (x,y) -> exp(-c*(x+y)) (x,y) -> exp(-c*(x+y)) (x,y) -> exp(-c*(x+y));]
vbddata = [1 2 3 4 5 6 7 8; 'D' 'D' 'D' 'D' 'D' 'D' 'D' 'D'; (x,y) ->exp(c*(x+y)) (x,y) -> exp(c*(x+y)) (x,y) -> exp(c*(x+y)) (x,y) -> exp(c*(x+y)) (x,y) -> exp(c*(x+y)) (x,y) -> exp(c*(x+y)) (x,y) -> exp(c*(x+y)) (x,y) -> exp(c*(x+y));]
The remaining section of the code
xcoord=zeros(size(mesh.nodes,2),1)
ycoord=zeros(size(mesh.nodes,2),1)
for i=1:size(mesh.nodes,2)
xcoord[i]=mesh.nodes[1,i]
ycoord[i]=mesh.nodes[2,i]
end
f = (x,y) -> exp(c*(x+y))
surf(vec(xcoord),vec(ycoord),vec(v),cmap="jet")
exacterror = maximum(abs(vec(v) - f(xcoord,ycoord)))
println("maximum error: $exacterror")
plots the solution v
and prints the exact error value for v
.
The equation in this example is the nonlinear Poisson-Boltzmann equation, i.e.
$ - \Delta u + \sinh(u) = h $
$ u = u_D on \partial\Omega_D$
$ u = b on \partial\Omega_N$
We choose
The function f
for this example should then be set to
First, the mesh file, right hand side function f
and its partial derivative w.r.t. u g
as well as the boundary data need to be prescribed:
mesh = read_mesh("mesh_s_p05.msh")
f = (x,y,u) -> 4*exp(-x.^2 -y.^2).*(1 - x.^2 - y.^2) + sinh(exp(-x.^2-y.^2)) - sinh(u)
g = (x,y,u) -> -cosh(u)
A = [(x) -> 1;(x)->0;(x)->0;(x)->1]
bddata=[1 2 3 4;'D' 'N' 'D' 'N';(x,y)->exp(-x.^2-y.^2) (x,y)->-2x.*exp(-x.^2-y.^2) (x,y)-> exp(-x.^2-y.^2) (x,y)->2x.*exp(-x.^2-y.^2)]
The solution is then obtained using
u=solve_semlin_poisson(mesh,A,bddata,f,g)
The remaining code section compares the obtained solution to the exact solution, calculates and prints the maximal error value and plots the solution:
xcoord=zeros(size(mesh.nodes,2),1)
ycoord=zeros(size(mesh.nodes,2),1)
for i=1:size(mesh.nodes,2)
xcoord[i]=mesh.nodes[1,i]
ycoord[i]=mesh.nodes[2,i]
end
exakt = vec(exp(-xcoord.^2 -ycoord.^2))
versuch = maximum(abs(vec(u)-exakt))
println("error maximum:$versuch")
surf(vec(xcoord),vec(ycoord),vec(u),cmap="jet")
- Caroline Geiersbach
- Clemens Heitzinger ([email protected], http://Clemens.Heitzinger.name)
- Gerhard Tulzer ([email protected])
- Gudmund Pammer ([email protected])
- Stefan Rigger ([email protected])