""" GeoTIFF storage method
"""
import os
import shutil
import numpy as np
import rasterio
from .._util import mkdir_p
from ..errors import FillValueException
from ..geoutils import meta_to_bounds
IMG_PATTERN = '{tile.timeseries_id}_{band.standard_name}.tif'
[docs]class GeoTIFFStore(object):
""" GeoTIFF tile store
A work in progress...
The GeoTIFF tile storage method separates individual acquisitions into
separate sub-directories. For example:
.. code-block:: bash
./
./LT50130302009294GNC01/
./LT50130292009294GNC01/
./LT50120292009303GNC01/
./LT50120292009303GNC01_sr_band1.tif
./LT50120292009303GNC01_sr_band2.tif
...
./LT50120292009303GNC01_sr_cfmask.tif
Args:
path (str): The root directory where the tile should be stored. The
path specified should already separate among tiles, if desired.
tile (Tile): The dataset tile to store
meta_options (dict): Additional creation options or metadata for
`rasterio` driver
"""
#: dict: GeoTIFF creation options
meta_options = {
'driver': 'GTiff',
'tiled': True,
'blockxsize': 256,
'blockysize': 256,
'compress': 'deflate'
}
def __init__(self, path, tile, meta_options=None):
self.path = path
self.tile = tile
self.meta_options.update(meta_options or {})
self.meta_options.update({
'transform': tile.transform,
'width': tile.tilespec.size[0],
'height': tile.tilespec.size[1]
})
[docs] def store_variable(self, product, band,
img_pattern=IMG_PATTERN,
overwrite=False):
""" Store product variable contained within this tile
Args:
product (BaseProduct): A product to store
band (Band): A :class:`Band` containing an observed variable
img_pattern (str): A format string that is used for creating the
output filename for this variable using Attributes of the
`product` and `band`. GeoTIFF driver's default is:
``{product.timeseries_id}_{band.standard_name}.tif``
overwrite (bool): Allow overwriting
Returns:
str: The path to the stored variable
"""
# Ensure source data has observations (i.e., not an edge)
dst_bounds = meta_to_bounds(**self.meta_options)
src_window = band.src.window(*dst_bounds, boundless=True)
src_data = band.src.read(1, window=src_window, boundless=True)
if np.all(src_data == band.fill):
raise FillValueException('Variable is 100% fill value')
dst_path = self._band_filename(product, band, img_pattern)
mkdir_p(os.path.dirname(dst_path))
dst_meta = band.src.meta.copy()
dst_meta.update(self.meta_options)
with rasterio.open(dst_path, 'w', **dst_meta) as dst:
dst.write_band(1, src_data)
return dst_path
[docs] def retrieve_variable(self, **kwargs):
""" Retrieve a product stored within this tile
"""
raise NotImplementedError('Reading is less important right now for '
'this driver at the moment as data from'
'it can be read directly from disk.')
[docs] def store_file(self, product, path):
""" Store a file with the product in an accessible way
An example use case for this method include storing metadata files
associated with a given product (e.g., "MTL" text files for Landsat).
Note that this method swallows `shutil.SameFileError` that may be
raised during the copy procedure. If the files are the same then
the copying has, in effect, worked correctly.
Args:
product (BaseProduct): A product to store
path (str): The path of the file to be stored
Returns:
str: The path of the file once copied into this product's store
"""
dest = os.path.join(self._product_filename(product),
os.path.basename(path))
try:
shutil.copy(path, dest)
except shutil.SameFileError:
pass
return dest
def _product_filename(self, product):
""" Return path to product
"""
return os.path.join(self.path, product.timeseries_id)
def _band_filename(self, product, band, img_pattern=IMG_PATTERN):
""" Return path to a band in a product
"""
name = img_pattern.format(product=product, band=band)
return os.path.join(self._product_filename(product), name)