Skip to content

Commit

Permalink
Merge pull request #28 from Open-EO/danlooo/dev
Browse files Browse the repository at this point in the history
danlooo/dev
  • Loading branch information
danlooo authored Jan 16, 2024
2 parents fbd0798 + ef99533 commit 2369525
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 16 deletions.
68 changes: 52 additions & 16 deletions src/Cubes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
# - convertsion chain: DataCube -> ProcessCall -> openEO JSON
#

import Base: broadcasted, +, -, *, /, cos, sqrt, abs, ==, !, !=, maximum, reduce
using Statistics
import Base: broadcasted, +, -, *, /, ==, !, !=, >, >=, <, <=, reduce
import Base: abs, acos, asin, atan, ceil, cos, cosh, exp, floor, log, maximum, minimum, sign, sin, sinh, sqrt, tan, tanh
import Statistics: mean, median, var

"""
openEO n-dimensional array of ratser data
Expand Down Expand Up @@ -124,7 +125,7 @@ function to_band(cube::DataCube, band::String)
)) |> ProcessGraph
)
call = ProcessCall("reduce_dimension", args)
return DataCube(cube.connection, call, nothing, dimensions, cube.spatial_extent, cube.temporal_extent, cube.description, cube.license, cube.collection)
return DataCube(cube.connection, call, [], dimensions, cube.spatial_extent, cube.temporal_extent, cube.description, cube.license, cube.collection)
end

Base.getindex(cube::DataCube, band_name) = to_band(cube, band_name)
Expand Down Expand Up @@ -190,6 +191,9 @@ function binary_operator(cube::DataCube, number::Real, openeo_process::String, r
)
end

# > and < needs reversed versions
binary_operator(number::Real, cube::DataCube, openeo_process::String, reverse=false) = binary_operator(cube::DataCube, number::Real, openeo_process::String, reverse)

merge(a, b) = a == b ? a : nothing

function binary_operator(cube1::DataCube, cube2::DataCube, openeo_process::String)
Expand Down Expand Up @@ -229,19 +233,21 @@ function reduce_dimension(cube::DataCube, openeo_process::String, dimension::Str
:reducer => ProcessCall(openeo_process, Dict(:data => ProcessCallParameter("data"))) |> ProcessGraph
))

bands = dimension == "bands" ? nothing : cube.bands
bands = dimension == "bands" ? [] : cube.bands
dimensions = isnothing(cube.dimensions) ? nothing : setdiff(cube.dimensions, [dimension])
spatial_extent = dimension in ["x", "y"] ? nothing : cube.spatial_extent
temporal_extent = dimension == "t" ? nothing : cube.temporal_extent

return DataCube(
cube.connection, call,
bands, dimensions, nothing, nothing,
bands, dimensions, spatial_extent, temporal_extent,
cube.collection.description,
cube.collection.license,
cube.collection
)
end

function unary_operator(cube::DataCube, openeo_process::String)
function unary_operator(cube::DataCube, openeo_process::String; kwargs...)
if cube.call.process_id in ["apply", "reduce_dimension"]
# can append operation to last existing process call
argument = Dict("apply" => :process, "reduce_dimension" => :reducer)[cube.call.process_id]
Expand All @@ -253,15 +259,15 @@ function unary_operator(cube::DataCube, openeo_process::String)
call.result = false
end

new_call = ProcessCall(openeo_process, Dict(:x => ProcessCallParameter("x")); result=true)
new_call = ProcessCall(openeo_process, Dict(:x => ProcessCallParameter("x"), kwargs...); result=true)
push!(new_steps, new_call)

call = cube.call
call.arguments[argument] = ProcessGraph(new_steps)
else
call = ProcessCall("apply", Dict(
:data => cube.call,
:process => ProcessCall(openeo_process, Dict(:x => ProcessCallParameter("x")); result=true) |> ProcessGraph
:process => ProcessCall(openeo_process, Dict(:x => ProcessCallParameter("x"), kwargs...); result=true) |> ProcessGraph
))
end

Expand All @@ -282,6 +288,7 @@ end
*(cube::DataCube, number::Real) = binary_operator(cube, number, "multiply")
*(number::Real, cube::DataCube) = binary_operator(cube, number, "multiply", true)
/(cube::DataCube, number::Real) = binary_operator(cube, number, "divide")

broadcasted(::typeof(+), cube::DataCube, number::Real) = binary_operator(cube, number, "add")
broadcasted(::typeof(+), number::Real, cube::DataCube) = binary_operator(cube, number, "add", true)
broadcasted(::typeof(-), cube::DataCube, number::Real) = binary_operator(cube, number, "subtract")
Expand All @@ -292,7 +299,19 @@ broadcasted(::typeof(/), cube::DataCube, number::Real) = binary_operator(cube, n
broadcasted(::typeof(/), number::Real, cube::DataCube) = binary_operator(cube, number, "divide", true)

broadcasted(::typeof(==), cube::DataCube, number::Real) = binary_operator(cube, number, "eq")
broadcasted(::typeof(==), number::DataCube, cube::Real) = binary_operator(cube, number, "eq", true)
broadcasted(::typeof(==), number::Real, cube::DataCube) = binary_operator(cube, number, "eq", true)
broadcasted(::typeof(!=), cube::DataCube, number::Real) = binary_operator(cube, number, "neq")
broadcasted(::typeof(!=), number::Real, cube::DataCube) = binary_operator(cube, number, "neq", true)

broadcasted(::typeof(<), cube::DataCube, number::Real) = binary_operator(cube, number, "lt")
broadcasted(::typeof(<), number::Real, cube::DataCube) = binary_operator(cube, number, "lt", true)
broadcasted(::typeof(>), cube::DataCube, number::Real) = binary_operator(cube, number, "gt")
broadcasted(::typeof(>), number::Real, cube::DataCube) = binary_operator(cube, number, "gt", true)

broadcasted(::typeof(<=), cube::DataCube, number::Real) = binary_operator(cube, number, "lte")
broadcasted(::typeof(<=), number::Real, cube::DataCube) = binary_operator(cube, number, "lte", true)
broadcasted(::typeof(>=), cube::DataCube, number::Real) = binary_operator(cube, number, "gte")
broadcasted(::typeof(>=), number::Real, cube::DataCube) = binary_operator(cube, number, "gte", true)

# element wise operations of two data cubes
+(cube1::DataCube, cube2::DataCube) = binary_operator(cube1, cube2, "add")
Expand All @@ -303,19 +322,36 @@ broadcasted(::typeof(*), cube1::DataCube, cube2::DataCube) = binary_operator(cub
broadcasted(::typeof(/), cube1::DataCube, cube2::DataCube) = binary_operator(cube1, cube2, "divide")

# element wise unary operations
broadcasted(::typeof(sqrt), cube::DataCube) = unary_operator(cube, "sqrt")
broadcasted(::typeof(!), cube::DataCube) = unary_operator(cube, "not")
broadcasted(::typeof(abs), cube::DataCube) = unary_operator(cube, "abs")
broadcasted(::typeof(sin), cube::DataCube) = unary_operator(cube, "sin")
broadcasted(::typeof(acos), cube::DataCube) = unary_operator(cube, "arccos")
broadcasted(::typeof(asin), cube::DataCube) = unary_operator(cube, "arcsin")
broadcasted(::typeof(atan), cube::DataCube) = unary_operator(cube, "arctan")
broadcasted(::typeof(ceil), cube::DataCube) = unary_operator(cube, "ceil")
broadcasted(::typeof(cos), cube::DataCube) = unary_operator(cube, "cos")
broadcasted(::typeof(!), cube::DataCube) = unary_operator(cube, "not")
broadcasted(::typeof(cosh), cube::DataCube) = unary_operator(cube, "cosh")
broadcasted(::typeof(exp), cube::DataCube) = unary_operator(cube, "exp")
broadcasted(::typeof(floor), cube::DataCube) = unary_operator(cube, "floor")
broadcasted(::typeof(log), base::Real, cube::DataCube) = unary_operator(cube, "log"; base=base)
broadcasted(::typeof(log), cube::DataCube) = unary_operator(cube, "ln")
broadcasted(::typeof(sign), cube::DataCube) = unary_operator(cube, "sgn")
broadcasted(::typeof(sin), cube::DataCube) = unary_operator(cube, "sin")
broadcasted(::typeof(sinh), cube::DataCube) = unary_operator(cube, "sinh")
broadcasted(::typeof(sqrt), cube::DataCube) = unary_operator(cube, "sqrt")
broadcasted(::typeof(tan), cube::DataCube) = unary_operator(cube, "tan")
broadcasted(::typeof(tanh), cube::DataCube) = unary_operator(cube, "tanh")

# reducing operations
mean(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "mean", dims)
median(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "median", dims)
minimum(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "min", dims)
maximum(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "max", dims)
var(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "variance", dims)

# reduce operations
function reduce(op::Process, cube::DataCube; dims::String)
("data" in op.parameters .|> x -> x.name) || error("Process must have argument data.")
dims in cube.dimensions || error("Dimension $dims not present in the data cube.")

reduce_dimension(cube::DataCube, op.id, dims)
end

maximum(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "max", dims)
Statistics.mean(cube::DataCube; dims::String) = reduce_dimension(cube::DataCube, "mean", dims)
end
20 changes: 20 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,24 @@ password = ENV["OPENEO_PASSWORD"]
@test cube["B01"].dimensions == ["x", "y", "t"]
@test maximum(cube["B01"], dims = "t").dimensions == ["x", "y"]
@test maximum(cube, dims = "bands").dimensions == ["x", "y", "t"]

@test (cube["B02"] .== 0.5) |> typeof == DataCube
@test (0.5 .== cube["B02"]) |> typeof == DataCube
@test (cube["B02"] .!= 0.5) |> typeof == DataCube
@test (0.5 .!= cube["B02"]) |> typeof == DataCube
@test (cube["B02"] .< 0.5) |> typeof == DataCube
@test (0.5 .< cube["B02"]) |> typeof == DataCube
@test (cube["B02"] .<= 0.5) |> typeof == DataCube
@test (0.5 .<= cube["B02"]) |> typeof == DataCube
@test (cube["B02"] .> 0.5) |> typeof == DataCube
@test (0.5 .> cube["B02"]) |> typeof == DataCube
@test (cube["B02"] .>= 0.5) |> typeof == DataCube
@test (0.5 .>= cube["B02"]) |> typeof == DataCube

@test sin.(cube) |> typeof == DataCube
@test_throws MethodError sin(cube)
@test sinh.(cube) |> typeof == DataCube
@test log.(10, cube) |> typeof == DataCube
@test log.(3301, cube).call.arguments[:process][1].arguments[:base] == 3301
@test_throws MethodError log(10, cube)
end

0 comments on commit 2369525

Please sign in to comment.