Skip to content

Commit

Permalink
Use pytest to dump layers to geotiff files
Browse files Browse the repository at this point in the history
  • Loading branch information
kcartier-wri committed Aug 14, 2024
1 parent 67957f3 commit 0d026e3
Show file tree
Hide file tree
Showing 9 changed files with 5,391 additions and 27 deletions.
5 changes: 3 additions & 2 deletions city_metrix/layers/high_land_surface_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def addDate(image):
# convert to date object
return datetime.datetime.strptime(hottest_date, "%Y%m%d").date()

def write(self, output_path):
self.data.rio.to_raster(output_path)
# TODO: Is this inherited class function needed?
# def write(self, output_path):
# self.data.rio.to_raster(output_path)


5 changes: 3 additions & 2 deletions city_metrix/layers/land_surface_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ def apply_scale_factors(image):
data = get_image_collection(ee.ImageCollection(l8_st), bbox, 30, "LST").ST_B10_mean
return data

def write(self, output_path):
self.data.rio.to_raster(output_path)
# TODO: Is this inherited class function needed?
# def write(self, output_path):
# self.data.rio.to_raster(output_path)


2 changes: 1 addition & 1 deletion tests/fixtures/bbox_constants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# File defines bboxes using in the test code


BBOX_BRAZIL_LAURO_DE_FREITAS_1 = (
BBOX_BR_LAURO_DE_FREITAS_1 = (
-38.35530428121955,
-12.821710300686393,
-38.33813814352424,
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# QGIS project files
QGIS files are used for testing layers geotiff files
5,175 changes: 5,175 additions & 0 deletions tests/resources/layers_for_br_lauro_de_freitas.qgs

Large diffs are not rendered by default.

43 changes: 22 additions & 21 deletions tests/test_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,36 @@
WorldPop
)
from city_metrix.layers.layer import get_image_collection
from tests.fixtures.bbox_constants import BBOX_BRAZIL_LAURO_DE_FREITAS_1
from tests.fixtures.bbox_constants import BBOX_BR_LAURO_DE_FREITAS_1

EE_IMAGE_DIMENSION_TOLERANCE = 1 # Tolerance compensates for variable results from GEE service


def test_albedo():
assert Albedo().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).mean()
assert Albedo().get_data(BBOX_BR_LAURO_DE_FREITAS_1).mean()


def test_alos_dsm():
mean = AlosDSM().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).mean()
mean = AlosDSM().get_data(BBOX_BR_LAURO_DE_FREITAS_1).mean()
assert mean


def test_average_net_building_height():
assert AverageNetBuildingHeight().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).mean()
assert AverageNetBuildingHeight().get_data(BBOX_BR_LAURO_DE_FREITAS_1).mean()


def test_esa_world_cover():
count = (
EsaWorldCover(land_cover_class=EsaWorldCoverClass.BUILT_UP)
.get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
.get_data(BBOX_BR_LAURO_DE_FREITAS_1)
.count()
)
assert count


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

expected_crs = 32724
expected_x_dimension = 187
Expand All @@ -67,76 +68,76 @@ def test_read_image_collection():

def test_read_image_collection_scale():
ic = ee.ImageCollection("ESA/WorldCover/v100")
data = get_image_collection(ic, BBOX_BRAZIL_LAURO_DE_FREITAS_1, 100, "test")
data = get_image_collection(ic, BBOX_BR_LAURO_DE_FREITAS_1, 100, "test")
expected_x_dimension = 19
expected_y_dimension = 20
assert data.dims == {"x": expected_x_dimension, "y": expected_y_dimension}


def test_high_land_surface_temperature():
data = HighLandSurfaceTemperature().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
data = HighLandSurfaceTemperature().get_data(BBOX_BR_LAURO_DE_FREITAS_1)
assert data.any()


def test_land_surface_temperature():
mean_lst = LandSurfaceTemperature().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).mean()
mean_lst = LandSurfaceTemperature().get_data(BBOX_BR_LAURO_DE_FREITAS_1).mean()
assert mean_lst


def test_landsat_collection_2():
bands = ['green']
data = LandsatCollection2(bands).get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
data = LandsatCollection2(bands).get_data(BBOX_BR_LAURO_DE_FREITAS_1)
assert data.any()


def test_nasa_dem():
mean = NasaDEM().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).mean()
mean = NasaDEM().get_data(BBOX_BR_LAURO_DE_FREITAS_1).mean()
assert mean


def test_natural_areas():
data = NaturalAreas().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
data = NaturalAreas().get_data(BBOX_BR_LAURO_DE_FREITAS_1)
assert data.any()


def test_openbuildings():
count = OpenBuildings().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).count().sum()
count = OpenBuildings().get_data(BBOX_BR_LAURO_DE_FREITAS_1).count().sum()
assert count


def test_open_street_map():
count = (
OpenStreetMap(osm_class=OpenStreetMapClass.ROAD)
.get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
.get_data(BBOX_BR_LAURO_DE_FREITAS_1)
.count()
.sum()
)
assert count


def test_overture_buildings():
count = OvertureBuildings().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).count().sum()
count = OvertureBuildings().get_data(BBOX_BR_LAURO_DE_FREITAS_1).count().sum()
assert count


def test_sentinel_2_level2():
sentinel_2_bands = ["green"]
data = Sentinel2Level2(sentinel_2_bands).get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
data = Sentinel2Level2(sentinel_2_bands).get_data(BBOX_BR_LAURO_DE_FREITAS_1)
assert data.any()


def test_smart_surface_lulc():
count = SmartSurfaceLULC().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).count()
count = SmartSurfaceLULC().get_data(BBOX_BR_LAURO_DE_FREITAS_1).count()
assert count


def test_tree_canopy_height():
count = TreeCanopyHeight().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).count()
count = TreeCanopyHeight().get_data(BBOX_BR_LAURO_DE_FREITAS_1).count()
assert count


def test_tree_cover():
actual = TreeCover().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).mean()
actual = TreeCover().get_data(BBOX_BR_LAURO_DE_FREITAS_1).mean()
expected = 54.0
tolerance = 0.1
assert (
Expand All @@ -145,9 +146,9 @@ def test_tree_cover():


def test_urban_land_use():
assert UrbanLandUse().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1).count()
assert UrbanLandUse().get_data(BBOX_BR_LAURO_DE_FREITAS_1).count()


def test_world_pop():
data = WorldPop().get_data(BBOX_BRAZIL_LAURO_DE_FREITAS_1)
data = WorldPop().get_data(BBOX_BR_LAURO_DE_FREITAS_1)
assert data.any()
1 change: 0 additions & 1 deletion tests/test_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
MockLayer,
MockMaskLayer,
)
from .fixtures.bbox_constants import *


def test_count():
Expand Down
165 changes: 165 additions & 0 deletions tests/test_write_layers_to_geotiff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import pytest
import os
import shutil

from city_metrix.layers import (
Albedo,
AlosDSM,
AverageNetBuildingHeight,
EsaWorldCover,
HighLandSurfaceTemperature,
LandsatCollection2,
LandSurfaceTemperature,
NasaDEM,
NaturalAreas,
OpenBuildings,
OpenStreetMap,
OvertureBuildings,
Sentinel2Level2,
SmartSurfaceLULC,
TreeCanopyHeight,
TreeCover,
UrbanLandUse,
WorldPop
)
from tests.fixtures.bbox_constants import *
from tools.general_tools import create_temp_folder, verify_file_is_populated

RUN_DUMPS = False
BBOX = BBOX_BR_LAURO_DE_FREITAS_1

@pytest.mark.skipif(RUN_DUMPS == False, reason='Skipping since RUN_DUMPS set to False')
def test_prepare_target():
qgis_project_file = 'layers_for_br_lauro_de_freitas.qgs'

source_folder = os.path.join(os.path.dirname(__file__), 'resources')
output_temp_folder = create_temp_folder('test_result_tif_files')
source_qgis_file = os.path.join(source_folder, qgis_project_file)
target_qgis_file = os.path.join(output_temp_folder, qgis_project_file)
shutil.copyfile(source_qgis_file, target_qgis_file)

process_layers(output_temp_folder)


def process_layers(output_temp_folder):
write_albedo(output_temp_folder)
write_alos_dsm(output_temp_folder)
write_average_net_building_height(output_temp_folder)
write_esa_world_cover(output_temp_folder)
write_high_land_surface_temperature(output_temp_folder)
write_land_surface_temperature(output_temp_folder)
# write_landsat_collection_2(output_temp_folder)
write_nasa_dem(output_temp_folder)
write_natural_areas(output_temp_folder)
write_openbuildings(output_temp_folder)
# write_open_street_map(output_temp_folder)
write_overture_buildings(output_temp_folder)
# write_sentinel_2_level2(output_temp_folder)
write_smart_surface_lulc(output_temp_folder)
write_tree_canopy_height(output_temp_folder)
write_tree_cover(output_temp_folder)
write_urban_land_use(output_temp_folder)
write_world_pop(output_temp_folder)


def write_albedo(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'albedo.tif')
Albedo().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_alos_dsm(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'alos_dsm.tif')
AlosDSM().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_average_net_building_height(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'average_net_building_height.tif')
AverageNetBuildingHeight().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_esa_world_cover(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'esa_world_cover.tif')
EsaWorldCover().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_high_land_surface_temperature(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'high_land_surface_temperature.tif')
HighLandSurfaceTemperature().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_land_surface_temperature(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'land_surface_temperature.tif')
LandSurfaceTemperature().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

# TODO: Determine how to output xarray.Dataset with time dimension for QGIS rendering
# def write_landsat_collection_2(output_temp_folder):
# file_path = prep_output_path(output_temp_folder, 'landsat_collection2.tif')
# bands = ['green']
# LandsatCollection2(bands).write(BBOX, file_path, tile_degrees=None)
# assert verify_file_is_populated(file_path)

def write_nasa_dem(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'nasa_dem.tif')
NasaDEM().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_natural_areas(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'natural_areas.tif')
NaturalAreas().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_openbuildings(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'open_buildings.tif')
OpenBuildings().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

# TODO: class function "write" does not properly handle call
# def write_open_street_map(output_temp_folder):
# file_path = prep_output_path(output_temp_folder, 'open_street_map.tif')
# OpenStreetMap().write(BBOX, file_path, tile_degrees=None)
# assert verify_file_is_populated(file_path)

def write_overture_buildings(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'overture_buildings.tif')
OvertureBuildings().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

# TODO: Determine how to output xarray.Dataset with time dimension for QGIS rendering
# def write_sentinel_2_level2(output_temp_folder):
# file_path = prep_output_path(output_temp_folder, 'sentinel_2_level2.tif')
# sentinel_2_bands = ["green"]
# Sentinel2Level2(sentinel_2_bands).write(BBOX, file_path, tile_degrees=None)
# assert verify_file_is_populated(file_path)

def write_smart_surface_lulc(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'smart_surface_lulc.tif')
SmartSurfaceLULC().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_tree_canopy_height(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'tree_canopy_height.tif')
TreeCanopyHeight().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_tree_cover(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'tree_cover.tif')
TreeCover().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_urban_land_use(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'urban_land_use.tif')
UrbanLandUse().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)

def write_world_pop(output_temp_folder):
file_path = prep_output_path(output_temp_folder, 'world_pop.tif')
WorldPop().write(BBOX, file_path, tile_degrees=None)
assert verify_file_is_populated(file_path)


def prep_output_path(output_temp_folder, file_name):
file_path = os.path.join(output_temp_folder, file_name)
if os.path.isfile(file_path):
os.remove(file_path)
return file_path
20 changes: 20 additions & 0 deletions tools/general_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import platform
import os

def create_temp_folder(sub_directory):
if platform.system() == 'Linux':
path = '/tmp/%s' % sub_directory
elif platform.system() == 'Windows':
localappdata_path = os.getenv("LOCALAPPDATA")
path = r'%s\Temp\%s' % (localappdata_path, sub_directory)
else:
raise ValueError('Method not implemented for this OS.')

if os.path.isdir(path) == False:
os.makedirs(path)

return path

def verify_file_is_populated(file_path):
is_populated = True if os.path.getsize(file_path) > 0 else False
return is_populated

0 comments on commit 0d026e3

Please sign in to comment.