Skip to content

Commit c109ce4

Browse files
Mikolaj-A-Kowalskiglwagnersimone-silvestri
authored
Use specialised implementation of newton_div on CUDA (#5140)
* feat: use fast division on Nvidia GPUs in newton_div context Adds specialised implementation of the approximate `newton_div` for the CUDA backend. It allows to avoid slow-path of the `rcp` and `div` and provides few per-cent speed-up of advection kernels. * fix: do not specify the type of numerator Since we just multiply reciprocal of denominator by the numerator we don't need to know the exact representation of the numerator. If specified can lead to unexpected dispatch to the fallback method if the numerator is e.g. π literal (of type Irrational). * refactor: select type of newton_div in a WENO scheme by type parameter * fix: newton_div type propagation into buffer schemes * test: update doctests * feat: add CUDA fast division for f32 * refactor: remove lower-precision WENO type parameter This is a breaking change! It requires requires minor version bump. It has been made since the 2nd floating precision type parameter is no longer required. It has been replaced with type-based specifier for the division type in WENO reconstruction scheme. * refactor: use `weight_computation` to refer to division type in WENO * refactor: make `newton_div` type names less verbose * test: add unit tests for newton_div Co-authored-by: Gregory L. Wagner <wagner.greg@gmail.com> * refactor: BackendOptimizedDivision in ConvertingDivision on CPU Add a fallback to enable `BackendOptimizedDivision` to run on the CPU. The fallback should be overriden for each device backend in an approperiate extension module. * refactor: use BackendOptimizedDivision by default * refactor: use normal division on the CPU The difference in latency between f32 and f64 is small. It is probably not enough to justify two conversions and FMAs. (not tested for performance, it is conjecture) * refactor: do not use CUDA intrinsics under Reactant The BackendOptimizedDivision optimization for `weno_weights_computation` uses LLVM's NVPTX backend intrinsics which are not understood by Reactant. Thus we need to change the default when running under Reactant. * feat: add materialize_advection to defer configuration options To resolve problems with Reactant not knowing about NVPTX intrinsics that we are using in the backend optimised implementation, we need to defer a choice of the default weno_weight_computation option until it is known on what backend the problem will be run. To do that we can rely on the `materialize` pattern used already in the similar circumstances. * feat: use advection materialisation in models * refactor: get rid of the global weight_computation setting It is no longer necessary since the default can be assigned in the materialization of the advection schemes. It can also be dependent on a specific architecture the problem will run on. To change the default setting user just needs to override the function `default_weno_weight_computation(arch)` * fix: failing reactant tests * fix: add missing materialize_advection overloads * test: fix tests broken by changes to the API * fix: add missing overload for Distributed grid * test: add missing materialization step to test_forcing Move the MockGrid to the include file. Multiple test files need it and we need to make sure it is defined once to avoid struct redefinition. * fix: extra end-of-file newlines Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com> * test: fix newton_div test There was a type instability and test input was getting promoted to Float64. As a result the Float32 was never verified and a typo in the intrinsic name was not caught ealier. * update minor version (numerical difference) --------- Co-authored-by: Gregory L. Wagner <wagner.greg@gmail.com> Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com>
1 parent b8012d5 commit c109ce4

23 files changed

Lines changed: 356 additions & 54 deletions

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Oceananigans"
22
uuid = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
3-
version = "0.106.5"
3+
version = "0.106.6"
44
authors = ["Climate Modeling Alliance and contributors"]
55

66
[deps]

ext/OceananigansCUDAExt.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,31 @@ end
132132
@inline UT.sync_device!(::CUDAGPU) = CUDA.synchronize()
133133
@inline UT.sync_device!(::CUDABackend) = CUDA.synchronize()
134134

135+
# Use faster versions of `newton_div` on Nvidia GPUs
136+
CUDA.@device_override UT.newton_div(::Type{UT.BackendOptimizedDivision}, a, b) = a * fast_inv_cuda(b)
137+
138+
function fast_inv_cuda(a::Float64)
139+
# Get the approximate reciprocal
140+
# https://docs.nvidia.com/cuda/parallel-thread-execution/#floating-point-instructions-rcp-approx-ftz-f64
141+
# This instruction chops off last 32bits of mantissa and computes inverse
142+
# while treating all subnormal numbers as 0.0
143+
# If reciprocal would be subnormal, underflows to 0.0
144+
# 32 least significant bits of the result are filled with 0s
145+
inv_a = ccall("llvm.nvvm.rcp.approx.ftz.d", llvmcall, Float64, (Float64,), a)
146+
147+
# Approximate the missing 32bits of mantissa with a single cubic iteration
148+
e = fma(inv_a, -a, 1.0)
149+
e = fma(e, e, e)
150+
inv_a = fma(e, inv_a, inv_a)
151+
return inv_a
152+
end
153+
154+
function fast_inv_cuda(a::Float32)
155+
# This instruction just computes reciprocal flushing subnormals to 0.0
156+
# Hence for subnormal inputs it returns Inf
157+
# For large number whose reciprocal is subnormal it underflows to 0.0
158+
inv_a = ccall("llvm.nvvm.rcp.approx.ftz.f", llvmcall, Float32, (Float32,), a)
159+
return inv_a
160+
end
161+
135162
end # module OceananigansCUDAExt

ext/OceananigansReactantExt/Models.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ using ..Grids: ShardedGrid, ShardedDistributed
1717
import Oceananigans.Models:
1818
complete_communication_and_compute_buffer!,
1919
interior_tendency_kernel_parameters
20+
import Oceananigans.Advection: default_weno_weight_computation
21+
2022

2123
const ReactantHFSM{TS, E} = Union{
2224
HydrostaticFreeSurfaceModel{TS, E, <:ReactantState},
@@ -60,4 +62,10 @@ maybe_prepare_first_time_step!(model::ReactantHFSM, callbacks) = nothing
6062
complete_communication_and_compute_buffer!(model, ::ShardedGrid, ::ShardedDistributed) = nothing
6163
interior_tendency_kernel_parameters(::ShardedDistributed, grid) = :xyz
6264

65+
# Reactant uses CUDA version of the code to uplift program description to MLIR.
66+
# Since default `weno_weight_computation` on CUDA uses LLVM's NVPTX intrinsics
67+
# it causes Reactant to crash.
68+
# We need to fall back to different optimization when running with Reactant
69+
default_weno_weight_computation(::ReactantState) = Oceananigans.Utils.ConvertingDivision{Float32}
70+
6371
end # module

ext/OceananigansReactantExt/OceananigansReactantExt.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ end
335335

336336
Base.getindex(array::OffsetVector{T, <:Reactant.AbstractConcreteArray{T, 1}}, ::Colon) where T = array
337337

338+
338339
# These are additional modules that may need to be Reactantified in the future:
339340
#
340341
# include("Utils.jl")

src/Advection/Advection.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,6 @@ include("tracer_advection_operators.jl")
8484
include("bounds_preserving_tracer_advection_operators.jl")
8585
include("cell_advection_timescale.jl")
8686
include("adapt_advection_order.jl")
87+
include("materialize_advection.jl")
8788

8889
end # module
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import Oceananigans: architecture
2+
3+
"""
4+
materialize_advection(advection, grid)
5+
6+
Return a fully materialized advection scheme appropriate for `grid`.
7+
It exists to allow advection schemes to defer specialising settings until
8+
additional information about the backend from grid is available.
9+
10+
For example it allows to set per-backend defaults for WENO weight computation
11+
setting.
12+
"""
13+
materialize_advection(advection, grid) = advection
14+
materialize_advection(::Nothing, grid) = nothing
15+
materialize_advection(advection::FluxFormAdvection, grid) = FluxFormAdvection(
16+
materialize_advection(advection.x, grid),
17+
materialize_advection(advection.y, grid),
18+
materialize_advection(advection.z, grid),
19+
)
20+
21+
# Upwinding treatments hold a cross_scheme that may contain deferred WENO weight computation
22+
materialize_advection(u::OnlySelfUpwinding, grid) =
23+
OnlySelfUpwinding(materialize_advection(u.cross_scheme, grid),
24+
u.δU_stencil, u.δV_stencil, u.δu²_stencil, u.δv²_stencil)
25+
26+
materialize_advection(u::CrossAndSelfUpwinding, grid) =
27+
CrossAndSelfUpwinding(materialize_advection(u.cross_scheme, grid),
28+
u.divergence_stencil, u.δu²_stencil, u.δv²_stencil)
29+
30+
materialize_advection(u::VelocityUpwinding, grid) =
31+
VelocityUpwinding(materialize_advection(u.cross_scheme, grid))
32+
33+
# VectorInvariant wraps multiple sub-schemes; recurse into each
34+
materialize_advection(vi::VectorInvariant{N,FT,M}, grid) where {N,FT,M} =
35+
VectorInvariant{N,FT,M}(
36+
materialize_advection(vi.vorticity_scheme, grid),
37+
vi.vorticity_stencil,
38+
materialize_advection(vi.vertical_advection_scheme, grid),
39+
materialize_advection(vi.kinetic_energy_gradient_scheme, grid),
40+
materialize_advection(vi.divergence_scheme, grid),
41+
materialize_advection(vi.upwinding, grid),
42+
)
43+
44+
45+
materialize_advection(weno::WENO{N,FT,WCT}, grid) where {N,FT,WCT} = WENO{N,FT,WCT}(
46+
weno.bounds,
47+
materialize_advection(weno.buffer_scheme, grid),
48+
materialize_advection(weno.advecting_velocity_scheme, grid),
49+
)
50+
51+
materialize_advection(weno::WENO{N,FT,Nothing}, grid) where {N,FT} =
52+
WENO{N,FT,default_weno_weight_computation(architecture(grid))}(
53+
weno.bounds,
54+
materialize_advection(weno.buffer_scheme, grid),
55+
materialize_advection(weno.advecting_velocity_scheme, grid),
56+
)
57+
58+
materialize_advection(scheme::UpwindBiased{N,FT}, grid) where {N,FT} = UpwindBiased{N,FT}(
59+
materialize_advection(scheme.buffer_scheme, grid),
60+
materialize_advection(scheme.advecting_velocity_scheme, grid),
61+
)
62+
63+
materialize_advection(scheme::Centered{N,FT}, grid) where {N,FT} =
64+
Centered{N,FT}(materialize_advection(scheme.buffer_scheme, grid))

src/Advection/vector_invariant_advection.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ function Base.summary(a::WENOVectorInvariant{N}) where N
137137
vertical_order = weno_order(a.vertical_advection_scheme)
138138
order = weno_order(a.vorticity_scheme)
139139
FT = eltype(a.vorticity_scheme)
140-
FT2 = eltype2(a.vorticity_scheme)
141-
return string("WENOVectorInvariant{$N, $FT, $FT2}(vorticity_order=$vorticity_order, vertical_order=$vertical_order)")
140+
return string("WENOVectorInvariant{$N, $FT}(vorticity_order=$vorticity_order, vertical_order=$vertical_order)")
142141
end
143142

144143
function Base.show(io::IO, a::VectorInvariant{N, FT}) where {N, FT}
@@ -193,12 +192,12 @@ Example
193192
julia> using Oceananigans
194193
195194
julia> WENOVectorInvariant()
196-
WENOVectorInvariant{5, Float64, Float32}(vorticity_order=9, vertical_order=5)
197-
├── vorticity_scheme: WENO{5, Float64, Float32}(order=9)
195+
WENOVectorInvariant{5, Float64}(vorticity_order=9, vertical_order=5)
196+
├── vorticity_scheme: WENO{5, Float64, Nothing}(order=9)
198197
├── vorticity_stencil: Oceananigans.Advection.VelocityStencil
199-
├── vertical_advection_scheme: WENO{3, Float64, Float32}(order=5)
200-
├── kinetic_energy_gradient_scheme: WENO{3, Float64, Float32}(order=5)
201-
├── divergence_scheme: WENO{3, Float64, Float32}(order=5)
198+
├── vertical_advection_scheme: WENO{3, Float64, Nothing}(order=5)
199+
├── kinetic_energy_gradient_scheme: WENO{3, Float64, Nothing}(order=5)
200+
├── divergence_scheme: WENO{3, Float64, Nothing}(order=5)
202201
└── upwinding: OnlySelfUpwinding
203202
```
204203
"""

src/Advection/weno_interpolants.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ end
291291
@inline function metaprogrammed_zweno_alpha_loop(buffer)
292292
elem = Vector(undef, buffer)
293293
for stencil = 1:buffer
294-
elem[stencil] = :(C★(scheme, Val($(stencil-1))) * (1 + (newton_div(FT2, τ, β[$stencil] + ϵ))^2))
294+
elem[stencil] = :(C★(scheme, Val($(stencil-1))) * (1 + (newton_div(WCT, τ, β[$stencil] + ϵ))^2))
295295
end
296296

297297
return :($(elem...),)
@@ -301,7 +301,7 @@ for buffer in advection_buffers[2:end]
301301
@eval begin
302302
@inline beta_sum(scheme::WENO{$buffer, FT}, β₁, β₂) where FT = @inbounds $(metaprogrammed_beta_sum(buffer))
303303
@inline beta_loop(scheme::WENO{$buffer, FT}, ψ) where FT = @inbounds $(metaprogrammed_beta_loop(buffer))
304-
@inline zweno_alpha_loop(scheme::WENO{$buffer, FT, FT2}, β, τ) where {FT, FT2} = @inbounds $(metaprogrammed_zweno_alpha_loop(buffer))
304+
@inline zweno_alpha_loop(scheme::WENO{$buffer, FT, WCT}, β, τ) where {FT, WCT} = @inbounds $(metaprogrammed_zweno_alpha_loop(buffer))
305305
end
306306
end
307307

src/Advection/weno_reconstruction.jl

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ import Oceananigans
44
##### Weighted Essentially Non-Oscillatory (WENO) advection scheme
55
#####
66

7-
struct WENO{N, FT, FT2, PP, CA, SI} <: AbstractUpwindBiasedAdvectionScheme{N, FT}
7+
struct WENO{N, FT, WCT, PP, CA, SI} <: AbstractUpwindBiasedAdvectionScheme{N, FT}
88
bounds :: PP
99
buffer_scheme :: CA
1010
advecting_velocity_scheme :: SI
1111

12-
function WENO{N, FT, FT2}(bounds::PP, buffer_scheme::CA,
13-
advecting_velocity_scheme :: SI) where {N, FT, FT2, PP, CA, SI}
12+
function WENO{N, FT, WCT}(bounds::PP, buffer_scheme::CA,
13+
advecting_velocity_scheme :: SI) where {N, FT, WCT, PP, CA, SI}
1414

15-
return new{N, FT, FT2, PP, CA, SI}(bounds, buffer_scheme, advecting_velocity_scheme)
15+
return new{N, FT, WCT, PP, CA, SI}(bounds, buffer_scheme, advecting_velocity_scheme)
1616
end
1717
end
1818

1919
"""
20-
WENO([FT=Float64, FT2=Float32;]
20+
WENO([FT=Float64;]
2121
order = 5,
2222
bounds = nothing,
2323
minimum_buffer_upwind_order = 3)
@@ -28,11 +28,12 @@ Arguments
2828
=========
2929
3030
- `FT`: The floating point type used in the scheme. Default: `Oceananigans.defaults.FloatType`
31-
- `FT2`: The floating point type used in some performance-critical parts of the scheme. Default: `Float32`
3231
3332
Keyword arguments
3433
=================
35-
34+
- `weight_computation`: The type of approximate division to used when computing WENO weights.
35+
Default: `Nothing` (deferred; a architecture-dependent default is assigned in
36+
`materialize_advection`)
3637
- `order`: The order of the WENO advection scheme. Default: 5
3738
- `bounds` (experimental): Whether to use bounds-preserving WENO, which produces a reconstruction
3839
that attempts to restrict a quantity to lie between a `bounds` tuple.
@@ -51,8 +52,8 @@ To build the default 5th-order scheme:
5152
julia> using Oceananigans
5253
5354
julia> WENO()
54-
WENO{3, Float64, Float32}(order=5)
55-
├── buffer_scheme: WENO{2, Float64, Float32}(order=3)
55+
WENO{3, Float64, Nothing}(order=5)
56+
├── buffer_scheme: WENO{2, Float64, Nothing}(order=3)
5657
│ └── buffer_scheme: Centered(order=2)
5758
└── advecting_velocity_scheme: Centered(order=4)
5859
```
@@ -62,10 +63,10 @@ yet minimally-dissipative advection scheme):
6263
6364
```jldoctest weno
6465
julia> WENO(order=9)
65-
WENO{5, Float64, Float32}(order=9)
66-
├── buffer_scheme: WENO{4, Float64, Float32}(order=7)
67-
│ └── buffer_scheme: WENO{3, Float64, Float32}(order=5)
68-
│ └── buffer_scheme: WENO{2, Float64, Float32}(order=3)
66+
WENO{5, Float64, Nothing}(order=9)
67+
├── buffer_scheme: WENO{4, Float64, Nothing}(order=7)
68+
│ └── buffer_scheme: WENO{3, Float64, Nothing}(order=5)
69+
│ └── buffer_scheme: WENO{2, Float64, Nothing}(order=3)
6970
│ └── buffer_scheme: Centered(order=2)
7071
└── advecting_velocity_scheme: Centered(order=8)
7172
```
@@ -75,24 +76,34 @@ which uses `Centered(order=2)` as the innermost buffer scheme:
7576
7677
```jldoctest weno
7778
julia> WENO(order=9, minimum_buffer_upwind_order=5)
78-
WENO{5, Float64, Float32}(order=9)
79-
├── buffer_scheme: WENO{4, Float64, Float32}(order=7)
80-
│ └── buffer_scheme: WENO{3, Float64, Float32}(order=5)
79+
WENO{5, Float64, Nothing}(order=9)
80+
├── buffer_scheme: WENO{4, Float64, Nothing}(order=7)
81+
│ └── buffer_scheme: WENO{3, Float64, Nothing}(order=5)
8182
│ └── buffer_scheme: Centered(order=2)
8283
└── advecting_velocity_scheme: Centered(order=8)
8384
```
8485
8586
```jldoctest weno
8687
julia> WENO(order=9, bounds=(0, 1))
87-
WENO{5, Float64, Float32}(order=9, bounds=(0.0, 1.0))
88-
├── buffer_scheme: WENO{4, Float64, Float32}(order=7, bounds=(0.0, 1.0))
89-
│ └── buffer_scheme: WENO{3, Float64, Float32}(order=5, bounds=(0.0, 1.0))
90-
│ └── buffer_scheme: WENO{2, Float64, Float32}(order=3, bounds=(0.0, 1.0))
88+
WENO{5, Float64, Nothing}(order=9, bounds=(0.0, 1.0))
89+
├── buffer_scheme: WENO{4, Float64, Nothing}(order=7, bounds=(0.0, 1.0))
90+
│ └── buffer_scheme: WENO{3, Float64, Nothing}(order=5, bounds=(0.0, 1.0))
91+
│ └── buffer_scheme: WENO{2, Float64, Nothing}(order=3, bounds=(0.0, 1.0))
9192
│ └── buffer_scheme: Centered(order=2)
9293
└── advecting_velocity_scheme: Centered(order=8)
9394
```
95+
96+
To build a WENO scheme that uses approximate division on a GPU to execute faster:
97+
```jldoctest weno
98+
julia> WENO(;weight_computation=Oceananigans.Utils.BackendOptimizedDivision)
99+
WENO{3, Float64, Oceananigans.Utils.BackendOptimizedDivision}(order=5)
100+
├── buffer_scheme: WENO{2, Float64, Oceananigans.Utils.BackendOptimizedDivision}(order=3)
101+
│ └── buffer_scheme: Centered(order=2)
102+
└── advecting_velocity_scheme: Centered(order=4)
103+
```
94104
"""
95-
function WENO(FT::DataType=Oceananigans.defaults.FloatType, FT2::DataType=Float32;
105+
function WENO(FT::DataType=Oceananigans.defaults.FloatType;
106+
weight_computation::DataType=Nothing,
96107
order = 5,
97108
buffer_scheme = DecreasingOrderAdvectionScheme(),
98109
bounds = nothing,
@@ -116,20 +127,19 @@ function WENO(FT::DataType=Oceananigans.defaults.FloatType, FT2::DataType=Float3
116127
# At minimum order, switch to Centered scheme
117128
buffer_scheme = Centered(FT; order=2)
118129
else
119-
buffer_scheme = WENO(FT, FT2; order=order-2, bounds, minimum_buffer_upwind_order)
130+
buffer_scheme = WENO(FT; order=order-2, bounds, minimum_buffer_upwind_order, weight_computation)
120131
end
121132
end
122133

123134
N = Int((order + 1) ÷ 2)
124-
return WENO{N, FT, FT2}(bounds, buffer_scheme, advecting_velocity_scheme)
135+
return WENO{N, FT, weight_computation}(bounds, buffer_scheme, advecting_velocity_scheme)
125136
end
126137
end
127138

128139
weno_order(::WENO{N}) where N = 2N-1
129140
Base.eltype(::WENO{N, FT}) where {N, FT} = FT
130-
eltype2(::WENO{N, FT, FT2}) where {N, FT, FT2} = FT2
131-
Base.summary(a::WENO{N, FT, FT2, Nothing}) where {N, FT, FT2} = string("WENO{$N, $FT, $FT2}(order=", 2N-1, ")")
132-
Base.summary(a::WENO{N, FT, FT2, PP}) where {N, FT, FT2, PP} = string("WENO{$N, $FT, $FT2}(order=", 2N-1, ", bounds=", string(a.bounds), ")")
141+
Base.summary(a::WENO{N, FT, WCT, Nothing}) where {N, FT, WCT} = string("WENO{$N, $FT, $WCT}(order=", 2N-1, ")")
142+
Base.summary(a::WENO{N, FT, WCT, PP}) where {N, FT, WCT, PP} = string("WENO{$N, $FT, $WCT}(order=", 2N-1, ", bounds=", string(a.bounds), ")")
133143

134144
function Base.show(io::IO, a::WENO)
135145
print(io, summary(a), '\n')
@@ -145,12 +155,16 @@ function Base.show(io::IO, a::WENO)
145155
print(io, "└── advecting_velocity_scheme: ", summary(a.advecting_velocity_scheme))
146156
end
147157

148-
Adapt.adapt_structure(to, scheme::WENO{N, FT, FT2}) where {N, FT, FT2} =
149-
WENO{N, FT, FT2}(Adapt.adapt(to, scheme.bounds),
158+
Adapt.adapt_structure(to, scheme::WENO{N, FT, WCT}) where {N, FT, WCT} =
159+
WENO{N, FT, WCT}(Adapt.adapt(to, scheme.bounds),
150160
Adapt.adapt(to, scheme.buffer_scheme),
151161
Adapt.adapt(to, scheme.advecting_velocity_scheme))
152162

153-
on_architecture(to, scheme::WENO{N, FT, FT2}) where {N, FT, FT2} =
154-
WENO{N, FT, FT2}(on_architecture(to, scheme.bounds),
163+
on_architecture(to, scheme::WENO{N, FT, WCT}) where {N, FT, WCT} =
164+
WENO{N, FT, WCT}(on_architecture(to, scheme.bounds),
155165
on_architecture(to, scheme.buffer_scheme),
156166
on_architecture(to, scheme.advecting_velocity_scheme))
167+
168+
# Select the default WENO weight computation
169+
# Specific backends may override
170+
default_weno_weight_computation(arch) = Oceananigans.Utils.BackendOptimizedDivision

src/DistributedComputations/DistributedComputations.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,9 @@ function precondition!(p, preconditioner::DistributedFourierTridiagonalPoissonSo
5959
return p
6060
end
6161

62+
# Correctly pass architecture to determine the default weno_weight_computation
63+
Oceananigans.Advection.default_weno_weight_computation(arch::Distributed) =
64+
Oceananigans.Advection.default_weno_weight_computation(child_architecture(arch))
65+
66+
6267
end # module

0 commit comments

Comments
 (0)