imap-processing 0.15.0__py3-none-any.whl → 0.16.1__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 (40) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +1404 -93
  3. imap_processing/cdf/config/imap_ialirt_l1_variable_attrs.yaml +113 -130
  4. imap_processing/cli.py +1 -4
  5. imap_processing/codice/codice_l1a.py +87 -62
  6. imap_processing/codice/codice_l2.py +0 -8
  7. imap_processing/codice/constants.py +16 -5
  8. imap_processing/hi/hi_l1a.py +447 -0
  9. imap_processing/hi/{l1b/hi_l1b.py → hi_l1b.py} +1 -1
  10. imap_processing/hi/{l1c/hi_l1c.py → hi_l1c.py} +21 -21
  11. imap_processing/hi/{l2/hi_l2.py → hi_l2.py} +13 -13
  12. imap_processing/hi/utils.py +10 -9
  13. imap_processing/hit/l0/constants.py +3 -1
  14. imap_processing/hit/l0/decom_hit.py +45 -11
  15. imap_processing/hit/l1a/hit_l1a.py +31 -24
  16. imap_processing/hit/l1b/hit_l1b.py +30 -11
  17. imap_processing/hit/l2/hit_l2.py +8 -11
  18. imap_processing/ialirt/constants.py +38 -0
  19. imap_processing/ialirt/l0/parse_mag.py +1 -1
  20. imap_processing/ialirt/l0/process_codice.py +91 -0
  21. imap_processing/ialirt/l0/process_hit.py +12 -21
  22. imap_processing/ialirt/l0/process_swapi.py +172 -23
  23. imap_processing/ialirt/l0/process_swe.py +3 -10
  24. imap_processing/ialirt/utils/constants.py +16 -2
  25. imap_processing/ialirt/utils/create_xarray.py +59 -11
  26. imap_processing/ultra/utils/ultra_l1_utils.py +4 -2
  27. {imap_processing-0.15.0.dist-info → imap_processing-0.16.1.dist-info}/METADATA +1 -1
  28. {imap_processing-0.15.0.dist-info → imap_processing-0.16.1.dist-info}/RECORD +31 -37
  29. imap_processing/hi/l1a/__init__.py +0 -0
  30. imap_processing/hi/l1a/hi_l1a.py +0 -98
  31. imap_processing/hi/l1a/histogram.py +0 -152
  32. imap_processing/hi/l1a/science_direct_event.py +0 -214
  33. imap_processing/hi/l1b/__init__.py +0 -0
  34. imap_processing/hi/l1c/__init__.py +0 -0
  35. imap_processing/hi/l2/__init__.py +0 -0
  36. imap_processing/ialirt/l0/process_codicehi.py +0 -156
  37. imap_processing/ialirt/l0/process_codicelo.py +0 -41
  38. {imap_processing-0.15.0.dist-info → imap_processing-0.16.1.dist-info}/LICENSE +0 -0
  39. {imap_processing-0.15.0.dist-info → imap_processing-0.16.1.dist-info}/WHEEL +0 -0
  40. {imap_processing-0.15.0.dist-info → imap_processing-0.16.1.dist-info}/entry_points.txt +0 -0
@@ -1,98 +0,0 @@
1
- """IMAP-HI L1A processing module."""
2
-
3
- import logging
4
- from pathlib import Path
5
- from typing import Union
6
-
7
- import xarray as xr
8
-
9
- from imap_processing import imap_module_directory
10
- from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
- from imap_processing.hi.l1a.histogram import create_dataset as hist_create_dataset
12
- from imap_processing.hi.l1a.science_direct_event import science_direct_event
13
- from imap_processing.hi.utils import HIAPID
14
- from imap_processing.utils import packet_file_to_datasets
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- def hi_l1a(packet_file_path: Union[str, Path]) -> list[xr.Dataset]:
20
- """
21
- Will process IMAP raw data to l1a.
22
-
23
- Parameters
24
- ----------
25
- packet_file_path : str
26
- Data packet file path.
27
-
28
- Returns
29
- -------
30
- processed_data : list[xarray.Dataset]
31
- List of processed xarray dataset.
32
- """
33
- datasets_by_apid = hi_packet_file_to_datasets(packet_file_path)
34
-
35
- # Process science to l1a.
36
- processed_data = []
37
- for apid in datasets_by_apid:
38
- try:
39
- apid_enum = HIAPID(apid)
40
- except ValueError as err:
41
- raise RuntimeError(f"Encountered unexpected APID [{apid}]") from err
42
-
43
- logger.info(f"Processing IMAP-Hi data for {apid_enum.name} packets")
44
-
45
- if apid_enum in [HIAPID.H45_SCI_CNT, HIAPID.H90_SCI_CNT]:
46
- data = hist_create_dataset(datasets_by_apid[apid])
47
- gattr_key = "imap_hi_l1a_hist_attrs"
48
- elif apid_enum in [HIAPID.H45_SCI_DE, HIAPID.H90_SCI_DE]:
49
- data = science_direct_event(datasets_by_apid[apid])
50
- gattr_key = "imap_hi_l1a_de_attrs"
51
- elif apid_enum in [HIAPID.H45_APP_NHK, HIAPID.H90_APP_NHK]:
52
- data = datasets_by_apid[apid]
53
- gattr_key = "imap_hi_l1a_hk_attrs"
54
- elif apid_enum in [HIAPID.H45_DIAG_FEE, HIAPID.H90_DIAG_FEE]:
55
- data = datasets_by_apid[apid]
56
- gattr_key = "imap_hi_l1a_diagfee_attrs"
57
-
58
- # Update dataset global attributes
59
- attr_mgr = ImapCdfAttributes()
60
- attr_mgr.add_instrument_global_attrs("hi")
61
- data.attrs.update(attr_mgr.get_global_attributes(gattr_key))
62
-
63
- # set the sensor string in Logical_source
64
- sensor_str = apid_enum.sensor
65
- data.attrs["Logical_source"] = data.attrs["Logical_source"].format(
66
- sensor=sensor_str
67
- )
68
- processed_data.append(data)
69
- return processed_data
70
-
71
-
72
- def hi_packet_file_to_datasets(
73
- packet_file_path: Union[str, Path], use_derived_value: bool = False
74
- ) -> dict[int, xr.Dataset]:
75
- """
76
- Extract hi datasets from packet file.
77
-
78
- Parameters
79
- ----------
80
- packet_file_path : str
81
- L0 packet file path.
82
- use_derived_value : bool
83
- Whether to use the derived value from the XTCE definition. Default is False.
84
-
85
- Returns
86
- -------
87
- datasets : dict[int, xarray.Dataset]
88
- Dictionary of xarray datasets keyed by APID.
89
- """
90
- packet_def_file = (
91
- imap_module_directory / "hi/packet_definitions/TLM_HI_COMBINED_SCI.xml"
92
- )
93
- datasets_by_apid = packet_file_to_datasets(
94
- packet_file=packet_file_path,
95
- xtce_packet_definition=packet_def_file,
96
- use_derived_value=use_derived_value,
97
- )
98
- return datasets_by_apid
@@ -1,152 +0,0 @@
1
- """Unpack IMAP-Hi histogram data."""
2
-
3
- import numpy as np
4
- import xarray as xr
5
- from numpy._typing import NDArray
6
-
7
- from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
8
-
9
- # define the names of the 24 counter arrays
10
- # contained in the histogram packet
11
- QUALIFIED_COUNTERS = (
12
- "ab_qualified",
13
- "c1c2_qualified",
14
- "ac1_qualified",
15
- "bc1_qualified",
16
- "abc1_qualified",
17
- "ac1c2_qualified",
18
- "bc1c2_qualified",
19
- "abc1c2_qualified",
20
- )
21
- LONG_COUNTERS = (
22
- "a_first_only",
23
- "b_first_only",
24
- "c_first_only",
25
- "ab_long",
26
- "c1c2_long",
27
- "ac1_long",
28
- "bc1_long",
29
- "abc1_long",
30
- "ac1c2_long",
31
- "bc1c2_long",
32
- "abc1c2_long",
33
- )
34
- TOTAL_COUNTERS = ("a_total", "b_total", "c_total", "fee_de_recd", "fee_de_sent")
35
-
36
-
37
- def create_dataset(input_ds: xr.Dataset) -> xr.Dataset:
38
- """
39
- Create dataset for a number of Hi Histogram packets.
40
-
41
- Parameters
42
- ----------
43
- input_ds : xarray.Dataset
44
- Dataset of packets generated using the
45
- `imap_processing.utils.packet_file_to_datasets` function.
46
-
47
- Returns
48
- -------
49
- dataset : xarray.Dataset
50
- Dataset with all metadata field data in xr.DataArray.
51
- """
52
- attr_mgr = ImapCdfAttributes()
53
- attr_mgr.add_instrument_global_attrs(instrument="hi")
54
- attr_mgr.add_instrument_variable_attrs(instrument="hi", level=None)
55
-
56
- # Rename shcoarse variable (do this first since it copies the input_ds)
57
- dataset = input_ds.rename_vars({"shcoarse": "ccsds_met"})
58
-
59
- dataset.epoch.attrs.update(
60
- attr_mgr.get_variable_attributes("epoch"),
61
- )
62
- # Add the hist_angle coordinate
63
- # Histogram data is binned in 90, 4-degree bins
64
- attrs = attr_mgr.get_variable_attributes("hi_hist_angle")
65
- dataset.coords.update(
66
- {
67
- "angle": xr.DataArray(
68
- np.arange(2, 360, 4),
69
- name="angle",
70
- dims=["angle"],
71
- attrs=attrs,
72
- )
73
- }
74
- )
75
- # Update existing variable attributes
76
- for var_name in [
77
- "version",
78
- "type",
79
- "sec_hdr_flg",
80
- "pkt_apid",
81
- "seq_flgs",
82
- "src_seq_ctr",
83
- "pkt_len",
84
- "ccsds_met",
85
- "esa_step",
86
- "num_of_spins",
87
- "cksum",
88
- ]:
89
- attrs = attr_mgr.get_variable_attributes(f"hi_hist_{var_name}")
90
- dataset.data_vars[var_name].attrs.update(attrs)
91
-
92
- new_vars = dict()
93
- # Populate 90-element histogram counters
94
- default_counter_attrs = attr_mgr.get_variable_attributes("hi_hist_counters")
95
- for counter_name in (*QUALIFIED_COUNTERS, *LONG_COUNTERS, *TOTAL_COUNTERS):
96
- # Inject counter name into generic counter attributes
97
- counter_attrs = default_counter_attrs.copy()
98
- for key, val in counter_attrs.items():
99
- if isinstance(val, str) and "{counter_name}" in val:
100
- counter_attrs[key] = val.format(counter_name=counter_name)
101
- # Instantiate the counter DataArray
102
- new_vars[counter_name] = xr.DataArray(
103
- data=unpack_hist_counter(input_ds[counter_name].data.sum()),
104
- dims=["epoch", "angle"],
105
- attrs=counter_attrs,
106
- )
107
-
108
- # Generate label variable for angle coordinate
109
- new_vars["angle_label"] = xr.DataArray(
110
- dataset.coords["angle"].values.astype(str),
111
- name="angle_label",
112
- dims=["angle"],
113
- attrs=attr_mgr.get_variable_attributes(
114
- "hi_hist_angle_label", check_schema=False
115
- ),
116
- )
117
-
118
- dataset.update(new_vars)
119
-
120
- return dataset
121
-
122
-
123
- def unpack_hist_counter(counter_bytes: bytes) -> NDArray[np.uint16]:
124
- """
125
- Unpack Hi SCI_CNT counter data for a single counter.
126
-
127
- Parameters
128
- ----------
129
- counter_bytes : bytes
130
- Sum individual bytes for all epochs of a Hi SCI_CNT counter.
131
-
132
- Returns
133
- -------
134
- output_array : numpy.ndarray[numpy.uint16]
135
- The unpacked 12-bit unsigned integers for the input bytes. The
136
- output array has a shape of (n, 90) where n is the number of SCI_CNT
137
- packets in the input dataset.
138
- """
139
- # Interpret bytes for all epochs of current counter as uint8 array
140
- counter_uint8 = np.frombuffer(counter_bytes, dtype=np.uint8)
141
- # Split into triplets of upper-byte, split-byte and lower-byte arrays
142
- upper_uint8, split_unit8, lower_uint8 = np.reshape(
143
- counter_uint8, (3, -1), order="F"
144
- ).astype(np.uint16)
145
- # Compute even indexed uint12 values from upper-byte and first 4-bits of
146
- # split-byte
147
- even_uint12 = (upper_uint8 << 4) + (split_unit8 >> 4)
148
- # Compute odd indexed uint12 values from lower 4-bits of split-byte and
149
- # lower-byte
150
- odd_uint12 = ((split_unit8 & (2**4 - 1)) << 8) + lower_uint8
151
- output_array = np.column_stack((even_uint12, odd_uint12)).reshape(-1, 90)
152
- return output_array
@@ -1,214 +0,0 @@
1
- """IMAP-Hi direct event processing."""
2
-
3
- import logging
4
- from collections import defaultdict
5
-
6
- import numpy as np
7
- import numpy._typing as npt
8
- import xarray as xr
9
-
10
- from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
- from imap_processing.spice.time import met_to_ttj2000ns
12
-
13
- # TODO: read DE_CLOCK_TICK_US from
14
- # instrument status summary later. This value
15
- # is rarely change but want to be able to change
16
- # it if needed. It stores information about how
17
- # fast the time was ticking. It is in microseconds.
18
- DE_CLOCK_TICK_US = 1999
19
- DE_CLOCK_TICK_S = DE_CLOCK_TICK_US / 1e6
20
- HALF_CLOCK_TICK_S = DE_CLOCK_TICK_S / 2
21
-
22
- MILLISECOND_TO_S = 1e-3
23
-
24
- logger = logging.getLogger(__name__)
25
-
26
-
27
- def parse_direct_events(de_data: bytes) -> dict[str, npt.ArrayLike]:
28
- """
29
- Parse event data from a binary blob.
30
-
31
- IMAP-Hi direct event data information is stored in
32
- 48-bits as follows:
33
-
34
- | Read 48-bits into 16, 2, 10, 10, 10, bits. Each of these breaks
35
- | down as:
36
- |
37
- | de_tag - 16 bits
38
- | start_bitmask_data - 2 bits (tA=1, tB=2, tC1=3)
39
- | tof_1 - 10 bit counter
40
- | tof_2 - 10 bit counter
41
- | tof_3 - 10 bit counter
42
-
43
- There are at most total of 664 of 48-bits in each data packet.
44
- This data packet is of variable length. If there is one event, then
45
- DE_TOF will contain 48-bits. If there are 664 events, then
46
- DE_TOF will contain 664 x 48-bits. If there is no event, then
47
- DE_TOF will contain 0-bits.
48
-
49
- There should be two data packets per ESA. Each packet contains meta-event
50
- data that is identical between the two packets for a common ESA.
51
- If there is no event record for certain ESA step, then both packets will
52
- contain 0-bits in DE_TOF.
53
-
54
- Parameters
55
- ----------
56
- de_data : bytes
57
- Binary blob from de_tag field of SCI_DE packet. Must be an integer
58
- multiple of 48-bits of data.
59
-
60
- Returns
61
- -------
62
- Dict[str, list]
63
- Parsed event data.
64
- """
65
- # The de_data is a binary blob with Nx6 bytes of data where N = number of
66
- # direct events encoded into the binary blob. Interpreting the data as
67
- # big-endian uint16 data and reshaping into a (3, -1) ndarray results
68
- # in an array with shape (3, N). Indexing the first axis of that array
69
- # (e.g. data_uint16[i]) gives the ith 2-bytes of data for each of the N
70
- # direct events.
71
- # Considering the 6-bytes of data for each DE as 3 2-byte words,
72
- # each word contains the following:
73
- # word_0: full 16-bits is the de_tag
74
- # word_1: 2-bits of Trigger ID, 10-bits tof_1, upper 4-bits of tof_2
75
- # word_2: lower 6-bits of tof_2, 10-bits of tof_3
76
- data_uint16 = np.reshape(
77
- np.frombuffer(de_data, dtype=">u2"), (3, -1), order="F"
78
- ).astype(np.uint16)
79
-
80
- de_dict = dict()
81
- de_dict["de_tag"] = data_uint16[0]
82
- de_dict["trigger_id"] = (data_uint16[1] >> 14).astype(np.uint8)
83
- de_dict["tof_1"] = (data_uint16[1] & int(b"00111111_11110000", 2)) >> 4
84
- de_dict["tof_2"] = ((data_uint16[1] & int(b"00000000_00001111", 2)) << 6) + (
85
- data_uint16[2] >> 10
86
- )
87
- de_dict["tof_3"] = data_uint16[2] & int(b"00000011_11111111", 2)
88
-
89
- return de_dict
90
-
91
-
92
- def create_dataset(de_data_dict: dict[str, npt.ArrayLike]) -> xr.Dataset:
93
- """
94
- Create xarray dataset.
95
-
96
- Parameters
97
- ----------
98
- de_data_dict : Dict[list]
99
- Dictionary of packet telemetry and direct event data lists.
100
-
101
- Returns
102
- -------
103
- dataset : xarray.Dataset
104
- Xarray dataset.
105
- """
106
- # Load the CDF attributes
107
- attr_mgr = ImapCdfAttributes()
108
- attr_mgr.add_instrument_global_attrs("hi")
109
- attr_mgr.add_instrument_variable_attrs(instrument="hi", level=None)
110
-
111
- # check_schema=False keeps DEPEND_0 = '' from being auto added
112
- epoch_attrs = attr_mgr.get_variable_attributes("epoch", check_schema=False)
113
- epoch_attrs["CATDESC"] = (
114
- "CCSDS creation time, number of nanoseconds since J2000 with leap "
115
- "seconds included"
116
- )
117
- epoch = xr.DataArray(
118
- met_to_ttj2000ns(de_data_dict["ccsds_met"]),
119
- name="epoch",
120
- dims=["epoch"],
121
- attrs=epoch_attrs,
122
- )
123
-
124
- event_met_attrs = attr_mgr.get_variable_attributes(
125
- "hi_de_event_met", check_schema=False
126
- )
127
- # For L1A DE, event_met is its own dimension, so we remove the DEPEND_0 attribute
128
- _ = event_met_attrs.pop("DEPEND_0")
129
-
130
- # Compute the meta-event MET in seconds
131
- meta_event_met = (
132
- np.array(de_data_dict["meta_seconds"]).astype(np.float64)
133
- + np.array(de_data_dict["meta_subseconds"]) * MILLISECOND_TO_S
134
- )
135
- # Compute the MET of each event in seconds
136
- # event MET = meta_event_met + de_clock
137
- # See Hi Algorithm Document section 2.2.5
138
- event_met_array = np.array(
139
- meta_event_met[de_data_dict["ccsds_index"]]
140
- + np.array(de_data_dict["de_tag"]) * DE_CLOCK_TICK_S,
141
- dtype=event_met_attrs.pop("dtype"),
142
- )
143
- event_met = xr.DataArray(
144
- event_met_array,
145
- name="event_met",
146
- dims=["event_met"],
147
- attrs=event_met_attrs,
148
- )
149
-
150
- dataset = xr.Dataset(
151
- coords={"epoch": epoch, "event_met": event_met},
152
- )
153
-
154
- for var_name, data in de_data_dict.items():
155
- attrs = attr_mgr.get_variable_attributes(
156
- f"hi_de_{var_name}", check_schema=False
157
- ).copy()
158
- dtype = attrs.pop("dtype")
159
- dataset[var_name] = xr.DataArray(
160
- np.array(data, dtype=np.dtype(dtype)),
161
- dims=attrs["DEPEND_0"],
162
- attrs=attrs,
163
- )
164
-
165
- return dataset
166
-
167
-
168
- def science_direct_event(packets_data: xr.Dataset) -> xr.Dataset:
169
- """
170
- Unpack IMAP-Hi direct event data.
171
-
172
- Processing step:
173
-
174
- | 1. Break binary stream data into unit of 48-bits
175
- | 2. Parse direct event data
176
- | 5. Save the data into xarray dataset.
177
-
178
- Parameters
179
- ----------
180
- packets_data : xarray.Dataset
181
- Packets extracted into a dataset.
182
-
183
- Returns
184
- -------
185
- dataset : xarray.Dataset
186
- Xarray dataset.
187
- """
188
- de_data_dict: dict[str, list] = defaultdict(list)
189
-
190
- # Add packet data to the dictionary, renaming some fields
191
- # This is done first so that these variables are first in the CDF
192
- for from_key, to_key in {
193
- "shcoarse": "ccsds_met",
194
- "src_seq_ctr": "src_seq_ctr",
195
- "pkt_len": "pkt_len",
196
- "last_spin_num": "last_spin_num",
197
- "spin_invalids": "spin_invalids",
198
- "esa_step_num": "esa_step",
199
- "meta_seconds": "meta_seconds",
200
- "meta_subseconds": "meta_subseconds",
201
- }.items():
202
- de_data_dict[to_key] = packets_data[from_key].data
203
-
204
- # For each packet, parse the DE data and add it to the Pointing
205
- # list of DE data usint `extend()`
206
- for i, data in enumerate(packets_data["de_tof"].data):
207
- parsed_de_data = parse_direct_events(data)
208
- for key, new_data in parsed_de_data.items():
209
- de_data_dict[key].extend(new_data)
210
- # Record the ccsds packet index for each DE
211
- de_data_dict["ccsds_index"].extend([i] * len(parsed_de_data["de_tag"]))
212
-
213
- # create dataset
214
- return create_dataset(de_data_dict)
File without changes
File without changes
File without changes
@@ -1,156 +0,0 @@
1
- """Functions to support I-ALiRT CoDICE Hi processing."""
2
-
3
- import logging
4
- from typing import Any
5
-
6
- import numpy as np
7
- import xarray as xr
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- def find_groups(data: xr.Dataset) -> xr.Dataset:
13
- """
14
- Find all occurrences of the sequential set of 234 values 0-233.
15
-
16
- If a value is missing, or we are starting/ending
17
- in the middle of a sequence we do not count that as a valid group.
18
-
19
- Parameters
20
- ----------
21
- data : xr.Dataset
22
- CoDICE Hi Dataset.
23
-
24
- Returns
25
- -------
26
- grouped_data : xr.Dataset
27
- Grouped data.
28
- """
29
- subcom_range = (0, 233)
30
-
31
- data = data.sortby("cod_hi_acq", ascending=True)
32
-
33
- # Use cod_hi_counter == 0 to define the beginning of the group.
34
- # Find cod_hi_acq at this index and use it as the beginning time for the group.
35
- start_sc_ticks = data["cod_hi_acq"][(data["cod_hi_counter"] == subcom_range[0])]
36
- start_sc_tick = start_sc_ticks.min()
37
- # Use cod_hi_counter == 233 to define the end of the group.
38
- last_sc_ticks = data["cod_hi_acq"][
39
- ([data["cod_hi_counter"] == subcom_range[-1]][-1])
40
- ]
41
- last_sc_tick = last_sc_ticks.max()
42
-
43
- # Filter out data before the first cod_hi_counter=0 and
44
- # after the last cod_hi_counter=233 and cod_hi_counter values != 0-233.
45
- grouped_data = data.where(
46
- (data["cod_hi_acq"] >= start_sc_tick)
47
- & (data["cod_hi_acq"] <= last_sc_tick)
48
- & (data["cod_hi_counter"] >= subcom_range[0])
49
- & (data["cod_hi_counter"] <= subcom_range[-1]),
50
- drop=True,
51
- )
52
-
53
- # Assign labels based on the cod_hi_acq times.
54
- group_labels = np.searchsorted(
55
- start_sc_ticks, grouped_data["cod_hi_acq"], side="right"
56
- )
57
- # Example:
58
- # grouped_data.coords
59
- # Coordinates:
60
- # * epoch (epoch) int64 7kB 315922822184000000 ... 315923721184000000
61
- # * group (group) int64 7kB 1 1 1 1 1 1 1 1 1 ... 15 15 15 15 15 15 15 15 15
62
- grouped_data["group"] = ("group", group_labels)
63
-
64
- return grouped_data
65
-
66
-
67
- def append_cod_hi_data(dataset: xr.Dataset) -> xr.Dataset:
68
- """
69
- Append the cod_hi_## data values and create an xarray.
70
-
71
- Parameters
72
- ----------
73
- dataset : xr.Dataset
74
- Original dataset of group.
75
-
76
- Returns
77
- -------
78
- appended_dataset : xr.Dataset
79
- Dataset with cod_hi_## stacked.
80
- """
81
- # Number of codice hi data rows
82
- num_cod_hi_rows = 5
83
- cod_hi_data = np.stack(
84
- [dataset[f"cod_hi_data_{i:02}"].values for i in range(num_cod_hi_rows)], axis=1
85
- )
86
-
87
- repeated_data = {
88
- var: np.repeat(dataset[var].values, num_cod_hi_rows)
89
- for var in dataset.data_vars
90
- if not var.startswith("cod_hi_data_")
91
- }
92
-
93
- repeated_data["cod_hi_appended"] = cod_hi_data.flatten()
94
- repeated_epoch = np.repeat(dataset["epoch"].values, num_cod_hi_rows)
95
-
96
- appended_dataset = xr.Dataset(
97
- data_vars={name: ("epoch", values) for name, values in repeated_data.items()},
98
- coords={"epoch": repeated_epoch},
99
- )
100
-
101
- return appended_dataset
102
-
103
-
104
- def process_codicehi(xarray_data: xr.Dataset) -> list[dict]:
105
- """
106
- Create final data products.
107
-
108
- Parameters
109
- ----------
110
- xarray_data : xr.Dataset
111
- Parsed data.
112
-
113
- Returns
114
- -------
115
- codicehi_data : list[dict]
116
- Dictionary of final data product.
117
-
118
- Notes
119
- -----
120
- This function is incomplete and will need to be updated to include the
121
- necessary calculations and data products.
122
- - Calculate species counts (pg 27 of Algorithm Document)
123
- - Calculate rates (assume 4 minutes per group)
124
- - Calculate L2 CoDICE pseudodensities (pg 37 of Algorithm Document)
125
- - Calculate the public data products
126
- """
127
- grouped_data = find_groups(xarray_data)
128
- unique_groups = np.unique(grouped_data["group"])
129
- codicehi_data: list[dict[str, Any]] = [{}]
130
-
131
- for group in unique_groups:
132
- # cod_hi_counter values for the group should be 0-233 with no duplicates.
133
- subcom_values = grouped_data["cod_hi_counter"][
134
- (grouped_data["group"] == group).values
135
- ]
136
-
137
- # Ensure no duplicates and all values from 0 to 233 are present
138
- if not np.array_equal(subcom_values, np.arange(234)):
139
- logger.warning(
140
- f"Group {group} does not contain all values from 0 to "
141
- f"233 without duplicates."
142
- )
143
- continue
144
-
145
- mask = grouped_data["group"] == group
146
- filtered_indices = np.where(mask)[0]
147
- group_data = grouped_data.isel(epoch=filtered_indices)
148
-
149
- append_cod_hi_data(group_data)
150
-
151
- # TODO: calculate species counts
152
- # TODO: calculate rates
153
- # TODO: calculate L2 CoDICE pseudodensities
154
- # TODO: calculate the public data products
155
-
156
- return codicehi_data
@@ -1,41 +0,0 @@
1
- """Functions to support I-ALiRT CoDICE Lo processing."""
2
-
3
- import logging
4
-
5
- import xarray as xr
6
-
7
- from imap_processing.codice.codice_l1a import create_ialirt_dataset
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- def process_codicelo(dataset: xr.Dataset) -> list[dict]:
13
- """
14
- Create final data products.
15
-
16
- Parameters
17
- ----------
18
- dataset : xr.Dataset
19
- Decommed L0 data.
20
-
21
- Returns
22
- -------
23
- codicelo_data : list[dict]
24
- Dictionary of final data product.
25
-
26
- Notes
27
- -----
28
- This function is incomplete and will need to be updated to include the
29
- necessary calculations and data products.
30
- - Calculate rates (assume 4 minutes per group)
31
- - Calculate L2 CoDICE pseudodensities (pg 37 of Algorithm Document)
32
- - Calculate the public data products
33
- """
34
- apid = dataset.pkt_apid.data[0]
35
- codicelo_data = create_ialirt_dataset(apid, dataset)
36
-
37
- # TODO: calculate rates
38
- # TODO: calculate L2 CoDICE pseudodensities
39
- # TODO: calculate the public data products
40
-
41
- return codicelo_data