Commit 11de3132 authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Fix for always returning returning float64 output data type in case of bilinear resampling.


Added output data type verification to tests.
Fix for an exception if the output of get_proj4info() contains trailing white spaces (fixed by an update of py_tools_ds).
Updated version info and HISTORY.rst.
Signed-off-by: Daniel Scheffler's avatarDaniel Scheffler <danschef@gfz-potsdam.de>
parent 2d8da58c
Pipeline #7234 passed with stages
in 1 minute and 36 seconds
...@@ -2,6 +2,15 @@ ...@@ -2,6 +2,15 @@
History History
======= =======
0.3.0 (coming soon)
-------------------
* Fix for always returning returning float64 output data type in case of bilinear resampling.
* Added output data type verification to tests.
* Fix for an exception if the output of get_proj4info() contains trailing white spaces
(fixed by an update of py_tools_ds).
0.2.0 (2020-01-06) 0.2.0 (2020-01-06)
------------------ ------------------
......
...@@ -67,7 +67,7 @@ class SensorMapGeometryTransformer(object): ...@@ -67,7 +67,7 @@ class SensorMapGeometryTransformer(object):
- weight_funcs: <list of function objects or function object> [ONLY 'custom'] List of weight - weight_funcs: <list of function objects or function object> [ONLY 'custom'] List of weight
functions f(dist) to use for the weighting of each channel 1 to k. If only one functions f(dist) to use for the weighting of each channel 1 to k. If only one
channel is resampled weight_funcs is a single function object. channel is resampled weight_funcs is a single function object.
- fill_value: <int or None> Set undetermined pixels to this value. - fill_value: <int or None> Set undetermined pixels to this value (default: 0).
If fill_value is None a masked array is returned with undetermined pixels masked If fill_value is None a masked array is returned with undetermined pixels masked
- reduce_data: <bool> Perform initial coarse reduction of source dataset in order to reduce - reduce_data: <bool> Perform initial coarse reduction of source dataset in order to reduce
execution time execution time
...@@ -249,11 +249,11 @@ class SensorMapGeometryTransformer(object): ...@@ -249,11 +249,11 @@ class SensorMapGeometryTransformer(object):
""" """
if self.resamp_alg == 'nearest': if self.resamp_alg == 'nearest':
opts = {k: v for k, v in self.opts.items() if k not in ['sigmas']} opts = {k: v for k, v in self.opts.items() if k not in ['sigmas']}
result = resample_nearest(source_geo_def, data, target_geo_def, **opts) result = resample_nearest(source_geo_def, data, target_geo_def, **opts).astype(data.dtype)
elif self.resamp_alg == 'bilinear': elif self.resamp_alg == 'bilinear':
opts = {k: v for k, v in self.opts.items() if k not in ['sigmas']} opts = {k: v for k, v in self.opts.items() if k not in ['sigmas']}
result = resample_bilinear(data, source_geo_def, target_geo_def, **opts) result = resample_bilinear(data, source_geo_def, target_geo_def, **opts).astype(data.dtype)
elif self.resamp_alg == 'gauss': elif self.resamp_alg == 'gauss':
opts = {k: v for k, v in self.opts.items()} opts = {k: v for k, v in self.opts.items()}
...@@ -266,13 +266,13 @@ class SensorMapGeometryTransformer(object): ...@@ -266,13 +266,13 @@ class SensorMapGeometryTransformer(object):
raise ValueError("The 'sigmas' parameter must have the same number of values like data.ndim." raise ValueError("The 'sigmas' parameter must have the same number of values like data.ndim."
"n_sigmas: %d; data.ndim: %d" % (len(opts['sigmas']), data.ndim)) "n_sigmas: %d; data.ndim: %d" % (len(opts['sigmas']), data.ndim))
result = resample_gauss(source_geo_def, data, target_geo_def, **opts) result = resample_gauss(source_geo_def, data, target_geo_def, **opts).astype(data.dtype)
elif self.resamp_alg == 'custom': elif self.resamp_alg == 'custom':
opts = {k: v for k, v in self.opts.items()} opts = {k: v for k, v in self.opts.items()}
if 'weight_funcs' not in opts: if 'weight_funcs' not in opts:
raise ValueError(opts, "Options must contain a 'weight_funcs' item.") raise ValueError(opts, "Options must contain a 'weight_funcs' item.")
result = resample_custom(source_geo_def, data, target_geo_def, **opts) result = resample_custom(source_geo_def, data, target_geo_def, **opts).astype(data.dtype)
else: else:
raise ValueError(self.resamp_alg) raise ValueError(self.resamp_alg)
...@@ -406,7 +406,7 @@ class SensorMapGeometryTransformer3D(object): ...@@ -406,7 +406,7 @@ class SensorMapGeometryTransformer3D(object):
- weight_funcs: <list of function objects or function object> [ONLY 'custom'] List of weight - weight_funcs: <list of function objects or function object> [ONLY 'custom'] List of weight
functions f(dist) to use for the weighting of each channel 1 to k. If only one functions f(dist) to use for the weighting of each channel 1 to k. If only one
channel is resampled weight_funcs is a single function object. channel is resampled weight_funcs is a single function object.
- fill_value: <int or None> Set undetermined pixels to this value. - fill_value: <int or None> Set undetermined pixels to this value (default: 0).
If fill_value is None a masked array is returned with undetermined pixels masked If fill_value is None a masked array is returned with undetermined pixels masked
- reduce_data: <bool> Perform initial coarse reduction of source dataset in order to reduce - reduce_data: <bool> Perform initial coarse reduction of source dataset in order to reduce
execution time execution time
......
...@@ -22,6 +22,6 @@ ...@@ -22,6 +22,6 @@
# You should have received a copy of the GNU Lesser General Public License along # You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>. # with this program. If not, see <http://www.gnu.org/licenses/>.
__version__ = '0.2.0' __version__ = '0.2.1'
__versionalias__ = '20200107.01' __versionalias__ = '20200310.01'
__author__ = 'Daniel Scheffler' __author__ = 'Daniel Scheffler'
...@@ -37,7 +37,7 @@ version = {} ...@@ -37,7 +37,7 @@ version = {}
with open("sensormapgeo/version.py") as version_file: with open("sensormapgeo/version.py") as version_file:
exec(version_file.read(), version) exec(version_file.read(), version)
requirements = ['numpy', 'gdal', 'pyresample>=1.11.0', 'py_tools_ds'] requirements = ['numpy', 'gdal', 'pyresample>=1.11.0', 'py_tools_ds>=0.14.26']
setup_requirements = [] setup_requirements = []
......
...@@ -21,7 +21,7 @@ dependencies: ...@@ -21,7 +21,7 @@ dependencies:
- ipython - ipython
- pip: - pip:
- py_tools_ds - py_tools_ds>=0.14.26
- sphinx-argparse - sphinx-argparse
- flake8 - flake8
- pycodestyle - pycodestyle
......
...@@ -68,23 +68,25 @@ class Test_SensorMapGeometryTransformer(TestCase): ...@@ -68,23 +68,25 @@ class Test_SensorMapGeometryTransformer(TestCase):
lats=self.lats, lats=self.lats,
resamp_alg=rsp_alg, resamp_alg=rsp_alg,
radius_of_influence=30 if rsp_alg != 'bilinear' else 45) radius_of_influence=30 if rsp_alg != 'bilinear' else 45)
dem_sensors_geo = SMGT.to_sensor_geometry(self.dem_map_geo, dem_sensor_geo = SMGT.to_sensor_geometry(self.dem_map_geo,
src_prj=32632, src_extent=self.dem_area_extent_coarse_subset_utm) src_prj=32632, src_extent=self.dem_area_extent_coarse_subset_utm)
self.assertIsInstance(dem_sensors_geo, np.ndarray) self.assertIsInstance(dem_sensor_geo, np.ndarray)
self.assertFalse(np.array_equal(np.unique(dem_sensors_geo), np.array([0]))) self.assertFalse(np.array_equal(np.unique(dem_sensor_geo), np.array([0])))
self.assertEquals(dem_sensors_geo.shape, (150, 1000)) self.assertEqual(dem_sensor_geo.shape, (150, 1000))
self.assertEqual(self.dem_map_geo.dtype, dem_sensor_geo.dtype)
def test_to_sensor_geometry_3DInput(self): def test_to_sensor_geometry_3DInput(self):
for rsp_alg in rsp_algs: for rsp_alg in rsp_algs:
SMGT = SensorMapGeometryTransformer(lons=self.lons, SMGT = SensorMapGeometryTransformer(lons=self.lons,
lats=self.lats, lats=self.lats,
resamp_alg=rsp_alg) resamp_alg=rsp_alg)
dem_sensors_geo = SMGT.to_sensor_geometry(np.dstack([self.dem_map_geo] * 2), dem_sensor_geo = SMGT.to_sensor_geometry(np.dstack([self.dem_map_geo] * 2),
src_prj=32632, src_extent=self.dem_area_extent_coarse_subset_utm) src_prj=32632, src_extent=self.dem_area_extent_coarse_subset_utm)
self.assertIsInstance(dem_sensors_geo, np.ndarray) self.assertIsInstance(dem_sensor_geo, np.ndarray)
self.assertFalse(np.array_equal(np.unique(dem_sensors_geo), np.array([0]))) self.assertFalse(np.array_equal(np.unique(dem_sensor_geo), np.array([0])))
self.assertEquals(dem_sensors_geo.shape, (150, 1000, 2)) self.assertEqual(dem_sensor_geo.shape, (150, 1000, 2))
self.assertTrue(np.array_equal(dem_sensors_geo[:, :, 0], dem_sensors_geo[:, :, 1])) self.assertTrue(np.array_equal(dem_sensor_geo[:, :, 0], dem_sensor_geo[:, :, 1]))
self.assertEqual(self.dem_map_geo.dtype, dem_sensor_geo.dtype)
def test_to_map_geometry_lonlat(self): def test_to_map_geometry_lonlat(self):
for rsp_alg in rsp_algs: for rsp_alg in rsp_algs:
...@@ -95,8 +97,8 @@ class Test_SensorMapGeometryTransformer(TestCase): ...@@ -95,8 +97,8 @@ class Test_SensorMapGeometryTransformer(TestCase):
# to Lon/Lat # to Lon/Lat
dem_map_geo, dem_gt, dem_prj = SMGT.to_map_geometry(self.dem_sensor_geo, tgt_prj=4326) dem_map_geo, dem_gt, dem_prj = SMGT.to_map_geometry(self.dem_sensor_geo, tgt_prj=4326)
self.assertIsInstance(dem_map_geo, np.ndarray) self.assertIsInstance(dem_map_geo, np.ndarray)
self.assertEquals(dem_map_geo.shape, (SMGT.area_definition.height, self.assertEqual(dem_map_geo.shape, (SMGT.area_definition.height,
SMGT.area_definition.width)) SMGT.area_definition.width))
xmin, xmax, ymin, ymax = corner_coord_to_minmax(get_corner_coordinates(gt=dem_gt, xmin, xmax, ymin, ymax = corner_coord_to_minmax(get_corner_coordinates(gt=dem_gt,
cols=dem_map_geo.shape[1], cols=dem_map_geo.shape[1],
rows=dem_map_geo.shape[0])) rows=dem_map_geo.shape[0]))
...@@ -106,6 +108,7 @@ class Test_SensorMapGeometryTransformer(TestCase): ...@@ -106,6 +108,7 @@ class Test_SensorMapGeometryTransformer(TestCase):
self.assertTrue(np.isclose(np.mean(dem_map_geo[dem_map_geo != 0]), self.assertTrue(np.isclose(np.mean(dem_map_geo[dem_map_geo != 0]),
np.mean(self.dem_sensor_geo), np.mean(self.dem_sensor_geo),
rtol=0.01)) rtol=0.01))
self.assertEqual(self.dem_sensor_geo.dtype, dem_map_geo.dtype)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
SMGT.to_map_geometry(self.dem_sensor_geo[:10, :10], tgt_prj=4326) # must have the shape of lons/lats SMGT.to_map_geometry(self.dem_sensor_geo[:10, :10], tgt_prj=4326) # must have the shape of lons/lats
...@@ -119,7 +122,7 @@ class Test_SensorMapGeometryTransformer(TestCase): ...@@ -119,7 +122,7 @@ class Test_SensorMapGeometryTransformer(TestCase):
# to UTM32 # to UTM32
dem_map_geo, dem_gt, dem_prj = SMGT.to_map_geometry(self.dem_sensor_geo, tgt_prj=32632, tgt_res=(30, 30)) dem_map_geo, dem_gt, dem_prj = SMGT.to_map_geometry(self.dem_sensor_geo, tgt_prj=32632, tgt_res=(30, 30))
self.assertIsInstance(dem_map_geo, np.ndarray) self.assertIsInstance(dem_map_geo, np.ndarray)
self.assertEquals(dem_map_geo.shape, (365, 975)) self.assertEqual(dem_map_geo.shape, (365, 975))
xmin, xmax, ymin, ymax = corner_coord_to_minmax(get_corner_coordinates(gt=dem_gt, xmin, xmax, ymin, ymax = corner_coord_to_minmax(get_corner_coordinates(gt=dem_gt,
cols=dem_map_geo.shape[1], cols=dem_map_geo.shape[1],
rows=dem_map_geo.shape[0])) rows=dem_map_geo.shape[0]))
...@@ -129,6 +132,7 @@ class Test_SensorMapGeometryTransformer(TestCase): ...@@ -129,6 +132,7 @@ class Test_SensorMapGeometryTransformer(TestCase):
self.assertTrue(np.isclose(np.mean(dem_map_geo[dem_map_geo != 0]), self.assertTrue(np.isclose(np.mean(dem_map_geo[dem_map_geo != 0]),
np.mean(self.dem_sensor_geo), np.mean(self.dem_sensor_geo),
rtol=0.01)) rtol=0.01))
self.assertEqual(self.dem_sensor_geo.dtype, dem_map_geo.dtype)
class Test_SensorMapGeometryTransformer3D(TestCase): class Test_SensorMapGeometryTransformer3D(TestCase):
...@@ -173,7 +177,7 @@ class Test_SensorMapGeometryTransformer3D(TestCase): ...@@ -173,7 +177,7 @@ class Test_SensorMapGeometryTransformer3D(TestCase):
# fixed numbers may fail here due to float uncertainty errors # fixed numbers may fail here due to float uncertainty errors
self.assertGreater(data_mapgeo_3D.shape[0], self.data_sensor_geo_3D.shape[0]) self.assertGreater(data_mapgeo_3D.shape[0], self.data_sensor_geo_3D.shape[0])
self.assertGreater(data_mapgeo_3D.shape[1], self.data_sensor_geo_3D.shape[1]) self.assertGreater(data_mapgeo_3D.shape[1], self.data_sensor_geo_3D.shape[1])
self.assertEquals(data_mapgeo_3D.shape[2], 2) self.assertEqual(data_mapgeo_3D.shape[2], 2)
xmin, xmax, ymin, ymax = corner_coord_to_minmax(get_corner_coordinates(gt=dem_gt, xmin, xmax, ymin, ymax = corner_coord_to_minmax(get_corner_coordinates(gt=dem_gt,
cols=data_mapgeo_3D.shape[1], cols=data_mapgeo_3D.shape[1],
rows=data_mapgeo_3D.shape[0])) rows=data_mapgeo_3D.shape[0]))
...@@ -183,6 +187,7 @@ class Test_SensorMapGeometryTransformer3D(TestCase): ...@@ -183,6 +187,7 @@ class Test_SensorMapGeometryTransformer3D(TestCase):
self.assertTrue(np.isclose(np.mean(data_mapgeo_3D[data_mapgeo_3D != 0]), self.assertTrue(np.isclose(np.mean(data_mapgeo_3D[data_mapgeo_3D != 0]),
np.mean(self.data_sensor_geo_3D), np.mean(self.data_sensor_geo_3D),
rtol=0.01)) rtol=0.01))
self.assertEqual(self.data_sensor_geo_3D.dtype, data_mapgeo_3D.dtype)
def test_to_sensor_geometry(self): def test_to_sensor_geometry(self):
for rsp_alg in rsp_algs: for rsp_alg in rsp_algs:
...@@ -193,4 +198,5 @@ class Test_SensorMapGeometryTransformer3D(TestCase): ...@@ -193,4 +198,5 @@ class Test_SensorMapGeometryTransformer3D(TestCase):
dem_sensors_geo = SMGT.to_sensor_geometry(self.data_map_geo_3D, dem_sensors_geo = SMGT.to_sensor_geometry(self.data_map_geo_3D,
src_prj=32632, src_extent=self.dem_area_extent_coarse_subset_utm) src_prj=32632, src_extent=self.dem_area_extent_coarse_subset_utm)
self.assertIsInstance(dem_sensors_geo, np.ndarray) self.assertIsInstance(dem_sensors_geo, np.ndarray)
self.assertEquals(dem_sensors_geo.shape, (150, 1000, 2)) self.assertEqual(dem_sensors_geo.shape, (150, 1000, 2))
self.assertEqual(self.data_map_geo_3D.dtype, dem_sensors_geo.dtype)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment