windborne 1.0.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,459 @@
1
+ from .config import (FORECASTS_API_BASE_URL,
2
+ FORECASTS_GRIDDED_URL,
3
+ FORECASTS_HISTORICAL_URL,
4
+ FORECASTS_TCS_URL,
5
+ TCS_SUPPORTED_FORMATS)
6
+
7
+ from .utils import (make_api_request,
8
+ parse_time,
9
+ download_and_save_nc,
10
+ save_csv_json,
11
+ save_as_geojson,
12
+ save_as_gpx,
13
+ save_as_kml,
14
+ save_as_little_r)
15
+
16
+ # Point forecasts
17
+ def get_point_forecasts(coordinates, min_forecast_time=None, max_forecast_time=None, min_forecast_hour=None, max_forecast_hour=None, initialization_time=None, save_to_file=None):
18
+ # Sanitize coordinates by removing whitespace
19
+ coordinates = coordinates.replace(" ", "")
20
+
21
+ params = {"coordinates": coordinates}
22
+
23
+ if not coordinates:
24
+ print("To get points forecasts you must provide coordinates.")
25
+ return
26
+ if min_forecast_time:
27
+ params["min_forecast_time"] = parse_time(min_forecast_time)
28
+ if max_forecast_time:
29
+ params["max_forecast_time"] = parse_time(max_forecast_time)
30
+ if min_forecast_hour:
31
+ params["min_forecast_hour"] = int(min_forecast_hour)
32
+ if max_forecast_hour:
33
+ params["max_forecast_hour"] = int(max_forecast_hour)
34
+ if initialization_time:
35
+ initialization_time = parse_time(initialization_time,init_time_flag=True)
36
+ params["initialization_time"] = initialization_time
37
+
38
+ print("We are initiating handshake procedure with our S3 server.\n")
39
+
40
+ response = make_api_request(f"{FORECASTS_API_BASE_URL}/points", params=params)
41
+
42
+ if save_to_file:
43
+ # Save as .json
44
+ save_csv_json(save_to_file, response, csv_data_key='forecasts')
45
+
46
+ return response
47
+
48
+ # Gridded forecasts
49
+ # We return the whole response, not just the url
50
+
51
+ # 500hPa geopotential
52
+ # 850hPa geopotential
53
+ # 500hPa wind u
54
+ # 500hPa wind v
55
+ # 500hPa temperature
56
+ # 850hPa temperature
57
+ # wind_u_10m
58
+ # wind_v_10m
59
+ # pressure_msl
60
+ # temperature_2m
61
+
62
+ def get_temperature_2m(time, save_to_file=None):
63
+ params = {}
64
+
65
+ if not time:
66
+ print("To get the gridded output of global 2m temperature forecast you need to provide the time for which to get the forecast.")
67
+ return
68
+ else:
69
+ time_parsed = parse_time(time)
70
+ params["time"] = time_parsed
71
+
72
+ print("We are initiating handshake procedure with our S3 server.\n")
73
+
74
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/temperature_2m", params=params, return_type='all')
75
+
76
+ if save_to_file:
77
+ download_and_save_nc(save_to_file, response)
78
+
79
+ return response
80
+
81
+ # not implemented yet
82
+ def get_dewpoint_2m(time, save_to_file=None):
83
+ params = {}
84
+
85
+ if not time:
86
+ print("To get the gridded output of global 2m dewpoint forecast you need to provide the time for which to get the forecast.")
87
+ return
88
+ else:
89
+ time_parsed = parse_time(time)
90
+ params["time"] = time_parsed
91
+
92
+ print("We are initiating handshake procedure with our S3 server.\n")
93
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/dewpoint_2m", params=params, return_type='all')
94
+
95
+ if save_to_file:
96
+ download_and_save_nc(save_to_file, response)
97
+
98
+ return response
99
+
100
+ def get_wind_u_10m(time, save_to_file=None):
101
+ params = {}
102
+
103
+ if not time:
104
+ print("To get the gridded output of global 10m u-component of wind forecasts you need to provide the time for which to get the forecast.")
105
+ return
106
+ else:
107
+ time_parsed = parse_time(time)
108
+ params["time"] = time_parsed
109
+
110
+ print("We are initiating handshake procedure with our S3 server.\n")
111
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/wind_u_10m", params=params, return_type='all')
112
+
113
+ if save_to_file:
114
+ download_and_save_nc(save_to_file, response)
115
+
116
+ return response
117
+
118
+ def get_wind_v_10m(time, save_to_file=None):
119
+ params = {}
120
+
121
+ if not time:
122
+ print("To get the gridded output of global 10m v-component of wind forecasts you need to provide the time for which to get the forecast.")
123
+ return
124
+ else:
125
+ time_parsed = parse_time(time)
126
+ params["time"] = time_parsed
127
+
128
+ print("We are initiating handshake procedure with our S3 server.\n")
129
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/wind_v_10m", params=params, return_type='all')
130
+
131
+ if save_to_file:
132
+ download_and_save_nc(save_to_file, response)
133
+
134
+ return response
135
+
136
+ def get_500hpa_wind_u(time, save_to_file=None):
137
+ params = {}
138
+
139
+ if not time:
140
+ print("To get the gridded output of global 500hPa wind u-component of wind forecasts you need to provide the time for which to get the forecast.")
141
+ return
142
+ else:
143
+ time_parsed = parse_time(time)
144
+ params["time"] = time_parsed
145
+
146
+ print("We are initiating handshake procedure with our S3 server.\n")
147
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/500/wind_u", params=params, return_type='all')
148
+
149
+ if save_to_file:
150
+ download_and_save_nc(save_to_file, response)
151
+
152
+ return response
153
+
154
+ def get_500hpa_wind_v(time, save_to_file=None):
155
+ params = {}
156
+
157
+ if not time:
158
+ print("To get the gridded output of global 500hPa wind v-component of wind forecasts you need to provide the time for which to get the forecast.")
159
+ return
160
+ else:
161
+ time_parsed = parse_time(time)
162
+ params["time"] = time_parsed
163
+
164
+ print("We are initiating handshake procedure with our S3 server.\n")
165
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/500/wind_v", params=params, return_type='all')
166
+
167
+ if save_to_file:
168
+ download_and_save_nc(save_to_file, response)
169
+
170
+ return response
171
+
172
+ def get_500hpa_temperature(time, save_to_file=None):
173
+ params = {}
174
+
175
+ if not time:
176
+ print("To get the gridded output of global 500hPa temperature forecasts you need to provide the time for which to get the forecast.")
177
+ return
178
+ else:
179
+ time_parsed = parse_time(time)
180
+ params["time"] = time_parsed
181
+
182
+ print("We are initiating handshake procedure with our S3 server.\n")
183
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/500/temperature", params=params, return_type='all')
184
+
185
+ if save_to_file:
186
+ download_and_save_nc(save_to_file, response)
187
+
188
+ return response
189
+
190
+ def get_850hpa_temperature(time, save_to_file=None):
191
+ params = {}
192
+
193
+ if not time:
194
+ print("To get the gridded output of global 850hPa temperature forecasts you need to provide the time for which to get the forecast.")
195
+ return
196
+ else:
197
+ time_parsed = parse_time(time)
198
+ params["time"] = time_parsed
199
+
200
+ print("We are initiating handshake procedure with our S3 server.\n")
201
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/850/temperature", params=params, return_type='all')
202
+
203
+ if save_to_file:
204
+ download_and_save_nc(save_to_file, response)
205
+
206
+ return response
207
+
208
+ def get_pressure_msl(time, save_to_file=None):
209
+ params = {}
210
+
211
+ if not time:
212
+ print("To get the gridded output of global mean sea level pressure forecasts you need to provide the time for which to get the forecast.")
213
+ return
214
+ else:
215
+ time_parsed = parse_time(time)
216
+ params["time"] = time_parsed
217
+
218
+ print("We are initiating handshake procedure with our S3 server.\n")
219
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/pressure_msl", params=params, return_type='all')
220
+
221
+ if save_to_file:
222
+ download_and_save_nc(save_to_file, response)
223
+
224
+ return response
225
+
226
+ def get_500hpa_geopotential(time, save_to_file=None):
227
+ params = {}
228
+
229
+ if not time:
230
+ print("To get the gridded output of global 500hPa geopotential forecasts you need to provide the time for which to get the forecast.")
231
+ return
232
+ else:
233
+ time_parsed = parse_time(time)
234
+ params["time"] = time_parsed
235
+
236
+ print("We are initiating handshake procedure with our S3 server.\n")
237
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/500/geopotential", params=params, return_type='all')
238
+
239
+ if save_to_file:
240
+ download_and_save_nc(save_to_file, response)
241
+
242
+ return response
243
+
244
+ def get_850hpa_geopotential(time, save_to_file=None):
245
+ params = {}
246
+
247
+ if not time:
248
+ print("To get the gridded output of global 850hPa geopotential forecasts you need to provide the time for which to get the forecast.")
249
+ return
250
+ else:
251
+ time_parsed = parse_time(time)
252
+ params["time"] = time_parsed
253
+
254
+ print("We are initiating handshake procedure with our S3 server.\n")
255
+ response = make_api_request(f"{FORECASTS_GRIDDED_URL}/850/geopotential", params=params, return_type='all')
256
+
257
+ if save_to_file:
258
+ download_and_save_nc(save_to_file, response)
259
+
260
+ return response
261
+
262
+ # Historical forecasts
263
+ # We return the whole response, not just the url
264
+
265
+ def get_historical_temperature_2m(initialization_time, forecast_hour, save_to_file=None):
266
+ params = {}
267
+
268
+ if not initialization_time or not forecast_hour:
269
+ print("To get the historical output of global temperature forecasts you need to provide:\n"
270
+ "- the initialization time of the forecast\n"
271
+ "- how many hours after the run time the forecast is valid at.\n")
272
+ return
273
+ else:
274
+ time_parsed = parse_time(initialization_time, init_time_flag=True)
275
+ params["initialization_time"] = time_parsed
276
+ params["forecast_hour"] = forecast_hour
277
+
278
+ print("We are initiating handshake procedure with our S3 server.\n")
279
+
280
+ response = make_api_request(f"{FORECASTS_HISTORICAL_URL}/temperature_2m", params=params, return_type='all')
281
+
282
+ if save_to_file:
283
+ download_and_save_nc(save_to_file, response)
284
+
285
+ return response
286
+
287
+ def get_historical_500hpa_geopotential(initialization_time, forecast_hour, save_to_file=None):
288
+ params = {}
289
+
290
+ if not initialization_time or not forecast_hour:
291
+ print("To get the historical output of global 500hPa geopotential forecasts you need to provide:\n"
292
+ "- the initialization time of the forecast\n"
293
+ "- how many hours after the run time the forecast is valid at.\n")
294
+ return
295
+ else:
296
+ time_parsed = parse_time(initialization_time,init_time_flag=True)
297
+ params["initialization_time"] = time_parsed
298
+ params["forecast_hour"] = forecast_hour
299
+
300
+ print("We are initiating handshake procedure with our S3 server.\n")
301
+
302
+ response = make_api_request(f"{FORECASTS_HISTORICAL_URL}/500/geopotential", params=params, return_type='all')
303
+
304
+ if save_to_file:
305
+ download_and_save_nc(save_to_file, response)
306
+
307
+ return response
308
+
309
+ def get_historical_500hpa_wind_u(initialization_time, forecast_hour, save_to_file=None):
310
+ params = {}
311
+
312
+ if not initialization_time or not forecast_hour:
313
+ print("To get the historical output of global 500hPa wind u forecasts you need to provide:\n"
314
+ "- the initialization time of the forecast\n"
315
+ "- how many hours after the run time the forecast is valid at.\n")
316
+ return
317
+ else:
318
+ time_parsed = parse_time(initialization_time,init_time_flag=True)
319
+ params["initialization_time"] = time_parsed
320
+ params["forecast_hour"] = forecast_hour
321
+
322
+ print("We are initiating handshake procedure with our S3 server.\n")
323
+
324
+ response = make_api_request(f"{FORECASTS_HISTORICAL_URL}/500/wind_u", params=params, return_type='all')
325
+
326
+ if save_to_file:
327
+ download_and_save_nc(save_to_file, response)
328
+
329
+ return response
330
+
331
+ def get_historical_500hpa_wind_v(initialization_time, forecast_hour, save_to_file=None):
332
+ params = {}
333
+
334
+ if not initialization_time or not forecast_hour:
335
+ print("To get the historical output of global 500hPa wind v forecasts you need to provide:\n"
336
+ "- the initialization time of the forecast\n"
337
+ "- how many hours after the run time the forecast is valid at.\n")
338
+ return
339
+ else:
340
+ time_parsed = parse_time(initialization_time, init_time_flag=True)
341
+ params["initialization_time"] = time_parsed
342
+ params["forecast_hour"] = forecast_hour
343
+
344
+ print("We are initiating handshake procedure with our S3 server.\n")
345
+
346
+ response = make_api_request(f"{FORECASTS_HISTORICAL_URL}/500/wind_v", params=params, return_type='all')
347
+
348
+ if save_to_file:
349
+ download_and_save_nc(save_to_file, response)
350
+
351
+ return response
352
+
353
+ # Other
354
+ # TCs
355
+ def get_tropical_cyclones(initialization_time=None, basin=None, save_to_file=None):
356
+ """
357
+ Get tropical cyclone data from the API.
358
+
359
+ Args:
360
+ initialization_time (str): Date in either ISO 8601 format (YYYY-MM-DDTHH:00:00)
361
+ or compact format (YYYYMMDDHH)
362
+ where HH must be 00, 06, 12, or 18
363
+ save_to_file (str, optional): Path to save the response data
364
+ Supported formats: .json, .csv, .gpx, .geojson, .kml, .little_r
365
+
366
+ Returns:
367
+ dict: API response data or None if there's an error
368
+ """
369
+ params = {}
370
+
371
+ if initialization_time:
372
+ initialization_time_parsed = parse_time(initialization_time, init_time_flag=True)
373
+ params["initialization_time"] = initialization_time_parsed
374
+ else:
375
+ # Madee this for our displaying message when no active tcs found
376
+ initialization_time = 'latest'
377
+
378
+ if basin:
379
+ if basin not in ['NA', 'EP', 'WP', 'NI', 'SI', 'AU', 'SP']:
380
+ print("Basin should be one of the following:")
381
+ print("NA - North Atlantic")
382
+ print("EP - Eastern Pacific")
383
+ print("WP - Western Pacific")
384
+ print("NI - North Indian")
385
+ print("SI - South West Indian")
386
+ print("AU - Australian Region")
387
+ print("SP - South Pacific")
388
+ exit(44)
389
+ params["basin"] = basin
390
+
391
+ # Response here is a .json
392
+ response = make_api_request(FORECASTS_TCS_URL, params=params)
393
+
394
+ if save_to_file:
395
+ if '.' not in save_to_file:
396
+ print("You have to provide a filetype for your output file.")
397
+ print_tc_supported_formats()
398
+ exit (4)
399
+ elif not save_to_file.lower().endswith(TCS_SUPPORTED_FORMATS):
400
+ print("Unsupported file format.")
401
+ print_tc_supported_formats()
402
+ exit(44)
403
+ elif response == {}:
404
+ # This should be prior to any check of specific .filetype format check and post filetype valid check
405
+ # make_api_request covers 403, 404, 502, HTTP, Connections Errors
406
+ # If we pass all of these and we get an empty dictionary ==> there are no active TCs
407
+ print("There are no active tropical cyclones for your request\n")
408
+ print("We didn't save any file on your machine.")
409
+ # It's pointless to save an empty file
410
+ # save_response_to_file() will throw error on saving {}
411
+ elif response is None:
412
+ print("-------------------------------------------------------")
413
+ print("You are too quick!\nThe tropical cyclone data for initialization time are not uploaded yet.")
414
+ print('You may check again in a few hours again.')
415
+ elif save_to_file.lower().endswith('.csv'):
416
+ # Flatten for CSV
417
+ flattened_data = []
418
+ for cyclone_id, tracks in response.items():
419
+ for track in tracks:
420
+ track_data = {
421
+ 'cyclone_id': cyclone_id,
422
+ 'latitude': track['latitude'],
423
+ 'longitude': track['longitude'],
424
+ 'time': track['time']
425
+ }
426
+ flattened_data.append(track_data)
427
+ save_csv_json(save_to_file, {'prediction': flattened_data}, csv_data_key='prediction')
428
+ elif save_to_file.lower().endswith('.json'):
429
+ # Direct save for JSON
430
+ save_csv_json(save_to_file, response)
431
+ elif save_to_file.lower().endswith('.geojson'):
432
+ save_as_geojson(save_to_file, response)
433
+ elif save_to_file.lower().endswith('.gpx'):
434
+ save_as_gpx(save_to_file, response)
435
+ elif save_to_file.lower().endswith('.kml'):
436
+ save_as_kml(save_to_file, response)
437
+ elif save_to_file.lower().endswith('.little_r'):
438
+ save_as_little_r(save_to_file, response)
439
+
440
+ return response
441
+
442
+ def get_initialization_times():
443
+ """
444
+ Get available initialization times for pointy.
445
+ Returns:
446
+ dict: API response data or None if there's an error
447
+ """
448
+
449
+ # Response here is a .json
450
+ response = make_api_request(f"{FORECASTS_API_BASE_URL}/initialization_times.json")
451
+
452
+ return response
453
+
454
+ # Tropical cyclones
455
+ def print_tc_supported_formats():
456
+ """Print supported file formats for saving tcs data."""
457
+ print("Supported formats:")
458
+ for fmt in TCS_SUPPORTED_FORMATS:
459
+ print(f" - {fmt}")