Package ucar.nc2.dataset.conv

Source Code of ucar.nc2.dataset.conv.CF1Convention

/*
* 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.conv;

import ucar.nc2.*;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CF;
import ucar.nc2.units.SimpleUnit;
import ucar.nc2.util.CancelTask;
import ucar.nc2.dataset.*;
import ucar.ma2.Array;
import ucar.ma2.IndexIterator;
import ucar.ma2.DataType;

import java.util.*;
import java.io.IOException;

/**
* CF-1 Convention.
* see http://www.cgd.ucar.edu/cms/eaton/cf-metadata/index.html
* <p/>
* <i>
* "The CF conventions for climate and forecast metadata are designed to promote the
* processing and sharing of files created with the netCDF API. The conventions define
* metadata that provide a definitive description of what the data in each variable
* represents, and of the spatial and temporal properties of the data.
* This enables users of data from different sources to decide which quantities are
* comparable, and facilitates building applications with powerful extraction, regridding,
* and display capabilities."
* </i>
*
* @author caron
*/

public class CF1Convention extends CSMConvention {

  /**
   * Guess the value of ZisPositive based on z axis name and units
   *
   * @param zaxisName      z coordinate axis name
   * @param vertCoordUnits z coordinate axis name
   * @return CF.POSITIVE_UP or CF.POSITIVE_DOWN
   */
  public static String getZisPositive(String zaxisName, String vertCoordUnits) {
    if (vertCoordUnits == null) return CF.POSITIVE_UP;

    if (SimpleUnit.isCompatible("millibar", vertCoordUnits))
      return CF.POSITIVE_DOWN;

    if (SimpleUnit.isCompatible("m", vertCoordUnits))
      return CF.POSITIVE_UP;

    // dunno - make it up
    return CF.POSITIVE_UP;
  }

  private static String[] vertical_coords = {
          "atmosphere_sigma_coordinate",
          "atmosphere_hybrid_sigma_pressure_coordinate",
          "atmosphere_hybrid_height_coordinate",
          "atmosphere_sleve_coordinate",
          "ocean_sigma_coordinate",
          "ocean_s_coordinate",
          "ocean_sigma_z_coordinate",
          "ocean_double_sigma_coordinate",
          "ocean_s_coordinate_g1",          // -sachin 03/25/09
          "ocean_s_coordinate_g2"};

  public CF1Convention() {
    this.conventionName = "CF-1.X";
  }

  public void augmentDataset(NetcdfDataset ds, CancelTask cancelTask) throws IOException {
    boolean got_grid_mapping = false;

    // look for transforms
    List<Variable> vars = ds.getVariables();
    for (Variable v : vars) {
      // look for special standard_names
      String sname = ds.findAttValueIgnoreCase(v, CF.STANDARD_NAME, null);
      if (sname != null) {
        sname = sname.trim();

        if (sname.equalsIgnoreCase("atmosphere_ln_pressure_coordinate")) { // LOOK why isnt this with other Transforms?
          makeAtmLnCoordinate(ds, v);
          continue;
        }

        if (sname.equalsIgnoreCase("forecast_reference_time")) { // experimental
          v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RunTime.toString()));
          continue;
        }

        if (sname.equalsIgnoreCase("ensemble")) {  // experimental
          v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Ensemble.toString()));
          continue;
        }

        for (String vertical_coord : vertical_coords)
          if (sname.equalsIgnoreCase(vertical_coord)) {
            v.addAttribute(new Attribute(_Coordinate.TransformType, TransformType.Vertical.toString()));
            if (v.findAttribute(_Coordinate.Axes) == null)
              v.addAttribute(new Attribute(_Coordinate.Axes, v.getFullName())); // LOOK: may also be time dependent
          }
      }

      // look for horiz transforms. only ones that are referenced by another variable.
      String grid_mapping = ds.findAttValueIgnoreCase(v, CF.GRID_MAPPING, null);
      if (grid_mapping != null) {
        Variable gridMap = ds.findVariable(grid_mapping);
        if (gridMap == null) {
          Group g = v.getParentGroup(); // might be group reletive - CF does not specify
          gridMap = g.findVariable(grid_mapping);
        }
        if (gridMap != null) {
          gridMap.addAttribute(new Attribute(_Coordinate.TransformType, TransformType.Projection.toString()));
          gridMap.addAttribute(new Attribute(_Coordinate.AxisTypes, "GeoX GeoY"));
          got_grid_mapping = true;
        }
      }

    }

    if (!got_grid_mapping) { // see if there are any grid mappings anyway
      for (Variable v : ds.getVariables()) {
        String grid_mapping_name = ds.findAttValueIgnoreCase(v, CF.GRID_MAPPING_NAME, null);
        if (grid_mapping_name != null) {
          v.addAttribute(new Attribute(_Coordinate.TransformType, TransformType.Projection.toString()));
          v.addAttribute(new Attribute(_Coordinate.AxisTypes, "GeoX GeoY"));
        }
      }
    }

    // make corrections for specific datasets
    String src = ds.findAttValueIgnoreCase(null, "Source", "");
    if (src.equals("NOAA/National Climatic Data Center")) {
      String title = ds.findAttValueIgnoreCase(null, "title", "");
      avhrr_oiv2 = title.indexOf("OI-V2") > 0;
    }
    ds.finish();
  }

  private boolean avhrr_oiv2 = false;


  // this is here because it doesnt fit into 3D array thing.
  private void makeAtmLnCoordinate(NetcdfDataset ds, Variable v) {
    // get the formula attribute
    String formula = ds.findAttValueIgnoreCase(v, "formula_terms", null);
    if (null == formula) {
      String msg = " Need attribute 'formula_terms' on Variable " + v.getFullName() + "\n";
      parseInfo.format(msg);
      userAdvice.format(msg);
      return;
    }

    // parse the formula string
    Variable p0Var = null, levelVar = null;
    StringTokenizer stoke = new StringTokenizer(formula, " :");
    while (stoke.hasMoreTokens()) {
      String toke = stoke.nextToken();
      if (toke.equalsIgnoreCase("p0")) {
        String name = stoke.nextToken();
        p0Var = ds.findVariable(name);
      } else if (toke.equalsIgnoreCase("lev")) {
        String name = stoke.nextToken();
        levelVar = ds.findVariable(name);
      }
    }

    if (null == p0Var) {
      String msg = " Need p0:varName on Variable " + v.getFullName() + " formula_terms\n";
      parseInfo.format(msg);
      userAdvice.format(msg);
      return;
    }

    if (null == levelVar) {
      String msg = " Need lev:varName on Variable " + v.getFullName() + " formula_terms\n";
      parseInfo.format(msg);
      userAdvice.format(msg);
      return;
    }

    String units = ds.findAttValueIgnoreCase(p0Var, "units", "hPa");

    // create the data and the variable
    try { // p(k) = p0 * exp(-lev(k))
      double p0 = p0Var.readScalarDouble();
      Array levelData = levelVar.read();
      Array pressureData = Array.factory(double.class, levelData.getShape());
      IndexIterator ii = levelData.getIndexIterator();
      IndexIterator iip = pressureData.getIndexIterator();
      while (ii.hasNext()) {
        double val = p0 * Math.exp(-1.0 * ii.getDoubleNext());
        iip.setDoubleNext(val);
      }

      CoordinateAxis1D p = new CoordinateAxis1D(ds, null, v.getShortName() + "_pressure", DataType.DOUBLE,
              levelVar.getDimensionsString(), units,
              "Vertical Pressure coordinate synthesized from atmosphere_ln_pressure_coordinate formula");
      p.setCachedData(pressureData, false);
      p.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Pressure.toString()));
      p.addAttribute(new Attribute(_Coordinate.AliasForDimension, p.getDimensionsString()));
      ds.addVariable(null, p);
      //Dimension d = p.getDimension(0);
      //d.addCoordinateVariable(p);
      parseInfo.format(" added Vertical Pressure coordinate %s\n", p.getFullName());

    } catch (IOException e) {
      String msg = " Unable to read variables from " + v.getFullName() + " formula_terms\n";
      parseInfo.format(msg);
      userAdvice.format(msg);
    }

  }

  /*  vertical coordinate will be identifiable by:
      1. units of pressure; or
      2. the presence of the positive attribute with a value of up or down (case insensitive).
      3. Optionally, the vertical type may be indicated additionally by providing the standard_name attribute with an appropriate value, and/or the axis attribute with the value Z.
   */

  // we assume that coordinate axes get identified by
  //  1) being coordinate variables or
  //  2) being listed in coordinates attribute.

  /**
   * Augment CSM axis type identification with "projection_x_coordinate", "projection_y_coordinate"
   * and  the various dimensionless vertical coordinates
   */
  protected AxisType getAxisType(NetcdfDataset ncDataset, VariableEnhanced v) {

    String sname = ncDataset.findAttValueIgnoreCase((Variable) v, CF.STANDARD_NAME, null);
    if (sname != null) {
      sname = sname.trim();

      if (sname.equalsIgnoreCase("latitude"))
        return AxisType.Lat;

      if (sname.equalsIgnoreCase("longitude"))
        return AxisType.Lon;

      if (sname.equalsIgnoreCase("projection_x_coordinate") || sname.equalsIgnoreCase("grid_longitude"))
        return AxisType.GeoX;

      if (sname.equalsIgnoreCase("projection_y_coordinate") || sname.equalsIgnoreCase("grid_latitude"))
        return AxisType.GeoY;

      for (String vertical_coord : vertical_coords)
        if (sname.equalsIgnoreCase(vertical_coord))
          return AxisType.GeoZ;
    }

    AxisType at = super.getAxisType(ncDataset, v);

    // check axis attribute - only for X, Y, Z
    if (at == null) {
      String axis = ncDataset.findAttValueIgnoreCase((Variable) v, "axis", null);
      if (axis != null) {
        axis = axis.trim();
        String unit = v.getUnitsString();

        if (axis.equalsIgnoreCase("X")) {
          if (SimpleUnit.isCompatible("m", unit))
            return AxisType.GeoX;

        } else if (axis.equalsIgnoreCase("Y")) {
          if (SimpleUnit.isCompatible("m", unit))
            return AxisType.GeoY;

        } else if (axis.equalsIgnoreCase("Z")) {
          if (unit == null) return AxisType.GeoZ;
          if (SimpleUnit.isCompatible("m", unit))
            return AxisType.Height;
          else if (SimpleUnit.isCompatible("mbar", unit))
            return AxisType.Pressure;
          else
            return AxisType.GeoZ;
        }
      }
    }

    if ((at == null) && avhrr_oiv2) {
      if (v.getShortName().equals("zlev"))
        return AxisType.Height;
    }

    return at;
  }

}

TOP

Related Classes of ucar.nc2.dataset.conv.CF1Convention

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.