spectre-core 0.0.22__py3-none-any.whl → 0.0.23__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.
- spectre_core/_file_io/__init__.py +4 -4
- spectre_core/_file_io/file_handlers.py +60 -106
- spectre_core/batches/__init__.py +20 -3
- spectre_core/batches/_base.py +85 -134
- spectre_core/batches/_batches.py +55 -99
- spectre_core/batches/_factory.py +21 -20
- spectre_core/batches/_register.py +8 -8
- spectre_core/batches/plugins/_batch_keys.py +7 -6
- spectre_core/batches/plugins/_callisto.py +65 -97
- spectre_core/batches/plugins/_iq_stream.py +105 -169
- spectre_core/capture_configs/__init__.py +46 -17
- spectre_core/capture_configs/_capture_config.py +25 -52
- spectre_core/capture_configs/_capture_modes.py +8 -6
- spectre_core/capture_configs/_capture_templates.py +50 -110
- spectre_core/capture_configs/_parameters.py +37 -74
- spectre_core/capture_configs/_pconstraints.py +40 -40
- spectre_core/capture_configs/_pnames.py +36 -34
- spectre_core/capture_configs/_ptemplates.py +260 -347
- spectre_core/capture_configs/_pvalidators.py +99 -102
- spectre_core/config/__init__.py +13 -8
- spectre_core/config/_paths.py +18 -35
- spectre_core/config/_time_formats.py +6 -5
- spectre_core/exceptions.py +38 -0
- spectre_core/jobs/__init__.py +3 -6
- spectre_core/jobs/_duration.py +12 -0
- spectre_core/jobs/_jobs.py +72 -43
- spectre_core/jobs/_workers.py +55 -105
- spectre_core/logs/__init__.py +7 -2
- spectre_core/logs/_configure.py +13 -17
- spectre_core/logs/_decorators.py +6 -4
- spectre_core/logs/_logs.py +37 -89
- spectre_core/logs/_process_types.py +5 -3
- spectre_core/plotting/__init__.py +13 -3
- spectre_core/plotting/_base.py +64 -138
- spectre_core/plotting/_format.py +10 -8
- spectre_core/plotting/_panel_names.py +7 -5
- spectre_core/plotting/_panel_stack.py +82 -115
- spectre_core/plotting/_panels.py +120 -155
- spectre_core/post_processing/__init__.py +6 -3
- spectre_core/post_processing/_base.py +41 -55
- spectre_core/post_processing/_factory.py +14 -11
- spectre_core/post_processing/_post_processor.py +16 -12
- spectre_core/post_processing/_register.py +10 -7
- spectre_core/post_processing/plugins/_event_handler_keys.py +4 -3
- spectre_core/post_processing/plugins/_fixed_center_frequency.py +54 -47
- spectre_core/post_processing/plugins/_swept_center_frequency.py +199 -174
- spectre_core/receivers/__init__.py +9 -2
- spectre_core/receivers/_base.py +82 -148
- spectre_core/receivers/_factory.py +20 -30
- spectre_core/receivers/_register.py +7 -10
- spectre_core/receivers/_spec_names.py +17 -15
- spectre_core/receivers/plugins/_b200mini.py +47 -60
- spectre_core/receivers/plugins/_receiver_names.py +8 -6
- spectre_core/receivers/plugins/_rsp1a.py +44 -40
- spectre_core/receivers/plugins/_rspduo.py +59 -44
- spectre_core/receivers/plugins/_sdrplay_receiver.py +67 -83
- spectre_core/receivers/plugins/_test.py +136 -129
- spectre_core/receivers/plugins/_usrp.py +93 -85
- spectre_core/receivers/plugins/gr/__init__.py +1 -1
- spectre_core/receivers/plugins/gr/_base.py +14 -22
- spectre_core/receivers/plugins/gr/_rsp1a.py +53 -60
- spectre_core/receivers/plugins/gr/_rspduo.py +77 -89
- spectre_core/receivers/plugins/gr/_test.py +49 -57
- spectre_core/receivers/plugins/gr/_usrp.py +61 -59
- spectre_core/spectrograms/__init__.py +21 -13
- spectre_core/spectrograms/_analytical.py +108 -99
- spectre_core/spectrograms/_array_operations.py +39 -46
- spectre_core/spectrograms/_spectrogram.py +289 -322
- spectre_core/spectrograms/_transform.py +106 -73
- spectre_core/wgetting/__init__.py +1 -3
- spectre_core/wgetting/_callisto.py +87 -93
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/METADATA +9 -23
- spectre_core-0.0.23.dist-info/RECORD +79 -0
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/WHEEL +1 -1
- spectre_core-0.0.22.dist-info/RECORD +0 -78
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/licenses/LICENSE +0 -0
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/top_level.txt +0 -0
@@ -12,10 +12,9 @@ from spectre_core.config import TimeFormat
|
|
12
12
|
from ._array_operations import find_closest_index, average_array, time_elapsed
|
13
13
|
from ._spectrogram import Spectrogram
|
14
14
|
|
15
|
+
|
15
16
|
def frequency_chop(
|
16
|
-
spectrogram: Spectrogram,
|
17
|
-
start_frequency : float,
|
18
|
-
end_frequency : float
|
17
|
+
spectrogram: Spectrogram, start_frequency: float, end_frequency: float
|
19
18
|
) -> Spectrogram:
|
20
19
|
"""
|
21
20
|
Extracts a portion of the spectrogram within the specified frequency range.
|
@@ -27,39 +26,53 @@ def frequency_chop(
|
|
27
26
|
:raises ValueError: If the start and end indices for the frequency range are identical.
|
28
27
|
:return: A new spectrogram containing only the specified frequency range.
|
29
28
|
"""
|
30
|
-
is_entirely_below_frequency_range = (
|
31
|
-
|
29
|
+
is_entirely_below_frequency_range = (
|
30
|
+
start_frequency < spectrogram.frequencies[0]
|
31
|
+
and end_frequency < spectrogram.frequencies[0]
|
32
|
+
)
|
33
|
+
is_entirely_above_frequency_range = (
|
34
|
+
start_frequency > spectrogram.frequencies[-1]
|
35
|
+
and end_frequency > spectrogram.frequencies[-1]
|
36
|
+
)
|
32
37
|
if is_entirely_below_frequency_range or is_entirely_above_frequency_range:
|
33
|
-
raise ValueError(
|
34
|
-
|
38
|
+
raise ValueError(
|
39
|
+
f"The requested frequency interval is entirely out of range of the input spectrogram."
|
40
|
+
)
|
41
|
+
|
35
42
|
# find the index of the nearest matching frequency bins in the spectrogram
|
36
|
-
start_index = find_closest_index(
|
37
|
-
|
38
|
-
|
43
|
+
start_index = find_closest_index(
|
44
|
+
np.float32(start_frequency), spectrogram.frequencies
|
45
|
+
)
|
46
|
+
end_index = find_closest_index(np.float32(end_frequency), spectrogram.frequencies)
|
47
|
+
|
39
48
|
# enforce distinct start and end indices
|
40
49
|
if start_index == end_index:
|
41
|
-
raise ValueError(
|
42
|
-
|
50
|
+
raise ValueError(
|
51
|
+
f"Start and end indices are equal! Got start_index: {start_index} and end_index: {end_index}"
|
52
|
+
)
|
53
|
+
|
43
54
|
# if start index is more than end index, swap the ordering so to enforce start_index <= end_index
|
44
55
|
if start_index > end_index:
|
45
56
|
start_index, end_index = end_index, start_index
|
46
|
-
|
57
|
+
|
47
58
|
# chop the spectrogram accordingly
|
48
|
-
transformed_dynamic_spectra = spectrogram.dynamic_spectra[
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
59
|
+
transformed_dynamic_spectra = spectrogram.dynamic_spectra[
|
60
|
+
start_index : end_index + 1, :
|
61
|
+
]
|
62
|
+
transformed_frequencies = spectrogram.frequencies[start_index : end_index + 1]
|
63
|
+
|
64
|
+
return Spectrogram(
|
65
|
+
transformed_dynamic_spectra,
|
66
|
+
spectrogram.times,
|
67
|
+
transformed_frequencies,
|
68
|
+
spectrogram.tag,
|
69
|
+
spectrogram.spectrum_unit,
|
70
|
+
spectrogram.start_datetime,
|
71
|
+
)
|
57
72
|
|
58
73
|
|
59
74
|
def time_chop(
|
60
|
-
spectrogram: Spectrogram,
|
61
|
-
start_datetime: datetime,
|
62
|
-
end_datetime: datetime
|
75
|
+
spectrogram: Spectrogram, start_datetime: datetime, end_datetime: datetime
|
63
76
|
) -> Spectrogram:
|
64
77
|
"""
|
65
78
|
Extracts a portion of the spectrogram within the specified time range.
|
@@ -72,45 +85,57 @@ def time_chop(
|
|
72
85
|
:return: A new spectrogram containing only the specified time range.
|
73
86
|
"""
|
74
87
|
start_datetime64 = np.datetime64(start_datetime)
|
75
|
-
end_datetime64
|
88
|
+
end_datetime64 = np.datetime64(end_datetime)
|
76
89
|
|
77
|
-
is_entirely_below_time_range = (
|
78
|
-
|
90
|
+
is_entirely_below_time_range = (
|
91
|
+
start_datetime64 < spectrogram.datetimes[0]
|
92
|
+
and end_datetime64 < spectrogram.datetimes[0]
|
93
|
+
)
|
94
|
+
is_entirely_above_time_range = (
|
95
|
+
start_datetime64 > spectrogram.datetimes[-1]
|
96
|
+
and end_datetime64 > spectrogram.datetimes[-1]
|
97
|
+
)
|
79
98
|
if is_entirely_below_time_range or is_entirely_above_time_range:
|
80
|
-
raise ValueError(
|
81
|
-
|
99
|
+
raise ValueError(
|
100
|
+
f"Requested time interval is entirely out of range of the input spectrogram."
|
101
|
+
)
|
102
|
+
|
82
103
|
# find the index of the nearest matching spectrums in the spectrogram.
|
83
104
|
start_index = find_closest_index(start_datetime64, spectrogram.datetimes)
|
84
|
-
end_index
|
85
|
-
|
105
|
+
end_index = find_closest_index(end_datetime64, spectrogram.datetimes)
|
106
|
+
|
86
107
|
# enforce distinct start and end indices
|
87
108
|
if start_index == end_index:
|
88
|
-
raise ValueError(
|
89
|
-
|
109
|
+
raise ValueError(
|
110
|
+
f"Start and end indices are equal! Got start_index: {start_index} and end_index: {end_index}"
|
111
|
+
)
|
112
|
+
|
90
113
|
# if start index is more than end index, swap the ordering so to enforce start_index <= end_index
|
91
114
|
if start_index > end_index:
|
92
115
|
start_index, end_index = end_index, start_index
|
93
116
|
|
94
117
|
# chop the spectrogram accordingly
|
95
|
-
transformed_dynamic_spectra = spectrogram.dynamic_spectra[
|
118
|
+
transformed_dynamic_spectra = spectrogram.dynamic_spectra[
|
119
|
+
:, start_index : end_index + 1
|
120
|
+
]
|
96
121
|
transformed_start_datetime = spectrogram.datetimes[start_index]
|
97
122
|
|
98
123
|
# chop the times array and translate such that the first spectrum to t=0 [s]
|
99
|
-
transformed_times
|
124
|
+
transformed_times = spectrogram.times[start_index : end_index + 1]
|
100
125
|
transformed_times -= transformed_times[0]
|
101
126
|
|
102
|
-
return Spectrogram(
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
127
|
+
return Spectrogram(
|
128
|
+
transformed_dynamic_spectra,
|
129
|
+
transformed_times,
|
130
|
+
spectrogram.frequencies,
|
131
|
+
spectrogram.tag,
|
132
|
+
spectrogram.spectrum_unit,
|
133
|
+
transformed_start_datetime,
|
134
|
+
)
|
108
135
|
|
109
136
|
|
110
137
|
def _validate_and_compute_average_over(
|
111
|
-
original_resolution: float,
|
112
|
-
resolution: Optional[float],
|
113
|
-
average_over: int
|
138
|
+
original_resolution: float, resolution: Optional[float], average_over: int
|
114
139
|
) -> int:
|
115
140
|
"""
|
116
141
|
Validates the input parameters and computes `average_over` if `resolution` is specified.
|
@@ -125,7 +150,9 @@ def _validate_and_compute_average_over(
|
|
125
150
|
return average_over
|
126
151
|
|
127
152
|
if not (resolution is not None) ^ (average_over != 1):
|
128
|
-
raise ValueError(
|
153
|
+
raise ValueError(
|
154
|
+
"Exactly one of 'resolution' or 'average_over' must be specified."
|
155
|
+
)
|
129
156
|
|
130
157
|
if resolution is not None:
|
131
158
|
return max(1, floor(resolution / original_resolution))
|
@@ -155,9 +182,7 @@ def time_average(
|
|
155
182
|
)
|
156
183
|
|
157
184
|
average_over = _validate_and_compute_average_over(
|
158
|
-
spectrogram.time_resolution,
|
159
|
-
resolution,
|
160
|
-
average_over
|
185
|
+
spectrogram.time_resolution, resolution, average_over
|
161
186
|
)
|
162
187
|
|
163
188
|
# Perform averaging
|
@@ -167,9 +192,9 @@ def time_average(
|
|
167
192
|
transformed_times = average_array(spectrogram.times, average_over)
|
168
193
|
|
169
194
|
# Update start datetime and adjust times to start at t=0
|
170
|
-
transformed_start_datetime = (
|
171
|
-
|
172
|
-
)
|
195
|
+
transformed_start_datetime = spectrogram.datetimes[0] + (
|
196
|
+
transformed_times[0] * 1e6
|
197
|
+
).astype("timedelta64[us]")
|
173
198
|
transformed_times -= transformed_times[0]
|
174
199
|
|
175
200
|
return Spectrogram(
|
@@ -197,9 +222,7 @@ def frequency_average(
|
|
197
222
|
:return: A new spectrogram with frequency-averaged data.
|
198
223
|
"""
|
199
224
|
average_over = _validate_and_compute_average_over(
|
200
|
-
spectrogram.frequency_resolution,
|
201
|
-
resolution,
|
202
|
-
average_over
|
225
|
+
spectrogram.frequency_resolution, resolution, average_over
|
203
226
|
)
|
204
227
|
|
205
228
|
# Perform averaging
|
@@ -218,9 +241,7 @@ def frequency_average(
|
|
218
241
|
)
|
219
242
|
|
220
243
|
|
221
|
-
def join_spectrograms(
|
222
|
-
spectrograms: list[Spectrogram]
|
223
|
-
) -> Spectrogram:
|
244
|
+
def join_spectrograms(spectrograms: list[Spectrogram]) -> Spectrogram:
|
224
245
|
"""
|
225
246
|
Joins multiple spectrograms into a single spectrogram along the time axis.
|
226
247
|
|
@@ -236,30 +257,42 @@ def join_spectrograms(
|
|
236
257
|
num_spectrograms = len(spectrograms)
|
237
258
|
if num_spectrograms == 0:
|
238
259
|
raise ValueError(f"Input list of spectrograms is empty!")
|
239
|
-
|
260
|
+
|
240
261
|
# extract the first element of the list, and use this as a reference for comparison
|
241
262
|
# input validations.
|
242
|
-
reference_spectrogram = spectrograms[0]
|
263
|
+
reference_spectrogram = spectrograms[0]
|
243
264
|
|
244
265
|
# perform checks on each spectrogram in teh list
|
245
266
|
for spectrogram in spectrograms:
|
246
|
-
if not np.all(
|
267
|
+
if not np.all(
|
268
|
+
np.equal(spectrogram.frequencies, reference_spectrogram.frequencies)
|
269
|
+
):
|
247
270
|
raise ValueError(f"All spectrograms must have identical frequency ranges")
|
248
271
|
if spectrogram.tag != reference_spectrogram.tag:
|
249
|
-
raise ValueError(
|
272
|
+
raise ValueError(
|
273
|
+
f"All tags must be equal for each spectrogram in the input list!"
|
274
|
+
)
|
250
275
|
if spectrogram.spectrum_unit != reference_spectrogram.spectrum_unit:
|
251
|
-
raise ValueError(
|
276
|
+
raise ValueError(
|
277
|
+
f"All units must be equal for each spectrogram in the input list!"
|
278
|
+
)
|
252
279
|
if not spectrogram.start_datetime_is_set:
|
253
280
|
raise ValueError(f"All spectrograms must have their start datetime set.")
|
254
281
|
|
255
282
|
# Concatenate all dynamic spectra directly along the time axis
|
256
|
-
transformed_dynamic_spectra = np.hstack(
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
283
|
+
transformed_dynamic_spectra = np.hstack(
|
284
|
+
[spectrogram.dynamic_spectra for spectrogram in spectrograms]
|
285
|
+
)
|
286
|
+
|
287
|
+
transformed_times = time_elapsed(
|
288
|
+
np.concatenate([s.datetimes for s in spectrograms])
|
289
|
+
)
|
290
|
+
|
291
|
+
return Spectrogram(
|
292
|
+
transformed_dynamic_spectra,
|
293
|
+
transformed_times,
|
294
|
+
reference_spectrogram.frequencies,
|
295
|
+
reference_spectrogram.tag,
|
296
|
+
reference_spectrogram.spectrum_unit,
|
297
|
+
reference_spectrogram.start_datetime,
|
298
|
+
)
|
@@ -10,74 +10,73 @@ from datetime import datetime, date
|
|
10
10
|
from typing import Tuple
|
11
11
|
|
12
12
|
from spectre_core.config import (
|
13
|
-
get_spectre_data_dir_path,
|
13
|
+
get_spectre_data_dir_path,
|
14
|
+
get_batches_dir_path,
|
15
|
+
TimeFormat,
|
14
16
|
)
|
15
17
|
|
16
18
|
from enum import Enum
|
17
19
|
|
20
|
+
|
18
21
|
class CallistoInstrumentCode(Enum):
|
19
22
|
"""e-Callisto network station codes."""
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
date: str,
|
78
|
-
time: str,
|
79
|
-
code: str
|
80
|
-
) -> str:
|
23
|
+
|
24
|
+
ALASKA_ANCHORAGE = "ALASKA-ANCHORAGE"
|
25
|
+
ALASKA_COHOE = "ALASKA-COHOE"
|
26
|
+
ALASKA_HAARP = "ALASKA-HAARP"
|
27
|
+
ALGERIA_CRAAG = "ALGERIA-CRAAG"
|
28
|
+
ALMATY = "ALMATY"
|
29
|
+
AUSTRIA_KRUMBACH = "AUSTRIA-Krumbach"
|
30
|
+
AUSTRIA_MICHELBACH = "AUSTRIA-MICHELBACH"
|
31
|
+
AUSTRIA_OE3FLB = "AUSTRIA-OE3FLB"
|
32
|
+
AUSTRIA_UNIGRAZ = "AUSTRIA-UNIGRAZ"
|
33
|
+
AUSTRALIA_ASSA = "Australia-ASSA"
|
34
|
+
BIR = "BIR"
|
35
|
+
CROATIA_VISNJAN = "Croatia-Visnjan"
|
36
|
+
DENMARK = "DENMARK"
|
37
|
+
EGYPT_ALEXANDRIA = "EGYPT-Alexandria"
|
38
|
+
EGYPT_SPACEAGENCY = "EGYPT-SpaceAgency"
|
39
|
+
FINLAND_SIUNTIO = "FINLAND-Siuntio"
|
40
|
+
FINLAND_KEMPELE = "Finland-Kempele"
|
41
|
+
GERMANY_DLR = "GERMANY-DLR"
|
42
|
+
GLASGOW = "GLASGOW"
|
43
|
+
GREENLAND = "GREENLAND"
|
44
|
+
HUMAIN = "HUMAIN"
|
45
|
+
HURBANOVO = "HURBANOVO"
|
46
|
+
INDIA_GAURI = "INDIA-GAURI"
|
47
|
+
INDIA_OOTY = "INDIA-OOTY"
|
48
|
+
INDIA_UDAIPUR = "INDIA-UDAIPUR"
|
49
|
+
JAPAN_IBARAKI = "JAPAN-IBARAKI"
|
50
|
+
KASI = "KASI"
|
51
|
+
MEXART = "MEXART"
|
52
|
+
MEXICO_FCFM_UANL = "MEXICO-FCFM-UANL"
|
53
|
+
MEXICO_LANCE_A = "MEXICO-LANCE-A"
|
54
|
+
MEXICO_LANCE_B = "MEXICO-LANCE-B"
|
55
|
+
MONGOLIA_UB = "MONGOLIA-UB"
|
56
|
+
MRO = "MRO"
|
57
|
+
MRT3 = "MRT3"
|
58
|
+
MALAYSIA_BANTING = "Malaysia-Banting"
|
59
|
+
NORWAY_EGERSUND = "NORWAY-EGERSUND"
|
60
|
+
NORWAY_NY_AALESUND = "NORWAY-NY-AALESUND"
|
61
|
+
NORWAY_RANDABERG = "NORWAY-RANDABERG"
|
62
|
+
POLAND_GROTNIKI = "POLAND-Grotniki"
|
63
|
+
ROMANIA = "ROMANIA"
|
64
|
+
ROSWELL_NM = "ROSWELL-NM"
|
65
|
+
SPAIN_PERALEJOS = "SPAIN-PERALEJOS"
|
66
|
+
SSRT = "SSRT"
|
67
|
+
SWISS_HB9SCT = "SWISS-HB9SCT"
|
68
|
+
SWISS_HEITERSWIL = "SWISS-HEITERSWIL"
|
69
|
+
SWISS_IRSOL = "SWISS-IRSOL"
|
70
|
+
SWISS_LANDSCHLACHT = "SWISS-Landschlacht"
|
71
|
+
SWISS_MUHEN = "SWISS-MUHEN"
|
72
|
+
TRIEST = "TRIEST"
|
73
|
+
TURKEY = "TURKEY"
|
74
|
+
UNAM = "UNAM"
|
75
|
+
URUGUAY = "URUGUAY"
|
76
|
+
USA_BOSTON = "USA-BOSTON"
|
77
|
+
|
78
|
+
|
79
|
+
def _get_batch_name(station: str, date: str, time: str, code: str) -> str:
|
81
80
|
"""
|
82
81
|
Create a standardised batch file name for a `spectre` batch file.
|
83
82
|
|
@@ -92,9 +91,7 @@ def _get_batch_name(
|
|
92
91
|
return f"{formatted_time}_callisto-{station.lower()}-{code}.fits"
|
93
92
|
|
94
93
|
|
95
|
-
def _get_batch_components(
|
96
|
-
gz_path: str
|
97
|
-
) -> list[str]:
|
94
|
+
def _get_batch_components(gz_path: str) -> list[str]:
|
98
95
|
"""
|
99
96
|
Extract station, date, time, and instrument code from the `.fit.gz` file name.
|
100
97
|
|
@@ -106,15 +103,15 @@ def _get_batch_components(
|
|
106
103
|
if not file_name.endswith(".fit.gz"):
|
107
104
|
raise ValueError(f"Invalid file extension: {file_name}. Expected .fit.gz")
|
108
105
|
file_base_name = file_name.rstrip(".fit.gz")
|
109
|
-
parts = file_base_name.split(
|
106
|
+
parts = file_base_name.split("_")
|
110
107
|
if len(parts) != 4:
|
111
|
-
raise ValueError(
|
108
|
+
raise ValueError(
|
109
|
+
"Invalid file name format. Expected '[station]_[date]_[time]_[code].fit.gz'"
|
110
|
+
)
|
112
111
|
return parts
|
113
112
|
|
114
113
|
|
115
|
-
def _get_batch_path(
|
116
|
-
gz_path: str
|
117
|
-
) -> str:
|
114
|
+
def _get_batch_path(gz_path: str) -> str:
|
118
115
|
"""
|
119
116
|
Generate the full path for the `spectre` batch file.
|
120
117
|
|
@@ -130,9 +127,7 @@ def _get_batch_path(
|
|
130
127
|
return os.path.join(batch_dir, batch_name)
|
131
128
|
|
132
129
|
|
133
|
-
def _unzip_file_to_batches(
|
134
|
-
gz_path: str
|
135
|
-
) -> str:
|
130
|
+
def _unzip_file_to_batches(gz_path: str) -> str:
|
136
131
|
"""
|
137
132
|
Decompress a `.fit.gz` file and save it as a `.fits` batch file.
|
138
133
|
|
@@ -145,9 +140,7 @@ def _unzip_file_to_batches(
|
|
145
140
|
return f_out.name
|
146
141
|
|
147
142
|
|
148
|
-
def _unzip_to_batches(
|
149
|
-
tmp_dir: str
|
150
|
-
) -> list[str]:
|
143
|
+
def _unzip_to_batches(tmp_dir: str) -> list[str]:
|
151
144
|
"""
|
152
145
|
Decompress all `.gz` files in a temporary directory and save them as `spectre`
|
153
146
|
batch files.
|
@@ -158,19 +151,14 @@ def _unzip_to_batches(
|
|
158
151
|
batch_file_names = []
|
159
152
|
for entry in os.scandir(tmp_dir):
|
160
153
|
if entry.is_file() and entry.name.endswith(".gz"):
|
161
|
-
batch_file_names.append(
|
154
|
+
batch_file_names.append(_unzip_file_to_batches(entry.path))
|
162
155
|
os.remove(entry.path)
|
163
156
|
shutil.rmtree(tmp_dir)
|
164
157
|
return batch_file_names
|
165
|
-
|
166
158
|
|
167
159
|
|
168
160
|
def _wget_callisto_data(
|
169
|
-
instrument_code: str,
|
170
|
-
year: int,
|
171
|
-
month: int,
|
172
|
-
day: int,
|
173
|
-
tmp_dir: str
|
161
|
+
instrument_code: str, year: int, month: int, day: int, tmp_dir: str
|
174
162
|
) -> None:
|
175
163
|
"""
|
176
164
|
Download raw `.fit.gz` files from the e-Callisto network using `wget`.
|
@@ -184,18 +172,24 @@ def _wget_callisto_data(
|
|
184
172
|
date_str = f"{year:04d}/{month:02d}/{day:02d}"
|
185
173
|
base_url = f"http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/{date_str}/"
|
186
174
|
command = [
|
187
|
-
"wget",
|
188
|
-
"-
|
189
|
-
"-
|
175
|
+
"wget",
|
176
|
+
"-r",
|
177
|
+
"-l1",
|
178
|
+
"-nd",
|
179
|
+
"-np",
|
180
|
+
"-R",
|
181
|
+
".tmp",
|
182
|
+
"-A",
|
183
|
+
f"{instrument_code}*.fit.gz",
|
184
|
+
"-P",
|
185
|
+
tmp_dir,
|
186
|
+
base_url,
|
190
187
|
]
|
191
188
|
subprocess.run(command, check=True)
|
192
189
|
|
193
190
|
|
194
191
|
def download_callisto_data(
|
195
|
-
instrument_code: CallistoInstrumentCode,
|
196
|
-
year: int,
|
197
|
-
month: int,
|
198
|
-
day: int
|
192
|
+
instrument_code: CallistoInstrumentCode, year: int, month: int, day: int
|
199
193
|
) -> Tuple[list[str], date]:
|
200
194
|
"""
|
201
195
|
Download and decompress e-Callisto FITS files, saving them as `spectre` batch files.
|
@@ -204,13 +198,13 @@ def download_callisto_data(
|
|
204
198
|
:param year: Year of the observation.
|
205
199
|
:param month: Month of the observation.
|
206
200
|
:param day: Day of the observation.
|
207
|
-
:return: A list of file names of all newly created batch files, as absolute paths within the container's file system. Additionally, return the start date shared by all batch files.
|
201
|
+
:return: A list of file names of all newly created batch files, as absolute paths within the container's file system. Additionally, return the start date shared by all batch files.
|
208
202
|
"""
|
209
203
|
tmp_dir = os.path.join(get_spectre_data_dir_path(), "tmp")
|
210
204
|
# if there are any residual files in the temporary directory, remove them.
|
211
205
|
if os.path.exists(tmp_dir):
|
212
206
|
shutil.rmtree(tmp_dir)
|
213
207
|
os.makedirs(tmp_dir, exist_ok=True)
|
214
|
-
|
208
|
+
|
215
209
|
_wget_callisto_data(instrument_code.value, year, month, day, tmp_dir)
|
216
|
-
return sorted(
|
210
|
+
return sorted(_unzip_to_batches(tmp_dir)), date(year, month, day)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: spectre-core
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.23
|
4
4
|
Summary: The core Python package used by the spectre program.
|
5
5
|
Maintainer-email: Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -691,33 +691,19 @@ Requires-Dist: scipy==1.12.0
|
|
691
691
|
Requires-Dist: astropy==6.0.1
|
692
692
|
Requires-Dist: matplotlib==3.5.0
|
693
693
|
Requires-Dist: watchdog==4.0.0
|
694
|
+
Provides-Extra: test
|
695
|
+
Requires-Dist: pytest; extra == "test"
|
696
|
+
Requires-Dist: mypy; extra == "test"
|
697
|
+
Requires-Dist: black; extra == "test"
|
694
698
|
Dynamic: license-file
|
695
699
|
|
696
700
|
# spectre-core
|
697
701
|
|
698
702
|
## Description
|
699
|
-
|
700
|
-
:loudspeaker: **This project is under active development. Contributors welcome.** :loudspeaker:
|
701
|
-
|
702
|
-
```spectre-core``` provides an extensible, receiver-agnostic toolkit for generating radio spectrograms in real-time. It is the core Python package used by the [`spectre`](https://github.com/jcfitzpatrick12/spectre.git) program.
|
703
|
-
|
704
|
-
|
705
|
-
## Installation
|
706
|
-
Simply call:
|
707
|
-
```bash
|
708
|
-
pip install spectre-core
|
709
|
-
```
|
710
|
-
|
711
|
-
Alternatively, you can clone the repository in your preferred directory:
|
712
|
-
```bash
|
713
|
-
git clone https://github.com/jcfitzpatrick12/spectre-core.git && cd spectre-core
|
714
|
-
```
|
715
|
-
|
716
|
-
Then run:
|
717
|
-
```
|
718
|
-
pip install -e .
|
719
|
-
```
|
703
|
+
A receiver-agnostic toolkit for generating radio spectrograms in real-time. Contains server-side implementations for [_Spectre_](https://github.com/jcfitzpatrick12/spectre.git).
|
720
704
|
|
705
|
+
**⚠️ Note:**
|
706
|
+
This repository is not intended for direct consumption.
|
721
707
|
|
722
708
|
## Contributing
|
723
|
-
|
709
|
+
If you'd like to raise an issue, or want to make a change, please refer to the _Contributing_ section in the [README](https://github.com/jcfitzpatrick12/spectre/blob/main/README.md) for _Spectre_.
|