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 gridGridVisualize.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
xxxxxxxxxxgrid1d_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_bendxxxxxxxxxxgridplot(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
xxxxxxxxxxgrid2d_a=let X=collect(range(0,1,length=11)) Y=collect(range(0,1,length=11)) simplexgrid(X,Y)endxxxxxxxxxxgridplot(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.
InterruptException:
xxxxxxxxxxgrid2d_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) gridendInterruptException:
xxxxxxxxxxgridplot(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.
InterruptException:
xxxxxxxxxxfunction 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) bendInterruptException:
xxxxxxxxxxFor debugging purposes, the current state of the builder and its possible output can be visualized:
InterruptException:
xxxxxxxxxxbuilderplot(builder,Plotter=PyPlot)Finally, we can create a grid from the builder:
InterruptException:
xxxxxxxxxxgrid2d_c=simplexgrid(builder,maxvolume=0.001)InterruptException:
xxxxxxxxxxgridplot(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)xxxxxxxxxxfunction 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)end1×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.0xxxxxxxxxxsolution1d_a=solve_diffproblem_dirichlet(grid1d_a)xxxxxxxxxxscalarplot(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.0xxxxxxxxxxsolution2d_a=solve_diffproblem_dirichlet(grid2d_a)xxxxxxxxxxscalarplot(grid2d_a,solution2d_a[1,:],Plotter=PyPlot)Diffusion with Robin boundary conditions
solve_diffproblem_robin (generic function with 1 method)xxxxxxxxxxfunction 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)end1×21 Matrix{Float64}:
5.33333 5.5875 5.81667 6.02083 6.2 … 6.4 6.25417 6.08333 5.8875 5.66667xxxxxxxxxxsolution1d_robin=solve_diffproblem_robin(grid1d_a,a=1)xxxxxxxxxxscalarplot(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.66667xxxxxxxxxxsolution2d_robin=solve_diffproblem_robin(grid2d_a,a=1)xxxxxxxxxxscalarplot(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)xxxxxxxxxxfunction 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)end2×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-30xxxxxxxxxxsolution_readiff_1d=solve_readiff(grid1d_a,k=10, D_2=1)xxxxxxxxxxlet 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)end2×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-32xxxxxxxxxxsolution_readiff_2d=solve_readiff(grid2d_a,k=2)xxxxxxxxxxlet 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)endTransient Reaction-Diffusion problem
Here, we regard two species
Boundary conditons not specified are assumed to be homogeneous Neumann.
transient_reaction_diffusion (generic function with 1 method)x
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) control=VoronoiFVM.NewtonControl() control.Δt_min=0.01*tstep control.Δt=tstep control.Δt_max=0.1*tend control.Δu_opt=0.1 control.Δt_grow=dtgrowth tsol=solve(inival,system,[0,tend];control=control) return grid,tsolendx
grid_readiff,tsol_readiff=transient_reaction_diffusion(grid1d_a,k=1,tend=100);time step number:
xxxxxxxxxxbegin 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_2UEMWi/Project.toml` [cfc395e8] ExtendableGrids v0.7.4 [5eed8a63] GridVisualize v0.1.5 [7f904dfe] PlutoUI v0.7.4 [d330b81b] PyPlot v2.9.0 [57bfcd06] SimplexGridFactory v0.5.1 [f7e6ffb2] Triangulate v1.0.1 [82b139dc] VoronoiFVM v0.10.9