@@ -21,25 +21,62 @@ The computed solution for the default parameters looks like this:
2121module Example250_NSELidDrivenCavity
2222
2323using ExtendableFEM
24- using GridVisualize
24+ using Triangulate
2525using ExtendableGrids
26+ using SimplexGridFactory
2627using LinearAlgebra
28+ using GridVisualize
29+ using LinearSolve
30+ using IncompleteLU
2731using 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
4075end
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
5996end
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
116184end
117185
118186generateplots = 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+
124201end # module
0 commit comments