Esempio n. 1
0
def test_band_snr_norm(testing_spectrum, sampling):
    """Compared to wav snr norm."""
    wav, flux = testing_spectrum
    wav, flux = convolve_and_resample(
        wav, flux, vsini=1, R=100000, band="J", sampling=sampling
    )
    assert snrnorm.snr_constant_band(
        wav, flux, band="J", snr=100, sampling=sampling
    ) == snrnorm.snr_constant_wav(wav, flux, wav_ref=1.25, snr=100, sampling=sampling)

    assert snrnorm.snr_constant_band(
        wav, flux, band="J", snr=100, sampling=sampling
    ) != snrnorm.snr_constant_wav(wav, flux, wav_ref=1.24, snr=100, sampling=sampling)
def test_snr_normalization(desired_snr, band, testing_spectrum):
    """Test SNR after normalizing function is the desired value.

    Testing on middle of J band.
    """
    wav, flux = testing_spectrum
    band_mid = utils.band_middle(band)

    # Searching for the closest index to 1.25
    index_reference = np.searchsorted(wav, [band_mid])[0]
    snr_estimate = np.sqrt(
        np.sum(flux[index_reference - 1:index_reference + 2]))

    assert round(snr_estimate, 1) != desired_snr  # Assert SNR is not correct

    norm_const = snrnorm.snr_constant_band(wav,
                                           flux,
                                           snr=desired_snr,
                                           band=band)

    new_flux = flux / norm_const
    new_snr_estimate = np.sqrt(
        np.sum(new_flux[index_reference - 1:index_reference + 2]))

    assert round(new_snr_estimate, 0) == desired_snr
Esempio n. 3
0
def real_spec(request):
    band = request.param
    wav, flux = load_aces_spectrum([3900, 4.5, 0.0, 0])
    wav, flux = wav_selector(wav, flux, *band_limits(band))
    flux = flux / snr_constant_band(wav, flux, 100, band)
    atm = Atmosphere.from_band(band).at(wav)
    return wav, flux, atm.transmission
Esempio n. 4
0
def test_snr_normalization_constant(desired_snr, band, testing_spectrum):
    """Test snr_constant_band and snr_constant_wav produce same result."""
    wav, flux = testing_spectrum
    band_mid = utils.band_middle(band)

    assert snrnorm.snr_constant_band(
        wav, flux, band=band, snr=desired_snr
    ) == snrnorm.snr_constant_wav(wav, flux, band_mid, snr=desired_snr)
Esempio n. 5
0
def test_band_snr_norm_test_data():
    """Compared to wav snr norm."""
    # snr_constant_band
    star, band, vel, res = "M0", "J", 1.0, "100k"
    test_data = os.path.join(eniric.paths["resampled"],
                             resampled_template.format(star, band, vel, res))
    wav, flux = io.pdread_2col(test_data)

    assert snrnorm.snr_constant_band(
        wav, flux, band="J", snr=100) == snrnorm.snr_constant_wav(wav,
                                                                  flux,
                                                                  wav_ref=1.25,
                                                                  snr=100)

    assert snrnorm.snr_constant_band(wav, flux, band="J",
                                     snr=100) != snrnorm.snr_constant_wav(
                                         wav, flux, wav_ref=1.24, snr=100)
Esempio n. 6
0
def test_snr_constant_band_returns_mid_value_const(band):
    size = 100
    np.random.seed(40)
    flux = 500 * np.random.rand(
        size
    )  # To give a random spectrum (but consistent between tests)
    lim = utils.band_limits(band)
    wav = np.linspace(lim[0], lim[1], size)

    band_const = snrnorm.snr_constant_band(wav, flux, band=band)
    wav_const = snrnorm.snr_constant_wav(wav, flux, wav_ref=utils.band_middle(band))

    assert isinstance(band_const, float)
    assert isinstance(wav_const, float)
    assert band_const == wav_const  # Since band calls wave at midpoint
Esempio n. 7
0
def normalize_flux(
    flux: ndarray,
    id_string: str,
    new: bool = True,
    snr: Union[int, float] = 100.0,
    ref_band: str = "J",
    sampling: Union[int, float] = 3.0,
) -> ndarray:
    """Normalize flux to have SNR of 100 in middle of reference band.

    Parameters
    ----------
    flux: ndarray
        Photon flux.
    id_string: str
        Identifying string for spectra.
    new: bool default=True
        Choose between new and old constant for testing.
    snr: int, float default=100
        SNR to normalize to, .
    ref_band: str default="J"
        References band to normalize to.
    sampling: int or float
       Number of pixels per resolution element.

    Returns
    -------
    normalized_flux: ndarray
        Flux normalized to a S/N of SNR in the middle of the ref_band.

    """
    # print("Starting norm of {}".format(id_string))
    if new:
        if ref_band.upper() == "SELF":
            __, ref_band, __, __ = decompose_id_string(id_string)

        wav_ref, flux_ref = get_reference_spectrum(id_string, ref_band)
        norm_const = snr_constant_band(
            wav_ref, flux_ref, snr=snr, band=ref_band, sampling=sampling
        )
    else:
        if (ref_band.upper() != "J") or (snr != 100):
            raise ValueError("The old way does not work with these reference values.")
        norm_const = old_norm_constant(id_string) * 1e4  # Input flux offset

    print("{0:s} normalization constant = {1:f}".format(id_string, norm_const))

    return flux / norm_const
Esempio n. 8
0
def test_snr_normalization_logic(band):
    """Testing direct value.

    snr = sqrt(sum(3 pixels))
    const = (snr/ref_snr)**2
    if pixel value = 3 then  the normalization constant will be 1.
    """
    size = 100
    band = "K"
    lim = utils.band_limits(band)
    wav = np.linspace(lim[0], lim[1], size)
    flux = 3 * np.ones(size)
    band_const = snrnorm.snr_constant_band(wav, flux, snr=3, band=band)
    wav_const = snrnorm.snr_constant_wav(
        wav, flux, snr=3, wav_ref=(lim[0] + lim[1]) / 2
    )
    assert band_const == 1
    assert wav_const == 1
Esempio n. 9
0
def test_snr_constant_band_with_invalid_wavelength(wav, band):
    with pytest.raises(ValueError):
        snrnorm.snr_constant_band(wav, np.ones(50), band=band)
Esempio n. 10
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
Esempio n. 11
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="phoenix",
):
    """Precision and Quality for specific parameter set.

    Parameters
    ----------
    air: bool
        Get model in air wavelengths.
    model: str
        Name of synthetic library to use. (phoenix, btsettl).
    rv: float
        Radial velocity.

    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.
        The RV should maybe come 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_procs_minus_1,
            "normalize": True,
        }

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

    if model == "phoenix":
        # Full photon count spectrum
        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 ValueError(
            "Model name error in '{}'. Valid choices are 'phoenix and 'btsettl'"
            .format(model))

    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

    # Spectral Quality
    q = quality(wav_grid, sampled_flux)

    # 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)
    sampled_flux = sampled_flux / snr_normalize

    if ref_band == band:
        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:
    prec1 = rv_precision(wav_grid, sampled_flux, mask=None)

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

    # Precision as given by the third condition: M = T**2
    prec3 = 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, prec1, prec2, prec3]