Diffusion equation As a first example, I try to solve the diffusion equation, i.e., $$ \frac {\partial c} {\partial t} + \nabla.(-D \nabla c)=0$$ The boundary condition is written in the general form of $$a \nabla \phi . \mathbf{n} + b \phi = c$$ We use Dirichlet boundary condition for the left and right boundaries, i.e., $c=1.0$ at the left boundary and $c=1.0$ at the right boundary. The initial condition is $c=0.0$ at $t=0.$
In [16]:
using JFVM
using PyPlot
In [23]:
D_val = 1.0 # [m^2/s]
Lx = 50.0 # [m]
c_init = 0.0
c_left = 1.0
c_right = 0.0
Out[23]:
First, we define a function that accepts a mesh, boundary condition, diffusion coefficient, and final simulation time, and returns a cell value, which is the final concentration profile. I also define a boundary condition function to assign values of one and zero to the left and right boundaries.
In [8]:
function trans_diff(m::MeshStructure, BC::BoundaryCondition, D_val::Real, t_final::Real)
# a transient diffusion
c_init = 0.0 # initial value of the variable
c_old = createCellVariable(m, 0.0, BC)
D_val = 1.0 # value of the diffusion coefficient
D_cell = createCellVariable(m, D_val) # assigned to cells
# Harmonic average
D_face = harmonicMean(D_cell)
N_steps = 20 # number of time steps
dt= t_final/N_steps # time step
M_diff = diffusionTerm(D_face) # matrix of coefficient for diffusion term
(M_bc, RHS_bc)=boundaryConditionTerm(BC) # matrix of coefficient and RHS for the BC
for i =1:N_steps
(M_t, RHS_t)=transientTerm(c_old, dt, 1.0)
M=M_t-M_diff+M_bc # add all the [sparse] matrices of coefficient
RHS=RHS_bc+RHS_t # add all the RHS's together
c_old = solveLinearPDE(m, M, RHS) # solve the PDE
end
return c_old
end
function dirich_bc(m::MeshStructure)
BC = createBC(m)
BC.left.a[:]=BC.right.a[:]=0.0
BC.left.b[:]=BC.right.b[:]=1.0
BC.left.c[:]=1.0
BC.right.c[:]=0.0
return BC
end
Out[8]:
I define two domains, one with uniform grids and another with a nonuniform grids with smaller cells near the left boundary. The total number of grids are the same for both case. The figure below shows how you can use grid refinement near the more important areas of the domain to get the best out of your numerical model.
In [34]:
t_final = 5
Nx = 11 # number of cells
m_uni = createMesh1D(Nx, Lx)
BC_uni = dirich_bc(m_uni)
c_uni = trans_diff(m_uni, BC_uni, D_val, t_final)
x = linspace(0,50,200)
m_nonuni = createMesh1D([linspace(0,10,5), linspace(14,50,5)])
BC_nonuni = dirich_bc(m_nonuni)
c_nonuni = trans_diff(m_nonuni, BC_nonuni, D_val, t_final)
c_analytic = 1-erf(x./(2.*sqrt(D_val*t_final)))
visualizeCells(c_uni)
visualizeCells(c_nonuni)
plot(x, c_analytic)
legend(["uniform", "nonuniform", "analytic"])
axis([0, 10, 0, 1])
Out[34]: