Beispiel #1
0
def optimize_filter(low_wave, high_wave, **kwargs):
    """
    Optimizes out-of-band filters based on the input bandpass
    
    ---
    Inputs:
    low_wave = Lower side of bandpass (units consistent with length)
    high_wave = High side of the bandpass

    Option inputs:
    
    qe_band = Which QE file to use (Default is "1")
    target_ratio = Out-of-band to in-band counts (0.5)
    blue_filter = If there's an asymmetric filter, apply this to everything blue-ward
        of the low_wave

    """
    from tdsat_telescope import load_qe, load_reflectivity
    from apply_transmission import apply_trans
    from zodi import load_zodi
    import astropy.units as ur

    # Check if the inputs make sense
    assert low_wave.unit.is_equivalent(
        ur.m), "Low-side wavelength does not have unit of length"
    assert high_wave.unit.is_equivalent(
        ur.m), "High-side wavelength does not have unit of length"

    qe_band = kwargs.pop('qe_band', 1)
    target_ratio = kwargs.pop('target_ratio', 0.5)
    blue_filter = kwargs.pop('blue_filter', False)
    diag = kwargs.pop('diag', False)
    # Load zodiacal background. Note that the out-of-band Zodi dominates over the
    # atmospheric lines (which are present here). Using the lowest Zodi background
    # represents the "worst case".
    zodi = load_zodi()

    # Load reflectivity and QE curves:
    ref_wave, reflectivity = load_reflectivity()
    qe_wave, qe = load_qe(band=qe_band)

    # Apply these to the Zodi spectrum:
    ref_flux = apply_trans(zodi['wavelength'], zodi['flux'], ref_wave,
                           reflectivity / 100.)
    qe_flux = apply_trans(zodi['wavelength'], ref_flux, qe_wave, qe)

    # Make a "standard" red filter:
    rejection = 1.0
    red_filter = make_red_filter(zodi['wavelength'],
                                 low_wave=low_wave,
                                 high_wave=high_wave,
                                 rejection=rejection,
                                 blue_filter=blue_filter,
                                 diag=diag)

    band_flux = apply_trans(zodi['wavelength'], qe_flux, zodi['wavelength'],
                            red_filter)

    # Get the in-band, out-of-band ratio:

    in_band = band_flux[(zodi['wavelength'] > low_wave)
                        & (zodi['wavelength'] < high_wave)].sum()

    out_of_band = band_flux[(
        (zodi['wavelength'] < low_wave) | (zodi['wavelength'] > high_wave))
                            & (zodi['wavelength'] < 1 * ur.micron)].sum()

    # Comput ratio:
    ratio = out_of_band / in_band
    target_rejection = (rejection * (target_ratio / ratio)).value

    if diag:
        print()
        print('Optimize filter diagnostics:')
        print('Low wave:{}'.format(low_wave))
        print('High wave:{}'.format(high_wave))
        print('Blue filter? {}'.format(blue_filter))
        print('Target ratio: {}'.format(target_ratio))
        print('Target rejection: {}'.format(target_rejection))
        print()
    return target_rejection
Beispiel #2
0
def outofband_bgd_sky_rate(**kwargs):
    """
    Loads the zodiacal background and normalizes it at 500 nm to a particular
    flux level (low_zodi = 77, med_zodi = 300, high_zodi = 6000), which are taken from
    a paper (to be dropped here later).
    Calculates out-of-band contribution to the background (up to a maximum wavelength, default 900 nm).
    Out-of-band rejection efficiency is folded in later, in the snr calculation.
        
    Optional Inputs (defaults):
    band = Bandpass (180-220)*ur.nm
    diameter=Telescope Diameter (21*ur.cm)
    pixel_size=Angular size of the pixel (6*ur.arcsec)
    max_wav = cutoff wavelength of detector (900*ur.nm)
    diag = Diagnostics toggle (False)
    
    low_zodi = (True)
    medium_zodi = (False)
    high_zodi = (False)
    
    
    Returns NumPh, NumElectrons, each of which are ph / cm2 / pixel and e- / cm2 / pixel
 
    
    """

    import astropy.units as ur
    import astropy.constants as cr
    import numpy as np
    from zodi import load_zodi

    # Set up units here for flux conversion below
    fλ_unit = ur.erg / ur.cm**2 / ur.s / ur.Angstrom  # Spectral radiances per Hz or per angstrom
    fλ_density_unit = fλ_unit / (ur.arcsec * ur.arcsec)

    diag = kwargs.pop('diag', False)

    pixel_size = kwargs.pop('pixel_size', 6 * ur.arcsec)
    pixel_area = pixel_size**2

    diameter = kwargs.pop('diameter', 21. * ur.cm)
    Area_Tel = np.pi * (diameter.to(ur.cm) * 0.5)**2
    max_wav = kwargs.pop('max_wav', 900. * ur.nm)

    low_zodi = kwargs.pop('low_zodi', True)
    med_zodi = kwargs.pop('med_zodi', False)
    high_zodi = kwargs.pop('high_zodi', False)

    band = kwargs.pop('band', [180, 220] * ur.nm)
    bandpass = np.abs(band[1] - band[0])

    effective_wavelength = (np.mean(band)).to(ur.AA)
    ph_energy = (cr.h.cgs * cr.c.cgs / effective_wavelength.cgs).to(ur.eV)

    elec_per_eV = 1 / (3.6 * ur.eV)  # per electron for Si

    #     ABmag = 20*ur.ABmag # Just a place holder here
    #     F_λ = ABmag.to(fλ_unit, equivalencies=ur.spectral_density(λ_mid)) # Already converts to flux at this midpoint

    if low_zodi:
        zodi_level = 77
    if med_zodi:
        zodi_level = 300
    if high_zodi:
        zodi_level = 6000

    zodi = load_zodi(scale=zodi_level)

    ctr = 0
    flux_density = 0
    for ind, wv in enumerate(zodi['wavelength']):
        if ((wv >= band[0].to(ur.AA).value) & (wv <= band[1].to(ur.AA).value) |
            (wv >= max_wav.to(ur.AA).value)):
            continue
        ctr += 1
        flux_density += zodi['flux'][ind]

    # Effective flux density in the band, per arcsecond:
    flux_density /= float(ctr)
    fden = flux_density.to(fλ_density_unit)

    outofbandpass = np.abs(max_wav - zodi['wavelength'][0] * ur.AA) - bandpass

    ReceivedPower = (outofbandpass.to(ur.AA) * fden * Area_Tel *
                     pixel_area).to(ur.eV / ur.s)
    NumPhotons = ReceivedPower / ph_energy  # Number of photons

    NumPhotons = NumPhotons

    ElectronsPerPhoton = (ph_energy.to(ur.eV)) * elec_per_eV

    NumElectrons = ReceivedPower * elec_per_eV

    if diag:
        print('')
        print('Out of band Background Computation Integrating over Pixel Area')
        print('Telescope diameter: {}'.format(diameter))
        print('Telescope aperture: {}'.format(Area_Tel))
        print('Fλ total per arcsec2 {}'.format(fden))
        print('Fλ ABmag per pixel {}'.format(
            (fden * pixel_area).to(
                ur.ABmag,
                equivalencies=ur.spectral_density(effective_wavelength))))
        print('Bandpass: {}'.format(bandpass))
        print('Detector cutoff wavelength: {}'.format(max_wav))
        print('Collecting Area: {}'.format(Area_Tel))
        print('Pixel Area: {}'.format(pixel_area))
        print('Photons {}'.format(NumPhotons))

    return NumPhotons, NumElectrons
Beispiel #3
0
def bgd_sky_qe_rate(**kwargs):
    """
    Loads the zodiacal background and normalizes it at 500 nm to a particular
    flux level (low_zodi = 77, med_zodi = 300, high_zodi = 6000).
    
    See the docstring for load_zodi in zodi.py 
        
    Optional Inputs (defaults):
    band = Bandpass (180-220)*ur.nm
    diameter=Telescope Diameter (21*u.cm)
    pixel_size=Angular size of the pixel (6*ur.arcsec)
    rejection = Out of band rejection (1e-3)
    diag = Diagnostics toggle (False)
    
    low_zodi = (True)
    medium_zodi = (False)
    high_zodi = (False)
    
    qe_band = Whivch QE curve to us (1 --> 180-220 nm, 2-->260-300 nm)
    blue_filter = Apply blue_side filter (False)
    
    
    Returns bgd_rate which is ph / s / pixel 
    
    """

    import astropy.units as ur
    import astropy.constants as cr
    import numpy as np
    from zodi import load_zodi, wavelength_to_energy
    from apply_transmission import apply_trans
    from tdsat_telescope import load_qe, load_reflectivity, load_redfilter, apply_filters
    from duet_filters import make_red_filter, optimize_filter

    # Set up units here for flux conversion below
    #    fλ_unit = ur.erg/ur.cm**2/ur.s / ur.Angstrom # Spectral radiances per Hz or per angstrom
    #    fλ_density_unit = fλ_unit / (ur.arcsec *ur.arcsec)

    diag = kwargs.pop('diag', False)

    pixel_size = kwargs.pop('pixel_size', 6 * ur.arcsec)
    pixel_area = pixel_size**2

    diameter = kwargs.pop('diameter', 21. * ur.cm)
    Area_Tel = np.pi * (diameter.to(ur.cm) * 0.5)**2

    low_zodi = kwargs.pop('low_zodi', True)
    med_zodi = kwargs.pop('med_zodi', False)
    high_zodi = kwargs.pop('high_zodi', False)

    band = kwargs.pop('band', [180, 220] * ur.nm)
    bandpass = np.abs(band[1] - band[0])

    qe_band = kwargs.pop('qe_band', 1)
    blue_filter = kwargs.pop('blue_filter', False)

    filter_target = kwargs.pop('filter_target', 0.5)

    real_red = kwargs.pop('real_red', False)

    #    effective_wavelength = (np.mean(band)).to(ur.AA)
    #    ph_energy = (cr.h.cgs * cr.c.cgs / effective_wavelength.cgs).to(ur.eV)

    # Specified from Kristin. The highest Zodi that we hit is actually only 900
    # (down from 6000 in previous iterations) sine any closer to the Sun we violate
    # our Sun-angle constraints.

    if low_zodi:
        zodi_level = 77
    if med_zodi:
        zodi_level = 165
    if high_zodi:
        zodi_level = 900

    zodi = load_zodi(scale=zodi_level)

    wave = zodi['wavelength']
    flux = zodi['flux']

    if real_red:
        band_flux = apply_filters(zodi['wavelength'],
                                  zodi['flux'],
                                  band=qe_band,
                                  diag=diag,
                                  **kwargs)
    else:

        # Make the red filter
        low_wave = band[0]
        high_wave = band[1]
        rejection = optimize_filter(low_wave,
                                    high_wave,
                                    target_ratio=filter_target,
                                    blue_filter=blue_filter)

        red_trans = make_red_filter(wave,
                                    rejection=rejection,
                                    high_wave=high_wave,
                                    low_wave=low_wave,
                                    blue_filter=blue_filter)
        red_wave = wave
        # Load reflectivity and QE curves:
        ref_wave, reflectivity = load_reflectivity()
        qe_wave, qe = load_qe(band=qe_band)

        # Apply reflectivity and QE to the Zodi spectrum:
        ref_flux = apply_trans(zodi['wavelength'], zodi['flux'], ref_wave,
                               reflectivity / 100.)
        qe_flux = apply_trans(zodi['wavelength'], ref_flux, qe_wave, qe)

        # Apply red filter
        band_flux = apply_trans(wave, qe_flux, red_wave, red_trans)

    # Assume bins are the same size:
    de = wave[1] - wave[0]
    # Convert to more convenient units:
    ph_flux = ((de * band_flux).cgs).to(1 / ((ur.cm**2 * ur.arcsec**2 * ur.s)))
    fluence = ph_flux.sum()

    BgdRatePerPix = pixel_area * fluence * Area_Tel

    if diag:
        print('Background Computation Integrating over Pixel Area')
        print('Telescope diameter: {}'.format(diameter))
        print('Collecting Area: {}'.format(Area_Tel))
        print('Band: {}'.format(band))
        print('Bandpass: {}'.format(bandpass))
        print()
        #        print('Out-of-band rejection: {}'.format(rejection))
        #        print('Apply blue filter? {}'.format(blue_filter))
        print()
        print('Pixel Area: {}'.format(pixel_area))
        print()
        print('Background fluence per arcsec2 {}'.format(fluence))
        print('Rate {}'.format(BgdRatePerPix))

    return BgdRatePerPix