Skip to content

Commit

Permalink
Merge pull request #851 from CliMA/ar/cuarray-scalar-ops
Browse files Browse the repository at this point in the history
  • Loading branch information
ali-ramadhan authored Aug 12, 2020
2 parents a8c35f5 + a30e597 commit a765fb4
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 96 deletions.
28 changes: 15 additions & 13 deletions src/Fields/field.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ end
data = zeros(arch, grid, (X, Y, Z)) ] )
Construct a `Field` on `grid` with `data` on architecture `arch` with
boundary conditions `bcs`. Each of `(X, Y, Z)` is either `Cell` or `Face` and determines
boundary conditions `bcs`. Each of `(X, Y, Z)` is either `Cell` or `Face` and determines
the field's location in `(x, y, z)`.
Example
Expand All @@ -61,7 +61,7 @@ Example
julia> ω = Field(Face, Face, Cell, CPU(), RegularCartesianmodel.grid)
"""
function Field(X, Y, Z, arch, grid,
function Field(X, Y, Z, arch, grid,
bcs = FieldBoundaryConditions(grid, (X, Y, Z)),
data = zeros(eltype(grid), arch, grid, (X, Y, Z)))

Expand Down Expand Up @@ -89,7 +89,7 @@ Field(L::Tuple, args...) = Field(destantiate.(L)..., args...)
#####

"""
CellField([ FT=eltype(grid) ], arch::AbstractArchitecture, grid,
CellField([ FT=eltype(grid) ], arch::AbstractArchitecture, grid,
[ bcs = TracerBoundaryConditions(grid),
data = zeros(FT, arch, grid, (Cell, Cell, Cell) ] )
Expand All @@ -111,13 +111,13 @@ end
Return a `Field{Face, Cell, Cell}` on architecture `arch` and `grid` containing `data`
with field boundary conditions `bcs`.
"""
function XFaceField(FT::DataType, arch, grid,
function XFaceField(FT::DataType, arch, grid,
bcs = UVelocityBoundaryConditions(grid),
data = zeros(FT, arch, grid, (Face, Cell, Cell)))

return Field{Face, Cell, Cell}(data, grid, bcs)
end

"""
YFaceField([ FT=eltype(grid) ], arch::AbstractArchitecture, grid,
[ bcs = VVelocityBoundaryConditions(grid),
Expand All @@ -132,7 +132,7 @@ function YFaceField(FT::DataType, arch, grid,

return Field{Cell, Face, Cell}(data, grid, bcs)
end

"""
ZFaceField([ FT=eltype(grid) ], arch::AbstractArchitecture, grid,
[ bcs = WVelocityBoundaryConditions(grid),
Expand Down Expand Up @@ -167,7 +167,7 @@ location(f, i) = location(f)[i]
architecture(f::Field) = architecture(f.data)
architecture(o::OffsetArray) = architecture(o.parent)

"Returns the length of a field's `data`."
"Returns the length of a field's `data`."
@inline length(f::Field) = length(f.data)


Expand Down Expand Up @@ -219,7 +219,9 @@ contained by `f` along `x, y, z`.

@inline cpudata(a) = data(a)

@hascuda @inline cpudata(f::Field{X, Y, Z, <:CuArray}) where {X, Y, Z} =
const OffsetCuArray = OffsetArray{T, D, <:CuArray} where {T, D}

@hascuda @inline cpudata(f::Field{X, Y, Z, <:OffsetCuArray}) where {X, Y, Z} =
OffsetArray(Array(parent(f)), f.grid, location(f))

# Endpoint for recursive `datatuple` function:
Expand All @@ -229,12 +231,12 @@ contained by `f` along `x, y, z`.
@inline Base.parent(f::Field) = f.data.parent

"Returns a view of `f` that excludes halo points."
@inline interior(f::Field{X, Y, Z}) where {X, Y, Z} = view(f.data, interior_indices(X, topology(f, 1), f.grid.Nx),
interior_indices(Y, topology(f, 2), f.grid.Ny),
@inline interior(f::Field{X, Y, Z}) where {X, Y, Z} = view(f.data, interior_indices(X, topology(f, 1), f.grid.Nx),
interior_indices(Y, topology(f, 2), f.grid.Ny),
interior_indices(Z, topology(f, 3), f.grid.Nz))

"Returns a reference (not a view) to the interior points of `field.data.parent.`"
@inline interiorparent(f::Field{X, Y, Z}) where {X, Y, Z} =
@inline interiorparent(f::Field{X, Y, Z}) where {X, Y, Z} =
@inbounds f.data.parent[interior_parent_indices(X, topology(f, 1), f.grid.Nx, f.grid.Hx),
interior_parent_indices(Y, topology(f, 2), f.grid.Ny, f.grid.Hy),
interior_parent_indices(Z, topology(f, 3), f.grid.Nz, f.grid.Hz)]
Expand Down Expand Up @@ -271,7 +273,7 @@ offset_indices(::Type{Face}, ::Type{Bounded}, N, H=0) = 1 - H : N + H + 1
OffsetArray(underlying_data, grid, loc)
Returns an `OffsetArray` that maps to `underlying_data` in memory,
with offset indices appropriate for the `data` of a field on
with offset indices appropriate for the `data` of a field on
a `grid` of `size(grid)` and located at `loc`.
"""
function OffsetArray(underlying_data, grid, loc)
Expand All @@ -286,7 +288,7 @@ end
zeros([FT=Float64], ::CPU, grid, loc)
Returns an `OffsetArray` of zeros of float type `FT`, with
parent data in CPU memory and indices corresponding to a field on a
parent data in CPU memory and indices corresponding to a field on a
`grid` of `size(grid)` and located at `loc`.
"""
function Base.zeros(FT, ::CPU, grid, loc=(Cell, Cell, Cell))
Expand Down
2 changes: 1 addition & 1 deletion src/Fields/set!.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function set!(Φ::NamedTuple; kwargs...)
return nothing
end

set!(u::Field, v::Number) = @. u.data = v
set!(u::Field, v::Number) = @. u.data.parent = v

set!(u::Field{X, Y, Z, A}, v::Field{X, Y, Z, A}) where {X, Y, Z, A} =
@. u.data.parent = v.data.parent
Expand Down
21 changes: 12 additions & 9 deletions src/Oceananigans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,6 @@ function write_output end
#####

include("Architectures.jl")

using Oceananigans.Architectures: @hascuda
@hascuda begin
@debug "CUDA-enabled GPU(s) detected:"
for (gpu, dev) in enumerate(CUDA.devices())
@debug "$dev: $(CUDA.name(dev))"
end
end

include("Utils/Utils.jl")
include("Logger.jl")
include("Grids/Grids.jl")
Expand All @@ -149,6 +140,7 @@ include("AbstractOperations/AbstractOperations.jl")
##### Re-export stuff from submodules
#####

using .Logger
using .Architectures
using .Utils
using .Grids
Expand All @@ -164,4 +156,15 @@ using .Models
using .TimeSteppers
using .Simulations

function __init__()
Logging.global_logger(ModelLogger())
@hascuda begin
@debug "CUDA-enabled GPU(s) detected:"
for (gpu, dev) in enumerate(CUDA.devices())
@debug "$dev: $(CUDA.name(dev))"
end
CUDA.allowscalar(false)
end
end

end # module
6 changes: 3 additions & 3 deletions src/OutputWriters/OutputWriters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ export

using CUDA

using Oceananigans
using Oceananigans.Architectures
using Oceananigans.Grids
using Oceananigans.Fields
using Oceananigans.Architectures
using Oceananigans.Models

using Oceananigans: AbstractOutputWriter, @hascuda
using Oceananigans: AbstractOutputWriter
using Oceananigans.Fields: OffsetArray

Base.open(ow::AbstractOutputWriter) = nothing
Expand Down
6 changes: 3 additions & 3 deletions src/Solvers/channel_pressure_solver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ function ChannelPressureSolver(::GPU, grid, pressure_bcs, no_args...)
M_ky = ones(1, Ny, 1) |> CuArray
M_kz = ones(1, 1, Nz) |> CuArray

M_ky[1] = 0
M_kz[1] = 0
CUDA.@allowscalar M_ky[1] = 0
CUDA.@allowscalar M_kz[1] = 0

constants = (ω_4Ny⁺ = ω_4Ny⁺, ω_4Nz⁺ = ω_4Nz⁺, ω_4Ny⁻ = ω_4Ny⁻, ω_4Nz⁻ = ω_4Nz⁻,
r_y_inds = r_y_inds, r_z_inds = r_z_inds,
Expand Down Expand Up @@ -142,7 +142,7 @@ function solve_poisson_equation!(solver::PressureSolver{Channel, GPU}, grid)

@. B = -B / (kx² + ky² + kz²)

B[1, 1, 1] = 0 # Setting DC component of the solution (the mean) to be zero.
CUDA.@allowscalar B[1, 1, 1] = 0 # Setting DC component of the solution (the mean) to be zero.

solver.transforms.IFFTx! * B # Calculate IFFTˣ(ϕ̂) in place.

Expand Down
4 changes: 2 additions & 2 deletions src/Solvers/horizontally_periodic_pressure_solver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function HorizontallyPeriodicPressureSolver(::GPU, grid, pressure_bcs, no_args..
# multiplied by 2. For some reason, we only need to account for this when
# doing a 1D IDCT (for PPN boundary conditions) but not for a 2D IDCT. It's
# possible that the masks are effectively doing this job.
ω_4Nz⁻[1] *= 1/2
CUDA.@allowscalar ω_4Nz⁻[1] *= 1/2

constants = (ω_4Nz⁺ = ω_4Nz⁺, ω_4Nz⁻ = ω_4Nz⁻)

Expand Down Expand Up @@ -145,7 +145,7 @@ function solve_poisson_equation!(solver::PressureSolver{HorizontallyPeriodic, GP
# Setting DC component of the solution (the mean) to be zero. This is also
# necessary because the source term to the Poisson equation has zero mean
# and so the DC component comes out to be ∞.
ϕ[1, 1, 1] = 0
CUDA.@allowscalar ϕ[1, 1, 1] = 0

solver.transforms.IFFTxy! * ϕ # Calculate IFFTˣʸ(ϕ̂) in place.

Expand Down
53 changes: 26 additions & 27 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,31 +72,30 @@ closures = (

include("runtests_utils.jl")

with_logger(ModelLogger()) do
@testset "Oceananigans" begin
include("test_grids.jl")
include("test_operators.jl")
include("test_boundary_conditions.jl")
include("test_fields.jl")
include("test_halo_regions.jl")
include("test_solvers.jl")
include("test_pressure_solvers.jl")
include("test_coriolis.jl")
include("test_buoyancy.jl")
include("test_surface_waves.jl")
include("test_models.jl")
include("test_simulations.jl")
include("test_time_stepping.jl")
include("test_time_stepping_bcs.jl")
include("test_forcings.jl")
include("test_turbulence_closures.jl")
include("test_dynamics.jl")
include("test_diagnostics.jl")
include("test_output_writers.jl")
include("test_abstract_operations.jl")
include("test_regression.jl")
include("test_examples.jl")
include("test_verification.jl")
include("test_benchmarks.jl")
end
@testset "Oceananigans" begin
include("test_grids.jl")
include("test_operators.jl")
include("test_boundary_conditions.jl")
include("test_fields.jl")
include("test_halo_regions.jl")
include("test_solvers.jl")
include("test_pressure_solvers.jl")
include("test_coriolis.jl")
include("test_buoyancy.jl")
include("test_surface_waves.jl")
include("test_models.jl")
include("test_simulations.jl")
include("test_time_stepping.jl")
include("test_time_stepping_bcs.jl")
include("test_forcings.jl")
include("test_turbulence_closures.jl")
include("test_dynamics.jl")
include("test_diagnostics.jl")
include("test_output_writers.jl")
include("test_abstract_operations.jl")
include("test_regression.jl")
include("test_examples.jl")
include("test_verification.jl")
include("test_benchmarks.jl")
end

20 changes: 16 additions & 4 deletions test/test_fields.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Oceananigans.Fields: cpudata

"""
correct_field_size(N, L, ftf)
Test that the field initialized by the field type function `ftf` on the grid g
has the correct size.
"""
correct_field_size(a, g, fieldtype, Tx, Ty, Tz) = size(parent(fieldtype(a, g))) == (Tx, Ty, Tz)

"""
correct_field_value_was_set(N, L, ftf, val)
Expand All @@ -16,7 +18,7 @@ function.
function correct_field_value_was_set(arch, grid, fieldtype, val::Number)
f = fieldtype(arch, grid)
set!(f, val)
return interior(f) val * ones(size(f))
CUDA.@allowscalar return interior(f) val * ones(size(f))
end

@testset "Fields" begin
Expand Down Expand Up @@ -84,11 +86,21 @@ end
end
end

@testset "Miscellaneous field functionality" begin
@info " Testing miscellaneous field functionality..."
@testset "Field utils" begin
@info " Testing field utils..."

@test Fields.has_velocities(()) == false
@test Fields.has_velocities((:u,)) == false
@test Fields.has_velocities((:u, :v)) == false
@test Fields.has_velocities((:u, :v, :w)) == true

grid = RegularCartesianGrid(size=(4, 6, 8), extent=(1, 1, 1))
ϕ = CellField(CPU(), grid)
@test cpudata(ϕ).parent isa Array

@hascuda begin
ϕ = CellField(GPU(), grid)
@test cpudata(ϕ).parent isa Array
end
end
end
2 changes: 1 addition & 1 deletion test/test_halo_regions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function halo_regions_correctly_filled(arch, FT, Nx, Ny, Nz)
grid = RegularCartesianGrid(FT, size=(Nx, Ny, Nz), extent=(Lx, Ly, Lz))
field = CellField(FT, arch, grid)

interior(field) .= rand(FT, Nx, Ny, Nz)
set!(field, rand(FT, Nx, Ny, Nz))
fill_halo_regions!(field, arch)

Hx, Hy, Hz = grid.Hx, grid.Hy, grid.Hz
Expand Down
Loading

0 comments on commit a765fb4

Please sign in to comment.