-
Notifications
You must be signed in to change notification settings - Fork 195
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
KernelFunctionOperation
produces incorrect result when given a NamedTuple
with an AbstractOperation
#3455
Comments
I'm having trouble following your example. Can you come up with a simpler illustration of the issue and avoid constructions with many operations on a line? |
Does this illustrate the problem? using Oceananigans
using Oceananigans.AbstractOperations: KernelFunctionOperation
using Oceananigans.Fields: @compute
grid = RectilinearGrid(size = (1, 1, 1), extent = (1, 1, 1))
model = NonhydrostaticModel(; grid)
set!(model, u=2)
get_u(i, j, k, grid, velocities) = velocities.u[i, j, k]
f_op = KernelFunctionOperation{Face, Center, Center}(get_u, model.grid, velocities)
# f_op[1, 1, 1] works?
u_avg = Field(Average(u))
u_prime = u - u_avg
perturbation_velocities = (; u = u_prime)
f_perturbation_op = KernelFunctionOperation{Face, Center, Center}(get_u, model.grid, perturbation_velocities)
# f_perturbation_op[1, 1, 1] doesn't work? If so, check that |
Yes, that's the core of it. I modified your example a bit to make it run and I'm posting it here for completeness: using Oceananigans
grid = RectilinearGrid(size = (1, 1, 1), extent = (1, 1, 1))
model = NonhydrostaticModel(; grid)
set!(model, u=2)
get_u(i, j, k, grid, velocities) = velocities.u[i, j, k]
f_op = KernelFunctionOperation{Face, Center, Center}(get_u, model.grid, model.velocities)
u_avg = Field(Average(model.velocities.u))
u_prime = model.velocities.u - u_avg
perturbation_velocities = (; u = u_prime)
f_perturbation_op = KernelFunctionOperation{Face, Center, Center}(get_u, model.grid, perturbation_velocities) Then And yes, I agree the core of the issue is that But is that the expected behavior? I'd expect either |
Hmm, well it looks like we do compute arguments:
But if the arguments are themselves wrapped inside a We could add a method PS it does seem to test this correctly then we need to further evaluate f_perturbation = Field(f_perturbation_op)
compute!(f_perturbation) |
So basically we could add two methods compute!(tup::Tuple) = Tuple(compute!(t) for t in tup)
compute!(nt::NamedTuple) = NamedTuple(name => compute!(nt[name]) for name in keys(nt)) as a convenience to auto-compute |
This seems reasonable. I'm not sure if there are performance implications. @navidcy @simone-silvestri any thoughts? |
I like the idea adding a method for tuples and named tuples. It seems to be the behavior we want when |
Perhaps a more concise and extendable implementation would be compute!(collection::Union{Tuple, NamedTuple}) = map(compute!, collection) inspired by Adapt |
test grid = RectilinearGrid(size = (1, 1, 1), extent = (1, 1, 1))
c = CenterField(grid)
set!(c, 1)
at_ijk(i, j, k, grid, a) = a[i, j, k]
one_c = Field(1 * c)
two_c = tuple(Field(2 * c))
ten_c = (; ten_c = Field(10 * c))
one_c_op = KernelFunctionOperation{Center, Center, Center}(at_ijk, grid, one_c)
two_c_op = KernelFunctionOperation{Center, Center, Center}(at_ijk, grid, two_c)
ten_c_op = KernelFunctionOperation{Center, Center, Center}(at_ijk, grid, ten_c)
one_c_field = Field(one_c_op)
two_c_field = Field(two_c_op)
ten_c_field = Field(ten_c_op)
compute!(one_c_field)
compute!(two_c_field)
compute!(ten_c_field)
@test all(interior(one_c) .== 1)
@test all(interior(two_c) .== 2)
@test all(interior(ten_c) .== 10) |
I noticed that when I pass a
NamedTuple
to aKernelFunctionOperation
, it'll generally give me an incorrect result if one of the variables used in the calculation is in the tuple and it's an operation.Here's a MWE where I'm creating a model with a constant
u=2
, setting up a simple KFO that returnsu
fromvelocities
:If I just pass
model.velocities
to it, it works fine and returnsu
. If I try to pass, for example, the perturbationu - Average(u)
, then for some reason the KFO returnsu
:I expected the above to either work (i.e. produce the correct result) or throw an error, but returning
u
is unexpected. If, however, I definevelocities = (u = Field(model.velocities.u - Field(Average(model.velocities.u))),)
(i.e. wrap the operation in aField
) then the result is correct.Curiously, if I use
u₀
as the average in the snippet above (without wrapping the operation inField
), it appears to work:Also if I bypass tuples altogether the result seems to be correct:
Are KFOs meant to be used only with
Field
s? Or is this a bug?The text was updated successfully, but these errors were encountered: