Oceananigans.jl icon indicating copy to clipboard operation
Oceananigans.jl copied to clipboard

Trying to plot heat map of field in halo region using Makie gives `BoundsError`

Open matt-graham opened this issue 3 weeks ago • 9 comments

I am not sure if this is intended behaviour or not, but when trying to plot a heatmap of a field with indices corresponding to a slice in the halo region, I get a BoundsError due to the line

https://github.com/CliMA/Oceananigans.jl/blob/df5150aebcdeb9bdbeddbbf5dd91cef0cc1d9a0e/ext/OceananigansMakieExt.jl#L149

which gets nodes for field, as with_halos=true is not set.

Minimal reproducing example

using Oceananigans
using CairoMakie

grid = RectilinearGrid(size=(5, 5, 5), halo=(1, 1, 1), x=(0, 1), y=(0, 1), z=(0, 1))
field = Field{Center, Center, Center}(grid, indices=(:, :, grid.Nz + 1))
heatmap(field)

gives error / stack trace

ERROR: BoundsError: attempt to access 5-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64} at index [6:6]
Stacktrace:
  [1] throw_boundserror(A::StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, I::Tuple{UnitRange{Int64}})
    @ Base ./essentials.jl:15
  [2] checkbounds
    @ ./abstractarray.jl:699 [inlined]
  [3] getindex(r::StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, s::UnitRange{Int64})
    @ Base ./twiceprecision.jl:496
  [4] view
    @ ./subarray.jl:234 [inlined]
  [5] rnodes
    @ ~/.julia/packages/Oceananigans/VsQ7B/src/Grids/vertical_discretization.jl:201 [inlined]
  [6] rnodes
    @ ~/.julia/packages/Oceananigans/VsQ7B/src/Grids/vertical_discretization.jl:202 [inlined]
  [7] znodes
    @ ~/.julia/packages/Oceananigans/VsQ7B/src/Grids/vertical_discretization.jl:213 [inlined]
  [8] #nodes#71
    @ ~/.julia/packages/Oceananigans/VsQ7B/src/Grids/rectilinear_grid.jl:489 [inlined]
  [9] nodes
    @ ~/.julia/packages/Oceananigans/VsQ7B/src/Grids/rectilinear_grid.jl:486 [inlined]
 [10] nodes
    @ ~/.julia/packages/Oceananigans/VsQ7B/src/Fields/field.jl:863 [inlined]
 [11] convert_field_argument(f::Field{Center, Center, Center, Nothing, RectilinearGrid{…}, Tuple{…}, OffsetArrays.OffsetArray{…}, Float64, FieldBoundaryConditions{…}, Nothing, Nothing})
    @ OceananigansMakieExt ~/.julia/packages/Oceananigans/VsQ7B/ext/OceananigansMakieExt.jl:149
 [12] _create_plot(F::Function, attributes::Dict{Symbol, Any}, f::Field{Center, Center, Center, Nothing, RectilinearGrid{…}, Tuple{…}, OffsetArrays.OffsetArray{…}, Float64, FieldBoundaryConditions{…}, Nothing, Nothing})
    @ OceananigansMakieExt ~/.julia/packages/Oceananigans/VsQ7B/ext/OceananigansMakieExt.jl:55
 [13] #heatmap#49
    @ ~/.julia/packages/Makie/TOy8O/src/recipes.jl:530 [inlined]
 [14] heatmap(args::Field{Center, Center, Center, Nothing, RectilinearGrid{…}, Tuple{…}, OffsetArrays.OffsetArray{…}, Float64, FieldBoundaryConditions{…}, Nothing, Nothing})
    @ Makie ~/.julia/packages/Makie/TOy8O/src/recipes.jl:528
 [15] top-level scope
    @ REPL[41]:1
Some type information was truncated. Use `show(err)` to see complete types.

matt-graham avatar Nov 28 '25 10:11 matt-graham

Is this maybe a problem with nodes? I think @tomchor was working on making nodes respect Field.indices.

glwagner avatar Nov 28 '25 21:11 glwagner

Is this maybe a problem with nodes? I think @tomchor was working on making nodes respect Field.indices.

Yes. This was already merged in https://github.com/CliMA/Oceananigans.jl/pull/4814. @matt-graham have you tried with the latest version?

tomchor avatar Nov 29 '25 17:11 tomchor

@tomchor did you specifically treat / test the case that the indices involve halo regions? I guess we interpret (:, :, :) as "interior", but then if we have (:, :, Nz+1) this might require a z slice inside the halo regions.

glwagner avatar Nov 30 '25 17:11 glwagner

Yes. This was already merged in #4814. @matt-graham have you tried with the latest version?

Can confirm the above minimal example still errors for me with v0.102.1 with same stack trace as above.

matt-graham avatar Dec 01 '25 10:12 matt-graham

Yes. This was already merged in #4814. @matt-graham have you tried with the latest version?

Can confirm the above minimal example still errors for me with v0.102.1 with same stack trace as above.

Can you make a more minimal example that isolates the nodes issue without requiring CairoMakie? Will help for debugging and solving! Also, this must not be tested.

glwagner avatar Dec 01 '25 14:12 glwagner

Yes. This was already merged in #4814. @matt-graham have you tried with the latest version?

Can confirm the above minimal example still errors for me with v0.102.1 with same stack trace as above.

Can you make a more minimal example that isolates the nodes issue without requiring CairoMakie? Will help for debugging and solving! Also, this must not be tested.

So the following also reproduces the error without requiring CairoMakie

using Oceananigans

grid = RectilinearGrid(size=(5, 5, 5), halo=(1, 1, 1), x=(0, 1), y=(0, 1), z=(0, 1))
field = Field{Center, Center, Center}(grid, indices=(:, :, grid.Nz + 1))
nodes(field)

and is directly analogous to the code path from which the error originates in the CairoMakie example. However in this case, I would say that its unclear if the behaviour is a bug, as there is a with_halos argument to nodes which defaults to false and so it would seem the 'correct' example in that case would be

using Oceananigans

grid = RectilinearGrid(size=(5, 5, 5), halo=(1, 1, 1), x=(0, 1), y=(0, 1), z=(0, 1))
field = Field{Center, Center, Center}(grid, indices=(:, :, grid.Nz + 1))
nodes(field, with_halos=true)

which returns a 3-tuple ([-0.1, 0.1, 0.3, 0.5, 0.7, 0.9, 1.1], [-0.1, 0.1, 0.3, 0.5, 0.7, 0.9, 1.1], [1.1]) of node values as expected. I guess it would be nice if the error reported in the original case specifically pointed out that using with_halos=true would resolve the error and the effect of with_halos was documented, but otherwise it seems the current behaviour is probably as expected?

For my use case the specific issue is that the nodes call in convert_field_argument in OceananigansMakieExt does not set with_halos=true and there isn't anyway to passthrough this keyword argument. A more faithful minimal example might therefore be something like

using Oceananigans

grid = RectilinearGrid(size=(5, 5, 5), halo=(1, 1, 1), x=(0, 1), y=(0, 1), z=(0, 1))
field = Field{Center, Center, Center}(grid, indices=(:, :, grid.Nz + 1))
convert_field_argument(field)

but I don't know how to load and use functionality in an extension module (to allow calling convert_field_argument) without explicitly importing the relevant dependency modules.

matt-graham avatar Dec 01 '25 14:12 matt-graham

@tomchor did you specifically treat / test the case that the indices involve halo regions? I guess we interpret (:, :, :) as "interior", but then if we have (:, :, Nz+1) this might require a z slice inside the halo regions.

I don't remember explicitly adding tests for this. Although if this was tested before, it should still be tested now since I didn't remove any tests.

tomchor avatar Dec 01 '25 15:12 tomchor

Thanks for the MWE @matt-graham. I'll take a look into it once I get back in office. As @glwagner said, we should test this (and any other potential cases the tests are missing).

As a side note, the Makie extension has very bare bones testing. We should probably bulk that sometime soon.

tomchor avatar Dec 01 '25 15:12 tomchor

However in this case, I would say that its unclear if the behaviour is a bug, as there is a with_halos argument to nodes

My opinion is that it is a bug. In fact, I think we should deprecate the with_halos argument. With a plotting extension and the ability to use nodes in abstract operations, there should be no need for users to call nodes themselves.

glwagner avatar Dec 01 '25 16:12 glwagner