RasmahRasmah

Stokes flow (u + p)

Overview

Creeping (Stokes) flow of a Newtonian fluid. StokesFlow() couples the velocity :u and pressure :p with Taylor–Hood (P2/P1) elements by default; the fluid supplies the dynamic viscosity μ.

using Rasmah

# 2D channel [0,1]×[0,1]; no-slip on the y walls, pressure-driven inlet/outlet
function channel(nx, ny)
    nv = (nx + 1) * (ny + 1)
    verts = Matrix{Float64}(undef, 3, nv)
    for j in 0:ny, i in 0:nx
        idx = i + j * (nx + 1) + 1
        verts[1, idx] = i / nx
        verts[2, idx] = j / ny
    end
    faces = Matrix{Int}(undef, 3, 2nx * ny)
    k = 0
    for j in 0:(ny - 1), i in 0:(nx - 1)
        a = i + j * (nx + 1) + 1; b = a + 1; c = a + nx + 1; d = c + 1
        k += 1; faces[:, k] = [a, b, c]
        k += 1; faces[:, k] = [b, d, c]
    end
    TriangleMesh(verts, faces)
end

m = channel(8, 8)
U = FESpace(m, ReferenceFE(2, 2); valuetype = VectorValue{2})
P = FESpace(m, ReferenceFE(2, 1))

# no-slip on y ∈ {0,1}: select the P2 wall nodes by bounding box
ufixed = vcat(dofs(U, BoundingBox([0.0, 0.0], [1.0, 0.0])),
              dofs(U, BoundingBox([0.0, 1.0], [1.0, 1.0])))

# pressure: p = 1 at inlet (x = 0), p = 0 at outlet (x = 1)
inlet  = dofs(P, BoundingBox([0.0, 0.0], [0.0, 1.0]))
outlet = dofs(P, BoundingBox([1.0, 0.0], [1.0, 1.0]))
pfixed = vcat(inlet, outlet)
pg     = vcat(fill(1.0, length(inlet)), fill(0.0, length(outlet)))

res = solve(StokesFlow(), m, water;
            bc = BoundaryConditions(FixedVelocity(ufixed), FixedPressure(pfixed; value = pg)))
println("max |u| = ", round(maximum(abs, res.u); digits = 3),
        ", p range = ", round(minimum(res.p); digits = 3), " … ",
        round(maximum(res.p); digits = 3))
max |u| = 19.883 m/s, p range = -0.488 Pa … 1.0 Pa

Visualize the pressure field on the channel mesh:

vtk(m; field = res.p, fieldname = "pressure")

Notes

  • The saddle system [A Bᵀ; B 0] is solved with LU by default; for preconditioned iteration use method = :gmres with NativeLinearAlgebra.amg.