Postprocessing
Plotting
Plotting can be performed using the package GridVisualize.jl. This package extends the API with a couple of methods for systems:
GridVisualize.gridplot — Function
GridVisualize.gridplot! — Function
GridVisualize.scalarplot — Function
scalarplot(
sys::VoronoiFVM.AbstractSystem,
sol::AbstractMatrix;
species,
scale,
kwargs...
) -> Any
Plot one species from solution
sourcescalarplot(
sys::VoronoiFVM.AbstractSystem,
sol::VoronoiFVM.AbstractTransientSolution;
species,
scale,
tscale,
kwargs...
) -> Any
Plot one species from transient solution
sourceGridVisualize.scalarplot! — Function
scalarplot!(
vis,
sys::VoronoiFVM.AbstractSystem,
sol::AbstractMatrix;
species,
scale,
kwargs...
) -> Any
Plot one species from solution
sourcescalarplot!(
vis,
sys::VoronoiFVM.AbstractSystem,
sol::VoronoiFVM.AbstractTransientSolution;
species,
scale,
tscale,
tlabel,
kwargs...
) -> Any
Plot one species from transient solution
sourceVoronoiFVM.plothistory — Function
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.
Grid verification
VoronoiFVM.nondelaunay — Function
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.
Norms & volumes
LinearAlgebra.norm — Function
VoronoiFVM.lpnorm — Function
lpnorm(sys, u, p)
lpnorm(sys, u, p, species_weights)
Calculate weighted discrete $L^p$ norm of a solution vector.
sourceVoronoiFVM.l2norm — Function
l2norm(sys, u)
l2norm(sys, u, species_weights)
Calculate weighted discrete $L^2(\Omega)$ norm of a solution vector.
sourceVoronoiFVM.w1pseminorm — Function
w1pseminorm(sys, u, p)
w1pseminorm(sys, u, p, species_weights)
Calculate weighted discrete $W^{1,p}(\Omega)$ seminorm of a solution vector.
sourceVoronoiFVM.h1seminorm — Function
h1seminorm(sys, u)
h1seminorm(sys, u, species_weights)
Calculate weighted discrete $H^1(\Omega)$ seminorm of a solution vector.
sourceVoronoiFVM.w1pnorm — Function
w1pnorm(sys, u, p)
w1pnorm(sys, u, p, species_weights)
Calculate weighted discrete $W^{1,p}(\Omega)$ norm of a solution vector.
sourceVoronoiFVM.h1norm — Function
h1norm(sys, u)
h1norm(sys, u, species_weights)
Calculate weighted discrete $H^1(\Omega)$ norm of a solution vector.
sourceVoronoiFVM.lpw1pseminorm — Function
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.
sourceVoronoiFVM.l2h1seminorm — Function
l2h1seminorm(sys, u)
l2h1seminorm(sys, u, species_weights)
Calculate weighted discrete $L^2([0,T];H^1(\Omega))$ seminorm of a transient solution.
sourceVoronoiFVM.lpw1pnorm — Function
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.
sourceVoronoiFVM.l2h1norm — Function
l2h1norm(sys, u)
l2h1norm(sys, u, species_weights)
Calculate weighted discrete $L^2([0,T];H^1(\Omega))$ norm of a transient solution.
sourceVoronoiFVM.nodevolumes — Function
Solution integrals
VoronoiFVM.integrate — Method
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$.
VoronoiFVM.integrate — Method
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$.
VoronoiFVM.integrate — Method
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$.
VoronoiFVM.edgeintegrate — Function
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.
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.TestFunctionFactory — Type
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 functionsTv: 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
VoronoiFVM.TestFunctionFactory — Method
TestFunctionFactory(system; control= SolverControl())Constructor for TestFunctionFactory from system.
sourceVoronoiFVM.testfunction — Function
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.
sourceVoronoiFVM.integrate — Method
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.
VoronoiFVM.integrate — Method
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 calculateU. Default:[].data: user data used to calculateU. Default:data(system)rate: Ifrate=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.
Special purpose cases
VoronoiFVM.integrate — Method
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 calculateU. Default:[].data: user data used to calculateU. Default:data(system)
The result is a nspec vector giving one value of the integral for each species.
VoronoiFVM.integrate_TxFunc — Function
integrate_TxFunc(system, T, f!, U; kwargs...)Calculate $I_{func}(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 storage or reaction function. See the definition of test function integral contributions.
VoronoiFVM.integrate_TxSrc — Function
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.
VoronoiFVM.integrate_∇TxFlux — Function
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.
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.
VoronoiFVM.integrate_TxEdgefunc — Function
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.
VoronoiFVM.integrate_stdy — Function
integrate_stdy(system, T, U; kwargs...)Calculate steady state contribution $I_j(T,u) - I_r(T,u)$ to test function integral $∫_Γ T \vec j(u) ⋅ \vec n dω$ for a given timestep solution. See the time step integrate method.
Used for impedance calculations.
sourceVoronoiFVM.integrate_tran — Function
integrate_tran(system, T, U; kwargs...)Calculate storage term contribution to test function integral. Used for impedance calculations.
sourceNodal flux reconstruction
VoronoiFVM.nodeflux — Function
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.
sourcenodeflux(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)sourceImpedance calculatiom
Impedance calculation can be seen as a postprocessing step after the solution of the unexcited stationary system.
VoronoiFVM.ImpedanceSystem — Type
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
VoronoiFVM.ImpedanceSystem — Method
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.
VoronoiFVM.ImpedanceSystem — Method
ImpedanceSystem(system, U0; λ0)
Construct impedance system from time domain system sys and steady state solution U0
CommonSolve.solve! — Method
VoronoiFVM.freqdomain_impedance — Method
VoronoiFVM.impedance — Method
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
VoronoiFVM.measurement_derivative — Method
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