1+ /*
2+ * Copyright (c) 2022-2026 University Corporation for Atmospheric Research/Unidata
3+ * See LICENSE for license information.
4+ */
5+
16package ucar .nc2 .filter ;
27
38import ucar .ma2 .Array ;
49import ucar .ma2 .DataType ;
10+ import ucar .ma2 .DataType .Signedness ;
511import ucar .ma2 .IndexIterator ;
612import ucar .nc2 .Attribute ;
713import ucar .nc2 .constants .CDM ;
1420public class ConvertMissing implements Enhancement {
1521
1622 private boolean hasValidMin , hasValidMax ;
23+ // If variable is packed and these must be packed values
1724 private double validMin , validMax ;
1825
1926 private boolean hasFillValue ;
@@ -35,12 +42,14 @@ public static ConvertMissing createFromVariable(VariableDS var) {
3542 // assume here its in units of unpacked data. correct this below
3643 Attribute validRangeAtt = var .findAttribute (CDM .VALID_RANGE );
3744 DataType validType = null ;
45+ boolean validRangeDifferentDataType = false ;
3846 if (validRangeAtt != null && !validRangeAtt .isString () && validRangeAtt .getLength () > 1 ) {
3947 validType = FilterHelpers .getAttributeDataType (validRangeAtt , signedness );
4048 validMin = var .convertUnsigned (validRangeAtt .getNumericValue (0 ), validType ).doubleValue ();
4149 validMax = var .convertUnsigned (validRangeAtt .getNumericValue (1 ), validType ).doubleValue ();
4250 hasValidMin = true ;
4351 hasValidMax = true ;
52+ validRangeDifferentDataType = !validType .equals (var .getDataType ());
4453 }
4554
4655 Attribute validMinAtt = var .findAttribute (CDM .VALID_MIN );
@@ -52,15 +61,27 @@ public static ConvertMissing createFromVariable(VariableDS var) {
5261 validType = FilterHelpers .getAttributeDataType (validMinAtt , signedness );
5362 validMin = var .convertUnsigned (validMinAtt .getNumericValue (), validType ).doubleValue ();
5463 hasValidMin = true ;
64+ validRangeDifferentDataType = !validType .equals (var .getDataType ());
5565 }
5666
5767 if (validMaxAtt != null && !validMaxAtt .isString ()) {
5868 validType = FilterHelpers .largestOf (validType , FilterHelpers .getAttributeDataType (validMaxAtt , signedness ));
5969 validMax = var .convertUnsigned (validMaxAtt .getNumericValue (), validType ).doubleValue ();
6070 hasValidMax = true ;
71+ validRangeDifferentDataType = !validType .equals (var .getDataType ());
6172 }
6273 }
6374
75+ if (validRangeDifferentDataType && !signedness .equals (Signedness .UNSIGNED )) {
76+ // Signal that valid range (or min/max) was specified in unpacked values, so we
77+ // need to repack those values. Only applies when the DataTypes do not match because
78+ // the variable is unsigned.
79+ double scale = var .attributes ().findAttributeDouble (CDM .SCALE_FACTOR , 1 );
80+ double offset = var .attributes ().findAttributeDouble (CDM .ADD_OFFSET , 0 );
81+ validMin = (validMin - offset ) / scale ;
82+ validMax = (validMax - offset ) / scale ;
83+ }
84+
6485 if (validMin > validMax ) {
6586 double temp = validMin ;
6687 validMin = validMax ;
@@ -113,6 +134,7 @@ public ConvertMissing(boolean fillValueIsMissing, boolean invalidDataIsMissing,
113134 this .missingDataIsMissing = missingDataIsMissing ;
114135 this .hasValidMin = hasValidMin ;
115136 this .hasValidMax = hasValidMax ;
137+ // If variable data is packed, validMin, validMax must also be packed
116138 this .validMin = validMin ;
117139 this .validMax = validMax ;
118140 this .hasFillValue = hasFillValue ;
@@ -150,14 +172,37 @@ public boolean hasValidData() {
150172 return hasValidMin || hasValidMax ;
151173 }
152174
175+ /**
176+ *
177+ * Return the minimum valid value used to enhance a variable.
178+ * <p>
179+ * If the variable is packed, this value will also be packed.
180+ *
181+ * @return the minimum valid value as a double.
182+ */
153183 public double getValidMin () {
154184 return validMin ;
155185 }
156186
187+ /**
188+ *
189+ * Return the maximum valid value used to enhance a variable.
190+ * <p>
191+ * If the variable is packed, this value will also be packed.
192+ *
193+ * @return the maximum valid value as a double.
194+ */
157195 public double getValidMax () {
158196 return validMax ;
159197 }
160198
199+ /**
200+ *
201+ * Return true if the value is outside the valid range.
202+ *
203+ * @param val the value to test (must be packed if the variable is packed).
204+ * @return true if the value is invalid.
205+ */
161206 public boolean isInvalidData (double val ) {
162207 if (Double .isNaN (val )) {
163208 return true ;
0 commit comments