def test_flux_calib_corr(datadir, plot=False):
    """
    Test the handling of the flux calibration
    """

    filename = datadir.join("test_sensitivity_cube.fits").strpath
    #filename = datadir.join("test.fits").strpath
    fcalib_corr = datadir.join("polyvals.txt").strpath
    wavelengths = [3500.0, 5500.0]
    alphas = [-3.5, -3.5]

    scube = SensitivityCube.from_file(filename, wavelengths, alphas)
    scube_corr1 = SensitivityCube.from_file(filename, wavelengths, alphas)
    scube_corr1.apply_flux_recalibration(
        1.0, flux_calib_correction_file=fcalib_corr)

    # The aper_corr should be multiplied though in the cubes
    ratio = scube.sigmas.filled() / scube_corr1.sigmas.filled()

    if plot:
        import matplotlib.pyplot as plt
        ra, dec, wls = scube.wcs.wcs_pix2world(0, 0,
                                               range(scube.sigmas.shape[0]), 0)
        plt.plot(wls,
                 (scube.f50vals[:, 10, 10] - scube_corr1.sigmas[:, 10, 10]) /
                 scube.sigmas[:, 10, 10])
        plt.show()

    # Check something happened
    assert ratio != pytest.approx(1.0)
Example #2
0
def sensitivity_cube(datadir):
    """ A sensitivity cube to add or read"""
    filename = datadir.join("test_sensitivity_cube.fits").strpath
    wavelengths = [3500.0, 5500.0]
    alphas = [-3.5, -3.5]

    return SensitivityCube.from_file(filename, wavelengths, alphas)
def test_aper_corr(datadir, aper_corr):
    """
    Test the handling of the aperture
    correction
    """
    filename = datadir.join("test_sensitivity_cube.fits").strpath
    wavelengths = [3500.0, 5500.0]
    alphas = [-3.5, -3.5]

    scube = SensitivityCube.from_file(filename,
                                      wavelengths,
                                      alphas,
                                      aper_corr=aper_corr)

    scube_corr1 = SensitivityCube.from_file(filename,
                                            wavelengths,
                                            alphas,
                                            aper_corr=1.0)

    # The aper_corr should be multiplied though in the cubes
    ratio = scube.sigmas.filled() / scube_corr1.sigmas.filled()

    assert ratio == pytest.approx(aper_corr)
def test_completeness_func(datadir, flux, model, sncut, expected):
    """
    Test that a value is returned
    """
    filename = datadir.join("test_sensitivity_cube.fits").strpath
    wavelengths = [3500.0, 5500.0]
    alphas = [-3.5, -3.5]

    if model == "hdr1":
        scube = SensitivityCube.from_file(filename,
                                          wavelengths,
                                          alphas,
                                          nsigma=1.0,
                                          flim_model=model,
                                          aper_corr=None)
    else:
        scube = SensitivityCube.from_file(filename,
                                          wavelengths,
                                          alphas,
                                          nsigma=1.0,
                                          flim_model=model)

    c = scube.return_completeness(flux, 161.4201, 50.8822, 3478, sncut)
    assert c == pytest.approx(expected)
def create_sensitivity_cube_from_astrom(racen,
                                        deccen,
                                        pa,
                                        nx,
                                        ny,
                                        nz,
                                        ifusize,
                                        wrange=[3470.0, 5542.0],
                                        **kwargs):
    """
    Return an (empty) sensitivity cube object to fill
    with data from simulations later

    Parameters
    ----------
    racen, deccen : float
        the central coordinates of the IFU
    pa : float
        the IFU rotation
    nx, ny, nz : int
        the dimensions of the cube in ra, dec, wave
    ifusize : float
        the length of an IFU side in arcsec
    wrange : array (optional)
        the lower and upper wavelength
        limits in Angstrom
    ***kwargs : 
        arguments to pass to SensitivityCube
    """

    cards = {}
    cards["NAXIS"] = 3
    cards["NAXIS1"] = nx
    cards["NAXIS2"] = ny
    cards["NAXIS3"] = nz
    cards["CTYPE1"] = "RA---TAN"
    cards["CTYPE2"] = "DEC--TAN"
    cards["CTYPE3"] = "Wave "
    cards["CUNIT1"] = "deg "
    cards["CUNIT2"] = "deg "

    cards["CRPIX1"] = nx / 2. + 0.5
    cards["CRPIX2"] = ny / 2. + 0.5
    cards["CRPIX3"] = 1.0

    coord = SkyCoord(racen * u.deg, deccen * u.deg)
    cards["CRVAL1"] = racen  #deg
    cards["CRVAL2"] = deccen  #deg
    cards["CRVAL3"] = wrange[0]  #AA

    deltapix = (float(ifusize) / nx / 3600.0)

    # this is rotation in focal plane, maybe not the IFU
    rot = deg2rad(pa)
    cards["CROTA2"] = pa
    cards["CD1_1"] = deltapix * cos(rot)
    cards["CD1_2"] = deltapix * sin(rot)
    cards["CD1_3"] = 0.0
    cards["CD2_1"] = -1.0 * deltapix * sin(rot)
    cards["CD2_2"] = deltapix * cos(rot)
    cards["CD2_3"] = 0.0
    cards["CD3_1"] = 0.0
    cards["CD3_2"] = 0.0
    cards["CD3_3"] = (wrange[1] - wrange[0]) / nz

    header = Header(cards=cards)
    sigmas = zeros((nz, ny, nx))
    alphas = zeros((nz, ny, nx))

    return SensitivityCube(sigmas,
                           header,
                           None,
                           alphas,
                           aper_corr=1.0,
                           nsigma=1.0,
                           **kwargs)
Example #6
0
def add_sensitivity_cube_to_hdf5(args=None):
    """
    Command line tool to add a sensitivity cube(s) 
    to an HDF5 containter

    """
    import argparse

    parser = argparse.ArgumentParser(
        description="Add sensitivty cubes to HDF5 container",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )

    parser.add_argument(
        "--regex",
        default=".*(2[0-9]{7}v[0-9]{3})_[0-9]{3}_([0-9]{3})",
        help="""Regex with two capture groups, the first for datevshot the second 
                                for IFU slot""",
    )

    parser.add_argument("--append", action="store_true", help="Append to existing HDF5")

    parser.add_argument(
        "--alpha", type=float, help="Alpha for Fleming function", default=-3.5
    )

    parser.add_argument(
        "fits_files",
        type=str,
        nargs="+",
        help="Files to add, filename must follow convention set out in --regex option",
    )

    parser.add_argument("hdf5_out", type=str, help="HDF5 container to add to")

    opts = parser.parse_args(args=args)

    if opts.append:
        hdfcont = SensitivityCubeHDF5Container(opts.hdf5_out, mode="a")
    else:
        hdfcont = SensitivityCubeHDF5Container(opts.hdf5_out, mode="w")

    # Compile the regex so it's faster
    regex = compile(opts.regex)

    for fn in opts.fits_files:

        m = regex.match(fn)
        datevshot = m.group(1)
        ifuslot = m.group(2)
        _logger.info(
            "Inserting {:s} with dateshot {:s} and IFU slot {:s}".format(
                fn, datevshot, ifuslot
            )
        )
        scube = SensitivityCube.from_file(
            fn, [3500.0, 5500.0], [opts.alpha, opts.alpha]
        )
        hdfcont.add_sensitivity_cube("virus_" + datevshot, "ifuslot_" + ifuslot, scube)

    hdfcont.close()
Example #7
0
    def extract_ifu_sensitivity_cube(self, ifuslot, datevshot=None, 
                                     cache_sim_interp=True):
        """
        Extract the sensitivity cube
        from IFU (ifuslot). If multiple
        shots are saved in the file specify
        which to use with datevshot

        Parameters
        ----------
        ifuslot : string
            the IFU slot to extract
        datevshot : string (Optional)
            the datevshot if multiple
            shots are stored in the 
            HDF5. If None then test
            that one shot is present 
            and return the IFU
            for that
        cache_sim_interp : bool
            cache the simulation interpolator
            to speed up execution (default: True)
 
        Returns
        -------
        scube : hetdex_api.flux_limits.sensitivity_cube:SensitivityCube
            the sensitivity cube
        """

        # Use first shot if dateshot not specified
        if not datevshot:
            shots = self.h5file.list_nodes(self.h5file.root)
            nshots = len(shots)
            if nshots > 1:
                _logger.warn(
                    """Datevshot not specified but multiple shots in file!
                                Using first in file."""
                )

            shot = shots[0]
        else:
            shot = self.h5file.get_node(self.h5file.root, name=datevshot)


        if self.h5mask:
            mask = self.h5mask.get_node(self.h5mask.root.Mask, 
                                        name=ifuslot).read()
        else:
            mask = None

        # Now get the desired IFU
        ifu = self.h5file.get_node(shot, name=ifuslot)

        # Extract the data we need for a sensitivity cube
        header = ifu.attrs.header
        wavelengths = ifu.attrs.wavelengths
        alphas = ifu.attrs.alphas

        # Remove any aperture correction
        sigmas = ifu.read() / ifu.attrs.aper_corr

        try:
            nsigma = ifu.attrs.nsigma
        except AttributeError as e:
            if self.flim_model == "hdr1":
                nsigma = 6.0
            else:
                nsigma = 1.0
            print("No nsigma found, assuming nsigma={:2.1f} ".format(nsigma))

        # Force apcor to be 1.0 here, so we don't double count it
        return SensitivityCube(sigmas, header, wavelengths, alphas, 
                               nsigma=nsigma, flim_model=self.flim_model,
                               aper_corr=self.aper_corr, mask=mask,
                               cache_sim_interp=cache_sim_interp)
Example #8
0
    def itercubes(self, datevshot=None, cache_sim_interp=True):
        """ 
        Iterate over the IFUs 

        Parameters
        ----------
        datevshot : str (Optional)
            specify a datevshot or
            just take the first shot in
            the HDF5 file

        Yields
        ------
        ifuslot : str
           the IFU slot of the 
           returned IFU
        scube : SensitivityCube
           a sensitivity cube
           object

        """
        # Use first shot if dateshot not specified
        if not datevshot:
            shots = self.h5file.list_nodes(self.h5file.root)
            nshots = len(shots)
            if nshots > 1:
                _logger.warn(
                    """Datevshot not specified but multiple shots in file!
                                Using first in file."""
                )

            shot = shots[0]
        else:
            shot = self.h5file.get_node(self.h5file.root, name=datevshot)

        first = True
        warn = True
        for ifu in shot:

            # Extract the data we need for a sensitivity cube
            header = ifu.attrs.header
            wavelengths = ifu.attrs.wavelengths
            alphas = ifu.attrs.alphas
            sigmas = ifu.read() / ifu.attrs.aper_corr

            if first:
                verbose = self.verbose
                first = False
            else:
                verbose = False

            if self.h5mask:
                mask = self.h5mask.get_node(self.h5mask.root.Mask, 
                                            name=ifu.name).read()
            else:
                mask = None

            try:
                nsigma = ifu.attrs.nsigma
            except AttributeError as e:
                if self.flim_model == "hdr1":
                    nsigma = 6.0
                else:
                    nsigma = 1.0
                if warn:
                    print("No nsigma found, assuming nsigma={:2.1f} (warning will not repeat)".format(nsigma))
                    warn = False

            # XXX HACK HACK HACK to change alpha
            #alphas = [-1.9, -1.9]

            yield ifu.name, SensitivityCube(sigmas, header, wavelengths, alphas, 
                                            flim_model=self.flim_model,
                                            aper_corr=self.aper_corr, 
                                            nsigma=nsigma, mask=mask, 
                                            verbose=verbose, 
                                            cache_sim_interp=cache_sim_interp)
Example #9
0
def collapse_datacubes_command(args=None):
    """
    Produce combined flux limit versus 
    wavelength estimates for sensitivity
    cubes passed on command line 
    """
    import argparse

    # Command line options
    parser = argparse.ArgumentParser(description="""
                                                 Collapse the RA and DEC of a single or 
                                                 set of sensitivity cube(s) to
                                                 produce one file of 50% flux limit versus
                                                 wavelength.
                                                 """)

    parser.add_argument("--plot",
                        type=str,
                        help="Filename for optional plot",
                        default="")

    parser.add_argument(
        "--fmin",
        help="Minimum flux to consider when interpolating for 50% limit",
        type=float,
        default=1e-17)

    parser.add_argument(
        "--fmax",
        help="""Maximum flux to consider when interpolating for 50% limit.
                                          Regions not 99% at this flux ignored!""",
        type=float,
        default=1e-15)

    parser.add_argument(
        "--nbins",
        help=
        "Number of flux bin to use when interpolating to measure 50% limit",
        type=int,
        default=100)

    parser.add_argument(
        "--alpha",
        help="The alpha of the Fleming function fit (default=-3.5)",
        default=-3.5,
        type=float)

    parser.add_argument(
        "scubes",
        nargs='+',
        help="The sensitivity cube(s) you want to collapse and combine")
    parser.add_argument("output", help="(Ascii) file to output to", type=str)
    opts = parser.parse_args(args=args)

    # Stores a list of the completeness versus flux and lambda for
    # all the cubes
    compl_cube_list = []

    # Flux bins to compute completeness in
    fluxes = linspace(opts.fmin, opts.fmax, opts.nbins)

    # A list of the number of good pixels in each cube as
    # a function of wavelength
    npixes_list = []
    for cube_name in opts.scubes:

        # Currently fix the alpha versus wavelength
        tscube = SensitivityCube.from_file(cube_name, [3500.0, 5500.0],
                                           [opts.alpha, opts.alpha])
        lambda_, npix, compls = return_spatially_collapsed_cube(tscube, fluxes)

        compl_cube_list.append(compls)
        npixes_list.append(npix)

    # Produce a combined cube of completness versus flux and lambda,
    # weighted by the number of good pixels in each cube
    combined_cube = compl_cube_list[0] * npixes_list[0]
    for npix, compl_cube in zip(npixes_list[1:], compl_cube_list[1:]):
        combined_cube += npix * compl_cube

    # This should give the correct completeness versus lambda and flux, ignoring empty pixels
    combined_cube /= sum(array(npixes_list), axis=0)

    # This should give is the 50% flux limits and the new alpha values
    f50vals, alphas = compute_new_fleming_fits(lambda_, fluxes, combined_cube)

    if opts.plot:
        plot_collapsed_cube(f50vals, alphas, lambda_, fluxes, combined_cube,
                            opts.plot)

    # Write out
    table = Table([lambda_, f50vals, alphas],
                  names=["wavelength", "f50", "alpha"])
    table.write(opts.output, format="ascii")