Skip to content

Repository files navigation

JFVTool

CI DOI License: MIT

A finite-volume tool for discretizing and solving transient advection–diffusion equations on structured meshes, in Cartesian, cylindrical and radial coordinates. Requires Julia 1.10 or newer.

] add JFVTool

JFVTool carries no plotting dependency: it hands you cell values that any plotting package can draw (the examples use Plots). The older JFVMvis.jl package, including its Mayavi-based 3D visualization, is separate and not required.

Formerly JFVM. This package was called JFVM up to and including its releases in Julia's old METADATA registry. It was renamed to JFVTool for the General registry — to match the rest of the FVTool family, and because a four-letter all-caps name cannot be registered. The code is unchanged: replace using JFVM with using JFVTool.

Equations

You can solve the following PDE (or a subset of it):
advection diffusion

with the following boundary conditions:
boundary condition

Believe it or not, the above equations describe the majority of the transport phenomena in chemical and petroleum engineering and similar fields.

A simple finite volume tool written in Julia

This code is a Matlabesque implementation of my Matlab finite volume tool. The code is not in its most beautiful form, but it works if you believe my words. Please remember that the code is written by a chemical/petroleum engineer. Petroleum engineers are known for being simple-minded folks and chemical engineers have only one rule: "any answer is better than no answer". You can expect to easily discretize a linear transient advection-diffusion PDE into the matrix of coefficients and RHS vectors. Domain shape is limited to rectangles, circles (or a section of a circle), cylinders, and soon spheres. The mesh can be uniform or nonuniform:

  • Cartesian (1D, 2D, 3D)
  • Cylindrical (1D, 2D, 3D)
  • Radial (2D r and \theta)

You can have the following boundary conditions or a combination of them on each boundary:

  • Dirichlet (constant value)
  • Neumann (constant flux)
  • Robin (a linear combination of the above)
  • Periodic (so funny when visualize)

It is relatively easy to use the code to solve a system of coupled linear PDE's and not too difficult to solve nonlinear PDE's.

Coordinate systems

Each mesh carries an explicit coordinate-system type, and the discretization kernels dispatch on it (rather than on the legacy numeric dimension tag). The constructors are unchanged; the type is selected automatically:

Constructor Coordinate system dimension (legacy)
createMesh1D Cartesian1D 1.0
createMeshCylindrical1D Cylindrical1D 1.5
createMesh2D Cartesian2D 2.0
createMeshCylindrical2D Cylindrical2D 2.5
createMeshRadial2D Radial2D 2.8
createMesh3D Cartesian3D 3.0
createMeshCylindrical3D Cylindrical3D 3.2

The coordinate system is available as m.coordinatesystem, with helpers is_1d(m), is_2d(m), is_3d(m). The numeric m.dimension field and the coordinatesystem_from_dimension / dimension_from_coordinatesystem bridges are retained for backward compatibility; prefer dispatching on the coordinate-system types in new code.

Linear solvers

solveLinearPDE and solveLinearPDE! accept a pluggable solver strategy (default behavior is unchanged):

solveLinearPDE(m, M, RHS)                              # DirectSolver() — sparse LU via `\`
solveLinearPDE(m, M, RHS; solver = DirectSolver())    # explicit default

# Reuse one factorization across a fixed-matrix transient loop (only RHS changes):
fs = FactorizedSolver(M)
for step in 1:nsteps
    phi = solveLinearPDE(m, M, RHS; solver = fs)      # M is factored once
    # ... update RHS ...
end

solveLinearPDE(m, M, RHS; solver = MUMPSSolver())     # optional MUMPS backend (import MUMPS first)

Installation

] add JFVTool

or, for the development version:

] add https://github.com/FiniteVolumeTransportPhenomena/JFVTool.jl

In action

Copy and paste the following to solve a transient diffusion equation:

using JFVTool
Nx = 10
Lx = 1.0
m = createMesh1D(Nx, Lx)
BC = createBC(m)                  # all-Neumann by default
BC.left.a  .= 0.0                 # left boundary: Dirichlet c = 1
BC.left.b  .= 1.0
BC.left.c  .= 1.0
BC.right.a .= 0.0                 # right boundary: Dirichlet c = 0
BC.right.b .= 1.0
BC.right.c .= 0.0
c_old  = createCellVariable(m, 0.0, BC)      # initial condition
D_val  = 1.0                                 # diffusion coefficient
D_cell = createCellVariable(m, D_val)        # assigned to the cells
D_face = harmonicMean(D_cell)                # averaged onto the faces
N_steps = 20
dt = sqrt(Lx^2 / D_val) / N_steps            # time step
M_diff = diffusionTerm(D_face)               # matrix for the diffusion term
M_bc, RHS_bc = boundaryConditionTerm(BC)     # matrix and RHS for the BCs
for i = 1:5
    M_t, RHS_t = transientTerm(c_old, dt, 1.0)
    M   = M_t - M_diff + M_bc                # add up the sparse matrices ...
    RHS = RHS_bc + RHS_t                     # ... and the right-hand sides
    global c_old = solveLinearPDE(m, M, RHS)
end
internalCells(c_old)      # the solution on the physical cells

Change the mesh line to m = createMesh2D(Nx, Nx, Lx, Lx) and the same code solves the 2D problem:

diffusion 2D

Examples and tutorials

The examples/ folder is organised into:

  • examples/notebooks — Jupyter notebooks, from a first steady problem through source terms, nonlinear coefficients and Cahn–Hilliard,
  • examples/tutorial — the same ground as short .jl scripts,
  • examples/cases — worked engineering problems (heat conduction, plug-flow reactor) that verify themselves against analytical solutions.

See examples/README.md for what each one covers and how to set up the environment they use.

Elsewhere:

How to cite

If you have used the code in your research, please cite it as

Ali A Eftekhari. (2017, August 23). JFVM.jl: A Finite Volume Tool for Solving Advection-Diffusion Equations. Zenodo. http://doi.org/10.5281/zenodo.847056

@misc{ali_a_eftekhari_2017_847056,
  author       = {Ali A Eftekhari},
  title        = {{JFVM.jl: A Finite Volume Tool for Solving 
                   Advection-Diffusion Equations}},
  month        = aug,
  year         = 2017,
  doi          = {10.5281/zenodo.847056},
  url          = {https://doi.org/10.5281/zenodo.847056}
}