Skip to content

Commit 8ca3b89

Browse files
committed
Extend unit tests for bin1d_vec and .get_index_of
* in `test_calc.TestBin1d`: * add `test_bin1d_single_bin2`, which inputs a single bin _and_ a single point; * split off a new `test_scalar_inside` from `test_scalar_outside`, which checks: * _all_ corner cases (*.*5) * _all_ center bins (*.*0) * _all_ end of bins (*.*99999999) * one large value (10) * add separate class `TestBin2d` in `test_region`, which makes more realistic unit tests by extending the self-check mentioned in #255 and performing it... * for three regions: Italy, California, NZ (New-Zealand); * for all origins, mid-points, and end-corners (in the bin, at the opposite side of origin); * for double precision (_float64_ / _f8_) and single precision (_float32_ / _f4_) of the points (not bin edges); * as loop (over each point individually) and single vector (all points at once). * ==> 36 unit test combinations * (albeit targeting `bin1d_vec`, it also unit-tests region's`CartesianGrid2D.get_index_of` and by extension `GriddedForecast.get_index_of`)
1 parent d4975b7 commit 8ca3b89

File tree

2 files changed

+93
-8
lines changed

2 files changed

+93
-8
lines changed

tests/test_calc.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ def test_bin1d_single_bin1(self):
106106
expected = [-1, -1, 0, 0, 0, 0, 0, -1]
107107
self.assertListEqual(test.tolist(), expected)
108108

109+
def test_bin1d_single_bin2(self):
110+
data = [4.0]
111+
bin_edges = [3.0]
112+
test = bin1d_vec(data, bin_edges)
113+
expected = [0]
114+
self.assertListEqual(test.tolist(), expected)
115+
109116
def test_upper_limit_right_continuous(self):
110117
data = [40, 40, 40]
111118
bin_edges = [0, 10, 20, 30]
@@ -134,18 +141,27 @@ def test_less_and_greater_than(self):
134141
expected = [-1, 3, -1]
135142
self.assertListEqual(test.tolist(), expected)
136143

137-
def test_scalar_outside(self):
138-
from csep.utils.calc import bin1d_vec
139-
mbins = numpy.arange(5.95, 9, 0.1) # This gives bins from 5.95 to 8.95
140-
idx = bin1d_vec(5.95, mbins, right_continuous=True)
141-
self.assertEqual(idx, 0)
144+
def test_scalar_inside(self):
145+
mbins = numpy.arange(5.95, 9, 0.1) # (magnitude) bins from 5.95 to 8.95
146+
147+
for i, m in enumerate(mbins):
148+
idx = bin1d_vec(m, mbins, right_continuous=True) # corner cases
149+
self.assertEqual(idx, i)
142150

143-
idx = bin1d_vec(6, mbins, right_continuous=True) # This would give 0: Which is fine.
144-
self.assertEqual(idx, 0)
151+
idx = bin1d_vec(m + 0.05, mbins, right_continuous=True) # center bins
152+
self.assertEqual(idx, i)
153+
154+
idx = bin1d_vec(m + 0.099999999, mbins, right_continuous=True) # end of bins
155+
self.assertEqual(idx, i)
156+
157+
idx = bin1d_vec(10, mbins, right_continuous=True) # larger than last bin edge
158+
self.assertEqual(idx, mbins.size - 1)
159+
160+
def test_scalar_outside(self):
161+
mbins = numpy.arange(5.95, 9, 0.1) # (magnitude) bins from 5.95 to 8.95
145162

146163
idx = bin1d_vec(5, mbins, right_continuous=True)
147164
self.assertEqual(idx, -1)
148165

149166
idx = bin1d_vec(4, mbins, right_continuous=True)
150167
self.assertEqual(idx, -1)
151-

tests/test_regions.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,72 @@ def test_origins(self):
8686
r = nz_csep_region()
8787
# they dont have to be in the same order, but they need
8888
numpy.testing.assert_array_equal(r.midpoints().sort(), self.from_dat.sort())
89+
90+
class TestBin2d(unittest.TestCase):
91+
92+
@classmethod
93+
def setUpClass(cls):
94+
super(TestBin2d, cls).setUpClass()
95+
96+
# (loading those is the bottleneck of this test case)
97+
cls.regions = [
98+
italy_csep_region(),
99+
california_relm_region(),
100+
nz_csep_region()
101+
]
102+
103+
def test_bin2d_regions_origins(self):
104+
"""every origin must be inside its own bin
105+
"""
106+
107+
for region in self.regions:
108+
origins = region.origins()
109+
self._test_bin2d_region_loop(region, origins)
110+
self._test_bin2d_region_vect(region, origins)
111+
self._test_bin2d_region_vect(region, origins.astype(numpy.float32))
112+
113+
def test_bin2d_regions_midpoints(self):
114+
"""every midpoint must be inside its own bin
115+
"""
116+
117+
for region in self.regions:
118+
midpoints = region.midpoints()
119+
self._test_bin2d_region_loop(region, midpoints)
120+
self._test_bin2d_region_vect(region, midpoints)
121+
self._test_bin2d_region_vect(region, midpoints.astype(numpy.float32))
122+
123+
def test_bin2d_regions_endcorner(self):
124+
"""every corner point (~opposite end of the origin) must be inside its own bin
125+
"""
126+
127+
for region in self.regions:
128+
frac = 0.9999999999
129+
endcorners = region.origins() + frac*region.dh
130+
self._test_bin2d_region_loop(region, endcorners)
131+
self._test_bin2d_region_vect(region, endcorners)
132+
frac = 0.999 # decrease frac for float32 due to its lower resolution
133+
endcorners = region.origins() + frac*region.dh
134+
self._test_bin2d_region_vect(region, endcorners.astype(numpy.float32))
135+
136+
def _test_bin2d_region_loop(self, region, coords):
137+
"""(slow) loop over origins; each time, calls bin1d_vec for lat & lon scalars
138+
"""
139+
140+
for i, origin in enumerate(coords):
141+
idx = region.get_index_of(
142+
origin[0],
143+
origin[1],
144+
)
145+
self.assertEqual(i, idx)
146+
147+
def _test_bin2d_region_vect(self, region, coords):
148+
"""call bin1d_vec once for all lat origins & all lon origins
149+
150+
Besides, also tests if vectors with ndim=2 are consumed properly
151+
(returns 2nd-order/nested list ([[...]]).
152+
"""
153+
154+
lons, lats = numpy.split(coords.T, 2) # both have ndim=2!
155+
test = region.get_index_of(lons, lats).tolist() # nested list ([[...]])
156+
expected = [numpy.arange(len(region.origins())).tolist()] # embed in another list
157+
self.assertListEqual(test, expected)

0 commit comments

Comments
 (0)