コード例 #1
0
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)
コード例 #2
0
ファイル: skyModel.py プロジェクト: LSSTDESC/imSim
 def angles(self):
     if self._angles is None:
         fratio = 1.234  # From https://www.lsst.org/scientists/keynumbers
         obscuration = 0.606  # (8.4**2 - 6.68**2)**0.5 / 8.4
         self._angles \
             = galsim.FRatioAngles(fratio, obscuration, self.randomNumbers)
     return self._angles
コード例 #3
0
ファイル: test_photon_array.py プロジェクト: sweverett/GalSim
def test_photon_io():
    """Test the ability to read and write photons to a file
    """
    nphotons = 1000

    obj = galsim.Exponential(flux=1.7, scale_radius=2.3)
    rng = galsim.UniformDeviate(1234)
    image = obj.drawImage(method='phot',
                          n_photons=nphotons,
                          save_photons=True,
                          rng=rng)
    photons = image.photons
    assert photons.size() == len(photons) == nphotons

    with assert_raises(galsim.GalSimIncompatibleValuesError):
        obj.drawImage(method='phot',
                      n_photons=nphotons,
                      save_photons=True,
                      maxN=1.e5)

    file_name = 'output/photons1.dat'
    photons.write(file_name)

    photons1 = galsim.PhotonArray.read(file_name)

    assert photons1.size() == nphotons
    assert not photons1.hasAllocatedWavelengths()
    assert not photons1.hasAllocatedAngles()

    np.testing.assert_array_equal(photons1.x, photons.x)
    np.testing.assert_array_equal(photons1.y, photons.y)
    np.testing.assert_array_equal(photons1.flux, photons.flux)

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

    wave_sampler = galsim.WavelengthSampler(sed, bandpass, rng)
    angle_sampler = galsim.FRatioAngles(1.3, 0.3, rng)

    ops = [wave_sampler, angle_sampler]
    for op in ops:
        op.applyTo(photons)

    file_name = 'output/photons2.dat'
    photons.write(file_name)

    photons2 = galsim.PhotonArray.read(file_name)

    assert photons2.size() == nphotons
    assert photons2.hasAllocatedWavelengths()
    assert photons2.hasAllocatedAngles()

    np.testing.assert_array_equal(photons2.x, photons.x)
    np.testing.assert_array_equal(photons2.y, photons.y)
    np.testing.assert_array_equal(photons2.flux, photons.flux)
    np.testing.assert_array_equal(photons2.dxdz, photons.dxdz)
    np.testing.assert_array_equal(photons2.dydz, photons.dydz)
    np.testing.assert_array_equal(photons2.wavelength, photons.wavelength)
コード例 #4
0
ファイル: timing_tests.py プロジェクト: LSSTDESC/imSim
    def __init__(self, obs_md, seed, nxy=64, pixel_scale=0.2):
        self.psf = SNRdocumentPSF(obs_md.OpsimMetaData['FWHMgeom'])
        self._rng = galsim.UniformDeviate(seed)
        self.nxy = nxy
        self.pixel_scale = pixel_scale

        fratio = 1.234
        obscuration = 0.606
        angles = galsim.FRatioAngles(fratio, obscuration, self._rng)

        self.bandpass = gs_bandpasses(obs_md.bandpass)
        self.sed = galsim.SED(lambda x: 1, 'nm',
                              'flambda').withFlux(1., self.bandpass)
        waves = galsim.WavelengthSampler(sed=self.sed, bandpass=self.bandpass,
                                         rng=self._rng)
        self.surface_ops = (waves, angles)
コード例 #5
0
def test_surface_ops():

    # Based on test_sensor.py:test_wavelengths_and_angles, but massively simplified.

    rng = galsim.BaseDeviate(1234)

    fratio = 1.2
    obscuration = 0.2
    assigner = galsim.FRatioAngles(fratio, obscuration, rng=rng)

    sed = galsim.SED('CWW_E_ext.sed', 'nm', 'flambda').thin()
    bandpass = galsim.Bandpass('LSST_i.dat', 'nm').thin()
    sampler = galsim.WavelengthSampler(sed, bandpass, rng=rng)

    obj = galsim.Gaussian(flux=353, sigma=0.3)
    im = galsim.Image(63, 63, scale=1)
    check_dep(obj.drawImage,
              im,
              method='phot',
              surface_ops=[sampler, assigner],
              rng=rng,
              save_photons=True)

    rng.reset(1234)
    assigner.ud.reset(rng)
    sampler.rng.reset(rng)
    photons = check_dep(obj.makePhot, surface_ops=[sampler, assigner], rng=rng)
    assert photons == im.photons

    rng.reset(1234)
    assigner.ud.reset(rng)
    sampler.rng.reset(rng)
    _, photons2 = check_dep(obj.drawPhot,
                            image=im.copy(),
                            surface_ops=[sampler, assigner],
                            rng=rng)
    assert photons2 == im.photons
コード例 #6
0
def main(argv):
    """
    Make images to be used for characterizing the brighter-fatter effect
      - Each fits file is 5 x 5 postage stamps.
      - Each postage stamp is 40 x 40 pixels.
      - There are 3 sets of 5 images each.  The 5 images are at 5 different flux levels
      - The three sets are (bf_1) B-F off, (bf_2) B-F on, diffusion off, (bf_3) B-F and diffusion on
      - Each image is in output/bf_set/bf_nfile.fits, where set ranges from 1-3 and nfile ranges from 1-5.
    """
    logging.basicConfig(format="%(message)s", level=logging.INFO, stream=sys.stdout)
    logger = logging.getLogger("bf_plots")

    # Add the wavelength info
    bppath = "../../share/bandpasses/"
    sedpath = "../../share/"
    sed = galsim.SED(os.path.join(sedpath, 'CWW_E_ext.sed'), 'nm', 'flambda').thin()

    # Add the directions (seems to work - CL)
    fratio = 1.2
    obscuration = 0.2
    seed = 12345
    assigner = galsim.FRatioAngles(fratio, obscuration, seed)
    bandpass = galsim.Bandpass(os.path.join(bppath, 'LSST_r.dat'), 'nm').thin()
    rng3 = galsim.BaseDeviate(1234)
    sampler = galsim.WavelengthSampler(sed, bandpass, rng3)


    # Define some parameters we'll use below.
    # Normally these would be read in from some parameter file.

    nx_tiles = 10                   #
    ny_tiles = 10                   #
    stamp_xsize = 40                #
    stamp_ysize = 40                #

    random_seed = 6424512           #

    pixel_scale = 0.2               # arcsec / pixel
    sky_level = 0.01                # ADU / arcsec^2

    # Make output directory if not already present.
    if not os.path.isdir('output'):
        os.mkdir('output')

    gal_sigma = 0.2     # arcsec
    psf_sigma = 0.01     # arcsec
    pixel_scale = 0.2  # arcsec / pixel
    noise = 0.01        # standard deviation of the counts in each pixel

    shift_radius = 0.2              # arcsec (=pixels)

    logger.info('Starting bf_plots using:')
    logger.info('    - image with %d x %d postage stamps',nx_tiles,ny_tiles)
    logger.info('    - postage stamps of size %d x %d pixels',stamp_xsize,stamp_ysize)
    logger.info('    - Centroid shifts up to = %.2f pixels',shift_radius)

    rng = galsim.BaseDeviate(5678)    
    sensor1 = galsim.Sensor()
    sensor2 = galsim.SiliconSensor(rng=rng, diffusion_factor=0.0)
    sensor3 = galsim.SiliconSensor(rng=rng)

    for set in range(1,4):
        starttime = time.time()
        exec("sensor = sensor%d"%set)
        for nfile in range(1,6):
            # Make bf_x directory if not already present.
            if not os.path.isdir('output/bf_%d'%set):
                os.mkdir('output/bf_%d'%set)

            gal_file_name = os.path.join('output','bf_%d/bf_%d.fits'%(set,nfile))
            sex_file_name = os.path.join('output','bf_%d/bf_%d_SEX.fits.cat.reg'%(set,nfile))
            sexfile = open(sex_file_name, 'w')
            gal_flux = 2.0e5 * nfile    # total counts on the image
            # Define the galaxy profile
            gal = galsim.Gaussian(flux=gal_flux, sigma=gal_sigma)
            logger.debug('Made galaxy profile')

            # Define the PSF profile
            psf = galsim.Gaussian(flux=1., sigma=psf_sigma) # PSF flux should always = 1
            logger.debug('Made PSF profile')

            # This profile is placed with different orientations and noise realizations
            # at each postage stamp in the gal image.
            gal_image = galsim.ImageF(stamp_xsize * nx_tiles-1 , stamp_ysize * ny_tiles-1,
                                      scale=pixel_scale)
            psf_image = galsim.ImageF(stamp_xsize * nx_tiles-1 , stamp_ysize * ny_tiles-1,
                                      scale=pixel_scale)

            shift_radius_sq = shift_radius**2

            first_in_pair = True  # Make pairs that are rotated by 90 degrees

            k = 0
            for iy in range(ny_tiles):
                for ix in range(nx_tiles):
                    # The normal procedure for setting random numbers in GalSim is to start a new
                    # random number generator for each object using sequential seed values.
                    # This sounds weird at first (especially if you were indoctrinated by Numerical 
                    # Recipes), but for the boost random number generator we use, the "random" 
                    # number sequences produced from sequential initial seeds are highly uncorrelated.
                    # 
                    # The reason for this procedure is that when we use multiple processes to build
                    # our images, we want to make sure that the results are deterministic regardless
                    # of the way the objects get parcelled out to the different processes. 
                    #
                    # Of course, this script isn't using multiple processes, so it isn't required here.
                    # However, we do it nonetheless in order to get the same results as the config
                    # version of this demo script (demo5.yaml).
                    ud = galsim.UniformDeviate(random_seed+k)

                    # Any kind of random number generator can take another RNG as its first 
                    # argument rather than a seed value.  This makes both objects use the same
                    # underlying generator for their pseudo-random values.
                    #gd = galsim.GaussianDeviate(ud, sigma=gal_ellip_rms)

                    # The -1's in the next line are to provide a border of
                    # 1 pixel between postage stamps
                    b = galsim.BoundsI(ix*stamp_xsize+1 , (ix+1)*stamp_xsize-1, 
                                       iy*stamp_ysize+1 , (iy+1)*stamp_ysize-1)
                    sub_gal_image = gal_image[b]
                    sub_psf_image = psf_image[b]

                    # Great08 randomized the locations of the two galaxies in each pair,
                    # but for simplicity, we just do them in sequential postage stamps.

                    if first_in_pair:
                        # Use a random orientation:
                        beta = ud() * 2. * math.pi * galsim.radians

                        # Determine the ellipticity to use for this galaxy.
                        ellip = 0.0
                        first_in_pair = False
                    else:
                        # Use the previous ellip and beta + 90 degrees
                        beta += 90 * galsim.degrees
                        first_in_pair = True

                    # Make a new copy of the galaxy with an applied e1/e2-type distortion 
                    # by specifying the ellipticity and a real-space position angle
                    this_gal = gal#gal.shear(e=ellip, beta=beta)

                    # Apply a random shift_radius:
                    rsq = 2 * shift_radius_sq
                    while (rsq > shift_radius_sq):
                        dx = (2*ud()-1) * shift_radius
                        dy = (2*ud()-1) * shift_radius
                        rsq = dx**2 + dy**2

                    this_gal = this_gal.shift(dx,dy)
                    # Note that the shifted psf that we create here is purely for the purpose of being able
                    # to draw a separate, shifted psf image.  We do not use it when convolving the galaxy
                    # with the psf.
                    this_psf = psf.shift(dx,dy)

                    # Make the final image, convolving with the (unshifted) psf
                    final_gal = galsim.Convolve([psf,this_gal])

                    # Draw the image

                    if ix == 0 and iy == 0:
                        final_gal.drawImage(sub_gal_image, method = 'phot', sensor=sensor, surface_ops=[sampler, assigner], rng = rng, save_photons = True)
                        photon_file = os.path.join('output','bf_%d/bf_%d_nx_%d_ny_%d_photon_file.fits'%(set,nfile,ix,iy))
                        sub_gal_image.photons.write(photon_file)
                    else:
                        final_gal.drawImage(sub_gal_image, method = 'phot', sensor=sensor, surface_ops=[sampler, assigner], rng = rng)
                    
                    # Now add an appropriate amount of noise to get our desired S/N
                    # There are lots of definitions of S/N, but here is the one used by Great08
                    # We use a weighted integral of the flux:
                    #   S = sum W(x,y) I(x,y) / sum W(x,y)
                    #   N^2 = Var(S) = sum W(x,y)^2 Var(I(x,y)) / (sum W(x,y))^2
                    # Now we assume that Var(I(x,y)) is constant so
                    #   Var(I(x,y)) = noise_var
                    # We also assume that we are using a matched filter for W, so W(x,y) = I(x,y).
                    # Then a few things cancel and we find that
                    # S/N = sqrt( sum I(x,y)^2 / noise_var )
                    #
                    # The above procedure is encapsulated in the function image.addNoiseSNR which
                    # sets the flux appropriately given the variance of the noise model.
                    # In our case, noise_var = sky_level_pixel
                    sky_level_pixel = sky_level * pixel_scale**2
                    noise = galsim.PoissonNoise(ud, sky_level=sky_level_pixel)
                    #sub_gal_image.addNoiseSNR(noise, gal_signal_to_noise)

                    # Draw the PSF image
                    # No noise on PSF images.  Just draw it as is.
                    this_psf.drawImage(sub_psf_image)

                    # For first instance, measure moments
                    """
                    if ix==0 and iy==0:
                        psf_shape = sub_psf_image.FindAdaptiveMom()
                        temp_e = psf_shape.observed_shape.e
                        if temp_e > 0.0:
                            g_to_e = psf_shape.observed_shape.g / temp_e
                        else:
                            g_to_e = 0.0
                        logger.info('Measured best-fit elliptical Gaussian for first PSF image: ')
                        logger.info('  g1, g2, sigma = %7.4f, %7.4f, %7.4f (pixels)',
                                    g_to_e*psf_shape.observed_shape.e1,
                                    g_to_e*psf_shape.observed_shape.e2, psf_shape.moments_sigma)
                    """
                    x = b.center().x
                    y = b.center().y
                    logger.info('Galaxy (%d,%d): center = (%.0f,%0.f)  (e,beta) = (%.4f,%.3f)',
                                ix,iy,x,y,ellip,beta/galsim.radians)
                    k = k+1
                    sexline = 'circle %f %f %f\n'%(x+dx/pixel_scale,y+dy/pixel_scale,gal_sigma/pixel_scale)
                    sexfile.write(sexline)

            sexfile.close()
            logger.info('Done making images of postage stamps')

            # Now write the images to disk.
            #psf_image.write(psf_file_name)
            #logger.info('Wrote PSF file %s',psf_file_name)

            gal_image.write(gal_file_name)
            logger.info('Wrote image to %r',gal_file_name)  # using %r adds quotes around filename for us

        finishtime = time.time()
        print("Time to complete set %d = %.2f seconds\n"%(set, finishtime-starttime))
コード例 #7
0
def test_sensor_wavelengths_and_angles():

    print('Starting test_wavelengths_and_angles')
    sys.stdout.flush()

    bppath = os.path.join(galsim.meta_data.share_dir, "bandpasses")
    sedpath = os.path.join(galsim.meta_data.share_dir, "SEDs")
    sed = galsim.SED(os.path.join(sedpath, 'CWW_E_ext.sed'), 'nm', 'flambda').thin()

    # Add the directions (not currently working?? seems to work - CL)
    fratio = 1.2
    obscuration = 0.2
    seed = 12345
    assigner = galsim.FRatioAngles(fratio, obscuration, seed)
    obj = galsim.Gaussian(flux=3539, sigma=0.3)

    if __name__ == "__main__":
        bands = ['r', 'i', 'z', 'y']
    else:
        bands = ['i'] # Only test the i band for nosetests

    for band in bands:
        bandpass = galsim.Bandpass(os.path.join(bppath, 'LSST_%s.dat'%band), 'nm').thin()
        rng3 = galsim.BaseDeviate(1234)
        sampler = galsim.WavelengthSampler(sed, bandpass, rng3)
        rng4 = galsim.BaseDeviate(5678)
        silicon = galsim.SiliconSensor(rng=rng4, diffusion_factor=0.0)

        # We'll draw the same object using SiliconSensor
        im1 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=silicon, no wavelengths
        im2 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=silicon, with wavelengths
        im3 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=silicon, with angles
        im4 = galsim.ImageD(64, 64, scale=0.3)  # Will use sensor=silicon, with wavelengths, angles

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

        # Use photon shooting first
        obj.drawImage(im1, method='phot', sensor=silicon, rng=rng1)
        obj.drawImage(im2, method='phot', sensor=silicon, surface_ops=[sampler], rng=rng2)
        obj.drawImage(im3, method='phot', sensor=silicon, surface_ops=[assigner], rng=rng3)
        obj.drawImage(im4, method='phot', sensor=silicon, surface_ops=[sampler, assigner], rng=rng4)

        r1 = im1.calculateMomentRadius(flux=obj.flux)
        r2 = im2.calculateMomentRadius(flux=obj.flux)
        r3 = im3.calculateMomentRadius(flux=obj.flux)
        r4 = im4.calculateMomentRadius(flux=obj.flux)
        print('Testing Wavelength and Angle sampling - %s band'%band)
        print('Flux = %.0f:                sum        peak          radius'%obj.flux)
        print('No lamb, no angles:         %.1f     %.2f       %f'%(
                im1.array.sum(),im1.array.max(), r1))
        print('W/ lamb, no angles:         %.1f     %.2f       %f'%(
                im2.array.sum(),im2.array.max(), r2))
        print('No lamb, w/ angles:         %.1f     %.2f       %f'%(
                im3.array.sum(),im3.array.max(), r3))
        print('W/ lamb, w/ angles:         %.1f     %.2f       %f'%(
                im4.array.sum(),im4.array.max(), r4))

        # r4 should be greater than r1 with wavelengths and angles turned on.
        sigma_r = 1. / np.sqrt(obj.flux) * im1.scale
        print('check r4 > r1 due to added wavelengths and angles')
        print('r1 = %f, r4 = %f, 2*sigma_r = %f'%(r1,r4,2.*sigma_r))
        assert r4 > r1

        # Now check fft
        obj.drawImage(im1, method='fft', sensor=silicon, rng=rng1)
        obj.drawImage(im2, method='fft', sensor=silicon, surface_ops=[sampler], rng=rng2)
        obj.drawImage(im3, method='fft', sensor=silicon, surface_ops=[assigner], rng=rng3)
        obj.drawImage(im4, method='fft', sensor=silicon, surface_ops=[sampler, assigner], rng=rng4)

        r1 = im1.calculateMomentRadius(flux=obj.flux)
        r2 = im2.calculateMomentRadius(flux=obj.flux)
        r3 = im3.calculateMomentRadius(flux=obj.flux)
        r4 = im4.calculateMomentRadius(flux=obj.flux)
        print('Testing Wavelength and Angle sampling - %s band'%band)
        print('Flux = %.0f:                sum        peak          radius'%obj.flux)
        print('No lamb, no angles:         %.1f     %.2f       %f'%(
                im1.array.sum(),im1.array.max(), r1))
        print('W/ lamb, no angles:         %.1f     %.2f       %f'%(
                im2.array.sum(),im2.array.max(), r2))
        print('No lamb, w/ angles:         %.1f     %.2f       %f'%(
                im3.array.sum(),im3.array.max(), r3))
        print('W/ lamb, w/ angles:         %.1f     %.2f       %f'%(
                im4.array.sum(),im4.array.max(), r4))

        # r4 should be greater than r1 with wavelengths and angles turned on.
        sigma_r = 1. / np.sqrt(obj.flux) * im1.scale
        print('check r4 > r1 due to added wavelengths and angles')
        print('r1 = %f, r4 = %f, 2*sigma_r = %f'%(r1,r4,2.*sigma_r))
        assert r4 > r1
コード例 #8
0
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
コード例 #9
0
ファイル: test_photon_array.py プロジェクト: esheldon/GalSim
def test_photon_angles():
    """Test the photon_array function
    """
    # Make a photon array
    seed = 12345
    ud = galsim.UniformDeviate(seed)
    gal = galsim.Sersic(n=4, half_light_radius=1)
    photon_array = gal.SBProfile.shoot(100000, ud)

    # Add the directions (N.B. using the same seed as for generating the photon array
    # above.  The fact that it is the same does not matter here; the testing routine
    # only needs to have a definite seed value so the consistency of the results with
    # expectations can be evaluated precisely
    fratio = 1.2
    obscuration = 0.2

    # rng can be None, an existing BaseDeviate, or an integer
    for rng in [ None, ud, 12345 ]:
        assigner = galsim.FRatioAngles(fratio, obscuration, rng)
        assigner.applyTo(photon_array)

        dxdz = photon_array.getDXDZArray()
        dydz = photon_array.getDYDZArray()

        phi = np.arctan2(dydz,dxdz)
        tantheta = np.sqrt(np.square(dxdz) + np.square(dydz))
        sintheta = np.sin(np.arctan(tantheta))

        # Check that the values are within the ranges expected
        # (The test on phi really can't fail, because it is only testing the range of the
        # arctan2 function.)
        np.testing.assert_array_less(-phi, np.pi, "Azimuth angles outside possible range")
        np.testing.assert_array_less(phi, np.pi, "Azimuth angles outside possible range")

        fov_angle = np.arctan(0.5 / fratio)
        obscuration_angle = obscuration * fov_angle
        np.testing.assert_array_less(-sintheta, -np.sin(obscuration_angle),
                                     "Inclination angles outside possible range")
        np.testing.assert_array_less(sintheta, np.sin(fov_angle),
                                     "Inclination angles outside possible range")

    # Compare these slopes with the expected distributions (uniform in azimuth 
    # over all azimiths and uniform in sin(inclination) over the range of
    # allowed inclinations
    # Only test this for the last one, so we make sure we have a deterministic result.
    # (The above tests should be reliable even for the default rng.)
    phi_histo, phi_bins = np.histogram(phi, bins=100)
    sintheta_histo, sintheta_bins = np.histogram(sintheta, bins=100)
    phi_ref = float(np.sum(phi_histo))/phi_histo.size
    sintheta_ref = float(np.sum(sintheta_histo))/sintheta_histo.size

    chisqr_phi = np.sum(np.square(phi_histo - phi_ref)/phi_ref) / phi_histo.size
    chisqr_sintheta = np.sum(np.square(sintheta_histo - sintheta_ref) /
                             sintheta_ref) / sintheta_histo.size

    print('chisqr_phi = ',chisqr_phi)
    print('chisqr_sintheta = ',chisqr_sintheta)
    assert 0.9 < chisqr_phi < 1.1, "Distribution in azimuth is not nearly uniform"
    assert 0.9 < chisqr_sintheta < 1.1, "Distribution in sin(inclination) is not nearly uniform"

    # Try some invalid inputs
    try:
        np.testing.assert_raises(ValueError, galsim.FRatioAngles, fratio=-0.3)
        np.testing.assert_raises(ValueError, galsim.FRatioAngles, fratio=1.2, obscuration=-0.3)
        np.testing.assert_raises(ValueError, galsim.FRatioAngles, fratio=1.2, obscuration=1.0)
        np.testing.assert_raises(ValueError, galsim.FRatioAngles, fratio=1.2, obscuration=1.9)
    except ImportError:
        pass
コード例 #10
0
sky_sed_file = 'sky_sed.txt'
band = 'r'
bandpass_file = '%s_band.txt' % band

gs_sed = galsim.SED(sky_sed_file, wave_type='nm',
                    flux_type='flambda').thin(rel_err=0.1)
gs_bandpass = galsim.Bandpass(bandpass_file, wave_type='nm').thin(rel_err=0.1)
print('made sed, bandpass')

seed = 140101
rng = galsim.UniformDeviate(seed)

waves = galsim.WavelengthSampler(sed=gs_sed, bandpass=gs_bandpass, rng=rng)
fratio = 1.234
obscuration = 0.606
angles = galsim.FRatioAngles(fratio, obscuration, rng)

treering_func = galsim.SiliconSensor.simple_treerings(0.26, 47.)
treering_center = galsim.PositionD(0, 0)

skyCounts = 800.
print('skyCounts = ', skyCounts)
bundles_per_pix = 0  # Note: bundling doesn't work right if using tree rings.
chunk_size = int(1e7)

image = galsim.ImageF(2000, 500)
print('image bounds = ', image.bounds)

num_photons = int(np.prod(image.array.shape) * skyCounts)
print('num_photons = ', num_photons)
コード例 #11
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)
コード例 #12
0
def main():
    pr = cProfile.Profile()
    pr.enable()

    rng = galsim.UniformDeviate(8675309)

    wcs = galsim.FitsWCS('../tests/des_data/DECam_00154912_12_header.fits')
    image = galsim.Image(xsize, ysize, wcs=wcs)
    bandpass = galsim.Bandpass('LSST_r.dat', wave_type='nm').thin(0.1)
    base_wavelength = bandpass.effective_wavelength

    angles = galsim.FRatioAngles(fratio, obscuration, rng)
    sensor = galsim.SiliconSensor(rng=rng, nrecalc=nrecalc)

    # Figure out the local_sidereal time from the observation location and time.
    lsst_lat = '-30:14:23.76'
    lsst_long = '-70:44:34.67'
    obs_time = '2012-11-24 03:37:25.023964'  # From the header of the wcs file

    obs = astropy.time.Time(obs_time, scale='utc', location=(lsst_long + 'd', lsst_lat + 'd'))
    local_sidereal_time = obs.sidereal_time('apparent').value

    # Convert the ones we need below to galsim Angles.
    local_sidereal_time *= galsim.hours
    lsst_lat = galsim.Angle.from_dms(lsst_lat)

    times = []
    mem = []
    phot = []

    t0 = time.clock()
    for iobj in range(nobjects):
        sys.stderr.write('.')
        psf = make_psf(rng)
        gal = make_gal(rng)
        obj = galsim.Convolve(psf, gal)

        sed = get_sed(rng)
        waves = galsim.WavelengthSampler(sed=sed, bandpass=bandpass, rng=rng)

        image_pos = get_pos(rng)
        sky_coord = wcs.toWorld(image_pos)
        bounds, offset = calculate_bounds(obj, image_pos, image)

        ha = local_sidereal_time - sky_coord.ra
        dcr = galsim.PhotonDCR(base_wavelength=base_wavelength,
                               obj_coord=sky_coord, HA=ha, latitude=lsst_lat)

        surface_ops = (waves, angles, dcr)

        obj.drawImage(method='phot', image=image[bounds], offset=offset,
                      rng=rng, sensor=sensor,
                      surface_ops=surface_ops)

        times.append(time.clock() - t0)
        mem.append(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
        phot.append(obj.flux)

    image.write('phot.fits')
    phot = np.cumsum(phot)
    make_plots(times, mem, phot)

    pr.disable()
    ps = pstats.Stats(pr).sort_stats('time')
    ps.print_stats(20)
コード例 #13
0
    def drawObject(self, gsObject):
        """
        Draw an astronomical object on all of the relevant FITS files.

        @param [in] gsObject is an instantiation of the GalSimCelestialObject
        class carrying all of the information for the object whose image
        is to be drawn

        @param [out] outputString is a string denoting which detectors the astronomical
        object illumines, suitable for output in the GalSim InstanceCatalog
        """

        # find the detectors which the astronomical object illumines
        outputString, \
        detectorList, \
        centeredObj = self.findAllDetectors(gsObject)

        # Make sure this object is marked as "drawn" since we only
        # care that this method has been called for this object.
        self.drawn_objects.add(gsObject.uniqueId)

        # Compute the realized object fluxes (as drawn from the
        # corresponding Poisson distribution) for each band and return
        # right away if all values are zero in order to save compute.
        fluxes = [gsObject.flux(bandpassName) for bandpassName in self.bandpassDict]
        realized_fluxes = [galsim.PoissonDeviate(self._rng, mean=f)() for f in fluxes]
        if all([f == 0 for f in realized_fluxes]):
            return outputString

        if len(detectorList) == 0:
            # there is nothing to draw
            return outputString

        self._addNoiseAndBackground(detectorList)

        # Create a surface operation to sample incident angles and a
        # galsim.SED object for sampling the wavelengths of the
        # incident photons.
        fratio = 1.234  # From https://www.lsst.org/scientists/keynumbers
        obscuration = 0.606  # (8.4**2 - 6.68**2)**0.5 / 8.4
        angles = galsim.FRatioAngles(fratio, obscuration, self._rng)

        sed_lut = galsim.LookupTable(x=gsObject.sed.wavelen,
                                     f=gsObject.sed.flambda)
        gs_sed = galsim.SED(sed_lut, wave_type='nm', flux_type='flambda',
                            redshift=0.)

        local_hour_angle \
            = self.getHourAngle(self.obs_metadata.mjd.TAI,
                                self.obs_metadata.pointingRA)*galsim.degrees
        obs_latitude = self.observatory.getLatitude().asDegrees()*galsim.degrees
        ra_obs, dec_obs = observedFromPupilCoords(gsObject.xPupilRadians,
                                                  gsObject.yPupilRadians,
                                                  obs_metadata=self.obs_metadata)
        obj_coord = galsim.CelestialCoord(ra_obs*galsim.degrees,
                                          dec_obs*galsim.degrees)
        for bandpassName, realized_flux in zip(self.bandpassDict, realized_fluxes):
            gs_bandpass = self.gs_bandpass_dict[bandpassName]
            waves = galsim.WavelengthSampler(sed=gs_sed, bandpass=gs_bandpass,
                                             rng=self._rng)
            dcr = galsim.PhotonDCR(base_wavelength=gs_bandpass.effective_wavelength,
                                   HA=local_hour_angle,
                                   latitude=obs_latitude,
                                   obj_coord=obj_coord)

            # Set the object flux to the value realized from the
            # Poisson distribution.
            obj = centeredObj.withFlux(realized_flux)

            for detector in detectorList:

                name = self._getFileName(detector=detector,
                                         bandpassName=bandpassName)

                xPix, yPix = detector.camera_wrapper\
                   .pixelCoordsFromPupilCoords(gsObject.xPupilRadians,
                                               gsObject.yPupilRadians,
                                               chipName=detector.name,
                                               obs_metadata=self.obs_metadata)

                # Ensure the rng used by the sensor object is set to the desired state.
                self.sensor[detector.name].rng.reset(self._rng)
                surface_ops = [waves, dcr, angles]

                # Desired position to draw the object.
                image_pos = galsim.PositionD(xPix, yPix)

                # Find a postage stamp region to draw onto.  Use (sky
                # noise)/3. as the nominal minimum surface brightness
                # for rendering an extended object.
                keep_sb_level = np.sqrt(self.sky_bg_per_pixel)/3.
                bounds = self.getStampBounds(gsObject, realized_flux, image_pos,
                                             keep_sb_level, 3*keep_sb_level)

                # Ensure the bounds of the postage stamp lie within the image.
                bounds = bounds & self.detectorImages[name].bounds

                if bounds.isDefined():
                    # offset is relative to the "true" center of the postage stamp.
                    offset = image_pos - bounds.true_center

                    obj.drawImage(method='phot',
                                  offset=offset,
                                  rng=self._rng,
                                  maxN=int(1e6),
                                  image=self.detectorImages[name][bounds],
                                  sensor=self.sensor[detector.name],
                                  surface_ops=surface_ops,
                                  add_to_image=True,
                                  poisson_flux=False,
                                  gain=detector.photParams.gain)

                    # If we are writing centroid files,store the entry.
                    if self.centroid_base_name is not None:
                        centroid_tuple = (detector.fileName, bandpassName, gsObject.uniqueId,
                                          gsObject.flux(bandpassName), xPix, yPix)
                        self.centroid_list.append(centroid_tuple)

        self.write_checkpoint()
        return outputString
コード例 #14
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)