@@ -95,17 +95,41 @@ def shared_tests(
9595 library_model .shelve (input_model , modify = False )
9696
9797 assert len (cat .meta ["aperture_radii" ]["circle_pix" ]) > 0
98+
99+ # Check for original (non-PSF-matched) columns
98100 assert sum (
99101 1 for name in cat .colnames if match (r"^aper\d+_f158_flux$" , name )
100102 ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
101103 assert sum (
102104 1 for name in cat .colnames if match (r"^aper\d+_f184_flux$" , name )
103105 ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
106+
107+ # Check for PSF-matched columns
108+ # Target filter (F184) should NOT have PSF-matched columns
109+ assert sum (
110+ 1 for name in cat .colnames if match (r"^aper\d+_f158m_flux$" , name )
111+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
112+ assert sum (1 for name in cat .colnames if match (r"^aper\d+_f184m_flux$" , name )) == 0
104113 assert "ee_fractions" in cat .meta
105114 assert isinstance (cat .meta ["ee_fractions" ], dict )
115+ # f158, f184 (no PSF-matched bands)
106116 assert len (cat .meta ["ee_fractions" ]) == 2
117+
118+ # check that sharpness, roundness1, is_extended, and
119+ # fluxfrac_radius_50 columns are not present for matched bands
120+ assert all (
121+ f"{ param } _f158m" not in cat .colnames
122+ for param in ["sharpness" , "roundness1" , "is_extended" , "fluxfrac_radius_50" ]
123+ )
124+
125+ # Check metadata for PSF match reference filter
126+ assert "psf_match_reference_filter" in cat .meta
127+ assert cat .meta ["psf_match_reference_filter" ] == "f184"
107128 assert "f158" in cat .meta ["ee_fractions" ]
108129 assert "f184" in cat .meta ["ee_fractions" ]
130+ # PSF-matched bands should not have ee_fractions
131+ assert "f158m" not in cat .meta ["ee_fractions" ]
132+ assert "f184m" not in cat .meta ["ee_fractions" ]
109133 for value in cat .meta ["ee_fractions" ].values ():
110134 assert len (value ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
111135
@@ -379,7 +403,7 @@ def test_multiband_source_injection_catalog(
379403 result ,
380404 cat ,
381405 library_model2 ,
382- test_multiband_catalog ,
406+ save_results ,
383407 function_jail ,
384408 shape = (5000 , 5000 ),
385409 )
@@ -453,3 +477,194 @@ def test_match_recovered_sources():
453477 # Test columns included or excluded as expected
454478 assert "one" in rec_table .colnames
455479 assert "empty" not in rec_table .colnames
480+
481+
482+ @pytest .fixture
483+ def library_model_three_filters (mosaic_model ):
484+ """
485+ Library with F062, F158, F184.
486+ """
487+ model1 = mosaic_model .copy ()
488+ model1 .meta .instrument .optical_element = "F062"
489+
490+ model2 = mosaic_model .copy ()
491+ model2 .meta .instrument .optical_element = "F158"
492+
493+ model3 = mosaic_model .copy ()
494+ model3 .meta .instrument .optical_element = "F184"
495+
496+ # input models not in wavelength order to test sorting
497+ return ModelLibrary ([model2 , model3 , model1 ])
498+
499+
500+ @pytest .mark .parametrize ("fit_psf" , (True , False ))
501+ def test_multiband_catalog_reddest_reference (
502+ library_model_three_filters , fit_psf , function_jail
503+ ):
504+ """
505+ Test PSF matching when reference filter is the reddest.
506+
507+ This tests the case where we have [F062, F158, F184] and F184 is
508+ selected as the reference (longest wavelength). F062 and F158 get
509+ PSF-matched to F184. Because F184 is the reference, no PSF-matched
510+ columns are created for F184.
511+ """
512+ step = MultibandCatalogStep ()
513+
514+ result = step .call (
515+ library_model_three_filters ,
516+ bkg_boxsize = 50 ,
517+ snr_threshold = 3 ,
518+ npixels = 10 ,
519+ fit_psf = fit_psf ,
520+ deblend = True ,
521+ save_results = False ,
522+ )
523+
524+ cat = result .source_catalog
525+ assert isinstance (cat , Table )
526+ assert len (cat ) == 7
527+
528+ # Check metadata for PSF match reference filter
529+ assert "psf_match_reference_filter" in cat .meta
530+ assert cat .meta ["psf_match_reference_filter" ] == "f184"
531+
532+ # F062 and F158 should have PSF-matched columns (matched to F184)
533+ assert sum (
534+ 1 for name in cat .colnames if match (r"^aper\d+_f062m_flux$" , name )
535+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
536+ assert sum (
537+ 1 for name in cat .colnames if match (r"^aper\d+_f158m_flux$" , name )
538+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
539+
540+ # F184 (reference) should NOT have PSF-matched columns
541+ assert sum (1 for name in cat .colnames if match (r"^aper\d+_f184m_flux$" , name )) == 0
542+
543+ # Check ee_fractions - should have 3 keys: f062, f158, f184 (no
544+ # PSF-matched bands)
545+ assert "ee_fractions" in cat .meta
546+ assert len (cat .meta ["ee_fractions" ]) == 3
547+ assert "f062" in cat .meta ["ee_fractions" ]
548+ assert "f158" in cat .meta ["ee_fractions" ]
549+ assert "f184" in cat .meta ["ee_fractions" ]
550+ # PSF-matched bands should not have ee_fractions
551+ assert "f062m" not in cat .meta ["ee_fractions" ]
552+ assert "f158m" not in cat .meta ["ee_fractions" ]
553+ assert "f184m" not in cat .meta ["ee_fractions" ]
554+
555+
556+ def test_multiband_catalog_middle_reference (library_model_three_filters , function_jail ):
557+ """
558+ Test PSF matching when reference filter is in the middle.
559+
560+ This tests the case where we have [F062, F158, F184] and F158 is
561+ selected as the reference (middle wavelength). F062 gets normal
562+ PSF-matching (convolved to F158), while F184 gets synthetic
563+ PSF-matching (correction factors). F158 has no PSF-matched columns
564+ as it is the reference.
565+ """
566+ step = MultibandCatalogStep ()
567+
568+ result = step .call (
569+ library_model_three_filters ,
570+ bkg_boxsize = 50 ,
571+ snr_threshold = 3 ,
572+ npixels = 10 ,
573+ fit_psf = False ,
574+ deblend = True ,
575+ reference_filter = "F158" ,
576+ save_results = False ,
577+ )
578+
579+ cat = result .source_catalog
580+ assert isinstance (cat , Table )
581+ assert len (cat ) == 7
582+
583+ # Check metadata for PSF match reference filter
584+ assert "psf_match_reference_filter" in cat .meta
585+ assert cat .meta ["psf_match_reference_filter" ] == "f158"
586+
587+ # F062 (bluer) should have PSF-matched columns (normal convolution
588+ # to F158)
589+ assert sum (
590+ 1 for name in cat .colnames if match (r"^aper\d+_f062m_flux$" , name )
591+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
592+
593+ # F158 (reference) should NOT have PSF-matched columns
594+ assert sum (1 for name in cat .colnames if match (r"^aper\d+_f158m_flux$" , name )) == 0
595+
596+ # F184 (redder) should have PSF-matched columns (synthetic via
597+ # correction factors)
598+ assert sum (
599+ 1 for name in cat .colnames if match (r"^aper\d+_f184m_flux$" , name )
600+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
601+
602+ # Check ee_fractions - should have 3 keys: f062, f158, f184 (no
603+ # PSF-matched bands)
604+ assert "ee_fractions" in cat .meta
605+ assert len (cat .meta ["ee_fractions" ]) == 3
606+ assert "f062" in cat .meta ["ee_fractions" ]
607+ assert "f158" in cat .meta ["ee_fractions" ]
608+ assert "f184" in cat .meta ["ee_fractions" ]
609+ # PSF-matched bands should not have ee_fractions
610+ assert "f062m" not in cat .meta ["ee_fractions" ]
611+ assert "f158m" not in cat .meta ["ee_fractions" ]
612+ assert "f184m" not in cat .meta ["ee_fractions" ]
613+
614+
615+ def test_multiband_catalog_bluest_reference (library_model_three_filters , function_jail ):
616+ """
617+ Test PSF matching when reference filter is the bluest.
618+
619+ This tests the case where we have [F062, F158, F184] and F062 is
620+ selected as the reference (shortest wavelength). Both F158 and
621+ F184 get synthetic PSF-matching (correction factors). F062 has no
622+ PSF-matched columns as it is the reference.
623+ """
624+ step = MultibandCatalogStep ()
625+
626+ result = step .call (
627+ library_model_three_filters ,
628+ bkg_boxsize = 50 ,
629+ snr_threshold = 3 ,
630+ npixels = 10 ,
631+ fit_psf = False ,
632+ deblend = True ,
633+ reference_filter = "F062" ,
634+ save_results = False ,
635+ )
636+
637+ cat = result .source_catalog
638+ assert isinstance (cat , Table )
639+ assert len (cat ) == 7
640+
641+ # Check metadata for PSF match reference filter
642+ assert "psf_match_reference_filter" in cat .meta
643+ assert cat .meta ["psf_match_reference_filter" ] == "f062"
644+
645+ # F062 (reference) should NOT have PSF-matched columns
646+ assert sum (1 for name in cat .colnames if match (r"^aper\d+_f062m_flux$" , name )) == 0
647+
648+ # F158 (redder) should have PSF-matched columns (synthetic via
649+ # correction factors)
650+ assert sum (
651+ 1 for name in cat .colnames if match (r"^aper\d+_f158m_flux$" , name )
652+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
653+
654+ # F184 (reddest) should have PSF-matched columns (synthetic via
655+ # correction factors)
656+ assert sum (
657+ 1 for name in cat .colnames if match (r"^aper\d+_f184m_flux$" , name )
658+ ) == len (cat .meta ["aperture_radii" ]["circle_pix" ])
659+
660+ # Check ee_fractions - should have 3 keys: f062, f158, f184 (no
661+ # PSF-matched bands)
662+ assert "ee_fractions" in cat .meta
663+ assert len (cat .meta ["ee_fractions" ]) == 3
664+ assert "f062" in cat .meta ["ee_fractions" ]
665+ assert "f158" in cat .meta ["ee_fractions" ]
666+ assert "f184" in cat .meta ["ee_fractions" ]
667+ # PSF-matched bands should not have ee_fractions
668+ assert "f062m" not in cat .meta ["ee_fractions" ]
669+ assert "f158m" not in cat .meta ["ee_fractions" ]
670+ assert "f184m" not in cat .meta ["ee_fractions" ]
0 commit comments