All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.nc2.dataset.CoordinateAxis Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.nc2.dataset;

import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.CF;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.dataset.conv.CF1Convention;
import ucar.nc2.dataset.conv.COARDSConvention;
import ucar.nc2.time.Calendar;

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 public 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() == 0) || (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; } /** * An interval coordinate consists of two numbers, bound1 and bound2. * The coordinate value must lie between them, but otherwise is somewhat arbitrary. * If not interval, then it has one number, the coordinate value. * @return true if its an interval coordinate. */ public boolean isInterval() { return false; // interval detection is done in subclasses } public boolean isIndependentCoordinate() { if (isCoordinateVariable()) return true; return null != findAttribute(_Coordinate.AliasForDimension); } /* * 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() { int result = super.hashCode(); if (getAxisType() != null) result = 37 * result + getAxisType().hashCode(); if (getPositive() != null) result = 37 * result + getPositive().hashCode(); return result; } ///////////////////////////////////// // needed by time coordinates public ucar.nc2.time.Calendar getCalendarFromAttribute() { Attribute cal = findAttribute(CF.CALENDAR); String s = (cal == null) ? null : cal.getStringValue(); if (s == null) { // default for CF and COARDS Attribute convention = (ncd == null) ? null : ncd.getRootGroup().findAttribute(CDM.CONVENTIONS); if (convention != null) { String hasName = convention.getStringValue(); int version = CF1Convention.getVersion(hasName); if (version >= 0) { return Calendar.gregorian; //if (version < 7 ) return Calendar.gregorian; //if (version >= 7 ) return Calendar.proleptic_gregorian; // } if (COARDSConvention.isMine(hasName)) return Calendar.gregorian; } } return ucar.nc2.time.Calendar.get(s); } /* @Override public boolean isCoordinateVariable() { return true; } */ }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy