@@ -74,6 +74,8 @@ class CoDICEL1aPipeline:
7474 Retrieve the ESA sweep values.
7575 get_hi_energy_table_data(species)
7676 Retrieve energy table data for CoDICE-Hi products
77+ reshape_binned_data(dataset)
78+ Reshape data arrays for binned datasets.
7779 reshape_data()
7880 Reshape the data arrays based on the data product being made.
7981 set_data_product_config()
@@ -92,8 +94,7 @@ def calculate_epoch_values(self) -> NDArray[int]:
9294 Calculate and return the values to be used for `epoch`.
9395
9496 On CoDICE, the epoch values are derived from the `acq_start_seconds` and
95- `acq_start_subseconds` fields in the packet. The exception to this is
96- the I-ALiRT packets, which use "acquisition_time".
97+ `acq_start_subseconds` fields in the packet.
9798
9899 Note that the `acq_start_subseconds` field needs to be converted from
99100 microseconds to seconds.
@@ -134,7 +135,7 @@ def decompress_data(self, science_values: list[NDArray[str]] | list[str]) -> Non
134135
135136 # I-ALiRT data already has byte count cut-off applied, so treat
136137 # it slightly differently
137- if self .config ["dataset_name" ] == "imap_codice_l1a_lo-ialirt" :
138+ if "ialirt" in self .config ["dataset_name" ]:
138139 for packet_data in science_values :
139140 # Convert from bit string to byte object
140141 values = int (packet_data , 2 ).to_bytes (
@@ -506,6 +507,79 @@ def get_hi_energy_table_data(
506507
507508 return centers , deltas
508509
510+ def reshape_binned_data (self , dataset : xr .Dataset ) -> dict [str , list ]:
511+ """
512+ Reshape data arrays for binned datasets.
513+
514+ Binned datasets get reshaped based on the number of species and their
515+ corresponding number of energy bins. Additionally, the number of spins
516+ during data acquisition are collapsed/summed which also needs to be taken
517+ into account when reshaping into the correct dimensions.
518+
519+ Parameters
520+ ----------
521+ dataset : xarray.Dataset
522+ ``xarray`` dataset for the data product.
523+
524+ Returns
525+ -------
526+ data : dict[str, list]
527+ Data arrays for each species.
528+ """
529+ # This will hold all of the data per-species and support variables,
530+ # ready to be put in a CDF file
531+ data : dict [str , list ] = {}
532+ for species in self .config ["energy_table" ]:
533+ data [species ] = []
534+ data ["epoch" ] = []
535+ data ["spin_period" ] = []
536+ data ["data_quality" ] = []
537+
538+ # Get the number of spins per species
539+ num_spins = self .config ["num_spins" ]
540+
541+ # Iterate through each epoch's data and pull out the data for each
542+ # species
543+ stacked_data = np .array (self .raw_data , dtype = np .uint32 )
544+ for i , epoch in enumerate (stacked_data ):
545+ current_epoch = dataset .epoch .data [i ]
546+ position = 0
547+ for species in self .config ["energy_table" ]:
548+ # Subtracting one here since the table includes endpoints
549+ num_bins = len (self .config ["energy_table" ][species ]) - 1
550+ species_data = (
551+ epoch [position : position + num_bins * self .config ["num_spins" ]]
552+ .reshape (num_bins , num_spins )
553+ .T
554+ )
555+
556+ # Now pull out the data for each spin within the species data
557+ for spin_data in species_data :
558+ data [species ].append (spin_data )
559+
560+ # We only need one set of support variables in the CDF,
561+ # so just iterate using one species for these
562+ if species == "h" :
563+ # For each spin, we add <spin_period>*<num_spins> to the
564+ # epoch value
565+ spin_period = (
566+ dataset .spin_period .data [i ]
567+ * constants .SPIN_PERIOD_CONVERSION
568+ )
569+ epoch_value = current_epoch + np .int64 (
570+ (spin_period * num_spins ) * 1e9 # Convert from s to ns
571+ )
572+ data ["epoch" ].append (epoch_value )
573+ current_epoch = epoch_value
574+
575+ # Other support variables
576+ data ["spin_period" ].append (spin_period )
577+ data ["data_quality" ].append (dataset .suspect .data [i ])
578+
579+ position += num_bins * num_spins
580+
581+ return data
582+
509583 def reshape_data (self ) -> None :
510584 """
511585 Reshape the data arrays based on the data product being made.
@@ -625,7 +699,9 @@ def group_ialirt_data(packets: xr.Dataset, data_field_range: range) -> list[byte
625699 return grouped_data
626700
627701
628- def create_binned_dataset (apid : int , dataset : xr .Dataset ) -> xr .Dataset :
702+ def create_binned_dataset (
703+ apid : int , dataset : xr .Dataset , science_values : list [str ]
704+ ) -> xr .Dataset :
629705 """
630706 Create dataset for data that is binned by energy.
631707
@@ -640,6 +716,8 @@ def create_binned_dataset(apid: int, dataset: xr.Dataset) -> xr.Dataset:
640716 The APID of the packet.
641717 dataset : xarray.Dataset
642718 The packets to process.
719+ science_values : list[str]
720+ The values of the "data" field of the dataset.
643721
644722 Returns
645723 -------
@@ -649,9 +727,6 @@ def create_binned_dataset(apid: int, dataset: xr.Dataset) -> xr.Dataset:
649727 # TODO: hi-sectored data product should be processed similar to hi-omni,
650728 # so I should be able to use this method.
651729
652- # Extract the data
653- science_values = [packet .data for packet in dataset .data ]
654-
655730 # Get the four "main" parameters for processing
656731 table_id , plan_id , plan_step , view_id = get_params (dataset )
657732
@@ -661,61 +736,7 @@ def create_binned_dataset(apid: int, dataset: xr.Dataset) -> xr.Dataset:
661736 pipeline .set_data_product_config (apid , dataset )
662737 pipeline .decompress_data (science_values )
663738
664- # hi-omni data gets reshaped a bit differently than other products,
665- # so we need to stray away from the nominal pipeline
666- stacked_data = np .stack (
667- [np .array (item , dtype = np .uint32 ) for item in pipeline .raw_data ]
668- )
669-
670- # This will hold all of the data per-species and support variables,
671- # ready to be put in a CDF file
672- data : dict [str , list ] = {}
673- for species in pipeline .config ["energy_table" ]:
674- data [species ] = []
675- data ["epoch" ] = []
676- data ["spin_period" ] = []
677- data ["data_quality" ] = []
678-
679- # Get the number of spins per species
680- num_spins = pipeline .config ["num_spins" ]
681-
682- # Iterate through each epoch's data and pull out the data for each
683- # species
684- for i , epoch in enumerate (stacked_data ):
685- current_epoch = dataset .epoch .data [i ]
686- position = 0
687- for species in pipeline .config ["energy_table" ]:
688- num_bins = (
689- len (pipeline .config ["energy_table" ][species ]) - 1
690- ) # Subtracting one here since the table includes endpoints
691- species_data = (
692- epoch [position : position + num_bins * pipeline .config ["num_spins" ]]
693- .reshape (num_bins , num_spins )
694- .T
695- )
696-
697- # Now pull out the data for each spin within the species data
698- for spin_data in species_data :
699- data [species ].append (spin_data )
700-
701- # We only need one set of support variables in the CDF,
702- # so just iterate using one species for these
703- if species == "h" :
704- # For each spin, we add <spin_period>*<num_spins> to the epoch value
705- spin_period = (
706- dataset .spin_period .data [i ] * constants .SPIN_PERIOD_CONVERSION
707- )
708- epoch_value = current_epoch + np .int64 (
709- (spin_period * num_spins ) * 1e9 # Convert from s to ns
710- )
711- data ["epoch" ].append (epoch_value )
712- current_epoch = epoch_value
713-
714- # Other support variables
715- data ["spin_period" ].append (spin_period )
716- data ["data_quality" ].append (dataset .suspect .data [i ])
717-
718- position += num_bins * num_spins
739+ data = pipeline .reshape_binned_data (dataset )
719740
720741 # Create the main dataset to hold all the variables
721742 coord = xr .DataArray (
@@ -957,42 +978,64 @@ def create_ialirt_dataset(apid: int, packets: xr.Dataset) -> xr.Dataset:
957978 # Group together packets of I-ALiRT data to form complete data sets
958979 grouped_data = group_ialirt_data (packets , data_field_range )
959980
981+ # Process each group to get the science data and corresponding metadata
960982 science_values , metadata_values = process_ialirt_data_streams (grouped_data )
961983
962- # Run the pipeline to create a dataset for the product
963- pipeline = CoDICEL1aPipeline (
964- metadata_values ["TABLE_ID" ][0 ],
965- metadata_values ["PLAN_ID" ][0 ],
966- metadata_values ["PLAN_STEP" ][0 ],
967- metadata_values ["VIEW_ID" ][0 ],
968- )
969- pipeline .set_data_product_config (apid , packets )
970- pipeline .decompress_data (science_values )
971- pipeline .reshape_data ()
972-
973- # The calculate_epoch_values method needs acq_start_seconds and
974- # acq_start_subseconds attributes on the dataset
975- pipeline .dataset ["acq_start_seconds" ] = ("_" , metadata_values ["ACQ_START_SECONDS" ])
976- pipeline .dataset ["acq_start_subseconds" ] = (
977- "_" ,
978- metadata_values ["ACQ_START_SUBSECONDS" ],
979- )
984+ # How data are processed is different for lo-iarlirt and hi-ialirt
985+ if apid == CODICEAPID .COD_HI_IAL :
986+ # Set some necessary values and process as a binned dataset similar to
987+ # a hi-omni data product
988+ metadata_for_processing = [
989+ "table_id" ,
990+ "plan_id" ,
991+ "plan_step" ,
992+ "view_id" ,
993+ "spin_period" ,
994+ "suspect" ,
995+ ]
996+ for var in metadata_for_processing :
997+ packets [var ] = metadata_values [var .upper ()]
998+ dataset = create_binned_dataset (apid , packets , science_values )
999+
1000+ elif apid == CODICEAPID .COD_LO_IAL :
1001+ # Create a nominal instance of the pipeline and process similar to a
1002+ # lo-sw-species data product
1003+ pipeline = CoDICEL1aPipeline (
1004+ metadata_values ["TABLE_ID" ][0 ],
1005+ metadata_values ["PLAN_ID" ][0 ],
1006+ metadata_values ["PLAN_STEP" ][0 ],
1007+ metadata_values ["VIEW_ID" ][0 ],
1008+ )
1009+ pipeline .set_data_product_config (apid , packets )
1010+ pipeline .decompress_data (science_values )
1011+ pipeline .reshape_data ()
1012+
1013+ # The calculate_epoch_values method needs acq_start_seconds and
1014+ # acq_start_subseconds attributes on the dataset
1015+ pipeline .dataset ["acq_start_seconds" ] = (
1016+ "_" ,
1017+ metadata_values ["ACQ_START_SECONDS" ],
1018+ )
1019+ pipeline .dataset ["acq_start_subseconds" ] = (
1020+ "_" ,
1021+ metadata_values ["ACQ_START_SUBSECONDS" ],
1022+ )
9801023
981- pipeline .define_coordinates ()
1024+ pipeline .define_coordinates ()
9821025
983- # The dataset also needs the metadata that will be carried through
984- # to the final data product
985- for field in [
986- "spin_period" ,
987- "suspect" ,
988- "st_bias_gain_mode" ,
989- "sw_bias_gain_mode" ,
990- "rgfo_half_spin" ,
991- "nso_half_spin" ,
992- ]:
993- pipeline .dataset [field ] = ("_" , metadata_values [field .upper ()])
1026+ # The dataset also needs the metadata that will be carried through
1027+ # to the final data product
1028+ for field in [
1029+ "spin_period" ,
1030+ "suspect" ,
1031+ "st_bias_gain_mode" ,
1032+ "sw_bias_gain_mode" ,
1033+ "rgfo_half_spin" ,
1034+ "nso_half_spin" ,
1035+ ]:
1036+ pipeline .dataset [field ] = ("_" , metadata_values [field .upper ()])
9941037
995- dataset = pipeline .define_data_variables ()
1038+ dataset = pipeline .define_data_variables ()
9961039
9971040 return dataset
9981041
@@ -1379,13 +1422,14 @@ def process_codice_l1a(file_path: Path) -> list[xr.Dataset]:
13791422 logger .info (f"\n Final data product:\n { processed_dataset } \n " )
13801423
13811424 # I-ALiRT data
1382- elif apid in [CODICEAPID .COD_LO_IAL ]:
1425+ elif apid in [CODICEAPID .COD_LO_IAL , CODICEAPID . COD_HI_IAL ]:
13831426 processed_dataset = create_ialirt_dataset (apid , dataset )
13841427 logger .info (f"\n Final data product:\n { processed_dataset } \n " )
13851428
13861429 # hi-omni data
13871430 elif apid == CODICEAPID .COD_HI_OMNI_SPECIES_COUNTS :
1388- processed_dataset = create_binned_dataset (apid , dataset )
1431+ science_values = [packet .data for packet in dataset .data ]
1432+ processed_dataset = create_binned_dataset (apid , dataset , science_values )
13891433 logger .info (f"\n Final data product:\n { processed_dataset } \n " )
13901434
13911435 # Everything else
@@ -1406,11 +1450,6 @@ def process_codice_l1a(file_path: Path) -> list[xr.Dataset]:
14061450
14071451 logger .info (f"\n Final data product:\n { processed_dataset } \n " )
14081452
1409- # TODO: Still need to implement hi-ialirt
1410- elif apid == CODICEAPID .COD_HI_IAL :
1411- logger .info ("\t Still need to properly implement" )
1412- processed_dataset = None
1413-
14141453 # For APIDs that don't require processing
14151454 else :
14161455 logger .info (f"\t { apid } does not require processing" )
0 commit comments