def test_reduced_arcs_contains_stable_wavelength_solution(config):
        """
        Make sure that the wavelength solution gives same results on different
        runs.
        """
        output = os.path.join(config.output_dir, config.filename)
        reference = os.path.join(config.ref_dir, config.filename)

        if not os.path.exists(output):
            pytest.skip("Output file not found: {}".format(output))

        if not os.path.exists(reference):
            pytest.fail("Reference file not found: {}".format(reference))

        ad_out = config.ad
        ad_ref = astrodata.open(reference)

        for ext_out, ext_ref in zip(ad_out, ad_ref):
            model = am.get_named_submodel(ext_out.wcs.forward_transform,
                                          'WAVE')
            ref_model = am.get_named_submodel(ext_ref.wcs.forward_transform,
                                              'WAVE')

            x = np.arange(ext_out.shape[1])
            y = model(x)
            ref_y = ref_model(x)

            np.testing.assert_allclose(y, ref_y, atol=1)

        del ad_out, ad_ref
Пример #2
0
def test_regression_determine_wavelength_solution(ad, fwidth, order, min_snr,
                                                  caplog, change_working_dir,
                                                  ref_ad_factory, request):
    """
    Make sure that the wavelength solution gives same results on different
    runs.
    """
    caplog.set_level(logging.INFO, logger="geminidr")

    with change_working_dir():
        logutils.config(
            file_name='log_regress_{:s}.txt'.format(ad.data_label()))
        p = GMOSLongslit([ad])
        p.viewer = geminidr.dormantViewer(p, None)

        p.determineWavelengthSolution(
            order=order,
            min_snr=min_snr,
            fwidth=fwidth,
            **determine_wavelength_solution_parameters)

        wcalibrated_ad = p.writeOutputs().pop()

        for record in caplog.records:
            if record.levelname == "WARNING":
                assert "No acceptable wavelength solution found" not in record.message

    ref_ad = ref_ad_factory(wcalibrated_ad.filename)
    model = am.get_named_submodel(wcalibrated_ad[0].wcs.forward_transform,
                                  "WAVE")
    ref_model = am.get_named_submodel(ref_ad[0].wcs.forward_transform, "WAVE")

    x = np.arange(wcalibrated_ad[0].shape[1])
    wavelength = model(x)
    ref_wavelength = ref_model(x)

    pixel_scale = wcalibrated_ad[0].pixel_scale()  # arcsec / px
    slit_size_in_arcsec = float(wcalibrated_ad[0].focal_plane_mask().replace(
        'arcsec', ''))
    slit_size_in_px = slit_size_in_arcsec / pixel_scale
    dispersion = abs(
        wcalibrated_ad[0].dispersion(asNanometers=True))  # nm / px

    tolerance = 0.5 * (slit_size_in_px * dispersion)
    np.testing.assert_allclose(wavelength, ref_wavelength, rtol=tolerance)

    if request.config.getoption("--do-plots"):
        do_plots(wcalibrated_ad)
    def wavelength_calibration_plots(self):
        """
        Makes the Wavelength Calibration Diagnosis Plots for each extension
        inside the reduced arc.
        """

        for ext_num, ext in enumerate(self.ad):

            if not hasattr(ext, "WAVECAL"):
                continue

            peaks = ext.WAVECAL[
                "peaks"] - 1  # ToDo: Refactor peaks to be 0-indexed
            wavelengths = ext.WAVECAL["wavelengths"]

            wavecal_model = am.get_named_submodel(ext.wcs.forward_transform,
                                                  "WAVE")

            middle = ext.data.shape[0] // 2
            sum_size = 10
            r1 = middle - sum_size // 2
            r2 = middle + sum_size // 2

            mask = np.round(np.average(ext.mask[r1:r2], axis=0)).astype(int)
            data = np.ma.masked_where(mask > 0, np.sum(ext.data[r1:r2],
                                                       axis=0))
            data = (data - data.min()) / data.ptp()

            self.plot_lines(ext_num, data, peaks, wavecal_model)
            self.plot_non_linear_components(ext_num, peaks, wavelengths,
                                            wavecal_model)
            self.plot_wavelength_solution_residuals(ext_num, peaks,
                                                    wavelengths, wavecal_model)
            self.create_artifact_from_plots()
Пример #4
0
def test_consistent_air_and_vacuum_solutions(ad, fwidth, order, min_snr):
    p = GMOSLongslit([])
    p.viewer = geminidr.dormantViewer(p, None)

    ad_air = p.determineWavelengthSolution(
        [deepcopy(ad)], order=order, min_snr=min_snr, fwidth=fwidth,
        in_vacuo=False, **determine_wavelength_solution_parameters).pop()
    ad_vac = p.determineWavelengthSolution(
        [ad], order=order, min_snr=min_snr, fwidth=fwidth,
        in_vacuo=True, **determine_wavelength_solution_parameters).pop()
    wave_air = am.get_named_submodel(ad_air[0].wcs.forward_transform, "WAVE")
    wave_vac = am.get_named_submodel(ad_vac[0].wcs.forward_transform, "WAVE")
    x = np.arange(ad_air[0].shape[1])
    wair = wave_air(x)
    wvac = air_to_vac(wair * u.nm).to(u.nm).value
    dw = wvac - wave_vac(x)
    assert abs(dw).max() < 0.001
Пример #5
0
def assert_wavelength_solutions_are_close(ad, ad_ref, atol=0, rtol=1e-7):
    """
    Checks if two :class:`~astrodata.AstroData` (or any subclass) have the
    wavelength solution.

    Parameters
    ----------
    ad : :class:`astrodata.AstroData` or any subclass
        AstroData object to be checked.
    ad_ref : :class:`astrodata.AstroData` or any subclass
        AstroData object used as reference
    atol, rtol : float
        absolute and relative tolerances
    """
    for ext, ext_ref in zip(ad, ad_ref):
        wcal = get_named_submodel(ext.wcs.forward_transform, 'WAVE')
        wcal_ref = get_named_submodel(ext_ref.wcs.forward_transform, 'WAVE')
        assert_allclose(wcal.parameters, wcal_ref.parameters,
                        atol=atol, rtol=rtol)
Пример #6
0
def do_plots(ad):
    """
    Generate diagnostic plots.

    Parameters
    ----------
    ad : astrodata
    """
    output_dir = ("./plots/geminidr/gmos/"
                  "test_gmos_spect_ls_determine_wavelength_solution")
    os.makedirs(output_dir, exist_ok=True)

    name, _ = os.path.splitext(ad.filename)
    grating = ad.disperser(pretty=True)
    bin_x = ad.detector_x_bin()
    bin_y = ad.detector_y_bin()
    central_wavelength = ad.central_wavelength(asNanometers=True)

    p = GMOSLongslit([ad])
    arc_table = os.path.join(p.inst_lookups, "CuAr_GMOS.dat")
    arc_lines = np.loadtxt(arc_table, usecols=[0]) / 10.0

    for ext_num, ext in enumerate(ad):

        if not hasattr(ext, "WAVECAL"):
            continue

        peaks = ext.WAVECAL["peaks"] - 1  # ToDo: Refactor peaks to be 0-indexed
        wavelengths = ext.WAVECAL["wavelengths"]
        wavecal_model = am.get_named_submodel(ext.wcs.forward_transform, "WAVE")

        middle = ext.data.shape[0] // 2
        sum_size = 10
        r1 = middle - sum_size // 2
        r2 = middle + sum_size // 2

        mask = np.round(np.average(ext.mask[r1:r2], axis=0)).astype(int)
        data = np.ma.masked_where(mask > 0, np.sum(ext.data[r1:r2], axis=0))
        data = (data - data.min()) / data.ptp()

        # -- Plot lines --
        fig, ax = plt.subplots(
            dpi=150, num="{:s}_{:d}_{:s}_{:.0f}".format(
                name, ext_num, grating, central_wavelength))

        w = wavecal_model(np.arange(data.size))

        arcs = [ax.vlines(line, 0, 1, color="k", alpha=0.25) for line in arc_lines]
        wavs = [ax.vlines(peak, 0, 1, color="r", ls="--", alpha=0.25)
                for peak in wavecal_model(peaks)]

        plot, = ax.plot(w, data, "k-", lw=0.75)

        ax.legend((plot, arcs[0], wavs[0]),
                  ("Normalized Data", "Reference Lines", "Matched Lines"))

        x0, x1 = wavecal_model([0, data.size])
        ax.grid(alpha=0.1)
        ax.set_xlim(x0, x1)
        ax.set_xlabel("Wavelength [nm]")
        ax.set_ylabel("Normalized intensity")
        ax.set_title("Wavelength Calibrated Spectrum for\n"
                     "{:s}\n obtained with {:s} at {:.0f} nm".format(
                        name, grating, central_wavelength))

        if x0 > x1:
            ax.invert_xaxis()

        fig_name = os.path.join(output_dir, "{:s}_{:d}_{:s}_{:.0f}.png".format(
            name, ext_num, grating, central_wavelength))

        fig.savefig(fig_name)
        del fig, ax

        # -- Plot non-linear components ---
        fig, ax = plt.subplots(
            dpi=150, num="{:s}_{:d}_{:s}_{:.0f}_non_linear_comps".format(
                name, ext_num, grating, central_wavelength))

        non_linear_model = wavecal_model.copy()
        _ = [setattr(non_linear_model, "c{}".format(k), 0) for k in [0, 1]]
        residuals = wavelengths - wavecal_model(peaks)

        p = np.linspace(min(peaks), max(peaks), 1000)
        ax.plot(wavecal_model(p), non_linear_model(p),
                "C0-", label="Generic Representation")
        ax.plot(wavecal_model(peaks), non_linear_model(peaks) + residuals,
                "ko", label="Non linear components and residuals")

        ax.legend()
        ax.grid(alpha=0.25)
        ax.set_xlabel("Wavelength [nm]")
        ax.set_title("Non-linear components for\n"
                     "{:s} obtained with {:s} at {:.0f}".format(
                        name, grating, central_wavelength))

        fig_name = os.path.join(
            output_dir, "{:s}_{:d}_{:s}_{:.0f}_non_linear_comps.png".format(
                name, ext_num, grating, central_wavelength))

        fig.savefig(fig_name)
        del fig, ax

        # -- Plot Wavelength Solution Residuals ---
        fig, ax = plt.subplots(
            dpi=150, num="{:s}_{:d}_{:s}_{:.0f}_residuals".format(
                name, ext_num, grating, central_wavelength))

        ax.plot(wavelengths, wavelengths - wavecal_model(peaks), "ko")

        ax.grid(alpha=0.25)
        ax.set_xlabel("Wavelength [nm]")
        ax.set_ylabel("Residuum [nm]")
        ax.set_title("Wavelength Calibrated Residuum for\n"
                     "{:s} obtained with {:s} at {:.0f}".format(
                        name, grating, central_wavelength))

        fig_name = os.path.join(
            output_dir, "{:s}_{:d}_{:s}_{:.0f}_residuals.png".format(
                name, ext_num, grating, central_wavelength))

        fig.savefig(fig_name)

    # -- Create artifacts ---
    if "BUILD_ID" in os.environ:
        branch_name = os.environ["BRANCH_NAME"].replace("/", "_")
        build_number = int(os.environ["BUILD_NUMBER"])

        tar_name = os.path.join(output_dir, "plots_{:s}_b{:03d}.tar.gz".format(
            branch_name, build_number))

        with tarfile.open(tar_name, "w:gz") as tar:
            for _file in glob.glob(os.path.join(output_dir, "*.png")):
                tar.add(name=_file, arcname=os.path.basename(_file))

        target_dir = "./plots/"
        target_file = os.path.join(target_dir, os.path.basename(tar_name))

        os.makedirs(target_dir, exist_ok=True)
        os.rename(tar_name, target_file)