11import galsim
22import galsim .roman as roman
33import galsim .config
4- from galsim .config import RegisterObjectType ,RegisterInputType ,OpticalPSF ,InputLoader
4+ from galsim .config import RegisterObjectType , RegisterInputType , OpticalPSF , InputLoader
5+
56
67class RomanPSF (object ):
78 """Class building needed Roman PSFs.
89 """
10+
911 def __init__ (self , SCA = None , WCS = None , n_waves = None , bpass = None , extra_aberrations = None , logger = None ):
1012
1113 logger = galsim .config .LoggerWrapper (logger )
1214
1315 if n_waves == - 1 :
14- if bpass .name == 'W146' :
15- n_waves = 10
16+ if bpass .name == 'W146' :
17+ n_waves = 10
1618 else :
17- n_waves = 5
19+ n_waves = 5
1820
19- corners = [galsim .PositionD (1 ,1 ),galsim .PositionD (1 ,roman .n_pix ),galsim .PositionD (roman .n_pix ,1 ),galsim .PositionD (roman .n_pix ,roman .n_pix )]
20- cc = galsim .PositionD (roman .n_pix / 2 ,roman .n_pix / 2 )
21- tags = ['ll' ,'lu' ,'ul' ,'uu' ]
21+ corners = [galsim .PositionD (1 , 1 ), galsim .PositionD (1 , roman .n_pix ), galsim .PositionD (
22+ roman .n_pix , 1 ), galsim .PositionD (roman .n_pix , roman .n_pix )]
23+ cc = galsim .PositionD (roman .n_pix / 2 , roman .n_pix / 2 )
24+ tags = ['ll' , 'lu' , 'ul' , 'uu' ]
2225 self .PSF = {}
2326 pupil_bin = 8
2427 self .PSF [pupil_bin ] = {}
25- for tag ,SCA_pos in tuple (zip (tags ,corners )):
26- self .PSF [pupil_bin ][tag ] = self ._psf_call (SCA ,bpass ,SCA_pos ,WCS ,pupil_bin ,n_waves ,logger ,extra_aberrations )
27- for pupil_bin in [4 ,2 ,'achromatic' ]:
28- self .PSF [pupil_bin ] = self ._psf_call (SCA ,bpass ,cc ,WCS ,pupil_bin ,n_waves ,logger ,extra_aberrations )
28+ for tag , SCA_pos in tuple (zip (tags , corners )):
29+ self .PSF [pupil_bin ][tag ] = self ._psf_call (
30+ SCA , bpass , SCA_pos , WCS , pupil_bin , n_waves , logger , extra_aberrations )
31+ for pupil_bin in [4 , 2 , 'achromatic' ]:
32+ self .PSF [pupil_bin ] = self ._psf_call (
33+ SCA , bpass , cc , WCS , pupil_bin , n_waves , logger , extra_aberrations )
34+
35+ self .PSF_coadd = self ._psf_call_coadd (bpass , n_waves , logger )
2936
30- def _parse_pupil_bin (self ,pupil_bin ):
31- if pupil_bin == 'achromatic' :
37+ def _parse_pupil_bin (self , pupil_bin ):
38+ if pupil_bin == 'achromatic' :
3239 return 8
3340 else :
3441 return pupil_bin
3542
36- def _psf_call (self ,SCA ,bpass ,SCA_pos ,WCS ,pupil_bin ,n_waves ,logger ,extra_aberrations ):
43+ def _psf_call_coadd (self , bpass , n_waves , logger ):
44+ # Currently only implementing a Gaussian PSF for each band
45+ fwhm_dict = {
46+ 'Y106' : 0.220 ,
47+ 'J129' : 0.231 ,
48+ 'H158' : 0.242 ,
49+ 'F184' : 0.253 ,
50+ 'K213' : 0.264 ,
51+ }
52+ psf = galsim .Gaussian (fwhm = fwhm_dict [bpass .name ])
53+ return psf .withGSParams (maximum_fft_size = 16384 )
54+
3755
38- if pupil_bin == 8 :
56+ def _psf_call (self , SCA , bpass , SCA_pos , WCS , pupil_bin , n_waves , logger , extra_aberrations ):
57+
58+ if pupil_bin == 8 :
3959 psf = roman .getPSF (SCA ,
40- bpass .name ,
41- SCA_pos = SCA_pos ,
42- wcs = WCS ,
43- pupil_bin = pupil_bin ,
44- n_waves = n_waves ,
45- logger = logger ,
46- # Don't set wavelength for this one.
47- # We want this to be chromatic for photon shooting.
48- # wavelength = bpass.effective_wavelength,
49- extra_aberrations = extra_aberrations
50- )
60+ bpass .name ,
61+ SCA_pos = SCA_pos ,
62+ wcs = WCS ,
63+ pupil_bin = pupil_bin ,
64+ n_waves = n_waves ,
65+ logger = logger ,
66+ # Don't set wavelength for this one.
67+ # We want this to be chromatic for photon shooting.
68+ # wavelength = bpass.effective_wavelength,
69+ extra_aberrations = extra_aberrations
70+ )
5171 else :
5272 psf = roman .getPSF (SCA ,
53- bpass .name ,
54- SCA_pos = SCA_pos ,
55- wcs = WCS ,
56- pupil_bin = self ._parse_pupil_bin (pupil_bin ),
57- n_waves = n_waves ,
58- logger = logger ,
59- # Note: setting wavelength makes it achromatic.
60- # We only use pupil_bin = 2,4 for FFT objects.
61- wavelength = bpass .effective_wavelength ,
62- extra_aberrations = extra_aberrations
63- )
64- if pupil_bin == 4 :
73+ bpass .name ,
74+ SCA_pos = SCA_pos ,
75+ wcs = WCS ,
76+ pupil_bin = self ._parse_pupil_bin (pupil_bin ),
77+ n_waves = n_waves ,
78+ logger = logger ,
79+ # Note: setting wavelength makes it achromatic.
80+ # We only use pupil_bin = 2,4 for FFT objects.
81+ wavelength = bpass .effective_wavelength ,
82+ extra_aberrations = extra_aberrations
83+ )
84+ if pupil_bin == 4 :
6585 return psf .withGSParams (maximum_fft_size = 16384 , folding_threshold = 1e-3 )
66- elif pupil_bin == 2 :
86+ elif pupil_bin == 2 :
6787 return psf .withGSParams (maximum_fft_size = 16384 , folding_threshold = 1e-4 )
6888 else :
6989 return psf .withGSParams (maximum_fft_size = 16384 )
7090
71- def getPSF (self ,pupil_bin ,pos ):
91+ def getPSF (self , pupil_bin , pos , is_coadd = False ):
7292 """
7393 Return a PSF to be convolved with sources.
7494
7595 @param [in] what pupil binning to request.
7696 """
7797
78- #temporary
98+ # temporary
7999 # psf = self.PSF[pupil_bin]['ll']
80100 # if ((pos.x-roman.n_pix)**2+(pos.y-roman.n_pix)**2)<((pos.x-1)**2+(pos.y-1)**2):
81101 # psf = self.PSF[pupil_bin]['uu']
@@ -87,8 +107,11 @@ def getPSF(self,pupil_bin,pos):
87107 # psf = self.PSF[pupil_bin]['cc']
88108 # return psf
89109
110+ if is_coadd :
111+ return self .PSF_coadd
112+
90113 psf = self .PSF [pupil_bin ]
91- if pupil_bin != 8 :
114+ if pupil_bin != 8 :
92115 return psf
93116
94117 wll = (roman .n_pix - pos .x )* (roman .n_pix - pos .y )
@@ -97,9 +120,11 @@ def getPSF(self,pupil_bin,pos):
97120 wuu = (pos .x - 1 )* (pos .y - 1 )
98121 return (wll * psf ['ll' ]+ wlu * psf ['lu' ]+ wul * psf ['ul' ]+ wuu * psf ['uu' ])/ ((roman .n_pix - 1 )* (roman .n_pix - 1 ))
99122
123+
100124class PSFLoader (InputLoader ):
101125 """PSF loader.
102126 """
127+
103128 def __init__ (self ):
104129 # Override some defaults in the base init.
105130 super ().__init__ (init_func = RomanPSF ,
@@ -110,7 +135,7 @@ def getKwargs(self, config, base, logger):
110135
111136 req = {}
112137 opt = {
113- 'n_waves' : int ,
138+ 'n_waves' : int ,
114139 }
115140 ignore = ['extra_aberrations' ]
116141
@@ -121,20 +146,25 @@ def getKwargs(self, config, base, logger):
121146 else :
122147 req ['SCA' ] = int
123148
124- kwargs , safe = galsim .config .GetAllParams (config , base , req = req , opt = opt , ignore = ignore )
149+ kwargs , safe = galsim .config .GetAllParams (
150+ config , base , req = req , opt = opt , ignore = ignore )
125151
126152 # If not given in kwargs, then it must have been in base, so this is ok.
127153 if 'SCA' not in kwargs :
128154 kwargs ['SCA' ] = base ['SCA' ]
129155
130- kwargs ['extra_aberrations' ] = galsim .config .ParseAberrations ('extra_aberrations' , config , base , 'RomanPSF' )
131- kwargs ['WCS' ] = galsim .config .BuildWCS (base ['image' ], 'wcs' , base , logger = logger )
132- kwargs ['bpass' ] = galsim .config .BuildBandpass (base ['image' ], 'bandpass' , base , logger )[0 ]
156+ kwargs ['extra_aberrations' ] = galsim .config .ParseAberrations (
157+ 'extra_aberrations' , config , base , 'RomanPSF' )
158+ kwargs ['WCS' ] = galsim .config .BuildWCS (
159+ base ['image' ], 'wcs' , base , logger = logger )
160+ kwargs ['bpass' ] = galsim .config .BuildBandpass (
161+ base ['image' ], 'bandpass' , base , logger )[0 ]
133162
134- logger .debug ("kwargs = %s" ,kwargs )
163+ logger .debug ("kwargs = %s" , kwargs )
135164
136165 return kwargs , False
137166
167+
138168# Register this as a valid type
139169RegisterInputType ('roman_psf' , PSFLoader ())
140170# RegisterObjectType('roman_psf', BuildRomanPSF, input_type='romanpsf_loader')
0 commit comments