VoronoiFVM.jl: Tipps and Examples
Grid generation
VoronoiFVM works on simplicial grids provided by the package ExtendableGrids.jl
There are several ways to create a grid.
1D grids
1D grids are created from a vector of monotonicaly increasing x-axis positions.
0.0
0.05
0.1
0.15
0.2
0.25
0.3
0.35
0.4
0.45
0.5
0.55
0.6
0.65
0.7
0.75
0.8
0.85
0.9
0.95
1.0
xxxxxxxxxx
# Create a 1D vector:
X=collect(range(0,1,length=21))
ExtendableGrids.ExtendableGrid{Float64, Int32};
dim: 1 nodes: 21 cells: 20 bfaces: 2
xxxxxxxxxx
# Create grid from vector:
grid1d_a=ExtendableGrids.simplexgrid(X)
xxxxxxxxxx
# Visualize grid
GridVisualize.gridplot(grid1d_a,resolution=(600,200),Plotter=PyPlot)
As we see, the grid is chacracterized by interior points, and boundary points. Each grid cell is endowed with a region number (for allowing different physics, parameters etc. for different regions). Each boundary node has a boundary region number, which is meant to be used to distinguish different boundary conditions.
More sophisticated grids can be created, as we see in the following example:
ExtendableGrids.ExtendableGrid{Float64, Int32};
dim: 1 nodes: 53 cells: 52 bfaces: 3
xxxxxxxxxx
grid1d_b=let
hmax=0.1
hmin=0.01
# Create vectors with geometric distributions of interval sizes
X1=ExtendableGrids.geomspace(0.0,1.0,hmax,hmin)
X2=geomspace(1.0,2.0,hmin,hmax)
# Glue them together at common point x=1 (this is different from vcat!)
X3=glue(X1,X2)
grid1d_b=simplexgrid(X3)
# Mark an additional interior boundary point at x=1
ExtendableGrids.bfacemask!(grid1d_b,[1.0],[1.0],3)
# Change cell region number at the right part
ExtendableGrids.cellmask!(grid1d_b,[1.0],[2.0],2)
grid1d_b
end
xxxxxxxxxx
gridplot(grid1d_b,resolution=(600,200),Plotter=PyPlot,aspect=0.5)
2D Tensor product grids
These are created from two vectors of x and y coordinates, respectively. This results in the creation of a grid of quadrilaterals. Then, each of them is subdivided into two triangles, resulting in a boundary conforming Delaunay grid.
ExtendableGrids.ExtendableGrid{Float64, Int32};
dim: 2 nodes: 121 cells: 200 bfaces: 40
xxxxxxxxxx
grid2d_a=let
X=collect(range(0,1,length=11))
Y=collect(range(0,1,length=11))
simplexgrid(X,Y)
end
xxxxxxxxxx
gridplot(grid2d_a,resolution=(600,200),Plotter=PyPlot,legend_location=(1.5,0))
Once again, we see a default distrbution of cell regions and boundary regions. This can be modified in a similar manner as in the 1D case.
ExtendableGrids.ExtendableGrid{Float64, Int32};
dim: 2 nodes: 121 cells: 200 bfaces: 56, edges: 320
xxxxxxxxxx
grid2d_b=let
X=collect(range(0,1,length=11))
Y=collect(range(0,1,length=11))
grid=simplexgrid(X,Y)
cellmask!(grid,[0.3,0.3],[0.7,0.7],2)
bfacemask!(grid,[0.3,0.3],[0.3,0.7],5)
bfacemask!(grid,[0.3,0.7],[0.7,0.7],6)
bfacemask!(grid,[0.7,0.3],[0.7,0.7],7)
bfacemask!(grid,[0.3,0.3],[0.7,0.3],8)
grid
end
xxxxxxxxxx
gridplot(grid2d_b,resolution=(600,200),Plotter=PyPlot,legend_location=(1.5,0))
2D Unstructured grids
These can be created using the mesh generator Triangle (by J. Shewchuk) via the packages Triangulate.jl and SimplexGridFactory.jl.
builder2d (generic function with 1 method)
xxxxxxxxxx
function builder2d()
b=SimplexGridFactory.SimplexGridBuilder(Generator=Triangulate)
p1=point!(b,0,0)
p2=point!(b,0,1)
p3=point!(b,0.5,0)
facetregion!(b,1)
facet!(b,p1,p2)
facetregion!(b,2)
facet!(b,p2,p3)
facetregion!(b,3)
facet!(b,p1,p3)
point!(b,0.1,0.1)
b
end
Triangulate
3
1
1.0
1.0e-12
1
2
3
1
2
2
3
1
3
2
1.0e-12
1.79769e308
1.79769e308
-1.79769e308
-1.79769e308
0.01
2×4 ElasticArrays.ElasticMatrix{Float64, 1, Vector{Float64}}: 0.0 0.0 0.5 0.1 0.0 1.0 0.0 0.1
0×0 Matrix{Vector{Int32}}
10
1
2
3
4
5
0.05
0
0
2×0 ElasticArrays.ElasticMatrix{Float64, 1, Vector{Float64}}
:optlevel
1
:attributes
true
:quiet
true
:verbose
false
:addflags
""
:maxvolume
Inf
:confdelaunay
true
:unsuitable
nothing
:debugfacets
true
:volumecontrol
true
:quality
true
:flags
nothing
:refine
false
:PLC
true
:nosteiner
false
:minangle
20
:check
false
true
For debugging purposes, the current state of the builder and its possible output can be visualized:
xxxxxxxxxx
builderplot(builder,Plotter=PyPlot)
Finally, we can create a grid from the builder:
ExtendableGrids.ExtendableGrid{Float64, Int32};
dim: 2 nodes: 230 cells: 381 bfaces: 77
xxxxxxxxxx
grid2d_c=simplexgrid(builder,maxvolume=0.001)
xxxxxxxxxx
gridplot(grid2d_c,resolution=(600,200),Plotter=PyPlot,legend_location=(2,0))
Stationary scalar problems
Diffusion with Dirichlet boundary conditions
This is mathematically similar to heat conduction and other problems.
Besides of the domain and its boundary it is characterize by a flux term and a source term.
solve_diffproblem_dirichlet (generic function with 1 method)
xxxxxxxxxx
function solve_diffproblem_dirichlet(grid;D=1.0)
species1=1
# Use finite difference flux between disretization points.
# Division by distance and multiplication by interface size
# is done by the VoronoiFVM Module.
function flux(f,u0,edge)
u=unknowns(edge,u0)
f[species1]=D*(u[species1,1]-u[species1,2])
end
# Specify a constant source term
function source(f,node)
f[species1]=10
end
# Combine flux and source to "physics"
physics=VoronoiFVM.Physics(flux=flux,source=source)
# Create system from physics and grid
system=VoronoiFVM.System(grid,physics)
# Enable species in cellregion 1
enable_species!(system,species1,[1])
# Enable boundary conditions. For those boundary regions
# which are not specified here, by default, homogeneous
# Neumann boundary conditions are assumed.
west=dim_space(grid)==1 ? 1 : 4
east=2
boundary_dirichlet!(system, species1, west, 0)
boundary_dirichlet!(system, species1, east, 1)
# Solve with given initial value
solve(unknowns(system,inival=0),system)
end
1×21 Matrix{Float64}:
6.0e-30 0.2875 0.55 0.7875 1.0 … 1.6875 1.6 1.4875 1.35 1.1875 1.0
xxxxxxxxxx
solution1d_a=solve_diffproblem_dirichlet(grid1d_a)
xxxxxxxxxx
scalarplot(grid1d_a,solution1d_a[1,:],Plotter=PyPlot)
1×121 Matrix{Float64}:
3.0e-31 0.55 1.0 1.35 1.6 1.75 1.8 … 1.6 1.75 1.8 1.75 1.6 1.35 1.0
xxxxxxxxxx
solution2d_a=solve_diffproblem_dirichlet(grid2d_a)
xxxxxxxxxx
scalarplot(grid2d_a,solution2d_a[1,:],Plotter=PyPlot)
Diffusion with Robin boundary conditions
solve_diffproblem_robin (generic function with 1 method)
xxxxxxxxxx
function solve_diffproblem_robin(grid;D=1.0,a=0.5)
species1=1
function flux(f,u0,edge)
u=unknowns(edge,u0)
f[species1]=D*(u[species1,1]-u[species1,2])
end
function source(f,node)
f[species1]=10
end
physics=VoronoiFVM.Physics(flux=flux,source=source)
system=VoronoiFVM.System(grid,physics)
enable_species!(system,species1,[1])
west=dim_space(grid)==1 ? 1 : 4
east=2
boundary_robin!(system, species1, west, a, 0)
boundary_robin!(system, species1, east, a, a*1)
solve(unknowns(system,inival=0),system)
end
1×21 Matrix{Float64}:
5.33333 5.5875 5.81667 6.02083 6.2 … 6.4 6.25417 6.08333 5.8875 5.66667
xxxxxxxxxx
solution1d_robin=solve_diffproblem_robin(grid1d_a,a=1)
xxxxxxxxxx
scalarplot(grid1d_a,solution1d_robin[1,:],Plotter=PyPlot)
1×121 Matrix{Float64}:
5.33333 5.81667 6.2 6.48333 6.66667 … 6.73333 6.61667 6.4 6.08333 5.66667
xxxxxxxxxx
solution2d_robin=solve_diffproblem_robin(grid2d_a,a=1)
xxxxxxxxxx
scalarplot(grid2d_a,solution2d_robin[1,:],Plotter=PyPlot)
Stationary Reaction-Diffusion problem
Here, we regard two species
Boundary conditons not specified are assumed to be homogeneous Neumann.
solve_readiff (generic function with 1 method)
xxxxxxxxxx
function solve_readiff(grid;D_1=1.0,D_2=1.0,k=1)
species1=1
species2=2
function flux(f,u0,edge)
u=unknowns(edge,u0)
f[species1]=D_1*(u[species1,1]-u[species1,2])
f[species2]=D_2*(u[species2,1]-u[species2,2])
end
function reaction(f,u0,node)
u=unknowns(node,u0)
r=k*u[species1]
f[species1]=r
f[species2]=-r
end
physics=VoronoiFVM.Physics(num_species=2,flux=flux,reaction=reaction)
system=VoronoiFVM.System(grid,physics)
enable_species!(system,species1,[1])
enable_species!(system,species2,[1])
west=dim_space(grid)==1 ? 1 : 4
east=2
boundary_dirichlet!(system, species1, west,1)
boundary_dirichlet!(system, species2, east,0)
solve(unknowns(system,inival=0),system)
end
2×21 Matrix{Float64}:
1.0 0.854464 0.730289 0.624372 … 0.0890498 0.0858439 0.0847841
2.24551 2.23301 2.19915 2.14703 0.311807 0.156976 3.16072e-30
xxxxxxxxxx
solution_readiff_1d=solve_readiff(grid1d_a,k=10, D_2=1)
xxxxxxxxxx
let
v=GridVisualizer(Plotter=PyPlot)
scalarplot!(v[1,1],grid1d_a, solution_readiff_1d[1,:],label="spec1", color=:red)
scalarplot!(v[1,1],grid1d_a, solution_readiff_1d[2,:],label="spec2", color=:green,show=true,clear=false)
end
2×121 Matrix{Float64}:
1.0 0.884085 0.785851 0.703335 0.634885 … 0.478053 0.464174 0.459578
0.71873 0.70873 0.681048 0.63765 0.580184 0.233355 0.121319 6.29576e-32
xxxxxxxxxx
solution_readiff_2d=solve_readiff(grid2d_a,k=2)
xxxxxxxxxx
let
v=GridVisualizer(Plotter=PyPlot,layout=(1,2))
scalarplot!(v[1,1],grid2d_a, solution_readiff_2d[1,:],label="spec1",flimits=(0,1))
scalarplot!(v[1,2],grid2d_a, solution_readiff_2d[2,:],label="spec2",flimits=(0,1), show=true)
end
Transient Reaction-Diffusion problem
Here, we regard two species
Boundary conditons not specified are assumed to be homogeneous Neumann.
evolution (generic function with 1 method)
xxxxxxxxxx
# Function describing evolution of system with initial value inival
# using the Implicit Euler method
function evolution(inival, # initial value
sys, # finite volume system
grid, # simplex grid
tstep, # initial time step
tend, # end time
dtgrowth # time step growth factor
)
time=0.0
# record time and solution
times=[time]
solutions=[copy(inival)]
solution=copy(inival)
while time<tend
time=time+tstep
solve!(solution,inival,sys,tstep=tstep) # solve implicit Euler time step
inival.=solution # copy solution to inivalue
push!(times,time)
push!(solutions,copy(solution))
tstep*=dtgrowth # increase timestep by factor when approaching stationary state
end
# return result and grid
(times=times,solutions=solutions,grid=grid)
end
transient_reaction_diffusion (generic function with 1 method)
xxxxxxxxxx
function transient_reaction_diffusion(grid;D_1=1.0,D_2=1.0,k=1,
tstep=1.0e-3,tend=1,dtgrowth=1.1)
species1=1
species2=2
function flux(f,u0,edge)
u=unknowns(edge,u0)
f[species1]=D_1*(u[species1,1]-u[species1,2])
f[species2]=D_2*(u[species2,1]-u[species2,2])
end
function reaction(f,u0,node)
u=unknowns(node,u0)
r=k*u[species1]
f[species1]=r
f[species2]=-r
end
function storage(f,u,node)
f.=u
end
physics=VoronoiFVM.Physics(num_species=2,flux=flux,reaction=reaction,storage=storage)
system=VoronoiFVM.System(grid,physics)
enable_species!(system,species1,[1])
enable_species!(system,species2,[1])
west=dim_space(grid)==1 ? 1 : 4
east=2
boundary_dirichlet!(system, species1, west,1)
boundary_dirichlet!(system, species2, east,0)
## Create a solution array
inival=unknowns(system,inival=0)
evolution(inival,system,grid,tstep,tend,dtgrowth)
end
0.0
0.001
0.0021
0.00331
0.004641
0.0061051
0.00771561
0.00948717
0.0114359
0.0135795
0.0159374
0.0185312
0.0213843
0.0245227
0.027975
0.0317725
0.0359497
0.0405447
0.0455992
0.0511591
43.8993
48.2902
53.1202
58.4332
64.2776
70.7063
77.778
85.5568
94.1134
103.526
2×21 Matrix{Float64}: 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2×21 Matrix{Float64}: 1.0 0.23429 0.0548919 … 4.53819e-12 1.11825e-12 4.96724e-13 0.00069226 0.000307586 0.00010615 5.37779e-14 1.25719e-14 2.63856e-43
2×21 Matrix{Float64}: 1.0 0.388729 0.129427 … 9.70382e-11 2.62235e-11 1.25317e-11 0.00131875 0.000780668 0.000345951 1.26334e-12 3.17705e-13 6.6674e-42
2×21 Matrix{Float64}: 1.0 0.493864 0.206185 … 1.06107e-9 3.13559e-10 1.60499e-10 0.00195214 0.00135646 0.000715781 1.51357e-11 4.07663e-12 8.55451e-41
2×21 Matrix{Float64}: 1.0 0.568244 0.277615 … 7.89166e-9 2.543e-9 1.38824e-9 0.00262716 0.0020111 0.00120404 1.23024e-10 3.53349e-11 7.41403e-40
2×21 Matrix{Float64}: 1.0 0.623046 0.341224 … 4.48229e-8 1.57063e-8 9.10588e-9 0.00336164 0.00273872 0.00180061 7.6171e-10 2.32314e-10 4.87393e-39
2×21 Matrix{Float64}: 1.0 0.665021 0.396862 … 2.0705e-7 7.8674e-8 4.82398e-8 0.00416662 0.0035414 0.00249964 3.82598e-9 1.23393e-9 2.58846e-38
2×21 Matrix{Float64}: 1.0 0.6983 0.445307 … 8.09271e-7 3.32497e-7 2.14744e-7 0.00505087 0.00442479 0.0032996 1.62192e-8 5.50887e-9 1.15546e-37
2×21 Matrix{Float64}: 1.0 0.725463 0.487589 0.305176 … 2.75049e-6 1.21828e-6 8.25489e-7 0.00602284 0.0053963 0.00420244 0.00294787 5.96309e-8 2.12446e-8 4.4553e-37
2×21 Matrix{Float64}: 1.0 0.748172 0.5247 … 8.29339e-6 3.94783e-6 2.79554e-6 0.00709136 0.00646445 0.00521286 1.93965e-7 7.22023e-8 1.51393e-36
2×21 Matrix{Float64}: 1.0 0.767529 0.557499 … 2.25305e-5 1.14884e-5 8.46976e-6 0.00826603 0.00763874 0.00633768 5.66815e-7 2.19619e-7 4.60412e-36
2×21 Matrix{Float64}: 1.0 0.784289 0.586693 … 5.58339e-5 3.03906e-5 2.32422e-5 0.00955732 0.00892964 0.00758547 1.50636e-6 6.05297e-7 1.2687e-35
2×21 Matrix{Float64}: 1.0 0.798987 0.612852 … 0.000127507 7.38152e-5 5.83576e-5 0.0109767 0.0103486 0.00896638 3.67743e-6 1.52712e-6 3.20013e-35
2×21 Matrix{Float64}: 1.0 0.812014 0.636436 0.481235 … 0.000270654 0.000166012 0.000135227 0.0125369 0.0119083 0.010492 0.00869996 8.31701e-6 3.55739e-6 7.45284e-35
2×21 Matrix{Float64}: 1.0 0.823661 0.657814 0.509094 … 0.000537948 0.000348231 0.000291341 0.0142516 0.0136224 0.0121755 0.010303 1.75533e-5 7.70879e-6 1.61459e-34
2×21 Matrix{Float64}: 1.0 0.834148 0.677286 0.534937 … 0.00100763 0.000685612 0.000587419 0.016136 0.0155062 0.0140313 0.0120849 3.47922e-5 1.56418e-5 3.27522e-34
2×21 Matrix{Float64}: 1.0 0.84365 0.695096 0.558939 … 0.00178873 0.00127411 0.00111488 0.0182066 0.0175763 0.0160757 0.0140608 6.5131e-5 2.98935e-5 6.25741e-34
2×21 Matrix{Float64}: 1.0 0.852303 0.711445 0.581259 … 0.00302446 0.00224611 0.00200222 0.0204818 0.0198507 0.0183264 0.0162479 0.000115737 5.40928e-5 1.13191e-33
2×21 Matrix{Float64}: 1.0 0.860217 0.726498 0.602042 … 0.00489262 0.00377326 0.00341869 0.0229814 0.0223495 0.020803 0.0186653 0.000196115 9.3122e-5 1.94791e-33
2×21 Matrix{Float64}: 1.0 0.867481 0.740397 0.621414 … 0.00760248 0.00606525 0.00557377 0.0257271 0.0250944 0.0235272 0.021334 0.000318206 0.000153182 3.20298e-33
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
2×21 Matrix{Float64}: 1.0 0.963161 0.928729 0.896619 … 0.651348 0.648916 0.648106 0.409894 0.408644 0.404986 0.399006 0.0729363 0.0372793 7.61788e-31
ExtendableGrids.ExtendableGrid{Float64, Int32}; dim: 1 nodes: 21 cells: 20 bfaces: 2
xxxxxxxxxx
tsol_readiff=transient_reaction_diffusion(grid1d_a,k=1,tend=100)
time=
xxxxxxxxxx
let
vis=GridVisualizer(layout=(1,2),resolution=(600,300),Plotter=PyPlot)
scalarplot!(vis[1,1],tsol_readiff.grid,
tsol_readiff.solutions[t_readiff][1,:],
title="u1: t=$(tsol_readiff.times[t_readiff])",
flimits=(0,1),colormap=:cool,levels=50,clear=true)
scalarplot!(vis[1,2],tsol_readiff.grid,
tsol_readiff.solutions[t_readiff][2,:],
title="u2: t=$(tsol_readiff.times[t_readiff])",
flimits=(0,1),colormap=:cool,levels=50,show=true)
end
xxxxxxxxxx
TableOfContents()
xxxxxxxxxx
begin
ENV["LANG"]="C"
using Pkg
Pkg.activate(mktempdir())
Pkg.add(["PyPlot","PlutoUI","ExtendableGrids","SimplexGridFactory","VoronoiFVM","GridVisualize","Triangulate"])
using PlutoUI,PyPlot,ExtendableGrids,SimplexGridFactory,VoronoiFVM,GridVisualize,Triangulate
PyPlot.svg(true)
end;
Status `/tmp/jl_SKqLWP/Project.toml` [cfc395e8] ExtendableGrids v0.7.4 [5eed8a63] GridVisualize v0.1.3 [7f904dfe] PlutoUI v0.7.2 [d330b81b] PyPlot v2.9.0 [57bfcd06] SimplexGridFactory v0.5.1 [f7e6ffb2] Triangulate v1.0.1 [82b139dc] VoronoiFVM v0.10.5