1414from prefect import get_run_logger
1515from remove_starfield import ImageHolder , ImageProcessor , Starfield
1616from remove_starfield .reducers import GaussianReducer
17+ from reproject import reproject_interp
18+ from reproject .mosaicking import find_optimal_celestial_wcs
1719from scipy .ndimage import percentile_filter
1820from scipy .stats import circmean
1921from solpolpy import resolve
2527 calculate_helio_wcs_from_celestial ,
2628 celestial_north_from_wcs ,
2729)
30+ from punchbowl .exceptions import InvalidDataError
2831from punchbowl .prefect import punch_flow , punch_task
29- from punchbowl .util import average_datetime
32+ from punchbowl .util import average_datetime , interpolate_data
3033
3134warnings .filterwarnings ("ignore" )
3235
@@ -334,7 +337,8 @@ def generate_starfield_background(
334337
335338@punch_task
336339def subtract_starfield_background_task (data_object : NDCube ,
337- starfield_background_path : str | None ,
340+ before_starfield_path : str | None ,
341+ after_starfield_path : str | None ,
338342 is_polarized : bool = False ) -> NDCube :
339343 """
340344 Subtracts a background starfield from an input data frame.
@@ -346,8 +350,10 @@ def subtract_starfield_background_task(data_object: NDCube,
346350 ----------
347351 data_object : NDCube
348352 A NDCube data frame to be background subtracted
349- starfield_background_path : str
350- path to a NDCube background starfield map
353+ before_starfield_path : str
354+ path to a NDCube background starfield map centered before the observation
355+ after_starfield_path : str
356+ path to a NDCube background starfield map centered after the observation
351357 is_polarized : bool
352358 whether the data is polarized
353359
@@ -360,17 +366,69 @@ def subtract_starfield_background_task(data_object: NDCube,
360366 logger = get_run_logger ()
361367 logger .info ("subtract_starfield_background started" )
362368
363- if starfield_background_path is None :
369+ if before_starfield_path is None and after_starfield_path is None :
364370 output = data_object
365371 output .meta .history .add_now ("LEVEL3-subtract_starfield_background" ,
366372 "starfield subtraction skipped since path is empty" )
373+ elif before_starfield_path is None or after_starfield_path is None :
374+ raise InvalidDataError ("subtract_starfield_background requires two input starfield models." )
367375 else :
368- star_datacube = load_ndcube_from_fits (starfield_background_path )
369- wcs_celestial = calculate_celestial_wcs_from_helio (star_datacube .wcs )
370- wcs_celestial .wcs .cdelt [0 ] = wcs_celestial .wcs .cdelt [0 ] * - 1
376+ star_datacube_before = load_ndcube_from_fits (before_starfield_path )
377+ star_datacube_after = load_ndcube_from_fits (after_starfield_path )
378+
379+ shape_before = star_datacube_before .data .shape [- 2 :]
380+ shape_after = star_datacube_after .data .shape [- 2 :]
381+
382+ wcs_celestial_before = calculate_celestial_wcs_from_helio (star_datacube_before .wcs )
383+ wcs_celestial_before .wcs .cdelt [0 ] = wcs_celestial_before .wcs .cdelt [0 ] * - 1
384+
385+ wcs_celestial_after = calculate_celestial_wcs_from_helio (star_datacube_after .wcs )
386+ wcs_celestial_after .wcs .cdelt [0 ] = wcs_celestial_after .wcs .cdelt [0 ] * - 1
387+
388+ # TODO - Test with polarized data...
389+ union_wcs , union_shape = find_optimal_celestial_wcs (
390+ [(shape_before , wcs_celestial_before ),
391+ (shape_after , wcs_celestial_after )],
392+ auto_rotate = False , projection = "CAR" )
393+
394+ starfield_reprojected_before = reproject_interp (
395+ (np .stack ([star_datacube_before .data , star_datacube_before .uncertainty .array ], axis = 0 ),
396+ wcs_celestial_before ),
397+ union_wcs ,
398+ shape_out = union_shape ,
399+ return_footprint = False )
400+
401+ starfield_reprojected_after = reproject_interp (
402+ (np .stack ([star_datacube_after .data , star_datacube_after .uncertainty .array ], axis = 0 ),
403+ wcs_celestial_after ),
404+ union_wcs ,
405+ shape_out = union_shape ,
406+ return_footprint = False )
407+
408+ starfield_before = NDCube (data = starfield_reprojected_before [0 ],
409+ uncertainty = StdDevUncertainty (starfield_reprojected_before [1 ]),
410+ wcs = union_wcs , meta = star_datacube_before .meta )
411+ starfield_after = NDCube (data = starfield_reprojected_after [0 ],
412+ uncertainty = StdDevUncertainty (starfield_reprojected_after [1 ]),
413+ wcs = union_wcs , meta = star_datacube_after .meta )
414+
415+ starfield_data_interpolated , starfield_uncert_interpolated = interpolate_data (starfield_before ,
416+ starfield_after ,
417+ data_object .meta .datetime ,
418+ allow_extrapolation = False ,
419+ and_uncertainty = True ,
420+ infill_nans = True )
421+ # TODO - metadata...
422+ star_datacube = NDCube (data = starfield_data_interpolated ,
423+ uncertainty = StdDevUncertainty (starfield_uncert_interpolated ),
424+ wcs = union_wcs ,
425+ meta = star_datacube_before .meta )
426+ wcs_celestial = union_wcs
371427
372428 original_mask = data_object .data == 0
373429
430+ # TODO - Think about where to do the interpolation at this stage...
431+ # Is this going to require a change in the subtraction code to avoid more reprojections back and forth?
374432 if is_polarized :
375433 starfield_model_m = Starfield (np .stack ((star_datacube .data [0 ], star_datacube .uncertainty .array [0 ])),
376434 wcs_celestial [0 ])
0 commit comments