# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: DESI master
#     language: python
#     name: desi-master
# ---

# # Test fibermap combination to avoid FITS errors

# ## Replicate `assemble_fibermap` script
#
# ```
# assemble_fibermap -n NIGHT -e EXPID -o OUTFILE
# ```

# ### Set up options

# +
import os
import sys
import argparse
from unittest.mock import patch
import glob
import warnings
import time
from pkg_resources import resource_filename

import yaml

import numpy as np
from astropy.table import Table, Column, join
from astropy.io import fits

from desitarget.targetmask import desi_mask

from desiutil.log import get_logger
from desiutil.depend import add_dependencies

from desispec.io.util import fitsheader, write_bintable, makepath, addkeys, parse_badamps
from desispec.io.meta import rawdata_root, findfile, faflavor2program
from desispec.io import iotime

from desispec.maskbits import fibermask
from desispec.io.fibermap import find_fiberassign_file, compare_fiberassign, assemble_fibermap

# +
os.environ['DESI_LOGLEVEL'] = 'DEBUG'
os.environ['SPECPROD'] = 'everest'
if 'CSCRATCH' not in os.environ:
    os.environ['CSCRATCH'] = os.path.join(os.environ['HOME'], 'Documents', 'Data', 'scratch')
night = '20210922'
expid = '00101293'
outfile = os.path.join(os.environ['CSCRATCH'], f'fibermap-{expid}.fits')

with patch('sys.argv', ['assemble_fibermap', '-n', night, '-e', expid, '-o', outfile]) as foo: 
    parser = argparse.ArgumentParser(usage = "{prog} [options]")
    parser.add_argument("-n", "--night", type=int, required=True,
            help="input night")
    parser.add_argument("-e", "--expid", type=int, required=True,
            help="spectroscopic exposure ID")
    parser.add_argument("-o", "--outfile", type=str, required=True,
            help="output filename")
    parser.add_argument("-b","--badamps", type=str,
            help="comma separated list of {camera}{petal}{amp}"+\
                 ", i.e. [brz][0-9][ABCD]. Example: 'b7D,z8A'")
    parser.add_argument("--badfibers", type=str,
            help="filename with table of bad fibers (with at least FIBER and FIBERSTATUS columns)")
    parser.add_argument("--debug", action="store_true",
            help="enter ipython debug mode at end")
    parser.add_argument("--overwrite", action="store_true",
            help="overwrite pre-existing output file")
    parser.add_argument("--force", action="store_true",
            help="make fibermap even if missing input guide or coordinates files")
    parser.add_argument("--no-svn-override", action="store_true",
            help="Do not allow fiberassign SVN to override raw data")

    args = parser.parse_args()

print(args)

# -

# ### Run `assemble_fibermap()`

# fibermap = assemble_fibermap(args.night, args.expid, badamps=args.badamps, force=args.force)
fibermap = assemble_fibermap(args.night, args.expid, badamps=args.badamps, badfibers_filename=args.badfibers, force=args.force, allow_svn_override=(not args.no_svn_override) )

# ### Write file

tmpfile = args.outfile+'.tmp'
fibermap.write(tmpfile, overwrite=args.overwrite, format='fits')
os.rename(tmpfile, args.outfile)
# log.info(f'Wrote {args.outfile}')

fibermap

fibermap.meta

# ## Recreate `assemble_fibermap()`

# ### Examine raw file

# +
log = get_logger()

rawfile = findfile('raw', night, int(expid))
try:
    rawheader = fits.getheader(rawfile, 'SPEC', disable_image_compression=True)
except KeyError:
    rawheader = fits.getheader(rawfile, 'SPS', disable_image_compression=True)
rawfafile = fafile = find_fiberassign_file(night, int(expid))

# -

rawfafile

allow_svn_override=(not args.no_svn_override)
#- Look for override fiberassign file in svn
tileid = rawheader['TILEID']
if allow_svn_override and ('DESI_TARGET' in os.environ):
    targdir = os.getenv('DESI_TARGET')
    testfile = f'{targdir}/fiberassign/tiles/trunk/{tileid//1000:03d}/fiberassign-{tileid:06d}.fits'
    if os.path.exists(testfile+'.gz'):
        fafile = testfile+'.gz'
    elif os.path.exists(testfile):
        fafile = testfile

    if rawfafile != fafile:
        log.info(f'Overriding raw fiberassign file {rawfafile} with svn {fafile}')
    else:
        log.info(f'{testfile}[.gz] not found; sticking with raw data fiberassign file')


# +
force=args.force
#- Find coordinates file in same directory
dirname, filename = os.path.split(rawfafile)
globfiles = glob.glob(dirname+'/coordinates-*.fits')
if len(globfiles) == 1:
    coordfile = globfiles[0]
elif len(globfiles) == 0:
    message = f'No coordinates*.fits file in fiberassign dir {dirname}'
    if force:
        log.error(message + '; continuing anyway')
        coordfile = None
    else:
        raise FileNotFoundError(message)

elif len(globfiles) > 1:
    raise RuntimeError(f'Multiple coordinates*.fits files in fiberassign dir {dirname}')


# +
#- And guide file
dirname, filename = os.path.split(rawfafile)
globfiles = glob.glob(dirname+'/guide-????????.fits.fz')
if len(globfiles) == 0:
    #- try falling back to acquisition image
    globfiles = glob.glob(dirname+'/guide-????????-0000.fits.fz')

if len(globfiles) == 1:
    guidefile = globfiles[0]
elif len(globfiles) == 0:
    message = f'No guide-*.fits.fz file in fiberassign dir {dirname}'
    if force:
        log.error(message + '; continuing anyway')
        guidefile = None
    else:
        raise FileNotFoundError(message)

elif len(globfiles) > 1:
    raise RuntimeError(f'Multiple guide-*.fits.fz files in fiberassign dir {dirname}')

# -

coordfile, guidefile

# +
#- Read QA parameters to find max offset for POOR and BAD positioning
#- replicates desispec.exposure_qa.get_qa_params, but that has
#- circular import if loaded from here
param_filename = resource_filename('desispec', 'data/qa/qa-params.yaml')
with open(param_filename) as f:
    qa_params = yaml.safe_load(f)['exposure_qa']

poor_offset_um = qa_params['poor_fiber_offset_mm']*1000
bad_offset_um = qa_params['bad_fiber_offset_mm']*1000

#- Preflight announcements
log.info(f'Night {night} spectro expid {expid}')
log.info(f'Raw data file {rawfile}')
log.info(f'Fiberassign file {fafile}')
if fafile != rawfafile:
    log.info(f'Original raw fiberassign file {rawfafile}')
log.info(f'Platemaker coordinates file {coordfile}')
log.info(f'Guider file {guidefile}')

#----
#- Read and assemble

# fa = Table.read(fafile, 'FIBERASSIGN')
# fa.sort('LOCATION')
with fits.open(fafile) as hdulist:
    fa = hdulist['FIBERASSIGN'].copy()
fa.data.sort(order='LOCATION')

# -

#- if using svn fiberassign override, check consistency of columns that
#- ICS / platemaker used for actual observations; they should never change
if fafile != rawfafile:
    with fits.open(rawfafile) as hdulist:
        rawfa = hdulist['FIBERASSIGN'].copy()
    rawfa.data.sort(order='LOCATION')
    # rawfa = Table.read(rawfafile, 'FIBERASSIGN')
    # rawfa.sort('LOCATION')
    badcol = compare_fiberassign(rawfa.data, fa.data)

    #- special case for tile 80713 on 20210110 with PMRA,PMDEC NaN -> 0.0
    if night == 20210110 and tileid == 80713:
        for col in ['PMRA', 'PMDEC']:
            if col in badcol:
                ii = rawfa[col] != fa[col]
                if np.all(np.isnan(rawfa.data[col][ii]) & (fa.data[col][ii] == 0.0)):
                    log.warning(f'Ignoring {col} mismatch NaN -> 0.0 on tile {tileid} night {night}')
                    badcol.remove(col)

    if len(badcol)>0:
        msg = f'incompatible raw/svn fiberassign files for columns {badcol}'
        log.critical(msg)
        raise ValueError(msg)
    else:
        log.info('svn fiberassign columns used for obervations match raw data (good)')


# +
#- Tiles designed before Fall 2021 had a LOCATION:FIBER swap for fibers
#- 3402 and 3429 at locations 6098 and 6099; check and correct if needed.
#- see desispec #1380
#- NOTE: this only swaps them if the incorrect combination is found
if (6098 in fa.data['LOCATION']) and (6099 in fa.data['LOCATION']):
    iloc6098 = np.where(fa.data['LOCATION'] == 6098)[0][0]
    iloc6099 = np.where(fa.data['LOCATION'] == 6099)[0][0]
    if (fa.data['FIBER'][iloc6098] == 3402) and (fa.data['FIBER'][iloc6099] == 3429):
        log.warning(f'FIBERS 3402 and 3429 are swapped in {fafile}; correcting')
        fa.data['FIBER'][iloc6098] = 3429
        fa.data['FIBER'][iloc6099] = 3402

#- add missing columns for data model consistency
if 'PLATE_RA' not in fa.data.columns.names:
    plate_ra_col = fa.data.columns['TARGET_RA'].copy()
    plate_ra_col.name = 'PLATE_RA'
    fa.data.columns.add_col(plate_ra_col)

if 'PLATE_DEC' not in fa.data.columns.names:
    plate_dec_col = fa.data.columns['TARGET_DEC'].copy()
    plate_dec_col.name = 'PLATE_DEC'
    fa.data.columns.add_col(plate_dec_col)

#- also read extra keywords from HDU 0
fa_hdr0 = fits.getheader(fafile, 0)
if 'OUTDIR' in fa_hdr0:
    fa_hdr0.rename_keyword('OUTDIR', 'FAOUTDIR')
longstrn = fits.Card('LONGSTRN', 'OGIP 1.0', 'The OGIP Long String Convention may be used.')
fa_hdr0.insert('DEPNAM00', longstrn)
fa.header.extend(fa_hdr0, unique=True)
# skipkeys = ['SIMPLE', 'EXTEND', 'COMMENT', 'EXTNAME', 'BITPIX', 'NAXIS']
# addkeys(fa.meta, fa_hdr0, skipkeys=skipkeys)

# -

fa.header

rawheader

# +
#- Read platemaker (pm) coordinates file; 3 formats to support:
#  1. has FLAGS_CNT/EXP_n and DX_n, DX_n (e.g. 20201214/00067678)
#  2. has FLAGS_CNT/EXP_n but not DX_n, DY_n (e.g. 20210402/00083144)
#  3. doesn't have any of these (e.g. 20201220/00069029)
# Notes:
#  * don't use FIBER_DX/DY because some files are missing those
#    (e.g. 20210224/00077902)
#  * don't use FLAGS_COR_n because some files are missing that
#    (e.g. 20210402/00083144)

pm = None
numiter = 0
if coordfile is None:
    log.error('No coordinates file, thus no info on fiber positioning')
else:
    with fits.open(coordfile) as hdulist:
        pm = hdulist['DATA'].copy()
    # pm = Table.read(coordfile, 'DATA')  #- PM = PlateMaker

    #- If missing columns *and* not the first in a (split) sequence,
    #- try again with the first expid in the sequence
    #- (e.g. 202010404/00083419 -> 83418)
    if 'DX_0' not in pm.data.columns.names:
        log.error(f'Missing DX_0 in {coordfile}')
        if 'VISITIDS' in rawheader:
            firstexp = int(rawheader['VISITIDS'].split(',')[0])
            if firstexp != rawheader['EXPID']:
                origcorrdfile = coordfile
                coordfile = findfile('coordinates', night, firstexp)
                log.info(f'trying again with {coordfile}')
                with fits.open(coordfile) as hdulist:
                    pm = hdulist['DATA'].copy()
                # pm = Table.read(coordfile, 'DATA')
            else:
                log.error(f'no earlier coordinates file for this tile')
        else:
            log.error('Missing VISITIDS header keywords to find earlier coordinates file')

    if 'FLAGS_CNT_0' not in pm.data.columns.names:
        log.error(f'Missing spotmatch FLAGS_CNT_0 in {coordfile}; no positioner offset info')
        pm = None
        numiter = 0
    else:
        #- Count number of iterations in file
        numiter = len([col for col in pm.data.columns.names if col.startswith('FLAGS_CNT_')])
        log.info(f'Using FLAGS_CNT_{numiter-1} in {coordfile}')

# -

fa

# +
#- Now let's merge that platemaker coordinates table (pm) with fiberassign
if pm is not None:
    pm_table = Table(pm.data)
    pm_table['LOCATION'] = 1000*pm_table['PETAL_LOC'] + pm_table['DEVICE_LOC']
    keep = np.in1d(pm_table['LOCATION'], fa.data['LOCATION'])
    pm_table = pm_table[keep]
    pm_table.sort('LOCATION')
    log.info('{}/{} fibers in coordinates file'.format(len(pm_table), len(fa.data)))

    #- Create fibermap table to merge with fiberassign file
    fibermap = Table()
    fibermap_header = fits.Header({'XTENSION': 'BINTABLE'})
    fibermap['LOCATION'] = pm_table['LOCATION']
    fibermap['NUM_ITER'] = numiter

    #- Sometimes these columns are missing in the coordinates files, maybe
    #- only when numiter=1, i.e. only a blind move but not corrections?
    if f'FPA_X_{numiter-1}' in pm_table.colnames:
        fibermap['FIBER_X'] = pm_table[f'FPA_X_{numiter-1}']
        fibermap['FIBER_Y'] = pm_table[f'FPA_Y_{numiter-1}']
        fibermap['DELTA_X'] = pm_table[f'DX_{numiter-1}']
        fibermap['DELTA_Y'] = pm_table[f'DY_{numiter-1}']
    else:
        log.error('No FIBER_X/Y or DELTA_X/Y information from platemaker')
        fibermap['FIBER_X'] = np.zeros(len(pm_table))
        fibermap['FIBER_Y'] = np.zeros(len(pm_table))
        fibermap['DELTA_X'] = np.zeros(len(pm_table))
        fibermap['DELTA_Y'] = np.zeros(len(pm_table))

    if ('FIBER_RA' in pm_table.colnames) and ('FIBER_DEC' in pm_table.colnames):
        fibermap['FIBER_RA'] = pm_table['FIBER_RA']
        fibermap['FIBER_DEC'] = pm_table['FIBER_DEC']
    else:
        log.error('No FIBER_RA or FIBER_DEC from platemaker')
        fibermap['FIBER_RA'] = np.zeros(len(pm_table))
        fibermap['FIBER_DEC'] = np.zeros(len(pm_table))

    #- Bit definitions at https://desi.lbl.gov/trac/wiki/FPS/PositionerFlags

    #- FLAGS_EXP bit 2 is for positioners (not FIF, GIF, ...)
    #- These should match what is in fiberassign, except broken fibers
    expflags = pm_table[f'FLAGS_EXP_{numiter-1}']
    goodmatch = ((expflags & 4) == 4)
    if np.any(~goodmatch):
        badloc = list(pm_table['LOCATION'][~goodmatch])
        log.warning(f'Flagging {len(badloc)} locations without POS_POS bit set: {badloc}')

    #- Keep only matched positioners (FLAGS_CNT_n bit 0)
    cntflags = pm_table[f'FLAGS_CNT_{numiter-1}']
    spotmatched = ((cntflags & 1) == 1)

    num_nomatch = np.sum(goodmatch & ~spotmatched)
    if num_nomatch > 0:
        badloc = list(pm_table['LOCATION'][goodmatch & ~spotmatched])
        log.error(f'Flagging {num_nomatch} unmatched fiber locations: {badloc}')

    goodmatch &= spotmatched

    #- pass forward dummy column for joining with fiberassign
    fibermap['_GOODMATCH'] = goodmatch

    #- WARNING: this join can re-order the table
    fibermap = join(Table(fa.data), fibermap, join_type='left')

    #- poor and bad positioning
    dr = np.sqrt(fibermap['DELTA_X']**2 + fibermap['DELTA_Y']**2) * 1000
    poorpos = ((poor_offset_um < dr) & (dr <= bad_offset_um))
    badpos = (dr > bad_offset_um) | np.isnan(dr)
    numpoor = np.count_nonzero(poorpos)
    numbad = np.count_nonzero(badpos)
    if numpoor > 0:
        log.warning(f'Flagging {numpoor} POOR positions with {poor_offset_um} < offset <= {bad_offset_um} microns')
    if numbad > 0:
        log.warning(f'Flagging {numbad} BAD positions with offset > {bad_offset_um} microns')

    #- Set fiber status bits
    missing = np.in1d(fibermap['LOCATION'], pm_table['LOCATION'], invert=True)
    missing |= ~fibermap['_GOODMATCH']
    fibermap['FIBERSTATUS'][missing] |= fibermask.MISSINGPOSITION
    fibermap['FIBERSTATUS'][poorpos] |= fibermask.POORPOSITION
    fibermap['FIBERSTATUS'][badpos] |= fibermask.BADPOSITION

    fibermap.remove_column('_GOODMATCH')

else:
    #- No coordinates file or no positioning iterations;
    #- just use fiberassign + dummy columns
    log.error('Unable to find useful coordinates file; proceeding with fiberassign + dummy columns')
    fibermap = Table(fa.data)
    fibermap['NUM_ITER'] = 0
    fibermap['FIBER_X'] = 0.0
    fibermap['FIBER_Y'] = 0.0
    fibermap['DELTA_X'] = 0.0
    fibermap['DELTA_Y'] = 0.0
    fibermap['FIBER_RA'] = 0.0
    fibermap['FIBER_DEC'] = 0.0
    # Update data types to be consistent with updated value if coord file was used.
    for val in ['FIBER_X','FIBER_Y','DELTA_X','DELTA_Y']:
        old_col = fibermap[val]
        fibermap.replace_column(val,Table.Column(name=val,data=old_col.data,dtype='>f8'))
    for val	in ['LOCATION','NUM_ITER']:
        old_col = fibermap[val]
        fibermap.replace_column(val,Table.Column(name=val,data=old_col.data,dtype=np.int64))

# -

#- Update SKY and STD target bits to be in both CMX_TARGET and DESI_TARGET
#- i.e. if they are set in one, also set in the other.  Ditto for SV*
for targetcol in ['CMX_TARGET', 'SV0_TARGET', 'SV1_TARGET', 'SV2_TARGET']:
    if targetcol in fibermap.colnames:
        for mask in [
                desi_mask.SKY, desi_mask.STD_FAINT, desi_mask.STD_BRIGHT]:
            ii  = (fibermap[targetcol] & mask) != 0
            iidesi = (fibermap['DESI_TARGET'] & mask) != 0
            fibermap[targetcol][iidesi] |= mask
            fibermap['DESI_TARGET'][ii] |= mask


# +
#- Add header information from rawfile
log.debug(f'Adding header keywords from {rawfile}')
# skipkeys = ['EXPTIME',]
# addkeys(fibermap.meta, rawheader, skipkeys=skipkeys)
fibermap_header.extend(rawheader, strip=True)
fibermap_header.remove('EXPTIME')
fibermap['EXPTIME'] = rawheader['EXPTIME']
#- Add header info from guide file
#- sometimes full header is in HDU 0, other times HDU 1...
if guidefile is not None:
    log.debug(f'Adding header keywords from {guidefile}')
    guideheader = fits.getheader(guidefile, 0)
    if 'TILEID' not in guideheader:
        guideheader = fits.getheader(guidefile, 1)

    if fibermap_header['TILEID'] != guideheader['TILEID']:
        raise RuntimeError('fiberassign tile {} != guider tile {}'.format(
            fibermap_header['TILEID'], guideheader['TILEID']))

    # addkeys(fibermap.meta, guideheader, skipkeys=skipkeys)
    fibermap_header.extend(guideheader, strip=True)
    fibermap_header.remove('EXPTIME')


fibermap_header['EXTNAME'] = 'FIBERMAP'
for key in ('ZIMAGE', 'ZSIMPLE', 'ZBITPIX', 'ZNAXIS', 'ZNAXIS1', 'ZTILE1', 'ZCMPTYPE', 'ZNAME1', 'ZVAL1', 'ZNAME2', 'ZVAL2'):
    fibermap_header.remove(key)
# -

fibermap_header

# +
#- Early data raw headers had bad >8 char 'FIBERASSIGN' keyword
if 'FIBERASSIGN' in fibermap_header:
    log.warning('Renaming header keyword FIBERASSIGN -> FIBASSGN')
    fibermap_header.rename_keyword('FIBERASSIGN', 'FIBASSGN')
    # fibermap.meta['FIBASSGN'] = fibermap.meta['FIBERASSIGN']
    # del fibermap.meta['FIBERASSIGN']

#- similarly for early splits in raw data file
if 'USESPLITS' in fibermap_header:
    log.warning('Renaming header keyword USESPLITS -> USESPLIT')
    fibermap_header.rename_keyword('USESPLITS', 'USESPLIT')
    # fibermap.meta['USESPLIT'] = fibermap.meta['USESPLITS']
    # del fibermap.meta['USESPLITS']

#- Record input guide and coordinates files
if guidefile is not None:
    fibermap_header['GUIDEFIL'] = os.path.basename(guidefile)
else:
    fibermap_header['GUIDEFIL'] = 'MISSING'

if coordfile is not None:
    fibermap_header['COORDFIL'] = os.path.basename(coordfile)
else:
    fibermap_header['COORDFIL'] = 'MISSING'

# -

badamps = None
#- mask the fibers defined by badamps
if badamps is not None:
    maskbits = {'b':fibermask.BADAMPB, 'r':fibermask.BADAMPR, 'z':fibermask.BADAMPZ}
    ampoffsets = {'A': 0, 'B':250, 'C':0, 'D':250}
    for (camera, petal, amplifier) in parse_badamps(badamps):
        maskbit = maskbits[camera]
        ampoffset = ampoffsets[amplifier]
        fibermin = int(petal)*500 + ampoffset
        fibermax = fibermin + 250
        ampfibs = np.arange(fibermin,fibermax)
        truefmax = fibermax - 1
        log.info(f'Masking fibers from {fibermin} to {truefmax} for camera {camera} because of badamp entry '+\
                 f'{camera}{petal}{amplifier}')
        ampfiblocs = np.in1d(fibermap['FIBER'], ampfibs)
        fibermap['FIBERSTATUS'][ampfiblocs] |= maskbit


badfibers_filename = None
#- mask the fibers defined by bad fibers
if badfibers_filename is not None:
    table=Table.read(badfibers_filename)

    # list of bad fibers that are in the fibermap
    badfibers=np.intersect1d(np.unique(table["FIBER"]),fibermap["FIBER"])

    for i,fiber in enumerate(badfibers) :
        # for each of the bad fiber, add the bad bits to the fiber status
        badfibermask = np.bitwise_or.reduce(table["FIBERSTATUS"][table["FIBER"]==fiber])
        fibermap['FIBERSTATUS'][fibermap["FIBER"]==fiber] |= badfibermask


# +
#- NaN are a pain; reset to dummy values
for col in [
    'FIBER_X', 'FIBER_Y',
    'DELTA_X', 'DELTA_Y',
    'FIBER_RA', 'FIBER_DEC',
    'GAIA_PHOT_G_MEAN_MAG',
    'GAIA_PHOT_BP_MEAN_MAG',
    'GAIA_PHOT_RP_MEAN_MAG',
    ]:
    ii = np.isnan(fibermap[col])
    if np.any(ii):
        n = np.sum(ii)
        log.warning(f'Setting {n} {col} NaN to 0.0')
        fibermap[col][ii] = 0.0
#
# Some SV1-era files had these extraneous columns, make sure they are not propagated.
#
for col in ('NUMTARGET', 'BLOBDIST', 'FIBERFLUX_IVAR_G', 'FIBERFLUX_IVAR_R', 'FIBERFLUX_IVAR_Z', 'HPXPIXEL'):
    if col in fibermap.colnames:
        log.debug("Removing column '%s' from fibermap table.", col)
        fibermap.remove_column(col)

#
# Some SV1-era files have RELEASE as int32.  Should be int16.
#
if fibermap['RELEASE'].dtype == np.dtype('>i2'):
    log.debug("RELEASE has correct type.")
else:
    log.warning("Setting RELEASE to int16.")
    fibermap['RELEASE'] = fibermap['RELEASE'].astype(np.int16)
    
#- Some code incorrectly relies upon the fibermap being sorted by
#- fiber number, so accomodate that before returning the table
fibermap.sort('FIBER')

# -

fibermap

fibermap_header

fibermap_hdu = fits.BinTableHDU(fibermap)
fibermap_hdu.header.extend(fibermap_header, unique=True)

fibermap_hdulist = fits.HDUList([fits.PrimaryHDU(), fibermap_hdu])

fibermap_hdulist.info()

fibermap_hdulist[0].header

foo = np.array([1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000], dtype=np.int32)

foo.astype(np.int16)

# ## Look at the list of exposures.

exposures = os.path.join(os.environ['DESI_SPECTRO_REDUX'], os.environ['SPECPROD'], "exposures-{SPECPROD}.fits".format(**os.environ))
with fits.open(exposures) as hdulist:
    exposures = hdulist['EXPOSURES'].data.copy()

program = faflavor2program(exposures['FAFLAVOR'])
sv1bright = (program == 'bright') & (exposures['SURVEY'] == 'sv1') & (exposures['NIGHT'] == 20210224)
exposures['NIGHT'][sv1bright], exposures['EXPID'][sv1bright]

exposures_row = np.nonzero((exposures['NIGHT'] == 20210224) & (exposures['EXPID'] == 77952))[0][0]
survey_program = "{0}-{1}".format(exposures['SURVEY'][exposures_row], program[exposures_row])
survey_program

sv1dark = (program == 'dark') & (exposures['SURVEY'] == 'sv1') & (exposures['NIGHT'] == 20210220)
exposures['NIGHT'][sv1dark], exposures['EXPID'][sv1dark]

sv2dark = (program == 'dark') & (exposures['SURVEY'] == 'sv2') & (exposures['NIGHT'] == 20210403) 
exposures['NIGHT'][sv2dark], exposures['EXPID'][sv2dark]

sv2bright = (program == 'bright') & (exposures['SURVEY'] == 'sv2') & (exposures['NIGHT'] == 20210324) 
exposures['NIGHT'][sv2bright], exposures['EXPID'][sv2bright]

sv3dark = (program == 'dark') & (exposures['SURVEY'] == 'sv3') & (exposures['NIGHT'] == 20210420) 
exposures['NIGHT'][sv3dark], exposures['EXPID'][sv3dark]

sv3bright = (program == 'bright') & (exposures['SURVEY'] == 'sv3') & (exposures['NIGHT'] == 20210420) 
exposures['NIGHT'][sv3bright], exposures['EXPID'][sv3bright]

maindark = (program == 'dark') & (exposures['SURVEY'] == 'main')  & (exposures['NIGHT'] == 20210531) 
exposures['NIGHT'][maindark], exposures['EXPID'][maindark]

mainbright = (program == 'bright') & (exposures['SURVEY'] == 'main')  & (exposures['NIGHT'] == 20210531) 
exposures['NIGHT'][mainbright], exposures['EXPID'][mainbright]

# ## Dealing with LONGSTRN
# Add this header
# ```
# LONGSTRN= 'OGIP 1.0'           / The OGIP Long String Convention may be used.
# ```
# [Reference](https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/f_user/node25.html).



StarcoderdataJupyterScriptsDedupFiltered