예제 #1
0
    def test_amp_ids(self):
        """Test auto-detection of amp names"""
        hdr = dict(
            CCDSECA=self.header['CCDSECA'],
            CCDSECB=self.header['CCDSECB'],
            CCDSECC=self.header['CCDSECC'],
            CCDSECD=self.header['CCDSECD'],
            )
        self.assertEqual(get_amp_ids(hdr), ['A', 'B', 'C', 'D'])

        hdr = dict(
            CCDSEC1=self.header['CCDSECA'],
            CCDSEC2=self.header['CCDSECB'],
            CCDSEC3=self.header['CCDSECC'],
            CCDSEC4=self.header['CCDSECD'],
            )
        self.assertEqual(get_amp_ids(hdr), ['1', '2', '3', '4'])

        hdr = dict()
        with self.assertRaises(KeyError):
            get_amp_ids(hdr)
예제 #2
0
def ampregion(image):
    """
    Get the pixel boundary regions for amps

    Args:
        image: desispec.image.Image object
    """
    pixboundary = []
    for kk in get_amp_ids(image.meta):  # A-D or 1-4
        #- get the amp region in pix
        ampboundary = parse_sec_keyword(image.meta["CCDSEC" + kk])
        pixboundary.append(ampboundary)
    return pixboundary
예제 #3
0
def cal_rdnoise(hdul, camera, ccd_calibration_filename, use_overscan_row,
                overscan_per_row, use_active):
    if True:
        hdul_this = hdul[camera]
        header = hdul_this.header
        rawimage = hdul_this.data
        # works!  preproc.preproc(hdul['B0'].data,hdul['B0'].header,h1)
        amp_ids = preproc.get_amp_ids(header)

        #- Output arrays
        ny = 0
        nx = 0
        for amp in amp_ids:
            yy, xx = parse_sec_keyword(header['CCDSEC%s' % amp])
            ny = max(ny, yy.stop)
            nx = max(nx, xx.stop)
        image = np.zeros((ny, nx))

        readnoise = np.zeros_like(image)
        nogain = False

        cfinder = None

        if ccd_calibration_filename is not False:
            cfinder = CalibFinder([header, primary_header],
                                  yaml_file=ccd_calibration_filename)

        for amp in amp_ids:
            # Grab the sections
            ov_col = parse_sec_keyword(header['BIASSEC' + amp])
            ov_row = parse_sec_keyword(header['ORSEC' + amp])

            if use_active:
                if amp == 'A' or amp == 'D':
                    ov_col2 = np.s_[ov_col[1].start:ov_col[1].stop, 0:100]
                else:
                    ov_col2 = np.s_[ov_col[1].start:ov_col[1].stop, 0:100]
            import pdb
            pdb.set_trace()

            if 'ORSEC' + amp in header.keys():
                ov_row = parse_sec_keyword(header['ORSEC' + amp])
            elif use_overscan_row:
                log.error(
                    'No ORSEC{} keyword; not using overscan_row'.format(amp))
                use_overscan_row = False

            if nogain:
                gain = 1.
            else:
                #- Initial teststand data may be missing GAIN* keywords; don't crash
                if 'GAIN' + amp in header:
                    gain = header['GAIN' + amp]  #- gain = electrons / ADU
                else:
                    if cfinder and cfinder.haskey('GAIN' + amp):
                        gain = float(cfinder.value('GAIN' + amp))
                        log.info(
                            'Using GAIN{}={} from calibration data'.format(
                                amp, gain))
                    else:
                        gain = 1.0
                        log.warning(
                            'Missing keyword GAIN{} in header and nothing in calib data; using {}'
                            .format(amp, gain))

            #- Add saturation level
            if 'SATURLEV' + amp in header:
                saturlev = header['SATURLEV' + amp]  # in electrons
            else:
                if cfinder and cfinder.haskey('SATURLEV' + amp):
                    saturlev = float(cfinder.value('SATURLEV' + amp))
                    log.info(
                        'Using SATURLEV{}={} from calibration data'.format(
                            amp, saturlev))
                else:
                    saturlev = 200000
                    log.warning(
                        'Missing keyword SATURLEV{} in header and nothing in calib data; using 200000'
                        .format(amp, saturlev))

            # Generate the overscan images
            raw_overscan_col = rawimage[ov_col].copy()  # 2064*64

            if use_overscan_row:
                raw_overscan_row = rawimage[ov_row].copy()  # 32*2057
                overscan_row = np.zeros_like(raw_overscan_row)

                # Remove overscan_col from overscan_row
                raw_overscan_squared = rawimage[ov_row[0],
                                                ov_col[1]].copy()  # 32*64
                for row in range(raw_overscan_row.shape[0]):
                    o, r = _overscan(raw_overscan_squared[row])
                    overscan_row[row] = raw_overscan_row[row] - o

            # Now remove the overscan_col
            nrows = raw_overscan_col.shape[0]
            log.info("nrows in overscan=%d" % nrows)
            overscan_col = np.zeros(nrows)
            rdnoise = np.zeros(nrows)
            if (cfinder and cfinder.haskey('OVERSCAN' + amp)
                    and cfinder.value("OVERSCAN" + amp).upper()
                    == "PER_ROW") or overscan_per_row:
                log.info(
                    "Subtracting overscan per row for amplifier %s of camera %s"
                    % (amp, camera))
                for j in range(nrows):
                    if np.isnan(np.sum(overscan_col[j])):
                        log.warning(
                            "NaN values in row %d of overscan of amplifier %s of camera %s"
                            % (j, amp, camera))
                        continue
                    o, r = _overscan(raw_overscan_col[j])
                    #log.info("%d %f %f"%(j,o,r))
                    overscan_col[j] = o
                    rdnoise[j] = r
            else:
                log.info(
                    "Subtracting average overscan for amplifier %s of camera %s"
                    % (amp, camera))
                o, r = _overscan(raw_overscan_col)
                overscan_col += o
                rdnoise += r

            rdnoise *= gain
            median_rdnoise = np.median(rdnoise)
            median_overscan = np.median(overscan_col)
    return rdnoise, median_rdnoise
예제 #4
0
def bias_stats(camera='z3', use_overscan_row=True):
    """
    Measure stats on bias-subtracted frames

    Args:
        camera:

    Returns:

    """
    dpath = '/home/xavier/DESI/DESI_SCRATCH/minisv2/data/20200304/'
    bias_files = glob.glob(dpath + '000*/desi-*.fz')
    bias_files.sort()

    # Load bias images
    hdul = fits.open(bias_files[0])
    hdu = hdul[camera.upper()]
    smnum = hdu.header['SPECID']
    new_bias_file = os.path.join(dpath, 'bias_{}.fits'.format(camera))
    new_bias = fits.open(new_bias_file)[0].data
    old_bias_file = os.path.join(
        os.getenv('DESI_SPECTRO_CALIB'), 'ccd',
        'bias-sm{}-{}-20191021.fits'.format(smnum, camera[0]))
    old_bias = fits.open(old_bias_file)[0].data

    calib_file = os.path.join(os.getenv('DESI_SPECTRO_CALIB'), 'spec',
                              'sm{}'.format(smnum),
                              'sm{}-{}.yaml'.format(smnum, camera[0]))

    # Loop and process
    stat_tbl = None
    for ss, bias_file in enumerate(bias_files):
        hdul = fits.open(bias_file)
        # Process
        tdict = dict(file=[os.path.basename(bias_file)])
        lbias = 'new'
        for lbias, bimg in zip(['new', 'old'], [new_bias, old_bias]):
            img = preproc.preproc(hdu.data,
                                  hdu.header,
                                  hdul[0].header,
                                  pixflat=False,
                                  mask=False,
                                  nocrosstalk=True,
                                  ccd_calibration_filename=calib_file,
                                  use_overscan_row=use_overscan_row,
                                  dark=False,
                                  flag_savgol=False,
                                  bias_img=bimg)
            # Stats
            amp_ids = preproc.get_amp_ids(hdu.header)
            for amp in amp_ids:
                kk = preproc.parse_sec_keyword(hdu.header['CCDSEC' + amp])
                zero, rms = preproc._overscan(img.pix[kk])
                tdict[lbias + amp + '_zero'] = [zero]
                tdict[lbias + amp + '_rms'] = [rms]
        # Add to Table
        if stat_tbl is None:
            stat_tbl = Table(tdict)
        else:
            stat_tbl.add_row(tdict)
    # Write
    if use_overscan_row:
        root = '_'
    else:
        root = '_norow_'
    outbase = 'bias_stats{}{}.fits'.format(root, camera)
    outfile = os.path.join(dpath, 'Stats', outbase)
    stat_tbl.write(outfile, overwrite=True)
    print("Wrote: {}".format(outfile))
예제 #5
0
def fiducialregion(frame, psf):
    """
    Get the fiducial amplifier regions on the CCD pixel to fiber by wavelength space

    Args:
        frame: desispec.frame.Frame object
        psf: desispec.psf.PSF like object
    """
    startspec = 0  #- will be None if don't have fibers on the right of the CCD.
    endspec = 499  #- will be None if don't have fibers on the right of the CCD
    startwave0 = 0  #- lower index for the starting fiber
    startwave1 = 0  #- lower index for the last fiber for the amp region
    endwave0 = frame.wave.shape[0]  #- upper index for the starting fiber
    endwave1 = frame.wave.shape[
        0]  #- upper index for the last fiber for that amp
    pixboundary = []
    fidboundary = []

    #- Adding the min, max boundary individually for the benefit of dumping to yaml.
    leftmax = 499  #- for amp 1 and 3
    rightmin = 0  #- for amp 2 and 4
    bottommax = frame.wave.shape[0]  #- for amp 1 and 2
    topmin = 0  #- for amp 3 and 4

    #- Loop over each amp
    for kk in get_amp_ids(frame.meta):  # A-D or 1-4
        #- get the amp region in pix
        ampboundary = parse_sec_keyword(frame.meta["CCDSEC" + kk])
        pixboundary.append(ampboundary)
        for ispec in range(frame.flux.shape[0]):
            if np.all(psf.x(ispec) > ampboundary[1].start):
                startspec = ispec
                #-cutting off wavelenth boundaries from startspec
                yy = psf.y(ispec, frame.wave)
                k = np.where(yy > ampboundary[0].start)[0]
                startwave0 = k[0]
                yy = psf.y(ispec, frame.wave)
                k = np.where(yy < ampboundary[0].stop)[0]
                endwave0 = k[-1]
                break
            else:
                startspec = None
                startwave0 = None
                endwave0 = None
        if startspec is not None:
            for ispec in range(frame.flux.shape[0])[::-1]:
                if np.all(psf.x(ispec) < ampboundary[1].stop):
                    endspec = ispec
                    #-cutting off wavelenth boundaries from startspec
                    yy = psf.y(ispec, frame.wave)
                    k = np.where(yy > ampboundary[0].start)[0]
                    startwave1 = k[0]
                    yy = psf.y(ispec, frame.wave)
                    k = np.where(yy < ampboundary[0].stop)[0]
                    endwave1 = k[-1]
                    break
        else:
            endspec = None
            startwave1 = None
            endwave1 = None
        if startwave0 is not None and startwave1 is not None:
            startwave = max(startwave0, startwave1)
        else:
            startwave = None
        if endwave0 is not None and endwave1 is not None:
            endwave = min(endwave0, endwave1)
        else:
            endwave = None
        if endspec is not None:
            #endspec+=1 #- last entry exclusive in slice, so add 1
            #endwave+=1

            if endspec < leftmax:
                leftmax = endspec
            if startspec > rightmin:
                rightmin = startspec
            if endwave < bottommax:
                bottommax = endwave
            if startwave > topmin:
                topmin = startwave
        else:
            rightmin = 0  #- Only if no spec in right side of CCD. passing 0 to encertain valid data type. Nontype throws a type error in yaml.dump.

        #fiducialb=(slice(startspec,endspec,None),slice(startwave,endwave,None))  #- Note: y,x --> spec, wavelength
        #fidboundary.append(fiducialb)

    #- return pixboundary,fidboundary
    return leftmax, rightmin, bottommax, topmin