Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i.emissivity: added test file for i.emissivity module #5127

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
162 changes: 162 additions & 0 deletions imagery/i.emissivity/testsuite/test_i_emissivity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from grass.gunittest.case import TestCase
from grass.gunittest.main import test


class TestIEmissivity(TestCase):
"""Test case for the i.emissivity module."""

@classmethod
def setUpClass(cls):
"""Set up input rasters and configure test environment."""
cls.use_temp_region()

cls.input_raster = "ndvi_test_map"
cls.output_raster = "emissivity_test_output"
cls.reference_raster = "emissivity_reference_map"
cls.temp_rasters = []

cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10)

# Predefined NDVI test cases
cls.ndvi_cases = {
"default": "if(row() <= 5, 0.2, 0.7)",
"valid_range": "if(col() == 1, 0.16, if(col() == 2, 0.74, 0.45))",
"extreme_values": "if(col() == 1, -1, if(col() == 2, 1.2, 0.5))",
}

cls.runModule(
"r.mapcalc",
expression=f"{cls.input_raster} = {cls.ndvi_cases['default']}",
overwrite=True,
)
cls.temp_rasters.append(cls.input_raster)

cls.runModule(
"r.mapcalc",
expression=f"{cls.reference_raster} = if(row() <= 5, 0.9, 0.95)",
overwrite=True,
)
cls.temp_rasters.append(cls.reference_raster)

@classmethod
def tearDownClass(cls):
"""Clean up generated data and reset the region."""
for raster in cls.temp_rasters + [cls.output_raster]:
cls.runModule("g.remove", type="raster", name=raster, flags="f")
cls.del_temp_region()

def test_emissivity_ndvi_range(self):
"""Test with NDVI values in the valid range using reference statistics."""
self.runModule(
"r.mapcalc",
expression=f"{self.input_raster} = {self.ndvi_cases['valid_range']}",
overwrite=True,
)
self.assertModule(
"i.emissivity",
input=self.input_raster,
output=self.output_raster,
overwrite=True,
)

# Reference statistics for the expected output
# These values are derived from the emissivity formula:
# For col 1 (NDVI = 0.16): emissivity = 0.97
# For col 2 (NDVI = 0.74): emissivity = 0.99
# For col 3+ (NDVI = 0.45): emissivity = 0.97 + 0.003 * 0.45 = 0.97135
reference_stats = {
"mean": 0.97712, # (0.97 + 0.99 + 0.97135) / 3
"min": 0.92,
"max": 0.99,
}
self.assertRasterFitsUnivar(
raster=self.output_raster, reference=reference_stats, precision=1e-2
)

def test_complex_mask(self):
"""Test with a complex mask involving irregular shape and regions."""
self.runModule(
"r.mapcalc",
expression="MASK = if((row() + col()) % 3 == 0 || row() < 3, 1, null())",
overwrite=True,
)
self.temp_rasters.append("MASK")

self.assertModule(
"i.emissivity",
input=self.input_raster,
output=self.output_raster,
overwrite=True,
)

self.runModule(
"r.mapcalc",
expression=f"masked_reference = if(isnull(MASK), null(), {self.reference_raster})",
overwrite=True,
)
self.temp_rasters.append("masked_reference")

self.runModule(
"r.mapcalc",
expression=f"diff_raster = abs({self.output_raster} - masked_reference)",
overwrite=True,
)
self.temp_rasters.append("diff_raster")

self.assertRasterMinMax("diff_raster", 0, 0.05)
self.runModule("r.mask", flags="r")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to remove the mask before you test the outputs.

It should be enough to check with assertRasterFitsUnivar, e.g., the mean, min, max and non-null cells.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I have removed the mask before testing the outputs and updated the test to use assertRasterFitsUnivar to check the mean, min and max as suggested.


def test_region_resolution(self):
"""Test the module behaviour with different region resolutions."""
results = {}
for res in [1, 0.1]:
with self.subTest(res=res):
self.runModule("g.region", n=10, s=0, e=10, w=0, res=res)
self.runModule(
"r.mapcalc", expression=f"{self.input_raster} = 0.6", overwrite=True
)
self.assertModule(
"i.emissivity",
input=self.input_raster,
output=self.output_raster,
overwrite=True,
)
results[res] = self.assertRasterMinMax(self.output_raster, 0, 1)

self.assertAlmostEqual(results[1], results[0.1], delta=0.01)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see much value in this test for i.emissivity specifically

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replaced the previous test with the new one focused on default emissivity calculation using critical NDVI values. This ensures that if the module is changed in the future, the test will catch it by failing.


def test_partial_null_values(self):
"""Test the module behavior when NDVI has null values."""
self.runModule(
"r.mapcalc",
expression=f"{self.input_raster} = if(col() % 2 == 0, null(), 0.5)",
overwrite=True,
)
self.assertModule(
"i.emissivity",
input=self.input_raster,
output=self.output_raster,
overwrite=True,
)
self.assertRasterExists(self.output_raster)
self.assertRasterMinMax(self.output_raster, 0, 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would test with assertRasterFitsUnivar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the test to use assertRasterFitsUnivar for validation.


def test_extreme_ndvi_values(self):
"""Test with extreme NDVI values beyond the valid range."""
self.runModule(
"r.mapcalc",
expression=f"{self.input_raster} = {self.ndvi_cases['extreme_values']}",
overwrite=True,
)
self.assertModule(
"i.emissivity",
input=self.input_raster,
output=self.output_raster,
overwrite=True,
)
self.assertRasterExists(self.output_raster)
self.assertRasterMinMax(self.output_raster, 0, 1)


if __name__ == "__main__":
test()
Loading