1414 filter_goodtimes ,
1515 lo_l1c ,
1616 set_background_rates ,
17+ set_pointing_directions ,
1718)
1819from imap_processing .spice .time import met_to_ttj2000ns
1920
@@ -170,7 +171,7 @@ def expected_bg():
170171 dtype = np .float16 ,
171172 )
172173
173- expected_uncert = np .array (
174+ expected_err = np .array (
174175 [
175176 np .full ((3600 , 40 ), 0.0025 ),
176177 np .full ((3600 , 40 ), 0.002 ),
@@ -183,15 +184,17 @@ def expected_bg():
183184 dtype = np .float16 ,
184185 )
185186
186- expected_err = np .zeros ((7 , 3600 , 40 ), dtype = np .float16 )
187+ expected_uncert = np .zeros ((7 , 3600 , 40 ), dtype = np .float16 )
187188
188189 expected_bg = (expected_rates , expected_uncert , expected_err )
189190 return expected_bg
190191
191192
192193@patch ("imap_processing.lo.l1c.lo_l1c.set_background_rates" )
193194@patch ("imap_processing.lo.l1c.lo_l1c.filter_goodtimes" )
195+ @patch ("imap_processing.lo.l1c.lo_l1c.set_pointing_directions" )
194196def test_lo_l1c (
197+ mock_set_pointing_directions ,
195198 mock_filter_goodtimes ,
196199 mock_set_background_rates ,
197200 l1b_de_spin ,
@@ -206,6 +209,10 @@ def test_lo_l1c(
206209 use_fake_repoint_data_for_time (np .arange (511000000 , 511000000 + 86400 * 5 , 86400 ))
207210 mock_set_background_rates .return_value = (None , None , None )
208211 mock_filter_goodtimes .return_value = l1b_de_spin
212+ mock_set_pointing_directions .return_value = (
213+ xr .DataArray (np .zeros ((3600 , 40 )), dims = ("spin_angle" , "off_angle" )),
214+ xr .DataArray (np .zeros ((3600 , 40 )), dims = ("spin_angle" , "off_angle" )),
215+ )
209216 expected_logical_source = "imap_lo_l1c_pset"
210217
211218 # Act
@@ -354,3 +361,95 @@ def test_set_background_rates_species_error(anc_dependencies, attr_mgr):
354361 rates , uncert , err = set_background_rates (
355362 pointing_start_met , pointing_end_met , species , anc_dependencies , attr_mgr
356363 )
364+
365+
366+ def test_set_pointing_directions ():
367+ """Test the set_pointing_directions function."""
368+ # Mock the external dependencies
369+ mock_et = 123456789.0
370+ mock_hae_az_el = np .stack (
371+ np .meshgrid (np .arange (3600 ), np .arange (40 ), indexing = "ij" ), axis = - 1
372+ ) # spin_angle x off_angle x 2
373+ with (
374+ patch ("imap_processing.lo.l1c.lo_l1c.ttj2000ns_to_et" ) as mock_ttj2000ns_to_et ,
375+ patch (
376+ "imap_processing.lo.l1c.lo_l1c.frame_transform_az_el"
377+ ) as mock_frame_transform ,
378+ ):
379+ # Set up mocks
380+ mock_ttj2000ns_to_et .return_value = mock_et
381+ mock_frame_transform .return_value = mock_hae_az_el
382+
383+ # Test input
384+ test_epoch = 1000000000.0
385+
386+ # Call the function
387+ hae_longitude , hae_latitude = set_pointing_directions (test_epoch )
388+
389+ # Verify ttj2000ns_to_et was called correctly
390+ mock_ttj2000ns_to_et .assert_called_once_with (test_epoch )
391+
392+ # Verify frame_transform_az_el was called correctly
393+ mock_frame_transform .assert_called_once ()
394+ call_args = mock_frame_transform .call_args
395+ assert call_args [0 ][0 ] == mock_et # et parameter
396+ assert call_args [1 ]["degrees" ] is True
397+ # Verify the shape of dps_az_el
398+ dps_az_el = call_args [0 ][1 ]
399+ assert dps_az_el .shape == (3600 , 40 , 2 ) # spin_angle x off_angle x 2
400+
401+ # Verify the returned DataArrays
402+ assert isinstance (hae_longitude , xr .DataArray )
403+ assert isinstance (hae_latitude , xr .DataArray )
404+
405+ # Check dimensions
406+ assert hae_longitude .dims == ("spin_angle" , "off_angle" )
407+ assert hae_latitude .dims == ("spin_angle" , "off_angle" )
408+
409+ # Check shapes
410+ assert hae_longitude .shape == (3600 , 40 ) # off_angle x spin_angle
411+ assert hae_latitude .shape == (3600 , 40 ) # off_angle x spin_angle
412+
413+ # Check data types
414+ assert hae_longitude .dtype == np .float64
415+ assert hae_latitude .dtype == np .float64
416+
417+ # Check that longitude uses first component (index 0)
418+ # and latitude uses second (index 1)
419+ np .testing .assert_array_equal (hae_longitude .values , mock_hae_az_el [:, :, 0 ])
420+ np .testing .assert_array_equal (hae_latitude .values , mock_hae_az_el [:, :, 1 ])
421+
422+
423+ def test_set_pointing_directions_meshgrid ():
424+ """Test that the meshgrid is created correctly."""
425+ with (
426+ patch ("imap_processing.lo.l1c.lo_l1c.ttj2000ns_to_et" ) as mock_ttj2000ns_to_et ,
427+ patch (
428+ "imap_processing.lo.l1c.lo_l1c.frame_transform_az_el"
429+ ) as mock_frame_transform ,
430+ ):
431+ mock_ttj2000ns_to_et .return_value = 123456789.0
432+ mock_hae_az_el = np .stack (
433+ np .meshgrid (np .arange (3600 ), np .arange (40 ), indexing = "ij" ), axis = - 1
434+ ) # spin_angle x off_angle x 2
435+ mock_frame_transform .return_value = mock_hae_az_el
436+
437+ set_pointing_directions (1000000000.0 )
438+
439+ # Get the dps_az_el array that was passed to frame_transform_az_el
440+ call_args = mock_frame_transform .call_args
441+ dps_az_el = call_args [0 ][1 ]
442+
443+ # Verify the meshgrid was created correctly
444+ # The first component should be spin angles repeated for each off angle
445+ expected_spin_shape = (3600 , 40 )
446+ assert dps_az_el [:, :, 0 ].shape == expected_spin_shape
447+
448+ # The second component should be off angles repeated for each spin angle
449+ assert dps_az_el [:, :, 1 ].shape == expected_spin_shape
450+
451+ # Check that spin angles vary along the first dimension
452+ assert not np .allclose (dps_az_el [0 , 0 , 0 ], dps_az_el [1 , 0 , 0 ])
453+
454+ # Check that off angles vary along the second dimension
455+ assert not np .allclose (dps_az_el [0 , 0 , 1 ], dps_az_el [0 , 1 , 1 ])
0 commit comments