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.
Files changed (77) hide show
  1. spectre_core/_file_io/__init__.py +4 -4
  2. spectre_core/_file_io/file_handlers.py +60 -106
  3. spectre_core/batches/__init__.py +20 -3
  4. spectre_core/batches/_base.py +85 -134
  5. spectre_core/batches/_batches.py +55 -99
  6. spectre_core/batches/_factory.py +21 -20
  7. spectre_core/batches/_register.py +8 -8
  8. spectre_core/batches/plugins/_batch_keys.py +7 -6
  9. spectre_core/batches/plugins/_callisto.py +65 -97
  10. spectre_core/batches/plugins/_iq_stream.py +105 -169
  11. spectre_core/capture_configs/__init__.py +46 -17
  12. spectre_core/capture_configs/_capture_config.py +25 -52
  13. spectre_core/capture_configs/_capture_modes.py +8 -6
  14. spectre_core/capture_configs/_capture_templates.py +50 -110
  15. spectre_core/capture_configs/_parameters.py +37 -74
  16. spectre_core/capture_configs/_pconstraints.py +40 -40
  17. spectre_core/capture_configs/_pnames.py +36 -34
  18. spectre_core/capture_configs/_ptemplates.py +260 -347
  19. spectre_core/capture_configs/_pvalidators.py +99 -102
  20. spectre_core/config/__init__.py +13 -8
  21. spectre_core/config/_paths.py +18 -35
  22. spectre_core/config/_time_formats.py +6 -5
  23. spectre_core/exceptions.py +38 -0
  24. spectre_core/jobs/__init__.py +3 -6
  25. spectre_core/jobs/_duration.py +12 -0
  26. spectre_core/jobs/_jobs.py +72 -43
  27. spectre_core/jobs/_workers.py +55 -105
  28. spectre_core/logs/__init__.py +7 -2
  29. spectre_core/logs/_configure.py +13 -17
  30. spectre_core/logs/_decorators.py +6 -4
  31. spectre_core/logs/_logs.py +37 -89
  32. spectre_core/logs/_process_types.py +5 -3
  33. spectre_core/plotting/__init__.py +13 -3
  34. spectre_core/plotting/_base.py +64 -138
  35. spectre_core/plotting/_format.py +10 -8
  36. spectre_core/plotting/_panel_names.py +7 -5
  37. spectre_core/plotting/_panel_stack.py +82 -115
  38. spectre_core/plotting/_panels.py +120 -155
  39. spectre_core/post_processing/__init__.py +6 -3
  40. spectre_core/post_processing/_base.py +41 -55
  41. spectre_core/post_processing/_factory.py +14 -11
  42. spectre_core/post_processing/_post_processor.py +16 -12
  43. spectre_core/post_processing/_register.py +10 -7
  44. spectre_core/post_processing/plugins/_event_handler_keys.py +4 -3
  45. spectre_core/post_processing/plugins/_fixed_center_frequency.py +54 -47
  46. spectre_core/post_processing/plugins/_swept_center_frequency.py +199 -174
  47. spectre_core/receivers/__init__.py +9 -2
  48. spectre_core/receivers/_base.py +82 -148
  49. spectre_core/receivers/_factory.py +20 -30
  50. spectre_core/receivers/_register.py +7 -10
  51. spectre_core/receivers/_spec_names.py +17 -15
  52. spectre_core/receivers/plugins/_b200mini.py +47 -60
  53. spectre_core/receivers/plugins/_receiver_names.py +8 -6
  54. spectre_core/receivers/plugins/_rsp1a.py +44 -40
  55. spectre_core/receivers/plugins/_rspduo.py +59 -44
  56. spectre_core/receivers/plugins/_sdrplay_receiver.py +67 -83
  57. spectre_core/receivers/plugins/_test.py +136 -129
  58. spectre_core/receivers/plugins/_usrp.py +93 -85
  59. spectre_core/receivers/plugins/gr/__init__.py +1 -1
  60. spectre_core/receivers/plugins/gr/_base.py +14 -22
  61. spectre_core/receivers/plugins/gr/_rsp1a.py +53 -60
  62. spectre_core/receivers/plugins/gr/_rspduo.py +77 -89
  63. spectre_core/receivers/plugins/gr/_test.py +49 -57
  64. spectre_core/receivers/plugins/gr/_usrp.py +61 -59
  65. spectre_core/spectrograms/__init__.py +21 -13
  66. spectre_core/spectrograms/_analytical.py +108 -99
  67. spectre_core/spectrograms/_array_operations.py +39 -46
  68. spectre_core/spectrograms/_spectrogram.py +289 -322
  69. spectre_core/spectrograms/_transform.py +106 -73
  70. spectre_core/wgetting/__init__.py +1 -3
  71. spectre_core/wgetting/_callisto.py +87 -93
  72. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/METADATA +9 -23
  73. spectre_core-0.0.23.dist-info/RECORD +79 -0
  74. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/WHEEL +1 -1
  75. spectre_core-0.0.22.dist-info/RECORD +0 -78
  76. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/licenses/LICENSE +0 -0
  77. {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 = (start_frequency < spectrogram.frequencies[0] and end_frequency < spectrogram.frequencies[0])
31
- is_entirely_above_frequency_range = (start_frequency > spectrogram.frequencies[-1] and end_frequency > spectrogram.frequencies[-1])
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(f"The requested frequency interval is entirely out of range of the input spectrogram.")
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(np.float32(start_frequency), spectrogram.frequencies)
37
- end_index = find_closest_index(np.float32(end_frequency) , spectrogram.frequencies)
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(f"Start and end indices are equal! Got start_index: {start_index} and end_index: {end_index}")
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[start_index:end_index+1, :]
49
- transformed_frequencies = spectrogram.frequencies[start_index:end_index+1]
50
-
51
- return Spectrogram(transformed_dynamic_spectra,
52
- spectrogram.times,
53
- transformed_frequencies,
54
- spectrogram.tag,
55
- spectrogram.spectrum_unit,
56
- spectrogram.start_datetime)
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 = np.datetime64(end_datetime)
88
+ end_datetime64 = np.datetime64(end_datetime)
76
89
 
77
- is_entirely_below_time_range = (start_datetime64 < spectrogram.datetimes[0] and end_datetime64 < spectrogram.datetimes[0])
78
- is_entirely_above_time_range = (start_datetime64 > spectrogram.datetimes[-1] and end_datetime64 > spectrogram.datetimes[-1])
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(f"Requested time interval is entirely out of range of the input spectrogram.")
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 = find_closest_index(end_datetime64, spectrogram.datetimes)
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(f"Start and end indices are equal! Got start_index: {start_index} and end_index: {end_index}")
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[:, start_index:end_index+1]
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 = spectrogram.times[start_index:end_index+1]
124
+ transformed_times = spectrogram.times[start_index : end_index + 1]
100
125
  transformed_times -= transformed_times[0]
101
126
 
102
- return Spectrogram(transformed_dynamic_spectra,
103
- transformed_times,
104
- spectrogram.frequencies,
105
- spectrogram.tag,
106
- spectrogram.spectrum_unit,
107
- transformed_start_datetime)
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("Exactly one of 'resolution' or 'average_over' must be specified.")
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
- spectrogram.datetimes[0] + (transformed_times[0]*1e6).astype("timedelta64[us]")
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(np.equal(spectrogram.frequencies, reference_spectrogram.frequencies)):
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(f"All tags must be equal for each spectrogram in the input list!")
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(f"All units must be equal for each spectrogram in the input list!")
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([spectrogram.dynamic_spectra for spectrogram in spectrograms])
257
-
258
- transformed_times = time_elapsed( np.concatenate([s.datetimes for s in spectrograms]) )
259
-
260
- return Spectrogram(transformed_dynamic_spectra,
261
- transformed_times,
262
- reference_spectrogram.frequencies,
263
- reference_spectrogram.tag,
264
- reference_spectrogram.spectrum_unit,
265
- reference_spectrogram.start_datetime)
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
+ )
@@ -6,6 +6,4 @@
6
6
 
7
7
  from ._callisto import download_callisto_data, CallistoInstrumentCode
8
8
 
9
- __all__ = [
10
- "download_callisto_data", "CallistoInstrumentCode"
11
- ]
9
+ __all__ = ["download_callisto_data", "CallistoInstrumentCode"]
@@ -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, get_batches_dir_path, TimeFormat
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
- ALASKA_ANCHORAGE = "ALASKA-ANCHORAGE"
21
- ALASKA_COHOE = "ALASKA-COHOE"
22
- ALASKA_HAARP = "ALASKA-HAARP"
23
- ALGERIA_CRAAG = "ALGERIA-CRAAG"
24
- ALMATY = "ALMATY"
25
- AUSTRIA_KRUMBACH = "AUSTRIA-Krumbach"
26
- AUSTRIA_MICHELBACH = "AUSTRIA-MICHELBACH"
27
- AUSTRIA_OE3FLB = "AUSTRIA-OE3FLB"
28
- AUSTRIA_UNIGRAZ = "AUSTRIA-UNIGRAZ"
29
- AUSTRALIA_ASSA = "Australia-ASSA"
30
- BIR = "BIR"
31
- CROATIA_VISNJAN = "Croatia-Visnjan"
32
- DENMARK = "DENMARK"
33
- EGYPT_ALEXANDRIA = "EGYPT-Alexandria"
34
- EGYPT_SPACEAGENCY = "EGYPT-SpaceAgency"
35
- FINLAND_SIUNTIO = "FINLAND-Siuntio"
36
- FINLAND_KEMPELE = "Finland-Kempele"
37
- GERMANY_DLR = "GERMANY-DLR"
38
- GLASGOW = "GLASGOW"
39
- GREENLAND = "GREENLAND"
40
- HUMAIN = "HUMAIN"
41
- HURBANOVO = "HURBANOVO"
42
- INDIA_GAURI = "INDIA-GAURI"
43
- INDIA_OOTY = "INDIA-OOTY"
44
- INDIA_UDAIPUR = "INDIA-UDAIPUR"
45
- JAPAN_IBARAKI = "JAPAN-IBARAKI"
46
- KASI = "KASI"
47
- MEXART = "MEXART"
48
- MEXICO_FCFM_UANL = "MEXICO-FCFM-UANL"
49
- MEXICO_LANCE_A = "MEXICO-LANCE-A"
50
- MEXICO_LANCE_B = "MEXICO-LANCE-B"
51
- MONGOLIA_UB = "MONGOLIA-UB"
52
- MRO = "MRO"
53
- MRT3 = "MRT3"
54
- MALAYSIA_BANTING = "Malaysia-Banting"
55
- NORWAY_EGERSUND = "NORWAY-EGERSUND"
56
- NORWAY_NY_AALESUND = "NORWAY-NY-AALESUND"
57
- NORWAY_RANDABERG = "NORWAY-RANDABERG"
58
- POLAND_GROTNIKI = "POLAND-Grotniki"
59
- ROMANIA = "ROMANIA"
60
- ROSWELL_NM = "ROSWELL-NM"
61
- SPAIN_PERALEJOS = "SPAIN-PERALEJOS"
62
- SSRT = "SSRT"
63
- SWISS_HB9SCT = "SWISS-HB9SCT"
64
- SWISS_HEITERSWIL = "SWISS-HEITERSWIL"
65
- SWISS_IRSOL = "SWISS-IRSOL"
66
- SWISS_LANDSCHLACHT = "SWISS-Landschlacht"
67
- SWISS_MUHEN = "SWISS-MUHEN"
68
- TRIEST = "TRIEST"
69
- TURKEY = "TURKEY"
70
- UNAM = "UNAM"
71
- URUGUAY = "URUGUAY"
72
- USA_BOSTON = "USA-BOSTON"
73
-
74
-
75
- def _get_batch_name(
76
- station: str,
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("Invalid file name format. Expected '[station]_[date]_[time]_[code].fit.gz'")
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( _unzip_file_to_batches(entry.path) )
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", "-r", "-l1", "-nd", "-np",
188
- "-R", ".tmp", "-A", f"{instrument_code}*.fit.gz",
189
- "-P", tmp_dir, base_url
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( _unzip_to_batches(tmp_dir) ), date(year, month, day)
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.22
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
- This repository is in active development. If you are interested, feel free to contact jcfitzpatrick12@gmail.com :)
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_.