Skip to content

Commit 7281df1

Browse files
committed
Modify NSE example to include iterative GMRES and ILU preconditioning
1 parent 8ace2e4 commit 7281df1

File tree

4 files changed

+111
-26
lines changed

4 files changed

+111
-26
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
## v1.0.0 April 7, 2025
66

7+
### Added
8+
9+
- example `Example250` now also demonstrates a nonlinear problem solved by an iterative linear solver
10+
with preconditioning and an initial solution.
11+
712
### Changed
813

914
- `solve` uses now the residual equation for the linear systems.

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: 102 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,62 @@ 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
29+
using LinearSolve
30+
using IncompleteLU
2731
using Test #hide
2832

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)
33+
34+
function create_cone(h)
35+
builder = SimplexGridBuilder(; Generator = Triangulate)
36+
37+
## points
38+
p1 = point!(builder, -1, 0)
39+
p2 = point!(builder, 1, 0)
40+
p3 = point!(builder, 0, -2)
41+
42+
## top face
43+
facetregion!(builder, 1)
44+
facet!(builder, p1, p2)
45+
46+
## other faces
47+
facetregion!(builder, 2)
48+
facet!(builder, p2, p3)
49+
facet!(builder, p3, p1)
50+
51+
cellregion!(builder, 1)
52+
maxvolume!(builder, h)
53+
regionpoint!(builder, 0, -0.5)
54+
55+
return simplexgrid(builder)
56+
end
57+
58+
const 𝕀 = [1 0; 0 1]
59+
60+
function NSE_kernel!(result, u_ops, qpinfo)
61+
62+
u = tensor_view(u_ops, 1, TDVector(2))
63+
v = tensor_view(result, 1, TDVector(2))
64+
∇u = tensor_view(u_ops, 3, TDMatrix(2))
65+
∇v = tensor_view(result, 3, TDMatrix(2))
66+
p = tensor_view(u_ops, 7, TDScalar())
67+
q = tensor_view(result, 7, TDScalar())
3168
μ = 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])
69+
70+
tmul!(v, ∇u, u)
71+
∇v .= μ .* ∇u .- p[1] .* 𝕀
72+
q[1] = -dot(∇u, 𝕀)
73+
3974
return nothing
4075
end
4176

42-
function boundarydata!(result, qpinfo)
77+
78+
## boundary function
79+
function u_boundary!(result, qpinfo)
4380
result[1] = 1
4481
result[2] = 0
4582
return nothing
@@ -58,7 +95,16 @@ function initialgrid_cone()
5895
return xgrid
5996
end
6097

61-
function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwargs...)
98+
function main(;
99+
μ_final = 0.0005, # flow parameter
100+
order = 2, # FE order of the flow field (pressure order is order-1)
101+
h = 1.0e-3, # grid cell volume
102+
nrefs = 1, # additional grid refinements
103+
method_linear = nothing, # linear solver ("nothing" invokes the default solver)
104+
precon_linear = nothing, # preconditioner
105+
Plotter = nothing,
106+
kwargs...
107+
)
62108

63109
## prepare parameter field
64110
extra_params = Array{Float64, 1}([max(μ_final, 0.05)])
@@ -70,30 +116,52 @@ function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwar
70116

71117
assign_unknown!(PD, u)
72118
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]))
119+
assign_operator!(PD, NonlinearOperator(NSE_kernel!, [id(u), grad(u), id(p)]; params = extra_params, kwargs...))
77120

121+
## boundary data
122+
assign_operator!(PD, InterpolateBoundaryData(u, u_boundary!; regions = 1))
123+
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [2]))
78124

79125
## grid
80-
xgrid = uniform_refine(initialgrid_cone(), nrefs)
126+
xgrid = uniform_refine(create_cone(h), nrefs)
81127

82128
## prepare FESpace
83-
FES = [FESpace{H1Pk{2, 2, order}}(xgrid), FESpace{H1Pk{1, 2, order - 1}}(xgrid)]
129+
FES = [
130+
FESpace{H1Pk{2, 2, order}}(xgrid),
131+
FESpace{H1Pk{1, 2, order - 1}}(xgrid),
132+
]
84133

85134
## prepare plots
86135
plt = GridVisualizer(; Plotter = Plotter, layout = (1, 2), clear = true, size = (1600, 800))
87136

137+
138+
## prepare an initial solution matching the boundary data
139+
sol = FEVector(FES; tags = PD.unknowns)
140+
interpolate!(sol[u], ON_BFACES, u_boundary!; regions = [1])
141+
142+
88143
## solve by μ embedding
89144
step = 0
90-
sol = nothing
91145
SC = nothing
92146
PE = PointEvaluator([id(1)])
93147
while (true)
94148
step += 1
95149
@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...)
150+
sol, SC = ExtendableFEM.solve(
151+
PD,
152+
FES,
153+
SC;
154+
init = sol,
155+
method_linear,
156+
# use new preconditioner API: https://docs.sciml.ai/LinearSolve/stable/basics/Preconditioners/#Specifying-Preconditioners
157+
# this does currently now work with ILU, see https://github.com/WIAS-PDELib/ExtendableFEM.jl/pull/47#issuecomment-2796849931
158+
precon_linear,
159+
return_config = true,
160+
target_residual = 1.0e-10,
161+
maxiterations = 20,
162+
kwargs...
163+
)
164+
97165
if step == 1
98166
initialize!(PE, sol)
99167
end
@@ -116,9 +184,18 @@ function main(; μ_final = 0.0005, order = 2, nrefs = 5, Plotter = nothing, kwar
116184
end
117185

118186
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
187+
function runtests() #hide
188+
sol, plt = main(; μ_final = 0.005) #hide
189+
sum(view(sol[1])) 237.24628017878518 #hide
190+
191+
method_linear = KrylovJL_GMRES() #hide
192+
precon_linear = IncompleteLU.ilu #hide
193+
194+
sol, plt = main(; μ_final = 0.005, method_linear, precon_linear) #hide
195+
@test sum(view(sol[1])) 237.24628017878518 #hide
196+
197+
return nothing #hide
198+
end #hide
199+
200+
124201
end # module

0 commit comments

Comments
 (0)