@@ -92,16 +92,19 @@ This function retrieves data from the Climate Data Store (CDS) (https://cds.clim
9292- `params`: A JSON string containing the request parameters. This string should be in the format expected
9393 by the CDSAPI. When using input via this option the `dataset` option is mandatory.
9494 If you feel brave, you can create the request parametrs yourself and pass them as a two elements string
95- vector with the output of the ``era5vars()`` and ``era5time()`` functions. In this case, a region selection,
96- if desired, must be provided via the `region` option that has the same syntax in all other GMT.jl modules
97- that use it, _e.g._ the ``coast`` function.
95+ vector with the output of the ``era5vars()`` and ``era5time()`` functions. In this case, a region selection
96+ and pressure levels, if desired, must be provided via the `region` and `pressure` options. The `region`
97+ option has the same syntax in all other GMT.jl modules that use it, _e.g._ the ``coast`` function.
9898- `key`: The API key for the CDSAPI server. Default is the value in the ``.cdsapirc`` file in the home directory.
9999 but if that file does not exist, the user can provide the `key` and `url` as arguments. Instructions on how
100100 to create the ``.cdsapirc`` file for your user account can be found at https://cds.climate.copernicus.eu/how-to-api
101101- `url`: The URL of the CDS API server. Default is https://cds.climate.copernicus.eu/api
102+ - `pressure`: List of pressure levels to retrieve. It can be a string to select a unique level, or a vector
103+ of strings or Ints to select multiple levels. But it can also be a range of levels, e.g. "1000:-100:500".
104+ This option is only used when the `params` argument is provided as a string vector.
102105- `region`: Specify a region of a specific geographic area. It can be provided as a string with form "N/W/S/E"
103106 or a 4-element vector or tuple with numeric data. This option is only used when the `params` argument is
104- provided as a two elements string vector.
107+ provided as a string vector.
105108- `format`: The format of the data to download. Default is "netcdf". Other options is "grib".
106109- `debug`: A boolean indicating whether to print the `params` from the outputs of the `era5vars()` and
107110 `era5time()` functions. I this case, we just print the `params` and return without trying to download any file.
@@ -139,7 +142,7 @@ datetime = era5time(hour=10:14);
139142era5(dataset="reanalysis-era5-land", params=[var, datetime], region=(-10, 0, 30, 45))
140143```
141144"""
142- function era5 (reanalysis:: Symbol = :reanalysis ; filename= " " , cb:: Bool = false , dataset= " " , params:: Union{AbstractString, Vector{String}} = " " , key:: String = " " , url:: String = " " , wait= 1.0 , region= " " , format= " netcdf" , debug:: Bool = false , verbose:: Bool = true )
145+ function era5 (reanalysis:: Symbol = :reanalysis ; filename= " " , cb:: Bool = false , dataset= " " , params:: Union{AbstractString, Vector{String}} = " " , key:: String = " " , url:: String = " " , wait= 1.0 , pressure = " " , region= " " , format= " netcdf" , debug:: Bool = false , verbose:: Bool = true )
143146
144147 function cdsapikey ():: Tuple{String, String}
145148 # Get the API key and URL from the ~/.cdsapirc file
@@ -185,6 +188,7 @@ function era5(reanalysis::Symbol=:reanalysis; filename="", cb::Bool=false, datas
185188 split (readlines (io)[1 ], ' ,' )
186189 end
187190 end
191+ # ======================== End of nested functions ========================
188192
189193 if (key == " " )
190194 KEY, URL = cdsapikey ()
@@ -201,8 +205,15 @@ function era5(reanalysis::Symbol=:reanalysis; filename="", cb::Bool=false, datas
201205 else
202206 if isa (params, Vector)
203207 params = join (params, ' \n ' )
208+ if (pressure != " " ) # Pressure levels are provided
209+ pr = getdtp (pressure, " 1000" ); (pr == " e" ) && error (" Unknown type for 'pressure'" )
210+ sp = @sprintf (" \" pressure_level\" : [\" %s\" ],\n " , pr)
211+ sp = replace (sp, " [\" [" => " [" ); sp = replace (sp, " ]\" ]" => " ]" ); # Remove double [[ & ]]
212+ params *= sp
213+ end
204214 params *= (format == " netcdf" ) ? " \" data_format\" : \" netcdf\" ,\n " : " \" data_format\" : \" grib\" ,\n "
205- params *= " \" download_format\" : \" unarchived\" ,\n "
215+ last = (region == " " ) ? " \n " : " ,\n " # Having an extra comma at the end of the line is a json syntax error
216+ params *= " \" download_format\" : \" unarchived\" " * last
206217 if (region != " " ) # The region is provided by parse_R() as a string like " -R58/6/55/9" (N/W/S/E)
207218 optR = split (parse_R (Dict (:R => region), " " )[1 ], ' /' )
208219 params *= " \" area\" : [" * optR[1 ][4 : end ] * " , " * optR[4 ] * " , " * optR[2 ] * " , " * optR[3 ] * " ]\n "
@@ -216,14 +227,15 @@ function era5(reanalysis::Symbol=:reanalysis; filename="", cb::Bool=false, datas
216227 (dataset == " " && _dataset != " " ) && (dataset = _dataset)
217228
218229 s = curl_post (URL * " /retrieve/v1/processes/$dataset /execute" , body, KEY)
219- st_line = findfirst (startswith .(s," \" status" ))
220- status = s[st_line][11 : end - 1 ] # It has the form "{\"status\":\"accepted\""
221- if (contains (s[st_line], " :4" ))
230+ ind = findfirst (startswith .(s," \" status" ))
231+ (ind === nothing ) && throw (ArgumentError (" The request was not accepted, probably a malformed one. Check it the 'debug' option." ))
232+ status = s[ind][11 : end - 1 ] # It has the form "{\"status\":\"accepted\""
233+ if (contains (s[ind], " :4" ))
222234 ind = findfirst (startswith .(s," \" title" ))
223235 throw (ArgumentError (split (s[ind], ' :' )[2 ][2 : end - 1 ])) # It has the form "\"title\":\"Autentication failed\""
224236 end
225- ep_line = findfirst (startswith .(s," {\" href" ))
226- endpoint = s[ep_line ][10 : end - 1 ] # It has the form "{\"href\":\"https://cds.climate...\""
237+ ind = findfirst (startswith .(s," {\" href" ))
238+ endpoint = s[ind ][10 : end - 1 ] # It has the form "{\"href\":\"https://cds.climate...\""
227239 while (status != " successful" )
228240 s = curl_get (endpoint, KEY)
229241 st_line = findfirst (startswith .(s," \" status" ))
@@ -347,7 +359,7 @@ This function returns a JSON formatted string that can be used as an input to th
347359 It can also be a range of hours, e.g. "01:10".
348360
349361### Returns
350- A string with the JSON formatted time.
362+ A string with the JSON formatted date- time.
351363
352364### Example
353365```julia
@@ -356,19 +368,19 @@ var = era5time(year="2023")
356368```
357369"""
358370function era5time (; year= " " , month= " " , day= " " , hour= " " )
359- function getdt (x, def)
360- (x == " " ) ? def : (typeof (x) <: OrdinalRange ) ? string .(collect (x)) : isa (x, Vector{Int}) ? string .(x) : isa (x, Vector{String}) ? x : " e"
361- end
362-
363371 _y, _m, _d, _h = agora ()
364- yr = (year == " all " ) ? string ( collect ( 2000 : parse (Int, _y))) : getdt (year, _y); (yr == " e" ) && error (" Unknown type for 'year'" )
365- mo = (month == " all " ) ? string ( collect ( 1 : 12 )) : getdt (month, _m); (mo == " e" ) && error (" Unknown type for 'month'" )
366- dy = (day == " all " ) ? string ( collect ( 1 : 30 )) : getdt (day, _d); (dy == " e" ) && error (" Unknown type for 'day'" )
367- hr = (day == " all " ) ? string ( collect ( 0 : 23 )) : getdt (hour, _h); (hr == " e" ) && error (" Unknown type for 'hour'" )
372+ yr = getdtp (year, _y); (yr == " e" ) && error (" Unknown type for 'year'" )
373+ mo = getdtp (month, _m); (mo == " e" ) && error (" Unknown type for 'month'" )
374+ dy = getdtp (day, _d); (dy == " e" ) && error (" Unknown type for 'day'" )
375+ hr = getdtp (hour, _h); (hr == " e" ) && error (" Unknown type for 'hour'" )
368376 s = @sprintf (" \" year\" : [\" %s\" ],\n\" month\" : [\" %s\" ],\n\" day\" : [\" %s\" ],\n\" time\" : [\" %s\" ],\n " , yr, mo, dy, hr)
369377 s = replace (s, " [\" [" => " [" ); s = replace (s, " ]\" ]" => " ]" ); # Remove double [[ & ]]
370378 return s
371379end
380+
381+ function getdtp (x, def) # used also in era5() to get the pressure levels
382+ (x == " " ) ? def : (typeof (x) <: OrdinalRange ) ? string .(collect (x)) : isa (x, Vector{Int}) ? string .(x) : isa (x, Vector{String}) ? x : " e"
383+ end
372384
373385function agora () # Must put this in a separate function because I want to use the keywords year, month, etc
374386 t = now ()
0 commit comments