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