Beispiel #1
0
def test_dict():
    """Test that we can create a FitsHeader from a dict
    """
    import time
    t1 = time.time()

    d = {'TIME-OBS': '04:28:14.105', 'FILTER': 'I', 'AIRMASS': 1.185}

    def check_dict(header):
        """Check that the header object has correct values from the given dict
        """
        assert header['TIME-OBS'] == '04:28:14.105'
        assert header['FILTER'] == 'I'
        assert header['AIRMASS'] == 1.185
        assert len(header) == 3

    # Construct from a given dict
    header = galsim.FitsHeader(header=d)
    check_dict(header)
    do_pickle(header)

    # Start with a blank dict and add elements individually
    header = galsim.FitsHeader(header={})
    do_pickle(header)
    for k in d:
        header[k] = d[k]
    check_dict(header)
    do_pickle(header)

    # Set with a comment field
    header = galsim.FitsHeader(header={})
    for k in d:
        header[k] = (d[k], 'The value of ' + k)
    check_dict(header)
    do_pickle(header)

    # Use update
    header = galsim.FitsHeader({})
    header.update(d)
    check_dict(header)
    do_pickle(header)

    # Use default constructor
    header = galsim.FitsHeader()
    do_pickle(header)
    assert len(header) == 0
    header.update(d)
    check_dict(header)
    do_pickle(header)

    t2 = time.time()
    print 'time for %s = %.2f' % (funcname(), t2 - t1)
Beispiel #2
0
def getheader(imgfilepath, **kwargs):
	"""
	Uses GalSim to quickly load the header
	"""
	logger.info("Getting FITS header from %s..." % (os.path.basename(imgfilepath)))
	header = galsim.FitsHeader(imgfilepath, **kwargs)
	return header
Beispiel #3
0
def test_comments():
    """Test that comments are correctly added to the cards.
    """
    # cf. Issue #877
    # This test is taken directly from Bryan's failing example

    im1 = galsim.Image(1, 1, dtype=float)
    im1.header = galsim.FitsHeader()
    im1.header["CARD"] = ("value", "comment")
    galsim.fits.write(im1, os.path.join('output', 'test_comments_im1.fits'))

    im2 = galsim.Image(1, 1, dtype=float)
    im2.header = {}
    im2.header["CARD"] = ("value", "comment")
    galsim.fits.write(im1, os.path.join('output', 'test_comments_im2.fits'))

    im3 = galsim.Image(1, 1, dtype=float)
    im3.header = {"CARD": ("value", "comment")}
    galsim.fits.write(im1, os.path.join('output', 'test_comments_im3.fits'))

    im1 = galsim.fits.read(os.path.join('output', 'test_comments_im1.fits'),
                           read_header=True)
    im2 = galsim.fits.read(os.path.join('output', 'test_comments_im2.fits'),
                           read_header=True)
    im3 = galsim.fits.read(os.path.join('output', 'test_comments_im3.fits'),
                           read_header=True)

    for im in [im1, im2, im3]:
        assert im.header['CARD'] == 'value'
        assert im.header.comment('CARD') == 'comment'
Beispiel #4
0
def check_dict(d):
    def check_dict(header):
        """Check that the header object has correct values from the given dict
        """
        assert header['TIME-OBS'] == '04:28:14.105'
        assert header['FILTER'] == 'I'
        assert header['AIRMASS'] == 1.185
        assert len(header) == 3

    # Construct from a given dict
    header = galsim.FitsHeader(header=d)
    check_dict(header)
    do_pickle(header)

    # Start with a blank dict and add elements individually
    header = galsim.FitsHeader(header={})
    do_pickle(header)
    for k in d:
        header[k] = d[k]
    check_dict(header)
    do_pickle(header)

    # Set with a comment field
    header = galsim.FitsHeader(header={})
    for k in d:
        header[k] = (d[k], 'The value of ' + k)
    check_dict(header)
    do_pickle(header)

    # Use update
    header = galsim.FitsHeader({})
    header.update(d)
    check_dict(header)
    do_pickle(header)

    # Use default constructor
    header = galsim.FitsHeader()
    do_pickle(header)
    assert len(header) == 0
    header.update(d)
    check_dict(header)
    do_pickle(header)
Beispiel #5
0
def test_scamp():
    """Test that we can read in a SCamp .head file correctly
    """
    dir = 'fits_files'
    file_name = 'scamp.head'

    header = galsim.FitsHeader(file_name=file_name, dir=dir, text_file=True)
    # Just check a few values.  The full test of this file as a wcs is in test_wcs.py
    assert header['RADECSYS'] == 'FK5'
    assert header['MAGZEROP'] == 30.
    assert header['ASTINST'] == 39
    do_pickle(header)
Beispiel #6
0
    def write_eimage_files(self, gs_interpreter):
        """
        Write the eimage files.

        Parameters
        ----------
        gs_interpreter: GalSimInterpreter object
        """
        # Add version keywords to eimage headers
        version_keywords = get_version_keywords()
        for image in gs_interpreter.detectorImages.values():
            image.header = galsim.FitsHeader(header=version_keywords)

        # Write the eimage files using filenames containing the visit number.
        prefix = IMAGE_SIMULATOR.config['persistence']['eimage_prefix']
        obsHistID = str(IMAGE_SIMULATOR.obs_md.OpsimMetaData['obshistID'])
        nameRoot = os.path.join(IMAGE_SIMULATOR.outdir, prefix) + obsHistID
        outfiles = gs_interpreter.writeImages(nameRoot=nameRoot)
        if IMAGE_SIMULATOR.config['persistence']['eimage_compress']:
            compress_files(outfiles)
Beispiel #7
0
    def __init__(self, file_name, image_file_name=None, wcs=None, dir=None):

        if dir:
            if not isinstance(file_name, basestring):
                raise ValueError("Cannot provide dir and an HDU instance")
            import os
            file_name = os.path.join(dir,file_name)
            if image_file_name is not None:
                image_file_name = os.path.join(dir,image_file_name)
        self.file_name = file_name
        if image_file_name:
            if wcs is not None:
                raise AttributeError("Cannot provide both image_file_name and wcs")
            header = galsim.FitsHeader(file_name=image_file_name)
            wcs, origin = galsim.wcs.readFromFitsHeader(header)
            self.wcs = wcs
        elif wcs:
            self.wcs = wcs
        else:
            self.wcs = None
        self.read()
Beispiel #8
0
    def __init__(self, file_name, image_file_name=None, wcs=None, dir=None):

        if dir:
            if not isinstance(file_name, str):
                raise TypeError("file_name must be a string")
            file_name = os.path.join(dir,file_name)
            if image_file_name is not None:
                image_file_name = os.path.join(dir,image_file_name)
        self.file_name = file_name
        if image_file_name:
            if wcs is not None:
                raise galsim.GalSimIncompatibleValuesError(
                    "Cannot provide both image_file_name and wcs",
                    image_file_name=image_file_name, wcs=wcs)
            header = galsim.FitsHeader(file_name=image_file_name)
            wcs, origin = galsim.wcs.readFromFitsHeader(header)
            self.wcs = wcs
        elif wcs:
            self.wcs = wcs
        else:
            self.wcs = None
        self.read()
Beispiel #9
0
    def finalize(self, config, base, main_data, logger):
        """Perform any final processing at the end of all the image processing.

        This function will be called after all images have been built.

        It returns some sort of final version of the object.  In the base class, it just returns
        self.data, but depending on the meaning of the output object, something else might be
        more appropriate.

        Parameters:
           config:     The configuration field for this output object.
           base:       The base configuration dict.
           main_data:  The main file data in case it is needed.
           logger:     If given, a logger object to log progress. [default: None]

        Returns:
           The final version of the object.
        """
        logger.warning("Making amplifier images")
        # Simple version of this for now.
        # main_data is a list of the single e-image.
        # Split it up into 16 amplifier images.
        det_name = base['det_name']  # This was saved by the LSST CCD Builder.
        eimage = main_data[0]

        # TODO: Do something with these numbers.
        readout_time = config[
            'readout_time']  # Maybe give default values for these using get?
        dark_current = config[
            'dark_current']  # Or if you want them to be parsable float values,
        bias_level = config[
            'bias_level']  # we can use the config ParseValue function.
        pcti = config['pcti']
        scti = config['scti']

        # I don't know which way is the short side, and I know some of these need to be
        # flipped in various ways.  Ignoring all that for now.
        # TODO: Do this right.
        xvals = [i * eimage.xmax / 8 for i in range(9)]
        yvals = [j * eimage.xmax / 2 for j in range(3)]
        bounds_list = [
            galsim.BoundsI(xvals[i] + 1, xvals[i + 1], yvals[j] + 1,
                           yvals[j + 1]) for i in range(8) for j in range(2)
        ]

        amps = [eimage[b] for b in bounds_list]

        for amp_num, amp in enumerate(amps):
            amp_name = det_name + "-C%02d" % amp_num  # XXX: Pretty sure this isn't right.
            logger.warning("Amp %s has bounds %s.", amp_name, amp.bounds)

            amp.header = galsim.FitsHeader()
            amp.header['AMP_NAME'] = amp_name
            # TODO: Add other header information.

            # XXX: I think these probably all should have their origin set to 1,1?
            #      At this point, the amp images still ahve the bounds from the original
            #      eimage, so we would need this next line to get back to 1,1 as the origin.
            amp.setOrigin(1, 1)

            # TODO: I think probably also the WCS might need to be changed?  Not sure.
            #       At this point, the WCS should be accurate for the re-origined image.
            #       But if we do something more complicated like mirror image the array or
            #       something like that, the WCS would probably need to change.

        return amps
Beispiel #10
0
def main(argv):

    root = 'DECam_00154912'

    data_dir = 'des_data'

    if not os.path.exists(data_dir):
        print('You will need to download some DES data to use this script.')
        print('Run the following commands from the directory GalSim/examples/des:')
        print()
        print('    wget http://www.sas.upenn.edu/~mjarvis/des_data.tar.gz')
        print('    tar xfz des_data.tar.gz')
        print()
        print('Then try running this script again.  It should work now.')
        sys.exit()

    # Set which chips to run on
    first_chip = 1
    last_chip = 62
    #first_chip = 12
    #last_chip = 12

    # quick and dirty command line parsing.
    for var in argv:
        if var.startswith('first='): first_chip = int(var[6:])
        if var.startswith('last='): last_chip = int(var[5:])
    print('Processing chips %d .. %d'%(first_chip, last_chip))

    out_dir = 'output'

    # The random seed, so the results are deterministic
    random_seed = 1339201

    x_col = 'X_IMAGE'
    y_col = 'Y_IMAGE'
    flux_col = 'FLUX_AUTO'
    flag_col = 'FLAGS'

    xsize_key = 'NAXIS1'
    ysize_key = 'NAXIS2'
    sky_level_key = 'SKYBRITE'
    sky_sigma_key = 'SKYSIGMA'

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

    for chipnum in range(first_chip,last_chip+1):
        print('Start chip ',chipnum)

        # Setup the file names
        image_file = '%s_%02d.fits.fz'%(root,chipnum)
        cat_file = '%s_%02d_cat.fits'%(root,chipnum)
        psfex_file = '%s_%02d_psfcat.psf'%(root,chipnum)
        fitpsf_file = '%s_%02d_fitpsf.fits'%(root,chipnum)
        psfex_image_file = '%s_%02d_psfex_image.fits'%(root,chipnum)
        fitpsf_image_file = '%s_%02d_fitpsf_image.fits'%(root,chipnum)

        # Get some parameters about the image from the data image header information
        image_header = galsim.FitsHeader(image_file, dir=data_dir)
        xsize = image_header[xsize_key]
        ysize = image_header[ysize_key]
        sky_sigma = image_header[sky_sigma_key]  # This is sqrt(variance) / pixel
        sky_level = image_header[sky_level_key]  # This is in ADU / pixel
        gain = sky_level / sky_sigma**2  # an approximation, since gain is missing.

        # Read the WCS
        wcs = galsim.FitsWCS(header=image_header)

        # Setup the images:
        psfex_image = galsim.Image(xsize, ysize, wcs=wcs)
        fitpsf_image = galsim.Image(xsize, ysize, wcs=wcs)

        # Read the other input files
        cat = galsim.Catalog(cat_file, hdu=2, dir=data_dir)
        psfex = galsim.des.DES_PSFEx(psfex_file, image_file, dir=data_dir)
        fitpsf = galsim.des.DES_Shapelet(fitpsf_file, dir=data_dir)

        nobj = cat.nobjects
        print('Catalog has ',nobj,' objects')

        for k in range(nobj):
            sys.stdout.write('.')
            sys.stdout.flush()

            # Skip objects with a non-zero flag
            flag = cat.getInt(k,flag_col)
            if flag: continue

            # Get the position from the galaxy catalog
            x = cat.getFloat(k,x_col)
            y = cat.getFloat(k,y_col)
            image_pos = galsim.PositionD(x,y)
            #print '    pos = ',image_pos
            x += 0.5   # + 0.5 to account for even-size postage stamps
            y += 0.5
            ix = int(math.floor(x+0.5))  # round to nearest pixel
            iy = int(math.floor(y+0.5))
            dx = x-ix
            dy = y-iy
            offset = galsim.PositionD(dx,dy)

            # Also get the flux of the galaxy from the catalog
            flux = cat.getFloat(k,flux_col)
            #print '    flux = ',flux
            #print '    wcs = ',wcs.local(image_pos)

            # First do the PSFEx image:
            if True:
                # Define the PSF profile
                psf = psfex.getPSF(image_pos).withFlux(flux)
                #print '    psfex psf = ',psf

                # Draw the postage stamp image
                # Note: Use no_pixel method, since the PSFEx estimate of the PSF already includes
                # the pixel response.
                stamp = psf.drawImage(wcs=wcs.local(image_pos), offset=offset, method='no_pixel')

                # Recenter the stamp at the desired position:
                stamp.setCenter(ix,iy)

                # Find overlapping bounds
                bounds = stamp.bounds & psfex_image.bounds
                psfex_image[bounds] += stamp[bounds]


            # Next do the ShapeletPSF image:
            # If the position is not within the interpolation bounds, fitpsf will
            # raise an exception telling us to skip this object.  Easier to check here.
            if fitpsf.bounds.includes(image_pos):
                # Define the PSF profile
                psf = fitpsf.getPSF(image_pos).withFlux(flux)
                #print '    fitpsf psf = ',psf

                # Draw the postage stamp image
                # Again, the PSF already includes the pixel response.
                stamp = psf.drawImage(wcs=wcs.local(image_pos), offset=offset, method='no_pixel')

                # Recenter the stamp at the desired position:
                stamp.setCenter(ix,iy)

                # Find overlapping bounds
                bounds = stamp.bounds & fitpsf_image.bounds
                fitpsf_image[bounds] += stamp[bounds]
            else:
                pass
                #print '...not in fitpsf.bounds'
        print()

        # Add background level
        psfex_image += sky_level
        fitpsf_image += sky_level

        # Add noise
        rng = galsim.BaseDeviate(random_seed)
        noise = galsim.CCDNoise(rng, gain=gain)
        psfex_image.addNoise(noise)
        # Reset the random seed to match the action of the yaml version
        # Note: the difference between seed and reset matters here.
        # reset would sever the connection between this rng instance and the one stored in noise.
        # seed changes the seed while keeping the connection between them.
        rng.seed(random_seed)
        fitpsf_image.addNoise(noise)

        # Now write the images to disk.
        psfex_image.write(psfex_image_file, dir=out_dir)
        fitpsf_image.write(fitpsf_image_file, dir=out_dir)
        print('Wrote images to %s and %s'%(
                os.path.join(out_dir,psfex_image_file),
                os.path.join(out_dir,fitpsf_image_file)))

        # Increment the random seed by the number of objects in the file
        random_seed += nobj
Beispiel #11
0
def getWCS(world_pos, PA=None, date=None, SCAs=None, PA_is_FPA=False):
    """
    This routine returns a dict containing a WCS for each of the WFIRST SCAs (Sensor Chip Array, the
    equivalent of a chip in an optical CCD).  The WFIRST SCAs are labeled 1-18, so these numbers are
    used as the keys in the dict.  Alternatively the user can request a subset of the SCAs using the
    `SCAs` option.  The basic instrument parameters used to create the WCS correspond to those in
    Cycle 6, which includes some significant updates from Cycle 5, including a 90 degree rotation of
    the focal plane axes relative to the payload axes, and two rows of SCAs are swapped.

    The user must specify a position for observation, at which the center of the focal plane array
    will point.  This must be supplied as a CelestialCoord `world_pos`.  In general, only certain
    positions are observable on certain dates, and for a given position there is an optimal position
    angle for the observatory (with the solar panels pointed as directly towards the sun as
    possible).  Users who are knowledgable about these details may choose to supply a position angle
    as `PA`, either for the observatory or for the focal plane (using `PA_is_FPA` to indicate this).
    But otherwise, the routine will simply choose the optimal position angle for a given date.

    To fully understand all possible inputs and outputs to this routine, users may wish to consult
    the diagram on the GalSim wiki,
    https://github.com/GalSim-developers/GalSim/wiki/GalSim-WFIRST-module-diagrams

    @param world_pos A galsim.CelestialCoord indicating the position to observe at the center of the
                     focal plane array (FPA).  Note that if the given position is not observable on
                     the given date, then the routine will raise an exception.
    @param PA        galsim.Angle representing the position angle of the observatory +Y axis, unless
                     `PA_is_FPA=True`, in which case it's the position angle of the FPA.  For users
                     to do not care about this, then leaving this as None will result in the routine
                     using the supplied `date` and `world_pos` to select the optimal orientation for
                     the observatory.  Note that if a user supplies a `PA` value, the routine does
                     not check whether this orientation is actually allowed.  [default: None]
    @param date      The date of the observation, as a python datetime object.  If None, then the
                     vernal equinox in 2025 will be used.  [default: None]
    @param PA_is_FPA If True, then the position angle that was provided was the PA of the focal
                     plane array, not the observatory. [default: False]
    @param SCAs      A single number or iterable giving the SCAs for which the WCS should be
                     obtained.  If None, then the WCS is calculated for all SCAs.
                     [default: None]
    @returns a dict of WCS objects for each SCA.
    """
    # Further gory details on coordinate systems, for developers: Observatory coordinate system is
    # defined such that +X_obs points along the boresight into the sky, +Z_obs points towards the
    # Sun in the absence of a roll offset (i.e., roll offset = 0 defines the optimal position angle
    # for the observatory), +Y_obs makes a right-handed system.
    #
    # Payload coordinate system: +X_pl points along -Y_obs, +Y_pl points along +Z_obs, +Z_pl points
    # along -X_obs (back towards observer).
    #
    # Wide field imager (WFI) focal plane assembly (FPA) coordinate system: This is defined by a
    # left-handed system f1, f2, that is rotated by an angle `theta_fpa` with respect to the payload
    # axes.  +f1 points along the long axis of the focal plane, transverse to the radius from the
    # telescope optic axis.  +f2 points radially out from the telescope optic axis, along the narrow
    # dimension of the focal plane.  If +f2 points North, then +f1 points East.  `theta_fpa` is a
    # positive CCW rotation of the f2 axis relative to -Y_pl, and of f1 relative to +X_pl.  In terms
    # of focal plane geometry, if +Y_fp is pointing North, then SCAs 3 and 12 will be at highest
    # declination, 8 and 17 at the lowest.  +Y_fp is aligned with the short axis of the focal plane
    # array.
    #
    # There is also a detector coordinate system (P1, P2).  +P1 and +P2 point along the fast- and
    # slow-scan directions of the pixel readout, respectively.
    #
    # So, for reference, if the boresight is pointed at RA=90, DEC=0 on March 21st (Sun at vernal
    # equinox), then +X_obs points at (RA,DEC)=(90,0), +Y_obs points North, and +Z_obs points at the
    # Sun.  The payload coordinates are +X_pl points South, -Y_pl points East.  Finally, the FPA
    # coordinate system is defined by +f2 being at a position angle 90+theta_fpa east of North.  If
    # the observatory +Y axis is at a position angle `pa_obsy` East of North, then the focal plane
    # (+f2) is at a position angle pa_fpa = pa_obsy + 90 + theta_fpa.

    # Parse input position
    if not isinstance(world_pos, galsim.CelestialCoord):
        raise TypeError(
            "Position on the sky must be given as a galsim.CelestialCoord!")

    # Get the date. (Vernal equinox in 2025, taken from
    # http://www.astropixels.com/ephemeris/soleq2001.html, if none was supplied.)
    if date is None:
        import datetime
        date = datetime.datetime(2025, 3, 20, 9, 2, 0)

    # Are we allowed to look here?
    if not allowedPos(world_pos, date):
        raise RuntimeError(
            "Error, WFIRST cannot look at this position on this date!")

    # If position angle was not given, then get the optimal one:
    if PA is None:
        PA_is_FPA = False
        PA = bestPA(world_pos, date)
    else:
        # Just enforce type
        if not isinstance(PA, galsim.Angle):
            raise TypeError("Position angle must be a galsim.Angle!")

    # Check which SCAs are to be done using a helper routine in this module.
    SCAs = galsim.wfirst._parse_SCAs(SCAs)

    # Compute position angle of FPA f2 axis, where positive corresponds to the angle east of North.
    if PA_is_FPA:
        pa_fpa = PA
        pa_obsy = PA - 90. * galsim.degrees - theta_fpa
    else:
        pa_obsy = PA
        pa_fpa = PA + 90. * galsim.degrees + theta_fpa
    cos_pa = np.cos(pa_fpa)
    sin_pa = np.sin(pa_fpa)

    # Figure out tangent-plane positions for FPA center:
    xc_fpa_tp, yc_fpa_tp = _det_to_tangplane_positions(xc_fpa, yc_fpa)

    # Note, this routine reads in the coeffs.  We don't use them until later, but read them in for
    # all SCAs at once.
    a_sip, b_sip = _parse_sip_file(sip_filename)

    # Loop over SCAs:
    wcs_dict = {}
    for i_sca in SCAs:
        # Set up the header.
        header = galsim.FitsHeader()
        # Populate some necessary variables in the FITS header that are always the same, regardless of
        # input and SCA number.
        _populate_required_fields(header)

        # And populate some things that just depend on the overall locations or other input, not on
        # the SCA.
        header['RA_TARG'] = (world_pos.ra / galsim.degrees,
                             "right ascension of the target (deg) (J2000)")
        header['DEC_TARG'] = (world_pos.dec / galsim.degrees,
                              "declination of the target (deg) (J2000)")
        header['PA_OBSY'] = (pa_obsy / galsim.degrees,
                             "position angle of observatory Y axis (deg)")
        header['PA_FPA'] = (pa_fpa / galsim.degrees,
                            "position angle of FPA Y axis (deg)")

        # Finally do all the SCA-specific stuff.
        header['SCA_NUM'] = (i_sca, "SCA number (1 - 18)")

        # Set the position of center of this SCA in focal plane angular coordinates.
        sca_xc_fpa = np.arctan(
            sca_xc_mm[i_sca] / focal_length) * galsim.radians
        sca_yc_fpa = np.arctan(
            sca_yc_mm[i_sca] / focal_length) * galsim.radians

        # Figure out tangent plane positions after distortion, and subtract off those for FPA center
        # (calculated in header).
        sca_xc_tp, sca_yc_tp = _det_to_tangplane_positions(
            sca_xc_fpa, sca_yc_fpa)
        # These define the tangent plane (X, Y) distance of the center of this SCA from the center
        # of the overall FPA.
        sca_xc_tp_f = sca_xc_tp - xc_fpa_tp
        sca_yc_tp_f = sca_yc_tp - yc_fpa_tp

        # Leave phi_p at 180 (0 if dec_targ==-90), so that tangent plane axes remain oriented along
        # celestial coordinates. In other words, phi_p is the angle of the +Y axis in the tangent
        # plane, which is of course pi if we're measuring these phi angles clockwise from the -Y
        # axis.  Note that this quantity is not used in any calculations at all, but for consistency
        # with the WCS code that comes from the WFIRST project office, we calculate this quantity
        # and put it in the FITS header.
        if world_pos.dec / galsim.degrees > -90.:
            phi_p = np.pi * galsim.radians
        else:
            phi_p = 0. * galsim.radians

        # Go from the tangent plane position of the SCA center, to the actual celestial coordinate,
        # using `world_pos` as the center point of the tangent plane projection.  This celestial
        # coordinate for the SCA center is `crval`, which goes into the WCS as CRVAL1, CRVAL2.
        u = -sca_xc_tp_f * cos_pa - sca_yc_tp_f * sin_pa
        v = -sca_xc_tp_f * sin_pa + sca_yc_tp_f * cos_pa
        crval = world_pos.deproject(galsim.PositionD(u / galsim.arcsec,
                                                     v / galsim.arcsec),
                                    projection='gnomonic')
        crval1 = crval.ra
        crval2 = crval.dec
        header['CRVAL1'] = (crval1 / galsim.degrees,
                            "first axis value at reference pixel")
        header['CRVAL2'] = (crval2 / galsim.degrees,
                            "second axis value at reference pixel")

        # Compute the position angle of the local pixel Y axis.
        # This requires projecting local North onto the detector axes.
        # Start by adding any SCA-unique rotation relative to FPA axes:
        sca_tp_rot = pa_fpa + sca_rot[i_sca] * galsim.degrees

        # Go some reasonable distance from crval in the +y direction.  Say, 1 degree.
        plus_y = world_pos.deproject(galsim.PositionD(
            u / galsim.arcsec, v / galsim.arcsec + 3600),
                                     projection='gnomonic')
        # Find the angle between this point, crval and due north.
        north = galsim.CelestialCoord(0. * galsim.degrees,
                                      90. * galsim.degrees)
        pa_sca = sca_tp_rot - crval.angleBetween(plus_y, north)

        # Compute CD coefficients: extract the linear terms from the a_sip, b_sip arrays.  These
        # linear terms are stored in the SIP arrays for convenience, but are defined differently.
        # The other terms have been divided by the linear terms, so that these become pure
        # multiplicative factors. There is no need to change signs of the SIP coefficents associated
        # with odd powers of X! Change sign of a10, b10 because the tangent-plane X pixel coordinate
        # has sign opposite to the detector pixel X coordinate, and this transformation maps pixels
        # to tangent plane.
        a10 = -a_sip[i_sca, 1, 0]
        a11 = a_sip[i_sca, 0, 1]
        b10 = -b_sip[i_sca, 1, 0]
        b11 = b_sip[i_sca, 0, 1]

        # Rotate by pa_fpa.
        cos_pa_sca = np.cos(pa_sca)
        sin_pa_sca = np.sin(pa_sca)
        header['CD1_1'] = (cos_pa_sca * a10 + sin_pa_sca * b10,
                           "partial of first axis coordinate w.r.t. x")
        header['CD1_2'] = (cos_pa_sca * a11 + sin_pa_sca * b11,
                           "partial of first axis coordinate w.r.t. y")
        header['CD2_1'] = (-sin_pa_sca * a10 + cos_pa_sca * b10,
                           "partial of second axis coordinate w.r.t. x")
        header['CD2_2'] = (-sin_pa_sca * a11 + cos_pa_sca * b11,
                           "partial of second axis coordinate w.r.t. y")
        header['ORIENTAT'] = (pa_sca / galsim.degrees,
                              "position angle of image y axis (deg. e of n)")
        header['LONPOLE'] = (phi_p / galsim.degrees,
                             "Native longitude of celestial pole")
        for i in range(n_sip):
            for j in range(n_sip):
                if i + j >= 2 and i + j < n_sip:
                    sipstr = "A_%d_%d" % (i, j)
                    header[sipstr] = a_sip[i_sca, i, j]
                    sipstr = "B_%d_%d" % (i, j)
                    header[sipstr] = b_sip[i_sca, i, j]

        wcs = galsim.GSFitsWCS(header=header)
        # Store the original header as an attribute of the WCS.  This ensures that we have all the
        # extra keywords for whenever an image with this WCS is written to file.
        wcs.header = header
        wcs_dict[i_sca] = wcs

    return wcs_dict
Beispiel #12
0
def test_read():
    """Test reading a FitsHeader from an existing FITS file
    """
    # Older pyfits versions treat the blank rows differently, so it comes out as 213.
    # I don't know exactly when it switched, but for < 3.1, I'll just update this to
    # whatever the initial value is.
    tpv_len = 215

    def check_tpv(header):
        """Check that the header object has correct values from the tpv.fits file
        """
        # Check using a few different access methods.
        assert header['TIME-OBS'] == '04:28:14.105'
        assert header.get('FILTER') == 'I'
        assert header['AIRMASS'] == 1.185
        assert len(header) == tpv_len
        assert 'ADC' in header
        assert ('FILPOS', 6) in header.items()
        assert ('FILPOS', 6) in header.iteritems()
        assert 'OBSERVAT' in header.keys()
        assert 'OBSERVAT' in header.iterkeys()
        assert 54384.18627436 in header.values()  # MJD-OBS
        assert 54384.18627436 in header.itervalues()

    file_name = 'tpv.fits'
    dir = 'fits_files'
    # First option: give a file_name
    header = galsim.FitsHeader(file_name=os.path.join(dir, file_name))
    if pyfits_version < '3.1':
        tpv_len = len(header)
    check_tpv(header)
    do_pickle(header)
    # Let the FitsHeader init handle the dir
    header = galsim.FitsHeader(file_name=file_name, dir=dir)
    check_tpv(header)
    do_pickle(header)
    # If the first arg is a str, then it should be interpreted as a file name
    header = galsim.FitsHeader(file_name, dir=dir)
    check_tpv(header)
    # If you pass in a pyfits hdulist, that should also work
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(hdu_list=hdu_list)
    check_tpv(header)
    do_pickle(header)
    # Can explicitly give an hdu number to use.  In this case, there is only 1, so need to use 0.
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(hdu_list=hdu_list, hdu=0)
    check_tpv(header)
    do_pickle(header)
    # Can explicitly give an hdu number to use.  In this case, there is only 1, so need to use 0.
    header = galsim.FitsHeader(file_name=file_name, dir=dir, hdu=0)
    check_tpv(header)
    do_pickle(header)
    # If you pass in a pyfits Header object, that should also work
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(header=hdu_list[0].header)
    check_tpv(header)
    do_pickle(header)
    # The header is the first parameter, so don't need to name it.
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(hdu_list[0].header)
    check_tpv(header)
    # FitsHeader can read from a compressed file too
    header = galsim.FitsHeader(file_name=file_name + '.gz',
                               dir=dir,
                               compression='auto')
    check_tpv(header)
    do_pickle(header)
    header = galsim.FitsHeader(file_name=file_name + '.gz',
                               dir=dir,
                               compression='gzip')
    check_tpv(header)
    do_pickle(header)

    # Remove an item from the header
    # Start with file_name constructor, to test that the repr is changed by the edit.
    orig_header = header
    header = galsim.FitsHeader(file_name=os.path.join(dir, file_name))
    assert header == orig_header
    del header['AIRMASS']
    assert 'AIRMASS' not in header
    if pyfits_version >= '3.1':
        assert len(header) == tpv_len - 1
    assert header != orig_header
    do_pickle(header)

    # Should be able to get with a default value if the key is not present
    assert header.get('AIRMASS', 2.0) == 2.0
    # key should still not be in the header
    assert 'AIRMASS' not in header
    if pyfits_version >= '3.1':
        assert len(header) == tpv_len - 1
    assert header != orig_header

    # Add items to a header
    header['AIRMASS'] = 2
    assert header.get('AIRMASS') == 2
    assert header != orig_header

    # Overwrite an existing value
    header['AIRMASS'] = 1.7
    assert header.get('AIRMASS') == 1.7
    assert header != orig_header

    # Set with a comment field
    header['AIRMASS'] = (1.9, 'The airmass of the observation')
    assert header.get('AIRMASS') == 1.9
    assert header != orig_header

    # Update with a dict
    d = {'AIRMASS': 1.185}
    header.update(d)
    assert header.get('AIRMASS') == 1.185
    # We are essentially back to where we started, except the len won't be right.
    # Deleting a key removed an item, but setting it overwrote a blank item.
    # But if we add back another one of these, we should be back to the original values.
    header.append('', '', useblanks=False)
    check_tpv(header)
    do_pickle(header)
    assert header != orig_header  # It's still not equal, because the AIRMASS item is in a
    # different location in the list, which is relevant for equality.

    # Clear all values
    header.clear()
    assert 'AIRMASS' not in header
    assert 'FILTER' not in header
    assert len(header) == 0
    do_pickle(header)
    assert header != orig_header
Beispiel #13
0
def main(argv):
    # For the file names, I pick a particular exposure.  The directory structure corresponds
    # to where the files are stored on folio at UPenn.

    root = 'DECam_00154912'

    # Directories in the Galsim repo
    img_dir = 'des_data'
    wl_dir = 'des_data'

    # Directories on Mike's laptop
    #img_dir = '/Users/Mike/Astro/des/SV/DECam_00154912_wl'
    #wl_dir = '/Users/Mike/Astro/des/SV/DECam_00154912_wl'

    # Directories on folio
    #img_dir = '/data3/DECAM/SV/DECam_154912'
    #wl_dir = '/data3/DECAM/wl/DECam_00154912_wl'

    # Set which chips to run on
    first_chip = 1
    last_chip = 62
    #first_chip = 12
    #last_chip = 12

    out_dir = 'output'

    # The random seed, so the results are deterministic
    random_seed = 1339201

    x_col = 'X_IMAGE'
    y_col = 'Y_IMAGE'
    flux_col = 'FLUX_AUTO'
    flag_col = 'FLAGS'

    xsize_key = 'NAXIS1'
    ysize_key = 'NAXIS2'
    pixel_scale_key = 'PIXSCAL1'
    sky_level_key = 'SKYBRITE'
    sky_sigma_key = 'SKYSIGMA'

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

    for chipnum in range(first_chip, last_chip + 1):
        print 'Start chip ', chipnum

        # Setup the file names
        image_file = '%s_%02d.fits.fz' % (root, chipnum)
        cat_file = '%s_%02d_cat.fits' % (root, chipnum)
        psfex_file = '%s_%02d_psfcat.psf' % (root, chipnum)
        fitpsf_file = '%s_%02d_fitpsf.fits' % (root, chipnum)
        psfex_image_file = '%s_%02d_psfex_image.fits' % (root, chipnum)
        fitpsf_image_file = '%s_%02d_fitpsf_image.fits' % (root, chipnum)

        # Get some parameters about the image from the data image header information
        image_header = galsim.FitsHeader(image_file, dir=img_dir)
        xsize = image_header[xsize_key]
        ysize = image_header[ysize_key]
        pixel_scale = image_header[pixel_scale_key]
        sky_sigma = image_header[
            sky_sigma_key]  # This is sqrt(variance) / pixel
        sky_level = image_header[sky_level_key]  # This is in ADU / pixel
        gain = sky_level / sky_sigma**2  # an approximation, since gain is missing.

        # Setup the images:
        psfex_image = galsim.ImageF(xsize, ysize)
        psfex_image.scale = pixel_scale
        fitpsf_image = galsim.ImageF(xsize, ysize)
        fitpsf_image.scale = pixel_scale

        # Read the other input files
        cat = galsim.Catalog(cat_file, hdu=2, dir=img_dir)
        psfex = galsim.des.DES_PSFEx(psfex_file, dir=wl_dir)
        fitpsf = galsim.des.DES_Shapelet(fitpsf_file, dir=wl_dir)

        nobj = cat.nobjects
        print 'Catalog has ', nobj, ' objects'

        for k in range(nobj):
            # The usual random number generator using a different seed for each galaxy.
            # I'm not actually using the rng for object creation (everything comes from the
            # input files), but the rng that matches the config version is here just in case.
            rng = galsim.BaseDeviate(random_seed + k)

            # Skip objects with a non-zero flag
            flag = cat.getInt(k, flag_col)
            if flag: continue

            # Get the position from the galaxy catalog
            x = cat.getFloat(k, x_col)
            y = cat.getFloat(k, y_col)
            ix = int(math.floor(x + 0.5))
            iy = int(math.floor(y + 0.5))
            dx = x - ix
            dy = y - iy
            image_pos = galsim.PositionD(x, y)
            print '    pos = ', image_pos

            # Also get the flux of the galaxy from the catalog
            flux = cat.getFloat(k, flux_col)

            # Define the pixel
            pix = galsim.Pixel(pixel_scale)

            # First do the PSFEx image:
            if True:
                # Define the PSF profile
                psf = psfex.getPSF(image_pos, pixel_scale)
                psf.setFlux(flux)

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

                # Apply partial-pixel shift
                final.applyShift(dx * pixel_scale, dy * pixel_scale)

                # Draw the postage stamp image
                stamp = final.draw(dx=pixel_scale)

                # Recenter the stamp at the desired position:
                stamp.setCenter(ix, iy)

                # Find overlapping bounds
                bounds = stamp.bounds & psfex_image.bounds
                psfex_image[bounds] += stamp[bounds]

            # Next do the ShapeletPSF image:
            # If the position is not within the interpolation bounds, fitpsf will
            # raise an exception telling us to skip this object.  Easier to check here.
            if fitpsf.bounds.includes(image_pos):
                # Define the PSF profile
                psf = fitpsf.getPSF(image_pos)
                psf.setFlux(flux)

                # Galsim doesn't have WCS functionality yet.
                # But for the shapelet PSF, it is important, since it really describes the
                # PSF in sky coordinates, not pixel coordinates.  But to first order,
                # the DES WCS is 90 degrees rotated from the sky, so for now, just apply
                # a 90 degree rotation to get the images to look approximately correct.
                # Eventually, we'll want to have a DES_WCS that can read the full WCS from
                # the fits header and account for all of the field distortion correctly.
                psf.applyRotation(-90 * galsim.degrees)

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

                # Apply partial-pixel shift
                final.applyShift(dx * pixel_scale, dy * pixel_scale)

                # Draw the postage stamp image
                stamp = final.draw(dx=pixel_scale)

                # Recenter the stamp at the desired position:
                stamp.setCenter(ix, iy)

                # Find overlapping bounds
                bounds = stamp.bounds & fitpsf_image.bounds
                fitpsf_image[bounds] += stamp[bounds]
            else:
                pass
                #print '...not in fitpsf.bounds'

        # Add background level
        psfex_image += sky_level
        fitpsf_image += sky_level

        # Add noise
        rng = galsim.BaseDeviate(random_seed + nobj)
        noise = galsim.CCDNoise(rng, gain=gain)
        psfex_image.addNoise(noise)
        # Reset the random seed to match the action of the yaml version
        # Note: the different between seed and reset matters here.
        # reset would sever the connection between this rng instance and the one stored in noise.
        # seed changes the seed while keeping the connection between them.
        rng.seed(random_seed + nobj)
        fitpsf_image.addNoise(noise)

        # Now write the images to disk.
        psfex_image.write(psfex_image_file, dir=out_dir)
        fitpsf_image.write(fitpsf_image_file, dir=out_dir)
        print 'Wrote images to %s and %s' % (os.path.join(
            out_dir, psfex_image_file), os.path.join(out_dir,
                                                     fitpsf_image_file))
Beispiel #14
0
def simImage(sourceDir,imFile,catFile,psfFile,outFile):

    """ 

    Create a simulated image using PSFEx modelled PSFs and noise properties of the source image 

    Input: sourceDir: input directory data
           imFile: imput image file name
           catFile: catalogue file (output from SeXtractor)
           psfFile: psf model (output from PSFEx)
           outFile: name of output file for image

    Output: writes to fits file. 

    The catFile must contain the fields X_IMAGE, Y_IMAGE, FLUX_APER (or the code to 
    be changed to equivalent for positions of sources and integrated flux). 

    """
    #load necessary stuff from files.

    #NOte that the MCS image files have two HDUs, one with
    #the WCS information, one with the image information. 
    
    galHdr1 = galsim.FitsHeader(imFile, dir=sourceDir, hdu=0)
    galHdr2 = galsim.FitsHeader(imFile, dir=sourceDir, hdu=1)
    cat = galsim.Catalog(catFile, hdu=2, dir=sourceDir, file_type="FITS")
    psfex=des.DES_PSFEx(psfFile,imFile,dir=sourceDir)
    image=galsim.fits.read(imFile,sourceDir,hdu=1)
    
    #get setup the image. match the (currently trivial) WCS with the image, and
    #create a blank image
    
    wcs = galsim.FitsWCS(header=galHdr1)
    xSize=galHdr2['NAXIS1']
    ySize=galHdr2['NAXIS2']
    simImage = galsim.Image(xSize, ySize, wcs=wcs)

    #some definitions for extracting catalogue columsn
    xCol="X_IMAGE"
    yCol="Y_IMAGE"
    fluxCol="FLUX_APER"

    #get noise statistics. Read in the catalogue positions to estimate the centre
    #of the image in whatever rotation it has. This is so we get the noise statistics
    #from teh mask region, excludin the rest of the image. 
    
    xVals=cat.data[xCol]
    yVals=cat.data[yCol]
    xMean=int(xVals.mean())
    yMean=int(yVals.mean())
    radius=1800

    subIm=image.array[int(xMean-radius):int(xMean+radius),int(yMean-radius):int(yMean+radius)]
    im,a,b=sigmaclip(subIm.ravel(),5,5)

    skyLevel=im.mean()
    skySigma=im.std()
    gain = skyLevel / skySigma**2  #this definition from teh galsim tutorials
    nobj = cat.nobjects

    print('Catalog has ',nobj,' objects. Sky level is ',int(skyLevel),' Sky sigma is ',int(skySigma))

    #now cycle over the catalogue.
    
    for k in range(nobj):

        #get position and flux
        x = cat.getFloat(k,xCol)
        y = cat.getFloat(k,yCol)
        flux = cat.getFloat(k,fluxCol)*5

        #some position calculation for the galsim routines
        # + 0.5 to account for even-size postage stamps
        x=x+0.5
        y=y+0.5
        ix = int(math.floor(x+0.5))
        iy = int(math.floor(y+0.5))
        dx = x-ix
        dy = y-iy

        imagePos = galsim.PositionD(x,y)
        offset = galsim.PositionD(dx,dy)

        #calculate PSF for given position and flux
        psf=psfex.getPSF(imagePos).withFlux(flux)

        #make image
        stamp = psf.drawImage(wcs=wcs.local(imagePos), offset=offset, method='no_pixel')
        stamp.setCenter(ix,iy)

        #and place on image, taking into consideration edges
        bounds = stamp.bounds & simImage.bounds
        simImage[bounds] += stamp[bounds]

    #now that we've done all the spots, add noise

    #background sky level
    simImage += skyLevel

    #CCD noise
    random_seed = 1339201
    rng=galsim.BaseDeviate(random_seed)
    noise = galsim.CCDNoise(rng, gain=gain)

    #poisonnian noise
    simImage.addNoise(noise)
    noise = galsim.PoissonNoise(rng, sky_level=skyLevel)
    simImage.addNoise(noise)

    #and dump to a file. Will overwrite existing file.
    simImage.write(outFile,clobber=True)
Beispiel #15
0
def test_read():
    """Test reading a FitsHeader from an existing FITS file
    """
    tpv_len = 215

    def check_tpv(header):
        """Check that the header object has correct values from the tpv.fits file
        """
        # Check using a few different access methods.
        assert header['TIME-OBS'] == '04:28:14.105'
        assert header.get('FILTER') == 'I'
        assert header['AIRMASS'] == 1.185
        assert len(header) == tpv_len
        assert 'ADC' in header
        assert ('FILPOS', 6) in header.items()
        assert ('FILPOS', 6) in header.iteritems()
        assert 'OBSERVAT' in header.keys()
        assert 'OBSERVAT' in header.iterkeys()
        assert 54384.18627436 in header.values()  # MJD-OBS
        assert 54384.18627436 in header.itervalues()

    file_name = 'tpv.fits'
    dir = 'fits_files'
    # First option: give a file_name
    header = galsim.FitsHeader(file_name=os.path.join(dir, file_name))
    check_tpv(header)
    do_pickle(header)
    # Let the FitsHeader init handle the dir
    header = galsim.FitsHeader(file_name=file_name, dir=dir)
    check_tpv(header)
    do_pickle(header)
    # If the first arg is a str, then it should be interpreted as a file name
    header = galsim.FitsHeader(file_name, dir=dir)
    check_tpv(header)
    # If you pass in a pyfits hdulist, that should also work
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(hdu_list=hdu_list)
    check_tpv(header)
    do_pickle(header)
    # Can explicitly give an hdu number to use.  In this case, there is only 1, so need to use 0.
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(hdu_list=hdu_list, hdu=0)
    check_tpv(header)
    do_pickle(header)
    # Can explicitly give an hdu number to use.  In this case, there is only 1, so need to use 0.
    header = galsim.FitsHeader(file_name=file_name, dir=dir, hdu=0)
    check_tpv(header)
    do_pickle(header)
    # If you pass in a pyfits Header object, that should also work
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(header=hdu_list[0].header)
    check_tpv(header)
    do_pickle(header)
    # The header is the first parameter, so don't need to name it.
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        header = galsim.FitsHeader(hdu_list[0].header)
    check_tpv(header)
    # FitsHeader can read from a compressed file too
    header = galsim.FitsHeader(file_name=file_name + '.gz',
                               dir=dir,
                               compression='auto')
    check_tpv(header)
    do_pickle(header)
    header = galsim.FitsHeader(file_name=file_name + '.gz',
                               dir=dir,
                               compression='gzip')
    check_tpv(header)
    do_pickle(header)

    assert_raises(TypeError,
                  galsim.FitsHeader,
                  file_name=file_name,
                  header=header)
    with pyfits.open(os.path.join(dir, file_name)) as hdu_list:
        assert_raises(TypeError,
                      galsim.FitsHeader,
                      file_name=file_name,
                      hdu_list=hdu_list)
        assert_raises(TypeError,
                      galsim.FitsHeader,
                      header=header,
                      hdu_list=hdu_list)

    # Remove an item from the header
    # Start with file_name constructor, to test that the repr is changed by the edit.
    orig_header = header
    header = galsim.FitsHeader(file_name=os.path.join(dir, file_name))
    assert header == orig_header
    del header['AIRMASS']
    assert 'AIRMASS' not in header
    assert len(header) == tpv_len - 1
    assert header != orig_header
    do_pickle(header)

    # Should be able to get with a default value if the key is not present
    assert header.get('AIRMASS', 2.0) == 2.0
    # key should still not be in the header
    assert 'AIRMASS' not in header
    assert len(header) == tpv_len - 1
    assert header != orig_header

    # Add items to a header
    header['AIRMASS'] = 2
    assert header.get('AIRMASS') == 2
    assert header != orig_header

    # Pop does a similar thing:
    assert header.pop('AIRMASS') == 2.0
    assert 'AIRMASS' not in header

    # Works if not preset, given default
    assert header.pop('AIRMASS', 2.0) == 2.0
    assert 'AIRMASS' not in header
    header['AIRMASS'] = 2
    assert header['AIRMASS'] == 2

    # Get real value if preset and given default value
    assert header.pop('AIRMASS', 1.9) == 2.0
    assert 'AIRMASS' not in header
    header['AIRMASS'] = 2
    assert header['AIRMASS'] == 2

    # Overwrite an existing value
    header['AIRMASS'] = 1.7
    assert header.get('AIRMASS') == 1.7
    assert header != orig_header

    # Set with a comment field
    header['AIRMASS'] = (1.9, 'The airmass of the observation')
    assert header.get('AIRMASS') == 1.9
    assert header != orig_header

    # Update with a dict
    d = {'AIRMASS': 1.185}
    header.update(d)
    assert header.get('AIRMASS') == 1.185

    # Extend is similar, but skip duplicates, and must be a FitsHeader
    h = galsim.FitsHeader({'AIRMASS': 1.2, 'RA': 123})
    header.extend(h)
    assert header['AIRMASS'] == 1.185  # unchanged
    assert header['RA'] == 123

    # If replace = true, then update to the new values.
    h['DEC'] = -22.5
    header.extend(h, replace=True)
    assert header['AIRMASS'] == 1.2  # changed
    assert header['RA'] == 123
    assert header['DEC'] == -22.5

    # We are essentially back to where we started, except the len won't be right.
    # Deleting a key removed an item each time, but setting it overwrote a blank item.
    # But if we add back another few of these, we should be back to the original values.
    header.append('', '', useblanks=False)
    header.append('', '', useblanks=False)
    header.append('', '', useblanks=False)
    header['AIRMASS'] = 1.185
    check_tpv(header)
    do_pickle(header)
    assert header != orig_header  # It's still not equal, because the AIRMASS item is in a
    # different location in the list, which is relevant for equality.

    # Clear all values
    header.clear()
    assert 'AIRMASS' not in header
    assert 'FILTER' not in header
    assert len(header) == 0
    do_pickle(header)
    assert header != orig_header
except:
    pass

psfimg = psf.drawImage(nx=args.nx, ny=args.nx, scale=0.2)
psfimg.write(os.path.join(args.outdir, 'psf.fits'))

infile = h5py.File(args.h5read)
for i, datum in enumerate(infile['data']):
    ra, dec, z, r, mag, e1, e2, g1, g2 = datum
    flux = etc.flux(mag)
    print i, mag, flux, e1, e2
    gal = (galsim.Exponential(half_light_radius=0.3).shear(e1=e1, e2=e2).shear(
        e1=g1, e2=g2).withFlux(flux))

    obj = galsim.Convolve(gal, psf)
    img = obj.drawImage(nx=args.nx, ny=args.nx, scale=0.2)
    img.addNoise(noise)
    h1 = galsim.FitsHeader()
    h1['RA'] = ra
    h1['DEC'] = dec
    h1['z'] = z
    h1['r'] = r
    h1['mag'] = mag
    h1['e1'] = e1
    h1['e2'] = e2
    h1['g1'] = g1
    h1['g2'] = g2
    img.header = h1
    # future proof with 11 digit filename #
    img.write(os.path.join(args.outdir, 'gal{0:011d}.fits'.format(i)))
Beispiel #17
0
    def buildImages(self, config, base, file_num, image_num, obj_num, ignore,
                    logger):
        """Build the images

        @param config           The configuration dict for the output field.
        @param base             The base configuration dict.
        @param file_num         The current file_num.
        @param image_num        The current image_num.
        @param obj_num          The current obj_num.
        @param ignore           A list of parameters that are allowed to be in config that we can
                                ignore here.  i.e. it won't be an error if they are present.
        @param logger           If given, a logger object to log progress.

        @returns a list of the images built
        """
        if 'nobjects' not in config:
            nobjects = galsim.config.ProcessInputNObjects(base)
            config['nobjects'] = nobjects
        req = {
            'nobjects': int,
            'nchips': int,
            'output_style': str,
        }
        opt = {
            'pointing_ra': galsim.Angle,
            'pointing_dec': galsim.Angle,
        }
        ignore = ignore + ['reference_wcs', 'reference_image']

        kwargs, safe = galsim.config.GetAllParams(config,
                                                  base,
                                                  req=req,
                                                  opt=opt,
                                                  ignore=ignore)

        nobjects = kwargs['nobjects']
        nchips = kwargs['nchips']
        output_style = kwargs['output_style']

        base['image']['nobjects'] = nobjects

        if 'eval_variables' not in base:
            base['eval_variables'] = {}

        # Read the reference wcs and image size
        if 'reference_wcs' not in config:
            raise ValueError(
                "reference_wcs is required for FocalPlane output type")
        if 'reference_image' not in config:
            raise ValueError(
                "reference_image is required for FocalPlane output type")
        if 'file_name' not in config['reference_image']:
            raise ValueError("file_name is required for reference_image")

        bounds = galsim.BoundsD()
        self.focal_wcs = []
        self.focal_size = []
        w_pos_list = []
        for chip_num in range(nchips):
            base['chip_num'] = chip_num
            base['eval_variables']['ichip_num'] = chip_num
            wcs_type = config['reference_wcs']['type']
            wcs_builder = galsim.config.wcs.valid_wcs_types[wcs_type]
            wcs = wcs_builder.buildWCS(config['reference_wcs'], base)
            self.focal_wcs.append(wcs)
            file_name = galsim.config.ParseValue(config['reference_image'],
                                                 'file_name', base, str)[0]
            if 'dir' in config['reference_image']:
                dir = galsim.config.ParseValue(config['reference_image'],
                                               'dir', base, str)[0]
                file_name = os.path.join(dir, file_name)
            header = galsim.FitsHeader(file_name)
            xsize = header['NAXIS1']
            ysize = header['NAXIS2']
            self.focal_size.append((xsize, ysize))

            im_pos1 = galsim.PositionD(0, 0)
            im_pos2 = galsim.PositionD(0, ysize)
            im_pos3 = galsim.PositionD(xsize, 0)
            im_pos4 = galsim.PositionD(xsize, ysize)
            w_pos_list.append(wcs.toWorld(im_pos1))
            w_pos_list.append(wcs.toWorld(im_pos2))
            w_pos_list.append(wcs.toWorld(im_pos3))
            w_pos_list.append(wcs.toWorld(im_pos4))

        for w_pos in w_pos_list:
            w_pos._set_aux()
        pointing_x = np.mean([w_pos._x for w_pos in w_pos_list])
        pointing_y = np.mean([w_pos._y for w_pos in w_pos_list])
        pointing_z = np.mean([w_pos._z for w_pos in w_pos_list])
        # TODO: Fix this to work when crossing RA = 0.
        pointing_minra = np.min([w_pos.ra for w_pos in w_pos_list])
        pointing_maxra = np.max([w_pos.ra for w_pos in w_pos_list])
        pointing_mindec = np.min([w_pos.dec for w_pos in w_pos_list])
        pointing_maxdec = np.max([w_pos.dec for w_pos in w_pos_list])
        pointing_ra = np.arctan2(pointing_y, pointing_x)
        pointing_dec = np.arctan2(pointing_z,
                                  np.sqrt(pointing_x**2 + pointing_y**2))
        pointing = galsim.CelestialCoord(pointing_ra, pointing_dec)
        proj_list = [
            pointing.project(w_pos, projection='gnomonic')
            for w_pos in w_pos_list
        ]
        for proj in proj_list:
            bounds += proj
        base['pointing'] = pointing
        base['eval_variables']['fpointing_ra'] = pointing_ra
        base['eval_variables']['fpointing_dec'] = pointing_dec
        base['eval_variables']['fpointing_minra'] = pointing_minra
        base['eval_variables']['fpointing_maxra'] = pointing_maxra
        base['eval_variables']['fpointing_mindec'] = pointing_mindec
        base['eval_variables']['fpointing_maxdec'] = pointing_maxdec
        base['eval_variables']['ifirst_image_num'] = base['image_num']
        base['eval_variables']['ichip_num'] = '$image_num - first_image_num'
        rmax = np.max([proj.x**2 + proj.y**2 for proj in proj_list])**0.5

        seed_offset = [1 - k * nobjects for k in range(nimages)]
        base['stamp']['seed_offset'] = {
            'index_key': 'image_num',
            'type': 'List',
            'items': seed_offset
        }

        if 'meta_params' in base:
            for key in base['meta_params']:
                param = galsim.config.ParseValue(base['meta_params'], key,
                                                 base, float)
                base['eval_variables']['f' + key] = param

        base['eval_variables']['ffocal_xmin'] = bounds.xmin
        base['eval_variables']['ffocal_xmax'] = bounds.xmax
        base['eval_variables']['ffocal_ymin'] = bounds.ymin
        base['eval_variables']['ffocal_ymax'] = bounds.ymax
        base['eval_variables']['ffocal_r'] = {
            'type':
            'Eval',
            'str':
            "base['pointing'].project(galsim.CelestialCoord(@gal.ra, @gal.dec))"
        }
        base['eval_variables']['ffocal_rmax'] = rmax

        return galsim.config.BuildImages(nimages,
                                         base,
                                         image_num,
                                         obj_num,
                                         logger=logger)