Skip to content

Commit c5d267b

Browse files
Gridded data null (#124)
* fix gridded data nullValue bug * small edit to test, bump version
1 parent 8b35f0f commit c5d267b

4 files changed

Lines changed: 49 additions & 9 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "hec-dss-python"
3-
version = "0.1.31"
3+
version = "0.1.32"
44
description = "Python wrapper for the HEC-DSS file database C library."
55
authors = ["Hydrologic Engineering Center"]
66
license = "MIT"

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = hecdss
3-
version = 0.1.31
3+
version = 0.1.32
44
author = Hydrologic Engineering Center
55
author_email =hec.dss@usace.army.mil
66
description = Python wrapper for the HEC-DSS file database C library.

src/hecdss/gridded_data.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def __init__(self):
8585
self.data = np.zeros(0)
8686
self.location_info = None
8787

88-
def range_limit_table(self, minval, maxval, range_, bins, datasize, data):
88+
def range_limit_table(self, minval, maxval, range_, bins, data):
8989
"""
9090
Calculate the range limit table and the number of values equal or exceeding each range limit.
9191
@@ -94,7 +94,6 @@ def range_limit_table(self, minval, maxval, range_, bins, datasize, data):
9494
maxval (float): Maximum value.
9595
range_ (float): Range of values.
9696
bins (int): Number of bins.
97-
datasize (int): Size of the data.
9897
data (numpy.ndarray): Data array.
9998
"""
10099
max_bins = 15
@@ -103,7 +102,7 @@ def range_limit_table(self, minval, maxval, range_, bins, datasize, data):
103102
bins = max_bins
104103

105104
self.rangeLimitTable = np.empty(bins, dtype=float)
106-
self.rangeLimitTable[0] = NULL_INT
105+
self.rangeLimitTable[0] = self.nullValue
107106
self.rangeLimitTable[1] = minval
108107

109108
step = range_ / bins
@@ -118,6 +117,7 @@ def update_grid_info(self):
118117
"""
119118
Update grid information based on the data array.
120119
"""
120+
self.data[self.data == self.nullValue] = np.nan
121121
self.numberOfCellsX = len(self.data[0])
122122
self.numberOfCellsY = len(self.data)
123123
n = np.size(self.data)
@@ -126,10 +126,14 @@ def update_grid_info(self):
126126
bin_range = int(math.ceil(self.maxDataValue) - math.floor(self.minDataValue))
127127
self.meanDataValue = np.nanmean(self.data)
128128

129-
self.data = np.nan_to_num(self.data, nan=NULL_INT)
130-
self.numberOfRanges = math.floor(2 + 3.322 * math.log10(n))
129+
self.data = np.nan_to_num(self.data, nan=self.nullValue)
130+
if bin_range == 0:
131+
self.numberOfRanges = 2
132+
else:
133+
self.numberOfRanges = math.floor(2 + 3.322 * math.log10(n))
131134
flat_data = self.data.flatten()
132-
self.range_limit_table(self.minDataValue, self.maxDataValue, bin_range, self.numberOfRanges, n, flat_data)
135+
self.range_limit_table(self.minDataValue, self.maxDataValue,
136+
bin_range, self.numberOfRanges, flat_data)
133137

134138
@staticmethod
135139
def create(path=None,
@@ -223,7 +227,7 @@ def create(path=None,
223227
gd.meanDataValue = meanDataValue
224228
gd.rangeLimitTable = rangeLimitTable
225229
gd.numberEqualOrExceedingRangeLimit = numberEqualOrExceedingRangeLimit
226-
gd.data = np.array(data)
230+
gd.data = np.array(data).astype(float)
227231
gd.location_info = location_info
228232

229233
gd.update_grid_info()

tests/test_gridded_data.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from hecdss.gridded_data import GriddedData
1010

1111

12+
NULL_INT = -3.4028234663852886e+38
13+
1214
class TestGriddedData(unittest.TestCase):
1315

1416
def setUp(self) -> None:
@@ -125,6 +127,40 @@ def test_gridded_data_write_precompressed(self):
125127
assert gd_original.numberOfCellsY == gd_readback.numberOfCellsY, "numberOfCellsY mismatch"
126128
assert gd_original.dataUnits == gd_readback.dataUnits, "dataUnits mismatch"
127129

130+
def test_null_consistency(self):
131+
"""
132+
This test serves to ensure that the range limit table remains consistent with different cases of missing values.
133+
"""
134+
gd_nan = self._create_half_nul_gd(np.nan)
135+
gd_negative = self._create_half_nul_gd(-9999)
136+
gd_null_int = self._create_half_nul_gd(NULL_INT)
137+
gd_zero = self._create_half_nul_gd(0)
138+
139+
assert (gd_nan.numberOfRanges == 2)
140+
assert (gd_nan.numberOfRanges == gd_negative.numberOfRanges)
141+
assert (gd_nan.numberOfRanges == gd_null_int.numberOfRanges)
142+
assert (gd_nan.numberOfRanges == gd_zero.numberOfRanges)
143+
144+
assert (gd_nan.maxDataValue == gd_negative.maxDataValue)
145+
assert (gd_nan.maxDataValue == gd_null_int.maxDataValue)
146+
assert (gd_nan.maxDataValue == gd_zero.maxDataValue)
147+
148+
assert (gd_nan.minDataValue == gd_negative.minDataValue)
149+
assert (gd_nan.minDataValue == gd_null_int.minDataValue)
150+
assert (gd_nan.minDataValue == gd_zero.minDataValue)
151+
152+
153+
def _create_half_nul_gd(self, default_value):
154+
gd_data = [[1 for _ in range(100)] for _ in range(50)]
155+
gd_data.extend([[default_value for _ in range(100)] for _ in range(50)])
156+
157+
gd_test = GriddedData.create(
158+
data=gd_data,
159+
nullValue=default_value
160+
)
161+
162+
return gd_test
163+
128164

129165
if __name__ == "__main__":
130166
unittest.main()

0 commit comments

Comments
 (0)