Skip to content

Commit a8894e0

Browse files
committed
Users can change the convective scheme through the keyword λ. Added central differences (cds) too.
1 parent d34773d commit a8894e0

File tree

3 files changed

+28
-25
lines changed

3 files changed

+28
-25
lines changed

src/Flow.jl

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
@inline (a,I::CartesianIndex{d},f::AbstractArray{T,d}) where {T,d} = @inbounds f[I]-f[I-δ(a,I)]
22
@inline (a,I::CartesianIndex{m},u::AbstractArray{T,n}) where {T,n,m} = @inbounds u[I+δ(a,I),a]-u[I,a]
3-
@inline ϕ(a,I,f) = @inbounds (f[I]+f[I-δ(a,I)])*0.5
3+
@inline ϕ(a,I,f) = @inbounds (f[I]+f[I-δ(a,I)])/2
44
@fastmath quick(u,c,d) = median((5c+2d-u)/6,c,median(10c-9u,c,d))
55
@fastmath vanLeer(u,c,d) = (cmin(u,d) || cmax(u,d)) ? c : c+(d-c)*(c-u)/(d-u)
6+
@fastmath cds(u,c,d) = (c+d)/2
67
@inline ϕu(a,I,f,u,λ=quick) = @inbounds u>0 ? u*λ(f[I-2δ(a,I)],f[I-δ(a,I)],f[I]) : u*λ(f[I+δ(a,I)],f[I],f[I-δ(a,I)])
78
@inline ϕuP(a,Ip,I,f,u,λ=quick) = @inbounds u>0 ? u*λ(f[Ip],f[I-δ(a,I)],f[I]) : u*λ(f[I+δ(a,I)],f[I],f[I-δ(a,I)])
89
@inline ϕuL(a,I,f,u,λ=quick) = @inbounds u>0 ? u*ϕ(a,I,f) : u*λ(f[I+δ(a,I)],f[I],f[I-δ(a,I)])
@@ -33,31 +34,31 @@ function median(a,b,c)
3334
return a
3435
end
3536

36-
function conv_diff!(r,u,Φ;ν=0.1,perdir=())
37+
function conv_diff!(r,u,Φ;ν=0.1,λ=quick,perdir=())
3738
r .= 0.
3839
N,n = size_u(u)
3940
for i 1:n, j 1:n
4041
# if it is periodic direction
4142
tagper = (j in perdir)
4243
# treatment for bottom boundary with BCs
43-
lowerBoundary!(r,u,Φ,ν,i,j,N,Val{tagper}())
44+
lowerBoundary!(r,u,Φ,ν,i,j,N,λ,Val{tagper}())
4445
# inner cells
45-
@loop (Φ[I] = ϕu(j,CI(I,i),u,ϕ(i,CI(I,j),u)) - ν*(j,CI(I,i),u);
46+
@loop (Φ[I] = ϕu(j,CI(I,i),u,ϕ(i,CI(I,j),u)) - ν*(j,CI(I,i),u);
4647
r[I,i] += Φ[I]) over I inside_u(N,j)
4748
@loop r[I-δ(j,I),i] -= Φ[I] over I inside_u(N,j)
4849
# treatment for upper boundary with BCs
49-
upperBoundary!(r,u,Φ,ν,i,j,N,Val{tagper}())
50+
upperBoundary!(r,u,Φ,ν,i,j,N,λ,Val{tagper}())
5051
end
5152
end
5253

5354
# Neumann BC Building block
54-
lowerBoundary!(r,u,Φ,ν,i,j,N,::Val{false}) = @loop r[I,i] += ϕuL(j,CI(I,i),u,ϕ(i,CI(I,j),u)) - ν*(j,CI(I,i),u) over I slice(N,2,j,2)
55-
upperBoundary!(r,u,Φ,ν,i,j,N,::Val{false}) = @loop r[I-δ(j,I),i] += -ϕuR(j,CI(I,i),u,ϕ(i,CI(I,j),u)) + ν*(j,CI(I,i),u) over I slice(N,N[j],j,2)
55+
lowerBoundary!(r,u,Φ,ν,i,j,N,λ,::Val{false}) = @loop r[I,i] += ϕuL(j,CI(I,i),u,ϕ(i,CI(I,j),u)) - ν*(j,CI(I,i),u) over I slice(N,2,j,2)
56+
upperBoundary!(r,u,Φ,ν,i,j,N,λ,::Val{false}) = @loop r[I-δ(j,I),i] += -ϕuR(j,CI(I,i),u,ϕ(i,CI(I,j),u)) + ν*(j,CI(I,i),u) over I slice(N,N[j],j,2)
5657

5758
# Periodic BC Building block
58-
lowerBoundary!(r,u,Φ,ν,i,j,N,::Val{true}) = @loop (
59-
Φ[I] = ϕuP(j,CIj(j,CI(I,i),N[j]-2),CI(I,i),u,ϕ(i,CI(I,j),u)) -ν*(j,CI(I,i),u); r[I,i] += Φ[I]) over I slice(N,2,j,2)
60-
upperBoundary!(r,u,Φ,ν,i,j,N,::Val{true}) = @loop r[I-δ(j,I),i] -= Φ[CIj(j,I,2)] over I slice(N,N[j],j,2)
59+
lowerBoundary!(r,u,Φ,ν,i,j,N,λ,::Val{true}) = @loop (
60+
Φ[I] = ϕuP(j,CIj(j,CI(I,i),N[j]-2),CI(I,i),u,ϕ(i,CI(I,j),u)) -ν*(j,CI(I,i),u); r[I,i] += Φ[I]) over I slice(N,2,j,2)
61+
upperBoundary!(r,u,Φ,ν,i,j,N,λ,::Val{true}) = @loop r[I-δ(j,I),i] -= Φ[CIj(j,I,2)] over I slice(N,N[j],j,2)
6162

6263
"""
6364
accelerate!(r,t,g,U)
@@ -94,11 +95,12 @@ struct Flow{D, T, Sf<:AbstractArray{T}, Vf<:AbstractArray{T}, Tf<:AbstractArray{
9495
U :: Union{NTuple{D,Number},Function} # domain boundary values
9596
Δt:: Vector{T} # time step (stored in CPU memory)
9697
ν :: T # kinematic viscosity
98+
λ :: Function # kinematic viscosity
9799
g :: Union{Function,Nothing} # (possibly time-varying) uniform acceleration field
98100
exitBC :: Bool # Convection exit
99101
perdir :: NTuple # tuple of periodic direction
100102
function Flow(N::NTuple{D}, U; f=Array, Δt=0.25, ν=0., g=nothing,
101-
::Function=(i, x) -> 0., perdir=(), exitBC=false, T=Float32) where D
103+
::Function=(i, x) -> 0., λ=quick, perdir=(), exitBC=false, T=Float32) where D
102104
Ng = N .+ 2
103105
Nd = (Ng..., D)
104106
u = Array{T}(undef, Nd...) |> f; apply!(uλ, u);
@@ -107,7 +109,7 @@ struct Flow{D, T, Sf<:AbstractArray{T}, Vf<:AbstractArray{T}, Tf<:AbstractArray{
107109
fv, p, σ = zeros(T, Nd) |> f, zeros(T, Ng) |> f, zeros(T, Ng) |> f
108110
V, μ₀, μ₁ = zeros(T, Nd) |> f, ones(T, Nd) |> f, zeros(T, Ng..., D, D) |> f
109111
BC!(μ₀,ntuple(zero, D),false,perdir)
110-
new{D,T,typeof(p),typeof(u),typeof(μ₁)}(u,u⁰,fv,p,σ,V,μ₀,μ₁,U,T[Δt],ν,g,exitBC,perdir)
112+
new{D,T,typeof(p),typeof(u),typeof(μ₁)}(u,u⁰,fv,p,σ,V,μ₀,μ₁,U,T[Δt],ν,λ,g,exitBC,perdir)
111113
end
112114
end
113115

@@ -144,15 +146,15 @@ and the `AbstractPoisson` pressure solver to project the velocity onto an incomp
144146
a.u⁰ .= a.u; scale_u!(a,0); t₁ = sum(a.Δt); t₀ = t₁-a.Δt[end]
145147
# predictor u → u'
146148
@log "p"
147-
conv_diff!(a.f,a.u⁰,a.σ,ν=a.ν,perdir=a.perdir)
149+
conv_diff!(a.f,a.u⁰,a.σ,ν=a.ν,λ=a.λ,perdir=a.perdir)
148150
udf!(a,udf,t₀; kwargs...)
149151
accelerate!(a.f,t₀,a.g,a.U)
150152
BDIM!(a); BC!(a.u,a.U,a.exitBC,a.perdir,t₁) # BC MUST be at t₁
151153
a.exitBC && exitBC!(a.u,a.u⁰,a.Δt[end]) # convective exit
152154
project!(a,b); BC!(a.u,a.U,a.exitBC,a.perdir,t₁)
153155
# corrector u → u¹
154156
@log "c"
155-
conv_diff!(a.f,a.u,a.σ,ν=a.ν,perdir=a.perdir)
157+
conv_diff!(a.f,a.u,a.σ,ν=a.ν,λ=a.λ,perdir=a.perdir)
156158
udf!(a,udf,t₁; kwargs...)
157159
accelerate!(a.f,t₁,a.g,a.U)
158160
BDIM!(a); scale_u!(a,0.5); BC!(a.u,a.U,a.exitBC,a.perdir,t₁)

src/WaterLily.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ include("MultiLevelPoisson.jl")
1818
export MultiLevelPoisson,solver!,mult!
1919

2020
include("Flow.jl")
21-
export Flow,mom_step!
21+
export Flow,mom_step!,quick,cds
2222

2323
include("Body.jl")
2424
export AbstractBody,measure_sdf!
@@ -64,7 +64,7 @@ mutable struct Simulation <: AbstractSimulation
6464
body :: AbstractBody
6565
pois :: AbstractPoisson
6666
function Simulation(dims::NTuple{N}, u_BC, L::Number;
67-
Δt=0.25, ν=0., g=nothing, U=nothing, ϵ=1, perdir=(),
67+
Δt=0.25, ν=0., λ=quick, g=nothing, U=nothing, ϵ=1, perdir=(),
6868
=nothing, exitBC=false, body::AbstractBody=NoBody(),
6969
T=Float32, mem=Array) where N
7070
@assert !(isa(u_BC,Function) && isa(uλ,Function)) "`u_BC` will be used to generate `uλ=u_BC(t=0)` do not provide both"
@@ -75,7 +75,7 @@ mutable struct Simulation <: AbstractSimulation
7575
isa(u_BC,Function) && @assert all(typeof.(ntuple(i->u_BC(i,zeros(SVector{N}),zero(T)),N)).==T) "`u_BC` is not type stable"
7676
isnothing(uλ) && (uλ = isa(u_BC, Function) ?= (i,x)->u_BC(i,x,0) := (i,_)->u_BC[i])
7777
isnothing(U) && (U = sum(abs2,u_BC))
78-
flow = Flow(dims,u_BC;uλ,Δt,ν,g,T,f=mem,perdir,exitBC)
78+
flow = Flow(dims,u_BC;uλ,Δt,ν,λ,g,T,f=mem,perdir,exitBC)
7979
measure!(flow,body;ϵ)
8080
new(U,L,ϵ,flow,body,MultiLevelPoisson(flow.p,flow.μ₀,flow.σ;perdir))
8181
end

src/util.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ end
262262

263263
# Turbulence modelling utils
264264
"""
265-
sgs(flow, t; νₜ, S, C=0.16)
265+
sgs!(flow, t; νₜ, S, C, Δ)
266266
267267
Implements a user-defined function `udf` to model subgrid-scale LES stresses based on the Boussinesq approximation
268268
τᵃᵢⱼ = τʳᵢⱼ - (1/3)τʳₖₖδᵢⱼ = -2νₜS̅ᵢⱼ
@@ -272,21 +272,22 @@ where
272272
273273
and we add -∂ⱼ(τᵃᵢⱼ) to the RHS as a body force (the isotropic part of the tensor is automatically modelled by the pressure gradient term).
274274
Users need to define the turbulent viscosity function `νₜ` and pass it as a keyword argument to this function together with rate-of-strain
275-
tensor array buffer `S` and model constant `C`. For example, the standard Smagorinsky–Lilly model for the sub-grid scale stresses
275+
tensor array buffer `S`, Smagorinsky constant `C`, and filter width `Δ`.
276+
For example, the standard Smagorinsky–Lilly model for the sub-grid scale stresses is
276277
277278
νₜ = (CΔ)²|S̅ᵢⱼ|=(CΔ)²√(2S̅ᵢⱼS̅ᵢⱼ)
278279
279-
could be defined as
280-
`smagorinsky(I::CartesianIndex{m} where m, S; C) = @views C^2*sqrt(2dot(S[I,:,:],S[I,:,:]))`
281-
and passed into `sim_step!` as a keyword argument together with the varibles than the function needs (`S` and `C`):
282-
`sim_step!(sim, ...; udf=sgs, νₜ=smagorinsky, S, C)`
280+
It can be implemented as
281+
`smagorinsky(I::CartesianIndex{m} where m; S, C, Δ) = @views (C*Δ)^2*sqrt(dot(S[I,:,:],S[I,:,:]))`
282+
and passed into `sim_step!` as a keyword argument together with the varibles than the function needs (`S`, `C`, and `Δ`):
283+
`sim_step!(sim, ...; udf=sgs, νₜ=smagorinsky, S, C, Δ)`
283284
"""
284-
function sgs!(flow, t; νₜ, S, C)
285+
function sgs!(flow, t; νₜ, S, C, Δ)
285286
N,n = size_u(flow.u)
286287
@loop S[I,:,:] .= WaterLily.S(I,flow.u) over I inside(flow.σ)
287288
for i 1:n, j 1:n
288289
WaterLily.@loop (
289-
flow.σ[I] = -νₜ(I;S,C)*(j,CI(I,i),flow.u);
290+
flow.σ[I] = -νₜ(I;S,C)*(j,CI(I,i),flow.u);
290291
flow.f[I,i] += flow.σ[I];
291292
) over I inside_u(N,j)
292293
WaterLily.@loop flow.f[I-δ(j,I),i] -= flow.σ[I] over I WaterLily.inside_u(N,j)

0 commit comments

Comments
 (0)