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

(0.94.4) PolarBoundaryCondition for tracer + views for AbstractOperations #3953

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9dddf39
add this check
simone-silvestri Nov 22, 2024
95e6612
flux boundary conditions not working
simone-silvestri Nov 22, 2024
3b03288
default polar BC for latitudelongitude grid
simone-silvestri Nov 22, 2024
ce3fef1
polar boundary conditions
simone-silvestri Nov 22, 2024
83a23e1
update
simone-silvestri Nov 22, 2024
09ce40b
update
simone-silvestri Nov 22, 2024
755b3bc
will this work?
simone-silvestri Nov 22, 2024
e2dbac9
Merge branch 'ss/top-boundary-condition' of github.com:CliMA/Oceanani…
simone-silvestri Nov 22, 2024
4c13313
update boundary conditions
simone-silvestri Nov 22, 2024
8004cb5
add offsetarrays
simone-silvestri Nov 22, 2024
575f8da
Merge branch 'main' into ss/top-boundary-condition
simone-silvestri Nov 23, 2024
f6f3dd1
indices in reductions
simone-silvestri Nov 23, 2024
621f1e6
Merge branch 'ss/top-boundary-condition' of github.com:CliMA/Oceanani…
simone-silvestri Nov 23, 2024
34dfe63
add a test
simone-silvestri Nov 23, 2024
7f7b86b
hmmm
simone-silvestri Nov 23, 2024
9add855
Merge branch 'main' into ss/top-boundary-condition
simone-silvestri Nov 27, 2024
929bc24
bugfix
simone-silvestri Nov 27, 2024
47b398f
another bugfix
simone-silvestri Nov 27, 2024
091c6cb
extending `view`s for operations
simone-silvestri Nov 27, 2024
6b0c234
should be ready to go
simone-silvestri Nov 27, 2024
9706ad6
sprinkle more OneTo around
simone-silvestri Nov 27, 2024
8c450e3
tests should pass
simone-silvestri Nov 27, 2024
8b75606
this works unfortunate we cannot use fields
simone-silvestri Nov 27, 2024
7c83f6b
revert what not needed
simone-silvestri Nov 27, 2024
8b3db85
stricter conditions
simone-silvestri Nov 27, 2024
ae32aed
should be ready to go
simone-silvestri Nov 28, 2024
391af30
another bugfix
simone-silvestri Nov 28, 2024
4b50abe
allowscalar
simone-silvestri Nov 28, 2024
44610fc
bump to 0.94.4
simone-silvestri Nov 28, 2024
96f098d
support for Flat grids
simone-silvestri Nov 28, 2024
d4f1c10
Update multiary_operations.jl
simone-silvestri Nov 28, 2024
dd3817c
support for nothing
simone-silvestri Nov 28, 2024
bd38e5f
Merge branch 'ss/top-boundary-condition' of github.com:CliMA/Oceanani…
simone-silvestri Nov 28, 2024
397bf28
bugfix
simone-silvestri Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Oceananigans"
uuid = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
authors = ["Climate Modeling Alliance and contributors"]
version = "0.94.3"
version = "0.94.4"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
Expand Down
5 changes: 5 additions & 0 deletions src/AbstractOperations/AbstractOperations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ using Oceananigans.Operators: interpolation_operator
using Oceananigans.Architectures: device

import Adapt
import Base

import Oceananigans.Architectures: architecture, on_architecture
import Oceananigans.BoundaryConditions: fill_halo_regions!
Expand All @@ -42,6 +43,10 @@ architecture(a::AbstractOperation) = architecture(a.grid)
# AbstractOperation macros add their associated functions to this list
const operators = Set()

# To allow view(o::AbstractOperation, i, j, k) to work
@inline get_field_view(a::Union{AbstractOperation, AbstractField}, i, j, k) = view(a, i, j, k)
@inline get_field_view(a, i, j, k) = a

"""
at(loc, abstract_operation)

Expand Down
24 changes: 17 additions & 7 deletions src/AbstractOperations/at.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ compute_index_intersection(::Colon, to_loc; kw...) = Colon()

compute_index_intersection(to_idx, to_loc, op; dim) =
_compute_index_intersection(to_idx, indices(op)[dim],
topology(op.grid)[dim],
to_loc, location(op, dim))

"""Compute index intersection recursively for `dim`ension ∈ (1, 2, 3)."""
Expand All @@ -85,23 +86,25 @@ function compute_index_intersection(to_idx, to_loc, op1, op2, more_ops...; dim)
return compute_index_intersection(new_to_idx, to_loc, op2, more_ops...; dim)
end

const Range = Union{UnitRange, Base.OneTo, Base.Slice{<:Base.OneTo}}

# Life is pretty simple in this case.
_compute_index_intersection(to_idx::Colon, from_idx::Colon, args...) = Colon()
_compute_index_intersection(::Colon, ::Colon, args...) = Colon()

# Because `from_idx` imposes no restrictions, we just return `to_idx`.
_compute_index_intersection(to_idx::UnitRange, from_idx::Colon, args...) = to_idx
_compute_index_intersection(to_idx::Range, ::Colon, args...) = to_idx

# This time we account for the possible range-reducing effect of interpolation on `from_idx`.
function _compute_index_intersection(to_idx::Colon, from_idx::UnitRange, to_loc, from_loc)
function _compute_index_intersection(::Colon, from_idx::Range, to_loc, from_loc)
shifted_idx = restrict_index_for_interpolation(from_idx, from_loc, to_loc)
validate_shifted_index(shifted_idx)
validate_shifted_index(shifted_idx, from_idx, from_loc, to_loc)
return shifted_idx
end

# Compute the intersection of two index ranges
function _compute_index_intersection(to_idx::UnitRange, from_idx::UnitRange, to_loc, from_loc)
function _compute_index_intersection(to_idx::Range, from_idx::Range, to_loc, from_loc)
shifted_idx = restrict_index_for_interpolation(from_idx, from_loc, to_loc)
validate_shifted_index(shifted_idx)
validate_shifted_index(shifted_idx, from_idx, from_loc, to_loc)

range_intersection = UnitRange(max(first(shifted_idx), first(to_idx)), min(last(shifted_idx), last(to_idx)))

Expand All @@ -112,7 +115,7 @@ function _compute_index_intersection(to_idx::UnitRange, from_idx::UnitRange, to_
return range_intersection
end

validate_shifted_index(shifted_idx) = first(shifted_idx) > last(shifted_idx) &&
validate_shifted_index(shifted_idx, from_idx, from_loc, to_loc) = first(shifted_idx) > last(shifted_idx) &&
throw(ArgumentError("Cannot compute index intersection for indices $(from_idx) interpolating from $(from_loc) to $(to_loc)!"))

"""
Expand All @@ -128,3 +131,10 @@ restrict_index_for_interpolation(from_idx, ::Type{Face}, ::Type{Face}) = Uni
restrict_index_for_interpolation(from_idx, ::Type{Center}, ::Type{Center}) = UnitRange(first(from_idx), last(from_idx))
restrict_index_for_interpolation(from_idx, ::Type{Face}, ::Type{Center}) = UnitRange(first(from_idx), last(from_idx)-1)
restrict_index_for_interpolation(from_idx, ::Type{Center}, ::Type{Face}) = UnitRange(first(from_idx)+1, last(from_idx))

# No restrictions for interpolating from `Nothing` or to `Nothing`
restrict_index_for_interpolation(from_idx, ::Type{Nothing}, ::Type{Face}) = from_idx
restrict_index_for_interpolation(from_idx, ::Type{Nothing}, ::Type{Center}) = from_idx
restrict_index_for_interpolation(from_idx, ::Type{Face}, ::Type{Nothing}) = from_idx
restrict_index_for_interpolation(from_idx, ::Type{Center}, ::Type{Nothing}) = from_idx
restrict_index_for_interpolation(from_idx, ::Type{Nothing}, ::Type{Nothing}) = from_idx
11 changes: 11 additions & 0 deletions src/AbstractOperations/binary_operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,14 @@ on_architecture(to, binary::BinaryOperation{LX, LY, LZ}) where {LX, LY, LZ} =
on_architecture(to, binary.▶a),
on_architecture(to, binary.▶b),
on_architecture(to, binary.grid))

# Extending views for `BinaryOperation`s
function Base.view(binary::BinaryOperation{LX, LY, LZ}, i, j, k) where {LX, LY, LZ}
# Propagate view over all arguments
view_a = get_field_view(binary.a, i, j, k)
view_b = get_field_view(binary.b, i, j, k)
view_▶a = get_field_view(binary.▶a, i, j, k)
view_▶b = get_field_view(binary.▶b, i, j, k)

return BinaryOperation{LX, LY, LZ}(binary.op, view_a, view_b, view_▶a, view_▶b, binary.grid)
end
10 changes: 10 additions & 0 deletions src/AbstractOperations/conditional_operations.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using Oceananigans.Fields: OneField
using Oceananigans.Grids: architecture

using OffsetArrays

import Oceananigans.Architectures: on_architecture
import Oceananigans.Fields: condition_operand, conditional_length, set!, compute_at!, indices


# For conditional reductions such as mean(u * v, condition = u .> 0))
struct ConditionalOperation{LX, LY, LZ, O, F, G, C, M, T} <: AbstractOperation{LX, LY, LZ, G, T}
operand :: O
Expand Down Expand Up @@ -159,3 +162,10 @@ Base.show(io::IO, operation::ConditionalOperation) =
"├── func: ", summary(operation.func), "\n",
"├── condition: ", summary(operation.condition), "\n",
"└── mask: ", operation.mask)

# Extending views for `ConditionalyOperation`s
function Base.view(co::ConditionalOperation{LX, LY, LZ}, i, j, k) where {LX, LY, LZ}
# Propagate view over all arguments
view_operand = get_field_view(co.operand, i, j, k)
return ConditionalOperation{LX, LY, LZ}(view_operand, co.func, co.grid, co.condition, co.mask)
end
10 changes: 9 additions & 1 deletion src/AbstractOperations/derivatives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,12 @@ on_architecture(to, deriv::Derivative{LX, LY, LZ}) where {LX, LY, LZ} =
on_architecture(to, deriv.▶),
deriv.abstract_∂,
on_architecture(to, deriv.grid))


# Extending views for `Derivative`s
function Base.view(deriv::Derivative{LX, LY, LZ}, i, j, k) where {LX, LY, LZ}
# Propagate view over all arguments
view_arg = get_field_view(deriv.arg, i, j, k)
view_▶ = get_field_view(deriv.▶, i, j, k)

return Derivative{LX, LY, LZ}(deriv.∂, view_arg, view_▶, deriv.grid)
end
3 changes: 3 additions & 0 deletions src/AbstractOperations/grid_metrics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ indices(::GridMetricOperation) = default_indices(3)
# Special constructor for BinaryOperation
GridMetricOperation(L, metric, grid) = GridMetricOperation{L[1], L[2], L[3]}(metric_function(L, metric), grid)

# Extend view on a GridMetricOperation (we return the same object)
Base.view(gm::GridMetricOperation, i, j, k) = gm

#####
##### Spacings
#####
Expand Down
7 changes: 7 additions & 0 deletions src/AbstractOperations/kernel_function_operation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,10 @@ Base.show(io::IO, kfo::KernelFunctionOperation) =
prettysummary(kfo.arguments[end])
end
)

# Extending views for KernelFunctionOperation
function Base.view(ko::KernelFunctionOperation{LX, LY, LZ}, i, j, k) where {LX, LY, LZ}
# Propagate view over all arguments
view_args = [get_field_view(a, i, j, k) for a in ko.arguments]
return KernelFunctionOperation{LX, LY, LZ}(ko.kernel_function, ko.grid, view_args...)
end
10 changes: 9 additions & 1 deletion src/AbstractOperations/multiary_operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,12 @@ on_architecture(to, multiary::MultiaryOperation{LX, LY, LZ}) where {LX, LY, LZ}
on_architecture(to, multiary.args),
on_architecture(to, multiary.▶),
on_architecture(to, multiary.grid))


# Extending views for `MultiaryOperation`s
function Base.view(multiary::MultiaryOperation{LX, LY, LZ}, i, j, k) where {LX, LY, LZ}
# Propagate view over all arguments
view_args = Tuple(get_field_view(arg, i, j, k) for args in multiary.args)
view_▶ = Tuple(get_field_view(▶, i, j, k) for ▶ in multiary.▶)

return MultiaryOperation{LX, LY, LZ}(multiary.op, view_args, view_▶, multiary.grid)
end
9 changes: 9 additions & 0 deletions src/AbstractOperations/unary_operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,12 @@ on_architecture(to, unary::UnaryOperation{LX, LY, LZ}) where {LX, LY, LZ} =
on_architecture(to, unary.arg),
on_architecture(to, unary.▶),
on_architecture(to, unary.grid))

# Extending views for `UnaryOperation`s
function Base.view(unary::UnaryOperation{LX, LY, LZ}, i, j, k) where {LX, LY, LZ}
# Propagate view over all arguments
view_arg = get_field_view(unary.arg, i, j, k)
view_▶ = get_field_view(unary.▶, i, j, k)

return UnaryOperation{LX, LY, LZ}(unary.op, view_arg, view_▶, unary.grid)
end
1 change: 1 addition & 0 deletions src/BoundaryConditions/BoundaryConditions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ include("fill_halo_regions_nothing.jl")
include("apply_flux_bcs.jl")

include("update_boundary_conditions.jl")
include("polar_boundary_condition.jl")

include("flat_extrapolation_open_boundary_matching_scheme.jl")
end # module
25 changes: 17 additions & 8 deletions src/BoundaryConditions/field_boundary_conditions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ FieldBoundaryConditions(indices::Tuple, bcs::FieldBoundaryConditions) =

FieldBoundaryConditions(indices::Tuple, ::Nothing) = nothing

window_boundary_conditions(::Colon, left, right) = left, right
window_boundary_conditions(::UnitRange, left, right) = nothing, nothing
const Range = Union{UnitRange, Base.OneTo, Base.Slice{<:Base.OneTo}}

window_boundary_conditions(::Colon, left, right) = left, right
window_boundary_conditions(::Range, left, right) = nothing, nothing

on_architecture(arch, fbcs::FieldBoundaryConditions) =
FieldBoundaryConditions(on_architecture(arch, fbcs.west),
Expand Down Expand Up @@ -178,6 +180,13 @@ function regularize_immersed_boundary_condition(ibc, grid, loc, field_name, args
return NoFluxBoundaryCondition()
end

regularize_west_boundary_condition(bc, args...) = regularize_boundary_condition(bc, args...)
regularize_east_boundary_condition(bc, args...) = regularize_boundary_condition(bc, args...)
regularize_south_boundary_condition(bc, args...) = regularize_boundary_condition(bc, args...)
regularize_north_boundary_condition(bc, args...) = regularize_boundary_condition(bc, args...)
regularize_bottom_boundary_condition(bc, args...) = regularize_boundary_condition(bc, args...)
regularize_top_boundary_condition(bc, args...) = regularize_boundary_condition(bc, args...)

# regularize default boundary conditions
function regularize_boundary_condition(default::DefaultBoundaryCondition, grid, loc, dim, args...)
default_bc = default_prognostic_bc(topology(grid, dim)(), loc[dim](), default)
Expand Down Expand Up @@ -212,12 +221,12 @@ function regularize_field_boundary_conditions(bcs::FieldBoundaryConditions,

loc = assumed_field_location(field_name)

west = regularize_boundary_condition(bcs.west, grid, loc, 1, LeftBoundary, prognostic_names)
east = regularize_boundary_condition(bcs.east, grid, loc, 1, RightBoundary, prognostic_names)
south = regularize_boundary_condition(bcs.south, grid, loc, 2, LeftBoundary, prognostic_names)
north = regularize_boundary_condition(bcs.north, grid, loc, 2, RightBoundary, prognostic_names)
bottom = regularize_boundary_condition(bcs.bottom, grid, loc, 3, LeftBoundary, prognostic_names)
top = regularize_boundary_condition(bcs.top, grid, loc, 3, RightBoundary, prognostic_names)
west = regularize_west_boundary_condition(bcs.west, grid, loc, 1, LeftBoundary, prognostic_names)
east = regularize_east_boundary_condition(bcs.east, grid, loc, 1, RightBoundary, prognostic_names)
south = regularize_south_boundary_condition(bcs.south, grid, loc, 2, LeftBoundary, prognostic_names)
north = regularize_north_boundary_condition(bcs.north, grid, loc, 2, RightBoundary, prognostic_names)
bottom = regularize_bottom_boundary_condition(bcs.bottom, grid, loc, 3, LeftBoundary, prognostic_names)
top = regularize_top_boundary_condition(bcs.top, grid, loc, 3, RightBoundary, prognostic_names)

immersed = regularize_immersed_boundary_condition(bcs.immersed, grid, loc, field_name, prognostic_names)

Expand Down
121 changes: 121 additions & 0 deletions src/BoundaryConditions/polar_boundary_condition.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Oceananigans.Architectures: device
using Oceananigans.Grids: inactive_node
using CUDA: @allowscalar

struct PolarValue{D, S}
data :: D
side :: S
end

Adapt.adapt_structure(to, pv::PolarValue) = PolarValue(Adapt.adapt(to, pv.data), nothing)

const PolarBoundaryCondition{V} = BoundaryCondition{<:Value, <:PolarValue}

function PolarBoundaryCondition(grid, side)
FT = eltype(grid)
arch = architecture(grid)
data = on_architecture(arch, zeros(FT, grid.Nz))
return ValueBoundaryCondition(PolarValue(data, side))
end

# Just a column
@inline getbc(pv::BC{<:Value, <:PolarValue}, i, k, args...) = @inbounds pv.condition.data[k]

# TODO: vectors should have a different treatment since vector components should account for the frame of reference
# North - South flux boundary conditions are not valid on a Latitude-Longitude grid if the last / first rows represent the poles
function latitude_north_auxiliary_bc(grid, loc, default_bc=DefaultBoundaryCondition())
# Check if the halo lies beyond the north pole
φmax = @allowscalar φnode(grid.Ny+1, grid, Center())

# No problem!
if φmax < 90 || loc[1] == Nothing
return default_bc
end

return PolarBoundaryCondition(grid, :north)
end

# North - South flux boundary conditions are not valid on a Latitude-Longitude grid if the last / first rows represent the poles
function latitude_south_auxiliary_bc(grid, loc, default_bc=DefaultBoundaryCondition())
# Check if the halo lies beyond the south pole
φmin = @allowscalar φnode(0, grid, Face())

# No problem!
if φmin > -90 || loc[1] == Nothing
return default_bc
end

return PolarBoundaryCondition(grid, :south)
end

regularize_north_boundary_condition(bc::DefaultBoundaryCondition, grid::LatitudeLongitudeGrid, loc, args...) =
regularize_boundary_condition(latitude_north_auxiliary_bc(grid, loc, bc), grid, loc, args...)

regularize_south_boundary_condition(bc::DefaultBoundaryCondition, grid::LatitudeLongitudeGrid, loc, args...) =
regularize_boundary_condition(latitude_south_auxiliary_bc(grid, loc, bc), grid, loc, args...)

@kernel function _average_pole_value!(data, c, j, grid, loc)
k = @index(Global, Linear)
c̄ = zero(grid)
n = 0
@inbounds for i in 1:grid.Nx
inactive = inactive_node(i, j, k, grid, loc...)
c̄ += ifelse(inactive, 0, c[i, j, k])
n += ifelse(inactive, 0, 1)
end
@inbounds data[k] = ifelse(n == 0, 0, c̄ / n)
end

function update_pole_value!(bc::PolarValue, c, grid, loc)
j = bc.side == :north ? grid.Ny : 1
dev = device(architecture(grid))
_average_pole_value!(dev, 16, grid.Nz)(bc.data, c, j, grid, loc)
return nothing
end

function fill_south_halo!(c, bc::PolarBoundaryCondition, size, offset, loc, arch, grid, args...; only_local_halos = false, kwargs...)
update_pole_value!(bc.condition, c, grid, loc)
return launch!(arch, grid, KernelParameters(size, offset),
_fill_only_south_halo!, c, bc, loc, grid, Tuple(args); kwargs...)
end

function fill_north_halo!(c, bc::PolarBoundaryCondition, size, offset, loc, arch, grid, args...; only_local_halos = false, kwargs...)
update_pole_value!(bc.condition, c, grid, loc)
return launch!(arch, grid, KernelParameters(size, offset),
_fill_only_north_halo!, c, bc, loc, grid, Tuple(args); kwargs...)
end

function fill_south_and_north_halo!(c, south_bc::PolarBoundaryCondition, north_bc, size, offset, loc, arch, grid, args...; only_local_halos = false, kwargs...)
update_pole_value!(south_bc.condition, c, grid, loc)
return launch!(arch, grid, KernelParameters(size, offset),
_fill_south_and_north_halo!, c, south_bc, north_bc, loc, grid, Tuple(args); kwargs...)
end

function fill_south_and_north_halo!(c, south_bc, north_bc::PolarBoundaryCondition, size, offset, loc, arch, grid, args...; only_local_halos = false, kwargs...)
update_pole_value!(north_bc.condition, c, grid, loc)
return launch!(arch, grid, KernelParameters(size, offset),
_fill_south_and_north_halo!, c, south_bc, north_bc, loc, grid, Tuple(args); kwargs...)
end

function fill_south_and_north_halo!(c, south_bc::PolarBoundaryCondition, north_bc::PolarBoundaryCondition, size, offset, loc, arch, grid, args...; only_local_halos = false, kwargs...)
update_pole_value!(south_bc.condition, c, grid, loc)
update_pole_value!(north_bc.condition, c, grid, loc)
return launch!(arch, grid, KernelParameters(size, offset),
_fill_south_and_north_halo!, c, south_bc, north_bc, loc, grid, Tuple(args); kwargs...)
end

# If it is a LatitudeLongitudeGrid, we include the PolarBoundaryConditions
function FieldBoundaryConditions(grid::LatitudeLongitudeGrid, location, indices=(:, :, :);
west = default_auxiliary_bc(topology(grid, 1)(), location[1]()),
east = default_auxiliary_bc(topology(grid, 1)(), location[1]()),
south = default_auxiliary_bc(topology(grid, 2)(), location[2]()),
north = default_auxiliary_bc(topology(grid, 2)(), location[2]()),
bottom = default_auxiliary_bc(topology(grid, 3)(), location[3]()),
top = default_auxiliary_bc(topology(grid, 3)(), location[3]()),
immersed = NoFluxBoundaryCondition())

north = latitude_north_auxiliary_bc(grid, location, north)
south = latitude_south_auxiliary_bc(grid, location, south)

return FieldBoundaryConditions(indices, west, east, south, north, bottom, top, immersed)
end
4 changes: 3 additions & 1 deletion src/Fields/abstract_field.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ Base.parent(f::AbstractField) = f
const Abstract3DField = AbstractField{<:Any, <:Any, <:Any, <:Any, <:Any, 3}
const Abstract4DField = AbstractField{<:Any, <:Any, <:Any, <:Any, <:Any, 4}

const Range = Union{UnitRange, Base.OneTo, Base.Slice{<:Base.OneTo}}

# TODO: to omit boundaries on Face fields, we have to return 2:N
# when topo=Bounded, and loc=Face
@inline axis(::Colon, N) = Base.OneTo(N)
@inline axis(index::UnitRange, N) = index
@inline axis(index::Range, N) = index

@inline function Base.axes(f::Abstract3DField)
Nx, Ny, Nz = size(f)
Expand Down
4 changes: 4 additions & 0 deletions src/Fields/constant_field.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ const CF = Union{ConstantField, ZeroField, OneField}
fill_halo_regions!(::ZeroField, args...; kw...) = nothing
fill_halo_regions!(::ConstantField, args...; kw...) = nothing

# Views of OneField, ZeroField, ConstantField are themselves
Base.view(f::OneField, args...) = f
Base.view(f::ZeroField, args...) = f
Base.view(f::ConstantField, args...) = f
Loading