コード例 #1
0
ファイル: io.py プロジェクト: desihub/nightwatch
def get_night_expid_header(hdr):
    '''
    Returns NIGHT, EXPID from input header keywords
    '''
    from desispec.util import header2night
    night = header2night(hdr)

    try:
        expid = int(hdr['EXPID'])
    except (KeyError, ValueError, TypeError):  # missing, not int, None
        log = get_logger()
        msg = 'Unable to determine int EXPID from header'
        log.error(msg)
        raise ValueError(msg)

    return night, expid
コード例 #2
0
def summarize_exposure(raw_data_dir, night, exp, obstypes=None, colnames=None, coldefaults=None, verbosely=False):
    """
    Given a raw data directory and exposure information, this searches for the raw DESI data files for that
    exposure and loads in relevant information for that flavor+obstype. It returns a dictionary if the obstype
    is one of interest for the exposure table, a string if the exposure signifies the end of a calibration sequence,
    and None if the exposure is not in the given obstypes.

    Args:
        raw_data_dir, str. The path to where the raw data is stored. It should be the upper level directory where the
                           nightly subdirectories reside.
        night, str or int. Used to know what nightly subdirectory to look for the given exposure in.
        exp, str or int or float. The exposure number of interest.
        obstypes, list or np.array of str's. The list of 'OBSTYPE' keywords to match to. If a match is found, the
                                             information about that exposure is taken and returned for the exposure
                                             table. Otherwise None is returned (or str if it is an end-of-cal manifest).
                                             If None, the default list in default_exptypes_for_exptable() is used.
        colnames, list or np.array. List of column names for an exposure table. If None, the defaults are taken from
                                    get_exposure_table_column_defs().
        coldefaults, list or np.array. List of default values for the corresponding colnames. If None, the defaults
                                       are taken from get_exposure_table_column_defs().
        verbosely, bool. Whether to print more detailed output (True) or more succinct output (False).

    Returns:
        outdict, dict. Dictionary with keys corresponding to the column names of an exposure table. Values are
                       taken from the data when found, otherwise the values are the corresponding default given in
                       coldefaults.
        OR
        str. If the exposures signifies the end of a calibration sequence, it returns a string describing the type of
             sequence that ended. Either "(short|long|arc) calib complete".
        OR
        NoneType. If the exposure obstype was not in the requested types (obstypes).
    """
    log = get_logger()

    ## Make sure the inputs are in the right format
    if type(exp) is not str:
        exp = int(exp)
        exp = f'{exp:08d}'
    night = str(night)

    ## Use defaults if things aren't defined
    if obstypes is None:
        obstypes = default_exptypes_for_exptable()
    if colnames is None or coldefaults is None:
        cnames, cdtypes, cdflts = get_exposure_table_column_defs(return_default_values=True)
        if colnames is None:
            colnames = cnames
        if coldefaults is None or len(coldefaults)!=len(colnames):
            coldefaults = cdflts
    colnames,coldefaults = np.asarray(colnames),np.asarray(coldefaults,dtype=object)

    ## Give a header for the exposure
    if verbosely:
        log.info(f'\n\n###### Summarizing exposure: {exp} ######\n')
    else:
        log.info(f'Summarizing exposure: {exp}')
    ## Request json file is first used to quickly identify science exposures
    ## If a request file doesn't exist for an exposure, it shouldn't be an exposure we care about
    reqpath = pathjoin(raw_data_dir, night, exp, f'request-{exp}.json')
    if not os.path.isfile(reqpath):
        if verbosely:
            log.info(f'{reqpath} did not exist!')
        else:
            log.info(f'{exp}: skipped  -- request not found')
        return None

    ## Load the json file in as a dictionary
    req_dict = get_json_dict(reqpath)

    ## Check to see if it is a manifest file for calibrations
    if "SEQUENCE" in req_dict and req_dict["SEQUENCE"].lower() == "manifest":
        ## standardize the naming of end of arc/flats as best we can
        if int(night) < 20200310:
            pass
        elif int(night) < 20200801:
            if 'PROGRAM' in req_dict:
                prog = req_dict['PROGRAM'].lower()
                if 'calib' in prog and 'done' in prog:
                    if 'short' in prog:
                        return "endofshortflats"
                    elif 'long' in prog:
                        return 'endofflats'
                    elif 'arc' in prog:
                        return 'endofarcs'
        else:
            if 'MANIFEST' in req_dict:
                manifest = req_dict['MANIFEST']
                if 'name' in manifest:
                    name = manifest['name'].lower()
                    if name in ['endofarcs', 'endofflats', 'endofshortflats']:
                        return name

    ## If FLAVOR is wrong or no obstype is defines, skip it
    if 'FLAVOR' not in req_dict.keys():
        if verbosely:
            log.info(f'WARNING: {reqpath} -- flavor not given!')
        else:
            log.info(f'{exp}: skipped  -- flavor not given!')
        return None

    flavor = req_dict['FLAVOR'].lower()
    if flavor != 'science' and 'dark' not in obstypes and 'zero' not in obstypes:
        ## If FLAVOR is wrong
        if verbosely:
            log.info(f'ignoring: {reqpath} -- {flavor} not a flavor we care about')
        else:
            log.info(f'{exp}: skipped  -- {flavor} not a relevant flavor')
        return None

    if 'OBSTYPE' not in req_dict.keys():
        ## If no obstype is defines, skip it
        if verbosely:
            log.info(f'ignoring: {reqpath} -- {flavor} flavor but obstype not defined')
        else:
            log.info(f'{exp}: skipped  -- obstype not given')
        return None
    else:
        if verbosely:
            log.info(f'using: {reqpath}')

    ## If obstype isn't in our list of ones we care about, skip it
    obstype = req_dict['OBSTYPE'].lower()
    if obstype not in obstypes:
        ## If obstype is wrong
        if verbosely:
            log.info(f'ignoring: {reqpath} -- {obstype} not an obstype we care about')
        else:
            log.info(f'{exp}: skipped  -- {obstype} not relevant obstype')
        return None

    ## Look for the data. If it's not there, say so then move on
    datapath = pathjoin(raw_data_dir, night, exp, f'desi-{exp}.fits.fz')
    if not os.path.exists(datapath):
        if verbosely:
            log.info(f'could not find {datapath}! It had obstype={obstype}. Skipping')
        else:
            log.info(f'{exp}: skipped  -- data not found')
        return None
    else:
        if verbosely:
            log.info(f'using: {datapath}')

    ## Raw data, so ensure it's read only and close right away just to be safe
    # log.debug(hdulist.info())

    header,fx = load_raw_data_header(pathname=datapath, return_filehandle=True)
    # log.debug(header)
    # log.debug(specs)

    ## Define the column values for the current exposure in a dictionary
    outdict = {}
    ## Set HEADERERR and EXPFLAG before loop because they may be set if other columns have missing information
    outdict['HEADERERR'] = coldefaults[colnames == 'HEADERERR'][0]
    outdict['EXPFLAG'] = coldefaults[colnames == 'EXPFLAG'][0]
    ## Loop over columns and fill in the information. If unavailable report/flag if necessary and assign default
    for key,default in zip(colnames,coldefaults):
        ## These are dealt with separately
        if key in ['NIGHT','HEADERERR','EXPFLAG']:
            continue
        ## These just need defaults, as they are user defined (except FA_SURV which comes from the request.json file
        elif key in ['CAMWORD', 'FA_SURV', 'BADCAMWORD', 'BADAMPS', 'LASTSTEP', 'COMMENTS']:
            outdict[key] = default
        ## Try to find the key in the raw data header
        elif key in header.keys():
            val = header[key]
            if type(val) is str:
                outdict[key] = val.lower()
            else:
                outdict[key] = val
        ## If key not in the header, identify that and place a default value
        ## If obstype isn't arc or flat, don't worry about seqnum or seqtot
        elif key in ['SEQNUM','SEQTOT'] and obstype not in ['arc','flat']:
            outdict[key] = default
        ## If tileid or TARGT and not science, just replace with default
        elif key in ['TILEID','TARGTRA','TARGTDEC'] and obstype not in ['science']:
            outdict[key] = default
        ## If trying to assign purpose and it's before that was defined, just give default
        elif key in ['PURPOSE'] and int(night) < 20201201:
            outdict[key] = default
        ## if something else, flag as missing metadata and replace with default
        else:
            if 'metadata_missing' not in outdict['EXPFLAG']:
                outdict['EXPFLAG'] = np.append(outdict['EXPFLAG'], 'metadata_missing')
            outdict[key] = default
            if np.isscalar(default):
                reporting = keyval_change_reporting(key, '', default)
                outdict['HEADERERR'] = np.append(outdict['HEADERERR'], reporting)

    ## Make sure that the night is defined:
    try:
        outdict['NIGHT'] = int(header['NIGHT'])
    except (KeyError, ValueError, TypeError):
        if 'metadata_missing' not in outdict['EXPFLAG']:
            outdict['EXPFLAG'] = np.append(outdict['EXPFLAG'], 'metadata_missing')
        outdict['NIGHT'] = header2night(header)
        try:
            orig = str(header['NIGHT'])
        except (KeyError, ValueError, TypeError):
            orig = ''
        reporting = keyval_change_reporting('NIGHT',orig,outdict['NIGHT'])
        outdict['HEADERERR'] = np.append(outdict['HEADERERR'],reporting)

    ## Get the cameras available in the raw data and summarize with camword
    cams = cameras_from_raw_data(fx)
    camword = create_camword(cams)
    outdict['CAMWORD'] = camword
    fx.close()

    ## Add the fiber assign survey, if it doesn't exist use the pre-defined one
    if "FA_SURV" in req_dict and "FA_SURV" in colnames:
        outdict['FA_SURV'] = req_dict['FA_SURV']

    ## Flag the exposure based on PROGRAM information
    if 'system test' in outdict['PROGRAM'].lower():
        outdict['LASTSTEP'] = 'ignore'
        outdict['EXPFLAG'] = np.append(outdict['EXPFLAG'], 'test')
        log.info(f"Exposure {exp} identified as system test. Not processing.")
    elif obstype == 'science' and float(outdict['EXPTIME']) < 59.0:
        outdict['LASTSTEP'] = 'skysub'
        outdict['EXPFLAG'] = np.append(outdict['EXPFLAG'], 'short_exposure')
        log.info(f"Science exposure {exp} with EXPTIME less than 59s. Processing through sky subtraction.")
    elif obstype == 'science' and 'undither' in outdict['PROGRAM']:
        outdict['LASTSTEP'] = 'fluxcal'
        log.info(f"Science exposure {exp} identified as undithered. Processing through flux calibration.")
    elif obstype == 'science' and 'dither' in outdict['PROGRAM']:
        outdict['LASTSTEP'] = 'skysub'
        log.info(f"Science exposure {exp} identified as dither. Processing through sky subtraction.")

    ## For Things defined in both request and data, if they don't match, flag in the
    ##     output file for followup/clarity
    for check in ['OBSTYPE']:#, 'FLAVOR']:
        rval, hval = req_dict[check], header[check]
        if rval != hval:
            log.warning(f'In keyword {check}, request and data header disagree: req:{rval}\tdata:{hval}')
            if 'metadata_mismatch' not in outdict['EXPFLAG']:
                outdict['EXPFLAG'] = np.append(outdict['EXPFLAG'], 'metadata_mismatch')
            outdict['COMMENTS'] = np.append(outdict['COMMENTS'],f'For {check}: req={rval} but hdu={hval}')
        else:
            if verbosely:
                log.info(f'{check} checks out')

    ## Special logic for EXPTIME because of real-world variance on order 10's - 100's of ms
    check = 'EXPTIME'
    rval, hval = req_dict[check], header[check]
    if np.abs(float(rval)-float(hval))>0.5:
        log.warning(f'In keyword {check}, request and data header disagree: req:{rval}\tdata:{hval}')
        if 'aborted' not in outdict['EXPFLAG']:
            outdict['EXPFLAG'] = np.append(outdict['EXPFLAG'], 'aborted')
        outdict['COMMENTS'] = np.append(outdict['COMMENTS'],f'For {check}: req={rval} but hdu={hval}')
    else:
        if verbosely:
            log.info(f'{check} checks out')

    log.info(f'Done summarizing exposure: {exp}')
    return outdict
コード例 #3
0
    def __init__(self, headers, yaml_file=None):
        """
        Class to read and select calibration data from $DESI_SPECTRO_CALIB using the keywords found in the headers
        
        Args:
            headers: list of fits headers, or list of dictionnaries
        
        Optional:
            yaml_file: path to a specific yaml file. By default, the code will
            automatically find the yaml file from the environment variable
            DESI_SPECTRO_CALIB and the CAMERA keyword in the headers

        """
        log = get_logger()

        old_version = False

        # temporary backward compatibility
        if not "DESI_SPECTRO_CALIB" in os.environ:
            if "DESI_CCD_CALIBRATION_DATA" in os.environ:
                log.warning(
                    "Using deprecated DESI_CCD_CALIBRATION_DATA env. variable to find calibration data\nPlease switch to DESI_SPECTRO_CALIB a.s.a.p."
                )
                self.directory = os.environ["DESI_CCD_CALIBRATION_DATA"]
                old_version = True
            else:
                log.error("Need environment variable DESI_SPECTRO_CALIB")
                raise KeyError("Need environment variable DESI_SPECTRO_CALIB")
        else:
            self.directory = os.environ["DESI_SPECTRO_CALIB"]

        if len(headers) == 0:
            log.error("Need at least a header")
            raise RuntimeError("Need at least a header")

        header = dict()
        for other_header in headers:
            for k in other_header:
                if k not in header:
                    try:
                        header[k] = other_header[k]
                    except KeyError:
                        # it happens with the current version of fitsio
                        # if the value = 'None'.
                        pass
        if "CAMERA" not in header:
            log.error("no 'CAMERA' keyword in header, cannot find calib")
            log.error("header is:")
            for k in header:
                log.error("{} : {}".format(k, header[k]))
            raise KeyError("no 'CAMERA' keyword in header, cannot find calib")

        log.debug("header['CAMERA']={}".format(header['CAMERA']))
        camera = header["CAMERA"].strip().lower()

        if "SPECID" in header:
            log.debug("header['SPECID']={}".format(header['SPECID']))
            specid = int(header["SPECID"])
        else:
            specid = None

        dateobs = header2night(header)

        detector = header["DETECTOR"].strip()
        if "CCDCFG" in header:
            ccdcfg = header["CCDCFG"].strip()
        else:
            ccdcfg = None
        if "CCDTMING" in header:
            ccdtming = header["CCDTMING"].strip()
        else:
            ccdtming = None

        #if "DOSVER" in header :
        #    dosver = str(header["DOSVER"]).strip()
        #else :
        #    dosver = None
        #if "FEEVER" in header :
        #    feever = str(header["FEEVER"]).strip()
        #else :
        #    feever = None

        # Support simulated data even if $DESI_SPECTRO_CALIB points to
        # real data calibrations
        self.directory = os.path.normpath(self.directory)  # strip trailing /
        if detector == "SIM" and (not self.directory.endswith("sim")):
            newdir = os.path.join(self.directory, "sim")
            if os.path.isdir(newdir):
                self.directory = newdir

        if not os.path.isdir(self.directory):
            raise IOError("Calibration directory {} not found".format(
                self.directory))

        if dateobs < 20191211 or detector == 'SIM':  # old spectro identifiers
            cameraid = camera
            spectro = int(camera[-1])
            if yaml_file is None:
                if old_version:
                    yaml_file = os.path.join(self.directory,
                                             "ccd_calibration.yaml")
                else:
                    yaml_file = "{}/spec/sp{}/{}.yaml".format(
                        self.directory, spectro, cameraid)
        else:
            if specid is None:
                log.error(
                    "dateobs = {} >= 20191211 but no SPECID keyword in header!"
                    .format(dateobs))
                raise RuntimeError(
                    "dateobs = {} >= 20191211 but no SPECID keyword in header!"
                    .format(dateobs))
            log.debug("Use spectrograph hardware identifier SMY")
            cameraid = "sm{}-{}".format(specid, camera[0].lower())
            if yaml_file is None:
                yaml_file = "{}/spec/sm{}/{}.yaml".format(
                    self.directory, specid, cameraid)

        if not os.path.isfile(yaml_file):
            log.error("Cannot read {}".format(yaml_file))
            raise IOError("Cannot read {}".format(yaml_file))

        log.debug("reading calib data in {}".format(yaml_file))

        stream = open(yaml_file, 'r')
        data = yaml.safe_load(stream)
        stream.close()

        if not cameraid in data:
            log.error("Cannot find data for camera %s in filename %s" %
                      (cameraid, yaml_file))
            raise KeyError("Cannot find  data for camera %s in filename %s" %
                           (cameraid, yaml_file))

        data = data[cameraid]
        log.debug("Found %d data for camera %s in filename %s" %
                  (len(data), cameraid, yaml_file))
        log.debug("Finding matching version ...")
        log.debug("DATE-OBS=%d" % dateobs)
        found = False
        matching_data = None
        for version in data:
            log.debug("Checking version %s" % version)
            datebegin = int(data[version]["DATE-OBS-BEGIN"])
            if dateobs < datebegin:
                log.debug(
                    "Skip version %s with DATE-OBS-BEGIN=%d > DATE-OBS=%d" %
                    (version, datebegin, dateobs))
                continue
            if "DATE-OBS-END" in data[version] and data[version][
                    "DATE-OBS-END"].lower() != "none":
                dateend = int(data[version]["DATE-OBS-END"])
                if dateobs > dateend:
                    log.debug(
                        "Skip version %s with DATE-OBS-END=%d < DATE-OBS=%d" %
                        (version, datebegin, dateobs))
                    continue
            if detector != data[version]["DETECTOR"].strip():
                log.debug("Skip version %s with DETECTOR=%s != %s" %
                          (version, data[version]["DETECTOR"], detector))
                continue

            if "CCDCFG" in data[version]:
                if ccdcfg is None or ccdcfg != data[version]["CCDCFG"].strip():
                    log.debug("Skip version %s with CCDCFG=%s != %s " %
                              (version, data[version]["CCDCFG"], ccdcfg))
                    continue

            if "CCDTMING" in data[version]:
                if ccdtming is None or ccdtming != data[version][
                        "CCDTMING"].strip():
                    log.debug("Skip version %s with CCDTMING=%s != %s " %
                              (version, data[version]["CCDTMING"], ccdtming))
                    continue

            #if dosver is not None and "DOSVER" in data[version] and dosver != str(data[version]["DOSVER"]).strip() :
            #     log.debug("Skip version %s with DOSVER=%s != %s "%(version,data[version]["DOSVER"],dosver))
            #    continue
            #if feever is not None and  "FEEVER" in data[version] and feever != str(data[version]["FEEVER"]).strip() :
            #    log.debug("Skip version %s with FEEVER=%s != %s"%(version,data[version]["FEEVER"],feever))
            #   continue

            log.debug("Found data version %s for camera %s in %s" %
                      (version, cameraid, yaml_file))
            if found:
                log.error(
                    "But we already has a match. Please fix this ambiguity in %s"
                    % yaml_file)
                raise KeyError(
                    "Duplicate possible calibration data. Please fix this ambiguity in %s"
                    % yaml_file)
            found = True
            matching_data = data[version]

        if not found:
            log.error("Didn't find matching calibration data in %s" %
                      (yaml_file))
            raise KeyError("Didn't find matching calibration data in %s" %
                           (yaml_file))

        self.data = matching_data
コード例 #4
0
def read_raw(filename, camera, fibermapfile=None, **kwargs):
    '''
    Returns preprocessed raw data from `camera` extension of `filename`

    Args:
        filename : input fits filename with DESI raw data
        camera : camera name (B0,R1, .. Z9) or FITS extension name or number

    Options:
        fibermapfile : read fibermap from this file; if None create blank fm
        Other keyword arguments are passed to desispec.preproc.preproc(),
        e.g. bias, pixflat, mask.  See preproc() documentation for details.

    Returns Image object with member variables pix, ivar, mask, readnoise
    '''

    log = get_logger()

    t0 = time.time()
    fx = fits.open(filename, memmap=False)
    if camera.upper() not in fx:
        raise IOError('Camera {} not in {}'.format(camera, filename))

    rawimage = fx[camera.upper()].data
    header = fx[camera.upper()].header
    hdu=0
    while True :
        primary_header= fx[hdu].header
        if "EXPTIME" in primary_header : break

        if len(fx)>hdu+1 :
            if hdu > 0:
                log.warning("Did not find header keyword EXPTIME in hdu {}, moving to the next".format(hdu))
            hdu +=1
        else :
            log.error("Did not find header keyword EXPTIME in any HDU of {}".format(filename))
            raise KeyError("Did not find header keyword EXPTIME in any HDU of {}".format(filename))

    #- Check if NIGHT keyword is present and valid; fix if needed
    #- e.g. 20210105 have headers with NIGHT='None' instead of YEARMMDD
    try:
        tmp = int(primary_header['NIGHT'])
    except (KeyError, ValueError, TypeError):
        primary_header['NIGHT'] = header2night(primary_header)

    try:
        tmp = int(header['NIGHT'])
    except (KeyError, ValueError, TypeError):
        try:
            header['NIGHT'] = header2night(header)
        except (KeyError, ValueError, TypeError):
            #- early teststand data only have NIGHT/timestamps in primary hdr
            header['NIGHT'] = primary_header['NIGHT']

    #- early data (e.g. 20200219/51053) had a mix of int vs. str NIGHT
    primary_header['NIGHT'] = int(primary_header['NIGHT'])
    header['NIGHT'] = int(header['NIGHT'])

    if primary_header['NIGHT'] != header['NIGHT']:
        msg = 'primary header NIGHT={} != camera header NIGHT={}'.format(
            primary_header['NIGHT'], header['NIGHT'])
        log.error(msg)
        raise ValueError(msg)

    #- early data have >8 char FIBERASSIGN key; rename to match current data
    if 'FIBERASSIGN' in primary_header:
        log.warning('renaming long header keyword FIBERASSIGN -> FIBASSGN')
        primary_header['FIBASSGN'] = primary_header['FIBERASSIGN']
        del primary_header['FIBERASSIGN']

    if 'FIBERASSIGN' in header:
        header['FIBASSGN'] = header['FIBERASSIGN']
        del header['FIBERASSIGN']

    skipkeys = ["EXTEND","SIMPLE","NAXIS1","NAXIS2","CHECKSUM","DATASUM","XTENSION","EXTNAME","COMMENT"]
    if 'INHERIT' in header and header['INHERIT']:
        h0 = fx[0].header
        for key in h0:
            if ( key not in skipkeys ) and ( key not in header ):
                header[key] = h0[key]

    if "fill_header" in kwargs :
        hdus = kwargs["fill_header"]

        if hdus is None :
            hdus=[0,]
            if "PLC" in fx :
                hdus.append("PLC")

        if hdus is not None :
            log.info("will add header keywords from hdus %s"%str(hdus))
            for hdu in hdus :
                try :
                    ihdu = int(hdu)
                    hdu = ihdu
                except ValueError:
                    pass
                if hdu in fx :
                    hdu_header = fx[hdu].header
                    for key in hdu_header:
                        if ( key not in skipkeys ) and ( key not in header ) :
                            log.debug("adding {} = {}".format(key,hdu_header[key]))
                            header[key] = hdu_header[key]
                        else :
                            log.debug("key %s already in header or in skipkeys"%key)
                else :
                    log.warning("warning HDU %s not in fits file"%str(hdu))

        kwargs.pop("fill_header")

    fx.close()
    duration = time.time() - t0
    log.info(iotime.format('read', filename, duration))

    img = desispec.preproc.preproc(rawimage, header, primary_header, **kwargs)

    if fibermapfile is not None and os.path.exists(fibermapfile):
        fibermap = desispec.io.read_fibermap(fibermapfile)
    else:
        log.warning('creating blank fibermap')
        fibermap = desispec.io.empty_fibermap(5000)

    #- Add image header keywords inherited from raw data to fibermap too
    desispec.io.util.addkeys(fibermap.meta, img.meta)

    #- Augment the image header with some tile info from fibermap if needed
    for key in ['TILEID', 'TILERA', 'TILEDEC']:
        if key in fibermap.meta:
            if key not in img.meta:
                log.info('Updating header from fibermap {}={}'.format(
                    key, fibermap.meta[key]))
                img.meta[key] = fibermap.meta[key]
            elif img.meta[key] != fibermap.meta[key]:
                #- complain loudly, but don't crash and don't override
                log.error('Inconsistent {}: raw header {} != fibermap header {}'.format(key, img.meta[key], fibermap.meta[key]))


    #- Trim to matching camera based upon PETAL_LOC, but that requires
    #- a mapping prior to 20191211

    #- HACK HACK HACK
    #- TODO: replace this with a mapping from calibfinder, as soon as
    #- that is implemented in calibfinder / desi_spectro_calib
    #- HACK HACK HACK

    #- From DESI-5286v5 page 3 where sp=sm-1 and
    #- "spectro logical number" = petal_loc
    spec_to_petal = {4:2, 2:9, 3:0, 5:3, 1:8, 0:4, 6:6, 7:7, 8:5, 9:1}
    assert set(spec_to_petal.keys()) == set(range(10))
    assert set(spec_to_petal.values()) == set(range(10))

    #- Mapping only for dates < 20191211
    if "NIGHT" in primary_header:
        dateobs = int(primary_header["NIGHT"])
    elif "DATE-OBS" in primary_header:
        dateobs=parse_date_obs(primary_header["DATE-OBS"])
    else:
        msg = "Need either NIGHT or DATE-OBS in primary header"
        log.error(msg)
        raise KeyError(msg)
    if dateobs < 20191211 :
        petal_loc = spec_to_petal[int(camera[1])]
        log.warning('Prior to 20191211, mapping camera {} to PETAL_LOC={}'.format(camera, petal_loc))
    else :
        petal_loc = int(camera[1])
        log.debug('Since 20191211, camera {} is PETAL_LOC={}'.format(camera, petal_loc))

    if 'PETAL_LOC' in fibermap.dtype.names : # not the case in early teststand data
        ii = (fibermap['PETAL_LOC'] == petal_loc)
        fibermap = fibermap[ii]

    if 'FIBER' in fibermap.dtype.names : # not the case in early teststand data

        ## Mask fibers
        cfinder = CalibFinder([header,primary_header])
        mod_fibers = fibermap['FIBER'].data % 500

        ## Mask blacklisted fibers
        fiberblacklist = cfinder.fiberblacklist()
        for fiber in fiberblacklist:
            loc = np.where(mod_fibers==fiber)[0]
            fibermap['FIBERSTATUS'][loc] |= maskbits.fibermask.BADFIBER

        # Mask Fibers that are set to be excluded due to CCD/amp/readout issues
        camname = camera.upper()[0]
        if camname == 'B':
            badamp_bit = maskbits.fibermask.BADAMPB
        elif camname == 'R':
            badamp_bit = maskbits.fibermask.BADAMPR
        else:
            #elif camname == 'Z':
            badamp_bit = maskbits.fibermask.BADAMPZ

        fibers_to_exclude = cfinder.fibers_to_exclude()
        for fiber in fibers_to_exclude:
            loc = np.where(mod_fibers==fiber)[0]
            fibermap['FIBERSTATUS'][loc] |= badamp_bit

    img.fibermap = fibermap

    return img
コード例 #5
0
ファイル: test_util.py プロジェクト: dmargala/desispec
    def test_header2night(self):
        from astropy.time import Time
        night = 20210105
        dateobs = '2021-01-06T04:33:55.704316928'
        mjd = Time(dateobs).mjd
        hdr = dict()

        #- Missing NIGHT and DATE-OBS falls back to MJD-OBS
        hdr['MJD-OBS'] = mjd
        self.assertEqual(util.header2night(hdr), night)

        #- Missing NIGHT and MJD-OBS falls back to DATE-OBS
        del hdr['MJD-OBS']
        hdr['DATE-OBS'] = dateobs
        self.assertEqual(util.header2night(hdr), night)

        #- NIGHT is NIGHT
        del hdr['DATE-OBS']
        hdr['NIGHT'] = night
        self.assertEqual(util.header2night(hdr), night)
        hdr['NIGHT'] = str(night)
        self.assertEqual(util.header2night(hdr), night)

        #- NIGHT trumps DATE-OBS
        hdr['NIGHT'] = night + 1
        hdr['DATE-OBS'] = dateobs
        self.assertEqual(util.header2night(hdr), night + 1)

        #- Bogus NIGHT falls back to DATE-OBS
        hdr['NIGHT'] = None
        self.assertEqual(util.header2night(hdr), night)
        hdr['NIGHT'] = '        '
        self.assertEqual(util.header2night(hdr), night)
        hdr['NIGHT'] = 'Sunday'
        self.assertEqual(util.header2night(hdr), night)

        #- Check rollover at noon KPNO (MST) = UTC 19:00
        hdr = dict()
        hdr['DATE-OBS'] = '2021-01-05T18:59:00'
        self.assertEqual(util.header2night(hdr), 20210104)
        hdr['DATE-OBS'] = '2021-01-05T19:00:01'
        self.assertEqual(util.header2night(hdr), 20210105)
        hdr['DATE-OBS'] = '2021-01-06T01:00:01'
        self.assertEqual(util.header2night(hdr), 20210105)
        hdr['DATE-OBS'] = '2021-01-06T18:59:59'
        self.assertEqual(util.header2night(hdr), 20210105)