Ejemplo n.º 1
0
def test_if_doppler_shift_changes_quality(testing_spectrum, rv):
    wavelength, flux_ = testing_spectrum[0], testing_spectrum[1]
    wmin_, wmax_ = 2.1, 2.3
    m1 = (wavelength < wmax_ + 0.2) * (wavelength > wmin_ - 0.2)
    # shorten spectra
    wavelength, flux_ = wavelength[m1], flux_[m1]

    mask = (wavelength < wmax_) * (wavelength > wmin_)
    wave = wavelength[mask]
    flux = flux_[mask]
    q1 = quality(wave, flux)

    wav2 = doppler_shift_wav(wavelength, rv)
    mask2 = (wav2 < wmax_) * (wav2 > wmin_)
    wav2 = wav2[mask2]
    flux2 = flux_[mask2]
    q2 = quality(wav2, flux2)
    assert q1 != q2

    flux3 = doppler_shift_flux(wavelength, flux_, rv, new_wav=wave)
    q3 = quality(wave, flux3)
    assert len(wave) == len(flux3)
    assert q1 != q3
    # There are differences due to interpolation
    assert q2 != q3
Ejemplo n.º 2
0
def test_quality_independent_of_units(test_spec, wav_unit, flux_unit):
    """Quality should be returned as unitless (not a quantity)."""
    wave = test_spec[0] * wav_unit
    flux = test_spec[1] * flux_unit
    q = quality(wave, flux)

    assert not isinstance(q, Quantity)
    assert isinstance(q, float)
    assert not hasattr(q, "__len__")  # assert value is a scalar
Ejemplo n.º 3
0
def test_quality_independent_of_flux_level(scale):
    """Q of a spectrum is independent of flux level."""
    wavelength = np.arange(100)
    flux = np.random.random(100)
    assert np.allclose(quality(wavelength, flux),
                       quality(wavelength, flux * scale))
Ejemplo n.º 4
0
def do_analysis(
    star_params,
    vsini: float,
    R: float,
    band: str,
    sampling: float = 3.0,
    conv_kwargs=None,
    snr: float = 100.0,
    ref_band: str = "J",
    rv: float = 0.0,
    air: bool = False,
    model: str = "aces",
    verbose: bool = False,
) -> Tuple[Quantity, ...]:
    """Calculate RV precision and Quality for specific parameter set.

    Parameters
    ----------
    star_param:
        Stellar parameters [temp, logg, feh, alpha] for phoenix model libraries.
    vsini: float
       Stellar equatorial rotation.
    R: float
        Instrumental resolution.
    band: str
        Spectral band.
    sampling: float (default=False)
        Per pixel sampling (after convolutions)
    conv_kwargs: Dict (default=None)
        Arguments specific for the convolutions,
        'epsilon', 'fwhm_lim', 'num_procs', 'normalize', 'verbose'.
    snr: float (default=100)
        SNR normalization level. SNR per pixel and the center of the ref_band.
    ref_band: str (default="J")
        Reference band for SNR normalization.
    rv: float
        Radial velocity in km/s (default = 0.0).
    air: bool
        Get model in air wavelengths (default=False).
    model: str
        Name of synthetic library (aces, btsettl) to use. Default = 'aces'.
    verbose:
        Enable verbose (default=False).

    Returns
    -------
    q: astropy.Quality
     Spectral quality.
    result_1: astropy.Quality
        RV precision under condition 1.
    result_2 : astropy.Quality
        RV precision under condition 2.
    result_3: astropy.Quality
        RV precision under condition 3.

    Notes
    -----
        We apply the radial velocity doppler shift after
            - convolution (rotation and resolution)
            - resampling
            - SNR normalization.

        in this way the RV only effects the precision due to the telluric mask interaction.
        Physically the RV should be applied between the rotational and instrumental convolution
        but we assume this effect is negligible.

    """
    if conv_kwargs is None:
        conv_kwargs = {
            "epsilon": 0.6,
            "fwhm_lim": 5.0,
            "num_procs": num_cpu_minus_1,
            "normalize": True,
            "verbose": verbose,
        }

    if ref_band.upper() == "SELF":
        ref_band = band

    model = check_model(model)

    if model == "aces":
        wav, flux = load_aces_spectrum(star_params, photons=True, air=air)
    elif model == "btsettl":
        wav, flux = load_btsettl_spectrum(star_params, photons=True, air=air)
    else:
        raise Exception("Invalid model name reached.")

    wav_grid, sampled_flux = convolve_and_resample(wav, flux, vsini, R, band,
                                                   sampling, **conv_kwargs)

    # Doppler shift
    try:
        if rv != 0:
            sampled_flux = doppler_shift_flux(wav_grid, sampled_flux, vel=rv)
    except Exception as e:
        print("Doppler shift was unsuccessful")
        raise e

    # Scale normalization for precision
    wav_ref, sampled_ref = convolve_and_resample(wav, flux, vsini, R, ref_band,
                                                 sampling, **conv_kwargs)
    snr_normalize = snr_constant_band(wav_ref,
                                      sampled_ref,
                                      snr=snr,
                                      band=ref_band,
                                      sampling=sampling,
                                      verbose=verbose)
    sampled_flux = sampled_flux / snr_normalize

    if (ref_band == band) and verbose:
        mid_point = band_middle(ref_band)
        index_ref = np.searchsorted(
            wav_grid,
            mid_point)  # searching for the index closer to 1.25 micron
        snr_estimate = np.sqrt(
            np.sum(sampled_flux[index_ref - 1:index_ref + 2]))
        print(
            "\tSanity Check: The S/N at {0:4.02} micron = {1:4.2f}, (should be {2:g})."
            .format(mid_point, snr_estimate, snr))

    # Load Atmosphere for this band.
    atm = Atmosphere.from_band(band=band, bary=True).at(wav_grid)
    assert np.allclose(atm.wl,
                       wav_grid), "The atmosphere does not cover the wav_grid"

    # Spectral Quality/Precision
    q = quality(wav_grid, sampled_flux)

    # Precision given by the first condition:
    result_1 = rv_precision(wav_grid, sampled_flux, mask=None)

    # Precision as given by the second condition
    result_2 = rv_precision(wav_grid, sampled_flux, mask=atm.mask)

    # Precision as given by the third condition: M = T**2
    result_3 = rv_precision(wav_grid, sampled_flux, mask=atm.transmission**2)

    # Turn quality back into a Quantity (to give it a .value method)
    q = q * u.dimensionless_unscaled
    return q, result_1, result_2, result_3