public void readShortMissing() throws Exception { Variable v = null; assert (null != (v = ncfileRead.findVariable("t4"))); assert (v.getDataType() == DataType.SHORT); // default use of missing_value assert (null != (v = dsRead.findVariable("t4"))); assert v instanceof VariableEnhanced; assert v instanceof VariableDS; VariableDS vs = (VariableDS) v; assert (vs.getDataType() == DataType.SHORT); Attribute att = vs.findAttribute(CDM.MISSING_VALUE); assert (null != att); assert (!att.isArray()); assert (1 == att.getLength()); System.out.println("missing_value = " + att.getNumericValue().shortValue()); assert (((short) -9999) == att.getNumericValue().shortValue()); assert (DataType.SHORT == att.getDataType()); assert (vs.hasMissing()); assert (vs.hasMissingValue()); assert (vs.isMissing((double) ((short) -9999))); assert (vs.isMissingValue((double) ((short) -9999))); Array A = vs.read(); Index ima = A.getIndex(); int[] shape = A.getShape(); int i, j; for (i = 0; i < shape[0]; i++) { for (j = 0; j < shape[1]; j++) { assert (A.getFloat(ima.set(i, j)) == (i * 10 + j)); } } // turn off missing data vs.setMissingDataIsMissing(false); assert (vs.getDataType() == DataType.SHORT); assert (!vs.hasMissing()); assert (vs.hasMissingValue()); assert (!vs.isMissing((double) ((short) -9999))); assert (vs.isMissingValue((double) ((short) -9999))); vs.setMissingDataIsMissing(true); assert (vs.hasMissing()); assert (vs.isMissing((double) ((short) -9999))); System.out.println("**************TestStandardVar Read readShortMissing"); }
public void readByte() throws Exception { Variable v = null; assert (null != (v = ncfileRead.findVariable("t3"))); assert (v.getDataType() == DataType.BYTE); assert (null != (v = dsRead.findVariable("t3"))); assert v instanceof VariableEnhanced; assert v instanceof VariableDS; VariableDS vs = (VariableDS) v; assert (vs.getDataType() == DataType.BYTE); Attribute att = vs.findAttribute("_FillValue"); assert (null != att); assert (!att.isArray()); assert (1 == att.getLength()); System.out.println("_FillValue = " + att.getNumericValue().byteValue()); assert (((byte) 255) == att.getNumericValue().byteValue()); assert (DataType.BYTE == att.getDataType()); assert (vs.hasMissing()); assert (vs.hasFillValue()); assert (vs.isMissing((double) ((byte) 255))); assert (vs.isFillValue((double) ((byte) 255))); Array A = vs.read(); assert (A.getElementType() == byte.class) : A.getElementType(); Index ima = A.getIndex(); int[] shape = A.getShape(); int i, j; for (i = 0; i < shape[0]; i++) { for (j = 0; j < shape[1]; j++) { assert (A.getFloat(ima.set(i, j)) == (i * 10 + j)); } } System.out.println("**************TestStandardVar ReadByte"); }
public void readShort2FloatMissing() throws Exception { Variable v = null; assert (null != (v = ncfileRead.findVariable("t5"))); assert (v.getDataType() == DataType.SHORT); // standard convert with missing data assert (null != (v = dsRead.findVariable("t5"))); assert v instanceof VariableEnhanced; assert v instanceof VariableDS; VariableDS vs = (VariableDS) v; assert (vs.getDataType() == DataType.FLOAT); assert (vs.hasMissing()); assert (vs.hasMissingValue()); double mv = 2 * (-9999) + 77; assert (vs.isMissing((double) mv)); assert (vs.isMissingValue((double) mv)); Array A = vs.read(); Index ima = A.getIndex(); int[] shape = A.getShape(); int i, j; assert (vs.isMissing(A.getFloat(ima.set(0, 0)))); for (i = 0; i < shape[0]; i++) { for (j = 1; j < shape[1]; j++) { float val = A.getFloat(ima.set(i, j)); float want = 2 * (i * 10 + j) + 77; if (val != want) System.out.println(i + " " + j + " " + val + " " + want); assert (val == want); } } // useNaNs vs.setUseNaNs(true); assert (vs.getDataType() == DataType.FLOAT); assert (vs.hasMissing()); assert (vs.hasMissingValue()); double mv2 = 2 * (-9999) + 77; assert (vs.isMissing((double) mv2)); assert (vs.isMissingValue((double) mv2)); Array A2 = vs.read(); Index ima2 = A2.getIndex(); int[] shape2 = A2.getShape(); double mval = A2.getFloat(ima2.set(0, 0)); assert vs.isMissing(mval); assert Double.isNaN(mval); for (i = 0; i < shape2[0]; i++) { for (j = 1; j < shape2[1]; j++) { float val = A2.getFloat(ima2.set(i, j)); float want = 2 * (i * 10 + j) + 77; if (val != want) System.out.println(i + " " + j + " " + val + " " + want); assert (val == want) : val + " != " + want; } } assert (null == vs.findAttribute(CDM.SCALE_FACTOR)); assert (null == vs.findAttribute("add_offset")); assert (null == vs.findAttribute(CDM.MISSING_VALUE)); System.out.println("**************TestStandardVar Read readShort2FloatMissing"); }
/** * Constructor. If scale/offset attributes are found, remove them from the decorated variable. * * @param forVar the Variable to decorate. * @param useNaNs pre-fill isMissing() data with NaNs * @param fillValueIsMissing use _FillValue for isMissing() * @param invalidDataIsMissing use valid_range for isMissing() * @param missingDataIsMissing use missing_value for isMissing() */ EnhanceScaleMissingImpl( VariableDS forVar, boolean useNaNs, boolean fillValueIsMissing, boolean invalidDataIsMissing, boolean missingDataIsMissing) { this.fillValueIsMissing = fillValueIsMissing; this.invalidDataIsMissing = invalidDataIsMissing; this.missingDataIsMissing = missingDataIsMissing; // see if underlying variable has scale/offset already applied Variable orgVar = forVar.getOriginalVariable(); if (orgVar instanceof VariableDS) { VariableDS orgVarDS = (VariableDS) orgVar; EnumSet<NetcdfDataset.Enhance> orgEnhanceMode = orgVarDS.getEnhanceMode(); if ((orgEnhanceMode != null) && orgEnhanceMode.contains(NetcdfDataset.Enhance.ScaleMissing)) return; } // the other possibility is that you want to apply scale and offset to a signed value, then // declare the result unsigned // this.isUnsigned = (orgVar != null) ? orgVar.isUnsigned() : forVar.isUnsigned(); this.isUnsigned = forVar.isUnsigned(); this.convertedDataType = forVar.getDataType(); DataType scaleType = null, missType = null, validType = null, fillType = null; if (debug) System.out.println("EnhancementsImpl for Variable = " + forVar.getFullName()); Attribute att; // scale and offset if (null != (att = forVar.findAttribute(CDM.SCALE_FACTOR))) { if (!att.isString()) { scale = att.getNumericValue().doubleValue(); hasScaleOffset = true; scaleType = att.getDataType(); forVar.remove(att); if (debug) System.out.println("scale = " + scale + " type " + scaleType); } } if (null != (att = forVar.findAttribute(CDM.ADD_OFFSET))) { if (!att.isString()) { offset = att.getNumericValue().doubleValue(); hasScaleOffset = true; DataType offType = att.getDataType(); if (rank(offType) > rank(scaleType)) scaleType = offType; forVar.remove(att); if (debug) System.out.println("offset = " + offset); } } ////// missing data : valid_range. assume here its in units of unpacked data. correct this below Attribute validRangeAtt; if (null != (validRangeAtt = forVar.findAttribute(CDM.VALID_RANGE))) { if (!validRangeAtt.isString() && validRangeAtt.getLength() > 1) { valid_min = validRangeAtt.getNumericValue(0).doubleValue(); valid_max = validRangeAtt.getNumericValue(1).doubleValue(); hasValidRange = true; validType = validRangeAtt.getDataType(); if (hasScaleOffset) forVar.remove(validRangeAtt); if (debug) System.out.println("valid_range = " + valid_min + " " + valid_max); } } Attribute validMinAtt = null, validMaxAtt = null; if (!hasValidRange) { if (null != (validMinAtt = forVar.findAttribute("valid_min"))) { if (!validMinAtt.isString()) { valid_min = validMinAtt.getNumericValue().doubleValue(); hasValidMin = true; validType = validMinAtt.getDataType(); if (hasScaleOffset) forVar.remove(validMinAtt); if (debug) System.out.println("valid_min = " + valid_min); } } if (null != (validMaxAtt = forVar.findAttribute("valid_max"))) { if (!validMaxAtt.isString()) { valid_max = validMaxAtt.getNumericValue().doubleValue(); hasValidMax = true; DataType t = validMaxAtt.getDataType(); if (rank(t) > rank(validType)) validType = t; if (hasScaleOffset) forVar.remove(validMaxAtt); if (debug) System.out.println("valid_min = " + valid_max); } } } boolean hasValidData = hasValidMin || hasValidMax || hasValidRange; if (hasValidMin && hasValidMax) hasValidRange = true; /// _FillValue if ((null != (att = forVar.findAttribute(CDM.FILL_VALUE))) && !att.isString()) { double[] values = getValueAsDouble(att); // LOOK double WTF ?? if (values.length > 0) { fillValue = values[0]; hasFillValue = true; fillType = att.getDataType(); if (hasScaleOffset) forVar.remove(att); if (debug) System.out.println("missing_datum from _FillValue = " + fillValue); } } /// missing_value if (null != (att = forVar.findAttribute(CDM.MISSING_VALUE))) { if (att.isString()) { String svalue = att.getStringValue(); if (forVar.getDataType() == DataType.CHAR) { missingValue = new double[1]; if (svalue.length() == 0) missingValue[0] = 0; else missingValue[0] = svalue.charAt(0); missType = DataType.CHAR; hasMissingValue = true; } else { // not a CHAR - try to fix problem where they use a numeric value as a String // attribute try { missingValue = new double[1]; missingValue[0] = Double.parseDouble(svalue); missType = att.getDataType(); hasMissingValue = true; } catch (NumberFormatException ex) { if (debug) System.out.println( "String missing_value not parsable as double= " + att.getStringValue()); } } } else { // not a string missingValue = getValueAsDouble(att); missType = att.getDataType(); for (double mv : missingValue) if (!Double.isNaN(mv)) hasMissingValue = true; // dont need to do anything if its already a NaN } if (hasScaleOffset) forVar.remove(att); } // missing boolean hasMissing = (invalidDataIsMissing && hasValidData) || (fillValueIsMissing && hasFillValue) || (missingDataIsMissing && hasMissingValue); /// assign convertedDataType if needed if (hasScaleOffset) { convertedDataType = forVar.getDataType(); if (hasMissing) { // has missing data : must be float or double if (rank(scaleType) > rank(convertedDataType)) convertedDataType = scaleType; if (missingDataIsMissing && rank(missType) > rank(convertedDataType)) convertedDataType = missType; if (fillValueIsMissing && rank(fillType) > rank(convertedDataType)) convertedDataType = fillType; if (invalidDataIsMissing && rank(validType) > rank(convertedDataType)) convertedDataType = validType; if (rank(convertedDataType) < rank(DataType.DOUBLE)) convertedDataType = DataType.FLOAT; } else { // no missing data; can use wider of data and scale if (rank(scaleType) > rank(convertedDataType)) convertedDataType = scaleType; } if (debug) System.out.println("assign dataType = " + convertedDataType); // validData may be external or internal if (hasValidData) { DataType orgType = forVar.getDataType(); // If valid_range is the same type as scale_factor (actually the wider of // scale_factor and add_offset) and this is wider than the external data, then it // will be interpreted as being in the units of the internal (unpacked) data. // Otherwise it is in the units of the external (unpacked) data. // we assumed unpacked data above, redo if its really packed data if (!((rank(validType) == rank(scaleType)) && (rank(scaleType) >= rank(orgType)))) { if (validRangeAtt != null) { double[] values = getValueAsDouble(validRangeAtt); valid_min = values[0]; valid_max = values[1]; } else { if (validMinAtt != null) { double[] values = getValueAsDouble(validMinAtt); valid_min = values[0]; } if (validMaxAtt != null) { double[] values = getValueAsDouble(validMaxAtt); valid_max = values[0]; } } } } } if (hasMissing && ((convertedDataType == DataType.DOUBLE) || (convertedDataType == DataType.FLOAT))) this.useNaNs = useNaNs; if (debug) System.out.println("this.useNaNs = " + this.useNaNs); }