def test_lsst_y_focus(): # Check that applying reasonable focus depth (from O'Connor++06) indeed leads to smaller spot # size for LSST y-band. rng = galsim.BaseDeviate(9876543210) bandpass = galsim.Bandpass("LSST_y.dat", wave_type='nm') sed = galsim.SED("1", wave_type='nm', flux_type='flambda') obj = galsim.Gaussian(fwhm=1e-5) oversampling = 32 photon_ops0 = [ galsim.WavelengthSampler(sed, bandpass, rng=rng), galsim.FRatioAngles(1.234, 0.606, rng=rng), galsim.FocusDepth(0.0), galsim.Refraction(3.9) ] img0 = obj.drawImage( sensor=galsim.SiliconSensor(), method='phot', n_photons=100000, photon_ops=photon_ops0, scale=0.2/oversampling, nx=32*oversampling, ny=32*oversampling, rng=rng ) T0 = img0.calculateMomentRadius() T0 *= 10*oversampling/0.2 # arcsec => microns # O'Connor finds minimum spot size when the focus depth is ~ -12 microns. Our sensor isn't # necessarily the same as the one there though; our minimum seems to be around -6 microns. # That could be due to differences in the design of the sensor though. We just use -6 microns # here, which is still useful to test the sign of the `depth` parameter and the interaction of # the 4 different surface operators required to produce this effect, and is roughly consistent # with O'Connor. depth1 = -6. # microns, negative means surface is intrafocal depth1 /= 10 # microns => pixels photon_ops1 = [ galsim.WavelengthSampler(sed, bandpass, rng=rng), galsim.FRatioAngles(1.234, 0.606, rng=rng), galsim.FocusDepth(depth1), galsim.Refraction(3.9) ] img1 = obj.drawImage( sensor=galsim.SiliconSensor(), method='phot', n_photons=100000, photon_ops=photon_ops1, scale=0.2/oversampling, nx=32*oversampling, ny=32*oversampling, rng=rng ) T1 = img1.calculateMomentRadius() T1 *= 10*oversampling/0.2 # arcsec => microns np.testing.assert_array_less(T1, T0)
bd = galsim.BaseDeviate(12) depths = np.linspace(-25, 25, 41) # microns obj = galsim.Gaussian(sigma=1e-4) sed = galsim.SED("1", wave_type='nm', flux_type='flambda') fig, ax = plt.subplots() oversampling = 16 for filter in ['g', 'z', 'y']: bandpass = galsim.Bandpass("LSST_{}.dat".format(filter), wave_type='nm') Ts = [] for depth in depths: depth_pix = depth / 10 surface_ops = [ galsim.WavelengthSampler(sed, bandpass, rng=bd), galsim.FRatioAngles(1.234, 0.606, rng=bd), galsim.FocusDepth(depth_pix), galsim.Refraction(3.9) # approx number for Silicon ] img = obj.drawImage( sensor=galsim.SiliconSensor(), method='phot', n_photons=1_000_000, surface_ops=surface_ops, scale=0.2 / oversampling, # oversample pixels to better resolve PSF size nx=32 * oversampling, # 6.4 arcsec stamp ny=32 * oversampling, ) Ts.append(img.calculateMomentRadius()) Ts = np.array(Ts) / 0.2 * 10 * oversampling # convert arcsec -> micron ax.scatter(depths, Ts, label=filter)
def test_focus_depth(): bd = galsim.BaseDeviate(1234) for _ in range(100): # Test that FocusDepth is additive photon_array = galsim.PhotonArray(1000) photon_array2 = galsim.PhotonArray(1000) photon_array.x = 0.0 photon_array.y = 0.0 photon_array2.x = 0.0 photon_array2.y = 0.0 galsim.FRatioAngles(1.234, obscuration=0.606, rng=bd).applyTo(photon_array) photon_array2.dxdz[:] = photon_array.dxdz photon_array2.dydz[:] = photon_array.dydz fd1 = galsim.FocusDepth(1.1) fd2 = galsim.FocusDepth(2.2) fd3 = galsim.FocusDepth(3.3) fd1.applyTo(photon_array) fd2.applyTo(photon_array) fd3.applyTo(photon_array2) np.testing.assert_allclose(photon_array.x, photon_array2.x, rtol=0, atol=1e-15) np.testing.assert_allclose(photon_array.y, photon_array2.y, rtol=0, atol=1e-15) # Assuming focus is at x=y=0, then # intrafocal (depth < 0) => (x > 0 => dxdz < 0) # extrafocal (depth > 0) => (x > 0 => dxdz > 0) # We applied an extrafocal operation above, so check for corresponding # relation between x, dxdz np.testing.assert_array_less(0, photon_array.x * photon_array.dxdz) # transforming by depth and -depth is null fd4 = galsim.FocusDepth(-3.3) fd4.applyTo(photon_array) np.testing.assert_allclose(photon_array.x, 0.0, rtol=0, atol=1e-15) np.testing.assert_allclose(photon_array.y, 0.0, rtol=0, atol=1e-15) # Check that invalid photon array is trapped pa = galsim.PhotonArray(10) fd = galsim.FocusDepth(1.0) with np.testing.assert_raises(galsim.GalSimError): fd.applyTo(pa) # Check that we can infer depth from photon positions before and after... for _ in range(100): photon_array = galsim.PhotonArray(1000) photon_array2 = galsim.PhotonArray(1000) ud = galsim.UniformDeviate(bd) ud.generate(photon_array.x) ud.generate(photon_array.y) photon_array.x -= 0.5 photon_array.y -= 0.5 galsim.FRatioAngles(1.234, obscuration=0.606, rng=bd).applyTo(photon_array) photon_array2.x[:] = photon_array.x photon_array2.y[:] = photon_array.y photon_array2.dxdz[:] = photon_array.dxdz photon_array2.dydz[:] = photon_array.dydz depth = ud() - 0.5 galsim.FocusDepth(depth).applyTo(photon_array2) np.testing.assert_allclose( (photon_array2.x - photon_array.x) / photon_array.dxdz, depth) np.testing.assert_allclose( (photon_array2.y - photon_array.y) / photon_array.dydz, depth) np.testing.assert_allclose(photon_array.dxdz, photon_array2.dxdz) np.testing.assert_allclose(photon_array.dydz, photon_array2.dydz)