def calculate_zeropoint(filter_name,verbose=False): cmd = sim.UserCommands("../notebooks/metis_image_NQ.config") cmd["ATMO_USE_ATMO_BG"] = "yes" cmd["SCOPE_USE_MIRROR_BG"] = "yes" cmd["SIM_VERBOSE"]="no" cmd["FPA_QE"]="../data/TC_detector_METIS_NQ_no_losses.dat" cmd["INST_FILTER_TC"]="../data/TC_filter_"+filter_name+".dat" opt = sim.OpticalTrain(cmd) fpa = sim.Detector(cmd, small_fov=False) ## generate a source with 0 mag lam, spec = sim.source.flat_spectrum(0, "../data/TC_filter_"+filter_name+".dat") src = sim.Source(lam=lam, spectra=np.array([spec]), ref=[0], x=[0], y=[0]) src.apply_optical_train(opt, fpa) exptime=1 ## ## noise-free image before applying Poisson noise photonflux = fpa.chips[0].array.T clean_image = photonflux * exptime ## ## detector image with Poisson noise hdu = fpa.read_out(OBS_EXPTIME=exptime) bg_counts = np.min(clean_image) source_minus_bg_counts = np.sum(clean_image - np.min(clean_image)) if verbose: print("Background counts/s: {0:.2E}".format(bg_counts)) print("Background-subtracted source counts/s: {0:.2E}".format(source_minus_bg_counts)) return(bg_counts,source_minus_bg_counts)
def run_simmetis(): import simmetis as sim import os cmd = sim.UserCommands() cmd["OBS_EXPTIME"] = 3600 cmd["OBS_NDIT"] = 1 cmd["INST_FILTER_TC"] = "J" src = sim.source.source_1E4_Msun_cluster() opt = sim.OpticalTrain(cmd) fpa = sim.Detector(cmd) src.apply_optical_train(opt, fpa) fpa.read_out("my_output.fits") is_there = os.path.exists("my_output.fits") os.remove("my_output.fits") return is_there
def calculate_zeropoint(filter_id, filter_path, verbose=False): ## ## find out if we have the LM or NQ band camera filter_data = ascii.read(filter_path) if filter_data["col1"][0] < 6: cmd = sim.UserCommands("../notebooks/metis_image_LM.config") cmd["FPA_QE"] = "../data/TC_detector_METIS_LM_no_losses.dat" else: cmd = sim.UserCommands("../notebooks/metis_image_NQ.config") cmd["FPA_QE"] = "TC_detector_METIS_NQ_no_losses.dat" cmd["INST_FILTER_TC"] = "../data/TC_filter_" + filter_id + ".dat" opt = sim.OpticalTrain(cmd) fpa = sim.Detector(cmd, small_fov=False) ## generate a source with 0 mag lam, spec = sim.source.flat_spectrum(0, filter_path) src = sim.Source(lam=lam, spectra=np.array([spec]), ref=[0], x=[0], y=[0]) src.apply_optical_train(opt, fpa) exptime = 1 ## ## noise-free image before applying Poisson noise photonflux = fpa.chips[0].array.T clean_image = photonflux * exptime ## ## detector image with Poisson noise hdu = fpa.read_out(OBS_EXPTIME=exptime) bg_counts = np.min(clean_image) source_minus_bg_counts = np.sum(clean_image - np.min(clean_image)) if verbose: print("Background counts/s: {0:.2E}".format(bg_counts)) print("Background-subtracted source counts/s: {0:.2E}".format( source_minus_bg_counts)) return (bg_counts, source_minus_bg_counts)
def background_increases_consistently_with_exptime(): """ Run an empty source for exposure time: (1,2,4,8,16,32,64) mins If true the background level increases linearly and the stdev increases as sqrt(exptime) """ import numpy as np import simmetis as sim cmd = sim.UserCommands() cmd["OBS_REMOVE_CONST_BG"] = "no" opt = sim.OpticalTrain(cmd) fpa = sim.Detector(cmd) stats = [] for t in [2**i for i in range(7)]: src = sim.source.empty_sky() src.apply_optical_train(opt, fpa) hdu = fpa.read_out(OBS_EXPTIME=60 * t, FPA_LINEARITY_CURVE=None) im = hdu[0].data stats += [[t, np.sum(im), np.median(im), np.std(im)]] stats = np.array(stats) factors = stats / stats[0, :] bg_stats = [ i == np.round(l**2) == np.round(j) == np.round(k) for i, j, k, l in factors ] return_val = np.all(bg_stats) if not return_val: print(factors) return return_val
def transmission_emission(self, conditions='median', plot=False): ''' Apply transission to src_cube and calculate emission spectrum ''' print() print("--------------------Transmission and Emission--------------------") if plot: plt.plot(self.wavelen, self.src_cube[:, self.plotpix[0], self.plotpix[1]]) plt.title("Pixel ["+str(self.plotpix[0])+","+str(self.plotpix[1])+"] in source cube") plt.xlabel("Wavelength [micron]") plt.ylabel("Flux [Jy/arcsec2]") plt.show() # calculate wavelens of detector, needed for emission # det_wavelen = (self.det_velocities * u.m/u.s).to(u.um, equivalencies=u.doppler_optical(self.restcoo)) ############################################################################# # Read in trans-/emission from skycal # if conditions == 'best': skyfile = 'skycal_R308296_best_conditions.fits' self.cmds["SCOPE_TEMPERATURE"] = 258. - 273. self.cmds["SCOPE_MIRROR_LIST"] = "EC_mirrors_EELT_SCAO_best.tbl" elif conditions == 'median': skyfile = 'skycal_R308296_median_conditions.fits' self.cmds["SCOPE_TEMPERATURE"] = 282. - 273. self.cmds["SCOPE_MIRROR_LIST"] = "EC_mirrors_EELT_SCAO_median.tbl" elif conditions == 'poor': skyfile = 'skycal_R308296_poor_conditions.fits' self.cmds["SCOPE_TEMPERATURE"] = 294. - 273. self.cmds["SCOPE_MIRROR_LIST"] = "EC_mirrors_EELT_SCAO_poor.tbl" else: raise ValueError('Undefined conditions "' + conditions + '", only "best", "median", and "poor" are defined') skyfile = sm.utils.find_file(skyfile) skytransfits = fits.open(skyfile) print("Reading ", skyfile) skytrans = skytransfits[1].data skylam = skytrans['LAMBDA'] skytran = skytrans['TRANS'] skyemis = skytrans['EMIS'] #plt.plot(skylam, skytran) #plt.show() idx = (np.where((skylam >= np.min(self.wavelen)) & (skylam <= np.max(self.wavelen))))[0] if self.verbose: print("wavelen:", np.min(self.wavelen), "...", np.max(self.wavelen)) print("skylam: ", np.min(skylam), "...", np.max(skylam)) print("Index skytran to src-wave:", idx[0], "...", idx[-1]) # # interpolate transmission/emission onto source-grid # self.transmission = np.interp(self.wavelen, skylam, skytran) # dimensionless, [0...1] sky_emission = (np.interp(det_wavelen.value, skylam, skyemis) * (self.det_pixscale/1000.)**2) # emission in data file is photons/s/um/m^2/arcsec2, convert to photons/s/um/m^2 if plot: plt.figure(num=1, figsize=self.wide_figsize) plt.subplots_adjust(left=0.1, right=0.75) plt.plot(skylam[idx], skytran[idx], "+", label='Sky transmission') plt.plot(self.wavelen, self.transmission, label='Sky tr. interpolated') plt.xlabel("Wavelength [micron]") plt.ylabel("Transmission") #plt.show() ############################################################################# # get trans-/emission from SimMETIS # if self.verbose: print("Steaming up optical train") print("Telescope temperature:", self.cmds["SCOPE_TEMPERATURE"]) # Create transmission curve. opttrain = sm.OpticalTrain(self.cmds) # Some comments about the OpticalTrain in SimMumble: # # For MICADO, AO means MAORY # For METIS, this should be configured to do nothing # # tc_ao = transmission of everything after first mirror in AO system # (n-1 AO mirrors, entrance window, dichroic, instrument...) # tc_mirror= transmission of everything after the telescope # (tc_ao + one AO mirror, but not M1) # tc_atmo = transmission of telescope and instrument # (i.e. _without_ the atmosphere) # tc_source= transmission seen by light from the source # (including atmosphere) # # ph_ao = blackbody @ INST_AO_TEMPERATURE * 0.1 * tc_ao # ph_mirror= _gen_thermal_emission (based on SCOPE_MIRROR_LIST) * tc_mirror # ph_atmo = atmospheric emission * tc_atmo # tc_trans = interp1d(opttrain.tc_atmo.lam, opttrain.tc_atmo.val, kind='linear', bounds_error=False, fill_value=0.) if plot: plt.plot(self.wavelen, tc_trans(self.wavelen), label='Tel. transmission') plt.title("Sky & Telescope Transmission") plt.xlabel("Wavelength [micron]") plt.legend(loc='upper left', bbox_to_anchor=(1.02, 1.0)) plt.show() # combine transmission of atmosphere, telescope, and LMS (the Roy factor) self.transmission *= tc_trans(self.wavelen) * 0.712599 ############################################################################# # # transmit the source cube! # self.target_cube = self.src_cube * self.transmission[:, np.newaxis, np.newaxis] self.add_cmds_to_header(self.target_hdr) # do not add skycal-file to self.cmds! # the optical train will be confused if we try to re-run it. if len(skyfile) > 50: self.target_hdr['SKYCAL_FILE'] = "... " + skyfile[-50:] else: self.target_hdr['SKYCAL_FILE'] = skyfile if plot: plt.plot(self.wavelen, self.target_cube[:, self.plotpix[0], self.plotpix[1]]) plt.title("Pixel [" + str(self.plotpix[0]) + "," + str(self.plotpix[1]) + "] in transmitted cube") plt.xlabel("Wavelength [micron]") plt.ylabel("Flux [Jy/arcsec2]") plt.show() ############################################################################# # let there be emitted light! # # this is the code in spectral.py/BlackbodyCurve to compute the bin width lam = opttrain.ph_mirror.lam lam_res = lam[1] - lam[0] edges = np.append(lam - 0.5 * lam_res, lam[-1] + 0.5 * lam_res) lam_res = edges[1:] - edges[:-1] # lam_res is now (approximately) the bin width in um # # calculate emission in photons/s/um/pixel ph_mirr_um = opttrain.ph_mirror.val / lam_res if opttrain.ph_ao is not None: ph_mirr_um += opttrain.ph_ao.val / lam_res ph_mirror = interp1d(lam, ph_mirr_um, kind='linear', bounds_error=False, fill_value=0.) mirr_list = self.cmds.mirrors_telescope mirr_area = np.pi / 4 * np.sum(mirr_list["Outer"]**2 - \ mirr_list["Inner"]**2) if self.verbose: print("Pix_res: ", opttrain.cmds.pix_res) print("Mirror area: ", mirr_area, "[m^2]") ph_atmo_um = sky_emission * mirr_area * tc_trans(det_wavelen) ph_mirrors = ph_mirror(det_wavelen) * 1.25 # Leo's fudge-factor to account for spiders and entrance window if plot: plt.figure(num=1, figsize=self.wide_figsize) plt.subplots_adjust(right=0.8) plt.plot(det_wavelen, ph_atmo_um, '+', label='Atmosphere') plt.plot(det_wavelen, ph_mirrors, label='Telescope') plt.plot(det_wavelen, ph_atmo_um+ph_mirrors, label='total') plt.title("Sky & Mirror Emission") plt.xlabel("Wavelength [micron]") plt.ylabel("Background Flux [photons/s/um/pixel]") plt.legend(loc='upper left', bbox_to_anchor=(1.02, 1.0)) plt.show() self.background = (ph_atmo_um + ph_mirrors) * 0.712599 # photons/s/um/pixel # apply Roy factor for transmission of LMS if self.verbose: print("Final telescope temperature:", opttrain.cmds["SCOPE_TEMPERATURE"])
def mimic_image(hdu, catalogue, cmds=None, hdu_ext=0, sim_chip_n=0, return_stamps=False, cat_ra_name="RA", cat_dec_name="DE", cat_filter_name="J", **kwargs): """ Create a SimMETIS image to mimic a real FITS file Parameters ---------- hdu : str, astropy.HDUList The original FITS object- either a filename or an astropy.HDUList object catalogue : str, astropy.Table A catalogue of stars - either a filename or an astropy.Table object cmds : str, simmetis.UserCommands Commands by which to simulate the image - a filename to a .config file or a UserCommands object hdu_ext : int The extension in the original FITS file which should be simulated sim_chip_n : int Which chip in the FPA_LAYOUT to simulate. Passed to apply_optical_train() and read_out() return_stamps : bool If True, returns two PostageStamps object for the original HDU and the generated HDU cat_ra_name, cat_dec_name, cat_filter_name : str The names of the column in catalogue which point to the RA, Dec and filter magnitudes for the stars Optional Parameters ------------------- As passed to a PostageStamps object "dx" : 0, "dy " : 0, "bg_tile_size" : 24, "stamp_width" : 24, "hot_pixel_threshold" : 3000 Returns ------- hdu_sim, src [, post_real, post_sim] If return_stamps is True, post_real and post_sim are returned Examples -------- :: >>> hdu_real = fits.open("HAWKI.2008-11-05T04_08_55.552.fits") >>> cat = ascii.read("ngc362_cohen.dat") >>> >>> dx, dy = -5, 15 >>> >>> cmd = sim.UserCommands("hawki_ngc362.config") >>> cmd["INST_FILTER_TC"] = "J" >>> cmd["OBS_EXPTIME"] = 10 >>> >>> out = mimic_image(hdu=hdu_real, catalogue=cat, cmds=cmd, hdu_ext=3, ... sim_chip_n=3, return_stamps=True, ... dx=dx, dy=dy) >>> hdu_sim, src, post_real, post_sim = out >>> len(out) 4 """ if isinstance(hdu, str) and os.path.exists(hdu): hdu = fits.open(hdu)[hdu_ext] elif isinstance(hdu, fits.HDUList): hdu = hdu[hdu_ext] else: raise ValueError("hdu must be a filename or an astropy HDU object: " + type(hdu)) if isinstance(catalogue, str) and os.path.exists(catalogue): cat = ascii.read(catalogue) elif isinstance(catalogue, Table): cat = catalogue else: raise ValueError( "catalogue must be a filename or an astropy.Table object: " + type(catalogue)) if isinstance(cmds, str) and os.path.exists(cmds): cmds = sim.UserCommands(cmds) elif isinstance(cmds, sim.UserCommands): pass else: raise ValueError( "cmds must be a filename or an simmetis.UserCommands object: " + type(cmds)) fig = plt.figure(figsize=(0.1, 0.1)) apl_fig = aplpy.FITSFigure(hdu, figure=fig) # get the RA DEC position of the centre of the HAWKI FoV xc, yc = hdu.header["CRPIX1"], hdu.header["CRPIX2"] ra_cen, dec_cen = apl_fig.pixel2world(xc, yc) # get the x,y positions in arcsec from the HAWKI FoV centre y = (cat[cat_dec_name] - dec_cen) * 3600 x = -(cat[cat_ra_name] - ra_cen) * 3600 * np.cos(cat[cat_dec_name] / 57.3) mag = cat[cat_filter_name] # make a Source object with the x,y positions in arcsec from the HAWKI FoV centre src = sim.source.stars(mags=mag, filter_name=cat_filter_name, x=x, y=y) opt = sim.OpticalTrain(cmds) fpa = sim.Detector(cmds, small_fov=False) print(sim_chip_n) src.apply_optical_train(opt, fpa, chips=sim_chip_n) hdu_sim = fpa.read_out(chips=sim_chip_n) ## Get the Postage Stamps if return_stamps: params = { "dx": 0, "dy ": 0, "bg_tile_size": 24, "stamp_width": 24, "hot_pixel_threshold": 3000 } params.update(**kwargs) w, h = hdu_sim[0].data.shape mask = (src.x_pix > 0) * (src.x_pix < w) * (src.y_pix > 0) * (src.y_pix < h) xw = cat[cat_ra_name][mask] yw = cat[cat_dec_name][mask] mag = cat[cat_filter_name][mask] # get the x,y pixel positions of the stars in the simulated image xps = src.x_pix[mask] yps = src.y_pix[mask] # get the x,y pixel positions of the stars in the real image, include offset if needed xpr, ypr = apl_fig.world2pixel(xw, yw) xpr += params["dx"] ypr += params["dy"] # get the images from the FITS objects im_sim = np.copy(hdu_sim[0].data) im_sim -= np.median(im_sim) post_sim = PostageStamps(im_sim, x=xps, y=yps, **params) im_real = np.copy(hdu.data) im_real -= np.median(im_real) post_real = PostageStamps(im_real, x=xpr, y=ypr, **params) return hdu_sim, src, post_real, post_sim else: return hdu_sim, src