def __init__(self): import pydl.pydlutils.yanny as yanny import os blockfile = os.path.join(os.getenv('PLATEDESIGN_DIR'), 'data', 'apogee', 'fiberBlocksAPOGEE_SOUTH.par') self.blocks = yanny.yanny(blockfile) self.fibers = self.blocks['TIFIBERBLOCK_APOGEE_SOUTH']
def __init__(self, schedule='normal', observatory='apo', observatoryfile=None): """Create Master object for schedule""" super().__init__(observatory=observatory, observatoryfile=observatoryfile) masterfile = 'master_schedule_{o}_{s}.par'.format(o=observatory, s=schedule) env_dir = os.getenv('ROBOSCHEDULER_DIR') if env_dir is None: env_dir = os.path.abspath(__file__).split( "/python/roboscheduler/")[0] schedulefile = os.path.join(env_dir, 'data', masterfile) print(schedulefile) self._schedulefile = schedulefile self.schedule = yanny.yanny(self._schedulefile) self._validate() self.event_dates = np.array( [date.decode() for date in self.schedule['SCHEDULE']['date']]) self.event_times = np.array( [time.decode() for time in self.schedule['SCHEDULE']['time']]) self.event_mjds = self._dateandtime2mjd() self.events = np.array( [event.decode() for event in self.schedule['SCHEDULE']['event']]) self.start = self._start() self.end = self._end() self.mjds = self._mjds() self.dark_twilight = np.float32(self.schedule['dark_twilight']) self.bright_twilight = np.float32(self.schedule['bright_twilight']) return
def __init__(self, schedulefile=None, observatory='apo', observatoryfile=None): """Create Master object for schedule""" super().__init__(observatory=observatory, observatoryfile=observatoryfile) if (schedulefile is None): masterfile = 'master_schedule_{observatory}.par'.format( observatory=observatory) schedulefile = os.path.join(os.getenv('OBSERVESIM_DIR'), 'data', masterfile) self._schedulefile = schedulefile self.schedule = yanny.yanny(self._schedulefile) self._validate() self.event_dates = np.array( [date.decode() for date in self.schedule['SCHEDULE']['date']]) self.event_times = np.array( [time.decode() for time in self.schedule['SCHEDULE']['time']]) self.event_mjds = self._dateandtime2mjd() self.events = np.array( [event.decode() for event in self.schedule['SCHEDULE']['event']]) self.start = self._start() self.end = self._end() self.mjds = self._mjds() return
def __init__(self, observatory='apo', observatoryfile=None, dark_twilight=-15., bright_twilight=-8.): """Create Observer object""" super().__init__() self.observatory = observatory if (observatoryfile is None): env_dir = os.getenv('ROBOSCHEDULER_DIR') if env_dir is None: env_dir = os.path.abspath(__file__).split( "/python/roboscheduler/")[0] observatoryfile = os.path.join(env_dir, 'data', 'observatories.par') self._file = observatoryfile self._data = yanny.yanny(self._file) observatories = np.array( [obs.decode() for obs in self._data['OBSERVATORY']['observatory']]) indx = np.where(observatories == self.observatory)[0] self.latitude = self._data['OBSERVATORY']['latitude'][indx] self.longitude = self._data['OBSERVATORY']['longitude'][indx] self.dark_twilight = np.float32(dark_twilight) self.bright_twilight = np.float32(bright_twilight) return
def from_par_file(cls, f): """ Instantiate the plan set from a par file """ # TODO: The approach here (read using yanny, set to par # individually, then covert back to record array using # ParDatabase) is stupid... if not os.path.isfile(f): raise FileNotFoundError('No file {0}.'.format(f)) par = yanny(filename=f, raw=True) if len(par['DAPPLAN']['drpqa_key']) == 0: raise ValueError('Could not find DAPPLAN entries in {0}!'.format(f)) # Setup the array of emission line database parameters nplan = len(par['DAPPLAN']['drpqa_key']) planlist = [] for i in range(nplan): planlist += [ AnalysisPlan(par['DAPPLAN']['drpqa_key'][i], bool(par['DAPPLAN']['drpqa_clobber'][i]), par['DAPPLAN']['bin_key'][i], bool(par['DAPPLAN']['bin_clobber'][i]), par['DAPPLAN']['continuum_key'][i], bool(par['DAPPLAN']['continuum_clobber'][i]), par['DAPPLAN']['elmom_key'][i], bool(par['DAPPLAN']['elmom_clobber'][i]), par['DAPPLAN']['elfit_key'][i], bool(par['DAPPLAN']['elfit_clobber'][i]), par['DAPPLAN']['spindex_key'][i], bool(par['DAPPLAN']['spindex_clobber'][i])) ] return cls(planlist)
def read_tiles(parfile): a = yanny(parfile) tile = np.array(a['STRUCT1']['tile']).astype('str') ra = np.array(a['STRUCT1']['racen']) tmp = (ra > 270.) ra[tmp] = ra[tmp] - 360. dec = np.array(a['STRUCT1']['deccen']) return [tile, ra, dec]
def __init__(self, observatory='apo', observatoryfile=None): """Create Observer object""" super().__init__() self.observatory = observatory if (observatoryfile is None): observatoryfile = os.path.join(os.getenv('OBSERVESIM_DIR'), 'data', 'observatories.par') self._file = observatoryfile self._data = yanny.yanny(self._file) observatories = np.array([ observatory.decode() for observatory in self._data['OBSERVATORY']['observatory'] ]) indx = np.where(observatories == self.observatory)[0][0] self.latitude = self._data['OBSERVATORY']['latitude'][indx] self.longitude = self._data['OBSERVATORY']['longitude'][indx]
def _parse_yanny(self): """ Parse the yanny file (provided by :attr:`file`) for the bandhead database. Returns: :obj:`list`: The list of :class:`mangadap.par.parset.ParSet` instances for each line of the database. """ # Read the yanny file par = yanny(filename=self.file, raw=True) if len(par['DAPABI']['index']) == 0: raise ValueError('Could not find DAPABI entries in {0}!'.format( self.file)) # Check if any of the bands are dummy bands and warn the user self.dummy = numpy.any(numpy.array(par['DAPABI']['blueside']) < 0, axis=1) self.dummy |= numpy.any(numpy.array(par['DAPABI']['redside']) < 0, axis=1) self.dummy |= numpy.any(numpy.array(par['DAPABI']['primary']) < 0, axis=1) if numpy.sum(self.dummy) > 0: warnings.warn( 'Bands with negative wavelengths are used to insert dummy values.' ' Ignoring input bands with indices: {0}'.format( numpy.array(par['DAPABI']['index'])[self.dummy])) # Setup the array of absorption-line index database parameters self.size = len(par['DAPABI']['index']) parlist = [] for i in range(self.size): invac = par['DAPABI']['waveref'][i] == 'vac' comp = par['DAPABI']['component'][i] != 0 parlist += [ BandPassFilterPar(index=par['DAPABI']['index'][i], name=par['DAPABI']['name'][i], blueside=par['DAPABI']['blueside'][i] if invac \ else airtovac(numpy.array(par['DAPABI']['blueside'][i])), redside=par['DAPABI']['redside'][i] if invac \ else airtovac(numpy.array(par['DAPABI']['redside'][i])), primary=par['DAPABI']['primary'][i] if invac \ else airtovac(numpy.array(par['DAPABI']['primary'][i])), units=par['DAPABI']['units'][i], integrand='flambda', component=comp) ] return parlist
def _read_fix_data(self, fix_file): """ Read "fix" data from the provided file. Fix data are generally corrections to the metadata provides by the NSA for specific MaNGA observations. Args: fix_file (:obj:`str`): SDSS parameter file with the fix data. Returns: yanny: A yanny structure with the data fixes. Returns None and raises a warning if the file does not exist. """ if not fix_file.exists(): warnings.warn(f'DAP "fix" file does not exist: {fix_file}') return None return yanny(filename=str(fix_file))
def load_yanny(platenum): platepath = paths.plateholes(platenum) if platepath.exists(): pass else: # need to get plugHoles files platebatch_path = paths.plate_batch(platenum) platebatch = platebatch_path.name print( f'{os.fspath(platepath)} does not exist. Getting files via rsync now' ) print( f'--- Please enter your password for {config.utah_username} below --' ) download.plugHoles_batch(platebatch) filepath = os.fspath(paths.plateholes(platenum)) pholes_obj = yanny(filepath, raw=True) return pholes_obj
def select_targets(outfile, location): numpy.random.seed(location) datafilename = '../target_info/SecQuanObj_%03i+00.fits' % location data = fitsio.read(datafilename) # De-redden ak = data['AK'] aj = ak * 2.5 j0 = data['J_M'] - aj k0 = data['K_M'] - ak # Cut on jk0,h indx = ((j0 - k0) > 0.8) * (data['H_M'] > 12.) * (data['H_M'] < 13.) data = data[indx] # setup dust map dmap = mwdust.Marshall06(filter='2MASS H') # Calculate A_H(7 kpc) according to Marshall et al. (2006) ahdmap = numpy.zeros(len(data)) lb = bovy_coords.radec_to_lb(data['RA'], data['DEC'], degree=True) for ii in range(len(data)): ahdmap[ii] = dmap(lb[ii, 0], lb[ii, 1], 7.) # Cut on AH <= 1.4 indx = ahdmap <= 1.4 data = data[indx] # Match against already drilled targets data = esutil.numpy_util.add_fields(data, [('FLAG_DONT_OBSERVE', int)]) data['FLAG_DONT_OBSERVE'] = 0 yannyfiles = glob.glob('../target_info/plateHolesSorted-*.par') for yannyfile in yannyfiles: drillFile = yanny.yanny(filename=yannyfile, np=True) drilled = drillFile['STRUCT1'] # spherematch h = esutil.htm.HTM() m1, m2, d12 = h.match(data['RA'], data['DEC'], drilled['target_ra'], drilled['target_dec'], 2. / 3600., maxmatch=1) data['FLAG_DONT_OBSERVE'][m1] = 1 # Write to file fitsio.write(outfile, data[numpy.random.permutation(len(data))], clobber=True) return None
def from_par_file(cls, f, name): r""" Define the object using an `SDSS-style parameter file`_. This has been tailored to work with the sdssMaskbits.par file in IDLUTILS; however, it can work with similar files. See :class:`mangadap.util.drpfits.DRPFitsBitMask` for an example that uses this function. Args: f (:obj:`str`): File name to use for defining the :class:`BitMask`. name (:obj:`str`): The designation of the bits to assign. For example, in :class:`mangadap.util.drpfits.DRPFitsBitMask` this is `'MANGA_DRP3PIXMASK'`. Returns: :class:`BitMask`: Object with bitmasks defined by the parameter file. Raises: FileNotFoundError: Raised if the input file does not exist. """ # Check the file exists if not os.path.isfile(f): raise FileNotFoundError('Could not find ini file: {0}'.format(f)) # Read the full yanny file and only select the maskbits typedef bits = yanny(filename=f, raw=True)['MASKBITS'] # Find the bits with the correct designation indx = numpy.array(bits['flag']) == name keys = numpy.array(bits['label'])[indx] vals = numpy.array(bits['bit'])[indx] descr = numpy.array(bits['description'])[indx] # Slot in NULLs where necessary and return the object instance keys, vals, descr = cls._fill_sequence(keys, vals, descr) srt = numpy.argsort(vals) return cls(keys[srt], descr=None if descr is None else descr[srt])
def from_par_file(cls, f): """ Read the observation parameters from the provided yanny file. Args: f (str) : Name of the file to read Returns: :class:`ObsInputPar`: Derived instance of :class:`mangadap.par.ParSet` with the input observational parameters of the DRP data product to analyze with the DAP. Raises: FileNotFoundError: Raised if the provided file does not exist. ValueError: Raised if the input yanny file has more than one entry of DAPPAR. KeyError: Raised if selected keys are not in provided file. """ if not os.path.isfile(f): raise FileNotFoundError('Could not open {0}!'.format(f)) # Read the file par = yanny(filename=f, raw=True) # Check the number of entries if len(par['DAPPAR']['plate']) > 1: raise ValueError('File must contain only instance of DAPPAR!') # Return the ObsInputPar instance return cls(par['DAPPAR']['plate'][0], par['DAPPAR']['ifudesign'][0], mode=par['DAPPAR']['mode'][0], vel=par['DAPPAR']['vel'][0], vdisp=par['DAPPAR']['vdisp'][0], ell=par['DAPPAR']['ell'][0], pa=par['DAPPAR']['pa'][0], reff=par['DAPPAR']['reff'][0])
def select_targets(outfile,location): numpy.random.seed(location) datafilename= '../target_info/SecQuanObj_%03i+00.fits' % location data= fitsio.read(datafilename) # De-redden ak= data['AK'] aj= ak*2.5 j0= data['J_M']-aj k0= data['K_M']-ak # Cut on jk0,h indx= ((j0-k0) > 0.8)*(data['H_M'] > 12.)*(data['H_M'] < 13.) data= data[indx] # setup dust map dmap= mwdust.Marshall06(filter='2MASS H') # Calculate A_H(7 kpc) according to Marshall et al. (2006) ahdmap= numpy.zeros(len(data)) lb= bovy_coords.radec_to_lb(data['RA'],data['DEC'],degree=True) for ii in range(len(data)): ahdmap[ii]= dmap(lb[ii,0],lb[ii,1],7.) # Cut on AH <= 1.4 indx= ahdmap <= 1.4 data= data[indx] # Match against already drilled targets data= esutil.numpy_util.add_fields(data,[('FLAG_DONT_OBSERVE', int)]) data['FLAG_DONT_OBSERVE']= 0 yannyfiles= glob.glob('../target_info/plateHolesSorted-*.par') for yannyfile in yannyfiles: drillFile= yanny.yanny(filename=yannyfile,np=True) drilled= drillFile['STRUCT1'] # spherematch h=esutil.htm.HTM() m1,m2,d12 = h.match(data['RA'],data['DEC'], drilled['target_ra'],drilled['target_dec'], 2./3600.,maxmatch=1) data['FLAG_DONT_OBSERVE'][m1]= 1 # Write to file fitsio.write(outfile,data[numpy.random.permutation(len(data))], clobber=True) return None
def _parse_yanny(self): """ Parse the yanny file (provided by :attr:`file`) for the emission-line database. Returns: :obj:`list`: The list of :class:`~mangadap.par.parset.ParSet` instances for each line of the database. """ # Read the yanny file par = yanny(filename=self.file, raw=True) if len(par['DAPEML']['index']) == 0: raise ValueError('Could not find DAPEML entries in {0}!'.format( self.file)) # Setup the array of emission line database parameters self.size = len(par['DAPEML']['index']) parlist = [] for i in range(self.size): invac = par['DAPEML']['waveref'][i] == 'vac' tie_index = -1 if par['DAPEML']['tie'][i][0] == 'None' \ else int(par['DAPEML']['tie'][i][0]) tie_par = [ None if t == 'None' else t for t in par['DAPEML']['tie'][i][1:] ] parlist += [EmissionLinePar(index=par['DAPEML']['index'][i], name=par['DAPEML']['name'][i], restwave=par['DAPEML']['restwave'][i] if invac else airtovac(par['DAPEML']['restwave'][i]), action=par['DAPEML']['action'][i], tie_index=tie_index, tie_par=tie_par, blueside=par['DAPEML']['blueside'][i] if invac else \ airtovac(numpy.array(par['DAPEML']['blueside'][i])), redside=par['DAPEML']['redside'][i] if invac else \ airtovac(numpy.array(par['DAPEML']['redside'][i])))] return parlist
def _parse_yanny(self): """ Parse the yanny file (provided by :attr:`file`) for the artifact database. Returns: :obj:`list`: The list of :class:`mangadap.par.parset.ParSet` instances for each line of the database. """ # Read the yanny file par = yanny(filename=self.file, raw=True) if len(par['DAPART']['index']) == 0: raise ValueError('Could not find DAPART entries in {0}!'.format(self.file)) # Setup the array of emission line database parameters self.size = len(par['DAPART']['index']) parlist = [] for i in range(self.size): invac = par['DAPART']['waveref'][i] == 'vac' parlist += [ ArtifactPar(index=par['DAPART']['index'][i], name=par['DAPART']['name'][i], waverange=numpy.asarray(par['DAPART']['waverange'][i]) \ if invac else airtovac(par['DAPEML']['waverange'][i]) )] return parlist
def load_filters(**kwargs): """ Load filter information from a list of files. Filter files should contain one structure with columns 'lambda' & 'pass'. The name of the table can be arbitrary though. """ from os import getenv from os.path import join from numpy import array from pydl.pydlutils.yanny import yanny if 'filterlist' not in kwargs: raise TypeError('Invalid keyword arguments passed to load_filters') if 'filterpath' not in kwargs: kwargs['filterpath'] = join(getenv('KCORRECT_DIR'),'data','filters') filterdata = {'lambda':[], 'pass':[]} for fil in kwargs['filterlist']: f = yanny(join(kwargs['filterpath'],fil)) if str(f) == '': raise IOError("Could not read {0}".format(join(kwargs['filterpath'],fil))) t = f.tables() filterdata['lambda'].append(array(f[t[0]]['lambda'])) filterdata['pass'].append(array(f[t[0]]['pass'])) return filterdata
def __init__(self, mode='boss', paramfile=None, parametersdir=None): self.mode = mode self.parametersdir = parametersdir self.param = yanny.yanny(paramfile) self.alignment = self._set_alignment(mode=mode) self.lighttrap = self._set_lighttrap(mode=mode) self.objects = self._set_objects(mode=mode) self.completion_text = self._set_completion_text(mode=mode) self.manga = self._set_manga(mode=mode) self.manga_alignment = self._set_manga_alignment(mode=mode) # Use different codes for movement for APOGEE south plates, # appropriate to drilling on a flat mandrel. if(self.mode == 'apogee_south'): self.coordcode = 'G56' else: self.coordcode = 'G54' # Comments in CNC code are labeled differently for MaNGA plates if(self.mode == 'manga'): self.name = 'SDSS/MaNGA' else: self.name = 'SDSS' self.acquisition_header = """(CAMERA MOUNTING HOLES) G90 G56 """ self.acquisition_offaxis_template = """G68 X0.0 Y0.0 R-90.0 G00 X{axy[0]:.6f} Y{axy[1]:.6f} M98 P9775 G69 """ self.acquisition_center = """M98 P9776 M01 """ self.header_text = """% O{plateId7K:d}({name} PLUG-PLATE {plateId:d}) (Drilling temperature {tempShopF:5.1f} degrees F) (INPUT FILE NAME: {plug_name}) (CNC PROGRAM NAME: {fanuc_name}) """ self.first_text = str(self.coordcode) + """ G60 X{cx:.6f} Y{cy:.6f} G43 H{drillSeq:02d} Z0.1 M08 """ self.hole_text = dict() self.hole_text['objects'] = """G83 G98 Z{cz:.6f} R{czr:.3f} L0 Q0.5 F9.0 G60 X{cx:.6f} Y{cy:.6f} ( {objId[0]} {objId[1]} {objId[2]} {objId[3]} {objId[4]} ) """ self.hole_text['lighttrap'] = self.hole_text['objects'] self.hole_text['manga'] = self.hole_text['objects'] self.hole_text['alignment'] = """G83 G98 Z{cz:.6f} R{czr:.3f} L0 Q0.02 F2.0 G60 X{cx:.6f} Y{cy:.6f} ( {objId[0]} {objId[1]} {objId[2]} {objId[3]} {objId[4]} ) """ self.hole_text['manga_alignment'] = """G83 G98 Z{cz:.6f} R{czr:.3f} L0 Q0.02 F1.5 G60 X{cx:.6f} Y{cy:.6f} ( {objId[0]} {objId[1]} {objId[2]} {objId[3]} {objId[4]} ) """ self.holediam_values = dict() self.holediam_values['OBJECT'] = np.float32(2.16662) self.holediam_values['COHERENT_SKY'] = np.float32(2.16662) self.holediam_values['GUIDE'] = np.float32(2.16662) self.holediam_values['LIGHT_TRAP'] = np.float32(3.175) self.holediam_values['ALIGNMENT'] = np.float32(1.1811) self.holediam_values['MANGA'] = np.float32(2.8448) self.holediam_values['MANGA_ALIGNMENT'] = np.float32(0.7874) self.holediam_values['MANGA_SINGLE'] = np.float32(3.2766) self.holediam_values['ACQUISITION_CENTER'] = np.float32(60.) self.holediam_values['ACQUISITION_OFFAXIS'] = np.float32(68.) self.drillSeq = dict() self.drillSeq['objects'] = 1 if(self.mode == 'apogee_south'): self.drillSeq['objects'] = 11 self.drillSeq['lighttrap'] = 2 self.drillSeq['alignment'] = 3 self.drillSeq['manga'] = 11 self.drillSeq['manga_alignment'] = 12
def epsilon_plugprob(xtarget=None, ytarget=None, gang=None, minavail=None, mininblock=0, maxinblock=24, fiberused=None, nmax=None, limitDegree=0.8148, toblock=None, blockfile=None, noycost=False, ylimits=None, reachfunc=None, stretch=0, observatory=None, blockcenx=None, blockceny=None, gangcheck=True): """Test AS4 epsilon plugging problem Parameters ---------- xtarget, ytarget : np.float32 ndarray with target locations in degrees Returns ------- fiberid ndarray with fiber IDs for each target toblock ndarray with block IDs for each target Notes ----- Calls write_plugprob.c in libdimage.so """ assert len(xtarget) == len(ytarget) if (toblock is None): toblock = np.zeros(len(xtarget), dtype=np.int32) if (nmax is None): nmax = len(xtarget) if (minavail is None): if (maxinblock < 8): minavail = maxinblock else: minavail = 8 if (blockfile is None): blockfile = os.path.join(os.getenv('PLATEDESIGN_DIR'), 'data', 'apogee', 'fiberBlocksAPOGEEepsilon.par') if (observatory is None): observatory = Observatory(name='APO') fiberblocks = yanny.yanny(blockfile) fiberlist = fiberblocks['TIFIBERBLOCK'] nblocks = fiberlist['blockid'].max() # Set block centers blockconstrain = True if (blockcenx is None or blockceny is None): blockcenx = np.zeros(nblocks, dtype=np.float64) blockceny = np.zeros(nblocks, dtype=np.float64) for block in (np.arange(nblocks) + 1): ib = np.nonzero(fiberlist['blockid'] == block)[0] blockcenx[block - 1] = np.mean(fiberlist['fibercenx'][ib]) blockceny[block - 1] = np.mean(fiberlist['fiberceny'][ib]) blockconstrain = False if (ylimits is None): ylimits = np.zeros((nblocks, 2), dtype=np.float64) ylimits[:, 0] = -10. ylimits[:, 1] = 10. xfiber = np.array(fiberlist['fibercenx'], dtype=np.float64) yfiber = np.array(fiberlist['fiberceny'], dtype=np.float64) fiberblockid = np.array(fiberlist['blockid'], dtype=np.int32) fgang = np.array(fiberlist['gang'], dtype=np.str_) xtarget_deg = xtarget / observatory.platescale ytarget_deg = ytarget / observatory.platescale used = np.zeros(len(xfiber), dtype=np.int32) if (fiberused is not None): used[fiberused - 1] = 1 fiberTargetsPossible = None fiberTargetsPossible = np.zeros((len(xtarget), len(xfiber)), dtype=np.int32) for j in np.arange(len(xfiber)): if (gangcheck): igang = np.nonzero(gang == fgang[j])[0] else: igang = np.arange(len(xtarget)) reachable = boss_reachcheck(xfiber[j] * observatory.platescale, yfiber[j] * observatory.platescale, xtarget[igang], ytarget[igang], stretch=stretch) fiberTargetsPossible[igang, j] = reachable probfile = tempfile.mkstemp()[1] write_plugprob(xtarget=xtarget_deg, ytarget=ytarget_deg, xfiber=xfiber, yfiber=yfiber, fiberblockid=fiberblockid, used=used, toblock=toblock, nMax=None, limitDegree=limitDegree, fiberTargetsPossible=fiberTargetsPossible, minAvailInBlock=0, minFibersInBlock=mininblock, maxFibersInBlock=maxinblock, blockcenx=blockcenx, blockceny=blockceny, blockconstrain=blockconstrain, probfile=probfile, noycost=noycost, blockylimits=ylimits) ansfile = tempfile.mkstemp()[1] pfp = open(probfile, mode="r") afp = open(ansfile, mode="w") cs2_path = os.path.join(os.getenv('PLATEDESIGN_DIR'), 'src', 'cs2', 'cs2') subprocess.call(cs2_path, stdin=pfp, stdout=afp) afp.close() pfp.close() (targetFiber, targetBlock) = read_plugprob(xtarget=xtarget_deg, ytarget=ytarget_deg, fiberblockid=fiberblockid, ansfile=ansfile) # os.remove(ansfile) # os.remove(probile) return (targetFiber, targetBlock, fiberTargetsPossible)
def fanuc(mode='boss', planfile=None): """Create plFanuc file for plates Parameters ---------- planfile : str name of plan file (e.g. 'plPlan-test.par') mode : str plate run type ('boss', 'manga', or 'apogee_south'; default 'boss') Notes ----- Creates plFanucUnadjusted files with CNC code for drilling SDSS plates. """ # Read in files plan = yanny.yanny(planfile) parametersdir = plan['parametersDir'] paramfile = os.path.join(parametersdir, plan['parameters']) param = yanny.yanny(paramfile) obs = yanny.yanny(plan['plObsFile']) # Set up templates for CNC code gcodes = Gcodes(mode=mode, paramfile=paramfile, parametersdir=parametersdir) # Loop through the plates plug_dir = plan['outFileDir'] plug_template = 'plPlugMapP-{plate}.par' fanuc_template = 'plFanucUnadjusted-{plate}.par' + post_str png_template = 'plFanucUnadjusted-{plate}.png' for plate in obs['PLOBS']: print("Making files for plate {plateid}".format(plateid=plate['plateId'])) plug_name = plug_template.format(plate=plate['plateId']) fanuc_name = fanuc_template.format(plate=plate['plateId']) png_name = png_template.format(plate=plate['plateId']) # Read in plug map file plugmap = yanny.yanny(os.path.join(plug_dir, plug_name)) # Make plDrillPos file _fanuc_drillpos(gcodes=gcodes, plugmap=plugmap, plate=plate, param=param) # Check overlapping holes ok = _fanuc_check(plateid=plate['plateId']) if(ok is False): print(" ... overlapping holes! not making holes for {plate}".format(plate=plate['plateId'])) break # Separate into types for sorting pmaps = _fanuc_separate(plugmap) # Some checks if((len(pmaps['acquisition_center']) > 0) & (mode != 'apogee_south')): print("Not an apogee_south mode plate, but central acquisition specified") sys.exit(1) if((len(pmaps['acquisition_offaxis']) > 0) & (mode != 'apogee_south')): print("Not an apogee_south mode plate, but offaxis acquisition specified") sys.exit(1) if(len(pmaps['acquisition_offaxis']) > 1): print("More than one offaxis camera specified") sys.exit(1) if(len(pmaps['acquisition_center']) > 1): print("More than one center camera specified") sys.exit(1) if((len(pmaps['acquisition_center']) == 0) & (mode == 'apogee_south')): print("No center camera specified") sys.exit(1) # Open Fanuc file and write header ffp = open(fanuc_name, 'w') hdr = _fanuc_header(gcodes=gcodes, plate=plate, param=param, fanuc_name=fanuc_name, plug_name=plug_name) ffp.write(hdr) # Open drilling path PNG plt.figure(dpi=150, figsize=(5, 5)) plt.title("plate {plateId}".format(plateId=plate['plateId'])) plt.xlim((-405., 485.)) plt.ylim((-405., 485.)) plt.xlabel("X drill (mm)") plt.ylabel("Y drill (mm)") # Plot circle at limit rlimit = np.float32(param['maxRadius']) theta = np.arange(1000) / 999. * np.pi * 2. xlimit = rlimit * np.cos(theta) ylimit = rlimit * np.sin(theta) plt.plot(xlimit, ylimit, color='black') # Loop through plug map hole types linecolor = dict() linecolor['objects'] = 'red' linecolor['lighttrap'] = 'blue' linecolor['alignment'] = 'green' linecolor['manga'] = 'cyan' linecolor['manga_alignment'] = 'magenta' for holetype in pmaps.keys(): pmap = pmaps[holetype] if((len(pmap) > 0) & (holetype != 'acquisition_center') & (holetype != 'acquisition_offaxis')): ffp.write(getattr(gcodes, holetype)) iorder = optimize_path(pmap['xFocal'], pmap['yFocal']) (x, y, z, zr, zo) = _fanuc_xyz(plugmap=pmap[iorder], plate=plate, param=param) length = _fanuc_length(x, y) codes, xpath, ypath = _fanuc_codes(gcodes=gcodes, x=x, y=y, z=z, zr=zr, objId=pmap['objId'][iorder], holetype=holetype, rlimit=rlimit) ffp.write(codes) label = "{holetype} holes ({length:.1f} m)" label = label.format(holetype=holetype, length=length / 1000.) _plot_path(x, y, xpath, ypath, color=linecolor[holetype], label=label) # Write completion (ax, ay, az, azr, azo) = _fanuc_xyz(plugmap=pmaps['acquisition_offaxis'], plate=plate, param=param) if(len(ax) > 0): ax = ax[0] ay = ay[0] else: ax = None ay = None completion = gcodes.completion(plateId=plate['plateId'], axy=(ax, ay)) ffp.write(completion) ffp.write("%\n") ffp.close() plt.legend(fontsize=6) plt.savefig(png_name) plt.close()
def _fanuc_check(plateid=None): """Read in plDrillPos file and make sure holes do not overlap Parameters ---------- plateid : np.int32, int plate ID Returns ------- ok : boolean True if OK, False if not Notes ----- Assumes 5 arcmin is biggest thing it needs to check For the off-axis acquisition camera at LCO, it assumes a 55 x 40 mm footprint. """ offaxis_xsize = 55. offaxis_ysize = 40. drillpos_template = 'plDrillPos-{plate}.par' + post_str drillpos_name = drillpos_template.format(plate=plateid) dpos = yanny.yanny(drillpos_name) (m1, m2, d12) = spheregroup.spherematch(dpos['DRILLPOS']['ra'], dpos['DRILLPOS']['dec'], dpos['DRILLPOS']['ra'], dpos['DRILLPOS']['dec'], 5. / 60., maxmatch=0) for indx1, indx2 in zip(m1, m2): if(indx1 != indx2): dx = (dpos['DRILLPOS']['xDrill'][indx1] - dpos['DRILLPOS']['xDrill'][indx2]) dy = (dpos['DRILLPOS']['yDrill'][indx1] - dpos['DRILLPOS']['yDrill'][indx2]) d12 = np.sqrt(dx**2 + dy**2) limit = 0.5 * (dpos['DRILLPOS']['holeDiam'][indx1] + dpos['DRILLPOS']['holeDiam'][indx2]) if(d12 < limit): conflict = True holeType1 = dpos['DRILLPOS']['holeType'][indx1].decode() holeType2 = dpos['DRILLPOS']['holeType'][indx2].decode() # Special case for acquisition camera if(holeType1 == "ACQUISITION_OFFAXIS" or holeType2 == "ACQUISITION_OFFAXIS"): conflict = False x1 = dpos['DRILLPOS']['xDrill'][indx1] x2 = dpos['DRILLPOS']['xDrill'][indx2] y1 = dpos['DRILLPOS']['yDrill'][indx1] y2 = dpos['DRILLPOS']['yDrill'][indx2] if(holeType1 == "ACQUISITION_OFFAXIS"): holeDiam = dpos['DRILLPOS']['holeDiam'][indx2] else: holeDiam = dpos['DRILLPOS']['holeDiam'][indx1] if(np.abs(x1 - x2) < 0.5 * (offaxis_xsize + holeDiam) and np.abs(y1 - y2) < 0.5 * (offaxis_ysize + holeDiam)): conflict = True if(conflict is True): return(False) return(True)
def pca_star(**kwargs): """Wrapper on pca_solve to handle stellar eigenspectra. """ import os import os.path import pickle import pylab from astropy.io import fits as pyfits import numpy as np import pydl.pydlutils.yanny as yanny from matplotlib.font_manager import fontManager, FontProperties from ... import uniq from ...pydlutils.goddard.astro import get_juldate from ...pydlutils.image import djs_maskinterp from . import pca_solve, readspec, skymask if 'inputfile' in kwargs: inputfile = kwargs['inputfile'] else: inputfile = os.path.join(os.getenv('IDLSPEC2D_DIR'), 'templates','eigeninput_star.par') wavemin = 0 wavemax = 0 snmax = 100.0 if 'niter' in kwargs: niter = kwargs['niter'] else: niter = 10 cspeed = 2.99792458e5 # # Name the output files. # jd = get_juldate() outfile = "spEigenStar-{0:d}".format(int(jd - 2400000.5)) # # Read the input spectra # par = yanny.yanny(inputfile,np=True) slist = par['EIGENOBJ'] spplate = readspec(slist['plate'],slist['fiberid'],mjd=slist['mjd'],align=True,**kwargs) objdloglam = spplate['loglam'][0,1] - spplate['loglam'][0,0] # # Insist that all of the requested spectra exist. # missing = spplate['plugmap']['FIBERID'] == 0 if missing.any(): imissing = missing.nonzero()[0] for k in imissing: print("Missing plate={0:d} mjd={1:d} fiber={2:d}".format(plate[k],mjd[k],fiber[k])) raise ValueError("{0:d} missing object(s).".format(missing.sum())) # # Do not fit where the spectrum may be dominated by sky-sub residuals. # objinvvar = skymask(spplate['invvar'],spplate['andmask'],spplate['ormask']) ifix = spplate['flux']**2 * objinvvar > snmax**2 if ifix.any(): objinvvar[ifix.nonzero()] = (snmax/spplate['flux'][ifix.nonzero()])**2 # # Find the list of unique star types # isort = np.argsort(slist['class']) classlist = slist['class'][isort[uniq(slist['class'][isort])]] # # Loop over each star type # fullflux = None namearr = list() colorvec = ['k','r','g','b','m','c'] smallfont = FontProperties(size='xx-small'); for c in classlist: # # Find the subclasses for this stellar type # print("Finding eigenspectra for Stellar class {0}".format(c)) indx = (slist['class'] == c).nonzero()[0] nindx = indx.size thesesubclass = slist['subclass'][indx] isort = np.argsort(thesesubclass) subclasslist = thesesubclass[isort[uniq(thesesubclass[isort])]] nsubclass = subclasslist.size # # Solve for 2 eigencomponents if we have specified subclasses for # this stellar type # if nsubclass == 1: nkeep = 1 else: nkeep = 2 newloglam = spplate['loglam'][0,:] pcaflux = pca_solve(spplate['flux'][indx,:],objinvvar[indx,:], spplate['loglam'][indx,:], slist['cz'][indx]/cspeed, wavemin=wavemin, wavemax=wavemax, niter=niter, nkeep=nkeep, newloglam=newloglam) # # Interpolate over bad flux values in the middle of a spectrum, # and set fluxes to zero at the blue+red ends of the spectrum # # minuse = 1 # ? minuse = np.floor((nindx+1) / 3.0) qbad = pcaflux['usemask'] < minuse # # Interpolate over all bad pixels # for j in range(nkeep): pcaflux['flux'][j,:] = djs_maskinterp(pcaflux['flux'][j,:],qbad,const=True) # # Set bad pixels at the very start or end of the spectrum to zero instead # npix = qbad.size igood = (~qbad).nonzero()[0] if qbad[0]: pcaflux['flux'][:,0:igood[0]-1] = 0 if qbad[npix-1]: pcaflux['flux'][:,igood[::-1][0]+1:npix] = 0 # # Re-normalize the first eigenspectrum to a mean of 1 # # print(pcaflux['flux'].dtype) norm = pcaflux['flux'][0,:].mean() pcaflux['flux'] /= norm pcaflux['acoeff'] *= norm # print(pcaflux['flux'].dtype) # # Now loop through each stellar subclass and reconstruct # an eigenspectrum for that subclass # thesesubclassnum = np.zeros(thesesubclass.size,dtype='i4') # # Create a figure for this class # fig = pylab.figure(dpi=100) ax = fig.add_subplot(111) for isub in range(nsubclass): ii = (thesesubclass == subclasslist[isub]).nonzero()[0] thesesubclassnum[ii] = isub if nkeep == 1: thisflux = pcaflux['flux'].reshape(pcaflux['newloglam'].shape) # print(thisflux.dtype) else: aratio = pcaflux['acoeff'][ii,1]/pcaflux['acoeff'][ii,0] # # np.median(foo) is equivalent to MEDIAN(foo,/EVEN) # thisratio = np.median(aratio) thisflux = pcaflux['flux'][0,:] + thisratio.astype('f') * pcaflux['flux'][1,:] # print(thisflux.dtype) if fullflux is None: fullflux = thisflux else: fullflux = np.vstack((fullflux,thisflux)) namearr.append(subclasslist[isub]) # # Plot spectra # plotflux = thisflux/thisflux.max() # print(pcaflux['newloglam'].shape) # print(plotflux.shape) ax.plot(10.0**pcaflux['newloglam'],plotflux,"{0}-".format(colorvec[isub%len(colorvec)]),linewidth=1) if isub == 0: ax.set_xlabel(r'Wavelength [$\AA$]') ax.set_ylabel('Flux [arbitrary units]') ax.set_title('STAR {0}: Eigenspectra Reconstructions'.format(c)) t = ax.text(10.0**pcaflux['newloglam'][-1],plotflux[-1],subclasslist[isub], horizontalalignment='right',verticalalignment='center', color=colorvec[isub%len(colorvec)],fontproperties=smallfont) fig.savefig(outfile+'.{0}.png'.format(c)) pylab.close(fig) # # Plot eigenvalue ratios if nkeep > 1 # if nkeep > 1: fig = pylab.figure(dpi=100) ax = fig.add_subplot(111) allratio = pcaflux['acoeff'][:,1]/pcaflux['acoeff'][:,0] isort = thesesubclassnum.argsort() p = ax.plot(thesesubclassnum[isort],allratio[isort],marker='None',linestyle='None') for k in range(len(indx)): t = ax.text(thesesubclassnum[isort[k]],allratio[isort[k]], "%04d-%04d"%(slist['plate'][indx[isort[k]]],slist['fiberid'][indx[isort[k]]]), horizontalalignment='center', verticalalignment='center', color=colorvec[k%len(colorvec)], fontproperties=smallfont) ax.set_xlabel('Subclass') ax.set_xticks(np.arange(nsubclass)) ax.set_xticklabels(subclasslist) ax.set_ylabel('Eigenvalue Ratio, $a_1/a_0$') ax.set_title('STAR {0}: Eigenvalue Ratios'.format(c)) fig.savefig(outfile+'.{0}.ratio.png'.format(c)) pylab.close(fig) # # Save output to FITS file. # if os.path.exists(outfile+'.fits'): os.remove(outfile+'.fits') hdu0 = pyfits.PrimaryHDU(fullflux) hdu1 = pyfits.new_table(pyfits.ColDefs([ pyfits.Column(name='plate',format='J',array=slist['plate']), pyfits.Column(name='mjd',format='J',array=slist['mjd']), pyfits.Column(name='fiber',format='J',array=slist['fiberid']), pyfits.Column(name='redshift',format='D',unit='km/s',array=slist['cz'])])) hdulist = pyfits.HDUList([hdu0,hdu1]) hdulist[0].header.update('OBJECT','STAR') hdulist[0].header.update('COEFF0',pcaflux['newloglam'][0]) hdulist[0].header.update('COEFF1',objdloglam) hdulist[0].header.update('IDLUTILS','pydlutils','Version of idlutils') hdulist[0].header.update('SPEC2D','eigenspectra','Version of idlspec2d') hdulist[0].header.update('RUN2D',os.getenv('RUN2D'),'Version of 2d reduction') hdulist[0].header.update('RUN1D',os.getenv('RUN1D'),'Version of 1d reduction') for i in range(len(namearr)): hdulist[0].header.update("NAME%d" % i,namearr[i]+' ') hdulist[1].header.update('FILENAME',inputfile) hdulist.writeto(outfile+'.fits') # plot_eig(outfile+'.fits') return
def overlay_print(plateid, numbers=False, noguides=False, renumber=False, rotate180=False): ''' This function returns a plate overlay as a pyx.document object. The calling script can determine what to do with it. To print this object as a PDF: overlay = overlay_print(plateid=12345) overlay.writePDFfile(destination_path) ''' # Get the needed files plateHolesSorted_file = sdssPath.full('plateHolesSorted', plateid=plateid) if not os.path.isfile(plateHolesSorted_file): raise IOError("File not found: {0}".format(plateHolesSorted_file)) platePlans_file = sdssPath.full('platePlans') if not os.path.isfile(platePlans_file): raise IOError("File not found: {0}".format(platePlans_file)) # Read in holes data, extract meta data holes_yanny = yanny.yanny(plateHolesSorted_file) racen = holes_yanny['raCen'] deccen = holes_yanny['decCen'] designid = holes_yanny['designid'] ha = holes_yanny['ha'] holes = holes_yanny['STRUCT1'] if (rotate180): holes['xfocal'] = -np.array(holes['xfocal']) holes['yfocal'] = -np.array(holes['yfocal']) # Read in plans plans = yanny.yanny(platePlans_file) iplan = np.nonzero(np.array(plans['PLATEPLANS']['plateid']) == plateid)[0] survey = plans['PLATEPLANS']['survey'][iplan[0]].decode() programname = plans['PLATEPLANS']['programname'][iplan[0]].decode() # Texify the string programname_str = str(programname) programname_str = re.sub("_", "\_", programname_str) # Create information string information = r"\font\myfont=cmr10 at 40pt {\myfont" information += " Plate=" + str(plateid) + "; " information += "Design=" + str(designid) + "; " information += "Survey=" + str(survey) + "; " information += "Program=" + str(programname_str) + "; " information += "RA=" + str(racen) + "; " information += "Dec=" + str(deccen) + "; " information += "HA=" + str(np.float32((ha.split())[0])) + "." information += "}" # Create message message = "Una placa para APOGEE Sur" message_tex = r"\font\myfont=cmr10 at 40pt {\myfont " + message + "}" apogee = apogee_layer(holes, numbers=numbers, renumber=renumber) if (noguides is False): guide = guide_layer(holes) else: guide = None whiteout = whiteout_layer(holes) plate_circle = plate_circle_layer(plateid, information, message_tex) outline = outline_layer() # pyx.canvas object acquisition = acquisition_layer(holes) outline.insert(apogee) if (guide is not None): outline.insert(guide) outline.insert(plate_circle) if (acquisition is not None): outline.insert(acquisition) outline.insert(whiteout) pformat = document.paperformat(limit_radius * 2., limit_radius * 2.) final = document.page(outline, paperformat=pformat) return document.document(pages=[final])
def pca_star(**kwargs): """Wrapper on pca_solve to handle stellar eigenspectra. """ import os import os.path import pickle import pylab from astropy.io import fits as pyfits import numpy as np import pydl.pydlutils.yanny as yanny from matplotlib.font_manager import fontManager, FontProperties from ... import uniq from ...pydlutils.goddard.astro import get_juldate from ...pydlutils.image import djs_maskinterp from . import pca_solve, readspec, skymask if 'inputfile' in kwargs: inputfile = kwargs['inputfile'] else: inputfile = os.path.join(os.getenv('IDLSPEC2D_DIR'), 'templates', 'eigeninput_star.par') wavemin = 0 wavemax = 0 snmax = 100.0 if 'niter' in kwargs: niter = kwargs['niter'] else: niter = 10 cspeed = 2.99792458e5 # # Name the output files. # jd = get_juldate() outfile = "spEigenStar-{0:d}".format(int(jd - 2400000.5)) # # Read the input spectra # par = yanny.yanny(inputfile, np=True) slist = par['EIGENOBJ'] spplate = readspec(slist['plate'], slist['fiberid'], mjd=slist['mjd'], align=True, **kwargs) objdloglam = spplate['loglam'][0, 1] - spplate['loglam'][0, 0] # # Insist that all of the requested spectra exist. # missing = spplate['plugmap']['FIBERID'] == 0 if missing.any(): imissing = missing.nonzero()[0] for k in imissing: print("Missing plate={0:d} mjd={1:d} fiber={2:d}".format( plate[k], mjd[k], fiber[k])) raise ValueError("{0:d} missing object(s).".format(missing.sum())) # # Do not fit where the spectrum may be dominated by sky-sub residuals. # objinvvar = skymask(spplate['invvar'], spplate['andmask'], spplate['ormask']) ifix = spplate['flux']**2 * objinvvar > snmax**2 if ifix.any(): objinvvar[ifix.nonzero()] = (snmax / spplate['flux'][ifix.nonzero()])**2 # # Find the list of unique star types # isort = np.argsort(slist['class']) classlist = slist['class'][isort[uniq(slist['class'][isort])]] # # Loop over each star type # fullflux = None namearr = list() colorvec = ['k', 'r', 'g', 'b', 'm', 'c'] smallfont = FontProperties(size='xx-small') for c in classlist: # # Find the subclasses for this stellar type # print("Finding eigenspectra for Stellar class {0}".format(c)) indx = (slist['class'] == c).nonzero()[0] nindx = indx.size thesesubclass = slist['subclass'][indx] isort = np.argsort(thesesubclass) subclasslist = thesesubclass[isort[uniq(thesesubclass[isort])]] nsubclass = subclasslist.size # # Solve for 2 eigencomponents if we have specified subclasses for # this stellar type # if nsubclass == 1: nkeep = 1 else: nkeep = 2 newloglam = spplate['loglam'][0, :] pcaflux = pca_solve(spplate['flux'][indx, :], objinvvar[indx, :], spplate['loglam'][indx, :], slist['cz'][indx] / cspeed, wavemin=wavemin, wavemax=wavemax, niter=niter, nkeep=nkeep, newloglam=newloglam) # # Interpolate over bad flux values in the middle of a spectrum, # and set fluxes to zero at the blue+red ends of the spectrum # # minuse = 1 # ? minuse = np.floor((nindx + 1) / 3.0) qbad = pcaflux['usemask'] < minuse # # Interpolate over all bad pixels # for j in range(nkeep): pcaflux['flux'][j, :] = djs_maskinterp(pcaflux['flux'][j, :], qbad, const=True) # # Set bad pixels at the very start or end of the spectrum to zero # instead. # npix = qbad.size igood = (~qbad).nonzero()[0] if qbad[0]: pcaflux['flux'][:, 0:igood[0] - 1] = 0 if qbad[npix - 1]: pcaflux['flux'][:, igood[::-1][0] + 1:npix] = 0 # # Re-normalize the first eigenspectrum to a mean of 1 # # print(pcaflux['flux'].dtype) norm = pcaflux['flux'][0, :].mean() pcaflux['flux'] /= norm pcaflux['acoeff'] *= norm # print(pcaflux['flux'].dtype) # # Now loop through each stellar subclass and reconstruct # an eigenspectrum for that subclass # thesesubclassnum = np.zeros(thesesubclass.size, dtype='i4') # # Create a figure for this class # fig = pylab.figure(dpi=100) ax = fig.add_subplot(111) for isub in range(nsubclass): ii = (thesesubclass == subclasslist[isub]).nonzero()[0] thesesubclassnum[ii] = isub if nkeep == 1: thisflux = pcaflux['flux'].reshape(pcaflux['newloglam'].shape) # print(thisflux.dtype) else: aratio = pcaflux['acoeff'][ii, 1] / pcaflux['acoeff'][ii, 0] # # np.median(foo) is equivalent to MEDIAN(foo,/EVEN) # thisratio = np.median(aratio) thisflux = (pcaflux['flux'][0, :] + thisratio.astype('f') * pcaflux['flux'][1, :]) # print(thisflux.dtype) if fullflux is None: fullflux = thisflux else: fullflux = np.vstack((fullflux, thisflux)) namearr.append(subclasslist[isub]) # # Plot spectra # plotflux = thisflux / thisflux.max() # print(pcaflux['newloglam'].shape) # print(plotflux.shape) ax.plot(10.0**pcaflux['newloglam'], plotflux, "{0}-".format(colorvec[isub % len(colorvec)]), linewidth=1) if isub == 0: ax.set_xlabel(r'Wavelength [$\AA$]') ax.set_ylabel('Flux [arbitrary units]') ax.set_title( 'STAR {0}: Eigenspectra Reconstructions'.format(c)) t = ax.text(10.0**pcaflux['newloglam'][-1], plotflux[-1], subclasslist[isub], horizontalalignment='right', verticalalignment='center', color=colorvec[isub % len(colorvec)], fontproperties=smallfont) fig.savefig(outfile + '.{0}.png'.format(c)) pylab.close(fig) # # Plot eigenvalue ratios if nkeep > 1 # if nkeep > 1: fig = pylab.figure(dpi=100) ax = fig.add_subplot(111) allratio = pcaflux['acoeff'][:, 1] / pcaflux['acoeff'][:, 0] isort = thesesubclassnum.argsort() p = ax.plot(thesesubclassnum[isort], allratio[isort], marker='None', linestyle='None') for k in range(len(indx)): t = ax.text(thesesubclassnum[isort[k]], allratio[isort[k]], "%04d-%04d" % (slist['plate'][indx[isort[k]]], slist['fiberid'][indx[isort[k]]]), horizontalalignment='center', verticalalignment='center', color=colorvec[k % len(colorvec)], fontproperties=smallfont) ax.set_xlabel('Subclass') ax.set_xticks(np.arange(nsubclass)) ax.set_xticklabels(subclasslist) ax.set_ylabel('Eigenvalue Ratio, $a_1/a_0$') ax.set_title('STAR {0}: Eigenvalue Ratios'.format(c)) fig.savefig(outfile + '.{0}.ratio.png'.format(c)) pylab.close(fig) # # Save output to FITS file. # if os.path.exists(outfile + '.fits'): os.remove(outfile + '.fits') hdu0 = pyfits.PrimaryHDU(fullflux) hdu1 = pyfits.new_table( pyfits.ColDefs([ pyfits.Column(name='plate', format='J', array=slist['plate']), pyfits.Column(name='mjd', format='J', array=slist['mjd']), pyfits.Column(name='fiber', format='J', array=slist['fiberid']), pyfits.Column(name='redshift', format='D', unit='km/s', array=slist['cz']) ])) hdulist = pyfits.HDUList([hdu0, hdu1]) hdulist[0].header.update('OBJECT', 'STAR') hdulist[0].header.update('COEFF0', pcaflux['newloglam'][0]) hdulist[0].header.update('COEFF1', objdloglam) hdulist[0].header.update('IDLUTILS', 'pydlutils', 'Version of idlutils') hdulist[0].header.update('SPEC2D', 'eigenspectra', 'Version of idlspec2d') hdulist[0].header.update('RUN2D', os.getenv('RUN2D'), 'Version of 2d reduction') hdulist[0].header.update('RUN1D', os.getenv('RUN1D'), 'Version of 1d reduction') for i in range(len(namearr)): hdulist[0].header.update("NAME%d" % i, namearr[i] + ' ') hdulist[1].header.update('FILENAME', inputfile) hdulist.writeto(outfile + '.fits') # plot_eig(outfile+'.fits') return