Skip to content

Conversation

@subagonsouth
Copy link
Contributor

@subagonsouth subagonsouth commented Feb 10, 2026

Change Summary

Overview

Sorry for how big this got...
This PR updates Hi L2 processing to properly handle full-spin heliocentric frame maps by generating ram and anti-ram maps separately, applying Compton-Getting corrections to each independently, and then combining them.

Updated Files

  • imap_processing/ena_maps/ena_maps.py
  • imap_processing/tests/ena_maps/test_ena_maps.py
  • imap_processing/ena_maps/utils/corrections.py
    • Added keyword input bool to keep systematic error from getting updated if not desired. Hi does not want systematic uncertainty to go through the flux correction.
  • imap_processing/tests/ena_maps/test_corrections.py
  • imap_processing/hi/hi_l2.py
    • create_sky_map_from_psets() now returns dict[str, RectangularSkyMap] instead of a single map
      • For helio-frame (hf) full-spin maps: returns {"ram": ..., "anti": ...}
      • For all other maps: returns {spin_phase: ...} (single entry)
    • Added new combine_maps() function to merge ram and anti-ram maps after CG correction
    • Added cleanup_intermediate_variables() to remove temporary calculation variables (bg_rate, energy_sc, ena_signal_rates, ena_signal_rate_stat_unc) from final output
  • imap_processing/tests/hi/test_hi_l2.py

Closes: #2561

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates IMAP-Hi L2 processing to correctly generate full-spin heliocentric-frame (HF) sky maps by building separate ram and anti-ram maps, applying Compton-Getting (CG) corrections independently, and then combining them.

Changes:

  • Refactors Hi L2 map generation so HF full-spin maps are produced as separate {"ram": ..., "anti": ...} maps and combined after CG correction.
  • Adds update_sys_err flag to interpolate_map_flux_to_helio_frame so Hi can avoid updating systematic uncertainty during flux interpolation.
  • Updates naming from bg_rates/bg_rates_unc to bg_rate/bg_rate_sys_err and expands unit/integration test coverage for the new pipeline pieces.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
imap_processing/hi/hi_l2.py Refactors Hi L2 pipeline into multi-map creation + per-map processing + combine step; adds cleanup helpers and map combination logic.
imap_processing/ena_maps/utils/corrections.py Adds update_sys_err parameter to optionally skip updating systematic error during heliocentric-frame interpolation.
imap_processing/ena_maps/ena_maps.py Updates HiPointingSet variable rename mapping (bg_rate, bg_rate_sys_err) and reduces az/el update logging verbosity.
imap_processing/tests/hi/test_hi_l2.py Updates integration/unit tests for new APIs and adds extensive tests for PSET processing, rate/intensity pipeline, cleanup, and combining maps.
imap_processing/tests/ena_maps/test_corrections.py Adds a test ensuring systematic uncertainty is unchanged when update_sys_err=False.
imap_processing/tests/ena_maps/test_ena_maps.py Updates expected HiPointingSet renamed variable names.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 208 to 212
for spin_phase, map in output_maps.items():
# Project (bin) the PSET variables into the map pixels
directional_mask = get_pset_directional_mask(pset_processed, spin_phase)
map.project_pset_values_to_map(
hi_pset, list(vars_to_bin), pset_valid_mask=directional_mask
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

Minor: using map as a loop variable shadows the built-in map() function (also used in the isinstance(map, ...) comprehension earlier). Renaming it (e.g., sky_map) would reduce confusion during debugging.

Copilot uses AI. Check for mistakes.
@subagonsouth subagonsouth force-pushed the 2561-hi-l2---update-how-full-spin-helio-frame-maps-are-produced branch from 5505752 to 85e321d Compare February 10, 2026 17:16
Comment on lines +223 to +224
for var in vars_to_exposure_time_average:
map.data_1d[var] /= map.data_1d["exposure_factor"]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you do this with xarray's list indexing syntax instead?

Suggested change
for var in vars_to_exposure_time_average:
map.data_1d[var] /= map.data_1d["exposure_factor"]
map.data_1d[vars_to_exposure_time_average] /= map.data_1d["exposure_factor"]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, cool... I didn't know you could do that. I'll test it out.

Comment on lines +158 to +159
# If we are making a full-spin, helio-frame map, we need to make one ram
# and one anti-ram map that get combined at the final L2 step.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This reminds me of Lo needing to make an extra "Oxygen" map for sputtering calculations and needing to carry it through to some extent as well. I'm wondering if this dictionary-like mapping should be carried over to the Lo calculations as well to keep things consistent or if there is another way of organizing this multi-map projections work across all instruments.

Just noting this as a comment, nothing to do here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, good point. I was toying with the idea of generating a dataset that had yet another dimension added for "spin_phase" which could later be combined. I think that some of these things would come easier if we did a refactor of the mapping code to leverage the xarray custom accessor functions.

Comment on lines +586 to +587
ram_ds = sky_maps["ram"].data_1d
anti_ds = sky_maps["anti"].data_1d
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if this would be useful to have more general, but I think a lot of the math below could be generalized to something where you are working with a list of datasets input (not just ram/anti, but maybe combining multiple 7-day maps or something like that in the future...)

datasets = [ds.data_1d for ds in sky_maps.values()]

weights = [xr.where(ds["ena_intensity_stat_uncert"] > 0, 1 / ds["ena_intensity_stat_uncert"] ** 2, 0) for ds in datasets]
...

Again, not needed here and I'm just writing it down for a quick note. It should be another ticket if this would even be useful.

…te sys_err vars or not.

Set update_sys_err to false for Hi L2
…ning into full-spin helio-frame map

Return dictionary of SkyMaps from create_sky_map_from_psets
Loop over SkyMaps for when calculating rates and intensities
Add function for combining data in multiple SkyMaps
Add function for cleaning up intermediate variables
Add test coverage for NotImplementedError
Simplify two tests by using existing fixture
@subagonsouth subagonsouth force-pushed the 2561-hi-l2---update-how-full-spin-helio-frame-maps-are-produced branch from 2841a54 to b6f1076 Compare February 10, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Hi L2 - Update how full spin helio frame maps are produced

2 participants