geospacelab 0.11.4__py3-none-any.whl → 0.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. geospacelab/__init__.py +1 -1
  2. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/downloader.py +103 -0
  3. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/edr_aur/__init__.py +17 -7
  4. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/edr_aur/downloader.py +13 -62
  5. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/sdr_disk/__init__.py +317 -0
  6. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/sdr_disk/downloader.py +44 -0
  7. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/sdr_disk/loader.py +198 -0
  8. geospacelab/datahub/sources/cdaweb/dmsp/ssusi/sdr_disk/variable_config.py +149 -0
  9. geospacelab/datahub/sources/cdaweb/downloader.py +396 -97
  10. geospacelab/datahub/sources/cdaweb/downloader_backup.py +93 -0
  11. geospacelab/datahub/sources/cdaweb/omni/__init__.py +26 -14
  12. geospacelab/datahub/sources/cdaweb/omni/downloader.py +97 -84
  13. geospacelab/datahub/sources/esa_eo/swarm/advanced/efi_tct02/__init__.py +1 -1
  14. geospacelab/datahub/sources/esa_eo/swarm/advanced/efi_tct02/downloader.py +1 -1
  15. geospacelab/datahub/sources/gfz/hpo/__init__.py +1 -1
  16. geospacelab/datahub/sources/gfz/hpo/variable_config.py +3 -1
  17. geospacelab/datahub/sources/madrigal/isr/pfisr/fitted/loader.py +1 -1
  18. geospacelab/datahub/sources/madrigal/satellites/dmsp/downloader.py +2 -1
  19. geospacelab/datahub/sources/tud/champ/dns_acc/__init__.py +24 -7
  20. geospacelab/datahub/sources/tud/champ/dns_acc/downloader.py +29 -36
  21. geospacelab/datahub/sources/tud/champ/dns_acc/loader.py +28 -2
  22. geospacelab/datahub/sources/tud/champ/wnd_acc/__init__.py +68 -10
  23. geospacelab/datahub/sources/tud/champ/wnd_acc/downloader.py +29 -36
  24. geospacelab/datahub/sources/tud/champ/wnd_acc/loader.py +36 -7
  25. geospacelab/datahub/sources/tud/champ/wnd_acc/variable_config.py +3 -3
  26. geospacelab/datahub/sources/tud/downloader.py +288 -113
  27. geospacelab/datahub/sources/tud/goce/dns_acc/__init__.py +354 -0
  28. geospacelab/datahub/sources/tud/goce/dns_acc/downloader.py +42 -0
  29. geospacelab/datahub/sources/tud/goce/dns_acc/loader.py +66 -0
  30. geospacelab/datahub/sources/tud/goce/dns_acc/variable_config.py +139 -0
  31. geospacelab/datahub/sources/tud/goce/dns_wnd_acc/__init__.py +3 -3
  32. geospacelab/datahub/sources/tud/goce/dns_wnd_acc_v01/__init__.py +339 -0
  33. geospacelab/datahub/sources/tud/goce/dns_wnd_acc_v01/downloader.py +42 -0
  34. geospacelab/datahub/sources/tud/goce/dns_wnd_acc_v01/loader.py +84 -0
  35. geospacelab/datahub/sources/tud/goce/dns_wnd_acc_v01/variable_config.py +212 -0
  36. geospacelab/datahub/sources/tud/goce/wnd_acc/__init__.py +339 -0
  37. geospacelab/datahub/sources/tud/goce/wnd_acc/downloader.py +42 -0
  38. geospacelab/datahub/sources/tud/goce/wnd_acc/loader.py +65 -0
  39. geospacelab/datahub/sources/tud/goce/wnd_acc/variable_config.py +188 -0
  40. geospacelab/datahub/sources/tud/grace/dns_acc/__init__.py +6 -3
  41. geospacelab/datahub/sources/tud/grace/dns_acc/downloader.py +29 -37
  42. geospacelab/datahub/sources/tud/grace/wnd_acc/__init__.py +21 -4
  43. geospacelab/datahub/sources/tud/grace/wnd_acc/downloader.py +29 -39
  44. geospacelab/datahub/sources/tud/grace/wnd_acc/loader.py +5 -1
  45. geospacelab/datahub/sources/tud/grace/wnd_acc/variable_config.py +74 -0
  46. geospacelab/datahub/sources/tud/grace_fo/dns_acc/__init__.py +6 -3
  47. geospacelab/datahub/sources/tud/grace_fo/dns_acc/downloader.py +35 -40
  48. geospacelab/datahub/sources/tud/grace_fo/wnd_acc/__init__.py +20 -4
  49. geospacelab/datahub/sources/tud/grace_fo/wnd_acc/downloader.py +29 -44
  50. geospacelab/datahub/sources/tud/grace_fo/wnd_acc/loader.py +4 -0
  51. geospacelab/datahub/sources/tud/grace_fo/wnd_acc/variable_config.py +73 -0
  52. geospacelab/datahub/sources/tud/swarm/dns_acc/__init__.py +27 -5
  53. geospacelab/datahub/sources/tud/swarm/dns_acc/downloader.py +29 -38
  54. geospacelab/datahub/sources/tud/swarm/dns_pod/__init__.py +24 -5
  55. geospacelab/datahub/sources/tud/swarm/dns_pod/downloader.py +29 -38
  56. geospacelab/datahub/sources/tud/swarm/dns_pod/loader.py +3 -0
  57. geospacelab/datahub/sources/wdc/asysym/downloader.py +2 -2
  58. geospacelab/visualization/mpl/panels.py +7 -3
  59. {geospacelab-0.11.4.dist-info → geospacelab-0.12.0.dist-info}/METADATA +1 -1
  60. {geospacelab-0.11.4.dist-info → geospacelab-0.12.0.dist-info}/RECORD +63 -45
  61. {geospacelab-0.11.4.dist-info → geospacelab-0.12.0.dist-info}/WHEEL +1 -1
  62. {geospacelab-0.11.4.dist-info → geospacelab-0.12.0.dist-info}/licenses/LICENSE +0 -0
  63. {geospacelab-0.11.4.dist-info → geospacelab-0.12.0.dist-info}/top_level.txt +0 -0
@@ -22,129 +22,304 @@ from contextlib import closing
22
22
  from geospacelab.datahub.__dataset_base__ import DownloaderBase
23
23
  import geospacelab.toolbox.utilities.pydatetime as dttool
24
24
  import geospacelab.toolbox.utilities.pylogging as mylog
25
- import geospacelab.datahub.sources.wdc as wdc
26
-
27
-
28
- class Downloader(DownloaderBase):
29
- """
30
- Base downloader for downloading the SWARM data files from ftp://swarm-diss.eo.esa.int/
31
-
32
- :param ftp_host: the FTP host address
33
- :type ftp_host: str
34
- :param ftp_port: the FTP port [21].
35
- :type ftp_port: int
36
- :param ftp_data_dir: the directory in the FTP that stores the data.
37
- :type ftp_data_dir: str
38
- """
39
-
40
- def __init__(self,
41
- dt_fr, dt_to,
42
- data_file_root_dir=None, ftp_data_dir=None, force=True, direct_download=True, file_name_patterns=[],
43
- **kwargs):
44
- self.ftp_host = "thermosphere.tudelft.nl"
45
- self.ftp_port = 21
46
- if ftp_data_dir is None:
47
- raise ValueError
48
-
49
- self.ftp_data_dir = ftp_data_dir
50
-
51
- self.file_name_patterns = file_name_patterns
52
-
53
- super(Downloader, self).__init__(
54
- dt_fr, dt_to, data_file_root_dir=data_file_root_dir, force=force, direct_download=direct_download, **kwargs
55
- )
56
-
57
- def download(self, **kwargs):
58
- done = False
59
- try:
60
- ftp = ftplib.FTP()
61
- ftp.connect(self.ftp_host, self.ftp_port, 30) # 30 timeout
62
- ftp.login()
63
- ftp.cwd(self.ftp_data_dir)
64
- file_list = ftp.nlst()
65
-
66
- file_names = self.search_files(file_list=file_list, file_name_patterns=self.file_name_patterns)
67
- file_dir_root = self.data_file_root_dir
68
- for ind_f, file_name in enumerate(file_names):
69
-
70
- file_path = file_dir_root / file_name
71
-
72
- if file_path.is_file():
73
- mylog.simpleinfo.info(
74
- "The file {} exists in the directory {}.".format(
75
- file_path.name, file_path.parent.resolve()
76
- )
77
- )
78
- if not self.force:
79
- done = True
80
- continue
81
- else:
82
- file_path.parent.resolve().mkdir(parents=True, exist_ok=True)
83
- mylog.simpleinfo.info(
84
- f"Downloading the file {file_name} from the FTP ..."
85
- )
86
- try:
87
- with open(file_path, 'w+b') as f:
88
- done = False
89
- res = ftp.retrbinary('RETR ' + file_name, f.write)
90
- print(res)
91
- if not res.startswith('226'):
92
- mylog.StreamLogger.warning('Downloaded of file {0} is not compile.'.format(file_name))
93
- pathlib.Path.unlink(file_path)
94
- done = False
95
- return done
96
- mylog.simpleinfo.info("Done.")
97
- except:
98
- pathlib.Path.unlink(file_path)
99
- mylog.StreamLogger.warning('Downloaded of file {0} is not compile.'.format(file_name))
100
- return False
101
- mylog.simpleinfo.info("Uncompressing the file ...")
25
+ from geospacelab.config import prf
26
+
27
+ from geospacelab.datahub.sources.cdaweb.downloader import DownloaderFromHTTPBase as DownloaderBase
28
+
29
+
30
+ class TUDownloader(DownloaderBase):
31
+
32
+ root_dir_remote = 'data/data'
33
+
34
+ def __init__(
35
+ self,
36
+ dt_fr, dt_to,
37
+ mission='SWARM',
38
+ sat_id=None,
39
+ product='DNS-POD',
40
+ version='v02',
41
+ root_dir_local=None,
42
+ direct_download=True,
43
+ force_download=False, dry_run=False,
44
+ **kwargs):
45
+
46
+ base_url = 'https://thermosphere.tudelft.nl'
47
+ if root_dir_local is None:
48
+ root_dir_local = prf.datahub_data_root_dir / 'TUD'
49
+
50
+ self.mission = mission
51
+ self.sat_id = sat_id
52
+ self.product = product
53
+ self.version = version
54
+
55
+ self._validate_mission_name()
56
+ self._validate_sat_id()
57
+ self._validate_product()
58
+ self._validate_version()
59
+ super().__init__(
60
+ dt_fr, dt_to,
61
+ base_url=base_url,
62
+ root_dir_local=root_dir_local,
63
+ direct_download=direct_download,
64
+ force_download=force_download,
65
+ dry_run=dry_run, **kwargs)
66
+
67
+ def search_from_http(self, subdirs = None, file_name_patterns = None, **kwargs):
68
+
69
+ diff_months = dttool.get_diff_months(self.dt_fr, self.dt_to)
70
+ file_paths_remote = []
71
+ for nm in range(diff_months + 1):
72
+ this_month = dttool.get_next_n_months(self.dt_fr, nm)
73
+
74
+ subdirs = [version_dict[self.version[:3]]]
75
+ subdirs.append(self.mission + '_data')
76
+
77
+ file_name_patterns = [
78
+ self.mission[0] + self.sat_id,
79
+ self.product.replace('-', '_'),
80
+ this_month.strftime('%Y'),
81
+ this_month.strftime('%m'),
82
+ self.version
83
+ ]
84
+ paths = super().search_from_http(subdirs, file_name_patterns, **kwargs)
85
+ if len(paths) > 1:
86
+ mylog.StreamLogger.warning(
87
+ f"Multiple versions found for {this_month.strftime('%Y-%m')}. All versions will be downloaded.")
88
+ file_paths_remote.extend(paths)
89
+ return file_paths_remote
90
+
91
+ def save_files_from_http(self, file_paths_local=None, root_dir_remote=None):
92
+
93
+ file_paths_local = []
94
+ for fp_remote in self.file_paths_remote:
95
+ fn_remote = fp_remote.split('/')[-1]
96
+
97
+ rc = re.compile(r'_(v[\w]+)')
98
+ rm = rc.search(fn_remote)
99
+ if rm is None:
100
+ raise ValueError(f"Cannot extract version info from file name {fn_remote}.")
101
+ version_in_fn = rm.groups()[0]
102
+
103
+ replacement = '/'.join([s.strip('/') for s in [
104
+ self.base_url,
105
+ self.root_dir_remote,
106
+ version_dict[version_in_fn[:3]],
107
+ self.mission + '_data'
108
+ ]]) + '/'
109
+
110
+ fp_local = fp_remote.replace(replacement, '')
111
+ file_paths_local.append(
112
+ self.root_dir_local / self.mission.upper() /
113
+ self.product.upper() / version_in_fn / fp_local)
114
+ super().save_files_from_http(file_paths_local, root_dir_remote)
115
+
116
+ for i, (done, file_path) in enumerate(zip(self.done, self.file_paths_local)):
117
+ if not done:
118
+ continue
119
+ else:
120
+ if not file_path.exists():
121
+ continue
122
+ mylog.simpleinfo.info(f"Uncompressing the file: {file_path} ...")
102
123
  with zipfile.ZipFile(file_path, 'r') as zip_ref:
103
124
  zip_ref.extractall(file_path.parent.resolve())
104
125
  file_path.unlink()
105
- mylog.simpleinfo.info("Done. The zip file has been removed.")
106
-
107
- done = True
108
- ftp.quit()
109
- except Exception as err:
110
- print(err)
111
- print('Error during download from FTP')
112
- done = False
113
- return done
114
-
115
- def search_files(self, file_list=None, file_name_patterns=None):
116
- def extract_timeline(files):
126
+ mylog.simpleinfo.info("Done. The zip file has been removed.")
127
+ self.file_paths_local[i] = file_path.with_suffix('.txt') # Update to unzipped file path
128
+ return
129
+
130
+ def _to_download(self, file_path, with_suffix='.txt'):
131
+ return super()._to_download(file_path, with_suffix=with_suffix)
132
+
133
+ def _validate_mission_name(self):
134
+ if self.mission.lower() == 'swarm':
135
+ self.mission = 'Swarm'
136
+ elif self.mission.lower() in ['champ', 'grace', 'goce', 'grace-fo']:
137
+ self.mission = self.mission.upper()
138
+ else:
139
+ raise NotImplementedError(f"Mission {self.mission} is not supported.")
140
+
141
+ def _validate_product(self):
142
+ if self.mission == 'Swarm' and self.sat_id in ['A', 'B', 'C']:
143
+ valid_products = ['DNS-POD', 'DNS-ACC']
144
+ assert self.product in valid_products, f"Invalid product {self.product}. Valid products are {valid_products}."
145
+ elif self.mission in ['CHAMP', 'GRACE', 'GOCE', 'GRACE-FO']:
146
+ valid_products = ['DNS-ACC', 'WND-ACC']
147
+ assert self.product in valid_products, f"Invalid product {self.product}. Valid products are {valid_products}."
148
+ else:
149
+ raise NotImplementedError(f"Mission {self.mission} with sat_id {self.sat_id} is not supported.")
150
+ return
117
151
 
118
- nf = len(files)
119
- dt_list = []
120
- for ind, fn in enumerate(files):
121
- dt_regex = re.compile(r'_(\d{4}_\d{2})_')
122
- rm = dt_regex.findall(fn)
123
- if not list(rm):
124
- continue
125
- dt_list.append(datetime.datetime.strptime(rm[0] + '_01', '%Y_%m_%d'))
126
- dt_list = np.array(dt_list, dtype=datetime.datetime)
152
+
153
+ def _validate_sat_id(self):
154
+
155
+ if self.mission.upper() == 'SWARM':
156
+ valid_sat_ids = ['A', 'B', 'C']
157
+ assert self.sat_id in valid_sat_ids, f"Invalid sat_id {self.sat_id}. Valid sat_ids are {valid_sat_ids}."
158
+ elif self.mission.upper() == 'CHAMP':
159
+ valid_sat_ids = ['']
160
+ assert self.sat_id in valid_sat_ids, f"Invalid sat_id {self.sat_id}. Valid sat_ids are {valid_sat_ids}."
161
+ elif self.mission.upper() == 'GRACE':
162
+ valid_sat_ids = ['A', 'B']
163
+ assert self.sat_id in valid_sat_ids, f"Invalid sat_id {self.sat_id}. Valid sat_ids are {valid_sat_ids}."
164
+ elif self.mission.upper() == 'GOCE':
165
+ valid_sat_ids = ['']
166
+ assert self.sat_id in valid_sat_ids, f"Invalid sat_id {self.sat_id}. Valid sat_ids are {valid_sat_ids}."
167
+ elif self.mission.upper() == 'GRACE-FO':
168
+ valid_sat_ids = ['FO1', '1', 'C']
169
+ assert self.sat_id in valid_sat_ids, f"Invalid sat_id {self.sat_id}. Valid sat_ids are {valid_sat_ids}."
170
+ self.sat_id = 'C' # Standardize to 'C' for GRACE-FO
171
+ else:
172
+ raise NotImplementedError(f"Mission {self.mission} is not supported.")
173
+ return
174
+
175
+ def _validate_version(self):
176
+ if self.mission.upper() in ['SWARM', 'CHAMP', 'GOCE', 'GRACE']:
177
+ valid_versions = ['v01', 'v02']
178
+ assert self.version in valid_versions, f"Invalid version {self.version}. Valid versions are {valid_versions}."
179
+ elif self.mission.upper() == 'GRACE-FO':
180
+ valid_versions = ['v02']
181
+ assert self.version in valid_versions, f"Invalid version {self.version}. Valid versions are {valid_versions}."
182
+ else:
183
+ raise NotImplementedError(f"Mission {self.mission} is not supported.")
184
+ return
185
+
186
+ version_dict = {
187
+ 'v01': 'version_01',
188
+ 'v02': 'version_02',
189
+ }
190
+
191
+
192
+ # class Downloader(DownloaderBase):
193
+ # """
194
+ # Base downloader for downloading the SWARM data files from ftp://swarm-diss.eo.esa.int/
195
+
196
+ # :param ftp_host: the FTP host address
197
+ # :type ftp_host: str
198
+ # :param ftp_port: the FTP port [21].
199
+ # :type ftp_port: int
200
+ # :param ftp_data_dir: the directory in the FTP that stores the data.
201
+ # :type ftp_data_dir: str
202
+ # """
203
+
204
+ # def __init__(self,
205
+ # dt_fr, dt_to,
206
+ # data_file_root_dir=None, ftp_data_dir=None, force=True, direct_download=True, file_name_patterns=[],
207
+ # **kwargs):
208
+ # self.ftp_host = "thermosphere.tudelft.nl"
209
+ # self.ftp_port = 21
210
+ # if ftp_data_dir is None:
211
+ # raise ValueError
212
+
213
+ # self.ftp_data_dir = ftp_data_dir
214
+
215
+ # self.file_name_patterns = file_name_patterns
216
+
217
+ # super(Downloader, self).__init__(
218
+ # dt_fr, dt_to, data_file_root_dir=data_file_root_dir, force=force, direct_download=direct_download, **kwargs
219
+ # )
220
+
221
+
222
+ # def download_from_http(self, **kwargs):
223
+
224
+ # return
225
+
226
+
227
+ # def download_from_ftp(self, **kwargs):
228
+ # """[DEPRECATED] Download data files from FTP server.
229
+
230
+ # Returns:
231
+ # _type_: _description_
232
+ # """
233
+ # done = False
234
+ # try:
235
+ # ftp = ftplib.FTP()
236
+ # ftp.connect(self.ftp_host, self.ftp_port, 30) # 30 timeout
237
+ # ftp.login()
238
+ # ftp.cwd(self.ftp_data_dir)
239
+ # file_list = ftp.nlst()
240
+
241
+ # file_names = self.search_files(file_list=file_list, file_name_patterns=self.file_name_patterns)
242
+ # file_dir_root = self.data_file_root_dir
243
+ # for ind_f, file_name in enumerate(file_names):
244
+
245
+ # file_path = file_dir_root / file_name
246
+
247
+ # if file_path.is_file():
248
+ # mylog.simpleinfo.info(
249
+ # "The file {} exists in the directory {}.".format(
250
+ # file_path.name, file_path.parent.resolve()
251
+ # )
252
+ # )
253
+ # if not self.force:
254
+ # done = True
255
+ # continue
256
+ # else:
257
+ # file_path.parent.resolve().mkdir(parents=True, exist_ok=True)
258
+ # mylog.simpleinfo.info(
259
+ # f"Downloading the file {file_name} from the FTP ..."
260
+ # )
261
+ # try:
262
+ # with open(file_path, 'w+b') as f:
263
+ # done = False
264
+ # res = ftp.retrbinary('RETR ' + file_name, f.write)
265
+ # print(res)
266
+ # if not res.startswith('226'):
267
+ # mylog.StreamLogger.warning('Downloaded of file {0} is not compile.'.format(file_name))
268
+ # pathlib.Path.unlink(file_path)
269
+ # done = False
270
+ # return done
271
+ # mylog.simpleinfo.info("Done.")
272
+ # except:
273
+ # pathlib.Path.unlink(file_path)
274
+ # mylog.StreamLogger.warning('Downloaded of file {0} is not compile.'.format(file_name))
275
+ # return False
276
+ # mylog.simpleinfo.info("Uncompressing the file ...")
277
+ # with zipfile.ZipFile(file_path, 'r') as zip_ref:
278
+ # zip_ref.extractall(file_path.parent.resolve())
279
+ # file_path.unlink()
280
+ # mylog.simpleinfo.info("Done. The zip file has been removed.")
281
+
282
+ # done = True
283
+ # ftp.quit()
284
+ # except Exception as err:
285
+ # print(err)
286
+ # print('Error during download from FTP')
287
+ # done = False
288
+ # return done
289
+
290
+ # def search_files(self, file_list=None, file_name_patterns=None):
291
+ # def extract_timeline(files):
292
+
293
+ # nf = len(files)
294
+ # dt_list = []
295
+ # for ind, fn in enumerate(files):
296
+ # dt_regex = re.compile(r'_(\d{4}_\d{2})_')
297
+ # rm = dt_regex.findall(fn)
298
+ # if not list(rm):
299
+ # continue
300
+ # dt_list.append(datetime.datetime.strptime(rm[0] + '_01', '%Y_%m_%d'))
301
+ # dt_list = np.array(dt_list, dtype=datetime.datetime)
127
302
 
128
- return dt_list
303
+ # return dt_list
129
304
 
130
- if file_name_patterns is None:
131
- file_name_patterns = []
305
+ # if file_name_patterns is None:
306
+ # file_name_patterns = []
132
307
 
133
- if list(file_name_patterns):
134
- search_pattern = '.*' + '.*'.join(file_name_patterns) + '.*'
135
- fn_regex = re.compile(search_pattern)
136
- file_list = list(filter(fn_regex.match, file_list))
308
+ # if list(file_name_patterns):
309
+ # search_pattern = '.*' + '.*'.join(file_name_patterns) + '.*'
310
+ # fn_regex = re.compile(search_pattern)
311
+ # file_list = list(filter(fn_regex.match, file_list))
137
312
 
138
- dt_list = extract_timeline(file_list)
313
+ # dt_list = extract_timeline(file_list)
139
314
 
140
- dt_fr = datetime.datetime(self.dt_fr.year, self.dt_fr.month, 1)
141
- dt_to = datetime.datetime(self.dt_to.year, self.dt_to.month, 1)
142
- ind_dt = np.where((dt_list >= dt_fr) & (dt_list <= dt_to))[0]
143
- if not list(ind_dt):
144
- raise FileExistsError
145
- file_list = [file_list[ii] for ii in ind_dt]
315
+ # dt_fr = datetime.datetime(self.dt_fr.year, self.dt_fr.month, 1)
316
+ # dt_to = datetime.datetime(self.dt_to.year, self.dt_to.month, 1)
317
+ # ind_dt = np.where((dt_list >= dt_fr) & (dt_list <= dt_to))[0]
318
+ # if not list(ind_dt):
319
+ # raise FileExistsError
320
+ # file_list = [file_list[ii] for ii in ind_dt]
146
321
 
147
- return file_list
322
+ # return file_list
148
323
 
149
324
 
150
325