Skip to content

Commit

Permalink
Merge pull request #75 from wri/CIF-247-Increase-unit-test-coverage-f…
Browse files Browse the repository at this point in the history
…or-CIF

Cif 247 increase unit test coverage for cif
  • Loading branch information
kcartier-wri authored Sep 13, 2024
2 parents b4fcc0e + 3719d7a commit 50e39dc
Show file tree
Hide file tree
Showing 11 changed files with 465 additions and 306 deletions.
10 changes: 8 additions & 2 deletions city_metrix/layers/impervious_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@


class ImperviousSurface(Layer):
def __init__(self, **kwargs):
"""
Attributes:
spatial_resolution: raster resolution in meters (see https://github.com/stac-extensions/raster)
"""

def __init__(self, spatial_resolution=100, **kwargs):
super().__init__(**kwargs)
self.spatial_resolution = spatial_resolution

def get_data(self, bbox):
# load impervious_surface
Expand All @@ -19,5 +25,5 @@ def get_data(self, bbox):
.sum()
)

data = get_image_collection(imperv_surf, bbox, 100, "imperv surf")
data = get_image_collection(imperv_surf, bbox, self.spatial_resolution, "imperv surf")
return data.change_year_index
2 changes: 1 addition & 1 deletion city_metrix/layers/ndvi_sentinel2_gee.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class NdviSentinel2(Layer):
Notebook: https://github.com/wri/cities-cities4forests-indicators/blob/dev-eric/scripts/extract-VegetationCover.ipynb
Reference: https://en.wikipedia.org/wiki/Normalized_difference_vegetation_index
"""
def __init__(self, year=None, spatial_resolution=10, **kwargs):
def __init__(self, year=2021, spatial_resolution=10, **kwargs):
super().__init__(**kwargs)
self.year = year
self.spatial_resolution = spatial_resolution
Expand Down
15 changes: 8 additions & 7 deletions tests/resources/layer_dumps_for_br_lauro_de_freitas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@
def pytest_configure(config):
qgis_project_file = 'layers_for_br_lauro_de_freitas.qgz'

source_folder = os.path.dirname(__file__)
target_folder = get_target_folder_path()
create_target_folder(target_folder, True)
if RUN_DUMPS is True:
source_folder = os.path.dirname(__file__)
target_folder = get_target_folder_path()
create_target_folder(target_folder, True)

source_qgis_file = os.path.join(source_folder, qgis_project_file)
target_qgis_file = os.path.join(target_folder, qgis_project_file)
shutil.copyfile(source_qgis_file, target_qgis_file)
source_qgis_file = os.path.join(source_folder, qgis_project_file)
target_qgis_file = os.path.join(target_folder, qgis_project_file)
shutil.copyfile(source_qgis_file, target_qgis_file)

print("\n\033[93m QGIS project file and layer files written to folder %s.\033[0m\n" % target_folder)
print("\n\033[93m QGIS project file and layer files written to folder %s.\033[0m\n" % target_folder)

@pytest.fixture
def target_folder():
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
TreeCanopyHeight,
TreeCover,
UrbanLandUse,
WorldPop, Layer
WorldPop, Layer, ImperviousSurface
)
from .conftest import RUN_DUMPS, prep_output_path, verify_file_is_populated
from ...tools.general_tools import get_class_default_spatial_resolution
Expand Down Expand Up @@ -62,6 +62,13 @@ def test_write_high_land_surface_temperature(target_folder, bbox_info, target_sp
HighLandSurfaceTemperature(spatial_resolution=target_resolution).write(bbox_info.bounds, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

@pytest.mark.skipif(RUN_DUMPS == False, reason='Skipping since RUN_DUMPS set to False')
def test_write_impervious_surface(target_folder, bbox_info, target_spatial_resolution_multiplier):
file_path = prep_output_path(target_folder, 'impervious_surface.tif')
target_resolution = target_spatial_resolution_multiplier * get_class_default_spatial_resolution(ImperviousSurface())
LandSurfaceTemperature(spatial_resolution=target_resolution).write(bbox_info.bounds, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

@pytest.mark.skipif(RUN_DUMPS == False, reason='Skipping since RUN_DUMPS set to False')
def test_write_land_surface_temperature(target_folder, bbox_info, target_spatial_resolution_multiplier):
file_path = prep_output_path(target_folder, 'land_surface_temperature.tif')
Expand Down Expand Up @@ -100,7 +107,7 @@ def test_write_ndvi_sentinel2_gee(target_folder, bbox_info, target_spatial_resol

@pytest.mark.skipif(RUN_DUMPS == False, reason='Skipping since RUN_DUMPS set to False')
def test_write_openbuildings(target_folder, bbox_info, target_spatial_resolution_multiplier):
file_path = prep_output_path(target_folder, 'open_buildings.tif')
file_path = prep_output_path(target_folder, 'open_buildings.geojson')
OpenBuildings(bbox_info.country).write(bbox_info.bounds, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

Expand All @@ -113,7 +120,7 @@ def test_write_openbuildings(target_folder, bbox_info, target_spatial_resolution

@pytest.mark.skipif(RUN_DUMPS == False, reason='Skipping since RUN_DUMPS set to False')
def test_write_overture_buildings(target_folder, bbox_info, target_spatial_resolution_multiplier):
file_path = prep_output_path(target_folder, 'overture_buildings.tif')
file_path = prep_output_path(target_folder, 'overture_buildings.geojson')
OvertureBuildings().write(bbox_info.bounds, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

Expand Down
19 changes: 0 additions & 19 deletions tests/test_layer_dimensions.py

This file was deleted.

106 changes: 106 additions & 0 deletions tests/test_layer_metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import ee
import pytest

from city_metrix.layers import NdviSentinel2, TreeCover, Albedo, AlosDSM
from tests.resources.bbox_constants import BBOX_BRA_LAURO_DE_FREITAS_1
from city_metrix.layers.layer import get_image_collection

EE_IMAGE_DIMENSION_TOLERANCE = 1 # Tolerance compensates for variable results from GEE service
COUNTRY_CODE_FOR_BBOX = 'BRA'
BBOX = BBOX_BRA_LAURO_DE_FREITAS_1

'''
Evalues various metrics of returned datasets, such as max value, min value, mean value, and
array-dimension size.
'''

def test_read_image_collection():
ic = ee.ImageCollection("ESA/WorldCover/v100")
data = get_image_collection(ic, BBOX, 10, "test")

expected_crs = 32724
expected_x_size = 186
expected_y_size = 199

actual_crs = data.rio.crs
actual_x_size = data['x'].size
actual_y_size = data['y'].size

assert expected_crs == actual_crs
assert (
pytest.approx(expected_x_size, rel=EE_IMAGE_DIMENSION_TOLERANCE) == actual_x_size,
pytest.approx(expected_y_size, rel=EE_IMAGE_DIMENSION_TOLERANCE) == actual_y_size
)

def test_read_image_collection_scale():
ic = ee.ImageCollection("ESA/WorldCover/v100")
data = get_image_collection(ic, BBOX, 100, "test")

expected_x_size = 19
expected_y_size = 20

actual_x_size = data['x'].size
actual_y_size = data['y'].size

assert (
pytest.approx(expected_x_size, rel=EE_IMAGE_DIMENSION_TOLERANCE) == actual_x_size,
pytest.approx(expected_y_size, rel=EE_IMAGE_DIMENSION_TOLERANCE) == actual_y_size
)

def test_albedo_metrics():
data = Albedo().get_data(BBOX)

# Bounding values
expected_min_value = _convert_fraction_to_rounded_percent(0.03)
expected_max_value = _convert_fraction_to_rounded_percent(0.34)
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_alos_dsm_metrics():
data = AlosDSM().get_data(BBOX)

# Bounding values
expected_min_value = 16
expected_max_value = 86
actual_min_value = _convert_to_rounded_integer(data.values.min())
actual_max_value = _convert_to_rounded_integer(data.values.max())

# Value range
assert expected_min_value == actual_min_value
assert expected_max_value == actual_max_value


def test_ndvi_metrics():
data = NdviSentinel2(year=2023).get_data(BBOX)

# Bounding values
expected_min_value = _convert_fraction_to_rounded_percent(0.21)
expected_max_value = _convert_fraction_to_rounded_percent(0.85)
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 actual_min_value == expected_min_value
assert actual_max_value == expected_max_value


def test_tree_cover_metrics():
expected_mean_value = 54.0
actual_mean_value = TreeCover().get_data(BBOX).mean()
tolerance = 0.1
assert (
pytest.approx(expected_mean_value, rel=tolerance) == actual_mean_value
)

def _convert_fraction_to_rounded_percent(fraction):
return _convert_to_rounded_integer(fraction * 100)


def _convert_to_rounded_integer(value):
return int(round((value)))

Loading

0 comments on commit 50e39dc

Please sign in to comment.