ucar.nc2.dataset.CoordinateAxis Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of netcdf Show documentation
Show all versions of netcdf Show documentation
The NetCDF-Java Library is a Java interface to NetCDF files,
as well as to many other types of scientific data formats.
The newest version!
/*
* Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.dataset;
import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.constants.AxisType;
import java.io.IOException;
import java.util.Formatter;
/**
* A Coordinate Axis is a Variable that specifies one of the coordinates of a CoordinateSystem.
* Mathematically it is a scalar function F from index space to S:
*
* F:D -> S
* where D is a product set of dimensions (aka index space), and S is the set of reals (R) or Strings.
*
*
* If its element type is char, it is considered a string-valued Coordinate Axis and rank is reduced by one,
* since the outermost dimension is considered the string length: v(i, j, .., strlen).
* If its element type is String, it is a string-valued Coordinate Axis.
* Otherwise it is numeric-valued, and isNumeric() is true.
*
* The one-dimensional case F(i) -> R is the common case which affords important optimizations.
* In that case, use the subtype CoordinateAxis1D. The factory methods will return
* either a CoordinateAxis1D if the variable is one-dimensional, a CoordinateAxis2D if its 2D, or a
* CoordinateAxis for the general case.
*
* A CoordinateAxis is optionally marked as georeferencing with an AxisType. It should have
* a units string and optionally a description string.
*
* A Structure cannot be a CoordinateAxis, although members of Structures can.
*
* @author john caron
*/
public class CoordinateAxis extends VariableDS {
static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CoordinateAxis.class);
static private final int axisSizeToCache = 100 * 1000; // bytes
protected NetcdfDataset ncd; // container dataset
protected AxisType axisType = null;
protected String positive = null;
protected String boundaryRef = null;
protected boolean isContiguous = true;
/**
* Create a coordinate axis from an existing Variable.
*
* @param ncd the containing dataset
* @param vds an existing Variable in dataset.
* @return CoordinateAxis or one of its subclasses (CoordinateAxis1D, CoordinateAxis2D, or CoordinateAxis1DTime).
*/
static public CoordinateAxis factory(NetcdfDataset ncd, VariableDS vds) {
if ((vds.getRank() == 1) ||
(vds.getRank() == 2 && vds.getDataType() == DataType.CHAR))
return new CoordinateAxis1D(ncd, vds);
else if (vds.getRank() == 2)
return new CoordinateAxis2D(ncd, vds);
else
return new CoordinateAxis(ncd, vds);
}
/**
* Create a coordinate axis from an existing Variable.
* General case.
*
* @param ncd the containing dataset
* @param vds an existing Variable
*/
protected CoordinateAxis(NetcdfDataset ncd, VariableDS vds) {
super(vds, false);
this.ncd = ncd;
if (vds instanceof CoordinateAxis) {
CoordinateAxis axis = (CoordinateAxis) vds;
this.axisType = axis.axisType;
this.boundaryRef = axis.boundaryRef;
this.isContiguous = axis.isContiguous;
this.positive = axis.positive;
}
setSizeToCache(axisSizeToCache);
}
/**
* Constructor when theres no underlying variable. You better set the values too!
*
* @param ds the containing dataset.
* @param group the containing group; if null, use rootGroup
* @param shortName axis name.
* @param dataType data type
* @param dims list of dimension names
* @param units units of coordinates, preferably udunit compatible.
* @param desc long name.
*/
public CoordinateAxis(NetcdfDataset ds, Group group, String shortName, DataType dataType, String dims, String units, String desc) {
super(ds, group, null, shortName, dataType, dims, units, desc);
this.ncd = ds;
setSizeToCache(axisSizeToCache);
}
/**
* Make a copy, with an independent cache.
*
* @return copy of this CoordinateAxis
*/
public CoordinateAxis copyNoCache() {
CoordinateAxis axis = new CoordinateAxis(ncd, getParentGroup(), getShortName(), getDataType(), getDimensionsString(),
getUnitsString(), getDescription());
// other state
axis.axisType = this.axisType;
axis.boundaryRef = this.boundaryRef;
axis.isContiguous = this.isContiguous;
axis.positive = this.positive;
axis.cache = new Variable.Cache(); // decouple cache
return axis;
}
// for section and slice
@Override
protected Variable copy() {
return new CoordinateAxis(this.ncd, this);
}
/**
* Get type of axis
*
* @return type of axis, or null if none.
*/
public AxisType getAxisType() {
return axisType;
}
/**
* Set type of axis, or null if none. Default is none.
*
* @param axisType set to this value
*/
public void setAxisType(AxisType axisType) {
this.axisType = axisType;
}
@Override
public String getUnitsString() {
String units = super.getUnitsString();
return units == null ? "" : units;
}
/**
* Does the axis have numeric values.
*
* @return true if the CoordAxis is numeric, false if its string valued ("nominal").
*/
public boolean isNumeric() {
return (getDataType() != DataType.CHAR) &&
(getDataType() != DataType.STRING) &&
(getDataType() != DataType.STRUCTURE);
}
/**
* If the edges are contiguous or disjoint
* Caution: many datasets do not explicitly specify this info, this is often a guess; default is true.
*
* @return true if the edges are contiguous or false if disjoint. Assumed true unless set otherwise.
*/
public boolean isContiguous() {
return isContiguous;
}
// causes TDS ERROR thredds.server.opendap.NcDDS: NcDDS: Variable time1_run missing coordinate variable in hash; dataset=fmrc/NCEP/GFS/Global_onedeg/NCEP-GFS-Global_onedeg_best.ncd
//@Override
//public boolean isCoordinateVariable() {
// return true;
//}
/*
* Set if the edges are contiguous or disjoint.
*
* @param isContiguous true if the adjacent edges touch
*
protected void setContiguous(boolean isContiguous) {
this.isContiguous = isContiguous;
} */
/**
* Get the direction of increasing values, used only for vertical Axes.
*
* @return POSITIVE_UP, POSITIVE_DOWN, or null if unknown.
*/
public String getPositive() {
return positive;
}
/**
* Set the direction of increasing values, used only for vertical Axes.
*
* @param positive POSITIVE_UP, POSITIVE_DOWN, or null if you dont know..
*/
public void setPositive(String positive) {
this.positive = positive;
}
/**
* The name of this coordinate axis' boundary variable
*
* @return the name of this coordinate axis' boundary variable, or null if none.
*/
public String getBoundaryRef() {
return boundaryRef;
}
/**
* Set a reference to a boundary variable.
*
* @param boundaryRef the name of a boundary coordinate variable in the same dataset.
*/
public void setBoundaryRef(String boundaryRef) {
this.boundaryRef = boundaryRef;
}
////////////////////////////////
private MAMath.MinMax minmax = null;
private void init() {
try {
Array data = read();
minmax = MAMath.getMinMax(data);
} catch (IOException ioe) {
log.error("Error reading coordinate values ", ioe);
throw new IllegalStateException(ioe);
}
}
/**
* The smallest coordinate value. Only call if isNumeric.
*
* @return the minimum coordinate value
*/
public double getMinValue() {
if (minmax == null) init();
return minmax.min;
}
/**
* The largest coordinate value. Only call if isNumeric.
*
* @return the maximum coordinate value
*/
public double getMaxValue() {
if (minmax == null) init();
return minmax.max;
}
//////////////////////
/**
* Get a string representation
*
* @param buf place info here
*/
public void getInfo(Formatter buf) {
buf.format("%-30s", getNameAndDimensions());
buf.format("%-20s", getUnitsString());
if (axisType != null) {
buf.format("%-10s", axisType.toString());
}
buf.format("%s", getDescription());
/* if (isNumeric) {
boolean debugCoords = ucar.util.prefs.ui.Debug.isSet("Dataset/showCoordValues");
int ndigits = debugCoords ? 9 : 4;
for (int i=0; i< getNumElements(); i++) {
buf.append(Format.d(getCoordValue(i), ndigits));
buf.append(" ");
}
if (debugCoords) {
buf.append("\n ");
for (int i=0; i<=getNumElements(); i++) {
buf.append(Format.d(getCoordEdge(i), ndigits));
buf.append(" ");
}
}
} else {
for (int i=0; i< getNumElements(); i++) {
buf.append(getCoordName(i));
buf.append(" ");
}
} */
//buf.append("\n");
}
/**
* Standard sort on Coordinate Axes
*/
static public class AxisComparator implements java.util.Comparator {
public int compare(CoordinateAxis c1, CoordinateAxis c2) {
AxisType t1 = c1.getAxisType();
AxisType t2 = c2.getAxisType();
if ((t1 == null) && (t2 == null))
return c1.getShortName().compareTo(c2.getShortName());
if (t1 == null)
return -1;
if (t2 == null)
return 1;
return t1.axisOrder() - t2.axisOrder();
}
public boolean equals(Object obj) {
return (this == obj);
}
}
/**
* Instances which have same content are equal.
*/
public boolean equals(Object oo) {
if (this == oo) return true;
if (!(oo instanceof CoordinateAxis)) return false;
if (!super.equals(oo)) return false;
CoordinateAxis o = (CoordinateAxis) oo;
if (getAxisType() != null)
if (!getAxisType().equals(o.getAxisType())) return false;
if (getPositive() != null)
if (!getPositive().equals(o.getPositive())) return false;
return true;
}
/**
* Override Object.hashCode() to implement equals.
*/
public int hashCode() {
if (hashCode == 0) {
int result = super.hashCode();
if (getAxisType() != null)
result = 37 * result + getAxisType().hashCode();
if (getPositive() != null)
result = 37 * result + getPositive().hashCode();
hashCode = result;
}
return hashCode;
}
private int hashCode = 0;
}