imap-processing 0.17.0__py3-none-any.whl → 0.18.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (89) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/ccsds/excel_to_xtce.py +12 -0
  3. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -6
  4. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +11 -0
  5. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +11 -0
  6. imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +24 -0
  7. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +163 -100
  8. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +4 -4
  9. imap_processing/cdf/config/imap_ialirt_l1_variable_attrs.yaml +97 -54
  10. imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +119 -36
  11. imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +16 -90
  12. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +30 -0
  13. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -1
  14. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +60 -0
  15. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +91 -11
  16. imap_processing/cli.py +28 -5
  17. imap_processing/codice/codice_l1a.py +36 -48
  18. imap_processing/codice/codice_l1b.py +1 -1
  19. imap_processing/codice/codice_l2.py +0 -9
  20. imap_processing/codice/constants.py +481 -498
  21. imap_processing/hit/l0/decom_hit.py +2 -2
  22. imap_processing/hit/l1a/hit_l1a.py +64 -24
  23. imap_processing/hit/l1b/constants.py +5 -0
  24. imap_processing/hit/l1b/hit_l1b.py +18 -16
  25. imap_processing/hit/l2/constants.py +1 -1
  26. imap_processing/hit/l2/hit_l2.py +4 -5
  27. imap_processing/ialirt/constants.py +21 -0
  28. imap_processing/ialirt/generate_coverage.py +188 -0
  29. imap_processing/ialirt/l0/parse_mag.py +62 -5
  30. imap_processing/ialirt/l0/process_swapi.py +1 -1
  31. imap_processing/ialirt/l0/process_swe.py +23 -7
  32. imap_processing/ialirt/utils/constants.py +22 -16
  33. imap_processing/ialirt/utils/create_xarray.py +42 -19
  34. imap_processing/idex/idex_constants.py +1 -5
  35. imap_processing/idex/idex_l2b.py +246 -67
  36. imap_processing/idex/idex_l2c.py +30 -196
  37. imap_processing/lo/l0/lo_apid.py +1 -0
  38. imap_processing/lo/l1a/lo_l1a.py +44 -0
  39. imap_processing/lo/packet_definitions/lo_xtce.xml +5359 -106
  40. imap_processing/mag/constants.py +1 -0
  41. imap_processing/mag/l1d/__init__.py +0 -0
  42. imap_processing/mag/l1d/mag_l1d.py +133 -0
  43. imap_processing/mag/l1d/mag_l1d_data.py +588 -0
  44. imap_processing/mag/l2/__init__.py +0 -0
  45. imap_processing/mag/l2/mag_l2.py +25 -20
  46. imap_processing/mag/l2/mag_l2_data.py +191 -130
  47. imap_processing/quality_flags.py +20 -2
  48. imap_processing/spice/geometry.py +25 -3
  49. imap_processing/spice/pointing_frame.py +1 -1
  50. imap_processing/spice/spin.py +4 -0
  51. imap_processing/spice/time.py +51 -0
  52. imap_processing/swapi/l2/swapi_l2.py +52 -8
  53. imap_processing/swapi/swapi_utils.py +1 -1
  54. imap_processing/swe/l1b/swe_l1b.py +2 -4
  55. imap_processing/ultra/constants.py +49 -1
  56. imap_processing/ultra/l0/decom_tools.py +15 -8
  57. imap_processing/ultra/l0/decom_ultra.py +35 -11
  58. imap_processing/ultra/l0/ultra_utils.py +97 -5
  59. imap_processing/ultra/l1a/ultra_l1a.py +25 -4
  60. imap_processing/ultra/l1b/cullingmask.py +3 -3
  61. imap_processing/ultra/l1b/de.py +53 -15
  62. imap_processing/ultra/l1b/extendedspin.py +26 -2
  63. imap_processing/ultra/l1b/lookup_utils.py +171 -50
  64. imap_processing/ultra/l1b/quality_flag_filters.py +14 -0
  65. imap_processing/ultra/l1b/ultra_l1b_culling.py +198 -5
  66. imap_processing/ultra/l1b/ultra_l1b_extended.py +304 -66
  67. imap_processing/ultra/l1c/helio_pset.py +54 -7
  68. imap_processing/ultra/l1c/spacecraft_pset.py +9 -1
  69. imap_processing/ultra/l1c/ultra_l1c.py +2 -0
  70. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +106 -109
  71. imap_processing/ultra/utils/ultra_l1_utils.py +13 -1
  72. {imap_processing-0.17.0.dist-info → imap_processing-0.18.0.dist-info}/METADATA +2 -2
  73. {imap_processing-0.17.0.dist-info → imap_processing-0.18.0.dist-info}/RECORD +76 -83
  74. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +0 -526
  75. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +0 -526
  76. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +0 -526
  77. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +0 -524
  78. imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +0 -32769
  79. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
  80. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
  81. imap_processing/ultra/lookup_tables/dps_grid45_compressed.cdf +0 -0
  82. imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +0 -4097
  83. imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +0 -2050
  84. imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +0 -4097
  85. imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +0 -2050
  86. imap_processing/ultra/lookup_tables/yadjust.csv +0 -257
  87. {imap_processing-0.17.0.dist-info → imap_processing-0.18.0.dist-info}/LICENSE +0 -0
  88. {imap_processing-0.17.0.dist-info → imap_processing-0.18.0.dist-info}/WHEEL +0 -0
  89. {imap_processing-0.17.0.dist-info → imap_processing-0.18.0.dist-info}/entry_points.txt +0 -0
@@ -97,4 +97,18 @@ imap_mag_l2_burst-dsrf:
97
97
  Data_type: L2_burst-dsrf>Level 2 burst rate data in DSRF
98
98
  Logical_source: imap_mag_l2_burst-dsrf
99
99
  Logical_source_description: IMAP Mission Burst Rate Instrument Level-2 Data in
100
- Despun Spacecraft Reference Frame.
100
+ Despun Spacecraft Reference Frame.
101
+
102
+ imap_mag_l2_norm-srf:
103
+ <<: *default
104
+ Data_type: L2_norm-srf>Level 2 normal rate data in SRF
105
+ Logical_source: imap_mag_l2_norm-srf
106
+ Logical_source_description: IMAP Mission Normal Rate Instrument Level-2 Data in
107
+ Spacecraft Reference Frame.
108
+
109
+ imap_mag_l2_burst-srf:
110
+ <<: *default
111
+ Data_type: L2_burst-srf>Level 2 burst rate data in SRF
112
+ Logical_source: imap_mag_l2_burst-srf
113
+ Logical_source_description: IMAP Mission Burst Rate Instrument Level-2 Data in
114
+ Spacecraft Reference Frame.
@@ -32,6 +32,66 @@ imap_ultra_l1a_90sensor-histogram-ena-phxtof-hi-ang:
32
32
  Logical_source: imap_ultra_l1a_90sensor-histogram-ena-phxtof-hi-ang
33
33
  Logical_source_description: IMAP-Ultra Instrument Level-1A PHxTOF Hi Angular Data.
34
34
 
35
+ imap_ultra_l1a_45sensor-histogram-ena-phxtof-hi-nrg:
36
+ <<: *instrument_base
37
+ Data_type: L1A_Histogram>Level-1A TOF
38
+ Logical_source: imap_ultra_l1a_45sensor-histogram-ena-phxtof-hi-nrg
39
+ Logical_source_description: IMAP-Ultra Instrument Level-1A PHxTOF Hi Energy Data.
40
+
41
+ imap_ultra_l1a_90sensor-histogram-ena-phxtof-hi-nrg:
42
+ <<: *instrument_base
43
+ Data_type: L1A_Histogram>Level-1A TOF
44
+ Logical_source: imap_ultra_l1a_90sensor-histogram-ena-phxtof-hi-nrg
45
+ Logical_source_description: IMAP-Ultra Instrument Level-1A PHxTOF Hi Energy Data.
46
+
47
+ imap_ultra_l1a_45sensor-histogram-ena-phxtof-hi-time:
48
+ <<: *instrument_base
49
+ Data_type: L1A_Histogram>Level-1A TOF
50
+ Logical_source: imap_ultra_l1a_45sensor-histogram-ena-phxtof-hi-time
51
+ Logical_source_description: IMAP-Ultra Instrument Level-1A PHxTOF Hi Time Data.
52
+
53
+ imap_ultra_l1a_90sensor-histogram-ena-phxtof-hi-time:
54
+ <<: *instrument_base
55
+ Data_type: L1A_Histogram>Level-1A TOF
56
+ Logical_source: imap_ultra_l1a_90sensor-histogram-ena-phxtof-hi-time
57
+ Logical_source_description: IMAP-Ultra Instrument Level-1A PHxTOF Hi Time Data.
58
+
59
+ imap_ultra_l1a_45sensor-histogram-ena-extof-hi-ang:
60
+ <<: *instrument_base
61
+ Data_type: L1A_Histogram>Level-1A TOF
62
+ Logical_source: imap_ultra_l1a_45sensor-histogram-ena-extof-hi-ang
63
+ Logical_source_description: IMAP-Ultra Instrument Level-1A ExTOF Hi Angular Data.
64
+
65
+ imap_ultra_l1a_90sensor-histogram-ena-extof-hi-ang:
66
+ <<: *instrument_base
67
+ Data_type: L1A_Histogram>Level-1A TOF
68
+ Logical_source: imap_ultra_l1a_90sensor-histogram-ena-extof-hi-ang
69
+ Logical_source_description: IMAP-Ultra Instrument Level-1A ExTOF Hi Angular Data.
70
+
71
+ imap_ultra_l1a_45sensor-histogram-ena-extof-hi-time:
72
+ <<: *instrument_base
73
+ Data_type: L1A_Histogram>Level-1A ExTOF
74
+ Logical_source: imap_ultra_l1a_45sensor-histogram-ena-extof-hi-time
75
+ Logical_source_description: IMAP-Ultra Instrument Level-1A ExTOF Hi Time Data.
76
+
77
+ imap_ultra_l1a_90sensor-histogram-ena-extof-hi-time:
78
+ <<: *instrument_base
79
+ Data_type: L1A_Histogram>Level-1A ExTOF
80
+ Logical_source: imap_ultra_l1a_90sensor-histogram-ena-extof-hi-time
81
+ Logical_source_description: IMAP-Ultra Instrument Level-1A ExTOF Hi Time Data.
82
+
83
+ imap_ultra_l1a_45sensor-histogram-ena-extof-hi-nrg:
84
+ <<: *instrument_base
85
+ Data_type: L1A_Histogram>Level-1A ExTOF
86
+ Logical_source: imap_ultra_l1a_45sensor-histogram-ena-extof-hi-nrg
87
+ Logical_source_description: IMAP-Ultra Instrument Level-1A ExTOF Hi Energy Data.
88
+
89
+ imap_ultra_l1a_90sensor-histogram-ena-extof-hi-nrg:
90
+ <<: *instrument_base
91
+ Data_type: L1A_Histogram>Level-1A ExTOF
92
+ Logical_source: imap_ultra_l1a_90sensor-histogram-ena-extof-hi-nrg
93
+ Logical_source_description: IMAP-Ultra Instrument Level-1A ExTOF Hi Energy Data.
94
+
35
95
  imap_ultra_l1a_45sensor-rates:
36
96
  <<: *instrument_base
37
97
  Data_type: L1A_Rates>Level-1A Rates
@@ -256,6 +256,20 @@ theta:
256
256
  LABLAXIS: theta
257
257
  UNITS: degrees
258
258
 
259
+ geometric_factor_blades:
260
+ <<: *default_float32
261
+ CATDESC: Ultra sensitive area within the field of view.
262
+ FIELDNAM: geometric_function_blades
263
+ LABLAXIS: geometric function blades
264
+ UNITS: " "
265
+
266
+ geometric_factor_noblades:
267
+ <<: *default_float32
268
+ CATDESC: Ultra sensitive area within the field of regard.
269
+ FIELDNAM: geometric_function_noblades
270
+ LABLAXIS: geometric function noblades
271
+ UNITS: " "
272
+
259
273
  phi_fwhm:
260
274
  <<: *default_float32
261
275
  CATDESC: FWHM of the phi distribution.
@@ -334,7 +348,8 @@ spin_start_time:
334
348
  LABLAXIS: spin start time
335
349
  # TODO: come back to format
336
350
  UNITS: s
337
- DEPEND_0: spin_number
351
+ DEPEND_0: epoch
352
+ DEPEND_1: spin_number
338
353
 
339
354
  spin_period:
340
355
  <<: *default
@@ -342,7 +357,8 @@ spin_period:
342
357
  FIELDNAM: spin_period
343
358
  LABLAXIS: spin_period
344
359
  UNITS: s
345
- DEPEND_0: spin_number
360
+ DEPEND_0: epoch
361
+ DEPEND_1: spin_number
346
362
 
347
363
  spin_rate:
348
364
  <<: *default
@@ -350,7 +366,8 @@ spin_rate:
350
366
  FIELDNAM: spin_rate
351
367
  LABLAXIS: spin_rate
352
368
  UNITS: rpm
353
- DEPEND_0: spin_number
369
+ DEPEND_0: epoch
370
+ DEPEND_1: spin_number
354
371
 
355
372
  rate_start_pulses:
356
373
  <<: *default
@@ -397,9 +414,46 @@ ena_rates:
397
414
  <<: *default_float32
398
415
  CATDESC: Rates calculated from de packet.
399
416
  FIELDNAM: ena_rates
400
- LABLAXIS: ena_rates
401
- DEPEND_0: spin_number
402
- DEPEND_1: energy_bin_geometric_mean
417
+ LABLAXIS: ena rates
418
+ DEPEND_0: epoch
419
+ DEPEND_1: spin_number
420
+ DEPEND_2: energy_bin_geometric_mean
421
+ UNITS: " "
422
+
423
+ start_pulses_per_spin:
424
+ <<: *default_float32
425
+ CATDESC: Total start pulses per spin.
426
+ FIELDNAM: start_pulses_per_spin
427
+ LABLAXIS: start pulses per spin
428
+ DEPEND_0: epoch
429
+ DEPEND_1: spin_number
430
+ UNITS: " "
431
+
432
+ stop_pulses_per_spin:
433
+ <<: *default_float32
434
+ CATDESC: Total start pulses per spin.
435
+ FIELDNAM: stop_pulses_per_spin
436
+ LABLAXIS: stop pulses per spin
437
+ DEPEND_0: epoch
438
+ DEPEND_1: spin_number
439
+ UNITS: " "
440
+
441
+ coin_pulses_per_spin:
442
+ <<: *default_float32
443
+ CATDESC: Total coincidence pulses per spin.
444
+ FIELDNAM: coin_pulses_per_spin
445
+ LABLAXIS: coin_pulses_per_spin
446
+ DEPEND_0: epoch
447
+ DEPEND_1: spin_number
448
+ UNITS: " "
449
+
450
+ rejected_events_per_spin:
451
+ <<: *default_uint16
452
+ CATDESC: Rejected events per spin.
453
+ FIELDNAM: rejected_events_per_spin
454
+ LABLAXIS: rejected events per spin
455
+ DEPEND_0: epoch
456
+ DEPEND_1: spin_number
403
457
  UNITS: " "
404
458
 
405
459
  ena_rates_threshold:
@@ -407,8 +461,9 @@ ena_rates_threshold:
407
461
  CATDESC: Rates threshold used for flagging data.
408
462
  FIELDNAM: ena_rates_threshold
409
463
  LABLAXIS: ena_rates_threshold
410
- DEPEND_0: spin_number
411
- DEPEND_1: energy_bin_geometric_mean
464
+ DEPEND_0: epoch
465
+ DEPEND_1: spin_number
466
+ DEPEND_2: energy_bin_geometric_mean
412
467
  UNITS: " "
413
468
 
414
469
  quality_ena_rates:
@@ -416,8 +471,9 @@ quality_ena_rates:
416
471
  CATDESC: Spin filter derived from Ultra ena rates. Bitwise flagging used to filter the spin.
417
472
  FIELDNAM: quality_ena_rates
418
473
  LABLAXIS: quality_ena_rates
419
- DEPEND_0: spin_number
420
- DEPEND_1: energy_bin_geometric_mean
474
+ DEPEND_0: epoch
475
+ DEPEND_1: spin_number
476
+ DEPEND_2: energy_bin_geometric_mean
421
477
  UNITS: " "
422
478
 
423
479
  quality_attitude:
@@ -427,7 +483,9 @@ quality_attitude:
427
483
  LABLAXIS: quality attitude
428
484
  # TODO: come back to format
429
485
  UNITS: " "
430
- DEPEND_0: spin_number
486
+ DEPEND_0: epoch
487
+ DEPEND_1: spin_number
488
+ DEPEND_2: energy_bin_geometric_mean
431
489
 
432
490
  quality_instruments:
433
491
  <<: *default_uint16
@@ -436,3 +494,25 @@ quality_instruments:
436
494
  LABLAXIS: quality instruments
437
495
  # TODO: come back to format
438
496
  UNITS: " "
497
+ DEPEND_0: epoch
498
+ DEPEND_1: spin_number
499
+ DEPEND_2: energy_bin_geometric_mean
500
+
501
+ quality_hk:
502
+ <<: *default_uint16
503
+ CATDESC: Spin filter derived from housekeeping data. Bitwise flagging used to filter the spin.
504
+ FIELDNAM: quality_hk
505
+ LABLAXIS: quality hk
506
+ # TODO: come back to format
507
+ UNITS: " "
508
+ DEPEND_0: epoch
509
+ DEPEND_1: spin_number
510
+ DEPEND_2: energy_bin_geometric_mean
511
+
512
+ quality_fov:
513
+ <<: *default_uint16
514
+ CATDESC: Quality flag for direct event for events outside of the FOV.
515
+ FIELDNAM: quality_fov
516
+ LABLAXIS: quality fov
517
+ # TODO: come back to format
518
+ UNITS: " "
imap_processing/cli.py CHANGED
@@ -68,6 +68,7 @@ from imap_processing.mag.constants import DataMode
68
68
  from imap_processing.mag.l1a.mag_l1a import mag_l1a
69
69
  from imap_processing.mag.l1b.mag_l1b import mag_l1b
70
70
  from imap_processing.mag.l1c.mag_l1c import mag_l1c
71
+ from imap_processing.mag.l1d.mag_l1d import mag_l1d
71
72
  from imap_processing.mag.l2.mag_l2 import mag_l2
72
73
  from imap_processing.spacecraft import quaternions
73
74
  from imap_processing.spice import pointing_frame, repoint, spin
@@ -516,7 +517,7 @@ class ProcessInstrument(ABC):
516
517
  self,
517
518
  processed_data: list[xr.Dataset | Path],
518
519
  dependencies: ProcessingInputCollection,
519
- ) -> None:
520
+ ) -> list[Path]:
520
521
  """
521
522
  Complete post-processing.
522
523
 
@@ -544,10 +545,17 @@ class ProcessInstrument(ABC):
544
545
  method.
545
546
  dependencies : ProcessingInputCollection
546
547
  Object containing dependencies to process.
548
+
549
+ Returns
550
+ -------
551
+ list[Path]
552
+ List of paths to CDF files produced.
547
553
  """
554
+ products: list[Path] = []
555
+
548
556
  if len(processed_data) == 0:
549
557
  logger.info("No products to write to CDF file.")
550
- return
558
+ return products
551
559
 
552
560
  logger.info("Writing products to local storage")
553
561
 
@@ -567,7 +575,6 @@ class ProcessInstrument(ABC):
567
575
  # start_date.
568
576
  # If it is start_date, skip repointing in the output filename.
569
577
 
570
- products = []
571
578
  for ds in processed_data:
572
579
  if isinstance(ds, xr.Dataset):
573
580
  ds.attrs["Data_version"] = self.version[1:] # Strip 'v' from version
@@ -581,6 +588,7 @@ class ProcessInstrument(ABC):
581
588
  products.append(ds)
582
589
 
583
590
  self.upload_products(products)
591
+ return products
584
592
 
585
593
  @final
586
594
  def cleanup(self) -> None:
@@ -916,8 +924,8 @@ class Idex(ProcessInstrument):
916
924
  f"{dependency_list}. Expected only one dependency."
917
925
  )
918
926
  sci_files = dependencies.get_file_paths(source="idex", descriptor="sci-1mo")
919
- dependency = load_cdf(sci_files[0])
920
- datasets = idex_l2c(dependency)
927
+ dependencies = [load_cdf(f) for f in sci_files]
928
+ datasets = [idex_l2c(dependencies)]
921
929
  return datasets
922
930
 
923
931
 
@@ -1073,6 +1081,21 @@ class Mag(ProcessInstrument):
1073
1081
  f"Invalid dependencies found for MAG L1C:"
1074
1082
  f"{dependencies}. Expected one or two dependencies."
1075
1083
  )
1084
+ if self.data_level == "l1d":
1085
+ science_files = dependencies.get_file_paths(source="mag", data_type="l1c")
1086
+ science_files.extend(
1087
+ dependencies.get_file_paths(source="mag", data_type="l1b")
1088
+ )
1089
+ input_data = [load_cdf(dep) for dep in science_files]
1090
+ calibration = dependencies.get_processing_inputs(
1091
+ descriptor="l1d-calibration"
1092
+ )
1093
+ combined_calibration = MagAncillaryCombiner(calibration[0], day_buffer)
1094
+ datasets = mag_l1d(
1095
+ input_data,
1096
+ combined_calibration.combined_dataset,
1097
+ current_day,
1098
+ )
1076
1099
 
1077
1100
  if self.data_level == "l2":
1078
1101
  science_files = dependencies.get_file_paths(source="mag", data_type="l1b")
@@ -143,8 +143,8 @@ class CoDICEL1aPipeline:
143
143
  self.coords = {}
144
144
 
145
145
  coord_names = [
146
- *self.config["output_dims"].keys(),
147
- *[key + "_label" for key in self.config["output_dims"].keys()],
146
+ *self.config["dims"].keys(),
147
+ *[key + "_label" for key in self.config["dims"].keys()],
148
148
  ]
149
149
 
150
150
  # Define epoch coordinates
@@ -174,7 +174,7 @@ class CoDICEL1aPipeline:
174
174
  "spin_sector_index",
175
175
  "ssd_index",
176
176
  ]:
177
- values = np.arange(self.config["output_dims"][name])
177
+ values = np.arange(self.config["dims"][name])
178
178
  dims = [name]
179
179
  elif name == "spin_sector_pairs_label":
180
180
  values = np.array(
@@ -188,15 +188,22 @@ class CoDICEL1aPipeline:
188
188
  ]
189
189
  )
190
190
  dims = [name]
191
+ elif name == "inst_az_label":
192
+ if self.config["dataset_name"] == "imap_codice_l1a_lo-nsw-angular":
193
+ values = [str(x) for x in range(4, 23)]
194
+ elif self.config["dataset_name"] == "imap_codice_l1a_lo-sw-angular":
195
+ values = ["1", "2", "3", "23", "24"]
196
+ else:
197
+ values = np.arange(self.config["dims"]["inst_az"]).astype(str)
198
+ dims = ["inst_az"]
191
199
  elif name in [
192
200
  "spin_sector_label",
193
201
  "esa_step_label",
194
- "inst_az_label",
195
202
  "spin_sector_index_label",
196
203
  "ssd_index_label",
197
204
  ]:
198
205
  key = name.removesuffix("_label")
199
- values = np.arange(self.config["output_dims"][key]).astype(str)
206
+ values = np.arange(self.config["dims"][key]).astype(str)
200
207
  dims = [key]
201
208
 
202
209
  coord = xr.DataArray(
@@ -230,16 +237,16 @@ class CoDICEL1aPipeline:
230
237
  # Stack the data so that it is easier to reshape and iterate over
231
238
  all_data = np.stack(self.data)
232
239
 
233
- # The dimension of all_data is something like (epoch, num_counters,
234
- # num_energy_steps, num_positions, num_spin_sectors) (or may be slightly
240
+ # The dimension of all_data is something like (epoch, num_energy_steps,
241
+ # num_positions, num_spin_sectors, num_counters) (or may be slightly
235
242
  # different depending on the data product). In any case, iterate over
236
243
  # the num_counters dimension to isolate the data for each counter so
237
244
  # each counter's data can be placed in a separate CDF data variable.
238
245
  for counter, variable_name in zip(
239
- range(all_data.shape[1]), self.config["variable_names"]
246
+ range(all_data.shape[-1]), self.config["variable_names"]
240
247
  ):
241
248
  # Extract the counter data
242
- counter_data = all_data[:, counter, ...]
249
+ counter_data = all_data[..., counter]
243
250
 
244
251
  # Get the CDF attributes
245
252
  descriptor = self.config["dataset_name"].split("imap_codice_l1a_")[-1]
@@ -249,7 +256,7 @@ class CoDICEL1aPipeline:
249
256
  # For most products, the final CDF dimensions always has "epoch" as
250
257
  # the first dimension followed by the dimensions for the specific
251
258
  # data product
252
- dims = ["epoch", *list(self.config["output_dims"].keys())]
259
+ dims = ["epoch", *list(self.config["dims"].keys())]
253
260
 
254
261
  # However, CoDICE-Hi products use specific energy bins for the
255
262
  # energy dimension
@@ -398,6 +405,12 @@ class CoDICEL1aPipeline:
398
405
  dims = ["epoch"]
399
406
  attrs = self.cdf_attrs.get_variable_attributes("spin_period")
400
407
 
408
+ # The k-factor is a constant that maps voltages to energies
409
+ elif variable_name == "k_factor":
410
+ variable_data = np.array([constants.K_FACTOR], dtype=np.float32)
411
+ dims = [""]
412
+ attrs = self.cdf_attrs.get_variable_attributes("k_factor")
413
+
401
414
  # Add variable to the dataset
402
415
  dataset[variable_name] = xr.DataArray(
403
416
  variable_data,
@@ -589,52 +602,27 @@ class CoDICEL1aPipeline:
589
602
 
590
603
  These data need to be divided up by species or priorities (or
591
604
  what I am calling "counters" as a general term), and re-arranged into
592
- 4D arrays representing dimensions such as time, spin sectors, positions,
593
- and energies (depending on the data product).
605
+ multidimensional arrays representing dimensions such as time,
606
+ spin sectors, positions, and energies (depending on the data product).
594
607
 
595
608
  However, the existence and order of these dimensions can vary depending
596
- on the specific data product, so we define this in the "input_dims"
597
- and "output_dims" values configuration dictionary; the "input_dims"
598
- defines how the dimensions are written into the packet data, while
599
- "output_dims" defines how the dimensions should be written to the final
600
- CDF product.
609
+ on the specific data product, so we define this in the "dims" key of the
610
+ configuration dictionary.
601
611
  """
602
612
  # This will contain the reshaped data for all counters
603
613
  self.data = []
604
614
 
605
- # First reshape the data based on how it is written to the data array of
606
- # the packet data. The number of counters is the first dimension / axis,
607
- # with the exception of lo-counters-aggregated which is treated slightly
608
- # differently
609
- if self.config["dataset_name"] != "imap_codice_l1a_lo-counters-aggregated":
610
- reshape_dims = (
611
- self.config["num_counters"],
612
- *self.config["input_dims"].values(),
613
- )
614
- else:
615
- reshape_dims = (
616
- *self.config["input_dims"].values(),
617
- self.config["num_counters"],
618
- )
619
-
620
- # Then, transpose the data based on how the dimensions should be written
621
- # to the CDF file. Since this is specific to each data product, we need
622
- # to determine this dynamically based on the "output_dims" config.
623
- # Again, lo-counters-aggregated is treated slightly differently
624
- input_keys = ["num_counters", *self.config["input_dims"].keys()]
625
- output_keys = ["num_counters", *self.config["output_dims"].keys()]
626
- if self.config["dataset_name"] != "imap_codice_l1a_lo-counters-aggregated":
627
- transpose_axes = [input_keys.index(dim) for dim in output_keys]
628
- else:
629
- transpose_axes = [1, 2, 0] # [esa_step, spin_sector_pairs, num_counters]
630
-
615
+ # Reshape the data based on how it is written to the data array of
616
+ # the packet data. The number of counters is the last dimension / axis.
617
+ reshape_dims = (
618
+ *self.config["dims"].values(),
619
+ self.config["num_counters"],
620
+ )
631
621
  for packet_data in self.raw_data:
632
622
  reshaped_packet_data = np.array(packet_data, dtype=np.uint32).reshape(
633
623
  reshape_dims
634
624
  )
635
- reshaped_cdf_data = np.transpose(reshaped_packet_data, axes=transpose_axes)
636
-
637
- self.data.append(reshaped_cdf_data)
625
+ self.data.append(reshaped_packet_data)
638
626
 
639
627
  # No longer need to keep the raw data around
640
628
  del self.raw_data
@@ -950,9 +938,9 @@ def create_direct_event_dataset(apid: int, packets: xr.Dataset) -> xr.Dataset:
950
938
 
951
939
  # Create the dataset to hold the data variables
952
940
  if apid == CODICEAPID.COD_LO_PHA:
953
- attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_lo-pha")
941
+ attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_lo-direct-events")
954
942
  elif apid == CODICEAPID.COD_HI_PHA:
955
- attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_hi-pha")
943
+ attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_hi-direct-events")
956
944
  dataset = xr.Dataset(
957
945
  coords={
958
946
  "epoch": epoch,
@@ -116,7 +116,7 @@ def process_codice_l1b(file_path: Path) -> xr.Dataset:
116
116
  descriptor = dataset_name.removeprefix("imap_codice_l1b_")
117
117
 
118
118
  # Direct event data products do not have a level L1B
119
- if descriptor in ["lo-pha", "hi-pha"]:
119
+ if descriptor in ["lo-direct-events", "hi-direct-events"]:
120
120
  logger.warning("Encountered direct event data product. Skipping L1b processing")
121
121
  return None
122
122
 
@@ -45,17 +45,8 @@ def process_codice_l2(file_path: Path) -> xr.Dataset:
45
45
  # TODO: Could clean this up by using imap-data-access methods?
46
46
  dataset_name = l1_dataset.attrs["Logical_source"]
47
47
  data_level = dataset_name.removeprefix("imap_codice_").split("_")[0]
48
- descriptor = dataset_name.removeprefix(f"imap_codice_{data_level}_")
49
48
  dataset_name = dataset_name.replace(data_level, "l2")
50
49
 
51
- # TODO: Temporary work-around to replace "PHA" naming convention with
52
- # "direct events" This will eventually be changed at the L1 level and
53
- # thus this will eventually be removed.
54
- if descriptor == "lo-pha":
55
- dataset_name = dataset_name.replace("lo-pha", "lo-direct-events")
56
- elif descriptor == "hi-pha":
57
- dataset_name = dataset_name.replace("hi-pha", "hi-direct-events")
58
-
59
50
  # Use the L1 data product as a starting point for L2
60
51
  l2_dataset = l1_dataset.copy()
61
52