4343
4444
4545def ultra_l1a ( # noqa: PLR0912
46- packet_file : str , apid_input : int | None = None
46+ packet_file : str , apid_input : int | None = None , create_derived_l1b : bool = False
4747) -> list [xr .Dataset ]:
4848 """
4949 Will process ULTRA L0 data into L1A CDF files at output_filepath.
@@ -54,6 +54,8 @@ def ultra_l1a( # noqa: PLR0912
5454 Path to the CCSDS data packet file.
5555 apid_input : Optional[int]
5656 Optional apid.
57+ create_derived_l1b : bool
58+ Whether to create the l1b datasets with derived values.
5759
5860 Returns
5961 -------
@@ -64,7 +66,17 @@ def ultra_l1a( # noqa: PLR0912
6466 f"{ imap_module_directory } /ultra/packet_definitions/ULTRA_SCI_COMBINED.xml"
6567 )
6668
69+ # Keep a list to track the two versions, l1a and l1b with the derived values.
70+ decommutated_packet_datasets = []
6771 datasets_by_apid = packet_file_to_datasets (packet_file , xtce )
72+ decommutated_packet_datasets .append (datasets_by_apid )
73+ if create_derived_l1b :
74+ # For the housekeeping products, we can create the l1b at the same time
75+ # as the l1a since there is no additional processing needed.
76+ datasets_by_apid = packet_file_to_datasets (
77+ packet_file , xtce , use_derived_value = True
78+ )
79+ decommutated_packet_datasets .append (datasets_by_apid )
6880
6981 output_datasets = []
7082
@@ -109,77 +121,114 @@ def ultra_l1a( # noqa: PLR0912
109121 attr_mgr .add_instrument_global_attrs ("ultra" )
110122 attr_mgr .add_instrument_variable_attrs ("ultra" , "l1a" )
111123
112- for apid in apids :
113- if apid in ULTRA_AUX .apid :
114- decom_ultra_dataset = datasets_by_apid [apid ]
115- gattr_key = ULTRA_AUX .logical_source [ULTRA_AUX .apid .index (apid )]
116- elif apid in all_l1a_image_apids :
117- packet_props = all_l1a_image_apids [apid ]
118- decom_ultra_dataset = process_ultra_tof (
119- datasets_by_apid [apid ], packet_props
120- )
121- gattr_key = packet_props .logical_source [packet_props .apid .index (apid )]
122- elif apid in ULTRA_RATES .apid :
123- decom_ultra_dataset = process_ultra_rates (datasets_by_apid [apid ])
124- decom_ultra_dataset = decom_ultra_dataset .drop_vars ("fastdata_00" )
125- gattr_key = ULTRA_RATES .logical_source [ULTRA_RATES .apid .index (apid )]
126- elif apid in ULTRA_ENERGY_RATES .apid :
127- decom_ultra_dataset = process_ultra_energy_rates (datasets_by_apid [apid ])
128- decom_ultra_dataset = decom_ultra_dataset .drop_vars ("ratedata" )
129- gattr_key = ULTRA_ENERGY_RATES .logical_source [
130- ULTRA_ENERGY_RATES .apid .index (apid )
131- ]
132- elif apid in all_event_apids :
133- decom_ultra_dataset = process_ultra_events (datasets_by_apid [apid ], apid )
134- gattr_key = all_event_apids [apid ]
124+ for i , datasets_by_apid in enumerate (decommutated_packet_datasets ):
125+ for apid in apids :
126+ if apid in ULTRA_AUX .apid :
127+ decom_ultra_dataset = datasets_by_apid [apid ]
128+ gattr_key = ULTRA_AUX .logical_source [ULTRA_AUX .apid .index (apid )]
129+ elif apid in all_l1a_image_apids :
130+ packet_props = all_l1a_image_apids [apid ]
131+ decom_ultra_dataset = process_ultra_tof (
132+ datasets_by_apid [apid ], packet_props
133+ )
134+ gattr_key = packet_props .logical_source [packet_props .apid .index (apid )]
135+ elif apid in ULTRA_RATES .apid :
136+ decom_ultra_dataset = process_ultra_rates (datasets_by_apid [apid ])
137+ decom_ultra_dataset = decom_ultra_dataset .drop_vars ("fastdata_00" )
138+ gattr_key = ULTRA_RATES .logical_source [ULTRA_RATES .apid .index (apid )]
139+ elif apid in ULTRA_ENERGY_RATES .apid :
140+ decom_ultra_dataset = process_ultra_energy_rates (datasets_by_apid [apid ])
141+ decom_ultra_dataset = decom_ultra_dataset .drop_vars ("ratedata" )
142+ gattr_key = ULTRA_ENERGY_RATES .logical_source [
143+ ULTRA_ENERGY_RATES .apid .index (apid )
144+ ]
145+ elif apid in all_event_apids :
146+ # We don't want to process the event l1b datasets since those l1b
147+ # products need more information
148+ if i == 1 :
149+ continue
150+ decom_ultra_dataset = process_ultra_events (datasets_by_apid [apid ], apid )
151+ gattr_key = all_event_apids [apid ]
152+ # Add coordinate attributes
153+ attrs = attr_mgr .get_variable_attributes ("event_id" )
154+ decom_ultra_dataset .coords ["event_id" ].attrs .update (attrs )
155+ elif apid in ULTRA_ENERGY_SPECTRA .apid :
156+ decom_ultra_dataset = process_ultra_energy_spectra (
157+ datasets_by_apid [apid ]
158+ )
159+ decom_ultra_dataset = decom_ultra_dataset .drop_vars ("compdata" )
160+ gattr_key = ULTRA_ENERGY_SPECTRA .logical_source [
161+ ULTRA_ENERGY_SPECTRA .apid .index (apid )
162+ ]
163+ elif apid in ULTRA_MACROS_CHECKSUM .apid :
164+ decom_ultra_dataset = process_ultra_macros_checksum (
165+ datasets_by_apid [apid ]
166+ )
167+ gattr_key = ULTRA_MACROS_CHECKSUM .logical_source [
168+ ULTRA_MACROS_CHECKSUM .apid .index (apid )
169+ ]
170+ elif apid in ULTRA_HK .apid :
171+ decom_ultra_dataset = datasets_by_apid [apid ]
172+ gattr_key = ULTRA_HK .logical_source [ULTRA_HK .apid .index (apid )]
173+ elif apid in ULTRA_CMD_TEXT .apid :
174+ decom_ultra_dataset = datasets_by_apid [apid ]
175+ decoded_strings = [
176+ s .decode ("ascii" ).rstrip ("\x00 " )
177+ for s in decom_ultra_dataset ["text" ].values
178+ ]
179+ decom_ultra_dataset = decom_ultra_dataset .drop_vars ("text" )
180+ decom_ultra_dataset ["text" ] = xr .DataArray (
181+ decoded_strings ,
182+ dims = ["epoch" ],
183+ coords = {"epoch" : decom_ultra_dataset ["epoch" ]},
184+ )
185+ gattr_key = ULTRA_CMD_TEXT .logical_source [
186+ ULTRA_CMD_TEXT .apid .index (apid )
187+ ]
188+ elif apid in ULTRA_CMD_ECHO .apid :
189+ decom_ultra_dataset = process_ultra_cmd_echo (datasets_by_apid [apid ])
190+ gattr_key = ULTRA_CMD_ECHO .logical_source [
191+ ULTRA_CMD_ECHO .apid .index (apid )
192+ ]
193+ else :
194+ logger .error (f"APID { apid } not recognized." )
195+ continue
196+
197+ decom_ultra_dataset .attrs .update (attr_mgr .get_global_attributes (gattr_key ))
198+
199+ if i == 1 :
200+ # Derived values dataset at l1b
201+ # We already have the l1a attributes, just update the l1a -> l1b
202+ # in the metadata.
203+ decom_ultra_dataset .attrs ["Data_type" ] = decom_ultra_dataset .attrs [
204+ "Data_type"
205+ ].replace ("1A" , "1B" )
206+ decom_ultra_dataset .attrs ["Logical_source" ] = decom_ultra_dataset .attrs [
207+ "Logical_source"
208+ ].replace ("l1a" , "l1b" )
209+ decom_ultra_dataset .attrs ["Logical_source_description" ] = (
210+ decom_ultra_dataset .attrs ["Logical_source_description" ].replace (
211+ "1A" , "1B"
212+ )
213+ )
214+
215+ # Add data variable attributes
216+ for key in decom_ultra_dataset .data_vars :
217+ attrs = attr_mgr .get_variable_attributes (key .lower ())
218+ decom_ultra_dataset .data_vars [key ].attrs .update (attrs )
219+ if i == 1 :
220+ # For l1b datasets, the FILLVAL and VALIDMIN/MAX may be
221+ # different datatypes, so we can't use them directly from l1a.
222+ # just remove them for now since we don't really have a need for
223+ # for them currently.
224+ for attr_key in ["FILLVAL" , "VALIDMIN" , "VALIDMAX" ]:
225+ if attr_key in decom_ultra_dataset .data_vars [key ].attrs :
226+ decom_ultra_dataset .data_vars [key ].attrs .pop (attr_key )
227+
135228 # Add coordinate attributes
136- attrs = attr_mgr .get_variable_attributes ("event_id" )
137- decom_ultra_dataset .coords ["event_id" ].attrs .update (attrs )
138- elif apid in ULTRA_ENERGY_SPECTRA .apid :
139- decom_ultra_dataset = process_ultra_energy_spectra (datasets_by_apid [apid ])
140- decom_ultra_dataset = decom_ultra_dataset .drop_vars ("compdata" )
141- gattr_key = ULTRA_ENERGY_SPECTRA .logical_source [
142- ULTRA_ENERGY_SPECTRA .apid .index (apid )
143- ]
144- elif apid in ULTRA_MACROS_CHECKSUM .apid :
145- decom_ultra_dataset = process_ultra_macros_checksum (datasets_by_apid [apid ])
146- gattr_key = ULTRA_MACROS_CHECKSUM .logical_source [
147- ULTRA_MACROS_CHECKSUM .apid .index (apid )
148- ]
149- elif apid in ULTRA_HK .apid :
150- decom_ultra_dataset = datasets_by_apid [apid ]
151- gattr_key = ULTRA_HK .logical_source [ULTRA_HK .apid .index (apid )]
152- elif apid in ULTRA_CMD_TEXT .apid :
153- decom_ultra_dataset = datasets_by_apid [apid ]
154- decoded_strings = [
155- s .decode ("ascii" ).rstrip ("\x00 " )
156- for s in decom_ultra_dataset ["text" ].values
157- ]
158- decom_ultra_dataset = decom_ultra_dataset .drop_vars ("text" )
159- decom_ultra_dataset ["text" ] = xr .DataArray (
160- decoded_strings ,
161- dims = ["epoch" ],
162- coords = {"epoch" : decom_ultra_dataset ["epoch" ]},
163- )
164- gattr_key = ULTRA_CMD_TEXT .logical_source [ULTRA_CMD_TEXT .apid .index (apid )]
165- elif apid in ULTRA_CMD_ECHO .apid :
166- decom_ultra_dataset = process_ultra_cmd_echo (datasets_by_apid [apid ])
167- gattr_key = ULTRA_CMD_ECHO .logical_source [ULTRA_CMD_ECHO .apid .index (apid )]
168- else :
169- logger .error (f"APID { apid } not recognized." )
170- continue
171-
172- decom_ultra_dataset .attrs .update (attr_mgr .get_global_attributes (gattr_key ))
173-
174- # Add data variable attributes
175- for key in decom_ultra_dataset .data_vars :
176- attrs = attr_mgr .get_variable_attributes (key .lower ())
177- decom_ultra_dataset .data_vars [key ].attrs .update (attrs )
178-
179- # Add coordinate attributes
180- attrs = attr_mgr .get_variable_attributes ("epoch" , check_schema = False )
181- decom_ultra_dataset .coords ["epoch" ].attrs .update (attrs )
182-
183- output_datasets .append (decom_ultra_dataset )
229+ attrs = attr_mgr .get_variable_attributes ("epoch" , check_schema = False )
230+ decom_ultra_dataset .coords ["epoch" ].attrs .update (attrs )
231+
232+ output_datasets .append (decom_ultra_dataset )
184233
185234 return output_datasets
0 commit comments