Пример #1
0
def test_qa():
    """ Test QA """
    if os.getenv('RUN_ALL_PYPIT_TESTS') is None:
        assert True
        return
    # Setup
    #wvmnx = [[5000., 6000.],
    #         [5000.5, 6000.5],
    #         [5000.8, 6000.8],
    #         ]
    #npix = [1000, 1000, 1000]
    dspec = dummy_spectra(s2n=10.)#, wvmnx=wvmnx, npix=npix)
    dspec.data['flux'][0, 700] *= 1000.  # One bad pixel
    dspec.data['sig'][0, 700] *= 500.
    coadd.coadd_spectra(dspec, wave_method='concatenate', qafile='tst.pdf')
Пример #2
0
def test_coadd():
    """ Test full coadd method"""
    # Setup
    dspec = dummy_spectra(s2n=10.)
    dspec.data['flux'][0, 700] *= 1000.  # One bad pixel
    dspec.data['sig'][0, 700] *= 500.
    spec1d = coadd.coadd_spectra(kast_blue, None, dspec, wave_grid_method='concatenate')
    assert np.isclose(np.median(spec1d.flux.value), 1., atol=0.003)
Пример #3
0
def test_coadd_with_fluxing():
    """ Test full coadd method with flux scaling"""
    scale_dict = dict(filter='DECAM-R', mag=19.0, mag_type='AB')
    # Setup
    dspec = dummy_spectra(s2n=10.)
    dspec.data['flux'][0, 700] *= 1000.  # One bad pixel
    dspec.data['sig'][0, 700] *= 500.
    spec1d = coadd.coadd_spectra(kast_blue, None, dspec, wave_grid_method='concatenate', flux_scale=scale_dict)
    # Test
    assert np.median(spec1d.flux.value) > 6.61
Пример #4
0
def ech_coadd(files,
              objids=None,
              extract='OPT',
              flux=True,
              giantcoadd=False,
              orderscale='median',
              mergeorder=True,
              wave_grid_method='velocity',
              niter=5,
              wave_grid_min=None,
              wave_grid_max=None,
              v_pix=None,
              scale_method='auto',
              do_offset=False,
              sigrej_final=3.,
              do_var_corr=False,
              SN_MIN_MEDSCALE=0.5,
              overlapfrac=0.01,
              num_min_pixels=10,
              phot_scale_dicts=None,
              qafile=None,
              outfile=None,
              do_cr=True,
              debug=False,
              **kwargs):
    """
    routines for coadding spectra observed with echelle spectrograph.
    parameters:
        files (list): file names
        objids (str): objid
        extract (str): 'OPT' or 'BOX'
        flux (bool): fluxed or not
        giantcoadd (bool): coadding order by order or do it at once?
        wave_grid_method (str): default velocity
        niter (int): number of iteration for rejections
        wave_grid_min (float): min wavelength, None means it will find the min value from your spectra
        wave_grid_max (float): max wavelength, None means it will find the max value from your spectra
        v_pix (float): delta velocity, see coadd.py
        scale_method (str): see coadd.py
        do_offset (str): see coadd.py, not implemented yet.
        sigrej_final (float): see coadd.py
        do_var_corr (bool): see coadd.py, default False. It seems True will results in a large error
        SN_MIN_MEDSCALE (float): minimum SNR for scaling different orders
        overlapfrac (float): minimum overlap fraction for scaling different orders.
        qafile (str): name of qafile
        outfile (str): name of coadded spectrum
        do_cr (bool): remove cosmic rays?
        debug (bool): show debug plots?
        kwargs: see coadd.py
    returns:
        spec1d: coadded XSpectrum1D
    """

    nfile = len(files)
    if nfile <= 1:
        msgs.info('Only one spectrum exits coadding...')
        return

    fname = files[0]
    ext_final = fits.getheader(fname, -1)
    norder = ext_final['ECHORDER'] + 1
    msgs.info('spectrum {:s} has {:d} orders'.format(fname, norder))
    if norder <= 1:
        msgs.error(
            'The number of orders have to be greater than one for echelle. Longslit data?'
        )

    if giantcoadd:
        msgs.info('Coadding all orders and exposures at once')
        spectra = load.ech_load_spec(files,
                                     objid=objids,
                                     order=None,
                                     extract=extract,
                                     flux=flux)
        wave_grid = np.zeros((2, spectra.nspec))
        for i in range(spectra.nspec):
            wave_grid[0, i] = spectra[i].wvmin.value
            wave_grid[1, i] = spectra[i].wvmax.value
        ech_kwargs = {
            'echelle': True,
            'wave_grid_min': np.min(wave_grid),
            'wave_grid_max': np.max(wave_grid),
            'v_pix': v_pix
        }
        kwargs.update(ech_kwargs)
        # Coadding
        spec1d = coadd.coadd_spectra(spectra,
                                     wave_grid_method=wave_grid_method,
                                     niter=niter,
                                     scale_method=scale_method,
                                     do_offset=do_offset,
                                     sigrej_final=sigrej_final,
                                     do_var_corr=do_var_corr,
                                     qafile=qafile,
                                     outfile=outfile,
                                     do_cr=do_cr,
                                     debug=debug,
                                     **kwargs)
    else:
        msgs.info('Coadding individual orders first and then merge order')
        spectra_list = []
        # Keywords for Table
        rsp_kwargs = {}
        rsp_kwargs['wave_tag'] = '{:s}_WAVE'.format(extract)
        rsp_kwargs['flux_tag'] = '{:s}_FLAM'.format(extract)
        rsp_kwargs['sig_tag'] = '{:s}_FLAM_SIG'.format(extract)
        #wave_grid = np.zeros((2,norder))
        for iord in range(norder):
            spectra = load.ech_load_spec(files,
                                         objid=objids,
                                         order=iord,
                                         extract=extract,
                                         flux=flux)
            ech_kwargs = {
                'echelle': False,
                'wave_grid_min': spectra.wvmin.value,
                'wave_grid_max': spectra.wvmax.value,
                'v_pix': v_pix
            }
            #wave_grid[0,iord] = spectra.wvmin.value
            #wave_grid[1,iord] = spectra.wvmax.value
            kwargs.update(ech_kwargs)
            # Coadding the individual orders
            if qafile is not None:
                qafile_iord = qafile + '_%s' % str(iord)
            else:
                qafile_iord = None
            spec1d_iord = coadd.coadd_spectra(
                spectra,
                wave_grid_method=wave_grid_method,
                niter=niter,
                scale_method=scale_method,
                do_offset=do_offset,
                sigrej_final=sigrej_final,
                do_var_corr=do_var_corr,
                qafile=qafile_iord,
                outfile=None,
                do_cr=do_cr,
                debug=debug,
                **kwargs)
            spectrum = spec_from_array(spec1d_iord.wavelength,
                                       spec1d_iord.flux, spec1d_iord.sig,
                                       **rsp_kwargs)
            spectra_list.append(spectrum)

        spectra_coadd = collate(spectra_list)

        # Rebin the spectra
        # ToDo: we should read in JFH's wavelength grid here.
        # Join into one XSpectrum1D object
        # Final wavelength array
        kwargs['wave_grid_min'] = np.min(
            spectra_coadd.data['wave'][spectra_coadd.data['wave'] > 0])
        kwargs['wave_grid_max'] = np.max(
            spectra_coadd.data['wave'][spectra_coadd.data['wave'] > 0])
        wave_final = coadd.new_wave_grid(spectra_coadd.data['wave'],
                                         wave_method=wave_grid_method,
                                         **kwargs)
        # The rebin function in linetools can not work on collated spectra (i.e. filled 0).
        # Thus I have to rebin the spectra first and then collate again.
        spectra_list_new = []
        for i in range(spectra_coadd.nspec):
            speci = spectra_list[i].rebin(wave_final * units.AA,
                                          all=True,
                                          do_sig=True,
                                          grow_bad_sig=True,
                                          masking='none')
            spectra_list_new.append(speci)
        spectra_coadd_rebin = collate(spectra_list_new)

        ## Note
        if orderscale == 'photometry':
            # Only tested on NIRES.
            if phot_scale_dicts is not None:
                spectra_coadd_rebin = order_phot_scale(spectra_coadd_rebin,
                                                       phot_scale_dicts,
                                                       debug=debug)
            else:
                msgs.warn(
                    'No photometric information is provided. Will use median scale.'
                )
                orderscale = 'median'
        elif orderscale == 'median':
            #rmask = spectra_coadd_rebin.data['sig'].filled(0.) > 0.
            #sn2, weights = coadd.sn_weights(fluxes, sigs, rmask, wave)
            ## scaling different orders
            order_median_scale(spectra_coadd_rebin,
                               nsig=sigrej_final,
                               niter=niter,
                               overlapfrac=overlapfrac,
                               num_min_pixels=num_min_pixels,
                               SN_MIN_MEDSCALE=SN_MIN_MEDSCALE,
                               debug=debug)
        else:
            msgs.warn('No any scaling is performed between different orders.')

        if mergeorder:
            fluxes, sigs, wave = coadd.unpack_spec(spectra_coadd_rebin,
                                                   all_wave=False)
            ## Megering orders
            msgs.info('Merging different orders')
            ## ToDo: Joe claimed not to use pixel depedent weighting.
            weights = 1.0 / sigs**2
            weights[~np.isfinite(weights)] = 0.0
            weight_combine = np.sum(weights, axis=0)
            weight_norm = weights / weight_combine
            weight_norm[np.isnan(weight_norm)] = 1.0
            flux_final = np.sum(fluxes * weight_norm, axis=0)
            sig_final = np.sqrt(np.sum((weight_norm * sigs)**2, axis=0))
            spec1d_final = spec_from_array(wave_final * units.AA, flux_final,
                                           sig_final, **rsp_kwargs)

            if outfile is not None:
                msgs.info(
                    'Saving the final calibrated spectrum as {:s}'.format(
                        outfile))
                coadd.write_to_disk(spec1d_final, outfile)

            if (qafile is not None) or (debug):
                # plot and save qa
                plt.figure(figsize=(12, 6))
                ax1 = plt.axes([0.07, 0.13, 0.9, 0.4])
                ax2 = plt.axes([0.07, 0.55, 0.9, 0.4])
                plt.setp(ax2.get_xticklabels(), visible=False)

                medf = np.median(spec1d_final.flux)
                ylim = (np.sort([0. - 0.3 * medf, 5 * medf]))
                cmap = plt.get_cmap('RdYlBu_r')
                for idx in range(spectra_coadd_rebin.nspec):
                    spectra_coadd_rebin.select = idx
                    color = cmap(float(idx) / spectra_coadd_rebin.nspec)
                    ind_good = spectra_coadd_rebin.sig > 0
                    ax1.plot(spectra_coadd_rebin.wavelength[ind_good],
                             spectra_coadd_rebin.flux[ind_good],
                             color=color)

                if (np.max(spec1d_final.wavelength) > (9000.0 * units.AA)):
                    skytrans_file = resource_filename(
                        'pypeit',
                        '/data/skisim/atm_transmission_secz1.5_1.6mm.dat')
                    skycat = np.genfromtxt(skytrans_file, dtype='float')
                    scale = 0.85 * ylim[1]
                    ax2.plot(skycat[:, 0] * 1e4,
                             skycat[:, 1] * scale,
                             'm-',
                             alpha=0.5)

                ax2.plot(spec1d_final.wavelength,
                         spec1d_final.sig,
                         ls='steps-',
                         color='0.7')
                ax2.plot(spec1d_final.wavelength,
                         spec1d_final.flux,
                         ls='steps-',
                         color='b')

                ax1.set_xlim([
                    np.min(spec1d_final.wavelength.value),
                    np.max(spec1d_final.wavelength.value)
                ])
                ax2.set_xlim([
                    np.min(spec1d_final.wavelength.value),
                    np.max(spec1d_final.wavelength.value)
                ])
                ax1.set_ylim(ylim)
                ax2.set_ylim(ylim)
                ax1.set_xlabel('Wavelength (Angstrom)')
                ax1.set_ylabel('Flux')
                ax2.set_ylabel('Flux')

                plt.tight_layout(pad=0.2, h_pad=0., w_pad=0.2)

                if len(qafile.split('.')) == 1:
                    msgs.info(
                        "No fomat given for the qafile, save to PDF format.")
                    qafile = qafile + '.pdf'
                if qafile:
                    plt.savefig(qafile)
                    msgs.info("Wrote coadd QA: {:s}".format(qafile))
                if debug:
                    plt.show()
                plt.close()

            ### Do NOT remove this part althoug it is deprecated.
            # we may need back to using this pieces of code after fixing the coadd.coadd_spectra problem on first order.
            #kwargs['echelle'] = True
            #kwargs['wave_grid_min'] = np.min(wave_grid)
            #kwargs['wave_grid_max'] = np.max(wave_grid)
            #spec1d_final = coadd.coadd_spectra(spectra_coadd_rebin, wave_grid_method=wave_grid_method, niter=niter,
            #                                  scale_method=scale_method, do_offset=do_offset, sigrej_final=sigrej_final,
            #                                  do_var_corr=do_var_corr, qafile=qafile, outfile=outfile,
            #                                  do_cr=do_cr, debug=debug, **kwargs)
            return spec1d_final
        else:
            msgs.warn('Skipped merging orders')
            if outfile is not None:
                for iord in range(len(spectra_list)):
                    outfile_iord = outfile.replace(
                        '.fits', '_ORDER{:04d}.fits'.format(iord))
                    msgs.info(
                        'Saving the final calibrated spectrum of order {:d} as {:s}'
                        .format(iord, outfile))
                    spectra_list[iord].write_to_fits(outfile_iord)
            return spectra_list
Пример #5
0
def main(args, unit_test=False, path=''):
    """ Runs the XSpecGui on an input file
    path : str, optional
      Mainly for running the unit test
    """

    import glob
    import yaml

    from numpy import isnan
    import pdb as debugger

    from astropy.io import fits

    from pypeit import msgs
    from pypeit.core import coadd
    from pypeit import specobjs
    from pypeit.spectrographs import util

    # Load the input file
    with open(args.infile, 'r') as infile:
        coadd_dict = yaml.load(infile)

    # Spectrograph
    spectrograph = util.load_spectrograph(coadd_dict.pop('spectrograph'))

    # Grab object names in the spectra
    filelist = coadd_dict.pop('filenames')
    # Allow for wildcards
    files = []
    for ifl in filelist:
        if '*' in ifl:
            files += glob.glob(path + ifl)
        else:
            files += [path + ifl]
    # Load spectra
    if len(files) == 0:
        msgs.error("No files match your input list")
    else:
        msgs.info("Coadding {:d} data frames".format(len(files)))
        # figure out whether it is Echelle or Longslit
        header0 = fits.getheader(files[0], 0)
        pypeline = header0['PYPELINE']
        # also need norder for Echelle data
        if pypeline == 'Echelle':
            ext_final = fits.getheader(files[0], -1)
            norder = ext_final['ECHORDER'] + 1
    fdict = {}
    for ifile in files:
        # Open file
        hdulist = fits.open(ifile)
        # Grab objects
        objects = [hdu.name for hdu in hdulist][1:]
        fdict[ifile] = objects

    # Global parameters?
    if 'global' in coadd_dict.keys():
        gparam = coadd_dict.pop('global')
    else:
        gparam = {}
    if args.debug:
        gparam['debug'] = True
    sv_gparam = gparam.copy()
    # Extraction
    if 'extract' in coadd_dict.keys():
        ex_value = coadd_dict.pop('extract')
    else:
        ex_value = 'OPT'
    msgs.info("Using {:s} extraction".format(ex_value))
    # Fluxed data?
    if 'flux' in coadd_dict.keys():
        flux_value = coadd_dict.pop('flux')
    else:
        flux_value = True

    # Loop on sources
    for key in coadd_dict.keys():
        # Re-init gparam
        gparam = sv_gparam.copy()
        iobj = coadd_dict[key]['object']
        # Check iobj input
        if isinstance(iobj, list):
            if len(iobj) != len(files):
                raise IOError(
                    "Input list of object names must have same length as files"
                )
        #
        outfile = coadd_dict[key]['outfile']

        # Scale
        if 'scale' in coadd_dict[key]:
            scale_dict = coadd_dict[key]['scale']
        else:
            scale_dict = None

        # Generate local keywords
        try:
            local_kwargs = coadd_dict[key]['local']
        except KeyError:
            local_kwargs = {}
        else:
            for lkey in local_kwargs:
                gparam[lkey] = local_kwargs[lkey]

        if unit_test:
            return gparam, ex_value, flux_value, iobj, outfile, files, local_kwargs

        # Loop on spec1d files
        gdfiles = []
        extensions = []
        gdobj = []

        for fkey in fdict:
            # Input as str or list
            if not isinstance(iobj, list) == 1:  # Simple single object
                use_obj = iobj
            else:
                ind = files.index(fkey)
                use_obj = iobj[ind]

            if pypeline == 'Echelle':
                gdfiles.append(fkey)
                gdobj += [use_obj]
            else:
                # Find object indices
                # FW: mtch_obj_to_objects will return None when no matching and raise TypeError: cannot unpack non-iterable NoneType object
                try:
                    mtch_obj, idx = specobjs.mtch_obj_to_objects(
                        use_obj, fdict[fkey], **local_kwargs)
                except TypeError:
                    mtch_obj = None
                if mtch_obj is None:
                    msgs.info("No object {:s} in file {:s}".format(iobj, fkey))
                elif len(mtch_obj) == 1:
                    #Check if optimal extraction is present in all objects.
                    # If not, warn the user and set ex_value to 'box'.
                    hdulist = fits.open(fkey)
                    try:  #In case the optimal extraction array is a NaN array
                        if flux_value is True:  # If we have a fluxed spectrum, look for flam
                            obj_opt = hdulist[mtch_obj[0]].data['OPT_FLAM']
                        else:  # If not, look for counts
                            obj_opt = hdulist[mtch_obj[0]].data['OPT_COUNTS']
                        if any(isnan(obj_opt)):
                            msgs.warn(
                                "Object {:s} in file {:s} has a NaN array for optimal extraction. Boxcar will be used instead."
                                .format(mtch_obj[0], fkey))
                            ex_value = 'box'
                    except KeyError:  #In case the array is absent altogether.
                        msgs.warn(
                            "Object {:s} in file {:s} doesn't have an optimal extraction. Boxcar will be used instead."
                            .format(mtch_obj[0], fkey))
                        try:
                            if flux_value is True:  # If we have a fluxed spectrum, look for flam
                                hdulist[mtch_obj[0]].data['BOX_FLAM']
                            else:  # If not, look for counts
                                hdulist[mtch_obj[0]].data['BOX_COUNTS']
                        except KeyError:
                            #In case the boxcar extract is also absent
                            msgs.error(
                                "Object {:s} in file {:s} doesn't have a boxcar extraction either. Co-addition cannot be performed"
                                .format(mtch_obj[0], fkey))
                        ex_value = 'box'
                    gdfiles.append(fkey)
                    gdobj += mtch_obj
                    extensions.append(idx[0] + 1)
                else:
                    raise ValueError(
                        "Multiple matches to object {:s} in file {:s}".format(
                            iobj, fkey))

        # Load spectra
        if len(gdfiles) == 0:
            msgs.error("No files match your input criteria")

        # QA file name
        exten = outfile.split('.')[-1]  # Allow for hdf or fits or whatever
        qafile = outfile.replace(exten, 'pdf')

        if pypeline == 'Echelle':

            # Check whether the scale_dict is in the right shape.
            if 'orderscale' in gparam.keys():
                orderscale_value = gparam['orderscale']
            else:
                orderscale_value = 'median'

            if (scale_dict is not None) and (orderscale_value == 'photometry'):
                if len(scale_dict) != norder:
                    raise IOError(
                        "You need to specifiy the photometric information for every order."
                    )

            spec1d = coadd.ech_coadd(gdfiles,
                                     objids=gdobj,
                                     extract=ex_value,
                                     flux=flux_value,
                                     phot_scale_dicts=scale_dict,
                                     outfile=outfile,
                                     qafile=qafile,
                                     **gparam)

        else:
            spectra = coadd.load_spec(gdfiles,
                                      iextensions=extensions,
                                      extract=ex_value,
                                      flux=flux_value)
            # Coadd!
            coadd.coadd_spectra(spectrograph,
                                gdfiles,
                                spectra,
                                qafile=qafile,
                                outfile=outfile,
                                flux_scale=scale_dict,
                                **gparam)
Пример #6
0
def ech_coadd(files,objids=None,extract='OPT',flux=True,giantcoadd=False,
              wave_grid_method='velocity', niter=5,wave_grid_min=None, wave_grid_max=None,v_pix=None,
              scale_method='auto', do_offset=False, sigrej_final=3.,do_var_corr=False,
              qafile=None, outfile=None,do_cr=True, debug=False,**kwargs):

    nfile = len(files)
    if nfile <=1:
        msgs.info('Only one spectrum exits coadding...')
        return

    fname = files[0]
    ext_final = fits.getheader(fname, -1)
    norder = ext_final['ORDER'] + 1
    msgs.info('spectrum {:s} has {:d} orders'.format(fname, norder))
    if norder <= 1:
        msgs.error('The number of orders have to be greater than one for echelle. Longslit data?')

    if giantcoadd:
        msgs.info('Coadding all orders and exposures at once')
        spectra = ech_load_spec(files, objid=objids,order=None, extract=extract, flux=flux)
        wave_grid = np.zeros((2,spectra.nspec))
        for i in range(spectra.nspec):
            wave_grid[0, i] = spectra[i].wvmin.value
            wave_grid[1, i] = spectra[i].wvmax.value
        ech_kwargs = {'echelle': True, 'wave_grid_min': np.min(wave_grid), 'wave_grid_max': np.max(wave_grid),
                      'v_pix': v_pix}
        kwargs.update(ech_kwargs)
        # Coadding
        spec1d = coadd.coadd_spectra(spectra, wave_grid_method=wave_grid_method, niter=niter,
                                          scale_method=scale_method, do_offset=do_offset, sigrej_final=sigrej_final,
                                          do_var_corr=do_var_corr, qafile=qafile, outfile=outfile,
                                          do_cr=do_cr, debug=debug,**kwargs)
    else:
        msgs.info('Coadding individual orders first and then merge order')
        spectra_list = []
        # Keywords for Table
        rsp_kwargs = {}
        rsp_kwargs['wave_tag'] = '{:s}_WAVE'.format(extract)
        rsp_kwargs['flux_tag'] = '{:s}_FLAM'.format(extract)
        rsp_kwargs['sig_tag'] = '{:s}_FLAM_SIG'.format(extract)
        wave_grid = np.zeros((2,norder))
        for iord in range(norder):
            spectra = ech_load_spec(files, objid=objids, order=iord, extract=extract, flux=flux)
            ech_kwargs = {'echelle': False, 'wave_grid_min': spectra.wvmin.value, 'wave_grid_max': spectra.wvmax.value, 'v_pix': v_pix}
            wave_grid[0,iord] = spectra.wvmin.value
            wave_grid[1,iord] = spectra.wvmax.value
            kwargs.update(ech_kwargs)
            # Coadding the individual orders
            if qafile is not None:
                qafile_iord = qafile+'_%s'%str(iord)
            else:
                qafile_iord =  None
            spec1d_iord = coadd.coadd_spectra(spectra, wave_grid_method=wave_grid_method, niter=niter,
                                       scale_method=scale_method, do_offset=do_offset, sigrej_final=sigrej_final,
                                       do_var_corr=do_var_corr, qafile=qafile_iord, outfile=outfile,
                                       do_cr=do_cr, debug=debug, **kwargs)
            spectrum = spec_from_array(spec1d_iord.wavelength, spec1d_iord.flux, spec1d_iord.sig,**rsp_kwargs)
            spectra_list.append(spectrum)
        # Join into one XSpectrum1D object
        spectra_coadd = collate(spectra_list)
        kwargs['echelle'] = True
        kwargs['wave_grid_min'] = np.min(wave_grid)
        kwargs['wave_grid_max'] = np.max(wave_grid)
        # ToDo: Currently I'm not using the first order due to some problem. Need to add it back after fix the problem.
        spec1d = coadd.coadd_spectra(spectra_coadd[1:], wave_grid_method=wave_grid_method, niter=niter,
                                          scale_method=scale_method, do_offset=do_offset, sigrej_final=sigrej_final,
                                          do_var_corr=do_var_corr, qafile=qafile, outfile=outfile,
                                          do_cr=do_cr, debug=debug, **kwargs)

    return spec1d