Skip to content

Commit e11c430

Browse files
committed
Add NSE example with iterative GMRES and ILU preconditioning
1 parent 8ace2e4 commit e11c430

File tree

6 files changed

+146
-1
lines changed

6 files changed

+146
-1
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+
- new example `Example251_NSEWithIterativeSolver` to demonstrate 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"

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ function make_all(; with_examples::Bool = true, modules = :all, run_examples::Bo
3636
"Example240_SVRTEnrichment.jl",
3737
"Example245_NSEFlowAroundCylinder.jl",
3838
"Example250_NSELidDrivenCavity.jl",
39+
"Example251_NSEWithIterativeSolver.jl",
3940
"Example252_NSEPlanarLatticeFlow.jl",
4041
"Example260_AxisymmetricNavierStokesProblem.jl",
4142
"Example265_FlowTransport.jl",
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#=
2+
3+
# 251 : Navier--Stokes Lid-driven cavity with iterative solver
4+
([source code](@__SOURCE_URL__))
5+
6+
This example is a simpler version of Example250 and uses an iterative solver GMRES with ILU preconditioner.
7+
8+
![](example251.png)
9+
=#
10+
11+
module Example251_NSEWithIterativeSolver
12+
13+
using ExtendableFEM
14+
#using ExtendableFEMBase
15+
using Triangulate
16+
using ExtendableGrids
17+
using SimplexGridFactory
18+
using LinearAlgebra
19+
using GridVisualize
20+
using LinearSolve
21+
using IncompleteLU
22+
using Test #hide
23+
24+
25+
function create_cone(h = 1.0e-2)
26+
builder = SimplexGridBuilder(; Generator = Triangulate)
27+
28+
## points
29+
p1 = point!(builder, -1, 0)
30+
p2 = point!(builder, 1, 0)
31+
p3 = point!(builder, 0, -2)
32+
33+
## top face
34+
facetregion!(builder, 1)
35+
facet!(builder, p1, p2)
36+
37+
## other faces
38+
facetregion!(builder, 2)
39+
facet!(builder, p2, p3)
40+
facet!(builder, p3, p1)
41+
42+
cellregion!(builder, 1)
43+
maxvolume!(builder, h)
44+
regionpoint!(builder, 0, -0.5)
45+
46+
return simplexgrid(builder)
47+
end
48+
49+
const 𝕀 = [1 0; 0 1]
50+
51+
function NSE_kernel!(result, u_ops, qpinfo)
52+
53+
u = tensor_view(u_ops, 1, TDVector(2))
54+
v = tensor_view(result, 1, TDVector(2))
55+
∇u = tensor_view(u_ops, 3, TDMatrix(2))
56+
∇v = tensor_view(result, 3, TDMatrix(2))
57+
p = tensor_view(u_ops, 7, TDScalar())
58+
q = tensor_view(result, 7, TDScalar())
59+
μ = qpinfo.params[1]
60+
61+
tmul!(v, ∇u, u)
62+
∇v .= μ .* ∇u .- p[1] .* 𝕀
63+
q[1] = -dot(∇u, 𝕀)
64+
65+
return nothing
66+
end
67+
68+
## boundary function
69+
function u_boundary!(result, qpinfo)
70+
result[1] = 1
71+
result[2] = 0
72+
return nothing
73+
end
74+
75+
function main(;
76+
params = [0.05], # viscosity
77+
order = 2, # FE order of the flow field (pressure order is order-1)
78+
h = 1.0e-3, # grid cell volume
79+
Plotter = nothing,
80+
)
81+
82+
## create the grid
83+
conegrid = create_cone(h)
84+
85+
## problem description
86+
PD = ProblemDescription("NSE")
87+
u = Unknown("u"; name = "velocity")
88+
p = Unknown("p"; name = "pressure")
89+
assign_unknown!(PD, u)
90+
assign_unknown!(PD, p)
91+
92+
assign_operator!(PD, NonlinearOperator(NSE_kernel!, [id(u), grad(u), id(p)]; params = params, parallel = true))
93+
94+
# boundary values
95+
assign_operator!(PD, HomogeneousBoundaryData(u; value = 1, mask = [1, 0], regions = [1]))
96+
assign_operator!(PD, HomogeneousBoundaryData(u; value = 0, mask = [0, 1], regions = [1]))
97+
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [2]))
98+
99+
## Taylor--Hood FE space
100+
FES = [
101+
FESpace{H1Pk{2, 2, order}}(conegrid),
102+
FESpace{H1Pk{1, 2, order - 1}}(conegrid),
103+
]
104+
105+
## prepare an initial solution matching the boundary data
106+
feVector = FEVector(FES; tags = PD.unknowns)
107+
interpolate!(feVector[u], ON_BFACES, u_boundary!; regions = [1])
108+
109+
## solve with initial solution
110+
sol = ExtendableFEM.solve(
111+
PD,
112+
FES;
113+
init = feVector,
114+
method_linear = KrylovJL_GMRES(verbose = 1),
115+
precon_linear = IncompleteLU.ilu, # preconditioner!
116+
maxiterations = 10,
117+
)
118+
119+
## plot streamlines
120+
PE = PointEvaluator([id(1)])
121+
initialize!(PE, sol)
122+
plt = GridVisualizer(; Plotter, layout = (1, 1), clear = true, size = (800, 800))
123+
GridVisualize.streamplot!(plt[1, 1], conegrid, eval_func_bary(PE), rasterpoints = 50, density = 2, title = "streamlines")
124+
125+
return sol, plt
126+
end
127+
128+
generateplots = ExtendableFEM.default_generateplots(Example251_NSEWithIterativeSolver, "example251.png") #hide
129+
function runtests() #hide
130+
sol, plt = main() #hide
131+
@test sum(view(sol[1])) 86.3125486317652 #hide
132+
return nothing #hide
133+
end #hide
134+
135+
end # module

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ function run_examples()
4444
"Example240_SVRTEnrichment.jl",
4545
"Example245_NSEFlowAroundCylinder.jl",
4646
"Example250_NSELidDrivenCavity.jl",
47+
"Example251_NSEWithIterativeSolver.jl",
4748
"Example252_NSEPlanarLatticeFlow.jl",
4849
"Example260_AxisymmetricNavierStokesProblem.jl",
4950
"Example265_FlowTransport.jl",

0 commit comments

Comments
 (0)