-
-
Notifications
You must be signed in to change notification settings - Fork 344
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.ifft: Add Test Suite #5264
base: main
Are you sure you want to change the base?
i.ifft: Add Test Suite #5264
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
import numpy as np | ||
from grass.script import array | ||
from grass.gunittest.case import TestCase | ||
from grass.gunittest.main import test | ||
|
||
|
||
class TestIIFFT(TestCase): | ||
"""Regression tests for the i.ifft GRASS GIS module.""" | ||
|
||
real_input = "real_input_raster" | ||
imag_input = "imag_input_raster" | ||
output_raster = "output_raster" | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
"""Set up an input raster and configure test environment.""" | ||
cls.use_temp_region() | ||
cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) | ||
cls.temp_rasters = [] | ||
cls.runModule( | ||
"r.mapcalc", expression=f"{cls.real_input} = col()", overwrite=True | ||
) | ||
cls.runModule("r.mapcalc", expression=f"{cls.imag_input} = 0", overwrite=True) | ||
cls.temp_rasters.append([cls.real_input, cls.imag_input]) | ||
|
||
@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_linearity_property(self): | ||
"""Test linearity of the IFFT by combining two rasters.""" | ||
self.runModule("r.mapcalc", expression="real_input2 = row()", overwrite=True) | ||
self.runModule("r.mapcalc", expression="imag_input2 = 0", overwrite=True) | ||
self.runModule( | ||
"r.mapcalc", | ||
expression="real_input_sum = real_input_raster + real_input2", | ||
overwrite=True, | ||
) | ||
self.runModule( | ||
"r.mapcalc", | ||
expression="imag_input_sum = imag_input_raster + imag_input2", | ||
overwrite=True, | ||
) | ||
self.temp_rasters.append( | ||
["real_input2", "imag_input2", "real_input_sum", "imag_input_sum"] | ||
) | ||
|
||
self.assertModule( | ||
"i.ifft", | ||
real=self.real_input, | ||
imaginary=self.imag_input, | ||
output=self.output_raster, | ||
overwrite=True, | ||
) | ||
self.assertRasterExists(self.output_raster) | ||
|
||
self.assertModule( | ||
"i.ifft", | ||
real="real_input2", | ||
imaginary="imag_input2", | ||
output="output_raster2", | ||
overwrite=True, | ||
) | ||
self.assertRasterExists("output_raster2") | ||
self.temp_rasters.append("output_raster2") | ||
|
||
self.assertModule( | ||
"i.ifft", | ||
real="real_input_sum", | ||
imaginary="imag_input_sum", | ||
output="output_raster_sum", | ||
overwrite=True, | ||
) | ||
self.assertRasterExists("output_raster_sum") | ||
self.temp_rasters.append("output_raster_sum") | ||
|
||
reference_stats = { | ||
"min": -5, | ||
"max": 110, | ||
"mean": 1.2, | ||
"stddev": 11.138222, | ||
} | ||
|
||
self.assertRasterFitsUnivar( | ||
"output_raster_sum", reference_stats, precision=1e-6 | ||
) | ||
|
||
def test_scaling_property(self): | ||
"""Test the scaling property of the IFFT: verify that ifft(2.5 * x) == 2.5 * ifft(x).""" | ||
self.assertModule( | ||
"i.ifft", | ||
real=self.real_input, | ||
imaginary=self.imag_input, | ||
output=self.output_raster, | ||
overwrite=True, | ||
) | ||
|
||
self.assertRasterExists(self.output_raster) | ||
|
||
reference_stats = { | ||
"min": -12.5, | ||
"max": 137.5, | ||
"mean": 1.5, | ||
"stddev": 14.173037, | ||
} | ||
|
||
expected_unscaled_stats = { | ||
key: value / 2.5 for key, value in reference_stats.items() | ||
} | ||
|
||
self.assertRasterFitsUnivar( | ||
self.output_raster, expected_unscaled_stats, precision=1e-6 | ||
) | ||
|
||
def test_coefficient_symmetry(self): | ||
"""Test if IFFT preserves expected symmetry in real-valued output.""" | ||
|
||
self.runModule( | ||
"r.mapcalc", | ||
expression="real_sym = if(col() > 5, 10 - col(), col())", | ||
overwrite=True, | ||
) | ||
self.runModule("r.mapcalc", expression="imag_zero = 0", overwrite=True) | ||
self.temp_rasters.append("real_sym") | ||
self.temp_rasters.append("imag_zero") | ||
|
||
self.assertModule( | ||
"i.ifft", | ||
real="real_sym", | ||
imaginary="imag_zero", | ||
output="output_sym", | ||
overwrite=True, | ||
) | ||
self.assertRasterExists("output_sym") | ||
self.temp_rasters.append("output_sym") | ||
|
||
self.runModule( | ||
"r.mapcalc", expression="shifted = output_sym[5, 5]", overwrite=True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you explain this test more? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test checks whether |
||
) | ||
self.temp_rasters.append("shifted") | ||
|
||
self.runModule( | ||
"r.mapcalc", | ||
expression="sym_diff = abs(output_sym - shifted)", | ||
overwrite=True, | ||
) | ||
self.temp_rasters.append("sym_diff") | ||
|
||
reference_stats = { | ||
"min": 0, | ||
"max": 25, | ||
"mean": 1.357770, | ||
"stddev": 5.102593, | ||
} | ||
|
||
self.assertRasterFitsUnivar("sym_diff", reference_stats, precision=1e-6) | ||
|
||
def test_mask_functionality(self): | ||
"""Test if masking functionality works properly.""" | ||
|
||
self.runModule( | ||
"r.mapcalc", | ||
expression=f"masked_input = if(row() > 5, {self.real_input}, 0)", | ||
overwrite=True, | ||
) | ||
self.temp_rasters.append("masked_input") | ||
self.assertModule( | ||
"i.ifft", | ||
real="masked_input", | ||
imaginary=self.imag_input, | ||
output=self.output_raster, | ||
overwrite=True, | ||
) | ||
|
||
reference_stats = { | ||
"min": -4.236067, | ||
"max": 27.5, | ||
"mean": 0.6, | ||
"stddev": 3.254228, | ||
} | ||
|
||
self.assertRasterFitsUnivar(self.output_raster, reference_stats, precision=1e-6) | ||
|
||
def test_ifft_reconstruction(self): | ||
"""Test if IFFT reconstructs the original raster.""" | ||
self.runModule( | ||
"r.mapcalc", | ||
expression="original = sin(row() * 0.1) + cos(col() * 0.1)", | ||
overwrite=True, | ||
) | ||
self.temp_rasters.append("original") | ||
|
||
self.runModule( | ||
"i.fft", | ||
input="original", | ||
real="fft_real", | ||
imaginary="fft_imag", | ||
overwrite=True, | ||
) | ||
self.assertRasterExists("fft_real") | ||
self.assertRasterExists("fft_imag") | ||
self.temp_rasters.append("fft_real") | ||
self.temp_rasters.append("fft_imag") | ||
|
||
self.assertModule( | ||
"i.ifft", | ||
real="fft_real", | ||
imaginary="fft_imag", | ||
output="ifft_reconstructed", | ||
overwrite=True, | ||
) | ||
self.assertRasterExists("ifft_reconstructed") | ||
self.temp_rasters.append("ifft_reconstructed") | ||
|
||
original_values = array.array("original") | ||
reconstructed_values = array.array("ifft_reconstructed") | ||
|
||
self.assertTrue( | ||
np.allclose(original_values, reconstructed_values, atol=1e-6), | ||
"Reconstructed raster does not match the original", | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
test() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are these 2 i.ifft runs testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two
i.ifft
runs generate two separate rasters by performing the inverse Fourier transform on different input sets. The outputs are then combined into a third raster (output_raster_sum
) using the summed inputs (real_input_sum
,imag_input_sum
). Finally, the results ofoutput_raster_sum
are compared against reference statistics, which were derived using the same method. This test validates the linearity property of the inverse Fourier transform by ensuring thatIFFT(A) + IFFT(B) = IFFT(A + B)
.