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

ucar.nc2.dataset.CoordinateSystem 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.nc2.*;
import ucar.nc2.constants.AxisType;
import ucar.unidata.geoloc.*;
import ucar.unidata.geoloc.projection.*;

import java.util.*;

/**
 * A CoordinateSystem specifies the coordinates of a Variable's values.
 *
 *  Mathematically it is a vector function F from index space to Sn:
 * 
 *  F(i,j,k,...) -> (S1, S2, ...Sn)
 *  where i,j,k are integers, and S is the set of reals (R) or Strings.
 * 
* The components of F are just its coordinate axes: *
 *  F = (A1, A2, ...An)
 *    A1(i,j,k,...) -> S1
 *    A2(i,j,k,...) -> S1
 *    An(i,j,k,...) -> Sn
 * 
* * Concretely, a CoordinateSystem is a set of coordinate axes, and an optional set * of coordinate transforms. * The domain rank of F is the number of dimensions it is a function of. The range rank is the number * of coordinate axes. * *

* An important class of CoordinateSystems are georeferencing Coordinate Systems, that locate a * Variable's values in space and time. A CoordinateSystem that has a Lat and Lon axis, or a GeoX and GeoY * axis and a Projection CoordinateTransform will have isGeoReferencing() true. * A CoordinateSystem that has a Height, Pressure, or GeoZ axis will have hasVerticalAxis() true. *

* Further CoordinateSystems specialization is done by "data type specific" classes such as * ucar.nc2.ft2.coverage.grid.GridCoordSys. * * @author caron * @see Coordinate System Object Model */ public class CoordinateSystem { static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CoordinateSystem.class); /** * Create standard name from list of axes. Sort the axes first * @param axes list of CoordinateAxis * @return CoordinateSystem name, created from axes names */ static public String makeName( List axes) { List axesSorted = new ArrayList<>( axes); Collections.sort( axesSorted, new CoordinateAxis.AxisComparator()); StringBuilder buff = new StringBuilder(); for (int i=0; i0) buff.append(" "); buff.append( axis.getFullNameEscaped()); } return buff.toString(); } ////////////////////////////////////////////////////////////////////////////////////// protected NetcdfDataset ds; protected List coordAxes = new ArrayList<>(); protected List coordTrans = new ArrayList<>(); protected Set domain = new HashSet<>(); // set of dimension protected String name; protected CoordinateAxis xAxis, yAxis, zAxis, tAxis, latAxis, lonAxis, hAxis, pAxis, ensAxis; protected CoordinateAxis aziAxis, elevAxis, radialAxis; protected boolean isImplicit; protected String dataType; // Grid, Station, etc // subclasses protected CoordinateSystem() {} /** * Constructor. * @param ds the containing dataset * @param axes Collection of type CoordinateAxis, must be at least one. * @param coordTrans Collection of type CoordinateTransform, may be empty or null. */ public CoordinateSystem(NetcdfDataset ds, Collection axes, Collection coordTrans) { this.ds = ds; this.coordAxes = new ArrayList<>( axes); this.name = makeName( coordAxes); if (coordTrans != null) this.coordTrans = new ArrayList<>( coordTrans); for (CoordinateAxis axis : coordAxes) { // look for AxisType AxisType axisType = axis.getAxisType(); if (axisType != null) { if (axisType == AxisType.GeoX) xAxis = lesserRank(xAxis, axis); if (axisType == AxisType.GeoY) yAxis = lesserRank(yAxis, axis); if (axisType == AxisType.GeoZ) zAxis = lesserRank(zAxis, axis); if (axisType == AxisType.Time) tAxis = lesserRank(tAxis, axis); if (axisType == AxisType.Lat) latAxis = lesserRank(latAxis, axis); if (axisType == AxisType.Lon) lonAxis = lesserRank(lonAxis, axis); if (axisType == AxisType.Height) hAxis = lesserRank(hAxis, axis); if (axisType == AxisType.Pressure) pAxis = lesserRank(pAxis, axis); if (axisType == AxisType.Ensemble) ensAxis = lesserRank(ensAxis, axis); if (axisType == AxisType.RadialAzimuth) aziAxis = lesserRank(aziAxis, axis); if (axisType == AxisType.RadialDistance) radialAxis = lesserRank(radialAxis, axis); if (axisType == AxisType.RadialElevation) elevAxis = lesserRank(elevAxis, axis); } // collect dimensions List dims = axis.getDimensionsAll(); for (Dimension dim : dims) { if (!domain.contains(dim)) domain.add(dim); } } } // prefer smaller ranks, in case more than one private CoordinateAxis lesserRank( CoordinateAxis a1, CoordinateAxis a2) { if (a1 == null) return a2; return (a1.getRank() <= a2.getRank()) ? a1 : a2; } /** add a CoordinateTransform * @param ct add this CoordinateTransform */ public void addCoordinateTransform(CoordinateTransform ct) { coordTrans.add( ct); ds.addCoordinateTransform( ct); } /** add a Collection of CoordinateTransform * @param ct add all CoordinateTransform in this collection */ public void addCoordinateTransforms(Collection ct) { if (ct != null) coordTrans.addAll( ct); } /** * get the List of CoordinateAxis objects * @return the List of CoordinateAxis objects * */ public List getCoordinateAxes() { return coordAxes; } /** * get the List of CoordinateTransform objects * @return the List of CoordinateTransform objects */ public List getCoordinateTransforms() { return coordTrans; } /** * get the name of the Coordinate System * @return the name of the Coordinate System */ public String getName() { return name; } /** * Get the underlying NetcdfDataset * @return the underlying NetcdfDataset. */ public NetcdfDataset getNetcdfDataset() { return ds; } /** * List of Dimensions that constitute the domain. * @return the List of Dimensions that constitute the domain. */ public Collection getDomain() { return domain; } /** * Get the domain rank of the coordinate system = number of dimensions it is a function of. * @return domain.size() */ public int getRankDomain() { return domain.size(); } /** Get the range rank of the coordinate system = number of coordinate axes. * @return coordAxes.size() */ public int getRankRange() { return coordAxes.size(); } /* Scientific Data type, if known, eg Grid, Station, etc. Considered Experimental public String getDataType() { return dataType; } /* Set the Scientific Data type, eg Grid, Station, etc. Considered Experimental public void setDataType(String dataType) { this.dataType = dataType; } */ /////////////////////////////////////////////////////////////////////////// // Convenience routines for finding georeferencing axes /** * Find the CoordinateAxis that has the given AxisType. * If more than one, return the one with lesser rank. * @param type look for this axisType * @return CoordinateAxis of the given AxisType, else null. */ public CoordinateAxis findAxis( AxisType type) { CoordinateAxis result = null; for (CoordinateAxis axis : coordAxes) { AxisType axisType = axis.getAxisType(); if ((axisType != null) && (axisType == type)) result = lesserRank(result, axis); } return result; } /** get the CoordinateAxis with AxisType.GeoX, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.GeoX, or null if none */ public CoordinateAxis getXaxis() { return xAxis; } /** get the CoordinateAxis with AxisType.GeoY, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.GeoY, or null if none */ public CoordinateAxis getYaxis() { return yAxis; } /** get the CoordinateAxis with AxisType.GeoZ, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.GeoZ, or null if none */ public CoordinateAxis getZaxis() { return zAxis; } /** get the CoordinateAxis with AxisType.Time, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.Time, or null if none */ public CoordinateAxis getTaxis() { return tAxis; } /** get the CoordinateAxis with AxisType.Lat, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.Lat, or null if none */ public CoordinateAxis getLatAxis() { return latAxis; } /** get the CoordinateAxis with AxisType.Lon, or null if none. * if more than one, choose one with smallest rank * * @return axis of type AxisType.Lon, or null if none */ public CoordinateAxis getLonAxis() { return lonAxis; } /** get the CoordinateAxis with AxisType.Height, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.Height, or null if none */ public CoordinateAxis getHeightAxis() { return hAxis; } /** get the CoordinateAxis with AxisType.Pressure, or null if none. * if more than one, choose one with smallest rank. * @return axis of type AxisType.Pressure, or null if none */ public CoordinateAxis getPressureAxis() { return pAxis; } /** get the CoordinateAxis with AxisType.Ensemble, or null if none. * if more than one, choose one with smallest rank. * @return axis of type AxisType.Ensemble, or null if none */ public CoordinateAxis getEnsembleAxis() { return ensAxis; } /** get the CoordinateAxis with AxisType.RadialAzimuth, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.RadialAzimuth, or null if none */ public CoordinateAxis getAzimuthAxis() { return aziAxis; } /** get the CoordinateAxis with AxisType.RadialDistance, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.RadialDistance, or null if none */ public CoordinateAxis getRadialAxis() { return radialAxis; } /** get the CoordinateAxis with AxisType.RadialElevation, or null if none. * if more than one, choose one with smallest rank * @return axis of type AxisType.RadialElevation, or null if none */ public CoordinateAxis getElevationAxis() { return elevAxis; } /** * Find the first ProjectionCT from the list of CoordinateTransforms. * @return ProjectionCT or null if none. */ public ProjectionCT getProjectionCT() { for (CoordinateTransform ct : coordTrans) { if (ct instanceof ProjectionCT) return (ProjectionCT) ct; } return null; } /** Get the Projection for this coordinate system. * If isLatLon(), then returns a LatLonProjection. Otherwise, extracts the * projection from any ProjectionCT CoordinateTransform. * @return ProjectionImpl or null if none. */ public ProjectionImpl getProjection() { if (projection == null) { if (isLatLon()) projection = new LatLonProjection(); ProjectionCT projCT = getProjectionCT(); if (null != projCT) projection = projCT.getProjection(); } return projection; } private ProjectionImpl projection = null; //////////////////////////////////////////////////////////////////////////// // classification /** * true if it has X and Y CoordinateAxis, and a CoordTransform Projection * @return true if it has X and Y CoordinateAxis, and a CoordTransform Projection */ public boolean isGeoXY() { if ((xAxis == null) || (yAxis == null)) return false; return null != getProjection() && !(projection instanceof LatLonProjection); } /** * true if it has Lat and Lon CoordinateAxis * @return true if it has Lat and Lon CoordinateAxis */ public boolean isLatLon() { return (latAxis != null) && (lonAxis != null); } /** true if it has radial distance and azimuth CoordinateAxis * @return true if it has radial distance and azimuth CoordinateAxis */ public boolean isRadial() { return (radialAxis != null) && (aziAxis != null); } /** true if isGeoXY or isLatLon * @return true if isGeoXY or isLatLon */ public boolean isGeoReferencing() { return isGeoXY() || isLatLon(); } /** * true if all axes are CoordinateAxis1D * @return true if all axes are CoordinateAxis1D */ public boolean isProductSet() { for (CoordinateAxis axis : coordAxes) { if (!(axis instanceof CoordinateAxis1D)) return false; } return true; } /** true if all axes are CoordinateAxis1D and are regular * * @return true if all axes are CoordinateAxis1D and are regular */ public boolean isRegular() { for (CoordinateAxis axis : coordAxes) { if (!(axis instanceof CoordinateAxis1D)) return false; if (!((CoordinateAxis1D) axis).isRegular()) return false; } return true; } /** * Check if this Coordinate System is complete for v, ie if all its dimensions are also used by v. * @param v check for this variable * @return true if all dimensions in V (including parents) are in the domain of this coordinate system. */ public boolean isComplete(VariableIF v) { return isSubset(v.getDimensionsAll(), domain); } /** * Check if this Coordinate System can be used for the given variable. * A CoordinateAxis can only be part of a Variable's CoordinateSystem if the CoordinateAxis' set of Dimensions is a * subset of the Variable's set of Dimensions. * So, a CoordinateSystem' set of Dimensions must be a subset of the Variable's set of Dimensions. * @param v check for this variable * @return true if all dimensions in the domain of this coordinate system are in V (including parents). */ public boolean isCoordinateSystemFor(VariableIF v) { return isSubset(domain, v.getDimensionsAll()); } /** * Test if all the Dimensions in subset are in set * @param subset is this a subset * @param set of this? * @return true if all the Dimensions in subset are in set */ public static boolean isSubset(Collection subset, Collection set) { for (Dimension d : subset) { if (!(set.contains(d))) return false; } return true; } public static Set makeDomain(Iterable axes) { Set domain = new HashSet<>(); for (Variable axis : axes) { for (Dimension dim : axis.getDimensions()) { domain.add(dim); } } return domain; } public static int countDomain(Variable[] axes) { Set domain = new HashSet<>(); for (Variable axis : axes) { for (Dimension dim : axis.getDimensions()) { domain.add(dim); } } return domain.size(); } /** * Implicit Coordinate System are constructed based on which Coordinate Variables exist for the Dimensions of the Variable. * This is in contrast to a Coordinate System that is explicitly specified in the file. * @return true if this coordinate system was constructed implicitly. */ public boolean isImplicit() { return isImplicit; } /** Set whether this Coordinate System is implicit * @param isImplicit true if constructed implicitly. */ protected void setImplicit(boolean isImplicit) { this.isImplicit = isImplicit; } /** true if has Height, Pressure, or GeoZ axis * @return true if has a vertical axis */ public boolean hasVerticalAxis() { return (hAxis != null) || (pAxis != null) || (zAxis != null); } /** true if has Time axis * @return true if has Time axis */ public boolean hasTimeAxis() { return (tAxis != null); } /** * Do we have all the axes in the list? * @param wantAxes List of CoordinateAxis * @return true if all in our list. */ public boolean containsAxes(List wantAxes) { for (CoordinateAxis ca : wantAxes) { if (!containsAxis(ca.getFullName())) return false; } return true; } /** * Do we have the named axis? * @param axisName (full unescaped) name of axis * @return true if we have an axis of that name */ public boolean containsAxis(String axisName) { for (CoordinateAxis ca : coordAxes) { if (ca.getFullName().equals(axisName)) return true; } return false; } /** * Do we have all the dimensions in the list? * @param wantDimensions List of Dimensions * @return true if all in our list. */ public boolean containsDomain(List wantDimensions) { for (Dimension d : wantDimensions) { if (!domain.contains(d)) return false; } return true; } /** * Do we have all the axes types in the list? * @param wantAxes List of AxisType * @return true if all in our list. */ public boolean containsAxisTypes(List wantAxes) { for (AxisType wantAxisType : wantAxes) { if (!containsAxisType(wantAxisType)) return false; } return true; } /** * Do we have an axes of the given type? * @param wantAxisType want this AxisType * @return true if we have at least one axis of that type. */ public boolean containsAxisType(AxisType wantAxisType) { for (CoordinateAxis ca : coordAxes) { if (ca.getAxisType() == wantAxisType) return true; } return false; } void makeTimeAxis() { if ((tAxis != null) && (tAxis instanceof CoordinateAxis1D) && !(tAxis instanceof CoordinateAxis1DTime)) { Formatter err = new Formatter(); try { CoordinateAxis1DTime timeAxis = CoordinateAxis1DTime.factory(ds, tAxis, err); coordAxes.remove(tAxis); coordAxes.add(timeAxis); tAxis = timeAxis; ds.addCoordinateAxis(timeAxis); // will remove old one } catch (Exception e) { log.error(tAxis.getDatasetLocation() + ": Error reading time coord= " + err, e); } } } //////////////////////////////////////////////////////////////////////////// /** * Instances which have same name are equal. */ public boolean equals(Object oo) { if (this == oo) return true; if ( !(oo instanceof CoordinateSystem)) return false; CoordinateSystem o = (CoordinateSystem) oo; if (!getName().equals(o.getName())) return false; List oaxes = o.getCoordinateAxes(); for (CoordinateAxis axis : getCoordinateAxes()) { if (!oaxes.contains(axis)) return false; } List otrans = o.getCoordinateTransforms(); for (CoordinateTransform tran : getCoordinateTransforms()) { if (!otrans.contains(tran)) return false; } return true; } /** Override Object.hashCode() to implement equals. */ public int hashCode() { if (hashCode == 0) { int result = 17; result = 37*result + getName().hashCode(); result = 37*result + getCoordinateAxes().hashCode(); result = 37*result + getCoordinateTransforms().hashCode(); hashCode = result; } return hashCode; } private volatile int hashCode = 0; public String toString() { return name; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy