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 +76 -0
- windborne/cli.py +544 -0
- windborne/config.py +42 -0
- windborne/data_api.py +784 -0
- windborne/forecasts_api.py +459 -0
- windborne/utils.py +940 -0
- windborne-1.0.0.dist-info/METADATA +25 -0
- windborne-1.0.0.dist-info/RECORD +11 -0
- windborne-1.0.0.dist-info/WHEEL +5 -0
- windborne-1.0.0.dist-info/entry_points.txt +2 -0
- windborne-1.0.0.dist-info/top_level.txt +1 -0
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')
|