Skip to content

Commit

Permalink
FIX: TerrainTiles/TileCompositor - construct tile composite from terr…
Browse files Browse the repository at this point in the history
…ain tiles to enable interpolation.

NOTE: I had to lightly round the coordinates of the terrain tiles because coordinate values used to index values in TileCompositor.get_data() were having float problems. The Coordinates.intersect() method was return coordinate values that were *slightly* different than the original coordinates, so the then when we tried to assign values in `output.loc[index] = source_data.values` xarray would fail to find the index. There is no way to realign here because `output` is a superset of `source_data`.
  • Loading branch information
mlshapiro committed Jun 11, 2020
1 parent bcb6a2c commit bc2bb16
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 8 deletions.
2 changes: 1 addition & 1 deletion podpac/compositor.py
Expand Up @@ -5,4 +5,4 @@
# REMINDER: update api docs (doc/source/user/api.rst) to reflect changes to this file

from podpac.core.compositor.ordered_compositor import OrderedCompositor
from podpac.core.compositor.tile_compositor import UniformTileCompositor, UniformTileMixin
from podpac.core.compositor.tile_compositor import UniformTileCompositor, UniformTileMixin, TileCompositor
4 changes: 2 additions & 2 deletions podpac/core/compositor/tile_compositor.py
Expand Up @@ -41,11 +41,11 @@ def get_data(self, coordinates, coordinates_index):

output = self.create_output_array(coordinates)
for source in self.sources:
c, I = source.coordinates.intersect(coordinates, return_indices=True)
c, I = source.coordinates.intersect(coordinates, outer=True, return_indices=True)
if c.size == 0:
continue
source_data = source.get_data(c, I)
output.loc[source_data.coords] = source_data
output.loc[source_data.coords] = source_data.data

return output

Expand Down
56 changes: 51 additions & 5 deletions podpac/datalib/terraintiles.py
Expand Up @@ -41,10 +41,13 @@
import traitlets as tl
import numpy as np

import podpac
from podpac.data import Rasterio
from podpac.compositor import OrderedCompositor
from podpac.compositor import OrderedCompositor, TileCompositor
from podpac.interpolators import Rasterio as RasterioInterpolator, ScipyGrid, ScipyPoint
from podpac.data import InterpolationTrait
from podpac.utils import cached_property
from podpac.authentication import S3Mixin

####
# private module attributes
Expand All @@ -67,6 +70,7 @@ class TerrainTilesSource(Rasterio):
dataset : :class:`rasterio.io.DatasetReader`
rasterio dataset
"""

anon = tl.Bool(True)
# attributes
interpolation = InterpolationTrait(
Expand Down Expand Up @@ -106,8 +110,40 @@ def download(self, path="terraintiles"):
_logger.debug("Downloading terrain tile {} to filepath: {}".format(self.source, filepath))
self.s3.get(self.source, filepath)

# this is a little crazy, but I get floating point issues with indexing if i don't round to 7 decimal digits
def get_coordinates(self):
coordinates = super(TerrainTilesSource, self).get_coordinates()

for dim in coordinates:
coordinates[dim] = np.round(coordinates[dim].coordinates, 6)

return coordinates


class TerrainTilesComposite(S3Mixin, TileCompositor):
urls = tl.List(trait=tl.Unicode()).tag(attr=True)

_repr_keys = ["urls"]

@cached_property
def sources(self):
return [self._create_source(url) for url in self.urls]

def get_coordinates(self):
return podpac.coordinates.union([source.coordinates for source in self.sources])

def _create_source(self, url):
return TerrainTilesSource(
source=url,
cache_ctrl=self.cache_ctrl,
force_eval=self.force_eval,
cache_output=self.cache_output,
cache_dataset=True,
s3=self.s3,
)


class TerrainTiles(OrderedCompositor):
class TerrainTiles(S3Mixin, OrderedCompositor):
"""Terrain Tiles gridded elevation tiles data library
Hosted on AWS S3
Expand Down Expand Up @@ -148,9 +184,10 @@ class TerrainTiles(OrderedCompositor):
def select_sources(self, coordinates):
# get all the tile sources for the requested zoom level and coordinates
sources = get_tile_urls(self.tile_format, self.zoom, coordinates)
urls = ["s3://{}/{}".format(self.bucket, s) for s in sources]

# create TerrainTilesSource classes for each url source
self.sources = [self._create_source(source) for source in sources]
self.sources = self._create_composite(urls)
return self.sources

def download(self, path="terraintiles"):
Expand All @@ -170,8 +207,17 @@ def download(self, path="terraintiles"):
except tl.TraitError as e:
raise ValueError("No terrain tile sources selected. Evaluate node at coordinates to select sources.")

def _create_source(self, source):
return TerrainTilesSource(source="s3://{}/{}".format(self.bucket, source), cache_ctrl=self.cache_ctrl)
def _create_composite(self, urls):
return [
TerrainTilesComposite(
urls=urls,
cache_ctrl=self.cache_ctrl,
force_eval=self.force_eval,
cache_output=self.cache_output,
cache_dataset=True,
s3=self.s3,
)
]


############
Expand Down

0 comments on commit bc2bb16

Please sign in to comment.