Пример #1
0
def time_silicon_accumulate():
    nx = 1000
    ny = 1000
    nobj = 1000
    photons_per_obj = 10000
    flux_per_photon = 1

    rng = galsim.UniformDeviate(314159)

    sensor = galsim.SiliconSensor(rng=rng.duplicate(), diffusion_factor=0.0)

    im = galsim.ImageF(nx, ny)

    num_photons = nobj * photons_per_obj
    photons = galsim.PhotonArray(num_photons)

    rng.generate(photons.x)
    photons.x *= nx
    photons.x += 0.5
    rng.generate(photons.y)
    photons.y *= ny
    photons.y += 0.5
    photons.flux = flux_per_photon

    t1 = time.time()
    sensor.accumulate(photons, im)
    t2 = time.time()
    print('Time = ', t2 - t1)
Пример #2
0
def get_photon_array(image, nphotons, rng):
    # Simpler method that has all the pixels with flux=1.
    # Might be too slow, in which case consider switching to the above code.
    photon_array = galsim.PhotonArray(int(nphotons))

    # Generate the x,y values.
    rng.generate(photon_array.x)  # 0..1 so far
    photon_array.x *= (image.xmax - image.xmin + 1)
    photon_array.x += image.xmin - 0.5  # Now from xmin-0.5 .. xmax+0.5
    rng.generate(photon_array.y)
    photon_array.y *= (image.ymax - image.ymin + 1)
    photon_array.y += image.ymin - 0.5

    # Flux in this case is simple.  All flux = 1.
    photon_array.flux = 1

    return photon_array
Пример #3
0
def get_bundled_photon_array(image, nphotons, nbundles_per_pix, rng):
    # A convenient way to do that is to have the fluxes of the
    # bundles be generated from a Poisson distribution.

    # Make a PhotonArray to hold the sky photons
    npix = np.prod(image.array.shape)
    nbundles = npix * nbundles_per_pix
    flux_per_bundle = np.float(nphotons) / nbundles
    #print('npix = ',npix)
    #print('nbundles = ',nbundles)
    #print('flux_per_bundle = ',flux_per_bundle)
    photon_array = galsim.PhotonArray(int(nbundles))

    # Generate the x,y values.
    xx, yy = np.meshgrid(np.arange(image.xmin, image.xmax + 1),
                         np.arange(image.ymin, image.ymax + 1))
    xx = xx.ravel()
    yy = yy.ravel()
    assert len(xx) == npix
    assert len(yy) == npix
    xx = np.repeat(xx, nbundles_per_pix)
    yy = np.repeat(yy, nbundles_per_pix)
    # If the photon_array is smaller than xx and yy,
    # randomly select the corresponding number of xy values.
    if photon_array.size() < len(xx):
        index = (np.random.permutation(np.arange(
            len(xx)))[:photon_array.size()], )
        xx = xx[index]
        yy = yy[index]
    assert len(xx) == photon_array.size()
    assert len(yy) == photon_array.size()
    galsim.random.permute(rng, xx, yy)  # Randomly reshuffle in place

    # The above values are pixel centers.  Add a random offset within each pixel.
    rng.generate(photon_array.x)  # Random values from 0..1
    photon_array.x -= 0.5
    rng.generate(photon_array.y)
    photon_array.y -= 0.5
    photon_array.x += xx
    photon_array.y += yy

    # Set the flux of the photons
    flux_pd = galsim.PoissonDeviate(rng, mean=flux_per_bundle)
    flux_pd.generate(photon_array.flux)

    return photon_array
Пример #4
0
    def get_photon_array(self, image, nphotons):
        """
        Generate an array of photons randomly distributed over the
        surface of the sensor.
        """
        photon_array = galsim.PhotonArray(int(nphotons))

        # Generate the x,y values.
        self.randomNumbers.generate(photon_array.x)  # 0..1 so far
        photon_array.x *= (image.xmax - image.xmin + 1)
        photon_array.x += image.xmin - 0.5  # Now from xmin-0.5 .. xmax+0.5
        self.randomNumbers.generate(photon_array.y)
        photon_array.y *= (image.ymax - image.ymin + 1)
        photon_array.y += image.ymin - 0.5
        photon_array.flux = 1

        return photon_array
Пример #5
0
def test_photon_array():
    """Test the basic methods of PhotonArray class
    """
    nphotons = 1000

    # First create from scratch
    photon_array = galsim.PhotonArray(nphotons)
    assert len(photon_array.x) == nphotons
    assert len(photon_array.y) == nphotons
    assert len(photon_array.flux) == nphotons
    assert not photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()

    # Initial values should all be 0
    np.testing.assert_array_equal(photon_array.x, 0.)
    np.testing.assert_array_equal(photon_array.y, 0.)
    np.testing.assert_array_equal(photon_array.flux, 0.)

    # Check picklability
    do_pickle(photon_array)

    # Check assignment via numpy [:]
    photon_array.x[:] = 5
    photon_array.y[:] = 17
    photon_array.flux[:] = 23
    np.testing.assert_array_equal(photon_array.x, 5.)
    np.testing.assert_array_equal(photon_array.y, 17.)
    np.testing.assert_array_equal(photon_array.flux, 23.)

    # Check assignment directly to the attributes
    photon_array.x = 25
    photon_array.y = 37
    photon_array.flux = 53
    np.testing.assert_array_equal(photon_array.x, 25.)
    np.testing.assert_array_equal(photon_array.y, 37.)
    np.testing.assert_array_equal(photon_array.flux, 53.)

    # Now create from shooting a profile
    obj = galsim.Exponential(flux=1.7, scale_radius=2.3)
    rng = galsim.UniformDeviate(1234)
    photon_array = obj.SBProfile.shoot(nphotons, rng)
    orig_x = photon_array.x.copy()
    orig_y = photon_array.y.copy()
    orig_flux = photon_array.flux.copy()
    assert len(photon_array.x) == nphotons
    assert len(photon_array.y) == nphotons
    assert len(photon_array.flux) == nphotons
    assert not photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()

    # Check arithmetic ops
    photon_array.x *= 5
    photon_array.y += 17
    photon_array.flux /= 23
    np.testing.assert_almost_equal(photon_array.x, orig_x * 5.)
    np.testing.assert_almost_equal(photon_array.y, orig_y + 17.)
    np.testing.assert_almost_equal(photon_array.flux, orig_flux / 23.)

    # Check picklability again with non-zero values
    do_pickle(photon_array)

    # Now assign to the optional arrays
    photon_array.dxdz = 0.17
    assert photon_array.hasAllocatedAngles()
    assert not photon_array.hasAllocatedWavelengths()
    np.testing.assert_array_equal(photon_array.dxdz, 0.17)
    np.testing.assert_array_equal(photon_array.dydz, 0.)

    photon_array.dydz = 0.59
    np.testing.assert_array_equal(photon_array.dxdz, 0.17)
    np.testing.assert_array_equal(photon_array.dydz, 0.59)

    # Start over to check that assigning to wavelength leaves dxdz, dydz alone.
    photon_array = obj.SBProfile.shoot(nphotons, rng)
    photon_array.wavelength = 500.
    assert photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()
    np.testing.assert_array_equal(photon_array.wavelength, 500)

    photon_array.dxdz = 0.23
    photon_array.dydz = 0.88
    photon_array.wavelength = 912.
    assert photon_array.hasAllocatedWavelengths()
    assert photon_array.hasAllocatedAngles()
    np.testing.assert_array_equal(photon_array.dxdz, 0.23)
    np.testing.assert_array_equal(photon_array.dydz, 0.88)
    np.testing.assert_array_equal(photon_array.wavelength, 912)

    # Check picklability again with non-zero values for everything
    do_pickle(photon_array)
Пример #6
0
def test_resume():
    """Test that the resume option for accumulate works properly.
    """
    # Note: This test is based on a script devel/lsst/treering_skybg_check.py

    rng = galsim.UniformDeviate(314159)

    if __name__ == "__main__":
        flux_per_pixel = 40
        nx = 200
        ny = 200
        block_size = int(1.2e5)
        nrecalc = 1.e6
    else:
        flux_per_pixel = 40
        nx = 20
        ny = 20
        block_size = int(1.3e3)
        nrecalc = 1.e4

    expected_num_photons = nx * ny * flux_per_pixel
    pd = galsim.PoissonDeviate(rng, mean=expected_num_photons)
    num_photons = int(pd())  # Poisson realization of the given expected number of photons.
    #nrecalc = num_photons / 2  # Only recalc once.
    flux_per_photon = 1
    print('num_photons = ',num_photons,' .. expected = ',expected_num_photons)

    # Use treerings to make sure that aspect of the setup is preserved properly on resume
    treering_func = galsim.SiliconSensor.simple_treerings(0.5, 250.)
    treering_center = galsim.PositionD(-1000,0)
    sensor1 = galsim.SiliconSensor(rng=rng.duplicate(), nrecalc=nrecalc,
                                   treering_func=treering_func, treering_center=treering_center)
    sensor2 = galsim.SiliconSensor(rng=rng.duplicate(), nrecalc=nrecalc,
                                   treering_func=treering_func, treering_center=treering_center)
    sensor3 = galsim.SiliconSensor(rng=rng.duplicate(), nrecalc=nrecalc,
                                   treering_func=treering_func, treering_center=treering_center)

    waves = galsim.WavelengthSampler(sed = galsim.SED('1', 'nm', 'fphotons'),
                                     bandpass = galsim.Bandpass('LSST_r.dat', 'nm'),
                                     rng=rng)
    angles = galsim.FRatioAngles(1.2, 0.4, rng)

    im1 = galsim.ImageF(nx,ny)  # Will not use resume
    im2 = galsim.ImageF(nx,ny)  # Will use resume
    im3 = galsim.ImageF(nx,ny)  # Will run all photons in one pass

    t_resume = 0
    t_no_resume = 0

    all_photons = galsim.PhotonArray(num_photons)
    n_added = 0

    first = True
    while num_photons > 0:
        print(num_photons,'photons left. image min/max =',im1.array.min(),im1.array.max())
        nphot = min(block_size, num_photons)
        num_photons -= nphot

        t0 = time.time()
        photons = galsim.PhotonArray(int(nphot))
        rng.generate(photons.x) # 0..1 so far
        photons.x *= nx
        photons.x += 0.5  # Now from xmin-0.5 .. xmax+0.5
        rng.generate(photons.y)
        photons.y *= ny
        photons.y += 0.5
        photons.flux = flux_per_photon
        waves.applyTo(photons)
        angles.applyTo(photons)

        all_photons.x[n_added:n_added+nphot] = photons.x
        all_photons.y[n_added:n_added+nphot] = photons.y
        all_photons.flux[n_added:n_added+nphot] = photons.flux
        all_photons.dxdz[n_added:n_added+nphot] = photons.dxdz
        all_photons.dydz[n_added:n_added+nphot] = photons.dydz
        all_photons.wavelength[n_added:n_added+nphot] = photons.wavelength
        n_added += nphot

        t1 = time.time()
        sensor1.accumulate(photons, im1)

        t2 = time.time()
        sensor2.accumulate(photons, im2, resume = not first)
        first = False
        t3 = time.time()
        print('Times = ',t1-t0,t2-t1,t3-t2)
        t_resume += t3-t2
        t_no_resume += t2-t1

    print('max diff = ',np.max(np.abs(im1.array - im2.array)))
    print('max rel diff = ',np.max(np.abs(im1.array - im2.array)/np.abs(im2.array)))
    np.testing.assert_almost_equal(im2.array/expected_num_photons, im1.array/expected_num_photons,
                                   decimal=5)
    print('Time with resume = ',t_resume)
    print('Time without resume = ',t_no_resume)
    assert t_resume < t_no_resume

    # The resume path should be exactly the same as doing all the photons at once.
    sensor3.accumulate(all_photons, im3)
    np.testing.assert_array_equal(im2.array, im3.array)

    # If resume is used either with the wrong image or on the first call to accumulate, then
    # this should raise an exception.
    assert_raises(RuntimeError, sensor3.accumulate, all_photons, im1, resume=True)
    sensor4 = galsim.SiliconSensor(rng=rng.duplicate(), nrecalc=nrecalc,
                                   treering_func=treering_func, treering_center=treering_center)
    assert_raises(RuntimeError, sensor4.accumulate, all_photons, im1, resume=True)
Пример #7
0
def test_silicon():
    """Test the basic construction and use of the SiliconSensor class.
    """

    # Note: Use something quite small in terms of npixels so the B/F effect kicks in without
    # requiring a ridiculous number of photons
    obj = galsim.Gaussian(flux=10000, sigma=0.3)

    # We'll draw the same object using SiliconSensor, Sensor, and the default (sensor=None)
    im1 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=silicon
    im2 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=simple
    im3 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=None

    rng1 = galsim.BaseDeviate(5678)
    rng2 = galsim.BaseDeviate(5678)
    rng3 = galsim.BaseDeviate(5678)

    silicon = galsim.SiliconSensor(rng=rng1, diffusion_factor=0.0)
    simple = galsim.Sensor()

    # Start with photon shooting, since that's more straightforward.
    obj.drawImage(im1, method='phot', poisson_flux=False, sensor=silicon, rng=rng1)
    obj.drawImage(im2, method='phot', poisson_flux=False, sensor=simple, rng=rng2)
    obj.drawImage(im3, method='phot', poisson_flux=False, rng=rng3)

    # First, im2 and im3 should be exactly equal.
    np.testing.assert_array_equal(im2.array, im3.array)

    # im1 should be similar, but not equal
    np.testing.assert_almost_equal(im1.array/obj.flux, im2.array/obj.flux, decimal=2)

    # Now use a different seed for 3 to see how much of the variation is just from randomness.
    rng3.seed(234241)
    obj.drawImage(im3, method='phot', poisson_flux=False, rng=rng3)

    r1 = im1.calculateMomentRadius(flux=obj.flux)
    r2 = im2.calculateMomentRadius(flux=obj.flux)
    r3 = im3.calculateMomentRadius(flux=obj.flux)
    print('Flux = %.0f:  sum        peak          radius'%obj.flux)
    print('im1:         %.1f     %.2f       %f'%(im1.array.sum(),im1.array.max(), r1))
    print('im2:         %.1f     %.2f       %f'%(im2.array.sum(),im2.array.max(), r2))
    print('im3:         %.1f     %.2f       %f'%(im3.array.sum(),im3.array.max(), r3))

    # Fluxes should all equal obj.flux
    np.testing.assert_almost_equal(im1.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im1.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.added_flux, obj.flux, decimal=6)

    # Sizes are all about equal since flux is not large enough for B/F to be significant
    # Variance of Irr for Gaussian with Poisson noise is
    # Var(Irr) = Sum(I r^4) = 4Irr [using Gaussian kurtosis = 8sigma^2, Irr = 2sigma^2]
    # r = sqrt(Irr/flux), so sigma(r) = 1/2 r sqrt(Var(Irr))/Irr = 1/sqrt(flux)
    # Use 2sigma for below checks.
    sigma_r = 1. / np.sqrt(obj.flux) * im1.scale
    np.testing.assert_allclose(r1, r2, atol=2.*sigma_r)
    np.testing.assert_allclose(r2, r3, atol=2.*sigma_r)

    # Repeat with 100X more photons where the brighter-fatter effect should kick in more.
    obj *= 100
    rng1 = galsim.BaseDeviate(5678)
    rng2 = galsim.BaseDeviate(5678)
    rng3 = galsim.BaseDeviate(5678)

    obj.drawImage(im1, method='phot', poisson_flux=False, sensor=silicon, rng=rng1)
    obj.drawImage(im2, method='phot', poisson_flux=False, sensor=simple, rng=rng2)
    obj.drawImage(im3, method='phot', poisson_flux=False, rng=rng3)

    r1 = im1.calculateMomentRadius(flux=obj.flux)
    r2 = im2.calculateMomentRadius(flux=obj.flux)
    r3 = im3.calculateMomentRadius(flux=obj.flux)
    print('Flux = %.0f:  sum        peak          radius'%obj.flux)
    print('im1:         %.1f     %.2f       %f'%(im1.array.sum(),im1.array.max(), r1))
    print('im2:         %.1f     %.2f       %f'%(im2.array.sum(),im2.array.max(), r2))
    print('im3:         %.1f     %.2f       %f'%(im3.array.sum(),im3.array.max(), r3))

    # Fluxes should still be fine.
    np.testing.assert_almost_equal(im1.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im1.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.added_flux, obj.flux, decimal=6)

    # Sizes for 2,3 should be about equal, but 1 should be larger.
    sigma_r = 1. / np.sqrt(obj.flux) * im1.scale
    print('check |r2-r3| = %f <? %f'%(np.abs(r2-r3), 2.*sigma_r))
    np.testing.assert_allclose(r2, r3, atol=2.*sigma_r)
    print('check r1 - r3 = %f > %f due to brighter-fatter'%(r1-r2,sigma_r))
    assert r1 - r3 > 2*sigma_r

    # Check that it is really responding to flux, not number of photons.
    # Using fewer shot photons will mean each one encapsulates several electrons at once.
    obj.drawImage(im1, method='phot', n_photons=1000, poisson_flux=False, sensor=silicon,
                  rng=rng1)
    obj.drawImage(im2, method='phot', n_photons=1000, poisson_flux=False, sensor=simple,
                  rng=rng2)
    obj.drawImage(im3, method='phot', n_photons=1000, poisson_flux=False, rng=rng3)

    r1 = im1.calculateMomentRadius(flux=obj.flux)
    r2 = im2.calculateMomentRadius(flux=obj.flux)
    r3 = im3.calculateMomentRadius(flux=obj.flux)
    print('Flux = %.0f:  sum        peak          radius'%obj.flux)
    print('im1:         %.1f     %.2f       %f'%(im1.array.sum(),im1.array.max(), r1))
    print('im2:         %.1f     %.2f       %f'%(im2.array.sum(),im2.array.max(), r2))
    print('im3:         %.1f     %.2f       %f'%(im3.array.sum(),im3.array.max(), r3))

    np.testing.assert_almost_equal(im1.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im1.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.added_flux, obj.flux, decimal=6)

    print('check r1 - r3 = %f > %f due to brighter-fatter'%(r1-r2,sigma_r))
    assert r1 - r3 > 2*sigma_r

    # Can also get the stronger BF effect with the strength parameter.
    obj /= 100  # Back to what it originally was.
    rng1 = galsim.BaseDeviate(5678)
    rng2 = galsim.BaseDeviate(5678)
    rng3 = galsim.BaseDeviate(5678)

    silicon = galsim.SiliconSensor(name='lsst_itl_8', strength=100., rng=rng1, diffusion_factor=0.0)
    obj.drawImage(im1, method='phot', poisson_flux=False, sensor=silicon, rng=rng1)
    obj.drawImage(im2, method='phot', poisson_flux=False, sensor=simple, rng=rng2)
    obj.drawImage(im3, method='phot', poisson_flux=False, rng=rng3)

    r1 = im1.calculateMomentRadius(flux=obj.flux)
    r2 = im2.calculateMomentRadius(flux=obj.flux)
    r3 = im3.calculateMomentRadius(flux=obj.flux)
    print('Flux = %.0f:  sum        peak          radius'%obj.flux)
    print('im1:         %.1f     %.2f       %f'%(im1.array.sum(),im1.array.max(), r1))
    print('im2:         %.1f     %.2f       %f'%(im2.array.sum(),im2.array.max(), r2))
    print('im3:         %.1f     %.2f       %f'%(im3.array.sum(),im3.array.max(), r3))

    # Fluxes should still be fine.
    np.testing.assert_almost_equal(im1.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.array.sum(), obj.flux, decimal=6)
    np.testing.assert_almost_equal(im1.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im2.added_flux, obj.flux, decimal=6)
    np.testing.assert_almost_equal(im3.added_flux, obj.flux, decimal=6)

    # Sizes for 2,3 should be about equal, but 1 should be larger.
    sigma_r = 1. / np.sqrt(obj.flux) * im1.scale
    print('check |r2-r3| = %f <? %f'%(np.abs(r2-r3), 2.*sigma_r))
    np.testing.assert_allclose(r2, r3, atol=2.*sigma_r)
    print('check r1 - r3 = %f > %f due to brighter-fatter'%(r1-r2,sigma_r))
    assert r1 - r3 > 2*sigma_r / 100

    # Check the construction with an explicit name
    s0 = galsim.SiliconSensor(rng=rng1)
    name = os.path.join(galsim.meta_data.share_dir, 'sensors', 'lsst_itl_8')
    s1 = galsim.SiliconSensor(name=name, strength=1.0, rng=rng1, diffusion_factor=1.0, qdist=3,
                              nrecalc=10000)
    assert s0 == s1
    s1 = galsim.SiliconSensor(name, 1.0, rng1, 1.0, 3, 10000)
    assert s0 == s1
    s2 = galsim.SiliconSensor(rng=rng1, name='lsst_itl_8')
    assert s0 == s2
    s3 = galsim.SiliconSensor(rng=rng1, strength=10.)
    s4 = galsim.SiliconSensor(rng=rng1, diffusion_factor=2.0)
    s5 = galsim.SiliconSensor(rng=rng1, qdist=4)
    s6 = galsim.SiliconSensor(rng=rng1, nrecalc=12345)
    s7 = galsim.SiliconSensor(name=name, strength=1.5, rng=rng1, diffusion_factor=1.3, qdist=4,
                              nrecalc=12345)
    for s in [ s3, s4, s5, s6, s7 ]:
        assert silicon != s
        assert s != s0

    do_pickle(s0)
    do_pickle(s1)
    do_pickle(s7)

    assert_raises(OSError, galsim.SiliconSensor, name='junk')
    assert_raises(OSError, galsim.SiliconSensor, name='output')
    assert_raises(TypeError, galsim.SiliconSensor, rng=3.4)
    assert_raises(TypeError, galsim.SiliconSensor, 'lsst_itl_8', rng1)

    # Invalid to accumulate onto undefined image.
    photons = galsim.PhotonArray(3)
    image = galsim.ImageD()
    with assert_raises(galsim.GalSimUndefinedBoundsError):
        simple.accumulate(photons, image)
    with assert_raises(galsim.GalSimUndefinedBoundsError):
        silicon.accumulate(photons, image)
Пример #8
0
def test_photon_array():
    """Test the basic methods of PhotonArray class
    """
    nphotons = 1000

    # First create from scratch
    photon_array = galsim.PhotonArray(nphotons)
    assert len(photon_array.x) == nphotons
    assert len(photon_array.y) == nphotons
    assert len(photon_array.flux) == nphotons
    assert not photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()

    # Initial values should all be 0
    np.testing.assert_array_equal(photon_array.x, 0.)
    np.testing.assert_array_equal(photon_array.y, 0.)
    np.testing.assert_array_equal(photon_array.flux, 0.)

    # Check picklability
    do_pickle(photon_array)

    # Check assignment via numpy [:]
    photon_array.x[:] = 5
    photon_array.y[:] = 17
    photon_array.flux[:] = 23
    np.testing.assert_array_equal(photon_array.x, 5.)
    np.testing.assert_array_equal(photon_array.y, 17.)
    np.testing.assert_array_equal(photon_array.flux, 23.)

    # Check assignment directly to the attributes
    photon_array.x = 25
    photon_array.y = 37
    photon_array.flux = 53
    np.testing.assert_array_equal(photon_array.x, 25.)
    np.testing.assert_array_equal(photon_array.y, 37.)
    np.testing.assert_array_equal(photon_array.flux, 53.)

    # Now create from shooting a profile
    obj = galsim.Exponential(flux=1.7, scale_radius=2.3)
    rng = galsim.UniformDeviate(1234)
    photon_array = obj.shoot(nphotons, rng)
    orig_x = photon_array.x.copy()
    orig_y = photon_array.y.copy()
    orig_flux = photon_array.flux.copy()
    assert len(photon_array.x) == nphotons
    assert len(photon_array.y) == nphotons
    assert len(photon_array.flux) == nphotons
    assert not photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()

    # Check arithmetic ops
    photon_array.x *= 5
    photon_array.y += 17
    photon_array.flux /= 23
    np.testing.assert_almost_equal(photon_array.x, orig_x * 5.)
    np.testing.assert_almost_equal(photon_array.y, orig_y + 17.)
    np.testing.assert_almost_equal(photon_array.flux, orig_flux / 23.)

    # Check picklability again with non-zero values
    do_pickle(photon_array)

    # Now assign to the optional arrays
    photon_array.dxdz = 0.17
    assert photon_array.hasAllocatedAngles()
    assert not photon_array.hasAllocatedWavelengths()
    np.testing.assert_array_equal(photon_array.dxdz, 0.17)
    np.testing.assert_array_equal(photon_array.dydz, 0.)

    photon_array.dydz = 0.59
    np.testing.assert_array_equal(photon_array.dxdz, 0.17)
    np.testing.assert_array_equal(photon_array.dydz, 0.59)

    # Start over to check that assigning to wavelength leaves dxdz, dydz alone.
    photon_array = obj.shoot(nphotons, rng)
    photon_array.wavelength = 500.
    assert photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()
    np.testing.assert_array_equal(photon_array.wavelength, 500)

    photon_array.dxdz = 0.23
    photon_array.dydz = 0.88
    photon_array.wavelength = 912.
    assert photon_array.hasAllocatedWavelengths()
    assert photon_array.hasAllocatedAngles()
    np.testing.assert_array_equal(photon_array.dxdz, 0.23)
    np.testing.assert_array_equal(photon_array.dydz, 0.88)
    np.testing.assert_array_equal(photon_array.wavelength, 912)

    # Check toggling is_corr
    assert not photon_array.isCorrelated()
    photon_array.setCorrelated()
    assert photon_array.isCorrelated()
    photon_array.setCorrelated(False)
    assert not photon_array.isCorrelated()
    photon_array.setCorrelated(True)
    assert photon_array.isCorrelated()

    # Check rescaling the total flux
    flux = photon_array.flux.sum()
    np.testing.assert_almost_equal(photon_array.getTotalFlux(), flux)
    photon_array.scaleFlux(17)
    np.testing.assert_almost_equal(photon_array.getTotalFlux(), 17 * flux)
    photon_array.setTotalFlux(199)
    np.testing.assert_almost_equal(photon_array.getTotalFlux(), 199)

    # Check rescaling the positions
    x = photon_array.x.copy()
    y = photon_array.y.copy()
    photon_array.scaleXY(1.9)
    np.testing.assert_almost_equal(photon_array.x, 1.9 * x)
    np.testing.assert_almost_equal(photon_array.y, 1.9 * y)

    # Check ways to assign to photons
    pa1 = galsim.PhotonArray(50)
    pa1.x = photon_array.x[:50]
    for i in range(50):
        pa1.y[i] = photon_array.y[i]
    pa1.flux[0:50] = photon_array.flux[:50]
    pa1.dxdz = photon_array.dxdz[:50]
    pa1.dydz = photon_array.dydz[:50]
    pa1.wavelength = photon_array.wavelength[:50]
    np.testing.assert_almost_equal(pa1.x, photon_array.x[:50])
    np.testing.assert_almost_equal(pa1.y, photon_array.y[:50])
    np.testing.assert_almost_equal(pa1.flux, photon_array.flux[:50])
    np.testing.assert_almost_equal(pa1.dxdz, photon_array.dxdz[:50])
    np.testing.assert_almost_equal(pa1.dydz, photon_array.dydz[:50])
    np.testing.assert_almost_equal(pa1.wavelength,
                                   photon_array.wavelength[:50])

    # Check assignAt
    pa2 = galsim.PhotonArray(100)
    pa2.assignAt(0, pa1)
    pa2.assignAt(50, pa1)
    np.testing.assert_almost_equal(pa2.x[:50], pa1.x)
    np.testing.assert_almost_equal(pa2.y[:50], pa1.y)
    np.testing.assert_almost_equal(pa2.flux[:50], pa1.flux)
    np.testing.assert_almost_equal(pa2.dxdz[:50], pa1.dxdz)
    np.testing.assert_almost_equal(pa2.dydz[:50], pa1.dydz)
    np.testing.assert_almost_equal(pa2.wavelength[:50], pa1.wavelength)
    np.testing.assert_almost_equal(pa2.x[50:], pa1.x)
    np.testing.assert_almost_equal(pa2.y[50:], pa1.y)
    np.testing.assert_almost_equal(pa2.flux[50:], pa1.flux)
    np.testing.assert_almost_equal(pa2.dxdz[50:], pa1.dxdz)
    np.testing.assert_almost_equal(pa2.dydz[50:], pa1.dydz)
    np.testing.assert_almost_equal(pa2.wavelength[50:], pa1.wavelength)

    # Error if it doesn't fit.
    assert_raises(ValueError, pa2.assignAt, 90, pa1)

    # Test some trivial usage of makeFromImage
    zero = galsim.Image(4, 4, init_value=0)
    photons = galsim.PhotonArray.makeFromImage(zero)
    print('photons = ', photons)
    assert len(photons) == 16
    np.testing.assert_array_equal(photons.flux, 0.)

    ones = galsim.Image(4, 4, init_value=1)
    photons = galsim.PhotonArray.makeFromImage(ones)
    print('photons = ', photons)
    assert len(photons) == 16
    np.testing.assert_almost_equal(photons.flux, 1.)

    tens = galsim.Image(4, 4, init_value=8)
    photons = galsim.PhotonArray.makeFromImage(tens, max_flux=5.)
    print('photons = ', photons)
    assert len(photons) == 32
    np.testing.assert_almost_equal(photons.flux, 4.)

    assert_raises(ValueError,
                  galsim.PhotonArray.makeFromImage,
                  zero,
                  max_flux=0.)
    assert_raises(ValueError,
                  galsim.PhotonArray.makeFromImage,
                  zero,
                  max_flux=-2)

    # Check some other errors
    undef = galsim.Image()
    assert_raises(galsim.GalSimUndefinedBoundsError, pa2.addTo, undef)

    # Check picklability again with non-zero values for everything
    do_pickle(photon_array)
Пример #9
0
def test_wavelength_sampler():
    nphotons = 1000
    obj = galsim.Exponential(flux=1.7, scale_radius=2.3)
    rng = galsim.UniformDeviate(1234)

    photon_array = obj.shoot(nphotons, rng)

    sed = galsim.SED(os.path.join(sedpath, 'CWW_E_ext.sed'), 'A',
                     'flambda').thin()
    bandpass = galsim.Bandpass(os.path.join(bppath, 'LSST_r.dat'), 'nm').thin()

    sampler = galsim.WavelengthSampler(sed, bandpass, rng)
    sampler.applyTo(photon_array)

    # Note: the underlying functionality of the sampleWavelengths function is tested
    # in test_sed.py.  So here we are really just testing that the wrapper class is
    # properly writing to the photon_array.wavelengths array.

    assert photon_array.hasAllocatedWavelengths()
    assert not photon_array.hasAllocatedAngles()

    print('mean wavelength = ', np.mean(photon_array.wavelength))
    print('min wavelength = ', np.min(photon_array.wavelength))
    print('max wavelength = ', np.max(photon_array.wavelength))

    assert np.min(photon_array.wavelength) > bandpass.blue_limit
    assert np.max(photon_array.wavelength) < bandpass.red_limit

    # This is a regression test based on the value at commit 134a119
    np.testing.assert_allclose(np.mean(photon_array.wavelength),
                               622.755128,
                               rtol=1.e-4)

    # If we use a flat SED (in photons/nm), then the mean sampled wavelength should very closely
    # match the bandpass effective wavelength.
    photon_array2 = galsim.PhotonArray(100000)
    sed2 = galsim.SED('1', 'nm', 'fphotons')
    sampler2 = galsim.WavelengthSampler(sed2, bandpass, rng)
    sampler2.applyTo(photon_array2)
    np.testing.assert_allclose(
        np.mean(photon_array2.wavelength),
        bandpass.effective_wavelength,
        rtol=0,
        atol=0.2,  # 2 Angstrom accuracy is pretty good
        err_msg="Mean sampled wavelength not close to effective_wavelength")

    # Test that using this as a surface op works properly.

    # First do the shooting and clipping manually.
    im1 = galsim.Image(64, 64, scale=1)
    im1.setCenter(0, 0)
    photon_array.flux[photon_array.wavelength < 600] = 0.
    photon_array.addTo(im1)

    # Make a dummy surface op that clips any photons with lambda < 600
    class Clip600(object):
        def applyTo(self, photon_array, local_wcs=None):
            photon_array.flux[photon_array.wavelength < 600] = 0.

    # Use (a new) sampler and clip600 as surface_ops in drawImage
    im2 = galsim.Image(64, 64, scale=1)
    im2.setCenter(0, 0)
    clip600 = Clip600()
    rng2 = galsim.BaseDeviate(1234)
    sampler2 = galsim.WavelengthSampler(sed, bandpass, rng2)
    obj.drawImage(im2,
                  method='phot',
                  n_photons=nphotons,
                  use_true_center=False,
                  surface_ops=[sampler2, clip600],
                  rng=rng2)
    print('sum = ', im1.array.sum(), im2.array.sum())
    np.testing.assert_array_equal(im1.array, im2.array)
Пример #10
0
def test_convolve():
    nphotons = 1000000

    obj = galsim.Gaussian(flux=1.7, sigma=2.3)
    rng = galsim.UniformDeviate(1234)
    pa1 = obj.shoot(nphotons, rng)
    pa2 = obj.shoot(nphotons, rng)

    # If not correlated then convolve is deterministic
    conv_x = pa1.x + pa2.x
    conv_y = pa1.y + pa2.y
    conv_flux = pa1.flux * pa2.flux * nphotons

    np.testing.assert_allclose(np.sum(pa1.flux), 1.7)
    np.testing.assert_allclose(np.sum(pa2.flux), 1.7)
    np.testing.assert_allclose(np.sum(conv_flux), 1.7 * 1.7)

    np.testing.assert_allclose(np.sum(pa1.x**2) / nphotons, 2.3**2, rtol=0.01)
    np.testing.assert_allclose(np.sum(pa2.x**2) / nphotons, 2.3**2, rtol=0.01)
    np.testing.assert_allclose(np.sum(conv_x**2) / nphotons,
                               2. * 2.3**2,
                               rtol=0.01)

    np.testing.assert_allclose(np.sum(pa1.y**2) / nphotons, 2.3**2, rtol=0.01)
    np.testing.assert_allclose(np.sum(pa2.y**2) / nphotons, 2.3**2, rtol=0.01)
    np.testing.assert_allclose(np.sum(conv_y**2) / nphotons,
                               2. * 2.3**2,
                               rtol=0.01)

    pa3 = galsim.PhotonArray(nphotons)
    pa3.assignAt(0, pa1)  # copy from pa1
    pa3.convolve(pa2)
    np.testing.assert_allclose(pa3.x, conv_x)
    np.testing.assert_allclose(pa3.y, conv_y)
    np.testing.assert_allclose(pa3.flux, conv_flux)

    # If one of them is correlated, it is still deterministic.
    pa3.assignAt(0, pa1)
    pa3.setCorrelated()
    pa3.convolve(pa2)
    np.testing.assert_allclose(pa3.x, conv_x)
    np.testing.assert_allclose(pa3.y, conv_y)
    np.testing.assert_allclose(pa3.flux, conv_flux)

    pa3.assignAt(0, pa1)
    pa3.setCorrelated(False)
    pa2.setCorrelated()
    pa3.convolve(pa2)
    np.testing.assert_allclose(pa3.x, conv_x)
    np.testing.assert_allclose(pa3.y, conv_y)
    np.testing.assert_allclose(pa3.flux, conv_flux)

    # But if both are correlated, then it's not this simple.
    pa3.assignAt(0, pa1)
    pa3.setCorrelated()
    assert pa3.isCorrelated()
    assert pa2.isCorrelated()
    pa3.convolve(pa2)
    with assert_raises(AssertionError):
        np.testing.assert_allclose(pa3.x, conv_x)
    with assert_raises(AssertionError):
        np.testing.assert_allclose(pa3.y, conv_y)
    np.testing.assert_allclose(np.sum(pa3.flux), 1.7 * 1.7)
    np.testing.assert_allclose(np.sum(pa3.x**2) / nphotons,
                               2 * 2.3**2,
                               rtol=0.01)
    np.testing.assert_allclose(np.sum(pa3.y**2) / nphotons,
                               2 * 2.3**2,
                               rtol=0.01)

    # Error to have different lengths
    pa4 = galsim.PhotonArray(50, pa1.x[:50], pa1.y[:50], pa1.flux[:50])
    assert_raises(galsim.GalSimError, pa1.convolve, pa4)
Пример #11
0
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)
Пример #12
0
def test_refract():
    ud = galsim.UniformDeviate(57721)
    for _ in range(1000):
        photon_array = galsim.PhotonArray(1000, flux=1)
        ud.generate(photon_array.dxdz)
        ud.generate(photon_array.dydz)
        photon_array.dxdz *= 1.2  # -0.6 to 0.6
        photon_array.dydz *= 1.2
        photon_array.dxdz -= 0.6
        photon_array.dydz -= 0.6
        # copy for testing later
        dxdz0 = np.array(photon_array.dxdz)
        dydz0 = np.array(photon_array.dydz)
        index_ratio = ud() * 4 + 0.25  # 0.25 to 4.25
        refract = galsim.Refraction(index_ratio)
        refract.applyTo(photon_array)

        # Triangle is length 1 in the z direction and length sqrt(dxdz**2+dydz**2)
        # in the 'r' direction.
        rsqr0 = dxdz0**2 + dydz0**2
        sintheta0 = np.sqrt(rsqr0) / np.sqrt(1 + rsqr0)
        # See if total internal reflection applies
        w = sintheta0 < index_ratio
        np.testing.assert_array_equal(photon_array.dxdz[~w], np.nan)
        np.testing.assert_array_equal(photon_array.dydz[~w], np.nan)
        np.testing.assert_array_equal(photon_array.flux, np.where(w, 1.0, 0.0))

        sintheta0 = sintheta0[w]
        dxdz0 = dxdz0[w]
        dydz0 = dydz0[w]
        dxdz1 = photon_array.dxdz[w]
        dydz1 = photon_array.dydz[w]
        rsqr1 = dxdz1**2 + dydz1**2
        sintheta1 = np.sqrt(rsqr1) / np.sqrt(1 + rsqr1)
        # Check Snell's law
        np.testing.assert_allclose(sintheta0, index_ratio * sintheta1)

        # Check azimuthal angle stays constant
        phi0 = np.arctan2(dydz0, dxdz0)
        phi1 = np.arctan2(dydz1, dxdz1)
        np.testing.assert_allclose(phi0, phi1)

        # Check plane of refraction is perpendicular to (0,0,1)
        np.testing.assert_allclose(np.dot(
            np.cross(
                np.stack([dxdz0, dydz0, -np.ones(len(dxdz0))], axis=1),
                np.stack([dxdz1, dydz1, -np.ones(len(dxdz1))], axis=1),
            ), [0, 0, 1]),
                                   0.0,
                                   rtol=0,
                                   atol=1e-13)

    # Try a wavelength dependent index_ratio
    index_ratio = lambda w: np.where(w < 1, 1.1, 2.2)
    photon_array = galsim.PhotonArray(100)
    ud.generate(photon_array.wavelength)
    ud.generate(photon_array.dxdz)
    ud.generate(photon_array.dydz)
    photon_array.dxdz *= 1.2  # -0.6 to 0.6
    photon_array.dydz *= 1.2
    photon_array.dxdz -= 0.6
    photon_array.dydz -= 0.6
    photon_array.wavelength *= 2  # 0 to 2
    dxdz0 = photon_array.dxdz.copy()
    dydz0 = photon_array.dydz.copy()

    refract_func = galsim.Refraction(index_ratio=index_ratio)
    refract_func.applyTo(photon_array)
    dxdz_func = photon_array.dxdz.copy()
    dydz_func = photon_array.dydz.copy()

    photon_array.dxdz = dxdz0.copy()
    photon_array.dydz = dydz0.copy()
    refract11 = galsim.Refraction(index_ratio=1.1)
    refract11.applyTo(photon_array)
    dxdz11 = photon_array.dxdz.copy()
    dydz11 = photon_array.dydz.copy()

    photon_array.dxdz = dxdz0.copy()
    photon_array.dydz = dydz0.copy()
    refract22 = galsim.Refraction(index_ratio=2.2)
    refract22.applyTo(photon_array)
    dxdz22 = photon_array.dxdz.copy()
    dydz22 = photon_array.dydz.copy()

    w = photon_array.wavelength < 1
    np.testing.assert_allclose(dxdz_func, np.where(w, dxdz11, dxdz22))
    np.testing.assert_allclose(dydz_func, np.where(w, dydz11, dydz22))
Пример #13
0
import galsim

# Make blank image
im = galsim.ImageF(31, 31, init_value=0)

# Set the coordinates so 0,0 refers to the central pixel.
#im.setCenter(0,0)
im.setCenter(0, 0)

# Make 80K photons with position 0,0
photons = galsim.PhotonArray(800000)

# """The PhotonArray class encapsulates the concept of a collection of photons incident on
# a detector.
# A PhotonArray object is not typically constructed directly by the user.  Rather, it is
# typically constructed as the return value of the `GSObject.shoot` method.
# At this point, the photons only have x,y,flux values.  Then there are a number of classes
# that perform various modifications to the photons such as giving them wavelengths or
# inclination angles or removing some due to fringing or vignetting.
# TODO: fringing, vignetting, and angles are not implemented yet, but we expect them to
# be implemented soon, so the above paragraph is a bit aspirational atm.
# Attributes
# ----------
# A PhotonArray instance has the following attributes, each of which is a numpy array:
# - x,y           the incidence positions at the top of the detector
# - flux          the flux of the photons
# - dxdz, dydz    the tangent of the inclination angles in each direction
# - wavelength    the wavelength of the photons
# Unlike most GalSim objects (but like Images), PhotonArrays are mutable.  It is permissible
# to write values to the above attributes with code like
#     >>> photon_array.x += numpy.random.random(1000) * 0.01