/* * 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.iosp.grid; import ucar.ma2.*; import ucar.nc2.*; import ucar.nc2.constants.AxisType; import ucar.nc2.constants._Coordinate; import ucar.nc2.units.SimpleUnit; import java.util.*; /** * A Coordinate System for a Grid variable. * * @author john */ public class GridCoordSys { /** * horizontal coordinate system */ private GridHorizCoordSys hcs; /** * a grid record */ private GridRecord record; /** * vertical name */ private String verticalName; /** * lookup table */ private GridTableLookup lookup; /** * list of levels */ private List<Double> levels; /** * flag for not using the vertical */ boolean dontUseVertical = false; /** * postive direction */ String positive = "up"; /** * units */ String units; /** * Create a coordinate system * * @param hcs horizontal coord sys * @param record grid record * @param name name of the vertical dimension * @param lookup lookuptable */ GridCoordSys(GridHorizCoordSys hcs, GridRecord record, String name, GridTableLookup lookup) { this.hcs = hcs; this.record = record; this.verticalName = name; this.lookup = lookup; this.levels = new ArrayList<Double>(); dontUseVertical = !lookup.isVerticalCoordinate(record); positive = lookup.isPositiveUp(record) ? "up" : "down"; units = lookup.getLevelUnit(record); if (GridServiceProvider.debugVert) { System.out.println("GridCoordSys: " + getVerticalDesc() + " useVertical= " + (!dontUseVertical) + " positive=" + positive + " units=" + units); } } /** * Get the coordinate system name * * @return the coordinate system name */ String getCoordSysName() { return verticalName + "_CoordSys"; } /** * Get the vertical name * * @return the vertical name */ String getVerticalName() { return verticalName; } /** * Get the vertical description * * @return the vertical description */ String getVerticalDesc() { return verticalName + "(" + record.getLevelType1() + ")"; } /** * Get the number of levels * * @return the number of levels */ int getNLevels() { return dontUseVertical ? 1 : levels.size(); } /** * Add levels from the GridRecords * * @param records the records */ void addLevels(List<GridRecord> records) { for (GridRecord record : records) { Double d = new Double(record.getLevel1()); if (!levels.contains(d)) { levels.add(d); } if (dontUseVertical && (levels.size() > 1)) { if (GridServiceProvider.debugVert) { System.out.println( "GribCoordSys: unused level coordinate has > 1 levels = " + verticalName + " " + record.getLevelType1() + " " + levels.size()); } } } Collections.sort(levels); if (positive.equals("down")) { Collections.reverse(levels); // TODO: delete /* for( int i = 0; i < (levels.size()/2); i++ ){ Double tmp = (Double) levels.get( i ); levels.set( i, levels.get(levels.size() -i -1)); levels.set(levels.size() -i -1, tmp ); } */ } } /** * Match levels * * @param records list of GridRecords * @return true if they match */ boolean matchLevels(List<GridRecord> records) { // first create a new list List<Double> levelList = new ArrayList<Double>(records.size()); for (GridRecord record : records) { Double d = new Double(record.getLevel1()); if (!levelList.contains(d)) { levelList.add(d); } } Collections.sort(levelList); if (positive.equals("down")) { Collections.reverse(levelList); } // gotta equal existing list return levelList.equals(levels); } /** * Add dimensions to the netcdf file * * @param ncfile the netCDF file * @param g the group to add to */ void addDimensionsToNetcdfFile(NetcdfFile ncfile, Group g) { if (dontUseVertical) { return; } int nlevs = levels.size(); ncfile.addDimension(g, new Dimension(verticalName, nlevs, true)); } /** * Add this coordinate system to the netCDF file * * @param ncfile the netCDF file * @param g the group to add to */ void addToNetcdfFile(NetcdfFile ncfile, Group g) { if (dontUseVertical) { return; } if (g == null) { g = ncfile.getRootGroup(); } String dims = "time"; if (!dontUseVertical) { dims = dims + " " + verticalName; } if (hcs.isLatLon()) { dims = dims + " lat lon"; } else { dims = dims + " y x"; } //Collections.sort( levels); int nlevs = levels.size(); // ncfile.addDimension(g, new Dimension(verticalName, nlevs, true)); // coordinate axis and coordinate system Variable Variable v = new Variable(ncfile, g, null, verticalName); v.setDataType(DataType.DOUBLE); v.addAttribute(new Attribute("long_name", lookup.getLevelDescription(record))); v.addAttribute(new Attribute("units", lookup.getLevelUnit(record))); // positive attribute needed for CF-1 Height and Pressure if (positive != null) { v.addAttribute(new Attribute("positive", positive)); } if (units != null) { AxisType axisType; if (SimpleUnit.isCompatible("millibar", units)) { axisType = AxisType.Pressure; } else if (SimpleUnit.isCompatible("m", units)) { axisType = AxisType.Height; } else { axisType = AxisType.GeoZ; } v.addAttribute( new Attribute( "grid_level_type", Integer.toString(record.getLevelType1()))); v.addAttribute(new Attribute(_Coordinate.AxisType, axisType.toString())); v.addAttribute(new Attribute(_Coordinate.Axes, dims)); if (!hcs.isLatLon()) { v.addAttribute(new Attribute(_Coordinate.Transforms, hcs.getGridName())); } } double[] data = new double[nlevs]; for (int i = 0; i < levels.size(); i++) { Double d = (Double) levels.get(i); data[i] = d.doubleValue(); } Array dataArray = Array.factory(DataType.DOUBLE, new int[]{nlevs}, data); v.setDimensions(verticalName); v.setCachedData(dataArray, false); ncfile.addVariable(g, v); // look for vertical transforms if (record.getLevelType1() == 109) { findCoordinateTransform(g, "Pressure", record.getLevelType1()); } } /** * Find the coordinate transform * * @param g group to check * @param nameStartsWith beginning of name * @param levelType type of level */ void findCoordinateTransform(Group g, String nameStartsWith, int levelType) { // look for variable that uses this coordinate List<Variable> vars = g.getVariables(); for (Variable v : vars) { if (v.getShortName().equals(nameStartsWith)) { Attribute att = v.findAttribute("grid_level_type"); if ((att == null) || (att.getNumericValue().intValue() != levelType)) { continue; } v.addAttribute(new Attribute(_Coordinate.TransformType, "Vertical")); v.addAttribute(new Attribute("transform_name", "Existing3DField")); } } } /** * Get the index of a particular GridRecord * * @param record record to find * @return the index or -1 */ int getIndex(GridRecord record) { Double d = new Double(record.getLevel1()); return levels.indexOf(d); } }