Finite element back ends
ModularEIT itself contains no finite element code. The generic layer — electrode models, ForwardModel, objectives, regularizers, optimizers, linear solvers and synthetic data — works with any discretization that implements a small contract. The discretization comes from a back end package, which is loaded next to ModularEIT:
| Back end | Package | Finite element library |
|---|---|---|
| Ferrite | ModularEITFerrite (in lib/ModularEITFerrite) | Ferrite.jl (fork with triangle bisection) |
| Gridap | ModularEITGridap (in lib/ModularEITGridap) | Gridap.jl |
using ModularEIT, ModularEITFerrite, Ferrite
disc = FerriteDiscretization(generate_grid(Triangle, (16, 16)))
using ModularEIT, ModularEITGridap, Gridap
disc = GridapDiscretization(simplexify(CartesianDiscreteModel((-1, 1, -1, 1), (16, 16))))Only the back end that is used has to be installed; the others are separate packages. On the same mesh both back ends give the same matrices (up to the numbering of the dofs), voltages, objective values and gradients; the Gridap back end's tests check this.
The Ferrite back end additionally provides structured, polar and conformally mapped grids, image maps, pixel parametrizations and adaptive meshing. The Gridap back end covers the contract below (Lagrange u of any order, piecewise constant or Lagrange σ) and works with every Gridap DiscreteModel, e.g. meshes read with GridapGmsh.
ModularEITFerrite.ModularEITFerrite — Module
ModularEITFerriteFerrite.jl back end of ModularEIT: finite element discretizations with separate spaces for the potential and the conductivity, assembly, electrode geometry and forward models, grids (structured, polar, conformally mapped), image maps, pixel parametrizations, total variation on meshes, and adaptive meshing (hanging nodes on quadrilaterals, newest vertex bisection on triangles).
ModularEITGridap — Module
ModularEITGridapGridap.jl back end of ModularEIT: finite element discretizations of a Gridap DiscreteModel with separate spaces for the potential (Lagrange, any order) and the conductivity (piecewise constants by default, or Lagrange). It implements the back end contract of ModularEIT, so forward models of all electrode models, objectives, regularizers, optimizers and linear solvers work unchanged on Gridap meshes.
ModularEITGridap.GridapDiscretization — Type
GridapDiscretization(model; order_u = 1, order_σ = 0, σ_conformity = order_σ == 0 ? :L2 : :H1,
boundary = nothing, degree = nothing)Finite element spaces for the potential u (Lagrange of order order_u) and the conductivity σ (Lagrange of order order_σ, discontinuous with σ_conformity = :L2, continuous with :H1; default: piecewise constants) on the Gridap DiscreteModel model (e.g. a CartesianDiscreteModel, simplexify(...) of it, or a mesh read with GridapGmsh).
boundary: boundary facets (global ids of the faces of dimension D-1). Default: all facets that belong to exactly one cell.degree: quadrature degree. Default: exact for the weighted stiffness matrix∫ σ ∇φᵢ⋅∇φⱼand the mass matrices on affine cells.
Facets are assumed straight (affine geometry) for facet measures and midpoints.
Fields: model, V, U (test and trial space of u), Vσ, Uσ, Ω, dΩ, degree, boundary_facets, boundary_dofs (u dofs on the boundary), order_u, order_σ.
The contract
A back end defines a subtype of AbstractDiscretization and adds methods to these functions and constructors (the electrode and regularizer primitives behind the forward models and the regularizers are listed in src/Galerkin/Electrodes.jl and src/Galerkin/RegularizersFE.jl):
| Purpose | Functions |
|---|---|
| Sizes | ndofs_u, ndofs_σ |
| Matrices | FEMatrices(disc), ConductivityTensor(disc; pattern, to_device), assemble_weighted_stiffness |
| Functions on the mesh | interpolate_function, l2_project, fe_inner, fe_norm, total_variation, lumped_mass |
| Electrodes and forward model | angular_electrodes, electrode_length, transfer_electrodes, ForwardModel(disc, model) for the electrode models |
| Regularizers | TikhonovRegularizer(disc; kind), TotalVariationRegularizer(disc; ε) with objective_value, value_and_gradient!, gauss_newton_hessian, prox! |
| Fast preconditioners (optional) | structured_grid, polar_structure |
| Pixel parametrizations (optional) | pixel_image |
The electrodes of GapModel and CompleteElectrodeModel are stored in the back end's representation (for Ferrite: vectors of FacetIndex). Everything else the generic layer needs is in the data types FEMatrices, ConductivityTensor and ForwardModel, which are back end independent.
ModularEIT.total_variation! — Function
total_variation(disc, σ; ε = 0)
total_variation!(g, disc, σ; ε = 0)Total variation ∫ √(|∇σ|² + ε²) of a conductivity (for piecewise constants: the facet jumps), and its coefficient gradient (in place). Back end contract.
ModularEIT.assemble_weighted_stiffness — Function
assemble_weighted_stiffness(disc, σ)The weighted stiffness matrix ∫ σ ∇φᵢ⋅∇φⱼ of a discretization, assembled directly (for repeated assembly use a ConductivityTensor). Back end contract.