Skip to content

Commit a7242d1

Browse files
authored
Merge pull request #9 from JuliaGeodynamics/Fix_3D
Add Zhang and Shun limiter
2 parents aad5b15 + 048048d commit a7242d1

16 files changed

+456
-132
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using FiniteDiffWENO5
2+
using GLMakie
3+
4+
function main(; nx = 400, ny = 400)
5+
6+
Lx = 1.0
7+
Δx = Lx / nx
8+
Δy = Lx / ny
9+
10+
x = range(0, stop = Lx, length = nx)
11+
12+
# Courant number
13+
CFL = 0.7
14+
period = 1
15+
16+
# Grid x assumed defined
17+
x = range(0, length = nx, stop = Lx)
18+
y = range(0, length = ny, stop = Lx)
19+
grid = (x .* ones(ny)', ones(nx) .* y')
20+
21+
# Staggered grids:
22+
# vx at x-faces → (nx+1, ny)
23+
x_vx = range(0, stop = Lx, length = nx + 1)
24+
y_vx = range(Δy / 2, stop = Lx - Δy / 2, length = ny)
25+
26+
# vy at y-faces → (nx, ny+1)
27+
x_vy = range(Δx / 2, stop = Lx - Δx / 2, length = nx)
28+
y_vy = range(0, stop = Lx, length = ny + 1)
29+
30+
# Make 2D coordinate arrays with correct orientation
31+
X_vx = repeat(x_vx, 1, ny) # (nx+1, ny)
32+
Y_vx = repeat(y_vx', nx + 1, 1) # (nx+1, ny)
33+
34+
X_vy = repeat(x_vy, 1, ny + 1) # (nx, ny+1)
35+
Y_vy = repeat(y_vy', nx, 1) # (nx, ny+1)
36+
37+
# Define velocity field (example: divergence-free vortex)
38+
vx0 = .-2π .* sin.(π .* X_vx) .* cos.(π .* Y_vx) # (nx+1, ny)
39+
vy0 = 2π .* cos.(π .* X_vy) .* sin.(π .* Y_vy) # (nx, ny+1)
40+
41+
v = (; x = vx0, y = vy0)
42+
43+
x0 = 1 / 4
44+
c = 0.08
45+
46+
u0 = zeros(ny, nx)
47+
48+
for I in CartesianIndices((ny, nx))
49+
u0[I] = sign(exp(-((grid[1][I] - x0)^2 + (grid[2][I]' - x0)^2) / c^2) - 0.5) * 0.5 + 0.5
50+
end
51+
52+
u = copy(u0)
53+
weno = WENOScheme(u; boundary = (2, 2, 2, 2), stag = true, multithreading = true)
54+
55+
56+
# grid size
57+
Δt = CFL * min(Δx, Δy)^(5 / 3)
58+
59+
tmax = 1
60+
t = 0
61+
counter = 0
62+
63+
f = Figure(size = (800, 600))
64+
ax = Axis(f[1, 1], title = "t = $(round(t, digits = 2))")
65+
u_obser = Observable(u0)
66+
hm = heatmap!(ax, x, y, u_obser; colormap = cgrad(:roma, rev = true), colorrange = (0, 1))
67+
Colorbar(f[1, 2], label = "u", hm)
68+
display(f)
69+
counter_half = 0
70+
71+
while t < tmax
72+
WENO_step!(u, v, weno, Δt, Δx, Δy)
73+
74+
75+
if t > tmax / 2 && counter_half == 0
76+
println("reversing velocity field...")
77+
vx0 .= .- vx0
78+
vy0 .= .- vy0
79+
counter_half += 1
80+
end
81+
82+
t += Δt
83+
84+
if t + Δt > tmax
85+
Δt = tmax - t
86+
end
87+
88+
if counter % 100 == 0
89+
u_obser[] = u
90+
ax.title = "t = $(round(t, digits = 2))"
91+
end
92+
93+
counter += 1
94+
95+
96+
end
97+
98+
return
99+
end
100+
101+
main(nx = 400, ny = 400)

ext/ChmyExt.jl

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module ChmyExt
22
using FiniteDiffWENO5
3+
using FiniteDiffWENO5: zhang_shu_limit, weno5_reconstruction_upwind, weno5_reconstruction_downwind
34
using MuladdMacro
45
using UnPack
56
using Chmy
@@ -21,7 +22,7 @@ Create a WENO scheme structure for the given field `u` on the specified `grid` u
2122
- `boundary::NTuple{2N, Int}`: Tuple specifying the boundary conditions for each dimension (0: homogeneous Neumann, 1: homogeneous Dirichlet, 2: periodic). Default is periodic (2).
2223
- `stag::Bool`: Whether the grid is staggered (velocities on cell faces) or not (velocities on cell centers).
2324
"""
24-
function WENOScheme(c0::AbstractField{T, N}, grid::StructuredGrid; boundary::NTuple = (2, 2), stag::Bool = true, kwargs...) where {T, N}
25+
function WENOScheme(c0::AbstractField{T, N}, grid::StructuredGrid; boundary::NTuple = (2, 2), stag::Bool = true, lim_ZS::Bool = false, kwargs...) where {T, N}
2526

2627
# check that boundary conditions are correctly defined
2728
@assert length(boundary) == 2N "Boundary conditions must be a tuple of length $(2N) for $(N)D data."
@@ -43,7 +44,7 @@ function WENOScheme(c0::AbstractField{T, N}, grid::StructuredGrid; boundary::NTu
4344
TFlux = typeof(fl)
4445
TArray = typeof(du)
4546

46-
return WENOScheme{T, TArray, TFlux, N_boundary}(stag = stag, boundary = boundary, multithreading = multithreading, fl = fl, fr = fr, du = du, ut = ut)
47+
return WENOScheme{T, TArray, TFlux, N_boundary}(stag = stag, boundary = boundary, multithreading = multithreading, lim_ZS = lim_ZS, fl = fl, fr = fr, du = du, ut = ut)
4748
end
4849

4950
function WENOScheme(c0::AbstractField; kwargs...)
@@ -75,7 +76,8 @@ include("KAExt3D.jl")
7576
v::NamedTuple{(:x,), <:Tuple{<:AbstractField{<:Real, 1}}},
7677
weno::FiniteDiffWENO5.WENOScheme,
7778
Δt, Δx,
78-
grid::StructuredGrid, arch) where {T_field <: AbstractField{<:Real, 1}}
79+
grid::StructuredGrid, arch;
80+
u_min = 0.0, u_max = 0.0) where {T_field <: AbstractField{<:Real, 1}}
7981
8082
Advance the solution `u` by one time step using the 3rd-order Runge-Kutta method with WENO5 spatial discretization using Chmy.jl fields in 1D.
8183
@@ -86,8 +88,11 @@ Advance the solution `u` by one time step using the 3rd-order Runge-Kutta method
8688
- `Δt`: Time step size.
8789
- `Δx`: Spatial grid size.
8890
- `grid::StructuredGrid`: Computational grid from Chmy.
91+
- `arch::Backend`: The KernelAbstractions backend in use (e.g., CPU(), CUDABackend(), etc.).
92+
- `u_min`: Minimum value of `u` for the Zhang-Shu positivity limiter.
93+
- `u_max`: Maximum value of `u` for the Zhang-Shu positivity limiter.
8994
"""
90-
function WENO_step!(u::T_field, v::NamedTuple{(:x,), <:Tuple{<:AbstractField{<:Real, 1}}}, weno::FiniteDiffWENO5.WENOScheme, Δt, Δx, grid::StructuredGrid, arch) where {T_field <: AbstractField{<:Real, 1}}
95+
function WENO_step!(u::T_field, v::NamedTuple{(:x,), <:Tuple{<:AbstractField{<:Real, 1}}}, weno::FiniteDiffWENO5.WENOScheme, Δt, Δx, grid::StructuredGrid, arch; u_min = 0.0, u_max = 0.0) where {T_field <: AbstractField{<:Real, 1}}
9196

9297
@assert get_backend(u) == get_backend(v.x)
9398

@@ -98,19 +103,19 @@ function WENO_step!(u::T_field, v::NamedTuple{(:x,), <:Tuple{<:AbstractField{<:R
98103
nx = grid.axes[1].length
99104
Δx_ = inv(Δx)
100105

101-
@unpack ut, du, fl, fr, stag, boundary, χ, γ, ζ, ϵ = weno
106+
@unpack ut, du, fl, fr, stag, lim_ZS, boundary, χ, γ, ζ, ϵ = weno
102107

103-
launch(arch, grid, WENO_flux_KA_1D => (fl.x, fr.x, u, boundary, nx, χ, γ, ζ, ϵ, grid))
108+
launch(arch, grid, WENO_flux_KA_1D => (fl.x, fr.x, u, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
104109
launch(arch, grid, WENO_semi_discretisation_weno5_KA_1D! => (du, fl, fr, v, stag, Δx_, grid))
105110

106111
interior(ut) .= @muladd interior(u) .- Δt .* interior(du)
107112

108-
launch(arch, grid, WENO_flux_KA_1D => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, grid))
113+
launch(arch, grid, WENO_flux_KA_1D => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
109114
launch(arch, grid, WENO_semi_discretisation_weno5_KA_1D! => (du, fl, fr, v, stag, Δx_, grid))
110115

111116
interior(ut) .= @muladd 0.75 .* interior(u) .+ 0.25 .* interior(ut) .- 0.25 .* Δt .* interior(du)
112117

113-
launch(arch, grid, WENO_flux_KA_1D => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, grid))
118+
launch(arch, grid, WENO_flux_KA_1D => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
114119
launch(arch, grid, WENO_semi_discretisation_weno5_KA_1D! => (du, fl, fr, v, stag, Δx_, grid))
115120

116121
interior(u) .= @muladd inv(3.0) .* interior(u) .+ 2.0 / 3.0 .* interior(ut) .- 2.0 / 3.0 .* Δt .* interior(du)
@@ -124,7 +129,8 @@ end
124129
v::NamedTuple{(:x, :y), <:Tuple{Vararg{AbstractField{<:Real}, 2}}},
125130
weno::FiniteDiffWENO5.WENOScheme,
126131
Δt, Δx,
127-
grid::StructuredGrid, arch) where T_field <: AbstractField{<:Real} where names
132+
grid::StructuredGrid, arch;
133+
u_min = 0.0, u_max = 0.0) where T_field <: AbstractField{<:Real} where names
128134
129135
Advance the solution `u` by one time step using the 3rd-order Runge-Kutta method with WENO5 spatial discretization using Chmy.jl fields in 2D.
130136
@@ -135,8 +141,11 @@ Advance the solution `u` by one time step using the 3rd-order Runge-Kutta method
135141
- `Δt`: Time step size.
136142
- `Δx`: Spatial grid size.
137143
- `grid::StructuredGrid`: Computational grid from Chmy.
144+
- `arch::Backend`: The KernelAbstractions backend in use (e.g., CPU(), CUDABackend(), etc.).
145+
- `u_min`: Minimum value of `u` for the Zhang-Shu positivity limiter.
146+
- `u_max`: Maximum value of `u` for the Zhang-Shu positivity limiter.
138147
"""
139-
function WENO_step!(u::T_field, v::NamedTuple{(:x, :y), <:Tuple{Vararg{AbstractField{<:Real}, 2}}}, weno::FiniteDiffWENO5.WENOScheme, Δt, Δx, Δy, grid::StructuredGrid, arch) where {T_field <: AbstractField{<:Real, 2}}
148+
function WENO_step!(u::T_field, v::NamedTuple{(:x, :y), <:Tuple{Vararg{AbstractField{<:Real}, 2}}}, weno::FiniteDiffWENO5.WENOScheme, Δt, Δx, Δy, grid::StructuredGrid, arch; u_min = 0.0, u_max = 0.0) where {T_field <: AbstractField{<:Real, 2}}
140149

141150
@assert get_backend(u) == get_backend(v.x)
142151
@assert get_backend(u) == get_backend(v.y)
@@ -150,22 +159,22 @@ function WENO_step!(u::T_field, v::NamedTuple{(:x, :y), <:Tuple{Vararg{AbstractF
150159
Δx_ = inv(Δx)
151160
Δy_ = inv(Δy)
152161

153-
@unpack ut, du, fl, fr, stag, boundary, χ, γ, ζ, ϵ = weno
162+
@unpack ut, du, fl, fr, stag, lim_ZS, boundary, χ, γ, ζ, ϵ = weno
154163

155-
launch(arch, grid, WENO_flux_KA_2D_x => (fl.x, fr.x, u, boundary, nx, χ, γ, ζ, ϵ, grid))
156-
launch(arch, grid, WENO_flux_KA_2D_y => (fl.y, fr.y, u, boundary, ny, χ, γ, ζ, ϵ, grid))
164+
launch(arch, grid, WENO_flux_KA_2D_x => (fl.x, fr.x, u, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
165+
launch(arch, grid, WENO_flux_KA_2D_y => (fl.y, fr.y, u, boundary, ny, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
157166
launch(arch, grid, WENO_semi_discretisation_weno5_KA_2D! => (du, fl, fr, v, stag, Δx_, Δy_, grid))
158167

159168
interior(ut) .= @muladd interior(u) .- Δt .* interior(du)
160169

161-
launch(arch, grid, WENO_flux_KA_2D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, grid))
162-
launch(arch, grid, WENO_flux_KA_2D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, grid))
170+
launch(arch, grid, WENO_flux_KA_2D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
171+
launch(arch, grid, WENO_flux_KA_2D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
163172
launch(arch, grid, WENO_semi_discretisation_weno5_KA_2D! => (du, fl, fr, v, stag, Δx_, Δy_, grid))
164173

165174
interior(ut) .= @muladd 0.75 .* interior(u) .+ 0.25 .* interior(ut) .- 0.25 .* Δt .* interior(du)
166175

167-
launch(arch, grid, WENO_flux_KA_2D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, grid))
168-
launch(arch, grid, WENO_flux_KA_2D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, grid))
176+
launch(arch, grid, WENO_flux_KA_2D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
177+
launch(arch, grid, WENO_flux_KA_2D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
169178
launch(arch, grid, WENO_semi_discretisation_weno5_KA_2D! => (du, fl, fr, v, stag, Δx_, Δy_, grid))
170179

171180
interior(u) .= @muladd inv(3.0) .* interior(u) .+ 2.0 / 3.0 .* interior(ut) .- 2.0 / 3.0 .* Δt .* interior(du)
@@ -179,7 +188,8 @@ end
179188
v::NamedTuple{names, <:Tuple{Vararg{AbstractField{<:Real}, 2}}},
180189
weno::FiniteDiffWENO5.WENOScheme,
181190
Δt, Δx, Δy, Δz,
182-
grid::StructuredGrid, arch) where T_field <: AbstractArray{<:Real, 3}
191+
grid::StructuredGrid, arch;
192+
u_min = 0.0, u_max = 0.0) where T_field <: AbstractArray{<:Real, 3}
183193
184194
Advance the solution `u` by one time step using the 3rd-order Runge-Kutta method with WENO5 spatial discretization using Chmy.jl fields in 3D.
185195
@@ -192,8 +202,11 @@ Advance the solution `u` by one time step using the 3rd-order Runge-Kutta method
192202
- `Δy`: Spatial grid size.
193203
- `Δz`: Spatial grid size.
194204
- `grid::StructuredGrid`: Computational grid from Chmy.
205+
- `arch::Backend`: The KernelAbstractions backend in use (e.g., CPU(), CUDABackend(), etc.).
206+
- `u_min`: Minimum value of `u` for the Zhang-Shu positivity limiter.
207+
- `u_max`: Maximum value of `u` for the Zhang-Shu positivity limiter.
195208
"""
196-
function WENO_step!(u::T_field, v::NamedTuple{(:x, :y, :z), <:Tuple{Vararg{AbstractField{<:Real}, 3}}}, weno::FiniteDiffWENO5.WENOScheme, Δt, Δx, Δy, Δz, grid::StructuredGrid, arch) where {T_field <: AbstractArray{<:Real, 3}}
209+
function WENO_step!(u::T_field, v::NamedTuple{(:x, :y, :z), <:Tuple{Vararg{AbstractField{<:Real}, 3}}}, weno::FiniteDiffWENO5.WENOScheme, Δt, Δx, Δy, Δz, grid::StructuredGrid, arch; u_min = 0.0, u_max = 0.0) where {T_field <: AbstractArray{<:Real, 3}}
197210

198211
@assert get_backend(u) == get_backend(v.x)
199212
@assert get_backend(u) == get_backend(v.y)
@@ -210,25 +223,25 @@ function WENO_step!(u::T_field, v::NamedTuple{(:x, :y, :z), <:Tuple{Vararg{Abstr
210223
Δy_ = inv(Δy)
211224
Δz_ = inv(Δz)
212225

213-
@unpack ut, du, fl, fr, stag, boundary, χ, γ, ζ, ϵ = weno
226+
@unpack ut, du, fl, fr, stag, lim_ZS, boundary, χ, γ, ζ, ϵ = weno
214227

215-
launch(arch, grid, WENO_flux_KA_3D_x => (fl.x, fr.x, u, boundary, nx, χ, γ, ζ, ϵ, grid))
216-
launch(arch, grid, WENO_flux_KA_3D_y => (fl.y, fr.y, u, boundary, ny, χ, γ, ζ, ϵ, grid))
217-
launch(arch, grid, WENO_flux_KA_3D_z => (fl.z, fr.z, u, boundary, nz, χ, γ, ζ, ϵ, grid))
228+
launch(arch, grid, WENO_flux_KA_3D_x => (fl.x, fr.x, u, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
229+
launch(arch, grid, WENO_flux_KA_3D_y => (fl.y, fr.y, u, boundary, ny, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
230+
launch(arch, grid, WENO_flux_KA_3D_z => (fl.z, fr.z, u, boundary, nz, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
218231
launch(arch, grid, WENO_semi_discretisation_weno5_KA_3D! => (du, fl, fr, v, stag, Δx_, Δy_, Δz_, grid))
219232

220233
interior(ut) .= @muladd interior(u) .- Δt .* interior(du)
221234

222-
launch(arch, grid, WENO_flux_KA_3D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, grid))
223-
launch(arch, grid, WENO_flux_KA_3D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, grid))
224-
launch(arch, grid, WENO_flux_KA_3D_z => (fl.z, fr.z, ut, boundary, nz, χ, γ, ζ, ϵ, grid))
235+
launch(arch, grid, WENO_flux_KA_3D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
236+
launch(arch, grid, WENO_flux_KA_3D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
237+
launch(arch, grid, WENO_flux_KA_3D_z => (fl.z, fr.z, ut, boundary, nz, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
225238
launch(arch, grid, WENO_semi_discretisation_weno5_KA_3D! => (du, fl, fr, v, stag, Δx_, Δy_, Δz_, grid))
226239

227240
interior(ut) .= @muladd 0.75 .* interior(u) .+ 0.25 .* interior(ut) .- 0.25 .* Δt .* interior(du)
228241

229-
launch(arch, grid, WENO_flux_KA_3D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, grid))
230-
launch(arch, grid, WENO_flux_KA_3D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, grid))
231-
launch(arch, grid, WENO_flux_KA_3D_z => (fl.z, fr.z, ut, boundary, nz, χ, γ, ζ, ϵ, grid))
242+
launch(arch, grid, WENO_flux_KA_3D_x => (fl.x, fr.x, ut, boundary, nx, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
243+
launch(arch, grid, WENO_flux_KA_3D_y => (fl.y, fr.y, ut, boundary, ny, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
244+
launch(arch, grid, WENO_flux_KA_3D_z => (fl.z, fr.z, ut, boundary, nz, χ, γ, ζ, ϵ, lim_ZS, u_min, u_max, grid))
232245
launch(arch, grid, WENO_semi_discretisation_weno5_KA_3D! => (du, fl, fr, v, stag, Δx_, Δy_, Δz_, grid))
233246

234247
interior(u) .= @muladd inv(3.0) .* interior(u) .+ 2.0 / 3.0 .* interior(ut) .- 2.0 / 3.0 .* Δt .* interior(du)

0 commit comments

Comments
 (0)