Skip to content

Commit

Permalink
document, test and add keyword method
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaqz committed Nov 15, 2023
1 parent ffa56ec commit 4e06f26
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 44 deletions.
4 changes: 3 additions & 1 deletion ext/RastersArchGDALExt/reproject.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ function Rasters._reproject(source::GeoFormat, target::GeoFormat, ::XDim, vals::
push!(paired_vals, (first(vals), one(first(vals))))
reps = AG.reproject(paired_vals, source, target; order=:trad)
at_one = pop!(reps)
# TODO is this test sufficient to reject the reprojection?
first(reps)[1] == at_one[1] || _reproject_crs_error(source, target)
return map(r -> r[1], reps)
end
Expand All @@ -16,4 +17,5 @@ function Rasters._reproject(source::GeoFormat, target::GeoFormat, dim::YDim, val
return map(r -> r[2], reps)
end

_reproject_crs_error(source, target) = throw(ArgumentError("Cannot reproject from: \n $source \nto: \n $target"))
_reproject_crs_error(source, target) =
throw(ArgumentError("Cannot reproject from: \n $source \nto: \n $target, coordinate reference systems are not aligned with on all axes. You may need to use `resample` instead"))
14 changes: 10 additions & 4 deletions ext/RastersArchGDALExt/resample.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
resample(x; kw...)
resample(xs...; to=first(xs), kw...)
`resample` uses `ArchGDAL.gdalwarp` to resample a [`Raster`](@ref) or
[`RasterStack`](@ref) to a new `resolution` and optionally new `crs`,
`resample` uses `warp` (which uses GDALs `gdalwarp`) to resample a [`Raster`](@ref)
or [`RasterStack`](@ref) to a new `resolution` and optionally new `crs`,
or to snap to the bounds, resolution and crs of the object `to`.
Dimensions without an `AbstractProjected` lookup (such as a `Ti` dimension)
are iteratively resampled with GDAL and joined back int a single array.
If projections can be converted for each axis independently, it may
be faster and more accurate to use [`reproject`](@ref).
# Arguments
- `x`: the object/s to resample.
Expand Down Expand Up @@ -39,8 +45,8 @@ $FILENAME_KEYWORD
$SUFFIX_KEYWORD
Note:
- GDAL may cause some unexpected changes in the data, such as returning a reversed Y dimension or
changing the `crs` type from `EPSG` to `WellKnownText` (it will represent the same CRS).
- GDAL may cause some unexpected changes in the raster, such as changing the `crs`
type from `EPSG` to `WellKnownText` (it will represent the same CRS).
# Example
Expand Down
40 changes: 11 additions & 29 deletions ext/RastersNCDatasetsExt/ncdatasets_source.jl
Original file line number Diff line number Diff line change
Expand Up @@ -201,48 +201,30 @@ function DD.layermetadata(ds::NCD.Dataset)
end
md
end
NamedTuple{map(Symbol, keys)}(dimtypes)
return NamedTuple{map(Symbol, keys)}(dimtypes)
end

RA.missingval(var::NCD.CFVariable{T}) where T = missing isa T ? missing : nothing
RA.missingval(var::NCD.Dataset) = missing

function RA.layerkeys(ds::NCD.Dataset)
dimkeys = _dimkeys(ds)
toremove = if "bnds" in dimkeys
dimkeys = setdiff(dimkeys, ("bnds",))
boundskeys = String[]
for k in dimkeys
var = NCD.variable(ds, k)
if haskey(var.attrib, "bounds")
push!(boundskeys, var.attrib["bounds"])
end
end
union(dimkeys, boundskeys)::Vector{String}
else
dimkeys::Vector{String}
end
nondim = setdiff(keys(ds), toremove)
grid_mapping = String[]
for k in nondim
var = NCD.variable(ds, k)
if haskey(var.attrib, "grid_mapping")
push!(grid_mapping, var.attrib["grid_mapping"])
end
return filter(keys(ds)) do key
key in dimkeys && return false
endswith(lowercase(key), r"bnds|bounds") return false
!haskey(NCD.variable(ds, k).attrib, "grid_mapping")
end
nondim = setdiff(nondim, grid_mapping)
end

function RA.FileStack{NCDsource}(ds::NCD.Dataset, filename::AbstractString; write=false, keys)
keys = map(Symbol, keys isa Nothing ? RA.layerkeys(ds) : keys) |> Tuple
type_size_ec_hc = map(keys) do key
var = ds[string(key)]
Union{Missing,eltype(var)}, size(var), _ncd_eachchunk(var), _ncd_haschunks(var)
vars = map(keys) do key
ds[string(key)]
end
layertypes = map(x->x[1], type_size_ec_hc)
layersizes = map(x->x[2], type_size_ec_hc)
eachchunk = map(x->x[3], type_size_ec_hc)
haschunks = map(x->x[4], type_size_ec_hc)
layertypes = map(v -> Union{Missing,eltype(v)}, vars)
layersizes = map(size, vars)
eachchunk = map(_ncd_eachchunk, vars)
haschunks = map(_ncd_haschunks, vars)
return RA.FileStack{NCDsource,keys}(filename, layertypes, layersizes, eachchunk, haschunks, write)
end
function RA.OpenStack(fs::RA.FileStack{NCDsource,K}) where K
Expand Down
7 changes: 5 additions & 2 deletions src/methods/crop_extend.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ to match the size of the object `to`, or smallest of any dimensions that are sha
area of all `xs` is used.
- `touches`: `true` or `false`. Whether to use `Touches` wraper on the object extent.
When lines need to be included in e.g. zonal statistics, `true` should be used.
- `boundary`: `:inside`, `:center` or `:touches`
As `crop` is lazy, `filename` and `suffix` keywords are not used.
Expand Down Expand Up @@ -100,11 +101,12 @@ function _crop_to(x, to::DimTuple; kw...)
end
return _crop_to(x, Extents.extent(sampled); kw...)
end
function _crop_to(x, to::Extents.Extent; touches=false)
function _crop_to(x, to::Extents.Extent; touches=false, boundary=:inside)
# Take a view over the bounds
_without_mapped_crs(x) do x1
if touches
view(x1, Touches(to))
e
else
view(x1, to)
end
Expand All @@ -124,7 +126,7 @@ covered by all `xs`, or by the keyword argument `to`.
- `to`: the Raster or dims to extend to. If no `to` keyword is passed, the largest
shared area of all `xs` is used.
- `touches`: `true` or `false`. Whether to use `Touches` wraper on the object extent.
When lines need to be included in e.g. zonal statistics, `true` shoudle be used.
When lines need to be included in e.g. zonal statistics, `true` should be used.
$FILENAME_KEYWORD
$SUFFIX_KEYWORD
Expand Down Expand Up @@ -215,6 +217,7 @@ function _extend_to(x::RasterStackOrArray, extent::Extents.Extent{K}; kw...) whe
shareddims = dims(x, dims(extent))
bnds = map(val, dims(extent, shareddims))
newdims = map(shareddims, bnds) do d, b
span(dim) isa Regular || throw(ArgumentError("Can only `extend` rasters with `Regular` lookups"))
l = lookup(d)
# Use ranges for math because they have TwicePrecision magic
# Define a range down to the lowest value,
Expand Down
19 changes: 14 additions & 5 deletions src/methods/reproject.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@

"""
reproject(target::GeoFormat, x)
reproject(obj; crs)
Reproject the dimensions of `x` to a different crs.
Reproject the lookups of `obj` to a different crs.
# Arguments
This is a lossless operation for the raster data, as only the
lookup values change. This is only possible when the axes of source
and destination projections are alligned: the change is usually from
a [`Regular`](@ref) and an [`Irregular`](@ref) lookup spans.
- `target`: any crs in a GeoFormatTypes.jl wrapper, e.g. `EPSG`, `WellKnownText`, `ProjString`.
- `x`: a `Dimension`, `Tuple` of `Dimension`, `Raster` or `RasterStack`.
For converting between projections that are rotated,
skewed or warped in any way, `resample` use [`resample`](@ref).
Dimensions without an `AbstractProjected` lookup (such as a `Ti` dimension)
are silently returned without modification.
# Arguments
- `obj`: a `LookupArray`, `Dimension`, `Tuple` of `Dimension`, `Raster` or `RasterStack`.
$CRS_KEYWORD
"""
reproject(x; crs::GeoFormat) = reproject(crs, x)
reproject(target::GeoFormat, x) = rebuild(x; dims=reproject(target, dims(x)))
reproject(target::GeoFormat, dims::Tuple) = map(d -> reproject(target, d), dims)
reproject(target::GeoFormat, l::LookupArray) = l
Expand Down
13 changes: 10 additions & 3 deletions test/reproject.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ using Rasters: reproject, convertlookup
@test reproject(wktcea, EPSG(4326), Y(), -3.658789324855012e6) -30.0
@test reproject(projcea, wkt4326, Y(), -3.658789324855012e6) -30.0
@test reproject(cea, proj4326, Y(), [-3.658789324855012e6]) [-30.0]


@test reproject(proj4326, cea, X(), 180.0) 1.7367530445161372e7
@test reproject(cea, EPSG(4326), X(), 1.7367530445161372e7) 180.0
Expand All @@ -23,15 +22,23 @@ using Rasters: reproject, convertlookup

x = X(Projected(0.0:1.0:360.0; crs=EPSG(4326), dim=X(), order=ForwardOrdered(), span=Regular(1.0), sampling=Intervals(Start())))
y = Y(Projected(-80.0:1.0:80.0; crs=EPSG(4326), dim=Y(), order=ReverseOrdered(), span=Regular(1.0), sampling=Intervals(Start())))
x1, y1 = reproject(projcea, (x, y))

x1, y1 = reproject((x, y); crs=projcea)
@test span(x1) isa Irregular
@test span(y1) isa Irregular
x2, y2 = reproject(EPSG(4326), (x, y))
x2, y2 = reproject((x, y); crs=EPSG(4326))
@test all(x .== x2)
@test all(y .== y2)
@test span(x2) == Regular(1.0)
@test span(y2) == Regular(1.0)

raster = rand(x, y)
reprojected_raster = reproject(raster; crs=projcea)
# Dims have changed
@test dims(reprojected_raster) == (x1, y1)
# Raster has not changed
@test reprojected_raster == raster

@test_throws ArgumentError reproject(cea, EPSG(32618), Y(), [-3.658789324855012e6])
@test_throws ArgumentError reproject(cea, EPSG(32618), X(), [-3.658789324855012e6])
end
Expand Down

0 comments on commit 4e06f26

Please sign in to comment.