Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend VoronoiFVM to incorporate FEM-computed velocity fields provided by ExtendableFEM #129

Merged
merged 27 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
da5c0ca
added extension for interpolating ExtendableFEM vectors into edgevelo…
Da-Be-Ru Oct 10, 2024
ac80d29
added bfacevelocities for fem coupling and adjusted test environment …
pjaap Oct 10, 2024
c6ef4b3
added full fem velocity example with differing grids
pjaap Oct 10, 2024
3719136
updated compat entry for ExtendableGrids to accommodate new extension
Da-Be-Ru Oct 11, 2024
de0d014
added ExtendableFEM(Base) to test and docs Project.tomls
Da-Be-Ru Oct 11, 2024
04a7284
Merge branch 'master' into feature/extendablefembaseext
j-fu Oct 12, 2024
faf98ae
use concrete types in Data struct to avoid allocations in flux!
j-fu Oct 13, 2024
91fe612
Remove allocations in analytical edgevelocities and bfacevelocities
j-fu Oct 16, 2024
57bd3a3
Reduce allocations and mark allocating lines
j-fu Oct 16, 2024
4ec9fb1
Code cleanup in VoronoiFVMExtendableFEMBaseExt.jl
pjaap Oct 17, 2024
52f25cd
added docstrings; adjusted example elements to P2 Bubble
Da-Be-Ru Oct 17, 2024
6c177d0
Make Documenter.jl find the extension methods
pjaap Oct 17, 2024
60b09c7
docs: cleanup the makedocs call and sort integrate methods
pjaap Oct 18, 2024
043e2fc
docs: add a more meaningful description of the ExtendableFEMBase exte…
pjaap Oct 18, 2024
e1f2798
remove unnecessary explicit imports
pjaap Oct 18, 2024
8ba19a0
added switches for disparate grids to example and adjusted stagnation…
Da-Be-Ru Oct 18, 2024
c880997
corrected _integrate_along_segments for facets at r=0
Da-Be-Ru Oct 18, 2024
4c2922d
docs: put internal integrate method to Internal API
pjaap Oct 21, 2024
be921f5
corrected edgevelocities computation; restructured and cleaned up Exa…
Da-Be-Ru Oct 21, 2024
13994e2
Update examples/Example240_FiniteElementVelocities.jl
pjaap Oct 21, 2024
5aa2bd1
update Example240 with @pjaap's suggestions
Da-Be-Ru Oct 21, 2024
259681b
removed obsolete counter in integration loop as suggested by @pjaap
Da-Be-Ru Oct 21, 2024
bc6dee9
Merge branch 'feature/extendablefembaseext' of github.com:Da-Be-Ru/Vo…
j-fu Oct 22, 2024
930e76b
Prevent ambiguity
j-fu Oct 22, 2024
74a7195
fix docs
j-fu Oct 22, 2024
bcabac8
fix stale import
j-fu Oct 22, 2024
740d8b9
bump minor version; Daniel as Coauthor
j-fu Oct 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"

[weakdeps]
ExtendableFEMBase = "12fb9182-3d4c-4424-8fd1-727a0899810c"

[extensions]
VoronoiFVMExtendableFEMBaseExt = "ExtendableFEMBase"

[compat]
BandedMatrices = "0.17,1"
Colors = "0.12"
CommonSolve = "0.2"
DiffResults = "1"
DocStringExtensions = "0.8,0.9"
ExtendableGrids = "1.9.2"
ExtendableFEMBase = "0.7.0"
ExtendableGrids = "1.10.1"
ExtendableSparse = "1.5.1"
ForwardDiff = "0.10.35"
GridVisualize = "0.5.2,0.6.1,1"
Expand Down
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
ExampleJuggler = "3bbe58f8-ed81-4c4e-a134-03e85fcf4a1a"
ExtendableFEM = "a722555e-65e0-4074-a036-ca7ce79a4aed"
ExtendableFEMBase = "12fb9182-3d4c-4424-8fd1-727a0899810c"
ExtendableGrids = "cfc395e8-590f-11e8-1f13-43a2532b2fa8"
ExtendableSparse = "95c220a8-a1cf-11e9-0c77-dbfce5f500b3"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Expand Down
17 changes: 12 additions & 5 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Documenter, ExampleJuggler, PlutoStaticHTML, VoronoiFVM, DocumenterCitations
using ExtendableGrids, GridVisualize, LinearAlgebra, RecursiveArrayTools, SciMLBase

using ExtendableFEMBase, ExtendableFEM

using OrdinaryDiffEqBDF, OrdinaryDiffEqLowOrderRK, OrdinaryDiffEqRosenbrock, OrdinaryDiffEqSDIRK, OrdinaryDiffEqTsit5

function make(; with_examples = true,
Expand Down Expand Up @@ -33,7 +35,8 @@ function make(; with_examples = true,
"misc.md",
"internal.md",
"allindex.md",
"devel.md",]
"devel.md",
"extensions.md"]
]


Expand Down Expand Up @@ -65,10 +68,14 @@ function make(; with_examples = true,
push!(pages, "Examples" => module_examples)
end

makedocs(; sitename = "VoronoiFVM.jl",
modules = [VoronoiFVM],
plugins = [bib],
checkdocs = :all,
makedocs(; sitename="VoronoiFVM.jl",
modules=[
VoronoiFVM,
# define extension modules manually: https://github.com/JuliaDocs/Documenter.jl/issues/2124#issuecomment-1557473415
Base.get_extension(VoronoiFVM, :VoronoiFVMExtendableFEMBaseExt)
],
plugins=[bib],
checkdocs=:all,
clean = false,
doctest = false,
authors = "J. Fuhrmann",
Expand Down
9 changes: 9 additions & 0 deletions docs/src/extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# [`ExtendableFEMBase`](https://github.com/chmerdon/ExtendableFEMBase.jl/) Extension

The extension for [`ExtendableFEMBase`](https://github.com/chmerdon/ExtendableFEMBase.jl/) extends the funcitons below for solution types of [`ExtendableFEM`](https://github.com/chmerdon/ExtendableFEM.jl/).
The name of the extension originates from the solution type `FEVectorBlock` that is definded in `ExtendableFEMBase`.

```@docs
edgevelocities(grid, vel::FEVectorBlock; kwargs...)
bfacevelocities(grid, vel::FEVectorBlock; kwargs...)
```
2 changes: 2 additions & 0 deletions docs/src/internal.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ prepare_diffeq!

## Misc tools
```@docs
VoronoiFVM.integrate(::Type{<:Cartesian2D}, coordl, coordr, hnormal, velofunc; kwargs...)
VoronoiFVM.integrate(::Type{<:Cylindrical2D}, coordl, coordr, hnormal, velofunc; kwargs...)
VoronoiFVM.doolittle_ludecomp!
VoronoiFVM.doolittle_lusolve!
VoronoiFVM.bernoulli_horner
Expand Down
5 changes: 4 additions & 1 deletion docs/src/post.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ nodevolumes

## Solution integrals
```@docs
VoronoiFVM.integrate
VoronoiFVM.integrate(system::VoronoiFVM.AbstractSystem, tf::Vector, U::AbstractMatrix; kwargs...)
VoronoiFVM.integrate(system::VoronoiFVM.AbstractSystem{Tv, Tc, Ti, Tm}, F::Function, U::AbstractMatrix{Tu}; boundary = false, data = system.physics.data) where {Tu, Tv, Tc, Ti, Tm}
VoronoiFVM.integrate(system::VoronoiFVM.AbstractSystem, U::AbstractMatrix; kwargs...)
VoronoiFVM.integrate(system::VoronoiFVM.AbstractSystem, F::Function, U::AbstractMatrix; boundary, data)
VoronoiFVM.edgeintegrate
```

Expand Down
291 changes: 291 additions & 0 deletions examples/Example240_FiniteElementVelocities.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
#=

# 240: 2D Convection in quadratic stagnation flow velocity field
([source code](@__SOURCE_URL__))

Solve the equation

```math
-\nabla \cdot ( D \nabla u - \mathbf{v} u) = 0
```
in $\Omega=(0,L)\times (0,H)$ with a homogeneous Neumann boundary condition
at $x=0$, an outflow boundary condition at $x=L$, a Dirichlet inflow
condition at $y=H$, and a homogeneous Dirichlet boundary condition
on part of $y=0$.

The analytical expression for the (quadratic variant of the) velocity field
is $\mathbf{v}(x,y)=(x^2,-2xy)$ in cartesian coordinates and (for the linear variant)
$\mathbf{v}(r,z)=(r,-2z)$ in cylindrical coordinates, i.e.
where the system is solved on $\Omega$ to represent a solution on the solid
of revolution arising from rotating $\Omega$ around $x=0$.

We compute the solution $u$ in both coordinate systems where $\mathbf{v}$ is given
as an analytical expression and as a finite element interpolation onto
the grid of $\Omega$.
=#

module Example240_FiniteElementVelocities
using Printf
using ExtendableFEMBase
using ExtendableFEM
using VoronoiFVM
using ExtendableGrids
using GridVisualize
using LinearAlgebra

function stagnation_flow_cartesian(x, y)
return (x^2, -2x * y)
end

# In the cylindrical case: since the reconstruction space $\mathtt{HDIVBDM2}$
# is only quadratic, but we have to reconstruct $r \, \mathbf{v}(r,z)$ for a
# (reconstructed) divergence-free solution,
# we can only resolve at most the linear case exactly.
function stagnation_flow_cylindrical(r, z)
return (r, -2 * z)
end

function inflow_cylindrical(u, qpinfo)
x = qpinfo.x
u .= stagnation_flow_cylindrical(x[1], x[2])
end

function inflow_cartesian(u, qpinfo)
x = qpinfo.x
u .= stagnation_flow_cartesian(x[1], x[2])
end

function flux!(f, u, edge, data)
vd = data.evelo[edge.index] / data.D
bp = fbernoulli(vd)
bm = fbernoulli(-vd)
f[1] = data.D * (bp * u[1] - bm * u[2])
end

function bconditions!(f, u, node, data)
## catalytic Dirichlet condition at y=0
if node.region == 5
boundary_dirichlet!(f, u, node, 1, node.region, 0.0)
end

## outflow condition at x = L
if node.region == 2
f[1] = data.bfvelo[node.ibnode, node.ibface] * u[1]
end

## inflow condition at y = H
if node.region == 3
boundary_dirichlet!(f, u, node, 1, node.region, data.cin)
end
end

mutable struct Data
D::Float64
cin::Float64
evelo::Array
bfvelo::Array

Data() = new()
end

#=
Calculate the analytical or FEM solution to the stagnation point flow field $\mathbf{v}$ and
use this as input to solve for the species concentration $u$ of the corresponding
convection-diffusion system.

The passed flags regulate the following behavior:
- `cylindrical_grid`: if true, calculates both the velocity field $\mathbf{v}(r,z)$
and the species concentration $u(r,z)$ in cylindrical coordinates, assuming
rotationally symmetric solutions for both.
- `usefem`: if true, calculates the velocity field $\mathbf{v}$ using the
finite element method provided by [`ExtendableFEM`](https://github.com/chmerdon/ExtendableFEM.jl).
- `reconst`: if true, interpolates the FEM-calculated
velocity field onto a "reconstruction" finite element space that
provides an exactly divergence-free solution. In a cylindrical grid,
this returns not $\mathbf{v}(r,z)$, but $r \, \mathbf{v}(r,z)$ as the velocity.
- `use_different_grids`: if true, calculates the FEM solution of the
velocity field on a uniform `flowgrid` and the species concentration
on an adaptively refined `chemgrid` while still interpolating the
calculated velocity correctly onto the `chemgrid`.
=#
function main(;
cylindrical_grid = false, usefem = true, reconst = cylindrical_grid, use_different_grids = false, nref = 1,
Plotter = nothing, μ = 1.0e-02, D = 0.01, cin = 1.0, assembly = :edgewise,
interpolation_eps = 1.0e-09)
H = 1.0
L = 5.0

if cylindrical_grid
coord_system = Cylindrical2D
else
coord_system = Cartesian2D
end

flowgrid = simplexgrid(range(0, L; length = 20 * 2^nref),
range(0, H; length = 5 * 2^nref))

if use_different_grids
h_fine = 1.0e-01
X_bottom = geomspace(0.0, L / 2, 5.0e-01, h_fine)
X_cat = range(L / 2, L; step = h_fine)
chemgrid = simplexgrid([X_bottom; X_cat[2:end]],
geomspace(0.0, H, 1.0e-03, 1.0e-01))
bfacemask!(chemgrid, [L / 2, 0.0], [3 * L / 4, 0.0], 5)
else
chemgrid = deepcopy(flowgrid)
bfacemask!(chemgrid, [L / 2, 0.0], [3 * L / 4, 0.0], 5)
end

if usefem
velocity = compute_velocity(
flowgrid, cylindrical_grid, reconst, μ; interpolation_eps)
DivIntegrator = L2NormIntegrator([div(1)]; quadorder = 2 * 2, resultdim = 1)
div_v = sqrt(sum(evaluate(DivIntegrator, [velocity])))
@info "||div(R(v))||_2 = $(div_v)"
else
if cylindrical_grid
velocity = stagnation_flow_cylindrical
else
velocity = stagnation_flow_cartesian
end
end

if coord_system == Cylindrical2D
Da-Be-Ru marked this conversation as resolved.
Show resolved Hide resolved
analytical_velocity = stagnation_flow_cylindrical
else
analytical_velocity = stagnation_flow_cartesian
end

if cylindrical_grid
Da-Be-Ru marked this conversation as resolved.
Show resolved Hide resolved
chemgrid[CoordinateSystem] = Cylindrical2D
end

data = Data()
data.D = D
data.cin = cin

evelo = edgevelocities(chemgrid, velocity; reconst)
bfvelo = bfacevelocities(chemgrid, velocity; reconst)

data.evelo = evelo
data.bfvelo = bfvelo

physics = VoronoiFVM.Physics(; flux = flux!, breaction = bconditions!, data)
sys = VoronoiFVM.System(chemgrid, physics; assembly = assembly)
Da-Be-Ru marked this conversation as resolved.
Show resolved Hide resolved
enable_species!(sys, 1, [1])

sol = solve(sys; inival = 0.0)

fvm_divs = VoronoiFVM.calc_divergences(sys, evelo, bfvelo)
@info "||div(v)||_∞ = $(norm(fvm_divs, Inf))"

vis = GridVisualizer(; Plotter = Plotter)

scalarplot!(vis[1, 1], chemgrid, sol[1, :]; flimits = (0, cin + 1.0e-5),
show = true)

minmax = extrema(sol)
@info "Minimal/maximal values of concentration: $(minmax)"

return sol, evelo, bfvelo, minmax
end

using Test
function runtests()
cin = 1.0
for cylindrical_grid in [false, true]
sol_analytical, evelo_analytical, bfvelo_analytical, minmax_analytical = main(;
cylindrical_grid, cin, usefem = false)
sol_fem, evelo_fem, bfvelo_fem, minmax_fem = main(;
cylindrical_grid, cin, usefem = true)
@test norm(evelo_analytical .- evelo_fem, Inf) ≤ 1.0e-11
@test norm(bfvelo_analytical .- bfvelo_fem, Inf) ≤ 1.0e-09
@test norm(sol_analytical .- sol_fem, Inf) ≤ 1.0e-10
@test norm(minmax_analytical .- [0.,cin], Inf) ≤ 1.0e-15
@test norm(minmax_fem .- [0.,cin], Inf) ≤ 1.0e-11
end
end

function compute_velocity(
flowgrid, cylindrical_grid, reconst, μ = 1.0e-02; interpolation_eps = 1.0e-10)
## define finite element spaces
FE_v, FE_p = H1P2B{2, 2}, L2P1{1}
reconst_FEType = HDIVBDM2{2}
FES = [FESpace{FE_v}(flowgrid), FESpace{FE_p}(flowgrid; broken = true)]

## describe problem
Problem = ProblemDescription("incompressible Stokes problem")
v = Unknown("v"; name = "velocity")
p = Unknown("p"; name = "pressure")
assign_unknown!(Problem, v)
assign_unknown!(Problem, p)

## assign stokes operator
assign_operator!(Problem,
BilinearOperator(
kernel_stokes!, cylindrical_grid ? [id(v), grad(v), id(p)] : [grad(v), id(p)];
bonus_quadorder = 2, store = false,
params = [μ, cylindrical_grid]))

## assign Dirichlet boundary conditions on all boundary regions to
## enforce match with analytical solution
if cylindrical_grid
assign_operator!(
Problem, InterpolateBoundaryData(v, inflow_cylindrical; regions = [1, 2, 3, 4]))
else
assign_operator!(
Problem, InterpolateBoundaryData(v, inflow_cartesian; regions = [1, 2, 3, 4]))
end

velocity_solution = solve(Problem, FES)

## ensure divergence free solution by projecting onto reconstruction spaces
FES_reconst = FESpace{reconst_FEType}(flowgrid)
R = FEVector(FES_reconst)
if reconst
if cylindrical_grid
lazy_interpolate!(R[1], velocity_solution, [id(v)]; postprocess = multiply_r,
bonus_quadorder = 2, eps = interpolation_eps)
else
lazy_interpolate!(
R[1], velocity_solution, [id(v)];
bonus_quadorder = 2, eps = interpolation_eps)
end
else
return velocity_solution[1]
end

return R[1]
end

function kernel_stokes!(result, u_ops, qpinfo)
μ = qpinfo.params[1]
cylindrical_grid = qpinfo.params[2]
if cylindrical_grid > 0
r = qpinfo.x[1]
u, ∇u, p = view(u_ops, 1:2), view(u_ops, 3:6), view(u_ops, 7)
result[1] = μ / r * u[1] - p[1]
result[2] = 0
result[3] = μ * r * ∇u[1] - r * p[1]
result[4] = μ * r * ∇u[2]
result[5] = μ * r * ∇u[3]
result[6] = μ * r * ∇u[4] - r * p[1]
result[7] = -(r * (∇u[1] + ∇u[4]) + u[1])
else
∇u, p = view(u_ops, 1:4), view(u_ops, 5)
result[1] = μ * ∇u[1] - p[1]
result[2] = μ * ∇u[2]
result[3] = μ * ∇u[3]
result[4] = μ * ∇u[4] - p[1]
result[5] = -(∇u[1] + ∇u[4])
end
return nothing
end

function multiply_r(result, input, qpinfo)
x = qpinfo.x
result .= input * x[1]
return nothing
end

end
Loading
Loading