def get_it_spectrum(opt): wl_lo = opt.channel.pipeline_params.wavrange_lo.val wl_hi = opt.channel.pipeline_params.wavrange_hi.val wl = opt.star.sed.wl planet_wl = opt.planet.sed.wl # CHANGE INTRODUCED # If the star is downsampled here it can cause inconsistencies in the representation of the source spectrum # Hence I err on the side of upsampling the planet spectrum to the star resolution, rather than downsampling # the star spectrum to the planet spectrum resolution. # The impact of this change on the final planet spectrum is minimal # R = wl/np.gradient((wl)) # R_planet = planet_wl/np.gradient((planet_wl)) # # select onyl wavelengths in range for channel # idx = np.argwhere((wl.value>= wl_lo) & (wl.value<= wl_hi)).T[0] # idx2 = np.argwhere((planet_wl.value>= wl_lo) & (planet_wl.value<= wl_hi)).T[0] # # rebin to lower resolution spectrum # if R_planet[idx2].min() < R[idx].min(): # opt.star.sed.rebin(planet_wl) # else: # opt.planet.sed.rebin(wl) opt.planet.sed.rebin(wl) # now make in-transit stellar spectrum star_sed_it = opt.star.sed.sed * (1 - opt.planet.sed.sed) opt.star.sed_it = Sed(opt.star.sed.wl, star_sed_it) return opt return opt
def getR(opt): #this needs updating disp = opt.channel.camera.dispersion.path.replace('__path__', opt.__path__) R_file = disp.replace('dispersion', 'R') dtmp = np.loadtxt(R_file, delimiter=',') wav = dtmp[..., 0] * u.um R = dtmp[..., 1] * u.dimensionless_unscaled R = np.interp(opt.x_wav_osr, wav, R, left=None, right=None) R = Sed(opt.x_wav_osr, R) return R
def zodical_light(opt): deg = opt.model_exosystem.ecliptic_lat.val.value wl = opt.x_wav_osr jexosim_msg('Zodi model initiated...\n', opt.diagnostics) jexosim_msg('Ecliptic latitude in deg: %s \n' % (deg), opt.diagnostics) deg = abs(deg) if deg >= 57.355: level = 1.0 else: level = -0.22968868 * (np.log10(deg + 1))**7 + 1.12162927 * (np.log10( deg + 1))**6 - 1.72338015 * (np.log10(deg + 1))**5 + 1.13119022 * ( np.log10(deg + 1) )**4 - 0.95684987 * (np.log10(deg + 1))**3 + 0.2199208 * (np.log10( deg + 1))**2 - 0.05989941 * (np.log10(deg + 1)) + 2.57035947 jexosim_msg('Zodi model coefficient... %s\n' % (level), opt.diagnostics) spectrum = level * (3.5e-14 * planck(wl, 5500 * u.K) + planck(wl, 270 * u.K) * 3.58e-8) sed = Sed(wl, spectrum) transmission = Sed(wl, np.ones(wl.size) * u.dimensionless_unscaled) zodi = [sed, transmission] return zodi
def emission_estimation(N, temp, emissivity, transmission): t_i = transmission.sed**(1. / N ) # estimate transmission of each optical surface for i in range(0, N): #loop through each surface i=0 to i = N-1 if i == 0: emission_sed = emissivity * planck(transmission.wl, temp) * t_i**(N - 1 - i) else: emission_sed = emission_sed + emissivity * planck( transmission.wl, temp) * t_i**(N - 1 - i) idx = np.argwhere(transmission.sed == 0) emission_sed[idx] = 0.0 * emission_sed.unit emission = Sed(transmission.wl, emission_sed) return emission
def sunshield_emission(opt): wl = opt.x_wav_osr # polynomial fit to publically available data z = [ -9.95238428e-15, 1.25072156e-12, -6.35949515e-11, 1.67141033e-09, -2.42822718e-08, 1.98344621e-07, -8.56711400e-07, 1.52392307e-06 ] r = 7 y = 0 for i in range(0, r + 1): y = y + z[i] * wl.value**(r - i) idx = np.argwhere(wl.value < 7) y[idx] = 0 y *= u.W / u.m**2 / u.um / u.sr sed = Sed(wl, y) return sed
def get_planet_spectrum(opt): fp_signal_it = opt.fp_signal_it[1::3, 1::3] fp_signal = opt.fp_signal[1::3, 1::3] rat = (1 - (fp_signal_it / fp_signal)) rat[np.isnan(rat)] = 0 cr_average = np.zeros(fp_signal.shape[1]) for i in range(fp_signal.shape[1]): slice = rat[:, i] idx = np.argwhere(slice > 0) slice = slice[idx] # wt = 1/slice # this is important to remove outliers idx = np.argwhere( abs(slice - np.median(slice)) > 0.01 * np.median(slice)).T[0] # sd = np.std(slice) # idx = np.argwhere(abs(slice-np.mean(slice) > sd)) slice = np.delete(slice, idx) # wt = 1/slice # if i == 200: # print (idx, 0.1*np.median(slice)) # plt.plot(slice, 'ro-') # # if i == 1760: # print (idx, 0.1*np.median(slice)) # plt.plot(slice, 'bo-') cr_average[i] = np.mean(slice) # cr_average[i] = np.sum(slice*wt)/ np.sum(wt) opt.planet.sed = Sed(opt.x_wav_osr[1::3], cr_average * u.dimensionless_unscaled) # remove values outside of the wavelength range of the channel idx = np.argwhere( opt.planet.sed.wl.value < opt.channel.pipeline_params.wavrange_lo.val - 0.5).T[0] opt.planet.sed.sed[idx] = 0 * u.dimensionless_unscaled idx = np.argwhere( opt.planet.sed.wl.value > opt.channel.pipeline_params.wavrange_hi.val + 0.5).T[0] opt.planet.sed.sed[idx] = 0 * u.dimensionless_unscaled idx = np.argwhere(opt.planet.sed.wl.value == 0).T[0] opt.planet.sed.sed[idx] = 0 * u.dimensionless_unscaled return opt.planet.sed
def optical_emission(opt): #telescope N = np.int(opt.common_optics.emissions.optical_surface.no_surfaces) temp = opt.common_optics.emissions.optical_surface.val emissivity = np.float( opt.common_optics.emissions.optical_surface.emissivity) opt.telescope_emission = emission_estimation(N, temp, emissivity, opt.telescope_transmission) jexosim_lib.sed_propagation(opt.telescope_emission, opt.channel_transmission) #channel N = np.int(opt.channel.emissions.optical_surface.no_surfaces) temp = opt.channel.emissions.optical_surface.val emissivity = np.float(opt.channel.emissions.optical_surface.emissivity) opt.channel_emission = emission_estimation(N, temp, emissivity, opt.channel_transmission) # combine emission = Sed(opt.channel_transmission.wl, opt.telescope_emission.sed + opt.channel_emission.sed) return emission
def run(opt): jexosim_msg('channel check0 : %s' % (opt.star.sed.sed.max()), opt.diagnostics) tr_ = np.array([1.] * len(opt.x_wav_osr)) * u.dimensionless_unscaled opt.channel.transmissions.optical_surface = opt.channel.transmissions.optical_surface if isinstance(opt.channel.transmissions.optical_surface, list) else \ [opt.channel.transmissions.optical_surface] for op in opt.channel.transmissions.optical_surface: dtmp = np.loadtxt(op.transmission.replace('__path__', opt.__path__), delimiter=',') tr = Sed(dtmp[:, 0] * u.um, dtmp[:, 1] * u.dimensionless_unscaled) tr.rebin(opt.x_wav_osr) tr_ *= tr.sed opt.channel_transmission = Sed(opt.x_wav_osr, tr_) opt.total_transmission = Sed( opt.channel_transmission.wl, opt.telescope_transmission.sed * opt.channel_transmission.sed) jexosim_lib.sed_propagation(opt.star.sed, opt.channel_transmission) jexosim_lib.sed_propagation(opt.star.sed_it, opt.channel_transmission) # apply QE and convert to electrons dtmp = np.loadtxt(opt.channel.detector_array.qe().replace( '__path__', opt.__path__), delimiter=',') qe = Sed(dtmp[:, 0] * u.um, dtmp[:, 1] * u.dimensionless_unscaled) qe.rebin(opt.x_wav_osr) PCE = Sed(opt.total_transmission.wl, opt.total_transmission.sed * qe.sed) TotTrans = Sed(opt.total_transmission.wl, opt.total_transmission.sed) opt.PCE = PCE.sed opt.TotTrans = TotTrans.sed jexosim_plot('PCE', opt.diagnostics, xdata=PCE.wl, ydata=PCE.sed) jexosim_plot('Total transmission not including QE', opt.diagnostics, xdata=TotTrans.wl, ydata=TotTrans.sed) opt.qe_spec = qe opt.Re = qe.sed * (qe.wl).to(u.m) / (const.c.value * const.h.value * u.m) opt.star.sed.sed *= opt.Re * u.electron / u.W / u.s opt.star.sed_it.sed *= opt.Re * u.electron / u.W / u.s jexosim_plot('channel star sed check', opt.diagnostics, xdata=opt.x_wav_osr, ydata=opt.star.sed.sed, marker='-') jexosim_msg('check 1.3 - Star sed max: %s' % (opt.star.sed.sed.max()), opt.diagnostics) jexosim_plot('Wavelength solution check -oversampled pixels', opt.diagnostics, xdata=opt.x_pix_osr, ydata=opt.x_wav_osr, marker='o-') jexosim_plot('Wavelength solution check -normal pixels', opt.diagnostics, xdata=opt.x_pix_osr[1::3], ydata=opt.x_wav_osr[1::3], marker='o-') opt.d_x_wav_osr = np.zeros_like(opt.x_wav_osr) idx = np.where(opt.x_wav_osr > 0.0) opt.d_x_wav_osr[idx] = np.gradient(opt.x_wav_osr[idx]) if np.any(opt.d_x_wav_osr < 0): opt.d_x_wav_osr *= -1.0 jexosim_plot('D x wav osr check', opt.diagnostics, xdata=opt.x_pix_osr, ydata=opt.d_x_wav_osr, marker='o') jexosim_plot('D x wav osr check 2', opt.diagnostics, xdata=opt.x_wav_osr, ydata=opt.d_x_wav_osr, marker='o') jexosim_msg("check 1.4: %s" % (opt.star.sed.sed.max()), opt.diagnostics) opt.planet_sed_original = copy.deepcopy(opt.planet.sed.sed) # opt.planet.sed.sed *= opt.star.sed.sed # opt.planet.sed.sed *= opt.d_x_wav_osr jexosim_msg("check 1.5: %s" % (opt.star.sed.sed.max()), opt.diagnostics) opt.star.sed.sed *= opt.d_x_wav_osr opt.star.sed_it.sed *= opt.d_x_wav_osr jexosim_msg("check 2: %s" % (opt.star.sed.sed.max()), opt.diagnostics) jexosim_plot('star sed check 2.0', opt.diagnostics, xdata=opt.x_wav_osr, ydata=opt.star.sed.sed, marker='-') return opt
def run(opt): opt.osf = np.int(opt.channel.simulation_factors.osf()) opt.offs = np.int(opt.channel.simulation_factors.pix_offs()) fpn = opt.channel.detector_array.array_geometry.val.split(',') opt.fpn = [int(fpn[0]), int(fpn[1])] opt.fp = np.zeros( (int(opt.fpn[0] * opt.channel.simulation_factors.osf.val), int(opt.fpn[1] * opt.channel.simulation_factors.osf.val))) opt.fp_signal = np.zeros( (int(opt.fpn[0] * opt.channel.simulation_factors.osf.val), int(opt.fpn[1] * opt.channel.simulation_factors.osf.val))) opt.fp_it = np.zeros( (int(opt.fpn[0] * opt.channel.simulation_factors.osf.val), int(opt.fpn[1] * opt.channel.simulation_factors.osf.val))) opt.fp_signal_it = np.zeros( (int(opt.fpn[0] * opt.channel.simulation_factors.osf.val), int(opt.fpn[1] * opt.channel.simulation_factors.osf.val))) opt.fp_delta = opt.channel.detector_pixel.pixel_size.val / opt.channel.simulation_factors.osf.val # opt.x_wav_osr, opt.x_pix_osr, opt.y_pos_osr = instrument_lib.usePoly(opt) if 'NIRISS' in opt.channel.name: # this is because d_x_wav_osr is not smooth with interp method opt.x_wav_osr, opt.x_pix_osr, opt.y_pos_osr = instrument_lib.usePoly( opt) else: opt.x_wav_osr, opt.x_pix_osr, opt.y_pos_osr = instrument_lib.useInterp( opt) opt.R = instrument_lib.getR(opt) jexosim_msg('tel check 1: %s' % (opt.star.sed.sed.max()), opt.diagnostics) opt.star_sed = copy.deepcopy(opt.star.sed) #copy of star flux at telescope opt.star_sed2 = copy.deepcopy( opt.star.sed) #copy of star flux at telescope opt.Aeff = 0.25 * np.pi * opt.common_optics.telescope_effective_diameter( )**2 opt.star.sed.sed *= opt.Aeff opt.star.sed_it.sed *= opt.Aeff jexosim_msg('tel check 2: %s' % (opt.star.sed.sed.max()), opt.diagnostics) tr_ = np.array([1.] * len(opt.x_wav_osr)) * u.dimensionless_unscaled opt.common_optics.transmissions.optical_surface = opt.common_optics.transmissions.optical_surface \ if isinstance(opt.common_optics.transmissions.optical_surface, list) \ else [opt.common_optics.transmissions.optical_surface] for op in opt.common_optics.transmissions.optical_surface: dtmp = np.loadtxt(op.transmission.replace('__path__', opt.__path__), delimiter=',') tr = Sed(dtmp[:, 0] * u.um, dtmp[:, 1] * u.dimensionless_unscaled) tr.rebin(opt.x_wav_osr) tr_ *= tr.sed opt.telescope_transmission = Sed(opt.x_wav_osr, tr_) if opt.diagnostics == 1: import matplotlib.pyplot as plt plt.figure('checking binning down of stellar spectrum') plt.plot(opt.star.sed.wl, opt.star.sed.sed, alpha=0.5) opt.star.sed.rebin(opt.x_wav_osr) opt.star.sed_it.rebin(opt.x_wav_osr) if opt.diagnostics == 1: plt.figure('checking binning down of stellar spectrum') plt.plot(opt.star.sed.wl, opt.star.sed.sed, 'r-') jexosim_msg('tel check 2a: %s' % (opt.star.sed.sed.max()), opt.diagnostics) opt.planet.sed.rebin(opt.x_wav_osr) jexosim_lib.sed_propagation(opt.star.sed, opt.telescope_transmission) jexosim_lib.sed_propagation(opt.star.sed_it, opt.telescope_transmission) jexosim_msg('tel check 3: %s' % (opt.star.sed.sed.max()), opt.diagnostics) dtmp = np.loadtxt(opt.channel.detector_array.quantum_yield().replace( '__path__', opt.__path__), delimiter=',') quantum_yield = Sed(dtmp[:, 0] * u.um, dtmp[:, 1] * u.dimensionless_unscaled) quantum_yield.rebin(opt.x_wav_osr) quantum_yield.sed = np.where( quantum_yield.sed == 0, 1, quantum_yield.sed ) # avoids quantum yield of 0 due to interpolation issue opt.quantum_yield = quantum_yield return opt
def sanity_check(opt): wl = opt.x_wav_osr[1::3] del_wl = abs(np.gradient(wl)) # del_wl = opt.d_x_wav_osr[1::3]*3 star_spec = opt.star_sed star_spec.rebin(wl) T = opt.planet.planet.star.T trans_sed = opt.total_transmission.sed * u.dimensionless_unscaled trans = Sed(opt.total_transmission.wl, trans_sed) trans.rebin(wl) QE = opt.qe_spec QE.rebin(wl) quantum_yield = opt.quantum_yield quantum_yield.rebin(wl) Rs = (opt.planet.planet.star.R).to(u.m) D = (opt.planet.planet.star.d).to(u.m) n = quantum_yield.sed * trans.sed * del_wl * np.pi * planck(wl, T) * ( Rs / D)**2 * opt.Aeff * QE.sed / (const.h.value * const.c.value / (wl * 1e-6)) n2 = quantum_yield.sed * trans.sed * del_wl * star_spec.sed * opt.Aeff * QE.sed / ( const.h.value * const.c.value / (wl * 1e-6)) jex_sig = quantum_yield.sed * opt.fp_signal[1::3, 1::3].sum(axis=0) n = np.where(n < 0, 0, n) n2 = np.where(n2 < 0, 0, n2) R = opt.pipeline.pipeline_R.val del_wav = wl / R opt.exp_sig = opt.t_int * del_wav * jex_sig / del_wl if opt.diagnostics == 1: plt.figure('sanity check 1 - check focal plane signal') if 'NIRISS' in opt.channel.name: plt.plot(wl[:-10], n[:-10], 'b^', label='BB check') plt.plot( wl[:-10], n2[:-10], 'r+', label='Phoenix check' ) # not convolved with PSF unlike JexoSim, so peak may be higher else: plt.plot(wl, n, 'b^', label='BB check') plt.plot( wl, n2, 'r+', label='Phoenix check' ) # not convolved with PSF unlike JexoSim, so peak may be higher plt.plot(wl, jex_sig, 'gx', label='JexoSim') plt.ylabel('e/s/pixel col') plt.xlabel('pixel col wavelength (microns)') plt.legend(loc='best') ################ plt.figure( 'sanity check 2 - expected final star signal in R bin of %s' % ((R))) plt.plot(wl, opt.exp_sig) plt.ylabel('e/bin') plt.xlabel('Wavelength (microns)') ################ plt.figure( 'sanity check 3 - expected photon noise (sd) in R bin of %s' % ((R))) plt.plot(wl, opt.exp_sig**0.5) plt.ylabel('e/bin') plt.xlabel('Wavelength (microns)')