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
fwith 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, ArrayDirPointsdefining 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_Tconstantn_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) ->0for homogeneous conditions.
- Input: mesh
mesh, ellipticity constantA, right-hand side functionf, partial derivative offwith respect to ug, boundary databddata. - Output: solution values
uon 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 offonu.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. iffis of the formf(x,y,u) = 4*x*y*u^2,gmust be entered as(x,y,u) -> 8*x*y*ubddata::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) -> 0for 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 (Clemens.Heitzinger@TUWien.ac.at, http://Clemens.Heitzinger.name)
- Gerhard Tulzer (Gerhard.Tulzer@TUWien.ac.at)
- Gudmund Pammer (gudmund.pammer@tuwien.ac.at)
- Stefan Rigger (stefan.rigger@tuwien.ac.at)




