imap-processing 1.0.1__py3-none-any.whl → 1.0.3__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 (58) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +18 -0
  3. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +101 -258
  4. imap_processing/cdf/config/imap_enamaps_l2-common_variable_attrs.yaml +1 -1
  5. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +12 -2
  6. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +1 -8
  7. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +16 -5
  8. imap_processing/cdf/config/imap_idex_l2a_variable_attrs.yaml +27 -25
  9. imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +16 -16
  10. imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +2 -2
  11. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +2 -13
  12. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +12 -0
  13. imap_processing/cdf/utils.py +2 -2
  14. imap_processing/cli.py +4 -16
  15. imap_processing/codice/codice_l1a_lo_angular.py +362 -0
  16. imap_processing/codice/codice_l1a_lo_species.py +282 -0
  17. imap_processing/codice/codice_l1b.py +80 -97
  18. imap_processing/codice/codice_l2.py +270 -103
  19. imap_processing/codice/codice_new_l1a.py +64 -0
  20. imap_processing/codice/constants.py +37 -2
  21. imap_processing/codice/utils.py +270 -0
  22. imap_processing/ena_maps/ena_maps.py +51 -39
  23. imap_processing/ena_maps/utils/corrections.py +196 -14
  24. imap_processing/ena_maps/utils/naming.py +3 -1
  25. imap_processing/hi/hi_l1c.py +57 -19
  26. imap_processing/hi/hi_l2.py +89 -36
  27. imap_processing/ialirt/calculate_ingest.py +19 -1
  28. imap_processing/ialirt/constants.py +12 -6
  29. imap_processing/ialirt/generate_coverage.py +6 -1
  30. imap_processing/ialirt/l0/parse_mag.py +1 -0
  31. imap_processing/ialirt/l0/process_hit.py +1 -0
  32. imap_processing/ialirt/l0/process_swapi.py +1 -0
  33. imap_processing/ialirt/l0/process_swe.py +2 -0
  34. imap_processing/ialirt/process_ephemeris.py +6 -2
  35. imap_processing/ialirt/utils/create_xarray.py +3 -2
  36. imap_processing/lo/l1b/lo_l1b.py +12 -2
  37. imap_processing/lo/l1c/lo_l1c.py +4 -4
  38. imap_processing/lo/l2/lo_l2.py +101 -8
  39. imap_processing/quality_flags.py +1 -0
  40. imap_processing/swapi/constants.py +4 -0
  41. imap_processing/swapi/l1/swapi_l1.py +47 -20
  42. imap_processing/swapi/l2/swapi_l2.py +17 -3
  43. imap_processing/ultra/l1a/ultra_l1a.py +121 -72
  44. imap_processing/ultra/l1b/de.py +57 -1
  45. imap_processing/ultra/l1b/ultra_l1b_annotated.py +0 -1
  46. imap_processing/ultra/l1b/ultra_l1b_extended.py +24 -11
  47. imap_processing/ultra/l1c/helio_pset.py +34 -8
  48. imap_processing/ultra/l1c/l1c_lookup_utils.py +4 -2
  49. imap_processing/ultra/l1c/spacecraft_pset.py +13 -7
  50. imap_processing/ultra/l1c/ultra_l1c.py +6 -6
  51. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +79 -20
  52. imap_processing/ultra/l2/ultra_l2.py +2 -2
  53. imap_processing/ultra/utils/ultra_l1_utils.py +6 -0
  54. {imap_processing-1.0.1.dist-info → imap_processing-1.0.3.dist-info}/METADATA +1 -1
  55. {imap_processing-1.0.1.dist-info → imap_processing-1.0.3.dist-info}/RECORD +58 -54
  56. {imap_processing-1.0.1.dist-info → imap_processing-1.0.3.dist-info}/LICENSE +0 -0
  57. {imap_processing-1.0.1.dist-info → imap_processing-1.0.3.dist-info}/WHEEL +0 -0
  58. {imap_processing-1.0.1.dist-info → imap_processing-1.0.3.dist-info}/entry_points.txt +0 -0
@@ -6,6 +6,7 @@ import astropy_healpix.healpy as hp
6
6
  import numpy as np
7
7
  import xarray as xr
8
8
 
9
+ from imap_processing.cdf.utils import parse_filename_like
9
10
  from imap_processing.quality_flags import ImapPSETUltraFlags
10
11
  from imap_processing.spice.repoint import get_pointing_times
11
12
  from imap_processing.spice.time import (
@@ -24,6 +25,7 @@ from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
24
25
  get_efficiencies_and_geometric_function,
25
26
  get_energy_delta_minus_plus,
26
27
  get_helio_adjusted_data,
28
+ get_spacecraft_background_rates,
27
29
  get_spacecraft_exposure_times,
28
30
  get_spacecraft_histogram,
29
31
  )
@@ -69,9 +71,14 @@ def calculate_helio_pset(
69
71
  dataset : xarray.Dataset
70
72
  Dataset containing the data.
71
73
  """
74
+ sensor = parse_filename_like(name)["sensor"][0:2]
72
75
  pset_dict: dict[str, np.ndarray] = {}
73
76
  # Select only the species we are interested in.
74
77
  indices = np.where(np.isin(de_dataset["ebin"].values, species_id))[0]
78
+ if indices.size == 0:
79
+ logger.info(f"No data available for {name}")
80
+ return None
81
+
75
82
  species_dataset = de_dataset.isel(epoch=indices)
76
83
 
77
84
  rejected = get_de_rejection_mask(
@@ -120,17 +127,22 @@ def calculate_helio_pset(
120
127
  )
121
128
  healpix = np.arange(n_pix)
122
129
 
130
+ # Get midpoint timestamp for pointing.
131
+ pointing_range_met = get_pointing_times(
132
+ et_to_met(species_dataset["event_times"].mean())
133
+ )
123
134
  logger.info("Calculating spacecraft exposure times with deadtime correction.")
124
135
  exposure_time, deadtime_ratios = get_spacecraft_exposure_times(
125
136
  rates_dataset,
126
137
  params_dataset,
127
138
  pixels_below_scattering,
128
139
  boundary_scale_factors,
140
+ pointing_range_met,
129
141
  n_pix=n_pix,
130
142
  )
131
143
  logger.info("Calculating spun efficiencies and geometric function.")
132
144
  # calculate efficiency and geometric function as a function of energy
133
- efficiencies, geometric_function = get_efficiencies_and_geometric_function(
145
+ geometric_function, efficiencies = get_efficiencies_and_geometric_function(
134
146
  pixels_below_scattering,
135
147
  boundary_scale_factors,
136
148
  theta_vals,
@@ -138,11 +150,20 @@ def calculate_helio_pset(
138
150
  n_pix,
139
151
  ancillary_files,
140
152
  )
141
- # Get midpoint timestamp for pointing.
142
- pointing_start, pointing_stop = get_pointing_times(
143
- et_to_met(species_dataset["event_times"].data[0])
153
+
154
+ logger.info("Calculating background rates.")
155
+ # TODO calculate helio background rates
156
+ # Calculate background rates
157
+ background_rates = get_spacecraft_background_rates(
158
+ rates_dataset,
159
+ sensor,
160
+ ancillary_files,
161
+ intervals,
162
+ goodtimes_dataset["spin_number"].values,
163
+ nside=nside,
144
164
  )
145
- mid_time = ttj2000ns_to_et(met_to_ttj2000ns((pointing_start + pointing_stop) / 2))
165
+
166
+ mid_time = ttj2000ns_to_et(met_to_ttj2000ns((np.sum(pointing_range_met)) / 2))
146
167
 
147
168
  logger.info("Adjusting data for helio frame.")
148
169
  exposure_time, _efficiency, geometric_function = get_helio_adjusted_data(
@@ -169,14 +190,19 @@ def calculate_helio_pset(
169
190
  helio_pset_quality_flags,
170
191
  nside=nside,
171
192
  )
172
- pointing_start = met_to_ttj2000ns(pointing_start)
193
+ # Convert pointing start and end time to ttj2000ns
194
+ pointing_range_ns = met_to_ttj2000ns(pointing_range_met)
173
195
  # Epoch should be the start of the pointing
174
- pset_dict["epoch"] = np.atleast_1d(pointing_start).astype(np.int64)
196
+ pset_dict["epoch"] = np.atleast_1d(pointing_range_ns[0]).astype(np.int64)
197
+ pset_dict["epoch_delta"] = np.atleast_1d(np.diff(pointing_range_ns)).astype(
198
+ np.int64
199
+ )
175
200
  pset_dict["counts"] = counts[np.newaxis, ...]
176
201
  pset_dict["latitude"] = latitude[np.newaxis, ...]
177
202
  pset_dict["longitude"] = longitude[np.newaxis, ...]
178
203
  pset_dict["energy_bin_geometric_mean"] = energy_bin_geometric_means
179
- pset_dict["helio_exposure_factor"] = exposure_time[np.newaxis, ...]
204
+ pset_dict["background_rates"] = background_rates[np.newaxis, ...]
205
+ pset_dict["exposure_factor"] = exposure_time[np.newaxis, ...]
180
206
  pset_dict["pixel_index"] = healpix
181
207
  pset_dict["energy_bin_delta"] = np.diff(intervals, axis=1).squeeze()[
182
208
  np.newaxis, ...
@@ -174,8 +174,10 @@ def calculate_fwhm_spun_scattering(
174
174
  fwhm_phi_sum[:, for_inds] += fwhm_phi.T
175
175
  sample_count[:, for_inds] += 1
176
176
 
177
- fwhm_phi_avg = np.divide(fwhm_theta_sum, sample_count, where=sample_count != 0)
178
- fwhm_theta_avg = np.divide(fwhm_theta_sum, sample_count, where=sample_count != 0)
177
+ fwhm_phi_avg = np.zeros_like(fwhm_phi_sum)
178
+ fwhm_theta_avg = np.zeros_like(fwhm_theta_sum)
179
+ np.divide(fwhm_phi_sum, sample_count, out=fwhm_phi_avg, where=sample_count != 0)
180
+ np.divide(fwhm_theta_sum, sample_count, out=fwhm_theta_avg, where=sample_count != 0)
179
181
  return (
180
182
  pixels_below_scattering,
181
183
  fwhm_theta_avg,
@@ -77,6 +77,7 @@ def calculate_spacecraft_pset(
77
77
 
78
78
  # If there are no species return None.
79
79
  if indices.size == 0:
80
+ logger.info(f"No data available for {name}")
80
81
  return None
81
82
 
82
83
  # Before we use the de_dataset to calculate the pointing set grid we need to filter.
@@ -126,7 +127,7 @@ def calculate_spacecraft_pset(
126
127
 
127
128
  logger.info("Calculating spun efficiencies and geometric function.")
128
129
  # calculate efficiency and geometric function as a function of energy
129
- efficiencies, geometric_function = get_efficiencies_and_geometric_function(
130
+ geometric_function, efficiencies = get_efficiencies_and_geometric_function(
130
131
  pixels_below_scattering,
131
132
  boundary_scale_factors,
132
133
  theta_vals,
@@ -136,6 +137,10 @@ def calculate_spacecraft_pset(
136
137
  )
137
138
  sensitivity = efficiencies * geometric_function
138
139
 
140
+ # Get the start and stop times of the pointing period
141
+ pointing_range_met = get_pointing_times(
142
+ float(et_to_met(species_dataset["event_times"].mean()))
143
+ )
139
144
  # Calculate exposure times
140
145
  logger.info("Calculating spacecraft exposure times with deadtime correction.")
141
146
  exposure_pointing, deadtime_ratios = get_spacecraft_exposure_times(
@@ -143,6 +148,7 @@ def calculate_spacecraft_pset(
143
148
  params_dataset,
144
149
  pixels_below_scattering,
145
150
  boundary_scale_factors,
151
+ pointing_range_met,
146
152
  n_pix=n_pix,
147
153
  )
148
154
  logger.info("Calculating background rates.")
@@ -172,13 +178,13 @@ def calculate_spacecraft_pset(
172
178
  spacecraft_pset_quality_flags,
173
179
  nside=nside,
174
180
  )
175
- # Get pointing start and stop times and convert to ttj2000ns
176
- pointing_start, _pointing_stop = get_pointing_times(
177
- float(et_to_met(species_dataset["event_times"].data[0]))
178
- )
179
- pointing_start = met_to_ttj2000ns(pointing_start)
181
+ # Convert pointing start and end time to ttj2000ns
182
+ pointing_range_ns = met_to_ttj2000ns(pointing_range_met)
180
183
  # Epoch should be the start of the pointing
181
- pset_dict["epoch"] = np.atleast_1d(pointing_start).astype(np.int64)
184
+ pset_dict["epoch"] = np.atleast_1d(pointing_range_ns[0]).astype(np.int64)
185
+ pset_dict["epoch_delta"] = np.atleast_1d(np.diff(pointing_range_ns)).astype(
186
+ np.int64
187
+ )
182
188
  pset_dict["counts"] = counts[np.newaxis, ...]
183
189
  pset_dict["latitude"] = latitude[np.newaxis, ...]
184
190
  pset_dict["longitude"] = longitude[np.newaxis, ...]
@@ -8,7 +8,7 @@ from imap_processing.ultra.l1c.spacecraft_pset import calculate_spacecraft_pset
8
8
 
9
9
 
10
10
  def ultra_l1c(
11
- data_dict: dict, ancillary_files: dict, imap_frames: bool
11
+ data_dict: dict, ancillary_files: dict, descriptor: str
12
12
  ) -> list[xr.Dataset]:
13
13
  """
14
14
  Will process ULTRA L1A and L1B data into L1C CDF files at output_filepath.
@@ -19,8 +19,8 @@ def ultra_l1c(
19
19
  The data itself and its dependent data.
20
20
  ancillary_files : dict
21
21
  Ancillary files.
22
- imap_frames : bool
23
- Whether to use IMAP frames.
22
+ descriptor : str
23
+ Job descriptor.
24
24
 
25
25
  Returns
26
26
  -------
@@ -28,15 +28,15 @@ def ultra_l1c(
28
28
  List of xarray.Dataset.
29
29
  """
30
30
  output_datasets = []
31
-
32
- # Account for possibility of having 45 and 90 in dictionary.
31
+ create_helio_pset = True if "helio" in descriptor else False
32
+ # Account for the possibility of having 45 and 90 in the dictionary.
33
33
  for instrument_id in [45, 90]:
34
34
  if (
35
35
  f"imap_ultra_l1b_{instrument_id}sensor-goodtimes" in data_dict
36
36
  and f"imap_ultra_l1b_{instrument_id}sensor-de" in data_dict
37
37
  and f"imap_ultra_l1a_{instrument_id}sensor-rates" in data_dict
38
38
  and f"imap_ultra_l1a_{instrument_id}sensor-params" in data_dict
39
- and imap_frames
39
+ and create_helio_pset
40
40
  ):
41
41
  helio_pset = calculate_helio_pset(
42
42
  data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
@@ -13,7 +13,11 @@ from imap_processing.spice.geometry import (
13
13
  cartesian_to_spherical,
14
14
  imap_state,
15
15
  )
16
- from imap_processing.spice.spin import get_spacecraft_spin_phase, get_spin_angle
16
+ from imap_processing.spice.spin import (
17
+ get_spacecraft_spin_phase,
18
+ get_spin_angle,
19
+ get_spin_data,
20
+ )
17
21
  from imap_processing.spice.time import ttj2000ns_to_met
18
22
  from imap_processing.ultra.constants import UltraConstants
19
23
  from imap_processing.ultra.l1b.lookup_utils import (
@@ -381,7 +385,7 @@ def calculate_exposure_time(
381
385
  # Get energy bin geometric means
382
386
  energy_bin_geometric_means = build_energy_bins()[2]
383
387
  # Exposure time should now be of shape (energy, npix)
384
- exposure_pointing = np.zeros((len(energy_bin_geometric_means), n_pix))
388
+ counts = np.zeros((len(energy_bin_geometric_means), n_pix))
385
389
  # nominal spin phase step.
386
390
  nominal_ms_step = 15 / len(pixels_below_scattering) # time step
387
391
  # Query the dead-time ratio and apply the nominal exposure time to pixels in the FOR
@@ -396,12 +400,13 @@ def calculate_exposure_time(
396
400
  continue
397
401
  # Apply the nominal exposure time (1 ms) scaled by the deadtime ratio to
398
402
  # every pixel in the FOR, that is below the FWHM scattering threshold,
399
- exposure_pointing[energy_bin_idx, pixels_at_energy_and_spin] += (
400
- nominal_ms_step
401
- * deadtime_ratios[i]
403
+ counts[energy_bin_idx, pixels_at_energy_and_spin] += (
404
+ deadtime_ratios[i]
402
405
  * boundary_scale_factors[pixels_at_energy_and_spin, i]
403
406
  )
404
407
 
408
+ # Multiply by the nominal spin step to get the exposure time in ms
409
+ exposure_pointing = counts * nominal_ms_step
405
410
  return exposure_pointing
406
411
 
407
412
 
@@ -410,6 +415,7 @@ def get_spacecraft_exposure_times(
410
415
  params_dataset: xr.Dataset,
411
416
  pixels_below_scattering: list[list],
412
417
  boundary_scale_factors: NDArray,
418
+ pointing_range_met: tuple[float, float],
413
419
  n_pix: int,
414
420
  ) -> tuple[NDArray, NDArray]:
415
421
  """
@@ -428,6 +434,8 @@ def get_spacecraft_exposure_times(
428
434
  below the FWHM scattering threshold.
429
435
  boundary_scale_factors : np.ndarray
430
436
  Boundary scale factors for each pixel at each spin phase.
437
+ pointing_range_met : tuple
438
+ Start and stop time of the pointing period in mission elapsed time.
431
439
  n_pix : int
432
440
  Number of HEALPix pixels.
433
441
 
@@ -440,13 +448,36 @@ def get_spacecraft_exposure_times(
440
448
  nominal_deadtime_ratios : np.ndarray
441
449
  Deadtime ratios at each spin phase step (1ms res).
442
450
  """
443
- # TODO: use the universal spin table and
444
- # universal pointing table here to determine actual number of spins
445
451
  sectored_rates = get_sectored_rates(rates_dataset, params_dataset)
446
452
  nominal_deadtime_ratios = get_deadtime_ratios_by_spin_phase(sectored_rates)
447
- exposure_pointing_adjusted = calculate_exposure_time(
453
+ # The exposure time will be approximately the same per spin, so to save
454
+ # computation time, calculate the exposure time for a single spin and then scale it
455
+ # by the number of spins in the pointing. For more information, see section 3.4.3
456
+ # of the Ultra Algorithm Document.
457
+ exposure_time = calculate_exposure_time(
448
458
  nominal_deadtime_ratios, pixels_below_scattering, boundary_scale_factors, n_pix
449
459
  )
460
+ # Use the universal spin table to determine the actual number of spins
461
+ nominal_spin_seconds = 15.0
462
+ spin_data = get_spin_data()
463
+ # Filter for spins only in pointing
464
+ spin_data = spin_data[
465
+ (spin_data["spin_start_met"] >= pointing_range_met[0])
466
+ & (spin_data["spin_start_met"] <= pointing_range_met[1])
467
+ ]
468
+ # Get only valid spin data
469
+ valid_mask = (spin_data["spin_phase_valid"].values == 1) & (
470
+ spin_data["spin_period_valid"].values == 1
471
+ )
472
+ n_spins_in_pointing: float = np.sum(
473
+ spin_data[valid_mask].spin_period_sec / nominal_spin_seconds
474
+ )
475
+ logger.info(
476
+ f"Calculated total spins universal spin table. Found {n_spins_in_pointing} "
477
+ f"valid spins."
478
+ )
479
+ # Adjust exposure time by the actual number of valid spins in the pointing
480
+ exposure_pointing_adjusted = n_spins_in_pointing * exposure_time
450
481
  return exposure_pointing_adjusted, nominal_deadtime_ratios
451
482
 
452
483
 
@@ -483,13 +514,17 @@ def get_efficiencies_and_geometric_function(
483
514
 
484
515
  Returns
485
516
  -------
486
- gf_summation : np.ndarray
487
- Summation of geometric factors for each pixel and energy bin.
488
- eff_summation : np.ndarray
489
- Summation of efficiencies for each pixel and energy bin.
517
+ gf_averaged : np.ndarray
518
+ Averaged geometric factors across all spin phases.
519
+ Shape = (n_energy_bins, npix).
520
+ eff_averaged : np.ndarray
521
+ Averaged efficiencies across all spin phases.
522
+ Shape = (n_energy_bins, npix).
490
523
  """
491
524
  # Load callable efficiency interpolator function
492
- eff_interpolator = get_efficiency_interpolator(ancillary_files)
525
+ eff_interpolator, theta_min_max, phi_min_max = get_efficiency_interpolator(
526
+ ancillary_files
527
+ )
493
528
  # load geometric factor lookup table
494
529
  geometric_lookup_table = load_geometric_factor_tables(
495
530
  ancillary_files, "l1b-sensor-gf-blades"
@@ -497,6 +532,24 @@ def get_efficiencies_and_geometric_function(
497
532
  # Get energy bin geometric means
498
533
  energy_bin_geometric_means = build_energy_bins()[2]
499
534
  energy_bins = len(energy_bin_geometric_means)
535
+ # clip arrays to avoid out of bounds errors
536
+ logger.info(
537
+ "Clipping Theta and Phi values to valid ranges for the efficiency "
538
+ "interpolation. \n"
539
+ f"Theta valid range: {theta_min_max}, Phi valid range: {phi_min_max}. \n "
540
+ f"Found "
541
+ f"{np.sum((theta_vals < theta_min_max[0]) | (theta_vals > theta_min_max[1]))}"
542
+ f" Theta values out of range. \n"
543
+ f"Found "
544
+ f"{np.sum((phi_vals < phi_min_max[0]) | (phi_vals > phi_min_max[1]))}"
545
+ f" Phi values out of range. \n"
546
+ f"Theta min and max values before clipping: "
547
+ f"{theta_vals.min()}, {theta_vals.max()} \n"
548
+ f"Phi min and max values before clipping:"
549
+ f" {phi_vals.min()}, {phi_vals.max()} \n"
550
+ )
551
+ theta_vals_clipped = np.clip(theta_vals, theta_min_max[0], theta_min_max[1])
552
+ phi_vals_clipped = np.clip(phi_vals, phi_min_max[0], phi_min_max[1])
500
553
  # Initialize summation arrays for geometric factors and efficiencies
501
554
  gf_summation = np.zeros((energy_bins, npix))
502
555
  eff_summation = np.zeros((energy_bins, npix))
@@ -507,6 +560,8 @@ def get_efficiencies_and_geometric_function(
507
560
  # Compute gf and eff for these theta/phi pairs
508
561
  theta_at_spin = theta_vals[:, i]
509
562
  phi_at_spin = phi_vals[:, i]
563
+ theta_at_spin_clipped = theta_vals_clipped[:, i]
564
+ phi_at_spin_clipped = phi_vals_clipped[:, i]
510
565
  gf_values = get_geometric_factor(
511
566
  phi=phi_at_spin,
512
567
  theta=theta_at_spin,
@@ -518,10 +573,12 @@ def get_efficiencies_and_geometric_function(
518
573
  if pixel_inds.size == 0:
519
574
  continue
520
575
  energy = energy_bin_geometric_means[energy_bin_idx]
576
+ # Clip energy to calibrated range
577
+ energy_clipped = np.clip(energy, 3.0, 80.0)
521
578
  eff_values = get_efficiency(
522
- np.full(phi_at_spin[pixel_inds].shape, energy),
523
- phi_at_spin[pixel_inds],
524
- theta_at_spin[pixel_inds],
579
+ np.full(phi_at_spin[pixel_inds].shape, energy_clipped),
580
+ phi_at_spin_clipped[pixel_inds],
581
+ theta_at_spin_clipped[pixel_inds],
525
582
  ancillary_files,
526
583
  interpolator=eff_interpolator,
527
584
  )
@@ -536,8 +593,10 @@ def get_efficiencies_and_geometric_function(
536
593
 
537
594
  # return averaged geometric factors and efficiencies across all spin phases
538
595
  # These are now energy dependent.
539
- gf_averaged = np.divide(gf_summation, sample_count, where=sample_count != 0)
540
- eff_averaged = np.divide(eff_summation, sample_count, where=sample_count != 0)
596
+ gf_averaged = np.zeros_like(gf_summation)
597
+ eff_averaged = np.zeros_like(eff_summation)
598
+ np.divide(gf_summation, sample_count, out=gf_averaged, where=sample_count != 0)
599
+ np.divide(eff_summation, sample_count, out=eff_averaged, where=sample_count != 0)
541
600
  return gf_averaged, eff_averaged
542
601
 
543
602
 
@@ -698,8 +757,8 @@ def get_spacecraft_background_rates(
698
757
  """
699
758
  pulses = get_pulses_per_spin(rates_dataset)
700
759
  # Pulses for the pointing.
701
- etof_min = get_image_params("eTOFMin", sensor, ancillary_files)
702
- etof_max = get_image_params("eTOFMax", sensor, ancillary_files)
760
+ etof_min = get_image_params("eTOFMin", f"ultra{sensor}", ancillary_files)
761
+ etof_max = get_image_params("eTOFMax", f"ultra{sensor}", ancillary_files)
703
762
  spin_number, _ = get_spin_and_duration(
704
763
  rates_dataset["shcoarse"], rates_dataset["spin"]
705
764
  )
@@ -364,8 +364,8 @@ def generate_ultra_healpix_skymap( # noqa: PLR0912
364
364
  for var in pointing_indep_vars:
365
365
  skymap.data_1d[var] = skymap.data_1d[var].squeeze("epoch", drop=True)
366
366
 
367
- # Background rates must be scaled by the ratio of the solid angles of the
368
- # map pixel / pointing set pixel
367
+ # Background rates must be scaled by
368
+ # the ratio of the solid angles of the map pixel / pointing set pixel
369
369
  skymap.data_1d["background_rates"] *= skymap.solid_angle / pointing_set.solid_angle
370
370
 
371
371
  # Get the energy bin widths from a PointingSet (they will all be the same)
@@ -102,6 +102,12 @@ def create_dataset( # noqa: PLR0912
102
102
  "spin_phase_step",
103
103
  ]:
104
104
  continue
105
+ elif key == "epoch_delta":
106
+ dataset[key] = xr.DataArray(
107
+ data,
108
+ dims=["epoch"],
109
+ attrs=cdf_manager.get_variable_attributes(key, check_schema=False),
110
+ )
105
111
  elif key in velocity_keys:
106
112
  dataset[key] = xr.DataArray(
107
113
  data,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: imap-processing
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: IMAP Science Operations Center Processing
5
5
  License: MIT
6
6
  Keywords: IMAP,SDC,SOC,Science Operations