Project

General

Profile

API » History » Version 72

Maarten Plieger, 10/04/2016 11:32 AM

1 1 Maarten Plieger
h1. API
2 1 Maarten Plieger
3 48 Maarten Plieger
h2. Clipc combine process
4 48 Maarten Plieger
5 67 Maarten Plieger
* PyWPS process to combine two netcdf files: [[Clipc Combine process]]
6 67 Maarten Plieger
* The clipc combine project page (wiki and repo) located under https://dev.knmi.nl/projects/clipccombine/
7 48 Maarten Plieger
8 68 Maarten Plieger
h2. Search GUI
9 68 Maarten Plieger
10 68 Maarten Plieger
* Check https://dev.knmi.nl/projects/impactportal/wiki/C4I_GUI_Components
11 68 Maarten Plieger
12 28 Maarten Plieger
h2. Access token API - service "account"
13 1 Maarten Plieger
14 28 Maarten Plieger
*1). Generate a token for the current user which can be used to access C4I services by using "generatetoken":*
15 33 Maarten Plieger
* https://dev.climate4impact.eu/impactportal/tokenapi?service=account&request=generatetoken
16 1 Maarten Plieger
17 17 Maarten Plieger
The token has the following structure:
18 17 Maarten Plieger
<pre><code class="json">
19 18 Maarten Plieger
{ 
20 18 Maarten Plieger
  "creationdate" : "2015-10-23T09:50:05Z",
21 17 Maarten Plieger
  "notafter" : "2015-10-30T09:50:05Z",
22 17 Maarten Plieger
  "notbefore" : "2015-10-23T09:50:05Z",
23 22 Maarten Plieger
  "openid" : "https://esg-dn1.nsc.liu.se/esgf-idp/openid/<identifier>",
24 24 Maarten Plieger
  "token" : "daad2944-1def-4bee-b032-b08048f88302", 
25 22 Maarten Plieger
  "userid" : "esg-dn1.nsc.liu.se.esgf-idp.openid.<identifier>"
26 17 Maarten Plieger
}
27 17 Maarten Plieger
</code></pre>
28 17 Maarten Plieger
29 28 Maarten Plieger
*2). List all tokens available for the current user by using "listtokens":*
30 33 Maarten Plieger
* https://dev.climate4impact.eu/impactportal/tokenapi?service=account&request=listtokens
31 1 Maarten Plieger
32 1 Maarten Plieger
*Service endpoints which can be used with a token:*
33 1 Maarten Plieger
* WMS can be used via <pre>https://dev.climate4impact.eu/impactportal/adagucserver/<accesstoken>/?</pre>
34 1 Maarten Plieger
* WCS can be used via <pre>https://dev.climate4impact.eu/impactportal/adagucserver/<accesstoken>/?</pre>
35 1 Maarten Plieger
* WPS can be used via <pre>https://dev.climate4impact.eu/impactportal/WPS/<accesstoken>/?</pre>
36 1 Maarten Plieger
* File download requests and OpenDAP requests from the basket can be done via <pre>https://dev.climate4impact.eu/impactportal/DAP/<accesstoken>/<userid>/<file>"</pre>
37 29 Maarten Plieger
* Basket requests can be done via <pre>https://dev.climate4impact.eu/impactportal/basket/<accesstoken>?&service=basket&request=getoverview&</pre>
38 55 Maarten Plieger
* ImpactService requests can be done via <pre>https://dev.climate4impact.eu/impactportal/ImpactService/<accesstoken>/?</pre>
39 39 Maarten Plieger
40 41 Maarten Plieger
*3). Crash course token generation:*
41 39 Maarten Plieger
# Login with a google account at https://dev.climate4impact.eu/impactportal/account/OAuth2.jsp 
42 40 Maarten Plieger
# Generate a new token via https://dev.climate4impact.eu/impactportal/tokenapi?service=account&request=generatetoken
43 39 Maarten Plieger
# Copy paste the accesstoken value in your URL
44 1 Maarten Plieger
45 50 Ernst de Vreede
h2. CLIP-C Access token API - service "clipcaccount"
46 50 Ernst de Vreede
47 70 Maarten Plieger
The accesstoken API is a machine to machine service endpoint, the CLIPC server uses this to request tokens onbehalfof the logged-in user at the CLIPC portal.
48 71 Maarten Plieger
This token then enables the CLIPC server to generate a token for the current user which can be used to access C4I services by using "generatetoken".
49 71 Maarten Plieger
50 50 Ernst de Vreede
* https://dev.climate4impact.eu/impactportal/tokenapi?service=clipcaccount&request=generatetoken&userid=<userid>
51 50 Ernst de Vreede
52 50 Ernst de Vreede
The token has the following structure:
53 50 Ernst de Vreede
<pre><code class="json">
54 50 Ernst de Vreede
{ 
55 50 Ernst de Vreede
  "creationdate" : "2015-10-23T09:50:05Z",
56 50 Ernst de Vreede
  "notafter" : "2015-10-30T09:50:05Z",
57 50 Ernst de Vreede
  "notbefore" : "2015-10-23T09:50:05Z",
58 50 Ernst de Vreede
  "openid" : "https://esg-dn1.nsc.liu.se/esgf-idp/openid/<identifier>",
59 50 Ernst de Vreede
  "token" : "daad2944-1def-4bee-b032-b08048f88302", 
60 50 Ernst de Vreede
  "userid" : "esg-dn1.nsc.liu.se.esgf-idp.openid.<identifier>"
61 50 Ernst de Vreede
}
62 50 Ernst de Vreede
</code></pre>
63 50 Ernst de Vreede
64 5 Maarten Plieger
h2. Basket requests
65 1 Maarten Plieger
66 2 Maarten Plieger
* Get overview of all files in the users basket: service=basket&request=getoverview, 
67 33 Maarten Plieger
** e.g. <pre>https://dev.climate4impact.eu/impactportal/basket?&service=basket&request=getoverview&</pre>
68 33 Maarten Plieger
** For commandline access with an access token: <pre>https://dev.climate4impact.eu/impactportal/basket/<accesstoken>/?&service=basket&request=getoverview&</pre>
69 7 Maarten Plieger
70 14 Maarten Plieger
The result is a json file with nested childs representing te directory structure at C4I
71 10 Maarten Plieger
<pre><code class="json">
72 12 Maarten Plieger
{ "browser" : "/impactportal/data/catalogbrowser.jsp?",
73 12 Maarten Plieger
  "children" : [ { "children" : [  ],
74 12 Maarten Plieger
        "date" : "",
75 12 Maarten Plieger
        "expanded" : true,
76 12 Maarten Plieger
        "iconCls" : "typeFolder",
77 12 Maarten Plieger
        "leaf" : false,
78 12 Maarten Plieger
        "text" : "Remote data"
79 1 Maarten Plieger
      },
80 13 Maarten Plieger
      { "children" : [ { "dapurl" : "https://localhost/impactportal/DAP/<userid>/INTER_OPER_R___RD3_____L3__20100101T000000_20100201T000000_0004.nc",
81 12 Maarten Plieger
              "date" : "2014-06-06 14:31:23Z",
82 12 Maarten Plieger
              "filesize" : "611.573K",
83 1 Maarten Plieger
              "hasdap" : true,
84 12 Maarten Plieger
              "hashttp" : true,
85 13 Maarten Plieger
              "httpurl" : "https://localhost/impactportal/DAP/<userid>/INTER_OPER_R___RD3_____L3__20100101T000000_20100201T000000_0004.nc",
86 12 Maarten Plieger
              "iconCls" : "typeOF",
87 12 Maarten Plieger
              "id" : "INTER_OPER_R___RD3_____L3__20100101T000000_20100201T000000_0004.nc",
88 12 Maarten Plieger
              "index" : 1,
89 12 Maarten Plieger
              "leaf" : true,
90 1 Maarten Plieger
              "text" : "INTER_OPER_R___RD3_____L3__20100101T000000_20100201T000000_0004.nc",
91 12 Maarten Plieger
              "type" : "file"
92 12 Maarten Plieger
            },
93 13 Maarten Plieger
            { "dapurl" : "https://localhost/impactportal/DAP/<userid>/tasmax_day_CNRM-CM5_historical_r1i1p1_1890.nc",
94 1 Maarten Plieger
              "date" : "2015-10-23 09:37:33Z",
95 12 Maarten Plieger
              "filesize" : "47.867M",
96 12 Maarten Plieger
              "hasdap" : true,
97 12 Maarten Plieger
              "hashttp" : true,
98 13 Maarten Plieger
              "httpurl" : "https://localhost/impactportal/DAP/<userid>/tasmax_day_CNRM-CM5_historical_r1i1p1_1890.nc",
99 12 Maarten Plieger
              "iconCls" : "typeOF",
100 12 Maarten Plieger
              "id" : "tasmax_day_CNRM-CM5_historical_r1i1p1_1890.nc",
101 12 Maarten Plieger
              "index" : 2,
102 12 Maarten Plieger
              "leaf" : true,
103 12 Maarten Plieger
              "text" : "tasmax_day_CNRM-CM5_historical_r1i1p1_1890.nc",
104 12 Maarten Plieger
              "type" : "file"
105 12 Maarten Plieger
            }
106 12 Maarten Plieger
          ],
107 12 Maarten Plieger
        "date" : "",
108 12 Maarten Plieger
        "expanded" : true,
109 12 Maarten Plieger
        "iconCls" : "typeFolder",
110 1 Maarten Plieger
        "leaf" : false,
111 12 Maarten Plieger
        "text" : "My data"
112 12 Maarten Plieger
      }
113 12 Maarten Plieger
    ],
114 12 Maarten Plieger
  "leaf" : false,
115 13 Maarten Plieger
  "text" : "https://esg-dn1.nsc.liu.se/esgf-idp/openid/<openid>",
116 11 Maarten Plieger
  "viewer" : "/impactportal/data/datasetviewer.jsp?"
117 11 Maarten Plieger
}
118 10 Maarten Plieger
</code>
119 56 Maarten Plieger
120 57 Maarten Plieger
</pre>
121 57 Maarten Plieger
122 57 Maarten Plieger
123 56 Maarten Plieger
*Remove a file from the basket*
124 56 Maarten Plieger
125 57 Maarten Plieger
<pre>
126 61 Maarten Plieger
GET request:
127 59 Maarten Plieger
https://dev.climate4impact.eu/impactportal/ImpactService/<access_token>/?&service=basket&request=removeFromList&id[]=<id from basket request>
128 57 Maarten Plieger
</pre>
129 56 Maarten Plieger
e.g.:
130 57 Maarten Plieger
<pre>
131 60 Maarten Plieger
https://dev.climate4impact.eu/impactportal/ImpactService/<access_token>/?&service=basket&request=removeFromList&id[]=INTER_OPER_R___RD3_____L3__20100101T000000_20100201T000000_0004.nc
132 58 Maarten Plieger
</pre>
133 61 Maarten Plieger
134 63 Maarten Plieger
To remove multiple files at once do:
135 63 Maarten Plieger
<pre>
136 63 Maarten Plieger
https://dev.climate4impact.eu/impactportal/ImpactService?&service=basket&request=removeFromList&id[]=WPS_clipc_combine_execute_20160222T150058Z&id[]=WPS_clipc_combine_execute_20160222T150045Z&id[]=WPS_clipc_combine_execute_20160222T145836Z&id[]=WPS_clipc_combine_execute_20160222T145649Z&id[]=WPS_clipc_combine_execute_20160222T145633Z&id[]=WPS_clipc_combine_execute_20160222T145449Z&id[]=WPS_clipc_combine_execute_20160222T145323Z&id[]=WPS_clipc_combine_execute_20160222T145308Z&id[]=WPS_clipc_combine_execute_20160222T145230Z&id[]=WPS_clipc_combine_execute_20160222T145030Z&id[]=WPS_clipc_combine_execute_20160222T144854Z&id[]=WPS_clipc_combine_execute_20160222T144852Z&id[]=WPS_clipc_combine_execute_20160222T144704Z&id[]=WPS_clipc_combine_execute_20160222T144549Z
137 63 Maarten Plieger
</pre>
138 63 Maarten Plieger
139 63 Maarten Plieger
140 61 Maarten Plieger
*Add a file to the basket*
141 61 Maarten Plieger
142 61 Maarten Plieger
<pre>
143 65 Maarten Plieger
GET request to https://dev.climate4impact.eu/impactportal/ImpactService/<access_token>/?service=basket&mode=add&id=<file basename>&opendap=<opendap url>
144 1 Maarten Plieger
</pre>
145 64 Maarten Plieger
E.g add 
146 66 Maarten Plieger
147 64 Maarten Plieger
* opendap: http://thredds.met.no/thredds/dodsC/osisaf/met.no/ice/conc/2016/04/ice_conc_sh_polstere-100_multi_201604091200.nc
148 64 Maarten Plieger
* id: ice_conc_sh_polstere-100_multi_201604091200.nc
149 64 Maarten Plieger
150 64 Maarten Plieger
Example:
151 61 Maarten Plieger
<pre>
152 65 Maarten Plieger
https://dev.climate4impact.eu/impactportal/ImpactService/<access_token>/?service=basket&mode=add&id=ice_conc_sh_polstere-100_multi_201604091200.nc&OPENDAP=http%3A%2F%2Fthredds.met.no%2Fthredds%2FdodsC%2Fosisaf%2Fmet.no%2Fice%2Fconc%2F2016%2F04%2Fice_conc_sh_polstere-100_multi_201604091200.nc
153 58 Maarten Plieger
</pre>
154 58 Maarten Plieger
155 58 Maarten Plieger
156 9 Maarten Plieger
157 30 Maarten Plieger
158 30 Maarten Plieger
h2. WPS Requests
159 30 Maarten Plieger
160 36 Maarten Plieger
Climate4impact uses PyWPS, see http://pywps.wald.intevation.org/documentation/course/ for more information
161 36 Maarten Plieger
162 36 Maarten Plieger
* WPS can be used via <pre>https://dev.climate4impact.eu/impactportal/WPS/<accesstoken>/?</pre>
163 36 Maarten Plieger
164 44 Maarten Plieger
165 44 Maarten Plieger
166 44 Maarten Plieger
*Example Python WPS client on WPS Process "binaryoperatoronnumbers"*
167 36 Maarten Plieger
168 46 Maarten Plieger
The following Python example behaves like a minimal WPS client, using C4I services to perform analysis. The example below makes use of the binaryoperatorfornumbers process, which enables operations on two numbers. The process needs five seconds to run, listing progress in percentages. This is done to ease progress monitoring developments. The process is executed asynchronously and is executed with the GET method. PyWPS also supports POST, this can be used for posting bigger inputs. This is described here: [[WPS]] 
169 46 Maarten Plieger
170 46 Maarten Plieger
The process has three inputs:
171 34 Maarten Plieger
# inputa - a float number
172 34 Maarten Plieger
# inputb - a float number
173 34 Maarten Plieger
# operation -  Can be "add", "substract", "divide" or "multiply"
174 35 Maarten Plieger
175 34 Maarten Plieger
176 30 Maarten Plieger
<pre><code class="python">
177 30 Maarten Plieger
#!/bin/python
178 30 Maarten Plieger
179 30 Maarten Plieger
"""
180 72 Maarten Plieger
181 1 Maarten Plieger
Obtain an access token:
182 72 Maarten Plieger
- Login with a google account at https://climate4impact.eu/impactportal/account/OAuth2.jsp 
183 72 Maarten Plieger
- Generate via https://climate4impact.eu/impactportal/tokenapi?service=account&request=generatetoken
184 1 Maarten Plieger
- Copy paste the accesstoken value in the "token" variable below.
185 72 Maarten Plieger
186 72 Maarten Plieger
Author: Maarten Plieger, KNMI, 2016-10-04
187 30 Maarten Plieger
"""
188 1 Maarten Plieger
189 72 Maarten Plieger
token="put your access token here"
190 30 Maarten Plieger
 
191 30 Maarten Plieger
192 72 Maarten Plieger
wpsendpoint="https://climate4impact.eu/impactportal/WPS/"+token+"/?"
193 30 Maarten Plieger
194 30 Maarten Plieger
inputa=11;
195 30 Maarten Plieger
inputb=22;
196 30 Maarten Plieger
operator="divide" # Any of add, substract, multiply, divide
197 30 Maarten Plieger
198 30 Maarten Plieger
print "Calculating ["+str(inputa)+" "+str(operator)+" "+str(inputb)+"]"
199 1 Maarten Plieger
200 30 Maarten Plieger
import xml.etree.ElementTree as et
201 30 Maarten Plieger
import urllib2
202 30 Maarten Plieger
import time
203 72 Maarten Plieger
from StringIO import StringIO
204 1 Maarten Plieger
205 1 Maarten Plieger
""" Parses URL to XML tree """
206 1 Maarten Plieger
def getandparsexml(url):
207 1 Maarten Plieger
  response = urllib2.urlopen(url)
208 1 Maarten Plieger
  html = response.read()
209 72 Maarten Plieger
  it = et.iterparse(StringIO(html))
210 72 Maarten Plieger
  for _, el in it:
211 72 Maarten Plieger
      if '}' in el.tag:
212 72 Maarten Plieger
          el.tag = el.tag.split('}', 1)[1]  # strip all namespaces
213 72 Maarten Plieger
  root = it.root
214 72 Maarten Plieger
  return root
215 30 Maarten Plieger
  
216 30 Maarten Plieger
# Execute the ultimatequestionprocess aynchronousely and obtain the statusLocation for progress
217 30 Maarten Plieger
datainputs = "inputa="+str(inputa)+";inputb="+str(inputb)+";operator="+str(operator)
218 30 Maarten Plieger
root = getandparsexml(wpsendpoint+"service=WPS&version=1.0.0&request=execute&storeExecuteResponse=true&status=true&identifier=binaryoperatorfornumbers&datainputs="+datainputs)    
219 30 Maarten Plieger
monitorURL = root.attrib['statusLocation']
220 30 Maarten Plieger
221 30 Maarten Plieger
print "Process executed checking " +monitorURL
222 30 Maarten Plieger
223 30 Maarten Plieger
# Get starttime of process, sometimes the monitorURL is not immediately available. Iterate until a valid creationtime is available would be good practice.
224 30 Maarten Plieger
numberOfTries=10
225 30 Maarten Plieger
while numberOfTries>0:
226 30 Maarten Plieger
  numberOfTries = numberOfTries-1 
227 1 Maarten Plieger
  try:
228 1 Maarten Plieger
    root = getandparsexml(monitorURL)
229 1 Maarten Plieger
    numberOfTries = -1
230 1 Maarten Plieger
    print "Process started at "+str(root[1].attrib['creationTime'])
231 1 Maarten Plieger
  except:
232 1 Maarten Plieger
    time.sleep(1)
233 1 Maarten Plieger
    pass
234 1 Maarten Plieger
235 72 Maarten Plieger
# Wait for process accepted to pass...
236 72 Maarten Plieger
ProcessAcceptedFound = True
237 72 Maarten Plieger
238 72 Maarten Plieger
while ProcessAcceptedFound == True:
239 72 Maarten Plieger
  root = getandparsexml(monitorURL)
240 72 Maarten Plieger
  ProcessAcceptedFound = False
241 72 Maarten Plieger
  for elem in root.iter(tag="ProcessAccepted"):
242 72 Maarten Plieger
    ProcessAcceptedFound = True;
243 72 Maarten Plieger
    print elem.tag, elem.attrib
244 72 Maarten Plieger
  time.sleep(1)
245 72 Maarten Plieger
246 72 Maarten Plieger
247 72 Maarten Plieger
# Now Monitor progress, polling the statuslocation frequently
248 72 Maarten Plieger
percentage = 0
249 30 Maarten Plieger
while percentage<100:
250 30 Maarten Plieger
  root = getandparsexml(monitorURL)
251 30 Maarten Plieger
  try:
252 72 Maarten Plieger
    for elem in root.iter(tag="ProcessStarted"):
253 72 Maarten Plieger
      percentage = float(elem.attrib['percentCompleted'])
254 72 Maarten Plieger
    for elem in root.iter(tag="ProcessSucceeded"):
255 72 Maarten Plieger
      percentage = 100
256 72 Maarten Plieger
      break
257 30 Maarten Plieger
  except:
258 30 Maarten Plieger
    percentage=100.0
259 30 Maarten Plieger
    pass
260 30 Maarten Plieger
  print "Progress: "+str(percentage)+ " complete."
261 30 Maarten Plieger
  time.sleep(1)
262 30 Maarten Plieger
263 30 Maarten Plieger
# Obtain the answer  
264 30 Maarten Plieger
root = getandparsexml(monitorURL)
265 30 Maarten Plieger
try:
266 30 Maarten Plieger
  print "The answer for ["+str(inputa)+" "+str(operator)+" "+str(inputb)+"] is "+(root[2][0][2][0].text)
267 30 Maarten Plieger
except:
268 30 Maarten Plieger
  print "Processing failed: "+root[1][0][0][0][0].text
269 30 Maarten Plieger
  pass
270 30 Maarten Plieger
</code>
271 30 Maarten Plieger
</pre>
272 42 Maarten Plieger
273 42 Maarten Plieger
The result is:
274 42 Maarten Plieger
<pre>
275 42 Maarten Plieger
(pyvirtenv)c4m@climate4impact:~$ python c4i_testwps_binaryoperator.py 
276 42 Maarten Plieger
Calculating [11 divide 22]
277 42 Maarten Plieger
Process executed checking http://climate4impact.eu/impactportal/WPS?OUTPUT=/pywps-144559994232.xml
278 42 Maarten Plieger
Process started at 2015-10-23T11:32:23Z
279 42 Maarten Plieger
Progress: 20.0 complete.
280 42 Maarten Plieger
Progress: 40.0 complete.
281 42 Maarten Plieger
Progress: 60.0 complete.
282 42 Maarten Plieger
Progress: 80.0 complete.
283 47 Maarten Plieger
Progress: 100.0 complete.
284 47 Maarten Plieger
The answer for [11 divide 22] is 0.5
285 47 Maarten Plieger
(pyvirtenv)c4m@climate4impact:~$ 
286 47 Maarten Plieger
</pre>
287 52 Maarten Plieger
288 52 Maarten Plieger
h3. WPS JobList requests
289 52 Maarten Plieger
290 52 Maarten Plieger
All submitted jobs are captured and stored in a per user joblist. The joblist can be obtained via:
291 52 Maarten Plieger
292 52 Maarten Plieger
* https://dev.climate4impact.eu/impactportal/ImpactService?service=processor&request=getProcessorStatusOverview
293 52 Maarten Plieger
294 52 Maarten Plieger
A json with array called jobs is returned:
295 52 Maarten Plieger
296 52 Maarten Plieger
<pre>
297 52 Maarten Plieger
{
298 52 Maarten Plieger
  jobs:[{
299 52 Maarten Plieger
    "wpspostdata": ...,
300 52 Maarten Plieger
    "creationdate": "2016-03-30 16:57:03Z",
301 52 Maarten Plieger
    "wpsid": "clipc_combine_execute",
302 52 Maarten Plieger
    "processid": "pywps-a9840c38-f687-11e5-98b2-901b0e19e05f.xml",
303 52 Maarten Plieger
    "statuslocation": "http://bhw485.knmi.nl:8280/impactportal/WPS?OUTPUT=/pywps-a9840c38-f687-11e5-98b2-901b0e19e05f.xml",
304 52 Maarten Plieger
    "progress": "ready", // Ready indicated completed job
305 52 Maarten Plieger
    "error": false,
306 52 Maarten Plieger
    "status": "ready" // Ready, running, failed
307 52 Maarten Plieger
  },{
308 52 Maarten Plieger
    "wpspostdata":  ...,
309 52 Maarten Plieger
    "creationdate": "2016-03-30 17:01:36Z",
310 52 Maarten Plieger
    "wpsid": "wps_simple_indice",
311 52 Maarten Plieger
    "processid": "pywps-4c323e96-f688-11e5-817a-901b0e19e05f.xml",
312 52 Maarten Plieger
    "statuslocation": "http://bhw485.knmi.nl:8280/impactportal/WPS?OUTPUT=/pywps-4c323e96-f688-11e5-817a-901b0e19e05f.xml",
313 52 Maarten Plieger
    "progress": "0 %", //Percentage completed
314 52 Maarten Plieger
    "error": false,
315 52 Maarten Plieger
    "status": "running" // Ready, running, failed
316 52 Maarten Plieger
  }]
317 52 Maarten Plieger
}
318 52 Maarten Plieger
</pre>
319 53 Maarten Plieger
320 53 Maarten Plieger
A job can be removed from the list by doing:
321 53 Maarten Plieger
322 53 Maarten Plieger
* https://dev.climate4impact.eu/impactportal/ImpactService?service=processor&request=removeFromList&id=pywps-4c323e96-f688-11e5-817a-901b0e19e05f.xml
323 69 Maarten Plieger
324 69 Maarten Plieger
h2. Search API
325 69 Maarten Plieger
326 69 Maarten Plieger
https://climate4impact.eu/impactportal/esgfsearch?service=search&request=getfacets&query=project%3DCMIP5%26variable%3Dtas%26time_frequency%3Dday%26experiment%3Dhistorical%26&pagelimit=25&pagenumber=0&