Skip to content

Commit

Permalink
add CHELSA V2 (#62)
Browse files Browse the repository at this point in the history
* download chelsa v2 bioclim

* add version keyword, implement bioclim+

* avoid Val(version), use if-else instead

* make constants UPPERCASE

* display info when downloading new data

* specify version and patch are keywords

* fix some types in documentation

* add future bioclimplus

* add koppen-geiger to bioclimplus layers

* add documentation for getraster with bioclimplus

* swb (soil water balance) is not monthly

* correct bioclimplus layers for future

* pet is called pet_penman

* add chelsa current climate

* add tests for chelsa bioclimplus and chelsa climate

* delete aqua toml formatting, test chelsa climate

* fix tests

* fix and test chelsa_warn_version

* rastername for pet uses pet_penman

* move a line away from docs

* update readme and chelsa docs
  • Loading branch information
tiemvanderdeure authored Jun 14, 2024
1 parent e36ed78 commit 37cf277
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Currently sources include:

| Source | URL | Status |
| --------- | ---------------------------------------- | ---------------------------------------- |
| CHELSA | https://chelsa-climate.org | BioClim, Future BioClim and Climate |
| CHELSA | https://chelsa-climate.org | BioClim, BioClimPlus, and Climate |
| WorldClim | https://www.worldclim.org | Climate, Weather, BioClim, and Elevation |
| EarthEnv | http://www.earthenv.org | LandCover and HabitatHeterogeneity |
| AWAP | http://www.bom.gov.au/jsp/awap/index.jsp | Complete |
Expand Down
5 changes: 4 additions & 1 deletion src/RasterDataSources.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import JSON.Parser as JP

export WorldClim, CHELSA, EarthEnv, AWAP, ALWB, SRTM, MODIS

export BioClim, Climate, Weather, Elevation, LandCover, HabitatHeterogeneity
export BioClim, BioClimPlus, Climate, Weather, Elevation, LandCover, HabitatHeterogeneity

export Future, CMIP5, CMIP6

Expand Down Expand Up @@ -47,6 +47,8 @@ export ACCESS1, BNUESM, CCSM4, CESM1BGC, CESM1CAM5, CMCCCMS, CMCCCM, CNRMCM5,
# Climate models from CMIP6 (used in WorldClim)
export BCCCSM2MR, CNRMCM61, CNRMESM21, CanESM5, GFDLESM4, IPSLCM6ALR, MIROCES2L, MIROC6, MRIESM2

# Climate models from CMIP6 (CHELSA)
export UKESM, MPIESMHR

export Values, Deciles

Expand All @@ -63,6 +65,7 @@ include("worldclim/weather.jl")
include("worldclim/elevation.jl")

include("chelsa/shared.jl")
include("chelsa/climate.jl")
include("chelsa/bioclim.jl")
include("chelsa/future.jl")

Expand Down
89 changes: 78 additions & 11 deletions src/chelsa/bioclim.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
layers(::Type{CHELSA{BioClim}}) = layers(BioClim)
layers(::Type{CHELSA{BioClimPlus}}) = layers(BioClimPlus)
layerkeys(::Type{CHELSA{BioClim}}, args...) = layerkeys(BioClim, args...)
layerkeys(::Type{CHELSA{BioClimPlus}}, args...) = layerkeys(BioClimPlus, args...)

"""
getraster(source::Type{CHELSA{BioClim}}, [layer]) => Union{Tuple,String}
getraster(source::Type{CHELSA{BioClim}}, [layer]; version = 2, [patch]) => Union{Tuple,String}
Download [`CHELSA`](@ref) [`BioClim`](@ref) data from [chelsa-climate.org](https://chelsa-climate.org/).
Expand All @@ -11,23 +13,88 @@ Download [`CHELSA`](@ref) [`BioClim`](@ref) data from [chelsa-climate.org](https
or `Symbol`s form `$(layerkeys(BioClim))`. Without a `layer` argument, all layers
will be downloaded, and a `NamedTuple` of paths returned.
# Keyword arguments
$CHELSA_KEYWORDS
Returns the filepath/s of the downloaded or pre-existing files.
"""
getraster(T::Type{CHELSA{BioClim}}, layer::Union{Tuple,Int,Symbol}) = _getraster(T, layer)
getraster(
T::Type{CHELSA{BioClim}},
layer::Union{Tuple,Int,Symbol};
version::Int = 2,
patch::Int = latest_patch(T, version)) = _getraster(T, layer, version, patch)

_getraster(T::Type{CHELSA{BioClim}}, layers::Tuple) = _map_layers(T, layers)
_getraster(T::Type{CHELSA{BioClim}}, layer::Symbol) = _getraster(T, bioclim_int(layer))
function _getraster(T::Type{CHELSA{BioClim}}, layer::Integer)
_getraster(T::Type{CHELSA{BioClim}}, layers::Tuple, version, patch) = _map_layers(T, layers, version, patch)
_getraster(T::Type{CHELSA{BioClim}}, layer::Symbol, version, patch) = _getraster(T, bioclim_int(layer), version, patch)
function _getraster(T::Type{CHELSA{BioClim}}, layer::Integer, version, patch)
_check_layer(T, layer)
path = rasterpath(T, layer)
url = rasterurl(T, layer)
path = rasterpath(T, layer; version, patch)
url = rasterurl(T, layer; version, patch)
CHELSA_warn_version(T, layer, version, patch, path)
return _maybe_download(url, path)
end
getraster_keywords(::Type{<:CHELSA{BioClim}}) = (:version,:patch)

rastername(::Type{CHELSA{BioClim}}, layer::Integer) = "CHELSA_bio10_$(lpad(layer, 2, "0")).tif"
function rastername(::Type{CHELSA{BioClim}}, layer::Integer; version::Int = 2, patch = latest_patch(CHELSA, version))
if version == 1
"CHELSA_bio10_$(lpad(layer, 2, "0")).tif"
elseif version == 2
"CHELSA_bio$(layer)_1981-2010_V.2.$patch.tif"
else
CHELSA_invalid_version(version)
end
end

rasterpath(::Type{CHELSA{BioClim}}) = joinpath(rasterpath(CHELSA), "BioClim")
rasterpath(T::Type{CHELSA{BioClim}}, layer::Integer) = joinpath(rasterpath(T), rastername(T, layer))
rasterpath(T::Type{CHELSA{BioClim}}, layer::Integer; version = 2, patch = latest_patch(CHELSA, version)) = joinpath(rasterpath(T), rastername(T, layer; version, patch))

function rasterurl(::Type{CHELSA{BioClim}}; version)
if version == 1
joinpath(rasterurl(CHELSA, version), "climatologies/")
elseif version == 2
joinpath(rasterurl(CHELSA, version), "climatologies/1981-2010/")
else
CHELSA_invalid_version(version)
end
end

rasterurl(T::Type{CHELSA{BioClim}}, layer::Integer; version = 2, patch = latest_patch(CHELSA, version)) =
joinpath(rasterurl(T; version), "bio", rastername(T, layer; version, patch))

### Bioclim+
"""
getraster(source::Type{CHELSA{BioClim}}, [layer]; version = 2, [patch]) => Union{Tuple,String}
Download [`CHELSA`](@ref) [`BioClim`](@ref) data from [chelsa-climate.org](https://chelsa-climate.org/).
# Arguments
- `layer`: iterable of `Symbol`s from `$(layerkeys(BioClimPlus))`. Without a `layer` argument, all layers
will be downloaded, and a `NamedTuple` of paths returned.
# Keyword arguments
$CHELSA_KEYWORDS
Returns the filepath/s of the downloaded or pre-existing files.
"""
getraster(
T::Type{CHELSA{BioClimPlus}},
layer::Union{Tuple,Int,Symbol};
version::Int = 2,
patch::Int = latest_patch(T, version)) = _getraster(T, layer, version, patch)

_getraster(T::Type{CHELSA{BioClimPlus}}, layers::Tuple, version, patch) = _map_layers(T, layers, version, patch)
function _getraster(T::Type{CHELSA{BioClimPlus}}, layer::Symbol, version, patch)
version == 2 || CHELSA_invalid_version(version, 2)
_check_layer(T, layer)
path = rasterpath(T, layer; version, patch)
url = rasterurl(T, layer; version, patch)
return _maybe_download(url, path)
end
getraster_keywords(::Type{<:CHELSA{BioClimPlus}}) = (:version,:patch)


rasterurl(::Type{CHELSA{BioClim}}) = joinpath(rasterurl(CHELSA), "chelsa_V1/climatologies/bio/")
rasterurl(T::Type{CHELSA{BioClim}}, layer::Integer) = joinpath(rasterurl(T), rastername(T, layer))
rastername(T::Type{CHELSA{BioClimPlus}}, layer::Symbol; version = 2, patch = latest_patch(T, version)) = "CHELSA_$(layer)_1981-2010_V.2.$patch.tif"
rasterpath(::Type{CHELSA{BioClimPlus}}) = rasterpath(CHELSA{BioClim})
rasterpath(T::Type{CHELSA{BioClimPlus}}, layer::Symbol; version = 2, patch = latest_patch(T, version)) = joinpath(rasterpath(T), rastername(T, layer; version, patch))
rasterurl(T::Type{CHELSA{BioClimPlus}}, layer::Symbol; version = 2, patch = latest_patch(T, version)) =
joinpath(rasterurl(CHELSA{BioClim}; version), "bio", rastername(T, layer; version, patch))
44 changes: 44 additions & 0 deletions src/chelsa/climate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
layers(::Type{CHELSA{Climate}}) = (:clt, :cmi, :hurs, :ncdf, :pet, :pr, :rsds, :sfcWind, :tas, :tasmax, :tasmin, :vpd)

"""
getraster(T::Type{CHELSA{Climate}}, [layer::Union{Tuple,Symbol}]; month) => Vector{String}
Download [`CHELSA`](@ref) [`Climate`](@ref) data.
# Arguments
- `layer` `Symbol` or `Tuple` of `Symbol` from `$(layers(CHELSA{Climate}))`.
# Keywords
- `month`: `Integer` or `AbstractArray` of `Integer`. Chosen from `1:12`.
Returns the filepath/s of the downloaded or pre-existing files.
"""
function getraster(T::Type{CHELSA{Climate}}, layers::Union{Tuple,Symbol}; month)
_getraster(T, layers, month)
end

getraster_keywords(::Type{CHELSA{Climate}}) = (:month,)

function _getraster(T::Type{CHELSA{Climate}}, layers, month::AbstractArray)
_getraster.(T, Ref(layers), month)
end
function _getraster(T::Type{CHELSA{Climate}}, layers::Tuple, month::Integer)
_map_layers(T, layers, month)
end
function _getraster(T::Type{CHELSA{Climate}}, layer::Symbol, month::Integer)
_check_layer(T, layer)
path = rasterpath(T, layer; month)
url = rasterurl(T, layer; month)
return _maybe_download(url, path)
end

# Climate layers don't get their own folder
rasterpath(T::Type{<:CHELSA{Climate}}, layer; month) =
joinpath(_rasterpath(T, layer), rastername(T, layer; month))
_rasterpath(T::Type{<:CHELSA{Climate}}, layer) = joinpath(rasterpath(T), string(layer))
rasterpath(T::Type{<:CHELSA{Climate}}) = joinpath(rasterpath(CHELSA), "Climate")
function rastername(T::Type{<:CHELSA{Climate}}, layer; month)
_layer = layer == :pet ? :pet_penman : layer
"CHELSA_$(_layer)_$(_pad2(month))_1981-2010_V.2.1.tif"
end
rasterurl(T::Type{CHELSA{Climate}}, layer::Symbol; month) = joinpath(rasterurl(CHELSA, 2), "climatologies/1981-2010", string(layer), rastername(T, layer; month))
61 changes: 59 additions & 2 deletions src/chelsa/future.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

layers(::Type{<:CHELSA{<:Future{BioClim}}}) = layers(BioClim)
layers(::Type{<:CHELSA{T}}) where T <:Future{BioClimPlus} = layers(T)
layerkeys(T::Type{<:CHELSA{<:Future{BioClim}}}, args...) = layerkeys(BioClim, args...)

layers(::Type{<:CHELSA{<:Future{Climate}}}) = (:prec, :temp, :tmin, :tmax)
Expand All @@ -24,7 +25,15 @@ returned.
- `date`: a `Date` or `DateTime` object, a Vector, or Tuple of start/end dates.
Note that CHELSA CMIP5 only has two datasets, for the periods 2041-2060 and
2061-2080. Dates must fall within these ranges.
2061-2080. CMIP6 has datasets for the periods 2011-2040, 2041-2070, and 2071-2100.
Dates must fall within these ranges.
## Example
```julia
using RasterDataSources, Dates
getraster(CHELSA{Future{BioClim, CMIP6, GFDLESM4, SSP370}}, 1, date = Date(2050))
```
"""
function getraster(
T::Type{<:CHELSA{<:Future{BioClim}}}, layers::Union{Tuple,Int,Symbol}; date
Expand All @@ -34,6 +43,34 @@ end

getraster_keywords(::Type{<:CHELSA{<:Future{BioClim}}}) = (:date,)

"""
getraster(T::Type{CHELSA{Future{BioClimPlus}}}, [layer]; date) => String
Download CHELSA [`BioClimPlus`](@ref) data, choosing layers from: `$(layers(CHELSA{BioClimPlus}))`.
See the docs for [`Future`](@ref) for model choices.
Without a layer argument, all layers will be downloaded, and a `NamedTuple` of paths
returned.
## Keywords
- `date`: a `Date` or `DateTime` object, a Vector, or Tuple of start/end dates.
Note that CHELSA CMIP5 only has two datasets, for the periods 2041-2060 and
2061-2080. CMIP6 has datasets for the periods 2011-2040, 2041-2070, and 2071-2100.
Dates must fall within these ranges.
## Example
"""
function getraster(
T::Type{<:CHELSA{<:Future{BioClimPlus}}}, layers::Union{Tuple,Int,Symbol}; date
)
_getraster(T, layers, date)
end

getraster_keywords(::Type{<:CHELSA{<:Future{BioClimPlus}}}) = (:date,)


"""
getraster(T::Type{CHELSA{Future{Climate}}}, [layer]; date, month) => String
Expand All @@ -47,8 +84,15 @@ Without a layer argument, all layers will be downloaded, and a `NamedTuple` of p
- `date`: a `Date` or `DateTime` object, a Vector, or Tuple of start/end dates.
Note that CHELSA CMIP5 only has two datasets, for the periods 2041-2060 and
2061-2080. Dates must fall within these ranges.
2061-2080. CMIP6 has datasets for the periods 2011-2040, 2041-2070, and 2071-2100.
Dates must fall within these ranges.
- `month`: the month of the year, from 1 to 12, or a array or range of months like `1:12`.
## Example
```
using Dates, RasterDataSources
getraster(CHELSA{Future{Climate, CMIP6, GFDLESM4, SSP370}}, :prec; date = Date(2050), month = 1)
```
"""
function getraster(
T::Type{<:CHELSA{<:Future{Climate}}}, layers::Union{Tuple,Symbol}; date, month
Expand Down Expand Up @@ -84,6 +128,12 @@ end
function _getraster(T::Type{<:CHELSA{<:Future{BioClim}}}, layers, date::TimeType)
_getraster(T, layers; date)
end
function _getraster(T::Type{<:CHELSA{<:Future{BioClimPlus}}}, layers, dates::AbstractArray)
map(date -> _getraster(T, layers, date), dates)
end
function _getraster(T::Type{<:CHELSA{<:Future{BioClimPlus}}}, layers, date::TimeType)
_getraster(T, layers; date)
end

# We have the extra args as keywords again to generalise rasterpath/rasterurl
function _getraster(T::Type{<:CHELSA{<:Future}}, layers::Tuple; kw...)
Expand Down Expand Up @@ -124,6 +174,12 @@ function _rastername(::Type{CMIP6}, T::Type{<:CHELSA{<:Future{BioClim}}}, layer:
scen = _format(CHELSA, _scenario(T))
return "CHELSA_bio$(layer)_$(date_string)_$(mod)_$(scen)_V.2.1.tif"
end
function _rastername(::Type{CMIP6}, T::Type{<:CHELSA{<:Future{BioClimPlus}}}, layer::Symbol; date)
date_string = _date_string(_phase(T), date)
mod = _format(CHELSA, _model(T))
scen = _format(CHELSA, _scenario(T))
return "CHELSA_$(layer)_$(date_string)_$(mod)_$(scen)_V.2.1.tif"
end
function _rastername(
::Type{CMIP6}, T::Type{<:CHELSA{<:Future{Climate}}}, layer::Symbol; date, month
)
Expand Down Expand Up @@ -151,6 +207,7 @@ function rasterurl(T::Type{<:CHELSA{<:Future}}, layer; date, kw...)
end

_chelsa_layer(::Type{<:BioClim}, layer) = :bio
_chelsa_layer(::Type{<:BioClimPlus}, layer) = :bio
_chelsa_layer(::Type{<:Climate}, layer) = layer

function _urlpath(::Type{CMIP5}, T::Type{<:CHELSA{<:Future}}, name, date_str)
Expand Down
40 changes: 37 additions & 3 deletions src/chelsa/shared.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
"""
CHELSA{Union{BioClim,<:Future}} <: RasterDataSource
CHELSA{Union{BioClim,BioClimPlus,Climate,<:Future}} <: RasterDataSource
Data from CHELSA, currently implements the current `BioClim` and
`Future{BioClim}` variables, and `Future{Climate}`.
Data from CHELSA, currently implements the `BioClim` `BioClimPlus`, and `Climate`
variables for current and future conditions.
See: [chelsa-climate.org](https://chelsa-climate.org/) for the dataset,
and the [`getraster`](@ref) docs for implementation details.
"""
struct CHELSA{X} <: RasterDataSource end

rasterpath(::Type{CHELSA}) = joinpath(rasterpath(), "CHELSA")
function rasterurl(T::Type{CHELSA}, version)
if version == 1
joinpath(rasterurl(T), "chelsa_V1")
elseif version == 2
joinpath(rasterurl(T), "chelsa_V2/GLOBAL")
else
CHELSA_invalid_version(version)
end
end
rasterurl(::Type{CHELSA}) = URI(scheme="https", host="os.zhdk.cloud.switch.ch", path="/envicloud/chelsa/")

function latest_patch(::Type{<:CHELSA}, v)
if v == 1
2
elseif v == 2
1
else
CHELSA_invalid_version(v)
end
end

const CHELSA_KEYWORDS = """
- `version`: `Integer` indicating the CHELSA version, currently either `1` or `2`.
- `patch`: `Integer` indicating the CHELSA patch number. Defaults to the latest patch (V1.2 and V2.1)
"""

CHELSA_invalid_version(v, valid_versions = [1,2]) =
throw(ArgumentError("Version $v is not available for CHELSA. Available versions: $valid_versions."))

function CHELSA_warn_version(T, layer, version, patch, path)
if version == 2 && !isfile(path) && isfile(rasterpath(T, layer; version = 1))
@info "File for CHELSA v1.2 detected, but requested version is CHELSA v$version.$patch.
To load data for CHELSA v1.2 instead, set version keyword to 1"
end
end
Loading

0 comments on commit 37cf277

Please sign in to comment.