From 73a77c3876b00f1c890aac2a800a81db5df3418a Mon Sep 17 00:00:00 2001 From: Kenn Cartier Date: Mon, 4 Nov 2024 17:24:22 -0800 Subject: [PATCH 1/6] Edited link for ERA5 setup --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56ae15e..4af03c1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ To run the module, 1. You need access to Google Earth Engine 2. Install - 3. If you want to use the ERA5 layer, you need to install the [Climate Data Store (CDS) Application Program Interface (API)](https://cds.climate.copernicus.eu/api-how-to) + 3. If you want to use the ERA5 layer, you need to install the [Climate Data Store (CDS) Application Program Interface (API)](https://cds.climate.copernicus.eu/how-to-api) ### Interactive development From 7a4012d325a208ae65f5c05ac19c6ba44555c142 Mon Sep 17 00:00:00 2001 From: Kenn Cartier Date: Tue, 17 Dec 2024 16:40:46 -0800 Subject: [PATCH 2/6] Added bilinear functionality for Albedo, DSM, and DEM --- city_metrix/layers/albedo.py | 7 +++++-- city_metrix/layers/alos_dsm.py | 3 ++- city_metrix/layers/layer.py | 14 ++++++++++++++ city_metrix/layers/nasa_dem.py | 3 ++- tests/resources/bbox_constants.py | 4 ++++ .../README.md | 0 .../__init__.py | 0 .../conftest.py | 5 +++-- .../test_write_all_layers.py | 0 .../test_write_layers_other.py | 0 .../test_write_layers_using_fixed_resolution.py | 2 +- 11 files changed, 31 insertions(+), 7 deletions(-) rename tests/resources/{layer_dumps_for_br_lauro_de_freitas => layer_dumps}/README.md (100%) rename tests/resources/{layer_dumps_for_br_lauro_de_freitas => layer_dumps}/__init__.py (100%) rename tests/resources/{layer_dumps_for_br_lauro_de_freitas => layer_dumps}/conftest.py (96%) rename tests/resources/{layer_dumps_for_br_lauro_de_freitas => layer_dumps}/test_write_all_layers.py (100%) rename tests/resources/{layer_dumps_for_br_lauro_de_freitas => layer_dumps}/test_write_layers_other.py (100%) rename tests/resources/{layer_dumps_for_br_lauro_de_freitas => layer_dumps}/test_write_layers_using_fixed_resolution.py (99%) diff --git a/city_metrix/layers/albedo.py b/city_metrix/layers/albedo.py index dc1780a..ff46bd0 100644 --- a/city_metrix/layers/albedo.py +++ b/city_metrix/layers/albedo.py @@ -1,6 +1,6 @@ import ee -from .layer import Layer, get_image_collection +from .layer import Layer, get_image_collection, set_bilinear_resampling class Albedo(Layer): """ @@ -115,7 +115,10 @@ def calc_s2_albedo(image): ## S2 MOSAIC AND ALBEDO dataset = get_masked_s2_collection(ee.Geometry.BBox(*bbox), self.start_date, self.end_date) s2_albedo = dataset.map(calc_s2_albedo) - albedo_mean = s2_albedo.reduce(ee.Reducer.mean()) + albedo_mean = (s2_albedo + .map(set_bilinear_resampling) + .reduce(ee.Reducer.mean()) + ) albedo_mean_ic = ee.ImageCollection(albedo_mean) data = get_image_collection( diff --git a/city_metrix/layers/alos_dsm.py b/city_metrix/layers/alos_dsm.py index c22df82..1e06066 100644 --- a/city_metrix/layers/alos_dsm.py +++ b/city_metrix/layers/alos_dsm.py @@ -1,6 +1,6 @@ import ee -from .layer import Layer, get_image_collection +from .layer import Layer, get_image_collection, set_bilinear_resampling class AlosDSM(Layer): @@ -18,6 +18,7 @@ def get_data(self, bbox): alos_dsm_ic = ee.ImageCollection(alos_dsm .filterBounds(ee.Geometry.BBox(*bbox)) + .map(set_bilinear_resampling) .select('DSM') .mean() ) diff --git a/city_metrix/layers/layer.py b/city_metrix/layers/layer.py index 3d2829f..c365f64 100644 --- a/city_metrix/layers/layer.py +++ b/city_metrix/layers/layer.py @@ -323,6 +323,20 @@ def get_stats_funcs(stats_func): return [stats_func] +def set_bilinear_resampling(data): + if isinstance(data, ee.ImageCollection): + resampled = data.map(_assign_bilinear_interpolation) + else: + resampled = data.resample('bilinear') + + return resampled + + +def _assign_bilinear_interpolation(dataset): + data = dataset.resample('bilinear') + return data + + def get_image_collection( image_collection: ImageCollection, bbox: Tuple[float], diff --git a/city_metrix/layers/nasa_dem.py b/city_metrix/layers/nasa_dem.py index d3840d3..6ed3c28 100644 --- a/city_metrix/layers/nasa_dem.py +++ b/city_metrix/layers/nasa_dem.py @@ -1,6 +1,6 @@ import ee -from .layer import Layer, get_image_collection +from .layer import Layer, get_image_collection, set_bilinear_resampling class NasaDEM(Layer): @@ -18,6 +18,7 @@ def get_data(self, bbox): nasa_dem_elev = (ee.ImageCollection(nasa_dem) .filterBounds(ee.Geometry.BBox(*bbox)) + .map(set_bilinear_resampling) .select('elevation') .mean() ) diff --git a/tests/resources/bbox_constants.py b/tests/resources/bbox_constants.py index 789ab48..01b1e15 100644 --- a/tests/resources/bbox_constants.py +++ b/tests/resources/bbox_constants.py @@ -24,3 +24,7 @@ -38.39993,-12.93239 ) +BBOX_NLD_AMSTERDAM_TEST = ( + 4.9012,52.3720, + 4.9083,52.3752 +) diff --git a/tests/resources/layer_dumps_for_br_lauro_de_freitas/README.md b/tests/resources/layer_dumps/README.md similarity index 100% rename from tests/resources/layer_dumps_for_br_lauro_de_freitas/README.md rename to tests/resources/layer_dumps/README.md diff --git a/tests/resources/layer_dumps_for_br_lauro_de_freitas/__init__.py b/tests/resources/layer_dumps/__init__.py similarity index 100% rename from tests/resources/layer_dumps_for_br_lauro_de_freitas/__init__.py rename to tests/resources/layer_dumps/__init__.py diff --git a/tests/resources/layer_dumps_for_br_lauro_de_freitas/conftest.py b/tests/resources/layer_dumps/conftest.py similarity index 96% rename from tests/resources/layer_dumps_for_br_lauro_de_freitas/conftest.py rename to tests/resources/layer_dumps/conftest.py index 6b33b51..9340996 100644 --- a/tests/resources/layer_dumps_for_br_lauro_de_freitas/conftest.py +++ b/tests/resources/layer_dumps/conftest.py @@ -4,7 +4,7 @@ import shutil from collections import namedtuple -from tests.resources.bbox_constants import BBOX_BRA_LAURO_DE_FREITAS_1 +from tests.resources.bbox_constants import BBOX_BRA_LAURO_DE_FREITAS_1, BBOX_NLD_AMSTERDAM_TEST from tests.tools.general_tools import create_target_folder, is_valid_path # RUN_DUMPS is the master control for whether the writes and tests are executed @@ -18,7 +18,8 @@ # Both the tests and QGIS file are implemented for the same bounding box in Brazil. COUNTRY_CODE_FOR_BBOX = 'BRA' -BBOX = BBOX_BRA_LAURO_DE_FREITAS_1 +# BBOX = BBOX_BRA_LAURO_DE_FREITAS_1 +BBOX = BBOX_NLD_AMSTERDAM_TEST # Specify None to write to a temporary default folder otherwise specify a valid custom target path. CUSTOM_DUMP_DIRECTORY = None diff --git a/tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_all_layers.py b/tests/resources/layer_dumps/test_write_all_layers.py similarity index 100% rename from tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_all_layers.py rename to tests/resources/layer_dumps/test_write_all_layers.py diff --git a/tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_layers_other.py b/tests/resources/layer_dumps/test_write_layers_other.py similarity index 100% rename from tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_layers_other.py rename to tests/resources/layer_dumps/test_write_layers_other.py diff --git a/tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_layers_using_fixed_resolution.py b/tests/resources/layer_dumps/test_write_layers_using_fixed_resolution.py similarity index 99% rename from tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_layers_using_fixed_resolution.py rename to tests/resources/layer_dumps/test_write_layers_using_fixed_resolution.py index 8964b86..0ca19c6 100644 --- a/tests/resources/layer_dumps_for_br_lauro_de_freitas/test_write_layers_using_fixed_resolution.py +++ b/tests/resources/layer_dumps/test_write_layers_using_fixed_resolution.py @@ -3,7 +3,7 @@ import pytest from city_metrix.layers import * -from .conftest import RUN_DUMPS, prep_output_path, verify_file_is_populated, get_file_count_in_folder +from .conftest import RUN_DUMPS, prep_output_path, verify_file_is_populated TARGET_RESOLUTION = 5 From 43f1c10a9a5ae106cd66dd8503a6db73fc355d2a Mon Sep 17 00:00:00 2001 From: Kenn Cartier Date: Tue, 17 Dec 2024 17:10:20 -0800 Subject: [PATCH 3/6] Added larger sampling area --- tests/resources/bbox_constants.py | 6 ++++++ tests/resources/layer_dumps/conftest.py | 10 ++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/resources/bbox_constants.py b/tests/resources/bbox_constants.py index 01b1e15..846f793 100644 --- a/tests/resources/bbox_constants.py +++ b/tests/resources/bbox_constants.py @@ -28,3 +28,9 @@ 4.9012,52.3720, 4.9083,52.3752 ) + +BBOX_NLD_AMSTERDAM_LARGE_TEST = ( + 4.884629880473071,52.34146514406914, + 4.914180290924863,52.359560786247165 +) + diff --git a/tests/resources/layer_dumps/conftest.py b/tests/resources/layer_dumps/conftest.py index 9340996..07faa75 100644 --- a/tests/resources/layer_dumps/conftest.py +++ b/tests/resources/layer_dumps/conftest.py @@ -4,13 +4,14 @@ import shutil from collections import namedtuple -from tests.resources.bbox_constants import BBOX_BRA_LAURO_DE_FREITAS_1, BBOX_NLD_AMSTERDAM_TEST +from tests.resources.bbox_constants import BBOX_BRA_LAURO_DE_FREITAS_1, BBOX_NLD_AMSTERDAM_TEST, \ + BBOX_NLD_AMSTERDAM_LARGE_TEST from tests.tools.general_tools import create_target_folder, is_valid_path # RUN_DUMPS is the master control for whether the writes and tests are executed # Setting RUN_DUMPS to True turns on code execution. # Values should normally be set to False in order to avoid unnecessary execution. -RUN_DUMPS = False +RUN_DUMPS = True # Multiplier applied to the default spatial_resolution of the layer # Use value of 1 for default resolution. @@ -18,8 +19,9 @@ # Both the tests and QGIS file are implemented for the same bounding box in Brazil. COUNTRY_CODE_FOR_BBOX = 'BRA' -# BBOX = BBOX_BRA_LAURO_DE_FREITAS_1 -BBOX = BBOX_NLD_AMSTERDAM_TEST +BBOX = BBOX_BRA_LAURO_DE_FREITAS_1 +# BBOX = BBOX_NLD_AMSTERDAM_TEST +# BBOX = BBOX_NLD_AMSTERDAM_LARGE_TEST # Specify None to write to a temporary default folder otherwise specify a valid custom target path. CUSTOM_DUMP_DIRECTORY = None From 14bfef616c0f39b45a872989fe98b0bd08dd751e Mon Sep 17 00:00:00 2001 From: Kenn Cartier Date: Tue, 17 Dec 2024 21:24:12 -0800 Subject: [PATCH 4/6] first attempt at adding optional resampling_method --- city_metrix/layers/albedo.py | 11 ++++++++--- city_metrix/layers/alos_dsm.py | 7 ++++--- city_metrix/layers/layer.py | 18 +++++++++--------- city_metrix/layers/nasa_dem.py | 7 ++++--- tests/test_layer_metrics.py | 4 +++- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/city_metrix/layers/albedo.py b/city_metrix/layers/albedo.py index ff46bd0..8596b7d 100644 --- a/city_metrix/layers/albedo.py +++ b/city_metrix/layers/albedo.py @@ -1,6 +1,7 @@ import ee -from .layer import Layer, get_image_collection, set_bilinear_resampling +from .layer import Layer, get_image_collection, set_resampling_method + class Albedo(Layer): """ @@ -11,11 +12,13 @@ class Albedo(Layer): threshold: threshold value for filtering the retrieval """ - def __init__(self, start_date="2021-01-01", end_date="2022-01-01", spatial_resolution=10, threshold=None, **kwargs): + def __init__(self, start_date="2021-01-01", end_date="2022-01-01", spatial_resolution=10, + resampling_method='bilinear', threshold=None, **kwargs): super().__init__(**kwargs) self.start_date = start_date self.end_date = end_date self.spatial_resolution = spatial_resolution + self.resampling_method = resampling_method self.threshold = threshold def get_data(self, bbox): @@ -116,7 +119,7 @@ def calc_s2_albedo(image): dataset = get_masked_s2_collection(ee.Geometry.BBox(*bbox), self.start_date, self.end_date) s2_albedo = dataset.map(calc_s2_albedo) albedo_mean = (s2_albedo - .map(set_bilinear_resampling) + .map(lambda x: set_resampling_method(x, self.resampling_method),) .reduce(ee.Reducer.mean()) ) @@ -132,3 +135,5 @@ def calc_s2_albedo(image): return data.where(data < self.threshold) return data + + diff --git a/city_metrix/layers/alos_dsm.py b/city_metrix/layers/alos_dsm.py index 1e06066..e1618db 100644 --- a/city_metrix/layers/alos_dsm.py +++ b/city_metrix/layers/alos_dsm.py @@ -1,6 +1,6 @@ import ee -from .layer import Layer, get_image_collection, set_bilinear_resampling +from .layer import Layer, get_image_collection, set_resampling_method class AlosDSM(Layer): @@ -9,16 +9,17 @@ class AlosDSM(Layer): spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) """ - def __init__(self, spatial_resolution=30, **kwargs): + def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs): super().__init__(**kwargs) self.spatial_resolution = spatial_resolution + self.resampling_method = resampling_method def get_data(self, bbox): alos_dsm = ee.ImageCollection("JAXA/ALOS/AW3D30/V3_2") alos_dsm_ic = ee.ImageCollection(alos_dsm .filterBounds(ee.Geometry.BBox(*bbox)) - .map(set_bilinear_resampling) + .map(lambda x: set_resampling_method(x, self.resampling_method),) .select('DSM') .mean() ) diff --git a/city_metrix/layers/layer.py b/city_metrix/layers/layer.py index c365f64..c41991e 100644 --- a/city_metrix/layers/layer.py +++ b/city_metrix/layers/layer.py @@ -323,17 +323,17 @@ def get_stats_funcs(stats_func): return [stats_func] -def set_bilinear_resampling(data): - if isinstance(data, ee.ImageCollection): - resampled = data.map(_assign_bilinear_interpolation) - else: - resampled = data.resample('bilinear') - - return resampled +def set_resampling_method(dataset, resampling_method): + valid_raster_resampling_methods = ['bilinear', 'bicubic', 'nearest'] + if resampling_method not in valid_raster_resampling_methods: + raise ValueError(f'Invalid resampling method ({resampling_method}). ' + f'Valid methods: ({valid_raster_resampling_methods})') -def _assign_bilinear_interpolation(dataset): - data = dataset.resample('bilinear') + if resampling_method != 'nearest': + data = dataset.resample(resampling_method) + else: + data = dataset return data diff --git a/city_metrix/layers/nasa_dem.py b/city_metrix/layers/nasa_dem.py index 6ed3c28..dab201a 100644 --- a/city_metrix/layers/nasa_dem.py +++ b/city_metrix/layers/nasa_dem.py @@ -1,6 +1,6 @@ import ee -from .layer import Layer, get_image_collection, set_bilinear_resampling +from .layer import Layer, get_image_collection, set_resampling_method class NasaDEM(Layer): @@ -9,16 +9,17 @@ class NasaDEM(Layer): spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) """ - def __init__(self, spatial_resolution=30, **kwargs): + def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs): super().__init__(**kwargs) self.spatial_resolution = spatial_resolution + self.resampling_method = resampling_method def get_data(self, bbox): nasa_dem = ee.Image("NASA/NASADEM_HGT/001") nasa_dem_elev = (ee.ImageCollection(nasa_dem) .filterBounds(ee.Geometry.BBox(*bbox)) - .map(set_bilinear_resampling) + .map(lambda x: set_resampling_method(x, self.resampling_method),) .select('elevation') .mean() ) diff --git a/tests/test_layer_metrics.py b/tests/test_layer_metrics.py index 0002f58..570b1f1 100644 --- a/tests/test_layer_metrics.py +++ b/tests/test_layer_metrics.py @@ -48,7 +48,9 @@ def test_read_image_collection_scale(): ) def test_albedo_metrics(): - data = Albedo().get_data(BBOX) + # data = Albedo(spatial_resolution=10, resampling_method='nearest').get_data(BBOX) + # data = Albedo(spatial_resolution=10, resampling_method='bilinear').get_data(BBOX) + data = Albedo(spatial_resolution=10, resampling_method='bicubic').get_data(BBOX) # Bounding values expected_min_value = _convert_fraction_to_rounded_percent(0.03) From b4ab1b060b06aa174c3e9df06b7c5f0dc5b5fc07 Mon Sep 17 00:00:00 2001 From: Kenn Cartier Date: Tue, 17 Dec 2024 21:46:03 -0800 Subject: [PATCH 5/6] renamed default resampling method --- city_metrix/layers/albedo.py | 1 + city_metrix/layers/alos_dsm.py | 1 + city_metrix/layers/layer.py | 13 +++++++------ city_metrix/layers/nasa_dem.py | 1 + tests/test_layer_metrics.py | 5 +++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/city_metrix/layers/albedo.py b/city_metrix/layers/albedo.py index 8596b7d..da63bb1 100644 --- a/city_metrix/layers/albedo.py +++ b/city_metrix/layers/albedo.py @@ -9,6 +9,7 @@ class Albedo(Layer): start_date: starting date for data retrieval end_date: ending date for data retrieval spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) + resampling_method: interpolation method used by Google Earth Engine. Albedo default is 'bilinear'. All options are: ('bilinear', 'bicubic', 'default'). threshold: threshold value for filtering the retrieval """ diff --git a/city_metrix/layers/alos_dsm.py b/city_metrix/layers/alos_dsm.py index e1618db..ca34ef6 100644 --- a/city_metrix/layers/alos_dsm.py +++ b/city_metrix/layers/alos_dsm.py @@ -7,6 +7,7 @@ class AlosDSM(Layer): """ Attributes: spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) + resampling_method: interpolation method used by Google Earth Engine. AlosDSM default is 'bilinear'. All options are: ('bilinear', 'bicubic', 'default'). """ def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs): diff --git a/city_metrix/layers/layer.py b/city_metrix/layers/layer.py index c41991e..d30deeb 100644 --- a/city_metrix/layers/layer.py +++ b/city_metrix/layers/layer.py @@ -324,16 +324,17 @@ def get_stats_funcs(stats_func): def set_resampling_method(dataset, resampling_method): - valid_raster_resampling_methods = ['bilinear', 'bicubic', 'nearest'] + valid_raster_resampling_methods = ['bilinear', 'bicubic', 'default'] if resampling_method not in valid_raster_resampling_methods: - raise ValueError(f'Invalid resampling method ({resampling_method}). ' - f'Valid methods: ({valid_raster_resampling_methods})') + raise ValueError(f"Invalid resampling method ('{resampling_method}'). " + f"Valid methods: {valid_raster_resampling_methods}") - if resampling_method != 'nearest': - data = dataset.resample(resampling_method) - else: + if resampling_method == 'default': data = dataset + else: + data = dataset.resample(resampling_method) + return data diff --git a/city_metrix/layers/nasa_dem.py b/city_metrix/layers/nasa_dem.py index dab201a..baf66af 100644 --- a/city_metrix/layers/nasa_dem.py +++ b/city_metrix/layers/nasa_dem.py @@ -7,6 +7,7 @@ class NasaDEM(Layer): """ Attributes: spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) + resampling_method: interpolation method used by Google Earth Engine. NasaDEM default is 'bilinear'. All options are: ('bilinear', 'bicubic', 'default'). """ def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs): diff --git a/tests/test_layer_metrics.py b/tests/test_layer_metrics.py index 570b1f1..434b211 100644 --- a/tests/test_layer_metrics.py +++ b/tests/test_layer_metrics.py @@ -48,9 +48,10 @@ def test_read_image_collection_scale(): ) def test_albedo_metrics(): - # data = Albedo(spatial_resolution=10, resampling_method='nearest').get_data(BBOX) + data = Albedo(spatial_resolution=10).get_data(BBOX) + # data = Albedo(spatial_resolution=10, resampling_method='default').get_data(BBOX) # data = Albedo(spatial_resolution=10, resampling_method='bilinear').get_data(BBOX) - data = Albedo(spatial_resolution=10, resampling_method='bicubic').get_data(BBOX) + # data = Albedo(spatial_resolution=10, resampling_method='bicubic').get_data(BBOX) # Bounding values expected_min_value = _convert_fraction_to_rounded_percent(0.03) From 5b0b2d8097f7fecfd5cf2f56de1682f39e53c4a0 Mon Sep 17 00:00:00 2001 From: Kenn Cartier Date: Wed, 18 Dec 2024 09:53:02 -0800 Subject: [PATCH 6/6] Added handling of no resampling --- city_metrix/layers/albedo.py | 16 +++++++++++----- city_metrix/layers/alos_dsm.py | 23 ++++++++++++++++------- city_metrix/layers/layer.py | 9 +++------ city_metrix/layers/nasa_dem.py | 21 ++++++++++++++------- tests/resources/layer_dumps/conftest.py | 2 +- tests/test_layer_metrics.py | 23 ++++++++++++++++++----- 6 files changed, 63 insertions(+), 31 deletions(-) diff --git a/city_metrix/layers/albedo.py b/city_metrix/layers/albedo.py index da63bb1..d8f1430 100644 --- a/city_metrix/layers/albedo.py +++ b/city_metrix/layers/albedo.py @@ -9,7 +9,7 @@ class Albedo(Layer): start_date: starting date for data retrieval end_date: ending date for data retrieval spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) - resampling_method: interpolation method used by Google Earth Engine. Albedo default is 'bilinear'. All options are: ('bilinear', 'bicubic', 'default'). + resampling_method: interpolation method used by Google Earth Engine. Albedo default is 'bilinear'. All options are: ('bilinear', 'bicubic', None). threshold: threshold value for filtering the retrieval """ @@ -119,10 +119,16 @@ def calc_s2_albedo(image): ## S2 MOSAIC AND ALBEDO dataset = get_masked_s2_collection(ee.Geometry.BBox(*bbox), self.start_date, self.end_date) s2_albedo = dataset.map(calc_s2_albedo) - albedo_mean = (s2_albedo - .map(lambda x: set_resampling_method(x, self.resampling_method),) - .reduce(ee.Reducer.mean()) - ) + + if self.resampling_method is not None: + albedo_mean = (s2_albedo + .map(lambda x: set_resampling_method(x, self.resampling_method)) + .reduce(ee.Reducer.mean()) + ) + else: + albedo_mean = (s2_albedo + .reduce(ee.Reducer.mean()) + ) albedo_mean_ic = ee.ImageCollection(albedo_mean) data = get_image_collection( diff --git a/city_metrix/layers/alos_dsm.py b/city_metrix/layers/alos_dsm.py index ca34ef6..4d5db37 100644 --- a/city_metrix/layers/alos_dsm.py +++ b/city_metrix/layers/alos_dsm.py @@ -7,7 +7,7 @@ class AlosDSM(Layer): """ Attributes: spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) - resampling_method: interpolation method used by Google Earth Engine. AlosDSM default is 'bilinear'. All options are: ('bilinear', 'bicubic', 'default'). + resampling_method: interpolation method used by Google Earth Engine. AlosDSM default is 'bilinear'. All options are: ('bilinear', 'bicubic', None). """ def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs): @@ -18,12 +18,21 @@ def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs def get_data(self, bbox): alos_dsm = ee.ImageCollection("JAXA/ALOS/AW3D30/V3_2") - alos_dsm_ic = ee.ImageCollection(alos_dsm - .filterBounds(ee.Geometry.BBox(*bbox)) - .map(lambda x: set_resampling_method(x, self.resampling_method),) - .select('DSM') - .mean() - ) + if self.resampling_method is not None: + alos_dsm_ic = ee.ImageCollection( + alos_dsm + .filterBounds(ee.Geometry.BBox(*bbox)) + .map(lambda x: set_resampling_method(x, self.resampling_method), ) + .select('DSM') + .mean() + ) + else: + alos_dsm_ic = ee.ImageCollection( + alos_dsm + .filterBounds(ee.Geometry.BBox(*bbox)) + .select('DSM') + .mean() + ) data = get_image_collection( alos_dsm_ic, diff --git a/city_metrix/layers/layer.py b/city_metrix/layers/layer.py index d30deeb..336b3ee 100644 --- a/city_metrix/layers/layer.py +++ b/city_metrix/layers/layer.py @@ -323,17 +323,14 @@ def get_stats_funcs(stats_func): return [stats_func] -def set_resampling_method(dataset, resampling_method): - valid_raster_resampling_methods = ['bilinear', 'bicubic', 'default'] +def set_resampling_method(image: ee.Image, resampling_method: str): + valid_raster_resampling_methods = ['bilinear', 'bicubic'] if resampling_method not in valid_raster_resampling_methods: raise ValueError(f"Invalid resampling method ('{resampling_method}'). " f"Valid methods: {valid_raster_resampling_methods}") - if resampling_method == 'default': - data = dataset - else: - data = dataset.resample(resampling_method) + data = image.resample(resampling_method) return data diff --git a/city_metrix/layers/nasa_dem.py b/city_metrix/layers/nasa_dem.py index baf66af..bcdd48a 100644 --- a/city_metrix/layers/nasa_dem.py +++ b/city_metrix/layers/nasa_dem.py @@ -7,7 +7,7 @@ class NasaDEM(Layer): """ Attributes: spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster) - resampling_method: interpolation method used by Google Earth Engine. NasaDEM default is 'bilinear'. All options are: ('bilinear', 'bicubic', 'default'). + resampling_method: interpolation method used by Google Earth Engine. NasaDEM default is 'bilinear'. All options are: ('bilinear', 'bicubic', None). """ def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs): @@ -18,12 +18,19 @@ def __init__(self, spatial_resolution=30, resampling_method='bilinear', **kwargs def get_data(self, bbox): nasa_dem = ee.Image("NASA/NASADEM_HGT/001") - nasa_dem_elev = (ee.ImageCollection(nasa_dem) - .filterBounds(ee.Geometry.BBox(*bbox)) - .map(lambda x: set_resampling_method(x, self.resampling_method),) - .select('elevation') - .mean() - ) + if self.resampling_method is not None: + nasa_dem_elev = (ee.ImageCollection(nasa_dem) + .filterBounds(ee.Geometry.BBox(*bbox)) + .map(lambda x: set_resampling_method(x, self.resampling_method), ) + .select('elevation') + .mean() + ) + else: + nasa_dem_elev = (ee.ImageCollection(nasa_dem) + .filterBounds(ee.Geometry.BBox(*bbox)) + .select('elevation') + .mean() + ) nasa_dem_elev_ic = ee.ImageCollection(nasa_dem_elev) data = get_image_collection( diff --git a/tests/resources/layer_dumps/conftest.py b/tests/resources/layer_dumps/conftest.py index 07faa75..9a5dd9a 100644 --- a/tests/resources/layer_dumps/conftest.py +++ b/tests/resources/layer_dumps/conftest.py @@ -11,7 +11,7 @@ # RUN_DUMPS is the master control for whether the writes and tests are executed # Setting RUN_DUMPS to True turns on code execution. # Values should normally be set to False in order to avoid unnecessary execution. -RUN_DUMPS = True +RUN_DUMPS = False # Multiplier applied to the default spatial_resolution of the layer # Use value of 1 for default resolution. diff --git a/tests/test_layer_metrics.py b/tests/test_layer_metrics.py index 434b211..659af0c 100644 --- a/tests/test_layer_metrics.py +++ b/tests/test_layer_metrics.py @@ -47,11 +47,24 @@ def test_read_image_collection_scale(): pytest.approx(expected_y_size, rel=EE_IMAGE_DIMENSION_TOLERANCE) == actual_y_size ) -def test_albedo_metrics(): + +def test_albedo_metrics_default_resampling(): + # Default resampling_method is bilinear data = Albedo(spatial_resolution=10).get_data(BBOX) - # data = Albedo(spatial_resolution=10, resampling_method='default').get_data(BBOX) - # data = Albedo(spatial_resolution=10, resampling_method='bilinear').get_data(BBOX) - # data = Albedo(spatial_resolution=10, resampling_method='bicubic').get_data(BBOX) + + # Bounding values + expected_min_value = _convert_fraction_to_rounded_percent(0.03) + expected_max_value = _convert_fraction_to_rounded_percent(0.32) + actual_min_value = _convert_fraction_to_rounded_percent(data.values.min()) + actual_max_value = _convert_fraction_to_rounded_percent(data.values.max()) + + # Value range + assert expected_min_value == actual_min_value + assert expected_max_value == actual_max_value + + +def test_albedo_metrics_no_resampling(): + data = Albedo(spatial_resolution=10, resampling_method= None).get_data(BBOX) # Bounding values expected_min_value = _convert_fraction_to_rounded_percent(0.03) @@ -65,7 +78,7 @@ def test_albedo_metrics(): def test_alos_dsm_metrics(): - data = AlosDSM().get_data(BBOX) + data = AlosDSM(resampling_method= None).get_data(BBOX) # Bounding values expected_min_value = 16