From 671e64ae8e2d99399bd4c2ccbcbed4fc10efa3c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20M=C3=BCller?= <mueller.seb@posteo.de>
Date: Wed, 22 Jan 2025 14:12:04 +0100
Subject: [PATCH] tests: add tests for regridding masked data

---
 tests/adapters/square_5x4/cells.txt  | 198 +++++++++++++++++++++++++++
 tests/adapters/square_5x4/points.txt | 118 ++++++++++++++++
 tests/adapters/square_5x4/types.txt  | 198 +++++++++++++++++++++++++++
 tests/adapters/test_regrid_mask.py   | 160 ++++++++++++++++++++++
 4 files changed, 674 insertions(+)
 create mode 100644 tests/adapters/square_5x4/cells.txt
 create mode 100644 tests/adapters/square_5x4/points.txt
 create mode 100644 tests/adapters/square_5x4/types.txt
 create mode 100644 tests/adapters/test_regrid_mask.py

diff --git a/tests/adapters/square_5x4/cells.txt b/tests/adapters/square_5x4/cells.txt
new file mode 100644
index 00000000..68fac1a8
--- /dev/null
+++ b/tests/adapters/square_5x4/cells.txt
@@ -0,0 +1,198 @@
+90 85 66
+89 39 77
+106 39 89
+97 94 44
+108 44 94
+87 63 66
+103 62 72
+87 69 63
+102 66 85
+100 85 90
+76 14 13
+104 72 62
+103 72 71
+112 76 13
+102 87 66
+97 79 94
+96 93 46
+108 68 91
+117 93 96
+104 89 77
+101 98 84
+109 91 68
+108 91 44
+101 69 87
+116 73 88
+105 77 39
+116 88 58
+95 67 94
+48 42 33
+74 47 11
+75 47 74
+75 74 72
+73 71 70
+73 70 36
+78 43 17
+76 47 75
+36 8 7
+74 11 10
+70 8 36
+77 76 75
+70 40 9
+79 34 42
+71 40 70
+47 12 11
+40 10 9
+42 34 33
+70 9 8
+79 35 34
+91 7 6
+41 26 25
+80 24 37
+83 56 53
+74 10 40
+82 26 41
+84 18 43
+80 41 25
+43 18 17
+85 80 37
+72 40 71
+81 41 80
+95 94 42
+84 19 18
+48 33 32
+59 58 57
+85 81 80
+61 59 60
+78 17 16
+82 27 26
+57 55 56
+95 42 48
+80 25 24
+91 36 7
+60 59 57
+37 24 23
+62 59 61
+58 55 57
+67 52 54
+89 62 61
+88 54 55
+68 67 54
+88 68 54
+88 55 58
+86 37 23
+56 55 53
+63 61 60
+55 54 53
+86 23 22
+83 53 51
+90 60 57
+74 40 72
+39 16 15
+90 57 56
+89 61 65
+54 52 53
+87 86 45
+90 66 60
+45 22 21
+66 63 60
+65 61 63
+53 52 51
+86 22 45
+83 51 64
+38 32 31
+91 6 44
+64 51 50
+52 49 51
+69 65 63
+44 6 5
+92 31 30
+46 30 29
+50 49 38
+78 16 39
+92 38 31
+51 49 50
+95 52 67
+92 30 46
+93 92 46
+92 50 38
+48 32 38
+49 48 38
+93 50 92
+94 79 42
+95 49 52
+93 64 50
+95 48 49
+115 101 84
+100 81 85
+96 28 27
+97 5 4
+98 21 20
+99 41 81
+100 56 83
+101 87 45
+102 85 37
+102 86 87
+103 58 59
+96 27 82
+97 44 5
+98 45 21
+104 75 72
+105 39 15
+108 94 67
+109 36 91
+99 82 41
+104 62 89
+110 29 3
+111 4 0
+111 0 35
+112 13 1
+112 1 12
+112 47 76
+113 2 19
+113 20 2
+110 3 28
+100 90 56
+102 37 86
+103 59 62
+117 64 93
+114 100 83
+117 96 82
+105 14 76
+109 88 73
+101 45 98
+115 84 43
+104 77 75
+109 68 88
+106 89 65
+107 65 69
+107 106 65
+105 15 14
+107 43 78
+105 76 77
+106 78 39
+107 78 106
+117 99 64
+108 67 68
+114 83 64
+114 81 100
+109 73 36
+110 28 96
+113 98 20
+111 97 4
+111 35 79
+112 12 47
+113 19 84
+110 46 29
+116 71 73
+116 58 103
+114 99 81
+114 64 99
+110 96 46
+113 84 98
+111 79 97
+117 82 99
+116 103 71
+115 69 101
+115 107 69
+115 43 107
diff --git a/tests/adapters/square_5x4/points.txt b/tests/adapters/square_5x4/points.txt
new file mode 100644
index 00000000..5d49f103
--- /dev/null
+++ b/tests/adapters/square_5x4/points.txt
@@ -0,0 +1,118 @@
+0.000000000000000000e+00 0.000000000000000000e+00
+5.000000000000000000e+00 0.000000000000000000e+00
+5.000000000000000000e+00 4.000000000000000000e+00
+0.000000000000000000e+00 4.000000000000000000e+00
+4.999999999995947131e-01 0.000000000000000000e+00
+9.999999999984133803e-01 0.000000000000000000e+00
+1.499999999996955102e+00 0.000000000000000000e+00
+1.999999999995512923e+00 0.000000000000000000e+00
+2.499999999996204814e+00 0.000000000000000000e+00
+2.999999999996965983e+00 0.000000000000000000e+00
+3.499999999997728040e+00 0.000000000000000000e+00
+3.999999999998489209e+00 0.000000000000000000e+00
+4.499999999999245048e+00 0.000000000000000000e+00
+5.000000000000000000e+00 4.999999999990952237e-01
+5.000000000000000000e+00 9.999999999976482146e-01
+5.000000000000000000e+00 1.499999999996189937e+00
+5.000000000000000000e+00 1.999999999994775957e+00
+5.000000000000000000e+00 2.499999999996049826e+00
+5.000000000000000000e+00 2.999999999997366995e+00
+5.000000000000000000e+00 3.499999999998682831e+00
+4.499999999999999112e+00 4.000000000000000000e+00
+3.999999999999997780e+00 4.000000000000000000e+00
+3.499999999999996891e+00 4.000000000000000000e+00
+2.999999999999996003e+00 4.000000000000000000e+00
+2.499999999999995115e+00 4.000000000000000000e+00
+1.999999999999994005e+00 4.000000000000000000e+00
+1.499999999999992006e+00 4.000000000000000000e+00
+9.999999999999911182e-01 4.000000000000000000e+00
+4.999999999999956146e-01 4.000000000000000000e+00
+0.000000000000000000e+00 3.499999999998003819e+00
+0.000000000000000000e+00 3.000000000001386002e+00
+0.000000000000000000e+00 2.500000000004854783e+00
+0.000000000000000000e+00 2.000000000008236967e+00
+0.000000000000000000e+00 1.500000000006241896e+00
+0.000000000000000000e+00 1.000000000004162004e+00
+0.000000000000000000e+00 5.000000000020810020e-01
+2.265798546853971196e+00 4.238914066109839007e-01
+2.749999999999935163e+00 3.577350269190534782e+00
+4.330127018896737789e-01 2.250000000006775913e+00
+4.515887990308685040e+00 1.721291157952514972e+00
+3.249999999997145839e+00 4.330127018927403815e-01
+1.749999999999994005e+00 3.573329484275529211e+00
+4.330127018913362269e-01 1.250000000006348033e+00
+4.599679368559095316e+00 2.734037287364882829e+00
+1.206637172643693967e+00 4.481480624790066258e-01
+3.745775399958263030e+00 3.578703610545325819e+00
+4.233860225254563736e-01 3.247881315359677057e+00
+4.230662432701146614e+00 4.218481522081570234e-01
+4.330127018898574098e-01 1.750000000008703038e+00
+8.660254037804282490e-01 2.000000000008117063e+00
+8.660254037794199444e-01 2.500000000006437961e+00
+1.299038105671252108e+00 2.250000000007863044e+00
+1.299038105671842080e+00 1.750000000008790080e+00
+1.732050807563251027e+00 2.000000000008578915e+00
+1.732050807563606964e+00 1.500000000008993917e+00
+2.165063509455331214e+00 1.750000000009032108e+00
+2.168763921158598951e+00 2.243590698928989102e+00
+2.598692946631000034e+00 1.998931783162479991e+00
+2.625210852851048937e+00 1.535103350557095903e+00
+3.033703670897030857e+00 1.753920133713432028e+00
+3.031627495395729177e+00 2.250475319485361059e+00
+3.464627171766605951e+00 2.000732575539676095e+00
+3.464101615131112144e+00 1.500000000010194068e+00
+3.470262035740892870e+00 2.522530415211392985e+00
+1.305354910972956084e+00 2.788748402221191025e+00
+3.897114317022456031e+00 2.250000000009737100e+00
+3.031088913238387139e+00 2.750000000008742784e+00
+1.307411517935652912e+00 1.264503175480730990e+00
+1.733099282557412968e+00 1.015972093721750902e+00
+3.897114317022187802e+00 2.750000000009475087e+00
+2.752633091139478960e+00 4.314924860121975847e-01
+2.965664888242407038e+00 8.430407192711438791e-01
+3.473466298134646912e+00 9.485033022443511985e-01
+2.495283483432777949e+00 8.191813640038545508e-01
+3.749999999997362998e+00 4.330127018933099259e-01
+3.999999999998494982e+00 8.660254037854584475e-01
+4.539957219767416952e+00 8.147052950646799241e-01
+4.249999999998625100e+00 1.299038105677188915e+00
+4.566987298108965199e+00 2.249999999994134026e+00
+4.233860225288407220e-01 7.521186846436920259e-01
+2.249999999999953815e+00 3.569771490982977191e+00
+1.986017662442111087e+00 3.172602692073807962e+00
+1.278337285646486077e+00 3.591790500907492856e+00
+1.736885620003159048e+00 2.478141994818935157e+00
+4.527193881727244573e+00 3.220499339533433147e+00
+2.543206966671962999e+00 3.068203009786670155e+00
+3.249295899993029924e+00 3.581030149777149951e+00
+3.484672574077193108e+00 3.081218998192642999e+00
+2.224749828680767205e+00 1.226702911488599002e+00
+3.949238975830291043e+00 1.718453006844590014e+00
+2.598076211346683095e+00 2.500000000008701928e+00
+1.735657837491481947e+00 5.051897496787564057e-01
+4.314082553290368161e-01 2.749646885897047088e+00
+8.243663844143013231e-01 3.015277068572050023e+00
+9.086100644094758927e-01 9.243779422283027181e-01
+8.745184159297654247e-01 1.489813519623498062e+00
+7.910885367730781104e-01 3.530452272734196928e+00
+7.456552845443471522e-01 4.161816644597777226e-01
+4.234352555081294156e+00 3.603882322562967921e+00
+1.532342419179892001e+00 3.204280363629865125e+00
+2.126965062766455805e+00 2.722917844972307044e+00
+3.999171452587594988e+00 3.190116389084741044e+00
+3.008323479140071033e+00 3.207158181768441807e+00
+3.063606654562874176e+00 1.306322380129556038e+00
+3.820890929013136983e+00 1.258109208728056982e+00
+4.665063509458925672e+00 1.250000000000385914e+00
+4.232125541608215968e+00 2.032051323961315159e+00
+4.232050807571533291e+00 2.499999999993876898e+00
+1.378283175007543049e+00 8.316382047177097725e-01
+2.094791281142887041e+00 8.112976320968601218e-01
+3.660254037837317176e-01 3.633974596215732156e+00
+3.660254037858404197e-01 3.660254037865067200e-01
+4.633974596214726738e+00 3.660254037848266750e-01
+4.633974596214662789e+00 3.633974596214311958e+00
+1.728839994976222982e+00 2.874968674216736186e+00
+4.251041965493531194e+00 2.878930603197281890e+00
+2.690002125042068037e+00 1.148726086499350929e+00
+1.146297907397342941e+00 3.226109721612958836e+00
diff --git a/tests/adapters/square_5x4/types.txt b/tests/adapters/square_5x4/types.txt
new file mode 100644
index 00000000..553cd6b0
--- /dev/null
+++ b/tests/adapters/square_5x4/types.txt
@@ -0,0 +1,198 @@
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
diff --git a/tests/adapters/test_regrid_mask.py b/tests/adapters/test_regrid_mask.py
new file mode 100644
index 00000000..2beb72d8
--- /dev/null
+++ b/tests/adapters/test_regrid_mask.py
@@ -0,0 +1,160 @@
+"""
+Unit tests for regridding with masked data.
+"""
+
+import unittest
+from pathlib import Path
+
+import numpy as np
+from numpy.testing import assert_array_equal
+
+from finam import Composition, FinamDataError, Info, Mask, UniformGrid, UnstructuredGrid
+from finam import data as fdata
+from finam.adapters.regrid import RegridLinear, RegridNearest
+from finam.modules import StaticSimplexNoise, debug
+
+
+def get_mask(points, rad=1.5):
+    return (points[:, 0] - 2.5) ** 2 + (points[:, 1] - 2) ** 2 > rad**2
+
+
+class TestRegridMask(unittest.TestCase):
+    @classmethod
+    def setUpClass(self):
+        here = Path(__file__).parent
+        points = np.loadtxt(here / "square_5x4" / "points.txt", dtype=float)
+        cells = np.loadtxt(here / "square_5x4" / "cells.txt", dtype=int)
+        types = np.loadtxt(here / "square_5x4" / "types.txt", dtype=int)
+
+        self.in_grid = UnstructuredGrid(points, cells, types)
+        self.out_grid = UniformGrid((25, 20), spacing=(0.2, 0.2))
+
+        self.in_mask = get_mask(self.in_grid.cell_centers, rad=1.5)
+        omask = get_mask(self.out_grid.cell_centers, rad=2.5)
+        self.out_mask = fdata.from_compressed(
+            omask, self.out_grid.data_shape, self.out_grid.order
+        )
+
+    def test_regrid_nearest_out_mask(self):
+
+        in_info = Info(grid=self.in_grid, units="", mask=self.in_mask)
+        source = StaticSimplexNoise(in_info, 0.15, 3, 0.5)
+        sink = debug.DebugPushConsumer({"Input": Info()})
+        regrid = RegridNearest(out_grid=self.out_grid, out_mask=self.out_mask)
+        composition = Composition([source, sink])
+
+        (source.outputs["Noise"] >> regrid >> sink.inputs["Input"])
+        composition.connect()
+
+        info = sink.inputs["Input"].info
+        data = sink.data["Input"][0, ...]
+        assert_array_equal(info.mask, data.mask)
+        assert_array_equal(info.mask, self.out_mask)
+
+        i_data = source.outputs["Noise"].data[0][1].magnitude.compressed()
+        o_data = data.magnitude.compressed()
+        self.assertAlmostEqual(i_data.mean(), o_data.mean(), 2)
+
+    def test_regrid_nearest_filled(self):
+
+        in_info = Info(grid=self.in_grid, units="", mask=self.in_mask)
+        source = StaticSimplexNoise(in_info, 0.15, 3, 0.5)
+        sink = debug.DebugPushConsumer({"Input": Info()})
+        regrid = RegridNearest(out_grid=self.out_grid, out_mask=Mask.NONE)
+        composition = Composition([source, sink])
+
+        (source.outputs["Noise"] >> regrid >> sink.inputs["Input"])
+        composition.connect()
+
+        info = sink.inputs["Input"].info
+        data = sink.data["Input"][0, ...].magnitude
+        self.assertEqual(info.mask, Mask.NONE)
+        self.assertFalse(fdata.is_masked_array(data))
+
+        i_data = source.outputs["Noise"].data[0][1].magnitude.compressed()
+        self.assertAlmostEqual(i_data.mean(), data.mean(), 1)
+
+    def test_regrid_linear_determine_mask(self):
+
+        in_info = Info(grid=self.in_grid, units="", mask=self.in_mask)
+        source = StaticSimplexNoise(in_info, 0.15, 3, 0.5)
+        sink = debug.DebugPushConsumer({"Input": Info()})
+        regrid = RegridLinear(
+            out_grid=self.out_grid, fill_with_nearest=False, out_mask=None
+        )
+        composition = Composition([source, sink])
+
+        (source.outputs["Noise"] >> regrid >> sink.inputs["Input"])
+        composition.connect()
+
+        info = sink.inputs["Input"].info
+        data = sink.data["Input"][0, ...]
+        assert_array_equal(info.mask, data.mask)
+        self.assertEqual(np.sum(data.mask), 306)
+
+        i_data = source.outputs["Noise"].data[0][1].magnitude.compressed()
+        o_data = data.magnitude.compressed()
+        self.assertAlmostEqual(i_data.mean(), o_data.mean(), 2)
+
+    def test_regrid_linear_error_domain(self):
+
+        in_info = Info(grid=self.in_grid, units="", mask=self.in_mask)
+        source = StaticSimplexNoise(in_info, 0.15, 3, 0.5)
+        sink = debug.DebugPushConsumer({"Input": Info()})
+        regrid = RegridLinear(
+            out_grid=self.out_grid, fill_with_nearest=False, out_mask=Mask.NONE
+        )
+        composition = Composition([source, sink])
+
+        (source.outputs["Noise"] >> regrid >> sink.inputs["Input"])
+
+        # not covering domain without fill
+        with self.assertRaises(FinamDataError):
+            composition.connect()
+
+    def test_regrid_linear_filled(self):
+
+        in_info = Info(grid=self.in_grid, units="", mask=self.in_mask)
+        source = StaticSimplexNoise(in_info, 0.15, 3, 0.5)
+        sink = debug.DebugPushConsumer({"Input": Info()})
+        regrid = RegridLinear(
+            out_grid=self.out_grid, fill_with_nearest=True, out_mask=Mask.NONE
+        )
+        composition = Composition([source, sink])
+
+        (source.outputs["Noise"] >> regrid >> sink.inputs["Input"])
+        composition.connect()
+
+        info = sink.inputs["Input"].info
+        data = sink.data["Input"][0, ...].magnitude
+        self.assertEqual(info.mask, Mask.NONE)
+        self.assertFalse(fdata.is_masked_array(data))
+
+        i_data = source.outputs["Noise"].data[0][1].magnitude.compressed()
+        self.assertAlmostEqual(i_data.mean(), data.mean(), 1)
+
+    def test_regrid_linear_filled_mask(self):
+
+        in_info = Info(grid=self.in_grid, units="", mask=self.in_mask)
+        source = StaticSimplexNoise(in_info, 0.15, 3, 0.5)
+        sink = debug.DebugPushConsumer({"Input": Info()})
+        regrid = RegridLinear(
+            out_grid=self.out_grid, fill_with_nearest=True, out_mask=self.out_mask
+        )
+        composition = Composition([source, sink])
+
+        (source.outputs["Noise"] >> regrid >> sink.inputs["Input"])
+        composition.connect()
+
+        info = sink.inputs["Input"].info
+        data = sink.data["Input"][0, ...]
+        assert_array_equal(info.mask, data.mask)
+        assert_array_equal(info.mask, self.out_mask)
+
+        i_data = source.outputs["Noise"].data[0][1].magnitude.compressed()
+        o_data = data.magnitude.compressed()
+        self.assertAlmostEqual(i_data.mean(), o_data.mean(), 2)
+
+
+if __name__ == "__main__":
+    unittest.main()
-- 
GitLab