Exemplo n.º 1
0
def test_Atmosphere_band_select():
    """Small test to check band selection."""
    band = "K"  # "K": (2.07, 2.35),

    atm = Atmosphere([2.0, 2.1, 2.2, 2.3, 2.4, 2.5],
                     np.arange(6),
                     std=None,
                     mask=[1, 0, 0, 1, 1, 0])
    atm2 = atm.band_select(band)

    assert np.allclose(atm2.wl, [2.1, 2.2, 2.3])
    assert np.allclose(atm2.mask, [0, 0, 1])
Exemplo n.º 2
0
def test_atmosphere_masking(trans, percent):
    cutoff = 1 - (percent / 100.0)

    assume(np.any(np.array(trans) < cutoff))
    assume(np.any(np.array(trans) >= cutoff))

    atmos = Atmosphere(wavelength=np.arange(len(trans)), transmission=trans)
    org_mask = atmos.mask
    atmos.mask_transmission(percent)

    assert np.any(atmos.mask != org_mask)
    assert np.all(atmos.transmission[atmos.mask] >= cutoff)
    assert np.all(atmos.transmission[~atmos.mask] < cutoff)
Exemplo n.º 3
0
def test_atmosphere_class_nomask(wave, transmission):
    atmos = Atmosphere(wave, transmission)
    assert np.all(atmos.wl == wave)
    assert np.all(atmos.transmission == transmission)
    assert np.all(atmos.mask == 1)
    assert len(atmos.mask) == len(atmos.transmission)
    assert atmos.mask.dtype == np.bool
Exemplo n.º 4
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
Exemplo n.º 5
0
def test_atmosphere_class_turns_lists_to_arrays(wave, transmission, std, mask):
    atmos = Atmosphere(wave, transmission, mask, std)
    assert isinstance(atmos.wl, np.ndarray)
    assert isinstance(atmos.transmission, np.ndarray)
    assert isinstance(atmos.std, np.ndarray)
    assert isinstance(atmos.mask, np.ndarray)
    assert atmos.mask.dtype == np.bool
Exemplo n.º 6
0
def test_from_band_is_a_constructor(band):
    """This is testing loading files using from_band method."""
    atm = Atmosphere.from_band(band)

    min_wl, max_wl = band_limits(band)
    assert isinstance(atm, Atmosphere)
    assert np.all(atm.wl <= max_wl * 1.01)
    assert np.all(atm.wl >= min_wl * 0.99)
Exemplo n.º 7
0
def test_atmosphere_class(wave, transmission, std, mask):
    atmos = Atmosphere(np.array(wave),
                       np.array(transmission),
                       np.array(mask),
                       std=np.array(std))
    assert np.all(atmos.wl == wave)
    assert np.all(atmos.transmission == transmission)
    assert np.all(atmos.mask == mask)
    assert np.all(atmos.std == std)
    assert atmos.mask.dtype == np.bool
def main(bands: Optional[List[str]] = None, verbose: bool = False) -> None:
    """Preform the barycentric shifting of atmosphere masks and saves result.

    This saves time in the precision determination code.

    Parameters
    ----------
    bands: list of str
        Wavelength bands to perform barycenter shifts on. Default is all bands.

    """
    if (bands is None) or ("ALL" in bands):
        bands_ = config.bands["all"]
    else:
        bands_ = bands

    for band in bands_:
        unshifted_atmmodel = join(
            config.pathdir,
            config.paths["atmmodel"],
            "{0}_{1}.dat".format(config.atmmodel["base"], band),
        )
        if verbose:
            print("Reading atmospheric model...", unshifted_atmmodel)

        atm = Atmosphere.from_file(unshifted_atmmodel)

        if verbose:
            print("Calculating impact of Barycentric movement on mask...")
        org_mask = atm.mask
        masked_before = np.sum(org_mask)
        atm.barycenter_broaden(consecutive_test=True)

        masked_after = np.sum(atm.mask)
        if verbose:
            print("Masked fraction before = {0:0.03f}".format(
                (len(org_mask) - masked_before) / len(org_mask)))
            print("Masked fraction after = {0:0.03f}".format(
                (len(atm.mask) - masked_after) / len(atm.mask)))

        shifted_atmmodel = unshifted_atmmodel.replace(".dat", "_bary.dat")
        if verbose:
            print("Saving doppler-shifted atmosphere model to {}".format(
                shifted_atmmodel))

        header = ["# atm_wav(nm)", "atm_flux", "atm_std_flux", "atm_mask"]
        atm.to_file(fname=shifted_atmmodel, header=header, fmt="%11.8f")

    if verbose:
        print("Finished barycentric shifting of atmosphere masks")
Exemplo n.º 9
0
def test_weights_clumping_grad(testing_spectrum, grad_flag, band):
    # Test masked clumping verse weight mask with new gradients
    # Test on an actual spectrum to check sizes of difference
    wav, flux = testing_spectrum
    atm = Atmosphere.from_band(band)
    mask = np.ones_like(wav)
    mask = atm.at(wav).mask

    clumped = RVprec_calc_masked(wav, flux, mask=mask, grad=grad_flag)
    weighted = RVprec_calc_weights_masked(wav, flux, mask=mask, grad=grad_flag)

    # They are not exactly the same by are within a specific percentage.
    ratio = (weighted.value - clumped.value) / clumped.value

    if grad_flag:
        # The difference for the new gradient is smaller.
        assert abs(ratio) < 0.008
    else:
        assert abs(ratio) < 0.04
    assert clumped.unit == weighted.unit
Exemplo n.º 10
0
def sliced_atmmodel_default_mask(request, atm_model):
    """To do own masking. Sliced in different places."""
    lower, upper = request.param  # slice limits
    atm = Atmosphere.from_file(atm_model)
    return atm[int(lower) : int(upper)]
Exemplo n.º 11
0
def atmosphere_fixture(request, atm_model):
    percent_cutoff = request.param
    atm = Atmosphere.from_file(atm_model)
    atm.mask_transmission(percent_cutoff)
    return atm
Exemplo n.º 12
0
def main(
    model: str = atmmodel,
    bands: Optional[List[str]] = None,
    new_name: Optional[str] = None,
    data_dir: Optional[str] = None,
    rv_extend: float = 100,
    cutoff_depth: float = 2.0,
):
    """Split the large atmospheric model transmission spectra into the separate bands.

    Keeps wavelength of atmosphere model as nanometers.

    Parameters
    ----------
    model: str
        Telluric model file to load. It has columns wavelength, flux, std_flux, mask.
    bands: list[str]
        List bands to split model into separate files.
    new_name: str
        New file name base.
    data_dir: Optional[str]
        Directory for results. Can also be given in config.yaml "paths:atmmodel:"...
    rv_extend: float (positive) (default 100)
        Rv amount to extend wavelength range of telluric band. To later apply barycenter shifting.
    cutoff_depth: float
       Telluric line depth cutoff. Default = 2%.
    """
    if (bands is None) or ("ALL" in bands):
        bands_ = eniric.bands["all"]
    else:
        bands_ = bands

    if new_name is None:
        new_name = model.split(".")[0]
    if data_dir is None:
        data_dir_ = eniric.paths["atmmodel"]
    else:
        data_dir_ = str(data_dir)

    model_name = join(data_dir_, model)

    # If trying to obtain the provided model extract from and it doesn't yet exist
    # extract from tar.gz file. (Extracted it is 230 MB which is to large for Git)
    if "Average_TAPAS_2014.dat" == atmmodel:
        if not os.path.exists(model_name):
            print("Unpacking Average_TAPAS_2014.dat.tar.gz...")
            import tarfile

            with tarfile.open(str(model_name) + ".tar.gz", "r") as tar:
                tar.extractall(data_dir_)
            print("Unpacked")
    print("Loading from_file {0}".format(model_name))
    atm = Atmosphere.from_file(model_name)

    # Return value from saving each band
    write_status = np.empty_like(bands_, dtype=int)

    for i, band in enumerate(bands_):
        print("Starting {0}".format(band))
        filename_band = "{0}_{1}.dat".format(new_name, band)
        band_min, band_max = band_limits(band)

        # * 1000 to convert into km/s
        band_min = doppler_shift_wav(band_min, -rv_extend)
        band_max = doppler_shift_wav(band_max, rv_extend)

        split_atm = atm.wave_select(band_min, band_max)

        # Apply telluric line mask
        atm.mask_transmission(depth=cutoff_depth)

        # Save the result to file
        filename = join(data_dir_, filename_band)
        header = ["# atm_wav(nm)", "atm_flux", "atm_std_flux", "atm_mask"]
        print("Saving to_file {}".format(filename))
        write_status[i] = split_atm.to_file(filename, header=header, fmt="%11.8f")
    print("Done Splitting")

    return np.sum(write_status)  # If any extracts fail they will turn up here.
Exemplo n.º 13
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]
Exemplo n.º 14
0
def calculate_prec(
    spectral_types,
    bands,
    vsini,
    resolution,
    sampling,
    plot_atm=False,
    plot_ste=False,
    plot_flux=True,
    paper_plots=True,
    rv_offset=0.0,
    use_unshifted=False,
    snr=100,
    ref_band="J",
    new=True,
    grad=True,
):
    """Calculate precisions for given combinations.

    grad: bool
        Use more precise gradient function.
    """
    # TODO: iterate over band last so that the J band normalization value can be
    # obtained first and applied to each band.

    print("using new config.yaml file here!!!!!!!!!!!!!!")
    results = {}  # creating empty dictionary for the results
    wav_plot_m0 = []  # creating empty lists for the plots
    flux_plot_m0 = []
    wav_plot_m3 = []
    flux_plot_m3 = []
    wav_plot_m6 = []
    flux_plot_m6 = []
    wav_plot_m9 = []
    flux_plot_m9 = []

    for band in bands:

        if use_unshifted:
            atmmodel = os.path.join(
                eniric.paths["atmmodel"],
                "{0}_{1}.dat".format(eniric.atmmodel["base"], band),
            )
            print("Reading atmospheric model...")
            atm = Atmosphere.from_file(atmmodel)
            wav_atm, flux_atm, std_flux_atm, mask_atm = (
                atm.wl,
                atm.transmission,
                atm.std,
                atm.mask,
            )

            print(
                (
                    "There were {0:d} unmasked pixels out of {1:d}., or {2:.1%}." ""
                ).format(
                    np.sum(mask_atm), len(mask_atm), np.sum(mask_atm) / len(mask_atm)
                )
            )

            print(
                "The model ranges from {0:4.2f} to {1:4.2f} micron.".format(
                    wav_atm[0], wav_atm[-1]
                )
            )
            print("Done.")
            print("Calculating impact of Barycentric movement on mask...")
            # mask_atm = atm.old_barycenter_shift(wav_atm, mask_atm, rv_offset=rv_offset)
            mask_atm = barycenter_shift(wav_atm, mask_atm, rv_offset=rv_offset)
        else:
            shifted_atmmodel = os.path.join(
                eniric.paths["atmmodel"],
                "{0}_{1}_bary.dat".format(eniric.atmmodel["base"], band),
            )
            print("Reading pre-doppler-shifted atmospheric model...")
            atm = Atmosphere.from_file(shifted_atmmodel)
            wav_atm, flux_atm, std_flux_atm, mask_atm = (
                atm.wl,
                atm.transmission,
                atm.std,
                atm.mask,
            )

        print("Done.")

        print(
            ("There were {0:d} unmasked pixels out of {1:d}, or {2:.1%}." "").format(
                np.sum(mask_atm), len(mask_atm), np.sum(mask_atm) / len(mask_atm)
            )
        )

        if plot_atm:
            # moved plotting code to separate code, eniric.obsolete.plotting_functions.py
            plt_functions.plot_atmosphere_model(wav_atm, flux_atm, mask_atm)

        # theoretical ratios calculation
        # wav_m0, flux_m0, wav_m3, flux_m3, wav_m6, flux_m6, wav_m9, flux_m9 = read_nIRspectra()

        iterations = itertools.product(spectral_types, vsini, resolution, sampling)
        # for star in spectral_types:
        #     for vel in vsini:
        #         for res in resolution:
        #             for smpl in sampling:
        for (star, vel, res, smpl) in iterations:
            file_to_read = (
                "Spectrum_{0}-PHOENIX-ACES_{1}band_vsini{2}_R{3}" "_res{4:2.01f}.dat"
            ).format(star, band, vel, res, float(smpl))
            # print("Working on "+file_to_read+".")
            try:
                wav_stellar, flux_stellar = io.pdread_2col(
                    os.path.join(eniric.paths["resampled"], file_to_read)
                )
            except FileNotFoundError:
                # Turn list of strings into strings without symbols  ["J", "K"] -> J K
                spectral_str = re.sub(r"[\[\]\"\',]", "", str(spectral_types))
                band_str = re.sub(r"[\[\]\"\',]", "", str(bands))
                vsini_str = re.sub(r"[\[\]\"\',]", "", str(vsini))
                res_str = re.sub(r"[\[\]\"\',]", "", str(resolution))
                sampling_str = re.sub(r"[\[\]\"\',]", "", str(sampling))

                print(
                    (
                        "\nFor just this file I suggest you run\n\tpython nIR_run.py -s {0} -b {1} -v {2} -R {3} "
                        "--sample_rate {4}\nOr for all the combinations you ran here\n\tpython nIR_run.py -s {5}"
                        " -b {6} -v {7} -R {8} --sample_rate {9}"
                        ""
                    ).format(
                        star,
                        band,
                        vel,
                        res,
                        smpl,
                        spectral_str,
                        band_str,
                        vsini_str,
                        res_str,
                        sampling_str,
                    )
                )
                raise
            if len(wav_stellar) == 0 or len(flux_stellar) == 0:
                raise Exception("The file {0} is empty".format(file_to_read))
            # Removing boundary effects
            wav_stellar = wav_stellar[2:-2]
            flux_stellar = flux_stellar[2:-2]

            # sample was left aside because only one value existed
            # TODO: Add metallicity and logg into id string
            id_string = "{0:s}-{1:s}-{2:.1f}-{3:s}".format(star, band, float(vel), res)

            # Getting the wav, flux and mask values from the atm model
            # that are the closest to the stellar wav values, see
            # https://stackoverflow.com/questions/2566412/find-nearest-value-in-numpy-array
            index_atm = np.searchsorted(wav_atm, wav_stellar)
            # replace indexes outside the array, at the very end, by the value at the very end
            # index_atm = [index if(index < len(wav_atm)) else len(wav_atm)-1 for index in index_atm]
            indx_mask = index_atm >= len(wav_atm)  # find broken indexs
            index_atm[indx_mask] = len(wav_atm) - 1  # replace with index of end.

            wav_atm_selected = wav_atm[index_atm]
            flux_atm_selected = flux_atm[index_atm]
            mask_atm_selected = mask_atm[index_atm]

            # Check mask masks out deep atmosphere absorption
            if np.any(flux_atm_selected[mask_atm_selected] < 0.98):
                print(
                    "####WARNGING####\nThis absorption mask does not mask out deep atmosphere transmission!"
                )
                print(
                    "Min flux_atm_selected[mask_atm_selected] = {} < 0.98\n####".format(
                        np.min(flux_atm_selected[mask_atm_selected])
                    )
                )

            # Normalize to SNR 100 in middle of J band 1.25 micron!
            # flux_stellar = normalize_flux(flux_stellar, id_string)
            # flux_stellar = snrnorm.normalize_flux(flux_stellar, id_string, new=True)  # snr=100, ref_band="J"
            flux_stellar = eniric.obsolete.snr_norm.normalize_flux(
                flux_stellar,
                id_string,
                new=new,
                snr=snr,
                ref_band=ref_band,
                sampling=smpl,
            )

            if id_string in [
                "M0-J-1.0-100k",
                "M3-J-1.0-100k",
                "M6-J-1.0-100k",
                "M9-J-1.0-100k",
            ]:
                index_ref = np.searchsorted(
                    wav_stellar, 1.25
                )  # searching for the index closer to 1.25 micron
                snr_estimate = np.sqrt(
                    np.sum(flux_stellar[index_ref - 1 : index_ref + 2])
                )
                print(
                    "\tSanity Check: The S/N for the {0:s} reference model was of {1:4.2f}.".format(
                        id_string, snr_estimate
                    )
                )
            elif "J" in id_string:
                index_ref = np.searchsorted(
                    wav_stellar, 1.25
                )  # searching for the index closer to 1.25 micron
                snr_estimate = np.sqrt(
                    np.sum(flux_stellar[index_ref - 1 : index_ref + 2])
                )
                print(
                    "\tSanity Check: The S/N for the {0:s} non-reference model was of {1:4.2f}.".format(
                        id_string, snr_estimate
                    )
                )

            # Precision given by the first method:
            print("Performing analysis for: ", id_string)
            prec_1 = Qcalculator.rv_precision(wav_stellar, flux_stellar, grad=grad)

            # Precision as given by the second_method
            wav_stellar_chunks, flux_stellar_chunks = eniric.legacy.mask_clumping(
                wav_stellar, flux_stellar, mask_atm_selected
            )

            prec_2_old = eniric.legacy.RVprec_calc_masked(
                wav_stellar_chunks, flux_stellar_chunks, grad=grad
            )
            prec_2 = eniric.legacy.RVprec_calc_masked(
                wav_stellar, flux_stellar, mask_atm_selected, grad=grad
            )

            assert np.all(prec_2_old == prec_2)

            """
            # histogram checking
            lengths = [len(chunk) for chunk in flux_stellar_chunks_unformatted]
            n, bins, patches = plt.hist(lengths, 500, range=[0.5, 500.5], histtype='stepfilled')
            plt.title(id_string)
            plt.show()
            """

            # Precision as given by the third_method
            prec_3 = Qcalculator.rv_precision(
                wav_stellar, flux_stellar, mask=flux_atm_selected ** 2, grad=grad
            )

            # Adding Precision results to the dictionary
            results[id_string] = [prec_1, prec_2, prec_3]

            # Prepare/Do for the plotting.
            if plot_ste or plot_ste == id_string:
                plt_functions.plot_stellar_spectum(
                    wav_stellar, flux_stellar, wav_atm_selected, mask_atm_selected
                )

            plot_ids = [
                "M3-Z-1.0-100k",
                "M3-Y-1.0-100k",
                "M3-J-1.0-100k",
                "M3-H-1.0-100k",
                "M3-K-1.0-100k",
            ]

            if plot_flux and id_string in plot_ids:
                wav_plot_m0.append(wav_stellar)
                flux_plot_m0.append(flux_stellar)
            if plot_flux and id_string in plot_ids:
                wav_plot_m3.append(wav_stellar)
                flux_plot_m3.append(flux_stellar)
            if plot_flux and id_string in plot_ids:
                wav_plot_m6.append(wav_stellar)
                flux_plot_m6.append(flux_stellar)
            if plot_flux and id_string in plot_ids:
                wav_plot_m9.append(wav_stellar)
                flux_plot_m9.append(flux_stellar)

    if plot_flux:
        plt_functions.plot_nIR_flux()

    if paper_plots:
        plt_functions.plot_paper_plots()

    else:
        return results
Exemplo n.º 15
0
def test_atmosphere_from_file(atm_model):
    atmos = Atmosphere.from_file(atmmodel=atm_model)
    assert len(atmos.wl) == len(atmos.transmission)
    assert len(atmos.transmission[atmos.mask]) != len(
        atmos.transmission)  # mask is not all ones
Exemplo n.º 16
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
Exemplo n.º 17
0
def test_atmosphere_broaden(R, num_procs):
    atm = Atmosphere.from_band("K")
    atm = atm.wave_select(2.3, 2.301)
    print(len(atm.wl))
    atm1 = atm.broaden(resolution=R, num_procs=num_procs)
    assert atm1 is None