def test_check_filters(self): filterlist = [ 'SDSS_U', 'SDSS_G', 'SDSS_R', 'SDSS_I', 'SDSS_Z', 'DECAM_U', 'DECAM_G', 'DECAM_R', 'DECAM_I', 'DECAM_Z', 'DECAM_Y', 'WISE_W1', 'WISE_W2' ] filters = ['XXXX', 'YYYY', 'ZZZZ'] stdwave = np.linspace(3000, 11000, 10000) stdflux = np.cos(stdwave) + 100. mags = np.array([20, 21, 22]) # No correct filters with self.assertRaises(SystemExit): normflux = normalize_templates(stdwave, stdflux, mags, filters) filters = filters + ['DECAM_R'] #This should use DECAM_R for calibration mags = np.concatenate([mags, np.array([23])]) normflux = normalize_templates(stdwave, stdflux, mags, filters) r = speclite.filters.load_filter('decam2014-r') rmag = r.get_ab_magnitude(1e-17 * normflux, stdwave) self.assertAlmostEqual(rmag, mags[-1]) #check dimensionality self.assertEqual(stdflux.shape, normflux.shape)
def test_check_filters(self): filterlist=['SDSS_U','SDSS_G','SDSS_R','SDSS_I','SDSS_Z','DECAM_U','DECAM_G','DECAM_R', 'DECAM_I','DECAM_Z','DECAM_Y','WISE_W1','WISE_W2'] filters=['XXXX','YYYY','ZZZZ'] stdwave=np.linspace(3000,11000,10000) stdflux=np.cos(stdwave)+100. mags=np.array([20,21,22]) # No correct filters with self.assertRaises(SystemExit): normflux=normalize_templates(stdwave,stdflux,mags,filters) filters=filters+['DECAM_R'] #This should use DECAM_R for calibration mags=np.concatenate([mags,np.array([23])]) normflux=normalize_templates(stdwave,stdflux,mags,filters) r = speclite.filters.load_filter('decam2014-r') rmag = r.get_ab_magnitude(1e-17*normflux, stdwave) self.assertAlmostEqual(rmag, mags[-1]) #check dimensionality self.assertEqual(stdflux.shape, normflux.shape)
def test_normalize_templates(self): """ Test for normalization to a given magnitude for calibration """ stdwave=np.linspace(3000,11000,10000) stdflux=np.cos(stdwave)+100. mag = 20.0 normflux=normalize_templates(stdwave,stdflux,mag,'DECAM_R') self.assertEqual(stdflux.shape, normflux.shape) r = speclite.filters.load_filter('decam2014-r') rmag = r.get_ab_magnitude(1e-17*normflux, stdwave) self.assertAlmostEqual(rmag, mag)
def test_normalize_templates(self): """ Test for normalization to a given magnitude for calibration """ stdwave = np.linspace(3000, 11000, 10000) stdflux = np.cos(stdwave) + 100. mag = 20.0 normflux = normalize_templates(stdwave, stdflux, mag, 'DECAM_R') self.assertEqual(stdflux.shape, normflux.shape) r = speclite.filters.load_filter('decam2014-r') rmag = r.get_ab_magnitude(1e-17 * normflux, stdwave) self.assertAlmostEqual(rmag, mag)
def test_normalize_templates(self): """ Test for normalization to a given magnitude for calibration """ stdwave=np.linspace(3000,11000,10000) stdflux=np.cos(stdwave)+100. mag = 20.0 normflux=normalize_templates(stdwave,stdflux,mag,'R','S') self.assertEqual(stdflux.shape, normflux.shape) r = load_legacy_survey_filter('R','S') rmag = r.get_ab_magnitude(1e-17*normflux, stdwave) self.assertAlmostEqual(rmag, mag)
def test_normalize_templates(self): """ Test for normalization to a given magnitude for calibration """ stdwave=np.linspace(3000,11000,10000) stdflux=np.cos(stdwave)+100. mags=np.array((20,21)) filters=['SDSS_I','SDSS_R'] #This should use SDSS_R for calibration normflux=normalize_templates(stdwave,stdflux,mags,filters) self.assertEqual(stdflux.shape, normflux.shape) r = speclite.filters.load_filter('sdss2010-r') rmag = r.get_ab_magnitude(1e-17*normflux, stdwave) self.assertAlmostEqual(rmag, mags[1])
def main() : """ finds the best models of all standard stars in the frame and normlize the model flux. Output is written to a file and will be called for calibration. """ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--fiberflatexpid', type = int, help = 'fiberflat exposure ID') parser.add_argument('--fibermap', type = str, help = 'path of fibermap file') parser.add_argument('--models', type = str, help = 'path of spectro-photometric stellar spectra fits') parser.add_argument('--spectrograph', type = int, default = 0, help = 'spectrograph number, can go 0-9') parser.add_argument('--outfile', type = str, help = 'output file for normalized stdstar model flux') args = parser.parse_args() log = get_logger() # Call necessary environment variables. No need if add argument to give full file path. if 'DESI_SPECTRO_REDUX' not in os.environ: raise RuntimeError('Set environment DESI_SPECTRO_REDUX. It is needed to read the needed datafiles') DESI_SPECTRO_REDUX=os.environ['DESI_SPECTRO_REDUX'] PRODNAME=os.environ['PRODNAME'] if 'DESISIM' not in os.environ: raise RuntimeError('Set environment DESISIM. It will be neede to read the filter transmission files for calibration') DESISIM=os.environ['DESISIM'] # to read the filter transmission files if args.fibermap is None or args.models is None or \ args.spectrograph is None or args.outfile is None or \ args.fiberflatexpid is None: log.critical('Missing a required argument') parser.print_help() sys.exit(12) # read Standard Stars from the fibermap file # returns the Fiber id, filter names and mags for the standard stars fiber_tbdata,fiber_header=io.read_fibermap(args.fibermap, header=True) #- Trim to just fibers on this spectrograph ii = (500*args.spectrograph <= fiber_tbdata["FIBER"]) ii &= (fiber_tbdata["FIBER"] < 500*(args.spectrograph+1)) fiber_tbdata = fiber_tbdata[ii] #- Get info for the standard stars refStarIdx=np.where(fiber_tbdata["OBJTYPE"]=="STD") refFibers=fiber_tbdata["FIBER"][refStarIdx] refFilters=fiber_tbdata["FILTER"][refStarIdx] refMags=fiber_tbdata["MAG"] fibers={"FIBER":refFibers,"FILTER":refFilters,"MAG":refMags} NIGHT=fiber_header['NIGHT'] EXPID=fiber_header['EXPID'] filters=fibers["FILTER"] if 'DESISIM' not in os.environ: raise RuntimeError('Set environment DESISIM. Can not find filter response files') basepath=DESISIM+"/data/" #now load all the skyfiles, framefiles, fiberflatfiles etc # all three channels files are simultaneously treated for model fitting skyfile={} framefile={} fiberflatfile={} for i in ["b","r","z"]: camera = i+str(args.spectrograph) skyfile[i] = io.findfile('sky', NIGHT, EXPID, camera) framefile[i] = io.findfile('frame', NIGHT, EXPID, camera) fiberflatfile[i] = io.findfile('fiberflat', NIGHT, args.fiberflatexpid, camera) #Read Frames, Flats and Sky files frameFlux={} frameIvar={} frameWave={} frameResolution={} framehdr={} fiberFlat={} ivarFlat={} maskFlat={} meanspecFlat={} waveFlat={} headerFlat={} sky={} skyivar={} skymask={} skywave={} skyhdr={} for i in ["b","r","z"]: #arg=(night,expid,'%s%s'%(i,spectrograph)) #- minimal code change for refactored I/O, while not taking advantage of simplified structure frame = io.read_frame(framefile[i]) frameFlux[i] = frame.flux frameIvar[i] = frame.ivar frameWave[i] = frame.wave frameResolution[i] = frame.resolution_data framehdr[i] = frame.header ff = io.read_fiberflat(fiberflatfile[i]) fiberFlat[i] = ff.fiberflat ivarFlat[i] = ff.ivar maskFlat[i] = ff.mask meanspecFlat[i] = ff.meanspec waveFlat[i] = ff.wave headerFlat[i] = ff.header skymodel = io.read_sky(skyfile[i]) sky[i] = skymodel.flux skyivar[i] = skymodel.ivar skymask[i] = skymodel.mask skywave[i] = skymodel.wave skyhdr[i] = skymodel.header # Convolve Sky with Detector Resolution, so as to subtract from data. Convolve for all 500 specs. Subtracting sky this way should be equivalent to sky_subtract convolvedsky={"b":sky["b"], "r":sky["r"], "z":sky["z"]} # Read the standard Star data and divide by flat and subtract sky stars=[] ivars=[] for i in fibers["FIBER"]: #flat and sky should have same wavelength binning as data, otherwise should be rebinned. stars.append((i,{"b":[frameFlux["b"][i]/fiberFlat["b"][i]-convolvedsky["b"][i],frameWave["b"]], "r":[frameFlux["r"][i]/fiberFlat["r"][i]-convolvedsky["r"][i],frameWave["r"]], "z":[frameFlux["z"][i]/fiberFlat["z"][i]-convolvedsky["z"][i],frameWave]},fibers["MAG"][i])) ivars.append((i,{"b":[frameIvar["b"][i]],"r":[frameIvar["r"][i,:]],"z":[frameIvar["z"][i,:]]})) stdwave,stdflux,templateid=io.read_stdstar_templates(args.models) #- Trim standard star wavelengths to just the range we need minwave = min([min(w) for w in frameWave.values()]) maxwave = max([max(w) for w in frameWave.values()]) ii = (minwave-10 < stdwave) & (stdwave < maxwave+10) stdwave = stdwave[ii] stdflux = stdflux[:, ii] log.info('Number of Standard Stars in this frame: {0:d}'.format(len(stars))) if len(stars) == 0: log.critical("No standard stars! Exiting") sys.exit(1) # Now for each star, find the best model and normalize. normflux=[] bestModelIndex=np.arange(len(stars)) templateID=np.arange(len(stars)) chi2dof=np.zeros(len(stars)) #- TODO: don't use 'l' as a variable name. Can look like a '1' for k,l in enumerate(stars): log.info("checking best model for star {0}".format(l[0])) starindex=l[0] mags=l[2] filters=fibers["FILTER"][k] rflux=stars[k][1]["r"][0] bflux=stars[k][1]["b"][0] zflux=stars[k][1]["z"][0] flux={"b":bflux,"r":rflux,"z":zflux} #print ivars rivar=ivars[k][1]["r"][0] bivar=ivars[k][1]["b"][0] zivar=ivars[k][1]["z"][0] ivar={"b":bivar,"r":rivar,"z":zivar} resol_star={"r":frameResolution["r"][l[0]],"b":frameResolution["b"][l[0]],"z":frameResolution["z"][l[0]]} # Now find the best Model bestModelIndex[k],bestmodelWave,bestModelFlux,chi2dof[k]=match_templates(frameWave,flux,ivar,resol_star,stdwave,stdflux) log.info('Star Fiber: {0}; Best Model Fiber: {1}; TemplateID: {2}; Chisq/dof: {3}'.format(l[0],bestModelIndex[k],templateid[bestModelIndex[k]],chi2dof[k])) # Normalize the best model using reported magnitude modelwave,normalizedflux=normalize_templates(stdwave,stdflux[bestModelIndex[k]],mags,filters,basepath) normflux.append(normalizedflux) # Now write the normalized flux for all best models to a file normflux=np.array(normflux) stdfibers=fibers["FIBER"] data={} data['BESTMODEL']=bestModelIndex data['CHI2DOF']=chi2dof data['TEMPLATEID']=templateid[bestModelIndex] norm_model_file=args.outfile io.write_stdstar_model(norm_model_file,normflux,stdwave,stdfibers,data)
def main(args): """ finds the best models of all standard stars in the frame and normlize the model flux. Output is written to a file and will be called for calibration. """ log = get_logger() log.info("mag delta %s = %f (for the pre-selection of stellar models)" % (args.color, args.delta_color)) frames = {} flats = {} skies = {} spectrograph = None starfibers = None starindices = None fibermap = None # READ DATA ############################################ for filename in args.frames: log.info("reading %s" % filename) frame = io.read_frame(filename) header = fits.getheader(filename, 0) frame_fibermap = frame.fibermap frame_starindices = np.where(frame_fibermap["OBJTYPE"] == "STD")[0] camera = safe_read_key(header, "CAMERA").strip().lower() if spectrograph is None: spectrograph = frame.spectrograph fibermap = frame_fibermap starindices = frame_starindices starfibers = fibermap["FIBER"][starindices] elif spectrograph != frame.spectrograph: log.error("incompatible spectrographs %d != %d" % (spectrograph, frame.spectrograph)) raise ValueError("incompatible spectrographs %d != %d" % (spectrograph, frame.spectrograph)) elif starindices.size != frame_starindices.size or np.sum( starindices != frame_starindices) > 0: log.error("incompatible fibermap") raise ValueError("incompatible fibermap") if frames.has_key(camera): log.error( "cannot handle for now several frame of same camera (%s)" % camera) raise ValueError( "cannot handle for now several frame of same camera (%s)" % camera) frames[camera] = frame for filename in args.skymodels: log.info("reading %s" % filename) sky = io.read_sky(filename) header = fits.getheader(filename, 0) camera = safe_read_key(header, "CAMERA").strip().lower() # NEED TO ADD MORE CHECKS if skies.has_key(camera): log.error("cannot handle several skymodels of same camera (%s)" % camera) raise ValueError( "cannot handle several skymodels of same camera (%s)" % camera) skies[camera] = sky for filename in args.fiberflats: log.info("reading %s" % filename) header = fits.getheader(filename, 0) flat = io.read_fiberflat(filename) camera = safe_read_key(header, "CAMERA").strip().lower() # NEED TO ADD MORE CHECKS if flats.has_key(camera): log.error("cannot handle several flats of same camera (%s)" % camera) raise ValueError( "cannot handle several flats of same camera (%s)" % camera) flats[camera] = flat if starindices.size == 0: log.error("no STD star found in fibermap") raise ValueError("no STD star found in fibermap") log.info("found %d STD stars" % starindices.size) imaging_filters = fibermap["FILTER"][starindices] imaging_mags = fibermap["MAG"][starindices] log.warning( "NO MAG ERRORS IN FIBERMAP, I AM IGNORING MEASUREMENT ERRORS !!") log.warning( "NO EXTINCTION VALUES IN FIBERMAP, I AM IGNORING THIS FOR NOW !!") # DIVIDE FLAT AND SUBTRACT SKY , TRIM DATA ############################################ for cam in frames: if not skies.has_key(cam): log.warning("Missing sky for %s" % cam) frames.pop(cam) continue if not flats.has_key(cam): log.warning("Missing flat for %s" % cam) frames.pop(cam) continue frames[cam].flux = frames[cam].flux[starindices] frames[cam].ivar = frames[cam].ivar[starindices] frames[cam].ivar *= (frames[cam].mask[starindices] == 0) frames[cam].ivar *= (skies[cam].ivar[starindices] != 0) frames[cam].ivar *= (skies[cam].mask[starindices] == 0) frames[cam].ivar *= (flats[cam].ivar[starindices] != 0) frames[cam].ivar *= (flats[cam].mask[starindices] == 0) frames[cam].flux *= (frames[cam].ivar > 0) # just for clean plots for star in range(frames[cam].flux.shape[0]): ok = np.where((frames[cam].ivar[star] > 0) & (flats[cam].fiberflat[star] != 0))[0] if ok.size > 0: frames[cam].flux[star] = frames[cam].flux[star] / flats[ cam].fiberflat[star] - skies[cam].flux[star] nstars = starindices.size starindices = None # we don't need this anymore # READ MODELS ############################################ log.info("reading star models in %s" % args.starmodels) stdwave, stdflux, templateid, teff, logg, feh = io.read_stdstar_templates( args.starmodels) # COMPUTE MAGS OF MODELS FOR EACH STD STAR MAG ############################################ model_filters = [] for tmp in np.unique(imaging_filters): if len(tmp) > 0: # can be one empty entry model_filters.append(tmp) log.info("computing model mags %s" % model_filters) model_mags = np.zeros((stdflux.shape[0], len(model_filters))) fluxunits = 1e-17 * units.erg / units.s / units.cm**2 / units.Angstrom for index in range(len(model_filters)): filter_response = load_filter(model_filters[index]) for m in range(stdflux.shape[0]): model_mags[m, index] = filter_response.get_ab_magnitude( stdflux[m] * fluxunits, stdwave) log.info("done computing model mags") # LOOP ON STARS TO FIND BEST MODEL ############################################ bestModelIndex = np.arange(nstars) templateID = np.arange(nstars) chi2dof = np.zeros((nstars)) redshift = np.zeros((nstars)) normflux = [] for star in range(nstars): log.info("finding best model for observed star #%d" % star) # np.array of wave,flux,ivar,resol wave = {} flux = {} ivar = {} resolution_data = {} for camera in frames: band = camera[0] wave[band] = frames[camera].wave flux[band] = frames[camera].flux[star] ivar[band] = frames[camera].ivar[star] resolution_data[band] = frames[camera].resolution_data[star] # preselec models based on magnitudes # compute star color index1, index2 = get_color_filter_indices(imaging_filters[star], args.color) if index1 < 0 or index2 < 0: log.error("cannot compute '%s' color from %s" % (color_name, filters)) filter1 = imaging_filters[star][index1] filter2 = imaging_filters[star][index2] star_color = imaging_mags[star][index1] - imaging_mags[star][index2] # compute models color model_index1 = -1 model_index2 = -1 for i, fname in enumerate(model_filters): if fname == filter1: model_index1 = i elif fname == filter2: model_index2 = i if model_index1 < 0 or model_index2 < 0: log.error("cannot compute '%s' model color from %s" % (color_name, filters)) model_colors = model_mags[:, model_index1] - model_mags[:, model_index2] # selection selection = np.where( np.abs(model_colors - star_color) < args.delta_color)[0] log.info( "star#%d fiber #%d, %s = %s-%s = %f, number of pre-selected models = %d/%d" % (star, starfibers[star], args.color, filter1, filter2, star_color, selection.size, stdflux.shape[0])) index_in_selection, redshift[star], chi2dof[star] = match_templates( wave, flux, ivar, resolution_data, stdwave, stdflux[selection], teff[selection], logg[selection], feh[selection], ncpu=args.ncpu, z_max=args.z_max, z_res=args.z_res) bestModelIndex[star] = selection[index_in_selection] log.info( 'Star Fiber: {0}; TemplateID: {1}; Redshift: {2}; Chisq/dof: {3}'. format(starfibers[star], bestModelIndex[star], redshift[star], chi2dof[star])) # Apply redshift to original spectrum at full resolution tmp = np.interp(stdwave, stdwave / (1 + redshift[star]), stdflux[bestModelIndex[star]]) # Normalize the best model using reported magnitude normalizedflux = normalize_templates(stdwave, tmp, imaging_mags[star], imaging_filters[star]) normflux.append(normalizedflux) # Now write the normalized flux for all best models to a file normflux = np.array(normflux) data = {} data['BESTMODEL'] = bestModelIndex data['TEMPLATEID'] = bestModelIndex # IS THAT IT? data['CHI2DOF'] = chi2dof data['REDSHIFT'] = redshift norm_model_file = args.outfile io.write_stdstar_models(args.outfile, normflux, stdwave, starfibers, data)
def main(args): """ finds the best models of all standard stars in the frame and normlize the model flux. Output is written to a file and will be called for calibration. """ log = get_logger() log.info("mag delta %s = %f (for the pre-selection of stellar models)" % (args.color, args.delta_color)) frames = {} flats = {} skies = {} spectrograph = None starfibers = None starindices = None fibermap = None # READ DATA ############################################ for filename in args.frames: log.info("reading %s" % filename) frame = io.read_frame(filename) header = fits.getheader(filename, 0) frame_fibermap = frame.fibermap frame_starindices = np.where(frame_fibermap["OBJTYPE"] == "STD")[0] # check magnitude are well defined or discard stars tmp = [] for i in frame_starindices: mags = frame_fibermap["MAG"][i] ok = np.sum((mags > 0) & (mags < 30)) if np.sum((mags > 0) & (mags < 30)) == mags.size: tmp.append(i) frame_starindices = np.array(tmp).astype(int) camera = safe_read_key(header, "CAMERA").strip().lower() if spectrograph is None: spectrograph = frame.spectrograph fibermap = frame_fibermap starindices = frame_starindices starfibers = fibermap["FIBER"][starindices] elif spectrograph != frame.spectrograph: log.error("incompatible spectrographs %d != %d" % (spectrograph, frame.spectrograph)) raise ValueError("incompatible spectrographs %d != %d" % (spectrograph, frame.spectrograph)) elif starindices.size != frame_starindices.size or np.sum( starindices != frame_starindices) > 0: log.error("incompatible fibermap") raise ValueError("incompatible fibermap") if not camera in frames: frames[camera] = [] frames[camera].append(frame) for filename in args.skymodels: log.info("reading %s" % filename) sky = io.read_sky(filename) header = fits.getheader(filename, 0) camera = safe_read_key(header, "CAMERA").strip().lower() if not camera in skies: skies[camera] = [] skies[camera].append(sky) for filename in args.fiberflats: log.info("reading %s" % filename) header = fits.getheader(filename, 0) flat = io.read_fiberflat(filename) camera = safe_read_key(header, "CAMERA").strip().lower() # NEED TO ADD MORE CHECKS if camera in flats: log.warning( "cannot handle several flats of same camera (%s), will use only the first one" % camera) #raise ValueError("cannot handle several flats of same camera (%s)"%camera) else: flats[camera] = flat if starindices.size == 0: log.error("no STD star found in fibermap") raise ValueError("no STD star found in fibermap") log.info("found %d STD stars" % starindices.size) imaging_filters = fibermap["FILTER"][starindices] imaging_mags = fibermap["MAG"][starindices] log.warning( "NO MAG ERRORS IN FIBERMAP, I AM IGNORING MEASUREMENT ERRORS !!") ebv = np.zeros(starindices.size) if "SFD_EBV" in fibermap.columns.names: log.info("Using 'SFD_EBV' from fibermap") ebv = fibermap["SFD_EBV"][starindices] else: log.warning("NO EXTINCTION VALUES IN FIBERMAP!!") # DIVIDE FLAT AND SUBTRACT SKY , TRIM DATA ############################################ for cam in frames: if not cam in skies: log.warning("Missing sky for %s" % cam) frames.pop(cam) continue if not cam in flats: log.warning("Missing flat for %s" % cam) frames.pop(cam) continue flat = flats[cam] for frame, sky in zip(frames[cam], skies[cam]): frame.flux = frame.flux[starindices] frame.ivar = frame.ivar[starindices] frame.ivar *= (frame.mask[starindices] == 0) frame.ivar *= (sky.ivar[starindices] != 0) frame.ivar *= (sky.mask[starindices] == 0) frame.ivar *= (flat.ivar[starindices] != 0) frame.ivar *= (flat.mask[starindices] == 0) frame.flux *= (frame.ivar > 0) # just for clean plots for star in range(frame.flux.shape[0]): ok = np.where((frame.ivar[star] > 0) & (flat.fiberflat[star] != 0))[0] if ok.size > 0: frame.flux[star] = frame.flux[star] / flat.fiberflat[ star] - sky.flux[star] frame.resolution_data = frame.resolution_data[starindices] nstars = starindices.size starindices = None # we don't need this anymore # READ MODELS ############################################ log.info("reading star models in %s" % args.starmodels) stdwave, stdflux, templateid, teff, logg, feh = io.read_stdstar_templates( args.starmodels) # COMPUTE MAGS OF MODELS FOR EACH STD STAR MAG ############################################ model_filters = [] for tmp in np.unique(imaging_filters): if len(tmp) > 0: # can be one empty entry model_filters.append(tmp) log.info("computing model mags %s" % model_filters) model_mags = np.zeros((stdflux.shape[0], len(model_filters))) fluxunits = 1e-17 * units.erg / units.s / units.cm**2 / units.Angstrom for index in range(len(model_filters)): if model_filters[index].startswith('WISE'): log.warning('not computing stdstar {} mags'.format( model_filters[index])) continue filter_response = load_filter(model_filters[index]) for m in range(stdflux.shape[0]): model_mags[m, index] = filter_response.get_ab_magnitude( stdflux[m] * fluxunits, stdwave) log.info("done computing model mags") mean_extinction_delta_mags = None mean_ebv = np.mean(ebv) if mean_ebv > 0: log.info( "Compute a mean delta_color from average E(B-V) = %3.2f based on canonial model star" % mean_ebv) # compute a mean delta_color from mean_ebv based on canonial model star ####################################################################### # will then use this color offset in the model pre-selection # find canonical f-type model: Teff=6000, logg=4, Fe/H=-1.5 canonical_model = np.argmin((teff - 6000.0)**2 + (logg - 4.0)**2 + (feh + 1.5)**2) canonical_model_mags_without_extinction = model_mags[canonical_model] canonical_model_mags_with_extinction = np.zeros( canonical_model_mags_without_extinction.shape) canonical_model_reddened_flux = stdflux[ canonical_model] * dust_transmission(stdwave, mean_ebv) for index in range(len(model_filters)): if model_filters[index].startswith('WISE'): log.warning('not computing stdstar {} mags'.format( model_filters[index])) continue filter_response = load_filter(model_filters[index]) canonical_model_mags_with_extinction[ index] = filter_response.get_ab_magnitude( canonical_model_reddened_flux * fluxunits, stdwave) mean_extinction_delta_mags = canonical_model_mags_with_extinction - canonical_model_mags_without_extinction # LOOP ON STARS TO FIND BEST MODEL ############################################ linear_coefficients = np.zeros((nstars, stdflux.shape[0])) chi2dof = np.zeros((nstars)) redshift = np.zeros((nstars)) normflux = [] star_colors_array = np.zeros((nstars)) model_colors_array = np.zeros((nstars)) for star in range(nstars): log.info("finding best model for observed star #%d" % star) # np.array of wave,flux,ivar,resol wave = {} flux = {} ivar = {} resolution_data = {} for camera in frames: for i, frame in enumerate(frames[camera]): identifier = "%s-%d" % (camera, i) wave[identifier] = frame.wave flux[identifier] = frame.flux[star] ivar[identifier] = frame.ivar[star] resolution_data[identifier] = frame.resolution_data[star] # preselec models based on magnitudes # compute star color index1, index2 = get_color_filter_indices(imaging_filters[star], args.color) if index1 < 0 or index2 < 0: log.error("cannot compute '%s' color from %s" % (color_name, filters)) filter1 = imaging_filters[star][index1] filter2 = imaging_filters[star][index2] star_color = imaging_mags[star][index1] - imaging_mags[star][index2] star_colors_array[star] = star_color # compute models color model_index1 = -1 model_index2 = -1 for i, fname in enumerate(model_filters): if fname == filter1: model_index1 = i elif fname == filter2: model_index2 = i if model_index1 < 0 or model_index2 < 0: log.error("cannot compute '%s' model color from %s" % (color_name, filters)) model_colors = model_mags[:, model_index1] - model_mags[:, model_index2] # apply extinction here # use the colors derived from the cannonical model with the mean ebv of the stars # and simply apply a scaling factor based on the ebv of this star # this is sufficiently precise for the broad model pre-selection we are doing here # the exact reddening of the star to each pre-selected model is # apply afterwards if mean_extinction_delta_mags is not None and mean_ebv != 0: delta_color = (mean_extinction_delta_mags[model_index1] - mean_extinction_delta_mags[model_index2] ) * ebv[star] / mean_ebv model_colors += delta_color log.info( "Apply a %s-%s color offset = %4.3f to the models for star with E(B-V)=%4.3f" % (model_filters[model_index1], model_filters[model_index2], delta_color, ebv[star])) # selection selection = np.abs(model_colors - star_color) < args.delta_color # smallest cube in parameter space including this selection (needed for interpolation) new_selection = (teff >= np.min(teff[selection])) & (teff <= np.max( teff[selection])) new_selection &= (logg >= np.min(logg[selection])) & (logg <= np.max( logg[selection])) new_selection &= (feh >= np.min(feh[selection])) & (feh <= np.max( feh[selection])) selection = np.where(new_selection)[0] log.info( "star#%d fiber #%d, %s = %s-%s = %f, number of pre-selected models = %d/%d" % (star, starfibers[star], args.color, filter1, filter2, star_color, selection.size, stdflux.shape[0])) # apply extinction to selected_models dust_transmission_of_this_star = dust_transmission(stdwave, ebv[star]) selected_reddened_stdflux = stdflux[ selection] * dust_transmission_of_this_star coefficients, redshift[star], chi2dof[star] = match_templates( wave, flux, ivar, resolution_data, stdwave, selected_reddened_stdflux, teff[selection], logg[selection], feh[selection], ncpu=args.ncpu, z_max=args.z_max, z_res=args.z_res, template_error=args.template_error) linear_coefficients[star, selection] = coefficients log.info( 'Star Fiber: {0}; TEFF: {1}; LOGG: {2}; FEH: {3}; Redshift: {4}; Chisq/dof: {5}' .format(starfibers[star], np.inner(teff, linear_coefficients[star]), np.inner(logg, linear_coefficients[star]), np.inner(feh, linear_coefficients[star]), redshift[star], chi2dof[star])) # Apply redshift to original spectrum at full resolution model = np.zeros(stdwave.size) for i, c in enumerate(linear_coefficients[star]): if c != 0: model += c * np.interp(stdwave, stdwave * (1 + redshift[star]), stdflux[i]) # Apply dust extinction model *= dust_transmission_of_this_star # Compute final model color mag1 = load_filter(model_filters[model_index1]).get_ab_magnitude( model * fluxunits, stdwave) mag2 = load_filter(model_filters[model_index2]).get_ab_magnitude( model * fluxunits, stdwave) model_colors_array[star] = mag1 - mag2 # Normalize the best model using reported magnitude normalizedflux = normalize_templates(stdwave, model, imaging_mags[star], imaging_filters[star]) normflux.append(normalizedflux) # Now write the normalized flux for all best models to a file normflux = np.array(normflux) data = {} data['LOGG'] = linear_coefficients.dot(logg) data['TEFF'] = linear_coefficients.dot(teff) data['FEH'] = linear_coefficients.dot(feh) data['CHI2DOF'] = chi2dof data['REDSHIFT'] = redshift data['COEFF'] = linear_coefficients data['DATA_%s' % args.color] = star_colors_array data['MODEL_%s' % args.color] = model_colors_array norm_model_file = args.outfile io.write_stdstar_models(args.outfile, normflux, stdwave, starfibers, data)