Postprocessing

Plotting

Plotting can be performed using the package GridVisualize.jl. This package extends the API with a couple of methods for systems:

GridVisualize.scalarplotFunction
scalarplot(
    sys::VoronoiFVM.AbstractSystem,
    sol::AbstractMatrix;
    species,
    scale,
    kwargs...
) -> Any

Plot one species from solution

source
scalarplot(
    sys::VoronoiFVM.AbstractSystem,
    sol::VoronoiFVM.AbstractTransientSolution;
    species,
    scale,
    tscale,
    kwargs...
)

Plot one species from transient solution

source
GridVisualize.scalarplot!Function
scalarplot!(
    vis,
    sys::VoronoiFVM.AbstractSystem,
    sol::AbstractMatrix;
    species,
    scale,
    kwargs...
) -> Any

Plot one species from solution

source
scalarplot!(
    vis,
    sys::VoronoiFVM.AbstractSystem,
    sol::VoronoiFVM.AbstractTransientSolution;
    species,
    scale,
    tscale,
    tlabel,
    kwargs...
) -> Any

Plot one species from transient solution

source
VoronoiFVM.plothistoryFunction
plothistory(tsol; 
            plots=[:timestepsizes,
                   :timestepupdates,
                   :newtonsteps,
                   :newtonupdates], 
            size=(700,600), 
            logmin=1.0e-20,
            Plotter=GridVisualize.default_plotter(),
            kwargs...)

Plot solution history stored in tsol. The plots argument allows to choose which plots are shown.

source

Grid verification

VoronoiFVM.nondelaunayFunction
nondelaunay(grid;tol=1.0e-14, verbose=true)

Return non-Delaunay edges. Returns a vector of tuples: Each tuple consists of (node1, node2, edge factor, region)

If the vector has length 0, the grid is boundary conforming Delaunay with respect to each cell region. This means that up to tol, all edge form factors are nonnegative.

source

Norms & volumes

LinearAlgebra.normFunction
norm(system, u)
norm(system, u, p)

Calculate Euklidean norm of the degree of freedom vector.

source
VoronoiFVM.lpnormFunction
lpnorm(sys, u, p)
lpnorm(sys, u, p, species_weights)

Calculate weighted discrete $L^p$ norm of a solution vector.

source
VoronoiFVM.l2normFunction
l2norm(sys, u)
l2norm(sys, u, species_weights)

Calculate weighted discrete $L^2(\Omega)$ norm of a solution vector.

source
VoronoiFVM.w1pseminormFunction
w1pseminorm(sys, u, p)
w1pseminorm(sys, u, p, species_weights)

Calculate weighted discrete $W^{1,p}(\Omega)$ seminorm of a solution vector.

source
VoronoiFVM.h1seminormFunction
h1seminorm(sys, u)
h1seminorm(sys, u, species_weights)

Calculate weighted discrete $H^1(\Omega)$ seminorm of a solution vector.

source
VoronoiFVM.w1pnormFunction
w1pnorm(sys, u, p)
w1pnorm(sys, u, p, species_weights)

Calculate weighted discrete $W^{1,p}(\Omega)$ norm of a solution vector.

source
VoronoiFVM.h1normFunction
h1norm(sys, u)
h1norm(sys, u, species_weights)

Calculate weighted discrete $H^1(\Omega)$ norm of a solution vector.

source
VoronoiFVM.lpw1pseminormFunction
lpw1pseminorm(sys, u, p)
lpw1pseminorm(sys, u, p, species_weights)

Calculate weighted discrete $L^p([0,T];W^{1,p}(\Omega))$ seminorm of a transient solution.

source
VoronoiFVM.l2h1seminormFunction
l2h1seminorm(sys, u)
l2h1seminorm(sys, u, species_weights)

Calculate weighted discrete $L^2([0,T];H^1(\Omega))$ seminorm of a transient solution.

source
VoronoiFVM.lpw1pnormFunction
lpw1pnorm(sys, u, p)
lpw1pnorm(sys, u, p, species_weights)

Calculate weighted discrete $L^p([0,T];W^{1,p}(\Omega))$ norm of a transient solution.

source
VoronoiFVM.l2h1normFunction
l2h1norm(sys, u)
l2h1norm(sys, u, species_weights)

Calculate weighted discrete $L^2([0,T];H^1(\Omega))$ norm of a transient solution.

source

Solution integrals

VoronoiFVM.integrateMethod
integrate(system,F,U; boundary=false, data=system.physics.data)

Integrate node function (same signature as reaction or storage) F of solution vector U region-wise over domain or boundary. The result is an nspec x nregion matrix $\int_{\Omega_j} F_i(U)\, dx$ or $\int_{\Gamma_j} F_i(U)\, ds$.

source
VoronoiFVM.integrateMethod
integrate(system,F, Ut; boundary=false, data=system.physics.data)

Integrate transient solution vector region-wise over domain or boundary. The result is an nspec x nregion x nsteps DiffEqArray $\int_{\Omega_j} F_i(U_k)\, dx$ or $\int_{\Gamma_j} F_i(U_k)\, ds$.

source
VoronoiFVM.integrateMethod
integrate(system,U; boundary=false)

Integrate solution vector region-wise over domain or boundary. The result is an nspec x nregion matrix $\int_{\Omega_j} U_i\, dx$ or $\int_{\Gamma_j} U_i\, ds$.

source
VoronoiFVM.edgeintegrateFunction
edgeintegrate(system,F,U; boundary=false)

Integrate edge function (same signature as flux function) F of solution vector region-wise over domain or boundary. The result is an nspec x nregion matrix.

source

Boundary fluxes

Continuum level motivation

For the calculation of boundary fluxes, we use a method inspired by H. Gajewski, WIAS Report No 6, 1993: "The regularity of the (weak) solutions of the drift-diffusion equations, which are guaranteed by existence statements, is not sufficient to justify a naive calculation of the currents as boundary integrals. Rather, it has also proven to be practical and necessary to reduce contact currents to volume integrals in accordance with the definition of weak solutions using suitable test functions."

We start with the continuous case for a problem

\[ \partial_t s(u) + \nabla\cdot \vec j(u) + r(u) - f =0 \]

defined in a domain $\Omega$ with a boundary $Γ=⋃_{i\in B}Γ_i$ subdivided into non-overlapping parts where the set of boundary regions $B$ is subdivided into $B=B_N\cup B_0 \cup B_1$. Assume that $\vec j\cdot \vec n=0$ on $\Gamma_i$ for $i\in B_N$.

Let $T(x)$ be a smooth test function such that

  • $\nabla T \cdot \vec n|_{Γ_i}= 0$ for $i\in B_N$,
  • $T|_{Γ_i} = 0$ for $i\in B_0$,
  • $T|_{Γ_i} = 1$ for $i\in B_1$.

Here, we obtain it by solving the Laplace equation

\[ -\Delta T =0 \quad \text{in}\; \Omega\]

To obtain as a quantity of interest the flux $Q$ through the boundaries $\Gamma_i$ for $i\in B_1$ of, calculate:

\[ \begin{aligned} Q=Q(t)&=\sum_{i \in B_1}\int\limits_{\Gamma_i} T\vec j(u)\cdot\vec n \,d\gamma\\ &=\sum_{i \in B_1}\int\limits_{\Gamma_i} T\vec j(u)\cdot\vec n \,d\gamma + \sum_{i \in B_N}\int\limits_{\Gamma_i} T\vec j(u)\cdot\vec n \,d\gamma + \sum_{i \in B_0}\int\limits_{\Gamma_l} T\vec j(u)\cdot\vec n \,d\gamma\\ &=\int\limits_{\Gamma} T\vec j(u)\cdot\vec n \,d\gamma\\ &=\int\limits_{\Omega}\nabla\cdot(T\vec j(u))\,d\omega\\ &=\int\limits_{\Omega}\nabla T \cdot \vec{j(u)} \,d\omega + \int\limits_{\Omega}T \nabla\cdot \vec{j(u)} \,d\omega\\ &=\int\limits_{\Omega}\nabla T \cdot \vec{j}(u) \,d\omega - \int\limits_{\Omega}T r(u) \,d\omega + \int\limits_{\Omega}T f \,d\omega - \int\limits_{\Omega}T \partial_ts(u) \,d\omega \end{aligned}\]

Discrete approximations of the integrals

The discete versions of these integrals for evaluation at $t=t^n$ are as follows:

\[ \begin{aligned} \int\limits_{\Omega}T r(u) \,d\omega &\approx \sum_{k\in N} T_kr(u^n_k)|\omega_k| =: I_{func}(r, T,u^n)\\ \int\limits_{\Omega}T f \,d\omega &\approx \sum_{k\in N} T_k f_k|\omega_k| =: I_{src}(f, T)\\ \int\limits_{\Omega}T \partial_ts(u) \,d\omega &\approx \frac{ I_{func}(s,T,u^n) -I_{func}(s,T,u^{n-1})}{t^n-t^{n-1}}\\ \int\limits_{\Omega}\nabla T \cdot \vec{j}(u^n) d\omega &\approx \sum\limits_{\stackrel{k,l}{\partial \omega_k \cup \partial \omega_l\neq\emptyset}} (T_{k}-T_{l})\frac{\sigma_{kl}}{h_{kl}}g(u^n_k, u^n_l) =: I_{flux}(j,T,u) \end{aligned}\]

General flux calculation API

VoronoiFVM.TestFunctionFactoryType
mutable struct TestFunctionFactory{Tu, Tv}

Data structure containing DenseSystem used to calculate test functions for boundary flux calculations.

Type parameters:

  • Tu: value type of test functions
  • Tv: Default value type of system

Fields:

  • system::VoronoiFVM.AbstractSystem{Tv} where Tv: Original system
  • state::VoronoiFVM.SystemState{Tu, Tp, TMatrix, TGenericMatrix, TSolArray} where {Tu, Tp, TMatrix<:AbstractMatrix{Tu}, TGenericMatrix, TSolArray<:AbstractMatrix{Tu}}: Test function system state
  • control::SolverControl: Solver control
source
VoronoiFVM.testfunctionFunction
testfunction(factory::TestFunctionFactory, B_0, B_1)

Create a test function $T$ defined in the domain $Ω$ given by the system behind the factory object. Assume that the boundary $Γ=∂Ω=⋃_{i∈ B}Γ_i$ is subdivided into non-overlapping parts where the set of boundary regions $B$ is subdivided into $B=B_N∪ B_0 ∪ B_1$. Create $T$ by solving

\[ -Δ T =0 \quad \text{in}\; Ω\]

such that

  • $∇ T ⋅ \vec n|_{Γ_i}= 0$ for $i∈ B_N$
  • $T|_{Γ_i} = 0$ for $i∈ B_0$,
  • $T|_{Γ_i} = 1$ for $i∈ B_1$.

Returns a vector representing T.

source
VoronoiFVM.integrateMethod
 integrate(system, T, U::AbstractMatrix)

Calculate test function integral for a steady state solution $u$ $∫_Γ T \vec j(u) ⋅ \vec n dω ≈ I_{flux}(j, T,u)-I_{func}(r,T,u) + I_{src}(f,T)$, see the definition of test function integral contributions.

The result is a nspec vector giving one value of the integral for each species.

source
VoronoiFVM.integrateMethod
integrate(system,T, U::AbstractTransientSolution; rate=true, params, data)

Calculate test function integrals for the transient solution $∫_Γ T \vec j(u^n) ⋅ \vec n dω ≈ I_{flux}(j,T,u^n)-I_{func}(r,T,u^n)-\frac{I_{func}(s,T,u^n)-I_{func}(s,T,u^{n-1})}{t^n-t^{n-1}} + I_{src}(f,T)$ for each time interval $(t^{n-1}, t^n)$, see the definition of test function integral contributions.

Keyword arguments:

  • params: vector of parameters used to calculate U. Default: [].
  • data: user data used to calculate U. Default: data(system)
  • rate: If rate=true (default), calculate the flow rate (per second) through the corresponding boundary. Otherwise, calculate the absolute amount per time interval.

The result is a nspec x (nsteps-1) DiffEqArray.

source

Special purpose cases

VoronoiFVM.integrateMethod
 integrate(system, T, U::AbstractMatrix, Uold::AbstractMatrix, Δt; kwargs...)

Calculate test function integrals for the implicit Euler time step results $u^n≡$ U and $u^{n-1}≡$ Uold as $∫_Γ T \vec j(u^n) ⋅ \vec n dω ≈ I_{flux}(j,T,u^n)-I_{func}(r,T,u^n)-\frac{I_{func}(s,T,u^n)-I_{func}(s,T,u^{n-1})}{Δt} + I_{src}(f,T)$, see the definition of test function integral contributions.

Keyword arguments:

  • params: vector of parameters used to calculate U. Default: [].
  • data: user data used to calculate U. Default: data(system)

The result is a nspec vector giving one value of the integral for each species.

source
VoronoiFVM.integrate_TxSrcFunction
integrate_TxSrc(system, T, f!; kwargs...)

Calculate $I_{src}(f!,T)= ∫_Ω T⋅ f! dω$ for a test function T. The functionf!` shall have the same signature as a storage or reaction function.

source
VoronoiFVM.integrate_∇TxFluxFunction
  integrate_∇TxFlux(system, T, f!, U; kwargs...)

Calculate $I_{flux}(f!,T, U)=∫_Ω ∇T⋅ f!(U) dω$ for a test function T and unknown vector U. The function f! shall have the same signature as a flux function.

source
  integrate_∇TxFlux(system, T, U; kwargs...)

Calculate $I_{flux}(f!,T, U)=∫_Ω ∇T⋅ f!(U) dω$ for a test function T and unknown vector U, where flux! is the system flux.

source
VoronoiFVM.integrate_TxEdgefuncFunction
  integrate_TxEdgeFunc(system, T, f!, U; kwargs...)

Calculate $∫_Ω T⋅ f!(U) dω$ for a test function T and unknown vector U. The function f! shall have the same signature as a flux function, but is assumed to describe a reaction term given on edges.

source
VoronoiFVM.integrate_tranFunction
integrate_tran(system, T, U; kwargs...)

Calculate storage term contribution to test function integral. Used for impedance calculations.

source

Nodal flux reconstruction

VoronoiFVM.nodefluxFunction
nodeflux(system, F,U; data)

Reconstruction of an edge function as vector function on the nodes of the triangulation. The result can be seen as a piecewiesw linear vector function in the FEM space spanned by the discretization nodes exhibiting the flux density.

The reconstruction is based on the "magic formula" R. Eymard, T. Gallouët, R. Herbin, IMA Journal of Numerical Analysis (2006) 26, 326−353, Lemma 2.4 (also: hal.science/hal-00004840 ).

The return value is a dim x nspec x nnodes vector.

CAVEAT: there is a possible unsolved problem with the values at domain corners in the code. Please see any potential boundary artifacts as a manifestation of this issue and report them.

source
nodeflux(system, U; data)

Reconstruction of the edge flux as vector function on the nodes of the triangulation. See nodeflux(system,F,U;data).

The flux of species i can e.g. plotted via GridVisualize.vectorplot.

Example:

    ispec=3
    vis=GridVisualizer(Plotter=Plotter)
    scalarplot!(vis,grid,solution[ispec,:],clear=true,colormap=:summer)
    vectorplot!(vis,grid,nf[:,ispec,:],clear=false)
    reveal(vis)
source

Impedance calculatiom

Impedance calculation can be seen as a postprocessing step after the solution of the unexcited stationary system.

VoronoiFVM.ImpedanceSystemType
mutable struct ImpedanceSystem{Tv} <: VoronoiFVM.AbstractImpedanceSystem{Tv}

Concrete type for impedance system.

  • sysnzval::AbstractArray{Complex{Tv}, 1} where Tv: Nonzero pattern of time domain system matrix
  • storderiv::AbstractMatrix: Derivative of storage term
  • matrix::AbstractArray{Complex{Tv}, 2} where Tv: Complex matrix of impedance system
  • F::AbstractArray{Complex{Tv}, 2} where Tv: Right hand side of impedance system
  • U0::AbstractMatrix: Stationary state
source
VoronoiFVM.ImpedanceSystemMethod
ImpedanceSystem(system, U0, excited_spec, excited_bc)

Construct impedance system from time domain system sys and steady state solution U0 under the assumption of a periodic perturbation of species excited_spec at boundary excited_bc.

source
VoronoiFVM.freqdomain_impedanceMethod
freqdomain_impedance(
    impedance_system,
    ω,
    U0,
    excited_spec,
    excited_bc,
    excited_bcval,
    dmeas_stdy,
    dmeas_tran
)

Calculate reciprocal value of impedance.

  • excitedspec,excitedbc,excited_bcval are ignored.
Warning

This is deprecated: use impedance.

source
VoronoiFVM.impedanceMethod
impedance(impedance_system,ω, U0 ,
          excited_spec, excited_bc, excited_bcval,
           dmeas_stdy,
           dmeas_tran 
           )
    

Calculate impedance.

  • ω: frequency
  • U0: steady state slution
  • dmeas_stdy: Derivative of steady state part of measurement functional
  • dmeas_tran Derivative of transient part of the measurement functional
source
VoronoiFVM.measurement_derivativeMethod
measurement_derivative(system, measurement_functional, U0)

Calculate the derivative of the scalar measurement functional at steady state U0

Usually, this functional is a test function integral. Initially, we assume that its value depends on all unknowns of the system.

source