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")
예제 #2
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)]
예제 #3
0
def atmosphere_fixture(request, atm_model):
    percent_cutoff = request.param
    atm = Atmosphere.from_file(atm_model)
    atm.mask_transmission(percent_cutoff)
    return atm
예제 #4
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.
예제 #5
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
예제 #6
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