imap-processing 0.18.0__py3-none-any.whl → 0.19.2__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.

Potentially problematic release.


This version of imap-processing might be problematic. Click here for more details.

Files changed (122) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/ancillary/ancillary_dataset_combiner.py +161 -1
  3. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -0
  4. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +221 -1057
  5. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +307 -283
  6. imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +1044 -203
  7. imap_processing/cdf/config/imap_constant_attrs.yaml +4 -2
  8. imap_processing/cdf/config/imap_enamaps_l2-common_variable_attrs.yaml +11 -0
  9. imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +15 -1
  10. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +5 -0
  11. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +10 -4
  12. imap_processing/cdf/config/imap_idex_l2a_variable_attrs.yaml +33 -4
  13. imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +8 -91
  14. imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +106 -16
  15. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +5 -4
  16. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +4 -15
  17. imap_processing/cdf/config/imap_lo_l1c_variable_attrs.yaml +189 -98
  18. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +85 -2
  19. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +24 -1
  20. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +20 -8
  21. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +45 -35
  22. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +110 -7
  23. imap_processing/cli.py +138 -93
  24. imap_processing/codice/codice_l0.py +2 -1
  25. imap_processing/codice/codice_l1a.py +167 -69
  26. imap_processing/codice/codice_l1b.py +42 -32
  27. imap_processing/codice/codice_l2.py +215 -9
  28. imap_processing/codice/constants.py +790 -603
  29. imap_processing/codice/data/lo_stepping_values.csv +1 -1
  30. imap_processing/decom.py +1 -4
  31. imap_processing/ena_maps/ena_maps.py +71 -43
  32. imap_processing/ena_maps/utils/corrections.py +291 -0
  33. imap_processing/ena_maps/utils/map_utils.py +20 -4
  34. imap_processing/ena_maps/utils/naming.py +8 -2
  35. imap_processing/glows/ancillary/imap_glows_exclusions-by-instr-team_20250923_v002.dat +10 -0
  36. imap_processing/glows/ancillary/imap_glows_map-of-excluded-regions_20250923_v002.dat +393 -0
  37. imap_processing/glows/ancillary/imap_glows_map-of-uv-sources_20250923_v002.dat +593 -0
  38. imap_processing/glows/ancillary/imap_glows_pipeline-settings_20250923_v002.json +54 -0
  39. imap_processing/glows/ancillary/imap_glows_suspected-transients_20250923_v002.dat +10 -0
  40. imap_processing/glows/l1b/glows_l1b.py +123 -18
  41. imap_processing/glows/l1b/glows_l1b_data.py +358 -47
  42. imap_processing/glows/l2/glows_l2.py +11 -0
  43. imap_processing/hi/hi_l1a.py +124 -3
  44. imap_processing/hi/hi_l1b.py +154 -71
  45. imap_processing/hi/hi_l1c.py +4 -109
  46. imap_processing/hi/hi_l2.py +104 -60
  47. imap_processing/hi/utils.py +262 -8
  48. imap_processing/hit/l0/constants.py +3 -0
  49. imap_processing/hit/l0/decom_hit.py +3 -6
  50. imap_processing/hit/l1a/hit_l1a.py +311 -21
  51. imap_processing/hit/l1b/hit_l1b.py +54 -126
  52. imap_processing/hit/l2/hit_l2.py +6 -6
  53. imap_processing/ialirt/calculate_ingest.py +219 -0
  54. imap_processing/ialirt/constants.py +12 -2
  55. imap_processing/ialirt/generate_coverage.py +15 -2
  56. imap_processing/ialirt/l0/ialirt_spice.py +6 -2
  57. imap_processing/ialirt/l0/parse_mag.py +293 -42
  58. imap_processing/ialirt/l0/process_hit.py +5 -3
  59. imap_processing/ialirt/l0/process_swapi.py +41 -25
  60. imap_processing/ialirt/process_ephemeris.py +70 -14
  61. imap_processing/ialirt/utils/create_xarray.py +1 -1
  62. imap_processing/idex/idex_l0.py +2 -2
  63. imap_processing/idex/idex_l1a.py +2 -3
  64. imap_processing/idex/idex_l1b.py +2 -3
  65. imap_processing/idex/idex_l2a.py +130 -4
  66. imap_processing/idex/idex_l2b.py +158 -143
  67. imap_processing/idex/idex_utils.py +1 -3
  68. imap_processing/lo/ancillary_data/imap_lo_hydrogen-geometric-factor_v001.csv +75 -0
  69. imap_processing/lo/ancillary_data/imap_lo_oxygen-geometric-factor_v001.csv +75 -0
  70. imap_processing/lo/l0/lo_science.py +25 -24
  71. imap_processing/lo/l1b/lo_l1b.py +93 -19
  72. imap_processing/lo/l1c/lo_l1c.py +273 -93
  73. imap_processing/lo/l2/lo_l2.py +949 -135
  74. imap_processing/lo/lo_ancillary.py +55 -0
  75. imap_processing/mag/l1a/mag_l1a.py +1 -0
  76. imap_processing/mag/l1a/mag_l1a_data.py +26 -0
  77. imap_processing/mag/l1b/mag_l1b.py +3 -2
  78. imap_processing/mag/l1c/interpolation_methods.py +14 -15
  79. imap_processing/mag/l1c/mag_l1c.py +23 -6
  80. imap_processing/mag/l1d/mag_l1d.py +57 -14
  81. imap_processing/mag/l1d/mag_l1d_data.py +202 -32
  82. imap_processing/mag/l2/mag_l2.py +2 -0
  83. imap_processing/mag/l2/mag_l2_data.py +14 -5
  84. imap_processing/quality_flags.py +23 -1
  85. imap_processing/spice/geometry.py +89 -39
  86. imap_processing/spice/pointing_frame.py +4 -8
  87. imap_processing/spice/repoint.py +78 -2
  88. imap_processing/spice/spin.py +28 -8
  89. imap_processing/spice/time.py +12 -22
  90. imap_processing/swapi/l1/swapi_l1.py +10 -4
  91. imap_processing/swapi/l2/swapi_l2.py +15 -17
  92. imap_processing/swe/l1b/swe_l1b.py +1 -2
  93. imap_processing/ultra/constants.py +30 -24
  94. imap_processing/ultra/l0/ultra_utils.py +9 -11
  95. imap_processing/ultra/l1a/ultra_l1a.py +1 -2
  96. imap_processing/ultra/l1b/badtimes.py +35 -11
  97. imap_processing/ultra/l1b/de.py +95 -31
  98. imap_processing/ultra/l1b/extendedspin.py +31 -16
  99. imap_processing/ultra/l1b/goodtimes.py +112 -0
  100. imap_processing/ultra/l1b/lookup_utils.py +281 -28
  101. imap_processing/ultra/l1b/quality_flag_filters.py +10 -1
  102. imap_processing/ultra/l1b/ultra_l1b.py +7 -7
  103. imap_processing/ultra/l1b/ultra_l1b_culling.py +169 -7
  104. imap_processing/ultra/l1b/ultra_l1b_extended.py +311 -69
  105. imap_processing/ultra/l1c/helio_pset.py +139 -37
  106. imap_processing/ultra/l1c/l1c_lookup_utils.py +289 -0
  107. imap_processing/ultra/l1c/spacecraft_pset.py +140 -29
  108. imap_processing/ultra/l1c/ultra_l1c.py +33 -24
  109. imap_processing/ultra/l1c/ultra_l1c_culling.py +92 -0
  110. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +400 -292
  111. imap_processing/ultra/l2/ultra_l2.py +54 -11
  112. imap_processing/ultra/utils/ultra_l1_utils.py +37 -7
  113. imap_processing/utils.py +3 -4
  114. {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/METADATA +2 -2
  115. {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/RECORD +118 -109
  116. imap_processing/idex/idex_l2c.py +0 -84
  117. imap_processing/spice/kernels.py +0 -187
  118. imap_processing/ultra/l1b/cullingmask.py +0 -87
  119. imap_processing/ultra/l1c/histogram.py +0 -36
  120. {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/LICENSE +0 -0
  121. {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/WHEEL +0 -0
  122. {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/entry_points.txt +0 -0
@@ -37,28 +37,28 @@ HistPacking = namedtuple(
37
37
 
38
38
  HIST_DATA_META = {
39
39
  # field: bit_length, section_length, shape
40
- "start_a": HistPacking(12, 504, (6, 7)),
41
- "start_c": HistPacking(12, 504, (6, 7)),
42
- "stop_b0": HistPacking(12, 504, (6, 7)),
43
- "stop_b3": HistPacking(12, 504, (6, 7)),
44
- "tof0_count": HistPacking(8, 336, (6, 7)),
45
- "tof1_count": HistPacking(8, 336, (6, 7)),
46
- "tof2_count": HistPacking(8, 336, (6, 7)),
47
- "tof3_count": HistPacking(8, 336, (6, 7)),
48
- "tof0_tof1": HistPacking(8, 3360, (60, 7)),
49
- "tof0_tof2": HistPacking(8, 3360, (60, 7)),
50
- "tof1_tof2": HistPacking(8, 3360, (60, 7)),
51
- "silver": HistPacking(8, 3360, (60, 7)),
52
- "disc_tof0": HistPacking(8, 336, (6, 7)),
53
- "disc_tof1": HistPacking(8, 336, (6, 7)),
54
- "disc_tof2": HistPacking(8, 336, (6, 7)),
55
- "disc_tof3": HistPacking(8, 336, (6, 7)),
56
- "pos0": HistPacking(12, 504, (6, 7)),
57
- "pos1": HistPacking(12, 504, (6, 7)),
58
- "pos2": HistPacking(12, 504, (6, 7)),
59
- "pos3": HistPacking(12, 504, (6, 7)),
60
- "hydrogen": HistPacking(8, 3360, (60, 7)),
61
- "oxygen": HistPacking(8, 3360, (60, 7)),
40
+ "start_a": HistPacking(12, 504, (7, 6)),
41
+ "start_c": HistPacking(12, 504, (7, 6)),
42
+ "stop_b0": HistPacking(12, 504, (7, 6)),
43
+ "stop_b3": HistPacking(12, 504, (7, 6)),
44
+ "tof0_count": HistPacking(8, 336, (7, 6)),
45
+ "tof1_count": HistPacking(8, 336, (7, 6)),
46
+ "tof2_count": HistPacking(8, 336, (7, 6)),
47
+ "tof3_count": HistPacking(8, 336, (7, 6)),
48
+ "tof0_tof1": HistPacking(8, 3360, (7, 60)),
49
+ "tof0_tof2": HistPacking(8, 3360, (7, 60)),
50
+ "tof1_tof2": HistPacking(8, 3360, (7, 60)),
51
+ "silver": HistPacking(8, 3360, (7, 60)),
52
+ "disc_tof0": HistPacking(8, 336, (7, 6)),
53
+ "disc_tof1": HistPacking(8, 336, (7, 6)),
54
+ "disc_tof2": HistPacking(8, 336, (7, 6)),
55
+ "disc_tof3": HistPacking(8, 336, (7, 6)),
56
+ "pos0": HistPacking(12, 504, (7, 6)),
57
+ "pos1": HistPacking(12, 504, (7, 6)),
58
+ "pos2": HistPacking(12, 504, (7, 6)),
59
+ "pos3": HistPacking(12, 504, (7, 6)),
60
+ "hydrogen": HistPacking(8, 3360, (7, 60)),
61
+ "oxygen": HistPacking(8, 3360, (7, 60)),
62
62
  }
63
63
 
64
64
 
@@ -399,7 +399,7 @@ def combine_segmented_packets(dataset: xr.Dataset) -> xr.Dataset:
399
399
  # Combine the segmented packets into a single binary string
400
400
  dataset["events"] = [
401
401
  "".join(dataset["data"].values[start : end + 1])
402
- for start, end in zip(seg_starts, seg_ends)
402
+ for start, end in zip(seg_starts, seg_ends, strict=False)
403
403
  ]
404
404
 
405
405
  # drop any group of segmented packets that aren't sequential
@@ -441,7 +441,8 @@ def find_valid_groups(
441
441
  """
442
442
  # Check if the sequence counters from the CCSDS header are sequential
443
443
  grouped_seq_ctrs = [
444
- np.array(seq_ctrs[start : end + 1]) for start, end in zip(seg_starts, seg_ends)
444
+ np.array(seq_ctrs[start : end + 1])
445
+ for start, end in zip(seg_starts, seg_ends, strict=False)
445
446
  ]
446
447
  valid_groups = [is_sequential(seq_ctrs) for seq_ctrs in grouped_seq_ctrs]
447
448
  return valid_groups
@@ -3,12 +3,13 @@
3
3
  import logging
4
4
  from dataclasses import Field
5
5
  from pathlib import Path
6
- from typing import Any, Union
6
+ from typing import Any
7
7
 
8
8
  import numpy as np
9
9
  import xarray as xr
10
10
 
11
11
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
12
+ from imap_processing.lo import lo_ancillary
12
13
  from imap_processing.lo.l1b.tof_conversions import (
13
14
  TOF0_CONV,
14
15
  TOF1_CONV,
@@ -16,20 +17,24 @@ from imap_processing.lo.l1b.tof_conversions import (
16
17
  TOF3_CONV,
17
18
  )
18
19
  from imap_processing.spice.geometry import SpiceFrame, instrument_pointing
20
+ from imap_processing.spice.repoint import get_pointing_times
21
+ from imap_processing.spice.spin import get_spin_number
19
22
  from imap_processing.spice.time import met_to_ttj2000ns, ttj2000ns_to_et
20
23
 
21
24
  logger = logging.getLogger(__name__)
22
25
  logger.setLevel(logging.INFO)
23
26
 
24
27
 
25
- def lo_l1b(dependencies: dict) -> list[Path]:
28
+ def lo_l1b(sci_dependencies: dict, anc_dependencies: list) -> list[Path]:
26
29
  """
27
30
  Will process IMAP-Lo L1A data into L1B CDF data products.
28
31
 
29
32
  Parameters
30
33
  ----------
31
- dependencies : dict
34
+ sci_dependencies : dict
32
35
  Dictionary of datasets needed for L1B data product creation in xarray Datasets.
36
+ anc_dependencies : list
37
+ List of ancillary file paths needed for L1B data product creation.
33
38
 
34
39
  Returns
35
40
  -------
@@ -43,17 +48,20 @@ def lo_l1b(dependencies: dict) -> list[Path]:
43
48
  # create the attribute manager to access L1A fillval attributes
44
49
  attr_mgr_l1a = ImapCdfAttributes()
45
50
  attr_mgr_l1a.add_instrument_variable_attrs(instrument="lo", level="l1a")
46
- logger.info(f"\n Dependencies: {list(dependencies.keys())}\n")
51
+ logger.info(f"\n Dependencies: {list(sci_dependencies.keys())}\n")
47
52
  # if the dependencies are used to create Annotated Direct Events
48
- if "imap_lo_l1a_de" in dependencies and "imap_lo_l1a_spin" in dependencies:
53
+ if "imap_lo_l1a_de" in sci_dependencies and "imap_lo_l1a_spin" in sci_dependencies:
49
54
  logger.info("\nProcessing IMAP-Lo L1B Direct Events...")
50
55
  logical_source = "imap_lo_l1b_de"
51
56
  # get the dependency dataset for l1b direct events
52
- l1a_de = dependencies["imap_lo_l1a_de"]
53
- spin_data = dependencies["imap_lo_l1a_spin"]
57
+ l1a_de = sci_dependencies["imap_lo_l1a_de"]
58
+ spin_data = sci_dependencies["imap_lo_l1a_spin"]
54
59
 
55
60
  # Initialize the L1B DE dataset
56
61
  l1b_de = initialize_l1b_de(l1a_de, attr_mgr_l1b, logical_source)
62
+ pointing_start_met, pointing_end_met = get_pointing_times(
63
+ l1a_de["met"].values[0].item()
64
+ )
57
65
  # Get the start and end times for each spin epoch
58
66
  acq_start, acq_end = convert_start_end_acq_times(spin_data)
59
67
  # Get the average spin durations for each epoch
@@ -66,7 +74,7 @@ def lo_l1b(dependencies: dict) -> list[Path]:
66
74
  # spin bins are 0 - 60 bins
67
75
  l1b_de = set_spin_bin(l1b_de, spin_angle)
68
76
  # set the spin cycle for each direct event
69
- l1b_de = set_spin_cycle(l1a_de, l1b_de)
77
+ l1b_de = set_spin_cycle(pointing_start_met, l1a_de, l1b_de)
70
78
  # get spin start times for each event
71
79
  spin_start_time = get_spin_start_times(l1a_de, l1b_de, spin_data, acq_end)
72
80
  # get the absolute met for each event
@@ -75,6 +83,10 @@ def lo_l1b(dependencies: dict) -> list[Path]:
75
83
  )
76
84
  # set the epoch for each event
77
85
  l1b_de = set_each_event_epoch(l1b_de)
86
+ # Set the ESA mode for each direct event
87
+ l1b_de = set_esa_mode(
88
+ pointing_start_met, pointing_end_met, anc_dependencies, l1b_de
89
+ )
78
90
  # Set the average spin duration for each direct event
79
91
  l1b_de = set_avg_spin_durations_per_event(
80
92
  l1a_de, l1b_de, avg_spin_durations_per_cycle
@@ -133,7 +145,7 @@ def initialize_l1b_de(
133
145
  # TODO: Add pos to YAML file
134
146
  # attrs=attr_mgr.get_variable_attributes("pos"),
135
147
  )
136
- l1b_de["mode"] = xr.DataArray(
148
+ l1b_de["mode_bit"] = xr.DataArray(
137
149
  l1a_de["mode"].values,
138
150
  dims=["epoch"],
139
151
  # TODO: Add mode to YAML file
@@ -155,6 +167,65 @@ def initialize_l1b_de(
155
167
  return l1b_de
156
168
 
157
169
 
170
+ def set_esa_mode(
171
+ pointing_start_met: float,
172
+ pointing_end_met: float,
173
+ anc_dependencies: list,
174
+ l1b_de: xr.Dataset,
175
+ ) -> xr.Dataset:
176
+ """
177
+ Set the ESA mode for each direct event.
178
+
179
+ The ESA mode is determined from the sweep table for the time period of the pointing.
180
+
181
+ Parameters
182
+ ----------
183
+ pointing_start_met : float
184
+ Start time for the pointing in MET seconds.
185
+ pointing_end_met : float
186
+ End time for the pointing in MET seconds.
187
+ anc_dependencies : list
188
+ List of ancillary file paths.
189
+ l1b_de : xarray.Dataset
190
+ The L1B DE dataset.
191
+
192
+ Returns
193
+ -------
194
+ l1b_de : xr.Dataset
195
+ The L1B DE dataset with the ESA mode added.
196
+ """
197
+ # Read the sweep table from the ancillary files
198
+ sweep_df = lo_ancillary.read_ancillary_file(
199
+ next(str(s) for s in anc_dependencies if "sweep-table" in str(s))
200
+ )
201
+
202
+ # Get the sweep table rows that correspond to the time period of the pointing
203
+ pointing_sweep_df = sweep_df[
204
+ (sweep_df["GoodTime_start"] >= pointing_start_met)
205
+ & (sweep_df["GoodTime_start"] <= pointing_end_met)
206
+ ]
207
+
208
+ # Check that there is only one ESA mode in the sweep table for the pointing
209
+ if len(pointing_sweep_df["ESA_Mode"].unique()) == 1:
210
+ # Update the ESA mode strings to be 0 for HiRes and 1 for HiThr
211
+ sweep_df["esa_mode"] = sweep_df["ESA_Mode"].map({"HiRes": 0, "HiThr": 1})
212
+ # Get the ESA mode for the pointing
213
+ esa_mode = sweep_df["esa_mode"].values[0]
214
+ # Repeat the ESA mode for each direct event in the pointing
215
+ esa_mode_array = np.repeat(esa_mode, len(l1b_de["epoch"]))
216
+ else:
217
+ raise ValueError("Multiple ESA modes found in sweep table for pointing.")
218
+
219
+ l1b_de["esa_mode"] = xr.DataArray(
220
+ esa_mode_array,
221
+ dims=["epoch"],
222
+ # TODO: Add esa_mode to YAML file
223
+ # attrs=attr_mgr.get_variable_attributes("esa_mode"),
224
+ )
225
+
226
+ return l1b_de
227
+
228
+
158
229
  def convert_start_end_acq_times(
159
230
  spin_data: xr.Dataset,
160
231
  ) -> tuple[xr.DataArray, xr.DataArray]:
@@ -204,7 +275,7 @@ def get_avg_spin_durations_per_cycle(
204
275
  return avg_spin_durations_per_cycle
205
276
 
206
277
 
207
- def get_spin_angle(l1a_de: xr.Dataset) -> Union[np.ndarray[np.float64], Any]:
278
+ def get_spin_angle(l1a_de: xr.Dataset) -> np.ndarray[np.float64] | Any:
208
279
  """
209
280
  Get the spin angle (0 - 360 degrees) for each DE.
210
281
 
@@ -252,7 +323,9 @@ def set_spin_bin(l1b_de: xr.Dataset, spin_angle: np.ndarray) -> xr.Dataset:
252
323
  return l1b_de
253
324
 
254
325
 
255
- def set_spin_cycle(l1a_de: xr.Dataset, l1b_de: xr.Dataset) -> xr.Dataset:
326
+ def set_spin_cycle(
327
+ pointing_start_met: float, l1a_de: xr.Dataset, l1b_de: xr.Dataset
328
+ ) -> xr.Dataset:
256
329
  """
257
330
  Set the spin cycle for each direct event.
258
331
 
@@ -265,6 +338,8 @@ def set_spin_cycle(l1a_de: xr.Dataset, l1b_de: xr.Dataset) -> xr.Dataset:
265
338
 
266
339
  Parameters
267
340
  ----------
341
+ pointing_start_met : float
342
+ The start time of the pointing in MET seconds.
268
343
  l1a_de : xarray.Dataset
269
344
  The L1A DE dataset.
270
345
  l1b_de : xarray.Dataset
@@ -275,19 +350,18 @@ def set_spin_cycle(l1a_de: xr.Dataset, l1b_de: xr.Dataset) -> xr.Dataset:
275
350
  l1b_de : xarray.Dataset
276
351
  The L1B DE dataset with the spin cycle added for each direct event.
277
352
  """
353
+ spin_start_num = get_spin_number(pointing_start_met)
278
354
  counts = l1a_de["de_count"].values
279
355
  # split the esa_steps into ASC groups
280
356
  de_asc_groups = np.split(l1a_de["esa_step"].values, np.cumsum(counts)[:-1])
281
357
  spin_cycle = []
282
- for i, esa_asc_group in enumerate(de_asc_groups):
283
- # TODO: Spin Number does not reset for each pointing. Need to figure out
284
- # how to retain this information across days
285
- # increment the spin_start by 28 after each aggregated science cycle
286
- spin_start = i * 28
358
+ for esa_asc_group in de_asc_groups:
287
359
  # calculate the spin cycle for each DE in the ASC group
288
360
  # TODO: Add equation number in algorithm document when new version is
289
- # available. Add to docstring as well
290
- spin_cycle.extend(spin_start + 7 + (esa_asc_group - 1) * 2)
361
+ # available. Add to docstring as well
362
+ spin_cycle.extend(spin_start_num + 7 + (esa_asc_group - 1) * 2)
363
+ # increment the spin start number by 28 for the next ASC
364
+ spin_start_num += 28
291
365
 
292
366
  l1b_de["spin_cycle"] = xr.DataArray(
293
367
  spin_cycle,
@@ -587,7 +661,7 @@ def convert_tofs_to_eu(
587
661
  tof_conversions = [TOF0_CONV, TOF1_CONV, TOF2_CONV, TOF3_CONV]
588
662
 
589
663
  # Loop through the TOF fields and convert them to engineering units
590
- for tof, conv in zip(tof_fields, tof_conversions):
664
+ for tof, conv in zip(tof_fields, tof_conversions, strict=False):
591
665
  # Get the fill value for the L1A and L1B TOF
592
666
  fillval_1a = attr_mgr_l1a.get_variable_attributes(tof)["FILLVAL"]
593
667
  fillval_1b = attr_mgr_l1b.get_variable_attributes(tof)["FILLVAL"]