oafuncs 0.0.63__py2.py3-none-any.whl → 0.0.64__py2.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.
@@ -0,0 +1,1173 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+ '''
4
+ Author: Liu Kun && 16031215@qq.com
5
+ Date: 2024-11-29 16:56:52
6
+ LastEditors: Liu Kun && 16031215@qq.com
7
+ LastEditTime: 2024-11-29 16:56:53
8
+ FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_down\\hycom_3hourly_wholeday.py
9
+ Description:
10
+ EditPlatform: vscode
11
+ ComputerInfo: XPS 15 9510
12
+ SystemInfo: Windows 11
13
+ Python Version: 3.12
14
+ '''
15
+
16
+
17
+ import datetime
18
+ import os
19
+ import random
20
+ import time
21
+ import warnings
22
+ from concurrent.futures import ThreadPoolExecutor
23
+ from pathlib import Path
24
+
25
+ import matplotlib.pyplot as plt
26
+ import numpy as np
27
+ import pandas as pd
28
+ import requests
29
+ from rich import print
30
+ from rich.progress import Progress
31
+
32
+ warnings.filterwarnings("ignore", category=RuntimeWarning, message="Engine '.*' loading failed:.*")
33
+
34
+ __all__ = ['draw_time_range', 'download', 'how_to_use', 'get_time_list']
35
+
36
+ # time resolution
37
+ data_info = {'yearly': {}, 'monthly': {}, 'daily': {}, 'hourly': {}}
38
+
39
+ # hourly data
40
+ # dataset: GLBv0.08, GLBu0.08, GLBy0.08
41
+ data_info['hourly']['dataset'] = {'GLBv0.08': {}, 'GLBu0.08': {}, 'GLBy0.08': {}}
42
+
43
+ # version
44
+ # version of GLBv0.08: 53.X, 56.3, 57.2, 92.8, 57.7, 92.9, 93.0
45
+ data_info['hourly']['dataset']['GLBv0.08']['version'] = {'53.X': {}, '56.3': {}, '57.2': {}, '92.8': {}, '57.7': {}, '92.9': {}, '93.0': {}}
46
+ # version of GLBu0.08: 93.0
47
+ data_info['hourly']['dataset']['GLBu0.08']['version'] = {'93.0': {}}
48
+ # version of GLBy0.08: 93.0
49
+ data_info['hourly']['dataset']['GLBy0.08']['version'] = {'93.0': {}}
50
+
51
+ # info details
52
+ # time range
53
+ # GLBv0.08
54
+ # 在网页上提交超过范围的时间,会返回该数据集实际时间范围,从而纠正下面的时间范围
55
+ # 目前只纠正了GLBv0.08 93.0的时间范围,具体到小时了
56
+ # 其他数据集的时刻暂时默认为00起,21止
57
+ data_info['hourly']['dataset']['GLBv0.08']['version']['53.X']['time_range'] = {'time_start': '19940101', 'time_end': '20151230'}
58
+ data_info['hourly']['dataset']['GLBv0.08']['version']['56.3']['time_range'] = {'time_start': '20140701', 'time_end': '20160430'}
59
+ data_info['hourly']['dataset']['GLBv0.08']['version']['57.2']['time_range'] = {'time_start': '20160501', 'time_end': '20170131'}
60
+ data_info['hourly']['dataset']['GLBv0.08']['version']['92.8']['time_range'] = {'time_start': '20170201', 'time_end': '20170531'}
61
+ data_info['hourly']['dataset']['GLBv0.08']['version']['57.7']['time_range'] = {'time_start': '20170601', 'time_end': '20170930'}
62
+ data_info['hourly']['dataset']['GLBv0.08']['version']['92.9']['time_range'] = {'time_start': '20171001', 'time_end': '20171231'}
63
+ data_info['hourly']['dataset']['GLBv0.08']['version']['93.0']['time_range'] = {'time_start': '2018010112', 'time_end': '2020021909'}
64
+ # GLBu0.08
65
+ data_info['hourly']['dataset']['GLBu0.08']['version']['93.0']['time_range'] = {'time_start': '20180919', 'time_end': '20181208'}
66
+ # GLBy0.08
67
+ data_info['hourly']['dataset']['GLBy0.08']['version']['93.0']['time_range'] = {'time_start': '20181204', 'time_end': '20300904'}
68
+
69
+ # variable
70
+ variable_info = {
71
+ 'u': {'var_name': 'water_u', 'standard_name': 'eastward_sea_water_velocity'},
72
+ 'v': {'var_name': 'water_v', 'standard_name': 'northward_sea_water_velocity'},
73
+ 'temp': {'var_name': 'water_temp', 'standard_name': 'sea_water_potential_temperature'},
74
+ 'salt': {'var_name': 'salinity', 'standard_name': 'sea_water_salinity'},
75
+ 'ssh': {'var_name': 'surf_el', 'standard_name': 'sea_surface_elevation'},
76
+ 'u_b': {'var_name': 'water_u_bottom', 'standard_name': 'eastward_sea_water_velocity_at_sea_floor'},
77
+ 'v_b': {'var_name': 'water_v_bottom', 'standard_name': 'northward_sea_water_velocity_at_sea_floor'},
78
+ 'temp_b': {'var_name': 'water_temp_bottom', 'standard_name': 'sea_water_potential_temperature_at_sea_floor'},
79
+ 'salt_b': {'var_name': 'salinity_bottom', 'standard_name': 'sea_water_salinity_at_sea_floor'},
80
+ }
81
+
82
+ # classification method
83
+ # year_different: the data of different years is stored in different files
84
+ # same_path: the data of different years is stored in the same file
85
+ # var_different: the data of different variables is stored in different files
86
+ # var_year_different: the data of different variables and years is stored in different files
87
+ data_info['hourly']['dataset']['GLBv0.08']['version']['53.X']['classification'] = 'year_different'
88
+ data_info['hourly']['dataset']['GLBv0.08']['version']['56.3']['classification'] = 'same_path'
89
+ data_info['hourly']['dataset']['GLBv0.08']['version']['57.2']['classification'] = 'same_path'
90
+ data_info['hourly']['dataset']['GLBv0.08']['version']['92.8']['classification'] = 'var_different'
91
+ data_info['hourly']['dataset']['GLBv0.08']['version']['57.7']['classification'] = 'same_path'
92
+ data_info['hourly']['dataset']['GLBv0.08']['version']['92.9']['classification'] = 'var_different'
93
+ data_info['hourly']['dataset']['GLBv0.08']['version']['93.0']['classification'] = 'var_different'
94
+ data_info['hourly']['dataset']['GLBu0.08']['version']['93.0']['classification'] = 'var_different'
95
+ data_info['hourly']['dataset']['GLBy0.08']['version']['93.0']['classification'] = 'var_year_different'
96
+
97
+ # download info
98
+ # base url
99
+ # GLBv0.08 53.X
100
+ url_53x = {}
101
+ for y_53x in range(1994, 2016):
102
+ # r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_53.X/data/2013?'
103
+ url_53x[str(y_53x)] = rf'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_53.X/data/{y_53x}?'
104
+ data_info['hourly']['dataset']['GLBv0.08']['version']['53.X']['url'] = url_53x
105
+ # GLBv0.08 56.3
106
+ data_info['hourly']['dataset']['GLBv0.08']['version']['56.3']['url'] = r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_56.3?'
107
+ # GLBv0.08 57.2
108
+ data_info['hourly']['dataset']['GLBv0.08']['version']['57.2']['url'] = r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_57.2?'
109
+ # GLBv0.08 92.8
110
+ url_928 = {
111
+ 'uv3z': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_92.8/uv3z?',
112
+ 'ts3z': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_92.8/ts3z?',
113
+ 'ssh': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_92.8/ssh?',
114
+ }
115
+ data_info['hourly']['dataset']['GLBv0.08']['version']['92.8']['url'] = url_928
116
+ # GLBv0.08 57.7
117
+ data_info['hourly']['dataset']['GLBv0.08']['version']['57.7']['url'] = r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_57.7?'
118
+ # GLBv0.08 92.9
119
+ url_929 = {
120
+ 'uv3z': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_92.9/uv3z?',
121
+ 'ts3z': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_92.9/ts3z?',
122
+ 'ssh': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_92.9/ssh?',
123
+ }
124
+ data_info['hourly']['dataset']['GLBv0.08']['version']['92.9']['url'] = url_929
125
+ # GLBv0.08 93.0
126
+ url_930_v = {
127
+ 'uv3z': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_93.0/uv3z?',
128
+ 'ts3z': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_93.0/ts3z?',
129
+ 'ssh': r'https://ncss.hycom.org/thredds/ncss/GLBv0.08/expt_93.0/ssh?',
130
+ }
131
+ data_info['hourly']['dataset']['GLBv0.08']['version']['93.0']['url'] = url_930_v
132
+ # GLBu0.08 93.0
133
+ url_930_u = {
134
+ 'uv3z': r'https://ncss.hycom.org/thredds/ncss/GLBu0.08/expt_93.0/uv3z?',
135
+ 'ts3z': r'https://ncss.hycom.org/thredds/ncss/GLBu0.08/expt_93.0/ts3z?',
136
+ 'ssh': r'https://ncss.hycom.org/thredds/ncss/GLBu0.08/expt_93.0/ssh?',
137
+ }
138
+ data_info['hourly']['dataset']['GLBu0.08']['version']['93.0']['url'] = url_930_u
139
+ # GLBy0.08 93.0
140
+ uv3z_930_y = {}
141
+ ts3z_930_y = {}
142
+ ssh_930_y = {}
143
+ for y_930_y in range(2018, 2025):
144
+ uv3z_930_y[str(
145
+ y_930_y)] = rf'https://ncss.hycom.org/thredds/ncss/GLBy0.08/expt_93.0/uv3z/{y_930_y}?'
146
+ ts3z_930_y[str(
147
+ y_930_y)] = rf'https://ncss.hycom.org/thredds/ncss/GLBy0.08/expt_93.0/ts3z/{y_930_y}?'
148
+ ssh_930_y[str(
149
+ y_930_y)] = rf'https://ncss.hycom.org/thredds/ncss/GLBy0.08/expt_93.0/ssh/{y_930_y}?'
150
+ url_930_y = {
151
+ 'uv3z': uv3z_930_y,
152
+ 'ts3z': ts3z_930_y,
153
+ 'ssh': ssh_930_y,
154
+ }
155
+ data_info['hourly']['dataset']['GLBy0.08']['version']['93.0']['url'] = url_930_y
156
+
157
+ var_group = {
158
+ 'uv3z': ['u', 'v', 'u_b', 'v_b'],
159
+ 'ts3z': ['temp', 'salt', 'temp_b', 'salt_b'],
160
+ 'ssh': ['ssh'],
161
+ }
162
+
163
+
164
+ def draw_time_range(pic_save_folder=None):
165
+ if pic_save_folder is not None:
166
+ os.makedirs(pic_save_folder, exist_ok=True)
167
+ # Converting the data into a format suitable for plotting
168
+ data = []
169
+ for dataset, versions in data_info['hourly']['dataset'].items():
170
+ for version, time_range in versions['version'].items():
171
+ t_s = time_range['time_range']['time_start']
172
+ t_e = time_range['time_range']['time_end']
173
+ if len(t_s) == 8:
174
+ t_s = t_s + '00'
175
+ if len(t_e) == 8:
176
+ t_e = t_e + '21'
177
+ t_s, t_e = t_s + '0000', t_e + '0000'
178
+ data.append({
179
+ 'dataset': dataset,
180
+ 'version': version,
181
+ 'start_date': pd.to_datetime(t_s),
182
+ 'end_date': pd.to_datetime(t_e),
183
+ })
184
+
185
+ # Creating a DataFrame
186
+ df = pd.DataFrame(data)
187
+
188
+ # Plotting with combined labels for datasets and versions on the y-axis
189
+ plt.figure(figsize=(12, 6))
190
+
191
+ # Combined labels for datasets and versions
192
+ combined_labels = [f"{dataset}_{version}" for dataset, version in zip(df['dataset'], df['version'])]
193
+
194
+ colors = plt.cm.viridis(np.linspace(0, 1, len(combined_labels)))
195
+
196
+ # Assigning a color to each combined label
197
+ label_colors = {label: colors[i] for i, label in enumerate(combined_labels)}
198
+
199
+ # Plotting each time range
200
+ k = 1
201
+ for _, row in df.iterrows():
202
+ plt.plot([row['start_date'], row['end_date']], [k, k], color=label_colors[f"{row['dataset']}_{row['version']}"], linewidth=6)
203
+ # plt.text(row['end_date'], k,
204
+ # f"{row['version']}", ha='right', color='black')
205
+ ymdh_s = row['start_date'].strftime('%Y-%m-%d %H')
206
+ ymdh_e = row['end_date'].strftime('%Y-%m-%d %H')
207
+ if k == 1 or k == len(combined_labels):
208
+ plt.text(row['start_date'], k+0.125, f"{ymdh_s}", ha='left', color='black')
209
+ plt.text(row['end_date'], k+0.125, f"{ymdh_e}", ha='right', color='black')
210
+ else:
211
+ plt.text(row['start_date'], k+0.125, f"{ymdh_s}", ha='right', color='black')
212
+ plt.text(row['end_date'], k+0.125, f"{ymdh_e}", ha='left', color='black')
213
+ k += 1
214
+
215
+ # Setting the y-axis labels
216
+ plt.yticks(range(1, len(combined_labels)+1), combined_labels)
217
+ plt.xlabel('Time')
218
+ plt.ylabel('Dataset - Version')
219
+ plt.title('Time Range of Different Versions of Datasets')
220
+ plt.xticks(rotation=45)
221
+ plt.grid(True)
222
+ plt.tight_layout()
223
+ if pic_save_folder:
224
+ plt.savefig(Path(pic_save_folder) / 'HYCOM_time_range.png')
225
+ print(f'[bold green]HYCOM_time_range.png has been saved in {pic_save_folder}')
226
+ else:
227
+ plt.savefig('HYCOM_time_range.png')
228
+ print('[bold green]HYCOM_time_range.png has been saved in the current folder')
229
+ print(f'Curren folder: {os.getcwd()}')
230
+ # plt.show()
231
+ plt.close()
232
+
233
+
234
+ def transform_time(time_str):
235
+ # old_time = '2023080203'
236
+ # time_new = '2023-08-02T03%3A00%3A00Z'
237
+ time_new = f'{time_str[:4]}-{time_str[4:6]}-{time_str[6:8]}T{time_str[8:10]}%3A00%3A00Z'
238
+ return time_new
239
+
240
+
241
+ def get_time_list(time_s, time_e, delta_hour):
242
+ '''
243
+ Description: get a list of time strings from time_s to time_e with delta_hour
244
+ Args:
245
+ time_s: start time string, e.g. '2023080203'
246
+ time_e: end time string, e.g. '2023080303'
247
+ delta_hour: interval of hours
248
+ Returns:
249
+ dt_list: a list of time strings
250
+ '''
251
+ dt = datetime.datetime.strptime(time_s, '%Y%m%d%H')
252
+ dt_list = []
253
+ while dt.strftime('%Y%m%d%H') <= time_e:
254
+ dt_list.append(dt.strftime('%Y%m%d%H'))
255
+ dt = dt + datetime.timedelta(hours=delta_hour)
256
+ return dt_list
257
+
258
+
259
+ def get_hour_list(time_s, time_e, delta_hour):
260
+ '''
261
+ Description: get a list of time strings from time_s to time_e with delta_hour
262
+ Args:
263
+ time_s: start time string, e.g. '2023080203'
264
+ time_e: end time string, e.g. '2023080303'
265
+ delta_hour: interval of hours
266
+ Returns:
267
+ dt_list: a list of time strings
268
+ '''
269
+ dt = datetime.datetime.strptime(time_s, '%Y%m%d%H')
270
+ dt_list = []
271
+ while dt.strftime('%Y%m%d%H') <= time_e:
272
+ dt_list.append(dt.strftime('%Y%m%d%H'))
273
+ dt = dt + datetime.timedelta(hours=delta_hour)
274
+ return dt_list
275
+
276
+
277
+ def get_day_list(time_s, time_e, delta_day):
278
+ '''
279
+ Description: get a list of time strings from time_s to time_e with delta_hour
280
+ Args:
281
+ time_s: start time string, e.g. '20230802'
282
+ time_e: end time string, e.g. '20230803'
283
+ delta_hour: interval of hours
284
+ Returns:
285
+ dt_list: a list of time strings
286
+ '''
287
+ time_s = time_s[:8]
288
+ time_e = time_e[:8]
289
+ dt = datetime.datetime.strptime(time_s, '%Y%m%d')
290
+ dt_list = []
291
+ while dt.strftime('%Y%m%d') <= time_e:
292
+ dt_list.append(dt.strftime('%Y%m%d'))
293
+ dt = dt + datetime.timedelta(days=delta_day)
294
+ return dt_list
295
+
296
+
297
+ def get_nearest_level_index(depth):
298
+ level_depth = [0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 125.0, 150.0, 200.0, 250.0, 300.0, 350.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 1250.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000]
299
+ return min(range(len(level_depth)), key=lambda i: abs(level_depth[i]-depth))
300
+
301
+
302
+ def set_query_dict_no_vertical(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh):
303
+ query_dict = {
304
+ 'var': variable_info[var]['var_name'],
305
+ 'north': lat_max,
306
+ 'west': lon_min,
307
+ 'east': lon_max,
308
+ 'south': lat_min,
309
+ 'horizStride': 1,
310
+ 'time': transform_time(time_str_ymdh),
311
+ 'addLatLon': 'true',
312
+ 'accept': 'netcdf4',
313
+ }
314
+ return query_dict
315
+
316
+
317
+ def set_query_dict_depth_or_level(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh):
318
+ query_dict = {
319
+ 'var': variable_info[var]['var_name'],
320
+ 'north': lat_max,
321
+ 'west': lon_min,
322
+ 'east': lon_max,
323
+ 'south': lat_min,
324
+ 'horizStride': 1,
325
+ 'time': transform_time(time_str_ymdh),
326
+ 'vertCoord': 0,
327
+ 'addLatLon': 'true',
328
+ 'accept': 'netcdf4',
329
+ }
330
+ return query_dict
331
+
332
+
333
+ def set_query_dict_full(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh):
334
+ query_dict = {
335
+ 'var': variable_info[var]['var_name'],
336
+ 'north': lat_max,
337
+ 'west': lon_min,
338
+ 'east': lon_max,
339
+ 'south': lat_min,
340
+ 'horizStride': 1,
341
+ 'time': transform_time(time_str_ymdh),
342
+ 'vertStride': 1,
343
+ 'addLatLon': 'true',
344
+ 'accept': 'netcdf4',
345
+ }
346
+ return query_dict
347
+
348
+
349
+ def get_query_dict_single_depth(var, lon_min, lon_max, lat_min, lat_max, depth, time_str_ymdh):
350
+ if var in ['ssh']:
351
+ query_dict = set_query_dict_no_vertical(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
352
+ else:
353
+ query_dict = set_query_dict_depth_or_level(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
354
+ if var in ['u', 'v', 'temp', 'salt']:
355
+ print('Please ensure the depth is in the range of 0-5000 m')
356
+ query_dict['vertCoord'] = get_nearest_level_index(depth)+1
357
+ return query_dict
358
+
359
+
360
+ def get_query_dict_single_level(var, lon_min, lon_max, lat_min, lat_max, level_num, time_str_ymdh):
361
+ if var in ['ssh']:
362
+ query_dict = set_query_dict_no_vertical(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
363
+ else:
364
+ # level_num: 1-40
365
+ query_dict = set_query_dict_depth_or_level(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
366
+ if var in ['u', 'v', 'temp', 'salt']:
367
+ print('Please ensure the level_num is in the range of 1-40')
368
+ if level_num == 0:
369
+ level_num = 1
370
+ print('The level_num is set to 1')
371
+ if level_num > 40:
372
+ level_num = 40
373
+ print('The level_num is set to 40')
374
+ query_dict['vertCoord'] = level_num
375
+ return query_dict
376
+
377
+
378
+ def get_query_dict_full_level(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh):
379
+ if var in ['ssh']:
380
+ query_dict = set_query_dict_no_vertical(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
381
+ else:
382
+ query_dict = set_query_dict_full(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
383
+ return query_dict
384
+
385
+
386
+ def get_query_dict_full_depth(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh):
387
+ if var in ['ssh']:
388
+ query_dict = set_query_dict_no_vertical(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
389
+ else:
390
+ query_dict = set_query_dict_full(var, lon_min, lon_max, lat_min, lat_max, time_str_ymdh)
391
+ return query_dict
392
+
393
+
394
+ def ymdh_in_which_dataset_and_version(time_ymdh):
395
+ time_ymdh = int(time_ymdh)
396
+ d_list = []
397
+ v_list = []
398
+ trange_list = []
399
+ have_data = False
400
+ for dataset_name in data_info['hourly']['dataset'].keys():
401
+ for version_name in data_info['hourly']['dataset'][dataset_name]['version'].keys():
402
+ time_s, time_e = list(data_info['hourly']['dataset'][dataset_name]['version'][version_name]['time_range'].values())
403
+ time_s, time_e = str(time_s), str(time_e)
404
+ if len(time_s) == 8:
405
+ time_s = time_s + '00'
406
+ if len(time_e) == 8:
407
+ time_e = time_e + '21'
408
+ if time_ymdh >= int(time_s) and time_ymdh <= int(time_e):
409
+ d_list.append(dataset_name)
410
+ v_list.append(version_name)
411
+ trange_list.append(f'{time_s}-{time_e}')
412
+ have_data = True
413
+ print(f'[bold red]{time_ymdh} is in the following dataset and version:')
414
+ if have_data:
415
+ for d, v, trange in zip(d_list, v_list, trange_list):
416
+ print(f'[bold blue]{d} {v} {trange}')
417
+ else:
418
+ raise ValueError(f'[bold red]{time_ymdh} is not in any dataset and version')
419
+
420
+
421
+ def ymd_in_which_dataset_and_version(time_ymd):
422
+ time_ymd = int(str(time_ymd)[:8])
423
+ d_list = []
424
+ v_list = []
425
+ trange_list = []
426
+ have_data = False
427
+ for dataset_name in data_info['hourly']['dataset'].keys():
428
+ for version_name in data_info['hourly']['dataset'][dataset_name]['version'].keys():
429
+ time_s, time_e = list(data_info['hourly']['dataset'][dataset_name]['version'][version_name]['time_range'].values())
430
+ time_s, time_e = str(time_s), str(time_e)
431
+ if len(time_s) == 8:
432
+ time_s = time_s + '00'
433
+ if len(time_e) == 8:
434
+ time_e = time_e + '21'
435
+ if time_ymd*100 >= int(time_s) and time_ymd*100+21 <= int(time_e):
436
+ d_list.append(dataset_name)
437
+ v_list.append(version_name)
438
+ trange_list.append(f'{time_s}-{time_e}')
439
+ have_data = True
440
+ print(f'[bold red]{time_ymd} is in the following dataset and version:')
441
+ if have_data:
442
+ for d, v, trange in zip(d_list, v_list, trange_list):
443
+ print(f'[bold blue]{d} {v} {trange}')
444
+ else:
445
+ raise ValueError(f'[bold red]{time_ymd} is not in any dataset and version')
446
+
447
+
448
+ def direct_choose_dataset_and_version(time_ymdh):
449
+ time_ymdh = int(time_ymdh)
450
+ for dataset_name in data_info['hourly']['dataset'].keys():
451
+ for version_name in data_info['hourly']['dataset'][dataset_name]['version'].keys():
452
+ [time_s, time_e] = list(data_info['hourly']['dataset'][dataset_name]['version'][version_name]['time_range'].values())
453
+ time_s, time_e = str(time_s), str(time_e)
454
+ if len(time_s) == 8:
455
+ time_s = time_s + '00'
456
+ if len(time_e) == 8:
457
+ time_e = time_e + '21'
458
+ if time_ymdh >= int(time_s) and time_ymdh <= int(time_e):
459
+ print(f'[bold purple]dataset: {dataset_name}, version: {version_name} is chosen')
460
+ return dataset_name, version_name
461
+
462
+
463
+ def direct_choose_dataset_and_version_whole_day(time_ymd):
464
+ time_ymd = int(str(time_ymd)[:8])
465
+ for dataset_name in data_info['hourly']['dataset'].keys():
466
+ for version_name in data_info['hourly']['dataset'][dataset_name]['version'].keys():
467
+ [time_s, time_e] = list(data_info['hourly']['dataset'][dataset_name]['version'][version_name]['time_range'].values())
468
+ time_s, time_e = str(time_s), str(time_e)
469
+ if len(time_s) == 8:
470
+ time_s = time_s + '00'
471
+ if len(time_e) == 8:
472
+ time_e = time_e + '21'
473
+ if time_ymd*100 >= int(time_s) and time_ymd*100+21 <= int(time_e):
474
+ print(f'[bold purple]dataset: {dataset_name}, version: {version_name} is chosen')
475
+ return dataset_name, version_name
476
+
477
+
478
+ def get_base_url(dataset_name, version_name, var, year_str):
479
+ url_dict = data_info['hourly']['dataset'][dataset_name]['version'][version_name]['url']
480
+ classification_method = data_info['hourly']['dataset'][dataset_name]['version'][version_name]['classification']
481
+ if classification_method == 'year_different':
482
+ base_url = url_dict[str(year_str)]
483
+ elif classification_method == 'same_path':
484
+ base_url = url_dict
485
+ elif classification_method == 'var_different':
486
+ base_url = None
487
+ for key, value in var_group.items():
488
+ if var in value:
489
+ base_url = url_dict[key]
490
+ break
491
+ if base_url is None:
492
+ print('Please ensure the var is in [u,v,temp,salt,ssh,u_b,v_b,temp_b,salt_b]')
493
+ elif classification_method == 'var_year_different':
494
+ base_url = None
495
+ for key, value in var_group.items():
496
+ if var in value:
497
+ base_url = url_dict[key][str(year_str)]
498
+ break
499
+ if base_url is None:
500
+ print('Please ensure the var is in [u,v,temp,salt,ssh,u_b,v_b,temp_b,salt_b]')
501
+ return base_url
502
+
503
+
504
+ def get_submit_url(dataset_name, version_name, var, year_str, query_dict):
505
+ base_url = get_base_url(dataset_name, version_name, var, year_str)
506
+ if isinstance(query_dict['var'], str):
507
+ query_dict['var'] = [query_dict['var']]
508
+ target_url = base_url + '&'.join(f"var={var}" for var in query_dict['var']) + '&' + '&'.join(f"{key}={value}" for key, value in query_dict.items() if key != 'var')
509
+ return target_url
510
+
511
+
512
+ def clear_existing_file(file_full_path):
513
+ if os.path.exists(file_full_path):
514
+ os.remove(file_full_path)
515
+ print(f'{file_full_path} has been removed')
516
+
517
+
518
+ def check_existing_file(file_full_path):
519
+ if os.path.exists(file_full_path):
520
+ print(f'{file_full_path} exists')
521
+ return True
522
+ else:
523
+ print(f'{file_full_path} does not exist')
524
+ return False
525
+
526
+
527
+ def get_ua():
528
+ ua_list = [
529
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60",
530
+ "Opera/8.0 (Windows NT 5.1; U; en)",
531
+ "Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50",
532
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50",
533
+ "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11",
534
+ "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11",
535
+ "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
536
+ "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0",
537
+ "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
538
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv,2.0.1) Gecko/20100101 Firefox/4.0.1",
539
+ "Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1",
540
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
541
+ "MAC:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36",
542
+ "Windows:Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
543
+ "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
544
+ "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
545
+ "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
546
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36",
547
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
548
+ "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16",
549
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
550
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36",
551
+ "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
552
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
553
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11",
554
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER",
555
+ "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)",
556
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)"
557
+ "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)",
558
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",
559
+ "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0",
560
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)",
561
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
562
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36",
563
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
564
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36",
565
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4094.1 Safari/537.36",
566
+ "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
567
+ "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
568
+ "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
569
+ "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
570
+ "Mozilla/5.0 (Linux; U; Android 2.2.1; zh-cn; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
571
+ "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
572
+ "MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
573
+ "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
574
+ "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
575
+ "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
576
+ "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
577
+ "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;",
578
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
579
+ "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
580
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
581
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
582
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)",
583
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)",
584
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)",
585
+ "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
586
+ "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124",
587
+ "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
588
+ "UCWEB7.0.2.37/28/999",
589
+ "NOKIA5700/UCWEB7.0.2.37/28/999",
590
+ "Openwave/UCWEB7.0.2.37/28/999",
591
+ "Openwave/UCWEB7.0.2.37/28/999",
592
+ ]
593
+ ua_index = random.randint(0, len(ua_list)-1)
594
+ ua = ua_list[ua_index]
595
+ # print(f'Using User-Agent: {ua}')
596
+ return ua
597
+
598
+
599
+ def get_proxy():
600
+ # 获取当前脚本的绝对路径
601
+ script_dir = os.path.dirname(os.path.abspath(__file__))
602
+ # 构建ip.txt的绝对路径
603
+ ip_file_txt = os.path.join(script_dir, 'ip.txt')
604
+ with open(ip_file_txt, 'r') as f:
605
+ ips = f.readlines()
606
+ ip_list = []
607
+ for ip in ips:
608
+ ip_list.append(ip.strip())
609
+ choose_ip = random.choice(ip_list)
610
+ proxies = {
611
+ 'http': 'http://' + choose_ip,
612
+ 'https': 'https://' + choose_ip
613
+ }
614
+ # print(f'Using proxy: {proxies}')
615
+ return proxies
616
+
617
+
618
+ def dlownload_file(target_url, store_path, file_name, check=False):
619
+ print(f'[bold red]Downloading {file_name}...')
620
+ # 创建会话
621
+ s = requests.Session()
622
+ download_success = False
623
+ request_times = 0
624
+ filename = Path(store_path) / file_name
625
+ if check:
626
+ if check_existing_file(filename):
627
+ return
628
+ clear_existing_file(filename)
629
+ print(f'Download_start_time: {datetime.datetime.now()}')
630
+ while not download_success:
631
+ if request_times > 0:
632
+ print(f'\r正在重试第 {request_times} 次', end="")
633
+ # 尝试下载文件
634
+ try:
635
+ headers = {
636
+ 'User-Agent': get_ua()}
637
+ response = s.get(target_url, headers=headers, timeout=5)
638
+ response.raise_for_status() # 如果请求返回的不是200,将抛出HTTPError异常
639
+
640
+ # 保存文件
641
+ with open(filename, 'wb') as f:
642
+ f.write(response.content)
643
+ # print(f'\r文件 {filename} 下载成功', end="")
644
+ print(f'[bold green]文件 {filename} 下载成功')
645
+ # query_ncfile_time(filename) # 这个函数在linux上目前会出问题
646
+ download_success = True
647
+
648
+ except requests.exceptions.HTTPError as errh:
649
+ print(f"Http Error: {errh}")
650
+ except requests.exceptions.ConnectionError as errc:
651
+ print(f"Error Connecting: {errc}")
652
+ except requests.exceptions.Timeout as errt:
653
+ print(f"Timeout Error: {errt}")
654
+ except requests.exceptions.RequestException as err:
655
+ print(f"OOps: Something Else: {err}")
656
+
657
+ time.sleep(3)
658
+ request_times += 1
659
+ print(f'Download_end_time: {datetime.datetime.now()}')
660
+
661
+
662
+ def check_hour_is_valid(ymdh_str):
663
+ # hour should be 00, 03, 06, 09, 12, 15, 18, 21
664
+ hh = int(str(ymdh_str[-2:]))
665
+ if hh in [0, 3, 6, 9, 12, 15, 18, 21]:
666
+ return True
667
+ else:
668
+ return False
669
+
670
+
671
+ def check_dataset_version_single_time(dataset_name, version_name, download_time):
672
+ download_time = str(download_time)
673
+ if not check_hour_is_valid(download_time):
674
+ print('Please ensure the hour is 00, 03, 06, 09, 12, 15, 18, 21')
675
+ raise ValueError('The hour is invalid')
676
+ if dataset_name is None and version_name is None:
677
+ print('The dataset_name and version_name are None, so the dataset and version will be chosen according to the download_time.\nIf there is more than one dataset and version in the time range, the first one will be chosen.')
678
+ print('If you wanna choose the dataset and version by yourself, please set the dataset_name and version_name together.')
679
+ ymdh_in_which_dataset_and_version(download_time)
680
+ dataset_name, version_name = direct_choose_dataset_and_version(download_time)
681
+ elif dataset_name is None and version_name is not None:
682
+ print('Please ensure the dataset_name is not None')
683
+ print('If you do not add the dataset_name, both the dataset and version will be chosen according to the download_time.')
684
+ ymdh_in_which_dataset_and_version(download_time)
685
+ dataset_name, version_name = direct_choose_dataset_and_version(download_time)
686
+ elif dataset_name is not None and version_name is None:
687
+ print('Please ensure the version_name is not None')
688
+ print('If you do not add the version_name, both the dataset and version will be chosen according to the download_time.')
689
+ ymdh_in_which_dataset_and_version(download_time)
690
+ dataset_name, version_name = direct_choose_dataset_and_version(download_time)
691
+ else:
692
+ print('The dataset_name and version_name are both set by yourself.')
693
+
694
+ return dataset_name, version_name
695
+
696
+
697
+ def get_submit_url_var(var, depth, level_num, lon_min, lon_max, lat_min, lat_max, dataset_name, version_name, download_time):
698
+ year_str = str(download_time)[:4]
699
+ if depth is not None and level_num is not None:
700
+ print('Please ensure the depth or level_num is None')
701
+ elif depth is not None:
702
+ print(f'Data of single depth ({depth}m) will be downloaded...')
703
+ query_dict = get_query_dict_single_depth(var, lon_min, lon_max, lat_min, lat_max, depth, download_time)
704
+ elif level_num is not None:
705
+ print(f'Data of single level ({level_num}) will be downloaded...')
706
+ query_dict = get_query_dict_single_level(var, lon_min, lon_max, lat_min, lat_max, level_num, download_time)
707
+ else:
708
+ print('Full depth or full level data will be downloaded...')
709
+ query_dict = get_query_dict_full_level(var, lon_min, lon_max, lat_min, lat_max, download_time)
710
+ submit_url = get_submit_url(
711
+ dataset_name, version_name, var, year_str, query_dict)
712
+ return submit_url
713
+
714
+
715
+ def direct_download_single_time(var, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, download_time='2024083100', depth=None, level_num=None, store_path=None, dataset_name=None, version_name=None, check=False):
716
+ download_time = str(download_time)
717
+ dataset_name, version_name = check_dataset_version_single_time(dataset_name, version_name, download_time)
718
+
719
+ if store_path is None:
720
+ store_path = str(Path.cwd())
721
+ else:
722
+ os.makedirs(str(store_path), exist_ok=True)
723
+
724
+ if isinstance(var, str):
725
+ var = [var]
726
+
727
+ if isinstance(var, list):
728
+ if len(var) == 1:
729
+ var = var[0]
730
+ submit_url = get_submit_url_var(var, depth, level_num, lon_min, lon_max, lat_min, lat_max, dataset_name, version_name, download_time)
731
+ file_name = f"HYCOM_{variable_info[var]['var_name']}_{download_time}.nc"
732
+ dlownload_file(submit_url, store_path, file_name, check)
733
+ else:
734
+ varlist = [_ for _ in var]
735
+ for key, value in var_group.items():
736
+ current_group = []
737
+ for v in varlist:
738
+ if v in value:
739
+ current_group.append(v)
740
+ if len(current_group) == 0:
741
+ continue
742
+
743
+ var = current_group[0]
744
+ submit_url = get_submit_url_var(var, depth, level_num, lon_min, lon_max, lat_min, lat_max, dataset_name, version_name, download_time)
745
+ file_name = f"HYCOM_{variable_info[var]['var_name']}_{download_time}.nc"
746
+ old_str = f'var={variable_info[var]["var_name"]}'
747
+ new_str = f'var={variable_info[var]["var_name"]}'
748
+ if len(current_group) > 1:
749
+ for v in current_group[1:]:
750
+ new_str = f'{new_str}&var={variable_info[v]["var_name"]}'
751
+ submit_url = submit_url.replace(old_str, new_str)
752
+ # file_name = f'HYCOM_{'-'.join([variable_info[v]["var_name"] for v in current_group])}_{download_time}.nc'
753
+ file_name = f'HYCOM_{key}_{download_time}.nc'
754
+ dlownload_file(submit_url, store_path, file_name, check)
755
+
756
+
757
+ def check_dataset_version_whold_day(dataset_name, version_name, download_time):
758
+ download_time = str(download_time)
759
+ if dataset_name is None and version_name is None:
760
+ print('The dataset_name and version_name are None, so the dataset and version will be chosen according to the download_time.\nIf there is more than one dataset and version in the time range, the first one will be chosen.')
761
+ print('If you wanna choose the dataset and version by yourself, please set the dataset_name and version_name together.')
762
+ ymd_in_which_dataset_and_version(download_time)
763
+ dataset_name, version_name = direct_choose_dataset_and_version_whole_day(download_time)
764
+ elif dataset_name is None and version_name is not None:
765
+ print('Please ensure the dataset_name is not None')
766
+ print('If you do not add the dataset_name, both the dataset and version will be chosen according to the download_time.')
767
+ ymd_in_which_dataset_and_version(download_time)
768
+ dataset_name, version_name = direct_choose_dataset_and_version_whole_day(download_time)
769
+ elif dataset_name is not None and version_name is None:
770
+ print('Please ensure the version_name is not None')
771
+ print('If you do not add the version_name, both the dataset and version will be chosen according to the download_time.')
772
+ ymd_in_which_dataset_and_version(download_time)
773
+ dataset_name, version_name = direct_choose_dataset_and_version_whole_day(download_time)
774
+ else:
775
+ print('The dataset_name and version_name are both set by yourself.')
776
+
777
+ return dataset_name, version_name
778
+
779
+
780
+ def direct_download_whole_day(var, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, download_time='20240831', depth=None, level_num=None, store_path=None, dataset_name=None, version_name=None, check=False):
781
+ download_time = str(download_time)[:8]+'00'
782
+ dataset_name, version_name = check_dataset_version_whold_day(dataset_name, version_name, download_time[:8])
783
+
784
+ if store_path is None:
785
+ store_path = str(Path.cwd())
786
+ else:
787
+ os.makedirs(str(store_path), exist_ok=True)
788
+
789
+ if isinstance(var, str):
790
+ var = [var]
791
+
792
+ if isinstance(var, list):
793
+ if len(var) == 1:
794
+ var = var[0]
795
+ submit_url = get_submit_url_var(var, depth, level_num, lon_min, lon_max, lat_min, lat_max, dataset_name, version_name, download_time)
796
+
797
+ # https://ncss.hycom.org/thredds/ncss/GLBu0.08/expt_93.0/ts3z?var=salinity&disableLLSubset=on&disableProjSubset=on&horizStride=1&time=2018-12-09T09%3A00%3A00Z&vertCoord=&accept=netcdf4
798
+ # https://ncss.hycom.org/thredds/ncss/GLBu0.08/expt_93.0/ts3z?var=salinity&disableLLSubset=on&disableProjSubset=on&horizStride=1&time_start=2018-09-19T12%3A00%3A00Z&time_end=2018-12-09T09%3A00%3A00Z&timeStride=1&vertCoord=&accept=netcdf4
799
+ # 将time=2018-12-09T09%3A00%3A00Z替换为time_start=2018-09-19T12%3A00%3A00Z&time_end=2018-12-09T09%3A00%3A00Z&timeStride=1
800
+ daytime_s = transform_time(str(download_time)[:8]+'00')
801
+ daytime_e = transform_time(str(download_time)[:8]+'21')
802
+ submit_url = submit_url.replace(
803
+ f'time={daytime_s}', f'time_start={daytime_s}&time_end={daytime_e}&timeStride=1')
804
+
805
+ file_name = f"HYCOM_{variable_info[var]['var_name']}_{download_time}.nc"
806
+
807
+ dlownload_file(submit_url, store_path, file_name, check)
808
+ else:
809
+ varlist = [_ for _ in var]
810
+ for key, value in var_group.items():
811
+ current_group = []
812
+ for v in varlist:
813
+ if v in value:
814
+ current_group.append(v)
815
+ if len(current_group) == 0:
816
+ continue
817
+
818
+ var = current_group[0]
819
+ submit_url = get_submit_url_var(var, depth, level_num, lon_min, lon_max, lat_min, lat_max, dataset_name, version_name, download_time)
820
+ daytime_s = transform_time(str(download_time)[:8]+'00')
821
+ daytime_e = transform_time(str(download_time)[:8]+'21')
822
+ submit_url = submit_url.replace(
823
+ f'time={daytime_s}', f'time_start={daytime_s}&time_end={daytime_e}&timeStride=1')
824
+ file_name = f"HYCOM_{variable_info[var]['var_name']}_{download_time}.nc"
825
+ old_str = f'var={variable_info[var]["var_name"]}'
826
+ new_str = f'var={variable_info[var]["var_name"]}'
827
+ if len(current_group) > 1:
828
+ for v in current_group[1:]:
829
+ new_str = f'{new_str}&var={variable_info[v]["var_name"]}'
830
+ submit_url = submit_url.replace(old_str, new_str)
831
+ # file_name = f'HYCOM_{'-'.join([variable_info[v]["var_name"] for v in current_group])}_{download_time}.nc'
832
+ file_name = f'HYCOM_{key}_{download_time}.nc'
833
+ dlownload_file(submit_url, store_path, file_name, check)
834
+
835
+
836
+ def convert_full_name_to_short_name(full_name):
837
+ for var, info in variable_info.items():
838
+ if full_name == info['var_name'] or full_name == info['standard_name'] or full_name == var:
839
+ return var
840
+ print('[bold #FFE4E1]Please ensure the var is in:\n[bold blue]u,v,temp,salt,ssh,u_b,v_b,temp_b,salt_b')
841
+ print('or')
842
+ print('[bold blue]water_u, water_v, water_temp, salinity, surf_el, water_u_bottom, water_v_bottom, water_temp_bottom, salinity_bottom')
843
+ return False
844
+
845
+
846
+ def download_task(var, time_str, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, check):
847
+ '''
848
+ # 并行下载任务
849
+ # 这个函数是为了并行下载而设置的,是必须的,直接调用direct_download并行下载会出问题
850
+
851
+ 任务封装:将每个任务需要的数据和操作封装在一个函数中,这样每个任务都是独立的,不会相互干扰。
852
+ 本情况下,download_task函数的作用是将每个下载任务封装起来,包括它所需的所有参数。
853
+ 这样,每个任务都是独立的,有自己的参数和数据,不会与其他任务共享或修改任何数据。
854
+ 因此,即使多个任务同时执行,也不会出现数据交互错乱的问题。
855
+ '''
856
+ if len(time_str) == 8:
857
+ direct_download_whole_day(var, lon_min, lon_max, lat_min, lat_max, time_str, depth, level, store_path, dataset_name, version_name, check)
858
+ else:
859
+ direct_download_single_time(var, lon_min, lon_max, lat_min, lat_max, time_str, depth, level, store_path, dataset_name, version_name, check)
860
+
861
+
862
+ def download(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False):
863
+ '''
864
+ Description:
865
+ Download the data of single time or a series of time
866
+
867
+ Parameters:
868
+ var: str, the variable name, such as 'u', 'v', 'temp', 'salt', 'ssh', 'u_b', 'v_b', 'temp_b', 'salt_b' or 'water_u', 'water_v', 'water_temp', 'salinity', 'surf_el', 'water_u_bottom', 'water_v_bottom', 'water_temp_bottom', 'salinity_bottom'
869
+ time_s: str, the start time, such as '2024110100' or '20241101', if add hour, the hour should be 00, 03, 06, 09, 12, 15, 18, 21
870
+ time_e: str, the end time, such as '2024110221' or '20241102', if add hour, the hour should be 00, 03, 06, 09, 12, 15, 18, 21
871
+ lon_min: float, the minimum longitude, default is 0
872
+ lon_max: float, the maximum longitude, default is 359.92
873
+ lat_min: float, the minimum latitude, default is -80
874
+ lat_max: float, the maximum latitude, default is 90
875
+ depth: float, the depth, default is None
876
+ level: int, the level number, default is None
877
+ store_path: str, the path to store the data, default is None
878
+ dataset_name: str, the dataset name, default is None, example: 'GLBv0.08', 'GLBu0.08', 'GLBy0.08'
879
+ version_name: str, the version name, default is None, example: '53.X', '56.3'
880
+ num_workers: int, the number of workers, default is None
881
+
882
+ Returns:
883
+ None
884
+ '''
885
+ if isinstance(var, list):
886
+ var = var[0]
887
+ var = convert_full_name_to_short_name(var)
888
+ if var is False:
889
+ raise ValueError('The var is invalid')
890
+ if lon_min < 0 or lon_min > 359.92 or lon_max < 0 or lon_max > 359.92 or lat_min < -80 or lat_min > 90 or lat_max < -80 or lat_max > 90:
891
+ print('Please ensure the lon_min, lon_max, lat_min, lat_max are in the range')
892
+ print('The range of lon_min, lon_max is 0~359.92')
893
+ print('The range of lat_min, lat_max is -80~90')
894
+ raise ValueError('The lon or lat is invalid')
895
+ ymdh_time_s = str(time_s)
896
+ if len(ymdh_time_s) == 8:
897
+ ymdh_time_s += '00'
898
+ ymdh_time_e = str(time_e)
899
+ if len(ymdh_time_e) == 8:
900
+ ymdh_time_e += '21'
901
+ if ymdh_time_s == ymdh_time_e:
902
+ direct_download_single_time(var, lon_min, lon_max, lat_min, lat_max, ymdh_time_s, depth, level, store_path, dataset_name, version_name)
903
+ elif int(ymdh_time_s) < int(ymdh_time_e):
904
+ print('Downloading a series of files...')
905
+ time_list = get_hour_list(ymdh_time_s, ymdh_time_e, 3)
906
+ with Progress() as progress:
907
+ task = progress.add_task("[cyan]Downloading...", total=len(time_list))
908
+ if num_workers is None or num_workers <= 1:
909
+ # 串行方式
910
+ for time_str in time_list:
911
+ direct_download_single_time(var, lon_min, lon_max, lat_min, lat_max, time_str, depth, level, store_path, dataset_name, version_name, check)
912
+ progress.update(task, advance=1)
913
+ else:
914
+ # 并行方式
915
+ if num_workers > 10:
916
+ print('The number of workers is too large!')
917
+ print('In order to avoid the server being blocked, the number of workers is set to 10')
918
+ num_workers = 10
919
+ with ThreadPoolExecutor(max_workers=num_workers) as executor:
920
+ futures = [executor.submit(download_task, var, time_str, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, check) for time_str in time_list]
921
+ for future in futures:
922
+ future.add_done_callback(
923
+ lambda _: progress.update(task, advance=1))
924
+ else:
925
+ print('Please ensure the ymdh_time_s is less than the ymdh_time_e')
926
+
927
+
928
+ def download_single_hour(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False):
929
+ '''
930
+ Description:
931
+ Download the data of single time or a series of time
932
+
933
+ Parameters:
934
+ var: str, the variable name, such as 'u', 'v', 'temp', 'salt', 'ssh', 'u_b', 'v_b', 'temp_b', 'salt_b' or 'water_u', 'water_v', 'water_temp', 'salinity', 'surf_el', 'water_u_bottom', 'water_v_bottom', 'water_temp_bottom', 'salinity_bottom'
935
+ time_s: str, the start time, such as '2024110100' or '20241101', if add hour, the hour should be 00, 03, 06, 09, 12, 15, 18, 21
936
+ time_e: str, the end time, such as '2024110221' or '20241102', if add hour, the hour should be 00, 03, 06, 09, 12, 15, 18, 21
937
+ lon_min: float, the minimum longitude, default is 0
938
+ lon_max: float, the maximum longitude, default is 359.92
939
+ lat_min: float, the minimum latitude, default is -80
940
+ lat_max: float, the maximum latitude, default is 90
941
+ depth: float, the depth, default is None
942
+ level: int, the level number, default is None
943
+ store_path: str, the path to store the data, default is None
944
+ dataset_name: str, the dataset name, default is None, example: 'GLBv0.08', 'GLBu0.08', 'GLBy0.08'
945
+ version_name: str, the version name, default is None, example: '53.X', '56.3'
946
+ num_workers: int, the number of workers, default is None
947
+
948
+ Returns:
949
+ None
950
+ '''
951
+ if isinstance(var, list):
952
+ if len(var) == 1:
953
+ var = convert_full_name_to_short_name(var[0])
954
+ else:
955
+ var = [convert_full_name_to_short_name(v) for v in var]
956
+ elif isinstance(var, str):
957
+ var = convert_full_name_to_short_name(var)
958
+ else:
959
+ raise ValueError('The var is invalid')
960
+ if var is False:
961
+ raise ValueError('The var is invalid')
962
+ if lon_min < 0 or lon_min > 359.92 or lon_max < 0 or lon_max > 359.92 or lat_min < -80 or lat_min > 90 or lat_max < -80 or lat_max > 90:
963
+ print('Please ensure the lon_min, lon_max, lat_min, lat_max are in the range')
964
+ print('The range of lon_min, lon_max is 0~359.92')
965
+ print('The range of lat_min, lat_max is -80~90')
966
+ raise ValueError('The lon or lat is invalid')
967
+ ymdh_time_s = str(time_s)
968
+ if len(ymdh_time_s) == 8:
969
+ ymdh_time_s += '00'
970
+ ymdh_time_e = str(time_e)
971
+ if len(ymdh_time_e) == 8:
972
+ ymdh_time_e += '21'
973
+ if ymdh_time_s == ymdh_time_e:
974
+ direct_download_single_time(var, lon_min, lon_max, lat_min, lat_max, ymdh_time_s, depth, level, store_path, dataset_name, version_name)
975
+ elif int(ymdh_time_s) < int(ymdh_time_e):
976
+ print('Downloading a series of files...')
977
+ time_list = get_hour_list(ymdh_time_s, ymdh_time_e, 3)
978
+ with Progress() as progress:
979
+ task = progress.add_task("[cyan]Downloading...", total=len(time_list))
980
+ if num_workers is None or num_workers <= 1:
981
+ # 串行方式
982
+ for time_str in time_list:
983
+ direct_download_single_time(var, lon_min, lon_max, lat_min, lat_max, time_str, depth, level, store_path, dataset_name, version_name, check)
984
+ progress.update(task, advance=1)
985
+ else:
986
+ # 并行方式
987
+ if num_workers > 10:
988
+ print('The number of workers is too large!')
989
+ print('In order to avoid the server being blocked, the number of workers is set to 10')
990
+ num_workers = 10
991
+ with ThreadPoolExecutor(max_workers=num_workers) as executor:
992
+ futures = [executor.submit(download_task, var, time_str, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, check) for time_str in time_list]
993
+ for future in futures:
994
+ future.add_done_callback(
995
+ lambda _: progress.update(task, advance=1))
996
+ else:
997
+ print('Please ensure the time_s is less than the time_e')
998
+
999
+
1000
+ def download_whole_day(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False):
1001
+ '''
1002
+ Description:
1003
+ Download the data of single time or a series of time
1004
+
1005
+ Parameters:
1006
+ var: str, the variable name, such as 'u', 'v', 'temp', 'salt', 'ssh', 'u_b', 'v_b', 'temp_b', 'salt_b' or 'water_u', 'water_v', 'water_temp', 'salinity', 'surf_el', 'water_u_bottom', 'water_v_bottom', 'water_temp_bottom', 'salinity_bottom'
1007
+ time_s: str, the start time, such as '20241101', without hour
1008
+ time_e: str, the end time, such as '20241102', without hour
1009
+ lon_min: float, the minimum longitude, default is 0
1010
+ lon_max: float, the maximum longitude, default is 359.92
1011
+ lat_min: float, the minimum latitude, default is -80
1012
+ lat_max: float, the maximum latitude, default is 90
1013
+ depth: float, the depth, default is None
1014
+ level: int, the level number, default is None
1015
+ store_path: str, the path to store the data, default is None
1016
+ dataset_name: str, the dataset name, default is None, example: 'GLBv0.08', 'GLBu0.08', 'GLBy0.08'
1017
+ version_name: str, the version name, default is None, example: '53.X', '56.3'
1018
+ num_workers: int, the number of workers, default is None
1019
+
1020
+ Returns:
1021
+ None
1022
+ '''
1023
+ if isinstance(var, list):
1024
+ if len(var) == 1:
1025
+ var = convert_full_name_to_short_name(var[0])
1026
+ else:
1027
+ var = [convert_full_name_to_short_name(v) for v in var]
1028
+ elif isinstance(var, str):
1029
+ var = convert_full_name_to_short_name(var)
1030
+ else:
1031
+ raise ValueError('The var is invalid')
1032
+ if var is False:
1033
+ raise ValueError('The var is invalid')
1034
+ if lon_min < 0 or lon_min > 359.92 or lon_max < 0 or lon_max > 359.92 or lat_min < -80 or lat_min > 90 or lat_max < -80 or lat_max > 90:
1035
+ print('Please ensure the lon_min, lon_max, lat_min, lat_max are in the range')
1036
+ print('The range of lon_min, lon_max is 0~359.92')
1037
+ print('The range of lat_min, lat_max is -80~90')
1038
+ raise ValueError('The lon or lat is invalid')
1039
+ time_s, time_e = str(time_s)[:8], str(time_e)[:8]
1040
+
1041
+ if time_s == time_e:
1042
+ direct_download_whole_day(var, lon_min, lon_max, lat_min, lat_max, time_s, depth, level, store_path, dataset_name, version_name)
1043
+ elif int(time_s) < int(time_e):
1044
+ print('Downloading a series of files...')
1045
+ time_list = get_day_list(time_s, time_e, 1)
1046
+ with Progress() as progress:
1047
+ task = progress.add_task("[cyan]Downloading...", total=len(time_list))
1048
+ if num_workers is None or num_workers <= 1:
1049
+ # 串行方式
1050
+ for time_str in time_list:
1051
+ direct_download_whole_day(var, lon_min, lon_max, lat_min, lat_max, time_str, depth, level, store_path, dataset_name, version_name, check)
1052
+ progress.update(task, advance=1)
1053
+ else:
1054
+ # 并行方式
1055
+ if num_workers > 10:
1056
+ print('The number of workers is too large!')
1057
+ print('In order to avoid the server being blocked, the number of workers is set to 10')
1058
+ num_workers = 10
1059
+ with ThreadPoolExecutor(max_workers=num_workers) as executor:
1060
+ futures = [executor.submit(download_task, var, time_str, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, check) for time_str in time_list]
1061
+ for future in futures:
1062
+ future.add_done_callback(
1063
+ lambda _: progress.update(task, advance=1))
1064
+ else:
1065
+ print('Please ensure the time_s is less than the time_e')
1066
+
1067
+
1068
+ def how_to_use():
1069
+ print('''
1070
+ # 1. Choose the dataset and version according to the time:
1071
+ # 1.1 Use function to query
1072
+ You can use the function ymd_in_which_dataset_and_version(time_ymd=20241101) to find the dataset and version according to the time.
1073
+ Then, you can see the dataset and version in the output.
1074
+ # 1.2 Draw a picture to see
1075
+ You can draw a picture to see the time range of each dataset and version.
1076
+ Using the function draw_time_range(pic_save_folder=None) to draw the picture.
1077
+
1078
+ # 2. Get the base url according to the dataset, version, var and year:
1079
+ # 2.1 Dataset and version were found in step 1
1080
+ # 2.2 Var: u, v, temp, salt, ssh, u_b, v_b, temp_b, salt_b
1081
+ # 2.3 Year: 1994-2024(current year)
1082
+
1083
+ # 3. Get the query_dict according to the var, lon_min, lon_max, lat_min, lat_max, depth, level_num, time_str_ymdh:
1084
+ # 3.1 Var: u, v, temp, salt, ssh, u_b, v_b, temp_b, salt_b
1085
+ # 3.2 Lon_min, lon_max, lat_min, lat_max: float
1086
+ # 3.3 Depth: 0-5000m, if you wanna get single depth data, you can set the depth
1087
+ # 3.4 Level_num: 1-40, if you wanna get single level data, you can set the level_num
1088
+ # 3.5 Time_str_ymdh: '2024110112', the hour normally is 00, 03, 06, 09, 12, 15, 18, 21, besides 1 hourly data
1089
+ # 3.6 Use the function to get the query_dict
1090
+ # 3.7 Note: If you wanna get the full depth or full level data, you can needn't set the depth or level_num
1091
+
1092
+ # 4. Get the submit url according to the dataset, version, var, year, query_dict:
1093
+ # 4.1 Use the function to get the submit url
1094
+ # 4.2 You can use the submit url to download the data
1095
+
1096
+ # 5. Download the data according to the submit url:
1097
+ # 5.1 Use the function to download the data
1098
+ # 5.2 You can download the data of single time or a series of time
1099
+ # 5.3 Note: If you wanna download a series of data, you can set the ymdh_time_s and ymdh_time_e different
1100
+ # 5.4 Note: The time resolution is 3 hours
1101
+
1102
+ # 6. Direct download the data:
1103
+ # 6.1 Use the function to direct download the data
1104
+ # 6.2 You can set the dataset_name and version_name by yourself
1105
+ # 6.3 Note: If you do not set the dataset_name and version_name, the dataset and version will be chosen according to the download_time
1106
+ # 6.4 Note: If you set the dataset_name and version_name, please ensure the dataset_name and version_name are correct
1107
+ # 6.5 Note: If you just set one of the dataset_name and version_name, both the dataset and version will be chosen according to the download_time
1108
+
1109
+ # 7. Simple use:
1110
+ # 7.1 You can use the function: download(var, ymdh_time_s, ymdh_time_e, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level_num=None, store_path=None, dataset_name=None, version_name=None)
1111
+ # 7.2 You can download the data of single time or a series of time
1112
+ # 7.3 The parameters you must set are var, ymdh_time_s, ymdh_time_e
1113
+ # 7.4 Example: download('u', '2024110112', '2024110212', lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level_num=None, store_path=None, dataset_name=None, version_name=None)
1114
+ ''')
1115
+
1116
+
1117
+ if __name__ == '__main__':
1118
+ time_s, time_e = '2018010512', '2018010800'
1119
+ merge_name = '201801'
1120
+ root_path = r'I:\hycom_data_2018'
1121
+ location_dict = {'west': 115, 'east': 130, 'south': 33, 'north': 45}
1122
+ download_dict = {
1123
+ 'water_u': {'simple_name': 'u', 'download': 1},
1124
+ 'water_v': {'simple_name': 'v', 'download': 1},
1125
+ 'surf_el': {'simple_name': 'ssh', 'download': 1},
1126
+ 'water_temp': {'simple_name': 'temp', 'download': 1},
1127
+ 'salinity': {'simple_name': 'salt', 'download': 1},
1128
+ }
1129
+
1130
+ # set depth or level, only one can be True
1131
+ # if you wanna download all depth or level, set both False
1132
+ set_depth, depth = False, 0 # 0-4000 meters
1133
+ set_level, level = False, 1 # 1-40 levels
1134
+ num_workers = 1
1135
+ check = True
1136
+
1137
+ download_switch = True
1138
+ combine_switch = False
1139
+
1140
+ def download_var(var_name):
1141
+ var = download_dict[var_name]['simple_name']
1142
+ if_download = download_dict[var_name]['download']
1143
+ if if_download == 0:
1144
+ return
1145
+ if set_depth:
1146
+ download_whole_day(var=var, time_s=time_s, time_e=time_e, store_path=Path(root_path)/var, lon_min=location_dict[
1147
+ 'west'], lon_max=location_dict['east'], lat_min=location_dict['south'], lat_max=location_dict['north'], depth=depth, num_workers=num_workers, check=check)
1148
+ elif set_level:
1149
+ download_whole_day(var=var, time_s=time_s, time_e=time_e, store_path=Path(root_path)/var, lon_min=location_dict[
1150
+ 'west'], lon_max=location_dict['east'], lat_min=location_dict['south'], lat_max=location_dict['north'], level=level, num_workers=num_workers, check=check)
1151
+ else:
1152
+ download_whole_day(var=var, time_s=time_s, time_e=time_e, store_path=Path(root_path)/var, lon_min=location_dict[
1153
+ 'west'], lon_max=location_dict['east'], lat_min=location_dict['south'], lat_max=location_dict['north'], num_workers=num_workers, check=check)
1154
+
1155
+ if download_switch:
1156
+ for var_name in download_dict.keys():
1157
+ download_var(var_name)
1158
+
1159
+ # draw_time_range(r'I:\Delete')
1160
+
1161
+ """ if combine_switch:
1162
+ time_list = get_time_list(time_s, time_e, 3)
1163
+ for var_name in download_dict.keys():
1164
+ var = download_dict[var_name]['simple_name']
1165
+ if_download = download_dict[var_name]['download']
1166
+ if if_download == 0:
1167
+ continue
1168
+ file_list = []
1169
+ for time_str in time_list:
1170
+ file_list.append(
1171
+ Path(root_path)/var/f'HYCOM_{var_name}_{time_str}.nc')
1172
+ merge5nc(file_list, var_name, 'time',
1173
+ Path(root_path)/var/f'HYCOM_{var_name}_{merge_name}.nc') """