Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix for parent_index_range #3573

Merged
merged 15 commits into from
May 16, 2024
Merged

Bugfix for parent_index_range #3573

merged 15 commits into from
May 16, 2024

Conversation

siddharthabishnu
Copy link
Contributor

Closes #3572.

@siddharthabishnu siddharthabishnu changed the title Extend parent array to variables without z-halos Extend Parent Array to Support 1D or 2D Fields Without Halos in Nonexistent Dimensions May 1, 2024
src/Fields/field.jl Outdated Show resolved Hide resolved
@glwagner glwagner changed the title Extend Parent Array to Support 1D or 2D Fields Without Halos in Nonexistent Dimensions Bugfix for parent_index_range May 1, 2024
@glwagner
Copy link
Member

glwagner commented May 1, 2024

There are a couple issues dedicated to index issues with the free surface that might be related. @siddharthabishnu can you try to track these down?

@glwagner glwagner marked this pull request as ready for review May 1, 2024 17:29
@glwagner
Copy link
Member

glwagner commented May 1, 2024

Might be good to add a test (or more than just one) for windowed fields. Even a simple one like

windowed_field = CenterField(grid, indices=(:, :, 1:1))
@test view(windowed_field, :, :, 1:1) isa AbstractArray

or something.

@siddharthabishnu can you add that? Pretty basic test so probably belongs in test_field.jl:

https://github.com/CliMA/Oceananigans.jl/blob/sb/extend-parent-indices/test/test_field.jl

@navidcy
Copy link
Collaborator

navidcy commented May 2, 2024

A lot of tests seem to fail...

@navidcy navidcy added the bug 🐞 Even a perfect program still has bugs label May 2, 2024
@glwagner
Copy link
Member

glwagner commented May 2, 2024

A lot of tests seem to fail...

This is troubling

@glwagner
Copy link
Member

glwagner commented May 2, 2024

Ok, I think it's because parent_index_range is used by the NetCDFOutputWriter. I suspect that it is being used incorrectly there though --- because I am nearly positive that this change does in fact fix a bug.

It's not the nicest code either

Dict("xC" => parent(xnodes(grid, Center(); with_halos=true))[parent_index_range(indices["xC"][1], Center(), TX(), Hx)],
"xF" => parent(xnodes(grid, Face(); with_halos=true))[parent_index_range(indices["xF"][1], Face(), TX(), Hx)],
"yC" => parent(ynodes(grid, Center(); with_halos=true))[parent_index_range(indices["yC"][2], Center(), TY(), Hy)],
"yF" => parent(ynodes(grid, Face(); with_halos=true))[parent_index_range(indices["yF"][2], Face(), TY(), Hy)],
"zC" => parent(znodes(grid, Center(); with_halos=true))[parent_index_range(indices["zC"][3], Center(), TZ(), Hz)],
"zF" => parent(znodes(grid, Face(); with_halos=true))[parent_index_range(indices["zF"][3], Face(), TZ(), Hz)])

@glwagner
Copy link
Member

glwagner commented May 2, 2024

Ok I think I understand the issue. parent_index_range is being used for two different purposes.

In NetCDFOutputWriter the "parent" is an array that spans the entire dimension; we just want to translate indices defined on the grid to indices defined on the underlying parent array (I think the reason we need a function is because we need to treat Nothing locations specially).

In offset_windowed_data the indices argument are the indices of a windowed field itself.

I think we just need two different functions. I'll fix it.

@glwagner
Copy link
Member

glwagner commented May 2, 2024

Ok here's a little more insight into the problem. The issue is actually with view, which doesn't work when called on windowed field. view can only create a windowed field from a full field, right now. In other words, view cannot act on a view. Haha.

I'm extending view to work correctly when the argument itself is already windowed.

This is probably the issue with outputting the free surface too. I can't remember exactly what went wrong there though. The output issue could also hint that things are more convoluted than they should be. Still though, we should be able to create views into fields that are already views. It should be fine.

@navidcy
Copy link
Collaborator

navidcy commented May 2, 2024

nice one!

@glwagner
Copy link
Member

glwagner commented May 2, 2024

OY.

Ok I worked on it a bit. This works:

julia> grid = RectilinearGrid(size=(1, 1, 3), x=(0, 1), y=(0, 1), z=(0, 1));

julia> c = CenterField(grid);

julia> set!(c, (x, y, z) -> rand())
1×1×3 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
└── data: 3×3×9 OffsetArray(::Array{Float64, 3}, 0:2, 0:2, -2:6) with eltype Float64 with indices 0:2×0:2×-2:6
    └── max=0.92472, min=0.40508, mean=0.67047

julia> cv = view(c, :, :, 2:3)
1×1×2 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 2:3)
└── data: 3×3×2 OffsetArray(view(::Array{Float64, 3}, :, :, 5:6), 0:2, 0:2, 2:3) with eltype Float64 with indices 0:2×0:2×2:3
    └── max=0.92472, min=0.681611, mean=0.803165

julia> cvv = view(cv, :, :, 3)
1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 3:3)
└── data: 3×3×1 OffsetArray(view(::Array{Float64, 3}, :, :, 6:6), 0:2, 0:2, 3:3) with eltype Float64 with indices 0:2×0:2×3:3
    └── max=0.681611, min=0.681611, mean=0.681611

julia> cvvv = view(cvv, :, :, 3)
1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 3:3)
└── data: 3×3×1 OffsetArray(view(::Array{Float64, 3}, :, :, 6:6), 0:2, 0:2, 3:3) with eltype Float64 with indices 0:2×0:2×3:3
    └── max=0.681611, min=0.681611, mean=0.681611

julia> interior(c, :, :, 3) .= 0
1×1 view(::Array{Float64, 3}, 2:2, 2:2, 6) with eltype Float64:
 0.0

julia> cvv
1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 3:3)
└── data: 3×3×1 OffsetArray(view(::Array{Float64, 3}, :, :, 6:6), 0:2, 0:2, 3:3) with eltype Float64 with indices 0:2×0:2×3:3
    └── max=0.0, min=0.0, mean=0.0

julia> cv
1×1×2 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 2:3)
└── data: 3×3×2 OffsetArray(view(::Array{Float64, 3}, :, :, 5:6), 0:2, 0:2, 2:3) with eltype Float64 with indices 0:2×0:2×2:3
    └── max=0.92472, min=0.0, mean=0.46236

Note that one of the quirks of fields that come from views, is that parent returns a view:

julia> parent(cv)
3×3×2 view(::Array{Float64, 3}, :, :, 5:6) with eltype Float64:
[:, :, 1] =
 0.0  0.0      0.0
 0.0  0.92472  0.0
 0.0  0.0      0.0

[:, :, 2] =
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> parent(cvv)
3×3×1 view(::Array{Float64, 3}, :, :, 6:6) with eltype Float64:
[:, :, 1] =
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

That's different than if you create a windowed field from scratch:

julia> b = CenterField(grid, indices=(:, :, 3))
1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×3 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 3:3)
└── data: 3×3×1 OffsetArray(::Array{Float64, 3}, 0:2, 0:2, 3:3) with eltype Float64 with indices 0:2×0:2×3:3
    └── max=0.0, min=0.0, mean=0.0

julia> parent(b)
3×3×1 Array{Float64, 3}:
[:, :, 1] =
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

This is how output works --- we use parent to get the data that needs to be saved down.

@glwagner
Copy link
Member

glwagner commented May 2, 2024

@siddharthabishnu could you help by adding some simple unit tests for views of views? It'd be nice to test correctness, I think something like this would work:

grid = RectilinearGrid(size=(1, 1, 3), x=(0, 1), y=(0, 1), z=(0, 1))
c = CenterField(grid)
set!(c, (x, y, z) -> rand())

# First test that regular view is right
cv = view(c, :, :, 2:3)
@test c[1, 1, 2] == cv[1, 1, 2]
@test c[1, 1, 3] == cv[1, 1, 3]

# Now test views of views
cvv = view(cv, :, :, 3)
@test cv[1, 1, 3] == cvv[1, 1, 3]

We may also want to test that things error correctly like

julia> view(cv, :, :, 1)
ERROR: ArgumentError: view indices (Colon(), Colon(), 1) do not intersect field indices (Colon(), Colon(), 2:3)
Stacktrace:
 [1] view(f::Field{…}, i::Function, j::Function, k::Int64)
   @ Oceananigans.Fields ~/Projects/dev/Oceananigans.jl/src/Fields/field.jl:315
 [2] top-level scope
   @ REPL[25]:1
Some type information was truncated. Use `show(err)` to see complete types.

Maybe

@test_throws ArgumentError view(cv, :, :, 1)

Not sure what else we might want maybe @navidcy has ideas.

@glwagner
Copy link
Member

glwagner commented May 2, 2024

Could do

@test_throws BoundsError cv[1, 1, 1]

@glwagner
Copy link
Member

glwagner commented May 2, 2024

And to do those tests on the GPU we need CUDA.@allowscalar.

@navidcy
Copy link
Collaborator

navidcy commented May 2, 2024

Thanks for this @glwagner!

@navidcy
Copy link
Collaborator

navidcy commented May 2, 2024

I ran the doctests locally and this one:

```jldoctest
julia> using Oceananigans
julia> grid = RectilinearGrid(size=(2, 3, 4), x=(0, 1), y=(0, 1), z=(0, 1));
julia> c = CenterField(grid)
2×3×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│ └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
└── data: 6×9×10 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, -2:7) with eltype Float64 with indices -1:4×-2:6×-2:7
└── max=0.0, min=0.0, mean=0.0
julia> c .= rand(size(c)...);
julia> v = view(c, :, 2:3, 1:2)
2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│ └── west: Periodic, east: Periodic, south: Nothing, north: Nothing, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, 2:3, 1:2)
└── data: 6×2×2 OffsetArray(view(::Array{Float64, 3}, :, 5:6, 4:5), -1:4, 2:3, 1:2) with eltype Float64 with indices -1:4×2:3×1:2
└── max=0.972136, min=0.0149088, mean=0.59198
julia> size(v)
(2, 2, 2)
julia> v[2, 2, 2] == c[2, 2, 2]
true

fails.

I need to head out now but I wanted to document this.

@navidcy
Copy link
Collaborator

navidcy commented May 2, 2024

julia> using Oceananigans

julia> grid = RectilinearGrid(size=(2, 3, 4), x=(0, 1), y=(0, 1), z=(0, 1));

julia> c = CenterField(grid)
2×3×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
└── data: 6×9×10 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, -2:7) with eltype Float64 with indices -1:4×-2:6×-2:7
    └── max=0.0, min=0.0, mean=0.0

julia> c .= rand(size(c)...);

julia> v = view(c, :, 2:3, 1:2)
2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Nothing, north: Nothing, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, 2:3, 1:2)
└── data: 6×2×2 OffsetArray(view(::Array{Float64, 3}, :, 1:2, 1:2), -1:4, 2:3, 1:2) with eltype Float64 with indices -1:4×2:3×1:2
    └── max=0.0, min=0.0, mean=0.0

julia> size(v)
(2, 2, 2)

julia> v[2, 2, 2] == c[2, 2, 2]
false

seems like v is empty!

julia> v
2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Nothing, north: Nothing, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, 2:3, 1:2)
└── data: 6×2×2 OffsetArray(view(::Array{Float64, 3}, :, 1:2, 1:2), -1:4, 2:3, 1:2) with eltype Float64 with indices -1:4×2:3×1:2
    └── max=0.0, min=0.0, mean=0.0

@glwagner
Copy link
Member

glwagner commented May 2, 2024

Can't reproduce that @navidcy

julia> using Oceananigans
Precompiling Oceananigans
  1 dependency successfully precompiled in 11 seconds. 160 already precompiled.

julia> grid = RectilinearGrid(size=(2, 3, 4), x=(0, 1), y=(0, 1), z=(0, 1));

julia> c = CenterField(grid)
2×3×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
└── data: 6×9×10 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, -2:7) with eltype Float64 with indices -1:4×-2:6×-2:7
    └── max=0.0, min=0.0, mean=0.0

julia> c .= rand(size(c)...);

julia> v = view(c, :, 2:3, 1:2)
2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Nothing, north: Nothing, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, 2:3, 1:2)
└── data: 6×2×2 OffsetArray(view(::Array{Float64, 3}, :, 5:6, 4:5), -1:4, 2:3, 1:2) with eltype Float64 with indices -1:4×2:3×1:2
    └── max=0.943733, min=0.11545, mean=0.571896

julia> size(v)
(2, 2, 2)

julia> v[2, 2, 2] == c[2, 2, 2]
true

@navidcy
Copy link
Collaborator

navidcy commented May 2, 2024

And all tests pass! Great! Ignore my messages!

@test all(cv[1, 1, i] == c[1, 1, i] for i in firstindex(interior(c), 3)+1:lastindex(interior(c), 3)-1)

# Now test the views of views
cvv = view(cv, :, :, firstindex(interior(c), 3)+2:lastindex(interior(c), 3)-2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe define k_tops = [Nz, Nz+1] and include that in the loop above

@glwagner
Copy link
Member

glwagner commented May 4, 2024

The tests use a lot of scalar indexing that's why they fail on the GPU:

https://buildkite.com/clima/oceananigans/builds/15604#018f40ed-787d-4e74-a5f4-ae1656fa3043/18-724

I think if we are comparing single numbers it makes sense to use @allowscalar.

If we are comparing vectors it could be nice to figure out how to get the tests to run without @allowscalar since presumably this is possible.

@navidcy
Copy link
Collaborator

navidcy commented May 8, 2024

@siddharthabishnu could you deal with this?

@siddharthabishnu
Copy link
Contributor Author

siddharthabishnu commented May 9, 2024

The tests use a lot of scalar indexing that's why they fail on the GPU:

https://buildkite.com/clima/oceananigans/builds/15604#018f40ed-787d-4e74-a5f4-ae1656fa3043/18-724

I think if we are comparing single numbers it makes sense to use @allowscalar.

If we are comparing vectors it could be nice to figure out how to get the tests to run without @allowscalar since presumably this is possible.

Given that we're comparing elements of vectors with a maximum length of 6, I opted to use CUDA.@allowscalar. The impact on performance in this situation is minimal when running on a GPU.

@siddharthabishnu
Copy link
Contributor Author

@siddharthabishnu could you deal with this?

Done. I think it's ready to merge once the tests pass.

@siddharthabishnu
Copy link
Contributor Author

@glwagner, @navidcy, could one of you please review the changes and approve them if you are satisfied?

# @test_throws BoundsError cvv[:, :, 7:8] for a ZFaceField with bounded topology in z else @test_throws BoundsError cvv[:, :, 6:7].
@test_throws BoundsError cvvv[:, :, 1:1+2]
@test_throws BoundsError cvvv[:, :, k_top-2:k_top]
# @test_throws BoundsError cvvv[:, :, 6:8] for a ZFaceField with bounded topology in z else @test_throws BoundsError cvvv[:, :, 5:7].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@siddharthabishnu can you put @allowscalar around only the specific lines where it is needed? I thought by using k_top we eliminated the need for the comments. Not sure what the comments mean

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glwagner, agreed. Resolved in commits 7d68c02 and 427cb51.

@test_throws BoundsError cvv[:, :, k_top-1:k_top]
# @test_throws BoundsError cvv[:, :, 7:8] for a ZFaceField with bounded topology in z else @test_throws BoundsError cvv[:, :, 6:7].
@test_throws BoundsError cvvv[:, :, 1:1+2]
@test_throws BoundsError cvvv[:, :, k_top-2:k_top]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this use interior? We don't ever directly index fields in the user interface

Suggested change
@test_throws BoundsError cvvv[:, :, k_top-2:k_top]
@test_throws BoundsError cvvv[:, :, k_top-2:k_top]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, not, unless we also extend the interior index range like we did with the parent index range. Consider the following MWE:

julia> using Oceananigans

julia> Nx, Ny, Nz = 1, 1, 7;

julia> grid = RectilinearGrid(size=(Nx, Ny, Nz), x=(0, 1), y=(0, 1), z=(0, 1), topology = (Periodic, Periodic, Bounded));

julia> k_top = Nz + 1;

julia> c = ZFaceField(grid)
1×1×8 Field{Center, Center, Face} on RectilinearGrid on CPU
├── grid: 1×1×7 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
└── data: 3×3×14 OffsetArray(::Array{Float64, 3}, 0:2, 0:2, -2:11) with eltype Float64 with indices 0:2×0:2×-2:11
    └── max=0.0, min=0.0, mean=0.0

julia> set!(c, (x, y, z) -> rand())
1×1×8 Field{Center, Center, Face} on RectilinearGrid on CPU
├── grid: 1×1×7 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
└── data: 3×3×14 OffsetArray(::Array{Float64, 3}, 0:2, 0:2, -2:11) with eltype Float64 with indices 0:2×0:2×-2:11
    └── max=0.72276, min=0.0939695, mean=0.428961

julia> cv = view(c, :, :, 1+1:k_top-1)
1×1×6 Field{Center, Center, Face} on RectilinearGrid on CPU
├── grid: 1×1×7 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── boundary conditions: FieldBoundaryConditions
│   └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux
├── indices: (:, :, 2:7)
└── data: 3×3×6 OffsetArray(view(::Array{Float64, 3}, :, :, 5:10), 0:2, 0:2, 2:7) with eltype Float64 with indices 0:2×0:2×2:7
    └── max=0.72276, min=0.0939695, mean=0.503409

julia> interior(cv)
1×1×6 view(::Array{Float64, 3}, 2:2, 2:2, 5:10) with eltype Float64:
[:, :, 1] =
 0.6491566506900277

[:, :, 2] =
 0.5118574586205709

[:, :, 3] =
 0.6214555441666034

[:, :, 4] =
 0.09396949649555086

[:, :, 5] =
 0.7227599953730516

[:, :, 6] =
 0.4212556767008805

julia> interior(cv, :, :, k_top-1)
ERROR: BoundsError: attempt to access 1×1×6 view(::Array{Float64, 3}, 2:2, 2:2, 5:10) with eltype Float64 at index [1:1, 1:1, 7]
Stacktrace:
 [1] throw_boundserror(A::SubArray{Float64, 3, Array{Float64, 3}, Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, false}, I::Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64})
   @ Base ./abstractarray.jl:737
 [2] checkbounds
   @ ./abstractarray.jl:702 [inlined]
 [3] view(::SubArray{Float64, 3, Array{Float64, 3}, Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, false}, ::Function, ::Function, ::Int64)
   @ Base ./subarray.jl:184
 [4] interior(::Field{Center, Center, Face, Nothing, RectilinearGrid{…}, Tuple{…}, OffsetArrays.OffsetArray{…}, Float64, FieldBoundaryConditions{…}, Nothing, Oceananigans.Fields.FieldBoundaryBuffers{…}}, ::Function, ::Function, ::Int64)
   @ Oceananigans.Fields /Users/Sid/Library/CloudStorage/Dropbox/StudyFolder/PostDocMITDesktop/Codes/Oceananigans/extend-parent-indices/src/Fields/field.jl:395
 [5] top-level scope
   @ REPL[20]:1
Some type information was truncated. Use `show(err)` to see complete types.

Currently, the interior indices start from 1 and extend up to the size of the interior of the field.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm not totally sure what the test is contributing

grid = RectilinearGrid(arch, FT, size=(Nx, Ny, Nz), x=(0, 1), y=(0, 1), z=(0, 1), topology = (Periodic, Periodic, ZTopology))
Hx, Hy, Hz = halo_size(grid)

k_top = (FieldType == ZFaceField && ZTopology == Bounded) ? Nz+1 : Nz
Copy link
Collaborator

@navidcy navidcy May 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a function for this; you need to do using Oceananigans.Grids: total_length and then do

Suggested change
k_top = (FieldType == ZFaceField && ZTopology == Bounded) ? Nz+1 : Nz
k_top = total_length(location(c, 3)(), topology(c, 3)(), size(grid, 3))

but after you create the field


# First test that the regular view is correct
cv = view(c, :, :, 1+1:k_top-1)
@test size(cv) == (1, 1, k_top-2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@test size(cv) == (1, 1, k_top-2)
@test size(cv) == (Nx, Ny, k_top-2)

# First test that the regular view is correct
cv = view(c, :, :, 1+1:k_top-1)
@test size(cv) == (1, 1, k_top-2)
@test size(parent(cv)) == (1+2Hx, 1+2Hy, k_top-2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@test size(parent(cv)) == (1+2Hx, 1+2Hy, k_top-2)
@test size(parent(cv)) == (Nx+2Hx, Ny+2Hy, k_top-2)

cv = view(c, :, :, 1+1:k_top-1)
@test size(cv) == (1, 1, k_top-2)
@test size(parent(cv)) == (1+2Hx, 1+2Hy, k_top-2)
CUDA.@allowscalar @test all(cv[1, 1, i] == c[1, 1, i] for i in 1+1:k_top-1)
Copy link
Collaborator

@navidcy navidcy May 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
CUDA.@allowscalar @test all(cv[1, 1, i] == c[1, 1, i] for i in 1+1:k_top-1)
CUDA.@allowscalar @test all(cv[i, j, k] == c[i, j, k] for k in 1+1:k_top-1, j in 1:Ny, i in 1:Nx)

Copy link
Collaborator

@navidcy navidcy May 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@siddharthabishnu could you remove all the rest hardcoded 1's below in the tests? (unless they are not hard coded and I missed it...)

Copy link
Collaborator

@navidcy navidcy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made few suggestions

@siddharthabishnu
Copy link
Contributor Author

siddharthabishnu commented May 15, 2024

made few suggestions

Incorporated in commit d71e14a.

@glwagner
Copy link
Member

good to merge by me

@navidcy
Copy link
Collaborator

navidcy commented May 16, 2024

I'm merging

@navidcy navidcy merged commit 11c317d into main May 16, 2024
46 checks passed
@navidcy navidcy deleted the sb/extend-parent-indices branch May 16, 2024 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐞 Even a perfect program still has bugs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug in determination of indices of parent array by parent_index_range
3 participants