Example #1
0
    def sn_slider_update(self):
        """
        Update exposure when SNR slider is changed.
        """
        new_sn = pre_decode(self.snratio)
        new_expt = pre_decode(self.exptime)
        #new_sn = self.refs["snr_slider"].value
        #new_expt = self.refs["exp_slider"].value
        if self.verbose:
            print("calling sn_updater with sn = {} and exptime {}".format(
                new_sn, new_expt))

        self.exposure.unknown = "magnitude"
        self.exposure.exptime = new_expt  #pre_decode(self.exptime)
        self.exposure.snr = new_sn  #pre_decode(self.snratio)

        vmag = self.exposure.recover('magnitude')[4].value
        distance = pre_decode(self.distance)
        distmod = 5. * np.log10((distance.value + 1e-5) * 1e6) - 5.

        lmsource = self.refs["cmd_lim_source"]
        lmsource.data = {
            'mags': [distmod - vmag - 0.4],
            'maglabel': ["{:4.1f}".format(vmag)],
            'sn': ["{}".format(new_sn.value)],
            'x_mag': [3.8],
            'x_sn': [3.2]
        }  # the 0.4 is just for display purposes (text alignment)
Example #2
0
    def load(self):
        # Get the filename from the bokeh interface
        calcid = self.refs["load_filename"].value

        #Load the file
        code = self.load_file(calcid)

        if not code:  #everything went fine
            #Update the interface
            self.refs["update_save"].disabled = False
            self.current_save = calcid
            self.refs["exp_slider"].value = pre_decode(self.exptime).value
            self.refs["mag_slider"].value = pre_decode(
                self.renorm_magnitude).value
            self.refs["ap_slider"].value = pre_decode(self.aperture).value
            self.refs["snr_slider"].value = pre_decode(self.snratio).value
            temp = self.templates.index(self.spectrum_type)
            self.refs["template_select"].value = self.template_options[temp]
            self.controller(None, None, None)

        errmsg = [
            "Calculation ID {} loaded successfully.".format(calcid),
            "Calculation ID {} does not exist, please try again.".format(
                calcid),
            "Load unsuccessful; please contact the administrators.",
            "There was an error restoring the save state; please contact"
            " the administrators."
        ][code]
        if code == 0 and self.load_mismatch:
            errmsg += "<br><br><b><i>Load Mismatch Warning:</b></i> "\
                      "The saved model parameters did not match the " \
                      "parameter values saved for this tool. Saved " \
                      "model values were given priority."
        self.refs["load_message"].text = errmsg
Example #3
0
 def _print_initcon(self, verbose):
     if verbose: #These are our initial conditions
         print('Telescope diffraction limit: {}'.format(pre_decode(self.telescope.diff_limit_wavelength)))
         print('Telescope aperture: {}'.format(pre_decode(self.telescope.aperture)))
         print('Telescope temperature: {}'.format(pre_decode(self.telescope.temperature)))
         print('Pivot waves: {}'.format(nice_print(self.pivotwave)))
         print('Pixel sizes: {}'.format(nice_print(self.pixel_size)))
         print('AB mag zero points: {}'.format(nice_print(self.ab_zeropoint)))
         print('Quantum efficiency: {}'.format(nice_print(self.total_qe)))
         print('Aperture correction: {}'.format(nice_print(self.ap_corr)))
         print('Bandpass resolution: {}'.format(nice_print(self.bandpass_r)))
         print('Derived_bandpass: {}'.format(nice_print(self.derived_bandpass)))
         print('Detector read noise: {}'.format(nice_print(self.detector_rn)))
         print('Dark rate: {}'.format(nice_print(self.dark_current)))
Example #4
0
    def _update_exptime(self):
        """
        Calculate the exposure time to achieve the desired S/N for the 
        given SED.
        """

        self.camera._print_initcon(self.verbose)

        #We no longer need to check the inputs, since they are now tracked
        #attributes instead.

        #Convert JsonUnits to Quantities for calculations
        (_snr, _nexp) = self.recover('snr', 'n_exp')
        (_total_qe, _detector_rn,
         _dark_current) = self.recover('camera.total_qe', 'camera.detector_rn',
                                       'camera.dark_current')

        snr2 = -(_snr**2)
        fstar = self._fstar
        fsky = self.camera._fsky(verbose=self.verbose)
        Npix = self.camera._sn_box(self.verbose)
        thermal = pre_decode(self.camera.c_thermal(verbose=self.verbose))

        a = (_total_qe * fstar)**2
        b = snr2 * (_total_qe *
                    (fstar + fsky) + thermal + _dark_current * Npix)
        c = snr2 * _detector_rn**2 * Npix * _nexp

        texp = ((-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a)).to(u.s)

        #serialize with JsonUnit for transportation
        self._exptime = pre_encode(texp)

        return True  #completed successfully
Example #5
0
    def exposure_update(self):
        """
        Update the exposure when sliders are updated.
        """
        self.update_exposure_params()

        self.exposure.unknown = 'snr'
        self.exposure.exptime = pre_decode(self.exptime)

        new_snrs = self._derived_snrs
        etcsource = self.refs["cmd_etc_source"]
        mlsource = self.refs["cmd_mag_source"]

        etcsource.data = {
            "mags": mlsource.data["mags"],
            "snr": new_snrs,
            "snr_label": new_snrs.astype('|S4'),
            'x': np.full(5, 3.2).tolist(),
            'y': np.arange(-10.4, 10., 5., dtype=float).tolist()
        }

        if self.verbose:
            print("mag_values in exposure_update: {}".format(
                etcsource.data['y']))
            print("new_snrs in exposure_update: {}".format(
                etcsource.data['snr']))

        noise_scale_factor = int(
            10000. / new_snrs[1]
        )  # divide an number by the S/N at AB = 5 absolute - set up to make it come out right
        self.refs["noise_stream"].event(noise=int(noise_scale_factor))
Example #6
0
 def sed(self):
     """
     Return a spectrum, redshifted if necessary. We don't just store the 
     redshifted spectrum because pysynphot doesn't save the original, it 
     just returns a new copy of the spectrum with redshifted wavelengths.
     """
     sed = pre_decode(self._sed)
     z = self.recover('redshift')
     return pre_encode(sed.redshift(z))
Example #7
0
    def update_exposure(self):
        """
        Update the exposure's parameters and recalculate everything.
        """
        #We turn off calculation at the beginning so we can update everything
        #at once without recalculating every time we change something
        self.exposure.disable()

        #Update all the parameters
        self.exposure.n_exp = 3
        self.exposure.exptime = pre_decode(self.exptime)
        self.exposure.snr = pre_decode(self.snratio)
        self.exposure.sed_id = self.spectrum_type
        self.telescope.aperture = self.aperture
        self.exposure.renorm_sed(pre_decode(self.renorm_magnitude))

        #Now we turn calculations back on and recalculate
        self.exposure.enable()

        #Set the spectrum template
        self.spectrum_template = pre_decode(self.exposure.sed)
Example #8
0
    def update_exposure(self):
        """
        Update the exposure's parameters and recalculate everything.
        """
        #We turn off calculation at the beginning so we can update everything
        #at once without recalculating every time we change something

        #Update all the parameters
        self.telescope.aperture = self.aperture
        self.spectrograph.mode = self.grating
        self.exposure.exptime = pre_decode(self.exptime)
        self.exposure.redshift = pre_decode(self.redshift)
        self.exposure.sed_id = self.spectrum_type
        self.exposure.renorm_sed(pre_decode(self.renorm_magnitude),
                                 bandpass='******')
        #Now we turn calculations back on and recalculate
        self.exposure.enable(make_image=self.make_image,
                             photon_count=self.photon_count,
                             gain=self.EM_gain)
        #Set the spectrum template
        self.spectrum_template = pre_decode(self.exposure.sed)
Example #9
0
def nice_print(arr):
    """
    Utility to make the verbose output more readable.
    """
    
    arr = pre_decode(arr) #in case it's a JsonUnit serialization

    if isinstance(arr, u.Quantity):
        l = ['{:.2f}'.format(i) for i in arr.value]
    else:
        l = ['{:.2f}'.format(i) for i in arr]
    return ', '.join(l)
Example #10
0
 def recover(self, *args):
     """
     Since we are now using JsonUnits to handle Bokeh Server JSON problems,
     this is a convenience method to ease the pain of converting attributes back
     to Quantities so they can be used for calculation.
     """
     
     out = []
     
     for arg in args:
         attr = reduce(getattr, [self] + arg.split('.')) #for nested dot access
         out.append(pre_decode(attr))
     
     if len(out) == 1:
         return out[0]
     return out
Example #11
0
 def c_thermal(self, verbose=True):
     """
     Calculate the thermal emission counts for the telescope.
     """
     
     #Convert to Quantities for calculation.
     (bandpass, pivotwave, aperture, ota_emissivity, 
      total_qe, pixel_size) = self.recover('derived_bandpass', 'pivotwave', 
             'telescope.effective_aperture',  'telescope.ota_emissivity', 
             'total_qe', 'pixel_size')
     
     box = self._sn_box(verbose)
     
     bandwidth = bandpass.to(u.cm)
 
     h = const.h.to(u.erg * u.s) # Planck's constant erg s 
     c = const.c.to(u.cm / u.s) # speed of light [cm / s] 
 
     energy_per_photon = h * c / pivotwave.to(u.cm) / u.ph
 
     D = aperture.to(u.cm) # telescope diameter in cm 
     
     Omega = (pixel_size**2 * box * u.pix).to(u.sr)
     
     planck = pre_decode(self.planck)
     qepephot = total_qe * planck / energy_per_photon
     
     if verbose:
         print('Planck spectrum: {}'.format(nice_print(planck)))
         print('QE * Planck / E_phot: {}'.format(nice_print(qepephot)))
         print('E_phot: {}'.format(nice_print(energy_per_photon)))
         print('Omega: {}'.format(nice_print(Omega)))
 
     thermal = (ota_emissivity * planck / energy_per_photon * 
 			(np.pi / 4. * D**2) * total_qe * Omega * bandwidth )
     
     #serialize with JsonUnit for transportation
     return pre_encode(thermal) 
Example #12
0
    def _update_magnitude(self):
        """
        Calculate the limiting magnitude given the desired S/N and exposure
        time.
        """

        self.camera._print_initcon(self.verbose)

        #We no longer need to check the inputs, since they are now tracked
        #attributes instead.

        #Grab values for calculation
        (_snr, _exptime, _nexp) = self.recover('snr', 'exptime', 'n_exp')
        (f0, c_ap, D, dlam) = self.recover('camera.ab_zeropoint',
                                           'camera.ap_corr',
                                           'telescope.effective_aperture',
                                           'camera.derived_bandpass')
        (QE, RN, DC) = self.recover('camera.total_qe', 'camera.detector_rn',
                                    'camera.dark_current')

        exptime = _exptime.to(u.s)
        D = D.to(u.cm)
        fsky = self.camera._fsky(verbose=self.verbose)
        Npix = self.camera._sn_box(self.verbose)
        c_t = pre_decode(self.camera.c_thermal(verbose=self.verbose))

        snr2 = -(_snr**2)
        a0 = (QE * exptime)**2
        b0 = snr2 * QE * exptime
        c0 = snr2 * ((QE * fsky + c_t + Npix * DC) * exptime +
                     (RN**2 * Npix * _nexp))
        k = (-b0 + np.sqrt(b0**2 - 4. * a0 * c0)) / (2. * a0)

        flux = (4. * k) / (f0 * c_ap * np.pi * D**2 * dlam)

        self._magnitude = pre_encode(-2.5 * np.log10(flux.value) * u.mag('AB'))

        return True  #completed successfully
Example #13
0
    def crowding_limit(self, crowding_apparent_magnitude, distance):
        """
        Calculate the crowding limit.
        """
        aperture = pre_decode(self.aperture)

        g_solar = 4.487
        stars_per_arcsec_limit = 10. * (aperture / 2.4)**2  # (JD1)

        distmod = 5. * np.log10((distance + 1e-5) * 1e6) - 5.  #why this fudge?

        g = np.array(
            -self.dataframe.gmag
        )  # absolute magnitude in the g band - the -1 corrects for the sign flip in load_datasets (for plotting)
        g.sort(
        )  # now sorted from brightest to faintest in terms of absolute g magnitude
        luminosity = 10.**(-0.4 * (g - g_solar))
        total_luminosity_in_lsun = np.sum(luminosity)
        number_of_stars = np.full_like(
            g, 1.0
        )  # initial number of stars in each "bin" - a list of 10,000 stars

        total_absolute_magnitude = -2.5 * np.log10(
            total_luminosity_in_lsun) + g_solar
        apparent_brightness_at_this_distance = total_absolute_magnitude + distmod

        scale_factor = 10.**(-0.4 * (crowding_apparent_magnitude -
                                     apparent_brightness_at_this_distance))
        cumulative_number_of_stars = np.cumsum(
            scale_factor *
            number_of_stars)  # the cumulative run of luminosity in Lsun

        crowding_limit = np.interp(stars_per_arcsec_limit.value,
                                   cumulative_number_of_stars, g)

        return crowding_limit
Example #14
0
    def _update_snr(self):
        """
        Calculate the SNR for the given exposure time and SED.
        """

        self.camera._print_initcon(self.verbose)

        #We no longer need to check the inputs, since they are now tracked
        #attributes instead.

        #Convert JsonUnits to Quantities for calculations
        (_exptime, _nexp, n_bands) = self.recover('_exptime', 'n_exp',
                                                  'camera.n_bands')
        (_total_qe, _detector_rn,
         _dark_current) = self.recover('camera.total_qe', 'camera.detector_rn',
                                       'camera.dark_current')

        #calculate everything
        number_of_exposures = np.full(n_bands, _nexp)
        desired_exp_time = (np.full(n_bands, _exptime.value) *
                            _exptime.unit).to(u.second)
        time_per_exposure = desired_exp_time / number_of_exposures

        fstar = self._fstar
        signal_counts = _total_qe * fstar * desired_exp_time

        fsky = self.camera._fsky(verbose=self.verbose)
        sky_counts = _total_qe * fsky * desired_exp_time

        shot_noise_in_signal = np.sqrt(signal_counts)
        shot_noise_in_sky = np.sqrt(sky_counts)

        sn_box = self.camera._sn_box(self.verbose)

        read_noise = _detector_rn**2 * sn_box * number_of_exposures
        dark_noise = sn_box * _dark_current * desired_exp_time

        thermal = pre_decode(self.camera.c_thermal(verbose=self.verbose))

        thermal_counts = desired_exp_time * thermal
        snr = signal_counts / np.sqrt(signal_counts + sky_counts + read_noise +
                                      dark_noise + thermal_counts)

        if self.verbose:
            print('# of exposures: {}'.format(_nexp))
            print('Time per exposure: {}'.format(time_per_exposure[0]))
            print('Signal counts: {}'.format(nice_print(signal_counts)))
            print('Signal shot noise: {}'.format(
                nice_print(shot_noise_in_signal)))
            print('Sky counts: {}'.format(nice_print(sky_counts)))
            print('Sky shot noise: {}'.format(nice_print(shot_noise_in_sky)))
            print('Total read noise: {}'.format(nice_print(read_noise)))
            print('Dark current noise: {}'.format(nice_print(dark_noise)))
            print('Thermal counts: {}'.format(nice_print(thermal_counts)))
            print()
            print('SNR: {}'.format(snr))
            print('Max SNR: {} in {} band'.format(
                snr.max(), self.camera.bandnames[snr.argmax()]))

        #serialize with JsonUnit for transportation
        self._snr = pre_encode(snr)

        return True  #completed successfully
Example #15
0
 def renorm_sed(self, new_mag, bandpass='******'):
     sed = self.recover('_sed')
     self._sed = renorm_sed(sed, pre_decode(new_mag), bandpass=bandpass)
     self.calculate(make_image=False)