def jitterless(opt): jexosim_msg ("using jitterless array", opt.diagnostics) blank_signal = np.ones((int(opt.fp.shape[0]/3), int(opt.fp.shape[1]/3), len(opt.frames_per_ndr))) jitterless = (blank_signal.transpose() * opt.fp[1::3,1::3].transpose() ).transpose() opt.signal = jitterless*opt.frames_per_ndr*opt.frame_time opt.pointing_timeline= np.zeros((opt.ndr_end_frame_number[-1], 3)) return opt
def subDark(opt): jexosim_msg("subtracting dark signal...", opt.diagnostics) dc_time = opt.channel.detector_pixel.Idc.val * opt.duration_per_ndr new_data = opt.data - dc_time opt.data = new_data return opt
def make_ramps(opt): jexosim_msg ("check point 6.1 %s"%(opt.signal.max()) , opt.diagnostics ) # Make ramps for i in range(0, opt.n_ndr, opt.effective_multiaccum): opt.signal[...,i:i+opt.effective_multiaccum] = np.cumsum(opt.signal[...,i:i+opt.effective_multiaccum], axis=2) return opt
def fast_method(opt): idx0, idx1, idxA, idxB = crop_array(opt) # apply x crop to 1D arrays opt.x_wav_osr0 = opt.x_wav_osr*1 opt.x_wav_osr = opt.x_wav_osr[idxA*3:idxB*3] opt.x_pix_osr = opt.x_pix_osr[idxA*3:idxB*3] opt.cr_wl = opt.cr_wl[idxA:idxB] opt.cr = opt.cr[idxA:idxB] if opt.timeline.apply_lc.val ==1: opt.ldc = opt.ldc[:,idxA:idxB] opt.lc = opt.lc[idxA:idxB] opt.zodi.sed = opt.zodi.sed[idxA*3:idxB*3] opt.sunshield.sed = opt.sunshield.sed[idxA*3:idxB*3] opt.emission.sed = opt.emission.sed[idxA*3:idxB*3] opt.quantum_yield.sed = opt.quantum_yield.sed[idxA*3:idxB*3] opt.qy_zodi = opt.qy_zodi[idxA*3:idxB*3] opt.qy_sunshield = opt.qy_sunshield[idxA*3:idxB*3] opt.qy_emission = opt.qy_emission[idxA*3:idxB*3] opt.exp_sig = opt.exp_sig[idxA:idxB] #expected final star signal in R bin from detector module sanity check # apply x and y crop to 2D arrays opt.qe = opt.qe[idx0:idx1][:, idxA:idxB] opt.qe_uncert = opt.qe_uncert[idx0:idx1][:, idxA:idxB] opt.fp = opt.fp[idx0*3:idx1*3][:, idxA*3:idxB*3] opt.fp_signal = opt.fp_signal[idx0*3:idx1*3][:, idxA*3:idxB*3] # obtain proxy bkg signal for pipeline background subtraction step opt.bkg_signal = proxy_bkg(opt) jexosim_msg ("fast method used, focal place image reduced from %s x %s to %s x %s"%(opt.fp_original.shape[0]/3, opt.fp_original.shape[1]/3 , opt.fp.shape[0]/3, opt.fp.shape[1]/3), opt.diagnostics) return opt
def apply_ipc(opt): # Apply IPC: should be before read noise if opt.simulation.sim_use_ipc.val == 1 and opt.channel.instrument.val !='MIRI': jexosim_msg('Applying IPC...', opt.diagnostics) ipc_kernel = np.load(opt.channel.detector_array.ipc_kernel.val.replace('__path__', '%s/%s'%(opt.jexosim_path, 'jexosim'))) opt.signal = noise_lib.apply_ipc(opt.signal, ipc_kernel) return opt
def subBackground(opt): jexosim_msg("subtracting background...", opt.diagnostics) if opt.simulation.sim_use_fast.val ==1 and opt.channel.instrument.val!='NIRISS' and \ opt.data.shape[0]>20: aa = opt.bkg_signal.sum( axis=0) / opt.bkg_signal.shape[0] #mean value per column if opt.channel.instrument.val != 'NIRSpec': # overall mean - okay if no slit since no wav-dep on zodi and emission aa = [] for i in range(opt.data.shape[2]): aa.append(opt.bkg_signal[..., i].mean().value) aa = np.array(aa) * u.electron opt.data = opt.data - aa else: border_pix = 5 if opt.data.shape[0] < 20: border_pix = 1 background_1 = opt.data[0:border_pix] background_2 = opt.data[-border_pix:] background = np.vstack((background_1, background_2)) aa = background.sum(axis=0) / background.shape[0] if opt.channel.instrument.val != 'NIRSpec': aa = [] for i in range(opt.data.shape[2]): aa.append(background[..., i].mean().value) aa = np.array(aa) * u.electron opt.data = opt.data - aa return opt
def open_Phoenix(self, t0, logg0, Z, sed_folder): cond = 0 for root, dirs, files in os.walk(sed_folder): for filename in files: if filename == 'lte0%s-%s-0.0a+0.0.BT-Settl.spec.fits'%(t0, logg0): ph_file = '%s/%s'%(sed_folder, filename) cond = 1 elif filename == 'lte0%s-%s-0.0a+0.0.BT-Settl.spec.fits.gz'%(t0, logg0): ph_file = '%s/%s'%(sed_folder, filename) jexosim_msg ("Star file used: %s"%(ph_file) , self.opt.diagnostics) cond = 1 if cond==0: jexosim_msg ("Error Star 2: no star file found", 1) sys.exit() else: with fits.open(ph_file) as hdu: wl = u.Quantity(hdu[1].data.field('Wavelength'), hdu[1].header['TUNIT1']).astype(np.float64) sed = u.Quantity(hdu[1].data.field('Flux'), u.W/u.m**2/u.um).astype(np.float64) if hdu[1].header['TUNIT2'] != 'W / (m2 um)': print ('Exception') #remove duplicates idx = np.nonzero(np.diff(wl)) wl = wl[idx] sed = sed[idx] hdu.close() return wl, sed
def apply_poisson_noise(opt): if opt.noise.EnableShotNoise.val == 1: jexosim_msg ("Applying Poisson noise", opt.diagnostics) opt.signal = np.where(opt.signal >= 0.0, opt.signal, 0) opt.combined_noise = noise_lib.calc_poission_noise(opt.signal.value) *u.electron else: jexosim_msg ("Poisson noise not being applied...", opt.diagnostics) return opt
def apply_utr_correction(opt): # UTR correction verfied as correct for read noise, poisson noise, fano noise, fano and poission noise if opt.noise.EnableShotNoise.val == 1 or opt.noise.EnableFanoNoise.val == 1: if opt.simulation.sim_full_ramps.val == 0 and opt.simulation.sim_use_UTR_noise_correction.val == 1: jexosim_msg ("applying correction to photon noise for UTR read", opt.diagnostics ) n = opt.projected_multiaccum opt.combined_noise, scale = noise_lib.poission_noise_UTR_correction(n, opt.combined_noise.value) opt.combined_noise = opt.combined_noise * u.electron return opt
def apply_systematic(opt): if opt.simulation.sim_use_systematic_model.val == 0: return opt else: jexosim_msg ("Applying systematic model...", opt.diagnostics) signal = opt.signal*1 syst = opt.syst*1 signal = signal*syst opt.signal = signal return opt
def apply_dc(opt): blank_fp_shape = np.ones((int(opt.fp.shape[0]/3), int(opt.fp.shape[1]/3), len(opt.frames_per_ndr))) opt.dc_signal = np.zeros_like(blank_fp_shape)*u.electron if opt.background.EnableDC.val ==1: jexosim_msg ("DARK CURRENT being added...%s"%(opt.channel.detector_pixel.Idc.val ), opt.diagnostics ) opt.dc_signal = blank_fp_shape* opt.channel.detector_pixel.Idc() * opt.frame_time * opt.frames_per_ndr opt.signal = opt.signal + opt.dc_signal else: jexosim_msg ("DARK CURRENT.. not... being added...", opt.diagnostics) return opt
def flatField(opt): jexosim_msg("applying flat field...", opt.diagnostics) QE_grid = opt.qe_grid opt.data = np.rollaxis(opt.data, 2, 0) opt.data = opt.data / QE_grid opt.data = np.rollaxis(opt.data, 0, 3) jexosim_msg("std of flat field...%s" % (QE_grid.std()), opt.diagnostics) return opt
def apply_lc(opt): if opt.timeline.apply_lc.val ==0: jexosim_msg ("OMITTING LIGHT CURVE...", opt.diagnostics) return opt else: jexosim_msg ("APPLYING LIGHT CURVE...", opt.diagnostics) signal = opt.signal*1 lc = opt.lc*1 signal = signal*lc opt.signal = signal return opt
def subZero(opt): jexosim_msg("subtracting zeroth read...", opt.diagnostics) multiaccum = opt.effective_multiaccum new_data = np.zeros( (opt.data.shape[0], opt.data.shape[1], opt.data.shape[2])) for i in range(0, opt.data.shape[2], multiaccum): for j in range(0, multiaccum): new_data[..., i + j] = opt.data[..., i + j] - opt.data[..., i] opt.data = new_data return opt
def read_phoenix_spectrum(self): jexosim_msg ("Star... star_temperature %s, star_logg %s, star_f_h %s"%(self.star_temperature, self.star_logg, self.star_f_h) , self.opt.diagnostics) if self.star_temperature.value >= 2400: t0 = np.round(self.star_temperature,-2)/100. else: t0= np.round(np.round(self.star_temperature,-1)/100./0.5)*0.5 logg0 = np.round(np.round(self.star_logg,1)/0.5)*0.5 cond=0 for root, dirs, files in os.walk(self.sed_folder): for filename in files: if filename == 'lte0%s-%s-0.0a+0.0.BT-Settl.spec.fits'%(t0.value, logg0): ph_file = '%s/%s'%(self.sed_folder, filename) cond = 1 elif filename == 'lte0%s-%s-0.0a+0.0.BT-Settl.spec.fits.gz'%(t0.value, logg0): ph_file = '%s/%s'%(self.sed_folder, filename) jexosim_msg ("Star file used: %s"%(ph_file) , self.opt.diagnostics) cond = 1 if cond==0: jexosim_msg ("Error Star 2: no star file found", 1) sys.exit() with fits.open(ph_file) as hdu: wl = u.Quantity(hdu[1].data.field('Wavelength'), hdu[1].header['TUNIT1']).astype(np.float64) sed = u.Quantity(hdu[1].data.field('Flux'), u.W/u.m**2/u.um).astype(np.float64) if hdu[1].header['TUNIT2'] != 'W / (m2 um)': print ('Exception') #remove duplicates idx = np.nonzero(np.diff(wl)) wl = wl[idx] sed = sed[idx] hdu.close() jexosim_msg("star check 1: %s"%sed.max(), self.opt.diagnostics) return wl, sed
def write_to_fits_intermediate(opt): jexosim_msg('Saving binned light curves to fits file ...', 1) output_directory = opt.common.output_directory.val hdu = fits.PrimaryHDU() hdu.header['NEXP'] = (opt.n_exp, 'Number of exposures') hdu.header['MACCUM_P'] = (opt.projected_multiaccum, 'Multiaccum (projected)') hdu.header['MACCUM_E'] = (opt.effective_multiaccum, 'Multiaccum (effective)') hdu.header['TEXP'] = (opt.exposure_time.value, 'Duration of each intergration cycle [s]') hdu.header['PLANET'] = (opt.planet.planet.name, 'Planet name') hdu.header['STAR'] = (opt.planet.planet.star.name, 'Star name') hdulist = fits.HDUList(hdu) hdu = fits.ImageHDU(opt.pipeline_stage_1.binnedLC.value.astype(np.float32)) hdu.header['EXTNAME'] = ('BINNED_LIGHT_CURVES') hdu.header['UNITS'] = ('%s' % (opt.pipeline_stage_1.binnedLC.unit)) hdulist.append(hdu) col1 = fits.Column(name='Wavelength {:s}'.format( opt.pipeline_stage_1.binnedWav.unit), format='E', array=opt.pipeline_stage_1.binnedWav.value) cols = fits.ColDefs([col1]) tbhdu = fits.BinTableHDU.from_columns(cols) tbhdu.name = 'WAVELENGTH' hdulist.append(tbhdu) col1 = fits.Column(name='Time {:s}'.format( opt.pipeline_stage_1.exp_end_time_grid.unit), format='E', array=opt.pipeline_stage_1.exp_end_time_grid.value) cols = fits.ColDefs([col1]) tbhdu = fits.BinTableHDU.from_columns(cols) tbhdu.name = 'TIME' hdulist.append(tbhdu) #write hdulist lab = '%s_%s' % (opt.observation.obs_channel.val, opt.exosystem_params.planet_name.val) time_tag = (datetime.now().strftime('%Y_%m_%d_%H%M_%S')) filename = 'jexosim_intermediate_%s_%s' % (lab, time_tag) hdulist.writeto('%s/%s.fits' % (output_directory, filename)) return '%s.fits' % (filename)
def crop_array(opt): fp_whole = opt.fp[1::3,1::3] fp_signal_whole = opt.fp_signal[1::3,1::3] #============================================================================== #1) Calculate the maximum width (y crop) in pixels and apply crop #============================================================================== aa = fp_signal_whole.sum(axis=1).value # sum of profile in x axis jexosim_plot('y crop selection', opt.diagnostics, ydata=aa, marker='ro-', grid=True) bb = np.mean(np.vstack((aa[:5],aa[-5:]))) # average of outer 5 pixels if bb == 0: aa_ = aa[np.argwhere(aa>0).T[0]] bb = aa_.min()/np.e idx_max = np.argmax(aa) print (bb) #find where signal falls below b*npe either side for i in range(int(len(aa)/2)): s = aa[idx_max-i] if s < bb*np.e: # idx0=1+ idx_max-i #+1 so that it starts within the region of > b8npe idx0=idx_max-i #+1 so that it starts within the region of > b8npe break for i in range(int(len(aa)/2)): s = aa[idx_max+i] if s < bb*np.e: # idx1=idx_max+i idx1=1+idx_max+i break #idx0, idx1 #indexs that bound this region idx1 = int(idx1) ; idx0 = int(idx0) print (idx0, idx1) w_crop = idx1- (idx0) jexosim_msg ("width of crop chosen %s"%(w_crop ) , opt.diagnostics) jexosim_plot('y crop selection', opt.diagnostics, xdata=np.arange(idx0, idx1,1), ydata=aa[idx0:idx1], marker='bo-', grid=True) #============================================================================== #2) Calculate the maximum length (x crop) in pixels and apply crop #============================================================================== wav_sol= opt.x_wav_osr[1::3].value # wav sol in whole pixels idx = np.argwhere((wav_sol>=opt.channel.pipeline_params.start_wav.val-0.5)& (wav_sol<=opt.channel.pipeline_params.end_wav.val+0.5)) idxA = idx[0].item() idxB = idx[-1].item() return idx0, idx1, idxA, idxB
def obtain_signal_only(opt): jexosim_msg ("generating seperate noiseless signal array", opt.diagnostics ) fp = opt.fp_signal[1::3,1::3] blank_signal = np.ones((fp.shape[0], fp.shape[1], len(opt.frames_per_ndr))) signal = (blank_signal.transpose() * fp.transpose() ).transpose() signal = signal*opt.frames_per_ndr*opt.frame_time if opt.timeline.apply_lc.val ==1: signal *= opt.lc signal = np.where(signal >= 0.0, signal, 0) for i in range(0, opt.n_ndr, opt.effective_multiaccum): signal[...,i:i+opt.effective_multiaccum] = np.cumsum(signal[...,i:i+opt.effective_multiaccum], axis=2) if opt.simulation.sim_use_ipc.val == 1 and opt.channel.instrument.val !='MIRI': ipc_kernel = np.load(opt.channel.detector_array.ipc_kernel.val.replace('__path__', '%s/%s'%(opt.jexosim_path, 'jexosim'))) signal = apply_ipc(signal, ipc_kernel) signal = signal* u.electron return signal
def apply_prnu(opt): opt.qe_grid = opt.qe # used for flat field in pipeline jexosim_msg ("mean and standard deviation of flat field: should match applied flat in data reduction %s %s"%(opt.qe.mean(), opt.qe.std()), opt.diagnostics ) jexosim_msg ("standard deviation of flat field uncertainty %s"%(opt.qe_uncert.std()), opt.diagnostics ) applied_qe= opt.qe*opt.qe_uncert if opt.noise.ApplyPRNU.val == 1: jexosim_msg ("PRNU GRID BEING APPLIED", opt.diagnostics) opt.signal= (opt.signal.transpose() * applied_qe.transpose() ).transpose() else: jexosim_msg ("PRNU GRID NOT APPLIED...", opt.diagnostics) return opt
def file_model(self): filename = self.opt.exosystem_params.star_spectrum_file.val # if the file is in the planet_spectra folder can be IDed only with filename not full path if '/' in filename: pass else: filename = '%s/jexosim/data/star_spectra/%s'%(self.opt.jexosim_path, filename) jexosim_msg('star spectrum from file: %s'%(filename),1) try: aa = np.loadtxt(filename) except IOError: jexosim_msg("Error6 planet class: No spectrum file found", 1) # if provided in m... convert to um if aa[:,0][0]< 1e-4: self.stellar_wl= aa[:,0]*1e6*u.um else: self.stellar_wl= aa[:,0]*u.um self.stellar_sed = aa[:,1]*u.W/(u.m)**2/u.um
def __init__(self, opt): self.opt = opt self.star_temperature = opt.exosystem.star.T self.star_logg = opt.exosystem.star.logg self.star_f_h = opt.exosystem.star.Z # currently only 0 can be chosen from files if opt.exosystem_params.star_spectrum_model.val =='complex': self.complex_model() jexosim_msg ("complex star spectrum chosen from database", 1) elif opt.exosystem_params.star_spectrum_model.val == 'simple': self.simple_model() jexosim_msg ("simple star spectrum chosen", 1) elif opt.exosystem_params.star_spectrum_model.val =='file': self.file_model() jexosim_msg ("filed star spectrum chosen", 1) else: jexosim_msg('Error1 star class: no compatible entry for star spectrum_model', 1) sys.exit() stellar_sed_pre_norm = self.stellar_sed*1 if self.opt.exosystem_params.star_spectrum_mag_norm.val == 1: self.stellar_sed = self.useTelFlux(self.stellar_wl, self.stellar_sed) elif self.opt.exosystem_params.star_spectrum_mag_norm.val == 2: self.stellar_sed *= ((self.opt.exosystem.star.R).to(u.m)/(self.opt.exosystem.star.d).to(u.m))**2 # [W/m^2/mu] elif self.opt.exosystem_params.star_spectrum_mag_norm.val == 0: pass jexosim_msg("star check 2: %s"%self.stellar_sed.max(), self.opt.diagnostics) self.sed = sed.Sed(self.stellar_wl, self.stellar_sed) self.sed_pre_norm = sed.Sed(self.stellar_wl, stellar_sed_pre_norm) if opt.diagnostics == 1: import matplotlib.pyplot as plt plt.figure('test star spectrum 1') plt.plot(self.stellar_wl, self.stellar_sed) plt.figure('test star spectrum pre-norm') plt.plot(self.stellar_wl, stellar_sed_pre_norm)
def convolve_prf(opt, fp, fp_signal): if opt.channel.detector_pixel.pixel_diffusion_length.val.value < 0.01: box = np.ones((3, 3)) fp = signal.fftconvolve(fp, box, 'same') fp_signal = signal.fftconvolve(fp_signal, box, 'same') jexosim_msg('Convolving with top-hat PRF', opt.diagnostics) else: kernel, kernel_delta = jexosim_lib.PixelResponseFunction( opt, opt.psf.shape[0:2], 7 * opt.channel.simulation_factors.osf(), opt.channel.detector_pixel.pixel_size(), lx=opt.channel.detector_pixel.pixel_diffusion_length()) # jexosim_msg ("kernel sum %s"%(kernel.sum()), opt.diagnostics) # jexosim_msg ("check 3.9 - unconvolved FP max %s"%(fp.max()) , opt.diagnostics) # jexosim_plot('test3', opt.diagnostics, xdata=opt.x_wav_osr, ydata = fp.sum(axis=0), marker='bo') # jexosim_plot('test4', opt.diagnostics, xdata=opt.x_pix_osr, ydata = opt.x_wav_osr, marker='bo') # jexosim_plot('test5', opt.diagnostics, xdata=opt.x_pix_osr, ydata = fp.sum(axis=0), marker='bo') # jexosim_plot('test6', opt.diagnostics, xdata=opt.x_wav_osr, ydata = opt.star.sed.sed, marker='bo') fp = jexosim_lib.fast_convolution(fp, opt.fp_delta, kernel, kernel_delta) fp_signal = jexosim_lib.fast_convolution(fp_signal, opt.fp_delta, kernel, kernel_delta) jexosim_msg("check 4 - convolved FP max %s" % (fp.max()), opt.diagnostics) jexosim_msg("check 4 - convolved FP signal max %s" % (fp_signal.max()), opt.diagnostics) opt.kernel = kernel opt.kernel_delta = kernel_delta # Fix units fp = fp * opt.star.sed.sed.unit fp_signal = fp_signal * opt.star.sed.sed.unit return fp, fp_signal
def __init__(self, data, opt): method = opt.pipeline.jitterMethod.val self.opt = opt self.data = data self.jdc = JexoSimDecorr(self.data, self.opt) if method == 'xcorr-interp' or method == 'xcorr-fft': jiggOffsetMeasure = { 'spec': np.zeros(self.jdc.nExp), 'spat': np.zeros(self.jdc.nExp) } for i in range(self.jdc.nExp): im = data[..., i] offset = getRelativeOffsets(self.jdc.modelBeam, im) jiggOffsetMeasure['spec'][i] = offset['spec'] jiggOffsetMeasure['spat'][i] = offset['spat'] if method == 'xcorr-interp': self.shiftedMaps = JitterRemoval.cubicIterp( self.jdc, jiggOffsetMeasure, data) elif method == 'xcorr-fft': self.shiftedMaps = JitterRemoval.fftShift( self.jdc, jiggOffsetMeasure, data) # does not need pointing info or pscale elif method == 'pointing-interp' or method == 'pointing-fft': if method == 'pointing-interp': jiggOffsetMeasure = self.jdc.getPointingOffsets() self.shiftedMaps = JitterRemoval.cubicIterp( self.jdc, self.jdc.getPointingOffsets(), self.data) if method == 'pointing-fft': self.shiftedMaps = JitterRemoval.fftShift( self.jdc, self.jdc.getPointingOffsets(), self.data) jexosim_msg("method %s" % (method), opt.diagnostics) self.getData()
def gen_prnu_grid(opt): if opt.noise.ApplyRandomPRNU.val == 1: opt.qe = np.random.normal( 1, 0.01 * opt.noise.sim_prnu_rms.val, opt.fp_original[1::3, 1::3].shape) # for random uncertainty opt.qe_uncert = np.random.normal( 1, 0.01 * opt.noise.sim_flat_field_uncert.val, opt.fp_original[1::3, 1::3].shape) # for random uncertainty jexosim_msg("RANDOM PRNU GRID SELECTED...", opt.diagnostics) else: opt.qe = np.load('%s/data/JWST/PRNU/qe_rms.npy' % (opt.__path__))[0:opt.fp_original[1::3, 1::3].shape[0], 0:opt.fp_original[1::3, 1::3].shape[1]] opt.qe_uncert = np.load( '%s/data/JWST/PRNU/qe_uncert.npy' % (opt.__path__))[0:opt.fp_original[1::3, 1::3].shape[0], 0:opt.fp_original[1::3, 1::3].shape[1]] jexosim_msg("PRNU GRID SELECTED FROM FILE...", opt.diagnostics) return opt
def satFlag(data, opt): margin = 0.1 jexosim_msg( "flagging pixels more than %s percent above saturation limit..." % (margin * 100), opt.diagnostics) # margin accounts for fact that noise may increase the counts to above the designated sat limit sat_limit = opt.sat_limit.value + margin * opt.sat_limit.value idx = np.argwhere(data.value > sat_limit) dq_array = opt.dq_array for i in range(len(idx)): dq_array[idx[i][0]][idx[i][1]][idx[i][2]] = 2 # flag 2 = 'saturated pixels' (overmaps flag 1) jexosim_msg("number of saturated pixels over all NDRs %s" % (len(idx)), opt.diagnostics) opt.dq_array = dq_array return opt.dq_array
def apply_read_noise(opt): if opt.noise.EnableReadoutNoise.val == 1: jexosim_msg ("READ NOISE... being added...", opt.diagnostics) opt.signal = noise_lib.apply_read_noise(opt.signal,opt) else: jexosim_msg ("READ NOISE...not... being added..." , opt.diagnostics ) jexosim_msg ("check point 7 %s %s"%(opt.signal.max(), opt.signal.min()) , opt.diagnostics ) return opt
def apply_fano(opt): if opt.noise.EnableFanoNoise.val ==1: jexosim_msg('Applying Fano noise...', opt.diagnostics) # old... # consider photons only, not dc. # qy_emission = opt.qy_emission[1::3][np.newaxis, :, np.newaxis] # qy_zodi = opt.qy_zodi[1::3][np.newaxis, :, np.newaxis] # qy_sunshield = opt.qy_sunshield[1::3][np.newaxis, :, np.newaxis] # qy_star = opt.quantum_yield.sed[1::3][np.newaxis, :, np.newaxis] # signal_total = opt.star_signal + opt.zodi_signal + +opt.sunshield_signal + opt.emission_signal # signal_total = np.where(signal_total<=0, 1e-10*u.electron, signal_total) # quantum_yield_for_fano = (qy_star*opt.star_signal + qy_zodi*opt.zodi_signal + qy_sunshield*opt.sunshield_signal + qy_emission*opt.emission_signal) / signal_total # quantum_yield_for_fano = np.where(quantum_yield_for_fano<1, 1, quantum_yield_for_fano) # jexosim_msg(f'max, min quantum yield applied for fano: {quantum_yield_for_fano.max()}, {quantum_yield_for_fano.min()}', opt.diagnostics) # jexosim_plot('quantum yield total', 1, xdata=opt.x_wav_osr[1::3], ydata=(quantum_yield_for_fano.mean(axis=2)).mean(axis=0) ) # fano_noise = noise_lib.calc_fano_noise(quantum_yield_for_fano, signal_total) # new... same result photons_total = opt.star_signal + opt.zodi_signal + opt.sunshield_signal + opt.emission_signal photons_total = np.where(photons_total<=0, 1e-10*u.electron, photons_total) fano_noise = noise_lib.calc_fano_noise(opt.quantum_yield_total, photons_total) # plt.figure('fano noise pixel level') # n = fano_noise.sum(axis=0) # n = n.std(axis=1) # plt.plot(opt.x_wav_osr[1::3], n, 'g-') opt.combined_noise = opt.combined_noise + fano_noise # plt.figure('combined noise pixel level') # n = opt.combined_noise.sum(axis=0) # n = n.std(axis=1) # plt.plot(opt.x_wav_osr[1::3], n, 'b-') else: jexosim_msg('Fano noise... not... applied', opt.diagnostics) return opt
def badCorr(data, opt): # jexosim_msg ("correcting bad pixels...", opt.diagnostics) jexosim_msg("applying zero value to saturated pixel timelines...", opt.diagnostics) opt.data_pre_flag = data * 1 dq_array = opt.dq_array bad_map = dq_array.sum(axis=2) idx = np.argwhere(bad_map > 0) jexosim_msg('number of saturated pixels per image %s' % (len(idx)), opt.diagnostics) bad_map = np.where(bad_map == 0, 0, 1) if opt.pipeline.pipeline_bad_corr.val == 1: for i in range(len(idx)): data[idx[i][0]][idx[i][ 1]] = 0 # make the entire time series of a saturated pixel = 0 opt.exp_image = data[..., 0] opt.bad_map = bad_map opt.no_sat = len(idx) opt.data = data return opt
def apply_quantum_yield(opt): # Apply weighted quantum yield to signal jexosim_msg ("Applying quantum yield", opt.diagnostics) qy_emission = opt.qy_emission[1::3][np.newaxis, :, np.newaxis] qy_zodi = opt.qy_zodi[1::3][np.newaxis, :, np.newaxis] qy_sunshield = opt.qy_sunshield[1::3][np.newaxis, :, np.newaxis] qy_star = opt.quantum_yield.sed[1::3][np.newaxis, :, np.newaxis] print (qy_star.max(), qy_star.min()) print (qy_zodi.max(), qy_zodi.min()) print (qy_sunshield.max(), qy_sunshield.min()) print (qy_emission.max(), qy_emission.min()) print (opt.star_signal.max(), opt.star_signal.min()) print (opt.zodi_signal.max(), opt.zodi_signal.min()) print (opt.sunshield_signal.max(), opt.sunshield_signal.min()) print (opt.emission_signal.max(), opt.emission_signal.min()) ## This works # signal_total = opt.star_signal + opt.zodi_signal + opt.sunshield_signal + opt.emission_signal + opt.dc_signal # signal_total = np.where(signal_total<=0, 1e-10*u.electron, signal_total) # opt.quantum_yield_total = (qy_star*opt.star_signal + qy_zodi*opt.zodi_signal + qy_sunshield*opt.sunshield_signal + qy_emission*opt.emission_signal + 1*opt.dc_signal) / signal_total # opt.quantum_yield_total = np.where(opt.quantum_yield_total<1, 1, opt.quantum_yield_total) # opt.signal = opt.signal*opt.quantum_yield_total # opt.combined_noise = opt.combined_noise*opt.quantum_yield_total ## This also works - newer photons_total = opt.star_signal + opt.zodi_signal + opt.sunshield_signal + opt.emission_signal photons_total = np.where(photons_total<=0, 1e-10*u.electron, photons_total) opt.quantum_yield_total = (qy_star*opt.star_signal + qy_zodi*opt.zodi_signal + qy_sunshield*opt.sunshield_signal + qy_emission*opt.emission_signal) / photons_total opt.quantum_yield_total = np.where(opt.quantum_yield_total <1, 1, opt.quantum_yield_total) # now only apply to photons, so remove dc, multiply in qy and add back dc signal = (opt.signal - opt.dc_signal)*opt.quantum_yield_total + opt.dc_signal noise = (opt.combined_noise - (opt.dc_signal/opt.signal)*opt.combined_noise)*opt.quantum_yield_total + (opt.dc_signal/opt.signal)*opt.combined_noise noise[np.isnan(noise)] = 0 # mostly for read noise where opt.signal = zero returns nans opt.signal = signal opt.combined_noise = noise if opt.quantum_yield_total.max() > 2 or opt.quantum_yield_total.min() <1: jexosim_msg('error in QY calculation') sys.exit() jexosim_msg(f'max, min quantum yield applied: {opt.quantum_yield_total.max()}, {opt.quantum_yield_total.min()}', opt.diagnostics) return opt
def get_psf(opt): if os.path.exists('%s/../archive/PSF/%s_psf_stack.npy' % (opt.__path__, opt.channel.instrument.val)): psf_stack = np.load('%s/../archive/PSF/%s_psf_stack.npy' % (opt.__path__, opt.channel.instrument.val)) psf_stack_wl = 1e6 * np.load( '%s/../archive/PSF/%s_psf_stack_wl.npy' % (opt.__path__, opt.channel.instrument.val)) psf = interpolate.interp1d(psf_stack_wl, psf_stack, axis=2, bounds_error=False, fill_value=0.0, kind='linear')(opt.x_wav_osr.value) psf = np.rot90(psf) psf_type = 'wfe' else: # uses airy if no psf database however this is to be avoided, as pipeline assumes the wfe database psfs. jexosim_msg('PSF files could not be found. Check psf files location.') sys.exit() # psf = jexosim_lib.Psf(opt.x_wav_osr.value, opt.channel.camera.wfno_x.val, opt.channel.camera.wfno_y.val, opt.fp_delta.value, shape='airy') # psf[np.isnan(psf)] =0 # psf_type = 'airy' jexosim_msg("PSF shape %s, %s" % (psf.shape[0], psf.shape[1]), opt.diagnostics) jexosim_plot('psf check', opt.diagnostics, image=True, image_data=psf[..., int(psf.shape[2] / 2)]) sum1 = [] for i in range(psf.shape[2]): sum1.append(psf[..., i].sum()) if psf[..., i].sum() != 0: # psf[...,i] =psf[...,i]/psf[...,i].sum() if np.round(psf[..., i].sum(), 3) != 1.0: jexosim_msg( 'error... check PSF normalisation %s %s' % (psf[..., i].sum(), opt.x_wav_osr[i]), 1) sys.exit() jexosim_plot('test7 - psf sum vs subpixel position (should be 1)', opt.diagnostics, xdata=opt.x_pix_osr, ydata=sum1, marker='bo') return psf, psf_type