From e459373225242a9b334e5014b7944604cb6aceb0 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Fri, 17 Oct 2025 17:07:35 +0200 Subject: [PATCH 01/28] go for it --- src/AbstractOperations/AbstractOperations.jl | 1 + src/AbstractOperations/binary_operations.jl | 32 ++++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/AbstractOperations/AbstractOperations.jl b/src/AbstractOperations/AbstractOperations.jl index 47ac657a6a1..7696712e213 100644 --- a/src/AbstractOperations/AbstractOperations.jl +++ b/src/AbstractOperations/AbstractOperations.jl @@ -16,6 +16,7 @@ using Oceananigans.Fields using Oceananigans.Utils using Oceananigans: location +using Oceananigans.Fields: instantiated_location using Oceananigans.Operators: interpolation_operator import Adapt diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index 41b869e76fb..9effea58d2c 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -35,21 +35,21 @@ indices(β::BinaryOperation) = construct_regionally(intersect_indices, location( """Create a binary operation for `op` acting on `a` and `b` at `Lc`, where `a` and `b` have location `La` and `Lb`.""" -function _binary_operation(Lc, op, a, b, La, Lb, grid) +function _binary_operation(Lc::Tuple{LX, LY, LZ}, op, a, b, La, Lb, grid) where {LX, LY, LZ} ▶a = interpolation_operator(La, Lc) ▶b = interpolation_operator(Lb, Lc) - return BinaryOperation{Lc[1], Lc[2], Lc[3]}(op, a, b, ▶a, ▶b, grid) + return BinaryOperation{LX, LY, LZ}(op, a, b, ▶a, ▶b, grid) end -const ConcreteLocationType = Union{Type{Face}, Type{Center}} +const ConcreteLocationType = Union{Face, Center} # Precedence rules for choosing operation location: choose_location(La, Lb, Lc) = Lc # Fallback to the specification Lc, but also... -choose_location(::Type{Face}, ::Type{Face}, Lc) = Face # keep common locations; and -choose_location(::Type{Center}, ::Type{Center}, Lc) = Center # -choose_location(La::ConcreteLocationType, ::Type{Nothing}, Lc) = La # don't interpolate unspecified locations. -choose_location(::Type{Nothing}, Lb::ConcreteLocationType, Lc) = Lb # +choose_location(::Face, ::Face, Lc) = Face # keep common locations; and +choose_location(::Center, ::Center, Lc) = Center # +choose_location(La::ConcreteLocationType, ::Nothing, Lc) = La # don't interpolate unspecified locations. +choose_location(::Nothing, Lb::ConcreteLocationType, Lc) = Lb # # Apply the function if the inputs are scalars, otherwise broadcast it over the inputs # This can occur in the binary operator code if we index into with an array, e.g. array[1:10] @@ -107,8 +107,8 @@ function define_binary_operator(op) if that is also Nothing, `Lc`. """ function $op(Lc::Tuple, a, b) - La = location(a) - Lb = location(b) + La = instantiated_location(a) + Lb = instantiated_location(b) Lab = choose_location.(La, Lb, Lc) grid = Oceananigans.AbstractOperations.validate_grid(a, b) @@ -127,15 +127,15 @@ function define_binary_operator(op) $op(Lc::Tuple, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(location(a), m, a.grid)) # Sugary versions with default locations - $op(a::AF, b::AF) = $op(location(a), a, b) - $op(a::AF, b) = $op(location(a), a, b) - $op(a, b::AF) = $op(location(b), a, b) + $op(a::AF, b::AF) = $op(instantiated_location(a), a, b) + $op(a::AF, b) = $op(instantiated_location(a), a, b) + $op(a, b::AF) = $op(instantiated_location(b), a, b) - $op(a::AF, b::Number) = $op(location(a), a, b) - $op(a::Number, b::AF) = $op(location(b), a, b) + $op(a::AF, b::Number) = $op(instantiated_location(a), a, b) + $op(a::Number, b::AF) = $op(instantiated_location(b), a, b) - $op(a::AF, b::ConstantField) = $op(location(a), a, b.constant) - $op(a::ConstantField, b::AF) = $op(location(b), a.constant, b) + $op(a::AF, b::ConstantField) = $op(instantiated_location(a), a, b.constant) + $op(a::ConstantField, b::AF) = $op(instantiated_location(b), a.constant, b) $op(a::Number, b::ConstantField) = ConstantField($op(a, b.constant)) $op(a::ConstantField, b::Number) = ConstantField($op(a.constant, b)) From 07eb42f8ba6b79ab50b84c03444b8bb6bf43af11 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Sat, 18 Oct 2025 15:39:51 +0200 Subject: [PATCH 02/28] better --- src/AbstractOperations/grid_metrics.jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/AbstractOperations/grid_metrics.jl b/src/AbstractOperations/grid_metrics.jl index 0dc32a59e89..4a60255cf7d 100644 --- a/src/AbstractOperations/grid_metrics.jl +++ b/src/AbstractOperations/grid_metrics.jl @@ -79,14 +79,13 @@ julia> c_dz[1, 1, 1] 3.0 ``` """ -grid_metric_operation(loc, metric, grid) = - KernelFunctionOperation{loc[1], loc[2], loc[3]}(metric_function(loc, metric), grid) +grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric, grid) where {LX, LY, LZ} = + KernelFunctionOperation{LX, LY, LZ}(metric_function(loc, metric), grid) const NodeMetric = Union{XNode, YNode, ZNode, ΛNode, ΦNode, RNode} -function grid_metric_operation(loc, metric::NodeMetric, grid) - LX, LY, LZ = loc - ℓx, ℓy, ℓz = LX(), LY(), LZ() +function grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric::NodeMetric, grid) where {LX, LY, LZ} + ℓx, ℓy, ℓz = loc ξnode = metric_function(loc, metric) return KernelFunctionOperation{LX, LY, LZ}(ξnode, grid, ℓx, ℓy, ℓz) end From f9c1d2fc9081cd9d6a56162e6e25376ec26793c9 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Sat, 18 Oct 2025 15:44:39 +0200 Subject: [PATCH 03/28] fix more functions --- .../conditional_operations.jl | 22 ++++++++----------- src/AbstractOperations/derivatives.jl | 18 ++++++++------- src/AbstractOperations/multiary_operations.jl | 6 ++--- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/AbstractOperations/conditional_operations.jl b/src/AbstractOperations/conditional_operations.jl index ac3b4ce7382..d67ff2cdbb2 100644 --- a/src/AbstractOperations/conditional_operations.jl +++ b/src/AbstractOperations/conditional_operations.jl @@ -26,9 +26,9 @@ struct ConditionalOperation{LX, LY, LZ, F, C, O, G, M, T} <: AbstractOperation{L end # Some special cases -const NoFuncCO = ConditionalOperation{<:Any, <:Any, <:Any, Nothing} -const NoConditionCO = ConditionalOperation{<:Any, <:Any, <:Any, <:Any, Nothing} -const NoFuncNoConditionCO = ConditionalOperation{<:Any, <:Any, <:Any, Nothing, Nothing} +const NoFuncCO{LX, LY, LZ} = ConditionalOperation{LX, LY, LZ, Nothing} +const NoConditionCO{LX, LY, LZ} = ConditionalOperation{LX, LY, LZ, <:Any, Nothing} +const NoFuncNoConditionCO{LX, LY, LZ} = ConditionalOperation{LX, LY, LZ, Nothing, Nothing} """ ConditionalOperation(operand::AbstractField; @@ -91,12 +91,11 @@ julia> d[2, 1, 1] 10.0 ``` """ -function ConditionalOperation(operand::AbstractField; +function ConditionalOperation(operand::AbstractField{LX, LY, LZ}; func = nothing, condition = nothing, - mask = zero(eltype(operand))) + mask = zero(eltype(operand))) where {LX, LY, LZ} condition = validate_condition(condition, operand) - LX, LY, LZ = location(operand) return ConditionalOperation{LX, LY, LZ}(operand, func, operand.grid, condition, mask) end @@ -111,23 +110,20 @@ function validate_condition(cond::AbstractArray, operand::AbstractField) return cond end -function ConditionalOperation(c::ConditionalOperation; +function ConditionalOperation(c::ConditionalOperation{LX, LY, LZ}; func = c.func, condition = c.condition, - mask = c.mask) + mask = c.mask) where {LX, LY, LZ} condition = validate_condition(condition, operand) - LX, LY, LZ = location(c) compined_func = func ∘ c.func - return ConditionalOperation{LX, LY, LZ}(c.operand, compined_func, c.grid, condition, mask) end -function ConditionalOperation(c::NoFuncCO; +function ConditionalOperation(c::NoFuncCO{LX, LY, LZ}; func = c.func, condition = c.condition, - mask = c.mask) + mask = c.mask) where {LX, LY, LZ} condition = validate_condition(condition, operand) - LX, LY, LZ = location(c) return ConditionalOperation{LX, LY, LZ}(c.operand, func, c.grid, condition, mask) end diff --git a/src/AbstractOperations/derivatives.jl b/src/AbstractOperations/derivatives.jl index 64dddc356ba..ef6b04c6bcf 100644 --- a/src/AbstractOperations/derivatives.jl +++ b/src/AbstractOperations/derivatives.jl @@ -28,9 +28,9 @@ end """Create a derivative operator `∂` acting on `arg` at `L∂`, followed by interpolation to `L` on `grid`.""" -function _derivative(L, ∂, arg, L∂, abstract_∂, grid) +function _derivative(L::Tuple{LX, LY, LZ}, ∂, arg, L∂, abstract_∂, grid) where {LX, LY, LZ} ▶ = interpolation_operator(L∂, L) - return Derivative{L[1], L[2], L[3]}(∂, arg, ▶, abstract_∂, grid) + return Derivative{LX, LY, LZ}(∂, arg, ▶, abstract_∂, grid) end indices(d::Derivative) = indices(d.arg) @@ -41,6 +41,8 @@ indices(d::Derivative) = indices(d.arg) """Return `Center` if given `Face` or `Face` if given `Center`.""" flip(::Type{Face}) = Center flip(::Type{Center}) = Face +flip(::Face) = Center() +flip(::Center) = Face() const LocationType = Union{Type{Face}, Type{Center}, Type{Nothing}} @@ -63,7 +65,7 @@ Return an abstract representation of an ``x``-derivative acting on field `arg` f by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. """ ∂x(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = - _derivative(L, ∂x(LX, LY, LZ), arg, (flip(LX), LY, LZ), ∂x, arg.grid) + _derivative(L, ∂x(LX(), LY(), LZ()), arg, (flip(LX()), LY(), LZ()), ∂x, arg.grid) """ ∂y(L::Tuple, arg::AbstractField) @@ -72,7 +74,7 @@ Return an abstract representation of a ``y``-derivative acting on field `arg` fo by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. """ ∂y(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = - _derivative(L, ∂y(LX, LY, LZ), arg, (LX, flip(LY), LZ), ∂y, arg.grid) + _derivative(L, ∂y(LX(), LY(), LZ()), arg, (LX(), flip(LY()), LZ()), ∂y, arg.grid) """ ∂z(L::Tuple, arg::AbstractField) @@ -81,7 +83,7 @@ Return an abstract representation of a ``z``-derivative acting on field `arg` fo by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. """ ∂z(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = - _derivative(L, ∂z(LX, LY, LZ), arg, (LX, LY, flip(LZ)), ∂z, arg.grid) + _derivative(L, ∂z(LX(), LY(), LZ()), arg, (LX(), LY(), flip(LZ())), ∂z, arg.grid) # Defaults @@ -90,21 +92,21 @@ by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. Return an abstract representation of a ``x``-derivative acting on field `arg`. """ -∂x(arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂x((flip(LX), LY, LZ), arg) +∂x(arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂x((flip(LX()), LY(), LZ()), arg) """ ∂y(arg::AbstractField) Return an abstract representation of a ``y``-derivative acting on field `arg`. """ -∂y(arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂y((LX, flip(LY), LZ), arg) +∂y(arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂y((LX(), flip(LY()), LZ()), arg) """ ∂z(arg::AbstractField) Return an abstract representation of a ``z``-derivative acting on field `arg`. """ -∂z(arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂z((LX, LY, flip(LZ)), arg) +∂z(arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂z((LX(), LY(), flip(LZ())), arg) ##### ##### Nested computations diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index dc9c41d972d..eb9dbac5e47 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -22,9 +22,9 @@ end indices(Π::MultiaryOperation) = construct_regionally(intersect_indices, location(Π), Π.args...) -function _multiary_operation(L, op, args, Largs, grid) +function _multiary_operation(L::Tuple{LX, LY, LZ}, op, args, Largs, grid) where {LX, LY, LZ} ▶ = Tuple(interpolation_operator(La, L) for La in Largs) - return MultiaryOperation{L[1], L[2], L[3]}(op, Tuple(a for a in args), ▶, grid) + return MultiaryOperation{LX, LY, LZ}(op, Tuple(a for a in args), ▶, grid) end # Recompute location of multiary operation @@ -52,7 +52,7 @@ function define_multiary_operator(op) $op(a::Oceananigans.Fields.AbstractField, b::Union{Function, Oceananigans.Fields.AbstractField}, c::Union{Function, Oceananigans.Fields.AbstractField}, - d::Union{Function, Oceananigans.Fields.AbstractField}...) = $op(Oceananigans.Fields.location(a), a, b, c, d...) + d::Union{Function, Oceananigans.Fields.AbstractField}...) = $op(Oceananigans.Fields.instantiated_location(a), a, b, c, d...) end end From c36775196ededeea55bf0c8e7dac73a2390dcf63 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Sat, 18 Oct 2025 15:45:49 +0200 Subject: [PATCH 04/28] also unary operations --- src/AbstractOperations/unary_operations.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index d6c05d058ec..3ec100c1372 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -28,9 +28,9 @@ indices(υ::UnaryOperation) = indices(υ.arg) """Create a unary operation for `operator` acting on `arg` which interpolates the result from `Larg` to `L`.""" -function _unary_operation(L, operator, arg, Larg, grid) +function _unary_operation(L::Tuple{{LX, LY, LZ}}, operator, arg, Larg, grid) where {LX, LY, LZ} ▶ = interpolation_operator(Larg, L) - return UnaryOperation{L[1], L[2], L[3]}(operator, arg, ▶, grid) + return UnaryOperation{LX, LY, LZ}(operator, arg, ▶, grid) end # Recompute location of unary operation From 41dff5903a9ad7874aac0a129334689c7a30d803 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Sat, 18 Oct 2025 15:47:20 +0200 Subject: [PATCH 05/28] bugfix --- src/AbstractOperations/unary_operations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index 3ec100c1372..c7f00507740 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -28,7 +28,7 @@ indices(υ::UnaryOperation) = indices(υ.arg) """Create a unary operation for `operator` acting on `arg` which interpolates the result from `Larg` to `L`.""" -function _unary_operation(L::Tuple{{LX, LY, LZ}}, operator, arg, Larg, grid) where {LX, LY, LZ} +function _unary_operation(L::Tuple{LX, LY, LZ}, operator, arg, Larg, grid) where {LX, LY, LZ} ▶ = interpolation_operator(Larg, L) return UnaryOperation{LX, LY, LZ}(operator, arg, ▶, grid) end From 2cd2b97d6bf0752ca5ef848c7125168c142233f4 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Mon, 20 Oct 2025 10:27:09 +0200 Subject: [PATCH 06/28] some more changes --- src/Fields/scans.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Fields/scans.jl b/src/Fields/scans.jl index d31d557a020..7dad4cc5771 100644 --- a/src/Fields/scans.jl +++ b/src/Fields/scans.jl @@ -34,8 +34,12 @@ Base.summary(::Accumulating) = "Accumulating" const Reduction = Scan{<:AbstractReducing} const Accumulation = Scan{<:AbstractAccumulating} -scan_indices(::AbstractReducing, indices; dims) = Tuple(i ∈ dims ? Colon() : indices[i] for i in 1:3) -scan_indices(::AbstractAccumulating, indices; dims) = indices +@inline location(s::Scan) = location(s.operand) +@inline instantiated_location(s::Scan) = instantiated_location(s.operand) + +scan_indices(::AbstractReducing, indices, dims) = Tuple(i ∈ dims ? Colon() : indices[i] for i in 1:3) +scan_indices(::AbstractAccumulating, indices, dims) = indices +scan_indices(::AbstractReducing, ::Tuple{Colon, Colon, Colon}, dims) = (:, :, :) Base.summary(s::Scan) = string(summary(s.type), " ", s.scan!, @@ -52,7 +56,7 @@ function Field(scan::Scan; grid = operand.grid LX, LY, LZ = loc = instantiated_location(scan) dims = filter_nothing_dims(scan.dims, loc) - indices = scan_indices(scan.type, indices; dims) + indices = scan_indices(scan.type, indices, dims) if isnothing(data) data = new_data(grid, loc, indices) From 851a605eca131a781787ee9b30f30eb24fe2c356 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 21 Oct 2025 14:14:15 +0200 Subject: [PATCH 07/28] revert conditional operations --- .../conditional_operations.jl | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/AbstractOperations/conditional_operations.jl b/src/AbstractOperations/conditional_operations.jl index d67ff2cdbb2..ac3b4ce7382 100644 --- a/src/AbstractOperations/conditional_operations.jl +++ b/src/AbstractOperations/conditional_operations.jl @@ -26,9 +26,9 @@ struct ConditionalOperation{LX, LY, LZ, F, C, O, G, M, T} <: AbstractOperation{L end # Some special cases -const NoFuncCO{LX, LY, LZ} = ConditionalOperation{LX, LY, LZ, Nothing} -const NoConditionCO{LX, LY, LZ} = ConditionalOperation{LX, LY, LZ, <:Any, Nothing} -const NoFuncNoConditionCO{LX, LY, LZ} = ConditionalOperation{LX, LY, LZ, Nothing, Nothing} +const NoFuncCO = ConditionalOperation{<:Any, <:Any, <:Any, Nothing} +const NoConditionCO = ConditionalOperation{<:Any, <:Any, <:Any, <:Any, Nothing} +const NoFuncNoConditionCO = ConditionalOperation{<:Any, <:Any, <:Any, Nothing, Nothing} """ ConditionalOperation(operand::AbstractField; @@ -91,11 +91,12 @@ julia> d[2, 1, 1] 10.0 ``` """ -function ConditionalOperation(operand::AbstractField{LX, LY, LZ}; +function ConditionalOperation(operand::AbstractField; func = nothing, condition = nothing, - mask = zero(eltype(operand))) where {LX, LY, LZ} + mask = zero(eltype(operand))) condition = validate_condition(condition, operand) + LX, LY, LZ = location(operand) return ConditionalOperation{LX, LY, LZ}(operand, func, operand.grid, condition, mask) end @@ -110,20 +111,23 @@ function validate_condition(cond::AbstractArray, operand::AbstractField) return cond end -function ConditionalOperation(c::ConditionalOperation{LX, LY, LZ}; +function ConditionalOperation(c::ConditionalOperation; func = c.func, condition = c.condition, - mask = c.mask) where {LX, LY, LZ} + mask = c.mask) condition = validate_condition(condition, operand) + LX, LY, LZ = location(c) compined_func = func ∘ c.func + return ConditionalOperation{LX, LY, LZ}(c.operand, compined_func, c.grid, condition, mask) end -function ConditionalOperation(c::NoFuncCO{LX, LY, LZ}; +function ConditionalOperation(c::NoFuncCO; func = c.func, condition = c.condition, - mask = c.mask) where {LX, LY, LZ} + mask = c.mask) condition = validate_condition(condition, operand) + LX, LY, LZ = location(c) return ConditionalOperation{LX, LY, LZ}(c.operand, func, c.grid, condition, mask) end From 07213b0d26061dd09fa4469c6e0648b8701e3da7 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 21 Oct 2025 14:15:32 +0200 Subject: [PATCH 08/28] solve grid metric --- src/AbstractOperations/binary_operations.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index 9effea58d2c..c4d033d2fb7 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -123,8 +123,8 @@ function define_binary_operator(op) $op(Lc::Tuple, f::Function, b::AbstractField) = $op(Lc, FunctionField(location(b), f, b.grid), b) $op(Lc::Tuple, a::AbstractField, f::Function) = $op(Lc, a, FunctionField(location(a), f, a.grid)) - $op(Lc::Tuple, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(location(b), m, b.grid), b) - $op(Lc::Tuple, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(location(a), m, a.grid)) + $op(Lc::Tuple, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(instantiated_location(b), m, b.grid), b) + $op(Lc::Tuple, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(instantiated_location(a), m, a.grid)) # Sugary versions with default locations $op(a::AF, b::AF) = $op(instantiated_location(a), a, b) From 0f75d652961826d23c13799b4613455029a03786 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 21 Oct 2025 14:28:01 +0200 Subject: [PATCH 09/28] instantiate unary operations --- src/AbstractOperations/unary_operations.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index c7f00507740..88315584283 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -91,7 +91,7 @@ macro unary(ops...) import Oceananigans.Grids: AbstractGrid import Oceananigans.Fields: AbstractField - local location = Oceananigans.Fields.location + local instantiated_location = Oceananigans.Fields.instantiated_location @inline $op(i, j, k, grid::AbstractGrid, a) = @inbounds $op(a[i, j, k]) @inline $op(i, j, k, grid::AbstractGrid, a::Number) = $op(a) @@ -103,11 +103,11 @@ macro unary(ops...) `a`, and subsequently interpolated to the location indicated by `Lop`. """ function $op(Lop::Tuple, a::AbstractField) - L = location(a) + L = instantiated_location(a) return Oceananigans.AbstractOperations._unary_operation(Lop, $op, a, L, a.grid) end - $op(a::AbstractField) = $op(location(a), a) + $op(a::AbstractField) = $op(instantiated_location(a), a) push!(Oceananigans.AbstractOperations.operators, Symbol($op)) push!(Oceananigans.AbstractOperations.unary_operators, Symbol($op)) From 675d981511afda6121c6cfa7893aa9067f931db6 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 21 Oct 2025 14:40:32 +0200 Subject: [PATCH 10/28] correct binary operations --- src/AbstractOperations/binary_operations.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index c4d033d2fb7..38ef095e96f 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -45,9 +45,9 @@ end const ConcreteLocationType = Union{Face, Center} # Precedence rules for choosing operation location: -choose_location(La, Lb, Lc) = Lc # Fallback to the specification Lc, but also... -choose_location(::Face, ::Face, Lc) = Face # keep common locations; and -choose_location(::Center, ::Center, Lc) = Center # +choose_location(La, Lb, Lc) = Lc # Fallback to the specification Lc, but also... +choose_location(::Face, ::Face, Lc) = Face() # keep common locations; and +choose_location(::Center, ::Center, Lc) = Center() # choose_location(La::ConcreteLocationType, ::Nothing, Lc) = La # don't interpolate unspecified locations. choose_location(::Nothing, Lb::ConcreteLocationType, Lc) = Lb # From 42e8ced92beb1349e6b3328580f90bbceefcd54c Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 21 Oct 2025 15:00:16 +0200 Subject: [PATCH 11/28] another bugfix --- .../compute_vertically_integrated_variables.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Models/HydrostaticFreeSurfaceModels/compute_vertically_integrated_variables.jl b/src/Models/HydrostaticFreeSurfaceModels/compute_vertically_integrated_variables.jl index d9bfe26e3bc..d3bf08f4f20 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/compute_vertically_integrated_variables.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/compute_vertically_integrated_variables.jl @@ -10,8 +10,8 @@ function compute_vertically_integrated_lateral_areas!(∫ᶻ_A) field_grid = ∫ᶻ_A.xᶠᶜᶜ.grid - Axᶠᶜᶜ = grid_metric_operation((Face, Center, Center), Ax, field_grid) - Ayᶜᶠᶜ = grid_metric_operation((Center, Face, Center), Ay, field_grid) + Axᶠᶜᶜ = grid_metric_operation((Face(), Center(), Center()), Ax, field_grid) + Ayᶜᶠᶜ = grid_metric_operation((Center(), Face(), Center()), Ay, field_grid) sum!(∫ᶻ_A.xᶠᶜᶜ, Axᶠᶜᶜ) sum!(∫ᶻ_A.yᶜᶠᶜ, Ayᶜᶠᶜ) From 5c1e2a738bfa3858af172c7e606c5a6329bbcc7c Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 4 Nov 2025 07:49:54 +0100 Subject: [PATCH 12/28] fix the @at --- src/AbstractOperations/at.jl | 17 ++++++++++++++++- src/AbstractOperations/derivatives.jl | 8 ++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/AbstractOperations/at.jl b/src/AbstractOperations/at.jl index 57f685f9cc4..6ab924dd6d8 100644 --- a/src/AbstractOperations/at.jl +++ b/src/AbstractOperations/at.jl @@ -22,6 +22,20 @@ function insert_location!(ex::Expr, location) return nothing end +# Transform expressions like :((LX, LY, LZ)) into :((LX(), LY(), LZ())) +# when LX, LY, LZ are Face, Center, or Nothing. Leave eveything else unchanged. +function instantiate_location_expression(exp::Expr) + new_exp = deepcopy(exp) + for (i, arg) in enumerate(new_exp.args) + new_exp.args[i] = instantiate_location_expression(arg) + end + return new_exp +end + +instantiate_location_expression(arg) = arg == :Center ? :(Center()) : + arg == :Face ? :(Face() ) : + arg == :Nothing ? :(nothing ) : arg + "Fallback for when `insert_location` is called on objects other than expressions." insert_location!(anything, location) = nothing @@ -43,11 +57,12 @@ Modify the `abstract_operation` so that it returns values at `location`, where `location` is a 3-tuple of `Face`s and `Center`s. """ macro at(location, abstract_operation) + location = instantiate_location_expression(location) insert_location!(abstract_operation, location) # We wrap it all in an interpolator to help "stubborn" binary operations # arrive in the right place. - wrapped_operation = quote + wrapped_operation = quote interpolate_operation($(esc(location)), $(esc(abstract_operation))) end diff --git a/src/AbstractOperations/derivatives.jl b/src/AbstractOperations/derivatives.jl index ef6b04c6bcf..eb68f83de0c 100644 --- a/src/AbstractOperations/derivatives.jl +++ b/src/AbstractOperations/derivatives.jl @@ -44,16 +44,16 @@ flip(::Type{Center}) = Face flip(::Face) = Center() flip(::Center) = Face() -const LocationType = Union{Type{Face}, Type{Center}, Type{Nothing}} +const Location = Union{Face, Center, Nothing} """Return the ``x``-derivative function acting at (`X`, `Y`, `Any`).""" -∂x(X::LocationType, Y::LocationType, Z::LocationType) = eval(Symbol(:∂x, interpolation_code(flip(X)), interpolation_code(Y), interpolation_code(Z))) +∂x(X::Location, Y::Location, Z::Location) = eval(Symbol(:∂x, interpolation_code(flip(X)), interpolation_code(Y), interpolation_code(Z))) """Return the ``y``-derivative function acting at (`X`, `Y`, `Any`).""" -∂y(X::LocationType, Y::LocationType, Z::LocationType) = eval(Symbol(:∂y, interpolation_code(X), interpolation_code(flip(Y)), interpolation_code(Z))) +∂y(X::Location, Y::Location, Z::Location) = eval(Symbol(:∂y, interpolation_code(X), interpolation_code(flip(Y)), interpolation_code(Z))) """Return the ``z``-derivative function acting at (`Any`, `Any`, `Z`).""" -∂z(X::LocationType, Y::LocationType, Z::LocationType) = eval(Symbol(:∂z, interpolation_code(X), interpolation_code(Y), interpolation_code(flip(Z)))) +∂z(X::Location, Y::Location, Z::Location) = eval(Symbol(:∂z, interpolation_code(X), interpolation_code(Y), interpolation_code(flip(Z)))) const derivative_operators = Set([:∂x, :∂y, :∂z]) push!(operators, derivative_operators...) From 0bbc3d66c2f86b489e29a1830d730f6e01667c01 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 4 Nov 2025 08:25:12 +0100 Subject: [PATCH 13/28] fix poisson operations --- src/AbstractOperations/AbstractOperations.jl | 2 ++ src/AbstractOperations/derivatives.jl | 2 -- src/AbstractOperations/grid_metrics.jl | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/AbstractOperations/AbstractOperations.jl b/src/AbstractOperations/AbstractOperations.jl index 7696712e213..5610ee865d3 100644 --- a/src/AbstractOperations/AbstractOperations.jl +++ b/src/AbstractOperations/AbstractOperations.jl @@ -33,6 +33,8 @@ abstract type AbstractOperation{LX, LY, LZ, G, T} <: AbstractField{LX, LY, LZ, G const AF = AbstractField # used in unary_operations.jl, binary_operations.jl, etc +const Location = Union{Face, Center, Nothing} + # We have no halos to fill @inline fill_halo_regions!(::AbstractOperation, args...; kwargs...) = nothing diff --git a/src/AbstractOperations/derivatives.jl b/src/AbstractOperations/derivatives.jl index eb68f83de0c..679015ed60d 100644 --- a/src/AbstractOperations/derivatives.jl +++ b/src/AbstractOperations/derivatives.jl @@ -44,8 +44,6 @@ flip(::Type{Center}) = Face flip(::Face) = Center() flip(::Center) = Face() -const Location = Union{Face, Center, Nothing} - """Return the ``x``-derivative function acting at (`X`, `Y`, `Any`).""" ∂x(X::Location, Y::Location, Z::Location) = eval(Symbol(:∂x, interpolation_code(flip(X)), interpolation_code(Y), interpolation_code(Z))) diff --git a/src/AbstractOperations/grid_metrics.jl b/src/AbstractOperations/grid_metrics.jl index 4a60255cf7d..0b2619b2fda 100644 --- a/src/AbstractOperations/grid_metrics.jl +++ b/src/AbstractOperations/grid_metrics.jl @@ -79,12 +79,14 @@ julia> c_dz[1, 1, 1] 3.0 ``` """ -grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric, grid) where {LX, LY, LZ} = +grid_metric_operation(loc metric, grid) = grid_metric_operation(instantiate(loc), metric, grid) + +grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric, grid) where {LX<:Location, LY<:Location, LZ<:Location} = KernelFunctionOperation{LX, LY, LZ}(metric_function(loc, metric), grid) const NodeMetric = Union{XNode, YNode, ZNode, ΛNode, ΦNode, RNode} -function grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric::NodeMetric, grid) where {LX, LY, LZ} +function grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric::NodeMetric, grid) where {LX<:Location, LY<:Location, LZ<:Location} ℓx, ℓy, ℓz = loc ξnode = metric_function(loc, metric) return KernelFunctionOperation{LX, LY, LZ}(ξnode, grid, ℓx, ℓy, ℓz) From d3abb9a1c87df81b3e84cc509ac87853f5c18a39 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 4 Nov 2025 08:27:50 +0100 Subject: [PATCH 14/28] bugfix --- src/AbstractOperations/grid_metrics.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AbstractOperations/grid_metrics.jl b/src/AbstractOperations/grid_metrics.jl index 0b2619b2fda..cc482f27591 100644 --- a/src/AbstractOperations/grid_metrics.jl +++ b/src/AbstractOperations/grid_metrics.jl @@ -79,7 +79,7 @@ julia> c_dz[1, 1, 1] 3.0 ``` """ -grid_metric_operation(loc metric, grid) = grid_metric_operation(instantiate(loc), metric, grid) +grid_metric_operation(loc::Tuple, metric, grid) = grid_metric_operation(instantiate(loc), metric, grid) grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric, grid) where {LX<:Location, LY<:Location, LZ<:Location} = KernelFunctionOperation{LX, LY, LZ}(metric_function(loc, metric), grid) From 83bcf10d7f266a6b6085703a100928eaf706c6ac Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Wed, 5 Nov 2025 06:23:41 +0100 Subject: [PATCH 15/28] Update src/AbstractOperations/at.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> --- src/AbstractOperations/at.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AbstractOperations/at.jl b/src/AbstractOperations/at.jl index 6ab924dd6d8..3c02c703f05 100644 --- a/src/AbstractOperations/at.jl +++ b/src/AbstractOperations/at.jl @@ -62,7 +62,7 @@ macro at(location, abstract_operation) # We wrap it all in an interpolator to help "stubborn" binary operations # arrive in the right place. - wrapped_operation = quote + wrapped_operation = quote interpolate_operation($(esc(location)), $(esc(abstract_operation))) end From 9a6af2edffadd400b80aaee38699725726b0d283 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Wed, 5 Nov 2025 06:47:21 +0100 Subject: [PATCH 16/28] anothe rbug --- src/MultiRegion/multi_region_models.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MultiRegion/multi_region_models.jl b/src/MultiRegion/multi_region_models.jl index c637ac6870b..a1d93fec957 100644 --- a/src/MultiRegion/multi_region_models.jl +++ b/src/MultiRegion/multi_region_models.jl @@ -1,6 +1,6 @@ using Oceananigans.Models: AbstractModel using Oceananigans.Advection: WENO, VectorInvariant -using Oceananigans.BuoyancyFormulations: BuoyancyForce, NegativeZDirection, AbstractBuoyancyFormulation, validate_unit_vector +using Oceananigans.BuoyancyFormulations: NegativeZDirection, AbstractBuoyancyFormulation, validate_unit_vector using Oceananigans.Models.HydrostaticFreeSurfaceModels: AbstractFreeSurface using Oceananigans.TimeSteppers: AbstractTimeStepper, QuasiAdamsBashforth2TimeStepper using Oceananigans.Models: PrescribedVelocityFields @@ -10,6 +10,7 @@ using Oceananigans.Advection: OnlySelfUpwinding, CrossAndSelfUpwinding using Oceananigans.ImmersedBoundaries: GridFittedBottom, PartialCellBottom, GridFittedBoundary using Oceananigans.Solvers: ConjugateGradientSolver +import Oceananigans.BuoyancyFormulations: BuoyancyForce import Oceananigans.Advection: WENO, cell_advection_timescale, adapt_advection_order import Oceananigans.Models.HydrostaticFreeSurfaceModels: build_implicit_step_solver, validate_tracer_advection import Oceananigans.TurbulenceClosures: implicit_diffusion_solver From a1ee7cafd409f20d98dd0db972211841874a94d6 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Wed, 5 Nov 2025 06:52:30 +0100 Subject: [PATCH 17/28] fix grid metric operation --- src/AbstractOperations/grid_metrics.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/AbstractOperations/grid_metrics.jl b/src/AbstractOperations/grid_metrics.jl index cc482f27591..973d6897d9d 100644 --- a/src/AbstractOperations/grid_metrics.jl +++ b/src/AbstractOperations/grid_metrics.jl @@ -79,11 +79,12 @@ julia> c_dz[1, 1, 1] 3.0 ``` """ -grid_metric_operation(loc::Tuple, metric, grid) = grid_metric_operation(instantiate(loc), metric, grid) - grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric, grid) where {LX<:Location, LY<:Location, LZ<:Location} = KernelFunctionOperation{LX, LY, LZ}(metric_function(loc, metric), grid) +# Instantiated location if location types are passed as values +grid_metric_operation(Loc::Tuple, metric, grid) = grid_metric_operation((Loc[1](), Loc[2](), Loc[3]()), metric, grid) + const NodeMetric = Union{XNode, YNode, ZNode, ΛNode, ΦNode, RNode} function grid_metric_operation(loc::Tuple{LX, LY, LZ}, metric::NodeMetric, grid) where {LX<:Location, LY<:Location, LZ<:Location} From fe7e945b1f77359e911a648075d44dbca1f80ad6 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Wed, 5 Nov 2025 07:42:02 +0100 Subject: [PATCH 18/28] instantiate everything just in case --- src/AbstractOperations/binary_operations.jl | 11 +++++++---- src/AbstractOperations/derivatives.jl | 17 +++++++++++------ src/AbstractOperations/multiary_operations.jl | 5 ++++- src/AbstractOperations/unary_operations.jl | 5 ++++- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index 38ef095e96f..5e9330657d5 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -35,9 +35,9 @@ indices(β::BinaryOperation) = construct_regionally(intersect_indices, location( """Create a binary operation for `op` acting on `a` and `b` at `Lc`, where `a` and `b` have location `La` and `Lb`.""" -function _binary_operation(Lc::Tuple{LX, LY, LZ}, op, a, b, La, Lb, grid) where {LX, LY, LZ} - ▶a = interpolation_operator(La, Lc) - ▶b = interpolation_operator(Lb, Lc) +function _binary_operation(Lc::Tuple{LX, LY, LZ}, op, a, b, La, Lb, grid) where {LX<:Location, LY<:Location, LZ<:Location} + ▶a = interpolation_operator(La, Lc) + ▶b = interpolation_operator(Lb, Lc) return BinaryOperation{LX, LY, LZ}(op, a, b, ▶a, ▶b, grid) end @@ -106,7 +106,7 @@ function define_binary_operator(op) the location of the dimension in question is supplied either by `location(b)` or if that is also Nothing, `Lc`. """ - function $op(Lc::Tuple, a, b) + function $op(Lc::Tuple{<:Location, <:Location, <:Location}, a, b) La = instantiated_location(a) Lb = instantiated_location(b) Lab = choose_location.(La, Lb, Lc) @@ -116,6 +116,9 @@ function define_binary_operator(op) return Oceananigans.AbstractOperations._binary_operation(Lab, $op, a, b, La, Lb, grid) end + # instantiate location if types are passed + $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) + # Numbers are not fields... $op(Lc::Tuple, a::Number, b::Number) = $op(a, b) diff --git a/src/AbstractOperations/derivatives.jl b/src/AbstractOperations/derivatives.jl index 679015ed60d..cc822661a2e 100644 --- a/src/AbstractOperations/derivatives.jl +++ b/src/AbstractOperations/derivatives.jl @@ -60,29 +60,34 @@ push!(operators, derivative_operators...) ∂x(L::Tuple, arg::AbstractField) Return an abstract representation of an ``x``-derivative acting on field `arg` followed -by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. +by interpolation to `L`, where `L` is a 3-tuple of instantiated `Face`s and `Center`s. """ -∂x(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = +∂x(L::Tuple{<:Location, <:Location, <:Location}, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = _derivative(L, ∂x(LX(), LY(), LZ()), arg, (flip(LX()), LY(), LZ()), ∂x, arg.grid) """ ∂y(L::Tuple, arg::AbstractField) Return an abstract representation of a ``y``-derivative acting on field `arg` followed -by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. +by interpolation to `L`, where `L` is a 3-tuple of instantiated `Face`s and `Center`s. """ -∂y(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = +∂y(L::Tuple{<:Location, <:Location, <:Location}, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = _derivative(L, ∂y(LX(), LY(), LZ()), arg, (LX(), flip(LY()), LZ()), ∂y, arg.grid) """ ∂z(L::Tuple, arg::AbstractField) Return an abstract representation of a ``z``-derivative acting on field `arg` followed -by interpolation to `L`, where `L` is a 3-tuple of `Face`s and `Center`s. +by interpolation to `L`, where `L` is a 3-tuple of instantiated `Face`s and `Center`s. """ -∂z(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = +∂z(L::Tuple{<:Location, <:Location, <:Location}, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = _derivative(L, ∂z(LX(), LY(), LZ()), arg, (LX(), LY(), flip(LZ())), ∂z, arg.grid) +# Instantiate location if types are passed +∂x(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂x((L[1](), L[2](), L[3]()), arg) +∂y(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂y((L[1](), L[2](), L[3]()), arg) +∂z(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂z((L[1](), L[2](), L[3]()), arg) + # Defaults """ diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index eb9dbac5e47..64cbbfa89da 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -33,7 +33,7 @@ end """Return an expression that defines an abstract `MultiaryOperator` named `op` for `AbstractField`.""" function define_multiary_operator(op) return quote - function $op(Lop::Tuple, + function $op(Lop::Tuple{{<:Location, <:Location, <:Location}}, a::Union{Function, Number, Oceananigans.Fields.AbstractField}, b::Union{Function, Number, Oceananigans.Fields.AbstractField}, c::Union{Function, Number, Oceananigans.Fields.AbstractField}, @@ -49,6 +49,9 @@ function define_multiary_operator(op) return Oceananigans.AbstractOperations._multiary_operation(Lop, $op, args, Largs, grid) end + # Instantiate location if types are passed + $op(Lop::Tuple, a, b, c, d...) = $op((Lop[1](), Lop[2](), Lop[3]()), a, b, c, d...) + $op(a::Oceananigans.Fields.AbstractField, b::Union{Function, Oceananigans.Fields.AbstractField}, c::Union{Function, Oceananigans.Fields.AbstractField}, diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index 88315584283..ed0be1ce6c7 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -102,11 +102,14 @@ macro unary(ops...) Returns an abstract representation of the operator `$($op)` acting on the Oceananigans `Field` `a`, and subsequently interpolated to the location indicated by `Lop`. """ - function $op(Lop::Tuple, a::AbstractField) + function $op(Lop::Tuple{<:Location, <:Location, <:Location}, a::AbstractField) L = instantiated_location(a) return Oceananigans.AbstractOperations._unary_operation(Lop, $op, a, L, a.grid) end + # instantiate location if types are passed + $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) + $op(a::AbstractField) = $op(instantiated_location(a), a) push!(Oceananigans.AbstractOperations.operators, Symbol($op)) From 911c9a184640514a9172add2cfb308a9e0fa6460 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Wed, 5 Nov 2025 07:47:46 +0100 Subject: [PATCH 19/28] some more bugfixes --- src/AbstractOperations/derivatives.jl | 6 +++--- src/AbstractOperations/multiary_operations.jl | 2 +- src/AbstractOperations/unary_operations.jl | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AbstractOperations/derivatives.jl b/src/AbstractOperations/derivatives.jl index cc822661a2e..83ca802bf81 100644 --- a/src/AbstractOperations/derivatives.jl +++ b/src/AbstractOperations/derivatives.jl @@ -84,9 +84,9 @@ by interpolation to `L`, where `L` is a 3-tuple of instantiated `Face`s and `Ce _derivative(L, ∂z(LX(), LY(), LZ()), arg, (LX(), LY(), flip(LZ())), ∂z, arg.grid) # Instantiate location if types are passed -∂x(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂x((L[1](), L[2](), L[3]()), arg) -∂y(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂y((L[1](), L[2](), L[3]()), arg) -∂z(L::Tuple, arg::AF{LX, LY, LZ}) where {LX, LY, LZ} = ∂z((L[1](), L[2](), L[3]()), arg) +∂x(L::Tuple, arg::AF) = ∂x((L[1](), L[2](), L[3]()), arg) +∂y(L::Tuple, arg::AF) = ∂y((L[1](), L[2](), L[3]()), arg) +∂z(L::Tuple, arg::AF) = ∂z((L[1](), L[2](), L[3]()), arg) # Defaults diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index 64cbbfa89da..d2b9f64f14c 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -33,7 +33,7 @@ end """Return an expression that defines an abstract `MultiaryOperator` named `op` for `AbstractField`.""" function define_multiary_operator(op) return quote - function $op(Lop::Tuple{{<:Location, <:Location, <:Location}}, + function $op(Lop::Tuple{<:Location, <:Location, <:Location}, a::Union{Function, Number, Oceananigans.Fields.AbstractField}, b::Union{Function, Number, Oceananigans.Fields.AbstractField}, c::Union{Function, Number, Oceananigans.Fields.AbstractField}, diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index ed0be1ce6c7..c1f549a2288 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -108,7 +108,7 @@ macro unary(ops...) end # instantiate location if types are passed - $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) + $op(Lc::Tuple, a) = $op((Lc[1](), Lc[2](), Lc[3]()), a) $op(a::AbstractField) = $op(instantiated_location(a), a) From 760712866deb71e3b7dc2217a83b7736149c5e22 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Wed, 5 Nov 2025 07:54:14 +0100 Subject: [PATCH 20/28] disambiguate --- src/AbstractOperations/binary_operations.jl | 20 ++++++++++------ src/AbstractOperations/multiary_operations.jl | 24 +++++++++++-------- src/AbstractOperations/unary_operations.jl | 2 +- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index 5e9330657d5..2995f65952e 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -116,18 +116,24 @@ function define_binary_operator(op) return Oceananigans.AbstractOperations._binary_operation(Lab, $op, a, b, La, Lb, grid) end - # instantiate location if types are passed - $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) - # Numbers are not fields... $op(Lc::Tuple, a::Number, b::Number) = $op(a, b) # Sugar for mixing in functions of (x, y, z) - $op(Lc::Tuple, f::Function, b::AbstractField) = $op(Lc, FunctionField(location(b), f, b.grid), b) - $op(Lc::Tuple, a::AbstractField, f::Function) = $op(Lc, a, FunctionField(location(a), f, a.grid)) + $op(Lc::Tuple{<:Location, <:Location, <:Location}, f::Function, b::AbstractField) = $op(Lc, FunctionField(location(b), f, b.grid), b) + $op(Lc::Tuple{<:Location, <:Location, <:Location}, a::AbstractField, f::Function) = $op(Lc, a, FunctionField(location(a), f, a.grid)) + + $op(Lc::Tuple{<:Location, <:Location, <:Location}, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(instantiated_location(b), m, b.grid), b) + $op(Lc::Tuple{<:Location, <:Location, <:Location}, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(instantiated_location(a), m, a.grid)) + + # instantiate location if types are passed + $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) + + $op(Lc::Tuple, f::Function, b::AbstractField) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) + $op(Lc::Tuple, a::AbstractField, f::Function) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) - $op(Lc::Tuple, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(instantiated_location(b), m, b.grid), b) - $op(Lc::Tuple, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(instantiated_location(a), m, a.grid)) + $op(Lc::Tuple, m::GridMetric, b::AbstractField) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) + $op(Lc::Tuple, a::AbstractField, m::GridMetric) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) # Sugary versions with default locations $op(a::AF, b::AF) = $op(instantiated_location(a), a, b) diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index d2b9f64f14c..d14e452b354 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -34,10 +34,10 @@ end function define_multiary_operator(op) return quote function $op(Lop::Tuple{<:Location, <:Location, <:Location}, - a::Union{Function, Number, Oceananigans.Fields.AbstractField}, - b::Union{Function, Number, Oceananigans.Fields.AbstractField}, - c::Union{Function, Number, Oceananigans.Fields.AbstractField}, - d::Union{Function, Number, Oceananigans.Fields.AbstractField}...) + a::Union{Function, Number, AbstractField}, + b::Union{Function, Number, AbstractField}, + c::Union{Function, Number, AbstractField}, + d::Union{Function, Number, AbstractField}...) args = tuple(a, b, c, d...) grid = Oceananigans.AbstractOperations.validate_grid(args...) @@ -50,12 +50,16 @@ function define_multiary_operator(op) end # Instantiate location if types are passed - $op(Lop::Tuple, a, b, c, d...) = $op((Lop[1](), Lop[2](), Lop[3]()), a, b, c, d...) - - $op(a::Oceananigans.Fields.AbstractField, - b::Union{Function, Oceananigans.Fields.AbstractField}, - c::Union{Function, Oceananigans.Fields.AbstractField}, - d::Union{Function, Oceananigans.Fields.AbstractField}...) = $op(Oceananigans.Fields.instantiated_location(a), a, b, c, d...) + $op(Lop::Tuple, + a::Union{Function, Number, AbstractField}, + b::Union{Function, Number, AbstractField}, + c::Union{Function, Number, AbstractField}, + d::Union{Function, Number, AbstractField}...) = $op((Lop[1](), Lop[2](), Lop[3]()), a, b, c, d...) + + $op(a::AbstractField, + b::Union{Function, Number, AbstractField}, + c::Union{Function, Number, AbstractField}, + d::Union{Function, Number, AbstractField}...) = $op(Oceananigans.Fields.instantiated_location(a), a, b, c, d...) end end diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index c1f549a2288..5dab1f62dc8 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -108,7 +108,7 @@ macro unary(ops...) end # instantiate location if types are passed - $op(Lc::Tuple, a) = $op((Lc[1](), Lc[2](), Lc[3]()), a) + $op(Lc::Tuple, a::AbstractField) = $op((Lc[1](), Lc[2](), Lc[3]()), a) $op(a::AbstractField) = $op(instantiated_location(a), a) From 765fad05b59459e1884061fded66edf379f2062e Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Fri, 7 Nov 2025 09:13:55 +0100 Subject: [PATCH 21/28] fix the averages --- src/Fields/Fields.jl | 1 - src/Fields/scans.jl | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/Fields/Fields.jl b/src/Fields/Fields.jl index 5d6406fe7c0..60a1968d47d 100644 --- a/src/Fields/Fields.jl +++ b/src/Fields/Fields.jl @@ -25,7 +25,6 @@ import Oceananigans: location, instantiated_location return (LX(), LY(), LZ()) end - include("abstract_field.jl") include("constant_field.jl") include("function_field.jl") diff --git a/src/Fields/scans.jl b/src/Fields/scans.jl index 7dad4cc5771..76b971c7e43 100644 --- a/src/Fields/scans.jl +++ b/src/Fields/scans.jl @@ -34,9 +34,6 @@ Base.summary(::Accumulating) = "Accumulating" const Reduction = Scan{<:AbstractReducing} const Accumulation = Scan{<:AbstractAccumulating} -@inline location(s::Scan) = location(s.operand) -@inline instantiated_location(s::Scan) = instantiated_location(s.operand) - scan_indices(::AbstractReducing, indices, dims) = Tuple(i ∈ dims ? Colon() : indices[i] for i in 1:3) scan_indices(::AbstractAccumulating, indices, dims) = indices scan_indices(::AbstractReducing, ::Tuple{Colon, Colon, Colon}, dims) = (:, :, :) From 57d1122203f502ffc5f3b71a3e55d5de53d0ffcb Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Fri, 7 Nov 2025 11:19:34 +0100 Subject: [PATCH 22/28] don't interpolat both if the location is equal to instantiated or location --- src/AbstractOperations/at.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AbstractOperations/at.jl b/src/AbstractOperations/at.jl index 3c02c703f05..4d5643e12c5 100644 --- a/src/AbstractOperations/at.jl +++ b/src/AbstractOperations/at.jl @@ -46,7 +46,9 @@ insert_location!(anything, location) = nothing interpolate_operation(L, x) = x function interpolate_operation(L, x::AbstractField) - L == location(x) && return x # Don't interpolate unnecessarily + if L == instantiated_location(x) || L == location(x) + return x # Don't interpolate unnecessarily + end return interpolate_identity(L, x) end From f7adf4b7f2f5b9741541bead0154dc8111f9599d Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Fri, 7 Nov 2025 11:49:35 +0100 Subject: [PATCH 23/28] add the location --- docs/src/operations.md | 17 ++++++++--------- src/AbstractOperations/binary_operations.jl | 10 +++++----- src/AbstractOperations/multiary_operations.jl | 2 +- src/AbstractOperations/unary_operations.jl | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/src/operations.md b/docs/src/operations.md index af23627766a..f6e68508d8e 100644 --- a/docs/src/operations.md +++ b/docs/src/operations.md @@ -53,18 +53,17 @@ and even by chaining expressions together, which may themselves include `Abstrac quadratic = c^2 + two_c + 1 # output -BinaryOperation at (Center, Center, Center) +MultiaryOperation at (Center, Center, Center) ├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo └── tree: + at (Center, Center, Center) -    ├── + at (Center, Center, Center) -    │   ├── ^ at (Center, Center, Center) -    │   │   ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU -    │   │   └── 2 -    │   └── * at (Center, Center, Center) -       │   ├── 2 -       │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU -    └── 1 + ├── ^ at (Center, Center, Center) + │ ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU + │ └── 2 + ├── * at (Center, Center, Center) + │ ├── 2 + │ └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU + └── 1 ``` Like `Field`s, `AbstractOperations` have a location and a grid. diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index 2995f65952e..f233015ae85 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -106,7 +106,7 @@ function define_binary_operator(op) the location of the dimension in question is supplied either by `location(b)` or if that is also Nothing, `Lc`. """ - function $op(Lc::Tuple{<:Location, <:Location, <:Location}, a, b) + function $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a, b) La = instantiated_location(a) Lb = instantiated_location(b) Lab = choose_location.(La, Lb, Lc) @@ -120,11 +120,11 @@ function define_binary_operator(op) $op(Lc::Tuple, a::Number, b::Number) = $op(a, b) # Sugar for mixing in functions of (x, y, z) - $op(Lc::Tuple{<:Location, <:Location, <:Location}, f::Function, b::AbstractField) = $op(Lc, FunctionField(location(b), f, b.grid), b) - $op(Lc::Tuple{<:Location, <:Location, <:Location}, a::AbstractField, f::Function) = $op(Lc, a, FunctionField(location(a), f, a.grid)) + $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, f::Function, b::AbstractField) = $op(Lc, FunctionField(location(b), f, b.grid), b) + $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a::AbstractField, f::Function) = $op(Lc, a, FunctionField(location(a), f, a.grid)) - $op(Lc::Tuple{<:Location, <:Location, <:Location}, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(instantiated_location(b), m, b.grid), b) - $op(Lc::Tuple{<:Location, <:Location, <:Location}, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(instantiated_location(a), m, a.grid)) + $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(instantiated_location(b), m, b.grid), b) + $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(instantiated_location(a), m, a.grid)) # instantiate location if types are passed $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index d14e452b354..769ef12d606 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -33,7 +33,7 @@ end """Return an expression that defines an abstract `MultiaryOperator` named `op` for `AbstractField`.""" function define_multiary_operator(op) return quote - function $op(Lop::Tuple{<:Location, <:Location, <:Location}, + function $op(Lop::Tuple{<:$Location, <:$Location, <:$Location}, a::Union{Function, Number, AbstractField}, b::Union{Function, Number, AbstractField}, c::Union{Function, Number, AbstractField}, diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index 5dab1f62dc8..f1fe908cc29 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -102,7 +102,7 @@ macro unary(ops...) Returns an abstract representation of the operator `$($op)` acting on the Oceananigans `Field` `a`, and subsequently interpolated to the location indicated by `Lop`. """ - function $op(Lop::Tuple{<:Location, <:Location, <:Location}, a::AbstractField) + function $op(Lop::Tuple{<:$Location, <:$Location, <:$Location}, a::AbstractField) L = instantiated_location(a) return Oceananigans.AbstractOperations._unary_operation(Lop, $op, a, L, a.grid) end From 849d17f47396a7c160be2f9b7c345cfe704009d0 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Fri, 7 Nov 2025 12:12:51 +0100 Subject: [PATCH 24/28] import AbstractField --- src/AbstractOperations/multiary_operations.jl | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index 769ef12d606..038eafee1f6 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -34,10 +34,10 @@ end function define_multiary_operator(op) return quote function $op(Lop::Tuple{<:$Location, <:$Location, <:$Location}, - a::Union{Function, Number, AbstractField}, - b::Union{Function, Number, AbstractField}, - c::Union{Function, Number, AbstractField}, - d::Union{Function, Number, AbstractField}...) + a::Union{Function, Number, Oceananigans.Fields.AbstractField}, + b::Union{Function, Number, Oceananigans.Fields.AbstractField}, + c::Union{Function, Number, Oceananigans.Fields.AbstractField}, + d::Union{Function, Number, Oceananigans.Fields.AbstractField}...) args = tuple(a, b, c, d...) grid = Oceananigans.AbstractOperations.validate_grid(args...) @@ -51,15 +51,15 @@ function define_multiary_operator(op) # Instantiate location if types are passed $op(Lop::Tuple, - a::Union{Function, Number, AbstractField}, - b::Union{Function, Number, AbstractField}, - c::Union{Function, Number, AbstractField}, - d::Union{Function, Number, AbstractField}...) = $op((Lop[1](), Lop[2](), Lop[3]()), a, b, c, d...) + a::Union{Function, Number, Oceananigans.Fields.AbstractField}, + b::Union{Function, Number, Oceananigans.Fields.AbstractField}, + c::Union{Function, Number, Oceananigans.Fields.AbstractField}, + d::Union{Function, Number, Oceananigans.Fields.AbstractField}...) = $op((Lop[1](), Lop[2](), Lop[3]()), a, b, c, d...) $op(a::AbstractField, - b::Union{Function, Number, AbstractField}, - c::Union{Function, Number, AbstractField}, - d::Union{Function, Number, AbstractField}...) = $op(Oceananigans.Fields.instantiated_location(a), a, b, c, d...) + b::Union{Function, Number, Oceananigans.Fields.AbstractField}, + c::Union{Function, Number, Oceananigans.Fields.AbstractField}, + d::Union{Function, Number, Oceananigans.Fields.AbstractField}...) = $op(Oceananigans.Fields.instantiated_location(a), a, b, c, d...) end end From c8da500a045da2025ef9f13dde005619bd3093b7 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Mon, 10 Nov 2025 11:32:30 +0100 Subject: [PATCH 25/28] another bugfix --- src/AbstractOperations/multiary_operations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index 038eafee1f6..f69e7c522cc 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -56,7 +56,7 @@ function define_multiary_operator(op) c::Union{Function, Number, Oceananigans.Fields.AbstractField}, d::Union{Function, Number, Oceananigans.Fields.AbstractField}...) = $op((Lop[1](), Lop[2](), Lop[3]()), a, b, c, d...) - $op(a::AbstractField, + $op(a::Oceananigans.Fields.AbstractField, b::Union{Function, Number, Oceananigans.Fields.AbstractField}, c::Union{Function, Number, Oceananigans.Fields.AbstractField}, d::Union{Function, Number, Oceananigans.Fields.AbstractField}...) = $op(Oceananigans.Fields.instantiated_location(a), a, b, c, d...) From bd4c6c453011b019eabebae384d29229ed43e8e5 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Mon, 10 Nov 2025 12:36:52 +0100 Subject: [PATCH 26/28] add qualifier --- src/AbstractOperations/binary_operations.jl | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index f233015ae85..9b4d024b652 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -107,8 +107,8 @@ function define_binary_operator(op) if that is also Nothing, `Lc`. """ function $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a, b) - La = instantiated_location(a) - Lb = instantiated_location(b) + La = Oceananigans.Fields.instantiated_location(a) + Lb = Oceananigans.Fields.instantiated_location(b) Lab = choose_location.(La, Lb, Lc) grid = Oceananigans.AbstractOperations.validate_grid(a, b) @@ -123,8 +123,8 @@ function define_binary_operator(op) $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, f::Function, b::AbstractField) = $op(Lc, FunctionField(location(b), f, b.grid), b) $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a::AbstractField, f::Function) = $op(Lc, a, FunctionField(location(a), f, a.grid)) - $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(instantiated_location(b), m, b.grid), b) - $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(instantiated_location(a), m, a.grid)) + $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, m::GridMetric, b::AbstractField) = $op(Lc, grid_metric_operation(Oceananigans.Fields.instantiated_location(b), m, b.grid), b) + $op(Lc::Tuple{<:$Location, <:$Location, <:$Location}, a::AbstractField, m::GridMetric) = $op(Lc, a, grid_metric_operation(Oceananigans.Fields.instantiated_location(a), m, a.grid)) # instantiate location if types are passed $op(Lc::Tuple, a, b) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) @@ -136,15 +136,15 @@ function define_binary_operator(op) $op(Lc::Tuple, a::AbstractField, m::GridMetric) = $op((Lc[1](), Lc[2](), Lc[3]()), a, b) # Sugary versions with default locations - $op(a::AF, b::AF) = $op(instantiated_location(a), a, b) - $op(a::AF, b) = $op(instantiated_location(a), a, b) - $op(a, b::AF) = $op(instantiated_location(b), a, b) + $op(a::AF, b::AF) = $op(Oceananigans.Fields.instantiated_location(a), a, b) + $op(a::AF, b) = $op(Oceananigans.Fields.instantiated_location(a), a, b) + $op(a, b::AF) = $op(Oceananigans.Fields.instantiated_location(b), a, b) - $op(a::AF, b::Number) = $op(instantiated_location(a), a, b) - $op(a::Number, b::AF) = $op(instantiated_location(b), a, b) + $op(a::AF, b::Number) = $op(Oceananigans.Fields.instantiated_location(a), a, b) + $op(a::Number, b::AF) = $op(Oceananigans.Fields.instantiated_location(b), a, b) - $op(a::AF, b::ConstantField) = $op(instantiated_location(a), a, b.constant) - $op(a::ConstantField, b::AF) = $op(instantiated_location(b), a.constant, b) + $op(a::AF, b::ConstantField) = $op(Oceananigans.Fields.instantiated_location(a), a, b.constant) + $op(a::ConstantField, b::AF) = $op(Oceananigans.Fields.instantiated_location(b), a.constant, b) $op(a::Number, b::ConstantField) = ConstantField($op(a, b.constant)) $op(a::ConstantField, b::Number) = ConstantField($op(a.constant, b)) From ba1aee3796a21bd4a56b1e25d239a18e97a96e49 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 11 Nov 2025 10:53:53 +0100 Subject: [PATCH 27/28] not sure why this should be different... --- docs/src/operations.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/src/operations.md b/docs/src/operations.md index f6e68508d8e..2e75e49eb79 100644 --- a/docs/src/operations.md +++ b/docs/src/operations.md @@ -57,14 +57,14 @@ MultiaryOperation at (Center, Center, Center) ├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo └── tree: + at (Center, Center, Center) - ├── ^ at (Center, Center, Center) - │ ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU - │ └── 2 - ├── * at (Center, Center, Center) - │ ├── 2 - │ └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU - └── 1 -``` +    ├── ^ at (Center, Center, Center) +    │   ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU +    │   └── 2 +    ├── * at (Center, Center, Center) +    │   ├── 2 +    │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU +    └── 1 + ``` Like `Field`s, `AbstractOperations` have a location and a grid. In addition to `BinaryOperation`s like the kind above, `UnaryOperation`s and `MultiaryOperation`s are also supported, From 5f600e5a0fc1e346cf42f630be92d1a6a96932f5 Mon Sep 17 00:00:00 2001 From: Simone Silvestri Date: Tue, 11 Nov 2025 10:54:41 +0100 Subject: [PATCH 28/28] remov the extra space --- docs/src/operations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/operations.md b/docs/src/operations.md index 2e75e49eb79..ebc9af9b749 100644 --- a/docs/src/operations.md +++ b/docs/src/operations.md @@ -64,7 +64,7 @@ MultiaryOperation at (Center, Center, Center)    │   ├── 2    │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU    └── 1 - ``` +``` Like `Field`s, `AbstractOperations` have a location and a grid. In addition to `BinaryOperation`s like the kind above, `UnaryOperation`s and `MultiaryOperation`s are also supported,