Example #1
0
def _get_dataset_tile_grid(dataset: xr.Dataset,
                           num_levels: int = None) -> TileGrid:
    geo_extent = get_dataset_bounds(dataset)
    inv_y = float(dataset.lat[0]) < float(dataset.lat[-1])
    width, height, tile_width, tile_height = _get_cube_spatial_sizes(dataset)
    if num_levels is not None and tile_width is not None and tile_height is not None:
        width_0 = width
        height_0 = height
        for i in range(num_levels):
            width_0 = (width_0 + 1) // 2
            height_0 = (height_0 + 1) // 2
        num_level_zero_tiles_x = (width_0 + tile_width - 1) // tile_width
        num_level_zero_tiles_y = (height_0 + tile_height - 1) // tile_height
        tile_grid = TileGrid(num_levels, num_level_zero_tiles_x,
                             num_level_zero_tiles_y, tile_width, tile_height,
                             geo_extent, inv_y)
    else:
        try:
            tile_grid = TileGrid.create(width, height, tile_width, tile_height,
                                        geo_extent, inv_y)
        except ValueError:
            num_levels = 1
            num_level_zero_tiles_x = 1
            num_level_zero_tiles_y = 1
            tile_grid = TileGrid(num_levels, num_level_zero_tiles_x,
                                 num_level_zero_tiles_y, width, height,
                                 geo_extent, inv_y)

    return tile_grid
Example #2
0
 def test_width_and_height(self):
     ts = TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=False)
     self.assertEqual(ts.width(2), 4320)
     self.assertEqual(ts.height(2), 2160)
     self.assertEqual(ts.max_width, 8640)
     self.assertEqual(ts.max_height, 4320)
     self.assertEqual(ts.min_width, 1080)
     self.assertEqual(ts.min_height, 540)
Example #3
0
 def test_to_json(self):
     ts = TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=True)
     self.assertEqual(ts.to_json(), {
         'numLevels': 4,
         'numLevelZeroTilesX': 2,
         'numLevelZeroTilesY': 1,
         'tileHeight': 540,
         'tileWidth': 540,
         'invY': True,
         'extent': {'west': -180.,
                    'south': -90.,
                    'east': 180.,
                    'north': 90.,
                    },
     })
Example #4
0
    def test_it(self):
        ds = _get_test_dataset()

        ml_ds1 = BaseMultiLevelDataset(ds)

        def input_ml_dataset_getter(ds_id):
            if ds_id == "ml_ds1":
                return ml_ds1
            self.fail(f"unexpected ds_id={ds_id!r}")

        ml_ds2 = ComputedMultiLevelDataset(os.path.join(os.path.dirname(__file__),
                                                        "..", "webapi", "res", "test", "script.py"),
                                           "compute_dataset",
                                           ["ml_ds1"],
                                           input_ml_dataset_getter,
                                           input_parameters=dict(period='1W'),
                                           ds_id="ml_ds2")
        self.assertEqual(3, ml_ds2.num_levels)
        self.assertEqual(TileGrid(3, 2, 1, 180, 180, (-180, -90, 180, 90), inv_y=False),
                         ml_ds2.tile_grid)

        ds0 = ml_ds2.get_dataset(0)
        self.assertEqual({'time': 3, 'lat': 720, 'lon': 1440, 'bnds': 2}, ds0.dims)

        ds1 = ml_ds2.get_dataset(1)
        self.assertEqual({'time': 3, 'lat': 360, 'lon': 720}, ds1.dims)

        ds2 = ml_ds2.get_dataset(2)
        self.assertEqual({'time': 3, 'lat': 180, 'lon': 360}, ds2.dims)

        self.assertEqual([ds0, ds1, ds2], ml_ds2.datasets)

        ml_ds1.close()
        ml_ds2.close()
Example #5
0
    def test_it(self):
        ds = _get_test_dataset()

        ml_ds = BaseMultiLevelDataset(ds)

        self.assertIsInstance(ml_ds.ds_id, str)

        self.assertEqual(3, ml_ds.num_levels)
        self.assertEqual(
            TileGrid(3, 2, 1, 180, 180, (-180, -90, 180, 90), inv_y=False),
            ml_ds.tile_grid)

        ds0 = ml_ds.get_dataset(0)
        self.assertIs(ds, ds0)

        ds1 = ml_ds.get_dataset(1)
        self.assertIsNot(ds, ds1)
        self.assertEqual({'time': 14, 'lat': 360, 'lon': 720}, ds1.dims)

        ds2 = ml_ds.get_dataset(2)
        self.assertIsNot(ds, ds2)
        self.assertEqual({'time': 14, 'lat': 180, 'lon': 360}, ds2.dims)

        self.assertEqual([ds0, ds1, ds2], ml_ds.datasets)

        ml_ds.close()
Example #6
0
    def create_from_image(cls,
                          source_image: TiledImage,
                          level_transformer: LevelTransformer,
                          geo_extent: GeoExtent = None,
                          **kwargs) -> 'ImagePyramid':
        """
        Create an image pyramid build from a single, max-resolution source image of type TiledImage.
        The given source image will be returned for highest resolution level in the pyramid.
        Other level images are created from the given level_image_factory function.

        :param source_image: the high-resolution source image, see TiledImage interface
        :param level_transformer: transforms level z+1 into level z. Called like:
               level_images[z_index] = level_transformer(source_image, level_images[z_index+1], z_index, **kwargs)
        :param geo_extent: the geographical extent.
        :param kwargs: keyword arguments passed to the level_image_factory function
        :return: a new ImagePyramid instance
        """
        if geo_extent is None:
            geo_extent = GLOBAL_GEO_EXTENT
        tile_grid = TileGrid.create(source_image.size[0], source_image.size[1],
                                    source_image.tile_size[0],
                                    source_image.tile_size[1], geo_extent)
        level_images = [None] * tile_grid.num_levels
        z_index_max = tile_grid.num_levels - 1
        level_images[z_index_max] = source_image
        level_image = source_image
        for i in range(1, tile_grid.num_levels):
            z_index = z_index_max - i
            image_id = '%s/%d' % (source_image.id, z_index)
            level_images[z_index] = level_image = level_transformer(
                source_image, level_image, i, image_id=image_id, **kwargs)
        return ImagePyramid(tile_grid, level_images)
Example #7
0
    def test_it(self):
        ml_ds_1 = BaseMultiLevelDataset(_get_test_dataset(('noise_1', 'noise_2')))
        ml_ds_2 = BaseMultiLevelDataset(_get_test_dataset(('noise_3', 'noise_4')))
        ml_ds_3 = BaseMultiLevelDataset(_get_test_dataset(('noise_5', 'noise_6')))

        ml_ds = CombinedMultiLevelDataset([ml_ds_1, ml_ds_2, ml_ds_3])

        self.assertEqual(3, ml_ds.num_levels)
        self.assertEqual(TileGrid(3, 2, 1, 180, 180, (-180, -90, 180, 90), inv_y=False),
                         ml_ds.tile_grid)

        expected_var_names = {'noise_1', 'noise_2',
                              'noise_3', 'noise_4',
                              'noise_5', 'noise_6'}

        ds0 = ml_ds.get_dataset(0)
        self.assertEqual({'time': 14, 'lat': 720, 'lon': 1440, 'bnds': 2}, ds0.dims)
        self.assertEqual(expected_var_names, set(map(str, ds0.data_vars)))
        self.assertTrue(all(v.dims == ('time', 'lat', 'lon') for v in ds0.data_vars.values()))

        ds1 = ml_ds.get_dataset(1)
        self.assertEqual({'time': 14, 'lat': 360, 'lon': 720}, ds1.dims)
        self.assertEqual(expected_var_names, set(map(str, ds1.data_vars)))
        self.assertTrue(all(v.dims == ('time', 'lat', 'lon') for v in ds1.data_vars.values()))

        ds2 = ml_ds.get_dataset(2)
        self.assertEqual({'time': 14, 'lat': 180, 'lon': 360}, ds2.dims)
        self.assertEqual(expected_var_names, set(map(str, ds2.data_vars)))
        self.assertTrue(all(v.dims == ('time', 'lat', 'lon') for v in ds2.data_vars.values()))

        self.assertEqual([ds0, ds1, ds2], ml_ds.datasets)

        ml_ds.close()
Example #8
0
def get_dataset_tile_grid(dataset: xr.Dataset,
                          num_levels: int = None) -> TileGrid:
    """
    Compute the tile grid for the given *dataset* and an optional number of resolution
    levels *num_levels*, if given.

    :param dataset: The dataset.
    :param num_levels: The number of resolution levels.
    :return: A TileGrid object
    """
    geo_extent = get_dataset_bounds(dataset)
    inv_y = float(dataset.lat[0]) < float(dataset.lat[-1])
    width, height, tile_width, tile_height = _get_cube_spatial_sizes(dataset)
    if num_levels is not None and tile_width is not None and tile_height is not None:
        width_0 = width
        height_0 = height
        for i in range(num_levels - 1):
            width_0 = (width_0 + 1) // 2
            height_0 = (height_0 + 1) // 2
        num_level_zero_tiles_x = (width_0 + tile_width - 1) // tile_width
        num_level_zero_tiles_y = (height_0 + tile_height - 1) // tile_height
        tile_grid = TileGrid(num_levels, num_level_zero_tiles_x,
                             num_level_zero_tiles_y, tile_width, tile_height,
                             geo_extent, inv_y)
    else:
        try:
            tile_grid = TileGrid.create(width, height, tile_width, tile_height,
                                        geo_extent, inv_y)
        except ValueError:
            num_levels = 1
            num_level_zero_tiles_x = 1
            num_level_zero_tiles_y = 1
            tile_grid = TileGrid(num_levels, num_level_zero_tiles_x,
                                 num_level_zero_tiles_y, width, height,
                                 geo_extent, inv_y)

    if tile_width is not None and tile_width != tile_grid.tile_width:
        warnings.warn(
            f'FIXME: wanted tile_width={tile_width} as of chunking, but will use {tile_grid.tile_width}. '
            f'This is inefficient.')
    if tile_height is not None and tile_height != tile_grid.tile_height:
        warnings.warn(
            f'FIXME: wanted tile_height={tile_width} as of chunking, but will use {tile_grid.tile_height}. '
            f'This is inefficient.')

    return tile_grid
Example #9
0
 def test_create_cci_ecv(self):
     # 72, 8, 85, 17
     # Soilmoisture CCI - daily L3S
     self.assertEqual(TileGrid.create(1440, 720, 500, 500, GLOBAL_GEO_EXTENT, inv_y=False),
                      TileGrid(2, 2, 1, 360, 360, GLOBAL_GEO_EXTENT, inv_y=False))
     # Aerosol CCI - monthly
     self.assertEqual(TileGrid.create(7200, 3600, 500, 500, GLOBAL_GEO_EXTENT, inv_y=False),
                      TileGrid(4, 2, 1, 450, 450, GLOBAL_GEO_EXTENT, inv_y=False))
     # Cloud CCI - monthly
     self.assertEqual(TileGrid.create(720, 360, 500, 500, GLOBAL_GEO_EXTENT, inv_y=True),
                      TileGrid(1, 2, 1, 360, 360, GLOBAL_GEO_EXTENT, inv_y=True))
     # SST CCI - daily L4
     self.assertEqual(TileGrid.create(8640, 4320, 500, 500, GLOBAL_GEO_EXTENT, inv_y=True),
                      TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=True))
     # Land Cover CCI
     self.assertEqual(TileGrid.create(129600, 64800, 500, 500, GLOBAL_GEO_EXTENT, inv_y=False),
                      TileGrid(6, 6, 3, 675, 675, GLOBAL_GEO_EXTENT, inv_y=False))
Example #10
0
    def test_create_illegal_geo_extent(self):
        # legal - explains why the next must fail
        self.assertEqual(TileGrid.create(50, 25, 5, 5, (0.0, 77.5, 25.0, 90.0), inv_y=True),
                         TileGrid(2, 5, 2, 5, 7, (0.0, 76.0, 25.0, 90.0), inv_y=True))
        with self.assertRaises(ValueError):
            TileGrid.create(50, 25, 5, 5, (0.0, 77.5, 25.0, 90.0), inv_y=False)

        # legal - explains why the next must fail
        self.assertEqual(TileGrid.create(50, 25, 5, 5, (0., -90.0, 25., -77.5), inv_y=False),
                         TileGrid(2, 5, 2, 5, 7, (0.0, -90.0, 25.0, -76.0), inv_y=False))
        with self.assertRaises(ValueError):
            TileGrid.create(50, 25, 5, 5, (0., -90.0, 25., -77.5), inv_y=True)
Example #11
0
 def test_str(self):
     ts = TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=False)
     self.assertEqual(str(ts),
                      'number of pyramid levels: 4\n'
                      'number of tiles at level zero: 2 x 1\n'
                      'pyramid tile size: 540 x 540\n'
                      'image size at level zero: 1080 x 540\n'
                      'image size at level 3: 8640 x 4320\n'
                      'geographic extent: (-180.0, -90.0, 180.0, 90.0)\n'
                      'y-axis points down: yes')
Example #12
0
def _tile_grid_to_ol4x_xyz_source_options(tile_grid: TileGrid, url: str):
    """
    Convert TileGrid into options to be used with ol.source.XYZ(options) of OpenLayers 4.x.

    See

    * https://openlayers.org/en/latest/apidoc/ol.source.XYZ.html
    * https://openlayers.org/en/latest/examples/xyz.html

    :param tile_grid: tile grid
    :param url: source url
    :return:
    """
    west, south, east, north = tile_grid.geo_extent

    delta_x = east - west + (0 if east >= west else 360)
    delta_y = north - south
    width = tile_grid.width(0)
    height = tile_grid.height(0)
    res0_x = delta_x / width
    res0_y = delta_y / height
    res0 = max(res0_x, res0_y)
    if abs(res0_y - res0_x) >= 1.e-5:
        warnings.warn(
            f'spatial resolutions in x and y direction differ significantly:'
            f' {res0_x} and {res0_y} degrees, using maximum {res0}')

    # https://openlayers.org/en/latest/examples/xyz.html
    # https://openlayers.org/en/latest/apidoc/ol.source.XYZ.html
    return dict(
        url=url,
        projection='EPSG:4326',
        minZoom=0,
        maxZoom=tile_grid.num_levels - 1,
        tileGrid=dict(
            extent=[west, south, east, north],
            origin=[west, south if tile_grid.inv_y else north],
            tileSize=[tile_grid.tile_size[0], tile_grid.tile_size[1]],
            resolutions=[res0 / (2**i) for i in range(tile_grid.num_levels)]))
Example #13
0
 def test_create_subsets(self):
     self.assertEqual(TileGrid.create(4000, 3000, 500, 500, (-20., 10., 60., 70.), inv_y=True),
                      TileGrid(4, 1, 1, 500, 375, (-20., 10., 60., 70.), inv_y=True))
     self.assertEqual(TileGrid.create(4012, 3009, 500, 500, (-20., 10., 60., 70.), inv_y=True),
                      TileGrid(2, 3, 5, 669, 301,
                               (-20.0, 9.980059820538386, 60.03988035892323, 70.), inv_y=True))
     self.assertEqual(TileGrid.create(4000, 3000, 500, 500, (170., 10., -160., 70.), inv_y=True),
                      TileGrid(4, 1, 1, 500, 375, (170.0, 10.0, -160.0, 70.0), inv_y=True))
Example #14
0
 def test_illegal_init(self):
     with self.assertRaises(ValueError):
         TileGrid(0, 2, 1, 540, 540, (0.0, 80., 20.0, 90.0), inv_y=True)
     with self.assertRaises(ValueError):
         TileGrid(4, 0, 1, 540, 540, (0.0, 80., 20.0, 90.0), inv_y=True)
     with self.assertRaises(ValueError):
         TileGrid(4, 2, 0, 540, 540, (0.0, 80., 20.0, 90.0), inv_y=True)
     with self.assertRaises(ValueError):
         TileGrid(4, 2, 1, 0, 540, (0.0, 80., 20.0, 90.0), inv_y=True)
     with self.assertRaises(ValueError):
         TileGrid(4, 2, 1, 540, 0, (0.0, 80., 20.0, 90.0), inv_y=True)
     with self.assertRaises(ValueError):
         TileGrid(4, 2, 1, 540, 540, (0.0, 80., 20.0, 90.01), inv_y=True)
Example #15
0
 def get_pyramid() -> ImagePyramid:
     """
     Return an instance of a 'Natural Earth v2' image pyramid:
     * global coverage
     * JPEG RGB format
     * 3 levels of detail: 0 to 2
     * tile size: 256 pixels
     * 2 x 1 tiles on level zero
     """
     dir_path = os.path.join(os.path.dirname(__file__), 'res', 'ne2')
     return ImagePyramid(
         TileGrid(NaturalEarth2Image.NUM_LEVELS,
                  NaturalEarth2Image.NUM_LEVEL_0_TILES_X,
                  NaturalEarth2Image.NUM_LEVEL_0_TILES_Y,
                  NaturalEarth2Image.TILE_SIZE,
                  NaturalEarth2Image.TILE_SIZE,
                  GLOBAL_GEO_EXTENT,
                  inv_y=False), [
                      NaturalEarth2Image(dir_path, level)
                      for level in range(NaturalEarth2Image.NUM_LEVELS)
                  ])
Example #16
0
 def test_repr(self):
     ts = TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=False)
     self.assertEqual(repr(ts), 'TileGrid(4, 2, 1, 540, 540, (-180.0, -90.0, 180.0, 90.0), inv_y=False)')
     ts = TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=True)
     self.assertEqual(repr(ts), 'TileGrid(4, 2, 1, 540, 540, (-180.0, -90.0, 180.0, 90.0), inv_y=True)')
Example #17
0
 def test_num_tiles(self):
     ts = TileGrid(4, 2, 1, 540, 540, GLOBAL_GEO_EXTENT, inv_y=False)
     self.assertEqual(ts.num_tiles_x(0), 2)
     self.assertEqual(ts.num_tiles_y(0), 1)
     self.assertEqual(ts.num_tiles_x(3), 16)
     self.assertEqual(ts.num_tiles_y(3), 8)
Example #18
0
 def test_create_cci_ecv_subsets(self):
     # Soilmoisture CCI - daily L3S - use case #6
     self.assertEqual(TileGrid.create(52, 36, 500, 500, (72, 8, 85, 17)),
                      TileGrid(1, 1, 1, 52, 36, (72., 8., 85., 17.)))