Stop the light attenuation kernels at the seafloor - #416
ali-ramadhan wants to merge 1 commit into
Conversation
|
Similar to Simone's comment on CliMA/Oceananigans.jl#5991, doesn't this introduce branching? Is the Oceananigans bug currently causing NaNs in the PAR or are you just saying something like that could cause this? |
|
Thanks for pointing that out. Yes, this PR currently introduces branch divergences on the GPU which did result in a measurable slowdown in that PR. I can refactor to avoid branch divergence.
It is currently causing NaNs so I saw it as two issues worth fixing. Either fix will be enough, but perhaps this PR is more about answering the question: Should light attenuation be computed below the seafloor? |
|
Is it okay if I merge the other PR now and we can discuss more? |
|
Is there a good way to do this that doesn't introduce branching? I guess at the moment we are possibly also calculating in land columns which I think we could fix with the active cell map machinery? |
Yes please go ahead! I just created the stacked PR to avoid merge conflicts, not necessarily to merge the two PRs together. Still figuring out if I like stacked PRs haha.
Lemme look at the code more closely. If we're worried about branch divergence in GPU kernels and CliMA/Oceananigans.jl#5991 avoids the NaNs for now, then we can save "not computing light attenuation below the seafloor" and related issues for a future more fundamental PR. |
On an ImmersedBoundaryGrid the light kernels walked every column down to k = 1, computing PAR in the cells below the seafloor: wasted work, and a field full of meaningless values that other code may reduce over or feed into a vertically implicit solve (#414). `integrate_light_attenuation!` (all four methods) and the multi-band kernel now stop at the first immersed cell, leaving the cells below it at zero, and `_compute_euphotic_depth!` no longer searches below the seafloor. `immersed_cell` is `false` for non-immersed grids, so nothing changes there. Adds tests checking, for every light kernel on CPU and GPU in Float64 and Float32, that the wet cells match the underlying grid exactly and the cells below the seafloor stay zero, and that the euphotic depth is not found inside the seafloor. Fixes #414 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014csaMS7wSc6sRJEuRoYXJr
e2a61c3 to
3716ead
Compare
|
I was thinking about this more, if we know before the kernel launches where the bottom index is (e.g. by writing it to a field when the modifier is constructed) and loop Nz:-1:kf where kf is read from the field, then we don't get branching just some threads waiting while others loop further right? |
|
So I asked Claude to do something benchmarking (see below) and it seems like this PR does not introduce any slowdown with the We can also do something like Does The divergence introduced by What was measured
Four bathymetries, chosen to span the range of lane-level trip-count variation within a warp:
The four variants1. @inbounds for k in grid.Nz:-1:1
...
PAR[i, j, k] = - PAR⁰ * total_cell_average(K, t, la)
K = attenuate(K, t, la)
end2. @inbounds for k in grid.Nz:-1:1
immersed_cell(i, j, k, grid) && break
...
end3. @inbounds for k in grid.Nz:-1:1
...
PAR[i, j, k] = ifelse(immersed_cell(i, j, k, grid), zero(PAR⁰), - PAR⁰ * total_cell_average(K, t, la))
K = attenuate(K, t, la)
end4. kᵇ = @inbounds k_bottom[i, j, 1]
@inbounds for k in grid.Nz:-1:kᵇ
...
endResultsKernel time per launch, and the mean fraction of each column that is wet:
InterpretationThe The divergence is lanes going idle, not code being run twice. There is no Branch-free predication is the worst option. It buys uniform control flow at the price of doing the full-depth work unconditionally, so it lands within noise of Hoisting the check into a bottom index is the only real win, and it is not about divergence. Genuinely divergence-free would be a different algorithm. Replacing the serial descent with a parallel scan along |
This PR resolves #414 by making
integrate_light_attenuation!andupdate_MultiBandPhotosyntheticallyActiveRadiation!stop at the first immersed cell.The multi-band kernel also no longer writes the top cell of fully immersed (land) columns. And
_compute_euphotic_depth!stops at the seafloor too.I suppose CliMA/Oceananigans.jl#5991 could also fix #414 but it feels correct to fix this too.