|
14 | 14 | PSET_SHAPE, |
15 | 15 | FilterType, |
16 | 16 | calculate_exposure_times, |
| 17 | + compute_pointing_directions, |
17 | 18 | create_pset_counts, |
18 | 19 | filter_goodtimes, |
19 | 20 | lo_l1c, |
20 | 21 | set_background_rates, |
21 | 22 | set_pointing_directions, |
22 | 23 | ) |
| 24 | +from imap_processing.spice.geometry import SpiceFrame |
23 | 25 | from imap_processing.spice.time import met_to_ttj2000ns |
24 | 26 |
|
25 | 27 |
|
@@ -729,3 +731,80 @@ def test_set_pointing_directions_pivot_angle(attr_mgr, pivot_angle): |
729 | 731 | # dps_az_el[:, :, 1] should have the adjusted off angles repeated across spin |
730 | 732 | actual_off_angles = dps_az_el[0, :, 1] # Take first spin angle |
731 | 733 | np.testing.assert_allclose(actual_off_angles, expected_off_angles, rtol=1e-10) |
| 734 | + |
| 735 | + |
| 736 | +def test_compute_pointing_directions_defaults(): |
| 737 | + """Default grid/frame reproduce the PSET (3600 x 40) IMAP_DPS->IMAP_HAE case.""" |
| 738 | + mock_et = 123456789.0 |
| 739 | + mock_az_el = np.stack( |
| 740 | + np.meshgrid(np.arange(3600), np.arange(40), indexing="ij"), axis=-1 |
| 741 | + ) |
| 742 | + with ( |
| 743 | + patch("imap_processing.lo.l1c.lo_l1c.ttj2000ns_to_et") as mock_ttj2000ns_to_et, |
| 744 | + patch( |
| 745 | + "imap_processing.lo.l1c.lo_l1c.frame_transform_az_el" |
| 746 | + ) as mock_frame_transform, |
| 747 | + ): |
| 748 | + mock_ttj2000ns_to_et.return_value = mock_et |
| 749 | + mock_frame_transform.return_value = mock_az_el |
| 750 | + |
| 751 | + result = compute_pointing_directions(1000000000.0, 90) |
| 752 | + |
| 753 | + # Returns the raw (n_spin, n_off, 2) array, not a DataArray. |
| 754 | + assert result.shape == (3600, 40, 2) |
| 755 | + call_args = mock_frame_transform.call_args |
| 756 | + assert call_args[0][1].shape == (3600, 40, 2) # dps_az_el grid |
| 757 | + assert call_args[0][2] == SpiceFrame.IMAP_DPS # from_frame |
| 758 | + assert call_args[0][3] == SpiceFrame.IMAP_HAE # default to_frame |
| 759 | + |
| 760 | + |
| 761 | +def test_compute_pointing_directions_custom_grid_and_frame(): |
| 762 | + """Custom spin/off angles and destination frame are honored.""" |
| 763 | + spin_angles = np.arange(3.0, 360.0, 6.0) # 60 bins |
| 764 | + off_angles = np.array([0.0]) # single pivot-cone off-angle |
| 765 | + pivot_angle = 75.0 |
| 766 | + with ( |
| 767 | + patch("imap_processing.lo.l1c.lo_l1c.ttj2000ns_to_et") as mock_ttj2000ns_to_et, |
| 768 | + patch( |
| 769 | + "imap_processing.lo.l1c.lo_l1c.frame_transform_az_el" |
| 770 | + ) as mock_frame_transform, |
| 771 | + ): |
| 772 | + mock_ttj2000ns_to_et.return_value = 123456789.0 |
| 773 | + mock_frame_transform.side_effect = lambda et, az_el, *a, **k: az_el |
| 774 | + |
| 775 | + result = compute_pointing_directions( |
| 776 | + 1000000000.0, |
| 777 | + pivot_angle, |
| 778 | + spin_angles=spin_angles, |
| 779 | + off_angles=off_angles, |
| 780 | + to_frame=SpiceFrame.ECLIPJ2000, |
| 781 | + ) |
| 782 | + |
| 783 | + assert result.shape == (60, 1, 2) |
| 784 | + # Spin component matches the requested spin angles. |
| 785 | + np.testing.assert_allclose(result[:, 0, 0], spin_angles) |
| 786 | + # Off component is the single off-angle offset by (90 - pivot_angle). |
| 787 | + np.testing.assert_allclose(result[:, 0, 1], 90 - pivot_angle) |
| 788 | + # Destination frame is forwarded. |
| 789 | + assert mock_frame_transform.call_args[0][3] == SpiceFrame.ECLIPJ2000 |
| 790 | + |
| 791 | + |
| 792 | +def test_set_pointing_directions_delegates(attr_mgr): |
| 793 | + """set_pointing_directions wraps compute_pointing_directions output unchanged.""" |
| 794 | + mock_az_el = np.stack( |
| 795 | + np.meshgrid(np.arange(3600), np.arange(40), indexing="ij"), axis=-1 |
| 796 | + ).astype(float) |
| 797 | + with patch( |
| 798 | + "imap_processing.lo.l1c.lo_l1c.compute_pointing_directions" |
| 799 | + ) as mock_compute: |
| 800 | + mock_compute.return_value = mock_az_el |
| 801 | + |
| 802 | + hae_longitude, hae_latitude = set_pointing_directions( |
| 803 | + 1000000000.0, attr_mgr, 90 |
| 804 | + ) |
| 805 | + |
| 806 | + mock_compute.assert_called_once_with(1000000000.0, 90) |
| 807 | + assert hae_longitude.dims == ("epoch", "spin_angle", "off_angle") |
| 808 | + assert hae_longitude.shape == (1, 3600, 40) |
| 809 | + np.testing.assert_array_equal(hae_longitude.values[0], mock_az_el[:, :, 0]) |
| 810 | + np.testing.assert_array_equal(hae_latitude.values[0], mock_az_el[:, :, 1]) |
0 commit comments