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.
windborne/__init__.py ADDED
@@ -0,0 +1,76 @@
1
+ # Import key functions and classes for easier access when users import the package
2
+
3
+ # Import Utils functions
4
+ from .utils import (
5
+ convert_to_netcdf,
6
+ sync_to_s3
7
+ )
8
+
9
+ # Import Data API functions
10
+ from .data_api import (
11
+ get_observations,
12
+ get_super_observations,
13
+
14
+ poll_super_observations,
15
+ poll_observations,
16
+
17
+ get_flying_missions,
18
+ get_mission_launch_site,
19
+ get_predicted_path,
20
+ )
21
+
22
+ # Import Forecasts API functions
23
+ from .forecasts_api import (
24
+ get_point_forecasts,
25
+ get_initialization_times,
26
+
27
+ get_temperature_2m,
28
+ get_dewpoint_2m,
29
+ get_wind_u_10m, get_wind_v_10m,
30
+ get_pressure_msl,
31
+ get_500hpa_wind_u, get_500hpa_wind_v,
32
+ get_500hpa_geopotential, get_850hpa_geopotential,
33
+ get_500hpa_temperature, get_850hpa_temperature,
34
+
35
+ get_historical_temperature_2m,
36
+ get_historical_500hpa_geopotential,
37
+ get_historical_500hpa_wind_u, get_historical_500hpa_wind_v,
38
+
39
+ get_tropical_cyclones
40
+ )
41
+
42
+ # Define what should be available when users import *
43
+ __all__ = [
44
+ "convert_to_netcdf",
45
+ "sync_to_s3",
46
+
47
+ "get_observations",
48
+ "get_super_observations",
49
+ "poll_super_observations",
50
+ "poll_observations",
51
+
52
+ "get_flying_missions",
53
+ "get_mission_launch_site",
54
+ "get_predicted_path",
55
+
56
+ "get_point_forecasts",
57
+ "get_initialization_times",
58
+
59
+ "get_temperature_2m",
60
+ "get_dewpoint_2m",
61
+ "get_wind_u_10m",
62
+ "get_wind_v_10m",
63
+ "get_500hpa_wind_u",
64
+ "get_500hpa_wind_v",
65
+ "get_pressure_msl",
66
+ "get_500hpa_geopotential",
67
+ "get_850hpa_geopotential",
68
+ "get_500hpa_temperature",
69
+ "get_850hpa_temperature",
70
+
71
+ "get_historical_temperature_2m",
72
+ "get_historical_500hpa_geopotential",
73
+ "get_historical_500hpa_wind_u",
74
+ "get_historical_500hpa_wind_v",
75
+ "get_tropical_cyclones"
76
+ ]
windborne/cli.py ADDED
@@ -0,0 +1,544 @@
1
+ import argparse
2
+
3
+ from . import (
4
+ poll_super_observations,
5
+ poll_observations,
6
+ get_observations,
7
+ get_super_observations,
8
+ get_flying_missions,
9
+ get_mission_launch_site,
10
+ get_predicted_path,
11
+
12
+ get_point_forecasts,
13
+ get_initialization_times,
14
+ get_temperature_2m,
15
+ get_dewpoint_2m,
16
+ get_wind_u_10m, get_wind_v_10m,
17
+ get_500hpa_wind_u, get_500hpa_wind_v,
18
+ get_500hpa_temperature, get_850hpa_temperature,
19
+ get_pressure_msl,
20
+ get_500hpa_geopotential, get_850hpa_geopotential,
21
+
22
+ get_historical_temperature_2m,
23
+ get_historical_500hpa_geopotential,
24
+ get_historical_500hpa_wind_u, get_historical_500hpa_wind_v,
25
+ get_tropical_cyclones
26
+
27
+ )
28
+
29
+ from pprint import pprint
30
+
31
+ def main():
32
+ parser = argparse.ArgumentParser(description='WindBorne API Command Line Interface')
33
+ subparsers = parser.add_subparsers(dest='command', help='Available commands')
34
+
35
+ ####################################################################################################################
36
+ # DATA API FUNCTIONS
37
+ ####################################################################################################################
38
+ # Poll Super Observations Command
39
+ poll_super_parser = subparsers.add_parser('poll-super-observations', help='Poll super observations within a time range')
40
+ poll_super_parser.add_argument('start_time', help='Starting time (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
41
+ poll_super_parser.add_argument('end_time', help='End time (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)', nargs='?', default=None)
42
+ poll_super_parser.add_argument('-i', '--interval', type=int, default=60, help='Polling interval in seconds')
43
+ poll_super_parser.add_argument('-b', '--bucket-hours', type=float, default=6.0, help='Hours per bucket')
44
+ poll_super_parser.add_argument('output', help='Save output to a single file (filename.csv, filename.json or filename.little_r) or to multiple files (csv or little_r)')
45
+
46
+ # Poll Observations Command
47
+ poll_parser = subparsers.add_parser('poll-observations', help='Poll observations within a time range')
48
+ poll_parser.add_argument('start_time', help='Starting time (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
49
+ poll_parser.add_argument('end_time', help='End time (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)', nargs='?', default=None)
50
+ poll_parser.add_argument('-m', '--mission-id', help='Filter observations by mission ID')
51
+ poll_parser.add_argument('-ml', '--min-latitude', type=float, help='Minimum latitude filter')
52
+ poll_parser.add_argument('-xl', '--max-latitude', type=float, help='Maximum latitude filter')
53
+ poll_parser.add_argument('-mg', '--min-longitude', type=float, help='Minimum longitude filter')
54
+ poll_parser.add_argument('-xg', '--max-longitude', type=float, help='Maximum longitude filter')
55
+ poll_parser.add_argument('-id', '--include-ids', action='store_true', help='Include observation IDs')
56
+ poll_parser.add_argument('-u', '--include-updated-at', action='store_true', help='Include update timestamps')
57
+ poll_parser.add_argument('-i', '--interval', type=int, default=60, help='Polling interval in seconds')
58
+ poll_parser.add_argument('-b', '--bucket-hours', type=float, default=6.0, help='Hours per bucket')
59
+ poll_parser.add_argument('output', help='Save output to a single file (filename.csv, filename.json or filename.little_r) or to multiple files (csv or little_r)')
60
+
61
+
62
+ # Get Observations Command
63
+ obs_parser = subparsers.add_parser('observations', help='Get observations with filters')
64
+ obs_parser.add_argument('since', help='Get observations since this time (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
65
+ obs_parser.add_argument('-mt', '--min-time', help='Minimum time filter (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
66
+ obs_parser.add_argument('-xt', '--max-time', help='Maximum time filter (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
67
+ obs_parser.add_argument('-m', '--mission-id', help='Filter by mission ID')
68
+ obs_parser.add_argument('-ml', '--min-latitude', type=float, help='Minimum latitude filter')
69
+ obs_parser.add_argument('-xl', '--max-latitude', type=float, help='Maximum latitude filter')
70
+ obs_parser.add_argument('-mg', '--min-longitude', type=float, help='Minimum longitude filter')
71
+ obs_parser.add_argument('-xg', '--max-longitude', type=float, help='Maximum longitude filter')
72
+ obs_parser.add_argument('-id', '--include-ids', action='store_true', help='Include observation IDs')
73
+ obs_parser.add_argument('-mn', '--include-mission-name', action='store_true', help='Include mission names')
74
+ obs_parser.add_argument('-u', '--include-updated-at', action='store_true', help='Include update timestamps')
75
+ obs_parser.add_argument('output', nargs='?', help='Output file')
76
+
77
+ # Get Super Observations Command
78
+ super_obs_parser = subparsers.add_parser('super-observations', help='Get super observations with filters')
79
+ super_obs_parser.add_argument('since', help='Get super observations since this time (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
80
+ super_obs_parser.add_argument('-mt', '--min-time', help='Minimum time filter (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
81
+ super_obs_parser.add_argument('-xt', '--max-time', help='Maximum time filter (YYYY-MM-DD_HH:MM, "YYYY-MM-DD HH:MM:SS" or YYYY-MM-DDTHH:MM:SS.fffZ)')
82
+ super_obs_parser.add_argument('-m', '--mission-id', help='Filter by mission ID')
83
+ super_obs_parser.add_argument('-id', '--include-ids', action='store_true', help='Include observation IDs')
84
+ super_obs_parser.add_argument('-mn', '--include-mission-name', action='store_true', help='Include mission names')
85
+ super_obs_parser.add_argument('-u', '--include-updated-at', action='store_true', help='Include update timestamps')
86
+ super_obs_parser.add_argument('output', nargs='?', help='Output file')
87
+
88
+ # Get Flying Missions Command
89
+ flying_parser = subparsers.add_parser('flying-missions', help='Get currently flying missions')
90
+ flying_parser.add_argument('output', nargs='?', help='Output file')
91
+
92
+ # Get Mission Launch Site Command
93
+ launch_site_parser = subparsers.add_parser('launch-site', help='Get mission launch site')
94
+ launch_site_parser.add_argument('mission_id', help='Mission ID')
95
+ launch_site_parser.add_argument('output', nargs='?', help='Output file')
96
+
97
+ # Get Predicted Path Command
98
+ prediction_parser = subparsers.add_parser('predict-path', help='Get predicted flight path')
99
+ prediction_parser.add_argument('mission_id', help='Mission ID')
100
+ prediction_parser.add_argument('output', nargs='?', help='Output file')
101
+
102
+ ####################################################################################################################
103
+ # FORECASTS API FUNCTIONS
104
+ ####################################################################################################################
105
+ # Points Forecast Command
106
+ # We have quite a few quite a few optional query parameters here
107
+ # so we set coordinates and output_file to required instead of
108
+ # setting all args into a parser arg (add_argument('args', nargs='*', ...)
109
+ points_parser = subparsers.add_parser('points', help='Get the forecast at a given point or set of points')
110
+ points_parser.add_argument('coordinates', help='Coordinate pairs in format "latitudeA,longitudeA; latitudeB,longitudeB"')
111
+ points_parser.add_argument('-mt','--min-time', help='Minimum forecast time')
112
+ points_parser.add_argument('-xt','--max-time', help='Maximum forecast time')
113
+ points_parser.add_argument('-mh','--min-hour', type=int, help='Minimum forecast hour')
114
+ points_parser.add_argument('-xh','--max-hour', type=int, help='Maximum forecast hour')
115
+ points_parser.add_argument('-i', '--init-time', help='Initialization time')
116
+ points_parser.add_argument('output_file', help='Output file')
117
+
118
+ # GRIDDED FORECASTS
119
+ ####################################################################################################################
120
+ # Gridded 2m temperature Command
121
+ gridded_temperature_2m_parser = subparsers.add_parser('grid_temp_2m', help='Get gridded output of global 2m temperature forecasts')
122
+ gridded_temperature_2m_parser.add_argument('args', nargs='*', help='time output_file')
123
+
124
+ # Gridded 2m dewpoint Command
125
+ gridded_dewpoint_2m_parser = subparsers.add_parser('grid_dewpoint_2m', help='Get gridded output of global dewpoint forecasts')
126
+ gridded_dewpoint_2m_parser.add_argument('args', nargs='*', help='time output_file')
127
+
128
+ # Gridded wind-u 10m Command
129
+ gridded_wind_u_10m_parser = subparsers.add_parser('grid_wind_u_10m', help='Get gridded output of global 10m u-component of wind forecasts')
130
+ gridded_wind_u_10m_parser.add_argument('args', nargs='*', help='time output_file')
131
+
132
+ # Gridded wind-v 10m Command
133
+ gridded_wind_v_10m_parser = subparsers.add_parser('grid_wind_v_10m', help='Get gridded output of global 10m v-component of wind forecasts')
134
+ gridded_wind_v_10m_parser.add_argument('args', nargs='*', help='time output_file')
135
+
136
+ # Gridded 500hPa wind-u Command
137
+ gridded_500hpa_wind_u_parser = subparsers.add_parser('grid_500hpa_wind_u', help='Get gridded output of global 500hPa wind v-component of wind forecasts')
138
+ gridded_500hpa_wind_u_parser.add_argument('args', nargs='*', help='time output_file')
139
+
140
+ # Gridded 500hPa wind-v Command
141
+ gridded_500hpa_wind_v_parser = subparsers.add_parser('grid_500hpa_wind_v', help='Get gridded output of global 500hPa wind u-component of wind forecasts')
142
+ gridded_500hpa_wind_v_parser.add_argument('args', nargs='*', help='time output_file')
143
+
144
+ # Gridded 500hPa temperature Command
145
+ gridded_500hpa_temperature_parser = subparsers.add_parser('grid_500hpa_temperature', help='Get gridded output of global 500hPa temperature forecasts')
146
+ gridded_500hpa_temperature_parser.add_argument('args', nargs='*', help='time output_file')
147
+
148
+ # Gridded 850hPa temperature Command
149
+ gridded_850hpa_temperature_parser = subparsers.add_parser('grid_850hpa_temperature', help='Get gridded output of global 850hPa temperature forecasts')
150
+ gridded_850hpa_temperature_parser.add_argument('args', nargs='*', help='time output_file')
151
+
152
+ # Gridded mean sea level pressure Command
153
+ gridded_pressure_msl_parser = subparsers.add_parser('grid_pressure_msl', help='Get gridded output of global mean sea level pressure forecasts')
154
+ gridded_pressure_msl_parser.add_argument('args', nargs='*', help='time output_file')
155
+
156
+ # Gridded 500hPa geopotential Command
157
+ gridded_500hpa_geopotential_parser = subparsers.add_parser('grid_500hpa_geopotential', help='Get gridded output of global 500hPa geopotential forecasts')
158
+ gridded_500hpa_geopotential_parser.add_argument('args', nargs='*', help='time output_file')
159
+
160
+ # Gridded 850hPa geopotential Command
161
+ gridded_850hpa_geopotential_parser = subparsers.add_parser('grid_850hpa_geopotential', help='Get gridded output of global 500hPa geopotential forecasts')
162
+ gridded_850hpa_geopotential_parser.add_argument('args', nargs='*', help='time output_file')
163
+
164
+ # HISTORICAL FORECASTS
165
+ ####################################################################################################################
166
+ # Historical 500hpa geopotential Command
167
+ historical_temperature_2m_parser = subparsers.add_parser('hist_temp_2m', help='Get historical output of global temperature forecasts')
168
+ historical_temperature_2m_parser.add_argument('args', nargs='*', help='initialization_time forecast_hour output_file')
169
+
170
+ # Historical 500hpa geopotential Command
171
+ historical_500hpa_geopotential_parser = subparsers.add_parser('hist_500hpa_geopotential', help='Get historical output of global 500hPa geopotential forecasts')
172
+ historical_500hpa_geopotential_parser.add_argument('args', nargs='*', help='initialization_time forecast_hour output_file')
173
+
174
+ # Historical 500hpa wind u Command
175
+ historical_500hpa_wind_u_parser = subparsers.add_parser('hist_500hpa_wind_u', help='Get historical output of global 500hPa wind u forecasts')
176
+ historical_500hpa_wind_u_parser.add_argument('args', nargs='*', help='initialization_time forecast_hour output_file')
177
+
178
+ # Historical 500hpa wind v Command
179
+ historical_500hpa_wind_v_parser = subparsers.add_parser('hist_500hpa_wind_v', help='Get historical output of global 500hPa wind v forecasts')
180
+ historical_500hpa_wind_v_parser.add_argument('args', nargs='*', help='initialization_time forecast_hour output_file')
181
+
182
+ # OTHER
183
+ # TCS
184
+ ####################################################################################################################
185
+
186
+ # Tropical Cyclones Command
187
+ cyclones_parser = subparsers.add_parser('cyclones', help='Get tropical cyclone forecasts')
188
+ cyclones_parser.add_argument('-b', '--basin', help='Optional: filter tropical cyclones on basin[ NA, EP, WP, NI, SI, AU, SP]')
189
+ cyclones_parser.add_argument('args', nargs='*',
190
+ help='[optional: initialization time (YYYYMMDDHH, YYYY-MM-DDTHH, or YYYY-MM-DDTHH:mm:ss)] output_file')
191
+
192
+ # Initialization Times Command
193
+ initialization_times_parser = subparsers.add_parser('init_times', help='Get available initialization times for point forecasts')
194
+
195
+
196
+ args = parser.parse_args()
197
+
198
+ ####################################################################################################################
199
+ # DATA API FUNCTIONS CALLED
200
+ ####################################################################################################################
201
+ if args.command == 'poll-super-observations':
202
+ # Error handling is performed within poll_super_observations
203
+ # and we display the appropriate error messages
204
+ # No need to implement them here
205
+
206
+ # In case user wants to save all poll observation data in a single file | filename.format
207
+ if '.' in args.output:
208
+ save_to_file = args.output
209
+ output_format = None
210
+ # In case user wants separate file for each data from missions (buckets)
211
+ else:
212
+ save_to_file = None
213
+ output_format = args.output
214
+
215
+ poll_super_observations(
216
+ start_time=args.start_time,
217
+ end_time=args.end_time,
218
+ interval=args.interval,
219
+ save_to_file=save_to_file,
220
+ bucket_hours=args.bucket_hours,
221
+ output_format=output_format
222
+ )
223
+
224
+ elif args.command == 'poll-observations':
225
+ # Error handling is performed within poll_observations
226
+ # and we display the appropriate error messages
227
+ # No need to implement them here
228
+
229
+ # In case user wants to save all poll observation data in a single file | filename.format
230
+ if '.' in args.output:
231
+ save_to_file = args.output
232
+ output_format = None
233
+ # In case user wants separate file for each data from missions (buckets)
234
+ else:
235
+ save_to_file = None
236
+ output_format = args.output
237
+
238
+ poll_observations(
239
+ start_time=args.start_time,
240
+ end_time=args.end_time,
241
+ include_ids=args.include_ids,
242
+ include_updated_at=args.include_updated_at,
243
+ mission_id=args.mission_id,
244
+ min_latitude=args.min_latitude,
245
+ max_latitude=args.max_latitude,
246
+ min_longitude=args.min_longitude,
247
+ max_longitude=args.max_longitude,
248
+ interval=args.interval,
249
+ save_to_file=save_to_file,
250
+ bucket_hours=args.bucket_hours,
251
+ output_format=output_format
252
+ )
253
+
254
+ elif args.command == 'observations':
255
+ get_observations(
256
+ since=args.since,
257
+ min_time=args.min_time,
258
+ max_time=args.max_time,
259
+ include_ids=args.include_ids,
260
+ include_mission_name=args.include_mission_name,
261
+ include_updated_at=args.include_updated_at,
262
+ mission_id=args.mission_id,
263
+ min_latitude=args.min_latitude,
264
+ max_latitude=args.max_latitude,
265
+ min_longitude=args.min_longitude,
266
+ max_longitude=args.max_longitude,
267
+ save_to_file=args.output
268
+ )
269
+
270
+ elif args.command == 'super-observations':
271
+ get_super_observations(
272
+ since=args.since,
273
+ min_time=args.min_time,
274
+ max_time=args.max_time,
275
+ include_ids=args.include_ids,
276
+ include_mission_name=args.include_mission_name,
277
+ include_updated_at=args.include_updated_at,
278
+ mission_id=args.mission_id,
279
+ save_to_file=args.output
280
+ )
281
+
282
+ elif args.command == 'flying-missions':
283
+ get_flying_missions(cli=True, save_to_file=args.output)
284
+
285
+ elif args.command == 'launch-site':
286
+ get_mission_launch_site(
287
+ mission_id=args.mission_id,
288
+ save_to_file=args.output
289
+ )
290
+
291
+ elif args.command == 'predict-path':
292
+ get_predicted_path(
293
+ mission_id=args.mission_id,
294
+ save_to_file=args.output
295
+ )
296
+ ####################################################################################################################
297
+ # FORECASTS API FUNCTIONS CALLED
298
+ ####################################################################################################################
299
+ elif args.command == 'points':
300
+ min_forecast_time = args.min_time if args.min_time else None
301
+ max_forecast_time = args.max_time if args.max_time else None
302
+ min_forecast_hour = args.min_hour if args.min_hour else None
303
+ max_forecast_hour = args.max_hour if args.max_hour else None
304
+ initialization_time = args.init_time if args.init_time else None
305
+
306
+ get_point_forecasts(
307
+ coordinates=args.coordinates,
308
+ min_forecast_time=min_forecast_time,
309
+ max_forecast_time=max_forecast_time,
310
+ min_forecast_hour=min_forecast_hour,
311
+ max_forecast_hour=max_forecast_hour,
312
+ initialization_time=initialization_time,
313
+ save_to_file=args.output_file
314
+ )
315
+
316
+ elif args.command == 'init_times':
317
+ if get_initialization_times():
318
+ print("Available initialization times for point forecasts:\n")
319
+ pprint(get_initialization_times())
320
+ else:
321
+ print("We can't currently display available initialization times for point forecasts:\n")
322
+
323
+ elif args.command == 'grid_temp_2m':
324
+ # Parse grid_temp_2m arguments
325
+ if len(args.args) in [0,1]:
326
+ print("To get the gridded output of global 2m temperature forecast you need to provide the time for which to get the forecast and an output file.")
327
+ print("\nUsage: windborne grid_temp_2m time output_file")
328
+ elif len(args.args) == 2:
329
+ get_temperature_2m(time=args.args[0], save_to_file=args.args[1])
330
+ else:
331
+ print("Too many arguments")
332
+ print("\nUsage: windborne grid_temp_2m time output_file")
333
+
334
+ elif args.command == 'grid_dewpoint_2m':
335
+ # Parse grid_dewpoint_2m arguments
336
+ if len(args.args) in [0,1]:
337
+ print(f"To get the gridded output of global 2m dew point forecast you need to provide the time for which to get the forecast and an output file.")
338
+ print("\nUsage: windborne grid_dewpoint_2m time output_file")
339
+ elif len(args.args) == 2:
340
+ get_dewpoint_2m(time=args.args[0], save_to_file=args.args[1])
341
+ else:
342
+ print("Too many arguments")
343
+ print("\nUsage: windborne grid_dewpoint_2m time output_file")
344
+
345
+ elif args.command == 'grid_wind_u_10m':
346
+ # Parse grid_wind_u_10m arguments
347
+ if len(args.args) in [0,1]:
348
+ print(f"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 and an output file.")
349
+ print("\nUsage: windborne grid_wind_u_10m time output_file")
350
+ elif len(args.args) == 2:
351
+ get_wind_u_10m(time=args.args[0], save_to_file=args.args[1])
352
+ else:
353
+ print("Too many arguments")
354
+ print("\nUsage: windborne grid_wind_u_10m time output_file")
355
+
356
+ elif args.command == 'grid_wind_v_10m':
357
+ # Parse grid_wind_v_10m arguments
358
+ if len(args.args) in [0,1]:
359
+ print(f"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 and an output file.")
360
+ print("\nUsage: windborne grid_wind_v_10m time output_file")
361
+ elif len(args.args) == 2:
362
+ get_wind_v_10m(time=args.args[0], save_to_file=args.args[1])
363
+ else:
364
+ print("Too many arguments")
365
+ print("\nUsage: windborne grid_wind_v_10m time output_file")
366
+
367
+ elif args.command == 'grid_500hpa_wind_u':
368
+ # Parse grid_500hpa_wind_u arguments
369
+ if len(args.args) in [0,1]:
370
+ print(f"To get the gridded output of global 500hPa u-component of wind forecasts you need to provide the time for which to get the forecast and an output file.")
371
+ print("\nUsage: windborne grid_500hpa_wind_u time output_file")
372
+ elif len(args.args) == 2:
373
+ get_500hpa_wind_u(time=args.args[0], save_to_file=args.args[1])
374
+ else:
375
+ print("Too many arguments")
376
+ print("\nUsage: windborne grid_500hpa_wind_u time output_file")
377
+
378
+ elif args.command == 'grid_500hpa_wind_v':
379
+ # Parse grid_500hpa_wind_v arguments
380
+ if len(args.args) in [0,1]:
381
+ print(f"To get the gridded output of global 500hPa v-component of wind forecasts you need to provide the time for which to get the forecast and an output file.")
382
+ print("\nUsage: windborne grid_500hpa_wind_v time output_file")
383
+ elif len(args.args) == 2:
384
+ get_500hpa_wind_v(time=args.args[0], save_to_file=args.args[1])
385
+ else:
386
+ print("Too many arguments")
387
+ print("\nUsage: windborne grid_500hpa_wind_v time output_file")
388
+
389
+ elif args.command == 'grid_500hpa_temperature':
390
+ # Parse grid_500hpa_temperature arguments
391
+ if len(args.args) in [0,1]:
392
+ print(f"To get the gridded output of global 500hPa temperature forecasts you need to provide the time for which to get the forecast and an output file.")
393
+ print("\nUsage: windborne grid_500hpa_temperature time output_file")
394
+ return
395
+ elif len(args.args) == 2:
396
+ get_500hpa_temperature(time=args.args[0], save_to_file=args.args[1])
397
+ else:
398
+ print("Too many arguments")
399
+ print("\nUsage: windborne grid_500hpa_temperature time output_file")
400
+
401
+ elif args.command == 'grid_850hpa_temperature':
402
+ # Parse grid_850hpa_temperature arguments
403
+ if len(args.args) in [0,1]:
404
+ print(f"To get the gridded output of global 850hPa temperature forecasts you need to provide the time for which to get the forecast and an output file.")
405
+ print("\nUsage: windborne grid_850hpa_temperature time output_file")
406
+ return
407
+ elif len(args.args) == 2:
408
+ get_850hpa_temperature(time=args.args[0], save_to_file=args.args[1])
409
+ else:
410
+ print("Too many arguments")
411
+ print("\nUsage: windborne grid_850hpa_temperature time output_file")
412
+
413
+ elif args.command == 'grid_pressure_msl':
414
+ # Parse grid_pressure_msl arguments
415
+ if len(args.args) in [0,1]:
416
+ print(f"To get the gridded output of global mean sea level pressure forecasts you need to provide the time for which to get the forecast and an output file.")
417
+ print("\nUsage: windborne grid_pressure_msl time output_file")
418
+ elif len(args.args) == 2:
419
+ get_pressure_msl(time=args.args[0], save_to_file=args.args[1])
420
+ else:
421
+ print("Too many arguments")
422
+ print("\nUsage: windborne grid_pressure_msl time output_file")
423
+
424
+ elif args.command == 'grid_500hpa_geopotential':
425
+ # Parse grid_500hpa_geopotential arguments
426
+ if len(args.args) in [0,1]:
427
+ print(f"To get the gridded output of global 500hPa geopotential forecasts you need to provide the time for which to get the forecast and an output file.")
428
+ print("\nUsage: windborne grid_500hpa_geopotential time output_file")
429
+ return
430
+ elif len(args.args) == 2:
431
+ get_500hpa_geopotential(time=args.args[0], save_to_file=args.args[1])
432
+ else:
433
+ print("Too many arguments")
434
+ print("\nUsage: windborne grid_500hpa_geopotential time output_file")
435
+
436
+ elif args.command == 'grid_850hpa_geopotential':
437
+ # Parse grid_850hpa_geopotential arguments
438
+ if len(args.args) in [0,1]:
439
+ print(f"To get the gridded output of global 850hPa geopotential forecasts you need to provide the time for which to get the forecast and an output file.")
440
+ print("\nUsage: windborne grid_850hpa_geopotential time output_file")
441
+ return
442
+ elif len(args.args) == 2:
443
+ get_850hpa_geopotential(time=args.args[0], save_to_file=args.args[1])
444
+ else:
445
+ print("Too many arguments")
446
+ print("\nUsage: windborne grid_850hpa_geopotential time output_file")
447
+
448
+ # HISTORICAL
449
+
450
+ elif args.command == 'hist_temp_2m':
451
+ # Parse historical temperature arguments
452
+ if len(args.args) in [0,1,2]:
453
+ print("To get the historical output of global temperature forecasts you need to provide\n"
454
+ " - initialization time of the forecast\n"
455
+ " - How many hours after the run time the forecast is valid at\n"
456
+ " - An ouput file to save the data")
457
+ print("\nUsage: windborne hist_temp_2m initialization_time forecast_hour output_file")
458
+ return
459
+ elif len(args.args) == 3:
460
+ get_historical_temperature_2m(initialization_time=args.args[0], forecast_hour=args.args[1], save_to_file=args.args[2])
461
+ else:
462
+ print("Too many arguments")
463
+ print("\nUsage: windborne hist_temp_2m initialization_time forecast_hour output_file")
464
+
465
+ elif args.command == 'hist_500hpa_geopotential':
466
+ # Parse historical 500 hpa geopotential arguments
467
+ if len(args.args) in [0,1,2]:
468
+ print("To get the historical output of global 500hPa geopotential forecasts you need to provide\n"
469
+ " - initialization time of the forecast\n"
470
+ " - How many hours after the run time the forecast is valid at\n"
471
+ " - An ouput file to save the data")
472
+ print("\nUsage: windborne hist_500hpa_geopotential initialization_time forecast_hour output_file")
473
+ return
474
+ elif len(args.args) == 3:
475
+ get_historical_500hpa_geopotential(initialization_time=args.args[0], forecast_hour=args.args[1], save_to_file=args.args[2])
476
+ else:
477
+ print("Too many arguments")
478
+ print("\nUsage: windborne hist_500hpa_geopotential initialization_time forecast_hour output_file")
479
+
480
+ elif args.command == 'hist_500hpa_wind_u':
481
+ if len(args.args) in [0,1,2]:
482
+ print("To get the historical output of global 500hPa wind u forecasts you need to provide\n"
483
+ " - initialization time of the forecast\n"
484
+ " - How many hours after the run time the forecast is valid at\n"
485
+ " - An ouput file to save the data")
486
+ print("\nUsage: windborne hist_500hpa_wind_u initialization_time forecast_hour output_file")
487
+ elif len(args.args) == 3:
488
+ get_historical_500hpa_wind_u(initialization_time=args.args[0], forecast_hour=args.args[1], save_to_file=args.args[2])
489
+ else:
490
+ print("Too many arguments")
491
+ print("\nUsage: windborne hist_500hpa_wind_u initialization_time forecast_hour output_file")
492
+
493
+ elif args.command == 'hist_500hpa_wind_v':
494
+ if len(args.args) in [0,1,2]:
495
+ print("To get the historical output of global 500hPa wind v forecasts you need to provide\n"
496
+ " - initialization time of the forecast\n"
497
+ " - How many hours after the run time the forecast is valid at\n"
498
+ " - An ouput file to save the data")
499
+ print("\nUsage: windborne hist_500hpa_wind_u initialization_time forecast_hour output_file")
500
+ elif len(args.args) == 3:
501
+ get_historical_500hpa_wind_v(initialization_time=args.args[0], forecast_hour=args.args[1], save_to_file=args.args[2])
502
+ else:
503
+ print("Too many arguments")
504
+ print("\nUsage: windborne hist_500hpa_wind_v initialization_time forecast_hour output_file")
505
+
506
+ elif args.command == 'cyclones':
507
+ # Parse cyclones arguments
508
+ basin_name = 'ALL basins'
509
+ if args.basin:
510
+ basin_name = f"{args.basin} basin"
511
+ print(f"Checking for tropical cyclones only within {args.basin} basin\n")
512
+
513
+ if len(args.args) == 0:
514
+ print("Loading tropical cyclones for our latest available initialization time\n")
515
+ if get_tropical_cyclones(basin=args.basin):
516
+ print(f"Found {len(get_tropical_cyclones())} cyclone(s)\n")
517
+ pprint(get_tropical_cyclones(basin=args.basin))
518
+ return
519
+ else:
520
+ print("There are no active tropical cyclones for our latest available initialization time.")
521
+ elif len(args.args) == 1:
522
+ if '.' in args.args[0]:
523
+ # Save tcs with the latest available initialization time in filename
524
+ get_tropical_cyclones(basin=args.basin, save_to_file=args.args[0])
525
+ else:
526
+ # Display tcs for selected initialization time
527
+ if get_tropical_cyclones(initialization_time=args.args[0], basin=args.basin):
528
+ print(f"Loading tropical cyclones for initialization time {args.args[0]}\n")
529
+ print(f"Found {len(get_tropical_cyclones(initialization_time=args.args[0]))} cyclone(s)\n")
530
+ pprint(get_tropical_cyclones(initialization_time=args.args[0], basin=args.basin))
531
+ else:
532
+ print(f"No active tropical cyclones for {basin_name} and {args.args[0]} initialization time.")
533
+ elif len(args.args) == 2:
534
+ print(f"Saving tropical cyclones for initialization time {args.args[0]} and {basin_name}\n")
535
+ get_tropical_cyclones(initialization_time=args.args[0], basin=args.basin, save_to_file=args.args[1])
536
+ else:
537
+ print("Error: Too many arguments")
538
+ print("Usage: windborne cyclones [initialization_time] output_file")
539
+
540
+ else:
541
+ parser.print_help()
542
+
543
+ if __name__ == '__main__':
544
+ main()
windborne/config.py ADDED
@@ -0,0 +1,42 @@
1
+ import os
2
+
3
+ # current APIs versions and links
4
+ DATA_API_BASE_URL = "https://sensor-data.windbornesystems.com/api/v1"
5
+ FORECASTS_API_BASE_URL = "https://forecasts.windbornesystems.com/api/v1"
6
+
7
+ # If not set properly make_api_request will display an error message
8
+ CLIENT_ID = os.getenv("WB_CLIENT_ID")
9
+ API_KEY = os.getenv("WB_API_KEY")
10
+
11
+ LAUNCH_SITES = {
12
+ '2af36807-2a03-4a89-a54c-c4a09906215a': 'VD',
13
+ '1d8f0702-bd4f-485c-b461-bac0375bbfdd': 'DC',
14
+ '95dc05e7-ebc2-4127-ae70-6a84cd7c9480': 'WS',
15
+ '72d649c7-6faa-4a12-8c78-3e5e9a149766': 'AL',
16
+ 'd06da229-94b2-4a9d-828c-a20d8b3c7e3f': 'NY',
17
+ '97186bc1-0fe5-4dcf-b86a-fd00b3e9ba92': 'FH',
18
+ '7dea0491-a41c-4d49-b371-db2a0babe98c': 'HW',
19
+ 'ac69c1de-91d9-4b2f-9a41-6aacec10ddcc': 'OAK',
20
+ 'ea9a469a-1f7d-4691-b2ad-73cd04842c42': 'SV',
21
+ '954ddab5-9a0d-48ad-899c-0207f32e123f': 'BW',
22
+ 'e6074c13-16ff-42c9-9316-bececf7184b5': 'LAH',
23
+ 'd65f0b97-f6e9-49d3-8ae5-89c1efd6690c': 'OKC',
24
+ 'dcdba72f-3fb2-4971-9ba1-30df7f67b932': 'FL',
25
+ '90fe9fd7-d656-4943-b57b-c90868cf3ca0': 'FB',
26
+ '51da1d97-4473-466d-96fe-8b2c45462189': 'CB',
27
+ 'd504fe5c-e3ec-4c83-87c7-807f63d3aed0': 'PR',
28
+ '7b5867eb-48d7-42c7-8028-346588877e95': 'SC',
29
+ '15a10191-ecc7-42ed-865d-aa2c304be720': 'SK',
30
+ '7489f53d-e937-4098-9666-b735b5ed5a06': 'DAEGU',
31
+ 'be90782a-59db-4dc4-bdb5-e41d81c60343': 'KE'
32
+ }
33
+
34
+ # GRIDDED FORECASTS
35
+ FORECASTS_GRIDDED_URL = f"{FORECASTS_API_BASE_URL}/gridded"
36
+
37
+ # HISTORICAL FORECASTS
38
+ FORECASTS_HISTORICAL_URL = f"{FORECASTS_API_BASE_URL}/gridded/historical"
39
+
40
+ # TCS
41
+ FORECASTS_TCS_URL = f"{FORECASTS_API_BASE_URL}/tropical_cyclones"
42
+ TCS_SUPPORTED_FORMATS = ('.csv', '.json', '.geojson', '.gpx', '.kml', 'little_r')