Skip to content

Commit

Permalink
fixed offsets in BilinearOperator, new Example330, some other improve…
Browse files Browse the repository at this point in the history
…ments
  • Loading branch information
chmerdon committed Jul 16, 2024
1 parent 328e1ad commit 229eccf
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 48 deletions.
55 changes: 15 additions & 40 deletions examples/Example203_PoissonProblemDG.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module Example203_PoissonProblemDG

using ExtendableFEM
using ExtendableGrids
using LinearAlgebra
using Symbolics
using Test #hide

Expand All @@ -32,21 +33,16 @@ function prepare_data(; μ = 1)

## exact solution
u = x^3 - 3 * x * y^2

## gradient
∇u = Symbolics.gradient(u, [x, y])

## Laplacian
Δu = Symbolics.gradient(∇u[1], [x]) + Symbolics.gradient(∇u[2], [y])

## right-hand side
Δu = Symbolics.gradient(∇u[1], [x]) + Symbolics.gradient(∇u[2], [y])
f = -μ * Δu[1]

## build functions
u_eval = build_function(u, x, y, expression = Val{false})
∇u_eval = build_function(∇u, x, y, expression = Val{false})
f_eval = build_function(f, x, y, expression = Val{false})

return f_eval, u_eval, ∇u_eval[2]
end

Expand All @@ -59,7 +55,7 @@ function main(; dg = true, μ = 1.0, τ = 10.0, nrefs = 4, order = 2, bonus_quad
exact_∇u!(result, qpinfo) = (∇u_eval(result, qpinfo.x[1], qpinfo.x[2]))

## problem description
PD = ProblemDescription()
PD = ProblemDescription("Poisson problem")
u = Unknown("u"; name = "potential")
assign_unknown!(PD, u)
assign_operator!(PD, BilinearOperator([grad(u)]; factor = μ, kwargs...))
Expand All @@ -71,11 +67,10 @@ function main(; dg = true, μ = 1.0, τ = 10.0, nrefs = 4, order = 2, bonus_quad
FES = FESpace{order == 0 ? L2P0{1} : H1Pk{1, 2, order}}(xgrid; broken = dg)

## add DG terms
assign_operator!(PD, BilinearOperatorDG(dg_kernel(xgrid), [jump(id(u))], [average(grad(u))]; entities = ON_FACES, factor = -μ, kwargs...))
assign_operator!(PD, BilinearOperatorDG(dg_kernelT(xgrid), [average(grad(u))], [jump(id(u))]; entities = ON_FACES, factor = -μ, kwargs...))
assign_operator!(PD, LinearOperatorDG(dg_kernel_bnd(xgrid, exact_u!), [average(grad(u))]; entities = ON_BFACES, factor = -μ, bonus_quadorder = bonus_quadorder, kwargs...))
assign_operator!(PD, BilinearOperatorDG(dg_kernel2(xgrid), [jump(id(u))]; entities = ON_FACES, factor = μ*τ, kwargs...))
assign_operator!(PD, LinearOperatorDG(dg_kernel2_bnd(xgrid, exact_u!), [id(u)]; entities = ON_BFACES, regions = 1:4, factor = μ*τ, bonus_quadorder = bonus_quadorder, kwargs...))
assign_operator!(PD, BilinearOperatorDG(dg_kernel, [jump(id(u))], [average(grad(u))]; entities = ON_FACES, factor = -μ, transposed_copy = 1, kwargs...))
assign_operator!(PD, LinearOperatorDG(dg_kernel_bnd(exact_u!), [average(grad(u))]; entities = ON_BFACES, factor = -μ, bonus_quadorder = bonus_quadorder, kwargs...))
assign_operator!(PD, BilinearOperatorDG(dg_kernel2, [jump(id(u))]; entities = ON_FACES, factor = μ*τ, kwargs...))
assign_operator!(PD, LinearOperatorDG(dg_kernel2_bnd(exact_u!), [id(u)]; entities = ON_BFACES, regions = 1:4, factor = μ*τ, bonus_quadorder = bonus_quadorder, kwargs...))

## solve
sol = solve(PD, FES; kwargs...)
Expand Down Expand Up @@ -108,39 +103,19 @@ function main(; dg = true, μ = 1.0, τ = 10.0, nrefs = 4, order = 2, bonus_quad
return L2error, plt
end

function dg_kernel(xgrid)
facenormals = xgrid[FaceNormals]
facecells = xgrid[FaceCells]
facevolumes = xgrid[FaceVolumes]
function closure(result, input, qpinfo)
result[1] = (input[1] * facenormals[1, qpinfo.item] + input[2] * facenormals[2, qpinfo.item])
end
function dg_kernel(result, input, qpinfo)
result[1] = dot(input, qpinfo.normal)
end

function dg_kernelT(xgrid)
facenormals = xgrid[FaceNormals]
facecells = xgrid[FaceCells]
facevolumes = xgrid[FaceVolumes]
function closure(result, input, qpinfo)
result[1:2] = input[1] .* view(facenormals, :, qpinfo.item)
end
end

function dg_kernel_bnd(xgrid, uDb! = nothing)
facenormals = xgrid[FaceNormals]
facecells = xgrid[FaceCells]
facevolumes = xgrid[FaceVolumes]
function dg_kernel_bnd(uDb! = nothing)
function closure(result, qpinfo)
uDb!(result, qpinfo)
result[1:2] = result[1] .* view(facenormals, :, qpinfo.item)
result[1:2] = result[1] .* qpinfo.normal
end
end
function dg_kernel2(xgrid)
function closure(result, input, qpinfo)
result .= input / qpinfo.volume
end
function dg_kernel2(result, input, qpinfo)
result .= input / qpinfo.volume
end
function dg_kernel2_bnd(xgrid, uDb! = nothing)
function dg_kernel2_bnd(uDb! = nothing)
function closure(result, qpinfo)
uDb!(result, qpinfo)
result /= qpinfo.volume
Expand All @@ -152,4 +127,4 @@ function runtests() #hide
L2error, ~ = main(; μ = 0.25, nrefs = 2, order = 2) #hide
@test L2error 0.00020400470505497443 #hide
end #hide
end # module
end # module
6 changes: 2 additions & 4 deletions examples/Example207_AdvectionUpwindDG.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,20 @@ function advection_kernel!(result, input, qpinfo)
end

function outflow_kernel!(xgrid)
facenormals = xgrid[FaceNormals]
beta = zeros(Float64, 2)
function closure(result, input, qpinfo)
face = qpinfo.item
β!(beta, qpinfo)
result[1] = dot(beta, view(facenormals, :, face)) * input[1]
result[1] = dot(beta, qpinfo.normal) * input[1]
end
end

function upwind_kernel!(xgrid)
facenormals = xgrid[FaceNormals]
beta = zeros(Float64, 2)
function closure(result, input, qpinfo)
face = qpinfo.item
β!(beta, qpinfo)
result[1] = dot(beta, view(facenormals, :, face))
result[1] = dot(beta, qpinfo.normal)
if result[1] > 0 ## wind blows this -> other
result[1] *= input[1] # upwind value = this
else ## wind blows this <- other
Expand Down
148 changes: 148 additions & 0 deletions examples/Example330_HyperElasticity.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#=
# 330 : Hyperelasticity
([source code](@__SOURCE_URL__))
This examples computes the solution of a nonlinear elasticity problem for hyperelastic media
via minimisation of the (neo-Hookian) energy functional
```math
\begin{aligned}
W(u, F(\mathbf{u})) := \int_\Omega \frac{\mu}{2} (F \cdot F - 3 - 2\log(\mathrm{det}(F))) + \frac{\lambda}{2} \log(\mathrm{det}(F))^2 - B \cdot \mathbf{u} \textit{dx} - \int_{\partial \Omega} T \cdot \mathbf{u} \textit{ds}
\end{aligned}
```
where ``F(\mathbf{u}) := I + \nabla u`` is the deformation gradient and ``\mu`` and ``\lambda`` are the Lame parameters.
The energy is differentiated twice by automatic differentiation to setup a Newton scheme for a
Lagrangian finite element approximation of ``\mathbf{u}``.
The deformed unit cube and the displacement for the default parameters and inhomogeneous boundary conditions as defined in the code
looks like this:
![](example330.png)
=#

module Example330_HyperElasticity

using ExtendableFEM, ExtendableFEMBase
using LinearSolve, LinearAlgebra
using DiffResults, ForwardDiff
using SimplexGridFactory
using TetGen


## inhomogeneous boundary conditions for bregion 1
function bnd_1!(result, qpinfo)
x, y, z = qpinfo.x[1], qpinfo.x[2], qpinfo.x[3]
angle = pi/3
result[1] = 0.0
result[2] = (0.5+(y-0.5)*cos(angle) - (z-0.5)*sin(angle)-y)/2.0
result[3] = (0.5+(y-0.5)*sin(angle) + (z-0.5)*cos(angle)-x)/2.0
end

## kernel for body and traction forces
function apply_force!(result, qpinfo)
result .= qpinfo.params[1]
end

## energy functional (only nonlinear part, without exterior forces)
function W!(result, F, qpinfo)
F[1] += 1
F[5] += 1
F[9] += 1
μ, λ = qpinfo.params[1], qpinfo.params[2]
detF = -(F[3]*(F[5]*F[7] - F[4]*F[8]) + F[2]*((-F[6])*F[7] + F[4]*F[9]) + F[1]*(F[6]*F[8] - F[5]*F[9]))
result[1] = μ/2 * (dot(F,F) - 3 - 2*log(detF)) + λ/2 * (log(detF))^2
end

## derivative of energy functional (by ForwardDiff)
function nonlinkernel_DW!()
Dresult = nothing
cfg = nothing
result_dummy = nothing
W(qpinfo) = (a,b) -> W!(a,b,qpinfo)

function closure(result, input, qpinfo)
if Dresult === nothing
## first initialization of DResult when type of input = F is known
result_dummy = zeros(eltype(input), 1)
Dresult = DiffResults.JacobianResult(result_dummy, input)
cfg = ForwardDiff.JacobianConfig(W(qpinfo), result_dummy, input, ForwardDiff.Chunk{length(input)}())
end
Dresult = ForwardDiff.vector_mode_jacobian!(Dresult, W(qpinfo), result_dummy, input, cfg)
copyto!(result, DiffResults.jacobian(Dresult))
return nothing
end
end


function main(;
maxvolume = 0.001, # parameter for grid generator
E = 10, # Young modulus
ν = 0.3, # Poisson ratio
order = 3, # finite element order
B = [0,-0.5,0], # body force
T = [0.1,0,0], # traction force
Plotter = nothing,
kwargs...)

## compute Lame parameters
μ = E / (2 * (1 + ν))
λ = E * ν / ((1+ν)*(1 - 2 * ν))

## define unknowns
u = Unknown("u"; name = "displacement")

## define problem
PD = ProblemDescription("Hyperelasticity problem")
assign_unknown!(PD, u)
assign_operator!(PD, NonlinearOperator(nonlinkernel_DW!(), [grad(u)]; sparse_jacobians = false, params = [μ, λ]))
assign_operator!(PD, LinearOperator(apply_force!, [id(u)]; params = [B]))
assign_operator!(PD, LinearOperator(apply_force!, [id(u)]; entities = ON_BFACES, store = true, regions = 1:6, params = [T]))
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [2]))
assign_operator!(PD, InterpolateBoundaryData(u, bnd_1!; regions = [1], quadorder = 10))

## grid
xgrid = tetrahedralization_of_cube(maxvolume = maxvolume)

## solve
FES = FESpace{H1P1{3}}(xgrid)
sol = solve(PD, FES; maxiterations = 20)

## displace mesh and plot final result
displace_mesh!(xgrid, sol[u])
plt = plot([grid(u), id(u)], sol; Plotter = Plotter, do_vector_plots = false)

return sol, plt
end

generateplots = default_generateplots(Example330_HyperElasticity, "example330.png") #hide

function tetrahedralization_of_cube(; maxvolume = 0.1)
builder = SimplexGridBuilder(; Generator = TetGen)

p1 = point!(builder, 0, 0, 0)
p2 = point!(builder, 1, 0, 0)
p3 = point!(builder, 1, 1, 0)
p4 = point!(builder, 0, 1, 0)
p5 = point!(builder, 0, 0, 1)
p6 = point!(builder, 1, 0, 1)
p7 = point!(builder, 1, 1, 1)
p8 = point!(builder, 0, 1, 1)

facetregion!(builder, 1)
facet!(builder, p1, p2, p3, p4)
facetregion!(builder, 2)
facet!(builder, p5, p6, p7, p8)
facetregion!(builder, 3)
facet!(builder, p1, p2, p6, p5)
facetregion!(builder, 4)
facet!(builder, p2, p3, p7, p6)
facetregion!(builder, 5)
facet!(builder, p3, p4, p8, p7)
facetregion!(builder, 6)
facet!(builder, p4, p1, p5, p8)

simplexgrid(builder; maxvolume = maxvolume)
end

end # module
4 changes: 2 additions & 2 deletions src/common_operators/bilinear_operator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ function build_assembler!(A, O::BilinearOperator{Tv}, FE_test, FE_ansatz, FE_arg
append!(op_offsets_ansatz, cumsum(op_lengths_ansatz))
append!(op_offsets_args, cumsum(op_lengths_args))
offsets_test = [FE_test[j].offset for j in 1:length(FES_test)]
offsets_ansatz = [FE_ansatz[j].offset for j in 1:length(FES_ansatz)]
offsets_ansatz = [FE_ansatz[j].offsetY for j in 1:length(FES_ansatz)]

## prepare sparsity pattern
use_sparsity_pattern = O.parameters[:use_sparsity_pattern]
Expand Down Expand Up @@ -707,7 +707,7 @@ function build_assembler!(A, O::BilinearOperator{Tv}, FE_test, FE_ansatz; time =
append!(op_offsets_test, cumsum(op_lengths_test))
append!(op_offsets_ansatz, cumsum(op_lengths_ansatz))
offsets_test = [FE_test[j].offset for j in 1:length(FES_test)]
offsets_ansatz = [FE_ansatz[j].offset for j in 1:length(FES_ansatz)]
offsets_ansatz = [FE_ansatz[j].offsetY for j in 1:length(FES_ansatz)]

## prepare sparsity pattern
use_sparsity_pattern = O.parameters[:use_sparsity_pattern]
Expand Down
4 changes: 2 additions & 2 deletions src/common_operators/bilinear_operator_dg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ function build_assembler!(A, O::BilinearOperatorDG{Tv}, FE_test, FE_ansatz, FE_a
append!(op_offsets_ansatz, cumsum(op_lengths_ansatz))
append!(op_offsets_args, cumsum(op_lengths_args))
offsets_test = [FE_test[j].offset for j in 1:length(FES_test)]
offsets_ansatz = [FE_ansatz[j].offset for j in 1:length(FES_ansatz)]
offsets_ansatz = [FE_ansatz[j].offsetY for j in 1:length(FES_ansatz)]
offsets_args = [FE_args[j].offset for j in 1:length(FES_args)]

## prepare sparsity pattern
Expand Down Expand Up @@ -688,7 +688,7 @@ function build_assembler!(A, O::BilinearOperatorDG{Tv}, FE_test, FE_ansatz; time
append!(op_offsets_test, cumsum(op_lengths_test))
append!(op_offsets_ansatz, cumsum(op_lengths_ansatz))
offsets_test = [FE_test[j].offset for j in 1:length(FES_test)]
offsets_ansatz = [FE_ansatz[j].offset for j in 1:length(FES_ansatz)]
offsets_ansatz = [FE_ansatz[j].offsetY for j in 1:length(FES_ansatz)]

## prepare sparsity pattern
use_sparsity_pattern = O.parameters[:use_sparsity_pattern]
Expand Down

0 comments on commit 229eccf

Please sign in to comment.