Beispiel #1
0
 def test_SNRdocumentPSF(self):
     fwhm_in = 0.3
     pixel_scale = 0.2
     psf_gen = SNRdocumentPSF(fwhm=fwhm_in, pixel_scale=pixel_scale)
     psf = psf_gen._getPSF()
     image = galsim.ImageD(256, 256, scale=pixel_scale)
     image = psf.drawImage(image)
     self.verify_analytic_fwhm(fwhm_in, pixel_scale, image.array)
class testGalSimStars(GalSimStars):
    #only draw images in the u and g band for speed
    bandpassNames = ['u','g']

    #convolve with a PSF; note that galaxies are not convolved with a PSF
    #PSF defined in galSimInterface/galSimUtilities.py
    PSF = SNRdocumentPSF()
Beispiel #3
0
    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)
Beispiel #4
0
    def testFwhmOfImage(self):
        """
        Test that GalSim generates images with the expected Full Width at Half Maximum.
        """
        scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testFwhmOfImage-')
        catName = os.path.join(scratchDir, 'fwhm_test_Catalog.dat')
        imageRoot = os.path.join(scratchDir, 'fwhm_test_Image')
        dbFileName = os.path.join(scratchDir, 'fwhm_test_InputCatalog.dat')

        baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests',
                               'cameraData')

        # instantiate a test camera with pixel_scale = 0.02 arcsec/pixel
        camera = ReturnCamera(baseDir)

        detector = camera[0]
        detName = detector.getName()
        imageName = '%s_%s_u.fits' % (imageRoot, detName)

        obs = ObservationMetaData(pointingRA=75.0,
                                  pointingDec=-12.0,
                                  boundType='circle',
                                  boundLength=4.0,
                                  rotSkyPos=33.0,
                                  mjd=49250.0)

        create_text_catalog(obs,
                            dbFileName,
                            np.array([3.0]),
                            np.array([1.0]),
                            mag_norm=[13.0])

        db = fwhmFileDBObj(dbFileName, runtable='test')

        for fwhm in (0.1, 0.14):

            cat = fwhmCat(db, obs_metadata=obs)
            cat.camera_wrapper = GalSimCameraWrapper(camera)

            psf = SNRdocumentPSF(fwhm=fwhm, pixel_scale=0.02)
            cat.setPSF(psf)

            cat.write_catalog(catName)
            cat.write_images(nameRoot=imageRoot)

            self.verify_fwhm(imageName, fwhm, 0.02)

            if os.path.exists(catName):
                os.unlink(catName)

            if os.path.exists(imageName):
                os.unlink(imageName)

        if os.path.exists(dbFileName):
            os.unlink(dbFileName)
        if os.path.exists(scratchDir):
            shutil.rmtree(scratchDir)
class testGalSimGalaxiesNoiseless(GalSimGalaxies):
    #only draw images for u and g bands (for speed)
    bandpassNames = ['u', 'g']

    #If you want to use the LSST camera, uncomment the line below.
    #You can similarly assign any camera object you want here
    #camera = LsstSimMapper().camera

    PSF = SNRdocumentPSF()
Beispiel #6
0
def make_psf(psf_name, obs_md, log_level='WARN', rng=None, **kwds):
    """
    Make the requested PSF object.

    Parameters
    ----------
    psf_name: str
        Either "DoubleGaussian", "Kolmogorov", or "Atmospheric".
        The name is case-insensitive.
    obs_md: lsst.sims.utils.ObservationMetaData
        Metadata associated with the visit, e.g., pointing direction,
        observation time, seeing, etc..
    log_level: str ['WARN']
        Logging level ('DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL').
    rng: galsim.BaseDeviate
        Instance of the galsim.baseDeviate random number generator.
    **kwds: **dict
        Additional keyword arguments to pass to the AtmosphericPSF,
        i.e., screen_size(=819.2) and screen_scale(=0.1).

    Returns
    -------
    lsst.sims.GalSimInterface.PSFbase: Instance of a subclass of PSFbase.
    """
    if psf_name.lower() == 'doublegaussian':
        return SNRdocumentPSF(obs_md.OpsimMetaData['FWHMgeom'])

    rawSeeing = obs_md.OpsimMetaData['rawSeeing']

    my_airmass = airmass(obs_md.OpsimMetaData['altitude'])

    if psf_name.lower() == 'kolmogorov':
        psf = Kolmogorov_and_Gaussian_PSF(my_airmass,
                                          rawSeeing=rawSeeing,
                                          band=obs_md.bandpass)
    elif psf_name.lower() == 'atmospheric':
        if rng is None:
            # Use the 'seed' value from the instance catalog for the rng
            # used by the atmospheric PSF.
            rng = galsim.UniformDeviate(obs_md.OpsimMetaData['seed'])
        if 'gaussianFWHM' not in kwds:
            # Retrieve the additional instrumental PSF FWHM from the
            # imSim config file.
            config = get_config()
            kwds['gaussianFWHM'] = config['psf']['gaussianFWHM']
        logger = get_logger(log_level, 'psf')
        psf = AtmosphericPSF(airmass=my_airmass,
                             rawSeeing=rawSeeing,
                             band=obs_md.bandpass,
                             rng=rng,
                             logger=logger,
                             **kwds)
    return psf
Beispiel #7
0
    def testPSF(self):
        """
        This method will test that SNRdocumentPSF returns a PSF
        with the correct Full Width at Half Max
        """

        fwhm = 0.4  # in arc-seconds; make sure that it divides evenly by scale, so that rounding
        # half integer numbers of pixels does not affect the unit test

        scale = 0.1  # arc-seconds per pixel

        psf = SNRdocumentPSF(fwhm=fwhm)
        image = psf._cached_psf.drawImage(scale=scale)
        xCenter = (image.getXMax() + image.getXMin()) / 2
        yCenter = (image.getYMax() + image.getYMin()) / 2

        maxValue = image(xCenter,
                         yCenter)  # because the default is to center GSObjects
        halfDex = int(np.round(
            0.5 * fwhm /
            scale))  # the distance from the center corresponding to FWHM

        # Test that pixel combinations bracketing the expected FWHM value behave
        # the way we expect them to
        midP1 = image(xCenter + halfDex + 1, yCenter)
        midM1 = image(xCenter + halfDex - 1, yCenter)
        msg = '%e is not > %e ' % (midM1, 0.5 * maxValue)
        self.assertGreater(midM1, 0.5 * maxValue, msg=msg)
        msg = '%e is not < %e ' % (midP1, 0.5 * maxValue)
        self.assertLess(midP1, 0.5 * maxValue, msg=msg)

        midP1 = image(xCenter - halfDex - 1, yCenter)
        midM1 = image(xCenter - halfDex + 1, yCenter)
        msg = '%e is not > %e ' % (midM1, 0.5 * maxValue)
        self.assertGreater(midM1, 0.5 * maxValue, msg=msg)
        msg = '%e is not < %e ' % (midP1, 0.5 * maxValue)
        self.assertLess(midP1, 0.5 * maxValue, msg=msg)

        midP1 = image(xCenter, yCenter + halfDex + 1)
        midM1 = image(xCenter, yCenter + halfDex - 1)
        msg = '%e is not > %e ' % (midM1, 0.5 * maxValue)
        self.assertGreater(midM1, 0.5 * maxValue, msg=msg)
        msg = '%e is not < %e ' % (midP1, 0.5 * maxValue)
        self.assertLess(midP1, 0.5 * maxValue, msg=msg)

        midP1 = image(xCenter, yCenter - halfDex - 1)
        midM1 = image(xCenter, yCenter - halfDex + 1)
        msg = '%e is not > %e ' % (midM1, 0.5 * maxValue)
        self.assertGreater(midM1, 0.5 * maxValue, msg=msg)
        msg = '%e is not < %e ' % (midP1, 0.5 * maxValue)
        self.assertLess(midP1, 0.5 * maxValue, msg=msg)
    def __init__(self, obs_metadata=None, detectors=None, bandpassDict=None,
                 noiseWrapper=None, epoch=None, seed=None, bf_strength=1):
        super(GalSimSiliconInterpeter, self)\
            .__init__(obs_metadata=obs_metadata, detectors=detectors,
                      bandpassDict=bandpassDict, noiseWrapper=noiseWrapper,
                      epoch=epoch, seed=seed)

        self.gs_bandpass_dict = {}
        for bandpassName in bandpassDict:
            bandpass = bandpassDict[bandpassName]
            index = np.where(bandpass.sb != 0)
            bp_lut = galsim.LookupTable(x=bandpass.wavelen[index],
                                        f=bandpass.sb[index])
            self.gs_bandpass_dict[bandpassName] \
                = galsim.Bandpass(bp_lut, wave_type='nm')

        self.sky_bg_per_pixel = None

        # Create a PSF that's fast to evaluate for the postage stamp
        # size calculation for extended objects in .getStampBounds.
        FWHMgeom = obs_metadata.OpsimMetaData['FWHMgeom']
        self._double_gaussian_psf = SNRdocumentPSF(FWHMgeom)

        # Save the parameters needed to create a Kolmogorov PSF for a
        # custom value of gsparams.folding_threshold.  That PSF will
        # to be used in the .getStampBounds function for bright stars.
        altRad = np.radians(obs_metadata.OpsimMetaData['altitude'])
        self._airmass = 1.0/np.sqrt(1.0-0.96*(np.sin(0.5*np.pi-altRad))**2)
        self._rawSeeing = obs_metadata.OpsimMetaData['rawSeeing']
        self._band = obs_metadata.bandpass

        # Save the default folding threshold for determining when to recompute
        # the PSF for bright point sources.
        self._ft_default = galsim.GSParams().folding_threshold

        # Create SiliconSensor objects for each detector.
        self.sensor = dict()
        for det in detectors:
            self.sensor[det.name] \
                = galsim.SiliconSensor(strength=bf_strength,
                                       treering_center=det.tree_rings.center,
                                       treering_func=det.tree_rings.func,
                                       transpose=True)
Beispiel #9
0
class testAgnCatalog(GalSimAgn):
    """
    Wraps the GalSimAgn class.  Adds columns to the output
    so that we can read the InstanceCatalog back in and verify that
    GalSim put the correct number of ADU in each FITS file.
    """
    bandpassNames = ['u', 'g', 'r']

    column_outputs = copy.deepcopy(GalSimAgn.column_outputs)
    column_outputs.remove('fitsFiles')
    column_outputs.append('magNorm')
    column_outputs.append('redshift')
    column_outputs.append('internalAv')
    column_outputs.append('internalRv')
    column_outputs.append('galacticAv')
    column_outputs.append('galacticRv')
    column_outputs.append('fitsFiles')

    PSF = SNRdocumentPSF()
Beispiel #10
0
class StarTimer(object):
    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)

    def get_sensor(self, nrecalc):
        return galsim.SiliconSensor(rng=self._rng, nrecalc=nrecalc)

    def timing(self, flux, sensor=None):
        point = galsim.DeltaFunction(flux=flux)
        star = galsim.Convolve(point*self.sed, self.psf._getPSF())

        image = galsim.Image(self.nxy, self.nxy)
        surface_ops = self.surface_ops if sensor is not None else ()
        t0 = time.clock()
        image = star.drawImage(method='phot', bandpass=self.bandpass,
                               image=image, scale=self.pixel_scale,
                               rng=self._rng, sensor=sensor,
                               surface_ops=surface_ops)
        return time.clock() - t0

    def flux_loop_timing(self, apply_model, nrecalc=10000, flux_min=10,
                         flux_max=1e5, nflux=8):
        sensor = self.get_sensor(nrecalc) if apply_model else None
        timing = OrderedDict()
        for flux in np.logspace(np.log10(flux_min), np.log10(flux_max), nflux):
            timing[flux] = self.timing(flux, sensor=sensor)
        return timing
Beispiel #11
0
class backgroundCatalog(testGalaxyCatalog):
    """
    Add sky background but no noise to testGalaxyCatalog
    """
    PSF = SNRdocumentPSF()
    noise_and_background = ExampleCCDNoise(addNoise=False, seed=42)
class testGalSimGalaxies(GalSimGalaxies):
    bandpassNames = ['u', 'g']

    PSF = SNRdocumentPSF()
Beispiel #13
0
    def testOutputWcsOfImage(self):
        """
        Test that, when GalSim generates an image, in encodes the WCS in a
        way afw can read.  This is done by creating an image,then reading
        it back in, getting its WCS, and comparing the pixel-to-sky conversion
        both for the read WCS and the original afw.cameraGeom.detector.
        Raise an exception if the median difference between the two is
        greater than 0.01 arcseconds.
        """
        scratchDir = os.path.join(getPackageDir('sims_GalSimInterface'),
                                  'tests', 'scratchSpace')
        catName = os.path.join(scratchDir, 'outputWcs_test_Catalog.dat')
        imageRoot = os.path.join(scratchDir, 'outputWcs_test_Image')
        dbFileName = os.path.join(scratchDir,
                                  'outputWcs_test_InputCatalog.dat')

        baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests',
                               'cameraData')
        camera = ReturnCamera(baseDir)

        detector = camera[0]
        detName = detector.getName()
        imageName = '%s_%s_u.fits' % (imageRoot, detName)

        nSamples = 3
        rng = np.random.RandomState(42)
        pointingRaList = rng.random_sample(nSamples) * 360.0
        pointingDecList = rng.random_sample(nSamples) * 180.0 - 90.0
        rotSkyPosList = rng.random_sample(nSamples) * 360.0

        for raPointing, decPointing, rotSkyPos in \
            zip(pointingRaList, pointingDecList, rotSkyPosList):

            obs = ObservationMetaData(pointingRA=raPointing,
                                      pointingDec=decPointing,
                                      boundType='circle',
                                      boundLength=4.0,
                                      rotSkyPos=rotSkyPos,
                                      mjd=49250.0)

            fwhm = 0.7
            create_text_catalog(obs, dbFileName, np.array([3.0]),
                                np.array([1.0]))

            db = outputWcsFileDBObj(dbFileName, runtable='test')

            cat = outputWcsCat(db, obs_metadata=obs)
            cat.camera = camera

            psf = SNRdocumentPSF(fwhm=fwhm)
            cat.setPSF(psf)

            cat.write_catalog(catName)
            cat.write_images(nameRoot=imageRoot)

            # 20 March 2017
            # the 'try' block is how it worked in SWIG;
            # the 'except' block is how it works in pybind11
            try:
                exposure = afwImage.ExposureD_readFits(imageName)
            except AttributeError:
                exposure = afwImage.ExposureD.readFits(imageName)

            wcs = exposure.getWcs()

            xxTestList = []
            yyTestList = []

            raImage = []
            decImage = []

            for xx in np.arange(0.0, 4001.0, 100.0):
                for yy in np.arange(0.0, 4001.0, 100.0):
                    xxTestList.append(xx)
                    yyTestList.append(yy)

                    pt = afwGeom.Point2D(xx, yy)
                    skyPt = wcs.pixelToSky(pt).getPosition()
                    raImage.append(skyPt.getX())
                    decImage.append(skyPt.getY())

            xxTestList = np.array(xxTestList)
            yyTestList = np.array(yyTestList)

            raImage = np.radians(np.array(raImage))
            decImage = np.radians(np.array(decImage))

            raControl, \
            decControl = _raDecFromPixelCoords(xxTestList, yyTestList,
                                               [detector.getName()]*len(xxTestList),
                                               camera=camera, obs_metadata=obs,
                                               epoch=2000.0)

            errorList = arcsecFromRadians(
                haversine(raControl, decControl, raImage, decImage))

            medianError = np.median(errorList)
            msg = 'medianError was %e' % medianError
            self.assertLess(medianError, 0.01, msg=msg)

            if os.path.exists(catName):
                os.unlink(catName)
            if os.path.exists(dbFileName):
                os.unlink(dbFileName)
            if os.path.exists(imageName):
                os.unlink(imageName)
    def testGalSimPhoSimCat(self):
        """
        Run a GalSimPhoSim catalog on some data. Then, generate an ordinary PhoSim catalog using
        the same data.  Verify that the two resulting PhoSim catalogs are identical.
        """

        galsim_cat_name = os.path.join(self.dataDir,
                                       'galSimPhoSim_galsim_cat.txt')
        phosim_cat_name = os.path.join(self.dataDir,
                                       'galSimPhoSim_phosim_cat.txt')
        galsim_image_root = os.path.join(self.dataDir, 'galSimPhoSim_images')
        db = fileDBObject(self.bulge_name,
                          dtype=self.dtype,
                          runtable='test_bulges',
                          idColKey='id')
        db.raColName = 'ra_deg'
        db.decColName = 'dec_deg'
        db.objectTypeId = 55

        gs_cat = GalSimPhoSimGalaxies(db, obs_metadata=self.obs)
        gs_cat.camera_wrapper = GalSimCameraWrapper(self.camera)
        gs_cat.bandpassNames = self.obs.bandpass
        gs_cat.PSF = SNRdocumentPSF()
        gs_cat.phoSimHeaderMap = {}
        gs_cat.write_catalog(galsim_cat_name)

        gs_cat_0 = gs_cat

        ps_cat = PhoSimCatalogSersic2D(db, obs_metadata=self.obs)
        ps_cat.phoSimHeaderMap = {}
        ps_cat.write_catalog(phosim_cat_name)

        db = fileDBObject(self.disk_name,
                          dtype=self.dtype,
                          runtable='test_disks',
                          idColKey='id')
        db.raColName = 'ra_deg'
        db.decColName = 'dec_deg'
        db.objectTypeId = 155

        gs_cat = GalSimPhoSimGalaxies(db, obs_metadata=self.obs)
        gs_cat.bandpassNames = self.obs.bandpass
        gs_cat.copyGalSimInterpreter(gs_cat_0)
        gs_cat.write_catalog(galsim_cat_name,
                             write_header=False,
                             write_mode='a')

        gs_cat_0 = gs_cat

        ps_cat = PhoSimCatalogSersic2D(db, obs_metadata=self.obs)
        ps_cat.write_catalog(phosim_cat_name,
                             write_header=False,
                             write_mode='a')

        db = fileDBObject(self.agn_name,
                          dtype=self.dtype,
                          runtable='test_agn',
                          idColKey='id')
        db.raColName = 'ra_deg'
        db.decColName = 'dec_deg'
        db.objectTypeId = 255

        gs_cat = GalSimPhoSimAgn(db, obs_metadata=self.obs)
        gs_cat.bandpassNames = self.obs.bandpass
        gs_cat.copyGalSimInterpreter(gs_cat_0)
        gs_cat.write_catalog(galsim_cat_name,
                             write_header=False,
                             write_mode='a')

        gs_cat_0 = gs_cat

        ps_cat = PhoSimCatalogZPoint(db, obs_metadata=self.obs)
        ps_cat.write_catalog(phosim_cat_name,
                             write_header=False,
                             write_mode='a')

        db = fileDBObject(self.star_name,
                          dtype=self.dtype,
                          runtable='test_agn',
                          idColKey='id')
        db.raColName = 'ra_deg'
        db.decColName = 'dec_deg'
        db.objectTypeId = 255

        gs_cat = GalSimPhoSimStars(db, obs_metadata=self.obs)
        gs_cat.bandpassNames = self.obs.bandpass
        gs_cat.copyGalSimInterpreter(gs_cat_0)
        gs_cat.write_catalog(galsim_cat_name,
                             write_header=False,
                             write_mode='a')

        ps_cat = PhoSimCatalogPoint(db, obs_metadata=self.obs)
        ps_cat.write_catalog(phosim_cat_name,
                             write_header=False,
                             write_mode='a')

        written_files = gs_cat.write_images(nameRoot=galsim_image_root)
        self.assertGreater(len(written_files), 0)
        for name in written_files:
            os.unlink(name)

        with open(galsim_cat_name, 'r') as galsim_input:
            with open(phosim_cat_name, 'r') as phosim_input:
                galsim_lines = galsim_input.readlines()
                phosim_lines = phosim_input.readlines()
                self.assertEqual(len(galsim_lines), len(phosim_lines))
                self.assertEqual(len(galsim_lines), 4 * self.n_objects + 7)
                for line in galsim_lines:
                    self.assertIn(line, phosim_lines)
                for line in phosim_lines:
                    self.assertIn(line, galsim_lines)

        if os.path.exists(galsim_cat_name):
            os.unlink(galsim_cat_name)

        if os.path.exists(phosim_cat_name):
            os.unlink(phosim_cat_name)
class testGalSimGalaxies(GalSimGalaxies):
    #only draw images for u and g bands (for speed)
    bandpassNames = ['u', 'g']

    PSF = SNRdocumentPSF()
Beispiel #16
0
    def testObjectPlacement(self):
        """
        Test that GalSim places objects on the correct pixel by drawing
        images, reading them in, and then comparing the flux contained in
        circles of 2 fwhm radii about the object's expected positions with
        the actual expected flux of the objects.
        """
        scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testObjectPlacement-')
        catName = os.path.join(scratchDir, 'placementCatalog.dat')
        imageRoot = os.path.join(scratchDir, 'placementImage')
        dbFileName = os.path.join(scratchDir, 'placementInputCatalog.dat')

        cameraDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData')
        camera = ReturnCamera(cameraDir)
        detector = camera[0]
        imageName = '%s_%s_u.fits' % (imageRoot, detector.getName())

        controlSed = Sed()
        controlSed.readSED_flambda(os.path.join(getPackageDir('sims_sed_library'),
                                                'flatSED', 'sed_flat.txt.gz'))

        uBandpass = Bandpass()
        uBandpass.readThroughput(os.path.join(getPackageDir('throughputs'),
                                              'baseline', 'total_u.dat'))

        controlBandpass = Bandpass()
        controlBandpass.imsimBandpass()

        ff = controlSed.calcFluxNorm(self.magNorm, uBandpass)
        controlSed.multiplyFluxNorm(ff)
        a_int, b_int = controlSed.setupCCMab()
        controlSed.addCCMDust(a_int, b_int, A_v=0.1, R_v=3.1)

        nSamples = 3
        rng = np.random.RandomState(42)
        pointingRaList = rng.random_sample(nSamples)*360.0
        pointingDecList = rng.random_sample(nSamples)*180.0 - 90.0
        rotSkyPosList = rng.random_sample(nSamples)*360.0
        fwhmList = rng.random_sample(nSamples)*1.0 + 0.3

        actualCounts = None

        for pointingRA, pointingDec, rotSkyPos, fwhm in \
        zip(pointingRaList, pointingDecList, rotSkyPosList, fwhmList):

            obs = ObservationMetaData(pointingRA=pointingRA,
                                      pointingDec=pointingDec,
                                      boundType='circle',
                                      boundLength=4.0,
                                      mjd=49250.0,
                                      rotSkyPos=rotSkyPos)

            xDisplacementList = rng.random_sample(nSamples)*60.0-30.0
            yDisplacementList = rng.random_sample(nSamples)*60.0-30.0
            create_text_catalog(obs, dbFileName, xDisplacementList, yDisplacementList,
                                mag_norm=[self.magNorm]*len(xDisplacementList))
            db = placementFileDBObj(dbFileName, runtable='test')
            cat = placementCatalog(db, obs_metadata=obs)
            cat.camera_wrapper = GalSimCameraWrapper(camera)
            if actualCounts is None:
                actualCounts = controlSed.calcADU(uBandpass, cat.photParams)

            psf = SNRdocumentPSF(fwhm=fwhm)
            cat.setPSF(psf)

            cat.write_catalog(catName)
            cat.write_images(nameRoot=imageRoot)

            objRaList = []
            objDecList = []
            with open(catName, 'r') as inFile:
                for line in inFile:
                    if line[0] != '#':
                        words = line.split(';')
                        objRaList.append(np.radians(np.float(words[2])))
                        objDecList.append(np.radians(np.float(words[3])))

            objRaList = np.array(objRaList)
            objDecList = np.array(objDecList)

            self.assertGreater(len(objRaList), 0)  # make sure we aren't testing
                                                   # an empty catalog/image

            self.check_placement(imageName, objRaList, objDecList,
                                 [fwhm]*len(objRaList),
                                 np.array([actualCounts]*len(objRaList)),
                                 cat.photParams.gain, detector, camera, obs, epoch=2000.0)

            if os.path.exists(dbFileName):
                os.unlink(dbFileName)
            if os.path.exists(catName):
                os.unlink(catName)
            if os.path.exists(imageName):
                os.unlink(imageName)

        if os.path.exists(scratchDir):
            shutil.rmtree(scratchDir)
Beispiel #17
0
class noisyCatalog(testGalaxyCatalog):
    """
    Adds a noise and sky background wrapper to testGalaxyCatalog
    """
    PSF = SNRdocumentPSF()
    noise_and_background = ExampleCCDNoise(seed=42)
Beispiel #18
0
def main(file, psf, outdir):
    """
    Drive GalSim to simulate the LSST.
    """
    # Setup a parser to take command line arguments

    config = desc.imsim.read_config(None)

    logger = desc.imsim.get_logger("INFO")

    # Get the number of rows to read from the instance file.  Use
    # default if not specified.

    numRows = None
    sensor = None
    # The PhoSim instance file contains both pointing commands and
    # objects.  The parser will split them and return a both phosim
    # command dictionary and a dataframe of objects.
    commands, phosim_objects = \
        desc.imsim.parsePhoSimInstanceFile(file, numRows)

    phosim_objects = \
        desc.imsim.validate_phosim_object_list(phosim_objects).accepted

    # Build the ObservationMetaData with values taken from the
    # PhoSim commands at the top of the instance file.
    obs_md = desc.imsim.phosim_obs_metadata(commands)
    #print (commands)
    #obs_md.OpsimMetaData['altitude' ] = 20
    camera = LsstSimMapper().camera

    # Sub-divide the source dataframe into stars and galaxies.
    if sensor is not None:
        # Trim the input catalog to a single chip.
        phosim_objects['chipName'] = \
            chipNameFromRaDec(phosim_objects['raICRS'].values,
                              phosim_objects['decICRS'].values,
                              parallax=phosim_objects['parallax'].values,
                              camera=camera, obs_metadata=obs_md,
                              epoch=2000.0)

        starDataBase = \
            phosim_objects.query("galSimType=='pointSource' and chipName=='%s'"
                                 % sensor)
        galaxyDataBase = \
            phosim_objects.query("galSimType=='sersic' and chipName=='%s'"
                                 % sensor)
    else:
        starDataBase = \
            phosim_objects.query("galSimType=='pointSource'")
        galaxyDataBase = \
            phosim_objects.query("galSimType=='sersic'")

    # Simulate the objects in the Pandas Dataframes.

    # First simulate stars
    phoSimStarCatalog = desc.imsim.ImSimStars(starDataBase, obs_md)
    phoSimStarCatalog.photParams = desc.imsim.photometricParameters(commands)

    # Add noise and sky background
    # The simple code using the default lsst-GalSim interface would be:
    #
    #    PhoSimStarCatalog.noise_and_background = ExampleCCDNoise(addNoise=True,
    #                                                             addBackground=True)
    #
    # But, we need a more realistic sky model and we need to pass more than
    # this basic info to use Peter Y's ESO sky model.
    # We must pass obs_metadata, chip information etc...
    phoSimStarCatalog.noise_and_background = ESOSkyModel(obs_md,
                                                         addNoise=True,
                                                         addBackground=True)

    # Add a PSF.
    if psf.lower() == "doublegaussian":
        # This one is taken from equation 30 of
        # www.astro.washington.edu/users/ivezic/Astr511/LSST_SNRdoc.pdf .
        #
        # Set seeing from self.obs_metadata.
        phoSimStarCatalog.PSF = \
            SNRdocumentPSF(obs_md.OpsimMetaData['FWHMgeom'])
    elif psf.lower() == "kolmogorov":
        # This PSF was presented by David Kirkby at the 23 March 2017
        # Survey Simulations Working Group telecon
        #
        # https://confluence.slac.stanford.edu/pages/viewpage.action?spaceKey=LSSTDESC&title=SSim+2017-03-23

        # equation 3 of Krisciunas and Schaefer 1991
        airmass = 1.0 / np.sqrt(
            1.0 - 0.96 *
            (np.sin(0.5 * np.pi - obs_md.OpsimMetaData['altitude']))**2)

        phoSimStarCatalog.PSF = \
            Kolmogorov_and_Gaussian_PSF(airmass=airmass,
                                        rawSeeing=obs_md.OpsimMetaData['rawSeeing'],
                                        band=obs_md.bandpass)
    else:
        raise RuntimeError("Do not know what to do with psf model: "
                           "%s" % psf)

    phoSimStarCatalog.camera = camera
    phoSimStarCatalog.get_fitsFiles()

    # Now galaxies
    phoSimGalaxyCatalog = desc.imsim.ImSimGalaxies(galaxyDataBase, obs_md)
    phoSimGalaxyCatalog.copyGalSimInterpreter(phoSimStarCatalog)
    phoSimGalaxyCatalog.PSF = phoSimStarCatalog.PSF
    phoSimGalaxyCatalog.noise_and_background = phoSimStarCatalog.noise_and_background
    phoSimGalaxyCatalog.get_fitsFiles()

    # Write out the fits files
    outdir = outdir
    if not os.path.isdir(outdir):
        os.makedirs(outdir)
    prefix = config['persistence']['eimage_prefix']
    phoSimGalaxyCatalog.write_images(nameRoot=os.path.join(outdir, prefix) +
                                     str(commands['obshistid']))
Beispiel #19
0
class psfCatalog(testGalaxyCatalog):
    """
    Adds a PSF to testGalaxyCatalog
    """
    PSF = SNRdocumentPSF()
Beispiel #20
0
    def testCamera(self):
        """
        Test that GalSimCatalogs respect the allowed_chips variable by
        generating a catalog with one object on each chip.

        Generate images from a control catalog that allows all chips.
        Verify that each image contains the expected flux.

        Generate images from a test catalog that only allows two chips.
        Verify that only the two expected images exist and that each
        contains only the expected flux.
        """

        controlCatalog = allowedChipsCatalog(self.db, obs_metadata=self.obs)
        testCatalog = allowedChipsCatalog(self.db, obs_metadata=self.obs)
        psf = SNRdocumentPSF()
        controlCatalog.setPSF(psf)
        testCatalog.setPSF(psf)
        controlCatalog.camera_wrapper = GalSimCameraWrapper(self.camera)
        testCatalog.camera_wrapper = GalSimCameraWrapper(self.camera)

        test_root = os.path.join(self.scratchDir, 'allowed_chip_test_image')
        control_root = os.path.join(self.scratchDir,
                                    'allowed_chip_control_image')

        name_list = []
        for dd in self.camera:
            if dd.getType() == WAVEFRONT or dd.getType() == GUIDER:
                continue
            name = dd.getName()
            name_list.append(name)
            stripped_name = name.replace(':', '')
            stripped_name = stripped_name.replace(',', '')
            stripped_name = stripped_name.replace(' ', '_')

            test_image_name = os.path.join(
                self.scratchDir, test_root + '_' + stripped_name + '_u.fits')
            control_image_name = os.path.join(
                self.scratchDir,
                control_root + '_' + stripped_name + '_u.fits')

            # remove any images that were generated the last time this test
            # was run
            if os.path.exists(test_image_name):
                os.unlink(test_image_name)
            if os.path.exists(control_image_name):
                os.unlink(control_image_name)

        # only allow two chips in the test catalog
        allowed_chips = [name_list[3], name_list[4]]

        testCatalog.allowed_chips = allowed_chips

        test_cat_name = os.path.join(self.scratchDir,
                                     'allowed_chips_test_cat.txt')
        control_cat_name = os.path.join(self.scratchDir,
                                        'allowed_chips_control_cat.txt')

        testCatalog.write_catalog(test_cat_name)
        controlCatalog.write_catalog(control_cat_name)

        testCatalog.write_images(nameRoot=test_root)
        controlCatalog.write_images(nameRoot=control_root)

        test_image_ct = 0

        for name in name_list:
            # Loop through each chip on the camera.
            # Verify that the control catalog generated an image for each chip.
            # Verify that the test catalog only generated images for the two
            # specified chips.
            # Verify that each image contains the expected amount of flux.

            stripped_name = name.replace(':', '')
            stripped_name = stripped_name.replace(',', '')
            stripped_name = stripped_name.replace(' ', '_')

            test_image_name = os.path.join(
                self.scratchDir, test_root + '_' + stripped_name + '_u.fits')
            control_image_name = os.path.join(
                self.scratchDir,
                control_root + '_' + stripped_name + '_u.fits')

            msg = '%s does not exist; it should' % control_image_name
            self.assertTrue(os.path.exists(control_image_name), msg=msg)
            im = afwImage.ImageF(control_image_name).getArray()
            msg = "\nimage contains %e counts\nshould contain %e\n\n" % (
                im.sum(), self.controlADU)
            self.assertLess(np.abs(im.sum() - self.controlADU),
                            3.0 * self.countSigma,
                            msg=msg)
            os.unlink(control_image_name)

            if name in allowed_chips:
                msg = '%s does not exist; it should' % test_image_name
                self.assertTrue(os.path.exists(test_image_name), msg=msg)
                im = afwImage.ImageF(test_image_name).getArray()
                self.assertLess(np.abs(im.sum() - self.controlADU),
                                3.0 * self.countSigma)
                os.unlink(test_image_name)
                test_image_ct += 1
            else:
                msg = '%s exists; it should not' % test_image_name
                self.assertFalse(os.path.exists(test_image_name), msg=msg)

        self.assertEqual(test_image_ct, len(allowed_chips))

        if os.path.exists(test_cat_name):
            os.unlink(test_cat_name)
        if os.path.exists(control_cat_name):
            os.unlink(control_cat_name)
Beispiel #21
0
    def testFitsHeader(self):
        """
        Create a test image with the LSST camera and with the
        cartoon camera.  Verify that the image created with the LSST
        camera has the DM-required cards in its FITS header while the
        image created with the cartoon camera does not
        """

        cameraDir = os.path.join(getPackageDir('sims_GalSimInterface'),
                                 'tests', 'cameraData')
        cartoonCamera = ReturnCamera(cameraDir)

        outputDir = tempfile.mkdtemp(dir=ROOT, prefix='testFitsHeader-')

        lsst_cat_name = os.path.join(outputDir, 'fits_test_lsst_cat.txt')
        lsst_cat_root = os.path.join(outputDir, 'fits_test_lsst_image')

        cartoon_cat_name = os.path.join(outputDir, 'fits_test_cartoon_cat.txt')
        cartoon_cat_root = os.path.join(outputDir, 'fits_test_cartoon_image')

        obs = ObservationMetaData(pointingRA=32.0,
                                  pointingDec=22.0,
                                  boundLength=0.1,
                                  boundType='circle',
                                  mjd=58000.0,
                                  rotSkyPos=14.0,
                                  bandpassName='u')

        obs.OpsimMetaData = {'obshistID': 112}

        dbFileName = os.path.join(outputDir, 'fits_test_db.dat')
        create_text_catalog(obs, dbFileName, np.array([30.0]),
                            np.array([30.0]), [22.0])
        db = fitsHeaderFileDBObj(dbFileName, runtable='test')

        # first test the lsst camera
        lsstCat = fitsHeaderCatalog(db, obs_metadata=obs)
        lsstCat.camera_wrapper = LSSTCameraWrapper()
        lsstCat.PSF = SNRdocumentPSF()
        lsstCat.write_catalog(lsst_cat_name)
        lsstCat.write_images(nameRoot=lsst_cat_root)

        list_of_files = os.listdir(outputDir)
        ct = 0
        for file_name in list_of_files:
            true_name = os.path.join(outputDir, file_name)
            if lsst_cat_root in true_name:
                ct += 1
                with fits.open(true_name) as fitsTest:
                    header = fitsTest[0].header
                    self.assertIn('CHIPID', header)
                    self.assertIn('OBSID', header)
                    self.assertIn('OUTFILE', header)
                    self.assertEqual(header['OBSID'], 112)
                    self.assertEqual(header['CHIPID'], 'R22_S11')
                    self.assertEqual(header['OUTFILE'],
                                     'lsst_e_112_f0_R22_S11_E000')
                os.unlink(true_name)

        self.assertGreater(ct, 0)
        if os.path.exists(lsst_cat_name):
            os.unlink(lsst_cat_name)

        # now test with the cartoon camera
        cartoonCat = fitsHeaderCatalog(db, obs_metadata=obs)
        cartoonCat.camera_wrapper = GalSimCameraWrapper(cartoonCamera)
        cartoonCat.PSF = SNRdocumentPSF()
        cartoonCat.write_catalog(cartoon_cat_name)
        cartoonCat.write_images(nameRoot=cartoon_cat_root)
        list_of_files = os.listdir(outputDir)
        ct = 0
        for file_name in list_of_files:
            true_name = os.path.join(outputDir, file_name)
            if cartoon_cat_root in true_name:
                ct += 1
                with fits.open(true_name) as fitsTest:
                    header = fitsTest[0].header
                    self.assertNotIn('CHIPID', header)
                    self.assertNotIn('OBSID', header)
                    self.assertNotIn('OUTFILE', header)
                os.unlink(true_name)

        self.assertGreater(ct, 0)
        if os.path.exists(cartoon_cat_name):
            os.unlink(cartoon_cat_name)

        if os.path.exists(dbFileName):
            os.unlink(dbFileName)

        if os.path.exists(outputDir):
            shutil.rmtree(outputDir)
class testGalSimAgn(GalSimAgn):
    bandpassNames = ['u', 'g']

    #defined in galSimInterface/galSimUtilities.py
    PSF = SNRdocumentPSF()
Beispiel #23
0
class testGalSimStars(GalSimStars):
    #only draw images for u and g bands (for speed)
    bandpassNames = ['u', 'g']

    #defined in galSimInterface/galSimUtilities.py
    PSF = SNRdocumentPSF()
    def testObjectPlacement(self):
        """
        Test that GalSim places objects on the correct pixel by drawing
        images containing single objects and no background, reading those
        images back in, and comparing the flux-averaged centroids of the
        images with the expected pixel positions of the input objects.
        """
        scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testLSSTObjectPlacement-')
        if os.path.exists(scratchDir):
            shutil.rmtree(scratchDir)
        os.mkdir(scratchDir)

        detector = lsst_camera()['R:0,3 S:2,2']
        det_name = 'R03_S22'

        magNorm = 19.0

        pixel_transformer = DMtoCameraPixelTransformer()

        for band in 'ugrizy':
            obs = self.obs_dict[band]

            catName = os.path.join(scratchDir, 'placementCatalog.dat')
            imageRoot = os.path.join(scratchDir, 'placementImage')
            dbFileName = os.path.join(scratchDir, 'placementInputCatalog.dat')


            imageName = '%s_%s_%s.fits' % (imageRoot, det_name, obs.bandpass)

            ra_c, dec_c = raDecFromPixelCoordsLSST(2000.0, 2000.0,
                                                   detector.getName(),
                                                   band=obs.bandpass,
                                                   obs_metadata=obs)

            nSamples = 30
            rng = np.random.RandomState(42)
            fwhm = 0.12

            for iteration in range(nSamples):
                if os.path.exists(dbFileName):
                    os.unlink(dbFileName)

                ra_obj = ra_c + rng.random_sample()*0.2 - 0.1
                dec_obj = dec_c + rng.random_sample()*0.2 - 0.1

                dmx_wrong, dmy_wrong = pixelCoordsFromRaDec(ra_obj, dec_obj,
                                                            chipName=detector.getName(),
                                                            obs_metadata=obs,
                                                            camera=lsst_camera())

                dmx_pix, dmy_pix = pixelCoordsFromRaDecLSST(ra_obj, dec_obj,
                                                            chipName=detector.getName(),
                                                            obs_metadata=obs,
                                                            band=obs.bandpass)

                x_pix, y_pix = pixel_transformer.cameraPixFromDMPix(dmx_pix, dmy_pix,
                                                                    detector.getName())

                x_pix_wrong, y_pix_wrong = pixel_transformer.cameraPixFromDMPix(dmx_wrong, dmy_wrong,
                                                                                detector.getName())

                d_ra = 360.0*(ra_obj - obs.pointingRA)  # in arcseconds
                d_dec = 360.0*(dec_obj - obs.pointingDec)

                create_text_catalog(obs, dbFileName,
                                    np.array([d_ra]), np.array([d_dec]),
                                    mag_norm=[magNorm])

                db = LSSTPlacementFileDBObj(dbFileName, runtable='test')
                cat = LSSTPlacementCatalog(db, obs_metadata=obs)
                cat.camera_wrapper = LSSTCameraWrapper()
                psf = SNRdocumentPSF(fwhm=fwhm)
                cat.setPSF(psf)

                cat.write_catalog(catName)
                cat.write_images(nameRoot=imageRoot)

                im = afwImage.ImageF(imageName).getArray()
                tot_flux = im.sum()
                self.assertGreater(tot_flux, 10.0)

                y_centroid = sum([ii*im[ii,:].sum() for ii in range(im.shape[0])])/tot_flux
                x_centroid = sum([ii*im[:,ii].sum() for ii in range(im.shape[1])])/tot_flux
                dd = np.sqrt((x_pix-x_centroid)**2 + (y_pix-y_centroid)**2)
                self.assertLess(dd, 0.5*fwhm)

                dd_wrong = np.sqrt((x_pix_wrong-x_centroid)**2 +
                                   (y_pix_wrong-y_centroid)**2)

                self.assertLess(dd, dd_wrong)

                if os.path.exists(dbFileName):
                    os.unlink(dbFileName)
                if os.path.exists(catName):
                    os.unlink(catName)
                if os.path.exists(imageName):
                    os.unlink(imageName)

        if os.path.exists(scratchDir):
            shutil.rmtree(scratchDir)
Beispiel #25
0
def main():
    """
    Drive GalSim to simulate the LSST.
    """
    # Setup a parser to take command line arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('file', help="The instance catalog")
    parser.add_argument('-n',
                        '--numrows',
                        default=None,
                        type=int,
                        help="Read the first numrows of the file.")
    parser.add_argument('--outdir',
                        type=str,
                        default='fits',
                        help='Output directory for eimage file')
    parser.add_argument(
        '--sensor',
        type=str,
        default=None,
        help='Sensor to simulate, e.g., "R:2,2 S:1,1".' +
        'If None, then simulate all sensors with sources on them')
    parser.add_argument(
        '--config_file',
        type=str,
        default=None,
        help="Config file. If None, the default config will be used.")
    parser.add_argument('--log_level',
                        type=str,
                        choices=['DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'],
                        default='INFO',
                        help='Logging level. Default: "INFO"')
    parser.add_argument(
        '--psf',
        type=str,
        default='Kolmogorov',
        choices=['DoubleGaussian', 'Kolmogorov'],
        help="PSF model to use; either the double Gaussian "
        "from LSE=40 (equation 30), or the Kolmogorov convolved "
        "with a Gaussian proposed by David Kirkby at the "
        "23 March 2017 SSims telecon")
    parser.add_argument('--checkpoint_file',
                        type=str,
                        default=None,
                        help='Checkpoint file name.')
    parser.add_argument('--nobj_checkpoint',
                        type=int,
                        default=1000,
                        help='# objects to process between checkpoints')
    parser.add_argument('--seed',
                        type=int,
                        default=267,
                        help='integer used to seed random number generator')
    arguments = parser.parse_args()

    config = desc.imsim.read_config(arguments.config_file)

    logger = desc.imsim.get_logger(arguments.log_level)

    # Get the number of rows to read from the instance file.  Use
    # default if not specified.
    numRows = arguments.numrows
    if numRows is not None:
        logger.info("Reading %i rows from the instance catalog %s.", numRows,
                    arguments.file)
    else:
        logger.info("Reading all rows from the instance catalog %s.",
                    arguments.file)

    camera_wrapper = LSSTCameraWrapper()

    catalog_contents = desc.imsim.parsePhoSimInstanceFile(arguments.file,
                                                          numRows=numRows)

    obs_md = catalog_contents.obs_metadata
    phot_params = catalog_contents.phot_params
    sources = catalog_contents.sources
    gs_object_arr = sources[0]
    gs_object_dict = sources[1]

    # Sub-divide the source dataframe into stars and galaxies.
    if arguments.sensor is not None:
        detector_list = [
            make_galsim_detector(camera_wrapper, arguments.sensor, phot_params,
                                 obs_md)
        ]
    else:
        detector_list = []
        for det in camera_wrapper.camera:
            det_type = det.getType()
            if det_type != WAVEFRONT and det_type != GUIDER:
                detector_list.append(
                    make_galsim_detector(camera_wrapper, det.getName(),
                                         phot_params, obs_md))

    # Add noise and sky background
    # The simple code using the default lsst-GalSim interface would be:
    #
    #    PhoSimStarCatalog.noise_and_background = ExampleCCDNoise(addNoise=True,
    #                                                             addBackground=True)
    #
    # But, we need a more realistic sky model and we need to pass more than
    # this basic info to use Peter Y's ESO sky model.
    # We must pass obs_metadata, chip information etc...
    noise_and_background \
        = ESOSkyModel(obs_md, addNoise=True, addBackground=True)

    bp_dict = BandpassDict.loadTotalBandpassesFromFiles(
        bandpassNames=obs_md.bandpass)

    gs_interpreter = GalSimInterpreter(obs_metadata=obs_md,
                                       epoch=2000.0,
                                       detectors=detector_list,
                                       bandpassDict=bp_dict,
                                       noiseWrapper=noise_and_background,
                                       seed=arguments.seed)

    gs_interpreter.checkpoint_file = arguments.checkpoint_file
    gs_interpreter.nobj_checkpoint = arguments.nobj_checkpoint
    gs_interpreter.restore_checkpoint(camera_wrapper, phot_params, obs_md)

    # Add a PSF.
    if arguments.psf.lower() == "doublegaussian":
        # This one is taken from equation 30 of
        # www.astro.washington.edu/users/ivezic/Astr511/LSST_SNRdoc.pdf .
        #
        # Set seeing from self.obs_metadata.
        local_PSF = \
            SNRdocumentPSF(obs_md.OpsimMetaData['FWHMgeom'])
    elif arguments.psf.lower() == "kolmogorov":
        # This PSF was presented by David Kirkby at the 23 March 2017
        # Survey Simulations Working Group telecon
        #
        # https://confluence.slac.stanford.edu/pages/viewpage.action?spaceKey=LSSTDESC&title=SSim+2017-03-23

        # equation 3 of Krisciunas and Schaefer 1991
        airmass = 1.0 / np.sqrt(
            1.0 - 0.96 *
            (np.sin(0.5 * np.pi - obs_md.OpsimMetaData['altitude']))**2)

        local_PSF = \
            Kolmogorov_and_Gaussian_PSF(airmass=airmass,
                                        rawSeeing=obs_md.OpsimMetaData['rawSeeing'],
                                        band=obs_md.bandpass)
    else:
        raise RuntimeError("Do not know what to do with psf model: "
                           "%s" % arguments.psf)

    gs_interpreter.setPSF(PSF=local_PSF)

    if arguments.sensor is not None:
        gs_objects_to_draw = gs_object_dict[arguments.sensor]
    else:
        gs_objects_to_draw = gs_object_arr

    for gs_obj in gs_objects_to_draw:
        if gs_obj.uniqueId in gs_interpreter.drawn_objects:
            continue
        gs_interpreter.drawObject(gs_obj)

    desc.imsim.add_cosmic_rays(gs_interpreter, phot_params)

    # Write out the fits files
    outdir = arguments.outdir
    if not os.path.isdir(outdir):
        os.makedirs(outdir)
    prefix = config['persistence']['eimage_prefix']
    gs_interpreter.writeImages(nameRoot=os.path.join(outdir, prefix) +
                               str(obs_md.OpsimMetaData['obshistID']))