# -*- coding: utf-8 -*-
"""
Convert setback geotiff to .h5 exclusion layers
"""
import logging
import numpy as np
import os
from warnings import warn
from reVX.handlers.geotiff import Geotiff
from reVX.handlers.outputs import Outputs
from reVX.utilities import ExclusionsConverter
logger = logging.getLogger(__name__)
[docs]def parse_setbacks(setbacks, chunks=(128, 128), is_inclusion_layer=False):
"""Load setbacks, combine multiple setbacks by state if needed
Parameters
----------
setbacks : list
List of paths to setback geotiffs to load and combine
chunks : tuple, optional
Chunk size of exclusions in Geotiff, by default (128, 128)
is_inclusion_layer : bool, optional
Flag indicating wether this layer should be an inclusion
layer instead of an exclusion mask, by default False.
Returns
-------
values : ndarray
Setbacks exclusion array
"""
logger.info("Merging setbacks...")
logger.debug("\n\t- ".join([""] + setbacks))
values = None
reduction_func = np.minimum if is_inclusion_layer else np.maximum
for geotiff in setbacks:
data = ExclusionsConverter.parse_tiff(geotiff, chunks=chunks,
check_tiff=False)[1]
if values is None:
values = data
else:
values = reduction_func(values, data)
return values
[docs]class SetbacksConverter(ExclusionsConverter):
"""
Convert setbacks goetiff(s) to excl .h5 layers
"""
[docs] def setbacks_to_layer(self, layer, setbacks, check_tiff=True,
is_inclusion_layer=False, transform_atol=0.01,
coord_atol=0.001, description=None,
scale_factor=None, dtype='uint8'):
"""
Transfer geotiff setbacks to h5 confirming they match existing layers
Parameters
----------
layer : str
Name of layer to create of replace.
setbacks : str
Path to geotiff file or directory containing multiple
geotiff files to be merged.
check_tiff : bool, optional
Flag to check tiff profile and coordinates against exclusion
.h5 profile and coordinates, by default True.
is_inclusion_layer : bool, optional
Flag indicating wether this layer should be an inclusion
layer instead of an exclusion mask, by default False.
transform_atol : float, optional
Absolute tolerance parameter when comparing geotiff
transform data, by default 0.01
coord_atol : float, optional.
Absolute tolerance parameter when comparing new un-projected
geotiff coordinates against previous coordinates,
by default 0.001.
description : str, optional
Description of exclusion layer, by default None.
scale_factor : int | float, optional
Scale factor to use to scale geotiff data when added to the
.h5 file, by default None, which does not apply any scaling.
dtype : str, optional
Dtype to save geotiff data as in the .h5 file. Only used
when 'scale_factor' is not None, by default 'uint8'
"""
if os.path.isdir(setbacks):
setbacks = [os.path.join(setbacks, file)
for file in os.listdir(setbacks)
if file.endswith('.tif')]
else:
setbacks = [setbacks]
logger.debug('\t- Combining setbacks in {}'.format(setbacks))
if not os.path.exists(self._excl_h5):
self._init_h5(self._excl_h5, setbacks[0], chunks=self._chunks)
msg = ("{} is already present in {}".format(layer, self._excl_h5))
if layer in self.layers:
if self._replace:
msg += " and will be replaced"
logger.warning(msg)
warn(msg)
else:
msg += ", to 'replace' set to True"
logger.error(msg)
raise KeyError(msg)
if check_tiff:
self._check_geotiff(self._excl_h5, setbacks[0],
chunks=self._chunks,
transform_atol=transform_atol,
coord_atol=coord_atol)
with Geotiff(setbacks[0], chunks=self._chunks) as tif:
profile = tif.profile
setbacks = parse_setbacks(setbacks, chunks=self._chunks,
is_inclusion_layer=is_inclusion_layer)
if scale_factor is not None:
setbacks = Outputs._check_data_dtype(setbacks, dtype,
scale_factor=scale_factor)
logger.debug('Writing final setback layer to {!r}'
.format(self._excl_h5))
self._write_layer(self._excl_h5, layer, profile, setbacks,
chunks=self._chunks, description=description,
scale_factor=scale_factor)
[docs] @classmethod
def layers_to_h5(cls, excl_h5, layers, chunks=(128, 128),
replace=True, check_tiff=True,
are_inclusion_layers=False, transform_atol=0.01,
coord_atol=0.001, descriptions=None, scale_factors=None):
"""
Create exclusions .h5 file, or load layers into existing exclusion .h5
file from provided setbacks
Parameters
----------
excl_h5 : str
Path to .h5 file containing or to contain exclusion layers
layers : dict | list
Dictionary where keys are layer names and values are paths
to the corresponding geotiff files or paths to directories
containing multiple geotiff files to be merged for each
layer. If input is a list of paths to geotiff files, then
the name of the layer is inferred from the geotiff file
name.
chunks : tuple, optional
Chunk size of exclusions in geotiff, by default (128, 128)
replace : bool, optional
Flag to replace existing layers if needed, by default True
check_tiff : bool, optional
Flag to check tiff profile and coordinates against exclusion
.h5 profile and coordinates, by default True.
are_inclusion_layers : bool, optional
Flag indicating wether the input layers should be treated
as inclusion layers instead of exclusion masks,
by default False.
transform_atol : float, optional
Absolute tolerance parameter when comparing geotiff
transform data, by default 0.01.
coord_atol : float, optional
Absolute tolerance parameter when comparing new un-projected
geotiff coordinates against previous coordinates,
by default 0.001.
description : dict, optional
Description of exclusion layers, by default None
scale_factor : dict, optional
Scale factors and dtypes to use when scaling given layers,
by default None
"""
if isinstance(layers, list):
layers = {os.path.basename(lyr).split('.')[0]: lyr
for lyr in layers}
if scale_factors is None:
scale_factors = {}
if descriptions is None:
descriptions = {}
excls = cls(excl_h5, chunks=chunks, replace=replace)
logger.info('Creating {}'.format(excl_h5))
for layer, setbacks in layers.items():
logger.info('- Transfering {}'.format(layer))
scale = scale_factors.get(layer, None)
if scale is not None:
scale_factor = scale['scale_factor']
dtype = scale['dtype']
else:
scale_factor = None
dtype = None
description = descriptions.get(layer, None)
excls.setbacks_to_layer(layer, setbacks, check_tiff=check_tiff,
is_inclusion_layer=are_inclusion_layers,
transform_atol=transform_atol,
coord_atol=coord_atol,
description=description,
scale_factor=scale_factor,
dtype=dtype)