From 9fc47b6642d4b58ba6dd7320e1e4783b72d925eb Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 22 Aug 2024 13:17:06 +0200
Subject: [PATCH 01/21] define climate models programatically

---
 src/RasterDataSources.jl |  14 +----
 src/chelsa/future.jl     | 112 ++++++++++++++++++++++-----------------
 src/types.jl             |  78 +++++++--------------------
 3 files changed, 83 insertions(+), 121 deletions(-)

diff --git a/src/RasterDataSources.jl b/src/RasterDataSources.jl
index dca1a62..8266921 100644
--- a/src/RasterDataSources.jl
+++ b/src/RasterDataSources.jl
@@ -37,19 +37,6 @@ export ECO4ESIPTJPL,ECO4WUE,GEDI03,GEDI04_B,MCD12Q1,MCD12Q2,MCD15A2H,
     MYD17A2H, MYD17A3HGF, MYD21A2, SIF005, SIF_ANN, VNP09A1, VNP09H1, 
     VNP13A1, VNP15A2H, VNP21A2, VNP22Q2
 
-# Climate models from CMIP5 (used in CHELSA)
-export ACCESS1, BNUESM, CCSM4, CESM1BGC, CESM1CAM5, CMCCCMS, CMCCCM, CNRMCM5,
-    CSIROMk3, CanESM2, FGOALS, FIOESM, GFDLCM3, GFDLESM2G, GFDLESM2M, GISSE2HCC,
-    GISSE2H, GISSE2RCC, GISSE2R, HadGEM2AO, HadGEM2CC, IPSLCM5ALR, IPSLCM5AMR,
-    MIROCESMCHEM, MIROCESM, MIROC5, MPIESMLR, MPIESMMR, MRICGCM3, MRIESM1, NorESM1M,
-    BCCCSM1, Inmcm4
-
-# 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
 
 export getraster
@@ -63,6 +50,7 @@ include("worldclim/bioclim.jl")
 include("worldclim/climate.jl")
 include("worldclim/weather.jl")
 include("worldclim/elevation.jl")
+include("worldclim/future.jl")
 
 include("chelsa/shared.jl")
 include("chelsa/climate.jl")
diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index 200c730..a1a76d6 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -260,54 +260,68 @@ _scenario(::Type{<:CHELSA{F}}) where F<:Future = _scenario(F)
 # Climate model string formatters for CHELSA Future
 
 # CMIP5
-_format(::Type{CHELSA}, ::Type{ACCESS1}) = "ACCESS1-0"
-_format(::Type{CHELSA}, ::Type{BNUESM}) = "BNU-ESM"
-_format(::Type{CHELSA}, ::Type{CCSM4}) = "CCSM4"
-_format(::Type{CHELSA}, ::Type{CESM1BGC}) = "CESM1-BGC"
-_format(::Type{CHELSA}, ::Type{CESM1CAM5}) = "CESM1-CAM5"
-_format(::Type{CHELSA}, ::Type{CMCCCMS}) = "CMCC-CMS"
-_format(::Type{CHELSA}, ::Type{CMCCCM}) = "CMCC-CM"
-_format(::Type{CHELSA}, ::Type{CNRMCM5}) = "CNRM-CM5"
-_format(::Type{CHELSA}, ::Type{CSIROMk3}) = "CSIRO-Mk3"
-_format(::Type{CHELSA}, ::Type{CanESM2}) = "CanESM2"
-_format(::Type{CHELSA}, ::Type{FGOALS}) = "FGOALS-g2"
-_format(::Type{CHELSA}, ::Type{FIOESM}) = "FIO-ESM"
-_format(::Type{CHELSA}, ::Type{GFDLCM3}) = "GFDL-CM3"
-_format(::Type{CHELSA}, ::Type{GFDLESM2G}) = "GFDL-ESM2G"
-_format(::Type{CHELSA}, ::Type{GFDLESM2M}) = "GFDL-ESM2M"
-_format(::Type{CHELSA}, ::Type{GISSE2HCC}) = "GISS-E2-H-CC"
-_format(::Type{CHELSA}, ::Type{GISSE2H}) = "GISS-E2-H"
-_format(::Type{CHELSA}, ::Type{GISSE2RCC}) = "GISS-E2-R-CC"
-_format(::Type{CHELSA}, ::Type{GISSE2R}) = "GISS-E2-R"
-_format(::Type{CHELSA}, ::Type{HadGEM2AO}) = "HadGEM2-AO"
-_format(::Type{CHELSA}, ::Type{HadGEM2CC}) = "HadGEM2-CC"
-_format(::Type{CHELSA}, ::Type{IPSLCM5ALR}) = "IPSL-CM5A-LR"
-_format(::Type{CHELSA}, ::Type{IPSLCM5AMR}) = "IPSL-CM5A-MR"
-_format(::Type{CHELSA}, ::Type{MIROCESMCHEM}) = "MIROC-ESM-CHEM"
-_format(::Type{CHELSA}, ::Type{MIROCESM}) = "MIROC-ESM"
-_format(::Type{CHELSA}, ::Type{MIROC5}) = "MIROC5"
-_format(::Type{CHELSA}, ::Type{MPIESMLR}) = "MPI-ESM-LR"
-_format(::Type{CHELSA}, ::Type{MPIESMMR}) = "MPI-ESM-MR"
-_format(::Type{CHELSA}, ::Type{MRICGCM3}) = "MRI-CGCM3"
-_format(::Type{CHELSA}, ::Type{MRIESM1}) = "MRI-ESM1"
-_format(::Type{CHELSA}, ::Type{NorESM1M}) = "NorESM1-M"
-_format(::Type{CHELSA}, ::Type{BCCCSM1}) = "bcc-csm-1"
-_format(::Type{CHELSA}, ::Type{Inmcm4}) = "inmcm4"
+const CHELSA_CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
+const CHELSA_CMIP5_MODEL_STRINGS =
+[
+    "ACCESS1-0"
+    "BNU-ESM"
+    "CCSM4"
+    "CESM1-BGC"
+    "CESM1-CAM5"
+    "CMCC-CMS"
+    "CMCC-CM"
+    "CNRM-CM5"
+    "CSIRO-Mk3"
+    "CanESM2"
+    "FGOALS-g2"
+    "FIO-ESM"
+    "GFDL-CM3"
+    "GFDL-ESM2G"
+    "GFDL-ESM2M"
+    "GISS-E2-H-CC"
+    "GISS-E2-H"
+    "GISS-E2-R-CC"
+    "GISS-E2-R"
+    "HadGEM2-AO"
+    "HadGEM2-CC"
+    "IPSL-CM5A-LR"
+    "IPSL-CM5A-MR"
+    "MIROC-ESM-CHEM"
+    "MIROC-ESM"
+    "MIROC5"
+    "MPI-ESM-LR"
+    "MPI-ESM-MR"
+    "MRI-CGCM3"
+    "MRI-ESM1"
+    "NorESM1-M"
+    "bcc-csm-1"
+    "inmcm4"
+]
 
 # CMIP6
-_format(::Type{CHELSA}, ::Type{GFDLESM4}) = "gfdl-esm4"
-_format(::Type{CHELSA}, ::Type{IPSLCM6ALR}) = "ipsl-cm6a-lr"
-_format(::Type{CHELSA}, ::Type{MPIESMHR}) = "mpi-esm1-2-hr"
-_format(::Type{CHELSA}, ::Type{MRIESM2}) = "mri-esm2-0"
-_format(::Type{CHELSA}, ::Type{UKESM}) = "ukesm1-0-ll"
-
-# Format scenarios
-_format(::Type{CHELSA}, ::Type{RCP26}) = "rcp26"
-_format(::Type{CHELSA}, ::Type{RCP45}) = "rcp45"
-_format(::Type{CHELSA}, ::Type{RCP60}) = "rcp60"
-_format(::Type{CHELSA}, ::Type{RCP85}) = "rcp85"
-
-_format(::Type{CHELSA}, ::Type{SSP126}) = "ssp126"
-_format(::Type{CHELSA}, ::Type{SSP245}) = "ssp245"
-_format(::Type{CHELSA}, ::Type{SSP370}) = "ssp370"
-_format(::Type{CHELSA}, ::Type{SSP585}) = "ssp585"
+const CHELSA_CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
+const CHELSA_CMIP6_MODEL_STRINGS = [
+    "GFDL-ESM4"
+    "IPSL-CM6A-LR"
+    "MPI-ESM1-2-HR"
+    "MRI-ESM2-0"
+    "UKESM1-0-LL"
+]
+
+for CMIP in [:CMIP5, :CMIP6]
+    strings = eval(Symbol("CHELSA_$(CMIP)_MODEL_STRINGS"))
+    models = eval(Symbol("CHELSA_$(CMIP)_MODELS"))
+    for model_str in strings
+        type = Symbol(replace(model_str, "-" => "_"))
+        @eval begin
+            if !(@isdefined $type) 
+                struct $type <: ClimateModel{$CMIP} end
+                export $type
+            end
+            _format(::Type{CHELSA}, ::Type{$type}) = lowercase($model_str)
+            push!($models, $type)
+        end
+    end
+    append!(eval(Symbol("$(CMIP)_MODELS")), models)
+    unique!(eval(Symbol("$(CMIP)_MODELS")))
+end
\ No newline at end of file
diff --git a/src/types.jl b/src/types.jl
index 87996b0..3185339 100644
--- a/src/types.jl
+++ b/src/types.jl
@@ -165,58 +165,6 @@ See the [`getraster`](@ref) docs for implementation details.
 """
 struct HabitatHeterogeneity <: RasterDataSet end
 
-"""
-    ClimateModel
-
-Abstract supertype for climate models use in [`Future`](@ref) datasets.
-"""
-abstract type ClimateModel end
-
-struct ACCESS1 <: ClimateModel end
-struct BNUESM <: ClimateModel end
-struct CCSM4 <: ClimateModel end
-struct CESM1BGC <: ClimateModel end
-struct CESM1CAM5 <: ClimateModel end
-struct CMCCCMS <: ClimateModel end
-struct CMCCCM <: ClimateModel end
-struct CNRMCM5 <: ClimateModel end
-struct CSIROMk3 <: ClimateModel end
-struct CanESM2 <: ClimateModel end
-struct FGOALS <: ClimateModel end
-struct FIOESM <: ClimateModel end
-struct GFDLCM3 <: ClimateModel end
-struct GFDLESM2G <: ClimateModel end
-struct GFDLESM2M <: ClimateModel end
-struct GISSE2HCC <: ClimateModel end
-struct GISSE2H <: ClimateModel end
-struct GISSE2RCC <: ClimateModel end
-struct GISSE2R <: ClimateModel end
-struct HadGEM2AO <: ClimateModel end
-struct HadGEM2CC <: ClimateModel end
-struct IPSLCM5ALR <: ClimateModel end
-struct IPSLCM5AMR <: ClimateModel end
-struct MIROCESMCHEM <: ClimateModel end
-struct MIROCESM <: ClimateModel end
-struct MIROC5 <: ClimateModel end
-struct MPIESMLR <: ClimateModel end
-struct MPIESMMR <: ClimateModel end
-struct MRICGCM3 <: ClimateModel end
-struct MRIESM1 <: ClimateModel end
-struct NorESM1M <: ClimateModel end
-struct BCCCSM1 <: ClimateModel end
-struct Inmcm4 <: ClimateModel end
-struct BCCCSM2MR <: ClimateModel end
-struct CNRMCM61 <: ClimateModel end
-struct CNRMESM21 <: ClimateModel end
-struct CanESM5 <: ClimateModel end
-struct GFDLESM4 <: ClimateModel end
-struct IPSLCM6ALR <: ClimateModel end
-struct MIROCES2L <: ClimateModel end
-struct MIROC6 <: ClimateModel end
-struct MRIESM2 <: ClimateModel end
-struct UKESM <: ClimateModel end
-struct MPIESMHR <: ClimateModel end
-
 """
     CMIPphase 
 
@@ -233,6 +181,7 @@ abstract type CMIPphase end
 The Coupled Model Intercomparison Project, Phase 5.
 """
 struct CMIP5 <: CMIPphase end
+const CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
 
 """
     CMIP6 <: CMIPphase
@@ -240,6 +189,14 @@ struct CMIP5 <: CMIPphase end
 The Coupled Model Intercomparison Project, Phase 6.
 """
 struct CMIP6 <: CMIPphase end
+const CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
+
+"""
+    ClimateModel
+
+Abstract supertype for climate models use in [`Future`](@ref) datasets.
+"""
+abstract type ClimateModel{CMIP<:CMIPphase} end
 
 """
     ClimateScenario 
@@ -296,14 +253,9 @@ Can be either [`CMIP5`](@ref) or [`CMIP6`](@ref).
 
 Climate models can be chosen from: 
 
-`ACCESS1`, `BNUESM`, `CCSM4`, `CESM1BGC`, `CESM1CAM5`, `CMCCCMS`, `CMCCCM`,
-`CNRMCM5`, `CSIROMk3`, `CanESM2`, `FGOALS`, `FIOESM`, `GFDLCM3`, `GFDLESM2G`,
-`GFDLESM2M`, `GISSE2HCC`, `GISSE2H`, `GISSE2RCC`, `GISSE2R`, `HadGEM2AO`,
-`HadGEM2CC`, `IPSLCM5ALR`, `IPSLCM5AMR`, `MIROCESMCHEM`, `MIROCESM`, `MIROC5`,
-`MPIESMLR`, `MPIESMMR`, `MRICGCM3`, `MRIESM1`, `NorESM1M`, `BCCCSM1`, `Inmcm4`,
-`BCCCSM2MR`, `CNRMCM61`, `CNRMESM21`, `CanESM5`, `MIROCES2L`, `MIROC6` for CMIP5;
+`$(join(CMIP5_MODELS, "`,  `"))` for `CMIP5`;
 
-`UKESM`, `MPIESMHR` `IPSLCM6ALR`, `MRIESM2`, `GFDLESM4` for `CMIP6`.
+`$(join(CMIP6_MODELS, "`,  `"))` for `CMIP6`;"
 
 #### `ClimateScenario`
 
@@ -335,9 +287,17 @@ struct Future{D<:RasterDataSet,C<:CMIPphase,M<:ClimateModel,S<:ClimateScenario}
 _dataset(::Type{<:Future{D}}) where D = D
 _dataset(::Type{<:Future{BioClimPlus}}) = BioClim
 _phase(::Type{<:Future{<:Any,P}}) where P = P
+_phase(::Type{<:ClimateModel{P}}) where P = P
+
 _model(::Type{<:Future{<:Any,<:Any,M}}) where M = M
 _scenario(::Type{<:Future{<:Any,<:Any,<:Any,S}}) where S = S
 layers(::Type{<:Future{BioClimPlus}}) = BIOCLIMPLUS_LAYERS_FUTURE
+
+# fallback for _format
+_format(::Type, RCP::Type{<:RepresentativeConcentrationPathway}) = lowercase(string(nameof(RCP)))
+_format(::Type, S::Type{<:SharedSocioeconomicPathway}) = lowercase(string(nameof(S)))
+_format(::Type, S::Type{<:ClimateModel}) = replace(string(nameof(S)), "_" => "-")
+
 """
     ModisProduct <: RasterDataSet
 

From 12f6ede3470cb3722448ec222f69663b336d28a1 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 22 Aug 2024 13:17:37 +0200
Subject: [PATCH 02/21] first draft for future wordclim climate

---
 src/worldclim/future.jl | 83 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 src/worldclim/future.jl

diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
new file mode 100644
index 0000000..d774e91
--- /dev/null
+++ b/src/worldclim/future.jl
@@ -0,0 +1,83 @@
+const WORLDCLIM_URI_CMIP6 = URI(scheme="https", host="geodata.ucdavis.edu", path="/cmip6")
+
+layers(::Type{<:WorldClim{<:Future{Climate}}}) = (:tmin, :tmax, :prec)
+getraster_keywords(::Type{<:WorldClim{<:Future{Climate}}}) = (:date, :res)
+
+
+function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union{Tuple,Symbol}; 
+    res::String=defres(T), date
+)
+    _getraster(T, layers, res, date)
+end
+
+
+function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layer::Symbol, res::String, date)
+    #date_str = _date_string(T, date)
+    _check_layer(T, layer)
+    _check_res(T, res)
+    raster_path = rasterpath(T, layer; res, date)
+    if !isfile(raster_path)
+        _maybe_download(rasterurl(T, layer; res, date), raster_path)
+    end
+    return raster_path
+end
+
+function rasterurl(T::Type{<:WorldClim{<:Future{Climate, CMIP6, M, S}}}, layer; res, date) where {M, S}
+    joinpath(WORLDCLIM_URI_CMIP6, res, _format(WorldClim, M), _format(CHELSA, S), rastername(T, layer; res, date))
+end
+
+function rastername(T::Type{<:WorldClim{<:Future{Climate, CMIP6, M, S}}}, layer; res, date) where {M, S}
+    join(["wc2.1", res, string(layer), _format(WorldClim, M), _format(CHELSA, S), date], "_") * ".tif"
+end
+
+
+function _date_string(::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, date)
+    if date < DateTime(2021)
+        _cmip6_date_error(date)
+    elseif date < DateTime(2041)
+        "2011-2040"
+    elseif date < DateTime(2061)
+        "2041-2060"
+    elseif date < DateTime(2081)
+        "2041-2080"
+    elseif date < DateTime(2101)
+        "2081-2100"
+    else
+        _cmip6_date_error(date)
+    end
+end
+
+const WORDCLIM_CMIP6_MODEL_STRINGS = [
+    "ACCESS-CM2"
+    "BCC-CSM2-MR"
+    "CMCC-ESM2"
+    "EC-Earth3-Veg"
+    "FIO-ESM-2-0"
+    "GFDL-ESM4"
+    "GISS-E2-1-G"
+    "HadGEM3-GC31-LL"
+    "INM-CM5-0"
+    "IPSL-CM6A-LR"
+    "MIROC6"
+    "MPI-ESM1-2-HR"
+    "MRI-ESM2-0"
+    "UKESM1-0-LL"
+]
+
+WORDCLIM_CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
+
+for model_str in WORDCLIM_CMIP6_MODEL_STRINGS
+    type = Symbol(replace(model_str, "-" => "_"))
+    @eval begin
+        export $type
+        if !(@isdefined $type) 
+            struct $type <: ClimateModel{CMIP6} end
+            export $type
+        end
+        push!(WORDCLIM_CMIP6_MODELS, $type)
+        _format(::Type{WorldClim}, ::Type{$type}) = $model_str
+    end
+end
+
+append!(CMIP6_MODELS, WORDCLIM_CMIP6_MODELS)
+unique!(CMIP6_MODELS)
\ No newline at end of file

From 2e1cc4aa7aa76a59388743368719f4fed06e0fcf Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 22 Aug 2024 13:24:44 +0200
Subject: [PATCH 03/21] define ClimateModel before using it

---
 src/types.jl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/types.jl b/src/types.jl
index 3185339..f1da0ff 100644
--- a/src/types.jl
+++ b/src/types.jl
@@ -181,7 +181,6 @@ abstract type CMIPphase end
 The Coupled Model Intercomparison Project, Phase 5.
 """
 struct CMIP5 <: CMIPphase end
-const CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
 
 """
     CMIP6 <: CMIPphase
@@ -189,7 +188,6 @@ const CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
 The Coupled Model Intercomparison Project, Phase 6.
 """
 struct CMIP6 <: CMIPphase end
-const CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
 
 """
     ClimateModel
@@ -197,6 +195,8 @@ const CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
 Abstract supertype for climate models use in [`Future`](@ref) datasets.
 """
 abstract type ClimateModel{CMIP<:CMIPphase} end
+const CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
+const CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
 
 """
     ClimateScenario 

From bc62db1ac13284858ebf2c36dd7d5fbcf8770073 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 22 Aug 2024 16:04:44 +0200
Subject: [PATCH 04/21] first draft for future worldclim bioclim

---
 src/worldclim/future.jl | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index d774e91..5ee596b 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -10,26 +10,47 @@ function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union
     _getraster(T, layers, res, date)
 end
 
-
 function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layer::Symbol, res::String, date)
     #date_str = _date_string(T, date)
     _check_layer(T, layer)
     _check_res(T, res)
-    raster_path = rasterpath(T, layer; res, date)
+    raster_path = rasterpath(T, "bioclim"; res, date)
     if !isfile(raster_path)
         _maybe_download(rasterurl(T, layer; res, date), raster_path)
     end
     return raster_path
 end
 
-function rasterurl(T::Type{<:WorldClim{<:Future{Climate, CMIP6, M, S}}}, layer; res, date) where {M, S}
-    joinpath(WORLDCLIM_URI_CMIP6, res, _format(WorldClim, M), _format(CHELSA, S), rastername(T, layer; res, date))
+function rasterurl(T::Type{<:WorldClim{<:Future}}, layer; res, date)
+    joinpath(WORLDCLIM_URI_CMIP6, res, _format(T, _model(T)), _format(T, _scenario(T)), rastername(T, layer; res, date))
+end
+
+function rastername(T::Type{<:WorldClim{<:Future}}, layer; res, date)
+    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), date], "_") * ".tif"
 end
 
-function rastername(T::Type{<:WorldClim{<:Future{Climate, CMIP6, M, S}}}, layer; res, date) where {M, S}
-    join(["wc2.1", res, string(layer), _format(WorldClim, M), _format(CHELSA, S), date], "_") * ".tif"
+function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}, layer::Symbol; res::String=defres(T), date)
+    _getraster(T, layers, res, date)
 end
 
+function _getraster(T::Type{<:WorldClim{<:Future{BioClim}}}, layer::Symbol, res::String, date)
+    #date_str = _date_string(T, date)
+    #_check_layer(T, layer)
+    #_check_res(T, res)
+    raster_path = rasterpath(T; res, date)
+    if !isfile(raster_path)
+        _maybe_download(rasterurl(T, layer; res, date), raster_path)
+    end
+    return raster_path
+end
+
+# copy-pasted in from CHELSA - must be some way to implement this abstractly?
+_dataset(::Type{<:WorldClim{F}}) where F<:Future = _dataset(F)
+_phase(::Type{<:WorldClim{F}}) where F<:Future = _phase(F)
+_model(::Type{<:WorldClim{F}}) where F<:Future = _model(F)
+_scenario(::Type{<:WorldClim{F}}) where F<:Future = _scenario(F)
+
+
 
 function _date_string(::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, date)
     if date < DateTime(2021)

From af8429416c78b59c7af9a94f2b7580bc94116439 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Tue, 3 Sep 2024 09:58:54 +0200
Subject: [PATCH 05/21] move exports to main file

---
 src/RasterDataSources.jl | 5 +++++
 src/worldclim/future.jl  | 1 -
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/RasterDataSources.jl b/src/RasterDataSources.jl
index 8266921..d0ca92a 100644
--- a/src/RasterDataSources.jl
+++ b/src/RasterDataSources.jl
@@ -72,4 +72,9 @@ include("modis/products.jl")
 include("modis/utilities.jl")
 include("modis/examples.jl")
 
+for model in [CMIP5_MODELS; CMIP6_MODELS]
+    symb = nameof(model)
+    @eval export $symb
+end
+
 end # module
diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index 5ee596b..7c59f01 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -90,7 +90,6 @@ WORDCLIM_CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
 for model_str in WORDCLIM_CMIP6_MODEL_STRINGS
     type = Symbol(replace(model_str, "-" => "_"))
     @eval begin
-        export $type
         if !(@isdefined $type) 
             struct $type <: ClimateModel{CMIP6} end
             export $type

From bc73812723f0ad5699a15cb7f5b22c92b1702c35 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Tue, 10 Sep 2024 16:54:18 +0200
Subject: [PATCH 06/21] reorganise future worldclim

---
 src/worldclim/future.jl | 53 +++++++++++++++++++++++++----------------
 src/worldclim/shared.jl |  3 ++-
 2 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index 7c59f01..0724a07 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -3,7 +3,6 @@ const WORLDCLIM_URI_CMIP6 = URI(scheme="https", host="geodata.ucdavis.edu", path
 layers(::Type{<:WorldClim{<:Future{Climate}}}) = (:tmin, :tmax, :prec)
 getraster_keywords(::Type{<:WorldClim{<:Future{Climate}}}) = (:date, :res)
 
-
 function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union{Tuple,Symbol}; 
     res::String=defres(T), date
 )
@@ -11,39 +10,50 @@ function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union
 end
 
 function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layer::Symbol, res::String, date)
-    #date_str = _date_string(T, date)
     _check_layer(T, layer)
     _check_res(T, res)
-    raster_path = rasterpath(T, "bioclim"; res, date)
+    raster_path = rasterpath(T, layer; res, date)
     if !isfile(raster_path)
         _maybe_download(rasterurl(T, layer; res, date), raster_path)
     end
     return raster_path
 end
 
-function rasterurl(T::Type{<:WorldClim{<:Future}}, layer; res, date)
-    joinpath(WORLDCLIM_URI_CMIP6, res, _format(T, _model(T)), _format(T, _scenario(T)), rastername(T, layer; res, date))
-end
-
-function rastername(T::Type{<:WorldClim{<:Future}}, layer; res, date)
-    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), date], "_") * ".tif"
-end
+## Bioclim
+getraster_keywords(::Type{<:WorldClim{<:Future{BioClim}}}) = (:date, :res)
 
-function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}, layer::Symbol; res::String=defres(T), date)
-    _getraster(T, layers, res, date)
+function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}; res::String=defres(T), date)
+    _getraster(T, res, date)
 end
 
-function _getraster(T::Type{<:WorldClim{<:Future{BioClim}}}, layer::Symbol, res::String, date)
-    #date_str = _date_string(T, date)
-    #_check_layer(T, layer)
-    #_check_res(T, res)
+function _getraster(T::Type{<:WorldClim{<:Future{BioClim}}}, res::String, date)
+    _check_res(T, res)
     raster_path = rasterpath(T; res, date)
     if !isfile(raster_path)
-        _maybe_download(rasterurl(T, layer; res, date), raster_path)
+        _maybe_download(rasterurl(T; res, date), raster_path)
     end
     return raster_path
 end
 
+function rasterpath(T::Type{<:WorldClim{<:Future{Climate}}}, layer; res, date)
+    joinpath(_rasterpath(T), rastername(T, layer; res, date))
+end
+function rasterpath(T::Type{<:WorldClim{<:Future{BioClim}}}; res, date)
+    joinpath(_rasterpath(T), rastername(T; res, date))
+end
+function _rasterpath(T::Type{<:WorldClim{<:Future}})
+    joinpath(rasterpath(WorldClim), "Future", string(_dataset(T)), string(_scenario(T)), string(_model(T)))
+end
+
+function rasterurl(T::Type{<:WorldClim{<:Future}}, args...; res, date)
+    joinpath(WORLDCLIM_URI_CMIP6, res, _format(T, _model(T)), _format(T, _scenario(T)), rastername(T, args...; res, date))
+end
+
+function rastername(T::Type{<:WorldClim{<:Future}}, layer; res, date)
+    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), _date_string(T, date)], "_") * ".tif"
+end
+rastername(T::Type{<:WorldClim{<:Future{BioClim}}}; kw...) = rastername(T, :bioc, ; kw...)
+
 # copy-pasted in from CHELSA - must be some way to implement this abstractly?
 _dataset(::Type{<:WorldClim{F}}) where F<:Future = _dataset(F)
 _phase(::Type{<:WorldClim{F}}) where F<:Future = _phase(F)
@@ -51,16 +61,15 @@ _model(::Type{<:WorldClim{F}}) where F<:Future = _model(F)
 _scenario(::Type{<:WorldClim{F}}) where F<:Future = _scenario(F)
 
 
-
-function _date_string(::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, date)
+function _date_string(::Type{<:WorldClim{<:Future{<:Any, CMIP6}}}, date)
     if date < DateTime(2021)
         _cmip6_date_error(date)
     elseif date < DateTime(2041)
-        "2011-2040"
+        "2021-2040"
     elseif date < DateTime(2061)
         "2041-2060"
     elseif date < DateTime(2081)
-        "2041-2080"
+        "2041-2060"
     elseif date < DateTime(2101)
         "2081-2100"
     else
@@ -68,6 +77,8 @@ function _date_string(::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, date)
     end
 end
 
+
+## Handle all the models
 const WORDCLIM_CMIP6_MODEL_STRINGS = [
     "ACCESS-CM2"
     "BCC-CSM2-MR"
diff --git a/src/worldclim/shared.jl b/src/worldclim/shared.jl
index 8b0d099..76cafd5 100644
--- a/src/worldclim/shared.jl
+++ b/src/worldclim/shared.jl
@@ -13,7 +13,8 @@ const WORLDCLIM_URI = URI(scheme="https", host="geodata.ucdavis.edu", path="/cli
 resolutions(::Type{<:WorldClim}) = ("30s", "2.5m", "5m", "10m")
 defres(::Type{<:WorldClim}) = "10m"
 
-rasterpath(::Type{WorldClim{T}}) where T = joinpath(rasterpath(), "WorldClim", string(nameof(T)))
+rasterpath(::Type{WorldClim}) = joinpath(rasterpath(), "WorldClim")
+rasterpath(::Type{WorldClim{T}}) where T = joinpath(rasterpath(WorldClim), string(nameof(T)))
 rasterpath(T::Type{<:WorldClim}, layer; kw...) =
     joinpath(rasterpath(T), string(layer), rastername(T, layer; kw...))
 

From 9c2e729493ccf02ef364524bce4ba576b80d206f Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Tue, 1 Oct 2024 12:07:46 +0200
Subject: [PATCH 07/21] reorganise some code

---
 src/chelsa/future.jl |   1 +
 src/shared.jl        |   6 +
 src/types.jl         | 264 +++++++++++++++++++++----------------------
 3 files changed, 138 insertions(+), 133 deletions(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index 7082846..1c36f47 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -254,6 +254,7 @@ _cmip5_date_error(date) = error("CMIP5 covers the period from 2041-2080, not inc
 _cmip6_date_error(date) = error("CMIP6 covers the period from 1981-2100, not including $date")
 
 _dataset(::Type{<:CHELSA{F}}) where F<:Future = _dataset(F)
+_dataset(::Type{<:Future{BioClimPlus}}) = BioClim # to make sure bioclimplus and bioclim end up in the same folder
 _phase(::Type{<:CHELSA{F}}) where F<:Future = _phase(F)
 _model(::Type{<:CHELSA{F}}) where F<:Future = _model(F)
 _scenario(::Type{<:CHELSA{F}}) where F<:Future = _scenario(F)
diff --git a/src/shared.jl b/src/shared.jl
index cbf76c6..0d3f473 100644
--- a/src/shared.jl
+++ b/src/shared.jl
@@ -81,3 +81,9 @@ function _map_layers(T, layers, args...; kw...)
     keys = layerkeys(T, layers)
     return NamedTuple{keys}(filenames)
 end
+
+# fallback for _format
+_format(RCP::Type{<:RepresentativeConcentrationPathway}) = lowercase(string(nameof(RCP)))
+_format(S::Type{<:SharedSocioeconomicPathway}) = lowercase(string(nameof(S)))
+_format(M::Type{<:ClimateModel}) = replace(string(nameof(M)), "_" => "-")
+_format(::Type, T::Type) = _format(T)
diff --git a/src/types.jl b/src/types.jl
index f1da0ff..419e133 100644
--- a/src/types.jl
+++ b/src/types.jl
@@ -12,6 +12,136 @@ Abstract supertype for datasets that belong to a [`RasterDataSource`](@ref).
 """
 abstract type RasterDataSet end
 
+"""
+    CMIPphase 
+
+Abstract supertype for phases of the CMIP,
+the Coupled Model Intercomparison Project.
+
+Subtypes are `CMIP5` and `CMIP6`.
+"""
+abstract type CMIPphase end
+
+"""
+    CMIP5 <: CMIPphase
+
+The Coupled Model Intercomparison Project, Phase 5.
+"""
+struct CMIP5 <: CMIPphase end
+
+"""
+    CMIP6 <: CMIPphase
+
+The Coupled Model Intercomparison Project, Phase 6.
+"""
+struct CMIP6 <: CMIPphase end
+
+"""
+    ClimateModel
+
+Abstract supertype for climate models use in [`Future`](@ref) datasets.
+"""
+abstract type ClimateModel{CMIP<:CMIPphase} end
+const CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
+const CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
+
+"""
+    ClimateScenario 
+
+Abstract supertype for scenarios used in [`CMIPphase`](@ref) models.
+"""
+abstract type ClimateScenario end
+
+"""
+    RepresentativeConcentrationPathway
+
+Abstract supertype for Representative Concentration Pathways (RCPs) for [`CMIP5`](@ref).
+
+Subtypes are: `RCP26`, `RCP45`, `RCP60`, `RCP85`
+"""
+abstract type RepresentativeConcentrationPathway <: ClimateScenario end
+
+struct RCP26 <: RepresentativeConcentrationPathway end
+struct RCP45 <: RepresentativeConcentrationPathway end
+struct RCP60 <: RepresentativeConcentrationPathway end
+struct RCP85 <: RepresentativeConcentrationPathway end
+
+"""
+    SharedSocioeconomicPathway
+
+Abstract supertype for Shared Socio-economic Pathways (SSPs) for [`CMIP6`](@ref).
+
+Subtypes are: `SSP126`, `SSP245`, SSP370`, SSP585`
+"""
+abstract type SharedSocioeconomicPathway <: ClimateScenario end
+
+struct SSP126 <: SharedSocioeconomicPathway end
+struct SSP245 <: SharedSocioeconomicPathway end
+struct SSP370 <: SharedSocioeconomicPathway end
+struct SSP585 <: SharedSocioeconomicPathway end
+
+"""
+    Future{<:RasterDataSet,<:CMIPphase,<:ClimateModel,<:ClimateScenario}
+
+Future climate datasets specified with a dataset, phase, model, and scenario.
+
+## Type Parameters
+
+#### `RasterDataSet`
+
+Currently [`BioClim`](@ref) and [`Climate`](@ref) are implemented
+for the [`CHELSA`](@ref) data source.
+
+#### `CMIPphase`
+
+Can be either [`CMIP5`](@ref) or [`CMIP6`](@ref).
+
+#### `ClimateModel`
+
+Climate models can be chosen from: 
+
+`$(join(CMIP5_MODELS, "`,  `"))` for `CMIP5`;
+
+`$(join(CMIP6_MODELS, "`,  `"))` for `CMIP6`;"
+
+#### `ClimateScenario`
+
+CMIP5 Climate scenarios are all [`RepresentativeConcentrationPathway`](@ref)
+and can be chosen from: `RCP26`, `RCP45`, `RCP60`, `RCP85`
+
+CMIP6 Climate scenarios are all [`SharedSocioeconomicPathway`](@ref) and
+can be chosen from: `SSP126`, `SSP245`, `SSP370`, `SSP585`
+
+However, note that not all climate scenarios are available for all models.
+
+## Example
+
+```jldoctest future
+using RasterDataSources
+dataset = Future{BioClim, CMIP5, BNUESM, RCP45}
+# output
+Future{BioClim, CMIP5, BNUESM, RCP45}
+```
+Currently `Future` is only implented for `CHELSA`
+
+```jldoctest future
+datasource = CHELSA{Future{BioClim, CMIP5, BNUESM, RCP45}}
+```
+
+"""
+struct Future{D<:RasterDataSet,C<:CMIPphase,M<:ClimateModel,S<:ClimateScenario} end
+
+_dataset(::Type{<:Future{D}}) where D = D
+_phase(::Type{<:Future{<:Any,P}}) where P = P
+_phase(::Type{<:ClimateModel{P}}) where P = P
+
+_model(::Type{<:Future{<:Any,<:Any,M}}) where M = M
+_scenario(::Type{<:Future{<:Any,<:Any,<:Any,S}}) where S = S
+
+# fallback for layers
+layers(::Type{<:Future{T}}) where T = layers(T) # need to define this after Future is defined
+
+### Define types for all RasterDataSets
 """
     BioClim <: RasterDataSet
 
@@ -103,6 +233,7 @@ const BIOCLIMPLUS_LAYERS_FUTURE = [
 ]
 
 layers(::Type{BioClimPlus}) = BIOCLIMPLUS_LAYERS
+layers(::Type{Future{BioClimPlus}}) = BIOCLIMPLUS_LAYERS_FUTURE
 
 """
     Climate <: RasterDataSet
@@ -165,139 +296,6 @@ See the [`getraster`](@ref) docs for implementation details.
 """
 struct HabitatHeterogeneity <: RasterDataSet end
 
-"""
-    CMIPphase 
-
-Abstract supertype for phases of the CMIP,
-the Coupled Model Intercomparison Project.
-
-Subtypes are `CMIP5` and `CMIP6`.
-"""
-abstract type CMIPphase end
-
-"""
-    CMIP5 <: CMIPphase
-
-The Coupled Model Intercomparison Project, Phase 5.
-"""
-struct CMIP5 <: CMIPphase end
-
-"""
-    CMIP6 <: CMIPphase
-
-The Coupled Model Intercomparison Project, Phase 6.
-"""
-struct CMIP6 <: CMIPphase end
-
-"""
-    ClimateModel
-
-Abstract supertype for climate models use in [`Future`](@ref) datasets.
-"""
-abstract type ClimateModel{CMIP<:CMIPphase} end
-const CMIP6_MODELS = Type{<:ClimateModel{CMIP6}}[]
-const CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
-
-"""
-    ClimateScenario 
-
-Abstract supertype for scenarios used in [`CMIPphase`](@ref) models.
-"""
-abstract type ClimateScenario end
-
-"""
-    RepresentativeConcentrationPathway
-
-Abstract supertype for Representative Concentration Pathways (RCPs) for [`CMIP5`](@ref).
-
-Subtypes are: `RCP26`, `RCP45`, `RCP60`, `RCP85`
-"""
-abstract type RepresentativeConcentrationPathway <: ClimateScenario end
-
-struct RCP26 <: RepresentativeConcentrationPathway end
-struct RCP45 <: RepresentativeConcentrationPathway end
-struct RCP60 <: RepresentativeConcentrationPathway end
-struct RCP85 <: RepresentativeConcentrationPathway end
-
-"""
-    SharedSocioeconomicPathway
-
-Abstract supertype for Shared Socio-economic Pathways (SSPs) for [`CMIP6`](@ref).
-
-Subtypes are: `SSP126`, `SSP245`, SSP370`, SSP585`
-"""
-abstract type SharedSocioeconomicPathway <: ClimateScenario end
-
-struct SSP126 <: SharedSocioeconomicPathway end
-struct SSP245 <: SharedSocioeconomicPathway end
-struct SSP370 <: SharedSocioeconomicPathway end
-struct SSP585 <: SharedSocioeconomicPathway end
-
-"""
-    Future{<:RasterDataSet,<:CMIPphase,<:ClimateModel,<:ClimateScenario}
-
-Future climate datasets specified with a dataset, phase, model, and scenario.
-
-## Type Parameters
-
-#### `RasterDataSet`
-
-Currently [`BioClim`](@ref) and [`Climate`](@ref) are implemented
-for the [`CHELSA`](@ref) data source.
-
-#### `CMIPphase`
-
-Can be either [`CMIP5`](@ref) or [`CMIP6`](@ref).
-
-#### `ClimateModel`
-
-Climate models can be chosen from: 
-
-`$(join(CMIP5_MODELS, "`,  `"))` for `CMIP5`;
-
-`$(join(CMIP6_MODELS, "`,  `"))` for `CMIP6`;"
-
-#### `ClimateScenario`
-
-CMIP5 Climate scenarios are all [`RepresentativeConcentrationPathway`](@ref)
-and can be chosen from: `RCP26`, `RCP45`, `RCP60`, `RCP85`
-
-CMIP6 Climate scenarios are all [`SharedSocioeconomicPathway`](@ref) and
-can be chosen from: `SSP126`, `SSP245`, `SSP370`, `SSP585`
-
-However, note that not all climate scenarios are available for all models.
-
-## Example
-
-```jldoctest future
-using RasterDataSources
-dataset = Future{BioClim, CMIP5, BNUESM, RCP45}
-# output
-Future{BioClim, CMIP5, BNUESM, RCP45}
-```
-Currently `Future` is only implented for `CHELSA`
-
-```jldoctest future
-datasource = CHELSA{Future{BioClim, CMIP5, BNUESM, RCP45}}
-```
-
-"""
-struct Future{D<:RasterDataSet,C<:CMIPphase,M<:ClimateModel,S<:ClimateScenario} end
-
-_dataset(::Type{<:Future{D}}) where D = D
-_dataset(::Type{<:Future{BioClimPlus}}) = BioClim
-_phase(::Type{<:Future{<:Any,P}}) where P = P
-_phase(::Type{<:ClimateModel{P}}) where P = P
-
-_model(::Type{<:Future{<:Any,<:Any,M}}) where M = M
-_scenario(::Type{<:Future{<:Any,<:Any,<:Any,S}}) where S = S
-layers(::Type{<:Future{BioClimPlus}}) = BIOCLIMPLUS_LAYERS_FUTURE
-
-# fallback for _format
-_format(::Type, RCP::Type{<:RepresentativeConcentrationPathway}) = lowercase(string(nameof(RCP)))
-_format(::Type, S::Type{<:SharedSocioeconomicPathway}) = lowercase(string(nameof(S)))
-_format(::Type, S::Type{<:ClimateModel}) = replace(string(nameof(S)), "_" => "-")
-
 """
     ModisProduct <: RasterDataSet
 

From 4bc9ac84af62b6d80709bd96071cb35bf903c4ce Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Tue, 1 Oct 2024 12:38:19 +0200
Subject: [PATCH 08/21] always use _format not string

---
 src/chelsa/future.jl    | 10 ++++++----
 src/shared.jl           |  3 +--
 src/worldclim/future.jl |  7 ++++---
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index 1c36f47..a9650b8 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -194,7 +194,7 @@ function _rastername(
 end
 
 function rasterpath(T::Type{<:CHELSA{<:Future}})
-    joinpath(rasterpath(CHELSA), "Future", string(_dataset(T)), string(_scenario(T)), string(_model(T)))
+    joinpath(rasterpath(CHELSA), "Future", _format(T, _dataset(T)), _format(T, _scenario(T)), _format(T, _model(T)))
 end
 function rasterpath(T::Type{<:CHELSA{<:Future}}, layer; kw...)
     joinpath(rasterpath(T), rastername(T, layer; kw...))
@@ -212,7 +212,7 @@ _chelsa_layer(::Type{<:BioClimPlus}, layer) = :bio
 _chelsa_layer(::Type{<:Climate}, layer) = layer
 
 function _urlpath(::Type{CMIP5}, T::Type{<:CHELSA{<:Future}}, name, date_str)
-    return "chelsa_V1/cmip5/$date_str/$name/"
+    return "chelsav1/cmip5/$date_str/$name/"
 end
 function _urlpath(::Type{CMIP6}, T::Type{<:CHELSA{<:Future}}, name, date_str)
     # The model is in uppercase in the URL for CMIP6
@@ -259,8 +259,11 @@ _phase(::Type{<:CHELSA{F}}) where F<:Future = _phase(F)
 _model(::Type{<:CHELSA{F}}) where F<:Future = _model(F)
 _scenario(::Type{<:CHELSA{F}}) where F<:Future = _scenario(F)
 
-# Climate model string formatters for CHELSA Future
+## overload _format to use lowercase
+_format(::Type{CHELSA}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
+_format(::Type{CHELSA}, T::Type{<:RepresentativeConcentrationPathway}) = lowercase(_format(T))
 
+## Climate model string formatters for CHELSA Future
 # CMIP5
 const CHELSA_CMIP5_MODELS = Type{<:ClimateModel{CMIP5}}[]
 const CHELSA_CMIP5_MODEL_STRINGS =
@@ -320,7 +323,6 @@ for CMIP in [:CMIP5, :CMIP6]
                 struct $type <: ClimateModel{$CMIP} end
                 export $type
             end
-            _format(::Type{CHELSA}, ::Type{$type}) = lowercase($model_str)
             push!($models, $type)
         end
     end
diff --git a/src/shared.jl b/src/shared.jl
index 0d3f473..e36294a 100644
--- a/src/shared.jl
+++ b/src/shared.jl
@@ -83,7 +83,6 @@ function _map_layers(T, layers, args...; kw...)
 end
 
 # fallback for _format
-_format(RCP::Type{<:RepresentativeConcentrationPathway}) = lowercase(string(nameof(RCP)))
-_format(S::Type{<:SharedSocioeconomicPathway}) = lowercase(string(nameof(S)))
+_format(T::Type) = string(nameof(T))
 _format(M::Type{<:ClimateModel}) = replace(string(nameof(M)), "_" => "-")
 _format(::Type, T::Type) = _format(T)
diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index 0724a07..b103091 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -42,7 +42,7 @@ function rasterpath(T::Type{<:WorldClim{<:Future{BioClim}}}; res, date)
     joinpath(_rasterpath(T), rastername(T; res, date))
 end
 function _rasterpath(T::Type{<:WorldClim{<:Future}})
-    joinpath(rasterpath(WorldClim), "Future", string(_dataset(T)), string(_scenario(T)), string(_model(T)))
+    joinpath(rasterpath(WorldClim), "Future", _format(T, _dataset(T)), _format(T, _scenario(T)), _format(T, _model(T)))
 end
 
 function rasterurl(T::Type{<:WorldClim{<:Future}}, args...; res, date)
@@ -50,7 +50,7 @@ function rasterurl(T::Type{<:WorldClim{<:Future}}, args...; res, date)
 end
 
 function rastername(T::Type{<:WorldClim{<:Future}}, layer; res, date)
-    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), _date_string(T, date)], "_") * ".tif"
+    join(["wc2.1", res, _format(T, layer), _format(T, _model(T)), _format(T, _scenario(T)), _date_string(T, date)], "_") * ".tif"
 end
 rastername(T::Type{<:WorldClim{<:Future{BioClim}}}; kw...) = rastername(T, :bioc, ; kw...)
 
@@ -60,6 +60,8 @@ _phase(::Type{<:WorldClim{F}}) where F<:Future = _phase(F)
 _model(::Type{<:WorldClim{F}}) where F<:Future = _model(F)
 _scenario(::Type{<:WorldClim{F}}) where F<:Future = _scenario(F)
 
+# overload _format
+_format(::Type{WorldClim}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
 
 function _date_string(::Type{<:WorldClim{<:Future{<:Any, CMIP6}}}, date)
     if date < DateTime(2021)
@@ -106,7 +108,6 @@ for model_str in WORDCLIM_CMIP6_MODEL_STRINGS
             export $type
         end
         push!(WORDCLIM_CMIP6_MODELS, $type)
-        _format(::Type{WorldClim}, ::Type{$type}) = $model_str
     end
 end
 

From 8bd19757bce3c7eabbf890f5bad59f54e4688000 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 11:51:36 +0200
Subject: [PATCH 09/21] add a dispatch on worldclim future with layers argument

---
 src/worldclim/future.jl | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index b103091..84ca46d 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -1,7 +1,7 @@
 const WORLDCLIM_URI_CMIP6 = URI(scheme="https", host="geodata.ucdavis.edu", path="/cmip6")
-
-layers(::Type{<:WorldClim{<:Future{Climate}}}) = (:tmin, :tmax, :prec)
-getraster_keywords(::Type{<:WorldClim{<:Future{Climate}}}) = (:date, :res)
+layers(::Type{WorldClim{Future{BioClim}}}) = layers(WorldClim{BioClim})
+layers(::Type{WorldClim{Future{Climate}}}) = (:tmin, :tmax, :prec)
+getraster_keywords(::Type{WorldClim{Future}}) = (:date, :res)
 
 function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union{Tuple,Symbol}; 
     res::String=defres(T), date
@@ -21,7 +21,17 @@ end
 
 ## Bioclim
 getraster_keywords(::Type{<:WorldClim{<:Future{BioClim}}}) = (:date, :res)
-
+# Future worldclim bioclim variables are in one big file. This is for syntax consistency
+function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}, layers::Union{Tuple,Symbol,Int}; kw...)
+    if layers isa Tuple
+        for l in layers
+            _check_layer(WorldClim{BioClim}, bioclim_int(l))
+        end
+    else
+        _check_layer(WorldClim{BioClim}, bioclim_int(layers))
+    end
+    getraster(T; kw...)
+end
 function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}; res::String=defres(T), date)
     _getraster(T, res, date)
 end

From 06e1b0beb91d25b58b49a3de64b0cf49712229ba Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 13:08:42 +0200
Subject: [PATCH 10/21] fix some dispatches

---
 src/chelsa/future.jl    |  4 ++--
 src/worldclim/future.jl | 24 +++++++++++-------------
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index 6506a15..427893a 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -260,8 +260,8 @@ _model(::Type{<:CHELSA{F}}) where F<:Future = _model(F)
 _scenario(::Type{<:CHELSA{F}}) where F<:Future = _scenario(F)
 
 ## overload _format to use lowercase
-_format(::Type{CHELSA}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
-_format(::Type{CHELSA}, T::Type{<:RepresentativeConcentrationPathway}) = lowercase(_format(T))
+_format(::Type{<:CHELSA}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
+_format(::Type{<:CHELSA}, T::Type{<:RepresentativeConcentrationPathway}) = lowercase(_format(T))
 
 ## Climate model string formatters for CHELSA Future
 # CMIP5
diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index 84ca46d..c20bf0c 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -1,7 +1,7 @@
 const WORLDCLIM_URI_CMIP6 = URI(scheme="https", host="geodata.ucdavis.edu", path="/cmip6")
-layers(::Type{WorldClim{Future{BioClim}}}) = layers(WorldClim{BioClim})
-layers(::Type{WorldClim{Future{Climate}}}) = (:tmin, :tmax, :prec)
-getraster_keywords(::Type{WorldClim{Future}}) = (:date, :res)
+layers(::Type{<:WorldClim{<:Future{BioClim}}}) = layers(WorldClim{BioClim})
+layers(::Type{<:WorldClim{<:Future{Climate}}}) = (:tmin, :tmax, :prec)
+getraster_keywords(::Type{<:WorldClim{<:Future}}) = (:date, :res)
 
 function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union{Tuple,Symbol}; 
     res::String=defres(T), date
@@ -45,13 +45,10 @@ function _getraster(T::Type{<:WorldClim{<:Future{BioClim}}}, res::String, date)
     return raster_path
 end
 
-function rasterpath(T::Type{<:WorldClim{<:Future{Climate}}}, layer; res, date)
-    joinpath(_rasterpath(T), rastername(T, layer; res, date))
+function rasterpath(T::Type{<:WorldClim{<:Future}}, args...; res, date) # splat to make sure this works with and without layer argument
+    joinpath(rasterpath(T), rastername(T, args...; res, date))
 end
-function rasterpath(T::Type{<:WorldClim{<:Future{BioClim}}}; res, date)
-    joinpath(_rasterpath(T), rastername(T; res, date))
-end
-function _rasterpath(T::Type{<:WorldClim{<:Future}})
+function rasterpath(T::Type{<:WorldClim{<:Future}})
     joinpath(rasterpath(WorldClim), "Future", _format(T, _dataset(T)), _format(T, _scenario(T)), _format(T, _model(T)))
 end
 
@@ -60,9 +57,10 @@ function rasterurl(T::Type{<:WorldClim{<:Future}}, args...; res, date)
 end
 
 function rastername(T::Type{<:WorldClim{<:Future}}, layer; res, date)
-    join(["wc2.1", res, _format(T, layer), _format(T, _model(T)), _format(T, _scenario(T)), _date_string(T, date)], "_") * ".tif"
+    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), _date_string(T, date)], "_") * ".tif"
 end
-rastername(T::Type{<:WorldClim{<:Future{BioClim}}}; kw...) = rastername(T, :bioc, ; kw...)
+rastername(T::Type{<:WorldClim{<:Future{BioClim}}}; kw...) = rastername(T, "bioc"; kw...)
+rastername(T::Type{<:WorldClim{<:Future{BioClim}}}, layers::Union{Tuple,Symbol,Int}; kw...) = rastername(T, "bioc"; kw...)
 
 # copy-pasted in from CHELSA - must be some way to implement this abstractly?
 _dataset(::Type{<:WorldClim{F}}) where F<:Future = _dataset(F)
@@ -71,7 +69,8 @@ _model(::Type{<:WorldClim{F}}) where F<:Future = _model(F)
 _scenario(::Type{<:WorldClim{F}}) where F<:Future = _scenario(F)
 
 # overload _format
-_format(::Type{WorldClim}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
+_format(::Type{<:WorldClim}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
+
 
 function _date_string(::Type{<:WorldClim{<:Future{<:Any, CMIP6}}}, date)
     if date < DateTime(2021)
@@ -115,7 +114,6 @@ for model_str in WORDCLIM_CMIP6_MODEL_STRINGS
     @eval begin
         if !(@isdefined $type) 
             struct $type <: ClimateModel{CMIP6} end
-            export $type
         end
         push!(WORDCLIM_CMIP6_MODELS, $type)
     end

From 3f29737cd997163914c9a897fe0c0f9b9343e205 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 13:08:48 +0200
Subject: [PATCH 11/21] add worldclim future tests

---
 test/worldclim-future.jl | 41 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 test/worldclim-future.jl

diff --git a/test/worldclim-future.jl b/test/worldclim-future.jl
new file mode 100644
index 0000000..9d24c1a
--- /dev/null
+++ b/test/worldclim-future.jl
@@ -0,0 +1,41 @@
+using RasterDataSources, Test, Dates
+using RasterDataSources: rasterurl, rastername, rasterpath
+
+@testset "WorldClim Future BioClim CMIP6" begin
+    bioclim_name = "wc2.1_10m_bioc_MRI-ESM2-0_ssp126_2041-2060.tif"
+    @test rastername(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050), res = "10m") == bioclim_name
+    bioclim_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "WorldClim", "Future", "BioClim", "ssp126", "MRI-ESM2-0")
+    @test rasterpath(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}) == bioclim_path
+
+    raster_path = joinpath(bioclim_path, bioclim_name)
+    raster_path2 = joinpath(bioclim_path, "wc2.1_10m_5_MRI-ESM2-0_SSP126_2041-2060.tif")
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050), res = "10m") == raster_path
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, :bio5; date=Date(2050)) == raster_path
+
+#=
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=Date(2050), res = "10m") == (bio5=raster_path,)
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, [5]; date=Date(2050), res = "10m") == (bio5=raster_path,)
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=[Date(2050)], res = "10m") == 
+        [(bio5=raster_path,)]
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (:bio5,); date=Date(2050)) == (bio5=raster_path,)
+    =#
+    @test isfile(raster_path)
+end
+
+@testset "WorldClim Future Climate CMIP6" begin
+    date_name =  "wc2.1_10m_tmin_GFDL-ESM4_ssp126_2021-2040.tif"
+    @test rastername(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res= "10m") == date_name
+
+    climate_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "WorldClim", "Future", "Climate", "ssp126", "GFDL-ESM4")
+    @test rasterpath(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}) == climate_path
+    date_path = joinpath(climate_path, date_name)
+    @test rasterpath(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
+    @test rasterpath(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
+    date_url = "https://geodata.ucdavis.edu/cmip6/10m/GFDL-ESM4/ssp126/wc2.1_10m_tmin_GFDL-ESM4_ssp126_2021-2040.tif"
+    @test rasterurl(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") |> string == date_url
+    @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
+#    @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, (:tmin,); date=Date(2030), res = "10m") == (tmin=date_path,)
+    @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
+
+    @test isfile(date_path)
+end

From 68790b4fbee8a5ea849979f5c0c204ac3d2f76d7 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 16:26:11 +0200
Subject: [PATCH 12/21] always _format(T) and no dashes in file path

---
 src/chelsa/future.jl | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index 427893a..1511cb5 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -155,30 +155,30 @@ function _rastername(
     ::Type{CMIP5}, T::Type{<:CHELSA{<:Future{BioClim}}}, layer::Integer; date
 )
     date_string = _date_string(_phase(T), date)
-    mod = _format(CHELSA, _model(T))
-    scen = _format(CHELSA, _scenario(T))
+    mod = _format(T, _model(T))
+    scen = _format(T, _scenario(T))
     return "CHELSA_bio_mon_$(mod)_$(scen)_r1i1p1_g025.nc_$(layer)_$(date_string)_V1.2.tif"
 end
 function _rastername(
     ::Type{CMIP5}, T::Type{<:CHELSA{<:Future{Climate}}}, layer::Symbol; date, month
 )
     date_string = _date_string(_phase(T), date)
-    mod = _format(CHELSA, _model(T))
-    scen = _format(CHELSA, _scenario(T))
+    mod = _format(T, _model(T))
+    scen = _format(T, _scenario(T))
     key = CHELSAKEY[layer]
     suffix = layer === :prec ? "" : "_V1.2" # prec filenames dont end in _V1.2
     return "CHELSA_$(key)_mon_$(mod)_$(scen)_r1i1p1_g025.nc_$(month)_$(date_string)$(suffix).tif"
 end
 function _rastername(::Type{CMIP6}, T::Type{<:CHELSA{<:Future{BioClim}}}, layer::Integer; date)
     date_string = _date_string(_phase(T), date)
-    mod = _format(CHELSA, _model(T))
-    scen = _format(CHELSA, _scenario(T))
+    mod = _format(T, _model(T))
+    scen = _format(T, _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))
+    mod = _format(T, _model(T))
+    scen = _format(T, _scenario(T))
     return "CHELSA_$(layer)_$(date_string)_$(mod)_$(scen)_V.2.1.tif"
 end
 function _rastername(
@@ -186,15 +186,15 @@ function _rastername(
 )
     # CMIP6 Climate uses an underscore in the date string, of course
     date_string = replace(_date_string(_phase(T), date), "-" => "_")
-    mod = _format(CHELSA, _model(T))
-    scen = _format(CHELSA, _scenario(T))
+    mod = _format(T, _model(T))
+    scen = _format(T, _scenario(T))
     key = CHELSAKEY[layer]
     mon = lpad(month, 2, '0')
     return "CHELSA_$(mod)_r1i1p1f1_w5e5_$(scen)_$(key)_$(mon)_$(date_string)_norm.tif"
 end
 
 function rasterpath(T::Type{<:CHELSA{<:Future}})
-    joinpath(rasterpath(CHELSA), "Future", _format(T, _dataset(T)), _format(T, _scenario(T)), _format(T, _model(T)))
+    joinpath(rasterpath(CHELSA), "Future", _format(T, _dataset(T)), _format(_scenario(T)), replace(_format(_model(T)), "-" => ""))
 end
 function rasterpath(T::Type{<:CHELSA{<:Future}}, layer; kw...)
     joinpath(rasterpath(T), rastername(T, layer; kw...))
@@ -216,8 +216,8 @@ function _urlpath(::Type{CMIP5}, T::Type{<:CHELSA{<:Future}}, name, date_str)
 end
 function _urlpath(::Type{CMIP6}, T::Type{<:CHELSA{<:Future}}, name, date_str)
     # The model is in uppercase in the URL for CMIP6
-    mod = uppercase(_format(CHELSA, _model(T)))
-    scen = _format(CHELSA, _scenario(T))
+    mod = uppercase(_format(T, _model(T)))
+    scen = _format(T, _scenario(T))
     key = CHELSAKEY[name]
     return "chelsav2/GLOBAL/climatologies/$date_str/$mod/$scen/$key/"
 end
@@ -262,6 +262,7 @@ _scenario(::Type{<:CHELSA{F}}) where F<:Future = _scenario(F)
 ## overload _format to use lowercase
 _format(::Type{<:CHELSA}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
 _format(::Type{<:CHELSA}, T::Type{<:RepresentativeConcentrationPathway}) = lowercase(_format(T))
+_format(::Type{<:CHELSA{<:Future{<:Any, CMIP6}}}, T::Type{<:ClimateModel}) = lowercase(_format(T))
 
 ## Climate model string formatters for CHELSA Future
 # CMIP5

From eb3f8c0cedd19dfe8bb282b706a9f80db7d87888 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 16:26:20 +0200
Subject: [PATCH 13/21] update chelsa future test

---
 test/chelsa-future.jl | 46 +++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/test/chelsa-future.jl b/test/chelsa-future.jl
index 48a378d..467791f 100644
--- a/test/chelsa-future.jl
+++ b/test/chelsa-future.jl
@@ -19,25 +19,25 @@ end
 
 @testset "CHELSA Future BioClim CMIP6" begin
     bioclim_name = "CHELSA_bio5_2041-2070_mri-esm2-0_ssp126_V.2.1.tif"
-    @test rastername(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, 5; date=Date(2050)) == bioclim_name
-    bioclim_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "CHELSA", "Future", "BioClim", "SSP126", "MRIESM2")
-    @test rasterpath(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}) == bioclim_path
+    @test rastername(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050)) == bioclim_name
+    bioclim_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "CHELSA", "Future", "BioClim", "SSP126", "mri-esm2-0")
+    @test rasterpath(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}) == bioclim_path
 
     raster_path = joinpath(bioclim_path, bioclim_name)
     raster_path2 = joinpath(bioclim_path, "CHELSA_bio5_2071-2100_mri-esm2-0_ssp126_V.2.1.tif")
-    @test getraster(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, 5; date=Date(2050)) == raster_path
-    @test getraster(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, (5,); date=Date(2050)) == (bio5=raster_path,)
-    @test getraster(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, [5]; date=Date(2050)) == (bio5=raster_path,)
-    @test getraster(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, (5,); date=[Date(2050)]) == 
+    @test getraster(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050)) == raster_path
+    @test getraster(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=Date(2050)) == (bio5=raster_path,)
+    @test getraster(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, [5]; date=Date(2050)) == (bio5=raster_path,)
+    @test getraster(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=[Date(2050)]) == 
         [(bio5=raster_path,)]
-    @test getraster(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, :bio5; date=Date(2050)) == raster_path
-    @test getraster(CHELSA{Future{BioClim,CMIP6,MRIESM2,SSP126}}, (:bio5,); date=Date(2050)) == (bio5=raster_path,)
-    @test getraster(CHELSA{Future{BioClimPlus,CMIP6,MRIESM2,SSP126}}, :bio5; date=Date(2050)) == raster_path
-    @test getraster(CHELSA{Future{BioClimPlus,CMIP6,MRIESM2,SSP126}}, (:bio5,); date=Date(2050)) == (bio5=raster_path,)
+    @test getraster(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, :bio5; date=Date(2050)) == raster_path
+    @test getraster(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (:bio5,); date=Date(2050)) == (bio5=raster_path,)
+    @test getraster(CHELSA{Future{BioClimPlus,CMIP6,MRI_ESM2_0,SSP126}}, :bio5; date=Date(2050)) == raster_path
+    @test getraster(CHELSA{Future{BioClimPlus,CMIP6,MRI_ESM2_0,SSP126}}, (:bio5,); date=Date(2050)) == (bio5=raster_path,)
     @test isfile(raster_path)
 
     # bioclimplus requires symbol input
-    @test_throws ArgumentError getraster(CHELSA{Future{BioClimPlus,CMIP6,MRIESM2,SSP126}}, 5; date=Date(2050))
+    @test_throws ArgumentError getraster(CHELSA{Future{BioClimPlus,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050))
 end
 
 @testset "CHELSA Future Climate CMIP5" begin
@@ -60,33 +60,33 @@ end
     @test isfile(raster_path)
     @test RasterDataSources.getraster_keywords(CHELSA{Future{Climate}}) == (:date, :month)
 end
-
+@edit rasterpath(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}})
 @testset "CHELSA Future Climate CMIP6" begin
     date_name =  "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_01_2011_2040_norm.tif"
     date_name2 = "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_01_2041_2070_norm.tif"
     date_name3 = "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_01_2071_2100_norm.tif"
     month_name =  "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_01_2011_2040_norm.tif"
     month_name2 = "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_02_2011_2040_norm.tif"
-    @test rastername(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_name
+    @test rastername(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_name
 
     climate_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "CHELSA", "Future", "Climate", "SSP585", "GFDLESM4")
-    @test rasterpath(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}) == climate_path
+    @test rasterpath(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}) == climate_path
     date_path = joinpath(climate_path, date_name)
     date_path2 = joinpath(climate_path, date_name2)
     date_path3 = joinpath(climate_path, date_name3)
     month_path = joinpath(climate_path, month_name)
     month_path2 = joinpath(climate_path, month_name2)
-    @test rasterpath(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
-    @test rasterpath(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
+    @test rasterpath(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
+    @test rasterpath(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
     date_url = "https://os.zhdk.cloud.switch.ch/chelsav2/GLOBAL/climatologies/2011-2040/GFDL-ESM4/ssp585/tas/" * date_name
-    @test rasterurl(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, :temp; date=Date(2030), month=1) |> string == date_url
-    @test getraster(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
-    @test getraster(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, (:temp,); date=Date(2030), month=1) == (temp=date_path,)
-    @test getraster(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
+    @test rasterurl(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, :temp; date=Date(2030), month=1) |> string == date_url
+    @test getraster(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
+    @test getraster(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, (:temp,); date=Date(2030), month=1) == (temp=date_path,)
+    @test getraster(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, :temp; date=Date(2030), month=1) == date_path
     # Month is the inner vector
-    @test getraster(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, [:temp]; date=[Date(2030)], month=1:2) == 
+    @test getraster(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, [:temp]; date=[Date(2030)], month=1:2) == 
         [[(temp=month_path,), (temp=month_path2,)]]
-    @test getraster(CHELSA{Future{Climate,CMIP6,GFDLESM4,SSP585}}, [:temp]; date=(Date(2030), Date(2090)), month=1:1) == 
+    @test getraster(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}}, [:temp]; date=(Date(2030), Date(2090)), month=1:1) == 
         [[(temp=date_path,)], [(temp=date_path2,)], [(temp=date_path3,)]]
 
     @test isfile(date_path)

From 29680b619ff04334bc6ef63122a7cc784425f856 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 16:39:08 +0200
Subject: [PATCH 14/21] fix a test

---
 test/chelsa-future.jl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/chelsa-future.jl b/test/chelsa-future.jl
index 467791f..38f602c 100644
--- a/test/chelsa-future.jl
+++ b/test/chelsa-future.jl
@@ -20,7 +20,7 @@ end
 @testset "CHELSA Future BioClim CMIP6" begin
     bioclim_name = "CHELSA_bio5_2041-2070_mri-esm2-0_ssp126_V.2.1.tif"
     @test rastername(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050)) == bioclim_name
-    bioclim_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "CHELSA", "Future", "BioClim", "SSP126", "mri-esm2-0")
+    bioclim_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "CHELSA", "Future", "BioClim", "SSP126", "MRIESM20")
     @test rasterpath(CHELSA{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}) == bioclim_path
 
     raster_path = joinpath(bioclim_path, bioclim_name)

From 81f42fdb19c00728e72974ee3cdc22e4edbf27c2 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 17:25:19 +0200
Subject: [PATCH 15/21] clean up a line outside testset

---
 test/chelsa-future.jl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/chelsa-future.jl b/test/chelsa-future.jl
index 38f602c..deb53d6 100644
--- a/test/chelsa-future.jl
+++ b/test/chelsa-future.jl
@@ -60,7 +60,7 @@ end
     @test isfile(raster_path)
     @test RasterDataSources.getraster_keywords(CHELSA{Future{Climate}}) == (:date, :month)
 end
-@edit rasterpath(CHELSA{Future{Climate,CMIP6,GFDL_ESM4,SSP585}})
+
 @testset "CHELSA Future Climate CMIP6" begin
     date_name =  "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_01_2011_2040_norm.tif"
     date_name2 = "CHELSA_gfdl-esm4_r1i1p1f1_w5e5_ssp585_tas_01_2041_2070_norm.tif"

From 63d815c880127b10e5c9ba24f441e0cea629af2f Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 2 Oct 2024 17:28:18 +0200
Subject: [PATCH 16/21] soft document why dashes in modelname path are dropped

---
 src/chelsa/future.jl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index 1511cb5..a2bff5d 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -194,7 +194,9 @@ function _rastername(
 end
 
 function rasterpath(T::Type{<:CHELSA{<:Future}})
-    joinpath(rasterpath(CHELSA), "Future", _format(T, _dataset(T)), _format(_scenario(T)), replace(_format(_model(T)), "-" => ""))
+    # drop dashes so paths are more (but not entirely!) compatibile with v0.6
+    modelname = replace(_format(_model(T)), "-" => "")
+    joinpath(rasterpath(CHELSA), "Future", _format(T, _dataset(T)), _format(_scenario(T)), modelname)
 end
 function rasterpath(T::Type{<:CHELSA{<:Future}}, layer; kw...)
     joinpath(rasterpath(T), rastername(T, layer; kw...))

From 83fddeacfa1a48cd96e2aebbd1241a998e6b6614 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 3 Oct 2024 12:43:28 +0200
Subject: [PATCH 17/21] add a generic date formatter

---
 src/chelsa/future.jl | 50 +++++++++-----------------------------------
 src/shared.jl        | 28 ++++++++++++++++++++++++-
 2 files changed, 37 insertions(+), 41 deletions(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index a2bff5d..d2859b4 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -4,12 +4,13 @@ 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)
+# A modified key is used in the file name, while the key is used as-is in the path
+const CHELSAKEY = (prec="pr", temp="tas", tmin="tasmin", tmax="tasmax", bio="bio")
 
 date_step(::Type{<:CHELSA{<:Future{Climate,CMIP5}}}) = Year(20) 
+date_range(::Type{<:CHELSA{<:Future{Climate,CMIP5}}}) = (Date(2041), Date(2080)) 
 date_step(::Type{<:CHELSA{<:Future{Climate,CMIP6}}}) = Year(30) 
-
-# A modified key is used in the file name, while the key is used as-is in the path
-const CHELSAKEY = (prec="pr", temp="tas", tmin="tasmin", tmax="tasmax", bio="bio")
+date_range(::Type{<:CHELSA{<:Future{Climate,CMIP6}}}) = (Date(1981), Date(2100)) 
 
 """
     getraster(T::Type{CHELSA{Future{BioClim}}}, [layer]; date) => String
@@ -154,7 +155,7 @@ end
 function _rastername(
     ::Type{CMIP5}, T::Type{<:CHELSA{<:Future{BioClim}}}, layer::Integer; date
 )
-    date_string = _date_string(_phase(T), date)
+    date_string = _format(T, date)
     mod = _format(T, _model(T))
     scen = _format(T, _scenario(T))
     return "CHELSA_bio_mon_$(mod)_$(scen)_r1i1p1_g025.nc_$(layer)_$(date_string)_V1.2.tif"
@@ -162,7 +163,7 @@ end
 function _rastername(
     ::Type{CMIP5}, T::Type{<:CHELSA{<:Future{Climate}}}, layer::Symbol; date, month
 )
-    date_string = _date_string(_phase(T), date)
+    date_string = _format(T, date)
     mod = _format(T, _model(T))
     scen = _format(T, _scenario(T))
     key = CHELSAKEY[layer]
@@ -170,13 +171,13 @@ function _rastername(
     return "CHELSA_$(key)_mon_$(mod)_$(scen)_r1i1p1_g025.nc_$(month)_$(date_string)$(suffix).tif"
 end
 function _rastername(::Type{CMIP6}, T::Type{<:CHELSA{<:Future{BioClim}}}, layer::Integer; date)
-    date_string = _date_string(_phase(T), date)
+    date_string = _format(T, date)
     mod = _format(T, _model(T))
     scen = _format(T, _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)
+    date_string = _format(T, date)
     mod = _format(T, _model(T))
     scen = _format(T, _scenario(T))
     return "CHELSA_$(layer)_$(date_string)_$(mod)_$(scen)_V.2.1.tif"
@@ -185,7 +186,7 @@ function _rastername(
     ::Type{CMIP6}, T::Type{<:CHELSA{<:Future{Climate}}}, layer::Symbol; date, month
 )
     # CMIP6 Climate uses an underscore in the date string, of course
-    date_string = replace(_date_string(_phase(T), date), "-" => "_")
+    date_string = replace(_format(T, date), "-" => "_")
     mod = _format(T, _model(T))
     scen = _format(T, _scenario(T))
     key = CHELSAKEY[layer]
@@ -203,7 +204,7 @@ function rasterpath(T::Type{<:CHELSA{<:Future}}, layer; kw...)
 end
 
 function rasterurl(T::Type{<:CHELSA{<:Future}}, layer; date, kw...)
-    date_str = _date_string(_phase(T), date)
+    date_str = _format(T, date)
     key = _chelsa_layer(_dataset(T), layer)
     path = _urlpath(_phase(T), T::Type{<:CHELSA{<:Future}}, key, date_str)
     joinpath(rasterurl(CHELSA), path, rastername(T, layer; date, kw...))
@@ -224,37 +225,6 @@ function _urlpath(::Type{CMIP6}, T::Type{<:CHELSA{<:Future}}, name, date_str)
     return "chelsav2/GLOBAL/climatologies/$date_str/$mod/$scen/$key/"
 end
 
-function _date_string(::Type{CMIP5}, date)
-    if date < DateTime(2041)
-        _cmip5_date_error(date)
-    elseif date < DateTime(2061)
-        "2041-2060"
-    elseif date < DateTime(2081)
-        "2061-2080"
-    else
-        _cmip5_date_error(date)
-    end
-end
-
-function _date_string(::Type{CMIP6}, date)
-    if date < DateTime(1981)
-        _cmip6_date_error(date)
-    elseif date < DateTime(2011)
-        "1981-2010"
-    elseif date < DateTime(2041)
-        "2011-2040"
-    elseif date < DateTime(2071)
-        "2041-2070"
-    elseif date < DateTime(2101)
-        "2071-2100"
-    else
-        _cmip6_date_error(date)
-    end
-end
-
-_cmip5_date_error(date) = error("CMIP5 covers the period from 2041-2080, not including $date")
-_cmip6_date_error(date) = error("CMIP6 covers the period from 1981-2100, not including $date")
-
 _dataset(::Type{<:CHELSA{F}}) where F<:Future = _dataset(F)
 _dataset(::Type{<:Future{BioClimPlus}}) = BioClim # to make sure bioclimplus and bioclim end up in the same folder
 _phase(::Type{<:CHELSA{F}}) where F<:Future = _phase(F)
diff --git a/src/shared.jl b/src/shared.jl
index e36294a..70c4825 100644
--- a/src/shared.jl
+++ b/src/shared.jl
@@ -32,6 +32,32 @@ _date_sequence(step, dates::AbstractArray) = dates
 _date_sequence(step, dates::NTuple{2}) = first(dates):step:last(dates)
 _date_sequence(step, date) = date:step:date
 
+function _format(T::Type{<:RasterDataSource}, date::TimeType)
+    daterange = date_range(T)
+    datestep = date_step(T)
+    # check if the date is within the range
+    if date < first(daterange) || date > last(daterange)
+        _date_error(date, daterange)
+    end
+
+    # find which bin it is in
+    r = range(daterange...; step = datestep)
+    idx = searchsortedfirst(r, date)
+
+    # from here on just use integer math
+    startyear = Dates.year(first(daterange))
+    yearstep = Dates.value(datestep)
+    startyear = startyear + yearstep * (idx - 2)
+    endyear = startyear + yearstep - 1
+    return "$startyear-$endyear"
+end
+
+function _date_error(date, daterange)
+    startyear = Dates.year(first(daterange))
+    endyear = Dates.year(last(daterange))
+    error("The requested dataset covers the period from $startyear-$endyear, which does not include $date")
+end         
+
 function _maybe_download(uri::URI, filepath, headers = [])
     if !isfile(filepath)
         mkpath(dirname(filepath))
@@ -83,6 +109,6 @@ function _map_layers(T, layers, args...; kw...)
 end
 
 # fallback for _format
+_format(::Type, T) = _format(T)
 _format(T::Type) = string(nameof(T))
 _format(M::Type{<:ClimateModel}) = replace(string(nameof(M)), "_" => "-")
-_format(::Type, T::Type) = _format(T)

From 0611501c8063732c56996b77329765379d610bed Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 3 Oct 2024 12:44:48 +0200
Subject: [PATCH 18/21] make future worldclim work for multiple dates

---
 src/worldclim/future.jl | 67 ++++++++++++++++++-----------------------
 1 file changed, 30 insertions(+), 37 deletions(-)

diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index c20bf0c..94208c1 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -1,15 +1,27 @@
-const WORLDCLIM_URI_CMIP6 = URI(scheme="https", host="geodata.ucdavis.edu", path="/cmip6")
-layers(::Type{<:WorldClim{<:Future{BioClim}}}) = layers(WorldClim{BioClim})
-layers(::Type{<:WorldClim{<:Future{Climate}}}) = (:tmin, :tmax, :prec)
+## Shared
 getraster_keywords(::Type{<:WorldClim{<:Future}}) = (:date, :res)
 
-function getraster(T::Type{<:WorldClim{<:Future{Climate, CMIP6}}}, layers::Union{Tuple,Symbol}; 
+date_step(::Type{<:WorldClim{<:Future{<:Any,CMIP6}}}) = Year(20) 
+date_range(::Type{<:WorldClim{<:Future{<:Any,CMIP6}}}) = (Date(2021), Date(2100))
+
+function getraster(T::Type{<:WorldClim{<:Future}}, layers::Union{Tuple,Symbol,Int}; 
     res::String=defres(T), date
 )
     _getraster(T, layers, res, date)
 end
 
-function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layer::Symbol, res::String, date)
+function _getraster(T::Type{<:WorldClim{<:Future}}, layers, res::String, dates)
+    map(date -> _getraster(T, layers, res, date), date_sequence(T, dates))
+end
+
+
+## Climate
+layers(::Type{<:WorldClim{<:Future{Climate}}}) = (:tmin, :tmax, :prec)
+
+function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layers::Tuple, res::String, date::TimeType)
+    _map_layers(T, layers, res, date)
+end
+function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layer::Symbol, res::String, date::TimeType)
     _check_layer(T, layer)
     _check_res(T, res)
     raster_path = rasterpath(T, layer; res, date)
@@ -19,24 +31,22 @@ function _getraster(T::Type{<:WorldClim{<:Future{Climate}}}, layer::Symbol, res:
     return raster_path
 end
 
+
 ## Bioclim
-getraster_keywords(::Type{<:WorldClim{<:Future{BioClim}}}) = (:date, :res)
-# Future worldclim bioclim variables are in one big file. This is for syntax consistency
-function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}, layers::Union{Tuple,Symbol,Int}; kw...)
+layers(::Type{<:WorldClim{<:Future{BioClim}}}) = layers(WorldClim{BioClim})
+
+function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}; res::String=defres(T), date)
+    getraster(T, :bio1; res, date)
+end
+
+function _getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}, layers, res::String, date::TimeType)
     if layers isa Tuple
         for l in layers
-            _check_layer(WorldClim{BioClim}, bioclim_int(l))
+            _check_layer(T, bioclim_int(l))
         end
     else
-        _check_layer(WorldClim{BioClim}, bioclim_int(layers))
+    _check_layer(T, bioclim_int(layers))
     end
-    getraster(T; kw...)
-end
-function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}; res::String=defres(T), date)
-    _getraster(T, res, date)
-end
-
-function _getraster(T::Type{<:WorldClim{<:Future{BioClim}}}, res::String, date)
     _check_res(T, res)
     raster_path = rasterpath(T; res, date)
     if !isfile(raster_path)
@@ -53,11 +63,12 @@ function rasterpath(T::Type{<:WorldClim{<:Future}})
 end
 
 function rasterurl(T::Type{<:WorldClim{<:Future}}, args...; res, date)
-    joinpath(WORLDCLIM_URI_CMIP6, res, _format(T, _model(T)), _format(T, _scenario(T)), rastername(T, args...; res, date))
+    joinpath(rasterurl(T), res, _format(T, _model(T)), _format(T, _scenario(T)), rastername(T, args...; res, date))
 end
+rasterurl(T::Type{<:WorldClim{<:Future}}) = URI(scheme="https", host="geodata.ucdavis.edu", path="/cmip6")
 
 function rastername(T::Type{<:WorldClim{<:Future}}, layer; res, date)
-    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), _date_string(T, date)], "_") * ".tif"
+    join(["wc2.1", res, string(layer), _format(T, _model(T)), _format(T, _scenario(T)), _format(T, date)], "_") * ".tif"
 end
 rastername(T::Type{<:WorldClim{<:Future{BioClim}}}; kw...) = rastername(T, "bioc"; kw...)
 rastername(T::Type{<:WorldClim{<:Future{BioClim}}}, layers::Union{Tuple,Symbol,Int}; kw...) = rastername(T, "bioc"; kw...)
@@ -71,24 +82,6 @@ _scenario(::Type{<:WorldClim{F}}) where F<:Future = _scenario(F)
 # overload _format
 _format(::Type{<:WorldClim}, T::Type{<:SharedSocioeconomicPathway}) = lowercase(_format(T))
 
-
-function _date_string(::Type{<:WorldClim{<:Future{<:Any, CMIP6}}}, date)
-    if date < DateTime(2021)
-        _cmip6_date_error(date)
-    elseif date < DateTime(2041)
-        "2021-2040"
-    elseif date < DateTime(2061)
-        "2041-2060"
-    elseif date < DateTime(2081)
-        "2041-2060"
-    elseif date < DateTime(2101)
-        "2081-2100"
-    else
-        _cmip6_date_error(date)
-    end
-end
-
-
 ## Handle all the models
 const WORDCLIM_CMIP6_MODEL_STRINGS = [
     "ACCESS-CM2"

From 809b3babeab039488d1d7e3f01cc3818a3cb7deb Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 3 Oct 2024 12:45:15 +0200
Subject: [PATCH 19/21] fix worldclim futur tests

---
 test/worldclim-future.jl | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/test/worldclim-future.jl b/test/worldclim-future.jl
index 9d24c1a..7394296 100644
--- a/test/worldclim-future.jl
+++ b/test/worldclim-future.jl
@@ -9,32 +9,40 @@ using RasterDataSources: rasterurl, rastername, rasterpath
 
     raster_path = joinpath(bioclim_path, bioclim_name)
     raster_path2 = joinpath(bioclim_path, "wc2.1_10m_5_MRI-ESM2-0_SSP126_2041-2060.tif")
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}; date=Date(2050), res = "10m") == raster_path
     @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, 5; date=Date(2050), res = "10m") == raster_path
     @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, :bio5; date=Date(2050)) == raster_path
-
-#=
-    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=Date(2050), res = "10m") == (bio5=raster_path,)
-    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, [5]; date=Date(2050), res = "10m") == (bio5=raster_path,)
-    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=[Date(2050)], res = "10m") == 
-        [(bio5=raster_path,)]
-    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (:bio5,); date=Date(2050)) == (bio5=raster_path,)
-    =#
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=Date(2050), res = "10m") == raster_path
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, [5]; date=Date(2050), res = "10m") == raster_path
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=[Date(2050)], res = "10m") == [raster_path]
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (5,); date=(Date(2050),Date(2050)), res = "10m") == 
+        [raster_path]
+    @test getraster(WorldClim{Future{BioClim,CMIP6,MRI_ESM2_0,SSP126}}, (:bio5,); date=Date(2050)) ==raster_path
+    
     @test isfile(raster_path)
 end
 
 @testset "WorldClim Future Climate CMIP6" begin
     date_name =  "wc2.1_10m_tmin_GFDL-ESM4_ssp126_2021-2040.tif"
+    date_name2 =  "wc2.1_10m_tmin_GFDL-ESM4_ssp126_2041-2060.tif"
+    date_name3 =  "wc2.1_10m_tmin_GFDL-ESM4_ssp126_2061-2080.tif"
+    date_name4 =  "wc2.1_10m_tmin_GFDL-ESM4_ssp126_2081-2100.tif"
+    date_names = [date_name, date_name2, date_name3, date_name4]
+
     @test rastername(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res= "10m") == date_name
 
     climate_path = joinpath(ENV["RASTERDATASOURCES_PATH"], "WorldClim", "Future", "Climate", "ssp126", "GFDL-ESM4")
     @test rasterpath(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}) == climate_path
     date_path = joinpath(climate_path, date_name)
+    date_paths = joinpath.(climate_path, date_names)
     @test rasterpath(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
     @test rasterpath(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
     date_url = "https://geodata.ucdavis.edu/cmip6/10m/GFDL-ESM4/ssp126/wc2.1_10m_tmin_GFDL-ESM4_ssp126_2021-2040.tif"
     @test rasterurl(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") |> string == date_url
     @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
-#    @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, (:tmin,); date=Date(2030), res = "10m") == (tmin=date_path,)
+    @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, (:tmin,); date=Date(2030), res = "10m") == (tmin=date_path,)
+    @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, (:tmin,); date=(Date(2030), Date(2090)), res = "10m") == 
+                [(tmin=date_path,) for date_path in date_paths]
     @test getraster(WorldClim{Future{Climate,CMIP6,GFDL_ESM4,SSP126}}, :tmin; date=Date(2030), res = "10m") == date_path
 
     @test isfile(date_path)

From 2b382d105253d39f1b107d74c7114943f14756ff Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Thu, 3 Oct 2024 12:50:35 +0200
Subject: [PATCH 20/21] fix date_step and range for chelsa bioclim

---
 src/chelsa/future.jl | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/chelsa/future.jl b/src/chelsa/future.jl
index d2859b4..fd4e6b5 100644
--- a/src/chelsa/future.jl
+++ b/src/chelsa/future.jl
@@ -7,10 +7,10 @@ layers(::Type{<:CHELSA{<:Future{Climate}}}) = (:prec, :temp, :tmin, :tmax)
 # A modified key is used in the file name, while the key is used as-is in the path
 const CHELSAKEY = (prec="pr", temp="tas", tmin="tasmin", tmax="tasmax", bio="bio")
 
-date_step(::Type{<:CHELSA{<:Future{Climate,CMIP5}}}) = Year(20) 
-date_range(::Type{<:CHELSA{<:Future{Climate,CMIP5}}}) = (Date(2041), Date(2080)) 
-date_step(::Type{<:CHELSA{<:Future{Climate,CMIP6}}}) = Year(30) 
-date_range(::Type{<:CHELSA{<:Future{Climate,CMIP6}}}) = (Date(1981), Date(2100)) 
+date_step(::Type{<:CHELSA{<:Future{<:Any,CMIP5}}}) = Year(20) 
+date_range(::Type{<:CHELSA{<:Future{<:Any,CMIP5}}}) = (Date(2041), Date(2080)) 
+date_step(::Type{<:CHELSA{<:Future{<:Any,CMIP6}}}) = Year(30) 
+date_range(::Type{<:CHELSA{<:Future{<:Any,CMIP6}}}) = (Date(1981), Date(2100)) 
 
 """
     getraster(T::Type{CHELSA{Future{BioClim}}}, [layer]; date) => String

From 4d0a476ee58a4289532a87ba2995cdd733fee463 Mon Sep 17 00:00:00 2001
From: tiemvanderdeure <tiemvanderdeure@gmail.com>
Date: Wed, 9 Oct 2024 15:14:23 +0200
Subject: [PATCH 21/21] define layerkeys for WorldClim{Future{BioClim}}

---
 src/worldclim/future.jl | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/worldclim/future.jl b/src/worldclim/future.jl
index 94208c1..e3a312f 100644
--- a/src/worldclim/future.jl
+++ b/src/worldclim/future.jl
@@ -34,6 +34,7 @@ end
 
 ## Bioclim
 layers(::Type{<:WorldClim{<:Future{BioClim}}}) = layers(WorldClim{BioClim})
+layerkeys(::Type{<:WorldClim{<:Future{BioClim}}}) = layerkeys(WorldClim{BioClim})
 
 function getraster(T::Type{<:WorldClim{<:Future{BioClim, CMIP6}}}; res::String=defres(T), date)
     getraster(T, :bio1; res, date)