/*
* Copyright 1998, University Corporation for Atmospheric Research
* All Rights Reserved.
* See file LICENSE for copying and redistribution conditions.
*
* $Id: Vetter.java,v 1.8 2001-03-14 17:44:15 steve Exp $
*/
package visad.data.netcdf.in;
import ucar.netcdf.Attribute;
import ucar.netcdf.Variable;
import visad.data.in.OffsetUnpacker;
import visad.data.in.ScaleAndOffsetUnpacker;
import visad.data.in.ScaleUnpacker;
import visad.data.in.ValueRanger;
import visad.data.in.ValueUnpacker;
import visad.data.in.ValueVetter;
/**
* The Vetter class vets netCDF values, replacing invalid values with their
* VisAD equivalents.
*/
final class
Vetter
{
/**
* The object that vets the raw data.
*/
private ValueVetter vetter;
/**
* The object that unpacks the vetted data.
*/
private ValueUnpacker unpacker;
/**
* The object that ranges the unpacked data.
*/
private ValueRanger ranger;
/**
* The type of the netCDF variable.
*/
private Class type;
/**
* The minimum, valid, external, netCDF value (won't be NaN).
*/
private double minValid;
/**
* The maximum, valid, external, netCDF value (won't be NaN).
*/
private double maxValid;
/**
* The fill-value value.
*/
private double fill;
/**
* Constructs from nothing. Protected to ensure use by subclasses
* only.
*/
protected
Vetter()
{}
/**
* Constructs from a netCDF variable type.
*
* @param type The Java type of the netCDF variable (i.e.
* float.class, char.class, etc.)
*/
Vetter(Class type)
{
this.type = type;
if (type.equals(byte.class))
{
fill = Double.NaN; // i.e. no default fill-value
minValid = Byte.MIN_VALUE;
maxValid = Byte.MAX_VALUE;
}
else if (type.equals(short.class))
{
fill = -32767;
minValid = Short.MIN_VALUE;
maxValid = Short.MAX_VALUE;
}
else if (type.equals(int.class))
{
fill = -2147483647;
minValid = Integer.MIN_VALUE;
maxValid = Integer.MAX_VALUE;
}
else if (type.equals(float.class))
{
fill = 9.9692099683868690e+36;
minValid = Float.NEGATIVE_INFINITY;
maxValid = Float.POSITIVE_INFINITY;
}
else if (type.equals(double.class))
{
fill = 9.9692099683868690e+36;
minValid = Double.NEGATIVE_INFINITY;
maxValid = Double.POSITIVE_INFINITY;
}
else
{
fill = 0;
minValid = 0;
maxValid = 0;
}
}
/**
* Constructs from a netCDF variable.
*
* @param var The netCDF variable to be examined.
*/
Vetter(Variable var)
{
this(var.getComponentType()); // set paramters to default values
Attribute attr;
double missing = Double.NaN;
double lower = Double.NEGATIVE_INFINITY;
double upper = Double.POSITIVE_INFINITY;
/*
* Set the object that will vet the raw data.
*/
{
attr = var.getAttribute("_FillValue");
if (attr != null)
{
fill = attr.getNumericValue().doubleValue();
if (fill < 0)
{
lower =
(type.equals(float.class) || type.equals(double.class))
? fill/2
: fill + 1;
}
else if (fill > 0)
{
upper =
(type.equals(float.class) || type.equals(double.class))
? fill/2
: fill - 1;
}
}
attr = var.getAttribute("missing_value");
if (attr != null)
missing = attr.getNumericValue().doubleValue();
vetter = ValueVetter.valueVetter(new double[] {fill, missing});
}
/*
* Set the object that will unpack the vetted data.
*/
{
attr = var.getAttribute("scale_factor");
double scale =
attr == null ? 1 : attr.getNumericValue().doubleValue();
attr = var.getAttribute("add_offset");
double offset =
attr == null ? 0 : attr.getNumericValue().doubleValue();
if (scale == scale && scale != 1 && offset == offset && offset != 0)
{
unpacker = ScaleAndOffsetUnpacker.scaleAndOffsetUnpacker(
scale, offset);
}
else if (scale == scale && scale != 1)
{
unpacker = ScaleUnpacker.scaleUnpacker(scale);
}
else if (offset == offset && offset != 0)
{
unpacker = OffsetUnpacker.offsetUnpacker(offset);
}
else
{
unpacker = ValueUnpacker.valueUnpacker();
}
}
/*
* Set the object that will range the unpacked data.
*/
{
attr = var.getAttribute("valid_range");
if (attr != null)
{
lower = attr.getNumericValue(0).doubleValue();
upper = attr.getNumericValue(1).doubleValue();
}
attr = var.getAttribute("valid_min");
if (attr != null)
lower = attr.getNumericValue().doubleValue();
attr = var.getAttribute("valid_max");
if (attr != null)
upper = attr.getNumericValue().doubleValue();
ranger = ValueRanger.valueRanger(lower, upper);
/*
* Account for NaN semantics in the following:
*/
if (minValid < lower)
minValid = lower;
if (maxValid > upper)
maxValid = upper;
}
}
/**
* Returns the minimum, valid, netCDF value.
*
* @return The minimum, valid, value for the variable.
*/
double
minValid()
{
return minValid;
}
/**
* Returns the maximum, valid, netCDF value.
*
* @return The maximum, valid, value for the variable.
*/
double
maxValid()
{
return maxValid;
}
/**
* Vets the given float values.
*
* @param values The values to be vetted.
* @postcondition All invalid values in <code>values</code> have been
* replaced with NaN's.
*/
public void
vet(float[] values)
{
ranger.process(unpacker.process(vetter.process(values)));
}
/**
* Vets the given double values.
*
* @param values The values to be vetted.
* @postcondition All invalid values in <code>values</code> have been
* replaced with NaN's.
*/
public void
vet(double[] values)
{
ranger.process(unpacker.process(vetter.process(values)));
}
}