Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions imap_processing/cdf/config/imap_constant_attrs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ epoch:
VALIDMIN: 315576066184000000 # 2010-01-01T00:00:00 mission start (APL 0 epoch)
VAR_TYPE: support_data

epoch_delta:
CATDESC: Epoch delta
DATA_TYPE: CDF_INT8
DEPEND_0: epoch
FIELDNAM: Epoch Delta
FILLVAL: -9223372036854775808
FORMAT: I19
LABLAXIS: Epoch delta
NAME: epoch_delta
RECORD_VARYING: RV

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this come from? It's the first time I have seen it and I can't find it in SPDF's list of variable attributes. https://spdf.gsfc.nasa.gov/istp_guide/vattributes.html

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L3 puts certain aspects of the variable definition in the SAMMI YAML; this is a difference between L2 and L3 that should be addressed in the move.

SCALETYP: linear
UNITS: ns
VALIDMAX: 86000000000000

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why such a specific value rather than double integer max?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took these straight out of L3, but I'll admit I'm not completely sure why the values were chosen.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's roughly a day (86000 seconds) which strikes me as Grant throwing up his hands and saying "I don't know, a day?" Maybe 1e14 makes more sense. Anything between "about an hour" and "about a day" is probably reasonable (we all know it's going to be awfully close to 300 seconds the vast majority of the time).

VALIDMIN: 0
VAR_TYPE: support_data

# <=== Data Variables ===>
# Default Attrs for all metadata variables unless overridden
Expand Down
71 changes: 70 additions & 1 deletion imap_processing/hit/l2/hit_l2.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ def add_cdf_attributes(
)
dataset.coords[f"{dim}_label"] = label_array

if "macropixel" in logical_source and "epoch" in dataset.coords:
dataset["epoch"].attrs["DELTA_MINUS_VAR"] = "epoch_delta"
dataset["epoch"].attrs["DELTA_PLUS_VAR"] = "epoch_delta"
Comment on lines +147 to +148

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if these were defined in the imap_hit_l2_variable_attrs.yaml file so that everything is in that single place, but that would still require custom code here to get those values and set them only to the macropixel product. Adding something like this to the above for dim in dataset.dims: loop:

if dim != "epoch":
    ...
elif "macropixel" in logical_source:
    dataset["epoch"].attrs.update(attr_mgr.get_variable_attributes("epoch_macropixel", check_schema=False))

Thoughts?


return dataset


Expand Down Expand Up @@ -782,4 +786,69 @@ def process_macropixel_intensity(
{var: f"{var}_macropixel_intensity"}
)

return macropixel_intensity_dataset
return transform_to_10_minute_chunks(macropixel_intensity_dataset)


def transform_to_10_minute_chunks(macropixel_dataset: xr.Dataset) -> xr.Dataset:
"""Transform macropixel records into 10-minute integration chunks.

Parameters
----------
macropixel_dataset : xarray.Dataset
Macropixel data containing one species and energy combination per
one-minute epoch.

Returns
-------
xarray.Dataset
Macropixel data combined into one record per 10-minute integration.
"""
species_energy = [
("h", 3),
("he4", 2),
("cno", 2),
("nemgsi", 2),
("fe", 1),
]

# Use the first record in each 10-record group as the output template.
transformed_dataset = macropixel_dataset.isel(
epoch=slice(None, None, 10),
).copy(deep=True)

# Each minute in a 10-record group contains one species/energy combination,
# ordered as described by species_energy. Track that minute's packet offset.
species_i = 0
for species, num_energy_levels in species_energy:
energy_dim = f"{species}_energy_mean"
# Gather the intensity and uncertainty variables that share this
# species' energy dimension.
species_variables = [
var
for var in macropixel_dataset.data_vars
if macropixel_dataset[var].dims[:2] == ("epoch", energy_dim)
]

for energy_i in range(num_energy_levels):
for var in species_variables:
# Select this species/energy packet from every 10-record group
# and place it in the corresponding output energy plane.
data_i = macropixel_dataset[var].values[species_i::10, energy_i]
transformed_dataset[var].values[:, energy_i] = data_i
species_i += 1
Comment on lines +822 to +838

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add comments in here? It looks like it is doing some sort of diagonal gather but it is a bit hard to follow.

@leowerneck leowerneck Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out. I added comments and changed variables name to hopefully make things a bit clearer. Let me know if it's still not so.


minute_cadence_epochs = macropixel_dataset["epoch"].values
ten_minute_cadence_epochs = minute_cadence_epochs.reshape(-1, 10)
nanoseconds_per_10_min = SECONDS_PER_10_MIN * 1_000_000_000
nanoseconds_per_5_min = nanoseconds_per_10_min // 2
start_times = ten_minute_cadence_epochs[:, 0]
end_times = ten_minute_cadence_epochs[:, -1]
new_epochs = start_times + (end_times - start_times) // 2 - nanoseconds_per_10_min

transformed_dataset = transformed_dataset.assign_coords(epoch=np.array(new_epochs))
transformed_dataset["epoch_delta"] = xr.DataArray(
np.full(len(new_epochs), nanoseconds_per_5_min, dtype=np.int64),
dims=["epoch"],
)

return transformed_dataset
Loading