windborne 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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')