Skip to content

Commit ec57ab3

Browse files
pjaapchmerdon
andauthored
Update example with iterative GMRES and ILU preconditioning (#47)
* Modify Example301 to demonstrate iterative solvers * Improvements in Example250 --------- Co-authored-by: Christian Merdon <[email protected]>
1 parent 503ad7a commit ec57ab3

File tree

5 files changed

+157
-52
lines changed

5 files changed

+157
-52
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@
88

99
- new example on coupled Stokes-Darcy (Example264)
1010

11+
### Added
12+
13+
- example `Example301` now also demonstrates a nonlinear problem solved by an iterative linear solver
14+
with preconditioning.
15+
1116
### Changed
1217

1318
- `solve` uses now the residual equation for the linear systems
19+
- facelift `Example250`.
1420

1521
### Fixed
1622

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ ExtendableGrids = "1.10.3"
3333
ExtendableSparse = "1.5.3"
3434
ForwardDiff = "0.10.35,1"
3535
GridVisualize = "1.8.1"
36+
IncompleteLU = "0.2.1"
3637
LinearAlgebra = "1.9"
3738
LinearSolve = "2, 3"
3839
Metis = "1.5.0"
@@ -55,6 +56,7 @@ julia = "1.9"
5556
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
5657
ExampleJuggler = "3bbe58f8-ed81-4c4e-a134-03e85fcf4a1a"
5758
ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7"
59+
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
5860
Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b"
5961
OrdinaryDiffEqRosenbrock = "43230ef6-c299-4910-a778-202eb28ce4ce"
6062
OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf"
@@ -65,4 +67,4 @@ TetGen = "c5d3f3f7-f850-59f6-8a2e-ffc6dc1317ea"
6567
Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344"
6668

6769
[targets]
68-
test = ["Aqua", "ExampleJuggler", "ExplicitImports", "Metis", "OrdinaryDiffEqRosenbrock", "OrdinaryDiffEqSDIRK", "SimplexGridFactory", "StaticArrays", "Test", "TetGen", "Triangulate"]
70+
test = ["Aqua", "ExampleJuggler", "ExplicitImports", "IncompleteLU", "Metis", "OrdinaryDiffEqRosenbrock", "OrdinaryDiffEqSDIRK", "SimplexGridFactory", "StaticArrays", "Test", "TetGen", "Triangulate"]

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ ExtendableGrids = "cfc395e8-590f-11e8-1f13-43a2532b2fa8"
88
ExtendableSparse = "95c220a8-a1cf-11e9-0c77-dbfce5f500b3"
99
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
1010
GridVisualize = "5eed8a63-0fb0-45eb-886d-8d5a387d12b8"
11+
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
1112
KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
1213
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1314
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"

examples/Example250_NSELidDrivenCavity.jl

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,74 @@ The computed solution for the default parameters looks like this:
2121
module Example250_NSELidDrivenCavity
2222

2323
using ExtendableFEM
24-
using GridVisualize
24+
using Triangulate
2525
using ExtendableGrids
26+
using SimplexGridFactory
2627
using LinearAlgebra
28+
using GridVisualize
2729
using Test #hide
2830

29-
function kernel_nonlinear!(result, u_ops, qpinfo)
30-
u, ∇u, p = view(u_ops, 1:2), view(u_ops, 3:6), view(u_ops, 7)
31+
32+
function create_cone(h)
33+
builder = SimplexGridBuilder(; Generator = Triangulate)
34+
35+
## points
36+
p1 = point!(builder, -1, 0)
37+
p2 = point!(builder, 1, 0)
38+
p3 = point!(builder, 0, -2)
39+
40+
## top face
41+
facetregion!(builder, 1)
42+
facet!(builder, p1, p2)
43+
44+
## other faces
45+
facetregion!(builder, 2)
46+
facet!(builder, p2, p3)
47+
facet!(builder, p3, p1)
48+
49+
cellregion!(builder, 1)
50+
maxvolume!(builder, h)
51+
regionpoint!(builder, 0, -0.5)
52+
53+
return simplexgrid(builder)
54+
end
55+
56+
const 𝕀 = [1 0; 0 1]
57+
58+
function NSE_kernel!(result, u_ops, qpinfo)
59+
60+
u = tensor_view(u_ops, 1, TDVector(2))
61+
v = tensor_view(result, 1, TDVector(2))
62+
∇u = tensor_view(u_ops, 3, TDMatrix(2))
63+
∇v = tensor_view(result, 3, TDMatrix(2))
64+
p = tensor_view(u_ops, 7, TDScalar())
65+
q = tensor_view(result, 7, TDScalar())
3166
μ = qpinfo.params[1]
32-
result[1] = dot(u, view(∇u, 1:2))
33-
result[2] = dot(u, view(∇u, 3:4))
34-
result[3] = μ * ∇u[1] - p[1]
35-
result[4] = μ * ∇u[2]
36-
result[5] = μ * ∇u[3]
37-
result[6] = μ * ∇u[4] - p[1]
38-
result[7] = -(∇u[1] + ∇u[4])
67+
68+
tmul!(v, ∇u, u)
69+
∇v .= μ .* ∇u .- p[1] .* 𝕀
70+
q[1] = -dot(∇u, 𝕀)
71+
3972
return nothing
4073
end
4174

42-
function boundarydata!(result, qpinfo)
75+
76+
## boundary function
77+
function u_boundary!(result, qpinfo)
4378
result[1] = 1
4479
result[2] = 0
4580
return nothing
4681
end
4782

48-
function initialgrid_cone()
49-
xgrid = ExtendableGrid{Float64, Int32}()
50-
xgrid[Coordinates] = Array{Float64, 2}([-1 0; 0 -2; 1 0]')
51-
xgrid[CellNodes] = Array{Int32, 2}([1 2 3]')
52-
xgrid[CellGeometries] = VectorOfConstants{ElementGeometries, Int}(Triangle2D, 1)
53-
xgrid[CellRegions] = ones(Int32, 1)
54-
xgrid[BFaceRegions] = Array{Int32, 1}([1, 2, 3])
55-
xgrid[BFaceNodes] = Array{Int32, 2}([1 2; 2 3; 3 1]')
56-
xgrid[BFaceGeometries] = VectorOfConstants{ElementGeometries, Int}(Edge1D, 3)
57-
xgrid[CoordinateSystem] = Cartesian2D
58-
return xgrid
59-
end
6083

61-
function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwargs...)
84+
function main(;
85+
μ_final = 0.0005, # flow parameter
86+
order = 2, # FE order of the flow field (pressure order is order-1)
87+
h = 1.0e-3, # grid cell volume
88+
nrefs = 1, # additional grid refinements
89+
Plotter = nothing,
90+
kwargs...
91+
)
6292

6393
## prepare parameter field
6494
extra_params = Array{Float64, 1}([max(μ_final, 0.05)])
@@ -70,17 +100,20 @@ function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwar
70100

71101
assign_unknown!(PD, u)
72102
assign_unknown!(PD, p)
73-
assign_operator!(PD, NonlinearOperator(kernel_nonlinear!, [id(u), grad(u), id(p)]; params = extra_params, kwargs...))
74-
assign_operator!(PD, InterpolateBoundaryData(u, boundarydata!; regions = 3))
75-
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [1, 2]))
76-
assign_operator!(PD, FixDofs(p; dofs = [1]))
103+
assign_operator!(PD, NonlinearOperator(NSE_kernel!, [id(u), grad(u), id(p)]; params = extra_params, kwargs...))
77104

105+
## boundary data
106+
assign_operator!(PD, InterpolateBoundaryData(u, u_boundary!; regions = 1))
107+
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [2]))
78108

79109
## grid
80-
xgrid = uniform_refine(initialgrid_cone(), nrefs)
110+
xgrid = uniform_refine(create_cone(h), nrefs)
81111

82112
## prepare FESpace
83-
FES = [FESpace{H1Pk{2, 2, order}}(xgrid), FESpace{H1Pk{1, 2, order - 1}}(xgrid)]
113+
FES = [
114+
FESpace{H1Pk{2, 2, order}}(xgrid),
115+
FESpace{H1Pk{1, 2, order - 1}}(xgrid),
116+
]
84117

85118
## prepare plots
86119
plt = GridVisualizer(; Plotter = Plotter, layout = (1, 2), clear = true, size = (1600, 800))
@@ -93,7 +126,16 @@ function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwar
93126
while (true)
94127
step += 1
95128
@info "Step $step : solving for μ=$(extra_params[1])"
96-
sol, SC = ExtendableFEM.solve(PD, FES, SC; return_config = true, target_residual = 1.0e-10, maxiterations = 20, kwargs...)
129+
sol, SC = ExtendableFEM.solve(
130+
PD,
131+
FES,
132+
SC;
133+
return_config = true,
134+
target_residual = 1.0e-10,
135+
maxiterations = 20,
136+
kwargs...
137+
)
138+
97139
if step == 1
98140
initialize!(PE, sol)
99141
end
@@ -116,9 +158,10 @@ function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwar
116158
end
117159

118160
generateplots = ExtendableFEM.default_generateplots(Example250_NSELidDrivenCavity, "example250.png") #hide
119-
function runtests() #hide
120-
sol, plt = main(; nrefs = 3, μ_final = 0.005) #hide
121-
@test sum(view(sol[1])) 9.501630403050289 #hide
122-
return nothing #hide
123-
end #hide
161+
function runtests() #hide
162+
sol, plt = main(; μ_final = 0.005) #hide
163+
sum(view(sol[1])) 237.24628017878518 #hide
164+
return nothing #hide
165+
end #hide
166+
124167
end # module

examples/Example301_PoissonProblem.jl

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,99 @@ parameters looks like this:
1515
1616
![](example301.png)
1717
18+
This examples uses an iterative solver with an IncompleteLU preconditioner as the default solver.
19+
It can be changed via the arguments 'method_linear' and 'precon_linear', see the runtests function
20+
for more examples.
21+
1822
=#
1923

2024
module Example301_PoissonProblem
2125

2226
using ExtendableFEM
2327
using ExtendableGrids
24-
using Test #hide
28+
using LinearSolve
29+
using IncompleteLU
30+
using LinearAlgebra
31+
using Test
32+
33+
function f!(result, qpinfo)
34+
result[1] = qpinfo.params[1] * (1.7^2 + 3.9^2) * sin(1.7 * qpinfo.x[1]) * cos(3.9 * qpinfo.x[2])
35+
return nothing
36+
end
2537

26-
function f!(fval, qpinfo)
27-
fval[1] = qpinfo.x[1] * qpinfo.x[2] * qpinfo.x[3]
38+
function u!(result, qpinfo)
39+
result[1] = sin(1.7 * qpinfo.x[1]) * cos(3.9 * qpinfo.x[2])
2840
return nothing
2941
end
3042

31-
function main(; μ = 1.0, nrefs = 3, Plotter = nothing, kwargs...)
43+
function main(;
44+
μ = 1.0,
45+
nrefs = 4,
46+
method_linear = KrylovJL_GMRES(),
47+
precon_linear = method_linear == KrylovJL_GMRES() ? IncompleteLU.ilu : nothing,
48+
Plotter = nothing,
49+
kwargs...
50+
)
3251

3352
## problem description
3453
PD = ProblemDescription()
3554
u = Unknown("u"; name = "potential")
3655
assign_unknown!(PD, u)
37-
assign_operator!(PD, BilinearOperator([grad(u)]; factor = μ, kwargs...))
38-
assign_operator!(PD, LinearOperator(f!, [id(u)]; kwargs...))
39-
assign_operator!(PD, HomogeneousBoundaryData(u; regions = 1:4))
56+
assign_operator!(PD, BilinearOperator([grad(u)]; factor = μ))
57+
assign_operator!(PD, LinearOperator(f!, [id(u)]; params = [μ]))
58+
assign_operator!(PD, InterpolateBoundaryData(u, u!; regions = 1:6))
4059

4160
## discretize
4261
xgrid = uniform_refine(grid_unitcube(Tetrahedron3D), nrefs)
4362
FES = FESpace{H1P2{1, 3}}(xgrid)
4463

4564
## solve
46-
sol = solve(PD, FES; kwargs...)
65+
sol = solve(PD, FES; method_linear, precon_linear, kwargs...)
66+
67+
## compute error
68+
function exact_error!(result, u, qpinfo)
69+
u!(result, qpinfo)
70+
result .-= u
71+
result .= result .^ 2
72+
return nothing
73+
end
74+
ErrorIntegratorExact = ItemIntegrator(exact_error!, [id(u)]; quadorder = 8)
75+
76+
## calculate error
77+
error = evaluate(ErrorIntegratorExact, sol)
78+
L2error = sqrt(sum(view(error, 1, :)))
79+
@info "L2 error = $L2error"
4780

4881
## plot
4982
plt = plot([id(u)], sol; Plotter = Plotter)
5083

51-
return sol, plt
84+
return L2error, plt
5285
end
5386

54-
generateplots = ExtendableFEM.default_generateplots(Example301_PoissonProblem, "example301.png") #hide
55-
function runtests() #hide
56-
sol, plt = main() #hide
57-
@test sum(sol.entries) 21.874305144549524 #hide
58-
return nothing #hide
59-
end #hide
87+
generateplots = ExtendableFEM.default_generateplots(Example301_PoissonProblem, "example301.png")
88+
function runtests()
89+
expected_error = 8.56e-5
90+
91+
## test direct solver
92+
L2error, plt = main(; nrefs = 4)
93+
@test L2error <= expected_error
94+
95+
## test iterative solver with IncompleteLU (fastest)
96+
method_linear = KrylovJL_GMRES()
97+
precon_linear = IncompleteLU.ilu
98+
L2error, plt = main(; method_linear, precon_linear, nrefs = 4)
99+
@test L2error <= expected_error
100+
101+
## test other iterative solvers
102+
method_linear = KrylovJL_GMRES(precs = (A, p) -> (Diagonal(A), I))
103+
precon_linear = nothing
104+
L2error, plt = main(; method_linear, precon_linear, nrefs = 4)
105+
@test L2error <= expected_error
106+
107+
## also working:
108+
## method_linear = KrylovJL_GMRES(precs = (A, p) -> (AMGCLWrap.AMGPrecon(ruge_stuben(A)), I))
109+
## method_linear = KrylovJL_GMRES(precs = (A, p) -> (AlgebraicMultigrid.aspreconditioner(ruge_stuben(A)), I))
110+
111+
return nothing
112+
end
60113
end # module

0 commit comments

Comments
 (0)