Exemple #1
0
 def test_existing_config_file_different_parameters(self):
     """
     on a user defined mss_settings_json without a defined num_labels this test should return its default value
     """
     create_mss_settings_file('{"num_interpolation_points": 20 }')
     if not fs.open_fs(MSS_CONFIG_PATH).exists("mss_settings.json"):
         pytest.skip('undefined test mss_settings.json')
     with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
         file_content = file_dir.readtext("mss_settings.json")
     assert "num_labels" not in file_content
     default_data = config_loader(default=True)
     config_file = fs.path.combine(MSS_CONFIG_PATH, "mss_settings.json")
     read_config_file(path=config_file)
     data = config_loader()
     assert data["num_labels"] == default_data["num_labels"]
     num_labels = config_loader(dataset="num_labels")
     assert num_labels == default_data["num_labels"]
     num_interpolation_points = config_loader(
         dataset="num_interpolation_points")
     assert num_interpolation_points == 20
     assert data["num_interpolation_points"] == 20
     with pytest.raises(KeyError):
         config_loader(dataset="UNDEFINED")
     with pytest.raises(KeyError):
         assert config_loader(dataset="UNDEFINED")
Exemple #2
0
 def test_sample_config_file(self):
     utils_path = os.path.dirname(os.path.abspath(utils.__file__))
     config_file = os.path.join(
         utils_path,
         '../',
         '../',
         'docs',
         'samples',
         'config',
         'mss',
         'mss_settings.json.sample',
     )
     read_config_file(path=config_file)
     data = config_loader(dataset="new_flighttrack_flightlevel")
     assert data == 250
     with pytest.raises(KeyError):
         config_loader(dataset="UNDEFINED")
     with pytest.raises(KeyError):
         assert config_loader(dataset="UNDEFINED")
     with pytest.raises(FileNotFoundError):
         config_file = os.path.join(
             utils_path,
             '../',
             '../',
             'docs',
             'samples',
             'config',
             'mss',
             'non_existent_mss_settings.json.sample',
         )
         read_config_file(config_file)
Exemple #3
0
 def test_sample_config_file(self):
     config_file = os.path.join(
         self.sample_path,
         'msui_settings.json.sample',
     )
     read_config_file(path=config_file)
     data = config_loader(dataset="new_flighttrack_flightlevel")
     assert data == 250
     with pytest.raises(KeyError):
         config_loader(dataset="UNDEFINED")
     with pytest.raises(KeyError):
         assert config_loader(dataset="UNDEFINED")
Exemple #4
0
 def teardown(self):
     config_file = os.path.join(
         self.sample_path,
         'empty_msui_settings.json.sample',
     )
     read_config_file(path=config_file)
     for i in range(self.window.listViews.count()):
         self.window.listViews.item(i).window.hide()
     self.window.hide()
     QtWidgets.QApplication.processEvents()
     self.application.quit()
     QtWidgets.QApplication.processEvents()
Exemple #5
0
 def test_modify_config_file_with_existing_parameters(self):
     """
     Test to check if modify_config_file properly modifies a key-value pair in the config file
     """
     create_msui_settings_file('{"MSCOLAB_mailid": "*****@*****.**"}')
     if not fs.open_fs(MSUI_CONFIG_PATH).exists("msui_settings.json"):
         pytest.skip('undefined test msui_settings.json')
     data_to_save_in_config_file = {"MSCOLAB_mailid": "*****@*****.**"}
     modify_config_file(data_to_save_in_config_file)
     config_file = fs.path.combine(MSUI_CONFIG_PATH, "msui_settings.json")
     read_config_file(path=config_file)
     data = config_loader()
     assert data["MSCOLAB_mailid"] == "*****@*****.**"
Exemple #6
0
 def test_add_users_with_updating_credentials_in_config_file(
         self, mockmessage):
     create_msui_settings_file(
         '{"MSCOLAB_mailid": "*****@*****.**", "MSCOLAB_password": "******"}'
     )
     read_config_file()
     # check current settings
     assert config_loader(
         dataset="MSCOLAB_mailid") == "*****@*****.**"
     assert config_loader(dataset="MSCOLAB_password") == "something"
     self._connect_to_mscolab()
     assert self.window.mscolab_server_url is not None
     self._create_user("anand", "*****@*****.**", "anand")
     # check changed settings
     assert config_loader(dataset="MSCOLAB_mailid") == "*****@*****.**"
     assert config_loader(dataset="MSCOLAB_password") == "anand"
     # check user is logged in
     assert self.main_window.usernameLabel.text() == "anand"
Exemple #7
0
 def test_existing_empty_config_file(self):
     """
     on a user defined empty mss_settings_json this test should return the default value for num_labels
     """
     create_mss_settings_file('{ }')
     if not fs.open_fs(MSS_CONFIG_PATH).exists("mss_settings.json"):
         pytest.skip('undefined test mss_settings.json')
     with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
         file_content = file_dir.readtext("mss_settings.json")
     assert ":" not in file_content
     default_data = config_loader(default=True)
     config_file = fs.path.combine(MSS_CONFIG_PATH, "mss_settings.json")
     read_config_file(path=config_file)
     data = config_loader()
     assert data["num_labels"] == default_data["num_labels"]
     num_labels = config_loader(dataset="num_labels")
     assert num_labels == default_data["num_labels"]
     with pytest.raises(KeyError):
         config_loader(dataset="UNDEFINED")
     with pytest.raises(KeyError):
         assert config_loader(dataset="UNDEFINED")
Exemple #8
0
    def test_existing_config_file_invalid_parameters(self):
        """
        on a user defined mss_settings_json with duplicate and empty keys should raise FatalUserError
        """
        create_mss_settings_file(
            '{"num_interpolation_points": 201, "num_interpolation_points": 10 }'
        )
        if not fs.open_fs(MSS_CONFIG_PATH).exists("mss_settings.json"):
            pytest.skip('undefined test mss_settings.json')
        with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
            file_content = file_dir.readtext("mss_settings.json")
        assert "num_interpolation_points" in file_content
        config_file = fs.path.combine(MSS_CONFIG_PATH, "mss_settings.json")
        with pytest.raises(utils.FatalUserError):
            read_config_file(path=config_file)

        create_mss_settings_file('{"": 201, "num_labels": 10 }')
        if not fs.open_fs(MSS_CONFIG_PATH).exists("mss_settings.json"):
            pytest.skip('undefined test mss_settings.json')
        with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
            file_content = file_dir.readtext("mss_settings.json")
        assert "num_labels" in file_content
        with pytest.raises(utils.FatalUserError):
            read_config_file(path=config_file)
Exemple #9
0
def main():
    parser = argparse.ArgumentParser(description="""
       This script automatically retrieves and stores a set of plots for the
       configured flights. The configuration is placed within the normal
       MSS frontend JSON file. E.g.

       "automated_plotting": {
           "flights": [
               ["ST25", "01 SADPAP (stereo)", "500,50",
                "ST25-joern.ftml",
                "2019-07-01T00:00:00Z", "2019-09-01T12:00:00Z"]
           ],
           "hsecs": [
               ["https://mss-server/campaigns2019",
                "ecmwf.PVTropo01", "default", "4.0"],
               ["https://mss-server/campaigns2019",
                "ecmwf.ertel_potential_vorticity_pl", "ertel_potential_vorticity_bh", "200.0"]
           ],
           "vsecs": [
               ["https://mss-server/campaigns2019",
                "ecmwf.VS_ertel_potential_vorticity_ml", "ertel_potential_vorticity_bh"],
               ["https://mss-server/campaigns2019",
                "ecmwf.TroposphereInversionLayer", ""]
           ]
       }

       will plot flight "ST25" with configured map section "01 SADPAP (stereo)" and
       vertical range 500hPa to 50hPa from the given FTML file for init time
       "2019-07-01T00:00:00Z" and valid time "2019-09-01T12:00:00Z". The plots
       are defined in the hsecs (horizontal cross-sections) and vsecs (vertical
       cross-sections) entries given each the URL of the server, the layer name, the style,
       and, for hsec only, the elevation to plot (if necessary).
    """)
    parser.add_argument("-v",
                        "--version",
                        help="show version",
                        action="store_true",
                        default=False)
    parser.add_argument("--debug",
                        help="show debugging log messages on console",
                        action="store_true",
                        default=False)
    parser.add_argument(
        "--logfile",
        help="Specify logfile location. Set to empty string to disable.",
        action="store",
        default=os.path.join(mslib.msui.constants.MSUI_CONFIG_PATH,
                             "msui.log"))
    args = parser.parse_args()

    if args.version:
        print(
            "***********************************************************************"
        )
        print("\n            Mission Support System (mss_retriever)\n")
        print(
            "***********************************************************************"
        )
        print("Documentation: http://mss.rtfd.io")
        print("Version:", mslib.__version__)
        sys.exit()

    mslib.utils.setup_logging(args)
    read_config_file(path=mslib.msui.constants.MSUI_SETTINGS)
    config = config_loader()
    num_interpolation_points = config["num_interpolation_points"]
    num_labels = config["num_labels"]
    tick_index_step = num_interpolation_points // num_labels

    fig = plt.figure()
    for flight, section, vertical, filename, init_time, time in \
            config["automated_plotting"]["flights"]:
        params = mslib.utils.coordinate.get_projection_params(
            config["predefined_map_sections"][section]["CRS"].lower())
        params["basemap"].update(
            config["predefined_map_sections"][section]["map"])
        wps = load_from_ftml(filename)
        wp_lats, wp_lons, wp_locs = [[x[i] for x in wps] for i in [0, 1, 3]]
        wp_presss = [
            thermolib.flightlevel2pressure(wp[2] * units.hft).magnitude
            for wp in wps
        ]
        for url, layer, style, elevation in config["automated_plotting"][
                "hsecs"]:
            fig.clear()
            ax = fig.add_subplot(111, zorder=99)
            bm = mslib.msui.mpl_map.MapCanvas(ax=ax, **(params["basemap"]))

            # plot path and labels
            bm.plot(wp_lons,
                    wp_lats,
                    color="blue",
                    marker="o",
                    linewidth=2,
                    markerfacecolor="red",
                    latlon=True,
                    markersize=4,
                    zorder=100)
            for i, (lon, lat, loc) in enumerate(zip(wp_lons, wp_lats,
                                                    wp_locs)):
                textlabel = f"{loc if loc else str(i)}   "
                x, y = bm(lon, lat)
                plt.text(x, y, textlabel, **TEXT_CONFIG)
            plt.tight_layout()

            # retrieve and draw WMS image
            ax_bounds = plt.gca().bbox.bounds
            width, height = int(round(ax_bounds[2])), int(round(ax_bounds[3]))
            bbox = params['basemap']
            req = requests.get(
                url,
                auth=tuple(config["WMS_login"][url]),
                params={
                    "version":
                    "1.3.0",
                    "request":
                    "GetMap",
                    "format":
                    "image/png",
                    "exceptions":
                    "XML",
                    "crs":
                    config["predefined_map_sections"][section]["CRS"],
                    "layers":
                    layer,
                    "styles":
                    style,
                    "elevation":
                    elevation,
                    "dim_init_time":
                    init_time,
                    "time":
                    time,
                    "width":
                    width,
                    "height":
                    height,
                    "bbox":
                    f"{bbox['llcrnrlat']},{bbox['llcrnrlon']},{bbox['urcrnrlat']},{bbox['urcrnrlon']}"
                })
            if req.headers['Content-Type'] == "text/xml":
                print(flight, section, vertical, filename, init_time, time)
                print(url, layer, style, elevation)
                print("WMS Error:")
                print(req.text)
                exit(1)
            image_io = io.BytesIO(req.content)
            img = PIL.Image.open(image_io)
            bm.imshow(img, interpolation="nearest", origin="upper")
            bm.drawcoastlines()
            bm.drawcountries()

            fig.savefig(f"{flight}_{layer}.png")

        # prepare vsec plots
        path = [(wp[0], wp[1], datetime.datetime.now()) for wp in wps]
        lats, lons = mslib.utils.coordinate.path_points(
            [_x[0] for _x in path], [_x[1] for _x in path],
            numpoints=num_interpolation_points + 1,
            connection="greatcircle")
        intermediate_indexes = []
        ipoint = 0
        for i, (lat, lon) in enumerate(zip(lats, lons)):
            if abs(lat - wps[ipoint][0]) < 1E-10 and abs(
                    lon - wps[ipoint][1]) < 1E-10:
                intermediate_indexes.append(i)
                ipoint += 1
            if ipoint >= len(wps):
                break

        for url, layer, style in config["automated_plotting"]["vsecs"]:
            fig.clear()

            # setup ticks and labels
            ax = fig.add_subplot(111, zorder=99)
            ax.set_yscale("log")
            p_bot, p_top = [float(x) * 100 for x in vertical.split(",")]
            bbox = ",".join(
                str(x) for x in (num_interpolation_points, p_bot / 100,
                                 num_labels, p_top / 100))
            ax.grid(visible=True)
            ax.patch.set_facecolor("None")
            pres_maj = mslib.msui.mpl_qtwidget.MplSideViewCanvas._pres_maj
            pres_min = mslib.msui.mpl_qtwidget.MplSideViewCanvas._pres_min
            major_ticks = pres_maj[(pres_maj <= p_bot) & (pres_maj >= p_top)]
            minor_ticks = pres_min[(pres_min <= p_bot) & (pres_min >= p_top)]
            labels = [
                f"{int(_mt / 100)}" if
                (_mt / 100.) - int(_mt / 100.) == 0 else f"{float(_mt / 100)}"
                for _mt in major_ticks
            ]
            if len(labels) > 20:
                labels = [
                    "" if _x.split(".")[-1][0] in "975" else _x
                    for _x in labels
                ]
            elif len(labels) > 10:
                labels = [
                    "" if _x.split(".")[-1][0] in "9" else _x for _x in labels
                ]
            ax.set_ylabel("pressure (hPa)")
            ax.set_yticks(minor_ticks, minor=True)
            ax.set_yticks(major_ticks, minor=False)
            ax.set_yticklabels([], minor=True, fontsize=10)
            ax.set_yticklabels(labels, minor=False, fontsize=10)
            ax.set_ylim(p_bot, p_top)
            ax.set_xlim(0, num_interpolation_points)
            ax.set_xticks(range(0, num_interpolation_points, tick_index_step))
            ax.set_xticklabels([
                f"{x[0]:2.1f}, {x[1]:2.1f}"
                for x in zip(lats[::tick_index_step], lons[::tick_index_step])
            ],
                               rotation=25,
                               fontsize=10,
                               horizontalalignment="right")
            ax.set_xlabel("lat/lon")

            # plot path and waypoint labels
            ax.plot(intermediate_indexes,
                    wp_presss,
                    color="blue",
                    marker="o",
                    linewidth=2,
                    markerfacecolor="red",
                    markersize=4)
            for i, (idx, press, loc) in enumerate(
                    zip(intermediate_indexes, wp_presss, wp_locs)):
                textlabel = f"{loc if loc else str(i)} "
                plt.text(idx + 1, press, textlabel, rotation=90, **TEXT_CONFIG)
            plt.tight_layout()

            # retrieve and draw WMS image
            ax_bounds = plt.gca().bbox.bounds
            width, height = int(round(ax_bounds[2])), int(round(ax_bounds[3]))
            req = requests.get(url,
                               auth=tuple(config["WMS_login"][url]),
                               params={
                                   "version":
                                   "1.3.0",
                                   "request":
                                   "GetMap",
                                   "format":
                                   "image/png",
                                   "exceptions":
                                   "XML",
                                   "crs":
                                   "VERT:LOGP",
                                   "layers":
                                   layer,
                                   "styles":
                                   style,
                                   "dim_init_time":
                                   init_time,
                                   "time":
                                   time,
                                   "width":
                                   width,
                                   "height":
                                   height,
                                   "path":
                                   ",".join(f"{wp[0]:.2f},{wp[1]:.2f}"
                                            for wp in wps),
                                   "bbox":
                                   bbox
                               })

            if req.headers['Content-Type'] == "text/xml":
                print(flight, section, vertical, filename, init_time, time)
                print(url, layer, style)
                print("WMS Error:")
                print(req.text)
                exit(1)
            image_io = io.BytesIO(req.content)
            img = PIL.Image.open(image_io)
            imgax = fig.add_axes(ax.get_position(),
                                 frameon=True,
                                 xticks=[],
                                 yticks=[],
                                 label="ax2",
                                 zorder=0)
            imgax.imshow(img,
                         interpolation="nearest",
                         aspect="auto",
                         origin="upper")
            imgax.set_xlim(0, img.size[0] - 1)
            imgax.set_ylim(img.size[1] - 1, 0)

            plt.savefig(f"{flight}_{layer}.png")
Exemple #10
0
 def _reset_config_file(self):
     create_msui_settings_file('{ }')
     config_file = fs.path.combine(MSUI_CONFIG_PATH, "msui_settings.json")
     read_config_file(path=config_file)
Exemple #11
0
 def test_default_config_wrong_file(self):
     # return default if no access to config file given
     with pytest.raises(FileNotFoundError):
         read_config_file(path="foo.json")
Exemple #12
0
 def teardown(self):
     if fs.open_fs(MSUI_CONFIG_PATH).exists("msui_settings.json"):
         fs.open_fs(MSUI_CONFIG_PATH).remove("msui_settings.json")
     config_file = os.path.join(self.sample_path,
                                'empty_msui_settings.json.sample')
     read_config_file(config_file)